Skip to content

Commit c8526dc

Browse files
silverwindclaude
andcommitted
Filter out Go prerelease versions unless --prerelease is used
Go modules were offering prerelease updates by default because the Go code path in findNewVersion() only filtered pseudo-versions but not actual prerelease tags. Also, per-package --prerelease matching was broken for Go because the data objects lacked a `name` property. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 5a7a9d9 commit c8526dc

File tree

3 files changed

+54
-4
lines changed

3 files changed

+54
-4
lines changed

fixtures/go-prerelease/go.mod

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

index.test.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const goUpdateModFile = fileURLToPath(new URL("fixtures/go-update/go.mod", impor
2424
const goUpdateMainFile = fileURLToPath(new URL("fixtures/go-update/main.go", import.meta.url));
2525
const goUpdateV2ModFile = fileURLToPath(new URL("fixtures/go-update-v2/go.mod", import.meta.url));
2626
const goUpdateV2MainFile = fileURLToPath(new URL("fixtures/go-update-v2/main.go", import.meta.url));
27+
const goPreFile = fileURLToPath(new URL("fixtures/go-prerelease/go.mod", import.meta.url));
2728
const dualFile = fileURLToPath(new URL("fixtures/dual", import.meta.url));
2829
const invalidConfigFile = fileURLToPath(new URL("fixtures/invalid-config/package.json", import.meta.url));
2930

@@ -182,6 +183,7 @@ beforeAll(async () => {
182183
{path: "/github.com/example/testpkg/@latest", response: JSON.stringify({Version: "v1.0.0", Time: "2024-01-01T00:00:00Z"})},
183184
{path: "/github.com/example/testpkg/v2/@latest", response: JSON.stringify({Version: "v2.0.0", Time: "2025-01-01T00:00:00Z"})},
184185
{path: "/github.com/google/uuid/v2/@latest", response: JSON.stringify({Version: "v2.0.0-20260217135312-8c5a7de9ffa1", Time: "2026-02-17T13:53:12Z"})},
186+
{path: "/github.com/example/prerelpkg/@latest", response: JSON.stringify({Version: "v1.1.0-rc.1", Time: "2025-06-01T00:00:00Z"})},
185187
];
186188
for (let v = 71; v <= 82; v++) {
187189
goProxyRoutes.push({
@@ -1199,6 +1201,45 @@ test.concurrent("go update v1 to v2", async ({expect = globalExpect}: any = {})
11991201
expect(updatedMain).not.toMatch(/"github\.com\/example\/testpkg"(?!\/v2)/);
12001202
});
12011203

1204+
test.concurrent("go prerelease excluded by default", async ({expect = globalExpect}: any = {}) => {
1205+
// Without --prerelease, Go prerelease versions should not be offered
1206+
expect(await makeTest(`-j -f ${goPreFile}`)()).toMatchInlineSnapshot(`undefined`);
1207+
});
1208+
1209+
test.concurrent("go prerelease with -p flag", async ({expect = globalExpect}: any = {}) => {
1210+
// With global --prerelease, Go prerelease versions should be offered
1211+
expect(await makeTest(`-j -f ${goPreFile} -p`)()).toMatchInlineSnapshot(`
1212+
{
1213+
"go": {
1214+
"deps": {
1215+
"github.com/example/prerelpkg": {
1216+
"info": "https://github.com/example/prerelpkg",
1217+
"new": "1.1.0-rc.1",
1218+
"old": "1.0.0",
1219+
},
1220+
},
1221+
},
1222+
}
1223+
`);
1224+
});
1225+
1226+
test.concurrent("go prerelease with -p per-package", async ({expect = globalExpect}: any = {}) => {
1227+
// With per-package --prerelease, Go prerelease versions should be offered for that package
1228+
expect(await makeTest(`-j -f ${goPreFile} -p github.com/example/prerelpkg`)()).toMatchInlineSnapshot(`
1229+
{
1230+
"go": {
1231+
"deps": {
1232+
"github.com/example/prerelpkg": {
1233+
"info": "https://github.com/example/prerelpkg",
1234+
"new": "1.1.0-rc.1",
1235+
"old": "1.0.0",
1236+
},
1237+
},
1238+
},
1239+
}
1240+
`);
1241+
});
1242+
12021243
test.concurrent("pin", async ({expect = globalExpect}: any = {}) => {
12031244
const {stdout, stderr} = await nanoSpawn(process.execPath, [
12041245
script,

index.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,7 @@ function parseGoMod(content: string): Record<string, string> {
562562
}
563563

564564
async function fetchGoVcsInfo(name: string, type: string, currentVersion: string, goCwd: string): Promise<PackageInfo> {
565-
const noUpdate: PackageInfo = [{old: currentVersion, new: currentVersion}, type, null, name];
565+
const noUpdate: PackageInfo = [{name, old: currentVersion, new: currentVersion}, type, null, name];
566566
const currentMajor = extractGoMajor(name);
567567

568568
const goListQuery = async (modulePath: string, timeout: number) => {
@@ -622,6 +622,7 @@ async function fetchGoVcsInfo(name: string, type: string, currentVersion: string
622622
}
623623

624624
return [{
625+
name,
625626
old: currentVersion,
626627
new: stripv(highestVersion),
627628
Time: highestTime,
@@ -632,7 +633,7 @@ async function fetchGoVcsInfo(name: string, type: string, currentVersion: string
632633
}
633634

634635
async function fetchGoProxyInfo(name: string, type: string, currentVersion: string, goCwd: string): Promise<PackageInfo> {
635-
const noUpdate: PackageInfo = [{old: currentVersion, new: currentVersion}, type, null, name];
636+
const noUpdate: PackageInfo = [{name, old: currentVersion, new: currentVersion}, type, null, name];
636637

637638
if (isGoNoProxy(name)) return fetchGoVcsInfo(name, type, currentVersion, goCwd);
638639

@@ -697,6 +698,7 @@ async function fetchGoProxyInfo(name: string, type: string, currentVersion: stri
697698
}
698699

699700
return [{
701+
name,
700702
old: currentVersion,
701703
new: stripv(highestVersion),
702704
Time: highestTime,
@@ -1128,10 +1130,12 @@ function findNewVersion(data: any, {mode, range, useGreatest, useRel, usePre, se
11281130
} else if (mode === "go") {
11291131
const oldVersion = coerceToVersion(range);
11301132
if (!oldVersion) return null;
1133+
const effectiveUsePre = usePre || isRangePrerelease(range);
1134+
const skipPrerelease = (v: string) => isVersionPrerelease(v) && (!effectiveUsePre || useRel);
11311135

11321136
// Check cross-major upgrade
11331137
const crossVersion = coerceToVersion(data.new);
1134-
if (crossVersion && !isGoPseudoVersion(data.new)) {
1138+
if (crossVersion && !isGoPseudoVersion(data.new) && !skipPrerelease(data.new)) {
11351139
const d = diff(oldVersion, crossVersion);
11361140
if (d && semvers.has(d)) {
11371141
return data.new;
@@ -1140,7 +1144,7 @@ function findNewVersion(data: any, {mode, range, useGreatest, useRel, usePre, se
11401144

11411145
// Fall back to same-major upgrade
11421146
const sameVersion = coerceToVersion(data.sameMajorNew);
1143-
if (sameVersion && !isGoPseudoVersion(data.sameMajorNew)) {
1147+
if (sameVersion && !isGoPseudoVersion(data.sameMajorNew) && !skipPrerelease(data.sameMajorNew)) {
11441148
const d = diff(oldVersion, sameVersion);
11451149
if (d && semvers.has(d)) {
11461150
data.Time = data.sameMajorTime;

0 commit comments

Comments
 (0)