diff --git a/lib/modules/datasource/packagist/index.spec.ts b/lib/modules/datasource/packagist/index.spec.ts index 9f90e007047898945435ebe24423ccaef4ce598b..9f973a86053fed4e96fcfbfa50f71cd835a82556 100644 --- a/lib/modules/datasource/packagist/index.spec.ts +++ b/lib/modules/datasource/packagist/index.spec.ts @@ -542,5 +542,51 @@ describe('modules/datasource/packagist/index', () => { releases: [{ gitRef: 'v2.5.4', version: '2.5.4' }], }); }); + + it('respects "available-packages" list', async () => { + httpMock + .scope('https://example.com') + .get('/packages.json') + .twice() + .reply(200, { + 'metadata-url': 'https://example.com/p2/%package%.json', + 'available-packages': ['foo/bar'], + }) + .get('/p2/foo/bar.json') + .reply(200, { + minified: 'composer/2.0', + packages: { + 'foo/bar': [ + { + name: 'foo/bar', + version: 'v1.2.3', + }, + ], + }, + }) + .get('/p2/foo/bar~dev.json') + .reply(404); + config.registryUrls = ['https://example.com']; + + const foo = await getPkgReleases({ + ...config, + datasource, + versioning, + packageName: 'foo/foo', + }); + expect(foo).toBeNull(); + + const bar = await getPkgReleases({ + ...config, + datasource, + versioning, + packageName: 'foo/bar', + }); + + expect(bar).toEqual({ + registryUrl: 'https://example.com', + releases: [{ gitRef: 'v1.2.3', version: '1.2.3' }], + }); + }); }); }); diff --git a/lib/modules/datasource/packagist/index.ts b/lib/modules/datasource/packagist/index.ts index 8970551bbd8669610f102ed5d9744d74eb756e8e..2fc93ff2957c3e4b6b845c56e91fc273cadbdd69 100644 --- a/lib/modules/datasource/packagist/index.ts +++ b/lib/modules/datasource/packagist/index.ts @@ -184,6 +184,10 @@ export class PackagistDatasource extends Datasource { try { const meta = await this.getRegistryMeta(registryUrl); + if (meta.availablePackages && !meta.availablePackages.has(packageName)) { + return null; + } + if (meta.metadataUrl) { const packagistResult = await this.packagistV2Lookup( registryUrl, diff --git a/lib/modules/datasource/packagist/schema.spec.ts b/lib/modules/datasource/packagist/schema.spec.ts index 12541ea984204bcd500c45e13dc4863a8a92c64c..78d90f49f6193de901c2cad178e5ede16cff900e 100644 --- a/lib/modules/datasource/packagist/schema.spec.ts +++ b/lib/modules/datasource/packagist/schema.spec.ts @@ -384,6 +384,7 @@ describe('modules/datasource/packagist/schema', () => { providersLazyUrl: null, providersUrl: null, metadataUrl: null, + availablePackages: null, }); }); }); diff --git a/lib/modules/datasource/packagist/schema.ts b/lib/modules/datasource/packagist/schema.ts index 4a9375c7cb4154a8a7b9f9d12c4fba64a7baf7b7..0b1616716aade0e04d57c1ea71ca67c4a9af9dfe 100644 --- a/lib/modules/datasource/packagist/schema.ts +++ b/lib/modules/datasource/packagist/schema.ts @@ -189,8 +189,9 @@ export const PackagistFile = PackagesResponse.merge( export type PackagistFile = z.infer<typeof PackagistFile>; export const RegistryMeta = z - .preprocess( - (x) => (is.plainObject(x) ? x : {}), + .record(z.unknown()) + .catch({}) + .pipe( PackagistFile.merge( z.object({ ['includes']: LooseRecord(HashSpec) @@ -206,6 +207,11 @@ export const RegistryMeta = z ['providers-lazy-url']: z.string().nullable().catch(null), ['providers-url']: z.string().nullable().catch(null), ['metadata-url']: z.string().nullable().catch(null), + ['available-packages']: z + .array(z.string()) + .transform((xs) => new Set(xs)) + .nullable() + .catch(null), }) ) ) @@ -218,6 +224,7 @@ export const RegistryMeta = z ['providers-lazy-url']: providersLazyUrl, ['providers-url']: providersUrl, ['metadata-url']: metadataUrl, + ['available-packages']: availablePackages, }) => ({ packages, includesFiles, @@ -227,6 +234,7 @@ export const RegistryMeta = z providersLazyUrl, metadataUrl, includesPackages: {} as Record<string, ReleaseResult | null>, + availablePackages, }) ); export type RegistryMeta = z.infer<typeof RegistryMeta>;