Skip to content

📈 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

SignalMethodReturn
Outdated packagescomp.GetOutdatedInfo()*OutdatedResult (Installed []OutdatedPackage)
Licensescomp.GetLicensesInfo()*LicensesResult (Licenses []LicenseInfo)
Abandonedcomp.GetAbandonedPackagesFromLock()[]string
Fundingcomp.GetFundingURLs()map[packageName][]string

Complete Runnable Example

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️⃣ 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.json

Advanced: Convenience Methods Quick Reference

Common convenience methods used in dashboards:

go
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 call

Render 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

Released under the MIT License