79c154f9af
对着试点仓落地时暴露的问题做的口径与模板修正(本轮不推、不打 tag、不部署): - 条目形状:四个自定义必填节 → **固定四类** Added/Changed/Fixed/Security (分类可省略、不许空栏目);过程记录进 docs/archive/,未合并事项进 docs/BACKLOG.md。 - 破坏性变化/迁移:固定写在 Changed 里、以 `**破坏性**` 开头并**必须链接发布文档**, 仓内 `docs/….md` 链接**对账**(不存在即红)。 - 构建身份:release_version / build_kind / commit_sha / display_version / built_at; 开发构建显示 X.Y.Z-dev+g<短SHA>(无基线 dev+g<短SHA>),**不许只显示上一正式版本号、 不许自称正式版**;release 只认显式发布上下文。 - **还没有正式版本一律放行**:不判红;首个正式版本号**由人指定**(预检把它列成阻塞项)。 - **没核对远端就不许说校验成功**:CI/预检用 `--require-remote`(本地模式明确写「未核对远端」)。 - 修正"CI 取不到 tag 所以不用 tag"的过时口径:正式版本**就是**用注释 tag, 只是**构建时不要用 git describe 取版本号**;**测试 tag 只在临时测试仓库里创建**。 - 模板同步:templates/check-changelog.py、templates/release-preflight.py、 新增 templates/version.py;ci-gate.py 的 version 项在 CI 下强制核对远端; new-project.sh 落 scripts/version.py 并按四类重写 CHANGELOG 骨架; README/07/模板 README 同步;04 增加 §I(V-1~V-4 四条,含负例在哪)。 验证:templates 两个检查器 --self-test 全过;new-project.sh bash -n 通过; 生成的新工程里 check_changelog --tags 绿、--identity 给出 dev+g<短SHA>、 CI=true 下 version 项因"未核对远端"判红(预期);试点仓反向夹具 80/0。
119 lines
9.8 KiB
Markdown
119 lines
9.8 KiB
Markdown
# Gitea 版工程规范(eng-standards 适配版)
|
||
|
||
> **性质**:跨仓库的系统级规范,按**本机真实环境**(自建 Gitea 1.26.2 + act_runner + ci-bridge + 阿里云测试/生产)改写。
|
||
> **来源**:评估并适配 `eng-standards-main.zip`(原稿是 GitLab/glab 口径),模板问题与修正见 `04-模板评估与修正.md`。
|
||
> **状态**:本次**只制定规范**。不部署生产、不运行附件原脚本、不改任何仓库。
|
||
> **正本仓库**:`zheromiku/eng-standards-main`(Gitea,https://gitea.zheromiku.top/zheromiku/eng-standards-main);本机工作副本 `~/eng-standards/`。
|
||
>
|
||
> **怎么读**:`README` 三十秒版 → `01-规范` 全文 → `02-流程说明与Runbook`(怎么操作)→ `03-待配置事项`(还差什么)→ `04-模板评估与修正`(原稿哪里不对)→ `05-应用机制`(怎么让它以后默认生效)→ `06-接入既有工程`(手头这个仓怎么接进来)→ `07-发版操作说明`(打 tag 与建 Release 的步骤)。
|
||
|
||
## 交付物
|
||
|
||
| 文件 | 是什么 |
|
||
|---|---|
|
||
| `README.md` | 本文件:索引 + 三十秒版 + 本环境**唯一取值表** |
|
||
| `01-规范-Git与CI-CD(Gitea版).md` | **正本**:分支/提交/评审/触发、自动检查与测试环境部署、生产发布与回滚、版本与产物 |
|
||
| `02-流程说明与Runbook.md` | 日常动作的**逐步命令**(提交前、看 CI、接入新仓、发布、回滚) |
|
||
| `03-待配置事项.md` | 逐项:现状 / 要做什么 / 为什么 / 怎么验证 / 谁来做 |
|
||
| `04-模板评估与修正.md` | 附件 15 处问题的证据与改法(含实测反证) |
|
||
| `05-应用机制-让规范在以后所有工程生效.md` | 三渠道(技能 / 仓内指针 / 生成器+守门)、已配 vs 待配、验证记录 |
|
||
| `06-接入既有工程.md` | **既有仓怎么接进来**:前置体检(含 PR 锁死陷阱)、一条命令、试点记录、验收判据 |
|
||
| `07-发版操作说明(tag与Release).md` | **怎么发版**:三态区分、四类小节变更记录(含破坏性变化的固定写法)、构建身份、只读预检、批准后打注释 tag + 建 Release 与读回判据、常见错误表 |
|
||
| `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. 三十秒版(只记六句)
|
||
|
||
1. **结论只来自可复现的命令**。数字、清单、成败一律由脚本打印或断言,禁止手抄进文档(原稿 §0-1,保留)。
|
||
2. **每个校验都要有反向自检**:故意弄坏一处,它必须红。永远返回 0 的校验器比没有校验更糟。
|
||
3. **密钥只从 Gitea Secrets / 目标机文件进**,不入库、不回显、不进命令行参数(会进 `ps`)。
|
||
4. **提交前跑本仓门禁命令**(唯一入口,如 `make verify`);CI 不是第一次验证,CI 只是"再来一遍"。
|
||
**CI 与 CD 分开**:推送流水线只做检查/测试/构建/证据,**不含部署**;部署由每个项目自己设计。
|
||
5. **生产部署只部署"测试验收过的那一份产物"**(同 sha、同镜像 ID)。这条是本环境新增的硬约束,见 §6.1。
|
||
6. **占位不许假报成功**:没实现的步骤要 `exit 1`(红的占位是设计),不要"打印 TODO 然后返回成功"。
|
||
|
||
## 1. 本环境事实(**唯一取值表**;以命令输出为准,不要手抄到别处)
|
||
|
||
```bash
|
||
# 取这张表的命令(改完环境重跑,别靠记忆)
|
||
python3 ~/.hermes/scripts/gitea_api.py GET /api/v1/version
|
||
python3 ~/.hermes/scripts/gitea_api.py GET /api/v1/repos/search?limit=50
|
||
docker ps --format '{{.Names}}\t{{.Image}}' | grep -E 'runner|bridge'
|
||
curl -s http://127.0.0.1:8899/healthz
|
||
```
|
||
|
||
| 项 | 值 |
|
||
|---|---|
|
||
| Gitea | 自建 **1.26.2**;LAN `http://192.168.50.223:3000`;公网别名 `https://gitea.zheromiku.top` |
|
||
| 账号 / 组织 | `zheromiku`;组织 `Weknora`、`aiball` |
|
||
| 仓库 | `Weknora/{dobotai-platform, knowledge-governance, knowledge-adapter-service, Enterprise-Knowledge-Base}`;`aiball/{protocol-docs, software-pc, upper-tool(空)}`;`zheromiku/{hello, protocol-docs(空)}` |
|
||
| CI 引擎 | Gitea Actions(act_runner,**仓库级** Runner 容器) |
|
||
| Runner | `runner-weknora-kg-01`→knowledge-governance、`runner-weknora-dp-01`→dobotai-platform、`runner-weknora-ka-01`→knowledge-adapter-service、`runner-software-01`(aiball 组织级,覆盖 protocol-docs/software-pc) |
|
||
| Runner 配置 | `capacity: 1`(同时只跑 1 个作业)、`force_pull: false`、labels `ubuntu-latest/24.04/22.04` → `docker://docker.gitea.com/runner-images:*`、注册令牌**文件挂载**(`/run/secrets/registration_token:ro`)、挂 `docker.sock` |
|
||
| 工具链/缓存 | 主机 `/srv/aiball/ci/toolcache` 只读挂载为容器内 `/opt/citools`;可写缓存 `/srv/aiball/ci/toolcache/cache` → `/opt/citools-cache` |
|
||
| ci-bridge | `/srv/aiball/ci/bridge/bridge.py`,监听 `0.0.0.0:8899`;容器内可达地址 `http://172.17.0.1:8899`;局域网 `http://192.168.50.134:8899`;Tailscale `http://100.92.49.78:8899` |
|
||
| bridge 接口 | `POST /api/ci/report`(作业结果→落盘+微信通知)、`POST /api/ci/publish`(静态产物 tar.gz→URL)、`GET /p/<ns>/<repo>/<sha>/…`、`GET /r/<id>`、`GET /healthz` |
|
||
| bridge 落盘 | 报告 `/srv/aiball/ci/reports/`(含 `pending/`、`undelivered/`);预览 `/srv/aiball/ci/previews/` |
|
||
| 仓库变量/密钥 | `CI_BRIDGE_URL`(variable)、`CI_BRIDGE_TOKEN`(secret)——仅 Weknora 三仓已配 |
|
||
| 提交闸门 | 本机 hook `~/.githooks/commit-msg`(`core.hooksPath`)+ CI 侧 `.gitea/scripts/ci_gate.py`(同一套规则,绕不过) |
|
||
| 仓库接入脚本 | `/srv/aiball/runner/attach_repo.sh <owner/repo> <runner-name>`、`/srv/aiball/runner/deploy_repo_runner.sh` |
|
||
| Gitea API 客户端 | `~/.hermes/scripts/gitea_api.py`(库/CLI)、`~/.local/bin/giteactl`(`runs/show/logs/watch/rerun`)、`giteacli`(**只读用途,本机 token 无 read:user**) |
|
||
| 测试服务器 | 阿里云 ECS `120.76.217.51`(key `~/.ssh/weknora-aliyun-test-ed25519`) |
|
||
| 生产服务器 | 阿里云 ECS `120.76.218.137`(key `~/.ssh/weknora-aliyun-prod-ed25519`) |
|
||
| 生产布局 | `/opt/dobotai/{config/dobotai.env, container/{compose.yaml,runtime.env,migrations/,backups/,ops/}, secrets/}`;镜像由 `container/runtime.env` 的 `DOBOTAI_IMAGE=` 选择 |
|
||
| 健康/版本 | `http://127.0.0.1:8090/healthz`(`{"status":"ok"}`)、`http://127.0.0.1:8090/version`(`version/commit_sha/build_time`) |
|
||
| 数据库 | **永远是阿里云 RDS(PostgreSQL 17.9)**;目标机 Docker 只跑应用容器,禁止本地库 |
|
||
| 构建受限 | 目标机 **不可达 Docker Hub** → 用 daocloud 镜像源;Go 用 `GOPROXY=https://goproxy.cn,direct` |
|
||
| 本机网络 | 出网走 mihomo;境外全 000 时先查 `~/.clashctl` 节点(`PUT /proxies/三毛机场 {"name":"<活节点>"}`) |
|
||
|
||
> ⚠️ 上表里**只有一个数字是"规范"**(如"生产路径 /opt/dobotai"),其余都是"现状快照"。现状会漂;所以每项都给了取数命令。
|
||
|
||
---
|
||
|
||
## 本地自检(不需要连 CI,可直接跑)
|
||
|
||
```bash
|
||
# 通用门禁模板:汇总 / 前端判据 / pytest 退出码语义 / 完整 SHA / 清单比对
|
||
python3 templates/ci-gate.py --self-test
|
||
|
||
# 上报核对(缺项/重复/未知项/短 SHA/档案/运行模式)
|
||
python3 templates/ci_report.py --self-test
|
||
|
||
# 预览脚本的打包判定(空产物 / 缺 index.html 必须被拒)
|
||
python3 templates/ci_preview.py --self-test
|
||
|
||
# 提交范围取法(截断/空范围/新分支/手工运行/shallow)
|
||
python3 templates/ci_gate.py --self-test
|
||
|
||
# 检出脚本的协议保留(https 不许被降级;未知协议拒绝;URL 不带凭据)
|
||
GITHUB_SERVER_URL=https://gitea.example.com GITHUB_REPOSITORY=owner/repo \
|
||
bash templates/ci_checkout.sh --print-remote
|
||
|
||
# 合并:判定纯函数 + 真实调用链(假 Gitea,断言 merge 请求发没发)
|
||
python3 scripts/adopt-existing.py --self-test
|
||
python3 scripts/adopt-existing.py --self-test-chain
|
||
|
||
# 生成器端到端
|
||
bash scripts/new-project.sh /tmp/probe Weknora/probe r1 && ls /tmp/probe/.gitea/scripts
|
||
```
|
||
|
||
⚠️ `templates/ci_report.py --self-test` 在**规范仓里**会因为找不到 `scripts/ci_checks.py`
|
||
(实现随项目走)而明确报"自检跑不了"—— 那是**故意**的:不许拿一份空清单去跑出莫名其妙的结论。
|
||
|
||
|
||
## 完整调用链(在**项目仓**里跑:空工作区 → 最小 bootstrap → 仓内脚本 → 提交范围闸门)
|
||
|
||
```bash
|
||
python3 scripts/ci_chain_fixture.py
|
||
```
|
||
|
||
它起一个本地 HTTP git 服务,并把 workflow 里 **bootstrap 那段 `run:` 原样抽出来**在**空目录**里执行
|
||
(所以 YAML 一旦改坏,这里立刻红):正例验证"空工作区能启动、检出到事件完整 SHA、协议保留、
|
||
新分支范围非空、合规提交通过",负例复现"第一步调用仓内脚本 = 127"、"取不到事件 SHA 必须失败"、
|
||
"含违规提交的新分支判红且**红在那条提交上**"。
|
||
|
||
⚠️ **模板 workflow 的第一步必须是最小 bootstrap**(只依赖 runner 给的环境变量):
|
||
空工作区里仓内脚本还不存在 —— `grep -n "name: 检出代码" -A3 templates/gitea-build.yml` 可核对。
|