📈 Dependency Dashboard
In 10 minutes, aggregate four signal types — Outdated / Licenses / Abandoned / Funding — into a dependency health report. Requires local PHP + Composer.
Why a Dashboard?
Looking at individual composer command outputs, it's hard to answer "are my dependencies healthy overall". Merging them into a structured table lets you see at a glance: which are outdated, which are abandoned, license risks, and which packages deserve sponsorship.
Four Data Sources
| Signal | Method | Return |
|---|---|---|
| Outdated packages | comp.GetOutdatedInfo() | *OutdatedResult (Installed []OutdatedPackage) |
| Licenses | comp.GetLicensesInfo() | *LicensesResult (Licenses []LicenseInfo) |
| Abandoned | comp.GetAbandonedPackagesFromLock() | []string |
| Funding | comp.GetFundingURLs() | map[packageName][]string |
Complete Runnable Example
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️⃣ Outdated packages
if info, err := comp.GetOutdatedInfo(); err == nil {
dash.Outdated = info.Installed
fmt.Printf("⏳ Outdated packages: %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️⃣ Licenses
if lic, err := comp.GetLicensesInfo(); err == nil {
dash.Licenses = lic.Licenses
fmt.Printf("\n📜 License types: %d packages\n", len(dash.Licenses))
for _, l := range dash.Licenses {
fmt.Printf(" - %s: %v\n", l.Package, l.Licenses)
}
}
// 3️⃣ Abandoned packages
if ab, err := comp.GetAbandonedPackagesFromLock(); err == nil {
dash.Abandoned = ab
fmt.Printf("\n🚫 Abandoned: %d\n", len(dash.Abandoned))
for _, name := range dash.Abandoned {
fmt.Printf(" - %s\n", name)
}
}
// 4️⃣ Funding links
if fund, err := comp.GetFundingURLs(); err == nil {
dash.Funding = fund
fmt.Printf("\n💰 Packages with funding: %d\n", len(dash.Funding))
for pkg, urls := range dash.Funding {
fmt.Printf(" - %s: %v\n", pkg, urls)
}
}
// 5️⃣ Write to disk
b, _ := json.MarshalIndent(dash, "", " ")
os.WriteFile("dependency-dashboard.json", b, 0644)
fmt.Println("\n✅ Dashboard written to dependency-dashboard.json")
}Expected Output
⏳ Outdated packages: 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)
📜 License types: 12 packages
- monolog/monolog: [MIT]
- guzzlehttp/guzzle: [MIT]
🚫 Abandoned: 1
- old/deprecated-pkg
💰 Packages with funding: 4
- monolog/monolog: [https://github.com/Seldaek]
✅ Dashboard written to dependency-dashboard.jsonAdvanced: Convenience Methods Quick Reference
Common convenience methods used in dashboards:
fmt.Println("Installed packages:", len(comp.GetDirectDependencyNames()))
fmt.Println("Has lock file:", comp.HasComposerLock())
fmt.Println("Has vendor:", comp.HasVendorDir())
summary := comp.GetProjectSummary() // Get project metadata in one callRender as Web Page
dependency-dashboard.json is pure structured data, any frontend charting library (ECharts / Chart.js) can render it. Have CI generate this JSON on a schedule and publish to an internal site for a live dependency dashboard.
GetAbandonedPackagesFromLock Requires Lock
This method reads composer.lock; if the project just ran require without update, results may not be current. Run comp.Install(false, true) first before collecting stats.
Next Steps
- Add a security dimension to the dashboard: 🔒 Building a Security Audit Pipeline.
- Have CI auto-generate this dashboard: 🤖 Auto-Detect & Install in CI/CD.