refactor!: Pass issue request by value and split CreateIssueRequest from IssueRequest#4396
refactor!: Pass issue request by value and split CreateIssueRequest from IssueRequest#4396jvm986 wants to merge 9 commits into
CreateIssueRequest from IssueRequest#4396Conversation
…dit` Towards google#3644. BREAKING CHANGE: `IssuesService.Create` and `IssuesService.Edit` now take `IssueRequest` by value instead of by pointer.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #4396 +/- ##
=======================================
Coverage 97.52% 97.52%
=======================================
Files 193 193
Lines 19668 19668
=======================================
Hits 19182 19182
Misses 268 268
Partials 218 218 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
gmlewis
left a comment
There was a problem hiding this comment.
Thank you, @jvm986!
LGTM.
Awaiting second LGTM+Approval from any other contributor to this repo before merging.
cc: @stevehipwell - @alexandear - @Not-Dhananjay-Mishra - @JamBalaya56562
Oh, and @jvm986 and @JamBalaya56562 - feel free to "cc:" each other on each PR to be extra careful that work is not duplicated.
|
What are your thoughts on the
|
I think there was a discussion for #4382 where the change of name was deemed valuable, so I think we should also address that here in the breaking change PR to remain consistent. Thank you for bringing this up! I appreciate it. |
Towards google#3644. BREAKING CHANGE: `IssuesService.Create` now takes a dedicated `CreateIssueRequest` with a required non-pointer `Title`, instead of the shared `IssueRequest`. The create and edit operations have different request contracts: the create API requires `title` and does not accept `state`/`state_reason`, whereas edit treats all fields as optional. The new `CreateIssueRequest` enforces the required `Title` at compile time and drops the edit-only fields. `CreateIssueRequest.Labels` and `.Assignees` use `[]string` (not `*[]string`), since an explicit empty array is only meaningful for edit.
| // IssueRequest represents a request to edit an issue. | ||
| // It is separate from Issue above because otherwise Labels | ||
| // and Assignee fail to serialize to the correct JSON. | ||
| type IssueRequest struct { |
There was a problem hiding this comment.
Can we update IssueRequest struct too.
It has one missing field duplicate_issue_id and we should use []string instead of *[]string for Labels and Assignees
There was a problem hiding this comment.
Nice find on duplicate_issue_id, will add it.
Regarding Labels and Assignees the logic here is that the update endpoint treats "labels": [] as "clear all labels" (distinct from omitting the field which leaves them unchanged). []string isn't able to distinguish between omission and an explicit empty array.
There was a problem hiding this comment.
@gmlewis could you help me with this? I assumed that we don't use *[]buildin in this repo.
Regarding
LabelsandAssigneesthe logic here is that the update endpoint treats"labels": []as "clear all labels" (distinct from omitting the field which leaves them unchanged).[]stringisn't able to distinguish between and an explicit empty array.
omitzero seems like a good fit here instead of omitempty, since it omits only nil slices while preserving an explicit empty slice.
There was a problem hiding this comment.
omitzeroseems like a good fit here instead ofomitempty, since it omits onlynilslices while preserving an explicit empty slice.
Yes, exactly right, @Not-Dhananjay-Mishra - this is what omitzero is for. So we can finally get rid of the *[]string, change it to []string and then use omitzero on it so that nil is different from []string{}.
There was a problem hiding this comment.
Thanks @gmlewis. @jvm986, you can change
*[]stringto[]stringforLabelsandAssignees, and useomitzeroinstead ofomitempty.
Yes, please, and just be absolutely sure to include a table-driven unit test where BOTH nil and []string{} are passed to ensure that the generated JSON matches our expections, and preferrably add a comment that explains when to use one versus the other. Thank you, @jvm986!
| // | ||
| //meta:operation PATCH /repos/{owner}/{repo}/issues/{issue_number} | ||
| func (s *IssuesService) Edit(ctx context.Context, owner, repo string, number int, body *IssueRequest) (*Issue, *Response, error) { | ||
| func (s *IssuesService) Edit(ctx context.Context, owner, repo string, number int, body IssueRequest) (*Issue, *Response, error) { |
There was a problem hiding this comment.
Can we rename this to Update? as API docs mentioned it as "Update an issue"
There was a problem hiding this comment.
Makes sense to me, will update after feedback from others.
There was a problem hiding this comment.
Makes sense to me, will update after feedback from others.
SGTM. Thank you, @Not-Dhananjay-Mishra and @jvm986!
I figure that while we are actually breaking the API, we should always attempt to make it as easy-to-understand and easy-to-use as possible, and this seems to fit into that category. 😄
Towards google#3644. The update-an-issue endpoint accepts `duplicate_issue_id`, which is required when `state_reason` is `duplicate`. Add the field to `IssueRequest` and update the `StateReason` comment to list the `duplicate` and `reopened` values.
IssueRequest by value in Issues.Create and Issues.EditCreateIssueRequest from IssueRequest
Towards google#3644. BREAKING CHANGE: `IssuesService.Edit` is renamed to `IssuesService.Update`. The method name now matches the underlying "update an issue" endpoint and GitHub's own naming, aligning it with the rest of the service
Towards google#3644. BREAKING CHANGE: `IssueRequest.Labels` and `IssueRequest.Assignees` change from `*[]string` to `[]string`. The update endpoint distinguishes omitting a field (leave unchanged) from sending an empty array (clear all). `[]string` with `omitzero` captures.
| // StateReason can be 'completed' or 'not_planned'. | ||
| StateReason *string `json:"state_reason,omitempty"` | ||
| type CreateIssueRequest struct { | ||
| // Title is required when creating an issue. |
There was a problem hiding this comment.
This comment can be removed.
| // | ||
| //meta:operation PATCH /repos/{owner}/{repo}/issues/{issue_number} | ||
| func (s *IssuesService) Edit(ctx context.Context, owner, repo string, number int, body *IssueRequest) (*Issue, *Response, error) { | ||
| func (s *IssuesService) Update(ctx context.Context, owner, repo string, number int, body IssueRequest) (*Issue, *Response, error) { |
There was a problem hiding this comment.
Let's rename this as well:
| func (s *IssuesService) Update(ctx context.Context, owner, repo string, number int, body IssueRequest) (*Issue, *Response, error) { | |
| func (s *IssuesService) Update(ctx context.Context, owner, repo string, number int, body UpdateIssueRequest) (*Issue, *Response, error) { |
There was a problem hiding this comment.
Good call, as it's a breaking change anyway.
Towards: google#3644 Remove redundant comment.
BREAKING CHANGE:
IssueService.Editis renamed toIssueService.Updateto match the underlying "update an issue" endpoint.IssuesService.Createnow takes a dedicatedCreateIssueRequestby value (with a required non-pointerTitle), andIssuesService.UpdatedtakesIssueRequestby value instead of by pointer.Towards #3644.