From 93ba1339ed71f80746a81605219ff1de8bcf1c1f Mon Sep 17 00:00:00 2001 From: jinjunnn Date: Fri, 3 Jul 2026 14:57:28 +0800 Subject: [PATCH] docs(ci): local-first CI standard + one-command local gate runner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add docs/CI.md (the CI 规范), scripts/alpha-check.sh (runs alpha-ci's three gates locally — north-star guard / typecheck / ui-mac tests — in seconds), an opt-in .githooks/pre-push, and a CLAUDE.md pointer. Principle: local-first — run the gates locally before push; CI is the enforcing backstop, not where failures first surface. Documents why only alpha-ci + sync-upstream are active (26 inherited upstream workflows disabled 2026-07-03: they need Blacksmith runners this fork lacks → queued forever = the real cause of "CI 卡/连不通"), plus a stuck-CI playbook. Additive alpha-owned files only; zero upstream edits. Co-Authored-By: Claude Opus 4.8 (1M context) --- .githooks/pre-push | 7 ++++ CLAUDE.md | 4 +++ docs/CI.md | 73 ++++++++++++++++++++++++++++++++++++++++++ scripts/alpha-check.sh | 52 ++++++++++++++++++++++++++++++ 4 files changed, 136 insertions(+) create mode 100755 .githooks/pre-push create mode 100644 docs/CI.md create mode 100755 scripts/alpha-check.sh diff --git a/.githooks/pre-push b/.githooks/pre-push new file mode 100755 index 000000000000..add85c993262 --- /dev/null +++ b/.githooks/pre-push @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +# alpha pre-push hook — enforce local-first (docs/CI.md). +# OPT-IN, not installed by default. Enable once with: +# git config core.hooksPath .githooks +# Disable with: git config --unset core.hooksPath +# Bypass a single push: git push --no-verify +exec bash "$(git rev-parse --show-toplevel)/scripts/alpha-check.sh" diff --git a/CLAUDE.md b/CLAUDE.md index f12380207218..215ac393cd78 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -34,4 +34,8 @@ ``` bun install bun --cwd packages/ui-mac run dev # electron 解析失败时加 ELECTRON_EXEC_PATH(见 ALPHA.md) +bash scripts/alpha-check.sh # push 前自检:北极星守卫 + typecheck + 单测(与 alpha-ci 1:1) ``` + +## CI(规范见 `docs/CI.md`) +**本地先跑,CI 兜底**。push 前必过 `scripts/alpha-check.sh`。GitHub 上只有 `alpha-ci`(三关,required)+ `sync-upstream` 两个 workflow active;继承的 ~26 个上游 workflow 已禁用(要 Blacksmith runner,本 fork 没有 → 永久 queued,即"CI 卡"真因)。排查手册见 `docs/CI.md` §5。 diff --git a/docs/CI.md b/docs/CI.md new file mode 100644 index 000000000000..7e1a6dc4d988 --- /dev/null +++ b/docs/CI.md @@ -0,0 +1,73 @@ +# CI 规范(alpha-code) + +> 一句话:**本地先跑,CI 兜底**。CI 不是你第一次看到失败的地方——它是 merge 前的强制关卡。 +> 权威触发定义在 `.github/workflows/alpha-ci.yml`;北极星守卫语义见 ADR-004,fork 纪律见 ADR-005。 + +## 0. TL;DR — push 前一条命令 + +```bash +bash scripts/alpha-check.sh +``` + +绿了再 push。它跑的就是 `alpha-ci` 的三关(北极星守卫 / typecheck / 单测),本地几秒出结果,和 CI 1:1 一致。 + +## 1. 为什么 local-first(优先本地跑) + +- **快**:本地三关秒级;CI 往返一轮 = 排队 + 起机 + 装依赖 + 跑,分钟级。 +- **省往返**:把 CI 当"第一次跑"= 每个错都要等一轮红了才知道 → 慢、烦、还堵别人的队。 +- **CI 的真正职责**是①**强制门禁**(branch protection:不绿不让 merge,挡手滑)②**中立环境兜底**(抓"在我机器上是好的"那类环境差异)——不是给你当调试台用的。 +- 所以顺序永远是:**本地 `alpha-check` 绿 → push → CI 复核 → merge**。 + +## 2. 三关是什么(与 `alpha-ci` 1:1) + +| 关 | 本地命令 | CI job | 失败含义 | +|---|---|---|---| +| **北极星守卫**(零改上游) | `scripts/alpha-check.sh` 内含;等价 `git diff --diff-filter=DMR --name-only origin/dev...HEAD -- <上游7包>` 必须空 | `north-star guard (zero upstream edits)` | 改了上游文件 → 下次 fork-sync 冲突,破北极星 | +| **typecheck**(两个 alpha 包) | `bun --cwd packages/ext run typecheck` + `bun --cwd packages/ui-mac run typecheck` | `typecheck (alpha packages)` | 类型不过 | +| **单元测试**(ui-mac) | `bun --cwd packages/ui-mac test` | `unit tests (ui-mac)` | 安全路径守卫等回归 | + +- **上游 7 包** = `packages/{opencode,core,server,app,ui,tui,sdk}`(见 alpha-ci.yml `env.UPSTREAM_PATHS`)。 +- **bun 版本钉 `1.3.14`**(与 CI 一致,根 `package.json` 的 `packageManager`)。本机版本不同先对齐。 +- 根 `bun test` 被故意禁用(`do not run tests from root`)——测试按包跑,别在根跑。 + +## 3. GitHub 上只跑两个 workflow(其余上游的已禁用) + +本仓是 opencode 的 fork,继承了 ~26 个上游 workflow。它们要上游订阅的 **Blacksmith 自建 runner**(如 `runs-on: blacksmith-4vcpu-ubuntu-2404`),本 fork 没有这种机器 → 一触发就永久 `queued` 挂死。**这是历史上"CI 一直卡 / 连不通"的真因**(不是 API、不是限流、不是 alpha-ci)。 + +2026-07-03 已 `gh workflow disable` 全部上游 workflow,**只保留**: + +| workflow | 作用 | 触发 | +|---|---|---| +| **`alpha-ci`** | 本仓 CI(上面三关) | `push` / `pull_request` → `alpha`;也可 `workflow_dispatch` | +| **`sync-upstream`** | 每日上游 `dev → merge alpha` 同步 | 定时 + 手动 | + +- **required check 只有 `alpha-ci` 的三个 job**;其它 workflow 一律**不影响 merge**(PR 上若看到别的 check = 历史残留,忽略)。 +- **不要盲目 `gh workflow enable`** 上游那些——除非你真给 fork 接了对应 runner。要恢复某个:`gh workflow enable .yml`(可逆,文件没删)。 + +## 4. 提交纪律 + +1. push 前 `bash scripts/alpha-check.sh` **必须绿**。 +2. 需要新增能力 → 走 alpha 自有文件(`packages/ext`、`packages/ui-mac`)或接缝(tool/plugin/MCP/sidecar,ADR-002/005),**绝不改上游 7 包**(改了北极星守卫本地就红)。 +3. 短命 `feat/*` / `fix/*` 分支 → PR → squash 合回 `alpha` → **合后即删分支**(ADR-005)。 +4. 想把 local-first 变**强制** → 装 §6 的 pre-push 钩子。 + +## 5. CI 卡住了怎么办(排查手册) + +1. **先分清谁卡**:`gh run list` 看是哪个 workflow。`alpha-ci` 卡 = 真问题;别的 = 已禁用的僵尸,忽略/取消。 +2. **queued(排队) vs in_progress(在跑但慢)**: + - 一直 `queued` = 等 runner(无匹配 runner / Actions 额度耗尽 / 并发上限); + - `in_progress` 慢 = job 本身慢(装依赖 / 测试)——那才是 REQ-009 缓存优化的场景。 +3. **命令**:`gh run cancel ` 取消 · `gh run watch ` 盯 · `gh run rerun ` 重跑 · `gh run list --workflow=alpha-ci.yml` 只看本仓 CI。 +4. **别被堵**:本地三关已绿 = 代码没问题;required 只有 alpha-ci 三个。真急可 `gh pr merge --admin` 绕过(慎用,别养成习惯)。 + +## 6. (可选)pre-push 钩子 —— 把 local-first 变强制 + +默认**不装**(不打断急活)。想要强约束: + +```bash +git config core.hooksPath .githooks # 一次性开启;仓库已带 .githooks/pre-push +# 关闭: git config --unset core.hooksPath +# 单次绕过: git push --no-verify +``` + +开启后每次 `git push` 会先跑 `scripts/alpha-check.sh`,不绿不让推。 diff --git a/scripts/alpha-check.sh b/scripts/alpha-check.sh new file mode 100755 index 000000000000..cf8d655f9d9b --- /dev/null +++ b/scripts/alpha-check.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +# alpha-check — run the exact gates alpha-ci enforces, LOCALLY, before you push. +# +# Standard: local-first (see docs/CI.md). CI is the enforcing backstop, not the place +# you first discover a failure. This mirrors alpha-ci's three jobs 1:1 and runs in seconds. +# +# bash scripts/alpha-check.sh +# +# Exit 0 = safe to push (CI will mirror this). Non-zero = fix before pushing. +set -uo pipefail +cd "$(git rev-parse --show-toplevel)" + +# Keep in lockstep with .github/workflows/alpha-ci.yml (env.UPSTREAM_PATHS) and ADR-004. +UPSTREAM_PATHS="packages/opencode packages/core packages/server packages/app packages/ui packages/tui packages/sdk" +fail=0 + +echo "▶ [1/3] north-star guard (zero upstream edits)" +git fetch --no-tags origin dev --quiet 2>/dev/null || echo " (warn: could not fetch origin/dev — comparing against last-known origin/dev)" +# committed delta (mirrors CI) ∪ working-tree edits (earlier local feedback) +committed="$(git diff --diff-filter=DMR --name-only origin/dev...HEAD -- $UPSTREAM_PATHS 2>/dev/null || true)" +worktree="$(git diff --diff-filter=DMR --name-only HEAD -- $UPSTREAM_PATHS 2>/dev/null || true)" +changed="$(printf '%s\n%s\n' "$committed" "$worktree" | sed '/^$/d' | sort -u)" +if [ -n "$changed" ]; then + echo " ✗ upstream files modified/deleted/renamed (fork-sync would conflict):" + echo "$changed" | sed 's/^/ /' + echo " → revert; extend via alpha files (packages/ext, packages/ui-mac) or seams (ADR-002/005)." + fail=1 +else + echo " ✓ zero upstream package edits" +fi + +echo "▶ [2/3] typecheck (alpha packages: ext + ui-mac)" +if bun --cwd packages/ext run typecheck && bun --cwd packages/ui-mac run typecheck; then + echo " ✓ typecheck" +else + echo " ✗ typecheck failed"; fail=1 +fi + +echo "▶ [3/3] unit tests (ui-mac)" +if bun --cwd packages/ui-mac test; then + echo " ✓ tests" +else + echo " ✗ tests failed"; fail=1 +fi + +echo +if [ "$fail" -eq 0 ]; then + echo "✅ all local gates green — safe to push (alpha-ci will mirror this in ~40s)." +else + echo "❌ local gates failed — fix before pushing (alpha-ci would fail the same way)." +fi +exit $fail