mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-11 14:36:25 +00:00
feat(nuget): detect feeds in NuGet.confg (#5757)
This commit is contained in:
parent
5c334f44af
commit
139e8bb2c2
14 changed files with 233 additions and 24 deletions
|
@ -6,6 +6,10 @@
|
|||
"settings": {
|
||||
"terminal.integrated.shell.linux": "/bin/bash"
|
||||
},
|
||||
"extensions": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"],
|
||||
"extensions": [
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode",
|
||||
"orta.vscode-jest"
|
||||
],
|
||||
"postCreateCommand": "yarn install"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ To convert your .NET Framework `.csproj`/`.fsproj`/`.vbproj` into an SDK-style p
|
|||
|
||||
## Alternate feeds
|
||||
|
||||
Renovate by default performs all lookups on `https://api.nuget.org/v3/index.json`, but it also supports alternative nuget feeds. Alternative feeds can be specified in configuration file:
|
||||
Renovate by default performs all lookups on `https://api.nuget.org/v3/index.json`, but it also supports alternative nuget feeds. Alternative feeds can be specified either [in a `NuGet.config` file](https://docs.microsoft.com/en-us/nuget/reference/nuget-config-file#package-source-sections) within your repository (Renovate will not search outside the repository) or in Renovate configuration options:
|
||||
|
||||
```json
|
||||
"nuget": {
|
||||
|
|
|
@ -6,6 +6,8 @@ import { GetReleasesConfig, ReleaseResult } from '../common';
|
|||
|
||||
export { id } from './common';
|
||||
|
||||
export { getDefaultFeed } from './v3';
|
||||
|
||||
function parseRegistryUrl(
|
||||
registryUrl: string
|
||||
): { feedUrl: string; protocolVersion: number } {
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<clear />
|
||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
|
||||
<add key="Contoso" value="https://contoso.com/packages/" />
|
||||
</packageSources>
|
||||
</configuration>
|
|
@ -0,0 +1,11 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp1.1</TargetFramework>
|
||||
<Version>0.1.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Autofac" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1 @@
|
|||
This is no XML document
|
|
@ -0,0 +1,11 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp1.1</TargetFramework>
|
||||
<Version>0.1.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Autofac" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<noPackageSources />
|
||||
</configuration>
|
|
@ -0,0 +1,11 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp1.1</TargetFramework>
|
||||
<Version>0.1.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Autofac" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,5 +1,25 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`lib/manager/nuget/extract extractPackageFile() considers NuGet.config 1`] = `
|
||||
Object {
|
||||
"deps": Array [
|
||||
Object {
|
||||
"currentValue": "4.5.0",
|
||||
"datasource": "nuget",
|
||||
"depName": "Autofac",
|
||||
"depType": "nuget",
|
||||
"managerData": Object {
|
||||
"lineNumber": 8,
|
||||
},
|
||||
"registryUrls": Array [
|
||||
"https://api.nuget.org/v3/index.json#protocolVersion=3",
|
||||
"https://contoso.com/packages/",
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`lib/manager/nuget/extract extractPackageFile() extracts all dependencies 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
|
@ -141,6 +161,38 @@ Array [
|
|||
]
|
||||
`;
|
||||
|
||||
exports[`lib/manager/nuget/extract extractPackageFile() handles NuGet.config without package sources 1`] = `
|
||||
Object {
|
||||
"deps": Array [
|
||||
Object {
|
||||
"currentValue": "4.5.0",
|
||||
"datasource": "nuget",
|
||||
"depName": "Autofac",
|
||||
"depType": "nuget",
|
||||
"managerData": Object {
|
||||
"lineNumber": 8,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`lib/manager/nuget/extract extractPackageFile() handles malformed NuGet.config 1`] = `
|
||||
Object {
|
||||
"deps": Array [
|
||||
Object {
|
||||
"currentValue": "4.5.0",
|
||||
"datasource": "nuget",
|
||||
"depName": "Autofac",
|
||||
"depType": "nuget",
|
||||
"managerData": Object {
|
||||
"lineNumber": 8,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`lib/manager/nuget/extract extractPackageFile() returns empty for invalid csproj 1`] = `
|
||||
Object {
|
||||
"deps": Array [],
|
||||
|
|
|
@ -1,23 +1,63 @@
|
|||
import { readFileSync } from 'fs';
|
||||
import * as path from 'path';
|
||||
import { extractPackageFile } from './extract';
|
||||
|
||||
const sample = readFileSync(
|
||||
'lib/manager/nuget/__fixtures__/sample.csproj',
|
||||
'utf8'
|
||||
);
|
||||
|
||||
describe('lib/manager/nuget/extract', () => {
|
||||
describe('extractPackageFile()', () => {
|
||||
let config;
|
||||
beforeEach(() => {
|
||||
config = {};
|
||||
config = {
|
||||
localDir: path.resolve('lib/manager/nuget/__fixtures__'),
|
||||
};
|
||||
});
|
||||
it('returns empty for invalid csproj', () => {
|
||||
expect(extractPackageFile('nothing here', config)).toMatchSnapshot();
|
||||
it('returns empty for invalid csproj', async () => {
|
||||
expect(
|
||||
await extractPackageFile('nothing here', 'bogus', config)
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
it('extracts all dependencies', () => {
|
||||
const res = extractPackageFile(sample, config).deps;
|
||||
expect(res).toMatchSnapshot();
|
||||
it('extracts all dependencies', async () => {
|
||||
const packageFile = 'sample.csproj';
|
||||
const sample = readFileSync(
|
||||
path.join(config.localDir, packageFile),
|
||||
'utf8'
|
||||
);
|
||||
const res = await extractPackageFile(sample, packageFile, config);
|
||||
expect(res.deps).toMatchSnapshot();
|
||||
});
|
||||
it('considers NuGet.config', async () => {
|
||||
const packageFile = 'with-config-file/with-config-file.csproj';
|
||||
const contents = readFileSync(
|
||||
path.join(config.localDir, packageFile),
|
||||
'utf8'
|
||||
);
|
||||
|
||||
expect(
|
||||
await extractPackageFile(contents, packageFile, config)
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
it('handles malformed NuGet.config', async () => {
|
||||
const packageFile =
|
||||
'with-malformed-config-file/with-malformed-config-file.csproj';
|
||||
const contents = readFileSync(
|
||||
path.join(config.localDir, packageFile),
|
||||
'utf8'
|
||||
);
|
||||
|
||||
expect(
|
||||
await extractPackageFile(contents, packageFile, config)
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
it('handles NuGet.config without package sources', async () => {
|
||||
const packageFile =
|
||||
'without-package-sources/without-package-sources.csproj';
|
||||
const contents = readFileSync(
|
||||
path.join(config.localDir, packageFile),
|
||||
'utf8'
|
||||
);
|
||||
|
||||
expect(
|
||||
await extractPackageFile(contents, packageFile, config)
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
import findUp from 'find-up';
|
||||
import * as path from 'path';
|
||||
import { XmlDocument } from 'xmldoc';
|
||||
import { readFile } from 'fs-extra';
|
||||
import { logger } from '../../logger';
|
||||
import { get } from '../../versioning';
|
||||
import { PackageDependency, ExtractConfig, PackageFile } from '../common';
|
||||
|
@ -5,15 +9,72 @@ import * as semverVersioning from '../../versioning/semver';
|
|||
import * as datasourceNuget from '../../datasource/nuget';
|
||||
import { SkipReason } from '../../types';
|
||||
|
||||
export function extractPackageFile(
|
||||
async function readFileAsXmlDocument(file: string): Promise<XmlDocument> {
|
||||
try {
|
||||
return new XmlDocument(await readFile(file, 'utf8'));
|
||||
} catch (err) {
|
||||
logger.debug({ err }, `failed to parse '${file}' as XML document`);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
async function determineRegistryUrls(
|
||||
packageFile: string,
|
||||
localDir: string
|
||||
): Promise<string[]> {
|
||||
const nuGetConfigPath = await findUp('NuGet.config', {
|
||||
cwd: path.dirname(path.join(localDir, packageFile)),
|
||||
type: 'file',
|
||||
});
|
||||
|
||||
if (nuGetConfigPath?.startsWith(localDir) !== true) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
logger.debug({ nuGetConfigPath }, 'found NuGet.config');
|
||||
const nuGetConfig = await readFileAsXmlDocument(nuGetConfigPath);
|
||||
if (!nuGetConfig) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const packageSources = nuGetConfig.childNamed('packageSources');
|
||||
if (!packageSources) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const registryUrls = [datasourceNuget.getDefaultFeed()];
|
||||
for (const child of packageSources.children) {
|
||||
if (child.type === 'element') {
|
||||
if (child.name === 'clear') {
|
||||
logger.debug(`clearing registry URLs`);
|
||||
registryUrls.length = 0;
|
||||
} else if (child.name === 'add') {
|
||||
let registryUrl = child.attr.value;
|
||||
if (child.attr.protocolVersion) {
|
||||
registryUrl += `#protocolVersion=${child.attr.protocolVersion}`;
|
||||
}
|
||||
logger.debug({ registryUrl }, 'adding registry URL');
|
||||
registryUrls.push(registryUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
return registryUrls;
|
||||
}
|
||||
|
||||
export async function extractPackageFile(
|
||||
content: string,
|
||||
packageFile: string,
|
||||
config: ExtractConfig = {}
|
||||
): PackageFile {
|
||||
logger.trace(`nuget.extractPackageFile(${packageFile})`);
|
||||
): Promise<PackageFile> {
|
||||
logger.trace({ packageFile }, 'nuget.extractPackageFile()');
|
||||
const { isVersion } = get(config.versioning || semverVersioning.id);
|
||||
const deps: PackageDependency[] = [];
|
||||
|
||||
const registryUrls = await determineRegistryUrls(
|
||||
packageFile,
|
||||
config.localDir
|
||||
);
|
||||
|
||||
let lineNumber = 0;
|
||||
for (const line of content.split('\n')) {
|
||||
/**
|
||||
|
@ -41,6 +102,9 @@ export function extractPackageFile(
|
|||
managerData: { lineNumber },
|
||||
datasource: datasourceNuget.id,
|
||||
};
|
||||
if (registryUrls) {
|
||||
dep.registryUrls = registryUrls;
|
||||
}
|
||||
if (!isVersion(currentValue)) {
|
||||
dep.skipReason = SkipReason.NotAVersion;
|
||||
}
|
||||
|
|
|
@ -129,6 +129,7 @@
|
|||
"detect-indent": "6.0.0",
|
||||
"email-addresses": "3.1.0",
|
||||
"fast-safe-stringify": "2.0.7",
|
||||
"find-up": "4.1.0",
|
||||
"fs-extra": "8.1.0",
|
||||
"get-installed-path": "4.0.8",
|
||||
"github-url-from-git": "1.5.0",
|
||||
|
|
16
yarn.lock
16
yarn.lock
|
@ -3995,6 +3995,14 @@ find-npm-prefix@^1.0.2:
|
|||
resolved "https://registry.yarnpkg.com/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz#8d8ce2c78b3b4b9e66c8acc6a37c231eb841cfdf"
|
||||
integrity sha512-KEftzJ+H90x6pcKtdXZEPsQse8/y/UnvzRKrOSQFprnrGaFuJ62fVkP34Iu2IYuMvyauCyoLTNkJZgrrGA2wkA==
|
||||
|
||||
find-up@4.1.0, find-up@^4.0.0, find-up@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
|
||||
integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
|
||||
dependencies:
|
||||
locate-path "^5.0.0"
|
||||
path-exists "^4.0.0"
|
||||
|
||||
find-up@^2.0.0, find-up@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
|
||||
|
@ -4009,14 +4017,6 @@ find-up@^3.0.0:
|
|||
dependencies:
|
||||
locate-path "^3.0.0"
|
||||
|
||||
find-up@^4.0.0, find-up@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
|
||||
integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
|
||||
dependencies:
|
||||
locate-path "^5.0.0"
|
||||
path-exists "^4.0.0"
|
||||
|
||||
find-versions@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/find-versions/-/find-versions-3.1.0.tgz#10161f29cf3eb4350dec10a29bdde75bff0df32d"
|
||||
|
|
Loading…
Reference in a new issue