Files
crearte-monorepo/docs/specs/2026-09-30-ci-test-baseline-design.md
T

8.2 KiB
Raw Blame History

P2 CI + 测试基线 — 设计规格

日期:2026-09-30 | 状态:已批准(用户指令:写计划、派子代理、端到端交付、不再提问) 涉及仓库:crearte-server(GitHub 私有)、crearte-deploy(GitHub 私有)、crearte(GitHub 公开) 前置事实:P0/P1/P4/P5 已交付;crearte/.github/workflows/validate.yml 已存在(pull_request 触发,node 24,check + e2e 两 job);后端/部署仓零 CI。

1. 问题定义(ROADMAP 原文拆解)

  1. 后端/部署仓无 CI → 两仓各建 validate.yml,风格对齐前端现有文件。
  2. Postgres 集成层静默 skip → 后端 CI 必须有真实 Postgres service,且当且仅当集成测试真的跑了才算绿(skip 在 CI 上下文里视为失败)。
  3. e2e:stack 全链路 → 真栈 Playwright full-loop 首次进 CI(宿主仓因凭据限制定为 crearte-server,见 2.2 修订)。

2. 范围决策

2.1 crearte-server validate.yml(新文件)

  • 触发:pull_request(paths: src/**、workflow 自身)+ push: master。与前端文件同构。
  • Job check(无 DB):gofmt -l 空断言 → go vet ./... → go build ./... → go test ./...。pg-gated 在此 job 正常 skip(语义与本地开发一致)。
  • Job integration:GitHub services: postgres(postgres:17-alpine,与 crearte-deploy 所用镜像一致,user/pass/db = crearte);TEST_DATABASE_URL 指向空库——集成测试自带 repository.Migrate 引导(migrate_test.go:testDB sync.Once + Migrate;service 层 gated 测试也各自 Migrate),所以空库即全量真跑,同时白赚一条"从空库可完整迁移"的每 PR 回归。
    • go test -v -count=1 -p 1 ./...:-p 1 必须——各 gated 测试对共享表做 TRUNCATE,包间并行(默认并行度)必互相踩踏;-p 1 序列化包执行是既有测试写法(不改测试)下唯一的正确姿势。
    • skip 守卫:tee 落日志后 grep 'skipping postgres integration test' 命中即 FAIL(pipefail 显式开)。没有守卫,这个 job 退化成 check 的复读机。
  • Go 版本:actions/setup-go@v5 + go-version-file: src/go.mod(1.24.1)+ cache-dependency-path: src/go.sum。

2.2 真栈 e2e 的宿主仓:放在 crearte-server,不放 crearte(计划阶段勘察后的范围修订)

原稿把 e2e-stack 挂进 crearte CI——勘察后不可行:XingfenD/crearte-server 是私有仓(GitHub API 404 验证),公开仓的 workflow 用默认 token 无法 checkout 它;本机无 GitHub API 凭据,不能自助签发 PAT。反向则天然可行:server 的 workflow checkout 公开的 crearte 无需任何 token。

修订后的布局:

  • e2e-stack job 落进 crearte-server 的 validate.yml:双 checkout(server=默认 token,crearte=公开无 token,均带 path)+ setup-go(go-version-file 指向 server 仓内 go.mod)+ node 24 + playwright chromium;env CREARTE_STACK_BACKEND_REF: ${{ github.sha }}——直接测 PR 那个后端 commit,信号强于拉 master(原布局只能测 master 后端)。路径适配:两仓 path 必须使 dirname(REPO_ROOT)/crearte-server 命中兄弟仓(即 path: crearte 与 path: crearte-server 同级);脚本用 $BACKEND/.git 的 origin 去 fetch SHA(GitHub 允许 fetch 任意 commit SHA)。working-directory 全部 crearte/src。
  • crearte 仓的改动缩小为:e2e-stack.sh 支持 CREARTE_STACK_GO(显式指定 go 二进制,解 runner 上 /usr/local/go/bin/go 版本地板假绿隐患;不设即旧逻辑,本地零变化)与 CREARTE_STACK_REQUIRED(置 1 时栈起不来直接 exit 1,封死“CI 里静默 skip=假绿”通道;不设即本地 skip 模式);validate.yml 补 push: branches: [master] 触发(既有两 job 不动);CHANGELOG 0.17.0。server CI 的 e2e-stack job 设这两个 env。
  • full-loop 假绿风险由 REQUIRED 模式从根上封死:webServer 命令非零退出 → playwright job 红。无需 JSON 报告器断言,不赌 reporter 输出格式。
  • 已接受的限制(如实记录):纯前端 PR(只动 crearte)不再有真栈 e2e 信号,改由 server 侧每次 PR/push 带最新 crearte master 补位(前端变更合入后即被覆盖);若 owner 日后在 crearte 仓配 STACK_BACKEND_TOKEN secret,可镜像同构 job 回 crearte——列为可选增强,不阻塞交付。

2.3 crearte-deploy validate.yml(新文件)

  • 无编译产物,CI 价值 = compose 健全性:docker compose --profile dev --profile prod --profile full config -q(:? 守卫变量注入假值,另测缺 POSTGRES_PASSWORD 必须非零退出,证明守卫没被无声旁路)。
  • config 不校验 bind 路径存在性,故 ../crearte 挂载在单仓 checkout 下也能过——如实记录:单仓 config ≠ 可部署;跨仓挂载完整性仍由本 monorepo 演练承担(P1 已证)。deploy 仓 README「单仓 clone」小节加一行指向本 spec,防误读。
  • deploy 的 AGENTS.md「no host-run workflows」指本机别跑 npm/go;GH Actions 跑 compose config 不落任何宿主机进程,不违反。
  • CHANGELOG 新 patch 条目(双语)。

2.4 全局非目标

  • 不做分支保护:无 GitHub API 凭据(gh 缺失、token 库空),owner 在 Settings→Branches 手动开启(server/deploy 必开,crearte 建议开)。写进 spec 交付清单,不进计划任务。
  • 不验证 Actions 已启用:私有仓 Actions 可能因计划限制未开/额度耗尽——推送后无 API 可查证。如实交付:计划里把「owner 在 GitHub UI 看 Actions 出现绿勾」列为部署后人工尾巴(与 P5 浏览器验收同类 manual-deferred);本机能验的全验(见 3)。
  • 不动 git.yoresee.cc 的 Gitea Actions(内层三仓不在 Gitea)。
  • 不重构测试文件(除任务 4 实测证明假绿通道时的最小修复)。
  • 不引入 lint(golangci-lint)、不引 codecov。

3. 验证策略(无 GitHub API,全部本地等价模拟)

任务 4 在本机以与 CI job 同构的容器化步骤跑三套:

  1. check:docker golang:1.24-alpine(GOPROXY 走 goproxy.cn——本机网络事实)四连。
  2. integration:postgres:17-alpine 容器(端口 5434,全新空库,--add-host=host.docker.internal:host-gateway 让测试容器可达)+ go test -v -count=1 -p 1 ./... + skip 守卫。跑两遍:第二遍证明 Migrate 幂等下的共存。
  3. e2e:stack:在 monorepo 真实布局(兄弟仓天然就位、宿主 go 1.26.8)跑 npm run e2e:stack,断言日志出现 [stack] ready:(真绿非假绿),另跑一次「无 docker 假绿反向验证」用 PATH 屏蔽 docker 令 stack_ok=0,确认 SKIP 模式在报告中显式可见。
  4. deploy config 正反两路。

推送本身(git push 成功)是 Actions 接收 workflow 的充分条件;job 结果查证为人工尾巴。

4. 交付物清单

仓库 文件 动作
crearte src/scripts/e2e-stack.sh CREARTE_STACK_GO + CREARTE_STACK_REQUIRED 两个 env 开关
crearte .github/workflows/validate.yml、docs/CHANGELOG.md push:master 触发;0.16.1
crearte-server .github/workflows/validate.yml、docs/CHANGELOG.md check + integration + e2e-stack 三 job;0.11.1
crearte-deploy .github/workflows/validate.yml、docs/CHANGELOG.md、README.md compose config 正反两路;0.5.1
wrapper 本 spec + 计划、ROADMAP P2 行、CHANGELOG 0.2.4 收尾
GitHub UI Actions 启用确认 + 分支保护 owner 手动(见 2.4)

5. 验收标准(Definition of Done)

  1. 三仓 .github/workflows/validate.yml 合入各自 master 并推送;分支删除。
  2. 任务 4 四组模拟全绿且证据留档(.superpowers/sdd/p2-task-4-report.md):integration 首跑必须含 RUN Test…Postgres/真跑字样、零 "skipping postgres integration test"。
  3. e2e:stack 真栈一跑 [stack] ready: 出现、full-loop 用例计数 >0 且全过;CREARTE_STACK_REQUIRED=1 反路在栈起不来时 exit 1(不静默 skip)。
  4. ROADMAP P2 → 完成(三 hash);wrapper CHANGELOG 0.2.4;人工尾巴(Actions 查证、分支保护)在 ROADMAP 行或 spec 有明确记载。