Skip to content
Merged
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
14 changes: 7 additions & 7 deletions .github/aw/actions-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
},
"actions/github-script@v8": {
"repo": "actions/github-script",
"version": "v8",
"version": "v8.0.0",
"sha": "ed597411d8f924073f98dfc5c65a23a2325f34cd"
},
"actions/setup-dotnet@v4": {
Expand Down Expand Up @@ -167,18 +167,18 @@
},
"github/codeql-action/upload-sarif@v3": {
"repo": "github/codeql-action/upload-sarif",
"version": "v3",
"sha": "c37a8b7cd97e31de3fcbd9d84c401870edeb8d34"
"version": "v3.31.9",
"sha": "70c165ac82ca0e33a10e9741508dd0ccb4dcf080"
},
"github/stale-repos@v3": {
"repo": "github/stale-repos",
"version": "v3",
"sha": "3477b6488008d9411aaf22a0924ec7c1f6a69980"
"version": "v3.0.2",
"sha": "a21e55567b83cf3c3f3f9085d3038dc6cee02598"
},
"haskell-actions/setup@v2": {
"repo": "haskell-actions/setup",
"version": "v2.9.0",
"sha": "782a7c5aa54495c3d21d7c8d5f03a8a2113a1ff7"
"version": "v2.9.1",
"sha": "55073cbd0e96181a9abd6ff4e7d289867dffc98d"
},
"oven-sh/setup-bun@v2": {
"repo": "oven-sh/setup-bun",
Expand Down
66 changes: 33 additions & 33 deletions .github/workflows/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .github/workflows/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
"private": true,
"license": "MIT",
"dependencies": {
"@sentry/mcp-server": "0.24.0"
"@sentry/mcp-server": "0.26.0"
}
}
13 changes: 13 additions & 0 deletions pkg/cli/semver.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,19 @@ func parseVersion(v string) *semanticVersion {
return ver
}

// isPreciseVersion returns true if this version has explicit minor and patch components
// For example, "v6.0.0" is precise, but "v6" is not
func (v *semanticVersion) isPreciseVersion() bool {
// Check if raw version has at least two dots (major.minor.patch format)
// or at least one dot for major.minor format
// "v6" -> not precise
// "v6.0" -> somewhat precise (has minor)
// "v6.0.0" -> precise (has minor and patch)
versionPart := strings.TrimPrefix(v.raw, "v")
dotCount := strings.Count(versionPart, ".")
return dotCount >= 2 // Require at least major.minor.patch
}

// isNewer returns true if this version is newer than the other
func (v *semanticVersion) isNewer(other *semanticVersion) bool {
if v.major != other.major {
Expand Down
101 changes: 101 additions & 0 deletions pkg/cli/semver_precise_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package cli

import (
"testing"
)

func TestIsPreciseVersion(t *testing.T) {
tests := []struct {
name string
version string
expected bool
}{
{
name: "major only - not precise",
version: "v6",
expected: false,
},
{
name: "major.minor - not precise",
version: "v6.0",
expected: false,
},
{
name: "major.minor.patch - precise",
version: "v6.0.0",
expected: true,
},
{
name: "major.minor.patch non-zero - precise",
version: "v6.0.1",
expected: true,
},
{
name: "full version - precise",
version: "v6.1.2",
expected: true,
},
{
name: "without v prefix - precise",
version: "6.0.0",
expected: true,
},
{
name: "single digit major - not precise",
version: "v1",
expected: false,
},
{
name: "three component version - precise",
version: "v1.2.3",
expected: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
v := parseVersion(tt.version)
if v == nil {
t.Fatalf("Failed to parse version: %s", tt.version)
}

result := v.isPreciseVersion()
if result != tt.expected {
t.Errorf("isPreciseVersion() for %q = %v, want %v", tt.version, result, tt.expected)
}
})
}
}

func TestPreciseVersionPreference(t *testing.T) {
// Test that when comparing equal versions, precise versions are preferred
v6 := parseVersion("v6")
v600 := parseVersion("v6.0.0")

if v6 == nil || v600 == nil {
t.Fatal("Failed to parse versions")
}

// They should parse to the same major.minor.patch
if v6.major != v600.major || v6.minor != v600.minor || v6.patch != v600.patch {
t.Errorf("v6 and v6.0.0 should parse to same major.minor.patch, got v6=%+v, v600=%+v", v6, v600)
}

// v6.0.0 should be precise, v6 should not
if !v600.isPreciseVersion() {
t.Error("v6.0.0 should be precise")
}

if v6.isPreciseVersion() {
t.Error("v6 should not be precise")
}

// Neither should be considered "newer" than the other
if v6.isNewer(v600) {
t.Error("v6 should not be newer than v6.0.0")
}

if v600.isNewer(v6) {
t.Error("v6.0.0 should not be newer than v6")
}
}
18 changes: 18 additions & 0 deletions pkg/cli/update_actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,15 @@ func getLatestActionRelease(repo, currentVersion string, allowMajor, verbose boo
if latestCompatibleVersion == nil || releaseVer.isNewer(latestCompatibleVersion) {
latestCompatible = release
latestCompatibleVersion = releaseVer
} else if !releaseVer.isNewer(latestCompatibleVersion) &&
releaseVer.major == latestCompatibleVersion.major &&
releaseVer.minor == latestCompatibleVersion.minor &&
releaseVer.patch == latestCompatibleVersion.patch {
// If versions are equal, prefer the more precise one (e.g., "v6.0.0" over "v6")
if releaseVer.isPreciseVersion() && !latestCompatibleVersion.isPreciseVersion() {
latestCompatible = release
latestCompatibleVersion = releaseVer
}
}
}

Expand Down Expand Up @@ -301,6 +310,15 @@ func getLatestActionReleaseViaGit(repo, currentVersion string, allowMajor, verbo
if latestCompatibleVersion == nil || releaseVer.isNewer(latestCompatibleVersion) {
latestCompatible = release
latestCompatibleVersion = releaseVer
} else if !releaseVer.isNewer(latestCompatibleVersion) &&
releaseVer.major == latestCompatibleVersion.major &&
releaseVer.minor == latestCompatibleVersion.minor &&
releaseVer.patch == latestCompatibleVersion.patch {
// If versions are equal, prefer the more precise one (e.g., "v6.0.0" over "v6")
if releaseVer.isPreciseVersion() && !latestCompatibleVersion.isPreciseVersion() {
latestCompatible = release
latestCompatibleVersion = releaseVer
}
}
}

Expand Down
Loading