All checks were successful
check / check (pull_request) Successful in 2m37s
No tag could be cut from this repo at all. Three independent blockers. goreleaser was configured for GitHub while the repo lives on Gitea: .goreleaser.yaml had a release: block but no gitea_urls:, so goreleaser defaulted to the GitHub API and a release would have failed or published somewhere nobody is looking. It now points at https://git.eeqj.de/api/v1. The version was a hardcoded Makefile constant, VERSION := 1.0.0-rc.1, so every local build claimed to be a release candidate that had never been tagged and did not exist, while git tag -l was empty and internal/globals defaulted to dev. The version now comes from git, via the new script/version: the exact tag with a leading v stripped when HEAD is on one (so a make build and a goreleaser build of the same commit report the same string, and it matches the archive names), otherwise dev-<12-char sha>, with -dirty appended in either case when tracked files are modified. Untracked files are not counted, matching git describe --dirty. goreleaser's snapshot template gets the same treatment: it was {{ incpatch .Version }}-next, which manufactures a release number from the last tag and, with no tags at all, from goreleaser's fabricated v0.0.0. That change had one non-obvious consequence. internal/cli/version.go gated its "this is a development build" notice on the version being exactly "dev", so as soon as untagged builds carried a commit sha the notice would have gone silent and an unreleased binary would have read as a release. The gate is now globals.IsDevVersion, a predicate over a string rather than a comparison against a global so that it can be tested, and it is tested at the boundary that matters: dev-<sha> and its -dirty variant are development builds, 1.0.0-dev and 1.0.0-rc.1 are not. The command writes to cmd.OutOrStdout() so its output can be asserted on at all. Releases now come from CI rather than a workstation: a tag-triggered .gitea/workflows/release.yml, with fetch-depth: 0 because a shallow checkout has no tags and would silently mislabel the release, and with the RELEASE_TOKEN repository secret passed as GITEA_TOKEN (documented in README.md; the runner's automatic token is deliberately not used, since it is not guaranteed to carry release write scope). script/release unsets any GITHUB_TOKEN or GITLAB_TOKEN it finds, because goreleaser picks its forge from whichever token variable is set and refuses to run when it sees more than one -- an unrelated runner token must not get to decide where these artifacts are published. make release and make release-snapshot were the last two Makefile targets that were not shims; they now call script/release and script/release-snapshot, which resolve goreleaser the way script/lint resolves the linter -- a PATH binary is accepted only at the pinned version, never as a silent fallback. script/bootstrap installs it from a sha256-verified GitHub release archive per REPO_POLICIES.md, through a separate script/install-goreleaser: separate because script/bootstrap hard-fails without a usable Docker daemon by design, and the release runner needs goreleaser without needing Docker. dist/ and .tool/ are gitignored and excluded from the Docker build context. Verified by running it: make release-snapshot produces the four linux,darwin x amd64,arm64 archives plus checksums.txt, and the binary from dist/ reports dev-<sha> with the development-build notice. Tag handling was exercised in a throwaway repository; no tag was created here, since that is the owner's call. Signing, SBOM, reproducible builds, shell completions and a man page remain out of scope.
74 lines
2.5 KiB
Bash
Executable File
74 lines
2.5 KiB
Bash
Executable File
#!/bin/sh
|
|
# script/version: output the version string to bake into the binary.
|
|
# Our own extension to scripts-to-rule-them-all, and the single source
|
|
# of truth for the version: the Makefile's LDFLAGS call this rather
|
|
# than carrying a hardcoded constant, which is what used to make every
|
|
# local build claim to be 1.0.0-rc.1 regardless of git state.
|
|
#
|
|
# The rules, in order:
|
|
#
|
|
# HEAD is exactly on an annotated or lightweight tag
|
|
# -> that tag, with a leading "v" stripped
|
|
# anything else
|
|
# -> "dev-<12 chars of HEAD>"
|
|
# not a git checkout at all (release tarball, `go install`)
|
|
# -> "dev"
|
|
#
|
|
# Either of the first two gains a "-dirty" suffix when tracked files
|
|
# have uncommitted changes, because a modified checkout of v1.0.0 is
|
|
# not v1.0.0. Untracked files are ignored, matching `git describe
|
|
# --dirty`: a stray scratch file does not change what was compiled.
|
|
#
|
|
# The "v" is stripped so that a `make` build and a goreleaser build of
|
|
# the same tagged commit report the *same* string: goreleaser's
|
|
# {{ .Version }} is the tag without the prefix, and the release archive
|
|
# names are built from it. A tag named `v1.0.0` therefore produces
|
|
# `vaultik 1.0.0`, matching `vaultik_1.0.0_linux_amd64.tar.gz`.
|
|
#
|
|
# Nothing here ever invents a version number. An untagged build says so
|
|
# and names the commit it was built from; it does not round up to the
|
|
# nearest plausible release.
|
|
set -eu
|
|
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
|
|
|
# Length of the commit prefix in a dev version. Matches
|
|
# globals.ShortCommit, so `vaultik version` shows the same 12 chars in
|
|
# its version line and its commit line.
|
|
SHORT_LEN=12
|
|
|
|
main() {
|
|
cd "$ROOT"
|
|
|
|
if ! git rev-parse --git-dir >/dev/null 2>&1; then
|
|
echo "dev"
|
|
return 0
|
|
fi
|
|
|
|
dirty=""
|
|
if [ -n "$(git status --porcelain --untracked-files=no 2>/dev/null)" ]; then
|
|
dirty="-dirty"
|
|
fi
|
|
|
|
# --exact-match so a *descendant* of a tag is not reported as that
|
|
# tag. Plain `git describe --tags` would call a commit 40 patches
|
|
# past v1.0.0 "v1.0.0-40-gabc1234", and the leading token of that is
|
|
# a released version the build is not.
|
|
tag="$(git describe --tags --exact-match HEAD 2>/dev/null || true)"
|
|
if [ -n "$tag" ]; then
|
|
echo "${tag#v}${dirty}"
|
|
return 0
|
|
fi
|
|
|
|
sha="$(git rev-parse "--short=$SHORT_LEN" HEAD 2>/dev/null || true)"
|
|
if [ -z "$sha" ]; then
|
|
# A repo with no commits at all.
|
|
echo "dev"
|
|
return 0
|
|
fi
|
|
|
|
echo "dev-${sha}${dirty}"
|
|
}
|
|
|
|
main "$@"
|