docs: 正本与 Runbook/接入文档口径同步(测试语义、CI-CD 分离、门禁唯一入口、必需检查清单)
按草案逐条落到正本,并把三处已知错误的口径改回: ① 测试语义:删掉"单测跑的是构建产物,不是源码"这条被过度推广的说法。 只有"跑产物"的套件(端到端 / 契约 / 产物自检)才必须排在构建之后; go test 自己编译测试程序、pytest 直读源码、vitest 默认也跑源码。 写错这条的代价是给每个套件加假依赖、拖慢门禁并制造假故障。T8 同步改。 ② CI 与 CD 分离:触发表删掉"推默认分支 → 自动部署测试环境",作业划分表删掉 deploy:test 行, §4.6 标注为"项目自己的 CD、不属于通用 CI",速查表同步。 ③ 门禁入口:统一为 make verify(名字可不同,但 AGENTS/Runbook/CI 必须指同一个), §3.1、§8 清单、§9 速查表一致。 ④ 新增 §4.8「必需检查清单与结果口径」:10 项必需检查的判据表 + 三条结果口径 (失败即停但汇总照做、not_run/skipped 不算过、汇总故障不能报绿), 以及预览/通知作为旁路的规则。 ⑤ 接入文档:修掉"直推也拦得住"这句错口径,并写明接入器不再自动合并、 --merge-pr 会先核对状态;试点记录里那一步标注为"当时的自动合并行为已改"。 ⑥ 03/04/05 里的同源表述一并同步(生成物 jobs 与假成功占位的判据)。 验证:本批 18 处精确替换在脚本里逐处断言"恰好命中 1 次"(DRY-RUN 先过一遍再应用); 替换后全仓 grep 复查,旧口径只在"说明它已被改掉"的上下文里出现。
This commit is contained in:
+58
-13
@@ -147,7 +147,10 @@ EOF
|
||||
|
||||
### 3.1 一条命令,串行,失败即停
|
||||
|
||||
每个仓库**必须**有一条"跑完本地门禁"的入口(`make check` / `npm run verify` / `scripts/verify.sh`)。
|
||||
每个仓库**必须**有一条"跑完本地门禁"的入口,而且**只许有一条**:
|
||||
`make verify`(首选名字,本环境已统一)/ `npm run verify` / `scripts/verify.sh` 都行。
|
||||
⚠️ **名字可以不同,但 AGENTS、Runbook、CI 必须指向同一个**:
|
||||
两边各写一套步骤的结局是"迟早只改一边",而症状是本地绿、CI 红(或反过来),谁都说不清哪边是对的。
|
||||
|
||||
- **必须串行**:构建会清空产物目录,而端到端/契约测试跑的是**产物** ⇒ 并行会随机报"某条路由 404"。这类假失败会把你带到完全错误的方向。
|
||||
- **失败即停**:后面很多步骤依赖前面的产物,继续跑只会产生一堆同因假失败,把真正的线索埋掉。
|
||||
@@ -160,14 +163,18 @@ EOF
|
||||
|---|---|---|
|
||||
| 1 格式 | `gofmt -l` / `prettier --check` / `ruff format --check` | CI 会因为这一条红 |
|
||||
| 2 静态检查 | `go vet` / `tsc --noEmit` / `ruff check` | 类型/静态错,后面全是噪声 |
|
||||
| 3 构建 | `go build ./...` / `npm run build` | **会清空产物目录**,必须排在测试之前 |
|
||||
| 4 单元测试 | `go test ./...` / `pytest -q` / `npm test` | 跑的是构建产物,不是源码 |
|
||||
| 3 构建 | `go build ./...` / `npm run build` | 产物会被"跑产物"的套件消费 ⇒ 那些套件必须排在它之后;构建本身**不是**所有测试的前提 |
|
||||
| 4 单元测试 | `go test ./...` / `pytest -q` / `npm test` | 大多数是**测源码**:Go 自己编译测试程序、pytest 直读源码、Vitest 默认也跑源码 |
|
||||
| 5 集成/端到端 | 真起服务、打真实端口 | 单测覆盖不到"TCP 上真的连得上" |
|
||||
| 6 部署脚本自测 | `bash deploy/deploy_test.sh` | 真跑一次 release;守的是**静默故障** |
|
||||
|
||||
### 3.2 八条通用铁律
|
||||
|
||||
1. ⚠️ **单测跑的是构建产物,不是源码**:改了源码不重建,测的是**旧代码**(第一次一定会被这个骗一次)。
|
||||
1. ⚠️ **"跑产物"的套件(端到端 / 契约 / 产物自检)必须排在构建之后**:它们读的是构建输出,
|
||||
改了源码不重建,测的就是**旧代码**(第一次一定会被这个骗一次)。
|
||||
⚠️ 但**别把这条推广成"所有单测都依赖预构建产物"** —— 那是错的:`go test` 自己编译测试程序、
|
||||
`pytest` 直读源码、`vitest` 默认也跑源码。写错这条的代价是给每个测试套件加上假的"先构建"依赖,
|
||||
白白拖慢门禁,还会制造"没构建所以红了"的假故障。(本规范早期版本就是这么写的,已改回。)
|
||||
2. ⚠️ **只在"干净 clone"里出现的缺陷**:本地工作区总有"恰好能跑"的残留。要专门造一次干净树(`git clean -xdf` 后 clone / CI 的干净检出)验证。
|
||||
3. ⚠️ **每个校验都要反向自检**:
|
||||
- 断言"它会红":故意弄坏一处,必须失败。
|
||||
@@ -190,8 +197,13 @@ Gitea 没有 `workflow: rules`,触发写在 `on:`。本环境只允许三类
|
||||
| 入口 | 写法 | 用途 |
|
||||
|---|---|---|
|
||||
| 推任意分支 | `on.push.branches: ["**"]` | 校验 + 编译(**不部署**) |
|
||||
| 推默认分支 | `on.push.branches: [main]` | 校验 + 编译 + **自动部署测试环境** |
|
||||
| 人工发起 | `on.workflow_dispatch` | 生产发布(**独立 workflow**,见 §5) |
|
||||
| 人工发起 | `on.workflow_dispatch` | 手动重跑校验;生产发布是**独立 workflow**(见 §5) |
|
||||
|
||||
⚠️ **CI 与 CD 分离(本环境口径)**:推送触发的流水线**只做 CI** —— 检查、测试、构建、证据。
|
||||
"推 main 就自动部署测试环境"**不是**通用规范:部署目标、产物形态、迁移与回滚由**每个项目自己设计**
|
||||
(§8)。通用模板里默认**不含**任何部署作业。
|
||||
反例(本规范早期版本):模板里放一个 `deploy:test` 占位作业,它打印 TODO 然后返回成功 ——
|
||||
那不是"还没做",那是**假报成功**:网页上看起来部署过了。
|
||||
|
||||
**硬约束**:
|
||||
|
||||
@@ -207,7 +219,7 @@ Gitea 没有 `workflow: rules`,触发写在 `on:`。本环境只允许三类
|
||||
| `gate` | 校验 | `.gitea/scripts/ci_gate.py` 提交信息闸门 | 失败就**不编译**,一次被拦的推送不会被误当编译错误 |
|
||||
| `build` | 构建 | 装依赖 → 静态检查 → 单测 → 构建 → **产物自检** → 打包/送产物 | 唯一产出交付物的作业 |
|
||||
| `validate` | 校验 | 环境参数不变量、配置语法、规范守门 | 只读仓库、几秒钟,没理由拖到部署阶段才发现 |
|
||||
| `deploy:test` | 部署 | 推 `main` 自动部署测试环境 | 见 §4.1 |
|
||||
| (无) | 部署 | **通用 CI 里没有部署作业** | CD 由项目独立设计(§8);占位作业不许假报成功 |
|
||||
|
||||
要点:
|
||||
- **校验类作业与 `gate` 归"校验/构建"**,用 `needs:` 显式等齐再进部署。
|
||||
@@ -240,9 +252,13 @@ Gitea 没有 `workflow: rules`,触发写在 `on:`。本环境只允许三类
|
||||
- 网络参数:`GOPROXY=https://goproxy.cn,direct`、`GOTOOLCHAIN=local`、npm 走国内源。
|
||||
- ⚠️ **不缓存 `node_modules`**(或等价的语言级依赖目录):它是平台相关的产物,缓存里混进另一套架构/运行时版本的二进制时,症状是"某次构建突然报原生模块加载失败",而那次构建的 diff 里什么都没有。
|
||||
|
||||
### 4.6 测试环境部署
|
||||
### 4.6 测试环境部署(**项目自己的 CD**,不属于通用 CI)
|
||||
|
||||
- 推 `main` → `gate` + `build` 通过 → 自动部署测试环境。
|
||||
> ⚠️ 本节描述的是**项目 CD 的目标形态**,不是通用 CI 的一部分。通用模板不会生成这些作业;
|
||||
> 项目要做部署时**另写独立 workflow**(`workflow_dispatch` 触发、`cancel-in-progress: false`)。
|
||||
|
||||
- **触发方式由项目自己决定**(例如"CI 全绿之后由人工发起")。通用 CI **不**替你决定,也**不**自动部署。
|
||||
⚠️ 本规范早期版本写的是"推 `main` → 自动部署测试环境"—— 那是把某个项目的选择当成了通用规则,已改。
|
||||
- 部署后**必须读回**(不是"启动成功"就算):
|
||||
1. 容器镜像 ID == 本次构建产物的镜像 ID(`docker inspect --format '{{.Id}}'`);
|
||||
2. `GET /healthz` 返回 `{"status":"ok"}`;
|
||||
@@ -258,6 +274,35 @@ Gitea 没有 `workflow: rules`,触发写在 `on:`。本环境只允许三类
|
||||
- ⚠️ 报告里给出的每个 URL(报告页、预览页)**都要探测到 200** 才算发出去了,否则会收到一条没有预览链接的通知。
|
||||
- ⚠️ 静态产物打包**不要产生 `.` 根成员**:`tar -czf x.tgz -C dir .` 会写入 `.` 和 `./index.html`;严格解包器可能拒绝或报错,而流水线**仍显示成功** —— 通知到了、预览没有。bridge 侧应**规范化**(剥掉 `./`,丢弃归一化为 `.`/空的成员),而不是直接拒绝整个包。
|
||||
|
||||
### 4.8 必需检查清单与结果口径(汇总不许自欺)
|
||||
|
||||
每个项目声明自己的**必需检查清单**,并让清单能被打印出来(如 `make list`),
|
||||
CI 与本地都按**清单**逐项核对:
|
||||
|
||||
| ID | 必需检查 | 判据 |
|
||||
|---|---|---|
|
||||
| identity | 触发提交 / 检出身份 | 实际 `HEAD` 等于**事件完整 SHA**(不是短 sha,也不是"当时的分支 HEAD") |
|
||||
| commits | 提交信息 | 本次推送范围内的提交全部通过规则 |
|
||||
| deps-install | 依赖安装 | **按锁文件**装;缺锁即失败,不回落 `npm install` / `-mod=mod` |
|
||||
| format | 格式 | 不合规即非零退出;CI **不自动修复** |
|
||||
| static | 静态检查 / 类型 | 声明的语言模块全部通过 |
|
||||
| build | 构建 | 声明的模块构建成功 |
|
||||
| tests | 自动化测试 | 必需套件**实际执行**且通过;空套件 / 全跳过不算通过 |
|
||||
| contracts | 项目契约 | 版本与产物/接口契约通过(被 SKIP 的断言**不算**通过) |
|
||||
| security | 密钥 / 依赖漏洞 | 无泄漏;无未获授权的适用高危风险;**扫描器没跑成也不许算过** |
|
||||
| manifests | 依赖清单 | 门禁过程中 `go.mod` / `go.sum` / 锁文件没有被任何一步改写 |
|
||||
|
||||
结果口径(三条,都是踩出来的):
|
||||
|
||||
1. **失败即停,但汇总照做**:第一个必需项失败后,剩下的记为 `not_run` 并**如实写进报告**,
|
||||
不许从报告里消失(消失了,下游就会当成"本来就没有这一项")。
|
||||
2. **`not_run` / `skipped` 都不算过**:汇总只认 `success`;
|
||||
不适用要**在清单里声明**(比如"本地没有事件负载,identity 只在 CI 必需"),不能在运行时悄悄跳过。
|
||||
3. **汇总本身故障 ⇒ 不能报绿**:读不到 / 解析不了报告时,结论是"质量无从判定",不是"没问题"。
|
||||
|
||||
预览与通知是**旁路**:预览只在全部必需项 `success` 之后发布(并且要断言产物包里真的有入口文件、
|
||||
报告里给出的每个地址都探测到 200);通知失败**不改质量结论**,只单独标注 `notification_status`。
|
||||
|
||||
---
|
||||
|
||||
## 5. 生产发布(人工确认 / 健康检查 / 互斥 / 回滚 / 同一产物)
|
||||
@@ -439,7 +484,7 @@ flock -n 9 || { echo "❌ 另一个部署正在进行,退出"; exit 1; }
|
||||
|
||||
- [ ] **1. 仓库与默认分支**:默认分支定 `main`;分支收敛到 `main` + 短命分支(长期分支要么合要么删)。
|
||||
- [ ] **2. `.gitignore`**:依赖 / 构建产物 / 运行期数据 / 密钥 / 发布产物各一条;再用 §1.4 的两条反查命令确认**没有已入库的漏网文件**。
|
||||
- [ ] **3. 门禁入口**:`make check` 或 `scripts/verify.sh` —— 一条命令跑完、**串行**、失败即停、末尾汇总;跳过项显式警告"不算全绿"。
|
||||
- [ ] **3. 门禁入口**:`make verify`(首选;`scripts/verify.sh` 亦可)—— 一条命令跑完、**串行**、失败即停、末尾汇总;跳过项显式警告"不算全绿"。**本地与 CI 必须是同一条命令**。
|
||||
- [ ] **4. CI 骨架**:复制 `templates/gitea-build.yml` → `.gitea/workflows/build.yml`;随仓带 `.gitea/scripts/{ci_gate.py,ci_report.py}`(**逐字节复制**已验证的版本,不要重写)。
|
||||
- [ ] **5. 仓库级 Runner**:`bash /srv/aiball/runner/attach_repo.sh <owner/repo> <runner-name>`(幂等;注册令牌走文件挂载,不落容器 env)。
|
||||
- [ ] **6. bridge 变量/密钥**:`CI_BRIDGE_URL`(variable)、`CI_BRIDGE_TOKEN`(secret),由上面的脚本写入;写完 `GET` 读回。
|
||||
@@ -457,7 +502,7 @@ flock -n 9 || { echo "❌ 另一个部署正在进行,退出"; exit 1; }
|
||||
|
||||
```bash
|
||||
# ── 提交前 ────────────────────────────────────────────────
|
||||
make check # 或 npm run verify —— 本仓门禁,串行、失败即停
|
||||
make verify # 本仓门禁(本地与 CI 同一条),串行、失败即停
|
||||
git status --short --ignored # 确认没有该入库却被忽略的文件
|
||||
git commit -F - <<'EOF' # ⚠️ 不用 -m:正文里的反引号/$() 会被 shell 吃掉
|
||||
feat(scope): 标题(中文)
|
||||
@@ -475,7 +520,7 @@ giteactl rerun <ns>/<repo> <runId> # 重跑(不推新提交即可验证整条
|
||||
# 构建注入版本 → 写 release-<sha12>.json → 部署测试 → 验收 → dispatch 生产
|
||||
|
||||
# ── 上线与回退 ───────────────────────────────────────────
|
||||
# 推 main → gate + build + deploy:test 自动跑
|
||||
# 推任意分支 → gate + build(**只做 CI,不部署**)
|
||||
# 生产 → Gitea「Actions → 生产 workflow → Run workflow」选 ref=main,填 sha 与 confirm
|
||||
# 回退(生产机上) → bash /opt/dobotai/container/ops/rollback_dobotai_prod.sh
|
||||
# ⚠️「取消流水线」不是回滚
|
||||
@@ -494,7 +539,7 @@ giteactl rerun <ns>/<repo> <runId> # 重跑(不推新提交即可验证整条
|
||||
| T5 | 断言"我这条守卫会红"之外,还要断言**不会假绿**:给它一条对照 | 通用 |
|
||||
| T6 | 测试里的**负向断言**会被"别的记录"撑成假绿(判据太宽) | 通用 |
|
||||
| T7 | 测试夹具只建不删 ⇒ `$TMPDIR` 攒到几万条,`mktemp -d` 开始卡住 | 通用 |
|
||||
| T8 | 单测跑的是构建产物,不是源码 —— 改了源码不重建,测的是旧代码 | 通用 |
|
||||
| T8 | "跑产物"的套件要排在构建之后;但**别**推广成"单测都依赖预构建产物" | 通用 |
|
||||
| **G1** | **act_runner 不自动检出代码**(Weknora 三仓)⇒ 工作流必须自 clone | 本环境 |
|
||||
| **G2** | **act 以 `bash -e -o pipefail` 执行每步** ⇒ `cmd \| head` 会假红 | 本环境 |
|
||||
| **G3** | **`uses:` 第三方 action 在部分 runner 上不可用**(实测 aiball runner 可用) | 本环境 |
|
||||
|
||||
+9
-4
@@ -19,7 +19,8 @@ git log --oneline origin/main..HEAD # 本地领先的提交 = 本次要发的
|
||||
### A2. 改完、提交前
|
||||
|
||||
```bash
|
||||
make check # 或 npm run verify / scripts/verify.sh —— 本仓门禁,串行、失败即停
|
||||
make verify # 本仓唯一门禁入口(本地与 CI 同一条),串行、失败即停
|
||||
# 名字不同也行(npm run verify / scripts/verify.sh),但 AGENTS / Runbook / CI 必须指同一个
|
||||
```
|
||||
|
||||
**判据**:末尾汇总表全绿;有跳过项会显式警告"不算全绿"且非 0 退出 —— 那就不是绿。
|
||||
@@ -116,15 +117,19 @@ python3 ~/.hermes/scripts/gitea_api.py GET "/api/v1/repos/<ns>/<repo>/actions/se
|
||||
|
||||
---
|
||||
|
||||
## C. 构建与测试环境部署
|
||||
## C. 构建与测试环境部署(**项目自己的 CD**;推送流水线不含部署)
|
||||
|
||||
### C1. 自动(推 main)
|
||||
|
||||
```
|
||||
git push origin main
|
||||
→ gate(提交信息闸门)→ build(依赖/静态/单测/构建/产物自检)→ deploy:test
|
||||
git push origin <分支>
|
||||
→ gate(提交信息闸门)→ build(依赖/静态/格式/单测/构建/安全/契约)
|
||||
```
|
||||
|
||||
⚠️ **推送只做 CI,不做 CD**:上面这条流水线里**没有**部署作业(正本 §4.1 / §8)。
|
||||
部署(测试环境/生产)由各项目自己设计,见 §D。本模板里不再有 `deploy:test` 占位作业 ——
|
||||
占位作业会打印 TODO 然后返回成功,那是假报成功。
|
||||
|
||||
### C2. 测试环境读回(每次部署都做全)
|
||||
|
||||
```bash
|
||||
|
||||
+2
-1
@@ -161,7 +161,8 @@
|
||||
## 不建议做的事(写下来防止被"顺手加上")
|
||||
|
||||
- ❌ 不要为了能 push 去改 Gitea 凭据/token scope —— 权限没配好要**问人**,自己换 remote/换账号会把"权限没配好"变成"动作做了一半"。
|
||||
- ❌ 不要把 `deploy:test` 也挂到 `workflow_dispatch` 上"顺便重部署测试环境"(生产 workflow 就是生产 workflow)。
|
||||
- ❌ 不要把测试环境部署塞回 `build.yml`(CI 流水线只管校验与编译);生产 workflow 就是生产 workflow。
|
||||
占位作业在填完真实逻辑之前**必须红**,不许"打印 TODO 然后返回成功"。
|
||||
- ❌ 不要给生产 workflow 设 `concurrency.cancel-in-progress: true`(会取消正在进行的部署,而取消不是回滚)。
|
||||
- ❌ 不要在生产与测试**同时**跑压测(两服共用同一套 RDS,会扰动生产)。
|
||||
- ❌ 不要在源码路径里用 `dist` / `data` / `secrets` 这些名字(`.gitignore` 会静默吞掉)。
|
||||
+1
-1
@@ -125,7 +125,7 @@
|
||||
## F. 保留的(原稿最有价值的部分,不要因为"平台换了"就丢掉)
|
||||
|
||||
1. **§0 四条地基**:结论只来自可复现命令 / 每个校验都要反向自检 / 密钥不进命令行 / 提交前跑门禁。
|
||||
2. **§4.2 六条铁律**:单测跑产物不跑源码、干净 clone、反向自检三问(会红吗 / 会假绿吗 / 真的作用在目标上吗)、断言要有唯一命中点、夹具要打扫、先确认无遗留进程。
|
||||
2. **§3.2 八条通用铁律**:只有"跑产物"的套件要排在构建之后(**不是**"所有单测都依赖预构建产物")、干净 clone、反向自检三问(会红吗 / 会假绿吗 / 真的作用在目标上吗)、断言要有唯一命中点、夹具要打扫、先确认无遗留进程。
|
||||
3. **§2.2 正文写"为什么"** 的四种要素(现象/根因/取舍/证据)与示例形状。
|
||||
4. **§2.3 heredoc 禁忌**(反引号 `$()` 会被 shell 先执行,且退出码仍是 0)。
|
||||
5. **§1.3 `.gitignore` 是契约** 与两条反查命令。
|
||||
|
||||
@@ -92,7 +92,8 @@ bash /srv/aiball/runner/attach_repo.sh <owner>/<repo> <runner-name>
|
||||
| 空目录 → 生成 | ✅ exit 0,9 个文件齐全 |
|
||||
| 非空目录 → 拒绝 | ✅ exit 1,`❌ 目标目录非空:…(不覆盖任何东西)` |
|
||||
| `<PROJECT>` 替换 | ✅ 生成物首行 `# demo-svc —— 提交触发的 CI(Gitea Actions)` |
|
||||
| 生成物 YAML 合法性 | ✅ `build.yml` jobs=`gate,build,deploy:test`;`deploy-production.yml` jobs=`guard,publish` |
|
||||
| 生成物 YAML 合法性 | ✅ 生成后解析:`build.yml` jobs=`gate,build`(**无 deploy 作业**,CI-only);`deploy-production.yml` jobs=`guard,publish` |
|
||||
| 生成物不含假成功占位 | ✅ `grep -c '^ deploy' build.yml` = 0;prod-deploy 的未实现步骤是 `exit 1` |
|
||||
| AGENTS.md 指针 | ✅ 含 `eng-standards-main` |
|
||||
| 闸门脚本逐字节一致 | ✅ `ci_gate.py` 3280 B / `ci_report.py` 2700 B |
|
||||
| 无构建入口时门禁行为 | ✅ exit 1("入口待补,不算全绿"),**不是静默通过** |
|
||||
|
||||
+10
-3
@@ -2,6 +2,10 @@
|
||||
|
||||
> 一句话:接入 = **前置体检 → 加指针 → 开保护 → 反向自检**,一条命令走完。
|
||||
> 为什么要有"前置体检"这一关,见 §2 —— 跳过它会把 PR **永久锁死**。
|
||||
>
|
||||
> ⚠️ **工具不替人合并、也不替人审批**(2026-10 改):它建完 PR 就把状态如实打给你,然后停下。
|
||||
> 批准之后才跑 `--merge-pr <n>`,而它会**先核对检查状态**:失败 / 取消 / 从未运行 /
|
||||
> 状态拿不到 / 等超时 / 头提交变了 —— 任一情形都拒绝请求合并(`--self-test` 逐条证明)。
|
||||
|
||||
## 1. 一条命令
|
||||
|
||||
@@ -24,7 +28,7 @@ python3 ~/eng-standards/scripts/adopt-existing.py <owner/repo> --apply --with-pr
|
||||
| 步 | 动作 | 怎么落地 |
|
||||
|---|---|---|
|
||||
| 1 | 体检 | 读默认分支、工作流触发方式、runner(仓库级/组织级)、最新提交的 status context、已有保护 |
|
||||
| 2 | 加指针 | 新起分支 → 写 `AGENTS.md` → 提交(过本机闸门)→ **PR** → 等 CI → 合并 → 删分支 |
|
||||
| 2 | 加指针 | 新起分支 → 写 `AGENTS.md` → 提交(过本机闸门)→ **PR** → 有界等 CI → **停下**(工具不替你合并) |
|
||||
| 3 | 开保护(**仅 `--with-protection` 时**) | `POST/PATCH /branch_protections`:禁直推 + 必须 PR;**状态检查按第 1 步判定**。**默认不做** —— 原稿口径是直推 `main`(正本 §1.3) |
|
||||
| 4 | 给自检命令 | 打印"直推必须被拒"的验证命令(**这步工具不代做,必须你跑**) |
|
||||
|
||||
@@ -72,7 +76,7 @@ python3 ~/eng-standards/scripts/adopt-existing.py <owner/repo> --apply --with-pr
|
||||
| 分支 + 提交 | `docs/agents-pointer`,提交通过本机提交闸门(`~/.githooks/commit-msg`) |
|
||||
| 推送触发 CI | 头提交 `d025fc9adfe2` → context `build / build (push)` → `combined=success` |
|
||||
| PR | **PR #1**,`mergeable=True`(**关键结论:强制状态检查认 PR** —— 因为推分支就产生了 `(push)` 状态) |
|
||||
| 合并 | HTTP 200(**空 body,属正常**,不重试)→ 读回 `state=closed` `merged=true` `merge_commit_sha=32b0ec58a612` |
|
||||
| 合并 | 当时由工具**自动**合并:HTTP 200(**空 body,属正常**,不重试)→ 读回 `state=closed` `merged=true` `merge_commit_sha=32b0ec58a612`。**该行为已改**:现在工具不自动合并(见上) |
|
||||
| 结果 | `AGENTS.md` 在 `main`;分支已自动删除 |
|
||||
| 反向自检 | 直推 main 被服务端拒绝:`Not allowed to push to protected branch main` / `pre-receive hook declined` |
|
||||
| 幂等 | 再跑一次 `--apply`:`AGENTS.md` 跳过、保护值不变、**main 仍是 `32b0ec58a612`** |
|
||||
@@ -112,7 +116,10 @@ cd /tmp/t && git commit --allow-empty -m 'chore(probe): 不该进 main' && git p
|
||||
1. `AGENTS.md`(或 `.hermes.md`)在默认分支上,且含指向 `zheromiku/eng-standards-main` 的路径。
|
||||
2. **(只在开了保护时)** `GET /repos/{r}/branch_protections` 非空、`enable_push=false`,且直推默认分支**被服务端拒绝**。
|
||||
⚠️ 默认口径是**直推 `main`**,所以正常情况下这里应当是"没有保护" —— **别把"没保护"当成缺陷**。
|
||||
3. 推一个故意违规的提交 → 本机 hook 红、CI 的 `gate` 红。**直推也拦得住**,因为 gate 在 CI 里(正本 §4.1)。
|
||||
3. 推一个故意违规的提交 → 本机 hook 红、CI 的 `gate` 红。
|
||||
⚠️ 注意口径:CI 的 `gate` 是**推完再跑**的,它拦不住那次推送本身(正本 §2 / §1.3)。
|
||||
"直推也拦得住"是**错的**说法:要拦推送只有两条路 —— 本机 hook,或开分支保护(禁直推)。
|
||||
gate 的价值是"把违规提交标红并挡住编译/部署",不是"阻止它进 main"。
|
||||
4. **(只在开了保护时)** PR 能正常合并 —— 证明强制状态检查没有把 PR 锁死。
|
||||
5. 会话里问"这个仓提交信息什么规范",代理能**不靠你重复**答出来(说明指针真的被注入了)。
|
||||
|
||||
|
||||
@@ -18,17 +18,20 @@
|
||||
| `04-模板评估与修正.md` | 附件 15 处问题的证据与改法(含实测反证) |
|
||||
| `05-应用机制-让规范在以后所有工程生效.md` | 三渠道(技能 / 仓内指针 / 生成器+守门)、已配 vs 待配、验证记录 |
|
||||
| `06-接入既有工程.md` | **既有仓怎么接进来**:前置体检(含 PR 锁死陷阱)、一条命令、试点记录、验收判据 |
|
||||
| `templates/` | 可直接落仓的骨架:`gitea-build.yml`、`gitea-prod-deploy.yml`、`gitignore`、`commit-msg`、`ci_gate.py`、`ci_report.py`、`README.md`(内含 AGENTS.md 骨架) |
|
||||
| `scripts/new-project.sh` | 新工程生成器:一条命令产出 9 个默认合规文件(已端到端测过) |
|
||||
| `scripts/adopt-existing.py` | 既有工程接入器:体检 → 加指针 → 开保护(幂等,默认 DRY-RUN) |
|
||||
| `templates/` | 可直接落仓的骨架:`gitea-build.yml`(**只做 CI**)、`gitea-prod-deploy.yml`(人工发起;未实现的步骤故意红)、`gitignore`、`commit-msg`、`ci_gate.py`、`ci_report.py`、`README.md`(内含 AGENTS.md 骨架) |
|
||||
| `scripts/new-project.sh` | 新工程生成器:一条命令产出默认合规的骨架(CI + 门禁 + 提交规范;已端到端测过) |
|
||||
| `scripts/adopt-existing.py` | 既有工程接入器:体检 → 加指针(建 PR 后**停下等你批准**)→ 开保护(幂等,默认 DRY-RUN);`--merge-pr <n>` 才是显式批准的合并 |
|
||||
| `docs/architecture/` | 两份设计依据草案:`universal-ci-standard.md`(通用 CI 规范)、`knowledge-governance-ci-pilot.md`(试点交接)。**已生效的部分在 `01-规范` 里**;它们是过程记录,不是配置 |
|
||||
|
||||
## 0. 三十秒版(只记五句)
|
||||
## 0. 三十秒版(只记六句)
|
||||
|
||||
1. **结论只来自可复现的命令**。数字、清单、成败一律由脚本打印或断言,禁止手抄进文档(原稿 §0-1,保留)。
|
||||
2. **每个校验都要有反向自检**:故意弄坏一处,它必须红。永远返回 0 的校验器比没有校验更糟。
|
||||
3. **密钥只从 Gitea Secrets / 目标机文件进**,不入库、不回显、不进命令行参数(会进 `ps`)。
|
||||
4. **提交前跑本仓门禁命令**;CI 不是第一次验证,CI 只是"再来一遍 + 部署"。
|
||||
4. **提交前跑本仓门禁命令**(唯一入口,如 `make verify`);CI 不是第一次验证,CI 只是"再来一遍"。
|
||||
**CI 与 CD 分开**:推送流水线只做检查/测试/构建/证据,**不含部署**;部署由每个项目自己设计。
|
||||
5. **生产部署只部署"测试验收过的那一份产物"**(同 sha、同镜像 ID)。这条是本环境新增的硬约束,见 §6.1。
|
||||
6. **占位不许假报成功**:没实现的步骤要 `exit 1`(红的占位是设计),不要"打印 TODO 然后返回成功"。
|
||||
|
||||
## 1. 本环境事实(**唯一取值表**;以命令输出为准,不要手抄到别处)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user