feat(workitems): add json tags to WorkItem to render the JSON shape explicit
Closes gitlab-org/cli#8498 (closed)
Part of the Work Items umbrella issue #2213.
When you marshal a WorkItem to JSON, the keys are Go field names like WebURL and NamespacePath. The nested author, assignees and labels already use snake_case, so one document mixes both styles. glab prints this struct as is for glab work-items create and update with --output json, so glab users see these keys today.
Now WorkItem and its parent, children and linked items marshal to snake_case keys like web_url, namespace_path and link_type. Nothing changes in how client-go talks to GitLab.
The glab part of the issue (removing glab's own copy of this struct) doesn't apply anymore. That copy came from gitlab-org/cli!3418 (closed), which was closed without merging.
- snake_case, not camelCase. Some other GraphQL-backed types in client-go use camelCase. But
WorkItemisn't a copy of the GraphQL response. client-go builds it from several parts of that response. snake_case matches the nested user and label objects, and it's what the issue asks for. - The type key is
type, notwork_item_type. In the REST API (and in the separate REST type in !3078 (merged)),work_item_typeis an object. Here it's only the type name, so I kepttypeas the issue asks. - Only the five EE-only fields (
status,color,health_status,iteration_id,weight) are left out when empty. On CE they would always benull. All other keys are always there, so an open item shows"closed_at": null. - There's one side effect. Go matches JSON keys to fields case-insensitively, so JSON saved with the old keys no longer fills multi-word fields like
WebURL. client-go never decodesWorkItemfrom JSON, so API calls are not affected. The Work Items API is marked experimental in client-go, so I usedfeatwithout!.
How I tested
I wrote a small Go program that fetches cli#8498 from gitlab.com with GetWorkItem (anonymous, read-only). It prints the result with json.MarshalIndent. I replaced the description and trimmed the output.
On main:
{
"ID": 197876139,
"IID": 8498,
"Type": "Issue",
"State": "OPEN",
"Status": "New",
...
"ClosedAt": null,
"WebURL": "https://gitlab.com/gitlab-org/cli/-/work_items/8498",
"Author": {
"id": 2935693,
"username": "phikai",
...
},
...
"Color": null,
"Confidential": false,
"DueDate": null,
"HealthStatus": null,
"IterationID": null,
...
"LinkedItems": null,
"MilestoneID": null,
"Parent": null,
"Children": null,
"StartDate": null,
"Weight": null
}On this branch:
{
"id": 197876139,
"iid": 8498,
"type": "Issue",
"state": "OPEN",
"status": "New",
...
"closed_at": null,
"web_url": "https://gitlab.com/gitlab-org/cli/-/work_items/8498",
"author": {
"id": 2935693,
"username": "phikai",
...
},
...
"confidential": false,
"due_date": null,
...
"linked_items": null,
"milestone_id": null,
"parent": null,
"children": null,
"start_date": null
}For the side effect in point 4, I unmarshalled {"ID":1,"WebURL":"https://x","Title":"t"} into a WorkItem. On main I got WebURL="https://x", and on this branch WebURL="". ID and Title are filled on both.
I added two unit tests. One checks the full key set and the nested shapes. The other checks that empty EE-only keys are left out and closed_at is null.
$ go test -count=1 -run 'WorkItem' -v .
...
ok gitlab.com/gitlab-org/api/client-go/v3 0.053sAll 84 tests and subtests matching WorkItem pass. gofumpt -l and go vet . printed nothing. golangci-lint, the -race tests and the generate scripts run in the pipeline.
Implemented with AI assistance; I reviewed and tested the changes.