composer脚本默认不传播非零退出码,需用@@前缀透传子进程码;裸写命令会被包装吞掉失败信号,正确写法如"analyze": "@phpstan analyse src/ --no-interaction"。

Composer脚本返回非零码时CI默认不中断?
默认情况下,composer run-script 即使执行的脚本(比如 phpstan 或 phpcs)以非零退出码结束,也不会让整个命令失败——除非你显式启用错误传播。这是 CI 流水线“看似跑过但实际没校验”的常见根源。
在 composer.json 中启用脚本失败即终止
关键在于 scripts 配置里用 @@ 前缀调用命令,它会透传子进程退出码;而裸写命令(如 "phpstan analyse")会被 Composer 包装成 shell 函数,自动吞掉失败信号。
- ✅ 正确写法:
"analyze": "@phpstan analyse src/ --no-interaction" - ❌ 错误写法:
"analyze": "phpstan analyse src/ --no-interaction" - 如果脚本依赖环境变量或需多步组合,用
sh -c并确保最后一条命令决定退出码,例如:"test": "sh -c 'vendor/bin/phpunit && vendor/bin/psalm'"
CI中执行时绕过Composer封装直接调用
某些 CI 场景下(比如想跳过 composer.json 的间接控制),直接运行底层命令更可控,也天然继承退出码语义:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 用
./vendor/bin/phpstan analyse替代composer run-script analyze - 注意路径:若 CI 使用
--no-dev安装依赖,phpstan等工具可能根本不在vendor/bin/下,此时必须保证composer install --dev已执行 - GitHub Actions 或 GitLab CI 中,建议显式加
set -e(Bash)或shell: bash -e {0},避免某条命令失败却被后续步骤掩盖
调试脚本退出码的快速验证方法
别等 CI 失败才排查——本地就能模拟:
- 手动触发:运行
composer run-script analyze --no-ansi,观察终端最后是否显示Script ... handling the analyze event returned with error code 1 - 检查实际退出码:
composer run-script analyze; echo "exit code: $?",非零即表示失败被正确传递 - 临时加调试命令:
"debug": "sh -c 'echo \"running\"; false'",再composer run-script debug看是否报错并中断
真正容易被忽略的是 Composer 对 @@ 的行为限制:它只对直接命令生效,不穿透到 sh -c 或管道内部;所以复杂逻辑仍建议剥离到独立可执行脚本中,并确保该脚本自身 exit code 正确。










