Files
narratio/docs/release.md

5.7 KiB

Releasing Narratio

This is the maintainer runbook for the Release Policy. The source release completes when the intended tag is successfully pushed to origin; binary delivery is a separate asynchronous status.

Prepare the candidate

Use main and the authoritative Git remote origin. Install Git, a POSIX shell, standard Unix build tools, and Go 1.26. Have the selected Go modules available before offline validation. Git access must permit fetch and tag push. Application-provider credentials are not required; Gitea delivery credentials belong to CI.

Choose an unused stable vMAJOR.MINOR.PATCH under the compatibility rules. Narratio is past v1.0.0, so intentional CLI or configuration breaks require a major release. Update affected canonical documentation with the change. Write the matching docs/releases/vMAJOR.MINOR.PATCH.md with a short summary and any relevant compatibility impact or upgrade action; choose sections to suit the release.

End that checked-in note with these three links, replacing the version in each URL with the intended tag. The tag need not exist remotely yet. Check that COPYRIGHT, LICENSE, and docs/oss/attribution.md are present in the candidate. The tag CI reuses the checked-in note as the hosted release body.

[COPYRIGHT](https://gitea.maximumdirect.net/eric/narratio/src/tag/vMAJOR.MINOR.PATCH/COPYRIGHT) | [LICENSE](https://gitea.maximumdirect.net/eric/narratio/src/tag/vMAJOR.MINOR.PATCH/LICENSE) | [ATTRIBUTION](https://gitea.maximumdirect.net/eric/narratio/src/tag/vMAJOR.MINOR.PATCH/docs/oss/attribution.md)

Retire completed roadmaps included in the release while preserving planned or deferred work and repairing affected links. Review the change through the ordinary development workflow for unintended files, credentials, private data, and documentation accuracy. Commit and push the candidate to origin/main before tagging; record its exact commit if needed:

git rev-parse HEAD

Publish

From a clean main checkout at the pushed candidate, run one command:

scripts/release.sh vMAJOR.MINOR.PATCH

It fetches origin/main and tags; requires local HEAD to equal origin/main; checks the committed note and unused version; runs the candidate checker once; then repeats cheap mutable-state guards before creating an unsigned lightweight tag at the recorded commit. It verifies the tag target and pushes only refs/tags/vMAJOR.MINOR.PATCH:refs/tags/vMAJOR.MINOR.PATCH. It does not commit, push main, force updates, or publish all tags.

The checker runs go mod tidy -diff, tracked Go formatting and diff whitespace checks, one go test -mod=readonly -race -count=1 ./... full suite, and go vet -mod=readonly ./.... Its asset builder cross-builds Linux amd64, Linux arm64, and best-effort macOS arm64, then checks the embedded version on a host binary. The macOS cross-build proves compilation, not native runtime behavior. Owned Go commands run with GOWORK=off; tests, vet, and builds use readonly module mode. The deterministic suite includes documentation and maintained-example checks. The command does not contact application services or Gitea and does not wait for CI.

A successful tag push is the source-release completion point. The command prints the tag and commit and exits without a separate network read-back. For optional diagnosis before publication, run scripts/check-release-candidate.sh vMAJOR.MINOR.PATCH; publication will validate the candidate again, so this is not a required preparation step.

Artifact delivery

Tag-triggered .woodpecker/release.yml independently validates the tagged source, builds the same three targets, and publishes these Gitea downloads:

  • narratio-vMAJOR.MINOR.PATCH-linux-amd64
  • narratio-vMAJOR.MINOR.PATCH-linux-arm64
  • narratio-vMAJOR.MINOR.PATCH-darwin-arm64 (best effort)
  • SHA256SUMS

The builder embeds the tag version and checks host version output. CI generates checksums and uses non-overwriting publication settings. It does not select versions, change the source, or move tags. No image or package registry output is declared. Tag publication is not proof that these asynchronous downloads are available.

Failure and recovery

If validation fails before tagging, correct and commit the candidate, push it to main, and rerun the publication command. If the tag push reports failure, its outcome may be ambiguous: keep the local tag and inspect the exact refs/tags/vMAJOR.MINOR.PATCH at origin before declaring success or retrying. A reachable matching remote tag at the recorded commit establishes publication; a confirmed absent tag permits investigation of the transport failure. If origin cannot be inspected, publication status is unknown. Do not move, overwrite, or automatically retry the tag. Remove a local tag only after confirming it was never published or used by a release channel.

A transient CI or delivery failure can be retried from the same immutable tag. Missing assets may be added later if they match the tagged source and any published checksum manifest; do not overwrite existing binaries, checksums, or release-note contents. A source/content defect, or delivery that cannot be corrected without replacement, requires a new suitable version and matching note. Leave the original release intact.

Optional consumer inspection may compare the tag's remote commit with the recorded candidate, check the Woodpecker delivery job and hosted Gitea note, download the assets into an empty directory, run sha256sum --check SHA256SUMS (or shasum -a 256 --check SHA256SUMS on macOS), and run the matching host binary's version command. This is separate delivery observation, never a source-release gate.