From 0d2d22167d88345ed257d703cbaddfe02ef7be68 Mon Sep 17 00:00:00 2001 From: IKEDA Sho <suicaicoca@gmail.com> Date: Tue, 12 Jul 2022 17:29:27 +0900 Subject: [PATCH] feat(versioning): add perl versioning (#16518) --- lib/modules/versioning/api.ts | 2 + lib/modules/versioning/perl/index.spec.ts | 71 +++++++++++++++++++++++ lib/modules/versioning/perl/index.ts | 60 +++++++++++++++++++ lib/modules/versioning/perl/readme.md | 3 + 4 files changed, 136 insertions(+) create mode 100644 lib/modules/versioning/perl/index.spec.ts create mode 100644 lib/modules/versioning/perl/index.ts create mode 100644 lib/modules/versioning/perl/readme.md diff --git a/lib/modules/versioning/api.ts b/lib/modules/versioning/api.ts index 83fb40fa00..6b70d0f9dd 100644 --- a/lib/modules/versioning/api.ts +++ b/lib/modules/versioning/api.ts @@ -17,6 +17,7 @@ import * as node from './node'; import * as npm from './npm'; import * as nuget from './nuget'; import * as pep440 from './pep440'; +import * as perl from './perl'; import * as poetry from './poetry'; import redhat from './redhat'; import * as regex from './regex'; @@ -50,6 +51,7 @@ api.set('node', node.api); api.set('npm', npm.api); api.set('nuget', nuget.api); api.set('pep440', pep440.api); +api.set(perl.id, perl.api); api.set('poetry', poetry.api); api.set('redhat', redhat); api.set('regex', regex.api); diff --git a/lib/modules/versioning/perl/index.spec.ts b/lib/modules/versioning/perl/index.spec.ts new file mode 100644 index 0000000000..87577df997 --- /dev/null +++ b/lib/modules/versioning/perl/index.spec.ts @@ -0,0 +1,71 @@ +import perl from '.'; + +describe('modules/versioning/perl/index', () => { + test.each` + input | expected + ${'1'} | ${true} + ${'1.2'} | ${true} + ${'1.02'} | ${true} + ${'1.002'} | ${true} + ${'1.0023'} | ${true} + ${'1.00203'} | ${true} + ${'1.002003'} | ${true} + ${'1.002_003'} | ${true} + ${'1._002003'} | ${false} + ${'1.002003_'} | ${false} + ${'1.00_20_03'} | ${false} + ${'v1'} | ${true} + ${'v1.200'} | ${true} + ${'v1.20.0'} | ${true} + ${'v1.2.3'} | ${true} + ${'1.2.3'} | ${true} + ${'v1.2_3'} | ${true} + ${'v1._23'} | ${false} + ${'v1.23_'} | ${false} + ${'v1.2_3_4'} | ${false} + `('isValid("$input") === $expected', ({ input, expected }) => { + const res = !!perl.isValid(input); + expect(res).toBe(expected); + }); + + test.each` + input | expected + ${'1'} | ${true} + ${'1.234'} | ${true} + ${'1.2_34'} | ${false} + ${'v1'} | ${true} + ${'v1.2'} | ${true} + ${'v1.2.3'} | ${true} + ${'v1.2.3_4'} | ${false} + `('isStable("$input") === $expected', ({ input, expected }) => { + expect(perl.isStable(input)).toBe(expected); + }); + + test.each` + a | b | expected + ${'1.2'} | ${'v1.200.0'} | ${true} + ${'1.02'} | ${'v1.20.0'} | ${true} + ${'1.002'} | ${'v1.2.0'} | ${true} + ${'1.0023'} | ${'v1.2.300'} | ${true} + ${'1.00203'} | ${'v1.2.30'} | ${true} + ${'1.002003'} | ${'v1.2.3'} | ${true} + ${'1.02_03'} | ${'1.020_3'} | ${true} + ${'1.02_03'} | ${'v1.20_300'} | ${true} + `('equals($a, $b) === $expected', ({ a, b, expected }) => { + expect(perl.equals(a, b)).toBe(expected); + }); + + test.each` + a | b | expected + ${'2.4.2'} | ${'2.4.1'} | ${true} + ${'0.1301'} | ${'0.13_01'} | ${true} + ${'0.13_01'} | ${'0.1301'} | ${false} + ${'1.900'} | ${'2.000'} | ${false} + ${'1.900'} | ${'1.901'} | ${false} + ${'1.2.0.1'} | ${'1.2.0'} | ${true} + ${'1.2.0'} | ${'1.2.0.1'} | ${false} + ${undefined} | ${'1.2.0'} | ${true} + `('isGreaterThan($a, $b) === $expected', ({ a, b, expected }) => { + expect(perl.isGreaterThan(a, b)).toBe(expected); + }); +}); diff --git a/lib/modules/versioning/perl/index.ts b/lib/modules/versioning/perl/index.ts new file mode 100644 index 0000000000..1acb75945b --- /dev/null +++ b/lib/modules/versioning/perl/index.ts @@ -0,0 +1,60 @@ +import { regEx } from '../../../util/regex'; +import { GenericVersion, GenericVersioningApi } from '../generic'; +import type { VersioningApi } from '../types'; + +export const id = 'perl'; +export const displayName = 'Perl'; +export const urls = ['https://metacpan.org/pod/version']; +export const supportsRanges = false; + +// https://metacpan.org/pod/version#Decimal-Versions +const decimalVersionPattern = regEx(/^(\d+)\.(\d+(?:_\d+)?)$/); +// https://metacpan.org/pod/version#Dotted-Decimal-Versions +const dottedDecimalVersionPattern = regEx(/^v?(\d+(?:\.\d+)*(?:_\d+)?)$/); + +class PerlVersioningApi extends GenericVersioningApi { + protected _parse(version: string): GenericVersion | null { + return ( + this._parseDecimalVersion(version) ?? + this._parseDottedDecimalVersion(version) + ); + } + + private _parseDecimalVersion(version: string): GenericVersion | null { + const matches = decimalVersionPattern.exec(version); + if (!matches) { + return null; + } + const [, intPart, decimalPart] = matches; + const prerelease = decimalPart.includes('_') ? 'alpha' : ''; + + const decimalComponents = + decimalPart + .replace(/_/g, '') + .match(/.{1,3}/g) + ?.map((value) => { + let component = value; + while (component.length < 3) { + component += '0'; + } + return Number.parseInt(component, 10); + }) ?? /* istanbul ignore next */ []; + const release = [Number.parseInt(intPart, 10), ...decimalComponents]; + return { release, prerelease }; + } + + private _parseDottedDecimalVersion(version: string): GenericVersion | null { + const matches = dottedDecimalVersionPattern.exec(version); + if (!matches) { + return null; + } + const [, versionValue] = matches; + const prerelease = versionValue.includes('_') ? 'alpha' : ''; + const release = versionValue.split(/[._]/).map(Number); + return { release, prerelease }; + } +} + +export const api: VersioningApi = new PerlVersioningApi(); + +export default api; diff --git a/lib/modules/versioning/perl/readme.md b/lib/modules/versioning/perl/readme.md new file mode 100644 index 0000000000..0cb3c741f2 --- /dev/null +++ b/lib/modules/versioning/perl/readme.md @@ -0,0 +1,3 @@ +Perl versioning is based on Perl's [`version` module](https://metacpan.org/pod/version). + +This could be used in combination with the `regex` manager and the `repology` datasource. -- GitLab