Skip to content

Fix GrumPHP config paths for global dev-tools sync #288

@coisa

Description

@coisa

Problem

When dev-tools:sync is run from a globally installed fast-forward/dev-tools, the synchronized GrumPHP configuration can point a consumer repository at the global DevTools installation path instead of a stable project-local path.

That makes the generated extra.grumphp.config-default-path brittle: the path depends on the machine's global Composer home and can become awkward, non-portable, or invalid for collaborators and CI.

Current Behavior

dev-tools:sync:composer currently updates the consumer composer.json with extra.grumphp.config-default-path derived from the packaged grumphp.yml path.

In a normal local package install, that path resolves under the consumer vendor/fast-forward/dev-tools tree. In a global DevTools workflow, it can instead resolve to the global DevTools checkout or Composer home location.

The synchronized Git hooks also call vendor/bin/grumphp.phar directly, so there is no DevTools command boundary that can normalize the GrumPHP config path before invoking GrumPHP.

Expected Behavior

Running sync from a global DevTools installation MUST leave the consumer repository with deterministic GrumPHP behavior.

Consumer repositories MUST NOT receive an extra.grumphp.config-default-path value that points into the global DevTools install location. The resulting hooks and Composer metadata should work for local installs, global installs, collaborators, and CI without requiring machine-specific path edits.

Failure Surface

  • dev-tools:sync
  • dev-tools:sync:composer
  • generated composer.json extra.grumphp.config-default-path
  • synchronized Git hooks under resources/git-hooks/
  • global invocation flows such as composer global exec dev-tools -- dev-tools:sync or a globally installed dev-tools binary run against a consumer repository

Proposal

Stop relying on a consumer composer.json entry that points directly at the packaged DevTools grumphp.yml when sync is run globally.

A preferred direction is to introduce a DevTools-owned GrumPHP runner command or service that:

  • resolves the canonical grumphp.yml through FileLocatorInterface;
  • invokes the GrumPHP shim with the resolved config path explicitly;
  • keeps hook scripts pointed at a stable DevTools command boundary instead of calling vendor/bin/grumphp.phar directly;
  • avoids inserting or rewriting extra.grumphp.config-default-path just to expose the packaged config.

If a command wrapper is not viable for every supported flow, sync may instead copy a managed grumphp.yml into the consumer repository. In that case, the copied file MUST be treated as a managed synchronized resource with deterministic overwrite or preservation rules.

Implementation Strategy

  • Isolate GrumPHP config resolution behind a dedicated service that can use FileLocatorInterface and be tested without running Git hooks.
  • Update the sync/composer step so global runs do not write global-install paths into composer.json.
  • Update synchronized hooks to call the new DevTools command boundary, or update sync to copy grumphp.yml project-locally if that path is selected.
  • Preserve compatibility for repositories that already define their own GrumPHP configuration deliberately.
  • Update docs that currently say sync sets extra.grumphp.config-default-path.

Related Context

Non-goals

  • Do not redesign the GrumPHP task set or rules in this issue.
  • Do not solve the full dev-tools-shim packaging design here.
  • Do not migrate every synchronized resource to the manifest model in this issue.
  • Do not require consumer repositories to hand-edit machine-specific GrumPHP paths.

Acceptance Criteria

Functional Criteria

  • dev-tools:sync no longer writes an extra.grumphp.config-default-path value that points into a global Composer home or globally installed fast-forward/dev-tools path.
  • Global DevTools invocation against a consumer repository produces working GrumPHP hooks without machine-specific path edits.
  • Local consumer installs that already use vendor/bin/dev-tools dev-tools:sync remain compatible.
  • Existing consumer-owned GrumPHP configuration is preserved when it is intentionally present.
  • The chosen behavior is documented in README and command docs that mention GrumPHP sync behavior.

Regression Criteria

  • Tests cover dev-tools:sync:composer behavior when DevTools is resolved outside the consumer repository.
  • Tests cover hook command generation or execution wiring for the new GrumPHP invocation path.
  • Tests cover preservation of explicit consumer GrumPHP configuration.

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.
  • MUST: Argument and option resolution MUST be validated separately from command execution logic.
  • MUST: Console formatting and rendering MUST stay separate from domain processing.
  • MUST: Exit behavior, error messaging, and generated output MUST remain deterministic and testable.
  • MUST: Data gathering or transformation MUST be isolated from filesystem writes or publishing steps.
  • MUST: Generated output ordering and formatting MUST remain deterministic across runs.
  • MUST: Re-running the workflow MUST be idempotent or clearly bounded in its side effects.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    Projects

    Status

    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions