infocyph/phpforge

Shared QA, refactoring, benchmark and release tooling for Infocyph PHP projects.

Maintainers

Package info

github.com/infocyph/PHPForge

Type:composer-plugin

pkg:composer/infocyph/phpforge

Statistics

Installs: 9

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-main 2026-04-23 07:54 UTC

This package is auto-updated.

Last update: 2026-04-23 07:55:52 UTC


README

Shared Composer-powered QA, refactoring, benchmark, release, hook, and CI tooling for Infocyph PHP projects.

PHPForge is installed as a dev dependency in PHP libraries and packages. It provides Composer commands under the ic:* namespace, ships default tool configuration, installs CaptainHook hooks, and exposes a reusable GitHub Actions workflow.

What It Includes

PHPForge brings these tools through one package:

Tool Used For
CaptainHook Git hook installation and pre-commit checks
Pest Test execution
Laravel Pint Code style checks and fixes
PHP_CodeSniffer / PHPCBF Semantic sniffing and fixable sniff repairs
PHPStan Static analysis and cognitive complexity
Psalm Security and taint analysis
Rector Refactor checks and automated refactors
PHPBench Benchmarks
Composer audit Release/security audit guard

Install

Install in the consuming project:

composer require --dev infocyph/phpforge:dev-main

Composer may ask for plugin approval. If approval is needed, run:

composer config allow-plugins.infocyph/phpforge true
composer config allow-plugins.pestphp/pest-plugin true
composer install

Inspect the detected setup:

composer ic:doctor

JSON diagnostics are available for automation:

composer ic:doctor --json

Agent Guide

For coding agents, CI agents, or external automation working inside a project that uses PHPForge, start with:

vendor/infocyph/phpforge/AGENTS.md

It summarizes project commands, verification steps, config priority rules, workflow inputs, hook behavior, and agent expectations. If an agent only auto-discovers root-level instruction files, copy or reference it from the project root as AGENTS.md.

Quick Start

Common daily commands:

composer ic:tests
composer ic:process
composer ic:benchmark
composer ic:release:guard

Initialize optional project files:

composer ic:init

ic:init is interactive by default. It uses selector prompts for common choices and keeps a custom option for project-specific values:

Install CaptainHook config?
Install GitHub Actions workflow wrapper?
PHPForge workflow ref
PHP version matrix
Dependency matrix
PHP extensions
Coverage driver
Extra Composer flags
PHPStan memory limit
Psalm threads
Enable SARIF code-scanning analysis?

Selector presets include:

