在CI/CD流水线中应使用composer run-script ci:test统一调用预定义脚本,而非shell拼接命令;scripts中用数组顺序执行、@xxx复用子脚本,确保环境一致、生命周期完整、错误可定位。

流水线里怎么用 composer run-script 串命令
直接用 composer run-script 是最稳妥的方式,它天然支持在 scripts 里定义多步骤逻辑,还能复用环境、自动加载 autoloader,比 shell 拼接更可靠。
常见错误是直接在 CI 脚本里写 composer install && php artisan migrate && phpunit——这看似简单,但失败后无法精准定位哪步挂了,且不同环境的 PATH、PHP 版本、扩展差异容易导致行为不一致。
- 所有命令必须定义在
composer.json的scripts字段下,例如:"scripts": { "ci:test": [ "@install", "@lint", "@test" ], "install": "composer install --no-interaction --prefer-dist", "lint": "php -l src/ || exit 1", "test": "vendor/bin/phpunit --colors=never" } - 用
@xxx语法可复用已有 script,避免重复写命令;数组形式保证顺序执行,任一失败即中止 - CI 中只调一条:
composer run-script ci:test,而不是拆成多条composer xxx
为什么不能用 composer exec 或 shell 管道串命令
composer exec 只是包装了 proc_open 执行单条命令,不支持链式调用;而 | 或 && 在 shell 层面拼接,会绕过 Composer 的脚本生命周期(比如不会触发 post-install-cmd),也丢失了 COMPOSER_ROOT_VERSION 这类内置变量。
-
composer exec php -- -v可以跑,但composer exec php -- -v && echo ok实际上是 shell 在执行&&,不是 Composer 控制的 - 某些 CI 平台(如 GitLab CI)默认用
sh启动,不支持[[ ]]或数组语法,直接写 shell 链容易因语法差异失败 - 若某步需前置条件(如先生成配置文件再跑测试),靠 shell 拼接很难做条件跳过,而
run-script可配合--no-dev或自定义 flag 控制分支
怎么传参给串联中的某条子命令
Composer 脚本本身不支持位置参数透传,但可以用环境变量或临时配置绕过限制。
- 在 CI 中设置变量再引用:
COMPOSER_TEST_FILTER=FeatureTest composer run-script test,然后在scripts.test里写vendor/bin/phpunit --filter=$COMPOSER_TEST_FILTER - 避免在
scripts值里硬编码参数,否则无法动态替换;推荐把参数逻辑下沉到独立脚本(如bin/run-ci.php),composer run-script只负责调用它 - 注意 Windows CI(如 GitHub Actions on windows-latest)中环境变量大小写敏感问题:
$COMPOSER_TEST_FILTER在 PowerShell 下要写成$env:COMPOSER_TEST_FILTER,统一用 sh/bash 环境更省事
遇到 “Script xxx returned with error code” 怎么快速定位
这个错误信息太笼统,实际可能是子命令本身报错,也可能是权限、路径或扩展缺失。关键看输出是否被截断,以及是否启用了 --verbose。
- 加
-v参数重试:composer run-script ci:test -v,能看到每步执行的真实命令和完整 stderr - 检查是否用了
--no-ansi或重定向了 stdout,导致错误堆栈被吞掉;CI 日志里搜PHP Fatal error或Class not found比看返回码更直接 - 某些脚本(如 Laravel 的
optimize:clear)依赖bootstrap/app.php,若composer install没装 dev 依赖,运行时可能报Class 'Illuminate\Support\ServiceProvider' not found,这不是串联逻辑问题,而是依赖范围没配对
真正麻烦的不是怎么串命令,而是每条子命令隐含的上下文依赖——比如某个 post-autoload-dump 脚本修改了 vendor/autoload.php,会影响后续所有 PHP 命令的行为。这些细节在本地跑得通,到了 CI 容器里就容易露馅。











