From e386711d221bb93105770c8627aae8057f3e2eb0 Mon Sep 17 00:00:00 2001 From: Rhys Arkins <rhys@arkins.net> Date: Fri, 24 Sep 2021 10:04:59 +0200 Subject: [PATCH] fix(npm): support release.sourceUrl (#11868) --- lib/datasource/npm/get.spec.ts | 44 ++++++++++++++++++-- lib/datasource/npm/get.ts | 75 +++++++++++++++++++--------------- lib/datasource/types.ts | 2 + 3 files changed, 86 insertions(+), 35 deletions(-) diff --git a/lib/datasource/npm/get.spec.ts b/lib/datasource/npm/get.spec.ts index a983e37223..c9e7e4baf1 100644 --- a/lib/datasource/npm/get.spec.ts +++ b/lib/datasource/npm/get.spec.ts @@ -269,7 +269,45 @@ describe('datasource/npm/get', () => { `); }); - it('warns about repo directory override', async () => { + it('handles mixed sourceUrls in releases', async () => { + setNpmrc('registry=https://test.org\n_authToken=XXX'); + + httpMock + .scope('https://test.org') + .get('/vue') + .reply(200, { + name: 'vue', + repository: { + type: 'git', + url: 'https://github.com/vuejs/vue.git', + }, + versions: { + '2.0.0': { + repository: { + type: 'git', + url: 'https://github.com/vuejs/vue.git', + }, + }, + '3.0.0': { + repository: { + type: 'git', + url: 'https://github.com/vuejs/vue-next.git', + }, + }, + }, + 'dist-tags': { latest: '2.0.0' }, + }); + + const dep = await getDependency('vue'); + + expect(dep.sourceUrl).toBe('https://github.com/vuejs/vue.git'); + expect(dep.releases[0].sourceUrl).toBeUndefined(); + expect(dep.releases[1].sourceUrl).toEqual( + 'https://github.com/vuejs/vue-next.git' + ); + }); + + it('does not override sourceDirectory', async () => { setNpmrc('registry=https://test.org\n_authToken=XXX'); httpMock @@ -280,7 +318,7 @@ describe('datasource/npm/get', () => { repository: { type: 'git', url: 'https://github.com/neutrinojs/neutrino/tree/master/packages/react', - directory: 'path/to/directory', + directory: 'packages/foo', }, versions: { '1.0.0': {} }, 'dist-tags': { latest: '1.0.0' }, @@ -289,7 +327,7 @@ describe('datasource/npm/get', () => { const dep = await getDependency('@neutrinojs/react'); expect(dep.sourceUrl).toBe('https://github.com/neutrinojs/neutrino'); - expect(dep.sourceDirectory).toBe('packages/react'); + expect(dep.sourceDirectory).toBe('packages/foo'); expect(httpMock.getTrace()).toMatchInlineSnapshot(` Array [ diff --git a/lib/datasource/npm/get.ts b/lib/datasource/npm/get.ts index 98ee0b7388..d9de4aedc9 100644 --- a/lib/datasource/npm/get.ts +++ b/lib/datasource/npm/get.ts @@ -21,6 +21,37 @@ export function resetCache(): void { resetMemCache(); } +interface PackageSource { + sourceUrl?: string; + sourceDirectory?: string; +} + +function getPackageSource(repository: any): PackageSource { + const res: PackageSource = {}; + if (repository) { + if (is.nonEmptyString(repository)) { + res.sourceUrl = repository; + } else if (is.nonEmptyString(repository.url)) { + res.sourceUrl = repository.url; + } + if (is.nonEmptyString(repository.directory)) { + res.sourceDirectory = repository.directory; + } + const sourceUrlCopy = `${res.sourceUrl}`; + const sourceUrlSplit: string[] = sourceUrlCopy.split('/'); + if (sourceUrlSplit.length > 7 && sourceUrlSplit[2] === 'github.com') { + // Massage the repository URL for non-compliant strings for github (see issue #4610) + // Remove the non-compliant segments of path, so the URL looks like "<scheme>://<domain>/<vendor>/<repo>" + // and add directory to the repository + res.sourceUrl = sourceUrlSplit.slice(0, 5).join('/'); + res.sourceDirectory ||= sourceUrlSplit + .slice(7, sourceUrlSplit.length) + .join('/'); + } + } + return res; +} + export async function getDependency( packageName: string ): Promise<NpmDependency | null> { @@ -70,49 +101,19 @@ export async function getDependency( res.repository = res.repository || latestVersion.repository; res.homepage = res.homepage || latestVersion.homepage; - // Determine repository URL - let sourceUrl: string; - - if (res.repository) { - if (is.string(res.repository)) { - sourceUrl = res.repository; - } else if (res.repository.url) { - sourceUrl = res.repository.url; - } - } + const { sourceUrl, sourceDirectory } = getPackageSource(res.repository); // Simplify response before caching and returning const dep: NpmDependency = { name: res.name, homepage: res.homepage, sourceUrl, + sourceDirectory, versions: {}, releases: null, 'dist-tags': res['dist-tags'], registryUrl, }; - if (res.repository?.directory) { - dep.sourceDirectory = res.repository.directory; - } - - // Massage the repository URL for non-compliant strings for github (see issue #4610) - // Remove the non-compliant segments of path, so the URL looks like "<scheme>://<domain>/<vendor>/<repo>" - // and add directory to the repository - const sourceUrlCopy = `${sourceUrl}`; - const sourceUrlSplit: string[] = sourceUrlCopy.split('/'); - - if (sourceUrlSplit.length > 7 && sourceUrlSplit[2] === 'github.com') { - if (dep.sourceDirectory) { - logger.debug( - { dependency: packageName }, - `Ambiguity: dependency has the repository URL path and repository/directory set at once; have to override repository/directory` - ); - } - dep.sourceUrl = sourceUrlSplit.slice(0, 5).join('/'); - dep.sourceDirectory = sourceUrlSplit - .slice(7, sourceUrlSplit.length) - .join('/'); - } if (latestVersion.deprecated) { dep.deprecationMessage = `On registry \`${registryUrl}\`, the "latest" version of dependency \`${packageName}\` has the following deprecation notice:\n\n\`${latestVersion.deprecated}\`\n\nMarking the latest version of an npm package as deprecated results in the entire package being considered deprecated, so contact the package author you think this is a mistake.`; @@ -131,6 +132,16 @@ export async function getDependency( if (res.versions[version].deprecated) { release.isDeprecated = true; } + const source = getPackageSource(res.versions[version].repository); + if (source.sourceUrl && source.sourceUrl !== dep.sourceUrl) { + release.sourceUrl = source.sourceUrl; + } + if ( + source.sourceDirectory && + source.sourceDirectory !== dep.sourceDirectory + ) { + release.sourceDirectory = source.sourceDirectory; + } return release; }); logger.trace({ dep }, 'dep'); diff --git a/lib/datasource/types.ts b/lib/datasource/types.ts index 098a172742..1d271a8a9a 100644 --- a/lib/datasource/types.ts +++ b/lib/datasource/types.ts @@ -44,6 +44,8 @@ export interface Release { dependencies?: Record<string, string>; devDependencies?: Record<string, string>; registryUrl?: string; + sourceUrl?: string; + sourceDirectory?: string; } export interface ReleaseResult { -- GitLab