Skip to content

Commit 45a238c

Browse files
authored
Normalize CLI help semantics for verbose/cool-down/days/spec wording and logs cache-eviction flag (#32385)
1 parent 5ea0990 commit 45a238c

13 files changed

Lines changed: 98 additions & 20 deletions

pkg/cli/add_wizard_command.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ Examples:
3838
3939
Workflow specifications:
4040
- Two parts: "owner/repo[@version]" (loads repository-root aw.yml package)
41-
- Three+ parts without .md: "owner/repo/path[@version]" (tries path/aw.yml; if path is a single segment and no manifest is found, falls back to workflows/path.md)
42-
- Four+ parts ending in .md: "owner/repo/path/to/workflow.md[@version]" (loads that explicit markdown workflow path)
41+
- Three+ parts without .md: "owner/repo/folder[@version]" (loads nested aw.yml package when present)
42+
- Three parts: "owner/repo/workflow-name[@version]" (implicitly looks in workflows/ directory)
43+
- Four+ parts: "owner/repo/workflows/workflow-name.md[@version]" (requires explicit .md extension)
4344
- GitHub URL: "https://github.com/owner/repo/blob/branch/path/to/workflow.md"
4445
- Local file: "./path/to/workflow.md"
4546
- Version can be tag, branch, or SHA (for remote workflows)

pkg/cli/add_wizard_command_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,10 @@ func TestAddWizardCommandMentionsCrush(t *testing.T) {
1414
require.NotNil(t, cmd, "Add wizard command should be created")
1515
assert.Contains(t, cmd.Long, "Copilot, Claude, Codex, Gemini, or Crush", "Add wizard help should mention all interactive engine options")
1616
}
17+
18+
func TestAddWizardCommand_UsesStandardThreePartWorkflowSpecWording(t *testing.T) {
19+
cmd := NewAddWizardCommand(func(string) error { return nil })
20+
require.NotNil(t, cmd)
21+
22+
assert.Contains(t, cmd.Long, `Three parts: "owner/repo/workflow-name[@version]" (implicitly looks in workflows/ directory)`)
23+
}

pkg/cli/deploy_command.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ Examples:
9999
cmd.Flags().Bool("no-stop-after", false, "Remove any stop-after field from the workflow")
100100
cmd.Flags().String("stop-after", "", "Override stop-after value in the workflow (e.g., '+48h', '2025-12-31 23:59:59')")
101101
cmd.Flags().Bool("disable-security-scanner", false, "Disable security scanning of workflow markdown content")
102-
cmd.Flags().String("cool-down", defaultDeployCooldown, "Cool-down period before applying a new release during update (e.g. 7d, 24h, 0)")
102+
cmd.Flags().String("cool-down", defaultDeployCooldown, coolDownFlagUsage)
103103

104104
RegisterEngineFlagCompletion(cmd)
105105
RegisterDirFlagCompletion(cmd, "dir")

pkg/cli/deploy_command_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,15 @@ func TestNewDeployCommand_RegistersCoreFlags(t *testing.T) {
5353
}
5454
}
5555

56+
func TestNewDeployCommand_CoolDownFlagUsageMatchesUpdate(t *testing.T) {
57+
cmd := NewDeployCommand(func(string) error { return nil })
58+
require.NotNil(t, cmd)
59+
60+
coolDownFlag := cmd.Flags().Lookup("cool-down")
61+
require.NotNil(t, coolDownFlag)
62+
assert.Equal(t, coolDownFlagUsage, coolDownFlag.Usage)
63+
}
64+
5665
func TestNewDeployCommand_RequiresRepoFlag(t *testing.T) {
5766
cmd := NewDeployCommand(func(string) error { return nil })
5867
require.NotNil(t, cmd)

pkg/cli/forecast_command.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,17 @@ Examples:
100100
},
101101
}
102102

103-
cmd.Flags().Int("days", 30, "Historical window in days to sample run history; must be 7 or 30")
103+
cmd.Flags().Int("days", 30, "Historical window in days to sample run history (allowed values: 7, 30)")
104104
cmd.Flags().String("period", "month", "Aggregation period for projections: week or month")
105105
cmd.Flags().Int("sample", 100, "Maximum number of completed runs to sample per workflow")
106106
cmd.Flags().Bool("eval", false, "Evaluate forecast quality against past data (backtesting mode)")
107107
addRepoFlag(cmd)
108108
addJSONFlag(cmd)
109109

110110
cmd.ValidArgsFunction = CompleteWorkflowNames
111+
_ = cmd.RegisterFlagCompletionFunc("days", func(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
112+
return []string{"7", "30"}, cobra.ShellCompDirectiveNoFileComp
113+
})
111114

