Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(pip): fix compatibility with some simple pip indexes #6649

Merged
merged 4 commits into from Jul 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
73 changes: 73 additions & 0 deletions lib/datasource/pypi/__snapshots__/index.spec.ts.snap
@@ -1,5 +1,69 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`datasource/pypi getReleases fall back from json and process data from simple endpoint 1`] = `
Object {
"releases": Array [
Object {
"version": "0.1.2",
},
Object {
"version": "0.1.3",
},
Object {
"version": "0.1.4",
},
Object {
"version": "0.2.0",
},
Object {
"version": "0.2.1",
},
Object {
"version": "0.2.2",
},
Object {
"version": "0.3.0",
},
Object {
"version": "0.4.0",
},
Object {
"version": "0.4.1",
},
Object {
"version": "0.4.2",
},
Object {
"version": "0.5.0",
},
],
}
`;

exports[`datasource/pypi getReleases fall back from json and process data from simple endpoint 2`] = `
Array [
Object {
"headers": Object {
"accept": "application/json",
"accept-encoding": "gzip, deflate",
"host": "custom.pypi.net",
"user-agent": "https://github.com/renovatebot/renovate",
},
"method": "GET",
"url": "https://custom.pypi.net/foo/dj-database-url/json",
},
Object {
"headers": Object {
"accept-encoding": "gzip, deflate",
"host": "custom.pypi.net",
"user-agent": "https://github.com/renovatebot/renovate",
},
"method": "GET",
"url": "https://custom.pypi.net/foo/dj-database-url",
},
]
`;

exports[`datasource/pypi getReleases find url from project_urls 1`] = `
Array [
Object {
Expand Down Expand Up @@ -318,6 +382,15 @@ Array [
"method": "GET",
"url": "https://pypi.org/pypi/something/json",
},
Object {
"headers": Object {
"accept-encoding": "gzip, deflate",
"host": "pypi.org",
"user-agent": "https://github.com/renovatebot/renovate",
},
"method": "GET",
"url": "https://pypi.org/pypi/something",
},
]
`;

Expand Down
21 changes: 21 additions & 0 deletions lib/datasource/pypi/index.spec.ts
Expand Up @@ -46,6 +46,7 @@ describe('datasource/pypi', () => {
});
it('returns null for 404', async () => {
httpMock.scope(baseUrl).get('/something/json').reply(404);
httpMock.scope(baseUrl).get('/something').reply(404);
expect(
await getPkgReleases({
datasource,
Expand Down Expand Up @@ -303,5 +304,25 @@ describe('datasource/pypi', () => {
})
).toBeNull();
});
it('fall back from json and process data from simple endpoint', async () => {
httpMock
.scope('https://custom.pypi.net/foo')
.get('/dj-database-url/json')
.reply(404);
httpMock
.scope('https://custom.pypi.net/foo')
.get('/dj-database-url')
.reply(200, htmlResponse + '');
const config = {
registryUrls: ['https://custom.pypi.net/foo'],
};
const result = await getPkgReleases({
datasource,
...config,
depName: 'dj-database-url',
});
expect(result).toMatchSnapshot();
expect(httpMock.getTrace()).toMatchSnapshot();
});
});
});
22 changes: 21 additions & 1 deletion lib/datasource/pypi/index.ts
Expand Up @@ -191,10 +191,30 @@ export async function getReleases({
registryUrl,
}: GetReleasesConfig): Promise<ReleaseResult | null> {
const hostUrl = ensureTrailingSlash(registryUrl);

// not all simple indexes use this identifier, but most do
if (hostUrl.endsWith('/simple/') || hostUrl.endsWith('/+simple/')) {
logger.trace({ lookupName, hostUrl }, 'Looking up pypi simple dependency');
return getSimpleDependency(lookupName, hostUrl);
}

logger.trace({ lookupName, hostUrl }, 'Looking up pypi api dependency');
return getDependency(lookupName, hostUrl, compatibility);
try {
// we need to resolve early here so we can catch any 404s and fallback to a simple lookup
const releases = await getDependency(lookupName, hostUrl, compatibility);
// the dep was found in the json api, return as-is
return releases;
} catch (err) {
if (err.statusCode !== 404) {
throw err;
}

// error contacting json-style api -- attempt to fallback to a simple-style api
logger.trace(
{ lookupName, hostUrl },
'Looking up pypi simple dependency via fallback'
);
const releases = await getSimpleDependency(lookupName, hostUrl);
return releases;
}
}