composer licenses 命令并非 composer 内置命令,而是依赖 zicht/composer-license-plugin 等第三方插件;原生命令仅支持 composer show vendor/package-name 查 license 字段,ci 中需用 jq 解析 composer.lock 实现早期合规卡点。

composer licenses 命令根本不存在,别在 CI 里硬写
直接运行 composer licenses 会报错:Command "licenses" is not defined. 这不是你环境没配好,也不是版本低——Composer 官方至今(2026年7月)**从未内置该命令**。所有文档或脚本里出现它,背后都依赖第三方插件,最常见的是 zicht/composer-license-plugin。CI 中没装这个插件却写了这行命令?构建直接失败,不是 warning,是 fatal error。
真正能用的原生命令只有 composer show
composer show vendor/package-name 是唯一不依赖插件、不联网、不解析文件的可靠方式,它读的是 vendor/ 下已安装包的 composer.json 中的 license 字段。但必须满足:
- 已执行过
composer install或composer update,否则报Package not found - 只查显式声明在
composer.json的require或require-dev中的包,symfony/polyfill-intl-idn这类传递依赖完全不会出现 - 字段值原样输出:遇到
"license": "SEE LICENSE IN LICENSE.md",它绝不会打开文件;遇到空值、"proprietary"、"unlicensed",也不会警告——你得自己盯住这些信号
CI 早期卡点必须绕过 vendor/,直接解析 composer.lock
想在 composer install 前拦截 GPL 类风险,不能等 vendor/ 生成。正确做法是直接读 composer.lock:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 用
jq -r '.packages[] | "\(.name)\t\(.version)\t\(.license // ["unknown"] | join(" | "))"' composer.lock提取结构化清单 - 对输出做
grep -E "(GPL|AGPL|LGPL|proprietary|unlicensed)",匹配到就exit 1 - 注意:有些包
license字段为空或为 URL(如"https://example.com/LICENSE"),jq会输出unknown,这类必须人工确认,不能跳过
zicht/composer-license-plugin 是目前最稳的批量方案
当需要覆盖传递依赖、标准化模糊 license 值、并尝试读取实际 LICENSE 文件时,它仍是当前最成熟的第三方选择:
- 安装:
composer require --dev zicht/composer-license-plugin - 导出:
composer licenses --format=json > licenses.json,它会递归扫描所有依赖(含require-dev和传递依赖) - 它能把
"The MIT License"归一化为MIT,把"SEE LICENSE IN LICENSE.md"替换为实际匹配到的 SPDX ID(如MIT或GPL-3.0-only) - 对私有 fork(如
"repositories": [{"type": "vcs", "url": "git@"}])默认跳过,得先composer archive导出再人工审计
SPDX 标识符和 LICENSE 文件全文,二者缺一不可。自动化只能筛出高危项,最终仍需人工核验原文与 SPDX 的一致性。










