diff --git a/docs/usage/nuget.md b/docs/usage/nuget.md index 5c4dc6f2c41cf9aa275d7cfab928ceca662cf658..e40b8db321bd416c47f11384c8b4b9f11cd5df5c 100644 --- a/docs/usage/nuget.md +++ b/docs/usage/nuget.md @@ -40,6 +40,18 @@ Renovate by default performs all lookups on `https://api.nuget.org/v3/index.json If this example we defined 3 nuget feeds. Packages resolving will process feeds consequentially. It means that if package will be resolved in second feed renovate won't look in last one. +### Protocol versions + +NuGet supports two protocol versions, `v2` and `v3`, which NuGet client and server need to agree on. Renovate as a NuGet client supports both versions and will use `v2` unless the configured feed URL ends with `index.json` (which mirrors the behavior of the official NuGet client). If you have `v3` feed that does not match this pattern (e.g. JFrog Artifactory) you need to help Renovate by appending `#protocolVersion=3` to the registry URL: + +```json +"nuget": { + "registryUrls": [ + "http://myV3feed#protocolVersion=3" + ] +} +``` + ## Authenticated feeds Credentials for authenticated/private feeds can be provided via host rules in the configuration options (file or command line parameter). diff --git a/lib/datasource/nuget/index.spec.ts b/lib/datasource/nuget/index.spec.ts index e14f02dedec8acd2bd6d08b81c1283fc1199d6dc..0c30b13a372381a965847cccc345c24295d4c827 100644 --- a/lib/datasource/nuget/index.spec.ts +++ b/lib/datasource/nuget/index.spec.ts @@ -107,6 +107,17 @@ describe('datasource/nuget', () => { ).toBeNull(); }); + it('extracts feed version from registry URL hash', async () => { + const config = { + lookupName: 'nunit', + registryUrls: ['https://my-registry#protocolVersion=3'], + }; + await nuget.getPkgReleases({ + ...config, + }); + expect(got.mock.calls[0][0]).toEqual('https://my-registry/'); + }); + it('queries the default nuget feed if no registries are supplied', async () => { await nuget.getPkgReleases({ ...configNoRegistryUrls, diff --git a/lib/datasource/nuget/index.ts b/lib/datasource/nuget/index.ts index e35d8b2299018d61bf6b741e58b5395a9e717da3..092cac6bb6ef22265770af6d71a1efa2be336381 100644 --- a/lib/datasource/nuget/index.ts +++ b/lib/datasource/nuget/index.ts @@ -6,17 +6,24 @@ import { GetReleasesConfig, ReleaseResult } from '../common'; export { id } from './common'; -function detectFeedVersion(url: string): 2 | 3 | null { +function parseRegistryUrl( + registryUrl: string +): { feedUrl: string; protocolVersion: number } { try { - const parsecUrl = urlApi.parse(url); - // Official client does it in the same way - if (parsecUrl.pathname.endsWith('.json')) { - return 3; + const parsedUrl = urlApi.parse(registryUrl); + let protocolVersion = 2; + const protolVersionRegExp = /#protocolVersion=(2|3)/; + const protocolVersionMatch = protolVersionRegExp.exec(parsedUrl.hash); + if (protocolVersionMatch) { + parsedUrl.hash = ''; + protocolVersion = Number.parseInt(protocolVersionMatch[1], 10); + } else if (parsedUrl.pathname.endsWith('.json')) { + protocolVersion = 3; } - return 2; + return { feedUrl: urlApi.format(parsedUrl), protocolVersion }; } catch (e) { - logger.debug({ e }, `nuget registry failure: can't parse ${url}`); - return null; + logger.debug({ e }, `nuget registry failure: can't parse ${registryUrl}`); + return { feedUrl: registryUrl, protocolVersion: null }; } } @@ -27,13 +34,13 @@ export async function getPkgReleases({ logger.trace(`nuget.getPkgReleases(${lookupName})`); let dep: ReleaseResult = null; for (const feed of registryUrls || [v3.getDefaultFeed()]) { - const feedVersion = detectFeedVersion(feed); - if (feedVersion === 2) { - dep = await v2.getPkgReleases(feed, lookupName); - } else if (feedVersion === 3) { - const queryUrl = await v3.getQueryUrl(feed); + const { feedUrl, protocolVersion } = parseRegistryUrl(feed); + if (protocolVersion === 2) { + dep = await v2.getPkgReleases(feedUrl, lookupName); + } else if (protocolVersion === 3) { + const queryUrl = await v3.getQueryUrl(feedUrl); if (queryUrl !== null) { - dep = await v3.getPkgReleases(feed, queryUrl, lookupName); + dep = await v3.getPkgReleases(feedUrl, queryUrl, lookupName); } } if (dep != null) {