Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
232 changes: 192 additions & 40 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
# ─────────────────────────────────────────────────────────────
# VextJS 文档站 — GitHub Pages 自动部署
# VextJS 文档站 — 保留源码仓库 Pages,并新增组织根站点
#
# 触发条件:
# - main 的 push-triggered CI 成功后,部署该次 CI 的精确 SHA
# - 手动触发(workflow_dispatch)
# - 在 main 手动触发(workflow_dispatch)
#
# 流水线结构:
# 1. build — 在 website/ 目录安装依赖并执行 rspress build
# 2. deploy — 部署到当前仓库 GitHub Pages: /vextjs/
# 2. deploy-pages — 保留源码仓库的 /vextjs/ Pages 发布
# 3. deploy-organization — 新增独立组织根站点 https://vextjs.github.io/
#
# 首次配置:目标仓库初始化 main,Pages 选择 main / (root),
# 添加可写 Deploy Key,并在源码仓库保存 VEXT_DOCS_DEPLOY_KEY。
#
# @see website/package.json §scripts
# @see https://rspress.dev/guide/start/deploy
Expand All @@ -23,16 +27,12 @@ on:
- main
workflow_dispatch:

# 同一分支同时只允许一个部署运行,新运行会取消旧运行
concurrency:
group: pages-${{ github.event.workflow_run.head_branch || github.ref_name || github.run_id }}
cancel-in-progress: true

# GitHub Pages 部署所需权限
# 源码与产物读取使用 GITHUB_TOKEN;目标仓库写入使用专用 SSH Deploy Key。
permissions:
contents: read
pages: write
id-token: write

env:
DEPLOY_SHA: ${{ github.event.workflow_run.head_sha || github.sha }}

# ── Jobs ─────────────────────────────────────────────────────

Expand All @@ -41,28 +41,43 @@ jobs:
# 1. 构建文档站
# ────────────────────────────────────────────────────────────
build:
name: Build Docs
name: Build Docs (${{ matrix.site }})
runs-on: ubuntu-latest
if: >-
${{
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main') ||
(
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'push' &&
github.event.workflow_run.head_branch == 'main'
github.event.workflow_run.head_branch == 'main' &&
github.event.workflow_run.head_repository.full_name == github.repository
)
}}
permissions:
contents: read
pages: write
strategy:
fail-fast: false
matrix:
include:
- site: project
base: /vextjs/
url: https://devcodex-labs.github.io/vextjs
- site: organization
base: /
url: https://vextjs.github.io
env:
DEPLOY_SHA: ${{ github.event.workflow_run.head_sha || github.sha }}
VEXT_DOCS_BASE: ${{ matrix.base }}
VEXT_DOCS_SITE_URL: ${{ matrix.url }}
steps:
- name: Checkout
uses: actions/checkout@v7
with:
fetch-depth: 0 # 获取完整提交历史,rspress lastUpdated 功能需要
ref: ${{ env.DEPLOY_SHA }}
persist-credentials: false

- name: Verify deployment commit
if: github.event_name == 'workflow_run'
shell: bash
run: |
ACTUAL_SHA=$(git rev-parse HEAD)
Expand All @@ -71,14 +86,7 @@ jobs:
echo "Checked out SHA: $ACTUAL_SHA"
exit 1
fi
echo "Deploying successful CI SHA: $ACTUAL_SHA"

- name: Resolve deployment target
id: target
shell: bash
run: |
echo "docs_base=/vextjs/" >> "$GITHUB_OUTPUT"
echo "site_url=https://devcodex-labs.github.io/vextjs" >> "$GITHUB_OUTPUT"
echo "Building deployment SHA: $ACTUAL_SHA"

- name: Setup Node.js
uses: actions/setup-node@v7
Expand All @@ -87,7 +95,8 @@ jobs:
cache: "npm"
cache-dependency-path: website/package-lock.json

- name: Setup GitHub Pages
- name: Setup source repository Pages
if: matrix.site == 'project'
uses: actions/configure-pages@v6

- name: Install dependencies
Expand All @@ -106,47 +115,190 @@ jobs:
run: npm run build:publish -- --rollout=final
env:
NODE_ENV: production
VEXT_DOCS_BASE: ${{ steps.target.outputs.docs_base }}
VEXT_DOCS_SITE_URL: ${{ steps.target.outputs.site_url }}