Prompt Built-in Choices
PHPForge workflow ref main, configured ref, or custom
PHP version matrix supported, current, stable, or custom JSON. Presets resolve from Endoflife API (https://endoflife.date/api/php.json) with fallback to ["8.2","8.3","8.4","8.5"].
Dependency matrix full => ["prefer-lowest","prefer-stable"], stable => ["prefer-stable"], or custom JSON. Prompt shows resolved JSON beside each option.
PHP extensions none => "", detected (from project composer.json ext-* entries in require, require-dev, and suggest), common, mysql, pgsql, mysql+pgsql, or custom
Coverage driver none, xdebug, or pcov
Extra Composer flags none => "", with-all-dependencies => --with-all-dependencies, ignore-ext-redis => --ignore-platform-req=ext-redis, or custom. Prompt explains each option effect.
PHPStan memory limit 1G, 2G, 4G, or custom
Psalm threads 1, 2, 4, or custom

supported includes non-EOL PHP minor cycles (>= 8.2), current uses the latest two supported cycles, and stable uses the latest supported cycle. PHP version, dependency matrix, PHP extensions, and Composer flags selectors show resolved values in the prompt and print the final resolved value after selection.

The generated files are:

captainhook.json
.github/workflows/security-standards.yml

After ic:init, run:

composer ic:tests

If captainhook.json was installed, hooks auto-install on the next composer install or composer update. Use composer ic:hooks only when you want to install/update hooks immediately.

Use targeted or non-interactive init commands when needed:

composer ic:init --captainhook
composer ic:init --workflow --workflow-ref=main
composer ic:init --no-interaction-defaults
composer ic:init --force

Command Reference

Test Commands

Command Purpose
composer ic:tests Full project quality suite: syntax, Pest parallel tests, Pint check, PHPCS summary, PHPStan, Psalm security analysis, and Rector dry run.
composer ic:tests:all Alias of ic:tests.
composer ic:tests:details Runs detailed checks without the parallel Pest shortcut.
composer ic:test:syntax Checks project PHP files while respecting .gitignore, .git/info/exclude, and global Git ignore rules.
composer ic:test:code Runs Pest.
composer ic:test:lint Runs Pint in check mode.
composer ic:test:sniff Runs PHPCS with a full report.
composer ic:test:static Runs PHPStan.
composer ic:test:security Runs Psalm security analysis.
composer ic:test:refactor Runs Rector in dry-run mode.
composer ic:test:bench Runs PHPBench aggregate benchmarks.

CI Commands

Command Purpose
composer ic:ci Runs syntax, Pest, Pint, PHPCS, Rector, PHPStan, and Psalm.
composer ic:ci --prefer-lowest Runs the CI set without PHPStan and Psalm for prefer-lowest dependency jobs.

Process Commands

Command Purpose
composer ic:process Runs Rector, Pint, and PHPCBF fixes.
composer ic:process:all Alias of ic:process.
composer ic:process:refactor Runs Rector fixes.
composer ic:process:lint Runs Pint fixes.
composer ic:process:sniff Runs PHPCBF fixes.
composer ic:process:sniff:fix Alias of ic:process:sniff.

Benchmark Commands

Command Purpose
composer ic:benchmark Runs PHPBench aggregate benchmarks.
composer ic:bench:run Alias of ic:benchmark.
composer ic:bench:quick Runs a shorter PHPBench pass.
composer ic:bench:chart Runs PHPBench chart report.

Release Commands

Command Purpose
composer ic:release:audit Runs Composer audit. Security advisories fail; abandoned packages warn.
composer ic:release:guard Runs Composer validation, audit, and the full test suite.

Config And Utility Commands

Command Purpose
composer ic:init Interactively sets up CaptainHook and the workflow wrapper.
composer ic:init --captainhook Copies only captainhook.json.
composer ic:init --workflow --workflow-ref=main Copies only the workflow wrapper and points it at the given PHPForge ref.
composer ic:init --no-interaction-defaults Copies default init files without prompting.
composer ic:init --force Overwrites existing copied files.
composer ic:hooks Installs enabled CaptainHook hooks.
composer ic:doctor Shows detected configs, vendor-dir, plugin permissions, hook status, and workflow wrapper validation warnings.
composer ic:doctor --json Outputs doctor diagnostics as JSON, including workflow wrapper validation details.
composer ic:list-config Lists config files and their resolution source.
composer ic:list-config --json Outputs config resolution as JSON.
composer ic:publish-config [file...] Copies selected bundled config files into the project.
composer ic:publish-config --all Copies every bundled config file into the project.
composer ic:publish-config --all --force Overwrites all project config files with bundled defaults.
composer ic:clean Removes known PHPForge output files and cache directories.
composer ic:version Shows PHPForge, PHP, PHP binary, and vendor-dir information.
composer ic:phpstan:sarif input.json output.sarif Converts PHPStan JSON output to SARIF 2.1.0.

Configuration

Project config files always have priority over PHPForge bundled defaults.

Tool Lookup Order
Pest pest.xml, then phpunit.xml, then pest.xml.dist, then phpunit.xml.dist, then bundled pest.xml
PHPBench phpbench.json, then bundled phpbench.json
PHPCS / PHPCBF phpcs.xml.dist, then bundled phpcs.xml.dist
PHPStan phpstan.neon.dist, then bundled phpstan.neon.dist
Pint pint.json, then bundled pint.json
Psalm psalm.xml, then bundled psalm.xml
Rector rector.php, then bundled rector.php
CaptainHook captainhook.json, then bundled captainhook.json

Check active config sources:

composer ic:list-config
composer ic:list-config --json

Publish config only when a project needs custom rules:

composer ic:publish-config pint.json phpstan.neon.dist
composer ic:publish-config --all

Use --force to overwrite existing files:

composer ic:publish-config psalm.xml --force

Environment Variables

Variable Default Purpose
IC_PEST_PROCESSES 10 Controls Pest parallel processes for ic:tests.
IC_PHPSTAN_MEMORY_LIMIT 1G Controls PHPStan memory limit.
IC_PSALM_THREADS 1 Controls Psalm thread count.
IC_HOOKS_STRICT 1 Fails Composer when automatic CaptainHook install fails. Set to 0 for best-effort hook installation.

Example:

IC_PEST_PROCESSES=4 composer ic:tests
IC_PHPSTAN_MEMORY_LIMIT=2G composer ic:test:static
IC_HOOKS_STRICT=0 composer install

Git Hooks

Install the bundled CaptainHook configuration:

composer ic:init --captainhook
composer ic:hooks

The bundled pre-commit hook runs:

composer validate --strict
composer ic:release:audit
composer ic:tests

This package also has a root post-autoload-dump script:

"post-autoload-dump": "captainhook install --only-enabled -nf"

That keeps hooks installed for this repository. Consuming projects get automatic hook installation from the PHPForge Composer plugin when captainhook.json exists.

GitHub Actions

PHPForge publishes a reusable workflow:

uses: infocyph/phpforge/.github/workflows/security-standards.yml@main

Install a wrapper workflow into a consuming project:

composer ic:init

For automated setup, skip prompts and choose the reusable workflow ref:

composer ic:init --workflow --workflow-ref=main --no-interaction-defaults

Generated wrapper shape:

name: "Security & Standards"

on:
  schedule:
    - cron: "0 0 * * 0"
  push:
    branches: [ "main", "master" ]
  pull_request:
    branches: [ "main", "master", "develop", "development" ]

jobs:
  phpforge:
    uses: infocyph/phpforge/.github/workflows/security-standards.yml@main
    permissions:
      security-events: write
      actions: read
      contents: read
    with:
      php_versions: '["8.2","8.3","8.4","8.5"]'
      dependency_versions: '["prefer-lowest","prefer-stable"]'
      php_extensions: ""
      coverage: "none"
      composer_flags: ""
      phpstan_memory_limit: "1G"
      psalm_threads: "1"
      run_analysis: true

Workflow inputs:

Input Default Purpose
php_versions ["8.2","8.3","8.4","8.5"] PHP matrix as a JSON array string.
dependency_versions ["prefer-lowest","prefer-stable"] Composer dependency modes as a JSON array string.
php_extensions "" Comma-separated PHP extensions passed to shivammathur/setup-php.
coverage none Coverage driver passed to shivammathur/setup-php; use xdebug, pcov, or none.
composer_flags "" Extra flags appended to Composer install/update commands.
phpstan_memory_limit 1G PHPStan memory limit used by workflow analysis.
psalm_threads 1 Psalm thread count used by workflow analysis.
run_analysis true Runs SARIF upload jobs for PHPStan and Psalm. Set to false for CI-only runs.

Workflow Input Details

php_versions must be a JSON array string because reusable workflow inputs are strings:

with:
  php_versions: '["8.3","8.4","8.5"]'

Use a smaller matrix for faster daily CI, or the full supported range for release confidence.

dependency_versions controls Composer update mode:

with:
  dependency_versions: '["prefer-stable"]'

For release confidence, keep both modes:

with:
  dependency_versions: '["prefer-lowest","prefer-stable"]'

When the matrix entry is prefer-lowest, PHPForge runs composer ic:ci --prefer-lowest, skipping heavyweight PHPStan and Psalm checks for that entry.

php_extensions is passed to shivammathur/setup-php:

with:
  php_extensions: "mbstring, intl, bcmath, pdo_mysql, pdo_pgsql"

Leave it empty when no extra extensions are needed:

with:
  php_extensions: ""

coverage controls the setup-php coverage driver:

with:
  coverage: "none"

Common values:

coverage: "none"
coverage: "xdebug"
coverage: "pcov"

composer_flags appends extra flags to Composer install/update:

with:
  composer_flags: "--ignore-platform-req=ext-redis"

Multiple flags can be passed as one string:

with:
  composer_flags: "--ignore-platform-req=ext-redis --with-all-dependencies"

phpstan_memory_limit controls PHPStan memory in both quality gates and SARIF generation:

with:
  phpstan_memory_limit: "2G"

psalm_threads controls Psalm parallelism:

with:
  psalm_threads: "2"

run_analysis controls the SARIF upload job:

with:
  run_analysis: false

Set it to false when the repository does not use GitHub code scanning, does not grant security-events: write, or wants CI-only runs.

Workflow Examples

Fast CI for active development:

jobs:
  phpforge:
    uses: infocyph/phpforge/.github/workflows/security-standards.yml@main
    with:
      php_versions: '["8.4","8.5"]'
      dependency_versions: '["prefer-stable"]'
      run_analysis: false

Release confidence matrix:

jobs:
  phpforge:
    uses: infocyph/phpforge/.github/workflows/security-standards.yml@main
    permissions:
      security-events: write
      actions: read
      contents: read
    with:
      php_versions: '["8.2","8.3","8.4","8.5"]'
      dependency_versions: '["prefer-lowest","prefer-stable"]'
      run_analysis: true

Project with extensions and no SARIF upload:

jobs:
  phpforge:
    uses: infocyph/phpforge/.github/workflows/security-standards.yml@main
    with:
      php_versions: '["8.3","8.4"]'
      php_extensions: "mbstring, intl, pdo_mysql"
      composer_flags: "--ignore-platform-req=ext-redis"
      run_analysis: false

Project with extensions, coverage, and larger analysis limits:

jobs:
  phpforge:
    uses: infocyph/phpforge/.github/workflows/security-standards.yml@main
    permissions:
      security-events: write
      actions: read
      contents: read
    with:
      php_versions: '["8.3","8.4"]'
      dependency_versions: '["prefer-stable"]'
      php_extensions: "mbstring, intl, bcmath, pdo_mysql"
      coverage: "xdebug"
      composer_flags: "--ignore-platform-req=ext-redis"
      phpstan_memory_limit: "2G"
      psalm_threads: "2"
      run_analysis: true

For code scanning, project-local phpstan.neon.dist and psalm.xml are used when present; otherwise the workflow falls back to PHPForge defaults.

Migration Guide

Replace individual QA dependencies with PHPForge.

Before:

"require-dev": {
    "captainhook/captainhook": "^5.29.2",
    "laravel/pint": "^1.29",
    "pestphp/pest": "^4.6.3",
    "pestphp/pest-plugin-drift": "^4.1",
    "phpbench/phpbench": "^1.6.1",
    "phpstan/phpstan": "^2.1.50",
    "rector/rector": "^2.4.2",
    "squizlabs/php_codesniffer": "^4.0.1",
    "symfony/var-dumper": "^7.3 || ^8.0.8",
    "tomasvotruba/cognitive-complexity": "^1.1",
    "vimeo/psalm": "^6.16.1"
}

After:

"require-dev": {
    "infocyph/phpforge": "^1.0"
}

Remove old local QA scripts such as:

test:*
process:*
bench:*
tests
process
benchmark
release:audit
release:guard
post-autoload-dump

Replace commands:

Old command New command
composer tests / composer test:all composer ic:tests
composer test:details composer ic:tests:details
composer test:syntax composer ic:test:syntax
composer test:code composer ic:test:code
composer test:lint composer ic:test:lint
composer test:sniff composer ic:test:sniff
composer test:static composer ic:test:static
composer test:security composer ic:test:security
composer test:refactor composer ic:test:refactor
composer process / composer process:all composer ic:process
composer process:lint composer ic:process:lint
composer process:sniff:fix composer ic:process:sniff:fix
composer process:refactor composer ic:process:refactor
composer benchmark / composer bench:run composer ic:benchmark
composer bench:quick composer ic:bench:quick
composer bench:chart composer ic:bench:chart
composer release:audit composer ic:release:audit
composer release:guard composer ic:release:guard

Old helper scripts are no longer needed:

.github/scripts/syntax.php
.github/scripts/composer-audit-guard.php
.github/scripts/phpstan-sarif.php

PHPForge provides those through:

composer ic:test:syntax
composer ic:release:audit
composer ic:phpstan:sarif phpstan-results.json phpstan-results.sarif

Troubleshooting

There are no commands defined in the "ic" namespace

The plugin is not active. Enable plugin permissions and reinstall:

composer config allow-plugins.infocyph/phpforge true
composer install

CaptainHook install fails during Composer install

By default hook installation is strict. To make it best-effort:

IC_HOOKS_STRICT=0 composer install

Then inspect manually:

composer ic:doctor
composer ic:hooks

GitHub code scanning upload fails

Set run_analysis: false in the workflow wrapper if the repository does not have SARIF upload permission:

with:
  run_analysis: false

A bundled rule is too strict

Publish the relevant config and edit it in the project:

composer ic:publish-config phpstan.neon.dist
composer ic:publish-config psalm.xml

Project config files always take priority over bundled defaults.