diff --git a/.github/workflows/tag-docs-release.yml b/.github/workflows/tag-docs-release.yml new file mode 100644 index 0000000..1667c41 --- /dev/null +++ b/.github/workflows/tag-docs-release.yml @@ -0,0 +1,50 @@ +name: Tag docs release + +# Tags every release squash commit on `main` as `docs/vYYYY.MDD.P`. +# +# The tag used to be a manual post-merge step, and 11 of the first 16 releases +# never got one. Release PRs are always titled +# `Release docs for paperclip vYYYY.MDD.P`, and a squash merge keeps that title +# as the commit subject, so the version can be read straight from the commit. + +on: + push: + branches: [main] + +permissions: + contents: write + +jobs: + tag: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Tag release commits + env: + BEFORE: ${{ github.event.before }} + AFTER: ${{ github.sha }} + run: | + set -euo pipefail + # A branch-creating push has an all-zero `before`; look at the tip only. + if [ -z "${BEFORE//0/}" ] || ! git cat-file -e "$BEFORE^{commit}" 2>/dev/null; then + range="$AFTER -1" + else + range="$BEFORE..$AFTER" + fi + + git log --format='%H %s' $range | while read -r sha subject; do + version=$(printf '%s\n' "$subject" \ + | sed -nE 's/^Release docs for paperclip (v[0-9]{4}\.[0-9]{1,4}\.[0-9]+)( .*)?$/\1/p') + [ -n "$version" ] || continue + tag="docs/$version" + if git rev-parse -q --verify "refs/tags/$tag" >/dev/null; then + echo "$tag already exists at $(git rev-parse --short "$tag^{commit}") — leaving it." + continue + fi + git tag "$tag" "$sha" + git push origin "refs/tags/$tag" + echo "Tagged $tag at ${sha:0:7}." + done diff --git a/maintenance/runbook.md b/maintenance/runbook.md index 208969b..3b8e0c1 100644 --- a/maintenance/runbook.md +++ b/maintenance/runbook.md @@ -126,12 +126,12 @@ When a new parent release tag drops (`v2026.X.Y`): - Frontmatter `paperclip_version` correctly stamped on changed pages. 4. Merge to `main` when satisfied. 5. **After merge — four follow-ups:** - - Tag the merge commit: + - Confirm the merge commit was tagged. The `Tag docs release` workflow does this automatically on the push to `main`, reading the version from the squash commit's subject — so keep the PR title `Release docs for paperclip v2026.X.Y`: ```sh - git checkout main && git pull - git tag docs/v2026.X.Y - git push --tags + git checkout main && git pull --tags + git rev-parse --short docs/v2026.X.Y # should print the squash commit ``` + If it's missing, check the workflow run, then tag by hand: `git tag docs/v2026.X.Y && git push origin docs/v2026.X.Y`. - Verify `.sync-state.json` on `main` now shows `base_release_tag: v2026.X.Y` and `base_release_sha` matches. - **Confirm the site actually rebuilt — don't assume.** Cloudflare Pages is supposed to auto-deploy on push to `main`, but that hook has silently no-opped (v2026.824.0 merged with a correct changelog entry and production served the previous build for hours). Check the live site, not the Pages dashboard: diff --git a/skills/sync-docs/SKILL.md b/skills/sync-docs/SKILL.md index 0b491f4..23cc776 100644 --- a/skills/sync-docs/SKILL.md +++ b/skills/sync-docs/SKILL.md @@ -457,11 +457,18 @@ Skip in nightly mode (Cloudflare branch previews are best-effort, not reader-fac skipped at least once; none are optional. ```sh - git checkout main && git pull - git tag docs/v2026.X.Y && git push --tags + git checkout main && git pull --tags + git rev-parse --short docs/v2026.X.Y # must print the release squash commit node scripts/sync/realign-nightly.mjs release/v2026.X.Y --push # see Phase 7 ``` + The `docs/v2026.X.Y` tag is created by `.github/workflows/tag-docs-release.yml` + on the push to `main`. It reads the version from the squash commit's subject, + so the release PR **must** keep the title `Release docs for paperclip vYYYY.MDD.P` + (anything after a space, like `(#132)`, is fine). If the tag is missing a minute + after the merge, check that workflow's run and tag by hand: + `git tag docs/v2026.X.Y && git push origin docs/v2026.X.Y`. + Then flip `nightly`'s `.sync-state.json` back to `"branch_mode": "nightly"` and commit it. The merge-down inherits `"release"` from `main` and nothing else corrects it, so the next nightly run starts from a state file that lies about @@ -497,7 +504,7 @@ Skip in nightly mode (Cloudflare branch previews are best-effort, not reader-fac 4. **Show the evidence in the run summary** — the URLs you checked, the status codes, and the changelog version you read back. "Merged" is not evidence. -> The "never push without asking" rule still holds here. Steps 1 and 3 push tags +> The "never push without asking" rule still holds here. Steps 1 and 3 push the nightly realign > and publish to production — ask before each, and if the answer is no, hand off > with the exact commands so the human can run them. What is **not** optional is > step 2: always check the live site and always report what you found, even when