Skip to content

Support workflow_call consumers without a local DevTools dependency #304

@coisa

Description

@coisa

Problem

The reusable workflows currently shipped from assume that the consumer repository already installs locally.

Today, only sets up PHP, warms the Composer cache, and runs . After that, the reusable workflows execute ____ _____ _
| _ \ _____ | |_ ___ | |___
| | | |/ _ \ \ / / | |/ _ \ / _ | / |
| || | __/\ V / | | () | () | _
|____/ _
| _/ ||_/ _/||___/
======================================== directly. That works for repositories that declare as a Composer dependency, but it blocks consumers that want to reuse the packaged automation without taking a direct package dependency.

This limitation is visible in workflows such as:

These workflows already check out the DevTools workflow action source, but they still fail when the consumer repository does not provide a local ____ _____ _
| _ \ _____ | |_ ___ | |___
| | | |/ _ \ \ / / | |/ _ \ / _ | / |
| || | __/\ V / | | () | () | _
|____/ _
| _/ ||_/ _/||___/

{"message":"Running code standards checks...","level":"info","context":[],"timestamp":"2026-04-30T03:42:38+00:00"}
{"message":"Running Rector for code refactoring...","level":"info","context":{"command":"refactor","options":{"ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:42:38+00:00"}

�[33mRefactoring Code with Rector�[39m
�[33m----------------------------�[39m

�[30;42m �[39;49m
�[30;42m [OK] Rector is done! �[39;49m
�[30;42m �[39;49m

{"message":"Code refactoring checks completed successfully.","level":"info","context":{"command":"refactor","options":{"ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:42:48+00:00"}
{"message":"Checking and fixing PHPDocs...","level":"info","context":{"command":"phpdoc","options":{"ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:42:49+00:00"}
{"message":"Created .docheader from repository template.","level":"info","context":[],"timestamp":"2026-04-30T03:42:49+00:00"}

�[33mFixing PHPDoc File Headers with PHP-CS-Fixer�[39m
�[33m--------------------------------------------�[39m

{"about":"PHP CS Fixer 3.95.1 Adalbertus by Fabien Potencier, Dariusz Ruminski and contributors.","files":[],"time":{"total":3.392},"memory":20}
�[33mAdding Missing PHPDoc with Rector�[39m
�[33m---------------------------------�[39m

�[30;42m �[39;49m
�[30;42m [OK] Rector is done! �[39;49m
�[30;42m �[39;49m

{"message":"PHPDoc checks completed successfully.","level":"info","context":{"command":"phpdoc","options":{"ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:42:59+00:00"}
{"message":"Running code style checks and fixes...","level":"info","context":[],"timestamp":"2026-04-30T03:42:59+00:00"}

�[33mRefreshing Composer Lock�[39m
�[33m------------------------�[39m

�[33mNormalizing composer.json with Composer Normalize�[39m
�[33m-------------------------------------------------�[39m

Running �[32mergebnis/composer-normalize�[39m by �[32mAndreas Möller�[39m and contributors.

�[32m./composer.json is already normalized.�[39m

�[33mChecking Code Style with Easy Coding Standard�[39m
�[33m---------------------------------------------�[39m

�[30;42m �[39;49m
�[30;42m [OK] No errors found. Great job - your code is shiny in style! �[39;49m
�[30;42m �[39;49m

{"message":"Code style checks completed successfully.","level":"info","context":{"fix":false,"config":"ecs.php","process_output":null,"command":"code-style","options":{"ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:43:03+00:00"}
{"message":"Generating frontpage for Fast Forward documentation...","level":"info","context":{"command":"reports","options":{"ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:43:03+00:00"}

�[33mGenerating Coverage Report�[39m
�[33m--------------------------�[39m

{"message":"Running PHPUnit tests...","level":"info","context":{"command":"tests","options":{"coverage":".dev-tools/coverage","coverage-summary":true,"ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:43:03+00:00"}

�[33mRunning PHPUnit Tests�[39m
�[33m---------------------�[39m

PHPUnit 12.5.23 by Sebastian Bergmann and contributors.

Runtime: PHP 8.5.5 with PCOV 1.0.12
Configuration: /Users/mentordosnerds/Sites/github.com/php-fast-forward/dev-tools/phpunit.xml

Time: 00:01.329, Memory: 80.50 MB

�[30;42mOK (631 tests, 1865 assertions)�[0m

Generating code coverage report in PHP format ... done [00:00.002]

Generating code coverage report in Clover XML format ... done [00:00.058]

Generating code coverage report in HTML format ... done [00:00.312]

�[1;37;40mCode Coverage Report Summary:�[0m
�[30;43m Classes: 57.39% (66/115) �[0m
�[30;43m Methods: 81.09% (433/534) �[0m
�[30;42m Lines: 92.14% (4563/4952)�[0m

{"message":"PHPUnit tests completed successfully.","level":"info","context":{"command":"tests","options":{"coverage":".dev-tools/coverage","coverage-summary":true,"ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:43:05+00:00"}

�[33mGenerating Metrics Report�[39m
�[33m-------------------------�[39m

{"message":"Running code metrics analysis...","level":"info","context":{"command":"metrics","options":{"target":".dev-tools/metrics","junit":".dev-tools/coverage/junit.xml","ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:43:05+00:00"}

�[33mGenerating Metrics with PhpMetrics�[39m
�[33m----------------------------------�[39m

{"message":"Code metrics analysis completed successfully.","level":"info","context":{"command":"metrics","options":{"target":".dev-tools/metrics","junit":".dev-tools/coverage/junit.xml","ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:43:19+00:00"}

�[33mGenerating API Docs Report�[39m
�[33m--------------------------�[39m

{"message":"Generating API documentation...","level":"info","context":{"command":"docs","options":{"target":".dev-tools","ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:43:03+00:00"}

�[33mGenerating API Docs with phpDocumentor�[39m
�[33m--------------------------------------�[39m

phpDocumentor 3.9.1

Parsing source files

Applying transformations (can take a while)

All done in 6 seconds!
{"message":"API documentation generated successfully.","level":"info","context":{"command":"docs","options":{"target":".dev-tools","ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:43:10+00:00"}
{"message":"Documentation reports generated successfully.","level":"info","context":{"command":"reports","options":{"ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:43:19+00:00"}
{"message":"Code standards checks completed successfully.","level":"info","context":{"commands":["refactor","phpdoc","code-style","reports"]},"timestamp":"2026-04-30T03:43:19+00:00"} entrypoint.

That makes it harder to sync and reuse the packaged automation in repositories such as , , and similar workflow-driven repositories that may not need the full local DevTools package as an application dependency.

Proposal

Support a workflow runtime fallback that prefers the consumer local installation when it exists and otherwise installs or resolves DevTools globally for workflow execution.

This should be treated as an interim compatibility improvement before the broader reusable-workflow extraction tracked in #240.

Goals

  • Allow consumers to run packaged DevTools workflows without adding to their local Composer dependencies.
  • Preserve the current behavior for repositories that already depend on locally.
  • Keep the fallback deterministic so workflow behavior does not depend on an unrelated implicit global package version.

Expected Behavior

When a reusable workflow needs to execute DevTools commands:

  • if the consumer repository already provides , the workflow continues to use that local installation;
  • if the consumer repository does not provide , the workflow resolves a global DevTools runtime and still completes successfully;
  • synced wrappers under continue to work for both kinds of consumers;
  • workflow output, failure handling, and generated artifacts remain equivalent between the local and fallback paths.

Implementation Strategy

  • Introduce a shared workflow bootstrap around or an adjacent helper so local-vs-global DevTools resolution happens in one place.
  • Update every reusable workflow that currently shells into ____ _____ _
    | _ \ _____ | |_ ___ | |___
    | | | |/ _ \ \ / / | |/ _ \ / _ | / |
    | || | __/\ V / | | () | () | _
    |____/ _
    | _/ ||_/ _/||___/
    ======================================== after to use that shared runtime bootstrap instead of assuming a local Composer script exists.
  • Keep the fallback limited to workflow execution; this issue should not change how repositories use DevTools locally through Composer, the plugin, or synced scripts.
  • Ensure the fallback runtime is resolved deterministically from the workflow execution context rather than silently pulling an arbitrary latest release.

Requirements

  • Reusable workflows that execute DevTools commands MUST support consumers that do not install locally.
  • The bootstrap MUST prefer a consumer-local DevTools installation when it exists and only fall back to a global runtime when it is missing.
  • The fallback MUST resolve a deterministic DevTools runtime aligned with the workflow source or ref strategy being executed.
  • The shared runtime bootstrap MUST be reused across affected workflows instead of duplicating local-vs-global resolution logic in each workflow file.
  • Workflow documentation and troubleshooting guidance MUST be updated when this makes the local package dependency optional for workflow-only consumers.

Non-goals

  • Migrating all reusable workflows and composite actions into as part of this issue; that broader extraction remains tracked by Extract shared GitHub Actions automation into php-fast-forward/.github #240.
  • Removing or deprecating the local dependency path for repositories that already rely on it.
  • Redesigning the overall workflow ref or release policy beyond what is necessary to make the fallback deterministic.

Benefits

This would let Fast Forward repositories adopt synced workflow automation without having to declare as a direct Composer dependency when they only need the reusable workflows. It also gives us a cleaner bridge while the larger workflow/action extraction work is still pending.

Acceptance Criteria

Functional Criteria

  • A consumer without in its local Composer dependencies can run the packaged workflows that require DevTools commands.
  • Consumers that already install locally continue to use the local installation without behavioral regressions.
  • , , , , and any other reusable workflow that executes DevTools commands use the shared fallback bootstrap instead of assuming ____ _____ _
    | _ \ _____ | |_ ___ | |___
    | | | |/ _ \ \ / / | |/ _ \ / _ | / |
    | || | __/\ V / | | () | () | _
    |____/ _
    | _/ ||_/ _/||___/
    ========================================

{"message":"Running code standards checks...","level":"info","context":[],"timestamp":"2026-04-30T03:43:23+00:00"}
{"message":"Running Rector for code refactoring...","level":"info","context":{"command":"refactor","options":{"ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:43:23+00:00"}

�[33mRefactoring Code with Rector�[39m
�[33m----------------------------�[39m

�[30;42m �[39;49m
�[30;42m [OK] Rector is done! �[39;49m
�[30;42m �[39;49m

{"message":"Code refactoring checks completed successfully.","level":"info","context":{"command":"refactor","options":{"ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:43:34+00:00"}
{"message":"Checking and fixing PHPDocs...","level":"info","context":{"command":"phpdoc","options":{"ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:43:34+00:00"}
{"message":"Created .docheader from repository template.","level":"info","context":[],"timestamp":"2026-04-30T03:43:34+00:00"}

�[33mFixing PHPDoc File Headers with PHP-CS-Fixer�[39m
�[33m--------------------------------------------�[39m

{"about":"PHP CS Fixer 3.95.1 Adalbertus by Fabien Potencier, Dariusz Ruminski and contributors.","files":[],"time":{"total":3.361},"memory":20}
�[33mAdding Missing PHPDoc with Rector�[39m
�[33m---------------------------------�[39m

�[30;42m �[39;49m
�[30;42m [OK] Rector is done! �[39;49m
�[30;42m �[39;49m

{"message":"PHPDoc checks completed successfully.","level":"info","context":{"command":"phpdoc","options":{"ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:43:45+00:00"}
{"message":"Running code style checks and fixes...","level":"info","context":[],"timestamp":"2026-04-30T03:43:45+00:00"}

�[33mRefreshing Composer Lock�[39m
�[33m------------------------�[39m

�[33mNormalizing composer.json with Composer Normalize�[39m
�[33m-------------------------------------------------�[39m

Running �[32mergebnis/composer-normalize�[39m by �[32mAndreas Möller�[39m and contributors.

�[32m./composer.json is already normalized.�[39m

�[33mChecking Code Style with Easy Coding Standard�[39m
�[33m---------------------------------------------�[39m

�[30;42m �[39;49m
�[30;42m [OK] No errors found. Great job - your code is shiny in style! �[39;49m
�[30;42m �[39;49m

{"message":"Code style checks completed successfully.","level":"info","context":{"fix":false,"config":"ecs.php","process_output":null,"command":"code-style","options":{"ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:43:50+00:00"}
{"message":"Generating frontpage for Fast Forward documentation...","level":"info","context":{"command":"reports","options":{"ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:43:50+00:00"}

�[33mGenerating Coverage Report�[39m
�[33m--------------------------�[39m

{"message":"Running PHPUnit tests...","level":"info","context":{"command":"tests","options":{"coverage":".dev-tools/coverage","coverage-summary":true,"ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:43:50+00:00"}

�[33mRunning PHPUnit Tests�[39m
�[33m---------------------�[39m

PHPUnit 12.5.23 by Sebastian Bergmann and contributors.

Runtime: PHP 8.5.5 with PCOV 1.0.12
Configuration: /Users/mentordosnerds/Sites/github.com/php-fast-forward/dev-tools/phpunit.xml

Time: 00:01.408, Memory: 80.50 MB

�[30;42mOK (631 tests, 1865 assertions)�[0m

Generating code coverage report in PHP format ... done [00:00.002]

Generating code coverage report in Clover XML format ... done [00:00.059]

Generating code coverage report in HTML format ... done [00:00.304]

�[1;37;40mCode Coverage Report Summary:�[0m
�[30;43m Classes: 57.39% (66/115) �[0m
�[30;43m Methods: 81.09% (433/534) �[0m
�[30;42m Lines: 92.14% (4563/4952)�[0m

{"message":"PHPUnit tests completed successfully.","level":"info","context":{"command":"tests","options":{"coverage":".dev-tools/coverage","coverage-summary":true,"ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:43:52+00:00"}

�[33mGenerating Metrics Report�[39m
�[33m-------------------------�[39m

{"message":"Running code metrics analysis...","level":"info","context":{"command":"metrics","options":{"target":".dev-tools/metrics","junit":".dev-tools/coverage/junit.xml","ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:43:52+00:00"}

�[33mGenerating Metrics with PhpMetrics�[39m
�[33m----------------------------------�[39m

{"message":"Code metrics analysis completed successfully.","level":"info","context":{"command":"metrics","options":{"target":".dev-tools/metrics","junit":".dev-tools/coverage/junit.xml","ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:44:05+00:00"}

�[33mGenerating API Docs Report�[39m
�[33m--------------------------�[39m

{"message":"Generating API documentation...","level":"info","context":{"command":"docs","options":{"target":".dev-tools","ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:43:50+00:00"}

�[33mGenerating API Docs with phpDocumentor�[39m
�[33m--------------------------------------�[39m

phpDocumentor 3.9.1

Parsing source files

Applying transformations (can take a while)

All done in 6 seconds!
{"message":"API documentation generated successfully.","level":"info","context":{"command":"docs","options":{"target":".dev-tools","ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:43:57+00:00"}
{"message":"Documentation reports generated successfully.","level":"info","context":{"command":"reports","options":{"ansi":true,"no-logo":true}},"timestamp":"2026-04-30T03:44:05+00:00"}
{"message":"Code standards checks completed successfully.","level":"info","context":{"commands":["refactor","phpdoc","code-style","reports"]},"timestamp":"2026-04-30T03:44:05+00:00"} exists locally.

  • The fallback runtime is deterministic and aligned with the workflow execution context instead of implicitly installing an unrelated latest global release.
  • Documentation explains when workflow consumers can omit a local dependency.

Regression Criteria

  • Add or update automated coverage for a consumer-style workflow scenario where is not installed locally.
  • Existing workflow consumers with a local DevTools dependency remain covered by regression checks.
  • Reports, changelog validation, PHPUnit and dependency checks, and wiki preview generation remain functionally equivalent after the runtime bootstrap change.

Architectural / Isolation Criteria

  • MUST: The core logic MUST be isolated into dedicated classes or services instead of living inside command or controller entrypoints.
  • MUST: Responsibilities MUST be separated across input resolution, domain logic, processing or transformation, and output rendering when the change is non-trivial.
  • MUST: The command or controller layer MUST act only as an orchestrator.
  • MUST: The implementation MUST avoid tight coupling between core behavior and CLI or framework-specific I/O.
  • MUST: The design MUST allow future extraction or reuse with minimal changes.
  • MUST: The solution MUST remain extensible without requiring major refactoring for adjacent use cases.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    Released

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions