Skip to content

🗂️ 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.json is 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

go
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

go
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

go
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

go
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

go
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 with os.MkdirTemp, switches into it with SetWorkingDir, and cleans up with defer os.RemoveAll. This way, even if the script actually runs Composer commands, it won't pollute the project.
  • 🆕 Create project: 01_create_project.go shows three paths — init (interactive generation of composer.json), create-project (pull a new project from a remote template), and manually writing composer.json. The first two are commented out in the example because they require interaction/network; after manually writing the file, Validate() and ValidateComposerJson(true, false) immediately do format and strict validation.
  • 🎬 Run scripts: 02_run_script.go first writes a composer.json with 4 scripts (including a combined script with @hello-style inter-script references), then uses ListScripts() to list them, ExecuteScript(name) to run each one, and finally RunScript(name, args...) to demonstrate passing through extra args.
  • 🖥️ Platform requirement checks: 03_platform_check.go declares php>=7.4 and three extensions in require, uses CheckPlatformReqs() to check them all at once, then uses IsPlatformAvailable("php","7.4") / IsPlatformAvailable("ext-imagick","") to probe whether a single platform item is satisfied.
  • 🔍 Dependency analysis: 04_dependency_analysis.go strings together an analysis chain via comments — Check validates lock consistency, ShowDependencyTree shows the dependency tree (a single package can be specified), ShowReverseDependencies shows who depends on a package, WhyPackage explains why it's installed, OutdatedPackages / OutdatedPackagesDirect find outdated packages, and the Audit family does security auditing.
  • 🩺 Integrity and diagnostics: 05_integrity_check.go runs through project health checks in one pass: Diagnose checks the system environment, Status shows whether packages have been locally modified, ClearCache clears the cache, GetComposerHome gets the home directory, ReadComposerJSON parses the config into a struct, and GetPHPVersion gets the runtime version.
  • ⚠️ Note: some methods in dependency analysis and diagnostics require install to 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:

bash
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 each Example function yourself from a main package. Before running, make sure PHP and Composer are installed locally; otherwise the SDK triggers the auto-install flow.

🔗 SDK Methods Involved

Method NamePackageDoc Link
Newpkg/composer/sdk/composer/methods/new
DefaultOptionspkg/composer/sdk/composer/methods/default-options
SetWorkingDirpkg/composer/sdk/composer/methods/set-working-dir
Validatepkg/composer/sdk/composer/methods/validate
ValidateComposerJsonpkg/composer/sdk/composer/methods/validate-composer-json
ValidateStrictpkg/composer/sdk/composer/methods/validate-strict
ValidateSchemapkg/composer/sdk/composer/methods/validate-schema
ListScriptspkg/composer/sdk/composer/methods/list-scripts
ExecuteScriptpkg/composer/sdk/composer/methods/execute-script
RunScriptpkg/composer/sdk/composer/methods/run-script
CheckPlatformReqspkg/composer/sdk/composer/methods/check-platform-reqs
IsPlatformAvailablepkg/composer/sdk/composer/methods/is-platform-available
Checkpkg/composer/sdk/composer/methods/check
ShowDependencyTreepkg/composer/sdk/composer/methods/show-dependency-tree
ShowReverseDependenciespkg/composer/sdk/composer/methods/show-reverse-dependencies
WhyPackagepkg/composer/sdk/composer/methods/why-package
OutdatedPackagespkg/composer/sdk/composer/methods/outdated-packages
OutdatedPackagesDirectpkg/composer/sdk/composer/methods/outdated-packages-direct
Auditpkg/composer/sdk/composer/methods/audit
AuditWithJSONpkg/composer/sdk/composer/methods/audit-with-json
GetHighSeverityVulnerabilitiespkg/composer/sdk/composer/methods/get-high-severity-vulnerabilities
Diagnosepkg/composer/sdk/composer/methods/diagnose
Statuspkg/composer/sdk/composer/methods/status
ClearCachepkg/composer/sdk/composer/methods/clear-cache
GetComposerHomepkg/composer/sdk/composer/methods/get-composer-home
ReadComposerJSONpkg/composer/sdk/composer/methods/read-composer-json
GetPHPVersionpkg/composer/sdk/composer/methods/get-php-version
CreateProjectpkg/composer/sdk/composer/methods/create-project

🚀 Going Further

  • 🔄 Real project creation: uncomment the create-project call in 01_create_project.go, pair it with composer.CreateProject("laravel/laravel", "my-project", ...) to actually pull a Laravel skeleton, then use ValidateComposerJson(true, true) to validate dependencies at the same time.
  • 🎬 Script orchestration and hooks: add event-hook scripts like pre-install-cmd / post-autoload-dump to composer.json, trigger them with ExecuteScript, and pass environment variables through with RunScript to build an automation pipeline.
  • 🖥️ CI gate: chain CheckPlatformReqs + IsPlatformAvailable into 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 / WhyPackage into a database, then layer on OutdatedPackages and Audit to build a project dependency-health dashboard.
  • 🩺 Self-healing script: use Diagnose to detect common errors, and when a hit is found, automatically ClearCache and re-Check for lightweight self-healing.
  • 📦 Structured output: swap Audit for AuditWithJSON, and Check for structured variants (like ValidateStructured, CheckPlatformReqsStructured) for programmatic parsing instead of text matching.

Released under the MIT License