- name: Rewrite robots sitemap URL
- name: Prepare Pages files
shell: bash
run: |
cat > website/dist/robots.txt <<EOF
User-agent: *
Allow: /

Sitemap: ${{ steps.target.outputs.site_url }}/sitemap.xml
Sitemap: ${VEXT_DOCS_SITE_URL}/sitemap.xml
EOF
touch website/dist/.nojekyll

- name: Upload docs artifact
uses: actions/upload-artifact@v7
with:
name: docs-dist
name: docs-dist-${{ matrix.site }}
path: website/dist
if-no-files-found: error
include-hidden-files: true

- name: Upload artifact
- name: Upload source repository Pages artifact
if: matrix.site == 'project'
uses: actions/upload-pages-artifact@v5
with:
path: website/dist

# ────────────────────────────────────────────────────────────
# 2a. 部署到当前仓库 GitHub Pages
# ────────────────────────────────────────────────────────────
deploy-pages:
name: Deploy to GitHub Pages
# 在进入发布并发组前跳过旧 CI 的迟到构建。
prepare-deployment:
name: Check deployment prerequisites
runs-on: ubuntu-latest
needs: build
outputs:
current: ${{ steps.current.outputs.publish }}
organization_ready: ${{ steps.organization.outputs.ready }}
steps:
- name: Check current main commit
id: current
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
CURRENT_SHA=$(gh api "repos/${GITHUB_REPOSITORY}/git/ref/heads/main" --jq '.object.sha')
if [[ "$CURRENT_SHA" == "$DEPLOY_SHA" ]]; then
echo "publish=true" >> "$GITHUB_OUTPUT"
else
echo "Skipping superseded build: $DEPLOY_SHA (main is $CURRENT_SHA)"
echo "publish=false" >> "$GITHUB_OUTPUT"
fi

- name: Check organization deployment setup
id: organization
if: steps.current.outputs.publish == 'true'
env:
DOCS_DEPLOY_KEY: ${{ secrets.VEXT_DOCS_DEPLOY_KEY }}
shell: bash
run: |
if [[ -n "$DOCS_DEPLOY_KEY" ]]; then
echo "ready=true" >> "$GITHUB_OUTPUT"
else
echo "ready=false" >> "$GITHUB_OUTPUT"
echo "::notice::Skipping organization Pages publication until VEXT_DOCS_DEPLOY_KEY is configured."
fi

# 原源码仓库 Pages 保留官方 Actions 发布流程,与组织站点并行。
deploy-pages:
name: Publish source repository Pages
runs-on: ubuntu-latest
needs: prepare-deployment
if: needs.prepare-deployment.outputs.current == 'true'
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: vextjs-docs-project
cancel-in-progress: false
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}

steps:
- name: Deploy to GitHub Pages
- name: Check current main commit
id: current
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
CURRENT_SHA=$(gh api "repos/${GITHUB_REPOSITORY}/git/ref/heads/main" --jq '.object.sha')
if [[ "$CURRENT_SHA" == "$DEPLOY_SHA" ]]; then
echo "publish=true" >> "$GITHUB_OUTPUT"
else
echo "Skipping superseded build: $DEPLOY_SHA (main is $CURRENT_SHA)"
echo "publish=false" >> "$GITHUB_OUTPUT"
fi

- name: Deploy source repository Pages
if: steps.current.outputs.publish == 'true'
id: deployment
uses: actions/deploy-pages@v5

- name: Print deployment URL
# ────────────────────────────────────────────────────────────
# 新增组织根站点;其密钥或推送失败不阻止原站点的独立发布任务。
# ────────────────────────────────────────────────────────────
deploy-organization:
name: Publish to vextjs.github.io
runs-on: ubuntu-latest
needs: prepare-deployment
if: >-
needs.prepare-deployment.outputs.current == 'true' &&
needs.prepare-deployment.outputs.organization_ready == 'true'

# 只串行化已通过构建且仍对应 main 的发布,不中断正在进行的 Git 推送。
concurrency:
group: vextjs-docs-organization
cancel-in-progress: false

environment:
name: organization-docs
url: https://vextjs.github.io/

env:
DOCS_PUBLISH_REPOSITORY: vextjs/vextjs.github.io
VEXT_DOCS_SITE_URL: https://vextjs.github.io

steps:
- name: Check current main commit
id: current
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
CURRENT_SHA=$(gh api "repos/${GITHUB_REPOSITORY}/git/ref/heads/main" --jq '.object.sha')
if [[ "$CURRENT_SHA" != "$DEPLOY_SHA" ]]; then
echo "Skipping superseded build: $DEPLOY_SHA (main is $CURRENT_SHA)"
echo "publish=false" >> "$GITHUB_OUTPUT"
else
echo "publish=true" >> "$GITHUB_OUTPUT"
fi

- name: Verify deployment key
if: steps.current.outputs.publish == 'true'
env:
DOCS_DEPLOY_KEY: ${{ secrets.VEXT_DOCS_DEPLOY_KEY }}
shell: bash
run: |
if [[ -z "$DOCS_DEPLOY_KEY" ]]; then
echo "::error::Set VEXT_DOCS_DEPLOY_KEY to the writable Deploy Key for ${DOCS_PUBLISH_REPOSITORY}."
exit 1
fi

- name: Checkout Pages repository
if: steps.current.outputs.publish == 'true'
uses: actions/checkout@v7
with:
repository: ${{ env.DOCS_PUBLISH_REPOSITORY }}
ref: main
path: site
ssh-key: ${{ secrets.VEXT_DOCS_DEPLOY_KEY }}

- name: Download verified docs
if: steps.current.outputs.publish == 'true'
uses: actions/download-artifact@v8
with:
name: docs-dist-organization
path: docs-dist

- name: Publish verified docs
if: steps.current.outputs.publish == 'true'
shell: bash
run: |
echo "✅ 文档站已部署至: ${{ steps.deployment.outputs.page_url }}"
test -f docs-dist/index.html
test -f docs-dist/zh/index.html
test -f docs-dist/docs-manifest.json
test -f docs-dist/sitemap.xml
git -C site rm -r --ignore-unmatch -- .
cp -a docs-dist/. site/
touch site/.nojekyll
cd site
git config user.name 'github-actions[bot]'
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
git add --all
if git diff --cached --quiet; then
echo "Documentation is already current."
else
git commit -m "docs: publish ${DEPLOY_SHA}"
git push origin HEAD:main
fi
echo "Published to ${DOCS_PUBLISH_REPOSITORY}; Pages will update ${VEXT_DOCS_SITE_URL}/"
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ AI-first describes the engineering surface: conventions, scaffolding, typed cont

The npm package name is `vextjs`; the CLI binary is `vext`. Requires Node.js **`^20.19.0 || >=22.12.0`**. Cold-start from the registry with **`npx vextjs …`**. After install, use project scripts or local `npx vext`.

**Docs:** https://devcodex-labs.github.io/vextjs/ · **Migration:** [MIGRATION.md](./MIGRATION.md) · **Changelog:** [CHANGELOG.md](./CHANGELOG.md)
**Docs:** https://devcodex-labs.github.io/vextjs/ · **Organization docs:** https://vextjs.github.io/ · **Migration:** [MIGRATION.md](./MIGRATION.md) · **Changelog:** [CHANGELOG.md](./CHANGELOG.md)

---

