diff --git a/.surface b/.surface index 03010afe..5f7c4cee 100644 --- a/.surface +++ b/.surface @@ -11606,7 +11606,6 @@ FLAG basecamp templates --profile type=string FLAG basecamp templates --project type=string FLAG basecamp templates --quiet type=bool FLAG basecamp templates --stats type=bool -FLAG basecamp templates --status type=string FLAG basecamp templates --styled type=bool FLAG basecamp templates --todolist type=string FLAG basecamp templates --verbose type=count @@ -11631,7 +11630,6 @@ FLAG basecamp templates construct --profile type=string FLAG basecamp templates construct --project type=string FLAG basecamp templates construct --quiet type=bool FLAG basecamp templates construct --stats type=bool -FLAG basecamp templates construct --status type=string FLAG basecamp templates construct --styled type=bool FLAG basecamp templates construct --todolist type=string FLAG basecamp templates construct --verbose type=count @@ -11653,7 +11651,6 @@ FLAG basecamp templates construction --profile type=string FLAG basecamp templates construction --project type=string FLAG basecamp templates construction --quiet type=bool FLAG basecamp templates construction --stats type=bool -FLAG basecamp templates construction --status type=string FLAG basecamp templates construction --styled type=bool FLAG basecamp templates construction --todolist type=string FLAG basecamp templates construction --verbose type=count @@ -11678,7 +11675,6 @@ FLAG basecamp templates create --profile type=string FLAG basecamp templates create --project type=string FLAG basecamp templates create --quiet type=bool FLAG basecamp templates create --stats type=bool -FLAG basecamp templates create --status type=string FLAG basecamp templates create --styled type=bool FLAG basecamp templates create --todolist type=string FLAG basecamp templates create --verbose type=count @@ -11700,7 +11696,6 @@ FLAG basecamp templates delete --profile type=string FLAG basecamp templates delete --project type=string FLAG basecamp templates delete --quiet type=bool FLAG basecamp templates delete --stats type=bool -FLAG basecamp templates delete --status type=string FLAG basecamp templates delete --styled type=bool FLAG basecamp templates delete --todolist type=string FLAG basecamp templates delete --verbose type=count @@ -11744,7 +11739,6 @@ FLAG basecamp templates show --profile type=string FLAG basecamp templates show --project type=string FLAG basecamp templates show --quiet type=bool FLAG basecamp templates show --stats type=bool -FLAG basecamp templates show --status type=string FLAG basecamp templates show --styled type=bool FLAG basecamp templates show --todolist type=string FLAG basecamp templates show --verbose type=count @@ -11769,7 +11763,6 @@ FLAG basecamp templates update --profile type=string FLAG basecamp templates update --project type=string FLAG basecamp templates update --quiet type=bool FLAG basecamp templates update --stats type=bool -FLAG basecamp templates update --status type=string FLAG basecamp templates update --styled type=bool FLAG basecamp templates update --todolist type=string FLAG basecamp templates update --verbose type=count diff --git a/.surface-breaking b/.surface-breaking index 3df26d10..342ab672 100644 --- a/.surface-breaking +++ b/.surface-breaking @@ -669,6 +669,13 @@ FLAG basecamp reopen --styled type=bool FLAG basecamp reopen --todolist type=string FLAG basecamp reopen --verbose type=count FLAG basecamp reopen --version type=bool +FLAG basecamp templates --status type=string +FLAG basecamp templates construct --status type=string +FLAG basecamp templates construction --status type=string +FLAG basecamp templates create --status type=string +FLAG basecamp templates delete --status type=string +FLAG basecamp templates show --status type=string +FLAG basecamp templates update --status type=string FLAG basecamp tlgroup create --name type=string FLAG basecamp tlgroup rename --name type=string FLAG basecamp tlgroup update --name type=string diff --git a/e2e/templates.bats b/e2e/templates.bats index 54441072..fc57f40f 100644 --- a/e2e/templates.bats +++ b/e2e/templates.bats @@ -133,15 +133,24 @@ load test_helper # Flag parsing -@test "templates --status without value shows error" { +@test "templates list --status without value shows error" { create_credentials create_global_config '{"account_id": 99999}' - run basecamp templates --status + run basecamp templates list --status assert_failure assert_output_contains "--status requires a value" } +@test "templates list --status with invalid value shows error" { + create_credentials + create_global_config '{"account_id": 99999}' + + run basecamp templates list --status bogus + assert_failure + assert_output_contains "unknown --status value" +} + # Help diff --git a/internal/commands/templates.go b/internal/commands/templates.go index 8709956b..654ba376 100644 --- a/internal/commands/templates.go +++ b/internal/commands/templates.go @@ -15,8 +15,6 @@ import ( // NewTemplatesCmd creates the templates command for managing project templates. func NewTemplatesCmd() *cobra.Command { - var status string - cmd := &cobra.Command{ Use: "templates", Short: "Manage project templates", @@ -27,10 +25,8 @@ tools, and content.`, Annotations: map[string]string{"agent_notes": "Construction from template is asynchronous — poll construction until status=completed to get the new project ID"}, } - cmd.PersistentFlags().StringVar(&status, "status", "active", "Filter: active, archived, trashed") - cmd.AddCommand( - newTemplatesListCmd(&status), + newTemplatesListCmd(), newTemplatesShowCmd(), newTemplatesCreateCmd(), newTemplatesUpdateCmd(), @@ -42,18 +38,33 @@ tools, and content.`, return cmd } -func newTemplatesListCmd(status *string) *cobra.Command { - return &cobra.Command{ +func newTemplatesListCmd() *cobra.Command { + var status string + + cmd := &cobra.Command{ Use: "list", Short: "List templates", Long: "List all project templates.", RunE: func(cmd *cobra.Command, args []string) error { - return runTemplatesList(cmd, *status) + return runTemplatesList(cmd, status) }, } + + cmd.Flags().StringVar(&status, "status", "active", "Filter: active, archived, trashed") + + return cmd } func runTemplatesList(cmd *cobra.Command, status string) error { + // Validate before the value reaches the request URL — only the lifecycle + // filters the API understands are allowed. + switch status { + case "", "active", "archived", "trashed": + default: + return output.ErrUsage( + fmt.Sprintf("unknown --status value %q (expected active, archived, or trashed)", status)) + } + app := appctx.FromContext(cmd.Context()) if err := ensureAccount(cmd, app); err != nil {