diff --git a/lib/modules/datasource/packagist/index.spec.ts b/lib/modules/datasource/packagist/index.spec.ts index 845c19082fdd889a142dc7004d8e052ad00f178f..c82a69ccac52fe072d9ac081028d9fbe70edd10c 100644 --- a/lib/modules/datasource/packagist/index.spec.ts +++ b/lib/modules/datasource/packagist/index.spec.ts @@ -176,6 +176,67 @@ describe('modules/datasource/packagist/index', () => { expect(res).not.toBeNull(); }); + it('supports older sha1 hashes', async () => { + hostRules.find = jest.fn(() => ({ + username: 'some-username', + password: 'some-password', + })); + const packagesJson = { + packages: [], + includes: { + 'include/all$afbf74d51f31c7cbb5ff10304f9290bfb4f4e68b.json': { + sha1: 'afbf74d51f31c7cbb5ff10304f9290bfb4f4e68b', + }, + }, + }; + httpMock + .scope('https://composer.renovatebot.com') + .get('/packages.json') + .reply(200, packagesJson) + .get('/include/all$afbf74d51f31c7cbb5ff10304f9290bfb4f4e68b.json') + .reply(200, includesJson); + const res = await getPkgReleases({ + ...config, + datasource, + versioning, + depName: 'guzzlehttp/guzzle', + }); + expect(res).toMatchObject({ + homepage: 'http://guzzlephp.org/', + registryUrl: 'https://composer.renovatebot.com', + releases: [ + { version: '3.0.0' }, + { version: '3.0.1' }, + { version: '3.0.2' }, + { version: '3.0.3' }, + { version: '3.0.4' }, + { version: '3.0.5' }, + { version: '3.0.6' }, + { version: '3.0.7' }, + { version: '3.1.0' }, + { version: '3.1.1' }, + { version: '3.1.2' }, + { version: '3.2.0' }, + { version: '3.3.0' }, + { version: '3.3.1' }, + { version: '3.4.0' }, + { version: '3.4.1' }, + { version: '3.4.2' }, + { version: '3.4.3' }, + { version: '3.5.0' }, + { version: '3.6.0' }, + { version: '3.7.0' }, + { version: '3.7.1' }, + { version: '3.7.2' }, + { version: '3.7.3' }, + { version: '3.7.4' }, + { version: '3.8.0' }, + { version: '3.8.1' }, + ], + sourceUrl: 'https://github.com/guzzle/guzzle', + }); + }); + it('supports lazy repositories', async () => { const packagesJson = { packages: [], diff --git a/lib/modules/datasource/packagist/index.ts b/lib/modules/datasource/packagist/index.ts index 8d902f99f39174c79046ff8981a8ca5a1eb1e7d4..9928405698b24875bb0300ee9285a201fc296106 100644 --- a/lib/modules/datasource/packagist/index.ts +++ b/lib/modules/datasource/packagist/index.ts @@ -68,8 +68,8 @@ export class PackagistDatasource extends Datasource { regUrl: string, regFile: RegistryFile ): string { - const { key, sha256 } = regFile; - const fileName = key.replace('%hash%', sha256); + const { key, hash } = regFile; + const fileName = hash ? key.replace('%hash%', hash) : key; const url = `${regUrl}/${fileName}`; return url; } diff --git a/lib/modules/datasource/packagist/schema.ts b/lib/modules/datasource/packagist/schema.ts index d71a9b27da9cec396d63acd3a8d04886c383f932..0205605fb9aca2d2a91e33e8c2616d52d27f9b66 100644 --- a/lib/modules/datasource/packagist/schema.ts +++ b/lib/modules/datasource/packagist/schema.ts @@ -155,10 +155,20 @@ export function parsePackagesResponses( return extractReleaseResult(...releaseArrays); } -export const RegistryFile = z.object({ - key: z.string(), - sha256: z.string(), -}); +export const HashSpec = z.union([ + z + .object({ sha256: z.string().nullable() }) + .transform(({ sha256 }) => ({ hash: sha256 })), + z + .object({ sha1: z.string().nullable() }) + .transform(({ sha1 }) => ({ hash: sha1 })), +]); +export type HashSpec = z.infer<typeof HashSpec>; + +export const RegistryFile = z.intersection( + HashSpec, + z.object({ key: z.string() }) +); export type RegistryFile = z.infer<typeof RegistryFile>; export const PackagesResponse = z.object({ @@ -168,13 +178,9 @@ export type PackagesResponse = z.infer<typeof PackagesResponse>; export const PackagistFile = PackagesResponse.merge( z.object({ - providers: looseRecord( - z.object({ - sha256: looseValue(z.string()), - }) - ).transform((x) => + providers: looseRecord(HashSpec).transform((x) => Object.fromEntries( - Object.entries(x).map(([key, { sha256 }]) => [key, sha256]) + Object.entries(x).map(([key, { hash }]) => [key, hash]) ) ), }) @@ -186,22 +192,11 @@ export const RegistryMeta = z (x) => (is.plainObject(x) ? x : {}), PackagistFile.merge( z.object({ - ['includes']: looseRecord( - z.object({ - sha256: z.string(), - }) - ).transform((x) => - Object.entries(x).map(([name, { sha256 }]) => ({ - key: name.replace(sha256, '%hash%'), - sha256, - })) + ['includes']: looseRecord(HashSpec).transform((x) => + Object.entries(x).map(([name, { hash }]) => ({ key: name, hash })) ), - ['provider-includes']: looseRecord( - z.object({ - sha256: z.string(), - }) - ).transform((x) => - Object.entries(x).map(([key, { sha256 }]) => ({ key, sha256 })) + ['provider-includes']: looseRecord(HashSpec).transform((x) => + Object.entries(x).map(([key, { hash }]) => ({ key, hash })) ), ['providers-lazy-url']: looseValue(z.string()), ['providers-url']: looseValue(z.string()),