Skip to content

🩺 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 Diagnose once to troubleshoot common Composer environment issues (HTTP proxy, certificates, disk space, etc.).
  • 📦 Pre-commit check: Status confirms no leftover local modifications polluting the dependency directory.
  • 🔄 CI sync validation: CheckStructured determines if composer.json and composer.lock are in sync.
  • 🚀 Pre-release overview: HealthCheck gets a "healthy / warning / critical" overall assessment and issue list in one call.
  • ⚙️ Run local tools: LocalExec invokes binaries under vendor/bin/ (e.g., phpunit, phpstan).

Structured Return Types

StatusResult

Returned by StatusStructured / ParseStatusOutput, corresponds to composer status.

go
type StatusResult struct {
	Modified bool     `json:"modified"`
	Files    []string `json:"files,omitempty"`
	Output   string   `json:"output,omitempty"`
}
FieldTypeDescription
ModifiedboolWhether locally modified files exist
Files[]stringList of modified files
OutputstringRaw output

CheckResult

Returned by CheckStructured / ParseCheckOutput, corresponds to composer check.

go
type CheckResult struct {
	Valid     bool     `json:"valid"`
	Messages  []string `json:"messages,omitempty"`
	Warnings  []string `json:"warnings,omitempty"`
	Errors    []string `json:"errors,omitempty"`
}
FieldTypeDescription
ValidboolWhether composer.json and composer.lock are in sync/valid
Messages[]stringNormal messages
Warnings[]stringWarning messages
Errors[]stringError messages (presence means Valid=false)

DiagnoseResult / DiagnoseCheck

Returned by DiagnoseStructured / ParseDiagnoseOutput, corresponds to composer diagnose.

go
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"`
}
FieldTypeDescription
NamestringCheck item name
StatusstringStatus: ok/warning/error/info
DetailstringRaw line content
Checks[]DiagnoseCheckAll 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.

go
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"`
}
FieldTypeDescription
Results[]RequireResult/[]RemoveResultPer-package results
SuccessCountintSuccess count
FailCountintFailure count
TotalCountintTotal count

HealthStatus

Comprehensive health status returned by HealthCheck.

go
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"`
}
FieldTypeDescription
ComposerInstalledboolWhether Composer is installed
ComposerVersionstringComposer version number
PHPAvailableboolWhether PHP is available
PHPVersionstringPHP version number
HasComposerJsonboolWhether composer.json exists
HasComposerLockboolWhether composer.lock exists
HasVendorDirboolWhether vendor directory exists
ValidboolWhether composer.json passes validation
OutdatedCountintOutdated package count
VulnerabilityCountintSecurity vulnerability count
AbandonedCountintAbandoned package count
OverallStatusstringOverall status: healthy / warning / critical
Issues[]stringList of discovered issues

OverallStatus Determination Rules

  • critical: Composer/PHP not installed, missing composer.json, composer.json validation failed, security vulnerabilities found.
  • warning: Missing composer.lock, missing vendor directory, outdated packages present, abandoned packages present (upgraded to warning when not critical).
  • healthy: All checks pass.

Status

🩺 Show local modifications of installed packages.

Signature

go
func (c *Composer) Status() (string, error)

Parameters

None.

Return Values

ValueTypeDescription
OutputstringOutput of composer status
ErrorerrorReturned on execution failure

Equivalent Command

composer status

Example

go
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

go
func (c *Composer) StatusWithOptions(options map[string]string) (string, error)

Appends custom options, equivalent to composer status <flags>.

go
output, err := comp.StatusWithOptions(map[string]string{"verbose": ""})

Diagnose

🩺 Diagnose the system to identify common errors.

Signature

go
func (c *Composer) Diagnose() (string, error)

Parameters

None.

Return Values

ValueTypeDescription
OutputstringOutput of composer diagnose
ErrorerrorReturned on execution failure

Equivalent Command

composer diagnose

Example

go
output, err := comp.Diagnose()
if err != nil {
	log.Fatalf("Diagnosis failed: %v", err)
}
fmt.Println("Diagnosis result:")
fmt.Println(output)

Advanced: DiagnoseWithOptions

go
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

go
func (c *Composer) Check() (string, error)

Parameters

None.

Return Values

ValueTypeDescription
OutputstringOutput of composer check
ErrorerrorReturned on execution failure

Equivalent Command

composer check

Example

go
output, err := comp.Check()
if err != nil {
	log.Fatalf("Check failed: %v", err)
}
fmt.Println("Check result:", output)

Advanced: CheckWithOptions

go
func (c *Composer) CheckWithOptions(options map[string]string) (string, error)

