🩺 诊断与健康检查
诊断系统环境、检查依赖本地修改与同步性,并执行覆盖环境/配置/依赖/安全的综合健康检查。
Composer 自带一组「自检」命令:status 查看已安装包是否有本地修改、diagnose 排查常见环境错误、check 校验 composer.json 与 composer.lock 的一致性、exec 执行本地包二进制。Composer Skills 在此之上提供两层封装:返回原始文本的基础方法,以及返回结构化结果的 *Structured 方法与解析函数。最顶层的 HealthCheck 把环境、配置、依赖、安全等多维度检查汇聚成一个 HealthStatus。
何时使用
- 🩺 新机器接入:跑一次
Diagnose排查 Composer 环境常见问题(HTTP 代理、证书、磁盘空间等)。 - 📦 提交前检查:
Status确认没有遗留的本地修改污染依赖目录。 - 🔄 CI 同步性校验:
CheckStructured判断composer.json与composer.lock是否同步。 - 🚀 发布前总览:
HealthCheck一次调用拿到「healthy / warning / critical」总评与问题清单。 - ⚙️ 运行本地工具:
LocalExec调用vendor/bin/下的二进制(如 phpunit、phpstan)。
结构化返回类型
StatusResult
StatusStructured / ParseStatusOutput 返回,对应 composer status。
type StatusResult struct {
Modified bool `json:"modified"`
Files []string `json:"files,omitempty"`
Output string `json:"output,omitempty"`
}| 字段 | 类型 | 说明 |
|---|---|---|
Modified | bool | 是否存在本地修改的文件 |
Files | []string | 被修改的文件列表 |
Output | string | 原始输出 |
CheckResult
CheckStructured / ParseCheckOutput 返回,对应 composer check。
type CheckResult struct {
Valid bool `json:"valid"`
Messages []string `json:"messages,omitempty"`
Warnings []string `json:"warnings,omitempty"`
Errors []string `json:"errors,omitempty"`
}| 字段 | 类型 | 说明 |
|---|---|---|
Valid | bool | composer.json 与 composer.lock 是否同步/有效 |
Messages | []string | 普通信息 |
Warnings | []string | 警告信息 |
Errors | []string | 错误信息(出现则 Valid=false) |
DiagnoseResult / DiagnoseCheck
DiagnoseStructured / ParseDiagnoseOutput 返回,对应 composer diagnose。
type DiagnoseCheck struct {
Name string `json:"name"`
Status string `json:"status"` // "ok", "warning", "error", "info"
Detail string `json:"detail,omitempty"`
}
type DiagnoseResult struct {
Checks []DiagnoseCheck `json:"checks,omitempty"`
}| 字段 | 类型 | 说明 |
|---|---|---|
Name | string | 检查项名称 |
Status | string | 状态:ok/warning/error/info |
Detail | string | 原始行内容 |
Checks | []DiagnoseCheck | 全部检查项 |
状态判定
ParseDiagnoseOutput 按行扫描,依据前缀判定状态:[OK] 或 ✓ → ok;[WARNING] 或 ⚠ → warning;[ERROR] 或 ✗ → error;其余归为 info。
BatchRequireResult / BatchRemoveResult
批量添加/移除包的结果。
type BatchRequireResult struct {
Results []RequireResult `json:"results,omitempty"`
SuccessCount int `json:"success_count"`
FailCount int `json:"fail_count"`
TotalCount int `json:"total_count"`
}
type BatchRemoveResult struct {
Results []RemoveResult `json:"results,omitempty"`
SuccessCount int `json:"success_count"`
FailCount int `json:"fail_count"`
TotalCount int `json:"total_count"`
}| 字段 | 类型 | 说明 |
|---|---|---|
Results | []RequireResult/[]RemoveResult | 各包的逐项结果 |
SuccessCount | int | 成功数量 |
FailCount | int | 失败数量 |
TotalCount | int | 总数量 |
HealthStatus
HealthCheck 返回的综合健康状态。
type HealthStatus struct {
ComposerInstalled bool `json:"composer_installed"`
ComposerVersion string `json:"composer_version,omitempty"`
PHPAvailable bool `json:"php_available"`
PHPVersion string `json:"php_version,omitempty"`
HasComposerJson bool `json:"has_composer_json"`
HasComposerLock bool `json:"has_composer_lock"`
HasVendorDir bool `json:"has_vendor_dir"`
Valid bool `json:"valid,omitempty"`
OutdatedCount int `json:"outdated_count,omitempty"`
VulnerabilityCount int `json:"vulnerability_count,omitempty"`
AbandonedCount int `json:"abandoned_count,omitempty"`
OverallStatus string `json:"overall_status"`
Issues []string `json:"issues,omitempty"`
}| 字段 | 类型 | 说明 |
|---|---|---|
ComposerInstalled | bool | Composer 是否已安装 |
ComposerVersion | string | Composer 版本号 |
PHPAvailable | bool | PHP 是否可用 |
PHPVersion | string | PHP 版本号 |
HasComposerJson | bool | 是否存在 composer.json |
HasComposerLock | bool | 是否存在 composer.lock |
HasVendorDir | bool | 是否存在 vendor 目录 |
Valid | bool | composer.json 是否通过验证 |
OutdatedCount | int | 过时包数量 |
VulnerabilityCount | int | 安全漏洞数量 |
AbandonedCount | int | 已放弃包数量 |
OverallStatus | string | 总体状态:healthy / warning / critical |
Issues | []string | 发现的问题清单 |
OverallStatus 判定规则
critical:Composer/PHP 未安装、缺少composer.json、composer.json验证失败、发现安全漏洞。warning:缺少composer.lock、缺少vendor目录、存在过时包、存在已放弃包(在非 critical 情况下升级为 warning)。healthy:所有检查均通过。
Status
🩺 显示已安装包的本地修改。
签名
func (c *Composer) Status() (string, error)参数
无。
返回值
| 值 | 类型 | 说明 |
|---|---|---|
| 输出 | string | composer status 的输出 |
| 错误 | error | 执行失败时返回 |
等价命令
composer status
示例
output, err := comp.Status()
if err != nil {
log.Fatalf("检查状态失败: %v", err)
}
if output != "" {
fmt.Println("发现本地修改:")
fmt.Println(output)
} else {
fmt.Println("无本地修改")
}进阶:StatusWithOptions
func (c *Composer) StatusWithOptions(options map[string]string) (string, error)附加自定义选项,等价 composer status <flags>。
output, err := comp.StatusWithOptions(map[string]string{"verbose": ""})Diagnose
🩺 诊断系统以识别常见错误。
签名
func (c *Composer) Diagnose() (string, error)参数
无。
返回值
| 值 | 类型 | 说明 |
|---|---|---|
| 输出 | string | composer diagnose 的输出 |
| 错误 | error | 执行失败时返回 |
等价命令
composer diagnose
示例
output, err := comp.Diagnose()
if err != nil {
log.Fatalf("诊断失败: %v", err)
}
fmt.Println("诊断结果:")
fmt.Println(output)进阶:DiagnoseWithOptions
func (c *Composer) DiagnoseWithOptions(options map[string]string) (string, error)附加自定义选项。
Check
🩺 检查依赖项是否满足要求(composer.json 与 composer.lock 同步性)。
签名
func (c *Composer) Check() (string, error)参数
无。
返回值
| 值 | 类型 | 说明 |
|---|---|---|
| 输出 | string | composer check 的输出 |
| 错误 | error | 执行失败时返回 |
等价命令
composer check
示例
output, err := comp.Check()
if err != nil {
log.Fatalf("检查失败: %v", err)
}
fmt.Println("检查结果:", output)进阶:CheckWithOptions
func (c *Composer) CheckWithOptions(options map[string]string) (string, error)附加自定义选项。
LocalExec
🩺 执行本地包中的二进制文件(vendor/bin/ 下的命令)。
签名
func (c *Composer) LocalExec(command string, args ...string) (string, error)参数
| 参数 | 类型 | 说明 |
|---|---|---|
command | string | 要执行的本地二进制名称,如 phpunit |
args | ...string | 透传给该二进制的参数 |
返回值
| 值 | 类型 | 说明 |
|---|---|---|
| 输出 | string | 二进制执行的标准输出 |
| 错误 | error | 执行失败时返回 |
等价命令
composer exec <command> [args...]
示例
// 运行 phpunit
output, err := comp.LocalExec("phpunit", "--testsuite=unit")
if err != nil {
log.Fatalf("执行失败: %v", err)
}
fmt.Println(output)进阶:LocalExecWithOptions
func (c *Composer) LocalExecWithOptions(command string, options map[string]string, args ...string) (string, error)在命令与参数之间插入自定义选项(如 --、--dev 等)。
output, err := comp.LocalExecWithOptions(
"phpstan",
map[string]string{"verbose": ""},
"analyse", "src",
)Structured 变体
StatusStructured
🩺 检查依赖是否有本地修改,返回结构化结果。
func (c *Composer) StatusStructured() (*StatusResult, error)| 值 | 类型 | 说明 |
|---|---|---|
| 结果 | *StatusResult | 含 Modified 与 Files |
| 错误 | error | 执行失败时返回 |
result, err := comp.StatusStructured()
if err != nil {
log.Fatalf("检查状态失败: %v", err)
}
if result.Modified {
fmt.Printf("发现 %d 个修改的文件\n", len(result.Files))
for _, f := range result.Files {
fmt.Println("- " + f)
}
}ParseStatusOutput
纯函数,把任意 composer status 文本输出解析为 *StatusResult。
func ParseStatusOutput(output string) *StatusResult解析逻辑:输出为空(含首尾空白)则 Modified=false;否则每一非空行视为一个被修改文件,置 Modified=true。
CheckStructured
🩺 检查 composer.json 与 composer.lock 是否同步,返回结构化结果。
func (c *Composer) CheckStructured() (*CheckResult, error)| 值 | 类型 | 说明 |
|---|---|---|
| 结果 | *CheckResult | 含 Valid/Messages/Warnings/Errors |
| 错误 | error | 执行错误(注意:命令返回非零退出码时 Valid 置 false,但不一定返回 error) |
实现细节
CheckStructured 先执行 composer check,无论是否出错都用 ParseCheckOutput 解析输出;若命令报错,则额外把 Valid 置为 false。即「报错一定不通过」,但「不通过不一定有 Go 层 error」。
ParseCheckOutput
纯函数,把任意 composer check 文本输出解析为 *CheckResult。
func ParseCheckOutput(output string) *CheckResult解析逻辑:逐行扫描,含 error/Error/FAIL 的行归入 Errors 并置 Valid=false;含 warning/Warning/WARN 的行归入 Warnings;其余归入 Messages。
ParseStatusOutput / ParseDiagnoseOutput
🩺 纯解析函数,便于对缓存或日志中的旧输出做事后分析,无需重新执行命令。
ParseDiagnoseOutput
func ParseDiagnoseOutput(output string) *DiagnoseResult| 参数 | 类型 | 说明 |
|---|---|---|
output | string | composer diagnose 的原始输出 |
返回 *DiagnoseResult,逐行按前缀([OK]/✓、[WARNING]/⚠、[ERROR]/✗)判定每项 Status。
ParseDiagnoseOutputAsChecks
定义在 parsing.go,把 diagnose 输出解析为 []DiagnoseCheck 切片形式。
func ParseDiagnoseOutputAsChecks(output string) []DiagnoseCheckDiagnoseStructured
🩺 执行诊断并返回结构化结果。
func (c *Composer) DiagnoseStructured() (*DiagnoseResult, error)| 值 | 类型 | 说明 |
|---|---|---|
| 结果 | *DiagnoseResult | 含 Checks 列表 |
| 错误 | error | 执行错误(注意:诊断发现问题不一定返回 error,需遍历 Checks 看状态) |
返回值语义
DiagnoseStructured 把命令的 error 原样返回,但同时把输出解析为 DiagnoseResult。因此即使 err != nil,result 仍可能非空且含有效检查项。建议先看 result.Checks 再决定如何处理 err。
result, err := comp.DiagnoseStructured()
if result != nil {
for _, chk := range result.Checks {
switch chk.Status {
case "error":
fmt.Printf("❌ %s\n", chk.Name)
case "warning":
fmt.Printf("⚠️ %s\n", chk.Name)
case "ok":
fmt.Printf("✅ %s\n", chk.Name)
}
}
}
if err != nil {
log.Printf("诊断执行返回错误: %v", err)
}BatchRequire / BatchRemove
🩺 批量添加/移除多个包,汇总成功与失败计数。
BatchRequire
func (c *Composer) BatchRequire(packages map[string]string, dev bool, continueOnError bool) (*BatchRequireResult, error)| 参数 | 类型 | 说明 |
|---|---|---|
packages | map[string]string | 包名 → 版本约束的映射 |
dev | bool | 是否作为开发依赖 |
continueOnError | bool | 遇到错误是否继续;false 则遇到第一个错误即停止 |
| 返回值 | 类型 | 说明 |
|---|---|---|
| 结果 | *BatchRequireResult | 含逐项结果与成功/失败计数 |
| 错误 | error | continueOnError=false 时返回第一个遇到的错误 |
packages := map[string]string{
"symfony/console": "^5.4",
"monolog/monolog": "^2.0",
"psr/log": "^1.1",
}
result, err := comp.BatchRequire(packages, false, true)
if err != nil {
log.Fatalf("批量添加失败: %v", err)
}
fmt.Printf("成功: %d, 失败: %d\n", result.SuccessCount, result.FailCount)BatchRemove
func (c *Composer) BatchRemove(packages []string, dev bool, continueOnError bool) (*BatchRemoveResult, error)| 参数 | 类型 | 说明 |
|---|---|---|
packages | []string | 要移除的包名列表 |
dev | bool | 是否从开发依赖中移除 |
continueOnError | bool | 遇到错误是否继续 |
| 返回值 | 类型 | 说明 |
|---|---|---|
| 结果 | *BatchRemoveResult | 含逐项结果与成功/失败计数 |
| 错误 | error | continueOnError=false 时返回第一个遇到的错误 |
失败处理
两个批量方法在失败时会把错误信息追加到对应项的 Warnings 字段,便于事后排查。continueOnError=true 适合「尽量多装、最后汇总报告」的场景;false 适合「全部成功才算成功」的严格场景。
HealthCheck
🩺 执行全面的项目健康检查,汇聚环境、配置、依赖、安全多维度结果为单一 HealthStatus。
签名
func (c *Composer) HealthCheck() (*HealthStatus, error)参数
无。
返回值
| 值 | 类型 | 说明 |
|---|---|---|
| 健康状态 | *HealthStatus | 含各项检查结果与总体状态 |
| 错误 | error | 错误信息 |
检查维度
依次执行以下检查(任一失败不影响后续检查):
- 🛠️ Composer 安装:
c.IsInstalled(),失败 → critical;成功则记录ComposerVersion。 - 💻 PHP 可用性:
installer.HasPHP(),失败 → critical;成功则记录PHPVersion。 - 📄 项目文件:
composer.json/composer.lock/vendor目录是否存在,缺失分别升级到 critical 或 warning。 - ✅ 配置有效性:
c.ValidateStructured(),失败 → critical,并把逐条错误加入Issues。 - 📦 过时包:
c.GetOutdatedInfo(),数量 > 0 → warning。 - 🔒 安全漏洞:
c.GetAuditInfo(),数量 > 0 → critical。 - 🗑️ 已放弃包:
c.GetAbandonedPackagesFromLock(),数量 > 0 → warning。
示例
health, err := comp.HealthCheck()
if err != nil {
log.Fatalf("健康检查失败: %v", err)
}
fmt.Printf("总体状态: %s\n", health.OverallStatus)
fmt.Printf("Composer: %s (installed=%v)\n", health.ComposerVersion, health.ComposerInstalled)
fmt.Printf("PHP: %s (available=%v)\n", health.PHPVersion, health.PHPAvailable)
fmt.Printf("过时包: %d, 漏洞: %d, 已放弃: %d\n",
health.OutdatedCount, health.VulnerabilityCount, health.AbandonedCount)
if len(health.Issues) > 0 {
fmt.Println("问题清单:")
for _, issue := range health.Issues {
fmt.Printf("- %s\n", issue)
}
}进阶:GetHealthAsJSON
把 HealthCheck 结果序列化为缩进 JSON 字符串,便于嵌入 API 响应或写入报告文件。
func (c *Composer) GetHealthAsJSON() (string, error)jsonStr, err := comp.GetHealthAsJSON()
if err != nil {
log.Fatalf("序列化失败: %v", err)
}
fmt.Println(jsonStr)进阶:GetInfoAsJSON
综合获取项目摘要信息并格式化为 JSON(基于 GetProjectSummary)。
func (c *Composer) GetInfoAsJSON() (string, error)