Files
notarius/docs/release.md

6.1 KiB

Source Releases

This procedure is for maintainers publishing Notarius source releases. A release is an immutable lightweight vMAJOR.MINOR.PATCH tag on main together with its checked-in docs/releases/<tag>.md note. Tag CI validates that source candidate after publication; it does not publish or repair a release.

Notarius publishes no binaries, archives, checksums, signatures, containers, package-manager entries, or Gitea release objects. Windows is not supported. Do not create retrospective notes for the pre-procedure v0.1.0, v0.2.0, or v0.3.0 tags.

Select And Describe The Release

Choose an unused stable semantic version in the form vMAJOR.MINOR.PATCH. Prereleases are not supported. Before v1.0.0, a minor release may change a documented CLI, configuration, durable artifact, integration, or operating contract when its note explains the impact and required operator action. A patch release must not intentionally break those documented contracts within its minor line.

Create the version-matched note as part of the candidate. Every new note uses this structure, with concise, truthful content in each section:

# Notarius vMAJOR.MINOR.PATCH

This release ...

## Summary

## Compatibility

## Upgrade

## Changes

The note is a historical summary. Link to current canonical documentation for exact behavior, and update that documentation in the candidate rather than using the note as a substitute.

Prepare The Candidate

Set the selected release version and disable Go workspace use for every candidate command:

RELEASE_VERSION=vMAJOR.MINOR.PATCH
export RELEASE_VERSION GOWORK=off

Run the shared source-candidate checks from the repository. They cover module hygiene, tests, race tests, vet, builds, formatting, whitespace, maintained configuration validation, and the Linux and Darwin command-build matrix:

./scripts/check-release-source.sh "$RELEASE_VERSION"

Before committing, manually follow every changed local Markdown link and review the candidate for unintended files, generated output, credentials, or other unrelated changes. Commit the release note and all affected current documentation, then run the shared checker against that exact candidate. Push the candidate commit to main only after it succeeds. Record the exact commit only after that push:

RELEASE_COMMIT=$(git rev-parse 'HEAD^{commit}')
export RELEASE_COMMIT

For private-module installation, configure standard GOPRIVATE matching this module and ordinary Git authentication for the hosting service before running the verification below. The exact authentication mechanism belongs to the maintainer environment; never record credentials or environment dumps in a release note, command history, or repository file.

Guard And Publish The Tag

Fetch current remote references, then run this guard without editing the candidate. It requires main, a clean worktree and index, disabled workspace use, a stable release version, the recorded and pushed commit, a matching note, and unused local and remote tags:

git fetch origin main --tags

if ! printf '%s\n' "$RELEASE_VERSION" |
  grep -E -x 'v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)' >/dev/null
then
  printf '%s\n' "invalid release version: $RELEASE_VERSION" >&2
  exit 1
fi
test "$GOWORK" = off
test "$(git branch --show-current)" = main
test -z "$(git status --porcelain)"
test "$RELEASE_COMMIT" = "$(git rev-parse 'HEAD^{commit}')"
test "$RELEASE_COMMIT" = "$(git rev-parse 'origin/main^{commit}')"
test -s "docs/releases/$RELEASE_VERSION.md"
grep -F -x "# Notarius $RELEASE_VERSION" "docs/releases/$RELEASE_VERSION.md"
for heading in '## Summary' '## Compatibility' '## Upgrade' '## Changes'; do
  grep -F -x "$heading" "docs/releases/$RELEASE_VERSION.md"
done
if git rev-parse -q --verify "refs/tags/$RELEASE_VERSION" >/dev/null; then
  printf '%s\n' "local tag already exists: $RELEASE_VERSION" >&2
  exit 1
fi
if git ls-remote --exit-code --tags origin "refs/tags/$RELEASE_VERSION" >/dev/null 2>&1; then
  printf '%s\n' "remote tag already exists: $RELEASE_VERSION" >&2
  exit 1
fi

Create an explicitly lightweight tag against the guarded commit, verify its target, and push only that tag ref:

git -c tag.gpgSign=false tag "$RELEASE_VERSION" "$RELEASE_COMMIT"
test "$(git cat-file -t "$RELEASE_VERSION")" = commit
test "$(git rev-parse "$RELEASE_VERSION^{commit}")" = "$RELEASE_COMMIT"
git push origin "refs/tags/$RELEASE_VERSION:refs/tags/$RELEASE_VERSION"

Never use git push --tags, move a published tag, or delete a published tag.

Verify The Published Release

Confirm that the remote tag still points at the guarded commit and that the note is available from the tagged tree:

REMOTE_TAG_COMMIT=$(git ls-remote origin "refs/tags/$RELEASE_VERSION" | awk '{print $1}')
test "$REMOTE_TAG_COMMIT" = "$RELEASE_COMMIT"
git show "$RELEASE_VERSION:docs/releases/$RELEASE_VERSION.md" >/dev/null

Verify a fresh source installation and its diagnostic version. The temporary directory confines the installed command to this check:

release_verification_dir=$(mktemp -d)
trap 'rm -rf "$release_verification_dir"' 0 HUP INT TERM
mkdir -p "$release_verification_dir/bin"
GOWORK=off GOBIN="$release_verification_dir/bin" go install \
  "gitea.maximumdirect.net/eric/notarius/cmd/notarius@$RELEASE_VERSION"
test "$("$release_verification_dir/bin/notarius" --version)" = "notarius $RELEASE_VERSION"

An exact fresh checkout and GOWORK=off go build ./cmd/notarius is an equivalent source verification when local installation policy requires it. notarius --version is diagnostic only; downstream compatibility remains defined by the published receipt and artifact contracts.

Failure And Correction Policy

If candidate validation fails before publication, fix the candidate on main, rerun the shared checker, and repeat the guards. An unpublished local tag may be deleted after inspection.

If the remote tag or tag CI reveals a defect, leave the published tag intact. Fix the defect on main, choose a new patch version, write a new matching note, and repeat this procedure. Do not weaken tag immutability or add release assets as a workaround.