Make the tagged-release path work on Gitea (closes #65)
All checks were successful
check / check (push) Successful in 3m7s
All checks were successful
check / check (push) Successful in 3m7s
No tag could be cut at all: .goreleaser.yaml had no gitea_urls block, so
goreleaser defaulted to the GitHub API, and the repo has zero tags.
.goreleaser.yaml now points at git.eeqj.de. Version derives from git via
a new script/version - exact tag with any leading v stripped, else
dev-<12-char sha>, with a -dirty suffix when tracked files are modified -
replacing the hardcoded 1.0.0-rc.1 that every local build was stamping
regardless of git state. A tag-triggered .gitea/workflows/release.yml
runs goreleaser with a scoped token (RELEASE_TOKEN); script/bootstrap
installs a sha256-verified goreleaser, and make release / release-snapshot
become script shims like every other target.
Two fabrications were removed rather than merely replaced. goreleaser's
snapshot.version_template was `{{ incpatch .Version }}-next`, which
invents a release number from the last tag - and with no tags, from
goreleaser's own fabricated v0.0.0. And internal/cli/version.go gated its
development-build notice on Version == "dev" exactly, so the moment
untagged builds carried a sha that notice would have gone silent and an
unreleased binary would have read as a release. Replaced with a tested
IsDevVersion predicate, and closed at both layers: the Makefile now
refuses to build when script/version yields nothing, and an empty version
counts as a development build - reachable today via
`docker build --build-arg VERSION=`.
The release workflow installs Go from a sha-pinned actions/setup-go
(v5.6.0) using go-version-file, so the compiler that produces released
binaries is pinned like every other external reference. Without it the
first tag push would either fail at goreleaser's before-hook or compile
the published artifacts with whatever unpinned Go the runner happened to
carry - the one unpinned thing in a release path that already refuses an
unpinned goreleaser.
Known gap: the Go tarball setup-go fetches is version-pinned but not
checksum-verified against a value in this repo, unlike the goreleaser
install and the Dockerfile digest.
This commit was merged in pull request #104.
This commit is contained in:
@@ -3,14 +3,23 @@
|
||||
package globals
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Appname is the application name, populated from main().
|
||||
var Appname = "vaultik" //nolint:gochecknoglobals // set via -ldflags at build time
|
||||
|
||||
// DevVersion is the version a binary reports when it was not built
|
||||
// from a tagged commit. script/version emits either this exact string
|
||||
// (outside a git checkout) or this string followed by "-" and the
|
||||
// commit it was built from, and goreleaser's snapshot template matches
|
||||
// that shape. It is deliberately not a number: a build that is not a
|
||||
// release must not name itself like one.
|
||||
const DevVersion = "dev"
|
||||
|
||||
// Version is the application version, populated from main().
|
||||
var Version = "dev" //nolint:gochecknoglobals // set via -ldflags at build time
|
||||
var Version = DevVersion //nolint:gochecknoglobals // set via -ldflags at build time
|
||||
|
||||
// Commit is the git commit hash, populated from main().
|
||||
var Commit = "unknown" //nolint:gochecknoglobals // set via -ldflags at build time
|
||||
@@ -24,6 +33,9 @@ const Author = "Jeffrey Paul <sneak@sneak.berlin>"
|
||||
// Homepage is the canonical URL for vaultik.
|
||||
const Homepage = "https://sneak.berlin/go/vaultik"
|
||||
|
||||
// ReleasesURL is where tagged release artifacts are published.
|
||||
const ReleasesURL = "https://git.eeqj.de/sneak/vaultik/releases"
|
||||
|
||||
// License is the SPDX identifier for the project license.
|
||||
const License = "MIT"
|
||||
|
||||
@@ -47,6 +59,21 @@ func New() (*Globals, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// IsDevVersion reports whether v names a development build rather than
|
||||
// a release. Both "dev" and "dev-<sha>" (and its "-dirty" variant)
|
||||
// count: a caller that compares against "dev" exactly would treat every
|
||||
// commit-stamped development build as a release.
|
||||
//
|
||||
// The empty string counts too. Nothing that knows its version reports
|
||||
// no version, so an empty Version means the stamping failed, and the
|
||||
// safe reading of "we could not establish that this is a release" is
|
||||
// that it is not one. The Makefile refuses to build at all in that
|
||||
// case; this is the second line of defence, for a binary linked by
|
||||
// something other than the Makefile.
|
||||
func IsDevVersion(v string) bool {
|
||||
return v == "" || v == DevVersion || strings.HasPrefix(v, DevVersion+"-")
|
||||
}
|
||||
|
||||
// shortCommitLen is the number of commit-hash characters ShortCommit keeps.
|
||||
const shortCommitLen = 12
|
||||
|
||||
|
||||
@@ -32,3 +32,56 @@ func TestGlobalsNew(t *testing.T) {
|
||||
t.Error("Commit should not be empty")
|
||||
}
|
||||
}
|
||||
|
||||
// TestIsDevVersion covers the boundary that matters: everything
|
||||
// script/version and goreleaser's snapshot template can emit for an
|
||||
// untagged build must be recognised as a development build, and a real
|
||||
// tag must not be. A plain equality check against "dev" used to decide
|
||||
// this, which classified every commit-stamped dev build as a release.
|
||||
func TestIsDevVersion(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cases := []struct {
|
||||
version string
|
||||
want bool
|
||||
}{
|
||||
// What an untagged build produces.
|
||||
{"dev", true},
|
||||
{"dev-b6e4a218a39e", true},
|
||||
{"dev-b6e4a218a39e-dirty", true},
|
||||
// What a tagged build produces (script/version strips the
|
||||
// leading "v", matching goreleaser's .Version).
|
||||
{"1.0.0", false},
|
||||
{"0.1.0", false},
|
||||
{"1.0.0-rc.1", false},
|
||||
{"v1.0.0", false},
|
||||
// A release must not be mistaken for a dev build just because
|
||||
// the string happens to contain "dev".
|
||||
{"1.0.0-dev", false},
|
||||
{"developer", false},
|
||||
// A binary with no version string at all did not get stamped,
|
||||
// which is a build failure, not a release. It must never print
|
||||
// as one. The Makefile refuses to build when script/version
|
||||
// yields nothing; this covers a binary linked some other way.
|
||||
{"", true},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
if got := globals.IsDevVersion(tc.version); got != tc.want {
|
||||
t.Errorf("IsDevVersion(%q) = %v, want %v", tc.version, got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestDefaultVersionIsDev pins the linker-flag contract: an unstamped
|
||||
// binary (no -ldflags at all, which is what `go build ./...` and `go
|
||||
// install` produce) must report itself as a development build rather
|
||||
// than as some default release number.
|
||||
func TestDefaultVersionIsDev(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if !globals.IsDevVersion(globals.DevVersion) {
|
||||
t.Errorf("DevVersion %q is not recognised as a dev version",
|
||||
globals.DevVersion)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user