feat: add issue delete, pin, and unpin (task 0006)
Add the remaining simple issue mutations. `issue delete` hard-deletes via the DELETE endpoint and is deliberately not idempotent — a nonexistent issue yields ISSUE_NOT_FOUND rather than reporting success. `issue pin` and `issue unpin` read the current pin state (Gitea's pin_order field) and short-circuit to an idempotent no-op with an Already pinned/unpinned message when there is nothing to do.
This commit was merged in pull request #7.
This commit is contained in:
@@ -12,8 +12,21 @@ The remaining simple issue mutations: `issue delete`, `issue pin`, `issue unpin`
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [ ] `issue delete <n>` outputs `issue: { number, status: "deleted" }` on success
|
||||
- [ ] Deleting a nonexistent issue yields `ISSUE_NOT_FOUND` (exit 1), not idempotent success
|
||||
- [ ] `issue pin <n>` outputs `issue: { number, state, pinned }`; pinning an already-pinned issue returns early with `message: "Already pinned"` and exit 0
|
||||
- [ ] `issue unpin <n>` mirrors pin with `message: "Already unpinned"` on the no-op
|
||||
- [ ] Fixture-server tests cover delete success, delete-missing refusal, and both pin/unpin no-ops
|
||||
- [x] `issue delete <n>` outputs `issue: { number, status: "deleted" }` on success
|
||||
- [x] Deleting a nonexistent issue yields `ISSUE_NOT_FOUND` (exit 1), not idempotent success
|
||||
- [x] `issue pin <n>` outputs `issue: { number, state, pinned }`; pinning an already-pinned issue returns early with `message: "Already pinned"` and exit 0
|
||||
- [x] `issue unpin <n>` mirrors pin with `message: "Already unpinned"` on the no-op
|
||||
- [x] Fixture-server tests cover delete success, delete-missing refusal, and both pin/unpin no-ops
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
Pin state is read from the Gitea `pin_order` field, not a boolean: Gitea has no `pinned` flag on the issue struct, and records pin position as a positive integer (`0`/absent means unpinned).
|
||||
A small `isPinned` helper wraps this so the two commands don't repeat the check.
|
||||
The `state` field in the pin/unpin output is the issue's own open/closed state, taken from the fetched issue — pinning never changes it.
|
||||
|
||||
`issue delete` runs no confirmation prompt.
|
||||
The review's Risk axis rated the change High solely because of the irreversible hard delete and suggested a `--yes` guard, but this is an agent-facing CLI with structured TOON output where interactive prompts don't fit, and the spec deliberately specifies a hard, non-idempotent delete without one.
|
||||
Left unguarded by design; the destructiveness is inherent to the operation, not a defect.
|
||||
|
||||
`issuePin` and `issueUnpin` are near-identical mirrors (flagged as a judgement-call duplication by the Standards axis).
|
||||
Kept as two functions per the repo's established one-function-per-subcommand convention, which the existing `issueClose`/`issueReopen` pair already follows.
|
||||
|
||||
Reference in New Issue
Block a user