112115
return cmd
113116
}

pkg/cli/forecast_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,15 @@ func TestRunForecast_InvalidDays(t *testing.T) {
7979
require.Error(t, err, "should error for days=90 (max is 30)")
8080
}
8181

82+
func TestNewForecastCommand_DaysFlagDocumentsAllowedValues(t *testing.T) {
83+
cmd := NewForecastCommand()
84+
require.NotNil(t, cmd)
85+
86+
daysFlag := cmd.Flags().Lookup("days")
87+
require.NotNil(t, daysFlag, "forecast command should register --days")
88+
assert.Equal(t, "Historical window in days to sample run history (allowed values: 7, 30)", daysFlag.Usage)
89+
}
90+
8291
// ── Duration enrichment ───────────────────────────────────────────────────────
8392

8493
// TestDurationEnrichment verifies that the forecast loop computes Duration from

pkg/cli/logs_command.go

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,10 @@ Examples:
100100
` + string(constants.CLIExtensionPrefix) + ` logs weekly-research --repo owner/repo # Download logs from specific repository
101101
102102
# Cache maintenance
103-
` + string(constants.CLIExtensionPrefix) + ` logs --after -1w # Evict local cache older than 1 week before downloading runs
104-
` + string(constants.CLIExtensionPrefix) + ` logs --after -30d # Evict local cache older than 30 days before downloading runs
105-
` + string(constants.CLIExtensionPrefix) + ` logs --after -1mo # Evict local cache older than 1 month before downloading runs
106-
` + string(constants.CLIExtensionPrefix) + ` logs --after 2024-01-01 # Evict local cache older than 2024-01-01 before downloading runs`,
103+
` + string(constants.CLIExtensionPrefix) + ` logs --cache-before -1w # Evict local cache older than 1 week before downloading runs
104+
` + string(constants.CLIExtensionPrefix) + ` logs --cache-before -30d # Evict local cache older than 30 days before downloading runs
105+
` + string(constants.CLIExtensionPrefix) + ` logs --cache-before -1mo # Evict local cache older than 1 month before downloading runs
106+
` + string(constants.CLIExtensionPrefix) + ` logs --cache-before 2024-01-01 # Evict local cache older than 2024-01-01 before downloading runs`,
107107
RunE: func(cmd *cobra.Command, args []string) error {
108108
logsCommandLog.Printf("Starting logs command: args=%d", len(args))
109109

@@ -221,7 +221,12 @@ Examples:
221221
train, _ := cmd.Flags().GetBool("train")
222222
format, _ := cmd.Flags().GetString("format")
223223
artifacts, _ := cmd.Flags().GetStringSlice("artifacts")
224-
after, _ := cmd.Flags().GetString("after")
224+
cacheBefore, _ := cmd.Flags().GetString("cache-before")
225+
if !cmd.Flags().Changed("cache-before") {
226+
if cmd.Flags().Changed("after") {
227+
cacheBefore, _ = cmd.Flags().GetString("after")
228+
}
229+
}
225230

226231
// Resolve relative dates to absolute dates for GitHub CLI
227232
now := time.Now()
@@ -254,7 +259,7 @@ Examples:
254259
}
255260
}
256261

257-
logsCommandLog.Printf("Executing logs download: workflow=%s, count=%d, engine=%s, train=%v, after=%s", workflowName, count, engine, train, after)
262+
logsCommandLog.Printf("Executing logs download: workflow=%s, count=%d, engine=%s, train=%v, cache_before=%s", workflowName, count, engine, train, cacheBefore)
258263

259264
return DownloadWorkflowLogs(cmd.Context(), LogsDownloadOptions{
260265
WorkflowName: workflowName,
@@ -281,7 +286,7 @@ Examples:
281286
Train: train,
282287
Format: format,
283288
ArtifactSets: artifacts,
284-
After: after,
289+
After: cacheBefore,
285290
})
286291
},
287292
}
@@ -310,7 +315,10 @@ Examples:
310315
logsCmd.Flags().String("format", "", "Output format for cross-run audit report: pretty, markdown (generates security audit report instead of default metrics table)")
311316
logsCmd.Flags().Int("last", 0, "Alias for --count: number of recent runs to download")
312317
logsCmd.Flags().StringSlice("artifacts", nil, "Artifact sets to download (default: all). Valid sets: "+strings.Join(ValidArtifactSetNames(), ", "))
313-
logsCmd.Flags().String("after", "", "(Cache eviction) Evict locally cached run folders for runs before this date, prior to downloading. Accepts deltas like -1d, -1w, -1mo (or explicit day counts like -30d), or an absolute date YYYY-MM-DD. Unlike --start-date, this only clears local cache and does not filter which runs are fetched.")
318+
logsCmd.Flags().String("cache-before", "", "(Cache eviction) Evict locally cached run folders for runs before this date, prior to downloading. Accepts deltas like -1d, -1w, -1mo (or explicit day counts like -30d), or an absolute date YYYY-MM-DD. Unlike --start-date, this only clears local cache and does not filter which runs are fetched.")
319+
logsCmd.Flags().String("after", "", "Alias for --cache-before")
320+
_ = logsCmd.Flags().MarkHidden("after")
321+
_ = logsCmd.Flags().MarkDeprecated("after", "use --cache-before")
314322
logsCmd.Flags().Bool("stdin", false, "Read workflow run IDs or URLs from stdin (one per line) instead of discovering runs via the GitHub API")
315323
logsCmd.MarkFlagsMutuallyExclusive("firewall", "no-firewall")
316324

