Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions __tests__/setup-go.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -683,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';
Expand Down
24 changes: 22 additions & 2 deletions dist/setup/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -94794,6 +94796,24 @@ 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) {
// 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);
}
//
// Convert the go version syntax into semver for semver matching
// 1.13.1 => 1.13.1
// 1.13 => 1.13.0
Expand Down
27 changes: 25 additions & 2 deletions src/installer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}`
Expand Down Expand Up @@ -459,6 +461,27 @@ export async function getVersionsDist(
return (await http.getJson<IGoVersion[]>(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 {
// 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 (e.g., rc1, beta1)
if (!/(?:rc|beta)\d+/.test(version)) {
return versionSpec;
}

return rangePrefix + makeSemver(version);
}

//
// Convert the go version syntax into semver for semver matching
// 1.13.1 => 1.13.1
Expand Down