Skip to content

Add global DevTools working directory and self-update flow #272

@coisa

Description

@coisa

Problem

DevTools is currently optimized for project-local Composer usage, but a global installation would benefit from Composer-like runtime affordances. In particular, users should be able to run DevTools against a specific project directory without first changing directories, and long-lived global installations should provide a safe way to detect and apply updates.

Without this, a global dev-tools binary can drift behind the version used by projects, and users need to remember both where the command should run and how to update the installed package.

Proposal

Introduce a global execution and update flow for the main DevTools binary:

  • add a global --working-dir option, similar to Composer's --working-dir, so any command can target a project directory consistently;
  • add a self-update command that updates the installed fast-forward/dev-tools package;
  • add a non-blocking version freshness check when the binary starts;
  • optionally support opt-in automatic updates through --auto-update and/or FAST_FORWARD_AUTO_UPDATE.

The update check MUST be advisory by default. If checking the latest version fails because of network, Packagist, GitHub, Composer, or filesystem issues, DevTools MUST continue running the requested command and MAY emit only a warning or debug-level context.

Expected Behavior

A user with a global DevTools installation can run commands such as:

dev-tools --working-dir=/path/to/project tests
dev-tools --working-dir=/path/to/project standards --fix
dev-tools self-update
dev-tools self-update --global
FAST_FORWARD_AUTO_UPDATE=1 dev-tools --working-dir=/path/to/project reports

The update behavior should distinguish installation context:

  • local project install: self-update SHOULD run the equivalent of composer update fast-forward/dev-tools in the resolved working directory;
  • global install: self-update --global SHOULD run the equivalent of composer global update fast-forward/dev-tools;
  • auto-update: when explicitly enabled by CLI option or environment variable, DevTools MAY run the same safe update path before delegating to the requested command.

When the installed version is not the latest known version, normal command execution should continue and DevTools should show an actionable warning, for example:

A newer fast-forward/dev-tools version is available. Run `dev-tools self-update` to update this installation.

Implementation Strategy

Consider implementing this as an application-level capability rather than duplicating logic inside individual commands:

  • add a working-directory resolver that applies before command execution and updates process context consistently;
  • evaluate Symfony Console application events or a small application bootstrap hook for the update check, while ensuring it never blocks normal command execution;
  • isolate version discovery from console rendering and from Composer process execution;
  • isolate update execution so local/global Composer invocation can be tested independently;
  • expose deterministic behavior for disabled checks, failed checks, stale versions, current versions, local updates, global updates, and auto-update.

The version freshness check should avoid becoming a startup tax. It should be bounded by timeout/cache policy, and it should be possible to disable or bypass in CI if needed.

Requirements

  • Add a global --working-dir option to the main DevTools binary and ensure commands resolve project-relative paths from that directory.
  • Add a self-update command with local and global update modes.
  • Add a non-blocking freshness check that warns when the installed version is stale.
  • Support opt-in automatic update through --auto-update and/or FAST_FORWARD_AUTO_UPDATE only when safe and explicit.
  • Ensure update-check failures never prevent the requested command from running.
  • Document global installation, --working-dir, self-update, update warnings, and auto-update behavior.
  • Include tests for working-directory resolution, stale-version warnings, failed update checks, local update execution, global update execution, and auto-update opt-in.

Non-goals

  • Do not make automatic updates the default behavior.
  • Do not require network access for normal command execution.
  • Do not replace project-local Composer workflows.
  • Do not make the update checker responsible for release publishing or Packagist synchronization.
  • Do not couple command implementations directly to Composer process details; keep update orchestration isolated.

Benefits

This would make DevTools safer and more ergonomic as a global binary while preserving local project workflows. It also creates a clearer path for users who want a shell alias or startup configuration that always runs against the intended project and optionally keeps the global tool current.

Acceptance Criteria

Functional Criteria

  • dev-tools --working-dir=/path/to/project <command> runs the command as if invoked from that project directory.
  • dev-tools self-update updates a local installation using the resolved working directory.
  • dev-tools self-update --global updates a global installation using Composer global update semantics.
  • startup version checks warn about stale installations without blocking command execution.
  • startup version-check failures continue the original command and expose only bounded warning/debug output.
  • --auto-update and/or FAST_FORWARD_AUTO_UPDATE trigger update behavior only when explicitly enabled.
  • CI and non-interactive execution remain deterministic and do not hang on update checks.
  • docs cover global install usage, --working-dir, self-update, auto-update, and failure behavior.

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.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

Status

Merged

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions