diff --git a/lib/modules/datasource/packagist/index.spec.ts b/lib/modules/datasource/packagist/index.spec.ts index 935c7443173efe4acf269b492deb434658785fe5..4ef75442e11e33227c2a323606f98ed25188319f 100644 --- a/lib/modules/datasource/packagist/index.spec.ts +++ b/lib/modules/datasource/packagist/index.spec.ts @@ -57,10 +57,10 @@ describe('modules/datasource/packagist/index', () => { const packagesOnly = { packages: { 'vendor/package-name': { - 'dev-master': { version: 'dev-master' }, - '1.0.x-dev': { version: '1.0.x-dev' }, - '0.0.1': { version: '0.0.1' }, - '1.0.0': { version: '1.0.0' }, + 'dev-master': {}, + '1.0.x-dev': {}, + '0.0.1': {}, + '1.0.0': {}, }, }, }; @@ -146,7 +146,7 @@ describe('modules/datasource/packagist/index', () => { packages: [], includes: { 'include/all$afbf74d51f31c7cbb5ff10304f9290bfb4f4e68b.json': { - sha256: 'afbf74d51f31c7cbb5ff10304f9290bfb4f4e68b', + sha1: 'afbf74d51f31c7cbb5ff10304f9290bfb4f4e68b', }, }, }; diff --git a/lib/modules/datasource/packagist/index.ts b/lib/modules/datasource/packagist/index.ts index cecac810beec87416fce9e7405bdaffe9988d7a4..9171467dc48c1d6d4b9dcfc22a0014e58d7b20fc 100644 --- a/lib/modules/datasource/packagist/index.ts +++ b/lib/modules/datasource/packagist/index.ts @@ -1,5 +1,4 @@ import URL from 'url'; -import is from '@sindresorhus/is'; import { logger } from '../../../logger'; import { ExternalHostError } from '../../../types/errors/external-host-error'; import { cache } from '../../../util/cache/package/decorator'; @@ -12,7 +11,13 @@ import * as composerVersioning from '../../versioning/composer'; import { Datasource } from '../datasource'; import type { GetReleasesConfig, ReleaseResult } from '../types'; import * as schema from './schema'; -import type { AllPackages, PackagistFile, RegistryFile } from './types'; +import type { + AllPackages, + PackageMeta, + PackagistFile, + RegistryFile, + RegistryMeta, +} from './types'; export class PackagistDatasource extends Datasource { static readonly id = 'packagist'; @@ -36,12 +41,46 @@ export class PackagistDatasource extends Datasource { return username && password ? { username, password } : {}; } - private async getRegistryMeta(regUrl: string): Promise<schema.RegistryMeta> { + private async getRegistryMeta(regUrl: string): Promise<RegistryMeta | null> { const url = URL.resolve(ensureTrailingSlash(regUrl), 'packages.json'); const opts = PackagistDatasource.getHostOpts(url); - const { body } = await this.http.getJson(url, opts); - const res = schema.RegistryMeta.parse(body); - return res; + const res = (await this.http.getJson<PackageMeta>(url, opts)).body; + const meta: RegistryMeta = { + providerPackages: {}, + packages: res.packages, + }; + if (res.includes) { + meta.includesFiles = []; + for (const [name, val] of Object.entries(res.includes)) { + const file = { + key: name.replace(val.sha256, '%hash%'), + sha256: val.sha256, + }; + meta.includesFiles.push(file); + } + } + if (res['providers-url']) { + meta.providersUrl = res['providers-url']; + } + if (res['providers-lazy-url']) { + meta.providersLazyUrl = res['providers-lazy-url']; + } + if (res['provider-includes']) { + meta.files = []; + for (const [key, val] of Object.entries(res['provider-includes'])) { + const file = { + key, + sha256: val.sha256, + }; + meta.files.push(file); + } + } + if (res.providers) { + for (const [key, val] of Object.entries(res.providers)) { + meta.providerPackages[key] = val.sha256; + } + } + return meta; } private static isPrivatePackage(regUrl: string): boolean { @@ -118,40 +157,39 @@ export class PackagistDatasource extends Datasource { packages, providersUrl, providersLazyUrl, - providerIncludes, - includes, - providers, + files, + includesFiles, + providerPackages, } = registryMeta; - - const includesPackages: Record<string, ReleaseResult> = {}; - - const tasks: (() => Promise<void>)[] = []; - - for (const file of providerIncludes) { - tasks.push(async () => { - const res = await this.getPackagistFile(regUrl, file); + if (files) { + const queue = files.map( + (file) => (): Promise<PackagistFile> => + this.getPackagistFile(regUrl, file) + ); + const resolvedFiles = await p.all(queue); + for (const res of resolvedFiles) { for (const [name, val] of Object.entries(res.providers)) { - providers[name] = val.sha256; + providerPackages[name] = val.sha256; } - }); + } } - - for (const file of includes) { - tasks.push(async () => { + const includesPackages: Record<string, ReleaseResult> = {}; + if (includesFiles) { + for (const file of includesFiles) { const res = await this.getPackagistFile(regUrl, file); - for (const [key, val] of Object.entries(res.packages ?? {})) { - includesPackages[key] = PackagistDatasource.extractDepReleases(val); + if (res.packages) { + for (const [key, val] of Object.entries(res.packages)) { + const dep = PackagistDatasource.extractDepReleases(val); + includesPackages[key] = dep; + } } - }); + } } - - await p.all(tasks); - const allPackages: AllPackages = { - packages: packages as never, // TODO: fix types (#9610) + packages, providersUrl, providersLazyUrl, - providers, + providerPackages, includesPackages, }; return allPackages; @@ -197,7 +235,7 @@ export class PackagistDatasource extends Datasource { packages, providersUrl, providersLazyUrl, - providers, + providerPackages, includesPackages, } = allPackages; if (packages?.[packageName]) { @@ -210,13 +248,13 @@ export class PackagistDatasource extends Datasource { return includesPackages[packageName]; } let pkgUrl: string; - const hash = providers[packageName]; - if (providersUrl && !is.undefined(hash)) { - let url = providersUrl.replace('%package%', packageName); - if (hash) { - url = url.replace('%hash%', hash); - } - pkgUrl = URL.resolve(registryUrl, url); + if (packageName in providerPackages) { + pkgUrl = URL.resolve( + registryUrl, + providersUrl! + .replace('%package%', packageName) + .replace('%hash%', providerPackages[packageName]) + ); } else if (providersLazyUrl) { pkgUrl = URL.resolve( registryUrl, diff --git a/lib/modules/datasource/packagist/schema.ts b/lib/modules/datasource/packagist/schema.ts index cd28d0f5ca9a3ba2cc4861af61b0cb24565ebfcd..4a5f379e128eb68e64f68daf83a746eb4cd19feb 100644 --- a/lib/modules/datasource/packagist/schema.ts +++ b/lib/modules/datasource/packagist/schema.ts @@ -144,77 +144,3 @@ export function parsePackagesResponses( return result; } - -const RegistryFile = z.object({ - key: z.string(), - sha256: z.string(), -}); -export type RegistryFile = z.infer<typeof RegistryFile>; - -const RegistryMetaFile = z.object({ - sha256: z.string().nullable(), -}); -type RegistryMetaFile = z.infer<typeof RegistryMetaFile>; - -const RegistryMetaFiles = z - .record(RegistryMetaFile.nullable().catch(null)) - .transform((obj) => { - // Remove all null values - // TODO: extract as schema utility - const result: Record<string, RegistryMetaFile> = {}; - for (const [key, val] of Object.entries(obj)) { - if (val !== null) { - result[key] = val; - } - } - return result; - }); - -const RegistryMetaIncludes = RegistryMetaFiles.transform( - (obj): RegistryFile[] => { - const result: RegistryFile[] = []; - for (const [key, { sha256 }] of Object.entries(obj)) { - if (sha256) { - result.push({ key, sha256 }); - } - } - return result; - } -) - .nullable() - .catch(null) - .transform((xs) => xs ?? []); - -export const RegistryMeta = z - .object({ - ['packages']: z.record(z.record(ComposerRelease)).nullable().catch(null), - ['includes']: RegistryMetaIncludes, - ['provider-includes']: RegistryMetaIncludes, - ['providers-url']: z.string().nullable().catch(null), - ['providers-lazy-url']: z.string().optional().nullable().catch(null), - ['providers']: RegistryMetaFiles.transform((obj) => { - const result: Record<string, string | null> = {}; - for (const [key, { sha256 }] of Object.entries(obj)) { - result[key] = sha256; - } - return result; - }).catch({}), - }) - .transform( - ({ - packages, - includes, - providers, - 'provider-includes': providerIncludes, - 'providers-url': providersUrl, - 'providers-lazy-url': providersLazyUrl, - }) => ({ - packages, - includes, - providers, - providerIncludes, - providersUrl, - providersLazyUrl, - }) - ); -export type RegistryMeta = z.infer<typeof RegistryMeta>; diff --git a/lib/modules/datasource/packagist/types.ts b/lib/modules/datasource/packagist/types.ts index e398c5a2b658865f31cb817312f66fa5869aea3e..fea795612e7fc3ff316c1a3fcc1576cb1026c8b8 100644 --- a/lib/modules/datasource/packagist/types.ts +++ b/lib/modules/datasource/packagist/types.ts @@ -1,5 +1,13 @@ import type { ReleaseResult } from '../types'; +export interface PackageMeta { + includes?: Record<string, { sha256: string }>; + packages: Record<string, RegistryFile>; + 'provider-includes': Record<string, { sha256: string }>; + providers: Record<string, { sha256: string }>; + 'providers-lazy-url'?: string; + 'providers-url'?: string; +} export interface RegistryFile { key: string; sha256: string; @@ -20,9 +28,9 @@ export interface PackagistFile { export interface AllPackages { packages: Record<string, RegistryFile>; - providersUrl: string | null; - providersLazyUrl: string | null; - providers: Record<string, string | null>; + providersUrl?: string; + providersLazyUrl?: string; + providerPackages: Record<string, string>; includesPackages: Record<string, ReleaseResult>; }