Skip to content

feat(field): read and write custom fields with per-type value coercion - #44

Open
timimsms wants to merge 1 commit into
mainfrom
feat/custom-fields
Open

feat(field): read and write custom fields with per-type value coercion#44
timimsms wants to merge 1 commit into
mainfrom
feat/custom-fields

Conversation

@timimsms

Copy link
Copy Markdown
Owner

Summary

Implements custom field read/write and adds a cu field command over it.

GetCustomFields and SetCustomFieldValue have been declared in internal/interfaces/api.go since the interface was written, with no implementation behind them. This adds those (plus RemoveCustomFieldValue) on api.Client and exposes:

cu field list [--list <id>]          # fields available on a list
cu field get <task-id> [field]       # values set on a task
cu field set <task-id> <field> <value>
cu field clear <task-id> <field>

Values are coerced per type rather than passed through as strings, which is the substance of the change — ClickUp expects epoch milliseconds for dates, option UUIDs for dropdowns, and an array of option UUIDs for labels. So names work on the command line:

$ cu field set 86dxbeqyt Machine "Chilastra,Sunrunner"
Set Machine on task 86dxbeqyt
$ cu field get 86dxbeqyt
name          type        id                                    value
Machine       labels      a258ab77-5866-4ee8-a83a-295fc614ab10  Chilastra, Sunrunner
Repo          url         a5013cb5-9244-49be-a6a2-90e1cc8a1d31  https://github.com/timimsms/cu
Last synced   date        43d99b00-1747-483c-824f-a887db7f3761  2026-08-22 04:00

Dates accept today, now, 2006-01-02, RFC3339, or epoch milliseconds.

Design choices worth reviewing:

  • Fields are resolved from the task's own list, so space- and folder-level fields resolve without the caller knowing where they were defined.
  • An ambiguous field name is an error, not a first match.
  • Unknown option names are rejected with the valid set listed.
  • Unsupported types refuse rather than guess. formula, rollup, manual_progress and friends return setting fields of type "manual_progress" is not supported — a silently wrong write is worse than a clear error.
$ cu field set 86dxbeqyt Machine Nonexistent
Error: no option "Nonexistent" on field "Machine" (available: Chilastra, Sunrunner, Aberama Gold, Rinzler)

Addresses PROJECT_SPEC §13 open question 1 ("Support ClickUp Custom Fields in JSON output?") — all four output formats share one row shape, so -o json gives {name, type, id, value}.

Tests

TestFindCustomField, TestCoerceCustomFieldValue, TestFormatCustomFieldValue cover every supported type, both resolution directions (name→id on write, id→name on read), and each rejection path. Set/get/clear round-trips were also exercised live against a real workspace.

Checklist

  • ./scripts/ci.sh passes locally — except errcheck, which reports the same 27 pre-existing findings on main, none in files this PR touches
  • Commit messages use conventional prefixes
  • CLI docs regenerated (cu docs markdown --dir docs/site/commands) and added to the mkdocs nav
  • Docs updated if user-facing behavior changed — README feature list and examples

Implements the GetCustomFields and SetCustomFieldValue methods that
internal/interfaces/api.go has declared since the interface was written, and
adds the `cu field` command over them: list, get, set, clear.

Values are coerced to the shape each type expects rather than passed through as
strings — epoch milliseconds for dates, resolved option ids for dropdowns and
labels — so `cu field set <task> Machine "Chilastra,Sunrunner"` works with
names. Unknown option names are rejected with the valid set; unsupported types
(formula, rollup, progress) refuse rather than guess, since a silently wrong
write is worse than a clear error.

Fields are resolved from the task's own list, so space- and folder-level fields
resolve without the caller knowing where they were defined. An ambiguous field
name is an error rather than a first match.

Addresses PROJECT_SPEC §13 open question 1.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014aqbmccWm1tqttmBUCR5rv
ClickUp: 86dxbeqyt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant