Make the tagged-release path work on Gitea (closes #65)
All checks were successful
check / check (pull_request) Successful in 2m24s
All checks were successful
check / check (pull_request) Successful in 2m24s
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. The release workflow installs its own Go toolchain, pinned. goreleaser is not a compiler: it shells out to go for the before: hook and for all four cross-compiles, and nothing else in this repo puts a toolchain on the runner, since check.yml does all of its work inside the digest-pinned Dockerfile images. Without that step a tag either fails at the before-hook or, worse, ships binaries built by whatever unpinned Go the runner happens to carry -- the one unpinned thing in a release path whose every other input is hash-pinned, in a repo whose policy admits no exceptions and whose own script/release refuses a goreleaser that is not the pinned build. actions/setup-go is pinned by commit sha like the checkout above it, and reads its version from go.mod rather than restating it. An unobtainable version can no longer produce a binary at all. $(shell) discards exit status, so a missing or broken script/version left VERSION empty and the build went ahead and stamped nothing; the Makefile now stops with an error instead. IsDevVersion("") became true as the second line of defence, for a binary linked by something other than the Makefile: nothing that knows its version reports no version, so an empty version means the stamping failed, and a build that cannot be shown to be a release is not one. This is the same defect class as the notice that went silent above, one layer down. 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.
This commit is contained in:
21
Makefile
21
Makefile
@@ -1,7 +1,20 @@
|
||||
.PHONY: all bootstrap setup check test lint lint-fix fmt fmt-check build clean deps test-coverage local install release release-snapshot docker hooks
|
||||
|
||||
# Version number
|
||||
VERSION := 1.0.0-rc.1
|
||||
# Version number, derived from git by script/version -- the tag when
|
||||
# HEAD is on one, otherwise dev-<sha>. This used to be a hardcoded
|
||||
# constant, which meant every local build claimed to be a release that
|
||||
# had never been tagged.
|
||||
VERSION := $(shell script/version)
|
||||
|
||||
# $(shell) discards exit status, so a script/version that is missing,
|
||||
# non-executable or broken would otherwise leave VERSION empty and every
|
||||
# binary built here would print "vaultik " with no version at all. A
|
||||
# build that cannot determine what it is must not produce an artifact.
|
||||
ifeq ($(strip $(VERSION)),)
|
||||
$(error script/version produced no version string; a build that cannot \
|
||||
determine its version will not be made. Check that script/version exists \
|
||||
and is executable)
|
||||
endif
|
||||
|
||||
# Build variables
|
||||
GIT_REVISION := $(shell git rev-parse HEAD 2>/dev/null || echo "unknown")
|
||||
@@ -87,11 +100,11 @@ install: vaultik
|
||||
|
||||
# Build and publish release artifacts (linux/darwin × amd64/arm64) via goreleaser.
|
||||
release:
|
||||
goreleaser release --clean
|
||||
@script/release
|
||||
|
||||
# Dry-run a release build without publishing or tagging.
|
||||
release-snapshot:
|
||||
goreleaser release --clean --snapshot
|
||||
@script/release-snapshot
|
||||
|
||||
# Build Docker image.
|
||||
docker:
|
||||
|
||||
Reference in New Issue
Block a user