根本原因是Satis不监听Git变更,WebHook仅通知而非触发构建;需自行搭建接收端(如PHP脚本)或用定时器/CI流程执行satis build,并确保packages.json更新、客户端强制重载元数据。

私有仓库元数据不自动更新,根本原因不是WebHook没配好
Composer私有仓库(如 Satis)本身不监听 Git 变更,它不会因为你在 GitHub/GitLab 推了新 tag 就自动重建 packages.json。WebHook 的作用只是“通知你该 rebuild 了”,不是“触发 rebuild”。很多团队卡在这一步:WebHook 请求发出去了,日志里也显示 200,但 packages.json 还是旧的——因为接收端压根没写处理逻辑。
GitLab/GitHub WebHook 怎么配才真正触发 Satis 构建
关键不在 WebHook 发送端,而在接收端是否具备可执行入口。Satis 本身无 HTTP 服务,必须自己搭一层轻量胶水层。常见可行路径:
- 用一个最小 PHP 脚本(如
webhook-handler.php)放在 Web 可访问目录,收到 POST 后校验X-Hub-Signature-256或X-Gitlab-Token,再执行php bin/satis build satis.json web/ - 用
supercronic或systemd-timer定时拉取 Git 仓库最新 commit,比对后决定是否构建(适合无法暴露 Web 入口的内网环境) - CI/CD 流水线中加一步:当 push 到
main或打 tag 时,自动运行构建命令并 rsync 到静态服务目录
注意:satis build 命令默认不覆盖已有文件,加 --no-interaction --skip-errors 参数避免中断;若用 Docker 运行,确保挂载的 web/ 目录有写权限。
为什么 WebHook 触发后还是看不到新版本
即使构建成功,客户端仍可能拉不到新包,常见断点如下:
-
repositories配置漏了"type": "composer",写成"type": "vcs"—— 这会让 Composer 去 Git 仓库直接 clone,绕过你的私有源 - Satis 构建时没覆盖全部分支:配置里只写了
"require-all": true,但新包在dev-main分支,而该选项默认只收 tagged 版本 - 客户端缓存了旧的
packages.json:运行composer clear-cache不够,要加composer update --no-cache强制重载元数据 - 私有包自身
composer.json的version字段写死为"dev-main",但 Satis 没配"require": {"vendor/package": "dev-main"},导致扫描时跳过
如何验证 WebHook + Satis 是否真生效
别只看日志有没有 200,要逐层确认数据流是否通:
- curl 直接请求你的私有源首页,比如
curl -I https://packages.example.org/packages.json,检查Last-Modified时间是否更新 - 查 Satis 构建日志末尾是否有类似
Writing packages.json to web/packages.json和实际解析到的 commit hash - 在客户端运行
composer show -p vendor/package,确认source行指向你的私有域名,且versions包含新 tag - 临时改
composer.json的require为"vendor/package": "dev-main",再composer update vendor/package --with-dependencies -v,观察日志里是否出现Reading composer.json of vendor/package和对应 Git URL
最易被忽略的是:Satis 构建输出的 web/ 目录必须由 Web 服务器(Nginx/Apache)直接提供静态服务,不能套一层 PHP Router,否则 packages.json 无法被 Composer 正确 GET 到。


















