Files
Gitea-Tools/docs/release-version-sop.md
T
sysadmin b1cea2a189 docs: add release/version process SOP (#68)
Add docs/release-version-sop.md: operator SOP for cutting a versioned
release — master-based flow, SemVer bump decision, version-bump PR prep,
required pre-release checks, scripts/release-tag policy (safe-by-default,
master-only, clean-tree, tag-after-merge), who may merge/tag, self-review/
self-merge restrictions, status:in-progress handling, worktree cleanup, and
an explicit do-not list. Kept distinct from docs/release-workflows.md
(future release-mcp orchestrator). Link from README.

Documentation only; no code behavior changed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 13:06:00 -04:00

6.8 KiB

Release / Version Process SOP

Operator standard operating procedure for cutting a versioned release of Gitea-Tools: version bump, checks, merge, tag, and cleanup.

Scope. This is the human/operator SOP. It is deliberately distinct from release-workflows.md, which describes the future release-mcp orchestrator boundary (a coordination concept), not the day-to-day tagging process. When they disagree, this document governs how a release is actually cut today.


1. Branch flow

The repo is master-based. Releases are cut from master; there is no separate dev/release branch unless and until that is explicitly introduced and this SOP is updated to match. All work lands on master via reviewed PRs from short-lived, issue-linked branches (e.g. docs/issue-68-...).

2. Where "the version" lives

There is no VERSION file and no CHANGELOG file in the repo today. The released version is expressed only as an annotated git tag of the form vMAJOR.MINOR.PATCH (existing tags: v1.0.0, v1.0.1). Release notes are carried as the annotated tag's message (via --notes-file), not a tracked changelog.

Do not confuse this with SUPPORTED_VERSION in gitea_config.py — that is the config-schema version, unrelated to the application release version.

If a VERSION/CHANGELOG file is added later, update this SOP to list it under "files to update".

3. Deciding the version bump (SemVer)

Pick the bump against the last tag using semantic-versioning intent:

  • PATCH (v1.0.1 → v1.0.2): bug fixes, docs, tests, internal cleanups — no change to tool names, parameters, return payloads, or behavior.
  • MINOR (v1.0.1 → v1.1.0): backward-compatible additions — new MCP tool, new optional parameter, new script, additive behavior.
  • MAJOR (v1.1.0 → v2.0.0): backward-incompatible changes — renamed or removed tools, changed return-payload shape, changed default behavior, or a tightened safety gate that rejects previously-accepted input.

When unsure between two levels, choose the higher one.

4. Preparing a version-bump / release PR

Releases are still gated by the normal issue-first, PR-reviewed flow.

  1. Open (or use) a tracking issue for the release and claim it with status:in-progress (see §9).
  2. Create an isolated, issue-linked branch + worktree from latest master (e.g. chore/issue-63-v1.1.0). Never commit directly to master.
  3. Include in the PR:
    • Any code/docs changes that belong to the release.
    • The release notes for the annotated tag (draft them in the PR body or a notes file you will pass to scripts/release-tag --notes-file).
    • If a VERSION/CHANGELOG file exists at that time, its update.
  4. Open the PR targeting master.

The tag is not created in the PR. Tagging happens only after merge (§6).

5. Required checks before release

Run all of these green before merging the release PR and before tagging:

python3 -m py_compile mcp_server.py
python3 -m py_compile manage_labels.py
bash -n scripts/clear-provenance
./venv/bin/python -m pytest tests/ -q
git diff --check

Plus a secret sweep (there is no third-party scanner wired in; do a staged-diff sweep — see developer-testing-guidelines.md §7):

git diff --cached | grep -nEi "authorization: (basic|bearer)|password[:=]|token=[A-Za-z0-9]" || echo "clean"

scripts/release-tag also runs the test suite itself before tagging (unless --skip-tests is passed), so tests are enforced twice by default.

6. Running scripts/release-tag

Tag only after the release PR is merged to master. scripts/release-tag enforces the tagging policy and is safe by default (creates nothing on a dry-run; never pushes without --push).

Before it tags, it requires all of:

  • version matches vMAJOR.MINOR.PATCH (SemVer);
  • fetch --prune has run;
  • you are on master;
  • the worktree is clean (no uncommitted changes);
  • local master equals <remote>/master;
  • HEAD is that same commit (the commit is present on remote master);
  • the tag does not already exist locally or on the remote;
  • the test suite passes (unless --skip-tests, which warns).

Typical sequence:

# 1. Dry-run to confirm the plan (changes nothing)
scripts/release-tag --dry-run v1.1.0

# 2. Create the annotated tag locally, with release notes
scripts/release-tag v1.1.0 --notes-file /path/to/release-notes.md

# 3. Push the tag only when ready
scripts/release-tag v1.1.0 --notes-file /path/to/release-notes.md --push

Env injection points (mainly for CI/tests): RELEASE_TAG_REMOTE (default prgs), RELEASE_TAG_TEST_CMD (default ./venv/bin/python -m pytest tests/ -q).

7. Who may merge / tag

  • The release PR must be merged by someone other than its author — the author-cannot-merge safety gate applies to releases exactly as to any other PR.
  • Merge uses the gated gitea_merge_pr workflow; CLI/legacy merge is disabled.
  • Whoever tags must operate on clean master synced to the remote (enforced by scripts/release-tag). Tagging is an operator action performed after merge.

8. Self-review / self-merge restrictions

Release PRs are not exempt from the safety model:

  • No self-review — the author may not approve their own release PR.
  • No self-merge — a different eligible identity merges.
  • These gates are enforced by the MCP tooling and must not be bypassed.

9. Handling status:in-progress during release work

  • Claim the release tracking issue with status:in-progress before starting.
  • Keep it claimed while the release PR is open and under review.
  • On merge/close, the tracker-hygiene automation releases status:in-progress for issues the PR closes; if it remains after the release lands, release it explicitly. Do not leave a shipped release issue marked in-progress.

10. Branch / worktree cleanup after merge

After the release PR merges and the tag is pushed:

  • Delete the remote release branch (if repo policy allows).

  • Remove the local worktree and delete the local branch:

    git worktree remove branches/<release-worktree>
    git branch -d <release-branch>
    git worktree prune
    
  • Confirm the root repo is clean and on master synced to the remote.

11. What NOT to do

  • No direct commits to master. All changes land via reviewed PRs.
  • No force-push (to master or to tags).
  • No self-merge of a release PR.
  • No tagging before merge — tag only commits already on remote master.
  • No release from a dirty worktreescripts/release-tag refuses, and so should you.
  • No --skip-tests for a real release unless there is an explicit, documented reason.
  • No re-tagging / moving an existing tag — pick the next version instead.