Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions src/discover/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3972,4 +3972,105 @@ mod tests {
std::borrow::Cow::<str>::Borrowed("git diff HEAD~1"),
);
}

// --- PHP (#1892) ---

#[test]
fn test_classify_php_bare_is_passthrough() {
assert!(matches!(
classify_command("php"),
Classification::Supported {
rtk_equivalent: "rtk php",
estimated_savings_pct: 0.0,
status: RtkStatus::Passthrough,
..
}
));
}

#[test]
fn test_classify_php_artisan_is_passthrough() {
assert!(matches!(
classify_command("php artisan migrate"),
Classification::Supported {
rtk_equivalent: "rtk php",
estimated_savings_pct: 0.0,
status: RtkStatus::Passthrough,
..
}
));
}

#[test]
fn test_classify_php_script_is_passthrough() {
assert!(matches!(
classify_command("php script.php"),
Classification::Supported {
rtk_equivalent: "rtk php",
estimated_savings_pct: 0.0,
status: RtkStatus::Passthrough,
..
}
));
}

#[test]
fn test_classify_phpunit_not_php() {
// phpunit is a different tool (PHPUnit test runner) — must not be misclassified
// as the php interpreter rule (#1892 regression guard).
// Unsupported / Ignored are both fine — we only forbid a php-rule match.
if let Classification::Supported { rtk_equivalent, .. } = classify_command("phpunit tests/")
{
assert_ne!(
rtk_equivalent, "rtk php",
"phpunit must not be rewritten via the php rule"
);
}
}

#[test]
fn test_rewrite_php_bare() {
assert_eq!(
rewrite_command_no_prefixes("php", &[]),
Some("rtk php".into())
);
}

#[test]
fn test_rewrite_php_artisan_migrate() {
assert_eq!(
rewrite_command_no_prefixes("php artisan migrate", &[]),
Some("rtk php artisan migrate".into())
);
}

#[test]
fn test_rewrite_php_artisan_serve() {
assert_eq!(
rewrite_command_no_prefixes("php artisan serve", &[]),
Some("rtk php artisan serve".into())
);
}

#[test]
fn test_rewrite_php_script_file() {
assert_eq!(
rewrite_command_no_prefixes("php script.php --opt", &[]),
Some("rtk php script.php --opt".into())
);
}

#[test]
fn test_rewrite_phpunit_not_rewritten_as_php() {
// phpunit must NOT be rewritten to `rtk php unit` or `rtk php …`.
// (It may be left unchanged, or rewritten via its own future rule —
// but the php rule must not steal it.)
let result = rewrite_command_no_prefixes("phpunit tests/", &[]);
if let Some(ref rewritten) = result {
assert!(
!rewritten.starts_with("rtk php "),
"phpunit should not be rewritten via php rule, got: {rewritten}"
);
}
}
}
14 changes: 14 additions & 0 deletions src/discover/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,20 @@ pub const RULES: &[RtkRule] = &[
subcmd_savings: &[],
subcmd_status: &[],
},
// PHP interpreter (artisan, scripts, -v, etc.). This is intentionally
// passthrough-only: there is no built-in PHP TOML/Rust filter, but routing
// through `rtk php` lets the hook preserve RTK history/tracking for #1892.
// Pattern uses a word boundary so it matches `php` and `php ...`, but never
// adjacent PHP tools like `phpunit`, `phpcs`, or `phpstan`.
RtkRule {
pattern: r"^(php)(?:\s|$)",
rtk_cmd: "rtk php",
rewrite_prefixes: &["php"],
category: "Build",
savings_pct: 0.0,
subcmd_savings: &[],
subcmd_status: &[("php", RtkStatus::Passthrough)],
},
RtkRule {
pattern: r"^df(\s|$)",
rtk_cmd: "rtk df",
Expand Down
Loading