feat: add issue edit, close, and reopen (task 0005) #6
Reference in New Issue
Block a user
Delete Branch "task-0005-issue-edit-close-reopen"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Task:
.claude/tasks/0005-issue-edit-close-reopen.mdSummary
Implements the issue state-transition mutations
issue edit,issue close, andissue reopen.issue edit—--title,--body/--body-file,--add-label/--remove-label,--add-assignee/--remove-assignee,--milestone. Label mutations use Gitea's dedicated additive/removal endpoints (names added directly, removals resolved to IDs, a 404 for an unapplied label treated as silent success); assignees use fetch-then-patch (ADR 0007). Title/body/milestone and the recomputed assignee list travel in one PATCH; name resolution runs before any mutation. Outputsedited: { number, status: "ok" }.issue close— PATCHesstate: "closed"; optional--commentis posted after the close with its failure surfaced rather than swallowed. Already-closed short-circuits withmessage: "Already closed".issue reopen— PATCHesstate: "open". Already-open short-circuits withmessage: "Already open".All acceptance criteria are met. Deviations, all recorded in the task file's Implementation Notes:
issue: { number, state, message }), mirroring gh-axi, since the spec's action-block departure is scoped to the success path only.--add/--removelabel and assignee flags are repeatable (matchingissue create's--label).VALIDATION_ERRORforissue editinvoked with no changes (documented in--help) — the spec left this case unspecified.getIssuehelper now used by view/edit/close/reopen (from review).Review
Overall: Medium (worst factor: Sensitive domain)
src/commands/issue.tsplus three new test files; only adds a dispatch case, no existing callers touched.Unaddressed findings
issueCloseandissueReopenare near-identical mirror images (read state → short-circuit → PATCH → render). Left as two functions — the per-subcommand form is the file's existing idiom and stays readable; a sharedsetIssueStatecore was judged not worth the indirection.All other review findings (the repeated fetch-issue block, comment density on the state-precheck, the missing
--body-fileedit test) were fixed and are in the diff. Spec review found no defects.Implement the issue state-transition mutations: - issue edit: --title, --body/--body-file, --add-label/--remove-label, --add-assignee/--remove-assignee, --milestone. Label mutations use Gitea's dedicated additive/removal endpoints (names added directly, removals resolved to IDs, unapplied-label 404 as silent success); assignees use fetch-then-patch (ADR 0007); title/body/milestone and the recomputed assignee list travel in one PATCH. Outputs edited: {number, status: ok}. - issue close: PATCHes state closed, optional --comment posted after with its failure surfaced; already-closed short-circuits with Already closed. - issue reopen: PATCHes state open; already-open short-circuits with Already open. Extract a shared getIssue helper used by view/edit/close/reopen.