Skip to content

Commit acb5af3

Browse files
committed
ci: replace docs/v* branches with tags for versioned docs deployment
Switch versioned docs from branch-based to tag-based deployment. Previously, both release tags (v*) and docs/v* branches triggered the publish-versioned-docs job in docs.yml, deploying to the same /X.Y/ path. This created a silent drift problem: the docs/v* branch could accumulate commits independently of releases, causing the live docs to diverge from the released version without any guardrail. The fix has two parts: 1. docs.yml: remove docs/v* from branch triggers; add docs/v* to tag triggers. The publish-versioned-docs job now fires only on release tags (v*) and docs-override tags (docs/v*). Tags require a deliberate force-push to move, making any docs redeploy an explicit, intentional act. 2. sync-docs-tag.yml (new): after each release tag push, automatically create or force-move the docs/vX.Y tag to that same commit. This keeps the tag in sync with the latest patch so docs-only cherry-picks always start from the right base. Because GITHUB_TOKEN pushes do not trigger other workflow runs, moving the tag here does NOT re-trigger docs.yml — no skip guards needed. Also documents the docs-only fix workflow (merge to main first, then cherry-pick to a local temp branch and force-move the tag) in docs-guidelines.md, and adds rollback steps for the docs/vX.Y tag to the release playbook. Migration: after this merges, create the docs/v0.2 tag from the current docs/v0.2 branch tip, then delete the branch: git fetch origin git tag docs/v0.2 origin/docs/v0.2 git push origin refs/tags/docs/v0.2 git push origin --delete docs/v0.2
1 parent 5bd1485 commit acb5af3

6 files changed

Lines changed: 121 additions & 15 deletions

File tree

.claude/docs-guidelines.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,32 @@ Documentation follows the Diátaxis framework:
3030
- When referencing alternatives in other docs, maintain this order: "Homebrew, shell script, ..." (e.g., "See the Installation Guide for Homebrew, shell script, or other options")
3131
- Both `icp-cli` and `ic-wasm` are available as official Homebrew formulas: `brew install icp-cli` and `brew install ic-wasm`
3232

33+
## Docs-Only Fixes for Released Versions
34+
35+
Versioned docs deployments (e.g. `/0.2/`) are controlled by `docs/vX.Y` tags. To fix or improve docs for an already-released version without cutting a new code release:
36+
37+
**Rule: always merge the change to `main` first.** The `docs/vX.Y` tag is only for immediate deployment — when the next patch release is tagged, `sync-docs-tag.yml` resets `docs/vX.Y` to the new release commit. Any commit that exists only on the tag (not in `main`) will be silently lost at that point.
38+
39+
**Workflow:**
40+
41+
```bash
42+
# 1. Merge the fix to main via a normal PR (always required)
43+
44+
# 2. To immediately deploy the fix to /X.Y/ without waiting for a release:
45+
git fetch --tags
46+
git checkout -b temp/docs-fix-vX.Y docs/vX.Y # start from current tag state
47+
git cherry-pick <commit-sha-from-main> # pick the merged commit(s)
48+
49+
git tag -f docs/vX.Y HEAD
50+
git push origin refs/tags/docs/vX.Y --force # triggers re-deploy of /X.Y/
51+
52+
git branch -D temp/docs-fix-vX.Y # local branch no longer needed
53+
```
54+
55+
The commits remain reachable via the tag — no remote branch is needed.
56+
57+
**On the next release:** `sync-docs-tag.yml` resets `docs/vX.Y` to the release commit. Because the fix was already merged to `main`, the release will contain it, and the reset preserves it automatically.
58+
3359
## Writing Guidelines
3460

3561
- Use "canister environment variables" (not just "environment variables") when referring to runtime variables stored in canister settings — this distinguishes them from shell/build environment variables