Appends custom options.


LocalExec

🩺 Execute binaries in local packages (commands under vendor/bin/).

Signature

go
func (c *Composer) LocalExec(command string, args ...string) (string, error)

Parameters

ParameterTypeDescription
commandstringLocal binary name to execute, e.g., phpunit
args...stringArguments passed through to the binary

Return Values

ValueTypeDescription
OutputstringStandard output of binary execution
ErrorerrorReturned on execution failure

Equivalent Command

composer exec <command> [args...]

Example

go
// Run phpunit
output, err := comp.LocalExec("phpunit", "--testsuite=unit")
if err != nil {
	log.Fatalf("Execution failed: %v", err)
}
fmt.Println(output)

Advanced: LocalExecWithOptions

go
func (c *Composer) LocalExecWithOptions(command string, options map[string]string, args ...string) (string, error)

Inserts custom options (like --, --dev, etc.) between command and args.

go
output, err := comp.LocalExecWithOptions(
	"phpstan",
	map[string]string{"verbose": ""},
	"analyse", "src",
)

Structured Variants

StatusStructured

🩺 Check dependencies for local modifications, returns structured result.

go
func (c *Composer) StatusStructured() (*StatusResult, error)
ValueTypeDescription
Result*StatusResultContains Modified and Files
ErrorerrorReturned on execution failure
go
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.

go
func ParseStatusOutput(output string) *StatusResult

Parsing 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.

go
func (c *Composer) CheckStructured() (*CheckResult, error)
ValueTypeDescription
Result*CheckResultContains Valid/Messages/Warnings/Errors
ErrorerrorExecution 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.

go
func ParseCheckOutput(output string) *CheckResult

Parsing 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

go
func ParseDiagnoseOutput(output string) *DiagnoseResult
ParameterTypeDescription
outputstringRaw 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.

go
func ParseDiagnoseOutputAsChecks(output string) []DiagnoseCheck

DiagnoseStructured

🩺 Execute diagnosis and return structured result.

go
func (c *Composer) DiagnoseStructured() (*DiagnoseResult, error)
ValueTypeDescription
Result*DiagnoseResultContains Checks list
ErrorerrorExecution 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.

go
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

go
func (c *Composer) BatchRequire(packages map[string]string, dev bool, continueOnError bool) (*BatchRequireResult, error)
ParameterTypeDescription
packagesmap[string]stringPackage name → version constraint mapping
devboolWhether to add as dev dependency
continueOnErrorboolWhether to continue on error; false stops on first error
Return ValueTypeDescription
Result*BatchRequireResultContains per-item results and success/failure counts
ErrorerrorReturns first error encountered when continueOnError=false
go
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

go
func (c *Composer) BatchRemove(packages []string, dev bool, continueOnError bool) (*BatchRemoveResult, error)
ParameterTypeDescription
packages[]stringList of package names to remove
devboolWhether to remove from dev dependencies
continueOnErrorboolWhether to continue on error
Return ValueTypeDescription
Result*BatchRemoveResultContains per-item results and success/failure counts
ErrorerrorReturns 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

go
func (c *Composer) HealthCheck() (*HealthStatus, error)

Parameters

None.

Return Values

ValueTypeDescription
Health status*HealthStatusContains all check results and overall status
ErrorerrorError message

Check Dimensions

The following checks are executed in sequence (any failure doesn't affect subsequent checks):

  1. 🛠️ Composer installation: c.IsInstalled(), failure → critical; success records ComposerVersion.
  2. 💻 PHP availability: installer.HasPHP(), failure → critical; success records PHPVersion.
  3. 📄 Project files: whether composer.json/composer.lock/vendor directory exist; missing upgrades to critical or warning respectively.
  4. Config validity: c.ValidateStructured(), failure → critical, and adds each error to Issues.
  5. 📦 Outdated packages: c.GetOutdatedInfo(), count > 0 → warning.
  6. 🔒 Security vulnerabilities: c.GetAuditInfo(), count > 0 → critical.
  7. 🗑️ Abandoned packages: c.GetAbandonedPackagesFromLock(), count > 0 → warning.

Example

go
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.

go
func (c *Composer) GetHealthAsJSON() (string, error)
go
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).

go
func (c *Composer) GetInfoAsJSON() (string, error)

  • Security Audit: HealthCheck internally calls GetAuditInfo and GetAbandonedPackagesFromLock.
  • Validate: HealthCheck internally calls ValidateStructured to check composer.json validity.
  • Package Management: BatchRequire/BatchRemove internally call RequirePackage/Remove.

Released under the MIT License