必须在composer.json的scripts字段中分环境定义更新命令:开发用"update-dev"仅更新dev依赖,预发用"update-staging"先dry-run再执行并提交lock,生产禁用update只允许install;私有包需纳入流水线审计,强制声明version、提交lock、校验content-hash。

不能靠“定时 composer update”硬刷,必须区分开发、预发、生产三阶段触发逻辑,否则会把未验证的依赖变更直接推到线上。
composer.json 的 scripts 字段怎么定义分环境更新命令
scripts 不是装饰用的,它是流水线的执行锚点。关键在于把 update 拆解为可验证、可回滚的动作,而不是笼统跑一次 composer update。
- 开发环境用
"update-dev": "composer update --with-dependencies":只更新 dev 依赖及其子依赖,不影响主业务链 - 预发环境用
"update-staging": "composer update --no-dev --dry-run && composer update --no-dev":先 dry-run 检查冲突,再执行;失败时脚本自动退出,不污染 lock 文件 - 生产环境禁用
update命令,只允许基于已验证的composer.lock执行install - 所有 update 类命令必须加
--lock(Composer 2.2+)或显式--with-all-dependencies,避免部分依赖被跳过
如何让私有包更新也走同一套流水线
私有包不是例外,而是要被纳入版本控制和变更审计范围。Satis 或 Private Packagist 镜像本身不提供“自动推送更新”的能力,必须由流水线主动拉取元数据并触发解析。
- 在 CI 脚本中先执行
curl -s https://satis.internal/packages.json | jq '.packages | keys[]'获取最新包列表,对比本地composer.lock中记录的 commit hash 或 version - 若发现新版本,再运行
composer update vendor/private-package --with-dependencies,而非全量 update - 私有源 URL 必须带末尾斜杠,否则
packages.json请求 404,导致流水线误判“无更新” - 私有包的
composer.json中必须声明"version"字段(哪怕只是"dev-main"),否则 Composer 无法识别语义化版本边界,update可能跳过它
为什么 composer.lock 提交到 Git 是强制前提
没有 composer.lock,就不存在“可复现的更新”。流水线里所有 update 行为都依赖它做 diff 和约束收敛。
- CI 流水线第一步永远是
git diff HEAD~1 -- composer.lock,检查是否有人绕过流程手动改 lock - 预发环境每次
update-staging后,必须git add composer.lock && git commit -m "chore: update deps for staging",否则下次构建仍用旧 lock - 生产部署脚本开头加校验:
if ! git ls-files --error-unmatch composer.lock >/dev/null 2>&1; then echo "FATAL: composer.lock missing"; exit 1; fi - 不要忽略
composer.lock中的content-hash字段——它反映composer.json结构变化,比如新增一个 require,即使没 run update,hash 也会变,流水线应据此触发 full install
最常被跳过的环节是私有包的 version 字段声明和 lock 文件的 Git 提交动作。这两个点一旦遗漏,整个流水线就退化成“人肉判断有没有更新”,自动化的意义就没了。


















