🗂️ cli_project_management — Project Management
This example demonstrates how to use the Composer Skills SDK to perform project-management operations on a local PHP project: create and validate projects, run scripts, check platform requirements, do dependency analysis, and run integrity checks and system diagnostics.
📌 Example Positioning
cli_project_management is the third stop in the Composer CLI example series, focusing on "project-level" management tasks. The previous example, cli_package_management, focuses on package CRUD; this example answers:
- 🆕 How to create and validate a new project (whether
composer.jsonis valid) - 🎬 How to list and run the scripts defined in
composer.json - 🖥️ How to check whether the current runtime meets PHP version and extension requirements
- 🔍 How to analyze dependencies (dependency tree, reverse dependencies, why-installed, outdated checks, security audit)
- 🩺 How to run integrity checks and system diagnostics on a project
These capabilities correspond to the project-management, validation, platform-check, dependency-analysis, and diagnostic method families in the pkg/composer package. All examples create the instance via composer.New(composer.DefaultOptions()) and then switch to a temp directory with SetWorkingDir to avoid polluting real projects.
💻 Full Code
Below is the key logic from this example's 5 source files (comments trimmed appropriately; logic fully preserved).
1️⃣ Create and Validate a Project
package cli_project_management
import (
"fmt"
"log"
"os"
"path/filepath"
"github.com/scagogogo/composer-skills/pkg/composer"
)
func Example01CreateProject() {
comp, err := composer.New(composer.DefaultOptions())
if err != nil {
log.Fatalf("Failed to initialize Composer: %v", err)
}
tempDir, err := os.MkdirTemp("", "composer-project-example")
if err != nil {
log.Fatalf("Failed to create temp directory: %v", err)
}
defer os.RemoveAll(tempDir)
comp.SetWorkingDir(tempDir)
// Example 1: init command to initialize a new project (actual execution prompts for input; here only illustrative)
// _, err = comp.Run("init")
// Example 2: create-project to create a project from a template (requires network; here only illustrative)
// composer create-project laravel/laravel my-project
// Example 3: Manually create composer.json and validate it
composerJsonPath := filepath.Join(tempDir, "composer.json")
sampleContent := `{
"name": "example/project",
"description": "A sample project",
"type": "project",
"license": "MIT",
"require": { "php": ">=7.4" }
}`
if err := os.WriteFile(composerJsonPath, []byte(sampleContent), 0644); err != nil {
log.Fatalf("Failed to create sample composer.json: %v", err)
}
if err := comp.Validate(); err != nil {
fmt.Printf("Validation failed: %v\n", err)
} else {
fmt.Printf("Validation succeeded: file format is valid\n")
}
// Example 4: Strict validation
if err := comp.ValidateComposerJson(true, false); err != nil {
fmt.Printf("Strict validation failed: %v\n", err)
} else {
fmt.Printf("Strict validation succeeded: file format and content are valid\n")
}
}2️⃣ Run Scripts
func Example02RunScript() {
comp, _ := composer.New(composer.DefaultOptions())
tempDir, _ := os.MkdirTemp("", "composer-script-example")
defer os.RemoveAll(tempDir)
comp.SetWorkingDir(tempDir)
// Write a composer.json with scripts
composerJsonContent := `{
"name": "example/run-script",
"scripts": {
"hello": "echo 'Hello from Composer script!'",
"list-files": "ls -la",
"custom-php": "php -r 'echo PHP_VERSION . \"\\n\";'",
"combined": ["@hello", "@list-files"]
}
}`
composerJsonPath := filepath.Join(tempDir, "composer.json")
os.WriteFile(composerJsonPath, []byte(composerJsonContent), 0644)
// 1) List scripts
scriptList, err := comp.ListScripts()
if err != nil {
log.Printf("Failed to list scripts: %v", err)
} else {
fmt.Printf("Available scripts:\n%s\n", scriptList)
}
// 2) Run a simple script
output, err := comp.ExecuteScript("hello")
if err != nil {
log.Printf("Failed to run script: %v", err)
} else {
fmt.Printf("Script output:\n%s\n", output)
}
// 3) Run a combined script
output, err = comp.ExecuteScript("combined")
// ...
// 4) RunScript passes through extra args
output, err = comp.RunScript("hello", "--verbose")
}3️⃣ Platform Requirement Checks
func Example03PlatformCheck() {
comp, _ := composer.New(composer.DefaultOptions())
tempDir, _ := os.MkdirTemp("", "composer-platform-example")
defer os.RemoveAll(tempDir)
comp.SetWorkingDir(tempDir)
composerJsonContent := `{
"name": "example/platform-check",
"require": {
"php": ">=7.4",
"ext-json": "*",
"ext-mbstring": "*",
"ext-ctype": "*"
}
}`
os.WriteFile(filepath.Join(tempDir, "composer.json"),
[]byte(composerJsonContent), 0644)
// 1) Check platform requirements
output, err := comp.CheckPlatformReqs()
fmt.Printf("Platform requirement check result:\n%s\n", output)
// 2) Normal validation + strict validation
comp.Validate()
comp.ValidateComposerJson(true, false)
// 3) Other validation methods
comp.ValidateStrict()
comp.ValidateSchema()
// 4) Check whether a specific platform is available
available, err := comp.IsPlatformAvailable("php", "7.4")
fmt.Printf("PHP 7.4 available: %v\n", available)
available, err = comp.IsPlatformAvailable("ext-imagick", "")
fmt.Printf("ext-imagick available: %v\n", available)
}4️⃣ Dependency Analysis
func Example04DependencyAnalysis() {
comp, _ := composer.New(composer.DefaultOptions())
tempDir, _ := os.MkdirTemp("", "composer-dependency-example")
defer os.RemoveAll(tempDir)
comp.SetWorkingDir(tempDir)
composerJsonContent := `{
"name": "example/dependency-analysis",
"require": {
"php": ">=7.4",
"guzzlehttp/guzzle": "^7.0",
"monolog/monolog": "^2.0"
},
"require-dev": {
"phpunit/phpunit": "^9.0"
}
}`
os.WriteFile(filepath.Join(tempDir, "composer.json"),
[]byte(composerJsonContent), 0644)
// Note: the following methods require dependencies to be installed first; here only the API usage is demonstrated
comp.Check() // Validate dependency consistency
comp.ShowDependencyTree("") // Full dependency tree
comp.ShowDependencyTree("guzzlehttp/guzzle") // Specified package's dependency tree
comp.ShowReverseDependencies("monolog/monolog") // Reverse dependencies
comp.WhyPackage("monolog/monolog") // Why installed
comp.OutdatedPackages() // All outdated packages
comp.OutdatedPackagesDirect() // Only direct-dependency outdated packages
comp.Audit() // Security audit
comp.AuditWithJSON() // JSON-format audit
comp.GetHighSeverityVulnerabilities() // High-severity vulnerabilities
}5️⃣ Integrity Check and Diagnostics
func Example05IntegrityCheck() {
comp, _ := composer.New(composer.DefaultOptions())
tempDir, _ := os.MkdirTemp("", "composer-integrity-example")
defer os.RemoveAll(tempDir)
comp.SetWorkingDir(tempDir)
os.WriteFile(filepath.Join(tempDir, "composer.json"),
[]byte(`{
"name": "example/integrity-check",
"require": { "php": ">=7.4", "monolog/monolog": "^2.0" }
}`), 0644)
comp.Check() // Dependency consistency
comp.Validate() // Validate composer.json
comp.ValidateComposerJson(true, false) // Strict validation
comp.ValidateSchema() // Validate schema only
comp.Diagnose() // System diagnostics
comp.Status() // Installed-package modification status
comp.ClearCache() // Clear cache
homeDir, _ := comp.GetComposerHome()
fmt.Printf("Composer home: %s\n", homeDir)
composerJSON, _ := comp.ReadComposerJSON()
fmt.Printf("Project name: %s\n", composerJSON.Name)
comp.GetPHPVersion() // Current PHP version
}📖 Code Walkthrough
- 🧱 Create instance and isolate the working directory: each sub-example uses
composer.New(composer.DefaultOptions())to get a*Composer, then builds a temp directory withos.MkdirTemp, switches into it withSetWorkingDir, and cleans up withdefer os.RemoveAll. This way, even if the script actually runs Composer commands, it won't pollute the project. - 🆕 Create project:
01_create_project.goshows three paths —init(interactive generation ofcomposer.json),create-project(pull a new project from a remote template), and manually writingcomposer.json. The first two are commented out in the example because they require interaction/network; after manually writing the file,Validate()andValidateComposerJson(true, false)immediately do format and strict validation. - 🎬 Run scripts:
02_run_script.gofirst writes acomposer.jsonwith 4 scripts (including a combined script with@hello-style inter-script references), then usesListScripts()to list them,ExecuteScript(name)to run each one, and finallyRunScript(name, args...)to demonstrate passing through extra args. - 🖥️ Platform requirement checks:
03_platform_check.godeclaresphp>=7.4and three extensions inrequire, usesCheckPlatformReqs()to check them all at once, then usesIsPlatformAvailable("php","7.4")/IsPlatformAvailable("ext-imagick","")to probe whether a single platform item is satisfied. - 🔍 Dependency analysis:
04_dependency_analysis.gostrings together an analysis chain via comments —Checkvalidates lock consistency,ShowDependencyTreeshows the dependency tree (a single package can be specified),ShowReverseDependenciesshows who depends on a package,WhyPackageexplains why it's installed,OutdatedPackages/OutdatedPackagesDirectfind outdated packages, and theAuditfamily does security auditing. - 🩺 Integrity and diagnostics:
05_integrity_check.goruns through project health checks in one pass:Diagnosechecks the system environment,Statusshows whether packages have been locally modified,ClearCacheclears the cache,GetComposerHomegets the home directory,ReadComposerJSONparses the config into a struct, andGetPHPVersiongets the runtime version. - ⚠️ Note: some methods in dependency analysis and diagnostics require
installto have been run first to produce real output; the example deliberately prints only API-usage notes to avoid errors in a dependency-free environment.
▶️ How to Run
This example is a Go package cli_project_management containing 5 ExampleXX functions. You can run a single file directly from this directory:
cd /home/cc11001100/github/scagogogo/composer-skills/examples/cli_project_management
# Run each in turn (each file is an independent Example function)
go run 01_create_project.go
go run 02_run_script.go
go run 03_platform_check.go
go run 04_dependency_analysis.go
go run 05_integrity_check.go📌 Since these files belong to the same package and the function names don't clash, you can also use
go run .to compile the whole package at once, but you'll need to call eachExamplefunction yourself from amainpackage. Before running, make sure PHP and Composer are installed locally; otherwise the SDK triggers the auto-install flow.
🔗 SDK Methods Involved
🚀 Going Further
- 🔄 Real project creation: uncomment the
create-projectcall in01_create_project.go, pair it withcomposer.CreateProject("laravel/laravel", "my-project", ...)to actually pull a Laravel skeleton, then useValidateComposerJson(true, true)to validate dependencies at the same time. - 🎬 Script orchestration and hooks: add event-hook scripts like
pre-install-cmd/post-autoload-dumptocomposer.json, trigger them withExecuteScript, and pass environment variables through withRunScriptto build an automation pipeline. - 🖥️ CI gate: chain
CheckPlatformReqs+IsPlatformAvailableinto CI and assert the target machine's PHP version and extensions are complete before deployment; fail directly if anything is missing. - 🔍 Dependency dashboard: parse the output of
ShowDependencyTree/ShowReverseDependencies/WhyPackageinto a database, then layer onOutdatedPackagesandAuditto build a project dependency-health dashboard. - 🩺 Self-healing script: use
Diagnoseto detect common errors, and when a hit is found, automaticallyClearCacheand re-Checkfor lightweight self-healing. - 📦 Structured output: swap
AuditforAuditWithJSON, andCheckfor structured variants (likeValidateStructured,CheckPlatformReqsStructured) for programmatic parsing instead of text matching.