From 8b40903a449a5a8bd6fd6a5458d235864e261634 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 9 Jun 2026 21:40:15 +0000 Subject: [PATCH 1/2] [Crane: crane-migration-python-to-go-full-apm-cli-rewrite] Iteration 79: fix cache subcommand --help routing; add --force/--yes flags and output parity Changes: - cmd/apm/cmd_cache.go: fix runCache to route subcommand --help to the subcommand handler instead of intercepting all --help flags at the top level (cache clean --help and cache prune --help now show their own usage, not the top-level cache menu) - cmd/apm/cmd_cache.go: add -f/--force and -y/--yes flags to cache clean help text; align output messages to Python ('Cleaning cache...' + 'Cache cleaned.' instead of 'Cache cleared: ') - cmd/apm/parity_harness_test.go: add 3 new parity contract tests (GoCacheCleanHelp, GoCachePruneHelp, GoCacheCleanOutputMessages) Score: 1.0 (858/858 parity, 903 Go tests, 247 Python tests, all 13 gates pass) Run: https://github.com/githubnext/apm/actions/runs/27236411257 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- cmd/apm/cmd_cache.go | 24 +++++++++++------- cmd/apm/parity_harness_test.go | 46 ++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 9 deletions(-) diff --git a/cmd/apm/cmd_cache.go b/cmd/apm/cmd_cache.go index ec8b9112..a6149cc4 100644 --- a/cmd/apm/cmd_cache.go +++ b/cmd/apm/cmd_cache.go @@ -44,11 +44,12 @@ func runCache(args []string) int { return 0 } - for _, a := range args { - if a == "--help" || a == "-h" { - printCacheHelp() - return 0 - } + // Only intercept --help/-h when it is the very first argument (top-level + // cache help). When a subcommand precedes --help (e.g. "cache clean --help"), + // delegate to the subcommand handler so it can show its own usage. + if args[0] == "--help" || args[0] == "-h" { + printCacheHelp() + return 0 } sub := args[0] @@ -109,7 +110,9 @@ func runCacheClean(args []string) int { fmt.Println(" Remove all cached content") fmt.Println() fmt.Println("Options:") - fmt.Println(" --help Show this message and exit.") + fmt.Println(" -f, --force Skip confirmation prompt") + fmt.Println(" -y, --yes Skip confirmation prompt") + fmt.Println(" --help Show this message and exit.") return 0 } } @@ -121,7 +124,8 @@ func runCacheClean(args []string) int { fmt.Fprintf(os.Stderr, "[x] Failed to create cache dir: %v\n", mkErr) return 1 } - fmt.Printf("[+] Cache cleared: %s\n", dir) + fmt.Println("[*] Cleaning cache...") + fmt.Println("[+] Cache cleaned.") return 0 } fmt.Fprintf(os.Stderr, "[x] Failed to read cache dir: %v\n", err) @@ -133,7 +137,8 @@ func runCacheClean(args []string) int { return 1 } } - fmt.Printf("[+] Cache cleared: %s\n", dir) + fmt.Println("[*] Cleaning cache...") + fmt.Println("[+] Cache cleaned.") return 0 } @@ -145,7 +150,8 @@ func runCachePrune(args []string) int { fmt.Println(" Remove cache entries older than N days") fmt.Println() fmt.Println("Options:") - fmt.Println(" --days INTEGER Remove entries older than N days. [default: 30]") + fmt.Println(" --days INTEGER Remove entries not accessed within this many days") + fmt.Println(" [default: 30]") fmt.Println(" --help Show this message and exit.") return 0 } diff --git a/cmd/apm/parity_harness_test.go b/cmd/apm/parity_harness_test.go index ea33382f..96bc94c4 100644 --- a/cmd/apm/parity_harness_test.go +++ b/cmd/apm/parity_harness_test.go @@ -375,6 +375,52 @@ func TestParityHarnessGoCacheInfo(t *testing.T) { } } +// TestParityHarnessGoCacheCleanHelp verifies `apm cache clean --help` routes +// to the subcommand help (not the top-level cache help). +func TestParityHarnessGoCacheCleanHelp(t *testing.T) { + r := runBothInTempRepo(t, minimalApmYML, "cache", "clean", "--help") + assertGoExitCode(t, r, 0) + assertPythonVsGoExitCode(t, r) + if !strings.Contains(r.GoStdout, "Usage: apm cache clean") { + t.Errorf("Go `apm cache clean --help` does not show subcommand help: %q", r.GoStdout) + } + if !strings.Contains(r.GoStdout, "--force") || !strings.Contains(r.GoStdout, "--yes") { + t.Errorf("Go `apm cache clean --help` missing --force/--yes flags: %q", r.GoStdout) + } +} + +// TestParityHarnessGoCachePruneHelp verifies `apm cache prune --help` routes +// to the subcommand help (not the top-level cache help). +func TestParityHarnessGoCachePruneHelp(t *testing.T) { + r := runBothInTempRepo(t, minimalApmYML, "cache", "prune", "--help") + assertGoExitCode(t, r, 0) + assertPythonVsGoExitCode(t, r) + if !strings.Contains(r.GoStdout, "Usage: apm cache prune") { + t.Errorf("Go `apm cache prune --help` does not show subcommand help: %q", r.GoStdout) + } + if !strings.Contains(r.GoStdout, "--days") { + t.Errorf("Go `apm cache prune --help` missing --days flag: %q", r.GoStdout) + } +} + +// TestParityHarnessGoCacheCleanOutputMessages verifies `apm cache clean --yes` +// outputs the same messages as Python. +func TestParityHarnessGoCacheCleanOutputMessages(t *testing.T) { + // Use an isolated temp cache dir so the test does not clear the user's real + // cache and both CLIs operate on the same fresh directory. + cacheDir := t.TempDir() + t.Setenv("APM_CACHE_DIR", cacheDir) + r := runBothInTempRepo(t, minimalApmYML, "cache", "clean", "--yes") + assertGoExitCode(t, r, 0) + assertPythonVsGoExitCode(t, r) + if !strings.Contains(r.GoStdout, "Cleaning cache") { + t.Errorf("Go `apm cache clean --yes` missing 'Cleaning cache' in stdout: %q", r.GoStdout) + } + if !strings.Contains(r.GoStdout, "Cache cleaned") { + t.Errorf("Go `apm cache clean --yes` missing 'Cache cleaned' in stdout: %q", r.GoStdout) + } +} + // TestParityHarnessGoConfigHelp verifies `apm config --help`. func TestParityHarnessGoConfigHelp(t *testing.T) { out, _, code := runGo(t, "config", "--help") From f02847267a544d9700e885f6edebe15f4c4aa406 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 9 Jun 2026 21:40:20 +0000 Subject: [PATCH 2/2] ci: trigger checks