Skip to content

feat(tia): support projects in git repository subdirectories (monorepos) - #1809

Closed
einar-hansen wants to merge 6 commits into
pestphp:5.xfrom
einar-hansen:tia-monorepo-support
Closed

einar-hansen wants to merge 6 commits into
pestphp:5.xfrom
einar-hansen:tia-monorepo-support

Conversation

@einar-hansen

@einar-hansen einar-hansen commented Jul 31, 2026 •

Copy link
Copy Markdown

What:

  • Bug Fix
  • New Feature

Description:

Allow TIA to run when a Pest project lives inside a Git repository, such as apps/api in a monorepo. Translate repository paths into project paths so dependency selection, baseline detection, and graph storage use the correct project.

  • ChangedFiles strips the project prefix from Git output, adds it to paths passed to Git, and ignores sibling projects. Null-delimited output preserves non-ASCII filenames, and --no-renames preserves deletions when files move outside the project.
  • GitRepository finds the nearest governing .git entry. For worktrees and submodules, it follows the gitdir file and resolves relative or absolute paths. Worktrees read the shared config through commondir; submodules read their own config. This fixes silent baseline detection failures for both GitHub and GitLab.
  • Storage gives sibling projects separate graph stores, and Fingerprint uses the governing repository for gitignore detection. Root-level projects retain their existing path translations and storage keys.

Verified:

  • The worktree and submodule regressions reproduce ten failures before the config fix. After the fix, PEST_TIA=0 php bin/pest tests/Unit/Plugins/Tia/GitRepository.php tests/Unit/Plugins/Tia/Baselines.php --compact passes all 28 cases, including real Git worktrees and submodules for both baseline providers.
  • An actual Pest worktree resolves the main checkout's .git/config and detects einar-hansen/pest as its baseline repository.
  • XDEBUG_MODE=off PEST_TIA=0 composer test passes for e933e7f40704f72efcbc5b1b98d9fd93a15d2f56: lint, static analysis, 100% type coverage, unit tests, parallel tests, and integration tests (239 passed, 1 skipped). Local PHP 8.5.8 used Xdebug so fixtures could toggle coverage through XDEBUG_MODE; PCOV was disabled for this run.
  • composer test:profanity passes. Output snapshots include the current suite totals.

The GitHub baseline artifact name remains pest-tia-baseline, so multiple baselined projects in one repository still share that artifact name.

Related:

🤖 Generated with Claude Code

Tia previously refused to run when the project root was not the git
repository root, telling monorepo users to "give the project its own git
repository". The underlying problem was a path-space mismatch: git's
plumbing (status --porcelain, diff --name-only, show SHA:path) speaks
repository-root-relative paths, while the dependency graph, watch patterns
and coverage edges all speak project-root-relative paths.

ChangedFiles now detects the project's location inside the repository once
(git rev-parse --show-prefix) and translates at every git boundary:

- status/diff output is mapped to project-relative paths, and paths outside
  the project subtree are dropped — they are as invisible to the project's
  graph as files outside the repository are for a root-level project, and
  leaking them through would hit the unknown-file catch-all and force a
  full rerun on every sibling-project change;
- the diff listing runs with -z (git C-quotes non-ASCII paths, which would
  silently fail the prefix match and drop a real change — a stale replay)
  and --no-renames (rename detection reports only the NEW path, so a
  project file renamed to a path outside the subtree would vanish from the
  listing; as delete+add both sides surface);
- git show SHA:path (behavioural-change filtering, composer.lock drift
  summaries) resolves project-relative paths through the prefix.

A new GitRepository helper locates the governing repository by walking
ancestors, fixing three more root==project assumptions: Fingerprint's
tracked-lockfile check, BaselineSync's GitHub-repo detection (baseline
fetching silently never activated for subdirectory projects), and
Storage's origin-based project key — which now also carries the
subdirectory prefix, so `apps/api` and `services/api` in one repository
never share a graph store.

Root-level projects keep their exact existing behaviour: the prefix is
empty and every translation is the identity. The TiaRequiresRepositoryRoot
exception is removed along with the guard.
einar-hansen and others added 3 commits August 6, 2026 09:15
Resolves conflicts with the upstream Tia refactor:

- Keep upstream's new branch-resolution flow (TiaRequiresCommit,
  TiaRequiresDefaultBranch, TiaRequiresRemote) while dropping the
  subdirectory panic and TiaRequiresRepositoryRoot, per this PR.
- Rebuild ChangedFiles' repo-prefix detection on the new
  Pest\Support\Git class (subdirectoryPrefix()) instead of raw
  Symfony Process calls.
- Keep the -z flag in diffSinceSha so non-ASCII filenames are not
  C-quoted, and translate diff output to project-relative paths.
- Route composerLockDelta through ChangedFiles::contentAtSha so the
  baseline lookup is repo-prefix aware.
- Rewrite the upstream feature test that expected nested projects to
  refuse to run: they now run from the subdirectory.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RioXB5bmhqgAd4rjH2spb4
@kolset

kolset commented Sep 4, 2026

Copy link
Copy Markdown

Hey guys, this will be vey helpful! Also talked with several people waiting for this fix!

Thanks for the great work🙏

Follow gitdir files and commondir pointers to locate the governing
repository config. Cover GitHub and GitLab baseline detection with real
worktrees and submodules, and refresh the suite output snapshots.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@nunomaduro

Copy link
Copy Markdown
Member

thank you! closing in favor of #1914, which covers the same fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

3 participants