pkg/cli/logs_command_test.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func TestNewLogsCommand(t *testing.T) {
1717
assert.Equal(t, "logs [workflow]", cmd.Use, "Command use should be 'logs [workflow]'")
1818
assert.Equal(t, "Download and analyze agentic workflow logs with aggregated metrics", cmd.Short, "Command short description should match")
1919
assert.Contains(t, cmd.Long, "Download and analyze agentic workflow logs", "Command long description should contain expected text")
20-
assert.Contains(t, cmd.Long, "Evict local cache older than 1 week before downloading runs", "Cache maintenance examples should describe eviction plus download behavior")
20+
assert.Contains(t, cmd.Long, "logs --cache-before -1w", "Cache maintenance examples should use the cache-before flag name")
2121

2222
// Verify flags are registered
2323
flags := cmd.Flags()
@@ -76,11 +76,16 @@ func TestNewLogsCommand(t *testing.T) {
7676
repoFlag := flags.Lookup("repo")
7777
assert.NotNil(t, repoFlag, "Should have 'repo' flag")
7878

79-
// Check after flag (cache maintenance)
80-
afterFlag := flags.Lookup("after")
81-
assert.NotNil(t, afterFlag, "Should have 'after' flag")
82-
assert.Contains(t, afterFlag.Usage, "-1d", "after flag should document day deltas")
83-
assert.Contains(t, afterFlag.Usage, "-30d", "after flag should document explicit day-count deltas")
79+
// Check cache-before flag (cache maintenance)
80+
cacheBeforeFlag := flags.Lookup("cache-before")
81+
assert.NotNil(t, cacheBeforeFlag, "Should have 'cache-before' flag")
82+
assert.Contains(t, cacheBeforeFlag.Usage, "-1d", "cache-before flag should document day deltas")
83+
assert.Contains(t, cacheBeforeFlag.Usage, "-30d", "cache-before flag should document explicit day-count deltas")
84+
85+
// Backward-compatible alias should remain registered but hidden from help output
86+
afterAliasFlag := flags.Lookup("after")
87+
assert.NotNil(t, afterAliasFlag, "Should retain hidden 'after' alias")
88+
assert.True(t, afterAliasFlag.Hidden, "'after' alias should be hidden from help output")
8489
}
8590

8691
func TestLogsCommandFlagDefaults(t *testing.T) {

pkg/cli/outcomes_command.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ Examples:
5959
},
6060
}
6161

62-
cmd.Flags().BoolP("verbose", "v", false, "Show detailed output")
6362
addJSONFlag(cmd)
6463
addRepoFlag(cmd)
6564
addOutputFlag(cmd, "")

pkg/cli/outcomes_command_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//go:build !integration
2+
3+
package cli
4+
5+
import (
6+
"testing"
7+
8+
"github.com/spf13/cobra"
9+
"github.com/stretchr/testify/assert"
10+
"github.com/stretchr/testify/require"
11+
)
12+
13+
func TestNewOutcomesCommand_DoesNotShadowGlobalVerboseFlag(t *testing.T) {
14+
cmd := NewOutcomesCommand()
15+
require.NotNil(t, cmd)
16+
17+
assert.Nil(t, cmd.Flags().Lookup("verbose"), "outcomes should not define a local --verbose flag")
18+
19+
root := &cobra.Command{Use: "gh aw"}
20+
root.PersistentFlags().BoolP("verbose", "v", false, "Enable verbose output showing detailed information")
21+
root.AddCommand(cmd)
22+
23+
inherited := cmd.InheritedFlags().Lookup("verbose")
24+
require.NotNil(t, inherited, "outcomes should inherit global --verbose flag")
25+
assert.Equal(t, "Enable verbose output showing detailed information", inherited.Usage)
26+
}

0 commit comments

Comments
 (0)