From 8fba24c0546bc0b9f736a45ebf809ad9a78e19ad Mon Sep 17 00:00:00 2001 From: Dylan Ravel Date: Thu, 15 Jan 2026 15:25:54 -0800 Subject: [PATCH 1/2] Improve version comparison to handle prereleases Enhanced CompareVersions to correctly handle prerelease tags, ensuring prerelease versions are considered less than stable releases and comparing prerelease tags alphabetically. Added comprehensive test cases to verify correct behavior for various prerelease and stable version scenarios. --- internal/update/checker.go | 44 ++++++++++++++++++++++++++++++ internal/update/checker_test.go | 48 +++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/internal/update/checker.go b/internal/update/checker.go index eff973d..5fc9641 100644 --- a/internal/update/checker.go +++ b/internal/update/checker.go @@ -60,6 +60,50 @@ func CompareVersions(current, latest string) int { current = strings.TrimPrefix(current, "v") latest = strings.TrimPrefix(latest, "v") + // separate out normal version and prerelease + currentCore, currentPrerelease := splitPrerelease(current) + latestCore, latestPrerelease := splitPrerelease(latest) + + coreComparison := compareCoreVersions(currentCore, latestCore) + + // return early if core versions differ + if coreComparison != 0 { + return coreComparison + } + + // prerelease is always less than stable (e.g., 1.0.0-rc.1 < 1.0.0) + if currentPrerelease != "" && latestPrerelease == "" { + return -1 + } + + // stable is always greater than prerelease + if currentPrerelease == "" && latestPrerelease != "" { + return 1 + } + + // both are prereleases, compare alphabetically + if currentPrerelease != "" && latestPrerelease != "" { + if currentPrerelease < latestPrerelease { + return -1 + } + if currentPrerelease > latestPrerelease { + return 1 + } + } + + return 0 +} + +// splitPrerelease separates out version and prerelease tag +func splitPrerelease(version string) (core, prerelease string) { + if idx := strings.Index(version, "-"); idx != -1 { + return version[:idx], version[idx+1:] + } + return version, "" +} + +// compareCoreVersions compares major.minor.patch numerically +func compareCoreVersions(current, latest string) int { currentParts := strings.Split(current, ".") latestParts := strings.Split(latest, ".") diff --git a/internal/update/checker_test.go b/internal/update/checker_test.go index 3d9db9d..251959f 100644 --- a/internal/update/checker_test.go +++ b/internal/update/checker_test.go @@ -79,6 +79,54 @@ func TestCompareVersions(t *testing.T) { latest: "1.2", expected: 1, }, + { + name: "prerelease is less than stable", + current: "1.0.0-rc.1", + latest: "1.0.0", + expected: -1, + }, + { + name: "stable is greater than prerelease", + current: "1.0.0", + latest: "1.0.0-rc.1", + expected: 1, + }, + { + name: "prerelease alpha less than beta", + current: "1.0.0-alpha", + latest: "1.0.0-beta", + expected: -1, + }, + { + name: "prerelease beta less than rc", + current: "1.0.0-beta", + latest: "1.0.0-rc.1", + expected: -1, + }, + { + name: "same prerelease version", + current: "1.0.0-rc.1", + latest: "1.0.0-rc.1", + expected: 0, + }, + { + name: "prerelease with v prefix", + current: "v1.0.0-rc.1", + latest: "v1.0.0", + expected: -1, + }, + { + name: "older prerelease than newer stable", + current: "1.0.0-beta", + latest: "1.1.0", + expected: -1, + }, + { + name: "newer stable than older prerelease", + current: "1.1.0", + latest: "1.0.0-rc.1", + expected: 1, + }, } for _, tt := range tests { From 38d76062a3418f0b92d83a6e3105e0e327358903 Mon Sep 17 00:00:00 2001 From: Dylan Ravel Date: Thu, 15 Jan 2026 15:26:17 -0800 Subject: [PATCH 2/2] Update checker.go --- internal/update/checker.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/update/checker.go b/internal/update/checker.go index 5fc9641..f0a099c 100644 --- a/internal/update/checker.go +++ b/internal/update/checker.go @@ -65,13 +65,13 @@ func CompareVersions(current, latest string) int { latestCore, latestPrerelease := splitPrerelease(latest) coreComparison := compareCoreVersions(currentCore, latestCore) - + // return early if core versions differ if coreComparison != 0 { return coreComparison } - // prerelease is always less than stable (e.g., 1.0.0-rc.1 < 1.0.0) + // prerelease is always less than stable if currentPrerelease != "" && latestPrerelease == "" { return -1 }