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 --- Makefile | 18 ++++---- go.mod | 1 + go.sum | 2 + version/gen/vgen.go | 115 +++++++++++++++++++++++++++++++++++++++++++++++ version/gen/vgen_test.go | 31 +++++++++++++ 5 files changed, 159 insertions(+), 8 deletions(-) create mode 100644 version/gen/vgen.go create mode 100644 version/gen/vgen_test.go diff --git a/Makefile b/Makefile index 2971c337..cfaad3d8 100644 --- a/Makefile +++ b/Makefile @@ -18,10 +18,12 @@ LINT_PROCS ?= $(shell nproc) endif COMMIT ?= `git rev-parse --short HEAD 2>/dev/null` -VERSION ?= `git describe --abbrev=0 --tags $(git rev-list --tags --max-count=1) 2>/dev/null | sed 's/v\(.*\)/\1/'` +VERSION ?= $(shell $(GO) run ./version/gen/vgen.go) -COMMIT_FLAG := -X `$(GO) list ./version`.GitCommit=$(COMMIT) -VERSION_FLAG := -X `$(GO) list ./version`.Version=$(VERSION) +VERSION_PATH := `$(GO) list ./version` +COMMIT_FLAG := -X $(VERSION_PATH).GitCommit=$(COMMIT) +VERSION_FLAG := -X $(VERSION_PATH).Version=$(VERSION) +GO_LDFLAGS ?= $(COMMIT_FLAG) $(VERSION_FLAG) GOOS ?= $(shell $(GO) version | sed 's/^.*\ \([a-z0-9]*\)\/\([a-z0-9]*\)/\1/') GOARCH ?= $(shell $(GO) version | sed 's/^.*\ \([a-z0-9]*\)\/\([a-z0-9]*\)/\2/') @@ -103,35 +105,35 @@ docker-images: gomplate.iid $(PREFIX)/bin/$(PKG_NAME)_%v5$(call extension,$(GOOS)): $(shell find $(PREFIX) -type f -name "*.go") GOOS=$(shell echo $* | cut -f1 -d-) GOARCH=$(shell echo $* | cut -f2 -d- ) GOARM=5 CGO_ENABLED=0 \ $(GO) build \ - -ldflags "-w -s $(COMMIT_FLAG) $(VERSION_FLAG)" \ + -ldflags "-w -s $(GO_LDFLAGS)" \ -o $@ \ ./cmd/$(PKG_NAME) $(PREFIX)/bin/$(PKG_NAME)_%v6$(call extension,$(GOOS)): $(shell find $(PREFIX) -type f -name "*.go") GOOS=$(shell echo $* | cut -f1 -d-) GOARCH=$(shell echo $* | cut -f2 -d- ) GOARM=6 CGO_ENABLED=0 \ $(GO) build \ - -ldflags "-w -s $(COMMIT_FLAG) $(VERSION_FLAG)" \ + -ldflags "-w -s $(GO_LDFLAGS)" \ -o $@ \ ./cmd/$(PKG_NAME) $(PREFIX)/bin/$(PKG_NAME)_%v7$(call extension,$(GOOS)): $(shell find $(PREFIX) -type f -name "*.go") GOOS=$(shell echo $* | cut -f1 -d-) GOARCH=$(shell echo $* | cut -f2 -d- ) GOARM=7 CGO_ENABLED=0 \ $(GO) build \ - -ldflags "-w -s $(COMMIT_FLAG) $(VERSION_FLAG)" \ + -ldflags "-w -s $(GO_LDFLAGS)" \ -o $@ \ ./cmd/$(PKG_NAME) $(PREFIX)/bin/$(PKG_NAME)_windows-%.exe: $(shell find $(PREFIX) -type f -name "*.go") GOOS=windows GOARCH=$* GOARM= CGO_ENABLED=0 \ $(GO) build \ - -ldflags "-w -s $(COMMIT_FLAG) $(VERSION_FLAG)" \ + -ldflags "-w -s $(GO_LDFLAGS)" \ -o $@ \ ./cmd/$(PKG_NAME) $(PREFIX)/bin/$(PKG_NAME)_%$(TARGETVARIANT)$(call extension,$(GOOS)): $(shell find $(PREFIX) -type f -name "*.go") GOOS=$(shell echo $* | cut -f1 -d-) GOARCH=$(shell echo $* | cut -f2 -d- ) GOARM=$(GOARM) CGO_ENABLED=0 \ $(GO) build \ - -ldflags "-w -s $(COMMIT_FLAG) $(VERSION_FLAG)" \ + -ldflags "-w -s $(GO_LDFLAGS)" \ -o $@ \ ./cmd/$(PKG_NAME) diff --git a/go.mod b/go.mod index 236cf219..107b57f6 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.18 require ( github.com/Masterminds/goutils v1.1.1 + github.com/Masterminds/semver v1.5.0 github.com/Shopify/ejson v1.3.3 github.com/aws/aws-sdk-go v1.44.219 github.com/docker/libkv v0.2.2-0.20180912205406-458977154600 diff --git a/go.sum b/go.sum index f91a2648..3e4c1f3c 100644 --- a/go.sum +++ b/go.sum @@ -473,6 +473,8 @@ github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXY github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= 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