mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-13 15:36:25 +00:00
feat(manager:nuget): support central version management (#15698)
This commit is contained in:
parent
c3acca8877
commit
c1da6b948d
8 changed files with 140 additions and 13 deletions
|
@ -0,0 +1,8 @@
|
||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageVersion Include="Serilog" Version="2.10.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
|
@ -0,0 +1,12 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
|
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Serilog" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"dependencies": {
|
||||||
|
".NETCoreApp,Version=v5.0": {
|
||||||
|
"Serilog": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[2.10.0, )",
|
||||||
|
"resolved": "2.10.0",
|
||||||
|
"contentHash": "+QX0hmf37a0/OZLxM3wL7V6/ADvC1XihXN4Kq/p6d8lCPfgkRdiuhbWlMaFjR9Av0dy5F0+MBeDmDdRZN/YwQA=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"dependencies": {
|
||||||
|
".NETCoreApp,Version=v5.0": {
|
||||||
|
"Serilog": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[2.10.0, )",
|
||||||
|
"resolved": "2.10.0",
|
||||||
|
"contentHash": "+QX0hmf37a0/OZLxM3wL7V6/ADvC1XihXN4Kq/p6d8lCPfgkRdiuhbWlMaFjR9Av0dy5F0+MBeDmDdRZN/YwQA=="
|
||||||
|
},
|
||||||
|
"one": {
|
||||||
|
"type": "Project",
|
||||||
|
"dependencies": {
|
||||||
|
"Serilog": "2.10.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
|
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Serilog" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="../one/one.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -22,7 +22,11 @@ import type {
|
||||||
UpdateArtifactsConfig,
|
UpdateArtifactsConfig,
|
||||||
UpdateArtifactsResult,
|
UpdateArtifactsResult,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import { getDependentPackageFiles } from './package-tree';
|
import {
|
||||||
|
MSBUILD_CENTRAL_FILE,
|
||||||
|
NUGET_CENTRAL_FILE,
|
||||||
|
getDependentPackageFiles,
|
||||||
|
} from './package-tree';
|
||||||
import {
|
import {
|
||||||
getConfiguredRegistries,
|
getConfiguredRegistries,
|
||||||
getDefaultRegistries,
|
getDefaultRegistries,
|
||||||
|
@ -116,7 +120,18 @@ export async function updateArtifacts({
|
||||||
}: UpdateArtifact): Promise<UpdateArtifactsResult[] | null> {
|
}: UpdateArtifact): Promise<UpdateArtifactsResult[] | null> {
|
||||||
logger.debug(`nuget.updateArtifacts(${packageFileName})`);
|
logger.debug(`nuget.updateArtifacts(${packageFileName})`);
|
||||||
|
|
||||||
if (!regEx(/(?:cs|vb|fs)proj$/i).test(packageFileName)) {
|
// https://github.com/NuGet/Home/wiki/Centrally-managing-NuGet-package-versions
|
||||||
|
// https://github.com/microsoft/MSBuildSdks/tree/main/src/CentralPackageVersions
|
||||||
|
const isCentralManament =
|
||||||
|
packageFileName === NUGET_CENTRAL_FILE ||
|
||||||
|
packageFileName === MSBUILD_CENTRAL_FILE ||
|
||||||
|
packageFileName.endsWith(`/${NUGET_CENTRAL_FILE}`) ||
|
||||||
|
packageFileName.endsWith(`/${MSBUILD_CENTRAL_FILE}`);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!isCentralManament &&
|
||||||
|
!regEx(/(?:cs|vb|fs)proj$/i).test(packageFileName)
|
||||||
|
) {
|
||||||
// This could be implemented in the future if necessary.
|
// This could be implemented in the future if necessary.
|
||||||
// It's not that easy though because the questions which
|
// It's not that easy though because the questions which
|
||||||
// project file to restore how to determine which lock files
|
// project file to restore how to determine which lock files
|
||||||
|
@ -129,10 +144,13 @@ export async function updateArtifacts({
|
||||||
}
|
}
|
||||||
|
|
||||||
const packageFiles = [
|
const packageFiles = [
|
||||||
...(await getDependentPackageFiles(packageFileName)),
|
...(await getDependentPackageFiles(packageFileName, isCentralManament)),
|
||||||
packageFileName,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (!isCentralManament) {
|
||||||
|
packageFiles.push(packageFileName);
|
||||||
|
}
|
||||||
|
|
||||||
logger.trace(
|
logger.trace(
|
||||||
{ packageFiles },
|
{ packageFiles },
|
||||||
`Found ${packageFiles.length} dependent package files`
|
`Found ${packageFiles.length} dependent package files`
|
||||||
|
|
|
@ -63,6 +63,25 @@ describe('modules/manager/nuget/package-tree', () => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('returns projects for two projects with one reference and central versions', async () => {
|
||||||
|
git.getFileList.mockResolvedValue(['one/one.csproj', 'two/two.csproj']);
|
||||||
|
Fixtures.mock({
|
||||||
|
'/tmp/repo/one/one.csproj': Fixtures.get(
|
||||||
|
'two-one-reference-with-central-versions/one/one.csproj'
|
||||||
|
),
|
||||||
|
'/tmp/repo/two/two.csproj': Fixtures.get(
|
||||||
|
'two-one-reference-with-central-versions/two/two.csproj'
|
||||||
|
),
|
||||||
|
'/tmp/repo/Directory.Packages.props': Fixtures.get(
|
||||||
|
'two-one-reference-with-central-versions/Directory.Packages.props'
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await getDependentPackageFiles('Directory.Packages.props', true)
|
||||||
|
).toEqual(['one/one.csproj', 'two/two.csproj']);
|
||||||
|
});
|
||||||
|
|
||||||
it('returns two projects for three projects with two linear references', async () => {
|
it('returns two projects for three projects with two linear references', async () => {
|
||||||
git.getFileList.mockResolvedValue([
|
git.getFileList.mockResolvedValue([
|
||||||
'one/one.csproj',
|
'one/one.csproj',
|
||||||
|
|
|
@ -6,28 +6,44 @@ import { logger } from '../../../logger';
|
||||||
import { readLocalFile } from '../../../util/fs';
|
import { readLocalFile } from '../../../util/fs';
|
||||||
import { getFileList } from '../../../util/git';
|
import { getFileList } from '../../../util/git';
|
||||||
|
|
||||||
|
export const NUGET_CENTRAL_FILE = 'Directory.Packages.props';
|
||||||
|
export const MSBUILD_CENTRAL_FILE = 'Packages.props';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all package files at any level of ancestry that depend on packageFileName
|
* Get all package files at any level of ancestry that depend on packageFileName
|
||||||
*/
|
*/
|
||||||
export async function getDependentPackageFiles(
|
export async function getDependentPackageFiles(
|
||||||
packageFileName: string
|
packageFileName: string,
|
||||||
|
isCentralManament = false
|
||||||
): Promise<string[]> {
|
): Promise<string[]> {
|
||||||
const packageFiles = await getAllPackageFiles();
|
const packageFiles = await getAllPackageFiles();
|
||||||
const graph: ReturnType<typeof Graph> = Graph();
|
const graph: ReturnType<typeof Graph> = Graph();
|
||||||
|
|
||||||
|
if (isCentralManament) {
|
||||||
|
graph.addNode(packageFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
const parentDir =
|
||||||
|
packageFileName === NUGET_CENTRAL_FILE ||
|
||||||
|
packageFileName === MSBUILD_CENTRAL_FILE
|
||||||
|
? ''
|
||||||
|
: upath.dirname(packageFileName);
|
||||||
|
|
||||||
for (const f of packageFiles) {
|
for (const f of packageFiles) {
|
||||||
graph.addNode(f);
|
graph.addNode(f);
|
||||||
|
|
||||||
|
if (isCentralManament && upath.dirname(f).startsWith(parentDir)) {
|
||||||
|
graph.addEdge(packageFileName, f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const f of packageFiles) {
|
for (const f of packageFiles) {
|
||||||
const packageFileContent = (await readLocalFile(f, 'utf8')).toString();
|
const packageFileContent = await readLocalFile(f, 'utf8');
|
||||||
|
|
||||||
const doc = new xmldoc.XmlDocument(packageFileContent);
|
const doc = new xmldoc.XmlDocument(packageFileContent);
|
||||||
const projectReferenceAttributes = (
|
const projectReferenceAttributes = doc
|
||||||
doc
|
.childrenNamed('ItemGroup')
|
||||||
.childrenNamed('ItemGroup')
|
.map((ig) => ig.childrenNamed('ProjectReference'))
|
||||||
.map((ig) => ig.childrenNamed('ProjectReference')) ?? []
|
|
||||||
)
|
|
||||||
.flat()
|
.flat()
|
||||||
.map((pf) => pf.attr['Include']);
|
.map((pf) => pf.attr['Include']);
|
||||||
|
|
||||||
|
@ -47,7 +63,13 @@ export async function getDependentPackageFiles(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return recursivelyGetDependentPackageFiles(packageFileName, graph);
|
const dependents = recursivelyGetDependentPackageFiles(
|
||||||
|
packageFileName,
|
||||||
|
graph
|
||||||
|
);
|
||||||
|
|
||||||
|
// deduplicate
|
||||||
|
return Array.from(new Set(dependents.reverse())).reverse();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,7 +79,7 @@ function recursivelyGetDependentPackageFiles(
|
||||||
packageFileName: string,
|
packageFileName: string,
|
||||||
graph: ReturnType<typeof Graph>
|
graph: ReturnType<typeof Graph>
|
||||||
): string[] {
|
): string[] {
|
||||||
const dependents: string[] = graph.adjacent(packageFileName);
|
const dependents = graph.adjacent(packageFileName);
|
||||||
|
|
||||||
if (dependents.length === 0) {
|
if (dependents.length === 0) {
|
||||||
return [];
|
return [];
|
||||||
|
|
Loading…
Reference in a new issue