diff --git a/lib/versioning/docker/index.spec.ts b/lib/versioning/docker/index.spec.ts index a1bbb55d1974ea86f61abe453b17cae4c5b351b8..def3a87ea2fcb058392c63b6c52e81d5d6725231 100644 --- a/lib/versioning/docker/index.spec.ts +++ b/lib/versioning/docker/index.spec.ts @@ -115,6 +115,30 @@ describe('docker.', () => { ); }); }); + + it('sorts unstable', () => { + const versions = [ + '3.7.0', + '3.7-alpine', + '3.7.0b1', + '3.7.0b5', + '3.8.0b1-alpine', + '3.8.0-alpine', + '3.8.2', + '3.8.0', + ]; + + expect(versions.sort(docker.sortVersions)).toEqual([ + '3.7.0b1', + '3.7.0b5', + '3.7.0', + '3.7-alpine', + '3.8.0b1-alpine', + '3.8.0-alpine', + '3.8.0', + '3.8.2', + ]); + }); }); describe('getNewValue(', () => { it('returns toVersion', () => { @@ -128,4 +152,65 @@ describe('docker.', () => { ).toBe('1.2.3'); }); }); + + it('isStable(version)', () => { + const versions = [ + '3.7.0', + '3.7.0b1', + '3.7-alpine', + '3.8.0-alpine', + '3.8.0b1-alpine', + '3.8.2', + ]; + + expect(versions.filter(docker.isStable)).toEqual([ + '3.7.0', + '3.7-alpine', + '3.8.0-alpine', + '3.8.2', + ]); + }); + + it('isCompatible(version)', () => { + const versions = [ + '3.7.0', + '3.7.0b1', + '3.7-alpine', + '3.8.0-alpine', + '3.8.0b1-alpine', + '3.8.2', + ]; + + expect(versions.filter((v) => docker.isCompatible(v, '3.7.0'))).toEqual([ + '3.7.0', + '3.7.0b1', + '3.8.2', + ]); + + expect( + versions.filter((v) => docker.isCompatible(v, '3.7.0-alpine')) + ).toEqual(['3.8.0-alpine', '3.8.0b1-alpine']); + }); + + it('valueToVersion(version)', () => { + const versions = [ + '3.7.0', + '3.7.0b1', + '3.7-alpine', + '3.8.0-alpine', + '3.8.0b1-alpine', + '3.8.2', + undefined, + ]; + + expect(versions.map(docker.valueToVersion)).toEqual([ + '3.7.0', + '3.7.0b1', + '3.7', + '3.8.0', + '3.8.0b1', + '3.8.2', + undefined, + ]); + }); }); diff --git a/lib/versioning/docker/index.ts b/lib/versioning/docker/index.ts index e53899ca1041d7f54698d41f30f07c2c85c19d0d..e2ba6bb3c6808cb12427a6263a2138d2363d71a1 100644 --- a/lib/versioning/docker/index.ts +++ b/lib/versioning/docker/index.ts @@ -8,16 +8,20 @@ export const urls = [ ]; export const supportsRanges = false; -function parse(version: string): any { +const versionRe = /^(?<version>\d+(?:\.\d+)*)(?<prerelease>.*)$/; + +function parse(version: string): generic.GenericVersion { const versionPieces = version.replace(/^v/, '').split('-'); const prefix = versionPieces.shift(); const suffix = versionPieces.join('-'); - const release = prefix.split('.').map(Number); - // eslint-disable-next-line @typescript-eslint/unbound-method - if (release.some(Number.isNaN)) { + const m = versionRe.exec(prefix); + if (!m?.groups) { return null; } - return { release, suffix }; + + const { version: ver, prerelease } = m.groups; + const release = ver.split('.').map(Number); + return { release, suffix, prerelease }; } function valueToVersion(value: string): string { @@ -47,6 +51,17 @@ function compare(version1: string, vervion2: string): number { return part1 - part2; } } + if (parsed1.prerelease !== parsed2.prerelease) { + // unstable is lower + if (!parsed1.prerelease && parsed2.prerelease) { + return 1; + } + if (parsed1.prerelease && !parsed2.prerelease) { + return -1; + } + // alphabetic order + return parsed1.prerelease.localeCompare(parsed2.prerelease); + } // equals return parsed2.suffix.localeCompare(parsed1.suffix); } diff --git a/lib/versioning/loose/generic.ts b/lib/versioning/loose/generic.ts index 49b5fc39bf2f5af9ff0f501ec7e1685d14f3e2c3..c616bce2433cec94dd6fa8346ae1a538750e6658 100644 --- a/lib/versioning/loose/generic.ts +++ b/lib/versioning/loose/generic.ts @@ -2,6 +2,8 @@ import { VersioningApi, NewValueConfig } from '../common'; export interface GenericVersion { release: number[]; + /** prereleases are treated in the standard semver manner, if present */ + prerelease?: string; suffix?: string; } export interface VersionParser { @@ -40,7 +42,8 @@ export const parser = (parse: VersionParser): Partial<VersioningApi> => { } function isStable(version: string): boolean { - return !!isValid(version); + const parsed = parse(version); + return parsed && !parsed.prerelease; } return { @@ -142,7 +145,8 @@ export abstract class GenericVersioningApi< } isStable(version: string): boolean { - return this.isValid(version); + const parsed = this._parse(version); + return parsed && !parsed.prerelease; } isSingleVersion(version: string): string | boolean {