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,
|
||||
UpdateArtifactsResult,
|
||||
} from '../types';
|
||||
import { getDependentPackageFiles } from './package-tree';
|
||||
import {
|
||||
MSBUILD_CENTRAL_FILE,
|
||||
NUGET_CENTRAL_FILE,
|
||||
getDependentPackageFiles,
|
||||
} from './package-tree';
|
||||
import {
|
||||
getConfiguredRegistries,
|
||||
getDefaultRegistries,
|
||||
|
@ -116,7 +120,18 @@ export async function updateArtifacts({
|
|||
}: UpdateArtifact): Promise<UpdateArtifactsResult[] | null> {
|
||||
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.
|
||||
// It's not that easy though because the questions which
|
||||
// project file to restore how to determine which lock files
|
||||
|
@ -129,10 +144,13 @@ export async function updateArtifacts({
|
|||
}
|
||||
|
||||
const packageFiles = [
|
||||
...(await getDependentPackageFiles(packageFileName)),
|
||||
packageFileName,
|
||||
...(await getDependentPackageFiles(packageFileName, isCentralManament)),
|
||||
];
|
||||
|
||||
if (!isCentralManament) {
|
||||
packageFiles.push(packageFileName);
|
||||
}
|
||||
|
||||
logger.trace(
|
||||
{ packageFiles },
|
||||
`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 () => {
|
||||
git.getFileList.mockResolvedValue([
|
||||
'one/one.csproj',
|
||||
|
|
|
@ -6,28 +6,44 @@ import { logger } from '../../../logger';
|
|||
import { readLocalFile } from '../../../util/fs';
|
||||
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
|
||||
*/
|
||||
export async function getDependentPackageFiles(
|
||||
packageFileName: string
|
||||
packageFileName: string,
|
||||
isCentralManament = false
|
||||
): Promise<string[]> {
|
||||
const packageFiles = await getAllPackageFiles();
|
||||
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) {
|
||||
graph.addNode(f);
|
||||
|
||||
if (isCentralManament && upath.dirname(f).startsWith(parentDir)) {
|
||||
graph.addEdge(packageFileName, f);
|
||||
}
|
||||
}
|
||||
|
||||
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 projectReferenceAttributes = (
|
||||
doc
|
||||
const projectReferenceAttributes = doc
|
||||
.childrenNamed('ItemGroup')
|
||||
.map((ig) => ig.childrenNamed('ProjectReference')) ?? []
|
||||
)
|
||||
.map((ig) => ig.childrenNamed('ProjectReference'))
|
||||
.flat()
|
||||
.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,
|
||||
graph: ReturnType<typeof Graph>
|
||||
): string[] {
|
||||
const dependents: string[] = graph.adjacent(packageFileName);
|
||||
const dependents = graph.adjacent(packageFileName);
|
||||
|
||||
if (dependents.length === 0) {
|
||||
return [];
|
||||
|
|
Loading…
Reference in a new issue