From 6679d7ed9b67c46b96eedd72165564b5a36ac593 Mon Sep 17 00:00:00 2001 From: Sergei Zharinov <zharinov@users.noreply.github.com> Date: Tue, 17 Jan 2023 07:47:02 +0300 Subject: [PATCH] refactor(packagist): Refactor schema (#19868) --- .../datasource/packagist/schema.spec.ts | 67 ++++++++-------- lib/modules/datasource/packagist/schema.ts | 79 ++++++++++--------- 2 files changed, 71 insertions(+), 75 deletions(-) diff --git a/lib/modules/datasource/packagist/schema.spec.ts b/lib/modules/datasource/packagist/schema.spec.ts index 679d5c1471..2bae8ee23f 100644 --- a/lib/modules/datasource/packagist/schema.spec.ts +++ b/lib/modules/datasource/packagist/schema.spec.ts @@ -1,6 +1,7 @@ +import type { ReleaseResult } from '../types'; import { ComposerRelease, - ComposerReleaseArray, + ComposerReleases, parsePackagesResponse, parsePackagesResponses, } from './schema'; @@ -14,60 +15,56 @@ describe('modules/datasource/packagist/schema', () => { expect(() => ComposerRelease.parse({})).toThrow(); expect(() => ComposerRelease.parse({ version: null })).toThrow(); expect(() => ComposerRelease.parse({ version: null })).toThrow(); - expect(() => ComposerRelease.parse({ version: '' })).toThrow(); - expect(() => ComposerRelease.parse({ version: 'dev-main' })).toThrow(); }); it('parses', () => { - const defaultResult = { - version: '1.2.3', - homepage: null, - source: null, - time: null, - }; + expect(ComposerRelease.parse({ version: '' })).toEqual({ version: '' }); + expect(ComposerRelease.parse({ version: 'dev-main' })).toEqual({ + version: 'dev-main', + }); - expect(ComposerRelease.parse({ version: '1.2.3' })).toEqual( - defaultResult - ); + expect(ComposerRelease.parse({ version: '1.2.3' })).toEqual({ + version: '1.2.3', + }); expect(ComposerRelease.parse({ version: '1.2.3', homepage: 42 })).toEqual( - defaultResult + { version: '1.2.3', homepage: null } ); expect( ComposerRelease.parse({ version: '1.2.3', homepage: 'example.com' }) - ).toEqual({ ...defaultResult, homepage: 'example.com' }); + ).toEqual({ version: '1.2.3', homepage: 'example.com' }); expect( ComposerRelease.parse({ version: '1.2.3', source: 'nonsense' }) - ).toEqual(defaultResult); + ).toEqual({ version: '1.2.3', source: null }); expect( ComposerRelease.parse({ version: '1.2.3', source: { url: 'foobar' } }) - ).toEqual({ ...defaultResult, source: 'foobar' }); + ).toEqual({ version: '1.2.3', source: { url: 'foobar' } }); expect( ComposerRelease.parse({ version: '1.2.3', time: '12345' }) - ).toEqual({ ...defaultResult, time: '12345' }); + ).toEqual({ version: '1.2.3', time: '12345' }); }); }); - describe('ComposerReleaseArray', () => { + describe('ComposerReleases', () => { it('rejects', () => { - expect(() => ComposerReleaseArray.parse(null)).toThrow(); - expect(() => ComposerReleaseArray.parse(undefined)).toThrow(); - expect(() => ComposerReleaseArray.parse('')).toThrow(); - expect(() => ComposerReleaseArray.parse({})).toThrow(); + expect(() => ComposerReleases.parse(null)).toThrow(); + expect(() => ComposerReleases.parse(undefined)).toThrow(); + expect(() => ComposerReleases.parse('')).toThrow(); + expect(() => ComposerReleases.parse({})).toThrow(); }); it('parses', () => { - expect(ComposerReleaseArray.parse([])).toEqual([]); - expect(ComposerReleaseArray.parse([null])).toEqual([]); - expect(ComposerReleaseArray.parse([1, 2, 3])).toEqual([]); - expect(ComposerReleaseArray.parse(['foobar'])).toEqual([]); - expect(ComposerReleaseArray.parse([{ version: '1.2.3' }])).toEqual([ - { version: '1.2.3', homepage: null, source: null, time: null }, - ]); + expect(ComposerReleases.parse([])).toEqual([]); + expect(ComposerReleases.parse([null])).toEqual([]); + expect(ComposerReleases.parse([1, 2, 3])).toEqual([]); + expect(ComposerReleases.parse(['foobar'])).toEqual([]); + expect( + ComposerReleases.parse([{ version: '1.2.3' }, { version: 'dev-main' }]) + ).toEqual([{ version: '1.2.3' }, { version: 'dev-main' }]); }); }); @@ -84,9 +81,7 @@ describe('modules/datasource/packagist/schema', () => { 'baz/qux': [{ version: '4.5.6' }], }, }) - ).toEqual([ - { version: '1.2.3', homepage: null, source: null, time: null }, - ]); + ).toEqual([{ version: '1.2.3' }]); }); }); @@ -140,15 +135,15 @@ describe('modules/datasource/packagist/schema', () => { ], }, }, - ]) + ] satisfies { packages: Record<string, ComposerRelease[]> }[]) ).toEqual({ - homepage: 'https://example.com/3', - sourceUrl: 'git@example.com:foo/bar-3', + homepage: 'https://example.com/1', + sourceUrl: 'git@example.com:foo/bar-1', releases: [ { version: '1.1.1', gitRef: 'v1.1.1', releaseTimestamp: '111' }, { version: '3.3.3', gitRef: 'v3.3.3', releaseTimestamp: '333' }, ], - }); + } satisfies ReleaseResult); }); }); }); diff --git a/lib/modules/datasource/packagist/schema.ts b/lib/modules/datasource/packagist/schema.ts index afaacc61d4..881b001257 100644 --- a/lib/modules/datasource/packagist/schema.ts +++ b/lib/modules/datasource/packagist/schema.ts @@ -1,28 +1,31 @@ import { z } from 'zod'; -import { api as versioning } from '../../versioning/composer'; +import { logger } from '../../../logger'; import type { Release, ReleaseResult } from '../types'; -export const ComposerRelease = z.object({ - version: z - .string() - .refine((v) => versioning.isSingleVersion(v), 'Invalid version'), - homepage: z.string().nullable().catch(null), - source: z - .object({ - url: z.string(), - }) - .transform((x) => x.url) - .nullable() - .catch(null), - time: z.string().nullable().catch(null), -}); +export const ComposerRelease = z + .object({ + version: z.string(), + }) + .merge( + z + .object({ + homepage: z.string().nullable().catch(null), + source: z + .object({ + url: z.string(), + }) + .nullable() + .catch(null), + time: z.string().nullable().catch(null), + }) + .partial() + ); +export type ComposerRelease = z.infer<typeof ComposerRelease>; -export const ComposerReleaseArray = z +export const ComposerReleases = z .array(ComposerRelease.nullable().catch(null)) - .transform((xs) => - xs.filter((x): x is z.infer<typeof ComposerRelease> => x !== null) - ); -export type ComposerReleaseArray = z.infer<typeof ComposerReleaseArray>; + .transform((xs) => xs.filter((x): x is ComposerRelease => x !== null)); +export type ComposerReleases = z.infer<typeof ComposerReleases>; export const ComposerPackagesResponse = z.object({ packages: z.record(z.unknown()), @@ -31,21 +34,18 @@ export const ComposerPackagesResponse = z.object({ export function parsePackagesResponse( packageName: string, packagesResponse: unknown -): ComposerReleaseArray { - const packagesResponseParsed = - ComposerPackagesResponse.safeParse(packagesResponse); - if (!packagesResponseParsed.success) { +): ComposerReleases { + try { + const { packages } = ComposerPackagesResponse.parse(packagesResponse); + const releases = ComposerReleases.parse(packages[packageName]); + return releases; + } catch (err) { + logger.debug( + { packageName, err }, + `Error parsing packagist response for ${packageName}` + ); return []; } - - const { packages } = packagesResponseParsed.data; - const releaseArray = packages[packageName]; - const releaseArrayParsed = ComposerReleaseArray.safeParse(releaseArray); - if (!releaseArrayParsed.success) { - return []; - } - - return releaseArrayParsed.data; } export function parsePackagesResponses( @@ -53,9 +53,8 @@ export function parsePackagesResponses( packagesResponses: unknown[] ): ReleaseResult | null { const releases: Release[] = []; - let maxVersion: string | null = null; - let homepage: string | null = null; - let sourceUrl: string | null = null; + let homepage: string | null | undefined; + let sourceUrl: string | null | undefined; for (const packagesResponse of packagesResponses) { const releaseArray = parsePackagesResponse(packageName, packagesResponse); @@ -71,10 +70,12 @@ export function parsePackagesResponses( releases.push(dep); - if (!maxVersion || versioning.isGreaterThan(version, maxVersion)) { - maxVersion = version; + if (!homepage && composerRelease.homepage) { homepage = composerRelease.homepage; - sourceUrl = composerRelease.source; + } + + if (!sourceUrl && composerRelease.source?.url) { + sourceUrl = composerRelease.source.url; } } } -- GitLab