1515 - " v[0-9]*.0.0"
1616 workflow_dispatch :
1717
18- # Deployment strategy: single mechanism — peaceiris/actions-gh-pages (gh-pages branch).
19- # • latest docs → pushed to gh-pages root (keep_files: true preserves snapshots)
20- # • versioned snapshot → pushed to gh-pages/<major>/ on major release tags
21- # GitHub Pages must be configured to serve from the gh-pages branch (not GitHub Actions).
22- #
23- # Snapshot job needs contents write to push to gh-pages and commit versions.json back to main.
18+ # Deployment strategy: GitHub Actions Pages source (actions/deploy-pages — official, no third party).
19+ # • gh-pages branch = versioned snapshot STORAGE only (not served directly by Pages)
20+ # • Every deploy job assembles a combined artifact:
21+ # - latest docs built from main at the artifact root
22+ # - each vX/ snapshot from the gh-pages branch merged in
23+ # → single artifact deployed via actions/deploy-pages
24+ # • Snapshot job stores the built snapshot in gh-pages branch via plain git,
25+ # then pushes the updated versions.json to main (no [skip ci]) which
26+ # re-triggers the deploy job to include the new snapshot immediately.
27+ # Requires: Settings → Pages → Source: GitHub Actions.
2428permissions :
2529 contents : write
30+ pages : write
31+ id-token : write
2632
2733# Only one concurrent deployment for the same ref; cancel outdated runs.
2834concurrency :
@@ -31,17 +37,29 @@ concurrency:
3137
3238jobs :
3339 # ── Deploy (latest) ─────────────────────────────────────────────────────────
34- # Builds docs and pushes them to the gh-pages root.
35- # keep_files: true ensures versioned snapshots (v1/, v2/ …) are not wiped.
36- # Requires: Settings → Pages → Source: Deploy from a branch → gh-pages / root.
40+ # Assembles a combined Pages artifact:
41+ # 1. Builds the latest docs (base: /github-code-search/)
42+ # 2. Merges existing versioned snapshots from the gh-pages storage branch
43+ # into the artifact (docs/.vitepress/dist/vX/ for each stored version)
44+ # 3. Uploads the artifact and deploys via actions/deploy-pages
45+ # Requires: Settings → Pages → Source: GitHub Actions.
3746 deploy :
38- name : Deploy docs (latest)
47+ name : Build and deploy docs
3948 if : github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch'
4049 runs-on : ubuntu-latest
50+ permissions :
51+ pages : write
52+ id-token : write
53+ environment :
54+ name : github-pages
55+ url : ${{ steps.deploy.outputs.page_url }}
4156
4257 steps :
4358 - name : Checkout
4459 uses : actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
60+ with :
61+ # Needed to fetch the gh-pages storage branch for versioned snapshots.
62+ fetch-depth : 0
4563
4664 - name : Setup Bun
4765 uses : oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2
@@ -51,24 +69,43 @@ jobs:
5169 - name : Install dependencies
5270 run : bun install --frozen-lockfile
5371
54- - name : Build docs
72+ - name : Build latest docs
5573 run : bun run docs:build
5674 # Base URL: /github-code-search/ (default in config.mts)
5775
58- - name : Publish to gh-pages root
59- uses : peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d231e62369c1b474e # v4.0.0
76+ - name : Merge versioned snapshots from gh-pages storage
77+ run : |
78+ if git ls-remote --heads origin gh-pages | grep -q gh-pages; then
79+ git fetch origin gh-pages
80+ # Copy each vX/ directory from the storage branch into the artifact root.
81+ for entry in $(git ls-tree --name-only origin/gh-pages); do
82+ if echo "$entry" | grep -qE '^v[0-9]+$'; then
83+ echo "Merging snapshot: $entry"
84+ mkdir -p "docs/.vitepress/dist/$entry"
85+ git archive origin/gh-pages "$entry" | tar -x -C docs/.vitepress/dist/
86+ fi
87+ done
88+ else
89+ echo "No gh-pages branch yet — skipping snapshot merge"
90+ fi
91+
92+ - name : Upload Pages artifact
93+ uses : actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1
6094 with :
61- github_token : ${{ secrets.GITHUB_TOKEN }}
62- publish_dir : docs/.vitepress/dist
63- # Preserve versioned snapshots already pushed to gh-pages (v1/, v2/ …)
64- keep_files : true
95+ path : docs/.vitepress/dist
96+
97+ - name : Deploy to GitHub Pages
98+ id : deploy
99+ uses : actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5
65100
66101 # ── Snapshot (versioned) ────────────────────────────────────────────────────
67102 # Triggered by a major release tag (e.g. v2.0.0).
68- # Builds docs with a versioned base URL (/github-code-search/v2/) and publishes
69- # the static output to the gh-pages branch under /v2/.
70- # Also appends the new entry to docs/public/versions.json on main so that
71- # future deployments expose the version in the nav dropdown.
103+ # 1. Builds docs with a versioned base URL (/github-code-search/v2/).
104+ # 2. Stores the output in the gh-pages branch under /v2/ using plain git
105+ # (no third-party action). The gh-pages branch is storage only — Pages
106+ # still points to GitHub Actions; the deploy job merges snapshots in.
107+ # 3. Prepends the entry to versions.json on main WITHOUT [skip ci], which
108+ # re-triggers the deploy job so the new snapshot is live immediately.
72109 #
73110 # Convention: only tags matching vX.0.0 (major bumps) trigger a snapshot.
74111 # Patch and minor releases update the main docs in-place via the deploy job.
@@ -83,15 +120,13 @@ jobs:
83120 - name : Checkout
84121 uses : actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
85122 with :
86- # Full history needed to push the versions.json commit back to main.
123+ # Full history needed to push to gh-pages and commit versions.json to main.
87124 fetch-depth : 0
88125
89126 - name : Extract major version from tag
90127 id : ver
91128 run : |
92- TAG="${GITHUB_REF_NAME}" # e.g. v2.0.0
93- MAJOR="$(echo "$TAG" | cut -d. -f1)" # e.g. v2
94- echo "tag=$TAG" >> "$GITHUB_OUTPUT"
129+ MAJOR="$(echo "$GITHUB_REF_NAME" | cut -d. -f1)" # e.g. v2
95130 echo "major=$MAJOR" >> "$GITHUB_OUTPUT"
96131
97132 - name : Setup Bun
@@ -108,30 +143,43 @@ jobs:
108143 VITEPRESS_BASE : /github-code-search/${{ steps.ver.outputs.major }}/
109144 run : bun run docs:build
110145
111- - name : Publish snapshot to gh-pages
112- uses : peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d231e62369c1b474e # v4.0.0
113- with :
114- github_token : ${{ secrets.GITHUB_TOKEN }}
115- publish_dir : docs/.vitepress/dist
116- destination_dir : ${{ steps.ver.outputs.major }}
117- # Preserve all existing pages (other versions, latest, etc.)
118- keep_files : true
146+ - name : Store snapshot in gh-pages branch
147+ run : |
148+ MAJOR="${{ steps.ver.outputs.major }}"
149+ git config user.name "github-actions[bot]"
150+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
151+ # Set up the gh-pages worktree (create orphan branch if it doesn't exist yet).
152+ if git ls-remote --heads origin gh-pages | grep -q gh-pages; then
153+ git fetch origin gh-pages
154+ git worktree add /tmp/gh-pages-storage origin/gh-pages
155+ else
156+ git worktree add --orphan -b gh-pages /tmp/gh-pages-storage
157+ touch /tmp/gh-pages-storage/.nojekyll # prevent Jekyll processing
158+ fi
159+ # Copy the built snapshot into its versioned directory.
160+ rm -rf "/tmp/gh-pages-storage/$MAJOR"
161+ cp -r docs/.vitepress/dist "/tmp/gh-pages-storage/$MAJOR"
162+ # Commit and push.
163+ cd /tmp/gh-pages-storage
164+ git add .
165+ git diff --staged --quiet || git commit -m "docs: store snapshot $MAJOR [skip ci]"
166+ git push origin gh-pages
119167
120168 - name : Prepend new version entry to versions.json
121169 run : |
122170 MAJOR="${{ steps.ver.outputs.major }}"
123- # Link is relative to the VitePress base — VitePress will not add the base a
124- # second time (same convention as the initial "v1 (latest)" entry: link "/")
125171 LINK="/${MAJOR}/"
126- # Idempotent: skip if the entry already exists
172+ # Idempotent — skip if the entry already exists.
127173 jq --arg text "$MAJOR" --arg link "$LINK" \
128174 'if any(.[]; .link == $link) then . else [{"text": $text, "link": $link}] + . end' \
129175 docs/public/versions.json > /tmp/versions_new.json
130176 mv /tmp/versions_new.json docs/public/versions.json
131177
132- - name : Commit updated versions.json to main
178+ - name : Commit versions.json to main
133179 uses : stefanzweifel/git-auto-commit-action@8621497c8c39c72f3e2a999a26b4ca1b5590082e # v5.0.1
134180 with :
135- commit_message : " docs: add ${{ steps.ver.outputs.major }} to versions.json [skip ci]"
181+ # No [skip ci] — the push to main matches paths: docs/** and re-triggers
182+ # the deploy job, which merges the new snapshot into the Pages artifact.
183+ commit_message : " docs: add ${{ steps.ver.outputs.major }} to versions.json"
136184 file_pattern : docs/public/versions.json
137185 branch : main
0 commit comments