masgeek / composer-scripts
Reusable Composer script callbacks for PHP projects — testing, linting, IDE helpers, and dev server. Framework-agnostic.
Package info
github.com/masgeek/composer-scripts
Type:composer-plugin
pkg:composer/masgeek/composer-scripts
Requires
- php: ^8.2
- composer-plugin-api: ^2.0
- composer/composer: ^2.0
Requires (Dev)
- phpunit/phpunit: 13.2.4
This package is auto-updated.
Last update: 2026-07-22 11:52:27 UTC
README
Reusable Composer script callbacks for PHP projects — testing, linting, IDE helpers, model generation, dev server, and queue management. Works with Laravel, Symfony, or plain PHP. No framework dependency.
Table of Contents
- Installation
- How it works
- All available scripts
- Passing arguments
- Overriding a script
- Manual wiring
- Scripts reference
- Non-Laravel projects
- Extending the package
- Requirements
Installation
composer require --dev masgeek/composer-scripts
Allow the plugin once in your composer.json:
{
"config": {
"allow-plugins": {
"masgeek/composer-scripts": true
}
}
}
Run composer install — every script listed below is immediately available with no further configuration.
How it works
This package is a Composer plugin. Plugin::activate() is called before any script runs and injects all default callbacks into the root package at runtime. Nothing is written to disk.
Your definitions always win. If a script name already exists in your composer.json, the plugin skips it entirely. You can override any default or add project-specific steps without touching the package.
All available scripts
Quick-reference of every script injected by the plugin.
| Script | Class::method | Notes |
|---|---|---|
test |
Testing::run |
config:clear + pest --bail |
test:unit |
Testing::unit |
pest tests/Unit |
test:feature |
Testing::feature |
pest tests/Feature |
test:controllers |
Testing::controllers |
pest tests/Feature/Http/Controllers |
test:services |
Testing::services |
pest tests/Unit/Services |
test:retry |
Testing::retry |
pest --retry --bail |
test:dirty |
Testing::dirty |
pest --dirty |
test:ci |
Testing::ci |
pest (no bail, all failures reported) |
test:file |
Testing::file |
bare pest, no flags — IDE runner friendly |
test:parallel |
Testing::parallel |
artisan test --parallel ¹ |
pest:test |
Testing::file |
alias for test:file |
pest:coverage |
Testing::coverage |
pest --coverage |
pest:coverage:xml |
Testing::coverageXml |
Clover XML → storage/coverage/coverage.xml |
pest:coverage-xml |
Testing::coverageXml |
alias (dash form) |
pint:fix |
CodeQuality::pintFix |
pint --dirty |
pint:fix:all |
CodeQuality::pintFixAll |
pint (all files) |
pint:check |
CodeQuality::pintCheck |
pint --test |
pint:repair |
CodeQuality::pintRepair |
pint --repair |
lint:fix |
CodeQuality::pintFix |
alias for pint:fix |
lint:fix-all |
CodeQuality::pintFixAll |
alias for pint:fix:all (dash form) |
lint:analyse |
CodeQuality::analyse |
phpstan analyse --memory-limit=256M |
lint:check |
CodeQuality::check |
alias for lint:analyse |
lint:all |
CodeQuality::all |
pint:check then lint:analyse |
sonar |
CodeQuality::sonar |
sonar-scanner |
meta:helper |
IdeHelper::generate |
artisan ide-helper:generate ¹ |
meta:ide |
IdeHelper::meta |
artisan ide-helper:meta ¹ |
meta:models |
IdeHelper::models |
artisan ide-helper:models --write ¹ |
meta:all |
IdeHelper::all |
all three ide-helper commands ¹ |
model:gen |
IdeHelper::modelGen |
code:models → ide-helper:models → pint --dirty ¹ |
dev |
DevServer::serve |
artisan serve or php -S (DEV_PORT env var) |
dev:all |
DevServer::serveAll |
server + queue + Vite via npx concurrently |
queue:listen |
DevServer::queueListen |
artisan queue:listen --timeout=0 ¹ |
check-deps |
Deps::checkUnused |
composer-unused |
scripts |
(alias) | composer run-script --list |
¹ Gracefully skips with a warning when
artisanis not found — safe on non-Laravel projects.
Discovering available scripts
After installing the package, run either of these to see every script available in your project — both those you defined and those injected by the plugin:
composer run-script --list
# or the short alias injected by this package
composer scripts
Scripts defined in your own composer.json show a description; plugin-injected ones appear without one:
Available scripts:
setup Runs the setup script as defined in composer.json
dev Runs the dev script as defined in composer.json
queue:all Runs the queue:all script as defined in composer.json
test ← injected by plugin
test:unit ← injected by plugin
test:feature ← injected by plugin
pint:fix ← injected by plugin
lint:analyse ← injected by plugin
model:gen ← injected by plugin
...
To add descriptions to plugin scripts (useful for team documentation), define the script
name in your composer.json with a scripts-descriptions entry:
{
"scripts-descriptions": {
"test": "Run the full test suite",
"pint:fix": "Fix formatting on changed files",
"lint:analyse": "Run PHPStan static analysis",
"model:gen": "Regenerate Eloquent models and IDE annotations",
"queue:listen": "Start a queue worker — pass --queue=name1,name2 after --"
}
}
Passing arguments
Every command forwards extra arguments passed after -- to the underlying tool.
# Run a single test file composer test -- tests/Feature/SmsControllerTest.php # Filter by test name composer test -- --filter=it_sends_an_sms # Run feature tests and stop on first failure composer test:feature -- --stop-on-failure # Re-run failures with verbose output composer test:retry -- --verbose # CI run producing a JUnit report composer test:ci -- --log-junit=build/test-results/junit.xml # Parallel tests with a fresh database composer test:parallel -- --recreate-databases # Coverage with a minimum threshold enforced composer pest:coverage -- --min=80 # Fix only a specific directory composer pint:fix -- app/Http/Controllers # Fix a single file composer lint:fix-all -- app/Services/AuthService.php # Check formatting for a single path composer pint:check -- app/Models # PHPStan at a stricter level composer lint:analyse -- --level=8 # PHPStan on a specific path composer lint:analyse -- app/Services # PHPStan with a custom config composer lint:analyse -- -c phpstan-strict.neon # Listen on specific queues composer queue:listen -- --queue=high,default,low # Queue worker with extra tuning composer queue:listen -- --queue=sms,email --sleep=3 --tries=3 # Annotate models in dry-run mode composer meta:models -- --no-write # Reset existing model docblocks composer meta:models -- --reset # SonarQube on a specific branch composer sonar -- -Dsonar.branch.name=develop
Overriding a script
Define the script name in your composer.json and the plugin leaves it alone. Use this to:
Add steps before or after the default:
{
"scripts": {
"test": [
"@php artisan db:seed --class=TestSeeder",
"Masgeek\\ComposerScripts\\Testing::run"
]
}
}
Change the port for the dev server:
{
"scripts": {
"dev": [
"Composer\\Config::disableProcessTimeout",
"@php artisan serve --port=8700"
]
}
}
Hardcode a project-specific queue list so you never have to type it:
{
"scripts": {
"queue:all": [
"Composer\\Config::disableProcessTimeout",
"@php artisan queue:listen --timeout=0 --queue=broadcast,sms,campaign,archive,zoho"
]
}
}
The
queue:listenscript injected by the plugin is the ad-hoc tool (pass queues via--). A named override likequeue:allabove is the convenience alias for your fixed production stack.
Replace entirely with a plain shell command:
{
"scripts": {
"sonar": "sonar-scanner -Dsonar.projectKey=my-project"
}
}
Manual wiring (opt-out of auto-discovery)
If you prefer explicit control, copy the entries you need from scripts.json into your composer.json. The class callbacks work identically whether discovered by the plugin or wired manually.
{
"scripts": {
"test": "Masgeek\\ComposerScripts\\Testing::run",
"pint:fix": "Masgeek\\ComposerScripts\\CodeQuality::pintFix",
"lint:analyse": "Masgeek\\ComposerScripts\\CodeQuality::analyse",
"model:gen": "Masgeek\\ComposerScripts\\IdeHelper::modelGen",
"dev": "Masgeek\\ComposerScripts\\DevServer::serve",
"queue:listen": "Masgeek\\ComposerScripts\\DevServer::queueListen"
}
}
Scripts reference
Testing (Masgeek\ComposerScripts\Testing)
Requires pestphp/pest.
test clears the Laravel config cache before running (no-op on non-Laravel projects).
test:parallel uses artisan test --parallel and gracefully skips if artisan is absent.
# Full suite — bails on first failure composer test # Filter to a single test composer test -- --filter=SmsServiceTest # Run a specific file (bare pest, no default flags) composer test:file -- tests/Feature/Http/Controllers/SmsControllerTest.php # Unit suite only composer test:unit # Feature suite, stop on first failure composer test:feature -- --stop-on-failure # Re-run only what failed last time composer test:retry # Tests for git-changed files only composer test:dirty # Full CI run — no bail, all failures reported composer test:ci # CI run with JUnit XML output composer test:ci -- --log-junit=build/test-results/junit.xml # Laravel parallel runner composer test:parallel # Parallel with fresh databases composer test:parallel -- --recreate-databases # HTML coverage report composer pest:coverage # Coverage with enforced minimum composer pest:coverage -- --min=80 # Clover XML for SonarQube composer pest:coverage:xml
Code Quality (Masgeek\ComposerScripts\CodeQuality)
Requires laravel/pint for formatting and
phpstan/phpstan for static analysis. Each tool is only
required when its specific command runs.
# Fix git-changed files only (fast, safe for pre-commit) composer pint:fix # Fix a specific directory composer pint:fix -- app/Http # Fix everything composer pint:fix:all # or composer lint:fix-all # Check formatting without changing anything (CI-friendly) composer pint:check # Check only a path composer pint:check -- app/Models # Repair files that couldn't be auto-fixed composer pint:repair # PHPStan at default level (256 MB memory limit) composer lint:analyse # Stricter level composer lint:analyse -- --level=8 # Analyse a single directory composer lint:analyse -- app/Services # Custom PHPStan config composer lint:analyse -- -c phpstan-strict.neon # Pint check + PHPStan in one shot (full CI quality gate) composer lint:all # SonarQube scan composer sonar # SonarQube on a feature branch composer sonar -- -Dsonar.branch.name=feat/my-feature
IDE Helper (Masgeek\ComposerScripts\IdeHelper)
Requires barryvdh/laravel-ide-helper.
All commands gracefully skip with a warning when artisan is not found.
# Generate _ide_helper.php (facades + container bindings) composer meta:helper # Generate .phpstorm.meta.php composer meta:ide # Annotate Eloquent models with @property docblocks composer meta:models # Annotate without writing (dry-run / preview) composer meta:models -- --no-write # Reset and rewrite all existing docblocks composer meta:models -- --reset # All three ide-helper commands in one go composer meta:all # Full model regeneration workflow (code:models → ide-helper → pint) composer model:gen
model:gen — three-step workflow
Replaces the common inline chain:
php artisan code:models # 1. regenerate Base model classes php artisan ide-helper:models --write # 2. add @property docblocks vendor/bin/pint --dirty # 3. format generated files
Step 1 requires a package that registers code:models
(e.g. masgeek/reliese-laravel-model-gen).
Steps 2 and 3 gracefully skip if the binaries are absent.
Dev Server & Queue (Masgeek\ComposerScripts\DevServer)
All three commands automatically disable the Composer process timeout so long-running processes are never killed after the default 300-second limit.
# Start artisan serve on port 8000 (or php -S for non-Laravel) composer dev # Start on a custom port DEV_PORT=8700 composer dev # Linux / macOS $env:DEV_PORT=8700; composer dev # Windows PowerShell # Start server + queue worker + Vite all at once (requires npx concurrently) composer dev:all # Listen on the default queue composer queue:listen # Listen on specific queues (priority order, left = highest) composer queue:listen -- --queue=high,default,low # Listen with extra tuning flags composer queue:listen -- --queue=sms,email --sleep=3 --tries=3
Port configuration
DEV_PORT controls the port for both dev and dev:all. Set it in .env for a permanent project default:
DEV_PORT=8700
Project-specific queue shortcut
queue:listen is the generic tool — pass any queues at runtime. For a fixed production
stack, define a named override in your composer.json so you never have to type the list:
{
"scripts": {
"queue:all": [
"Composer\\Config::disableProcessTimeout",
"@php artisan queue:listen --timeout=0 --queue=broadcast,sms,campaign,archive,zoho"
]
}
}
Then just run composer queue:all.
Dependency Analysis (Masgeek\ComposerScripts\Deps)
Requires icanhazstring/composer-unused.
# List packages that are required but not referenced in code
composer check-deps
Non-Laravel projects
Commands that call artisan go through Support\Artisan, which resolves the binary:
vendor/bin/artisan— symlink placed bylaravel/frameworkphp artisan— script in the project root
If neither exists the command prints a warning and exits cleanly (code 0), so the Composer script chain is never broken:
$ composer model:gen
[warning] Skipping 'code:models' — artisan not found (not a Laravel project?).
[warning] Skipping 'ide-helper:models --write' — artisan not found (not a Laravel project?).
> vendor/bin/pint --dirty
Commands that gracefully skip: meta:helper, meta:ide, meta:models, meta:all,
model:gen, test:parallel, queue:listen.
Commands that work without artisan: all pint:*, lint:*, test:* (pest), sonar, check-deps.
Forcing a hard failure — call Artisan::require() in your own script class when
you want an error instead of a silent skip:
use Masgeek\ComposerScripts\Support\Artisan; use Composer\Script\Event; class MyScripts { public static function deploy(Event $event): void { Artisan::require($event, 'config:cache'); // throws if artisan absent Artisan::require($event, 'route:cache'); Artisan::require($event, 'view:cache'); } }
Extending the package
Compose package callbacks with project-specific steps in any scripts array:
{
"scripts": {
"ci": [
"Masgeek\\ComposerScripts\\CodeQuality::pintCheck",
"Masgeek\\ComposerScripts\\CodeQuality::analyse",
"Masgeek\\ComposerScripts\\Testing::ci",
"Masgeek\\ComposerScripts\\CodeQuality::sonar"
],
"fresh": [
"@php artisan migrate:fresh --seed",
"Masgeek\\ComposerScripts\\IdeHelper::modelGen"
],
"queue:all": [
"Composer\\Config::disableProcessTimeout",
"@php artisan queue:listen --timeout=0 --queue=broadcast,sms,campaign,archive,zoho,map-network,call-back"
]
}
}
Requirements
- PHP 8.2+
- Composer 2.x
No framework dependency — works with Laravel, Symfony, or plain PHP projects.
Each script only requires its own tool (pest, pint, phpstan, sonar-scanner, etc.)
and only when that specific script is run.