From 48a6546fbb4ecbef6b9fd2dda053964d47b0979a Mon Sep 17 00:00:00 2001 From: Dave Henderson Date: Sun, 12 Mar 2023 13:46:12 -0400 Subject: Generate prerelease versions Signed-off-by: Dave Henderson --- version/gen/vgen.go | 115 +++++++++++++++++++++++++++++++++++++++++++++++ version/gen/vgen_test.go | 31 +++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 version/gen/vgen.go create mode 100644 version/gen/vgen_test.go (limited to 'version') diff --git a/version/gen/vgen.go b/version/gen/vgen.go new file mode 100644 index 00000000..c6c1913b --- /dev/null +++ b/version/gen/vgen.go @@ -0,0 +1,115 @@ +// run as 'go run ./version/gen/vgen.go' + +package main + +import ( + "fmt" + "log" + "os/exec" + "strings" + + "github.com/Masterminds/semver" +) + +func main() { + descVer, err := describedVersion() + if err != nil { + log.Fatal(err) + } + + latest, err := latestTag() + if err != nil { + log.Fatal(err) + } + + ver, err := version(descVer, latest) + if err != nil { + log.Fatal(err) + } + + fmt.Println(ver.String()) +} + +func describedVersion() (*semver.Version, error) { + desc, err := runCmd("git describe --always") + if err != nil { + return nil, fmt.Errorf("git describe failed: %w", err) + } + + ver, err := semver.NewVersion(desc) + if err != nil { + return nil, err + } + + return ver, nil +} + +func version(descVer, latest *semver.Version) (*semver.Version, error) { + ver := *descVer + if ver.Prerelease() != "" { + ver = ver.IncPatch().IncPatch() + ver, _ = ver.SetPrerelease(descVer.Prerelease()) + ver, _ = ver.SetMetadata(descVer.Metadata()) + } else if ver.Metadata() != "" { + ver = ver.IncPatch() + ver, _ = ver.SetMetadata(descVer.Metadata()) + } + + // if we're on a release tag already, we're done + if descVer.Equal(&ver) { + return descVer, nil + } + + // If 'latest' is greater than 'ver', we need to skip to the next patch. + // If 'latest' is already a prerelease (i.e. if v5.0.0-pre was tagged), + // we should use + // If 'latest' is a prerelease, it's the same logic, except that we don't + // want to increment the patch version. + if latest.GreaterThan(&ver) || latest.Prerelease() != "" { + v := *latest + if v.Prerelease() == "" { + v = v.IncPatch() + } + v, _ = v.SetPrerelease(ver.Prerelease()) + v, _ = v.SetMetadata(ver.Metadata()) + + ver = v + } + + return &ver, nil +} + +func latestTag() (*semver.Version, error) { + // get the latest tag + tags, err := runCmd("git tag --list v*") + if err != nil { + return nil, fmt.Errorf("git tag failed: %w", err) + } + + // find the latest tag + var latest *semver.Version + for _, tag := range strings.Split(tags, "\n") { + ver, err := semver.NewVersion(tag) + if err != nil { + return nil, fmt.Errorf("parsing tag %q failed: %w", tag, err) + } + + if latest == nil || ver.GreaterThan(latest) { + latest = ver + } + } + + if latest == nil { + return nil, fmt.Errorf("no tags found") + } + + return latest, nil +} + +func runCmd(c string) (string, error) { + parts := strings.Split(c, " ") + //nolint:gosec + cmd := exec.Command(parts[0], parts[1:]...) + out, err := cmd.CombinedOutput() + return strings.TrimSpace(string(out)), err +} diff --git a/version/gen/vgen_test.go b/version/gen/vgen_test.go new file mode 100644 index 00000000..2bbc3e3a --- /dev/null +++ b/version/gen/vgen_test.go @@ -0,0 +1,31 @@ +package main + +import ( + "testing" + + "github.com/Masterminds/semver" + "github.com/stretchr/testify/require" +) + +func TestVersion(t *testing.T) { + testdata := []struct { + desc, latest string + expected string + }{ + {"v1.0.0", "", "1.0.0"}, + {"v1.0.0-1-gabcdef0", "v1.0.0", "1.0.1-1-gabcdef0"}, + {"v1.0.0-1-gabcdef0", "v2.3.4", "2.3.5-1-gabcdef0"}, + {"v1.0.0+123", "v2.3.4", "2.3.5+123"}, + } + + for _, td := range testdata { + var l *semver.Version + if td.latest != "" { + l = semver.MustParse(td.latest) + } + + ver, err := version(semver.MustParse(td.desc), l) + require.NoError(t, err) + require.Equal(t, td.expected, ver.String()) + } +} -- cgit v1.2.3