.claude/skills/release/rollback.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,20 @@ If something fails mid-release, here's how to clean up depending on how far you
99
git tag -d v$ARGUMENTS
1010
```
1111
If a GitHub Release was already created, delete it first via `gh release delete v$ARGUMENTS --yes`, then delete the tag.
12+
Also revert the `docs/vX.Y` tag that `sync-docs-tag.yml` moved automatically. If a previous patch existed (e.g. rolling back v0.2.3 means docs/v0.2 should revert to v0.2.2), force-move it back:
13+
```bash
14+
MINOR=$(echo "$ARGUMENTS" | sed 's/\.[0-9]*$//')
15+
git tag -f docs/v${MINOR} v${MINOR}.$(( $(echo "$ARGUMENTS" | sed 's/.*\.//') - 1 ))
16+
git push origin refs/tags/docs/v${MINOR} --force
17+
```
18+
If this was the first release of the minor (no previous patch), delete the docs tag instead:
19+
```bash
20+
MINOR=$(echo "$ARGUMENTS" | sed 's/\.[0-9]*$//')
21+
git push origin --delete refs/tags/docs/v${MINOR}
22+
git tag -d docs/v${MINOR}
23+
```
1224
- **Task 3 failed (Release workflow)**: Investigate the failure. The tag still exists. Once fixed, you can re-run the workflow from the GitHub Actions UI. Do **not** delete and re-push the tag — that creates duplicate runs.
1325
- **Task 4 failed (NPM publish)**: NPM publishes are not easily reversible. If the publish partially succeeded, check `npm info @icp-sdk/icp-cli versions` and coordinate with the team. The workflow can be re-triggered from the GitHub Actions UI.
1426
- **Task 5 failed (homebrew-tap)**: If the workflow failed, it can be re-triggered. If the PR was created but has issues, close it and delete the branch `update/icp-cli-beta-$ARGUMENTS` on `dfinity/homebrew-tap` via the GitHub UI. No packages were published.
15-
- **Task 6 failed (docs versions)**: Close the PR and delete the branch. The versioned docs are deployed independently and are unaffected.
27+
- **Task 6 failed (docs versions)**: Close the versions.json PR and delete the branch. The versioned docs at `/X.Y/` are deployed independently by the tag push and are unaffected. The `docs/vX.Y` tag was already moved by `sync-docs-tag.yml` as part of Task 2 — no additional cleanup needed for the tag unless you are also rolling back Task 2.
1628
- **Task 7 (homebrew-core check)**: This task is read-only — no cleanup needed. If it fails, just check manually.

.claude/skills/release/task6-docs.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22

33
*Skip if `$ARGUMENTS` is a beta release. Requires Task 2. Runs concurrently with Task 3.*
44

5-
The tag push triggers a docs deployment workflow that builds and publishes the versioned docs to `/X.Y/` on the `docs-deployment` branch (served at `https://cli.internetcomputer.org/X.Y/`). The `versions.json` PR must not be merged until that deployment succeeds, otherwise the root redirect will point to a path that does not exist yet.
5+
The tag push triggers two automated workflows:
6+
7+
1. **`docs.yml` (`publish-versioned-docs` job):** Builds and publishes the versioned docs to `/X.Y/` on the `docs-deployment` branch (served at `https://cli.internetcomputer.org/X.Y/`). The `versions.json` PR must not be merged until that deployment succeeds, otherwise the root redirect will point to a path that does not exist yet.
8+
9+
2. **`sync-docs-tag.yml`:** Creates or moves the `docs/vX.Y` tag to the new release commit — no manual action required. This keeps the docs-override tag in sync with the latest patch. Because the tag is moved via `GITHUB_TOKEN`, the push does not re-trigger `docs.yml` (GitHub prevents recursive workflow runs from `GITHUB_TOKEN` pushes).
10+
- The reset overwrites any docs-only commits that were on `docs/vX.Y` but not in the release. This is safe as long as the "merge to main first" rule was followed — those commits will be in the release itself. See `.claude/docs-guidelines.md` → "Docs-Only Fixes for Released Versions".
611

712
Once the `versions.json` PR merges to `main`, the `publish-root-files` CI job runs automatically and copies `og-image.png`, `llms.txt`, `llms-full.txt`, and `feed.xml` from the new version's folder to the deployment root — no manual step needed.
813

.github/workflows/docs.yml

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ on:
55
tags:
66
- 'v*'
77
- '!v*-*' # exclude pre-release tags (e.g. v0.2.0-beta.0)
8+
- 'docs/v*' # docs-only overrides for specific minor versions (e.g. docs/v0.2)
9+
- '!docs/v*-*' # exclude pre-release doc-override tags
810
branches:
911
- main
10-
- 'docs/v*'
11-
- '!docs/v*-*' # exclude pre-release doc branches
1212
paths:
1313
- 'docs/**'
1414
- 'docs-site/**'
@@ -255,9 +255,9 @@ jobs:
255255
destination_dir: main
256256
keep_files: true
257257

258-
# Publish versioned docs - runs on tags (v*) or docs branches (docs/v*)
258+
# Publish versioned docs - runs on release tags (v*) or docs-override tags (docs/v*)
259259
publish-versioned-docs:
260-
if: github.event_name == 'push' && (startsWith(github.ref, 'refs/tags/v') || startsWith(github.ref, 'refs/heads/docs/v'))
260+
if: github.event_name == 'push' && (startsWith(github.ref, 'refs/tags/v') || startsWith(github.ref, 'refs/tags/docs/v'))
261261
needs: build
262262
runs-on: ubuntu-latest
263263
steps:
@@ -277,22 +277,21 @@ jobs:
277277
working-directory: ./docs-site
278278
run: npm ci
279279

