Skip to content
Merged
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
6 changes: 5 additions & 1 deletion internal/commands/cards.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,8 @@ func newCardsCreateCmd(project, cardTable *string) *cobra.Command {
Use: "create <title> [body]",
Short: "Create a new card",
Long: "Create a new card in a project's card table.",
Example: ` basecamp cards create "My card" --in myproject
basecamp cards create --in myproject -- "--title with dashes"`,
RunE: func(cmd *cobra.Command, args []string) error {
// Show help when invoked with no title
if len(args) == 0 {
Expand Down Expand Up @@ -769,7 +771,9 @@ func NewCardCmd() *cobra.Command {
Use: "card <title> [body]",
Short: "Create a new card",
Long: "Create a card in a project's card table. Shortcut for 'basecamp cards create'.",
Args: cobra.ArbitraryArgs,
Example: ` basecamp card "My card" --in myproject
basecamp card --in myproject -- "--title with dashes"`,
Args: cobra.ArbitraryArgs,
RunE: func(cmd *cobra.Command, args []string) error {
// Show help when invoked with no title
if len(args) == 0 {
Expand Down
83 changes: 83 additions & 0 deletions internal/commands/cards_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -975,3 +975,86 @@ func TestCardsMovePositionNumericToMultiTableAmbiguous(t *testing.T) {
assert.Contains(t, e.Message, "card table")
}
}

// =============================================================================
// Dash-separator title tests
// =============================================================================

// TestCardsCreateDashSeparatorTitle verifies that `--` lets a dash-prefixed
// title pass through without being parsed as a flag.
func TestCardsCreateDashSeparatorTitle(t *testing.T) {
app, _ := setupTestApp(t)
// ProjectID intentionally empty — --in must be parsed for the command to
// proceed past project resolution.

cmd := NewCardsCmd()

err := executeCommand(cmd, app, "create", "--in", "123", "--", "--some-title")

// No-network transport guarantees an error past arg parsing.
require.NotNil(t, err)
assert.NotContains(t, err.Error(), "unknown flag")
assert.NotContains(t, err.Error(), "unknown shorthand")

var e *output.Error
if errors.As(err, &e) {
assert.NotEqual(t, "Project ID required", e.Message)
}
}

// TestCardShortcutDashSeparatorTitle verifies the same for the card shortcut.
func TestCardShortcutDashSeparatorTitle(t *testing.T) {
app, _ := setupTestApp(t)

cmd := NewCardCmd()

err := executeCommand(cmd, app, "--in", "123", "--", "--some-title")

require.NotNil(t, err)
assert.NotContains(t, err.Error(), "unknown flag")
assert.NotContains(t, err.Error(), "unknown shorthand")

var e *output.Error
if errors.As(err, &e) {
assert.NotEqual(t, "Project ID required", e.Message)
}
}

// TestCardsCreateFlagsAfterTitle guards the flags-anywhere behavior:
// flags placed after the positional title must still be parsed.
func TestCardsCreateFlagsAfterTitle(t *testing.T) {
app, _ := setupTestApp(t)
// ProjectID intentionally empty — if --in after the title is NOT parsed,
// the command would fail with "Project ID required".

cmd := NewCardsCmd()

err := executeCommand(cmd, app, "create", "Normal title", "--in", "123")

require.NotNil(t, err)
assert.NotContains(t, err.Error(), "unknown flag")
assert.NotContains(t, err.Error(), "unknown shorthand")

var e *output.Error
if errors.As(err, &e) {
assert.NotEqual(t, "Project ID required", e.Message)
}
}

// TestCardShortcutFlagsAfterTitle guards the same for the card shortcut.
func TestCardShortcutFlagsAfterTitle(t *testing.T) {
app, _ := setupTestApp(t)

cmd := NewCardCmd()

err := executeCommand(cmd, app, "Normal title", "--in", "123")

require.NotNil(t, err)
assert.NotContains(t, err.Error(), "unknown flag")
assert.NotContains(t, err.Error(), "unknown shorthand")

var e *output.Error
if errors.As(err, &e) {
assert.NotEqual(t, "Project ID required", e.Message)
}
}
Loading