|
1 | | -description: Cut a release — verify, bump version, push, publish a GitHub release, and validate the install/update path |
2 | | -argument-hint: "[patch|minor|major|X.Y.Z] [no-deploy]" |
3 | | -allowed-tools: Bash, Read, Edit, Write |
| 1 | +description: Cut a production-ready release with a minimal cross-platform install package |
| 2 | +argument-hint: "[patch|minor|major|X.Y.Z]" |
| 3 | +allowed-tools: Bash, PowerShell, Read, Edit, Write |
4 | 4 | --- |
5 | 5 |
|
6 | | -You are running the **full git-auto-sync release flow**. Follow the phases in order. |
7 | | -Treat every verification as a gate: if a step fails, **STOP and report** — do not tag, push, or publish the release. |
| 6 | +You are running the **git-auto-sync release runbook**. Execute these phases in order. |
| 7 | +Treat any failing check as a hard stop. Do not tag, push, or publish a release until every |
| 8 | +required gate passes. |
8 | 9 |
|
9 | 10 | Arguments: `$ARGUMENTS` |
10 | | -- First token = the bump: `patch` (default), `minor`, `major`, or an explicit `X.Y.Z`. |
11 | | -- If `no-deploy` appears anywhere, skip the optional deployment verification phase. |
| 11 | +- First token = `patch` (default), `minor`, `major`, or explicit `X.Y.Z`. |
12 | 12 |
|
13 | | -## Phase 0 — Preflight (abort on any problem) |
| 13 | +## Phase 0 — Preflight |
14 | 14 |
|
15 | | -1. Confirm the branch is `main` and the working tree is clean except for changes you are about to make. |
16 | | -2. `git fetch --tags origin` to ensure release tags are present locally. |
17 | | -3. Run the verification gate and require all green: |
18 | | - - `uv run pytest -q` |
19 | | - - `uv run ruff check .` |
20 | | - - `uv run ruff format --check git_auto_sync/ tests/` |
| 15 | +1. Confirm branch state and remote: |
| 16 | + |
| 17 | +```bash |
| 18 | +git remote -v |
| 19 | +git branch --show-current |
| 20 | +git status --short |
| 21 | +git fetch --all --prune |
| 22 | +git pull --ff-only origin main |
| 23 | +``` |
| 24 | + |
| 25 | +2. Make sure required release tooling is available: |
| 26 | + |
| 27 | +```bash |
| 28 | +command -v gh >/dev/null || { echo "Install gh first"; exit 1; } |
| 29 | +command -v uv >/dev/null || { echo "Install uv first"; exit 1; } |
| 30 | +command -v tar >/dev/null || { echo "Install tar first"; exit 1; } |
| 31 | +``` |
| 32 | + |
| 33 | +3. Fetch tags and run verification gates: |
| 34 | + |
| 35 | +```bash |
| 36 | +git fetch --tags origin |
| 37 | +uv run pytest -q |
| 38 | +uv run ruff check . |
| 39 | +uv run ruff format --check git_auto_sync/ tests/ |
| 40 | +``` |
| 41 | + |
| 42 | +4. Verify release payload files exist: |
| 43 | + |
| 44 | +```bash |
| 45 | +test -f install.sh |
| 46 | +test -f install.ps1 |
| 47 | +test -f pyproject.toml |
| 48 | +test -f git_auto_sync/__init__.py |
| 49 | +test -f uv.lock |
| 50 | +``` |
21 | 51 |
|
22 | 52 | ## Phase 1 — Version bump |
23 | 53 |
|
24 | | -1. Read current `version` from `pyproject.toml`. |
25 | | -2. Compute new version from bump argument (default `patch`). |
26 | | -3. Update `pyproject.toml` and refresh lockfile: |
27 | | - - `uv sync` |
28 | | -4. Commit exactly version files: |
29 | | - ```bash |
30 | | - git add pyproject.toml uv.lock |
31 | | - git commit -m "chore: bump version to X.Y.Z" |
32 | | - ``` |
33 | | - |
34 | | -## Phase 2 — Push |
35 | | - |
36 | | -`git push origin main`. |
37 | | - |
38 | | -## Phase 3 — GitHub release |
39 | | - |
40 | | -1. Resolve previous tag: `git describe --tags --abbrev=0 HEAD^` (after fetching tags). |
41 | | -2. Draft release notes from `git log <prevtag>..HEAD --no-merges` in repo style: |
42 | | - - Title: `vX.Y.Z — <short summary>` |
43 | | - - A short lead, then `## Fixed` / `## Changed` / `## Added` sections as warranted. |
44 | | - - Install one-liner: |
45 | | - `curl -fsSL https://raw.githubusercontent.com/OctopusGarage/git-auto-sync/main/install.sh | bash` |
46 | | - - `**Full Changelog**: https://github.com/OctopusGarage/git-auto-sync/compare/<prevtag>...vX.Y.Z` |
47 | | -3. Create release: |
48 | | - ```bash |
49 | | - gh release create vX.Y.Z --target main --title "vX.Y.Z — ..." --notes-file - <<'EOF' |
50 | | - ... |
51 | | - EOF |
52 | | - ``` |
53 | | -4. Verify: |
54 | | - - `gh release list -L 3` shows `vX.Y.Z` as **Latest** |
55 | | - - `git ls-remote --tags origin vX.Y.Z` resolves |
56 | | -
|
57 | | -## Phase 4 — Self-consistency check |
58 | | -
|
59 | | -Because install/update pull the latest release tarball, confirm the new tag's tarball includes the built code: |
| 54 | +1. Read current versions: |
| 55 | + |
| 56 | +```bash |
| 57 | +grep -n '^version' pyproject.toml |
| 58 | +grep -n '^__version__' git_auto_sync/__init__.py |
| 59 | +``` |
| 60 | + |
| 61 | +2. Set new version (`vX.Y.Z`, patch by default): |
| 62 | + |
| 63 | +```bash |
| 64 | +VERSION="vX.Y.Z" |
| 65 | +``` |
| 66 | + |
| 67 | +3. Bump files and refresh lockfile: |
| 68 | + |
| 69 | +```bash |
| 70 | +sed -i "s/^version = \".*\"/version = \"${VERSION#v}\"/" pyproject.toml |
| 71 | +sed -i "s/^__version__ = \".*\"/__version__ = \"${VERSION#v}\"/" git_auto_sync/__init__.py |
| 72 | +uv sync |
| 73 | +``` |
| 74 | + |
| 75 | +4. Commit the bump: |
| 76 | + |
| 77 | +```bash |
| 78 | +git add pyproject.toml git_auto_sync/__init__.py uv.lock |
| 79 | +git commit -m "chore: bump version to ${VERSION}" |
| 80 | +``` |
| 81 | + |
| 82 | +## Phase 2 — Build a minimal release package |
| 83 | + |
| 84 | +Build a distributable that excludes repository internals not needed by users. |
| 85 | +The package must contain runtime source + launch scripts only. |
| 86 | + |
| 87 | +```bash |
| 88 | +VERSION="vX.Y.Z" |
| 89 | +PACKAGE_NAME="git-auto-sync-${VERSION}-release.tar.gz" |
| 90 | +PACKAGE_DIR="dist/tmp/git-auto-sync-${VERSION}" |
| 91 | +RELEASE_FILES=( |
| 92 | + git_auto_sync |
| 93 | + README.md |
| 94 | + config.example.toml |
| 95 | + install.sh |
| 96 | + install.ps1 |
| 97 | + pyproject.toml |
| 98 | + uv.lock |
| 99 | +) |
| 100 | + |
| 101 | +mkdir -p "$PACKAGE_DIR" |
| 102 | +for item in "${RELEASE_FILES[@]}"; do |
| 103 | + test -e "$item" || { echo "Missing $item"; exit 1; } |
| 104 | + cp -R "$item" "$PACKAGE_DIR/" |
| 105 | +done |
| 106 | + |
| 107 | +cp -f .claude/commands/release.md "$PACKAGE_DIR/" |
| 108 | + |
| 109 | +mkdir -p dist |
| 110 | +tar -czf "dist/${PACKAGE_NAME}" -C dist/tmp "git-auto-sync-${VERSION}" |
| 111 | +sha256sum "dist/${PACKAGE_NAME}" | tee "dist/${PACKAGE_NAME}.sha256sum" |
| 112 | +ls -lh "dist/${PACKAGE_NAME}" "dist/${PACKAGE_NAME}.sha256sum" |
| 113 | + |
| 114 | +rm -rf dist/tmp |
| 115 | +``` |
| 116 | + |
| 117 | +## Phase 3 — GitHub release and asset upload |
| 118 | + |
| 119 | +1. Draft release notes: |
| 120 | + |
| 121 | +```bash |
| 122 | +PREV_TAG="$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || git rev-list --max-parents=0 HEAD)" |
| 123 | +cat <<'EOF' > /tmp/release-notes.md |
| 124 | +## What's Changed |
| 125 | +
|
| 126 | +## Added |
| 127 | +- ... |
| 128 | +
|
| 129 | +## Changed |
| 130 | +- ... |
| 131 | +
|
| 132 | +## Fixed |
| 133 | +- ... |
| 134 | +
|
| 135 | +**Full Changelog** |
| 136 | +https://github.com/OctopusGarage/git-auto-sync/compare/${PREV_TAG}...${VERSION} |
| 137 | +
|
| 138 | +**Install** |
| 139 | +curl -fsSL https://raw.githubusercontent.com/OctopusGarage/git-auto-sync/main/install.sh | bash |
| 140 | +
|
| 141 | +**Install (Windows)** |
| 142 | +powershell -ExecutionPolicy ByPass -c "irm https://raw.githubusercontent.com/OctopusGarage/git-auto-sync/main/install.ps1 | iex" |
| 143 | +EOF |
| 144 | +``` |
| 145 | + |
| 146 | +2. Create release and attach package: |
| 147 | + |
| 148 | +```bash |
| 149 | +gh release create "${VERSION}" --target main --title "${VERSION} — release notes" --notes-file /tmp/release-notes.md |
| 150 | +gh release upload "${VERSION}" "dist/${PACKAGE_NAME}" "dist/${PACKAGE_NAME}.sha256sum" --clobber |
| 151 | +``` |
| 152 | + |
| 153 | +3. Verify assets and tag: |
| 154 | + |
| 155 | +```bash |
| 156 | +gh release view "${VERSION}" --json name,tagName,isLatest,publishedAt,url -q '{name, tag: .tagName, latest: .isLatest, publishedAt, url}' |
| 157 | +gh release view "${VERSION}" --json assets --jq ".assets[].name" | sort |
| 158 | +git ls-remote --tags origin "${VERSION}" |
| 159 | +``` |
| 160 | + |
| 161 | +## Phase 3.1 — Monitor CI for this tag |
| 162 | + |
| 163 | +```bash |
| 164 | +RUN_ID="$(gh run list --workflow ci.yml --limit 1 --json databaseId --jq '.[0].databaseId')" |
| 165 | +gh run view "$RUN_ID" --json status,conclusion,workflowName,name,url -q '{workflow: .workflowName, name: .name, status: .status, conclusion: .conclusion, url: .url}' |
| 166 | +gh run watch "$RUN_ID" |
| 167 | +``` |
| 168 | + |
| 169 | +```powershell |
| 170 | + $runId = (gh run list --workflow ci.yml --limit 1 --json databaseId --jq "[0].databaseId") |
| 171 | + gh run view $runId --json status,conclusion,workflowName,name,url -q '{workflow: .workflowName, name: .name, status: .status, conclusion: .conclusion, url: .url}' |
| 172 | + gh run watch $runId |
| 173 | +``` |
| 174 | + |
| 175 | +If a failure is found, fix locally and rerun from the current failed phase only after pushing follow-up commits. |
| 176 | + |
| 177 | +## Phase 4 — Validate installer and updater (all platforms) |
| 178 | + |
| 179 | +### macOS / Linux |
| 180 | + |
60 | 181 | ```bash |
61 | | -TAG=$(git describe --tags --abbrev=0) |
62 | | -url=$(curl -fsSLI -o /dev/null -w '%{url_effective}' "https://github.com/OctopusGarage/git-auto-sync/releases/latest") |
63 | | -TAG="${url##*/}" |
64 | | -curl -fsSL "https://github.com/OctopusGarage/git-auto-sync/archive/refs/tags/${TAG}.tar.gz" -o /tmp/git-auto-sync.tar.gz |
65 | | -tar -tzf /tmp/git-auto-sync.tar.gz | rg "setup\.(sh|ps1)|pyproject.toml|git_auto_sync/cli.py" |
| 182 | +curl -fsSL https://raw.githubusercontent.com/OctopusGarage/git-auto-sync/main/install.sh | bash |
| 183 | +git-auto-sync --help |
| 184 | +git-auto-sync --version |
| 185 | +git-auto-sync update --check |
66 | 186 | ``` |
67 | 187 |
|
68 | | -## Phase 5 — Optional local validation (if not skipped) |
| 188 | +### Windows |
| 189 | + |
| 190 | +```powershell |
| 191 | +powershell -ExecutionPolicy ByPass -c "irm https://raw.githubusercontent.com/OctopusGarage/git-auto-sync/main/install.ps1 | iex" |
| 192 | +git-auto-sync --help |
| 193 | +git-auto-sync --version |
| 194 | +git-auto-sync update --check |
| 195 | +``` |
| 196 | + |
| 197 | +## AI Release Operator Prompt (copy/paste) |
| 198 | + |
| 199 | +```text |
| 200 | +You are a strict release operator for the git-auto-sync repository. |
| 201 | +Run this command sequence exactly: |
| 202 | +1) preflight checks on main |
| 203 | +2) version bump (`patch|minor|major|X.Y.Z`) |
| 204 | +3) minimal package build |
| 205 | +4) GitHub release creation and asset upload |
| 206 | +5) CI monitor |
| 207 | +6) macOS/Linux/Windows install+update verification |
| 208 | +Stop at the first failed command and report the command, output, and required fix. |
| 209 | +All outputs must be in English. |
| 210 | +Release argument is: `$ARGUMENTS`. |
| 211 | +``` |
69 | 212 |
|
70 | | -Run installation/update smoke checks: |
71 | | -1. `curl -fsSL https://raw.githubusercontent.com/OctopusGarage/git-auto-sync/main/install.sh | bash` |
72 | | -2. `git-auto-sync --help` |
73 | | -3. `uv run git-auto-sync config check` |
74 | | -4. `git-auto-sync update --check` expects to report up-to-date at new version. |
| 213 | +## AI Install Prompt (copy/paste) |
| 214 | + |
| 215 | +```text |
| 216 | +I need a clean install on current machine. |
| 217 | +Use the latest release package and do not clone the full source. |
| 218 | +Run one of these: |
| 219 | +
|
| 220 | +macOS/Linux: |
| 221 | +curl -fsSL https://raw.githubusercontent.com/OctopusGarage/git-auto-sync/main/install.sh | bash |
| 222 | +
|
| 223 | +Windows: |
| 224 | +powershell -ExecutionPolicy ByPass -c "irm https://raw.githubusercontent.com/OctopusGarage/git-auto-sync/main/install.ps1 | iex" |
| 225 | +``` |
75 | 226 |
|
76 | | -## Report |
| 227 | +## Completion report |
77 | 228 |
|
78 | | -Summarize: new version, commit SHA, release URL, and verification results. If stopped early, identify the failing gate and required fix. |
| 229 | +Record: |
| 230 | +- New version and tag |
| 231 | +- Release URL |
| 232 | +- Asset names and checksums |
| 233 | +- Verification outputs |
| 234 | +- Blocking issues and fixes if stopped early |
0 commit comments