Skip to content
Snippets Groups Projects
Unverified Commit ab842850 authored by Sergio Zharinov's avatar Sergio Zharinov Committed by GitHub
Browse files

fix(nuget): Parse nested Version XML elements (#7190)


* fix(nuget): Parse nested Version XML elements

* Compactify currentValue extraction chain

* Fix coverage

* Don't walk through entire XML

Co-authored-by: default avatarMichael Kriese <michael.kriese@visualon.de>
parent 73a6e23a
No related branches found
No related tags found
No related merge requests found
...@@ -18,13 +18,17 @@ ...@@ -18,13 +18,17 @@
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.1.2" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.2" /> <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.2" />
<PackageReference Include="Newtonsoft.Json" VersionOverride="10.0.2" /> <PackageReference Include="Newtonsoft.Json" VersionOverride="10.0.2" />
<PackageReference Include="Serilog" Version="2.4.0" /> <PackageReference Include="Serilog">
<VersionOverride>
2.4.0
</VersionOverride>
</PackageReference>
<PackageReference Include="Serilog.Extensions.Logging" Version="1.4.0" /> <PackageReference Include="Serilog.Extensions.Logging" Version="1.4.0" />
<PackageReference Include="Serilog.Sinks.Literate" Version="2.1.0" /> <PackageReference Include="Serilog.Sinks.Literate" Version="2.1.0" />
<PackageReference Include="Stateless" Version="3.1.0.5" /> <PackageReference Include="Stateless" Version="3.1.0.5" />
<PackageReference Include="Range1" Version="[1.2.3]" /> <PackageReference Include="Range1" Version="[1.2.3]" />
<PackageReference Include="Range2" Version="[1.2.3,]" /> <PackageReference Include="Range2" Version="[1.2.3,]" />
<PackageReference Include="Range3" Version="[1.2.3,)" /> <PackageReference Include="Range3"><Version>[1.2.3,)</Version></PackageReference>
<PackageReference Include="NotUpdatable1" Version="[,1.2.3)" /> <PackageReference Include="NotUpdatable1" Version="[,1.2.3)" />
<PackageReference Include="NotUpdatable2" Version="(1.2.3,)" /> <PackageReference Include="NotUpdatable2" Version="(1.2.3,)" />
<PackageReference Include="NotUpdatable3" Version="(1.2.3, 3.2.1)" /> <PackageReference Include="NotUpdatable3" Version="(1.2.3, 3.2.1)" />
......
...@@ -74,7 +74,52 @@ async function determineRegistryUrls( ...@@ -74,7 +74,52 @@ async function determineRegistryUrls(
return registryUrls; return registryUrls;
} }
const packageRe = /<(?:PackageReference|DotNetCliToolReference|GlobalPackageReference).*(?:Include|Update)\s*=\s*"(?<depName>[^"]+)".*(?:Version|VersionOverride)\s*=\s*"(?:[[])?(?:(?<currentValue>[^"(,[\]]+)\s*(?:,\s*[)\]]|])?)"/; /**
* https://docs.microsoft.com/en-us/nuget/concepts/package-versioning
* This article mentions that Nuget 3.x and later tries to restore the lowest possible version
* regarding to given version range.
* 1.3.4 equals [1.3.4,)
* Due to guarantee that an update of package version will result in its usage by the next restore + build operation,
* only following constrained versions make sense
* 1.3.4, [1.3.4], [1.3.4, ], [1.3.4, )
* The update of the right boundary does not make sense regarding to the lowest version restore rule,
* so we don't include it in the extracting regexp
*/
const checkVersion = /^\s*(?:[[])?(?:(?<currentValue>[^"(,[\]]+)\s*(?:,\s*[)\]]|])?)\s*$/;
function extractDepsFromXml(xmlNode: XmlDocument): PackageDependency[] {
const results = [];
const itemGroups = xmlNode.childrenNamed('ItemGroup');
for (const itemGroup of itemGroups) {
const relevantChildren = [
...itemGroup.childrenNamed('PackageReference'),
...itemGroup.childrenNamed('DotNetCliToolReference'),
...itemGroup.childrenNamed('GlobalPackageReference'),
];
for (const child of relevantChildren) {
const { attr } = child;
const depName = attr?.Include || attr?.Update;
const version =
attr?.Version ||
child.valueWithPath('Version') ||
attr?.VersionOverride ||
child.valueWithPath('VersionOverride');
const currentValue = version
?.match(checkVersion)
?.groups?.currentValue?.trim();
if (depName && currentValue) {
results.push({
datasource: datasourceNuget.id,
depType: 'nuget',
depName,
currentValue,
});
}
}
}
return results;
}
export async function extractPackageFile( export async function extractPackageFile(
content: string, content: string,
packageFile: string, packageFile: string,
...@@ -82,7 +127,6 @@ export async function extractPackageFile( ...@@ -82,7 +127,6 @@ export async function extractPackageFile(
): Promise<PackageFile | null> { ): Promise<PackageFile | null> {
logger.trace({ packageFile }, 'nuget.extractPackageFile()'); logger.trace({ packageFile }, 'nuget.extractPackageFile()');
const versioning = get(config.versioning || semverVersioning.id); const versioning = get(config.versioning || semverVersioning.id);
const deps: PackageDependency[] = [];
const registryUrls = await determineRegistryUrls( const registryUrls = await determineRegistryUrls(
packageFile, packageFile,
...@@ -90,6 +134,7 @@ export async function extractPackageFile( ...@@ -90,6 +134,7 @@ export async function extractPackageFile(
); );
if (packageFile.endsWith('.config/dotnet-tools.json')) { if (packageFile.endsWith('.config/dotnet-tools.json')) {
const deps: PackageDependency[] = [];
let manifest: DotnetToolsManifest; let manifest: DotnetToolsManifest;
try { try {
...@@ -123,36 +168,19 @@ export async function extractPackageFile( ...@@ -123,36 +168,19 @@ export async function extractPackageFile(
return { deps }; return { deps };
} }
for (const line of content.split('\n')) { let deps: PackageDependency[] = [];
/** try {
* https://docs.microsoft.com/en-us/nuget/concepts/package-versioning const parsedXml = new XmlDocument(content);
* This article mentions that Nuget 3.x and later tries to restore the lowest possible version deps = extractDepsFromXml(parsedXml).map((dep) => ({
* regarding to given version range. ...dep,
* 1.3.4 equals [1.3.4,) ...(registryUrls && { registryUrls }),
* Due to guarantee that an update of package version will result in its usage by the next restore + build operation, ...(!versioning.isVersion(dep.currentValue) && {
* only following constrained versions make sense skipReason: SkipReason.NotAVersion,
* 1.3.4, [1.3.4], [1.3.4, ], [1.3.4, ) }),
* The update of the right boundary does not make sense regarding to the lowest version restore rule, }));
* so we don't include it in the extracting regexp return { deps };
*/ } catch (err) {
logger.debug({ err }, `Failed to parse ${packageFile}`);
const match = packageRe.exec(line);
if (match) {
const { currentValue, depName } = match.groups;
const dep: PackageDependency = {
depType: 'nuget',
depName,
currentValue,
datasource: datasourceNuget.id,
};
if (registryUrls) {
dep.registryUrls = registryUrls;
}
if (!versioning.isVersion(currentValue)) {
dep.skipReason = SkipReason.NotAVersion;
}
deps.push(dep);
}
} }
return { deps }; return { deps };
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment