Skip to content

Commit 4eb1140

Browse files
ci(docs-deploy): deploy the Object UI docs site (www.objectui.org) from ui/apps/site (#27005)
<!-- claude-projects-attribution: {"github_login":"os-tesla"} --> _Requested by **Tesla** · [project thread](https://claude.ai/code/project/chan_01AXsQkLFKRdQCqQ3RTr6Jao?thread=cmsg_01AXsQkLFKRdQCqQ3RTr6JaoE27UVDXhUp74pztDpSVFdR)_ Part of #26993. This PR carries the code half. The card stays open for its proof: one `workflow_dispatch` run of the new job on `main` that prints the deployment URL, after the maintainer action below. Tier H (`.github/workflows/**`): draft until green, GOVERNED_APPROVERS review it, the maintainer merges, and no seat enqueues it. Clause-②: no Metadata-protocol: none ## 维护者速读 - **改了什么**:根仓 `.github/workflows/docs-deploy.yml` 加第二个作业 `Deploy objectui docs to Vercel (production)`,和现有 `apps/docs` 作业同一套做法(runner 上 `vercel pull` → `vercel build --prod` → `vercel deploy --prebuilt --prod`),部署 `ui/apps/site` 到 Vercel 项目 `objectui`(www.objectui.org)。原 `apps/docs` 作业一个字没改。 - **为什么改**:objectui 仓自己的部署 workflow 随 `ui/.github/workflows/` 一起删了,`ui/apps/site/vercel.json` 又关了 Git 自动部署,所以合并后没有任何流程发布 www.objectui.org,18.2 之后的文档改动都上不了线。 - **风险与回滚**:只在 `main` 上按定时(每 6 小时)或手动触发运行,不影响任何 PR 检查。两个作业互相独立,新作业红了不影响 `apps/docs` 的部署。回滚 = revert 本 PR。 - **先看**:`.github/workflows/docs-deploy.yml` 末尾的 `deploy-ui-site` 作业,重点看 "Require the project's Root Directory to be ui/apps/site" 这一步和 build 步骤不带 token 的写法。 - **两分钟验证**:合并后在 Actions 页对 Docs Deploy 点 "Run workflow"(选 `main`)。Root Directory 改好之前,新作业会在 Root Directory 那一步红,报错里写明要改的设置;改好之后应该绿,并在 summary 里打印部署 URL。 - **需要你做的**:在 Vercel 控制台把项目 `objectui`(`prj_v1rXIczaI7YGmXmseQCLFUFOFxTB`)的 Settings → Build and Deployment → Root Directory 从 `apps/site` 改成 `ui/apps/site`,然后批准合并本 PR。 ## What changes - `.github/workflows/docs-deploy.yml`: - The header now names both sites and says the two jobs are independent. - New job `deploy-ui-site`, named `Deploy objectui docs to Vercel (production)`. It keeps the shape of the existing `deploy` job: - the same refusal steps: a ref other than `main`, then a missing `VERCEL_TOKEN`, each an `::error::` and a red run; - checkout and `./.github/actions/setup-workspace`; - `vercel pull` → `vercel build --prod` → `vercel deploy --prebuilt --prod`, all run from the repository root; - the same pinned `VERCEL_CLI_VERSION` (`60.1.3`) and the same team id; the project id is objectui's old one, `prj_v1rXIczaI7YGmXmseQCLFUFOFxTB`; - the post-build assertions against `ui/apps/site/.next/BUILD_ID` and `.vercel/output/config.json`; - the step-summary line with the deployment URL. - Two differences from `deploy`, both explained in the job's header: - A step after `vercel pull` reads `settings.rootDirectory` from the `.vercel/project.json` the pull wrote. It goes red, naming the dashboard setting and the value it needs, unless that reads `ui/apps/site`. The project's setting still reads `apps/site` from when the site lived in objectui. Without this step that would fail later inside `vercel build`, with an error that does not name the cause. - `vercel build` gets no `VERCEL_TOKEN`. Only `pull` and `deploy` call the Vercel API. This is the card's ask and objectui's original choice: the build runs every workspace package's lifecycle scripts. - Not ported, per the card: objectui's pinned-@objectstack restore, build and save steps. Every @objectstack package the site imports is a workspace package here. - The `deploy` job (apps/docs) is byte-for-byte unchanged. - `ui/apps/site/vercel.json` is unchanged. Its commands work in the merged layout, as measured below. ## Tests Cold local build of the exact production command, run the way Vercel runs it (cwd `ui/apps/site`, then `cd ../..`): <details><summary>`pnpm turbo run build --filter=@object-ui/site` from `ui/`, head 137ca90</summary> - `turbo run --dry=json` from `ui/` resolved this repository's root and scheduled the site with its whole closure: 67 build tasks, 30 in @object-ui packages and 37 in @objectstack packages (65 of them have work to do, per the run below). - The real run at `--concurrency=2`, under `scripts/pm/os-verify-lock.sh`: `Tasks: 65 successful, 65 total` · `Cached: 0 cached, 65 total` · `WALL 596s EXIT 0`. - `ui/apps/site/.next/BUILD_ID` was written. - `pnpm exec turbo --version` reads 2.11.5 from both the root and `ui/`, so the `cd ../..` into `ui/` does not pick up a different turbo. </details> The YAML parses: the jobs are `deploy` and `deploy-ui-site`, with 10 steps in the new job. ## Verification Derived gates (`node scripts/pm/dispatch-gates.mjs --commands`, 36 commands for this one-file diff). The 35 fast ones were run locally on 137ca90 and every one exited 0. They were run again on the final head 2defad3 (a comment-only change on top), and all 35 exited 0 again. The long one, `GITHUB_ACTIONS=true GITHUB_EVENT_NAME=push pnpm check:pm-dispatch-gates`, ran on 2defad3: `✓ dispatch-gates self-test: 2224 cases pass.` (fast 1935, slow 289), `EXIT 0`, 1191 s. <details><summary>Local gate list, each `:: exit 0`</summary> - `node scripts/check-closing-keyword-parity.mjs` - `node scripts/check-closing-keyword-parity.mjs --self-test` - `node scripts/check-comment-mask-corpus.mjs` - `node scripts/check-self-test-wired.mjs` - `node scripts/check-self-test-wired.mjs --self-test` - `node scripts/check-self-test-workflow-commands.mjs` - `node scripts/check-self-test-workflow-commands.mjs --self-test` - `node scripts/check-step-collectors.mjs` - `node scripts/check-step-collectors.mjs --self-test` - `node scripts/check-whole-set-label-write.mjs` - `node scripts/check-whole-set-label-write.mjs --self-test` - `node scripts/docs-audit/check-drift-comment.mjs` - `node scripts/pm/ci-failure.mjs --self-test` - `pnpm check:agent-test-spelling` - `pnpm check:aggregator-roster` - `pnpm check:cross-package-test-inputs` - `pnpm check:declared-population-live` - `pnpm check:driver-memory-census` - `pnpm check:gitlink-declared` - `pnpm check:node-version` - `pnpm check:nul-bytes` - `pnpm check:pm-expected-skips` - `pnpm check:pm-governed-merges` - `pnpm check:pm-post-stamped` - `pnpm check:pm-record-recognisers` - `pnpm check:pnpm-acquisition` - `pnpm check:pnpm-filter-targets` - `pnpm check:refd-timer-probe` - `pnpm check:required-contexts` - `pnpm check:shard-attestation` - `pnpm check:stall-guard-budget` - `pnpm check:stall-guard-headroom` - `pnpm check:watch-hint-literal` - `pnpm check:workflow-status-functions` - `pnpm check:workflow-step-name-quoting` </details> CI-only families are read from this PR's check-runs. NOT MEASURED, and what proves it: - `vercel pull`, the Root Directory step's reading of `.vercel/project.json` and the upload. They need `VERCEL_TOKEN`, which this container does not have. The `settings.rootDirectory` key is what the CLI's `pull` writes. The first `workflow_dispatch` run on `main` after the merge is the proof the card asks for. - Whether the organization's `VERCEL_TOKEN` can deploy to the `objectui` project. The token belongs to the same team as the `objectstack` project. This is part of the card's maintainer action. ## Acceptance notes - **No PR job builds `@object-ui/site`.** The card allowed adding one to a ui lane, or saying why not. Not added, for three reasons: - The build is the whole site closure: 65 tasks, 596 s cold on 2 workers here. `Build UI Deps` hands the ui jobs only its seven @objectstack packages, so the site's other 30 @objectstack packages and its @object-ui packages would build cold in every ui PR's run. That is a new advisory lane on the hottest filter. - A broken site build is not silent. The deploy job reds at most six hours after it lands on `main`, and "Run workflow" re-checks it at once. - The lane can be added later as one job, if the maintainer wants deploys predicted per PR. That choice is left on #26993 and on #26717's row 7 rather than taken here. - `ui/content/docs/guide/ci-cd-pipeline.md` still describes objectui's deleted `docs-deploy.yml` (its cron, its secret table row). That page's rewrite or retirement is #26944, so it is not touched here. --- _Generated by [Claude Code](https://claude.ai/code/session_01L9qibyAYPFxpNP4BCr7Z82)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 0eb2d21 commit 4eb1140

1 file changed

Lines changed: 149 additions & 2 deletions

File tree

‎.github/workflows/docs-deploy.yml‎

Lines changed: 149 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
11
name: Docs Deploy
22

3-
# The ONE path by which the docs site (Vercel project `objectstack`, Root
4-
# Directory `apps/docs`) reaches production.
3+
# The ONE path by which this repository's two docs sites reach production,
4+
# one job each:
5+
#
6+
# - `deploy`: the ObjectStack docs, Vercel project `objectstack`, Root
7+
# Directory `apps/docs`;
8+
# - `deploy-ui-site`: the Object UI docs at www.objectui.org, Vercel project
9+
# `objectui`, Root Directory `ui/apps/site`. That site came here with the
10+
# objectui tree; objectui's own copy of this workflow was deleted with the
11+
# rest of `ui/.github/workflows/`, and nothing else deploys it. Its header
12+
# below says what differs from `deploy`.
13+
#
14+
# Everything this header says applies to both jobs. The two are independent:
15+
# one going red does not stop or cancel the other.
516
#
617
# ## Why the build runs here and not on Vercel
718
#
@@ -206,3 +217,139 @@ jobs:
206217
echo
207218
echo "Deployment: ${{ steps.deploy.outputs.url || 'none (the run stopped before the deploy step finished)' }}"
208219
} >> "$GITHUB_STEP_SUMMARY"
220+
221+
# ── The Object UI docs site (www.objectui.org) ─────────────────────────────
222+
#
223+
# The same build-here, upload-prebuilt path as `deploy` above, for the Vercel
224+
# project `objectui`. `ui/apps/site/vercel.json` turns that project's Git
225+
# deployments off (`git.deploymentEnabled: false`), so this job is the only
226+
# thing that publishes the site, and every failure is red, as above.
227+
#
228+
# What differs from `deploy`, and why:
229+
#
230+
# - The project's Root Directory must read `ui/apps/site`. It read
231+
# `apps/site` while the site lived in the objectui repository, and it is
232+
# a dashboard setting that no file here can change. A step right after
233+
# `vercel pull` reads the setting the pull wrote and goes red, naming the
234+
# setting and its value, when it is anything else; without that step
235+
# the old value fails later inside `vercel build`, as an error that does
236+
# not say a dashboard setting is the cause.
237+
# - `vercel build` gets no token. It runs `vercel.json`'s install and build
238+
# commands, which run every workspace package's lifecycle scripts, and
239+
# it does not call the Vercel API. Only the `pull` and `deploy` steps,
240+
# which do, see VERCEL_TOKEN. objectui's own workflow made this choice
241+
# for the same reason.
242+
# - objectui's pinned-@objectstack restore and build steps are not ported.
243+
# In this repository every @objectstack package the site imports is a
244+
# workspace package, and `vercel.json`'s build command builds it from
245+
# this tree through turbo's `^build`.
246+
#
247+
# The site's own install and build commands live in `ui/apps/site/vercel.json`
248+
# and are unchanged from objectui: `pnpm i` installs this whole workspace from
249+
# any member directory, and its build command's `cd ../..` lands in `ui/`,
250+
# from which turbo resolves this repository's root and builds
251+
# `@object-ui/site` with its full closure (65 tasks, all built, on the
252+
# local run measured below).
253+
deploy-ui-site:
254+
name: Deploy objectui docs to Vercel (production)
255+
runs-on: ubuntu-latest
256+
# The build behind `vercel.json`'s command (the site, its @object-ui
257+
# packages and their @objectstack closure: 65 turbo tasks, none cached)
258+
# measured 596 s at `--concurrency=2` on a shared dev container; the runner
259+
# adds install and upload.
260+
timeout-minutes: 30
261+
env:
262+
# Identifiers, not credentials, as in `deploy`: the same team, and the
263+
# project that serves www.objectui.org.
264+
VERCEL_ORG_ID: team_06nvlGKZCkwhzdXmRdxeCNnB
265+
VERCEL_PROJECT_ID: prj_v1rXIczaI7YGmXmseQCLFUFOFxTB
266+
# The same pin as `deploy`'s VERCEL_CLI_VERSION; move the two together.
267+
VERCEL_CLI_VERSION: '60.1.3'
268+
# The value the project's Root Directory must have; see the header.
269+
VERCEL_ROOT_DIRECTORY: ui/apps/site
270+
steps:
271+
- name: Refuse any ref but main
272+
if: github.ref != 'refs/heads/main'
273+
run: |
274+
echo "::error::Docs Deploy publishes to PRODUCTION and runs only from main; this run is on ${GITHUB_REF}. Re-run it with 'main' selected in the branch picker."
275+
exit 1
276+
277+
- name: Require the Vercel token
278+
env:
279+
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
280+
run: |
281+
if [ -z "${VERCEL_TOKEN:-}" ]; then
282+
echo "::error::The secret VERCEL_TOKEN is not visible to this run, so www.objectui.org cannot be deployed and production is NOT being updated. It is provided as an objectstack-ai ORGANIZATION secret: check that it still exists and that this repository is in its repository access list (org Settings -> Secrets and variables -> Actions). Then re-run this workflow."
283+
exit 1
284+
fi
285+
echo "VERCEL_TOKEN is set."
286+
287+
- name: Checkout repository
288+
uses: actions/checkout@v7
289+
290+
- name: Setup workspace
291+
uses: ./.github/actions/setup-workspace
292+
293+
# From the repository root, for the reason `deploy`'s comment on this
294+
# step gives: the CLI applies the Root Directory relative to its cwd.
295+
- name: Pull the production project settings
296+
env:
297+
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
298+
run: npx --yes "vercel@${VERCEL_CLI_VERSION}" pull --yes --environment=production --token="$VERCEL_TOKEN"
299+
300+
- name: Require the project's Root Directory to be ui/apps/site
301+
run: |
302+
set -euo pipefail
303+
actual="$(node -e "
304+
const fs = require('node:fs');
305+
const file = '.vercel/project.json';
306+
if (!fs.existsSync(file)) { console.log('(vercel pull wrote no ' + file + ')'); process.exit(0); }
307+
const settings = JSON.parse(fs.readFileSync(file, 'utf8')).settings || {};
308+
console.log(settings.rootDirectory ?? '(not set)');
309+
")"
310+
if [ "$actual" != "$VERCEL_ROOT_DIRECTORY" ]; then
311+
echo "::error::The Vercel project ${VERCEL_PROJECT_ID} has Root Directory '${actual}', and this repository builds the site from '${VERCEL_ROOT_DIRECTORY}'. Nothing is deployed. A maintainer sets it in the Vercel dashboard: project objectui -> Settings -> Build and Deployment -> Root Directory = ${VERCEL_ROOT_DIRECTORY}. Then re-run this workflow."
312+
exit 1
313+
fi
314+
echo "Root Directory: ${actual}"
315+
316+
# No VERCEL_TOKEN here; see the header. TURBO_FORCE for the reason
317+
# `deploy`'s build step gives.
318+
- name: Build the site (vercel build --prod)
319+
env:
320+
TURBO_FORCE: 'true'
321+
run: npx --yes "vercel@${VERCEL_CLI_VERSION}" build --prod
322+
323+
- name: Assert the build produced a deployable output
324+
run: |
325+
set -euo pipefail
326+
if [ ! -f ui/apps/site/.next/BUILD_ID ]; then
327+
echo "::error file=ui/apps/site/vercel.json::vercel build exited 0 but produced no ui/apps/site/.next/BUILD_ID - the site was not built, so nothing is deployed."
328+
exit 1
329+
fi
330+
if [ ! -f .vercel/output/config.json ]; then
331+
echo "::error::vercel build exited 0 but wrote no .vercel/output/config.json at the repository root - there is no prebuilt output to deploy."
332+
exit 1
333+
fi
334+
echo "Built the objectui site: BUILD_ID=$(cat ui/apps/site/.next/BUILD_ID)"
335+
336+
- name: Deploy the prebuilt output to production
337+
id: deploy
338+
env:
339+
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
340+
run: |
341+
set -euo pipefail
342+
url=$(npx --yes "vercel@${VERCEL_CLI_VERSION}" deploy --prebuilt --prod --token="$VERCEL_TOKEN")
343+
echo "url=${url}" >> "$GITHUB_OUTPUT"
344+
echo "Deployed: ${url}"
345+
346+
- name: Publish the run to the summary
347+
if: always()
348+
run: |
349+
{
350+
echo "### Docs Deploy (www.objectui.org) — ${{ job.status }}"
351+
echo
352+
echo "Commit: \`${{ github.sha }}\` (${{ github.event_name }})"
353+
echo
354+
echo "Deployment: ${{ steps.deploy.outputs.url || 'none (the run stopped before the deploy step finished)' }}"
355+
} >> "$GITHUB_STEP_SUMMARY"

0 commit comments

Comments
 (0)