Skip to content
Closed
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
9 changes: 4 additions & 5 deletions .github/workflows/validate-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ on:
- 'src/**/*.rs'
- 'Cargo.toml'
- '**.md'
- '.claude/hooks/*.sh'
push:
branches:
- master
Expand Down Expand Up @@ -54,9 +53,10 @@ jobs:

- name: Verify hook coverage
run: |
HOOK_FILE=".claude/hooks/rtk-rewrite.sh"
if [ ! -f "$HOOK_FILE" ]; then
echo "❌ Hook file not found: $HOOK_FILE"
# Check native hook module (src/hook/) for command coverage
HOOK_DIR="src/hook"
if [ ! -d "$HOOK_DIR" ]; then
echo "❌ Hook module directory not found: $HOOK_DIR"
exit 1
fi

Expand All @@ -68,7 +68,6 @@ jobs:
fi

# Verify all Python/Go commands are covered in the registry
# Since PR #241, constants live in src/discover/rules.rs (extracted from registry.rs)
for cmd in ruff pytest pip golangci; do
if ! grep -qr "\"$cmd\"" src/discover/; then
echo "❌ Registry missing rewrite_prefixes for: $cmd"
Expand Down
7 changes: 7 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
fn main() {
// Windows default stack is 1 MB, which overflows in debug builds
// due to the large Commands enum (30+ Clap variants) and match routing.
// Set 8 MB stack to match Unix defaults.
#[cfg(target_os = "windows")]
println!("cargo:rustc-link-arg=/STACK:8388608");
}
16 changes: 8 additions & 8 deletions scripts/validate-docs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,18 @@ for cmd in "${PYTHON_GO_CMDS[@]}"; do
done
echo "✅ Python/Go commands: documented in README.md and CLAUDE.md"

# 4. Hooks cohérents avec doc
HOOK_FILE=".claude/hooks/rtk-rewrite.sh"
if [ -f "$HOOK_FILE" ]; then
echo "🪝 Checking hook rewrites..."
# 4. Hooks cohérents avec doc (native hook module)
HOOK_DIR="src/hook"
if [ -d "$HOOK_DIR" ]; then
echo "🪝 Checking native hook rewrites..."
for cmd in "${PYTHON_GO_CMDS[@]}"; do
if ! grep -q "$cmd" "$HOOK_FILE"; then
echo "⚠️ Hook may not rewrite $cmd (verify manually)"
if ! grep -rq "$cmd" "$HOOK_DIR"; then
echo "⚠️ Hook module may not rewrite $cmd (verify manually)"
fi
done
echo "✅ Hook file exists and mentions Python/Go commands"
echo "✅ Hook module exists and mentions Python/Go commands"
else
echo "⚠️ Hook file not found: $HOOK_FILE"
echo "⚠️ Hook module directory not found: $HOOK_DIR"
fi

echo ""
Expand Down
58 changes: 58 additions & 0 deletions src/hook/cargo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use lazy_static::lazy_static;
use regex::Regex;

lazy_static! {
/// Cargo toolchain prefix: cargo +nightly ...
static ref CARGO_TOOLCHAIN_RE: Regex =
Regex::new(r"^\+\S+\s+").unwrap();
}

pub fn try_rewrite_cargo(match_cmd: &str, cmd_body: &str) -> Option<String> {
let after_cargo = match_cmd.strip_prefix("cargo ").unwrap_or("");
let after_toolchain = CARGO_TOOLCHAIN_RE.replace(after_cargo, "");
let subcmd = after_toolchain.split_whitespace().next().unwrap_or("");
match subcmd {
"test" | "build" | "clippy" | "check" | "install" | "fmt" => {
Some(format!("rtk {}", cmd_body))
}
_ => None,
}
}

#[cfg(test)]
mod tests {
use super::super::rewrite_chain;

fn rewrite(cmd: &str) -> Option<String> {
if cmd.contains("<<") {
return None;
}
rewrite_chain(cmd)
}

#[test]
fn test_cargo_test() {
assert_eq!(rewrite("cargo test"), Some("rtk cargo test".into()));
}

#[test]
fn test_cargo_build_release() {
assert_eq!(
rewrite("cargo build --release"),
Some("rtk cargo build --release".into())
);
}

#[test]
fn test_cargo_with_toolchain() {
assert_eq!(
rewrite("cargo +nightly build"),
Some("rtk cargo +nightly build".into())
);
}

#[test]
fn test_cargo_run_no_match() {
assert_eq!(rewrite("cargo run"), None);
}
}
79 changes: 79 additions & 0 deletions src/hook/containers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use super::helpers::replace_prefix;
use lazy_static::lazy_static;
use regex::Regex;

lazy_static! {
/// Strips docker global flags: -H, --context, --config
static ref DOCKER_GLOBAL_FLAGS_RE: Regex =
Regex::new(r"(?:(-H|--context|--config)\s+\S+\s*|--[a-z-]+=\S+\s*)").unwrap();

/// Strips kubectl global flags: --context, --kubeconfig, --namespace, -n
static ref KUBECTL_GLOBAL_FLAGS_RE: Regex =
Regex::new(r"(?:(--context|--kubeconfig|--namespace|-n)\s+\S+\s*|--[a-z-]+=\S+\s*)").unwrap();
}

pub fn try_rewrite_docker(match_cmd: &str, cmd_body: &str) -> Option<String> {
let after_docker = match_cmd.strip_prefix("docker ").unwrap_or("");

// docker compose → always rewrite
if after_docker.starts_with("compose") {
return Some(replace_prefix(cmd_body, "docker ", "rtk docker "));
}

// Strip docker global flags
let stripped = DOCKER_GLOBAL_FLAGS_RE.replace_all(after_docker, "");
let stripped = stripped.trim_start();
let subcmd = stripped.split_whitespace().next().unwrap_or("");
match subcmd {
"ps" | "images" | "logs" | "run" | "build" | "exec" => {
Some(replace_prefix(cmd_body, "docker ", "rtk docker "))
}
_ => None,
}
}

pub fn try_rewrite_kubectl(match_cmd: &str, cmd_body: &str) -> Option<String> {
let after_kubectl = match_cmd.strip_prefix("kubectl ").unwrap_or("");
let stripped = KUBECTL_GLOBAL_FLAGS_RE.replace_all(after_kubectl, "");
let stripped = stripped.trim_start();
let subcmd = stripped.split_whitespace().next().unwrap_or("");
match subcmd {
"get" | "logs" | "describe" | "apply" => {
Some(replace_prefix(cmd_body, "kubectl ", "rtk kubectl "))
}
_ => None,
}
}

#[cfg(test)]
mod tests {
use super::super::rewrite_chain;

fn rewrite(cmd: &str) -> Option<String> {
if cmd.contains("<<") {
return None;
}
rewrite_chain(cmd)
}

#[test]
fn test_docker_ps() {
assert_eq!(rewrite("docker ps"), Some("rtk docker ps".into()));
}

#[test]
fn test_docker_compose() {
assert_eq!(
rewrite("docker compose up -d"),
Some("rtk docker compose up -d".into())
);
}

#[test]
fn test_kubectl_get() {
assert_eq!(
rewrite("kubectl get pods"),
Some("rtk kubectl get pods".into())
);
}
}
Loading