feat: scripts/release-tag automation helper (#50) #53

Merged
sysadmin merged 1 commits from feat/issue-50-release-tag-helper into master 2026-07-02 04:40:08 -05:00
Owner

Closes #50. Refs #48 (implements the deferred automation).

What

scripts/release-tag — automate the documented release checklist with every safety gate built in.

Gates / behavior

  • Requires a SemVer tag vMAJOR.MINOR.PATCH (validated before any git/network).
  • Fetch/prune first, then refuses: dirty worktree · non-master branch · local master ≠ remote master · HEAD not on remote master · existing local or remote tag of the same name.
  • Runs the full suite by default; --skip-tests is an explicit opt-out that prints a warning.
  • Creates an annotated tag (git tag -a) only — never lightweight.
  • Safe by default: no push unless --push; --dry-run prints planned actions and changes nothing. --notes-file <path> supplies the annotation message.
  • Prints commit / tag / tests_run / tag_created / tag_pushed.
  • Test/CI injection env: RELEASE_TAG_REMOTE, RELEASE_TAG_TEST_CMD.
scripts/release-tag --dry-run v0.4.0
scripts/release-tag v0.4.0 --notes-file /tmp/release-notes.md
scripts/release-tag v0.4.0 --notes-file /tmp/release-notes.md --push

Tests

tests/test_release_tag.py — 14 cases: valid dry-run · invalid version · dirty · 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 builds a throwaway repo with a local bare remote seeded by clone (no network, no pushing from this repo, no real tags) and stubs the test command via RELEASE_TAG_TEST_CMD.

Docs

scripts/release-tag referenced from docs/llm-workflow-runbooks.md, skills/llm-project-workflow/SKILL.md, and the release-tag.md template (script preferred; manual steps are the fallback).

Checks

  • bash -n scripts/release-tag clean.
  • Full suite (isolated worktree): 305 passed, 0 failures, 0 errors (JUnit XML).
  • git diff --check clean; secret scan clean.

Files changed

scripts/release-tag (new), tests/test_release_tag.py (new), docs/llm-workflow-runbooks.md, skills/llm-project-workflow/SKILL.md, skills/llm-project-workflow/templates/release-tag.md.

Process

Isolated worktree: ./scripts/worktree-start feat/issue-50-release-tag-helperbranches/feat-issue-50-release-tag-helper.


⚠️ Authored by me — do not self-merge. Needs review by another author.

Closes #50. Refs #48 (implements the deferred automation). ## What `scripts/release-tag` — automate the documented release checklist with every safety gate built in. ## Gates / behavior - Requires a SemVer tag `vMAJOR.MINOR.PATCH` (validated before any git/network). - Fetch/prune first, then refuses: dirty worktree · non-master branch · local `master` ≠ remote `master` · HEAD not on remote `master` · existing local **or** remote tag of the same name. - Runs the full suite by default; `--skip-tests` is an explicit opt-out that prints a warning. - Creates an **annotated** tag (`git tag -a`) only — never lightweight. - **Safe by default:** no push unless `--push`; `--dry-run` prints planned actions and changes nothing. `--notes-file <path>` supplies the annotation message. - Prints `commit / tag / tests_run / tag_created / tag_pushed`. - Test/CI injection env: `RELEASE_TAG_REMOTE`, `RELEASE_TAG_TEST_CMD`. ```bash scripts/release-tag --dry-run v0.4.0 scripts/release-tag v0.4.0 --notes-file /tmp/release-notes.md scripts/release-tag v0.4.0 --notes-file /tmp/release-notes.md --push ``` ## Tests `tests/test_release_tag.py` — 14 cases: valid dry-run · invalid version · dirty · 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 builds a **throwaway repo with a local bare remote seeded by clone** (no network, no pushing from this repo, no real tags) and stubs the test command via `RELEASE_TAG_TEST_CMD`. ## Docs `scripts/release-tag` referenced from `docs/llm-workflow-runbooks.md`, `skills/llm-project-workflow/SKILL.md`, and the `release-tag.md` template (script preferred; manual steps are the fallback). ## Checks - `bash -n scripts/release-tag` clean. - Full suite (isolated worktree): **305 passed, 0 failures, 0 errors** (JUnit XML). - `git diff --check` clean; secret scan clean. ## Files changed `scripts/release-tag` (new), `tests/test_release_tag.py` (new), `docs/llm-workflow-runbooks.md`, `skills/llm-project-workflow/SKILL.md`, `skills/llm-project-workflow/templates/release-tag.md`. ## Process Isolated worktree: `./scripts/worktree-start feat/issue-50-release-tag-helper` → `branches/feat-issue-50-release-tag-helper`. --- ⚠️ Authored by me — do **not** self-merge. Needs review by another author.
jcwalker3 added 1 commit 2026-07-02 04:38:00 -05:00
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>
jcwalker3 force-pushed feat/issue-50-release-tag-helper from c4e539c7f7 to 4e43347b2d 2026-07-02 04:38:00 -05:00 Compare
sysadmin reviewed 2026-07-02 04:40:07 -05:00
sysadmin left a comment
Owner

Approved after reviewer-profile validation. Checks passed: bash -n scripts/release-tag; targeted release-tag tests; full test suite; git diff --check; changed-file secret scan. No real tags were created or pushed.

Approved after reviewer-profile validation. Checks passed: bash -n scripts/release-tag; targeted release-tag tests; full test suite; git diff --check; changed-file secret scan. No real tags were created or pushed.
sysadmin merged commit 6089ec724a into master 2026-07-02 04:40:08 -05:00
Sign in to join this conversation.