From 90b0ced86ed8c044702da66cc62ed3c6dd8c87c9 Mon Sep 17 00:00:00 2001 From: 2921323707 <2921323707@users.noreply.github.com> Date: Wed, 22 Jul 2026 23:20:14 +0800 Subject: [PATCH] ci: automate documentation deployment Co-Authored-By: Claude --- .github/dependabot.yml | 7 +++ .github/workflows/docs.yml | 105 +++++++++++++++++++++++++++++++++++++ docs/deploy.md | 22 +++++++- docs/zh/deploy.md | 22 +++++++- 4 files changed, 152 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/docs.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 02879ae..a7174ec 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -7,6 +7,13 @@ updates: groups: frontend-dependencies: patterns: ["*"] + - package-ecosystem: npm + directory: /docs + schedule: + interval: weekly + groups: + documentation-dependencies: + patterns: ["*"] - package-ecosystem: gomod directory: /server schedule: diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..bc1301c --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,105 @@ +name: Documentation + +on: + push: + branches: [main] + paths: + - 'docs/**' + - '.github/workflows/docs.yml' + pull_request: + paths: + - 'docs/**' + - '.github/workflows/docs.yml' + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: docs-production-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +jobs: + build: + name: Build VitePress site + runs-on: ubuntu-latest + defaults: + run: + working-directory: docs + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-node@v7 + with: + node-version: 22 + cache: npm + cache-dependency-path: docs/package-lock.json + - run: npm ci + - name: Add deployment revision + env: + DOCS_REVISION: ${{ github.sha }} + run: printf '%s\n' "$DOCS_REVISION" > public/revision.txt + - run: npm run build + - name: Verify generated routes + run: | + test -f .vitepress/dist/index.html + test -f .vitepress/dist/roadmap.html + test -f .vitepress/dist/zh/roadmap.html + test -f .vitepress/dist/revision.txt + - uses: actions/upload-artifact@v4 + with: + name: cpa-orbit-docs-${{ github.sha }} + path: docs/.vitepress/dist + if-no-files-found: error + retention-days: 14 + + deploy: + name: Deploy documentation + if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' + needs: build + runs-on: ubuntu-latest + environment: + name: documentation + url: http://165.154.205.54/cpa_orbit/ + steps: + - uses: actions/download-artifact@v4 + with: + name: cpa-orbit-docs-${{ github.sha }} + path: dist + - name: Configure SSH + env: + DOCS_SSH_PRIVATE_KEY: ${{ secrets.DOCS_SSH_PRIVATE_KEY }} + DOCS_SSH_KNOWN_HOSTS: ${{ secrets.DOCS_SSH_KNOWN_HOSTS }} + run: | + install -m 700 -d ~/.ssh + printf '%s\n' "$DOCS_SSH_PRIVATE_KEY" > ~/.ssh/docs_deploy + chmod 600 ~/.ssh/docs_deploy + printf '%s\n' "$DOCS_SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts + chmod 600 ~/.ssh/known_hosts + - name: Synchronize generated site + env: + DOCS_HOST: ${{ vars.DOCS_HOST }} + DOCS_SSH_PORT: ${{ vars.DOCS_SSH_PORT }} + DOCS_SSH_USER: ${{ vars.DOCS_SSH_USER }} + DOCS_DEPLOY_PATH: ${{ vars.DOCS_DEPLOY_PATH }} + run: | + : "${DOCS_HOST:?Set DOCS_HOST in the documentation environment}" + : "${DOCS_SSH_USER:?Set DOCS_SSH_USER in the documentation environment}" + : "${DOCS_DEPLOY_PATH:?Set DOCS_DEPLOY_PATH in the documentation environment}" + DOCS_SSH_PORT="${DOCS_SSH_PORT:-22}" + case "$DOCS_DEPLOY_PATH" in + /cpa_orbit|/cpa_orbit/) ;; + *) echo "Refusing unexpected deployment path: $DOCS_DEPLOY_PATH" >&2; exit 1 ;; + esac + rsync -az --delete --delay-updates \ + -e "ssh -i ~/.ssh/docs_deploy -p $DOCS_SSH_PORT" \ + dist/ "$DOCS_SSH_USER@$DOCS_HOST:${DOCS_DEPLOY_PATH%/}/" + - name: Verify public deployment + env: + DOCS_REVISION: ${{ github.sha }} + run: | + base='http://165.154.205.54/cpa_orbit' + curl --fail --silent --show-error --retry 5 --retry-delay 3 "$base/" >/dev/null + curl --fail --silent --show-error --retry 5 --retry-delay 3 "$base/roadmap" >/dev/null + curl --fail --silent --show-error --retry 5 --retry-delay 3 "$base/zh/roadmap" >/dev/null + curl --fail --silent --show-error --retry 5 --retry-delay 3 "$base/favicon.svg" >/dev/null + test "$(curl --fail --silent --show-error --retry 5 --retry-delay 3 "$base/revision.txt")" = "$DOCS_REVISION" diff --git a/docs/deploy.md b/docs/deploy.md index b25a174..8629e43 100644 --- a/docs/deploy.md +++ b/docs/deploy.md @@ -44,10 +44,28 @@ location ^~ /cpa_orbit/ { } ``` +## Automatic publication + +`docs/` is the single source for the online site, including [`roadmap.md`](./roadmap.md), which builds to `/cpa_orbit/roadmap`. The `Documentation` GitHub Actions workflow builds every documentation pull request and deploys documentation changes merged into `main`. + +Configure a GitHub environment named `documentation` with: + +| Name | Type | Purpose | +| --- | --- | --- | +| `DOCS_SSH_PRIVATE_KEY` | Secret | Private key for the restricted deployment account. | +| `DOCS_SSH_KNOWN_HOSTS` | Secret | Pinned SSH host-key entry for the documentation server. | +| `DOCS_HOST` | Variable | Deployment host, currently `165.154.205.54`. | +| `DOCS_SSH_USER` | Variable | Restricted SSH deployment user. | +| `DOCS_SSH_PORT` | Variable | SSH port; defaults to `22` when omitted. | +| `DOCS_DEPLOY_PATH` | Variable | Must be `/cpa_orbit`; the workflow refuses any other path. | + +The deployment account must have write access only to `/cpa_orbit`. The workflow uploads generated `dist/` files with `rsync`, removes stale generated files within that bounded directory, and then verifies the home, English/Chinese roadmap, favicon, and commit revision marker over HTTP. Use the workflow's manual dispatch to republish the current `main` documentation without a source change. + ## Release checks -- Direct refresh works on the home, guide, and modules routes. +- Direct refresh works on the home, guide, roadmap, and modules routes. - English is the default and the language menu opens the matching Chinese route. -- `/cpa_orbit/favicon.svg` and `/cpa_orbit/assets/` return 200. +- `/cpa_orbit/favicon.svg`, `/cpa_orbit/assets/`, and `/cpa_orbit/revision.txt` return 200. +- The deployed `revision.txt` matches the commit built by GitHub Actions. - Only the generated `dist/` contents are public. - Source, `.git/`, `node_modules/`, and local runtime data remain outside the web surface. diff --git a/docs/zh/deploy.md b/docs/zh/deploy.md index e98f04e..9337808 100644 --- a/docs/zh/deploy.md +++ b/docs/zh/deploy.md @@ -17,9 +17,27 @@ npm run build 发布目录为 `docs/.vitepress/dist/`。当前站点使用基础路径 `/cpa_orbit/`,可通过 **[CPA Orbit 在线文档](http://165.154.205.54/cpa_orbit/)** 直接访问。 +## 自动发布 + +`docs/` 是在线文档的唯一内容来源,其中 [`docs/roadmap.md`](../roadmap.md) 构建为 `/cpa_orbit/roadmap`,本文档的中文路线图构建为 `/cpa_orbit/zh/roadmap`。GitHub Actions 的 `Documentation` 工作流会构建每个文档 PR,并在文档改动合并到 `main` 后自动发布。 + +需要在 GitHub 中建立名为 `documentation` 的 Environment,并配置: + +| 名称 | 类型 | 用途 | +| --- | --- | --- | +| `DOCS_SSH_PRIVATE_KEY` | Secret | 受限部署账号的 SSH 私钥。 | +| `DOCS_SSH_KNOWN_HOSTS` | Secret | 文档服务器固定的 SSH host key。 | +| `DOCS_HOST` | Variable | 部署主机,当前为 `165.154.205.54`。 | +| `DOCS_SSH_USER` | Variable | 仅用于文档部署的 SSH 用户。 | +| `DOCS_SSH_PORT` | Variable | SSH 端口;未设置时使用 `22`。 | +| `DOCS_DEPLOY_PATH` | Variable | 必须为 `/cpa_orbit`,工作流会拒绝其他路径。 | + +部署账号应当仅能写入 `/cpa_orbit`。工作流通过 `rsync` 同步生成的 `dist/` 文件、清除该限定目录中的旧生成文件,然后通过 HTTP 验证首页、中英文路线图、favicon 以及提交 revision 标记。需要重新发布当前 `main` 文档而不改源码时,可以手动运行该工作流。 + ## 发布检查 -- 首页、指南与模块页面可以直接刷新。 +- 首页、指南、路线图与模块页面可以直接刷新。 - 默认显示英文,语言菜单可以切换到对应中文页面。 -- favicon 与静态资源返回 200。 +- `/cpa_orbit/favicon.svg`、`/cpa_orbit/assets/` 与 `/cpa_orbit/revision.txt` 返回 200。 +- 线上 `revision.txt` 与 GitHub Actions 构建的提交一致。 - 服务器只公开 `dist/`,不公开源码、`.git/`、`node_modules/` 或运行数据。