Skip to content

Commit

Permalink
feat(packagist): De-minify release fields
Browse files Browse the repository at this point in the history
  • Loading branch information
zharinov committed Jan 17, 2023
1 parent 142bebc commit d2d4410
Show file tree
Hide file tree
Showing 2 changed files with 156 additions and 9 deletions.
115 changes: 107 additions & 8 deletions lib/modules/datasource/packagist/schema.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,74 @@ import type { ReleaseResult } from '../types';
import {
ComposerRelease,
ComposerReleases,
MinifiedArray,
parsePackagesResponse,
parsePackagesResponses,
} from './schema';

describe('modules/datasource/packagist/schema', () => {
describe('MinifiedArray', () => {
it('parses MinifiedArray', () => {
expect(MinifiedArray.parse([])).toEqual([]);

// Source: https://github.com/composer/metadata-minifier/blob/1.0.0/tests/MetadataMinifierTest.php
expect(
MinifiedArray.parse([
{
name: 'foo/bar',
version: '2.0.0',
version_normalized: '2.0.0.0',
type: 'library',
scripts: {
foo: 'bar',
},
license: ['MIT'],
},
{
version: '1.2.0',
version_normalized: '1.2.0.0',
license: ['GPL'],
homepage: 'https://example.org',
scripts: '__unset',
},
{
version: '1.0.0',
version_normalized: '1.0.0.0',
homepage: '__unset',
},
])
).toEqual([
{
name: 'foo/bar',
version: '2.0.0',
version_normalized: '2.0.0.0',
type: 'library',
scripts: {
foo: 'bar',
},
license: ['MIT'],
},
{
name: 'foo/bar',
version: '1.2.0',
version_normalized: '1.2.0.0',
type: 'library',
license: ['GPL'],
homepage: 'https://example.org',
},
{
name: 'foo/bar',
version: '1.0.0',
version_normalized: '1.0.0.0',
type: 'library',
license: ['GPL'],
},
]);
});
});

describe('ComposerRelease', () => {
it('rejects', () => {
it('rejects ComposerRelease', () => {
expect(() => ComposerRelease.parse(null)).toThrow();
expect(() => ComposerRelease.parse(undefined)).toThrow();
expect(() => ComposerRelease.parse('')).toThrow();
Expand All @@ -17,7 +78,7 @@ describe('modules/datasource/packagist/schema', () => {
expect(() => ComposerRelease.parse({ version: null })).toThrow();
});

it('parses', () => {
it('parses ComposerRelease', () => {
expect(ComposerRelease.parse({ version: '' })).toEqual({ version: '' });
expect(ComposerRelease.parse({ version: 'dev-main' })).toEqual({
version: 'dev-main',
Expand Down Expand Up @@ -50,14 +111,14 @@ describe('modules/datasource/packagist/schema', () => {
});

describe('ComposerReleases', () => {
it('rejects', () => {
it('rejects ComposerReleases', () => {
expect(() => ComposerReleases.parse(null)).toThrow();
expect(() => ComposerReleases.parse(undefined)).toThrow();
expect(() => ComposerReleases.parse('')).toThrow();
expect(() => ComposerReleases.parse({})).toThrow();
});

it('parses', () => {
it('parses ComposerReleases', () => {
expect(ComposerReleases.parse([])).toEqual([]);
expect(ComposerReleases.parse([null])).toEqual([]);
expect(ComposerReleases.parse([1, 2, 3])).toEqual([]);
Expand All @@ -69,7 +130,7 @@ describe('modules/datasource/packagist/schema', () => {
});

describe('parsePackageResponse', () => {
it('parses', () => {
it('parses package response', () => {
expect(parsePackagesResponse('foo/bar', null)).toEqual([]);
expect(parsePackagesResponse('foo/bar', {})).toEqual([]);
expect(parsePackagesResponse('foo/bar', { packages: '123' })).toEqual([]);
Expand All @@ -83,10 +144,36 @@ describe('modules/datasource/packagist/schema', () => {
})
).toEqual([{ version: '1.2.3' }]);
});

it('expands minified fields', () => {
expect(
parsePackagesResponse('foo/bar', {
packages: {
'foo/bar': [
{ version: '3.3.3', require: { php: '^8.0' } },
{ version: '2.2.2' },
{ version: '1.1.1' },
{ version: '0.0.4', require: { php: '^7.0' } },
{ version: '0.0.3' },
{ version: '0.0.2', require: '__unset' },
{ version: '0.0.1' },
],
},
})
).toEqual([
{ version: '3.3.3', require: { php: '^8.0' } },
{ version: '2.2.2', require: { php: '^8.0' } },
{ version: '1.1.1', require: { php: '^8.0' } },
{ version: '0.0.4', require: { php: '^7.0' } },
{ version: '0.0.3', require: { php: '^7.0' } },
{ version: '0.0.2' },
{ version: '0.0.1' },
] satisfies ComposerRelease[]);
});
});

describe('parsePackagesResponses', () => {
it('parses', () => {
it('parses array of responses', () => {
expect(parsePackagesResponses('foo/bar', [null])).toBeNull();
expect(parsePackagesResponses('foo/bar', [{}])).toBeNull();
expect(
Expand All @@ -103,6 +190,7 @@ describe('modules/datasource/packagist/schema', () => {
time: '111',
homepage: 'https://example.com/1',
source: { url: 'git@example.com:foo/bar-1' },
require: { php: '^8.0' },
},
],
'baz/qux': [
Expand All @@ -123,6 +211,7 @@ describe('modules/datasource/packagist/schema', () => {
time: '333',
homepage: 'https://example.com/3',
source: { url: 'git@example.com:foo/bar-3' },
require: { php: '^7.0' },
},
],
'baz/qux': [
Expand All @@ -140,8 +229,18 @@ describe('modules/datasource/packagist/schema', () => {
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' },
{
version: '1.1.1',
gitRef: 'v1.1.1',
releaseTimestamp: '111',
constraints: { php: ['^8.0'] },
},
{
version: '3.3.3',
gitRef: 'v3.3.3',
releaseTimestamp: '333',
constraints: { php: ['^7.0'] },
},
],
} satisfies ReleaseResult);
});
Expand Down
50 changes: 49 additions & 1 deletion lib/modules/datasource/packagist/schema.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,44 @@
import is from '@sindresorhus/is';
import { z } from 'zod';
import { logger } from '../../../logger';
import type { Release, ReleaseResult } from '../types';

export const MinifiedArray = z.array(z.record(z.unknown())).transform((xs) => {
// Ported from: https://github.com/composer/metadata-minifier/blob/main/src/MetadataMinifier.php#L17
if (xs.length === 0) {
return xs;
}

const prevVals: Record<string, unknown> = {};
for (const x of xs) {
for (const key of Object.keys(x)) {
prevVals[key] ??= undefined;
}

for (const key of Object.keys(prevVals)) {
const val = x[key];
if (val === '__unset') {
delete x[key];
prevVals[key] = undefined;
continue;
}

if (!is.undefined(val)) {
prevVals[key] = val;
continue;
}

if (!is.undefined(prevVals[key])) {
x[key] = prevVals[key];
continue;
}
}
}

return xs;
});
export type MinifiedArray = z.infer<typeof MinifiedArray>;

export const ComposerRelease = z
.object({
version: z.string(),
Expand All @@ -17,6 +54,12 @@ export const ComposerRelease = z
.nullable()
.catch(null),
time: z.string().nullable().catch(null),
require: z
.object({
php: z.string(),
})
.nullable()
.catch(null),
})
.partial()
);
Expand All @@ -37,7 +80,8 @@ export function parsePackagesResponse(
): ComposerReleases {
try {
const { packages } = ComposerPackagesResponse.parse(packagesResponse);
const releases = ComposerReleases.parse(packages[packageName]);
const array = MinifiedArray.parse(packages[packageName]);
const releases = ComposerReleases.parse(array);
return releases;
} catch (err) {
logger.debug(
Expand Down Expand Up @@ -68,6 +112,10 @@ export function parsePackagesResponses(
dep.releaseTimestamp = composerRelease.time;
}

if (composerRelease.require?.php) {
dep.constraints = { php: [composerRelease.require.php] };
}

releases.push(dep);

if (!homepage && composerRelease.homepage) {
Expand Down

0 comments on commit d2d4410

Please sign in to comment.