Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(versioning): add devbox versioning module #31408

Merged
merged 12 commits into from
Dec 20, 2024
2 changes: 2 additions & 0 deletions lib/modules/versioning/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import * as composer from './composer';
import * as conan from './conan';
import * as deb from './deb';
import * as debian from './debian';
import * as devbox from './devbox';
import * as docker from './docker';
import * as git from './git';
import * as glasskube from './glasskube';
Expand Down Expand Up @@ -52,6 +53,7 @@ api.set(composer.id, composer.api);
api.set(conan.id, conan.api);
api.set(deb.id, deb.api);
api.set(debian.id, debian.api);
api.set(devbox.id, devbox.api);
api.set(docker.id, docker.api);
api.set(git.id, git.api);
api.set(glasskube.id, glasskube.api);
Expand Down
103 changes: 103 additions & 0 deletions lib/modules/versioning/devbox/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import devbox from '.';

describe('modules/versioning/devbox/index', () => {
it.each`
version | expected
${'1'} | ${false}
${'01'} | ${false}
${'1.01'} | ${false}
${'1.1'} | ${false}
${'1.3.0'} | ${true}
${'2.1.20'} | ${true}
${'v1.4'} | ${false}
${'V0.5'} | ${false}
${'3.5.0'} | ${true}
${'4.2.21.Final'} | ${false}
${'1234'} | ${false}
${'foo'} | ${false}
${'latest'} | ${false}
${''} | ${false}
${'3.5.0-beta.3'} | ${false}
${'*'} | ${false}
${'x'} | ${false}
${'X'} | ${false}
${'~1.2.3'} | ${false}
${'>1.2.3'} | ${false}
${'^1.2.3'} | ${false}
${'1.2.3-foo'} | ${false}
${'1.2.3foo'} | ${false}
`('isVersion("$version") === $expected', ({ version, expected }) => {
expect(!!devbox.isVersion(version)).toBe(expected);
});

it.each`
version | isValid
${'1'} | ${true}
${'01'} | ${false}
${'1.01'} | ${false}
${'1.1'} | ${true}
${'1.3.0'} | ${true}
${'2.1.20'} | ${true}
${'v1.4'} | ${false}
${'V0.5'} | ${false}
${'3.5.0'} | ${true}
${'4.2.21.Final'} | ${false}
${'1234'} | ${true}
${'foo'} | ${false}
${'latest'} | ${true}
${''} | ${false}
${'3.5.0-beta.3'} | ${false}
${'*'} | ${false}
${'x'} | ${false}
${'X'} | ${false}
${'~1.2.3'} | ${false}
${'>1.2.3'} | ${false}
${'^1.2.3'} | ${false}
${'1.2.3-foo'} | ${false}
${'1.2.3foo'} | ${false}
`('isValid("$version") === $isValid', ({ version, isValid }) => {
expect(!!devbox.isValid(version)).toBe(isValid);
});

it.each`
version | range | expected
${'1'} | ${'1'} | ${false}
${'1'} | ${'0'} | ${false}
${'1.2.3'} | ${'1'} | ${true}
${'1.2'} | ${'1'} | ${false}
${'1.0.0'} | ${'1'} | ${true}
${'1.2.0'} | ${'1.2'} | ${true}
${'1.2.3'} | ${'1.2'} | ${true}
${'0'} | ${'latest'} | ${false}
${'1.2.3'} | ${'latest'} | ${true}
${'1.2.3.5'} | ${'1.2.3.5'} | ${false}
${'1.2'} | ${'1.2.3'} | ${false}
`(
'matches("$version", "$range") === $expected',
({ version, range, expected }) => {
expect(devbox.matches(version, range)).toBe(expected);
},
);

it.each`
version | range | expected
${'1'} | ${'1'} | ${true}
${'1'} | ${'0'} | ${false}
${'1.2.3'} | ${'1'} | ${true}
${'1.2'} | ${'1'} | ${true}
${'1.0.0'} | ${'1'} | ${true}
${'1.2.0'} | ${'1.2'} | ${true}
${'1.2.3'} | ${'1.2'} | ${true}
${'0'} | ${'latest'} | ${true}
${'1.2.3'} | ${'latest'} | ${true}
${'1.2.3.5'} | ${'1.2.3.5'} | ${false}
${'latest'} | ${'latest'} | ${false}
${'latest'} | ${'1.2.3'} | ${false}
${'1.2'} | ${'1.2.3'} | ${true}
`(
'equals("$version", "$range") === $expected',
({ version, range, expected }) => {
expect(devbox.equals(version, range)).toBe(expected);
},
);
});
74 changes: 74 additions & 0 deletions lib/modules/versioning/devbox/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { regEx } from '../../../util/regex';
import type { GenericVersion } from '../generic';
import { GenericVersioningApi } from '../generic';
import type { VersioningApi } from '../types';

export const id = 'devbox';
export const displayName = 'devbox';
export const urls = [];
export const supportsRanges = false;

const validPattern = regEx(/^((\d|[1-9]\d*)(\.(\d|[1-9]\d*)){0,2})$/);
const versionPattern = regEx(/^((\d|[1-9]\d*)(\.(\d|[1-9]\d*)){2})$/);

class DevboxVersioningApi extends GenericVersioningApi {
protected _parse(version: string): GenericVersion | null {
const matches = validPattern.exec(version);
if (!matches) {
return null;
}
const release = matches[0].split('.').map(Number);
return { release };
}

override isValid(version: string): boolean {
if (version === 'latest') {
return true;
}
return this._parse(version) !== null;
}

override isVersion(version: string): boolean {
if (version === 'latest') {
return false;
}
const matches = versionPattern.exec(version);
return !!matches;
}

override matches(version: string, range: string): boolean {
return this.isVersion(version) && this.equals(version, range);
}

protected override _compare(version: string, other: string): number {
const parsed1 = this._parse(version);
const parsed2 = this._parse(other);

// Treat "latest" as * and always return equal
if (other === 'latest' && parsed1) {
return 0;
}

// If either version is invalid, return unequal
if (!(parsed1 && parsed2)) {
return 1;
}
// support variable length compare
const length = Math.max(parsed1.release.length, parsed2.release.length);
for (let i = 0; i < length; i += 1) {
// 2.1 and 2.1.0 are equivalent
const part1 = parsed1.release[i];
const part2 = parsed2.release[i];
// if part1 or part2 is undefined, we should treat them as equal
// e.g. 1.0.0 === 1.0
if (part1 !== undefined && part2 !== undefined && part1 !== part2) {
return part1 - part2;
}
}
return 0;
}
}

export const api: VersioningApi = new DevboxVersioningApi();

export default api;
2 changes: 2 additions & 0 deletions lib/modules/versioning/devbox/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Devbox's Nixhub uses fairly strict versioning, characters such as ~, ^ and >= are not allowed.
The semver values must not include "\*" or "x". "1.2.3" "1.2" and "1" are the only valid formats.
Loading