From 28849c7a2ad0a65856bc31ce6000e039ba267d86 Mon Sep 17 00:00:00 2001 From: Mike Letellier Date: Tue, 18 Aug 2026 12:40:23 -0300 Subject: [PATCH 1/3] Workflow improvements (cancel in progress action and only install necessary composer deps) --- .github/workflows/jscs.yml | 7 +++++ .github/workflows/mago.yml | 25 +++++++++++++++-- .github/workflows/oxlint.yml | 7 +++++ .github/workflows/php-cs-fixer.yml | 24 +++++++++++++++-- .github/workflows/phpcs.yml | 25 +++++++++++++++-- .github/workflows/phpstan.yml | 43 ++++++++++++++++++++++++++++-- .github/workflows/phpunit.yml | 7 +++++ .github/workflows/psalm.yml | 7 +++++ .github/workflows/rector.yml | 26 ++++++++++++++++-- .github/workflows/stylelint.yml | 7 +++++ .github/workflows/syntax.yml | 7 +++++ .github/workflows/typos.yml | 7 +++++ 12 files changed, 182 insertions(+), 10 deletions(-) diff --git a/.github/workflows/jscs.yml b/.github/workflows/jscs.yml index 821cfdc7a5..b1119825a4 100644 --- a/.github/workflows/jscs.yml +++ b/.github/workflows/jscs.yml @@ -7,6 +7,13 @@ on: pull_request: types: [opened, labeled, synchronize] +# Cancel superseded runs for the same branch. The group is named explicitly +# rather than derived from github.workflow: several files share the workflow +# name `Inspections` and would otherwise cancel each other. +concurrency: + group: formidable-jscs-${{ github.ref }} + cancel-in-progress: true + jobs: runESLintInspection: if: contains(github.event.pull_request.labels.*.name, 'run analysis') diff --git a/.github/workflows/mago.yml b/.github/workflows/mago.yml index 4ff73b9054..a6fa908522 100644 --- a/.github/workflows/mago.yml +++ b/.github/workflows/mago.yml @@ -1,6 +1,13 @@ on: [push] name: Mago Code Analysis and Linting +# Cancel superseded runs for the same branch. The group is named explicitly +# rather than derived from github.workflow: several files share the workflow +# name `Inspections` and would otherwise cancel each other. +concurrency: + group: formidable-mago-${{ github.ref }} + cancel-in-progress: true + jobs: mago: name: Mago @@ -16,8 +23,22 @@ jobs: with: php-version: '8.1' - - name: Install dependencies - run: composer install --dev --prefer-dist --no-progress + # Install only what this job runs, instead of every require-dev package. + # mago.toml lists vendor/php-stubs/wordpress-stubs/wordpress-stubs.php under + # includes. Without it `mago analyze` reports 8000+ non-existent-function + # errors for every WordPress call. + # The guard fails the job if a package is renamed or dropped from + # composer.json, rather than silently narrowing to nothing. + - name: Install Mago + run: | + NEED='carthage-software/mago php-stubs/wordpress-stubs' + for pkg in $NEED; do + jq -e --arg pkg "$pkg" '."require-dev" | has($pkg)' composer.json > /dev/null \ + || { echo "::error::composer.json has no require-dev entry for $pkg"; exit 1; } + done + jq '{require, autoload, config, "require-dev": (."require-dev" | with_entries(select(.key as $k | $ARGS.positional | index($k))))}' \ + composer.json --args $NEED > composer.ci.json + COMPOSER=composer.ci.json composer install --prefer-dist --no-progress - name: "โœ… Mago Lint" run: vendor/bin/mago lint diff --git a/.github/workflows/oxlint.yml b/.github/workflows/oxlint.yml index ff28416e57..823e1f36bd 100644 --- a/.github/workflows/oxlint.yml +++ b/.github/workflows/oxlint.yml @@ -7,6 +7,13 @@ on: pull_request: types: [opened, labeled, synchronize] +# Cancel superseded runs for the same branch. The group is named explicitly +# rather than derived from github.workflow: several files share the workflow +# name `Inspections` and would otherwise cancel each other. +concurrency: + group: formidable-oxlint-${{ github.ref }} + cancel-in-progress: true + jobs: runOxlintInspection: if: contains(github.event.pull_request.labels.*.name, 'run analysis') diff --git a/.github/workflows/php-cs-fixer.yml b/.github/workflows/php-cs-fixer.yml index e08bd6aed2..4e53713539 100644 --- a/.github/workflows/php-cs-fixer.yml +++ b/.github/workflows/php-cs-fixer.yml @@ -8,6 +8,13 @@ on: types: [ opened, labeled, synchronize ] name: Inspections +# Cancel superseded runs for the same branch. The group is named explicitly +# rather than derived from github.workflow: several files share the workflow +# name `Inspections` and would otherwise cancel each other. +concurrency: + group: formidable-php-cs-fixer-${{ github.ref }} + cancel-in-progress: true + jobs: runPHPCSFixerInspection: if: contains(github.event.pull_request.labels.*.name, 'run analysis') @@ -15,8 +22,21 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4.1.1 - - name: Install dependencies - run: composer install --dev --prefer-dist --no-progress + # Install only what this job runs, instead of every require-dev package. + # .php-cs-fixer.php references PhpCsFixerCustomFixers\Fixer\* rules, which is + # what the second package provides. + # The guard fails the job if a package is renamed or dropped from + # composer.json, rather than silently narrowing to nothing. + - name: Install PHP-CS-Fixer + run: | + NEED='friendsofphp/php-cs-fixer kubawerlos/php-cs-fixer-custom-fixers' + for pkg in $NEED; do + jq -e --arg pkg "$pkg" '."require-dev" | has($pkg)' composer.json > /dev/null \ + || { echo "::error::composer.json has no require-dev entry for $pkg"; exit 1; } + done + jq '{require, autoload, config, "require-dev": (."require-dev" | with_entries(select(.key as $k | $ARGS.positional | index($k))))}' \ + composer.json --args $NEED > composer.ci.json + COMPOSER=composer.ci.json composer install --prefer-dist --no-progress - name: PHPCSFixer check run: ./vendor/bin/php-cs-fixer fix --dry-run --allow-risky=yes --verbose diff --git a/.github/workflows/phpcs.yml b/.github/workflows/phpcs.yml index bc90478921..260f0b6826 100644 --- a/.github/workflows/phpcs.yml +++ b/.github/workflows/phpcs.yml @@ -8,6 +8,13 @@ on: types: [ opened, labeled, synchronize ] name: Inspections +# Cancel superseded runs for the same branch. The group is named explicitly +# rather than derived from github.workflow: several files share the workflow +# name `Inspections` and would otherwise cancel each other. +concurrency: + group: formidable-phpcs-${{ github.ref }} + cancel-in-progress: true + jobs: runPHPCSInspection: if: contains(github.event.pull_request.labels.*.name, 'run analysis') @@ -15,8 +22,22 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4.1.1 - - name: Install dependencies - run: composer install --dev --prefer-dist --no-progress + # Install only what this job runs, instead of every require-dev package. + # phpcs.xml references WordPress, WordPressVIPMinimum and SlevomatCodingStandard; + # wpcs also pulls phpcsextra/phpcsutils and the dealerdirect installer that + # registers all three standards with phpcs. + # The guard fails the job if a package is renamed or dropped from + # composer.json, rather than silently narrowing to nothing. + - name: Install PHPCS and its standards + run: | + NEED='squizlabs/php_codesniffer wp-coding-standards/wpcs automattic/vipwpcs slevomat/coding-standard' + for pkg in $NEED; do + jq -e --arg pkg "$pkg" '."require-dev" | has($pkg)' composer.json > /dev/null \ + || { echo "::error::composer.json has no require-dev entry for $pkg"; exit 1; } + done + jq '{require, autoload, config, "require-dev": (."require-dev" | with_entries(select(.key as $k | $ARGS.positional | index($k))))}' \ + composer.json --args $NEED > composer.ci.json + COMPOSER=composer.ci.json composer install --prefer-dist --no-progress - name: Register custom PHPCS sniffs run: | diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 1f25d40865..13e94aa662 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -1,6 +1,13 @@ on: [push] name: PHPStan Code Analysis +# Cancel superseded runs for the same branch. The group is named explicitly +# rather than derived from github.workflow: several files share the workflow +# name `Inspections` and would otherwise cancel each other. +concurrency: + group: formidable-phpstan-${{ github.ref }} + cancel-in-progress: true + jobs: phpstan: name: PHPStan @@ -19,8 +26,40 @@ jobs: ini-values: display_errors = on, error_reporting = E_ALL tools: composer - - name: "๐Ÿ’ฝ Installing Composer Packages" - run: composer install + # Install only what this job runs, instead of every require-dev package. + # phpstan.neon bootstraps vendor/php-stubs/wordpress-stubs and stubs.php, and + # stubs.php references PHPUnit\Framework\TestCase - without phpunit-polyfills + # the run dies while loading the bootstrap file. + # The guard fails the job if a package is renamed or dropped from + # composer.json, rather than silently narrowing to nothing. + - name: Install PHPStan + run: | + NEED='phpstan/phpstan phpstan/extension-installer phpstan/phpstan-strict-rules php-stubs/wordpress-stubs yoast/phpunit-polyfills' + for pkg in $NEED; do + jq -e --arg pkg "$pkg" '."require-dev" | has($pkg)' composer.json > /dev/null \ + || { echo "::error::composer.json has no require-dev entry for $pkg"; exit 1; } + done + jq '{require, autoload, config, "require-dev": (."require-dev" | with_entries(select(.key as $k | $ARGS.positional | index($k))))}' \ + composer.json --args $NEED > composer.ci.json + COMPOSER=composer.ci.json composer install --prefer-dist --no-progress + + # PHPStan's result cache means only changed files get re-analysed. + # /tmp/phpstan is where it lands by default (sys_get_temp_dir() + + # '/phpstan'); this PHPStan build has no flag to relocate it, and pointing + # tmpDir into the working tree would make `analyze ./` walk its own + # cache. PHPStan + # validates the cache against its own version and the config, so a stale + # restore degrades to a full analysis rather than a wrong result. The sha + # suffix is needed because cache entries are immutable - without it the + # first entry would win forever and the cache would never advance. + - name: Cache PHPStan results + uses: actions/cache@v4 + with: + path: /tmp/phpstan + key: formidable-phpstan-${{ hashFiles('composer.json', 'phpstan.neon') }}-${{ github.sha }} + restore-keys: | + formidable-phpstan-${{ hashFiles('composer.json', 'phpstan.neon') }}- + formidable-phpstan- - name: "๐Ÿงช Test" run: vendor/bin/phpstan analyze ./ --memory-limit=2G diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 5e5f3a97ce..367ae8c4a5 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -8,6 +8,13 @@ on: types: [ opened, labeled, synchronize ] name: PHPUnit +# Cancel superseded runs for the same branch. The group is named explicitly +# rather than derived from github.workflow: several files share the workflow +# name `Inspections` and would otherwise cancel each other. +concurrency: + group: formidable-phpunit-${{ github.ref }} + cancel-in-progress: true + jobs: build-test: if: contains(github.event.pull_request.labels.*.name, 'run tests') diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml index 2535f3cdd8..6421376b4d 100644 --- a/.github/workflows/psalm.yml +++ b/.github/workflows/psalm.yml @@ -9,6 +9,13 @@ on: - master name: Psalm Code Analysis +# Cancel superseded runs for the same branch. The group is named explicitly +# rather than derived from github.workflow: several files share the workflow +# name `Inspections` and would otherwise cancel each other. +concurrency: + group: formidable-psalm-${{ github.ref }} + cancel-in-progress: true + jobs: psalm: name: Psalm diff --git a/.github/workflows/rector.yml b/.github/workflows/rector.yml index e59ef89840..d6a36893ce 100644 --- a/.github/workflows/rector.yml +++ b/.github/workflows/rector.yml @@ -8,6 +8,13 @@ on: types: [ opened, labeled, synchronize ] name: Inspections +# Cancel superseded runs for the same branch. The group is named explicitly +# rather than derived from github.workflow: several files share the workflow +# name `Inspections` and would otherwise cancel each other. +concurrency: + group: formidable-rector-${{ github.ref }} + cancel-in-progress: true + jobs: runRectorInspection: if: contains(github.event.pull_request.labels.*.name, 'run analysis') @@ -15,8 +22,23 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4.1.1 - - name: Install dependencies - run: composer install --dev --prefer-dist --no-progress + # Install only what this job runs, instead of every require-dev package. + # phpstan/phpstan is here for its exact pin, which is what holds Rector at + # 2.3.5 - resolving without it picks Rector 2.6.2, which fails this job on + # deprecated-rule warnings. phpunit-polyfills supplies the PHPUnit classes + # that rector.php's withAutoloadPaths() ends up loading. + # The guard fails the job if a package is renamed or dropped from + # composer.json, rather than silently narrowing to nothing. + - name: Install Rector + run: | + NEED='rector/rector phpstan/phpstan yoast/phpunit-polyfills' + for pkg in $NEED; do + jq -e --arg pkg "$pkg" '."require-dev" | has($pkg)' composer.json > /dev/null \ + || { echo "::error::composer.json has no require-dev entry for $pkg"; exit 1; } + done + jq '{require, autoload, config, "require-dev": (."require-dev" | with_entries(select(.key as $k | $ARGS.positional | index($k))))}' \ + composer.json --args $NEED > composer.ci.json + COMPOSER=composer.ci.json composer install --prefer-dist --no-progress - name: Rector check run: ./vendor/bin/rector process --dry-run diff --git a/.github/workflows/stylelint.yml b/.github/workflows/stylelint.yml index 832552204b..3547c7d357 100644 --- a/.github/workflows/stylelint.yml +++ b/.github/workflows/stylelint.yml @@ -7,6 +7,13 @@ on: pull_request: types: [opened, labeled, synchronize] +# Cancel superseded runs for the same branch. The group is named explicitly +# rather than derived from github.workflow: several files share the workflow +# name `Inspections` and would otherwise cancel each other. +concurrency: + group: formidable-stylelint-${{ github.ref }} + cancel-in-progress: true + jobs: runStylelintInspection: if: contains(github.event.pull_request.labels.*.name, 'run analysis') diff --git a/.github/workflows/syntax.yml b/.github/workflows/syntax.yml index 9773575ac4..a671d6701f 100644 --- a/.github/workflows/syntax.yml +++ b/.github/workflows/syntax.yml @@ -8,6 +8,13 @@ on: types: [ opened, labeled, synchronize ] name: PHP Syntax Check +# Cancel superseded runs for the same branch. The group is named explicitly +# rather than derived from github.workflow: several files share the workflow +# name `Inspections` and would otherwise cancel each other. +concurrency: + group: formidable-syntax-${{ github.ref }} + cancel-in-progress: true + jobs: runPHPSyntaxCheck: if: contains(github.event.pull_request.labels.*.name, 'run analysis') diff --git a/.github/workflows/typos.yml b/.github/workflows/typos.yml index 726343afca..ddc7f51a8f 100644 --- a/.github/workflows/typos.yml +++ b/.github/workflows/typos.yml @@ -9,6 +9,13 @@ on: - master name: Typo Checks +# Cancel superseded runs for the same branch. The group is named explicitly +# rather than derived from github.workflow: several files share the workflow +# name `Inspections` and would otherwise cancel each other. +concurrency: + group: formidable-typos-${{ github.ref }} + cancel-in-progress: true + jobs: run: name: Spell Check with Typos From 71c2f8c0fe11787e5f6b2222c7182bf4ae0a0019 Mon Sep 17 00:00:00 2001 From: Mike Letellier Date: Tue, 18 Aug 2026 12:44:17 -0300 Subject: [PATCH 2/3] Install older mago version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 8e3c0abf43..a4032384d8 100644 --- a/composer.json +++ b/composer.json @@ -42,7 +42,7 @@ "rector/rector": "^2.3.4", "phpstan/phpstan-strict-rules": "^2.0", "kubawerlos/php-cs-fixer-custom-fixers": "^3.36", - "carthage-software/mago": "^1.40.1" + "carthage-software/mago": "1.46.0" }, "config": { "allow-plugins": { From 760249ec16747ea35ff5e6096d9028bc237340e2 Mon Sep 17 00:00:00 2001 From: Mike Letellier Date: Tue, 18 Aug 2026 12:47:41 -0300 Subject: [PATCH 3/3] Put cancel in progress on e2e --- .github/workflows/cypress.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/cypress.yml b/.github/workflows/cypress.yml index 7e9ed1e913..5951181f61 100644 --- a/.github/workflows/cypress.yml +++ b/.github/workflows/cypress.yml @@ -8,6 +8,13 @@ on: types: [ opened, labeled, synchronize ] name: E2E Test +# Cancel superseded runs for the same branch. The group is named explicitly +# rather than derived from github.workflow: several files share the workflow +# name `Inspections` and would otherwise cancel each other. +concurrency: + group: formidable-cypress-${{ github.ref }} + cancel-in-progress: true + jobs: cypress: if: contains(github.event.pull_request.labels.*.name, 'run tests')