Fix cards column color 404 from missing bucket in URL#455
Fix cards column color 404 from missing bucket in URL#455packagethief wants to merge 1 commit intomainfrom
cards column color 404 from missing bucket in URL#455Conversation
`basecamp cards column color` was sending PUT requests without the
`/buckets/{id}` path segment, causing every invocation to 404.
The SDK's generated client (basecamp-sdk/go v0.7.3) builds the path
`/{accountId}/card_tables/columns/{columnId}/color.json` — missing the
bucket. Basecamp tolerates this for `Get`/`Update` but rejects it for
`/color.json`, so the command was unusable.
Workaround in the CLI until the SDK is fixed: resolve the bucket from
the URL, `--in`/`--project` flag, or config (the same pattern as
`cards column show` and others), then send the PUT via the raw API
helper `app.Account().Put` to the correct bucket-scoped path. Re-fetch
through the SDK `Get` so the typed `*CardColumn` return shape is
preserved.
Same SDK bug affects `cards column on-hold` and `cards column
no-on-hold` (`/on_hold.json`); those are not addressed here.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Fixes basecamp cards column color 404s by bypassing a Basecamp Go SDK route bug and issuing a bucket-scoped PUT .../color.json request.
Changes:
- Plumbs the
project/--inpointer intonewCardsColumnColorCmdand resolves the bucket before setting the color. - Uses
app.Account().Put()against/buckets/<id>/card_tables/columns/<id>/color.json, then re-fetches the column via the SDKGet. - Updates the existing help test to use the new command constructor signature.
Tip
If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| internal/commands/cards.go | Updates the column color command to resolve bucket and use a raw bucket-scoped PUT workaround. |
| internal/commands/cards_test.go | Updates the help-test call site for the new newCardsColumnColorCmd(project *string) signature. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Resolve project - use URL > flag > config, with interactive fallback. | ||
| // The color endpoint requires a bucket-scoped path (PUT /buckets/<id>/card_tables/columns/<id>/color.json). | ||
| projectID := *project | ||
| if projectID == "" && urlProjectID != "" { | ||
| projectID = urlProjectID | ||
| } | ||
| if projectID == "" { | ||
| projectID = app.Flags.Project |
There was a problem hiding this comment.
The project-resolution precedence doesn’t match what’s stated here (and in the PR description). The code initializes projectID from the --in/--project pointer and only falls back to urlProjectID if that’s empty, so flags override the URL. Either update the precedence logic to prefer urlProjectID when present, or adjust the comment/PR description to reflect the actual behavior to avoid confusion and unexpected bucket selection when both are provided.
| path := fmt.Sprintf("/buckets/%s/card_tables/columns/%d/color.json", resolvedProjectID, columnID) | ||
| if _, err := app.Account().Put(cmd.Context(), path, map[string]string{"color": color}); err != nil { | ||
| return convertSDKError(err) | ||
| } |
There was a problem hiding this comment.
This new raw PUT to a bucket-scoped /color.json endpoint is the core of the fix, but there’s no unit test asserting that the command actually issues a PUT to /buckets/<project>/card_tables/columns/<id>/color.json (and that URL-form args populate the bucket). Since cards_test.go already uses custom RoundTrippers for request-path assertions, consider adding a transport-backed test that captures the PUT path/body and validates the bucket segment is present.
|
Root-cause SDK fix opened: basecamp/basecamp-sdk#291 That PR adds Recommend keeping this PR as a stopgap until the SDK release lands, since customers (per card 9825845889) are blocked today. |
Summary
basecamp cards column colorwas sendingPUT /{account}/card_tables/columns/{id}/color.json(no bucket segment) and 404ing on every invocation. Reported in Basecamp card 9825845889.basecamp-sdk/gov0.7.3: the generated client atpkg/generated/client.gen.go:7757builds the path without/buckets/{bucket_id}. The SDK'spkg/basecamp/url-routes.json(lines 165, 183, 200) shows the same bucket-less pattern forGetCardColumn,SetCardColumnColor,EnableCardColumnOnHold,DisableCardColumnOnHold. Basecamp tolerates the bucket-less path for the read/update endpoints but rejects it for/color.jsonand/on_hold.json.coloronly —on-holdandno-on-holdhave the same problem and need separate fixes.Reproduction (verified live)
PUT /3642500/card_tables/columns/7103332776/color.json→ 404 Not FoundPUT /3642500/buckets/36395297/card_tables/columns/7103332776/color.json→ 200 OKFix
internal/commands/cards.go:newCardsColumnColorCmd(project *string)— accept the project pointer plumbed from thecardscommand group (cards.go:1274), matching the existing pattern used bycolumn show,column move, etc.--in/--projectflag > config > interactive (the same 8-line pattern repeated in 23 sites across 8 command files).app.Account().Put(ctx, "/buckets/<id>/card_tables/columns/<id>/color.json", body)— the existing raw API escape hatch already used bytodos.go:1157for similar SDK gaps. This bypasses the broken generated client path.Get(which works on the bucket-less path) so the response is still a typed*CardColumn.internal/commands/cards_test.go:TestCardsColumnColorShowsHelpcall site for the new signature.Verified live
basecamp cards column color 7103332776 --color blue --account 3642500 --in 36395297 -vv→PUT .../buckets/36395297/.../color.json→ 200, color updated.basecamp cards column color https://3.basecamp.com/.../columns/7103332776 --color blue→ resolves project from URL, hits correct path, returns 200.Test plan
make fmt-check vet test check-bare-groups check-skill-drift check-surfaceall pass locally.Follow-ups (separate, not blocking this PR)
basecamp-sdkfor the missingbucketIdpath parameter onSetCardColumnColor,EnableCardColumnOnHold,DisableCardColumnOnHold(and review whetherGetCardColumn/UpdateCardColumnshould also include it now that the API requires it for some sibling endpoints).newCardsColumnOnHoldCmdandnewCardsColumnNoOnHoldCmd— they 404 today for the same reason.app.Account().CardColumns().SetColor(...)call.🤖 Generated with Claude Code