Commit 29634da
Fix delete:true on issue fields by calling deleteIssueFieldValue mutation (#2755)
* Fall back to REST DELETE when the PATCH can't carry an issue field clear
The dotcom REST update endpoint uses set semantics for issue_field_values:
sending {"issue_field_values": [...]} overwrites the whole list, and
anything not in the new list is treated as a deletion. UpdateIssue
already exploits this via merge-and-filter — delete:true on a field
removes it from the kept list and the server clears it as a side effect.
That breaks for one specific case: when the kept list ends up empty
(e.g. you're deleting the only remaining field value, or every field in
one call), go-github's omitempty tag on
`IssueRequest.IssueFieldValues` strips the empty slice from the JSON
body. The dotcom REST handler's top-level
`if data.include?(ISSUE_FIELD_VALUES)` guard then short-circuits — the
key isn't in the payload, so the whole block is skipped and the field
keeps its old value. The MCP tool returns success regardless, so a
coding agent would happily report the field as cleared.
Detect this case in UpdateIssue and fall back to the dedicated REST
DELETE endpoint per field: DELETE /repos/{owner}/{repo}/issues/{number}/
issue-field-values/{field_id}. The endpoint is idempotent, takes the
integer field ID (no GraphQL node ID needed), and is the same one the
public OpenAPI documents.
Empirical confirmation on #2756:
- Set Priority=P1 via REST
- Before the fix: MCP issue_write delete:true returns success, PATCH body
on the wire is literally {}, Priority remains P1 (silent no-op).
- After the fix: MCP issue_write delete:true returns success, PATCH body
is still {}, but the follow-up DELETE clears the field. Priority is
cleared as expected.
Three new tests in issues_delete_test.go cover:
- The omitempty contract (so we know if go-github ever drops the tag)
- The 1-of-1 fallback path (PATCH body has no issue_field_values, DELETE
fires)
- The N-1 set-semantics path (kept list is non-empty, PATCH alone
handles it, no DELETE call)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Address review: handle delete-absent-field and DELETE partial failures
Two issues surfaced in code review of the original delete fix:
1. Asking to delete a field that isn't set on the issue used to be a
silent no-op (PATCH body is {} after omitempty stripping, server
skips the issue_field_values block, tool returns success). The fix
turned it into a hard error because the fallback DELETE loop fires
unconditionally for every field ID in fieldIDsToDelete, and the
dotcom DELETE endpoint returns 404 when the field has no value to
delete. This breaks idempotent 'ensure field X is cleared' callers
that may re-run the same delete on a field that's already been
cleared.
Fix: before queueing the fallback DELETEs, filter
fallbackDeleteFieldIDs down to IDs that actually appeared in the
existing field values. This preserves the pre-fix silent-no-op
behaviour and avoids a guaranteed 404.
2. The DELETE loop returned on the first error. If a caller asks to
clear three fields and the second fails (transient 5xx, rate limit,
etc.), the first is gone, the third is never attempted, and the
user gets a generic error with no indication of which field failed
or which had already succeeded. This is unrecoverable from the
caller side.
Fix: continue on per-field errors, accumulate the failed and
succeeded IDs, and return a single aggregated error naming both
sets so callers can retry the right fields.
Tests:
- Test_UpdateIssue_DeleteAbsentFieldIsNoOp: existing field values is
empty, fieldIDsToDelete=[101]. Asserts no DELETE call fires (the
mock returns 404 if it does, which would fail the test) and the
tool returns success.
- Test_UpdateIssue_DeleteFallbackContinuesOnPartialFailure: three
fields exist, all three are deleted. Mock returns 500 for the
middle DELETE, 204 for the others. Asserts all three DELETEs
fired (the middle failure didn't short-circuit the third) and the
error result names failed=[202] and cleared=[101 303].
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Slim down code comments in delete-fix region
Trim the doc comments on UpdateIssue's omitempty-trap region + test
file to the bare minimum needed to understand the non-obvious behaviour
(why the DELETE fallback exists, why we filter to existing IDs, why
errors are aggregated). Drop restated context and step-by-step
explanations.
No behaviour change.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>1 parent 067756a commit 29634da
3 files changed
Lines changed: 499 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
66 | 66 | | |
67 | 67 | | |
68 | 68 | | |
| 69 | + | |
69 | 70 | | |
70 | 71 | | |
71 | 72 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2148 | 2148 | | |
2149 | 2149 | | |
2150 | 2150 | | |
| 2151 | + | |
| 2152 | + | |
| 2153 | + | |
| 2154 | + | |
2151 | 2155 | | |
2152 | | - | |
2153 | | - | |
2154 | | - | |
| 2156 | + | |
| 2157 | + | |
2155 | 2158 | | |
2156 | 2159 | | |
2157 | 2160 | | |
| |||
2170 | 2173 | | |
2171 | 2174 | | |
2172 | 2175 | | |
2173 | | - | |
| 2176 | + | |
| 2177 | + | |
| 2178 | + | |
| 2179 | + | |
| 2180 | + | |
| 2181 | + | |
| 2182 | + | |
| 2183 | + | |
| 2184 | + | |
| 2185 | + | |
| 2186 | + | |
| 2187 | + | |
| 2188 | + | |
| 2189 | + | |
| 2190 | + | |
| 2191 | + | |
2174 | 2192 | | |
2175 | 2193 | | |
2176 | 2194 | | |
| |||
2191 | 2209 | | |
2192 | 2210 | | |
2193 | 2211 | | |
| 2212 | + | |
| 2213 | + | |
| 2214 | + | |
| 2215 | + | |
| 2216 | + | |
| 2217 | + | |
| 2218 | + | |
| 2219 | + | |
| 2220 | + | |
| 2221 | + | |
| 2222 | + | |
| 2223 | + | |
| 2224 | + | |
| 2225 | + | |
| 2226 | + | |
| 2227 | + | |
| 2228 | + | |
| 2229 | + | |
| 2230 | + | |
| 2231 | + | |
| 2232 | + | |
| 2233 | + | |
| 2234 | + | |
| 2235 | + | |
| 2236 | + | |
| 2237 | + | |
| 2238 | + | |
| 2239 | + | |
| 2240 | + | |
| 2241 | + | |
| 2242 | + | |
| 2243 | + | |
| 2244 | + | |
| 2245 | + | |
| 2246 | + | |
| 2247 | + | |
| 2248 | + | |
2194 | 2249 | | |
2195 | 2250 | | |
2196 | 2251 | | |
| |||
0 commit comments