🔄 CI/CD pipeline
Composer Skills is designed for CI/CD: typed return values make "failure decisions" a one-line if, and auto-install means you don't need to pre-install Composer on the runner. This page provides a complete example of using it in GitHub Actions.
🎯 Typical pipeline
A PHP project's CI pipeline usually has four steps:
- 📥 Auto-install — SDK auto-provisions Composer when missing.
- 📦 install — Install project dependencies.
- 🔒 audit — Security audit; fail if vulnerabilities found.
- ✅ validate — Validate
composer.jsonschema.
Below we write these four steps as Go code and pair it with a GitHub Actions workflow.
📝 Go code: pipeline main program
Save the following as ci/main.go. It will auto-install Composer, install dependencies, audit vulnerabilities, validate schema — and exit non-zero on any failure (CI red light).
package main
import (
"fmt"
"log"
"os"
"github.com/scagogogo/composer-skills/pkg/composer"
)
func main() {
workingDir := os.Getenv("GITHUB_WORKSPACE")
if workingDir == "" {
workingDir = "."
}
// 1. Auto-install + create instance
// QuickSetup auto-pulls Composer if missing
comp, err := composer.QuickSetup(workingDir, true)
if err != nil {
log.Fatalf("❌ Composer init failed: %v", err)
}
// 2. Install dependencies (--no-dev can be adjusted as needed)
fmt.Println("📦 Installing dependencies...")
if err := comp.Install(false, true); err != nil {
log.Fatalf("❌ install failed: %v", err)
}
// 3. Security audit
fmt.Println("🔒 Security audit...")
result, err := comp.AuditWithJSON()
if err != nil {
log.Fatalf("❌ audit failed: %v", err)
}
fmt.Printf(" Vulnerabilities found: %d\n", result.Found)
for _, v := range result.Advisories {
fmt.Printf(" ⚠ %s: %s (%s)\n", v.Package, v.Title, v.Severity)
}
if result.Found > 0 {
log.Fatalf("❌ %d vulnerabilities present, pipeline failed", result.Found)
}
// 4. Validate composer.json
fmt.Println("✅ Validating composer.json...")
res, err := comp.ValidateStructured()
if err != nil {
log.Fatalf("❌ validate failed: %v", err)
}
if !res.Valid {
for _, e := range res.Errors {
fmt.Printf(" ❌ Line %d: %s\n", e.Line, e.Message)
}
log.Fatal("❌ composer.json validation failed")
}
fmt.Println("🎉 Pipeline passed completely")
}Fail = red light
In CI, a process exiting with a non-zero code marks the job red. We use log.Fatalf to exit immediately on any failure, no extra conditionals needed.
⚙️ GitHub Actions workflow
.github/workflows/composer-ci.yml:
name: Composer CI
on:
push:
branches: [main]
pull_request:
jobs:
composer-skills:
runs-on: ubuntu-latest
steps:
- name: 📥 Checkout code
uses: actions/checkout@v4
- name: 🐹 Install Go
uses: actions/setup-go@v5
with:
go-version: '1.23'
- name: 🐘 Install PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
# Composer Skills can auto-install Composer too; pre-installing saves time
coverage: none
- name: 📦 Download Go dependencies
run: |
go mod download
go mod tidy
- name: 🚀 Run Composer Skills pipeline
run: go run ./ci/main.go
- name: 📤 Upload audit report (optional)
if: always()
run: |
# You could call comp.AuditWithJSON and write results to a file, then upload-artifact
echo "Audit completed"Why still use setup-php?
Composer Skills can auto-install Composer, but PHP itself needs to be pre-installed or pulled by the SDK's installer.InstallPHP (via apt on Linux). In CI, setup-php is faster and more reliable; SDK auto-install serves as a fallback.
🔒 Pure remote audit (PHP-less runner)
If you just want to pull Packagist security advisories for vulnerability scanning, you don't need PHP at all — use the Packagist API SDK; the runner is smaller:
package main
import (
"fmt"
"os"
"github.com/scagogogo/composer-skills/pkg/client"
)
func main() {
c := client.NewComposerClient(30 * 0) // Set a reasonable timeout
advisories, err := c.GetSecurityAdvisoriesForPackages(
"monolog/monolog", "symfony/console",
)
if err != nil {
fmt.Printf("❌ %v\n", err)
os.Exit(1)
}
if len(advisories.Advisories) > 0 {
fmt.Printf("❌ Found %d advisories\n", len(advisories.Advisories))
os.Exit(1)
}
fmt.Println("✅ No security advisories")
}The corresponding workflow can drop setup-php and keep only Go.
💡 Advanced suggestions
- 🧪 Cache dependencies: Add
actions/cachein the workflow to cache~/.composer/cacheand speed upinstall. - 🔑 Private repo auth: Store GitHub Token as a repo Secret, inject it via workflow
env, then in Go code usecomp.AddGitHubToken("github.com", os.Getenv("GITHUB_TOKEN"))to access private packages. - 📈 Outdated package monitoring: Run
comp.GetOutdatedInfo()in a scheduled job (on: schedule) and open an issue if outdated. - 🧾 License check:
comp.GetLicensesInfo()outputs dependency licenses to avoid non-compliant licenses.
Timeout
Commands in CI can hang due to slow networks. Use Options with a timeout:
options := composer.DefaultOptions()
options.DefaultTimeout = 30 * 60 * 1e9 // 30 minutes (nanoseconds)
comp, _ = composer.New(options)🧭 Next steps
- 🐳 Docker deployment — containerize the pipeline.
- 🔒 Security audit SDK —
AuditWithJSONfield reference. - ✅ Validation SDK —
ValidateStructuredusage. - 🌐 Packagist security advisories — remote audit API.