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
28 changes: 6 additions & 22 deletions v4/semver.go
Original file line number Diff line number Diff line change
Expand Up @@ -470,21 +470,19 @@ func (v versionExtension) Compare(o versionExtension) int {

// 2. Handle Numeric vs Alphanumeric
// Identify segments containing pre-release identifiers (rc, alpha, beta).
isPreReleaseLabel := func(s string) bool {
sl := strings.ToLower(s)
return strings.Contains(sl, "rc") || (strings.Contains(sl, "-") &&
(strings.Contains(sl, "alpha") || strings.Contains(sl, "beta")))
isStabilityLabel := func(s string) bool {
return strings.Contains(s, "-")
}

if v.IsNum && !o.IsNum {
if isPreReleaseLabel(o.VersionStr) {
return 1 // Stability Priority: Stable > Pre-release
if isStabilityLabel(o.VersionStr) {
return 1 // Number wins against an RC/Alpha/Beta string
}
return -1 // Standard SemVer: Number < String
}
if !v.IsNum && o.IsNum {
if isPreReleaseLabel(v.VersionStr) {
return -1 // Stability Priority: Pre-release < Stable
if isStabilityLabel(v.VersionStr) {
return -1 // RC/Alpha/Beta string loses against a Number
}
return 1 // Standard SemVer: String > Number
}
Expand All @@ -494,20 +492,6 @@ func (v versionExtension) Compare(o versionExtension) int {
return 0
}

// Pre-release marker check for string-vs-string
isPre := func(s string) bool {
sl := strings.ToLower(s)
return strings.Contains(sl, "rc") || strings.Contains(sl, "alpha") || strings.Contains(sl, "beta")
}

preV, preO := isPre(v.VersionStr), isPre(o.VersionStr)
if preV != preO {
if preV {
return -1
}
return 1
}

// Natural sort fallback for generic segments (e.g. "9-fips" vs "10-fips")
if naturalLess(v.VersionStr, o.VersionStr) {
return -1
Expand Down
10 changes: 10 additions & 0 deletions v4/semver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,16 @@ func TestEdgeCases_NaturalSortAndMetadata(t *testing.T) {

// 3. Mixed Alphanumeric: abc2 should be less than abc10
{"1.0.0+abc2", "1.0.0+abc10", -1, "Natural sort: abc2 should be less than abc10"},

// 4. Vendir Compatibility (The new case pre < rc)
{"0.0.1-pre.1", "0.0.1-rc.0", -1, "Vendir: pre < rc alphabetically"},

// 5. Standard SemVer: Numeric segments are always less than alphanumeric ones
// Compares segment '1' (Numeric) vs segment 'beta' (Alphanumeric)
{"1.0.0-alpha.1", "1.0.0-alpha.beta", -1, "Standard: numeric < alphanumeric"},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the comparison for alphanumeric vs alpha numeric .

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected. Updated the description to clarify this compares a numeric segment (1) vs an alphanumeric segment (beta) per SemVer precedence.


// 6. Stability Check: Ensure alpha/beta without hyphens follow standard rules
{"1.0.0-beta", "1.0.0-rc", -1, "Standard: beta < rc alphabetically as segments have no internal hyphens"},
}

for _, tt := range tests {
Expand Down