feat: add scripts/release-tag automation helper (#50)
Automate the documented release-tag checklist (#48) without bypassing safety gates. scripts/release-tag: - Requires a SemVer tag (vMAJOR.MINOR.PATCH); validates before any git/network. - Fetch/prune first, then refuses: dirty worktree, non-master branch, local master != remote master, HEAD not on remote master, and an existing local or remote tag of the same name. - Runs the full suite by default; --skip-tests is an explicit opt-out that warns. - Creates an ANNOTATED tag (git tag -a), never lightweight. - Safe by default: no push unless --push; --dry-run prints planned actions and changes nothing. Supports --notes-file <path> for the annotation message. - Prints: commit, tag, tests_run, tag_created, tag_pushed. - Env injection points for testing/CI: RELEASE_TAG_REMOTE, RELEASE_TAG_TEST_CMD. tests/test_release_tag.py (14 cases): valid SemVer dry-run; invalid version; dirty worktree; non-master; master/remote mismatch; existing tag; missing notes-file; annotated-not-lightweight; no-push-without-flag; push-only-with-flag; notes-file message; --skip-tests warns; default runs tests (fail blocks tag, pass tags). Each test builds a throwaway repo with a LOCAL bare remote (cloned, not pushed) and stubs the test command — no network, no real tags, no pushing from the project repo. Docs: reference scripts/release-tag from the runbook, SKILL, and the release-tag template (script preferred; manual steps are the fallback). Full suite 305 passed / 0 failures; bash -n clean; git diff --check clean; no secrets. Closes #50. Refs #48. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -250,3 +250,9 @@ Release process (see [`templates/release-tag.md`](templates/release-tag.md)):
|
||||
6. Create the annotated tag on remote `master` with release notes.
|
||||
7. Push the tag.
|
||||
8. Create/update release notes if the forge supports it.
|
||||
|
||||
Where present, `scripts/release-tag` automates this with all gates built in
|
||||
(SemVer, fetch/prune, on-master, clean tree, local==remote master, HEAD on
|
||||
remote master, no duplicate tag, tests, annotated-only). Safe by default: no
|
||||
push without `--push`; `--dry-run` changes nothing; `--skip-tests` must be
|
||||
explicit and warns.
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
Copy, fill the `<...>` fields, and paste as the task prompt. Tagging is
|
||||
irreversible-ish and outward-facing — fail closed on any doubt.
|
||||
|
||||
> If the project ships `scripts/release-tag`, prefer it — it enforces every gate
|
||||
> below automatically and is safe by default (no push without `--push`,
|
||||
> `--dry-run` changes nothing):
|
||||
>
|
||||
> ```bash
|
||||
> scripts/release-tag --dry-run <vX.Y.Z>
|
||||
> scripts/release-tag <vX.Y.Z> --notes-file <path>
|
||||
> scripts/release-tag <vX.Y.Z> --notes-file <path> --push
|
||||
> ```
|
||||
>
|
||||
> The manual steps below are the fallback / what the script does.
|
||||
|
||||
```text
|
||||
Task: cut release <vX.Y.Z> from master.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user