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.

  1. snake_case, not camelCase. Some other GraphQL-backed types in client-go use camelCase. But WorkItem isn'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.
  2. The type key is type, not work_item_type. In the REST API (and in the separate REST type in !3078 (merged)), work_item_type is an object. Here it's only the type name, so I kept type as the issue asks.
  3. Only the five EE-only fields (status, color, health_status, iteration_id, weight) are left out when empty. On CE they would always be null. All other keys are always there, so an open item shows "closed_at": null.
  4. 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 decodes WorkItem from JSON, so API calls are not affected. The Work Items API is marked experimental in client-go, so I used feat without !.

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.053s

All 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.

Edited by Hamza Hassanain

Merge request reports

Loading
Loading