Skip to content

feat(php): add PHPUnit support with compact output (65%+ token savings)#874

Closed
Beninho wants to merge 3 commits into
rtk-ai:developfrom
Beninho:feat/phpunit-support
Closed

feat(php): add PHPUnit support with compact output (65%+ token savings)#874
Beninho wants to merge 3 commits into
rtk-ai:developfrom
Beninho:feat/phpunit-support

Conversation

@Beninho

@Beninho Beninho commented Mar 26, 2026

Copy link
Copy Markdown
Contributor

Summary

  • New rtk phpunit command with a state-machine output filter (65%+ token savings)
  • Supports all PHPUnit invocation variants: phpunit, vendor/bin/phpunit, bin/phpunit (Symfony), php vendor/bin/phpunit, php bin/phpunit

Changes

File Change
src/cmds/mod.rs Add entry for PHP
src/cmds/php/mod.rs New PHP module
src/cmds/php/phpunit_cmd.rs New module — state-machine filter, binary detection, tee integration
src/main.rs Routing, doc comment, is_operational_command registration
src/discover/rules.rs PATTERNS regex + RtkRule with 5 rewrite prefixes
src/discover/registry.rs 10 classify/rewrite tests for all variants
tests/fixtures/phpunit_raw.txt Realistic fixture (PHPUnit 10, 110 tests, 1 failure)
scripts/test-all.sh PHP section (conditional on phpunit/vendor/bin presence)
README.md Quick-ref line + hook mapping table entry

Filter design

State machine: Header → Failures → Done

PHPUnit 10.5.0 ...          ← stripped (Header state)
Runtime: PHP 8.2.0          ← stripped
.F.......  100/100 (100%)   ← stripped
Time: 00:01:23, Memory: ... ← stripped
There was 1 failure:        ← triggers Failures state
1) UserTest::testEmail      ← captured
Failed asserting ...        ← captured (up to 2 detail lines)
/path/to/test:42            ← captured
FAILURES!                   ← triggers Done state
Tests: 110, Assertions: 340, Failures: 1.  ← parsed for summary

Output:

PHPUnit: 110 tests, 340 assertions, 1 failures
═══════════════════════════════════════
Failures:
1. 1) UserTest::testEmail
   Failed asserting that false is true.
   /path/to/test:42

Test plan

  • cargo test --all — 1143 passed, 0 failed
  • cargo fmt --all && cargo clippy --all-targets — clean for updated files
  • Token savings test asserts ≥65% on realistic fixture
  • All 5 invocation variants tested for classify + rewrite
  • Manual: rtk phpunit --help shows description
  • Manual: hook rewrites phpunit tests/rtk phpunit tests/

@CLAassistant

CLAassistant commented Mar 27, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@Beninho Beninho changed the base branch from master to develop March 27, 2026 10:12
@Beninho Beninho marked this pull request as draft March 27, 2026 16:40
@Beninho Beninho force-pushed the feat/phpunit-support branch 2 times, most recently from e4a75f6 to a320846 Compare March 27, 2026 16:49
@Beninho Beninho marked this pull request as ready for review March 30, 2026 06:59
@Beninho Beninho force-pushed the feat/phpunit-support branch from a320846 to 37d822a Compare April 25, 2026 10:04
@Beninho Beninho force-pushed the feat/phpunit-support branch from dd90f42 to 2e28122 Compare April 28, 2026 14:01
iliaal added a commit to iliaal/rtk that referenced this pull request Apr 30, 2026
…t, paratest, ecs, pint, artisan)

Consolidates three stalled upstream PRs plus a new .phpt filter and Pint
support into one coherent PHP ecosystem module:

