Skip to content

Commit 5505b52

Browse files
papauorgRahulGautamSinghviceice
authored
feat(manager/nuget): Support single file package directives (renovatebot#40040)
* Add nuget capability to read packages from cs files This is useful for dotnet source files that make use of the .NET 10 feature to have single file projects, where packages and sdks can be defined in a source file. * Add tests to validate that the nuget.config file is respected for single csharp files * Apply PR linter suggestion for prettier code * Remove unnecessary try-catch to increase code coverage * Update phrasing in documentation Co-authored-by: RahulGautamSingh <rahultesnik@gmail.com> * Use codeblock instead of fixture * Remove unused import * Remove unnecessary fixtures and only verify required methods are called * Fix imports in single-chsarp-file.ts * Fix import ordering * Increase code block indent --------- Co-authored-by: RahulGautamSingh <rahultesnik@gmail.com> Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
1 parent 7ebba26 commit 5505b52

File tree

4 files changed

+105
-0
lines changed

4 files changed

+105
-0
lines changed

lib/modules/manager/nuget/extract.spec.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type { RepoGlobalConfig } from '../../../config/types.ts';
77
import { DotnetVersionDatasource } from '../../datasource/dotnet-version/index.ts';
88
import type { ExtractConfig } from '../types.ts';
99
import { extractPackageFile } from './index.ts';
10+
import * as nugetExtractUtil from './util.ts';
1011

1112
const config: ExtractConfig = {};
1213

@@ -577,5 +578,59 @@ describe('modules/manager/nuget/extract', () => {
577578
expect(await extractPackageFile('{{', packageFile, config)).toBeNull();
578579
});
579580
});
581+
582+
describe('single-csharp-file', () => {
583+
it('reads sdk and package directives', async () => {
584+
const packageFile = 'single-csharp-file/singlefile.cs';
585+
const contents = codeBlock`
586+
#:sdk Some.Sdk@6.0.0
587+
#:package Some.NuGet.Package@3.0.1
588+
589+
// https://devblogs.microsoft.com/dotnet/announcing-dotnet-run-app/
590+
591+
Console.WriteLine("Hello World!");
592+
`;
593+
expect(await extractPackageFile(contents, packageFile, config)).toEqual(
594+
{
595+
deps: [
596+
{
597+
datasource: 'nuget',
598+
currentValue: '6.0.0',
599+
depName: 'Some.Sdk',
600+
depType: 'msbuild-sdk',
601+
},
602+
{
603+
datasource: 'nuget',
604+
currentValue: '3.0.1',
605+
depName: 'Some.NuGet.Package',
606+
depType: 'nuget',
607+
},
608+
],
609+
},
610+
);
611+
});
612+
});
613+
614+
describe('single-csharp-file-nuget', () => {
615+
it('calls applyRegistries to honor nuget.config files if present', async () => {
616+
const packageFile = 'single-csharp-file-nuget/singlefile.cs';
617+
const contents = codeBlock`
618+
#:sdk Some.Sdk@6.0.0
619+
#:package Some.NuGet.Package@3.0.1
620+
621+
// https://devblogs.microsoft.com/dotnet/announcing-dotnet-run-app/
622+
623+
Console.WriteLine("Hello World!");
624+
`;
625+
626+
const applyRegistriesSpy = vi
627+
.spyOn(nugetExtractUtil, 'applyRegistries')
628+
.mockImplementation((deps: any) => deps);
629+
630+
await extractPackageFile(contents, packageFile, config);
631+
632+
expect(applyRegistriesSpy).toHaveBeenCalled();
633+
});
634+
});
580635
});
581636
});

lib/modules/manager/nuget/extract.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import type {
1313
PackageFileContent,
1414
} from '../types.ts';
1515
import { extractMsbuildGlobalManifest } from './extract/global-manifest.ts';
16+
import { extractPackagesFromSingleCsharpFile } from './extract/single-csharp-file.ts';
1617
import type { DotnetToolsManifest, NugetPackageDependency } from './types.ts';
1718
import {
1819
applyRegistries,
@@ -204,6 +205,14 @@ export async function extractPackageFile(
204205
return extractMsbuildGlobalManifest(content, packageFile, registries);
205206
}
206207

208+
if (packageFile.endsWith('.cs')) {
209+
return extractPackagesFromSingleCsharpFile(
210+
content,
211+
packageFile,
212+
registries,
213+
);
214+
}
215+
207216
// Simple xml validation.
208217
// Should start with `<` and end with `>` after trimming all whitespace
209218
if (!regEx(/^\s*<.+>$/m).test(content.trim())) {
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { regEx } from '../../../../util/regex.ts';
2+
import { NugetDatasource } from '../../../datasource/nuget/index.ts';
3+
import type { PackageDependency, PackageFileContent } from '../../types.ts';
4+
import type { NugetPackageDependency, Registry } from '../types.ts';
5+
import { applyRegistries } from '../util.ts';
6+
7+
// regex for finding
8+
// #:package Name@Version
9+
// or
10+
// #:sdk Name@Version
11+
const packageRegex = regEx(
12+
/^#:(?<type>package|sdk)\s+(?<depName>[A-Za-z0-9_.-]+)@(?<currentValue>[0-9][^\s]*)/,
13+
'gm',
14+
);
15+
16+
export function extractPackagesFromSingleCsharpFile(
17+
content: string,
18+
packageFile: string,
19+
registries: Registry[] | undefined,
20+
): PackageFileContent | null {
21+
const deps: PackageDependency[] = [];
22+
23+
for (const match of content.matchAll(packageRegex)) {
24+
const { type, depName, currentValue } = match.groups!;
25+
26+
const dep: NugetPackageDependency = {
27+
depName,
28+
currentValue,
29+
datasource: NugetDatasource.id,
30+
depType: type === 'package' ? 'nuget' : 'msbuild-sdk',
31+
};
32+
33+
applyRegistries(dep, registries);
34+
deps.push(dep);
35+
}
36+
37+
return { deps };
38+
}

lib/modules/manager/nuget/readme.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ For Renovate to work with .NET Framework projects, you need to update these file
2020
- `.props`
2121
- `.targets`
2222

23+
You can also extract from the single code file projects (since `.NET 10`).
24+
But, you need to add those files manually to the `managerFilePatterns` as they are not supported by default.
25+
2326
### Disabling updates for pinned versions
2427

2528
In NuGet, when you use versions like `Version="1.2.3"` then it means "1.2.3 or greater, up to v2"

0 commit comments

Comments
 (0)