From 389daec2099de803559a7d15df7c03be472f7fd3 Mon Sep 17 00:00:00 2001 From: FUJI Goro Date: Fri, 26 Dec 2025 22:39:44 +0900 Subject: [PATCH 1/2] support go 1.26rc1 --- __tests__/setup-go.test.ts | 27 +++++++++++++++++++++++++++ dist/setup/index.js | 26 ++++++++++++++++++++++++-- src/installer.ts | 30 ++++++++++++++++++++++++++++-- 3 files changed, 79 insertions(+), 4 deletions(-) diff --git a/__tests__/setup-go.test.ts b/__tests__/setup-go.test.ts index 8cefcce..d916339 100644 --- a/__tests__/setup-go.test.ts +++ b/__tests__/setup-go.test.ts @@ -265,6 +265,33 @@ describe('setup-go', () => { expect(fileName).toBe('go1.14rc1.linux-amd64.tar.gz'); }); + it('finds unstable pre-release version using Go-style version format', async () => { + os.platform = 'linux'; + os.arch = 'x64'; + + // User specifies "1.14rc1" (Go-style) instead of "1.14.0-rc.1" (semver-style) + // This should match go1.14rc1 + const match: im.IGoVersion | undefined = await im.findMatch('1.14rc1'); + expect(match).toBeDefined(); + const version: string = match ? match.version : ''; + expect(version).toBe('go1.14rc1'); + const fileName = match ? match.files[0].filename : ''; + expect(fileName).toBe('go1.14rc1.linux-amd64.tar.gz'); + }); + + it('finds latest version matching caret range with Go-style prerelease', async () => { + os.platform = 'linux'; + os.arch = 'x64'; + + // spec: ^1.13beta1 should match go1.13.7 (latest 1.13.x) + const match: im.IGoVersion | undefined = await im.findMatch('^1.13beta1'); + expect(match).toBeDefined(); + const version: string = match ? match.version : ''; + expect(version).toBe('go1.13.7'); + const fileName = match ? match.files[0].filename : ''; + expect(fileName).toBe('go1.13.7.linux-amd64.tar.gz'); + }); + it('evaluates to stable with input as true', async () => { inputs['go-version'] = '1.13.0'; inputs.stable = 'true'; diff --git a/dist/setup/index.js b/dist/setup/index.js index e35f338..73f0106 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -94474,6 +94474,7 @@ exports.getManifest = getManifest; exports.getInfoFromManifest = getInfoFromManifest; exports.findMatch = findMatch; exports.getVersionsDist = getVersionsDist; +exports.normalizeVersionSpec = normalizeVersionSpec; exports.makeSemver = makeSemver; exports.parseGoVersionFile = parseGoVersionFile; exports.resolveStableVersionInput = resolveStableVersionInput; @@ -94758,12 +94759,13 @@ function findMatch(versionSpec_1) { if (!candidates) { throw new Error(`golang download url did not return results`); } + const normalizedVersionSpec = normalizeVersionSpec(versionSpec); let goFile; for (let i = 0; i < candidates.length; i++) { const candidate = candidates[i]; const version = makeSemver(candidate.version); - core.debug(`check ${version} satisfies ${versionSpec}`); - if (semver.satisfies(version, versionSpec)) { + core.debug(`check ${version} satisfies ${normalizedVersionSpec}`); + if (semver.satisfies(version, normalizedVersionSpec)) { goFile = candidate.files.find(file => { core.debug(`${file.arch}===${archFilter} && ${file.os}===${platFilter}`); return file.arch === archFilter && file.os === platFilter; @@ -94794,6 +94796,26 @@ function getVersionsDist(dlUrl) { }); } // +// Normalize user-provided version spec for semver matching +// Converts Go-style prerelease versions while preserving range semantics +// 1.13 => 1.13 (preserved for range matching) +// 1.14rc1 => 1.14.0-rc.1 +// ^1.14rc1 => ^1.14.0-rc.1 +// ~1.14beta1 => ~1.14.0-beta.1 +function normalizeVersionSpec(versionSpec) { + var _a; + const rangePrefix = ((_a = versionSpec.match(/^[~^]/)) === null || _a === void 0 ? void 0 : _a[0]) || ''; + const version = versionSpec.replace(/^[~^]/, ''); + // Only convert if it has Go-style prerelease (rc/beta without hyphen prefix) + const hasGoStylePrerelease = (version.includes('rc') || version.includes('beta')) && + !version.includes('-rc.') && + !version.includes('-beta.'); + if (!hasGoStylePrerelease) { + return versionSpec; + } + return rangePrefix + makeSemver(version); +} +// // Convert the go version syntax into semver for semver matching // 1.13.1 => 1.13.1 // 1.13 => 1.13.0 diff --git a/src/installer.ts b/src/installer.ts index 9402a83..5cd869b 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -417,13 +417,15 @@ export async function findMatch( throw new Error(`golang download url did not return results`); } + const normalizedVersionSpec = normalizeVersionSpec(versionSpec); + let goFile: IGoVersionFile | undefined; for (let i = 0; i < candidates.length; i++) { const candidate: IGoVersion = candidates[i]; const version = makeSemver(candidate.version); - core.debug(`check ${version} satisfies ${versionSpec}`); - if (semver.satisfies(version, versionSpec)) { + core.debug(`check ${version} satisfies ${normalizedVersionSpec}`); + if (semver.satisfies(version, normalizedVersionSpec)) { goFile = candidate.files.find(file => { core.debug( `${file.arch}===${archFilter} && ${file.os}===${platFilter}` @@ -459,6 +461,30 @@ export async function getVersionsDist( return (await http.getJson(dlUrl)).result; } +// +// Normalize user-provided version spec for semver matching +// Converts Go-style prerelease versions while preserving range semantics +// 1.13 => 1.13 (preserved for range matching) +// 1.14rc1 => 1.14.0-rc.1 +// ^1.14rc1 => ^1.14.0-rc.1 +// ~1.14beta1 => ~1.14.0-beta.1 +export function normalizeVersionSpec(versionSpec: string): string { + const rangePrefix = versionSpec.match(/^[~^]/)?.[0] || ''; + const version = versionSpec.replace(/^[~^]/, ''); + + // Only convert if it has Go-style prerelease (rc/beta without hyphen prefix) + const hasGoStylePrerelease = + (version.includes('rc') || version.includes('beta')) && + !version.includes('-rc.') && + !version.includes('-beta.'); + + if (!hasGoStylePrerelease) { + return versionSpec; + } + + return rangePrefix + makeSemver(version); +} + // // Convert the go version syntax into semver for semver matching // 1.13.1 => 1.13.1 From f5562dd1e7b202dfd9f98fab0d29b8b5273e3a94 Mon Sep 17 00:00:00 2001 From: FUJI Goro Date: Fri, 26 Dec 2025 22:53:54 +0900 Subject: [PATCH 2/2] fix normalizeVersionSpec to cover edge cases pointed out by review comments --- __tests__/setup-go.test.ts | 35 +++++++++++++++++++++++++++++++++++ dist/setup/index.js | 16 +++++++--------- src/installer.ts | 17 +++++++---------- 3 files changed, 49 insertions(+), 19 deletions(-) diff --git a/__tests__/setup-go.test.ts b/__tests__/setup-go.test.ts index d916339..27c6c7e 100644 --- a/__tests__/setup-go.test.ts +++ b/__tests__/setup-go.test.ts @@ -710,6 +710,41 @@ describe('setup-go', () => { expect(im.makeSemver('1.13.1')).toBe('1.13.1'); }); + describe('normalizeVersionSpec', () => { + it('converts Go-style prerelease to semver format', () => { + expect(im.normalizeVersionSpec('1.14rc1')).toBe('1.14.0-rc.1'); + expect(im.normalizeVersionSpec('1.14beta1')).toBe('1.14.0-beta.1'); + expect(im.normalizeVersionSpec('1.21rc2')).toBe('1.21.0-rc.2'); + }); + + it('preserves range prefixes when converting', () => { + expect(im.normalizeVersionSpec('^1.14rc1')).toBe('^1.14.0-rc.1'); + expect(im.normalizeVersionSpec('~1.14beta1')).toBe('~1.14.0-beta.1'); + expect(im.normalizeVersionSpec('>=1.14rc1')).toBe('>=1.14.0-rc.1'); + expect(im.normalizeVersionSpec('>1.14rc1')).toBe('>1.14.0-rc.1'); + expect(im.normalizeVersionSpec('<=1.14rc1')).toBe('<=1.14.0-rc.1'); + expect(im.normalizeVersionSpec('<1.14rc1')).toBe('<1.14.0-rc.1'); + expect(im.normalizeVersionSpec('=1.14rc1')).toBe('=1.14.0-rc.1'); + }); + + it('preserves versions without Go-style prerelease', () => { + expect(im.normalizeVersionSpec('1.13')).toBe('1.13'); + expect(im.normalizeVersionSpec('1.13.7')).toBe('1.13.7'); + expect(im.normalizeVersionSpec('^1.13.6')).toBe('^1.13.6'); + expect(im.normalizeVersionSpec('>=1.13')).toBe('>=1.13'); + }); + + it('preserves already valid semver prerelease format', () => { + expect(im.normalizeVersionSpec('1.14.0-rc.1')).toBe('1.14.0-rc.1'); + expect(im.normalizeVersionSpec('^1.14.0-beta.1')).toBe('^1.14.0-beta.1'); + }); + + it('does not match false positives like "traced"', () => { + // "traced" contains "rc" but should not be treated as prerelease + expect(im.normalizeVersionSpec('1.13traced')).toBe('1.13traced'); + }); + }); + describe('check-latest flag', () => { it("use local version and don't check manifest if check-latest is not specified", async () => { os.platform = 'linux'; diff --git a/dist/setup/index.js b/dist/setup/index.js index 73f0106..0133c2f 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -94801,16 +94801,14 @@ function getVersionsDist(dlUrl) { // 1.13 => 1.13 (preserved for range matching) // 1.14rc1 => 1.14.0-rc.1 // ^1.14rc1 => ^1.14.0-rc.1 -// ~1.14beta1 => ~1.14.0-beta.1 +// >=1.14beta1 => >=1.14.0-beta.1 function normalizeVersionSpec(versionSpec) { - var _a; - const rangePrefix = ((_a = versionSpec.match(/^[~^]/)) === null || _a === void 0 ? void 0 : _a[0]) || ''; - const version = versionSpec.replace(/^[~^]/, ''); - // Only convert if it has Go-style prerelease (rc/beta without hyphen prefix) - const hasGoStylePrerelease = (version.includes('rc') || version.includes('beta')) && - !version.includes('-rc.') && - !version.includes('-beta.'); - if (!hasGoStylePrerelease) { + // Match semver range prefixes: ^, ~, >, >=, <, <=, = + const rangePrefixMatch = versionSpec.match(/^([~^]|[<>]=?|=)/); + const rangePrefix = (rangePrefixMatch === null || rangePrefixMatch === void 0 ? void 0 : rangePrefixMatch[0]) || ''; + const version = versionSpec.slice(rangePrefix.length); + // Only convert if it has Go-style prerelease (e.g., rc1, beta1) + if (!/(?:rc|beta)\d+/.test(version)) { return versionSpec; } return rangePrefix + makeSemver(version); diff --git a/src/installer.ts b/src/installer.ts index 5cd869b..2c57eb8 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -467,18 +467,15 @@ export async function getVersionsDist( // 1.13 => 1.13 (preserved for range matching) // 1.14rc1 => 1.14.0-rc.1 // ^1.14rc1 => ^1.14.0-rc.1 -// ~1.14beta1 => ~1.14.0-beta.1 +// >=1.14beta1 => >=1.14.0-beta.1 export function normalizeVersionSpec(versionSpec: string): string { - const rangePrefix = versionSpec.match(/^[~^]/)?.[0] || ''; - const version = versionSpec.replace(/^[~^]/, ''); + // Match semver range prefixes: ^, ~, >, >=, <, <=, = + const rangePrefixMatch = versionSpec.match(/^([~^]|[<>]=?|=)/); + const rangePrefix = rangePrefixMatch?.[0] || ''; + const version = versionSpec.slice(rangePrefix.length); - // Only convert if it has Go-style prerelease (rc/beta without hyphen prefix) - const hasGoStylePrerelease = - (version.includes('rc') || version.includes('beta')) && - !version.includes('-rc.') && - !version.includes('-beta.'); - - if (!hasGoStylePrerelease) { + // Only convert if it has Go-style prerelease (e.g., rc1, beta1) + if (!/(?:rc|beta)\d+/.test(version)) { return versionSpec; }