Composer不支持自动更新,盲目在cron或CI中无条件执行update会重算依赖图、引入BC Break或环境不兼容,必须通过outdated预检、--dry-run预演、显式路径切换和锁文件管控来确保安全。

Composer 本身不支持自动更新,所谓“自动更新”必须靠外部调度 + 明确约束策略;盲目让 composer update 在 cron 或 CI 中无条件执行,大概率导致线上故障。
为什么不能直接 cron + composer update
因为 composer update 是破坏性操作:它会重算整个依赖图,可能把 monolog/monolog 从 2.9.1 升到 2.10.0,而新版本悄悄改了 Logger::error() 参数顺序;也可能让 guzzlehttp/guzzle 要求 PHP 8.1+,但你的服务器还是 8.0。
-
composer update不区分“安全补丁”和“BC Break”,默认全量更新 - cron 默认用
/bin/sh,但 Composer 需要bash特性(如命令替换),不显式指定会静默失败 - 没重定向日志(
> /var/log/composer-auto-update.log 2>&1)就等于没监控,失败了你根本不知道 - 没加
--working-dir,cron 执行时 pwd 可能是/root,结果更新了错误项目的vendor/
怎么写一个最小可行的定时检查脚本
核心原则:只查、不改;有更新才通知,不自动执行 update。
- 用
composer outdated --direct --minor-only查直接依赖的小版本可升项,跳过主版本跃迁 - 输出为空时不做任何事;非空时才触发后续逻辑(比如发 Slack、生成 PR、写日志)
- 加
--no-interaction --dry-run预演变更:composer update --dry-run --no-interaction monolog/monolog - 务必用
bash -c "cd /path/to/project && ..."显式切换路径,避免环境差异
CI/CD 中更稳的替代方案
比起让机器半夜自己升级,不如把更新动作收口到部署流程中——每次变更可审计、可回滚、可测试。
- GitHub Actions 里用
git diff --name-only HEAD~1 composer.lock判断是否真有依赖变更,再决定是否通知 - 跑
composer install --no-dev --optimize-autoloader,确保用的是锁文件里的确定版本 -
composer.lock必须提交进 Git 仓库;不提交它,“自动更新”只是制造不确定性 - 用
composer audit(Composer 2.5+)代替盲目升级,它只报已知漏洞,不改任何东西
scripts 钩子适合封装什么
"scripts" 是声明式钩子,不是自动执行器。它只在你明确运行 composer run-script 或特定生命周期(如 install)时触发,适合封装带校验的更新步骤。
- 定义
"update-dev-tools": "composer update phpunit/phpunit --no-interaction",只更新开发工具 - 配合
composer install --no-dev确保生产环境仍用旧 lock 文件,不被意外污染 - 避免在
post-update-cmd里写git commit或composer dump-autoload -o——不同环境执行上下文差异大,容易失败 - 用环境变量判断上下文:
$COMPOSER_COMMAND和$COMPOSER_EVENT可区分是update还是install
真正容易被忽略的点是:自动更新的危险不来自命令本身,而来自版本约束没写死、没跑兼容性测试、以及把 composer.lock 排除在 Git 之外。信 outdated + 人工判断 + 锁定 composer.lock,比任何“全自动”都可靠。


