Expand Down
10 changes: 5 additions & 5 deletions scripts/validation/verify-documentation-contract.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1908,6 +1908,7 @@ function verifyReadmePublicEntryContract() {
"res.render",
"Apache-2.0",
"https://devcodex-labs.github.io/vextjs/",
"https://vextjs.github.io/",
"https://github.com/devcodex-labs/vextjs",
"https://devcodex-labs.github.io/vextjs/llms.txt",
"https://devcodex-labs.github.io/vextjs/capabilities.json",
Expand All @@ -1932,7 +1933,6 @@ function verifyReadmePublicEntryContract() {
"rateLimit.enabled: true",
]);
forbidTokens("README.md", [
"vextjs.github.io",
"github.com/vextjs/vext",
"License: MIT",
"Node.js-%3E%3D18.0.0",
Expand Down Expand Up @@ -2616,17 +2616,17 @@ function verifyRenderedMachineArtifacts() {
locale: "en",
indexName: "llms.txt",
fullName: "llms-full.txt",
fullUrl: "https://devcodex-labs.github.io/vextjs/llms-full.txt",
alternateUrl: "https://devcodex-labs.github.io/vextjs/zh/llms.txt",
fullUrl: `${siteUrl}/llms-full.txt`,
alternateUrl: `${siteUrl}/zh/llms.txt`,
optionalHeading: "## Other language",
forbiddenOptionalHeading: "## Optional",
},
{
locale: "zh",
indexName: "zh/llms.txt",
fullName: "zh/llms-full.txt",
fullUrl: "https://devcodex-labs.github.io/vextjs/zh/llms-full.txt",
alternateUrl: "https://devcodex-labs.github.io/vextjs/llms.txt",
fullUrl: `${siteUrl}/zh/llms-full.txt`,
alternateUrl: `${siteUrl}/llms.txt`,
optionalHeading: "## 可选语言",
forbiddenOptionalHeading: "## Optional",
},
Expand Down
19 changes: 18 additions & 1 deletion website/docs/en/guide/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -887,7 +887,24 @@ Run Job schedulers and workers as processes separate from HTTP. `npx vextjs job

## Publish the documentation site

When maintaining this VextJS repository, `.github/workflows/docs.yml` publishes the documentation to [GitHub Pages](https://devcodex-labs.github.io/vextjs/) with base path `/vextjs/`. Automatic publishing follows a successful main push CI and checks out that exact SHA. This is separate from application deployment above. The DevCodex Labs organization homepage is maintained in a separate repository.
When maintaining this VextJS repository, documentation sources remain in `devcodex-labs/vextjs`. The same commit is published to two documentation sites. These are separate from application deployment above.

| Site | URL | Base path | Publishing method |
| ------------------------------- | ---------------------------------------------------------------------------------- | ---------- | -------------------------------------------------------------------------------------------------------------- |
| Source repository documentation | [https://devcodex-labs.github.io/vextjs/](https://devcodex-labs.github.io/vextjs/) | `/vextjs/` | GitHub Actions Pages deployment in the source repository |
| Organization documentation | [https://vextjs.github.io/](https://vextjs.github.io/) | `/` | Push to the separate public repository `vextjs/vextjs.github.io`, then publish through that repository's Pages |

Keep **GitHub Actions** selected in the source repository's `Settings → Pages → Source`. Complete this setup once for the additional organization site; subsequent builds publish automatically:

1. Create the public repository `vextjs.github.io` in the `vextjs` organization and initialize its `main` branch. This repository is reserved for build output: publishing replaces the site files at its root, removes stale output, and preserves Git commit history.
2. Create a dedicated SSH Deploy Key for that repository. Add the public key in the site repository's `Settings → Deploy keys` with **Allow write access** enabled. Save the private key as `VEXT_DOCS_DEPLOY_KEY` in the source repository's `Settings → Secrets and variables → Actions`. Never put the private key in source code, documentation, or chat messages.
3. In the site repository's `Settings → Pages`, select **Deploy from a branch**, branch **main**, and folder **/(root)**. The repository name determines the organization root URL; no CNAME is needed.

`.github/workflows/docs.yml` builds with Node.js 22 and sets `VEXT_DOCS_BASE` and `VEXT_DOCS_SITE_URL` separately for the paths and URLs in the table. Both artifacts are validated and uploaded separately to keep root-path assets distinct from `/vextjs/` assets. Automatic publishing follows a successful source-repository `main` push CI and checks out that exact SHA.

After both builds and their complete documentation publishing checks pass, independent publishing jobs start: the source repository uses a Pages artifact and the built-in `GITHUB_TOKEN`; the organization site uses `VEXT_DOCS_DEPLOY_KEY` to push its output. Until that key is configured, the workflow skips organization publication with a notice and continues publishing the source site. After setup, a failed organization push also does not block the source repository's publishing job. Either build failing prevents both sites from publishing in that run. Before publishing, each job checks the current source `main` commit and skips builds superseded by a later commit.

To rebuild and republish both sites, select `main` in the source repository's `Actions → Deploy Docs → Run workflow`. This manual entry also runs the complete documentation checks; other branches cannot publish to the production site through it. After the organization site's push succeeds, wait for the target repository's Pages publishing job to finish before checking the updated site.

## Next step

Expand Down
Loading
Loading