- `rtk php` + `rtk artisan`: syntax check (-l) and Laravel artisan wrapper
- `rtk phpunit`: structured-state parser; aggregate counts + bounded failure list
  (sourced from rtk-ai#874, refactored to use runner::run_filtered and strip emoji)
- `rtk phpstan`: typed serde::Deserialize parser for --error-format=json;
  groups errors by file, sorts by count desc; handles utility commands
  (--version, list, clear-result-cache) as passthrough
  (sourced from rtk-ai#1110, strip emoji in success path)
- `rtk pest` + `rtk paratest`: shared test_output helper (from rtk-ai#1246)
- `rtk ecs` + `rtk pint`: code style fixers; pint uses --format=json for
  structured per-file rule counts
- `rtk phpt`: wraps `php run-tests.php` for php-src and PHP extensions;
  collapses per-test PASS chatter (99.5% byte reduction on a 5322-test run)

Composer custom-bin-dir detection: `composer_bin_dirs()` reads COMPOSER_BIN_DIR
and composer.json `config.bin-dir` so `tools/bin/phpunit` classifies identically
to `vendor/bin/phpunit`. registry.rs normalizes tool paths before matching
so one rule covers every Composer layout.

Sources:
- rtk-ai#1246 (aaronflorey): php, artisan, ecs, pest, paratest, test_output,
  utils, composer_bin_dirs + registry normalization. phpunit and phpstan stubs
  replaced with deeper implementations below.
- rtk-ai#874 (Beninho): phpunit state-machine parser (ported).
- rtk-ai#1110 (LucianoVandi): phpstan typed parser (emoji stripped).
- New: pint_cmd.rs, phpt_cmd.rs.

1744 tests pass (1683 baseline + 61 new).
iliaal added a commit to iliaal/rtk that referenced this pull request May 9, 2026
…t, paratest, ecs, pint, artisan)

Consolidates three stalled upstream PRs plus a new .phpt filter and Pint
support into one coherent PHP ecosystem module:

- `rtk php` + `rtk artisan`: syntax check (-l) and Laravel artisan wrapper
- `rtk phpunit`: structured-state parser; aggregate counts + bounded failure list
  (sourced from rtk-ai#874, refactored to use runner::run_filtered and strip emoji)
- `rtk phpstan`: typed serde::Deserialize parser for --error-format=json;
  groups errors by file, sorts by count desc; handles utility commands
  (--version, list, clear-result-cache) as passthrough
  (sourced from rtk-ai#1110, strip emoji in success path)
- `rtk pest` + `rtk paratest`: shared test_output helper (from rtk-ai#1246)
- `rtk ecs` + `rtk pint`: code style fixers; pint uses --format=json for
  structured per-file rule counts
- `rtk phpt`: wraps `php run-tests.php` for php-src and PHP extensions;
  collapses per-test PASS chatter (99.5% byte reduction on a 5322-test run)

Composer custom-bin-dir detection: `composer_bin_dirs()` reads COMPOSER_BIN_DIR
and composer.json `config.bin-dir` so `tools/bin/phpunit` classifies identically
to `vendor/bin/phpunit`. registry.rs normalizes tool paths before matching
so one rule covers every Composer layout.

Sources:
- rtk-ai#1246 (aaronflorey): php, artisan, ecs, pest, paratest, test_output,
  utils, composer_bin_dirs + registry normalization. phpunit and phpstan stubs
  replaced with deeper implementations below.
- rtk-ai#874 (Beninho): phpunit state-machine parser (ported).
- rtk-ai#1110 (LucianoVandi): phpstan typed parser (emoji stripped).
- New: pint_cmd.rs, phpt_cmd.rs.

1744 tests pass (1683 baseline + 61 new).
iliaal added a commit to iliaal/rtk that referenced this pull request May 17, 2026
…t, paratest, ecs, pint, artisan)

Consolidates three stalled upstream PRs plus a new .phpt filter and Pint
support into one coherent PHP ecosystem module:

- `rtk php` + `rtk artisan`: syntax check (-l) and Laravel artisan wrapper
- `rtk phpunit`: structured-state parser; aggregate counts + bounded failure list
  (sourced from rtk-ai#874, refactored to use runner::run_filtered and strip emoji)
- `rtk phpstan`: typed serde::Deserialize parser for --error-format=json;
  groups errors by file, sorts by count desc; handles utility commands
  (--version, list, clear-result-cache) as passthrough
  (sourced from rtk-ai#1110, strip emoji in success path)
- `rtk pest` + `rtk paratest`: shared test_output helper (from rtk-ai#1246)
- `rtk ecs` + `rtk pint`: code style fixers; pint uses --format=json for
  structured per-file rule counts
- `rtk phpt`: wraps `php run-tests.php` for php-src and PHP extensions;
  collapses per-test PASS chatter (99.5% byte reduction on a 5322-test run)

Composer custom-bin-dir detection: `composer_bin_dirs()` reads COMPOSER_BIN_DIR
and composer.json `config.bin-dir` so `tools/bin/phpunit` classifies identically
to `vendor/bin/phpunit`. registry.rs normalizes tool paths before matching
so one rule covers every Composer layout.

Sources:
- rtk-ai#1246 (aaronflorey): php, artisan, ecs, pest, paratest, test_output,
  utils, composer_bin_dirs + registry normalization. phpunit and phpstan stubs
  replaced with deeper implementations below.
- rtk-ai#874 (Beninho): phpunit state-machine parser (ported).
- rtk-ai#1110 (LucianoVandi): phpstan typed parser (emoji stripped).
- New: pint_cmd.rs, phpt_cmd.rs.

1744 tests pass (1683 baseline + 61 new).
iliaal added a commit to iliaal/rtk that referenced this pull request May 17, 2026
…pest, paratest, ecs, pint)

Consolidates the PHP-tooling work from three upstream PRs plus a new
Pint module, leaving phpt to its own PR (rtk-ai#1503).

- rtk php / rtk artisan: syntax check (-l) and Laravel artisan wrapper.
- rtk phpunit: structured-state parser, aggregate counts, bounded
  failure list. Uses runner::run_filtered.
- rtk phpstan: typed serde::Deserialize parser for --error-format=json,
  groups errors by file, sorts by count desc. Utility commands
  (--version, list, clear-result-cache) pass through unchanged.
- rtk pest / rtk paratest: shared test_output helper.
- rtk ecs / rtk pint: code-style fixers; pint uses --format=json for
  structured per-file rule counts.

Composer custom-bin-dir detection: composer_bin_dirs() reads
COMPOSER_BIN_DIR and composer.json config.bin-dir, so tools/bin/phpunit
classifies identically to vendor/bin/phpunit. registry.rs normalizes
tool paths before matching.

Sources:
- rtk-ai#1246 (aaronflorey, self-closed): php, artisan, ecs, pest,
  paratest, test_output, utils, composer_bin_dirs, registry normalization.
- rtk-ai#874 (Beninho, open): phpunit state-machine parser.
- rtk-ai#1110 (LucianoVandi, open): phpstan typed parser.
- New: pint_cmd.rs.

Tests: discover::registry 253 pass; cmds::php 36 pass; cargo build
--release 0 errors; cargo fmt --check clean.
Beninho and others added 3 commits May 19, 2026 10:32
- New `rtk phpunit` command: state-machine filter that captures test
  names, assertion messages, and file locations from PHPUnit output,
  stripping version banner, progress dots, timing, and memory noise
- Supports all invocation variants: `phpunit`, `vendor/bin/phpunit`,
  `bin/phpunit` (Symfony), `php vendor/bin/phpunit`, `php bin/phpunit`
- Binary detection priority: global phpunit → bin/phpunit → vendor/bin/phpunit
- Registers in discover/rules.rs for `rtk discover` and hook rewriting
- 17 tests: 7 filter tests (including token savings ≥60%), 10 registry
  tests for classify/rewrite across all variants; real fixture in
  tests/fixtures/phpunit_raw.txt
- "OK (X tests, Y assertions)" → already worked, now also shows
  counts for the generic fallback path
- "OK, but incomplete, skipped, or risky tests!" → new handler
  shows skipped count (e.g. "PHPUnit: 9 tests, 15 assertions, 2 skipped")
- Generic fallback now calls parse_counts to show test/assertion
  counts instead of bare "PHPUnit: OK"
- parse_counts returns 4-tuple (tests, assertions, failures, skipped)
  to support Skipped: field with trailing-period stripping
- 3 new tests covering each success variant
- catch segfault + Fatal error

# Conflicts:
#	src/cmds/mod.rs
#	src/main.rs
…rent_prefixes arg

Remove unused PATTERNS const that triggered dead-code error.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Beninho Beninho force-pushed the feat/phpunit-support branch from 2e28122 to f97e423 Compare May 19, 2026 08:51
iliaal added a commit to iliaal/rtk that referenced this pull request May 30, 2026
…t, paratest, ecs, pint, artisan)

Consolidates three stalled upstream PRs plus a new .phpt filter and Pint
support into one coherent PHP ecosystem module:

- `rtk php` + `rtk artisan`: syntax check (-l) and Laravel artisan wrapper
- `rtk phpunit`: structured-state parser; aggregate counts + bounded failure list
  (sourced from rtk-ai#874, refactored to use runner::run_filtered and strip emoji)
- `rtk phpstan`: typed serde::Deserialize parser for --error-format=json;
  groups errors by file, sorts by count desc; handles utility commands
  (--version, list, clear-result-cache) as passthrough
  (sourced from rtk-ai#1110, strip emoji in success path)
- `rtk pest` + `rtk paratest`: shared test_output helper (from rtk-ai#1246)
- `rtk ecs` + `rtk pint`: code style fixers; pint uses --format=json for
  structured per-file rule counts
- `rtk phpt`: wraps `php run-tests.php` for php-src and PHP extensions;
  collapses per-test PASS chatter (99.5% byte reduction on a 5322-test run)

Composer custom-bin-dir detection: `composer_bin_dirs()` reads COMPOSER_BIN_DIR
and composer.json `config.bin-dir` so `tools/bin/phpunit` classifies identically
to `vendor/bin/phpunit`. registry.rs normalizes tool paths before matching
so one rule covers every Composer layout.

Sources:
- rtk-ai#1246 (aaronflorey): php, artisan, ecs, pest, paratest, test_output,
  utils, composer_bin_dirs + registry normalization. phpunit and phpstan stubs
  replaced with deeper implementations below.
- rtk-ai#874 (Beninho): phpunit state-machine parser (ported).
- rtk-ai#1110 (LucianoVandi): phpstan typed parser (emoji stripped).
- New: pint_cmd.rs, phpt_cmd.rs.

1744 tests pass (1683 baseline + 61 new).
iliaal added a commit to iliaal/rtk that referenced this pull request May 30, 2026
…pest, paratest, ecs, pint)

Consolidates the PHP-tooling work from three upstream PRs plus a new
Pint module, leaving phpt to its own PR (rtk-ai#1503).

- rtk php / rtk artisan: syntax check (-l) and Laravel artisan wrapper.
- rtk phpunit: structured-state parser, aggregate counts, bounded
  failure list. Uses runner::run_filtered.
- rtk phpstan: typed serde::Deserialize parser for --error-format=json,
  groups errors by file, sorts by count desc. Utility commands
  (--version, list, clear-result-cache) pass through unchanged.
- rtk pest / rtk paratest: shared test_output helper.
- rtk ecs / rtk pint: code-style fixers; pint uses --format=json for
  structured per-file rule counts.

Composer custom-bin-dir detection: composer_bin_dirs() reads
COMPOSER_BIN_DIR and composer.json config.bin-dir, so tools/bin/phpunit
classifies identically to vendor/bin/phpunit. registry.rs normalizes
tool paths before matching.

Sources:
- rtk-ai#1246 (aaronflorey, self-closed): php, artisan, ecs, pest,
  paratest, test_output, utils, composer_bin_dirs, registry normalization.
- rtk-ai#874 (Beninho, open): phpunit state-machine parser.
- rtk-ai#1110 (LucianoVandi, open): phpstan typed parser.
- New: pint_cmd.rs.

Tests: discover::registry 253 pass; cmds::php 36 pass; cargo build
--release 0 errors; cargo fmt --check clean.
iliaal added a commit to iliaal/rtk that referenced this pull request Jun 9, 2026
…pest, paratest, ecs, pint)

Consolidates the PHP-tooling work from three upstream PRs plus a new
Pint module, leaving phpt to its own PR (rtk-ai#1503).

- rtk php / rtk artisan: syntax check (-l) and Laravel artisan wrapper.
- rtk phpunit: structured-state parser, aggregate counts, bounded
  failure list. Uses runner::run_filtered.
- rtk phpstan: typed serde::Deserialize parser for --error-format=json,
  groups errors by file, sorts by count desc. Utility commands
  (--version, list, clear-result-cache) pass through unchanged.
- rtk pest / rtk paratest: shared test_output helper.
- rtk ecs / rtk pint: code-style fixers; pint uses --format=json for
  structured per-file rule counts.

Composer custom-bin-dir detection: composer_bin_dirs() reads
COMPOSER_BIN_DIR and composer.json config.bin-dir, so tools/bin/phpunit
classifies identically to vendor/bin/phpunit. registry.rs normalizes
tool paths before matching.

Sources:
- rtk-ai#1246 (aaronflorey, self-closed): php, artisan, ecs, pest,
  paratest, test_output, utils, composer_bin_dirs, registry normalization.
- rtk-ai#874 (Beninho, open): phpunit state-machine parser.
- rtk-ai#1110 (LucianoVandi, open): phpstan typed parser.
- New: pint_cmd.rs.

Tests: discover::registry 253 pass; cmds::php 36 pass; cargo build
--release 0 errors; cargo fmt --check clean.
iliaal added a commit to iliaal/rtk that referenced this pull request Jun 9, 2026
…t, paratest, ecs, pint, artisan)

Consolidates three stalled upstream PRs plus a new .phpt filter and Pint
support into one coherent PHP ecosystem module:

- `rtk php` + `rtk artisan`: syntax check (-l) and Laravel artisan wrapper
- `rtk phpunit`: structured-state parser; aggregate counts + bounded failure list
  (sourced from rtk-ai#874, refactored to use runner::run_filtered and strip emoji)
- `rtk phpstan`: typed serde::Deserialize parser for --error-format=json;
  groups errors by file, sorts by count desc; handles utility commands
  (--version, list, clear-result-cache) as passthrough
  (sourced from rtk-ai#1110, strip emoji in success path)
- `rtk pest` + `rtk paratest`: shared test_output helper (from rtk-ai#1246)
- `rtk ecs` + `rtk pint`: code style fixers; pint uses --format=json for
  structured per-file rule counts
- `rtk phpt`: wraps `php run-tests.php` for php-src and PHP extensions;
  collapses per-test PASS chatter (99.5% byte reduction on a 5322-test run)

Composer custom-bin-dir detection: `composer_bin_dirs()` reads COMPOSER_BIN_DIR
and composer.json `config.bin-dir` so `tools/bin/phpunit` classifies identically
to `vendor/bin/phpunit`. registry.rs normalizes tool paths before matching
so one rule covers every Composer layout.

Sources:
- rtk-ai#1246 (aaronflorey): php, artisan, ecs, pest, paratest, test_output,
  utils, composer_bin_dirs + registry normalization. phpunit and phpstan stubs
  replaced with deeper implementations below.
- rtk-ai#874 (Beninho): phpunit state-machine parser (ported).
- rtk-ai#1110 (LucianoVandi): phpstan typed parser (emoji stripped).
- New: pint_cmd.rs, phpt_cmd.rs.

1744 tests pass (1683 baseline + 61 new).

@KuSh KuSh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Beninho,

Thanks for your PR! I’ve left some feedback and suggestions for improvement. Once those are addressed, please rebase your changes on the latest develop branch to ensure a clean merge.

Let me know if you have any questions!

Comment thread Cargo.lock

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those changes are unwanted. Please revert

Comment thread src/discover/registry.rs
// --- PHP tooling ---

#[test]
fn test_classify_phpunit() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See how it has been done in test_classify_vitest() and test_rewrite_vitest for example. You can merge all your tests in two test functions

Comment thread scripts/test-all.sh
section "PHP (conditional)"

if command -v phpunit &>/dev/null || [ -f vendor/bin/phpunit ] || [ -f bin/phpunit ]; then
assert_help "rtk phpunit" rtk phpunit --help

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure it is worth it without at least one assert_ok or assert_contains and/or assert_fails

Comment on lines +9 to +13
let phpunit_script = if std::path::Path::new("bin/phpunit").exists() {
"bin/phpunit"
} else {
"vendor/bin/phpunit"
};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should go in the else block

Comment thread src/discover/rules.rs
},
// PHP tooling
RtkRule {
pattern: r"^(?:php\s+)?(?:(?:vendor/bin|bin)/)?phpunit(?:\s|$)",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems, phpunit also document calling it like that:
./phpunit, ./bin/phpunit or ./vendor/bin/phpunit

You should check how rtk rewrite is called in that case and, if necessary, handle those rewrites too

result
}

fn filter_phpunit_output(output: &str) -> String {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion, you could use a struct like that for failures:

struct Failure {
    header: String,
    details: Vec<String>,
}

As you only use the first 2 lines of detail, only store that and skip everything else.

Also, another possibility to reduce output a little bit: aggregate on error message so that we can list errors per message (if that's a good idea), something like:

PHPUnit: 110 tests, 340 assertions.
2 Failures:
- Failed asserting that false is true.
   - UserTest::testEmail /path/to/test:42
   - UserTest::testPassword /path/to/test:99
   - AuthTest::testLogin /src/auth:15
- Failed asserting array has key "id".
   - UserValidationTest::testStructure /src/validation:203

}

fn build_phpunit_summary(output: &str, failures: &[Vec<String>]) -> String {
let (tests, assertions, failures_count, _skipped) = parse_counts(output);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems if failures there's no skipped tests but that seems strange, could you check that it can't have skipped with failures? In that case, skipped is a valuable information that should not be erased

tests, assertions, failures_count
);
result.push_str("═══════════════════════════════════════\n");
result.push_str("Failures:\n");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be simplfied.

Just output the failure numbers directly on second line:

PHPUnit: {} tests, {} assertions[, {} skipped.
{} Failures:
- ...failures detail

k if k.starts_with("Skipped") => skipped = val,
_ => {}
}
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't we break after the Tests line? Or should the numbers be accumulated?

Comment on lines +202 to +206
for line in output.lines() {
let trimmed = line.trim();
if !trimmed.starts_with("Tests:") {
continue;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to always be the last line in your tests. At least it should be localted on the end, so iterating in the reverse order seems a good idea

@KuSh KuSh self-assigned this Jun 16, 2026
iliaal added a commit to iliaal/rtk that referenced this pull request Jun 18, 2026
…t, paratest, ecs, pint, artisan)

Consolidates three stalled upstream PRs plus a new .phpt filter and Pint
support into one coherent PHP ecosystem module:

- `rtk php` + `rtk artisan`: syntax check (-l) and Laravel artisan wrapper
- `rtk phpunit`: structured-state parser; aggregate counts + bounded failure list
  (sourced from rtk-ai#874, refactored to use runner::run_filtered and strip emoji)
- `rtk phpstan`: typed serde::Deserialize parser for --error-format=json;
  groups errors by file, sorts by count desc; handles utility commands
  (--version, list, clear-result-cache) as passthrough
  (sourced from rtk-ai#1110, strip emoji in success path)
- `rtk pest` + `rtk paratest`: shared test_output helper (from rtk-ai#1246)
- `rtk ecs` + `rtk pint`: code style fixers; pint uses --format=json for
  structured per-file rule counts
- `rtk phpt`: wraps `php run-tests.php` for php-src and PHP extensions;
  collapses per-test PASS chatter (99.5% byte reduction on a 5322-test run)

Composer custom-bin-dir detection: `composer_bin_dirs()` reads COMPOSER_BIN_DIR
and composer.json `config.bin-dir` so `tools/bin/phpunit` classifies identically
to `vendor/bin/phpunit`. registry.rs normalizes tool paths before matching
so one rule covers every Composer layout.

Sources:
- rtk-ai#1246 (aaronflorey): php, artisan, ecs, pest, paratest, test_output,
  utils, composer_bin_dirs + registry normalization. phpunit and phpstan stubs
  replaced with deeper implementations below.
- rtk-ai#874 (Beninho): phpunit state-machine parser (ported).
- rtk-ai#1110 (LucianoVandi): phpstan typed parser (emoji stripped).
- New: pint_cmd.rs, phpt_cmd.rs.

1744 tests pass (1683 baseline + 61 new).
iliaal added a commit to iliaal/rtk that referenced this pull request Jun 26, 2026
…pest, paratest, ecs, pint)

Consolidates the PHP-tooling work from three upstream PRs plus a new
Pint module, leaving phpt to its own PR (rtk-ai#1503).

- rtk php / rtk artisan: syntax check (-l) and Laravel artisan wrapper.
- rtk phpunit: structured-state parser, aggregate counts, bounded
  failure list. Uses runner::run_filtered.
- rtk phpstan: typed serde::Deserialize parser for --error-format=json,
  groups errors by file, sorts by count desc. Utility commands
  (--version, list, clear-result-cache) pass through unchanged.
- rtk pest / rtk paratest: shared test_output helper.
- rtk ecs / rtk pint: code-style fixers; pint uses --format=json for
  structured per-file rule counts.

Composer custom-bin-dir detection: composer_bin_dirs() reads
COMPOSER_BIN_DIR and composer.json config.bin-dir, so tools/bin/phpunit
classifies identically to vendor/bin/phpunit. registry.rs normalizes
tool paths before matching.

Sources:
- rtk-ai#1246 (aaronflorey, self-closed): php, artisan, ecs, pest,
  paratest, test_output, utils, composer_bin_dirs, registry normalization.
- rtk-ai#874 (Beninho, open): phpunit state-machine parser.
- rtk-ai#1110 (LucianoVandi, open): phpstan typed parser.
- New: pint_cmd.rs.

Tests: discover::registry 253 pass; cmds::php 36 pass; cargo build
--release 0 errors; cargo fmt --check clean.
@KuSh

KuSh commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Hi, thanks for your PR. This has been superseded by #1649, and you’ve been properly credited there.

@KuSh KuSh closed this Jun 30, 2026
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.

4 participants