🩺 Diagnosis and Health Check
Diagnose system environment, check dependency local modifications and sync status, and perform comprehensive health checks covering environment/config/dependencies/security.
Composer ships with a set of "self-check" commands: status checks installed packages for local modifications, diagnose troubleshoots common environment errors, check validates composer.json/composer.lock consistency, and exec runs local package binaries. Composer Skills provides two layers on top: base methods returning raw text, and *Structured methods and parse functions returning structured results. The top-level HealthCheck aggregates environment, config, dependency, security, and other multi-dimensional checks into a single HealthStatus.
When to Use
- 🩺 New machine onboarding: run
Diagnoseonce to troubleshoot common Composer environment issues (HTTP proxy, certificates, disk space, etc.). - 📦 Pre-commit check:
Statusconfirms no leftover local modifications polluting the dependency directory. - 🔄 CI sync validation:
CheckStructureddetermines ifcomposer.jsonandcomposer.lockare in sync. - 🚀 Pre-release overview:
HealthCheckgets a "healthy / warning / critical" overall assessment and issue list in one call. - ⚙️ Run local tools:
LocalExecinvokes binaries undervendor/bin/(e.g., phpunit, phpstan).
Structured Return Types
StatusResult
Returned by StatusStructured / ParseStatusOutput, corresponds to composer status.
type StatusResult struct {
Modified bool `json:"modified"`
Files []string `json:"files,omitempty"`
Output string `json:"output,omitempty"`
}| Field | Type | Description |
|---|---|---|
Modified | bool | Whether locally modified files exist |
Files | []string | List of modified files |
Output | string | Raw output |
CheckResult
Returned by CheckStructured / ParseCheckOutput, corresponds to composer check.
type CheckResult struct {
Valid bool `json:"valid"`
Messages []string `json:"messages,omitempty"`
Warnings []string `json:"warnings,omitempty"`
Errors []string `json:"errors,omitempty"`
}| Field | Type | Description |
|---|---|---|
Valid | bool | Whether composer.json and composer.lock are in sync/valid |
Messages | []string | Normal messages |
Warnings | []string | Warning messages |
Errors | []string | Error messages (presence means Valid=false) |
DiagnoseResult / DiagnoseCheck
Returned by DiagnoseStructured / ParseDiagnoseOutput, corresponds to 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"`
}| Field | Type | Description |
|---|---|---|
Name | string | Check item name |
Status | string | Status: ok/warning/error/info |
Detail | string | Raw line content |
Checks | []DiagnoseCheck | All check items |
Status Determination
ParseDiagnoseOutput scans line by line, determining status by prefix: [OK] or ✓ → ok; [WARNING] or ⚠ → warning; [ERROR] or ✗ → error; others classified as info.
BatchRequireResult / BatchRemoveResult
Results of batch add/remove packages.
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"`
}| Field | Type | Description |
|---|---|---|
Results | []RequireResult/[]RemoveResult | Per-package results |
SuccessCount | int | Success count |
FailCount | int | Failure count |
TotalCount | int | Total count |
HealthStatus
Comprehensive health status returned by 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"`
}| Field | Type | Description |
|---|---|---|
ComposerInstalled | bool | Whether Composer is installed |
ComposerVersion | string | Composer version number |
PHPAvailable | bool | Whether PHP is available |
PHPVersion | string | PHP version number |
HasComposerJson | bool | Whether composer.json exists |
HasComposerLock | bool | Whether composer.lock exists |
HasVendorDir | bool | Whether vendor directory exists |
Valid | bool | Whether composer.json passes validation |
OutdatedCount | int | Outdated package count |
VulnerabilityCount | int | Security vulnerability count |
AbandonedCount | int | Abandoned package count |
OverallStatus | string | Overall status: healthy / warning / critical |
Issues | []string | List of discovered issues |
OverallStatus Determination Rules
critical: Composer/PHP not installed, missingcomposer.json,composer.jsonvalidation failed, security vulnerabilities found.warning: Missingcomposer.lock, missingvendordirectory, outdated packages present, abandoned packages present (upgraded to warning when not critical).healthy: All checks pass.
Status
🩺 Show local modifications of installed packages.
Signature
func (c *Composer) Status() (string, error)Parameters
None.
Return Values
| Value | Type | Description |
|---|---|---|
| Output | string | Output of composer status |
| Error | error | Returned on execution failure |
Equivalent Command
composer status
Example
output, err := comp.Status()
if err != nil {
log.Fatalf("Status check failed: %v", err)
}
if output != "" {
fmt.Println("Local modifications found:")
fmt.Println(output)
} else {
fmt.Println("No local modifications")
}Advanced: StatusWithOptions
func (c *Composer) StatusWithOptions(options map[string]string) (string, error)Appends custom options, equivalent to composer status <flags>.
output, err := comp.StatusWithOptions(map[string]string{"verbose": ""})Diagnose
🩺 Diagnose the system to identify common errors.
Signature
func (c *Composer) Diagnose() (string, error)Parameters
None.
Return Values
| Value | Type | Description |
|---|---|---|
| Output | string | Output of composer diagnose |
| Error | error | Returned on execution failure |
Equivalent Command
composer diagnose
Example
output, err := comp.Diagnose()
if err != nil {
log.Fatalf("Diagnosis failed: %v", err)
}
fmt.Println("Diagnosis result:")
fmt.Println(output)Advanced: DiagnoseWithOptions
func (c *Composer) DiagnoseWithOptions(options map[string]string) (string, error)Appends custom options.
Check
🩺 Check whether dependencies meet requirements (sync between composer.json and composer.lock).
Signature
func (c *Composer) Check() (string, error)Parameters
None.
Return Values
| Value | Type | Description |
|---|---|---|
| Output | string | Output of composer check |
| Error | error | Returned on execution failure |
Equivalent Command
composer check
Example
output, err := comp.Check()
if err != nil {
log.Fatalf("Check failed: %v", err)
}
fmt.Println("Check result:", output)Advanced: CheckWithOptions
func (c *Composer) CheckWithOptions(options map[string]string) (string, error)Appends custom options.
LocalExec
🩺 Execute binaries in local packages (commands under vendor/bin/).
Signature
func (c *Composer) LocalExec(command string, args ...string) (string, error)Parameters
| Parameter | Type | Description |
|---|---|---|
command | string | Local binary name to execute, e.g., phpunit |
args | ...string | Arguments passed through to the binary |
Return Values
| Value | Type | Description |
|---|---|---|
| Output | string | Standard output of binary execution |
| Error | error | Returned on execution failure |
Equivalent Command
composer exec <command> [args...]
Example
// Run phpunit
output, err := comp.LocalExec("phpunit", "--testsuite=unit")
if err != nil {
log.Fatalf("Execution failed: %v", err)
}
fmt.Println(output)Advanced: LocalExecWithOptions
func (c *Composer) LocalExecWithOptions(command string, options map[string]string, args ...string) (string, error)Inserts custom options (like --, --dev, etc.) between command and args.
output, err := comp.LocalExecWithOptions(
"phpstan",
map[string]string{"verbose": ""},
"analyse", "src",
)Structured Variants
StatusStructured
🩺 Check dependencies for local modifications, returns structured result.
func (c *Composer) StatusStructured() (*StatusResult, error)| Value | Type | Description |
|---|---|---|
| Result | *StatusResult | Contains Modified and Files |
| Error | error | Returned on execution failure |
result, err := comp.StatusStructured()
if err != nil {
log.Fatalf("Status check failed: %v", err)
}
if result.Modified {
fmt.Printf("Found %d modified files\n", len(result.Files))
for _, f := range result.Files {
fmt.Println("- " + f)
}
}ParseStatusOutput
Pure function, parses any composer status text output into *StatusResult.
func ParseStatusOutput(output string) *StatusResultParsing logic: if output is empty (including whitespace), Modified=false; otherwise, each non-empty line is treated as a modified file, setting Modified=true.
CheckStructured
🩺 Check whether composer.json and composer.lock are in sync, returns structured result.
func (c *Composer) CheckStructured() (*CheckResult, error)| Value | Type | Description |
|---|---|---|
| Result | *CheckResult | Contains Valid/Messages/Warnings/Errors |
| Error | error | Execution error (note: when the command returns non-zero exit code, Valid is set to false, but may not return an error) |
Implementation Detail
CheckStructured first executes composer check; regardless of error, it parses the output with ParseCheckOutput; if the command errors, it additionally sets Valid to false. That is, "error means definitely not passed", but "not passed doesn't necessarily mean a Go-level error".
ParseCheckOutput
Pure function, parses any composer check text output into *CheckResult.
func ParseCheckOutput(output string) *CheckResultParsing logic: scans line by line; lines containing error/Error/FAIL go into Errors and set Valid=false; lines containing warning/Warning/WARN go into Warnings; others go into Messages.
ParseStatusOutput / ParseDiagnoseOutput
🩺 Pure parse functions, convenient for post-analysis of old outputs in cache or logs, without re-executing commands.
ParseDiagnoseOutput
func ParseDiagnoseOutput(output string) *DiagnoseResult| Parameter | Type | Description |
|---|---|---|
output | string | Raw output of composer diagnose |
Returns *DiagnoseResult, determining each item's Status by prefix ([OK]/✓, [WARNING]/⚠, [ERROR]/✗) line by line.
ParseDiagnoseOutputAsChecks
Defined in parsing.go, parses diagnose output into a []DiagnoseCheck slice.
func ParseDiagnoseOutputAsChecks(output string) []DiagnoseCheckDiagnoseStructured
🩺 Execute diagnosis and return structured result.
func (c *Composer) DiagnoseStructured() (*DiagnoseResult, error)| Value | Type | Description |
|---|---|---|
| Result | *DiagnoseResult | Contains Checks list |
| Error | error | Execution error (note: diagnosis finding issues doesn't necessarily return an error; need to check Checks status) |
Return Value Semantics
DiagnoseStructured returns the command's error as-is, but also parses the output into DiagnoseResult. So even if err != nil, result may still be non-nil and contain valid checks. Recommend checking result.Checks first before deciding how to handle 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("Diagnosis execution returned error: %v", err)
}BatchRequire / BatchRemove
🩺 Batch add/remove multiple packages, summarizing success and failure counts.
BatchRequire
func (c *Composer) BatchRequire(packages map[string]string, dev bool, continueOnError bool) (*BatchRequireResult, error)| Parameter | Type | Description |
|---|---|---|
packages | map[string]string | Package name → version constraint mapping |
dev | bool | Whether to add as dev dependency |
continueOnError | bool | Whether to continue on error; false stops on first error |
| Return Value | Type | Description |
|---|---|---|
| Result | *BatchRequireResult | Contains per-item results and success/failure counts |
| Error | error | Returns first error encountered when 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("Batch add failed: %v", err)
}
fmt.Printf("Success: %d, Failed: %d\n", result.SuccessCount, result.FailCount)BatchRemove
func (c *Composer) BatchRemove(packages []string, dev bool, continueOnError bool) (*BatchRemoveResult, error)| Parameter | Type | Description |
|---|---|---|
packages | []string | List of package names to remove |
dev | bool | Whether to remove from dev dependencies |
continueOnError | bool | Whether to continue on error |
| Return Value | Type | Description |
|---|---|---|
| Result | *BatchRemoveResult | Contains per-item results and success/failure counts |
| Error | error | Returns first error encountered when continueOnError=false |
Failure Handling
Both batch methods append error info to the corresponding item's Warnings field on failure, for later troubleshooting. continueOnError=true is suitable for "install as much as possible, summarize at end" scenarios; false is suitable for "all must succeed" strict scenarios.
HealthCheck
🩺 Perform comprehensive project health check, aggregating environment, config, dependency, and security multi-dimensional results into a single HealthStatus.
Signature
func (c *Composer) HealthCheck() (*HealthStatus, error)Parameters
None.
Return Values
| Value | Type | Description |
|---|---|---|
| Health status | *HealthStatus | Contains all check results and overall status |
| Error | error | Error message |
Check Dimensions
The following checks are executed in sequence (any failure doesn't affect subsequent checks):
- 🛠️ Composer installation:
c.IsInstalled(), failure → critical; success recordsComposerVersion. - 💻 PHP availability:
installer.HasPHP(), failure → critical; success recordsPHPVersion. - 📄 Project files: whether
composer.json/composer.lock/vendordirectory exist; missing upgrades to critical or warning respectively. - ✅ Config validity:
c.ValidateStructured(), failure → critical, and adds each error toIssues. - 📦 Outdated packages:
c.GetOutdatedInfo(), count > 0 → warning. - 🔒 Security vulnerabilities:
c.GetAuditInfo(), count > 0 → critical. - 🗑️ Abandoned packages:
c.GetAbandonedPackagesFromLock(), count > 0 → warning.
Example
health, err := comp.HealthCheck()
if err != nil {
log.Fatalf("Health check failed: %v", err)
}
fmt.Printf("Overall status: %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("Outdated: %d, Vulnerabilities: %d, Abandoned: %d\n",
health.OutdatedCount, health.VulnerabilityCount, health.AbandonedCount)
if len(health.Issues) > 0 {
fmt.Println("Issue list:")
for _, issue := range health.Issues {
fmt.Printf("- %s\n", issue)
}
}Advanced: GetHealthAsJSON
Serialize HealthCheck result to indented JSON string, convenient for embedding in API responses or writing to report files.
func (c *Composer) GetHealthAsJSON() (string, error)jsonStr, err := comp.GetHealthAsJSON()
if err != nil {
log.Fatalf("Serialization failed: %v", err)
}
fmt.Println(jsonStr)Advanced: GetInfoAsJSON
Comprehensively get project summary info and format as JSON (based on GetProjectSummary).
func (c *Composer) GetInfoAsJSON() (string, error)🔍 Related Methods
- Security Audit:
HealthCheckinternally callsGetAuditInfoandGetAbandonedPackagesFromLock. - Validate:
HealthCheckinternally callsValidateStructuredto checkcomposer.jsonvalidity. - Package Management:
BatchRequire/BatchRemoveinternally callRequirePackage/Remove.