After a stable tag vX.Y.Z, untagged commits now produce X.Y.(Z+1)~date.branch.n+gSHA so test DEBs sort above the last official release and still below the next official X.Y.(Z+1).
6.8 KiB
builder
按统一契约完成项目的 DEB 包与 Docker 镜像构建和发布。规范本体见
references/contract.md,scripts/check.py 是契约的
可执行校验器。
什么时候使用
- "用 builder 初始化这个项目"
- "帮我构建这个项目的 DEB / Docker 镜像"
- "把 1.2.3 发布到包仓库 / 镜像仓库"
- "检查这个项目的 makefile.builder 是否符合 builder 契约"
- "看看项目现在的发布流程"
只构建不上传时明确说明即可;上传永远需要你显式授权。
安装
pouch add builder # 当前项目
pouch add builder -g # 全局
不要 pouch init builder。对新项目说「用 builder 初始化」。
使用前准备
- Python 3 和
make。 - DEB 轨道需要
dpkg-deb;Docker 轨道需要 Docker 和 buildx。 - 发布时在项目根
.env.builder填写仓库地址和 token(不要写进.env,也不要进 git)。 - 正式版本号由 manage-release 打 annotated tag;builder 只读当前 HEAD。
- 脏工作树默认拒绝发布。
项目接入契约
对新项目说「用 builder 初始化」。Agent 会探测轨道、按
templates/makefile.builder 写出项目根 makefile.builder,并列出缺的发布配置。
不改用户已有的 Makefile 或 .env。
makefile.builder目标:help/build/clean/version+ 条件deb/docker/push*, 变量ARCH/VERSION/DIST_DIR/PROJECT_NAME。VERSION通过include <builder>/scripts/version.mk从 Git 推导。- 运行
python3 -I -S <builder>/scripts/check.py . --ready直到构建项 PASS。 缺发布键只挡住上传,不挡住构建。 - 在项目根
.env.builder配置发布环境变量(不要写进.env):
DEB_SERVER_URL=https://deb.example.com
DEB_REPOSITORY=main
DEB_TOKEN=<token> # 只放 .env.builder 或密钥系统,不进 git
DOCKER_REGISTRY=registry.example.com
- 日常发布就是两条命令:
make -f makefile.builder deb && make -f makefile.builder push-deb、make -f makefile.builder push-docker。
版本号
产物版本从 当前 HEAD 的 Git 祖先 推导,不调用 manage-release。 正式 tag 仍由 manage-release 创建;builder 只读取。完整规则见 contract.md「版本号」。
| 谁 | 做什么 |
|---|---|
| manage-release | 选定下一个正式 SemVer,打 annotated tag vX.Y.Z |
| builder | 读 HEAD:落在稳定 tag 上则打正式产物,否则打测试产物 |
make -f makefile.builder version |
输出一行规范版本(无 v 前缀),DEB / Docker 都从它渲染 |
不要用 git tag \| sort -V \| tail -1 取全仓库最大号,也不要把
git describe --dirty 的原始字符串写进 DEB 或镜像 tag。
正式(HEAD 恰好是稳定 tag v1.4.2)
Git tag v1.4.2
规范版本 1.4.2
DEB foo_1.4.2_amd64.deb Version: 1.4.2
Docker registry/ns/foo:1.4.2
稳定 tag 仅匹配 v<major>.<minor>.<patch>,不含 -rc、-app-N 等后缀。
不是 exact-match 就不是正式包。
测试(其它任何 commit)
基线 = 祖先上最近的那颗稳定 tag(没有则为 0.0.0)。有基线时测试号把
patch 机械 +1,再加构建日 YYYYMMDD、清洗后的分支名、相对距离、短 SHA。
这是排序键,不是在选定下一正式 SemVer。测试与正式进同一个 apt /
Docker 仓库,所以 DEB 必须用 ~ 挂在下一 patch 上:1.4.2 <
1.4.3~20260908… < 1.4.3。已装上一正式版的机器可以升到 bugfix 测试包;
同号正式版仍盖住测试。
分支 feat/login-v2,相对 v1.4.2 第 7 个 commit,SHA abc1234,
构建日 20260908:
规范 / DEB 1.4.3~20260908.feat-login-v2.7+gabc1234
文件名 foo_1.4.3~20260908.feat-login-v2.7+gabc1234_amd64.deb
Docker registry/ns/foo:1.4.3-20260908.feat-login-v2.7.gabc1234
Docker tag 由规范版本映射:~ → -,+g → .g(Docker 不允许 ~)。
无参 apt upgrade 会从上一正式版升到下一 patch 的测试包,但不会盖住同号
正式包。生产若不能自动吃到测试包,应拆仓库/组件。构建日取本机当前日期;
设了 SOURCE_DATE_EPOCH 则用该时刻的 UTC 日期。
分支名清洗
小写;/、_ 改为 -;去掉其它非法字符;压缩连续 -;过长截断。
detached HEAD 用 detached,CI 可注入 BUILD_BRANCH / CI_COMMIT_BRANCH /
GITHUB_REF_NAME。脏工作树不把 -dirty 写进版本(发布本身会拒绝)。
使用示例
用 builder 初始化这个项目。
用 builder 检查这个项目的 makefile.builder 是否符合契约。
用 builder 构建当前版本的 DEB 和镜像,先不要上传。
用 builder 把当前 commit 的产物发布到项目已配置的仓库。
用 builder 发布多平台 linux/amd64,linux/arm64 镜像。
Agent 会做什么
- 初始化:探测 DEB / Docker 轨道,写出
makefile.builder和.env.builder骨架,不改你已有的Makefile或.env。 - 检查:只跑
scripts/check.py --ready,不改文件。 - 构建:走
make -f makefile.builder;只获构建授权时不走会自动上传的目标。 - 发布:先校验产物,再上传。缺发布键、未授权、或可能覆盖同版本时停下问你。
Docker 只有你点名镜像时才走。token 不会写进输出、提交或回复。
如何判断完成
- 初始化:
check.py --ready的构建项 PASS。只缺发布键算部分完成,仍可构建、不能上传。 - 构建:产物路径、规范版本、架构与
make -f makefile.builder version一致。 - 发布:HTTP 成功或远端 digest 对得上;回复里有包名或镜像引用、SHA-256 / digest、源 commit。
- 测试包不会通过无参
apt upgrade盖住同号正式包;会作为下一 patch 候选盖住上一正式包。
脚本一览
| 脚本 | 用途 |
|---|---|
scripts/check.py |
校验契约(--ready 含工具链与发布键名,--build 实构核对产物) |
templates/makefile.builder |
初始化用的契约文件骨架,拷到项目根 |
templates/env.builder |
初始化用的 .env.builder 骨架(注释键,不含值) |
scripts/version.sh |
从 Git 祖先稳定 tag 推导规范版本 / Docker tag |
scripts/version.mk |
makefile.builder include,设置 VERSION 与 IMAGE_TAG |
scripts/upload_deb.sh |
上传 .deb 到 HTTP 包仓库(multipart package/token/repository_name) |
scripts/publish_docker.sh |
buildx 构建 + 推送镜像,远端 digest 验证 |
scripts/verify_deb.sh |
核对包元数据、内容与 SHA-256 |
环境变量契约、脚本解析顺序($BUILDER_SKILL_DIR → ~/.pouch/skills/builder/scripts/)、
脏工作树策略等完整规则见 contract.md。