280-
- name: Extract version from tag or branch
280+
- name: Extract version from tag
281281
run: |
282282
if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
283-
# Tag: v0.1.0 -> extract major.minor -> 0.1
283+
# Release tag: v0.1.0 -> extract major.minor -> 0.1
284284
VERSION=${GITHUB_REF#refs/tags/v}
285-
# Strip patch version (0.1.0 -> 0.1)
286285
VERSION=${VERSION%.*}
287286
echo "DOCS_VERSION=${VERSION}" >> $GITHUB_ENV
288287
echo "DOCS_BASE_PATH=/${VERSION}/" >> $GITHUB_ENV
289-
elif [[ "${GITHUB_REF}" == refs/heads/docs/v* ]]; then
290-
# Branch: docs/v0.1 -> extract version -> 0.1
291-
VERSION=${GITHUB_REF#refs/heads/docs/v}
288+
elif [[ "${GITHUB_REF}" == refs/tags/docs/v* ]]; then
289+
# Docs-override tag: docs/v0.1 -> extract version -> 0.1
290+
VERSION=${GITHUB_REF#refs/tags/docs/v}
292291
echo "DOCS_VERSION=${VERSION}" >> $GITHUB_ENV
293292
echo "DOCS_BASE_PATH=/${VERSION}/" >> $GITHUB_ENV
294293
else
295-
echo "❌ Docs should only be published for version tags (v*) or docs branches (docs/v*)"
294+
echo "❌ Docs should only be published for release tags (v*) or docs-override tags (docs/v*)"
296295
echo "Current ref: ${GITHUB_REF}"
297296
exit 1
298297
fi
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Sync docs tag after release
2+
3+
# When a release tag is pushed, create or force-move the docs/vX.Y tag to that
4+
# same commit. This keeps the docs-override tag in sync with the latest patch
5+
# and prevents stale content from being served if someone later moves the tag
6+
# for a docs-only fix on top of an outdated base.
7+
#
8+
# docs/vX.Y tags are the stable mechanism for docs-only updates to an older
9+
# minor version without cutting a new code release. Moving them is intentional
10+
# and requires explicit force-push — unlike branches, they cannot drift by
11+
# accident.
12+
#
13+
# Note: pushes via GITHUB_TOKEN do not trigger other workflow runs, so moving
14+
# the docs/vX.Y tag here will NOT re-trigger publish-versioned-docs in
15+
# docs.yml. Only a human explicitly pushing the tag triggers a re-deploy.
16+
17+
on:
18+
push:
19+
tags:
20+
- 'v*'
21+
- '!v*-*' # exclude pre-release tags (e.g. v0.2.0-beta.0)
22+
23+
permissions:
24+
contents: write
25+
26+
jobs:
27+
sync-docs-tag:
28+
runs-on: ubuntu-latest
29+
steps:
30+
- name: Checkout
31+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
32+
with:
33+
fetch-depth: 0
34+
35+
- name: Configure git
36+
run: |
37+
git config user.name "github-actions[bot]"
38+
git config user.email "github-actions[bot]@users.noreply.github.com"
39+
40+
- name: Extract version info
41+
run: |
42+
TAG=${GITHUB_REF_NAME} # e.g. v0.2.3
43+
PATCH=${TAG#v} # e.g. 0.2.3
44+
MINOR=${PATCH%.*} # e.g. 0.2
45+
echo "TAG=${TAG}" >> $GITHUB_ENV
46+
echo "MINOR=${MINOR}" >> $GITHUB_ENV
47+
echo "DOCS_TAG=docs/v${MINOR}" >> $GITHUB_ENV
48+
49+
- name: Create or move docs tag to release commit
50+
run: |
51+
if git ls-remote --exit-code --tags origin "refs/tags/${DOCS_TAG}" > /dev/null 2>&1; then
52+
git tag -f "${DOCS_TAG}" "${TAG}"
53+
git push origin "refs/tags/${DOCS_TAG}" --force
54+
echo "Moved ${DOCS_TAG} to ${TAG}"
55+
else
56+
git tag "${DOCS_TAG}" "${TAG}"
57+
git push origin "refs/tags/${DOCS_TAG}"
58+
echo "Created ${DOCS_TAG} at ${TAG}"
59+
fi

docs-site/README.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,13 @@ The site is hosted on an IC asset canister and served at `https://cli.internetco
119119
### Triggers
120120

121121
- **Push to `main`**: Rebuilds `/main/` docs and root files (`index.html`, `versions.json`, `robots.txt`, `sitemap.xml`, IC config). Also copies `og-image.png`, `llms.txt`, `llms-full.txt`, and `feed.xml` from the latest versioned deployment to the root.
122-
- **Tags (`v*`)**: Builds versioned docs (e.g., `v0.2.0``/0.2/`)
123-
- **Branches (`docs/v*`)**: Updates versioned docs (e.g., `docs/v0.1``/0.1/`)
122+
- **Release tags (`v*`)**: Builds and deploys versioned docs (e.g., `v0.2.0``/0.2/`). Also triggers `sync-docs-tag.yml` which automatically creates or moves the `docs/v0.2` tag to that same commit — no manual step needed.
123+
- **Docs-override tags (`docs/v*`)**: Redeploys versioned docs for a specific minor version without cutting a new code release (e.g., `docs/v0.1``/0.1/`). To trigger a re-deploy, force-move the tag to the desired commit:
124+
```bash
125+
git tag -f docs/v0.2 <commit-sha>
126+
git push origin refs/tags/docs/v0.2 --force
127+
```
128+
Note: `sync-docs-tag.yml` uses `GITHUB_TOKEN` to move the tag after each release, which does **not** re-trigger `docs.yml` (GitHub prevents recursive workflow runs from `GITHUB_TOKEN` pushes). Only a human explicitly pushing the tag triggers a re-deploy.
124129

125130
### Root-level files
126131

0 commit comments

Comments
 (0)