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:
65
TODO.md
65
TODO.md
@@ -14,10 +14,73 @@ pre-1.0
|
||||
|
||||
# Next Step
|
||||
|
||||
Define remaining scope for a first tagged release and cut v0.1.0.
|
||||
Define the remaining scope for the first tagged release under the 1.0.0
|
||||
milestone, then cut that tag. The mechanism to cut it now exists and is
|
||||
exercised; what is left is the scope decision, which is the owner's.
|
||||
This step deliberately names one version number: it previously said
|
||||
"cut v0.1.0" while the `Makefile` baked in `1.0.0-rc.1` and the issue
|
||||
milestone said 1.0.0, and three different answers to "what is the next
|
||||
release" is exactly the contradiction
|
||||
[issue #65](https://git.eeqj.de/sneak/vaultik/issues/65) was filed over.
|
||||
|
||||
# Completed Steps
|
||||
|
||||
- 2026-08-09: Made the tagged-release path actually work on Gitea
|
||||
([issue #65](https://git.eeqj.de/sneak/vaultik/issues/65)). Three
|
||||
independent blockers, one of which was the whole
|
||||
release: `.goreleaser.yaml` had no `gitea_urls:` block, so goreleaser
|
||||
defaulted to the GitHub API and a `goreleaser release` from this repo
|
||||
would have failed or published where nobody is looking. It now points
|
||||
at `https://git.eeqj.de/api/v1`. The version is the second: it was a
|
||||
hardcoded `VERSION := 1.0.0-rc.1` in the `Makefile`, 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`. Version now comes from git via the new
|
||||
`script/version` — the exact tag with a leading `v` stripped (so a
|
||||
`make` build and a goreleaser build of one 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 deliberately not counted, matching
|
||||
`git describe --dirty`. The same honesty was owed by the snapshot
|
||||
path: `snapshot.version_template` 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`; it now emits the
|
||||
same `dev-<sha>`. The one non-obvious consequence is that
|
||||
`internal/cli/version.go` gated its "this is a development build"
|
||||
notice on the version being exactly `dev`, so the moment untagged
|
||||
builds began carrying a commit sha that notice would have gone silent
|
||||
and an unreleased binary would have read as a release — the gate is
|
||||
now `globals.IsDevVersion`, which is a predicate over a string rather
|
||||
than a comparison against a global precisely so it can be tested, and
|
||||
it is tested at the boundary (`1.0.0-dev` is a release, `dev-<sha>`
|
||||
is not). Release automation is the third blocker: a tag-triggered
|
||||
`.gitea/workflows/release.yml` runs the build in CI rather than from
|
||||
a laptop, 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 not used because it
|
||||
is not guaranteed to carry release write scope). `script/release`
|
||||
unsets any `GITHUB_TOKEN`/`GITLAB_TOKEN` it finds, since goreleaser
|
||||
chooses its forge from whichever token variable is set and refuses to
|
||||
run when it sees more than one — a runner-provided token must not get
|
||||
to decide where these artifacts are published. `make release` and
|
||||
`make release-snapshot`, the last two Makefile targets that were not
|
||||
shims, now call `script/release` and `script/release-snapshot`, which
|
||||
resolve goreleaser exactly the way `script/lint` resolves the linter:
|
||||
a `PATH` binary is used 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`, via 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. Verified by running
|
||||
the thing rather than reading it: `make release-snapshot` produced
|
||||
four archives and `checksums.txt`, and the linux/amd64 binary from
|
||||
`dist/` reports `dev-<sha>` with the development-build notice. Tag
|
||||
handling was exercised in a throwaway repository rather than by
|
||||
tagging this one; no tag was created here, since that is the owner's
|
||||
call. Signing, SBOM, reproducible builds, completions and a man page
|
||||
are out of scope by the issue.
|
||||
|
||||
- 2026-08-09: Isolated the lint cache per worktree and context-gated the
|
||||
native lint path (issues #99, #80). One defect seen twice:
|
||||
`script/lint` decided whether it could skip the pinned image by asking
|
||||
|
||||
Reference in New Issue
Block a user