Skip to content

📈 依赖仪表盘

10 分钟,把 Outdated / Licenses / Abandoned / Funding 四类信号聚合成一份依赖健康报告。需要本机有 PHP + Composer。

为什么需要仪表盘

单独看每个 composer 命令的输出,很难回答"我的依赖整体健康吗"。把它们合并成一张结构化表,就能一眼看到:哪些过期、哪些被废弃、许可证有没有风险、哪些包该赞助。

四类数据源

信号方法返回
过期包comp.GetOutdatedInfo()*OutdatedResultInstalled []OutdatedPackage
许可证comp.GetLicensesInfo()*LicensesResultLicenses []LicenseInfo
被废弃comp.GetAbandonedPackagesFromLock()[]string
资金comp.GetFundingURLs()map[包名][]string

完整可运行示例

go
package main

import (
	"encoding/json"
	"fmt"
	"log"
	"os"

	"github.com/scagogogo/composer-skills/pkg/composer"
)

type Dashboard struct {
	Outdated    []composer.OutdatedPackage       `json:"outdated"`
	Licenses    []composer.LicenseInfo           `json:"licenses"`
	Abandoned   []string                         `json:"abandoned"`
	Funding     map[string][]string              `json:"funding"`
}

func main() {
	comp, err := composer.New(composer.DefaultOptions())
	if err != nil {
		log.Fatal(err)
	}
	comp.SetWorkingDir(".")

	dash := Dashboard{}

	// 1️⃣ 过期包
	if info, err := comp.GetOutdatedInfo(); err == nil {
		dash.Outdated = info.Installed
		fmt.Printf("⏳ 过期包: %d\n", len(dash.Outdated))
		for _, p := range dash.Outdated {
			fmt.Printf("   - %s: %s%s (%s)\n", p.Name, p.Installed, p.Latest, p.LatestStatus)
		}
	}

	// 2️⃣ 许可证
	if lic, err := comp.GetLicensesInfo(); err == nil {
		dash.Licenses = lic.Licenses
		fmt.Printf("\n📜 许可证种类: %d 个包\n", len(dash.Licenses))
		for _, l := range dash.Licenses {
			fmt.Printf("   - %s: %v\n", l.Package, l.Licenses)
		}
	}

	// 3️⃣ 被废弃的包
	if ab, err := comp.GetAbandonedPackagesFromLock(); err == nil {
		dash.Abandoned = ab
		fmt.Printf("\n🚫 被废弃: %d\n", len(dash.Abandoned))
		for _, name := range dash.Abandoned {
			fmt.Printf("   - %s\n", name)
		}
	}

	// 4️⃣ 资金链接
	if fund, err := comp.GetFundingURLs(); err == nil {
		dash.Funding = fund
		fmt.Printf("\n💰 有资金入口的包: %d\n", len(dash.Funding))
		for pkg, urls := range dash.Funding {
			fmt.Printf("   - %s: %v\n", pkg, urls)
		}
	}

	// 5️⃣ 落盘
	b, _ := json.MarshalIndent(dash, "", "  ")
	os.WriteFile("dependency-dashboard.json", b, 0644)
	fmt.Println("\n✅ 仪表盘已写入 dependency-dashboard.json")
}

预期输出

⏳ 过期包: 3
   - monolog/monolog: 3.5.0 → 3.7.1 (semver-safe-update)
   - guzzlehttp/guzzle: 7.7.0 → 7.8.1 (semver-safe-update)
   - psr/log: 3.0.0 → 3.0.2 (semver-safe-update)

📜 许可证种类: 12 个包
   - monolog/monolog: [MIT]
   - guzzlehttp/guzzle: [MIT]

🚫 被废弃: 1
   - old/deprecated-pkg

💰 有资金入口的包: 4
   - monolog/monolog: [https://github.com/Seldaek]

✅ 仪表盘已写入 dependency-dashboard.json

进阶:便捷方法速查

仪表盘里常会用到的组合便捷方法:

go
fmt.Println("已安装包数:", len(comp.GetDirectDependencyNames()))
fmt.Println("有 lock 文件:", comp.HasComposerLock())
fmt.Println("有 vendor:", comp.HasVendorDir())
summary := comp.GetProjectSummary() // 一次性拿到项目元信息

渲染成网页

dependency-dashboard.json 是纯结构化数据,前端用任意图表库(ECharts / Chart.js)即可渲染。把这份 JSON 由 CI 定时生成并发布到内部站点,就是活的依赖看板。

GetAbandonedPackagesFromLock 依赖 lock

该方法读 composer.lock,若项目刚 require 还没 update,可能拿不到最新结果。先跑一次 comp.Install(false, true) 再统计。

下一步

基于 MIT 许可证发布