pestphp / pestphp/pest

TIA: change detection misses all changes when the Pest project is a subdirectory of the git repository (monorepo)

Open
#1,783 2 comments 24 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
PHP
Stars
11.7k
Forks
538
Avg merge
4d 11h
Merged PRs (30d)
8

Description

What happened

In a monorepo where the Pest project lives in a subdirectory of the git repository (e.g. backend/), TIA never detects any PHP source change. In the worst case it replays the previous results as passing without executing the tests affected by the change.

repo/                <- git root
├── frontend/
└── backend/         <- Laravel app, composer.json, pest runs here
    ├── app/
    └── tests/

Reproduction:

  1. Record a baseline: PEST_ALLOW_XDEBUG=1 XDEBUG_MODE=coverage vendor/bin/pest --tia (from backend/, all green, graph written).
  2. Make a semantic change to backend/app/Services/Billing/PartialInvoiceService.php (e.g. add a private const).
  3. Run vendor/bin/pest --tia again.

Expected: the tests covering that file are re-executed (in our suite: 40 tests across 4 files).
Actual: Tests: 1669 passed (…, 1669 replayed) in ~3s — the change maps to zero tests and everything is replayed as unchanged.

With no coverage driver loaded the failure is the safe-but-slow variant instead: WARN Detected PHP source changes but no coverage driver is available followed by a full-suite run on every invocation.

Root cause

src/Plugins/Tia/ChangedFiles.php collects changed paths via:

  • workingTreeChanges()git status --porcelain -z --untracked-files=all (cwd = project root)
  • diffSinceSha()git diff --name-only <sha>..HEAD

Both git commands print paths relative to the repository root (backend/app/Services/...), regardless of cwd. Downstream these are consumed as project-relative paths:

  • currentHash() prepends the project root → …/backend/backend/app/...is_file() false
  • the dependency-graph keys are project-relative (app/Services/...) → the changed path never matches an edge → affected set is empty

Verified identical logic in v4.7.5 (installed) and v5.0.0 (GitHub source). Projects whose composer root equals the git root never notice, since both path notions coincide.

Proof it is exactly this

Creating a throwaway git repository inside backend/ (making project root == git root) and repeating the same experiment yields correct behavior immediately: Tests: 1669 passed (…, 40 affected, 1629 replayed) in ~100s. Removing the inner repo restores the broken behavior.

Suggested fix

Ask git for the prefix once (git rev-parse --show-prefix, empty at repo root) and strip it from every path returned by workingTreeChanges() / diffSinceSha() before they are compared with project-relative graph keys; paths outside the prefix (sibling packages, e.g. frontend/…) can be discarded or kept for the structural-change checks.

Environment
  • Pest v4.7.5 (same code confirmed in v5.0.0)
  • PHP 8.4.10, Laravel 12.64, PostgreSQL, macOS (darwin arm64)
  • Layout: Laravel app in backend/ subdirectory of the git repo, tests/Pest.php maps Tests\TestCase onto Feature + Unit, suite is 100% functional Pest style (1669 tests)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with src/Plugins/Tia/ChangedFiles.php and trace workingTreeChanges() and diffSinceSha(), then reproduce the monorepo case from the issue. Verify that Git paths from a repository-rooted command align with project-relative graph keys, that sibling paths are handled, and that the affected tests are rerun instead of replayed.

Written by the indexing model from the issue text.

Assessment

Tech stack
git, php
Domain
testing-qa
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.