mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-27 21:55:14 +08:00
Retain semver build metadata in immutable release identities
This commit is contained in:
@@ -20,6 +20,13 @@ describe('compatible registry selection', () => {
|
||||
expect(choose(rows.reverse()).version).toBe('1.10.0');
|
||||
expect(choose([release('2.0.0', { engines: '>=2' }), release('1.0.0')], { engineVersion: '2.1.0' }).version).toBe('2.0.0');
|
||||
});
|
||||
it('preserves build metadata identity with deterministic equal-precedence selection', () => {
|
||||
const rows = [release('1.0.0+z'), release('1.0.0+a'), release('v2.0.0')];
|
||||
expect(choose(rows).version).toBe('1.0.0+a');
|
||||
expect(choose(rows.reverse()).version).toBe('1.0.0+a');
|
||||
expect(choose(rows, { version: '1.0.0+z' }).version).toBe('1.0.0+z');
|
||||
expect(() => choose(rows, { version: 'v2.0.0' })).toThrow('exact semantic version');
|
||||
});
|
||||
it('skips invalid metadata and unsupported APIs instead of adopting them', () => {
|
||||
expect(choose([null, release('bad'), release('9.0.0', { apiVersion: 2 }), release('8.0.0', { engines: 'nonsense' }),
|
||||
release('7.0.0', { integrity: 'bad' }), release('6.0.0', { id: 'other' }), release('5.0.0', { capabilities: ['languages'] }),
|
||||
|
||||
@@ -147,7 +147,10 @@ async function cli(args, expected = 0) {
|
||||
await cli(['install', registry + '/api/download/compatible-demo/1.9.0', '--path', roots[2]]); await expectGraph(roots[2], '1.9.0');
|
||||
const file = path.join(lab, 'pinned.cgext'); fs.writeFileSync(file, pinned.bytes);
|
||||
await cli(['install', file, '--path', roots[2]]); await expectGraph(roots[2], '1.10.0');
|
||||
checks.push('exact artifact URL/file semantics preserved');
|
||||
await publish('1.10.0+fixture.1');
|
||||
await cli(['install', 'compatible-demo', '--registry', registry, '--version', '1.10.0+fixture.1', '--path', roots[2]]);
|
||||
await expectGraph(roots[2], '1.10.0+fixture.1');
|
||||
checks.push('exact artifact URL/file semantics and build-metadata pin identity preserved');
|
||||
await page.setViewportSize({ width: 390, height: 844 });
|
||||
await page.locator('.compatibility').filter({ hasText: 'Selected 3.0.0' }).waitFor();
|
||||
assert.ok(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth));
|
||||
|
||||
@@ -16,10 +16,17 @@ export interface ReleaseSelection {
|
||||
export function validateExtensionId(id: unknown): asserts id is string {
|
||||
if (typeof id !== 'string' || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(id)) throw new Error('Expected a lowercase extension id');
|
||||
}
|
||||
function exactVersion(value: unknown): value is string {
|
||||
if (typeof value !== 'string') return false;
|
||||
const parsed = semver.parse(value);
|
||||
// semver.valid()/SemVer.version omit build metadata; retain it for immutable
|
||||
// artifact identity while rejecting aliases such as v1.0.0 or whitespace.
|
||||
return !!parsed && value === parsed.version + (parsed.build.length ? '+' + parsed.build.join('.') : '');
|
||||
}
|
||||
export function resolveRelease(raw: unknown, id: string, options: ReleaseSelection): ExtensionRelease {
|
||||
validateExtensionId(id);
|
||||
if (!semver.valid(options.engineVersion)) throw new Error('Cannot determine the connected CodeGraph version');
|
||||
if (options.version !== undefined && (typeof options.version !== 'string' || semver.valid(options.version) !== options.version)) throw new Error('Request an exact semantic version, such as 1.2.3 (prereleases require an exact pin)');
|
||||
if (options.version !== undefined && !exactVersion(options.version)) throw new Error('Request an exact semantic version, such as 1.2.3 (prereleases require an exact pin)');
|
||||
if (!Array.isArray(raw)) throw new Error('Registry returned an invalid release catalog');
|
||||
if (options.currentVersion !== undefined && !semver.valid(options.currentVersion)) throw new Error('Installed version is invalid; request an explicit version to repair it');
|
||||
const candidates: ExtensionRelease[] = [], reasons: string[] = [];
|
||||
@@ -28,7 +35,7 @@ export function resolveRelease(raw: unknown, id: string, options: ReleaseSelecti
|
||||
const r = item as ExtensionRelease;
|
||||
if (options.version !== undefined && r?.version !== options.version) continue;
|
||||
try {
|
||||
if (!r || r.id !== id || typeof r.version !== 'string' || semver.valid(r.version) !== r.version ||
|
||||
if (!r || r.id !== id || !exactVersion(r.version) ||
|
||||
typeof r.integrity !== 'string' || !/^[a-f0-9]{64}$/.test(r.integrity) || typeof r.engines !== 'string') throw new Error('invalid release identity, version, integrity or engine range');
|
||||
if (versions.has(r.version)) throw new Error(`Registry returned duplicate immutable version ${r.version}`);
|
||||
versions.add(r.version);
|
||||
|
||||
Reference in New Issue
Block a user