Skip to content

Commit 989a679

Browse files
authored
Merge pull request #39 from fulll/docs/30-versioning
docs: versioning strategy — CI snapshot + deploy workflow
2 parents 9c0d85f + d8320a5 commit 989a679

2 files changed

Lines changed: 161 additions & 9 deletions

File tree

.github/workflows/docs.yml

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
name: Docs
2+
3+
# Triggers:
4+
# - push to main touching docs/** or this workflow → deploy latest to GitHub Pages
5+
# - push of a major release tag (v2.0.0, v3.0.0 …) → versioned snapshot
6+
# - workflow_dispatch → manual deploy of latest
7+
on:
8+
push:
9+
branches: [main]
10+
paths:
11+
- "docs/**"
12+
- ".github/workflows/docs.yml"
13+
tags:
14+
# Glob pattern (not regex): matches v1.0.0, v2.0.0, v10.0.0 …
15+
- "v[0-9]*.0.0"
16+
workflow_dispatch:
17+
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.
24+
permissions:
25+
contents: write
26+
27+
# Only one concurrent deployment for the same ref; cancel outdated runs.
28+
concurrency:
29+
group: docs-${{ github.ref }}
30+
cancel-in-progress: true
31+
32+
jobs:
33+
# ── 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.
37+
deploy:
38+
name: Deploy docs (latest)
39+
if: github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch'
40+
runs-on: ubuntu-latest
41+
42+
steps:
43+
- name: Checkout
44+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
45+
46+
- name: Setup Bun
47+
uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2
48+
with:
49+
bun-version: latest
50+
51+
- name: Install dependencies
52+
run: bun install --frozen-lockfile
53+
54+
- name: Build docs
55+
run: bun run docs:build
56+
# Base URL: /github-code-search/ (default in config.mts)
57+
58+
- name: Publish to gh-pages root
59+
uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d231e62369c1b474e # v4.0.0
60+
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
65+
66+
# ── Snapshot (versioned) ────────────────────────────────────────────────────
67+
# 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.
72+
#
73+
# Convention: only tags matching vX.0.0 (major bumps) trigger a snapshot.
74+
# Patch and minor releases update the main docs in-place via the deploy job.
75+
snapshot:
76+
name: Snapshot versioned docs
77+
if: startsWith(github.ref, 'refs/tags/')
78+
runs-on: ubuntu-latest
79+
permissions:
80+
contents: write
81+
82+
steps:
83+
- name: Checkout
84+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
85+
with:
86+
# Full history needed to push the versions.json commit back to main.
87+
fetch-depth: 0
88+
89+
- name: Extract major version from tag
90+
id: ver
91+
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"
95+
echo "major=$MAJOR" >> "$GITHUB_OUTPUT"
96+
97+
- name: Setup Bun
98+
uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2
99+
with:
100+
bun-version: latest
101+
102+
- name: Install dependencies
103+
run: bun install --frozen-lockfile
104+
105+
- name: Build versioned snapshot
106+
env:
107+
# config.mts reads VITEPRESS_BASE when set; falls back to /github-code-search/
108+
VITEPRESS_BASE: /github-code-search/${{ steps.ver.outputs.major }}/
109+
run: bun run docs:build
110+
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
119+
120+
- name: Prepend new version entry to versions.json
121+
run: |
122+
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 "/")
125+
LINK="/${MAJOR}/"
126+
# Idempotent: skip if the entry already exists
127+
jq --arg text "$MAJOR" --arg link "$LINK" \
128+
'if any(.[]; .link == $link) then . else [{"text": $text, "link": $link}] + . end' \
129+
docs/public/versions.json > /tmp/versions_new.json
130+
mv /tmp/versions_new.json docs/public/versions.json
131+
132+
- name: Commit updated versions.json to main
133+
uses: stefanzweifel/git-auto-commit-action@8621497c8c39c72f3e2a999a26b4ca1b5590082e # v5.0.1
134+
with:
135+
commit_message: "docs: add ${{ steps.ver.outputs.major }} to versions.json [skip ci]"
136+
file_pattern: docs/public/versions.json
137+
branch: main

docs/.vitepress/config.mts

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,24 @@
11
import { defineConfig } from "vitepress";
2+
import versionsData from "../public/versions.json";
3+
4+
// ── Versioning convention ────────────────────────────────────────────────────
5+
// • main branch → always publishes the "latest" docs at /github-code-search/
6+
// • Major release tag (vX.0.0) → CI takes a snapshot:
7+
// 1. Builds with VITEPRESS_BASE=/github-code-search/vX/
8+
// 2. Publishes to gh-pages under /vX/
9+
// 3. Prepends the new entry to docs/public/versions.json on main
10+
// 4. The next main deploy re-builds this config and picks up the new entry
11+
// → the nav dropdown (generated from versionsData below) shows the new version
12+
// Patch and minor releases (vX.Y.Z, Y>0 or Z>0) update main docs in-place only.
13+
// See .github/workflows/docs.yml for the full snapshot job.
214

315
export default defineConfig({
416
title: "github-code-search",
517
description:
618
"Interactive CLI to search GitHub code across an organization — per-repository aggregation, keyboard-driven TUI, markdown/JSON output.",
7-
base: "/github-code-search/",
19+
// VITEPRESS_BASE is injected by the snapshot CI job for versioned builds.
20+
// Falls back to the canonical base for regular deploys.
21+
base: (process.env.VITEPRESS_BASE ?? "/github-code-search/") as `/${string}/`,
822

923
// ── Theme ──────────────────────────────────────────────────────────────────
1024
// "force-auto" = respect prefers-color-scheme by default; user can still toggle
@@ -41,16 +55,17 @@ export default defineConfig({
4155
{ text: "Usage", link: "/usage/search-syntax" },
4256
{ text: "Reference", link: "/reference/cli-options" },
4357
{ text: "Architecture", link: "/architecture/overview" },
44-
// Version dropdown — implemented as a plain VitePress nav group.
45-
// vitepress-plugin-versions was evaluated but not adopted: it requires
46-
// a non-trivial CI setup for snapshot publishing and adds a runtime
47-
// dependency for a feature (multi-version docs) that is fully handled
48-
// by the CI snapshot job in issue #30. The nav item and
49-
// docs/public/versions.json are updated by that workflow.
58+
// Version dropdown — items are read from docs/public/versions.json.
59+
// The CI snapshot job prepends a new entry to that file on every major release;
60+
// the next main deploy re-builds this config and picks up the change automatically.
61+
// (vitepress-plugin-versions was evaluated but not adopted — see issue #30.)
5062
{
51-
text: "v1 ▾",
63+
text: `${versionsData[0].text} ▾`,
5264
items: [
53-
{ text: "v1 (latest)", link: "/" },
65+
...versionsData.map((v: { text: string; link: string }) => ({
66+
text: v.text,
67+
link: v.link,
68+
})),
5469
{
5570
text: "Releases",
5671
link: "https://github.com/fulll/github-code-search/releases",

0 commit comments

Comments
 (0)