-
Notifications
You must be signed in to change notification settings - Fork 8
Reject whitespace-only content in mutation commands #238
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a748846
ccc9cad
746d94c
81c545b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -143,6 +143,64 @@ load test_helper | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
robzolkos marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Whitespace-only content errors | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @test "todo with whitespace-only content shows help" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| create_credentials | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| create_global_config '{"account_id": 99999, "project_id": 123}' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run basecamp todo " " | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert_success | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert_output_contains "basecamp todo" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @test "todos create with whitespace-only content shows help" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| create_credentials | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| create_global_config '{"account_id": 99999, "project_id": 123}' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run basecamp todos create " " | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert_success | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert_output_contains "basecamp todos create" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @test "cards create with whitespace-only title shows help" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| create_credentials | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| create_global_config '{"account_id": 99999, "project_id": 123}' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run basecamp cards create " " | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert_success | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert_output_contains "basecamp cards create" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @test "messages create with whitespace-only title shows help" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| create_credentials | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| create_global_config '{"account_id": 99999, "project_id": 123}' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run basecamp messages create " " | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert_success | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert_output_contains "basecamp messages create" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @test "message with whitespace-only title shows help" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| create_credentials | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| create_global_config '{"account_id": 99999, "project_id": 123}' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run basecamp message " " | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert_success | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert_output_contains "basecamp message" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+157
to
+190
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @test "todos create with whitespace-only content shows help" { | |
| create_credentials | |
| create_global_config '{"account_id": 99999, "project_id": 123}' | |
| run basecamp todos create " " | |
| assert_success | |
| assert_output_contains "basecamp todos create" | |
| } | |
| @test "cards create with whitespace-only title shows help" { | |
| create_credentials | |
| create_global_config '{"account_id": 99999, "project_id": 123}' | |
| run basecamp cards create " " | |
| assert_success | |
| assert_output_contains "basecamp cards create" | |
| } | |
| @test "messages create with whitespace-only title shows help" { | |
| create_credentials | |
| create_global_config '{"account_id": 99999, "project_id": 123}' | |
| run basecamp messages create " " | |
| assert_success | |
| assert_output_contains "basecamp messages create" | |
| } | |
| @test "message with whitespace-only title shows help" { | |
| create_credentials | |
| create_global_config '{"account_id": 99999, "project_id": 123}' | |
| run basecamp message " " | |
| assert_success | |
| assert_output_contains "basecamp message" | |
| @test "todos create with whitespace-only content shows error" { | |
| create_credentials | |
| create_global_config '{"account_id": 99999, "project_id": 123}' | |
| run basecamp todos create " " | |
| assert_failure | |
| assert_json_value '.error' '<content> required' | |
| assert_json_value '.code' 'usage' | |
| } | |
| @test "cards create with whitespace-only title shows error" { | |
| create_credentials | |
| create_global_config '{"account_id": 99999, "project_id": 123}' | |
| run basecamp cards create " " | |
| assert_failure | |
| assert_json_value '.error' '<title> required' | |
| assert_json_value '.code' 'usage' | |
| } | |
| @test "messages create with whitespace-only title shows error" { | |
| create_credentials | |
| create_global_config '{"account_id": 99999, "project_id": 123}' | |
| run basecamp messages create " " | |
| assert_failure | |
| assert_json_value '.error' '<title> required' | |
| assert_json_value '.code' 'usage' | |
| } | |
| @test "message with whitespace-only title shows error" { | |
| create_credentials | |
| create_global_config '{"account_id": 99999, "project_id": 123}' | |
| run basecamp message " " | |
| assert_failure | |
| assert_json_value '.error' '<title> required' | |
| assert_json_value '.code' 'usage' |
robzolkos marked this conversation as resolved.
Show resolved
Hide resolved
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -295,6 +295,9 @@ func newCardsCreateCmd(project, cardTable *string) *cobra.Command { | |||||
| } | ||||||
|
|
||||||
| title := args[0] | ||||||
| if strings.TrimSpace(title) == "" { | ||||||
| return cmd.Help() | ||||||
|
||||||
| return cmd.Help() | |
| return missingArg(cmd, "<title>") |
robzolkos marked this conversation as resolved.
Show resolved
Hide resolved
cubic-dev-ai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
Copilot
AI
Mar 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new no-changes guard trims whitespace, but request construction below still checks title != "" / content != "". As a result, a whitespace-only --title " " or --body " " will still be sent when combined with another field (e.g. --due ...), so whitespace-only updates are not actually rejected. Consider using strings.TrimSpace(...) when deciding whether to set req.Title/req.Content so whitespace-only values are treated as “no input.”
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -1176,7 +1176,7 @@ You can pass either an item ID or a Basecamp URL: | |||||||||||||||||||||||||||||
| basecamp files update 789 --content "new content" --in my-project`, | ||||||||||||||||||||||||||||||
| Args: cobra.ExactArgs(1), | ||||||||||||||||||||||||||||||
| RunE: func(cmd *cobra.Command, args []string) error { | ||||||||||||||||||||||||||||||
| if title == "" && content == "" && itemType == "" { | ||||||||||||||||||||||||||||||
| if strings.TrimSpace(title) == "" && strings.TrimSpace(content) == "" && itemType == "" { | ||||||||||||||||||||||||||||||
| return noChanges(cmd) | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
robzolkos marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
Comment on lines
+1179
to
1182
|
||||||||||||||||||||||||||||||
| if strings.TrimSpace(title) == "" && strings.TrimSpace(content) == "" && itemType == "" { | |
| return noChanges(cmd) | |
| } | |
| trimmedTitle := strings.TrimSpace(title) | |
| trimmedContent := strings.TrimSpace(content) | |
| if trimmedTitle == "" && trimmedContent == "" && itemType == "" { | |
| return noChanges(cmd) | |
| } | |
| // Use normalized values for the rest of the function so that | |
| // whitespace-only inputs are treated as "not provided". | |
| title = trimmedTitle | |
| content = trimmedContent |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -4,6 +4,7 @@ import ( | |||||
| "fmt" | ||||||
| "os" | ||||||
| "strconv" | ||||||
| "strings" | ||||||
|
|
||||||
| "github.com/spf13/cobra" | ||||||
|
|
||||||
|
|
@@ -237,6 +238,10 @@ func newMessagesCreateCmd(project *string, messageBoard *string) *cobra.Command | |||||
| body = args[1] | ||||||
| } | ||||||
|
|
||||||
| if strings.TrimSpace(title) == "" { | ||||||
| return cmd.Help() | ||||||
|
||||||
| return cmd.Help() | |
| return missingArg(cmd, "<title>") |
cubic-dev-ai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
robzolkos marked this conversation as resolved.
Show resolved
Hide resolved
Copilot
AI
Mar 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new no-changes guard trims whitespace, but the update request still uses raw flag values. This means a whitespace-only title/body can still be sent if the other field is non-empty (e.g. --title " " --body "hi"), which contradicts “whitespace-only fields are treated as no input” and may still hit the API with invalid values. Consider building UpdateMessageRequest by only setting Subject/Content when strings.TrimSpace(...) != "" (similar to how the TUI updates only provided fields).
Copilot
AI
Mar 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same issue for the message shortcut: cmd.Help() on whitespace-only title bypasses missingArg() and will exit 0 in machine-output contexts. Use missingArg(cmd, "<title>") for consistent rejection semantics.
| return cmd.Help() | |
| return missingArg(cmd, "<title>") |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -91,6 +91,9 @@ func NewTodoCmd() *cobra.Command { | |||||
| return missingArg(cmd, "<content>") | ||||||
| } | ||||||
| content := strings.Join(args, " ") | ||||||
| if strings.TrimSpace(content) == "" { | ||||||
cubic-dev-ai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
| return cmd.Help() | ||||||
|
||||||
| return cmd.Help() | |
| return missingArg(cmd, "<content>") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test expects whitespace-only title to return help with exit 0. If the CLI intends to reject whitespace-only required args consistently (especially in piped/CI contexts), consider expecting a usage error (non-zero + JSON envelope) similar to the “card without title” case.