Skip to content

⚙️ cli_configuration — Configuration Management

This example demonstrates how to programmatically operate on composer.json, composer config, auth tokens, and repository sources with the SDK — four configuration scenarios in one place.

🎯 Example Positioning

examples/cli_configuration splits "configuration-type" operations into four functions, corresponding to Composer's four configuration systems: 📄 composer.json file operations (dependencies/scripts/autoload/config/top-level properties, without invoking the binary), ⚙️ the composer config command (read/write project-level and global-level config, query the home directory, clear the cache), 🔑 auth management (GitHub/GitLab/Bearer/HTTP Basic credentials), 🗂️ repository management (VCS/Composer/Path/Artifact sources, enable/disable Packagist, stability policy). Mastering this covers all configuration APIs for scaffolding, CI, and private-mirror scenarios.

📜 Full Code

go
package cli_configuration

import (
	"fmt"
	"log"

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

// Example01ComposerJson operates on composer.json (pure file, does not invoke composer)
func Example01ComposerJson() {
	c, err := composer.New(composer.DefaultOptions())
	if err != nil {
		log.Fatalf("Failed to create Composer instance: %v", err)
	}
	c.SetWorkingDir("/path/to/project")

	// 1. Read composer.json
	if cj, err := c.ReadComposerJSON(); err != nil {
		log.Printf("Read failed: %v", err)
	} else {
		fmt.Printf("Project: %s / %s / %s\n", cj.Name, cj.Description, cj.Type)
	}

	// 2. Set top-level properties (only name/description/type/keywords, etc. are supported)
	c.SetProperty("name", "myvendor/mypackage")
	c.SetProperty("description", "An awesome PHP library")
	c.SetProperty("keywords", []string{"php", "library"})

	// 3. Add/remove dependencies (only modifies the file, does not run install)
	c.AddRequire("symfony/console", "^6.0", false) // require
	c.AddRequire("phpunit/phpunit", "^10.0", true) // require-dev
	c.RemoveRequire("old/package", false)

	// 4. Add/remove scripts
	c.AddScript("test", "phpunit", "Run tests")
	c.AddScript("post-install-cmd", []string{"php artisan optimize:clear"}, "Clear cache after install")
	c.RemoveScript("old-script")

	// 5. Autoload (psr-4 / psr-0 / classmap / files)
	c.AddAutoload("psr-4", "App\\", "src/", false)
	c.AddAutoload("psr-4", "Tests\\", "tests/", true)

	// 6. Read/write the config field of composer.json
	c.SetConfig("process-timeout", 500)
	timeout, _ := c.GetConfig("process-timeout")
	fmt.Printf("Process timeout: %v\n", timeout)
}

// Example02Config goes through the composer config command (project-level/global-level)
func Example02Config() {
	c, _ := composer.New(composer.DefaultOptions())
	c.SetWorkingDir("/path/to/project")

	v, _ := c.GetConfigWithGlobal("vendor-dir", false) // false = project-level
	fmt.Printf("vendor-dir: %s\n", v)
	c.SetConfigWithGlobal("vendor-dir", "vendor", false)

	g, _ := c.GetConfigWithGlobal("bin-dir", true) // true = global
	fmt.Printf("Global bin-dir: %s\n", g)

	home, _ := c.GetComposerHome()
	fmt.Printf("Composer home: %s\n", home)
	c.ClearCache()
}

// Example03Auth manages auth configuration (auth.json)
func Example03Auth() {
	c, _ := composer.New(composer.DefaultOptions())

	auth, _ := c.GetAuthConfig()
	fmt.Printf("GitHub token count: %d, GitLab token count: %d\n", len(auth.GitHub), len(auth.GitLab))

	c.AddGitHubToken("github.com", "your-github-token")
	c.AddGitLabToken("gitlab.com", "your-gitlab-token")
	c.AddBearerToken("example.com", "your-bearer-token")
	c.AddHTTPBasicAuth("example.com", "username", "password")

	// authType ∈ github-oauth / gitlab-oauth / bearer / http-basic
	token, _ := c.GetToken("github-oauth", "github.com")
	fmt.Printf("GitHub token: %s\n", token)
	c.RemoveToken("github-oauth", "github.com")
}

// Example04Repository manages repository sources
func Example04Repository() {
	c, _ := composer.New(composer.DefaultOptions())
	c.SetWorkingDir("/path/to/project")

	output, _ := c.ListRepositories()
	fmt.Println(output)

	c.AddVcsRepository("my-vcs", "https://github.com/myorg/myrepo")
	c.AddComposerRepository("private-repo", "https://packages.example.com")
	c.AddPathRepository("local-lib", "../my-lib", nil)
	c.AddArtifactRepository("my-artifacts", "/path/to/artifacts")
	c.RemoveRepository("my-vcs")

	c.DisablePackagistRepository()
	c.EnablePackagistRepository()

	c.SetMinimumStability("stable")
	c.SetPreferStable(true)
}

🔍 Code Walkthrough

  • 🚀 Create the instance: composer.New(composer.DefaultOptions()) gets a *Composer, and SetWorkingDir specifies the PHP project directory to operate on. If there's no composer locally, AutoInstall=true pulls it automatically.
  • 📄 Read → modify → write pattern: ReadComposerJSON returns a structured *ComposerJSON; subsequent SetProperty / AddRequire / AddScript / AddAutoload / SetConfig all modify the file in memory and atomically write it back, without ever invoking the composer binary.
  • ⚙️ Distinguish the two config routes: SetConfig / GetConfig (composer_json.go) only modifies the config field of the JSON file, and the value can be any type; GetConfigWithGlobal / SetConfigWithGlobal (config.go) go through the composer config command, the value must be a string, and the third param global bool controls global vs. project-level.
  • 🔑 Auth bucketed by type: the four Add* methods write into different fields of auth.json; the authType of GetToken / RemoveToken must be one of github-oauth / gitlab-oauth / bearer / http-basic.
  • 🗂️ Repository four-pack: VCS (Git repo), Composer (private mirror), Path (local path, options can be passed as the third param), and Artifact (artifact directory) cover virtually all private-source scenarios; DisablePackagistRepository is suitable for pure-intranet environments.
  • 🧯 Error handling: the example uses log.Printf to record failures but keeps going, convenient for running all steps in one pass; in production, return on error.

▶️ How to Run

bash
git clone https://github.com/scagogogo/composer-skills.git
cd composer-skills/examples/cli_configuration

# Requires PHP 7.4+ and Composer 2.0+ locally; otherwise the SDK auto-installs
go run 01_composer_json_config_auth_repo.go

Will actually modify files

The /path/to/project in the example is a placeholder path; change it to a real PHP project directory on your machine before running. The auth and repository writes will actually modify that project's composer.json and auth.json, so run it in a test project.

📚 SDK Methods Involved

MethodDoc Link
New / DefaultOptions / SetWorkingDirnew · set-working-dir
ReadComposerJSON / SetProperty / AddRequire / RemoveRequire / AddScript / RemoveScript / AddAutoloadread-composer-json · set-property · add-require · remove-require · add-script · remove-script · add-autoload
SetConfig / GetConfigcomposer.json operations
GetConfigWithGlobal / SetConfigWithGlobal / GetComposerHome / ClearCacheget-config-with-global · set-config-with-global · get-composer-home · clear-cache
GetAuthConfig / AddGitHubToken / AddGitLabToken / AddBearerToken / AddHTTPBasicAuth / GetToken / RemoveTokenget-auth-config · add-github-token · add-gitlab-token · add-bearer-token · add-http-basic-auth · auth management
ListRepositories / AddVcsRepository / AddComposerRepository / AddPathRepository / AddArtifactRepository / RemoveRepository / DisablePackagistRepository / EnablePackagistRepositorylist-repositories · add-vcs-repository · add-composer-repository · add-path-repository · remove-repository · repository management
SetMinimumStability / SetPreferStableset-minimum-stability · set-prefer-stable

All methods belong to pkg/composer.

🚀 Going Further

  • 🏗️ Scaffolding combo: chain WriteComposerJSON (write an empty template) + SetProperty + AddRequire + AddAutoload to programmatically generate a brand-new project's composer.json — no composer init interaction needed.
  • 🔐 CI secure injection: in the pipeline, use AddBearerToken / AddHTTPBasicAuth to temporarily inject private-source credentials, then clean up with RemoveToken afterward to avoid persisting credentials.
  • 🪞 Mirror acceleration: AddComposerRepository to add a domestic mirror, then DisablePackagistRepository to turn off the official source — all dependency pulls go through the mirror.
  • 🧪 Mock testing: SetMockComposerJSON makes ReadComposerJSON return injected data, so unit tests don't need a real project directory (note that the convenience variant ReadComposerJson is not affected by this mock).
  • 🔄 File vs. command: use the composer_json.go family for file-only changes (fast, binary-free, free value types); use the config.go family through commands when you need composer to actually take effect (recompute lock, refresh metadata).

Released under the MIT License