🗂️ cli_project_management — 项目管理
本示例演示如何通过 Composer Skills SDK 对本地 PHP 项目执行项目管理类操作:创建与校验项目、运行脚本、平台需求检查、依赖分析,以及完整性检查与系统诊断。
📌 示例定位
cli_project_management 是 Composer CLI 系列示例的第三站,聚焦于「项目级」管理任务。前一个示例 cli_package_management 关注包的增删改查,而本示例回答的是:
- 🆕 如何创建并校验一个新项目(
composer.json是否合法) - 🎬 如何列出与运行
composer.json中定义的脚本 - 🖥️ 如何检查当前运行环境是否满足 PHP 版本与扩展需求
- 🔍 如何分析依赖关系(依赖树、反向依赖、为什么安装、过时检查、安全审计)
- 🩺 如何对项目做完整性检查与系统诊断
这些能力对应 SDK 中 pkg/composer 包的项目管理、验证、平台检查、依赖分析与诊断方法族。所有示例都通过 composer.New(composer.DefaultOptions()) 创建实例,再用 SetWorkingDir 切换到临时目录,避免污染真实工程。
💻 完整代码
下面贴出本示例 5 个源文件的关键逻辑(注释适当精简,逻辑完整保留)。
1️⃣ 创建并校验项目
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("初始化 Composer 失败: %v", err)
}
tempDir, err := os.MkdirTemp("", "composer-project-example")
if err != nil {
log.Fatalf("创建临时目录失败: %v", err)
}
defer os.RemoveAll(tempDir)
comp.SetWorkingDir(tempDir)
// 示例 1: init 命令初始化新项目(实际执行会提示输入,此处仅示意)
// _, err = comp.Run("init")
// 示例 2: create-project 从模板创建项目(需网络,此处仅示意)
// composer create-project laravel/laravel my-project
// 示例 3: 手动创建 composer.json 并校验
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("创建示例 composer.json 失败: %v", err)
}
if err := comp.Validate(); err != nil {
fmt.Printf("校验失败: %v\n", err)
} else {
fmt.Printf("校验成功: 文件格式有效\n")
}
// 示例 4: 严格校验
if err := comp.ValidateComposerJson(true, false); err != nil {
fmt.Printf("严格校验失败: %v\n", err)
} else {
fmt.Printf("严格校验成功: 文件格式和内容都有效\n")
}
}2️⃣ 运行脚本
go
func Example02RunScript() {
comp, _ := composer.New(composer.DefaultOptions())
tempDir, _ := os.MkdirTemp("", "composer-script-example")
defer os.RemoveAll(tempDir)
comp.SetWorkingDir(tempDir)
// 写入含脚本的 composer.json
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) 列出脚本
scriptList, err := comp.ListScripts()
if err != nil {
log.Printf("列出脚本失败: %v", err)
} else {
fmt.Printf("可用脚本列表:\n%s\n", scriptList)
}
// 2) 运行简单脚本
output, err := comp.ExecuteScript("hello")
if err != nil {
log.Printf("运行脚本失败: %v", err)
} else {
fmt.Printf("脚本输出:\n%s\n", output)
}
// 3) 运行组合脚本
output, err = comp.ExecuteScript("combined")
// ...
// 4) RunScript 透传额外参数
output, err = comp.RunScript("hello", "--verbose")
}3️⃣ 平台需求检查
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) 检查平台需求
output, err := comp.CheckPlatformReqs()
fmt.Printf("平台需求检查结果:\n%s\n", output)
// 2) 普通校验 + 严格校验
comp.Validate()
comp.ValidateComposerJson(true, false)
// 3) 其他验证方法
comp.ValidateStrict()
comp.ValidateSchema()
// 4) 检查特定平台是否可用
available, err := comp.IsPlatformAvailable("php", "7.4")
fmt.Printf("PHP 7.4 是否可用: %v\n", available)
available, err = comp.IsPlatformAvailable("ext-imagick", "")
fmt.Printf("ext-imagick 是否可用: %v\n", available)
}4️⃣ 依赖分析
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)
// 注意:以下方法需先 install 依赖,此处仅演示 API 用途
comp.Check() // 校验依赖一致性
comp.ShowDependencyTree("") // 完整依赖树
comp.ShowDependencyTree("guzzlehttp/guzzle") // 指定包依赖树
comp.ShowReverseDependencies("monolog/monolog") // 反向依赖
comp.WhyPackage("monolog/monolog") // 为何安装
comp.OutdatedPackages() // 全部过时包
comp.OutdatedPackagesDirect() // 仅直接依赖的过时包
comp.Audit() // 安全审计
comp.AuditWithJSON() // JSON 格式审计
comp.GetHighSeverityVulnerabilities() // 高危漏洞
}5️⃣ 完整性检查与诊断
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() // 依赖一致性
comp.Validate() // 校验 composer.json
comp.ValidateComposerJson(true, false) // 严格校验
comp.ValidateSchema() // 仅校验 Schema
comp.Diagnose() // 系统诊断
comp.Status() // 已安装包修改状态
comp.ClearCache() // 清除缓存
homeDir, _ := comp.GetComposerHome()
fmt.Printf("Composer 主目录: %s\n", homeDir)
composerJSON, _ := comp.ReadComposerJSON()
fmt.Printf("项目名称: %s\n", composerJSON.Name)
comp.GetPHPVersion() // 当前 PHP 版本
}📖 代码讲解
- 🧱 创建实例与隔离工作目录:每个子示例都用
composer.New(composer.DefaultOptions())拿到一个*Composer,再通过os.MkdirTemp建临时目录、SetWorkingDir切进去,并用defer os.RemoveAll清理。这样即便脚本真的执行 Composer 命令也不会污染工程。 - 🆕 创建项目:
01_create_project.go展示了三条路径——init(交互式生成composer.json)、create-project(从远程模板拉取新工程)、手动写composer.json。前两者因需交互/网络在示例中被注释,手动写文件后立即用Validate()与ValidateComposerJson(true, false)做格式与严格校验。 - 🎬 运行脚本:
02_run_script.go先写入一个含 4 个脚本的composer.json(含@hello这种脚本间引用的组合脚本),再用ListScripts()列出、ExecuteScript(name)逐个执行,最后用RunScript(name, args...)演示如何透传额外参数。 - 🖥️ 平台需求检查:
03_platform_check.go在require中声明php>=7.4和三个扩展,用CheckPlatformReqs()一次性检查全部,再用IsPlatformAvailable("php","7.4")/IsPlatformAvailable("ext-imagick","")单点探测某个平台项是否满足。 - 🔍 依赖分析:
04_dependency_analysis.go用注释串起一套分析链——Check验证 lock 一致性,ShowDependencyTree看依赖树(可指定单包),ShowReverseDependencies看谁依赖了某包,WhyPackage解释安装原因,OutdatedPackages/OutdatedPackagesDirect找过时包,Audit系列做安全审计。 - 🩺 完整性与诊断:
05_integrity_check.go把项目健康检查一次走完:Diagnose查系统环境、Status看包是否被本地修改、ClearCache清缓存、GetComposerHome取主目录、ReadComposerJSON把配置解析为结构体、GetPHPVersion取运行时版本。 - ⚠️ 注意:依赖分析与诊断中的部分方法需要先执行过
install才有真实输出;示例刻意只打印 API 用途说明,避免在无依赖环境下报错。
▶️ 运行方式
本示例为 Go package cli_project_management,包含 5 个 ExampleXX 函数。可在该目录下直接运行单个文件:
bash
cd /home/cc11001100/github/scagogogo/composer-skills/examples/cli_project_management
# 依次运行(每个文件都是独立的 Example 函数)
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📌 由于这些文件同属一个 package 且函数名不冲突,也可以用
go run .一次性编译整个包,但需要自行在main包中调用各Example函数。运行前请确保本地已安装 PHP 与 Composer,否则 SDK 会触发自动安装流程。
🔗 涉及的 SDK 方法
🚀 进阶
- 🔄 真实创建项目:把
01_create_project.go中注释掉的create-project调用打开,配合composer.CreateProject("laravel/laravel", "my-project", ...)真正拉取一个 Laravel 骨架,再用ValidateComposerJson(true, true)同时校验依赖。 - 🎬 脚本编排与钩子:在
composer.json中加入pre-install-cmd/post-autoload-dump等事件钩子脚本,用ExecuteScript触发,结合RunScript透传环境变量,构建自动化流水线。 - 🖥️ CI 门禁:将
CheckPlatformReqs+IsPlatformAvailable串入 CI,在部署前断言目标机器的 PHP 版本与扩展齐全,缺失时直接 fail。 - 🔍 依赖看板:把
ShowDependencyTree/ShowReverseDependencies/WhyPackage的输出解析后入库,再叠加OutdatedPackages与Audit,做成项目依赖健康看板。 - 🩺 自愈脚本:用
Diagnose检测常见错误,命中问题时自动ClearCache并重新Check,实现轻量自愈。 - 📦 结构化输出:把
Audit换成AuditWithJSON,Check换成结构化变体(如ValidateStructured、CheckPlatformReqsStructured),便于程序解析而非靠文本匹配。