Skip to content

Commit

Permalink
internal/semver: add SemverToGoTag
Browse files Browse the repository at this point in the history
Add SemverToGoTag, which reverses GoTagToSemver.
The exception is when converting a go tag to the semver would have
resulted in an invalid semver (such as go RC versions). GoTagToSemver
returns an empty string in that case, and as such is not reversible.

Change-Id: I8d68c2372261b1ec7ec8b72354ac1919ad24d6f6
Reviewed-on: https://go-review.googlesource.com/c/vuln/+/617396
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Zvonimir Pavlinovic <zpavlinovic@google.com>
  • Loading branch information
Maceo Thompson committed Oct 3, 2024
1 parent fd700f3 commit 1aec043
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 0 deletions.
45 changes: 45 additions & 0 deletions internal/semver/semver.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package semver

import (
"fmt"
"regexp"
"strings"

Expand Down Expand Up @@ -93,3 +94,47 @@ func GoTagToSemver(tag string) string {
}
return version
}

// This is a modified copy of pkgsite/internal/stlib:TagForVersion
func SemverToGoTag(v string) string {
// Special case: v1.0.0 => go1.
if v == "v1.0.0" {
return "go1"
}

goVersion := semver.Canonical(v)
prerelease := semver.Prerelease(goVersion)
versionWithoutPrerelease := strings.TrimSuffix(goVersion, prerelease)
patch := strings.TrimPrefix(versionWithoutPrerelease, semver.MajorMinor(goVersion)+".")
if patch == "0" && (semver.Compare(v, "v1.21.0") < 0 || prerelease != "") {
// Starting with go1.21.0, the first patch version includes .0.
// Prereleases do not include .0 (we don't do prereleases for other patch releases).
versionWithoutPrerelease = strings.TrimSuffix(versionWithoutPrerelease, ".0")
}
goVersion = fmt.Sprintf("go%s", strings.TrimPrefix(versionWithoutPrerelease, "v"))
if prerelease != "" {
i := finalDigitsIndex(prerelease)
if i >= 1 {
// Remove the dot.
prerelease = prerelease[:i-1] + prerelease[i:]
}
goVersion += prerelease
}
return goVersion
}

// finalDigitsIndex returns the index of the first digit in the sequence of digits ending s.
// If s doesn't end in digits, it returns -1.
func finalDigitsIndex(s string) int {
// Assume ASCII (since the semver package does anyway).
var i int
for i = len(s) - 1; i >= 0; i-- {
if s[i] < '0' || s[i] > '9' {
break
}
}
if i == len(s)-1 {
return -1
}
return i + 1
}
21 changes: 21 additions & 0 deletions internal/semver/semver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,27 @@ func TestGoTagToSemver(t *testing.T) {
}
}

func TestSemverToGoTag(t *testing.T) {
for _, test := range []struct {
v string
want string
}{
{"v1.19.0", "go1.19"},
{"v1.20.0-pre.4", "go1.20-pre4"},
{"v1.0.0", "go1"},
{"v1.20.0-rc.1", "go1.20-rc1"},
{"v1.20.0-beta.1", "go1.20-beta1"},
{"v1.20.0-alpha.1", "go1.20-alpha1"},
{"v1.20.0-alpha.1+incompatible", "go1.20-alpha1"},
{"v1.20.0-alpha.1-0.20220101230456-1234abcd", "go1.20-alpha.1-0.20220101230456-1234abcd"},
} {
got := SemverToGoTag(test.v)
if got != test.want {
t.Errorf("want %s; got %s", test.want, got)
}
}
}

func TestLess(t *testing.T) {
for _, test := range []struct {
v1 string
Expand Down

0 comments on commit 1aec043

Please sign in to comment.