Skip to content

Commit

Permalink
fix(npm): support release.sourceUrl (#11868)
Browse files Browse the repository at this point in the history
  • Loading branch information
rarkins committed Sep 24, 2021
1 parent 1842bda commit e386711
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 35 deletions.
44 changes: 41 additions & 3 deletions lib/datasource/npm/get.spec.ts
Expand Up @@ -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
Expand All @@ -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' },
Expand All @@ -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 [
Expand Down
75 changes: 43 additions & 32 deletions lib/datasource/npm/get.ts
Expand Up @@ -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> {
Expand Down Expand Up @@ -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.`;
Expand All @@ -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');
Expand Down
2 changes: 2 additions & 0 deletions lib/datasource/types.ts
Expand Up @@ -44,6 +44,8 @@ export interface Release {
dependencies?: Record<string, string>;
devDependencies?: Record<string, string>;
registryUrl?: string;
sourceUrl?: string;
sourceDirectory?: string;
}

export interface ReleaseResult {
Expand Down

0 comments on commit e386711

Please sign in to comment.