diff --git a/internal/update/checker.go b/internal/update/checker.go index eff973d..f0a099c 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 + 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 {