Skip to content

🗂️ 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.gorequire 中声明 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 方法

方法名所属包文档链接
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

🚀 进阶

  • 🔄 真实创建项目:把 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 的输出解析后入库,再叠加 OutdatedPackagesAudit,做成项目依赖健康看板。
  • 🩺 自愈脚本:用 Diagnose 检测常见错误,命中问题时自动 ClearCache 并重新 Check,实现轻量自愈。
  • 📦 结构化输出:把 Audit 换成 AuditWithJSONCheck 换成结构化变体(如 ValidateStructuredCheckPlatformReqsStructured),便于程序解析而非靠文本匹配。

基于 MIT 许可证发布