Files
gitea-axi/.claude/tasks/0015-label-commands.md
alexion 0bf914cbdd
Some checks failed
CI / test (pull_request) Failing after 38s
feat: add label commands (task 0015)
2026-07-14 07:24:16 -04:00

3.7 KiB
Raw Blame History

spec, blocked-by
spec blocked-by
gitea-axi 0004-issue-create-and-comment

What to build

The label command group: label list, label create, label edit, label delete. label list takes --limit (default 500) and outputs a count line plus labels: [ { name } ]. label create requires --name and --color (hex without #; the # is prepended before the API call) with optional --description; it is idempotent via a case-insensitive existence check, reporting create: already_exists instead of failing. label edit <name> and label delete <name> resolve the positional name via the standard case-insensitive label lookup with VALIDATION_ERROR when not found. label delete is deliberately not idempotent — a nonexistent label is refused rather than reported as success (see ADR 0010).

Acceptance criteria

  • label list renders the count line and labels: block; empty repos get the explicit empty state
  • label create --name --color creates the label, prepending # to the color, and outputs created: ok + label: <name>
  • Creating an existing label (case-insensitive) outputs create: already_exists + the existing name, exit 0
  • label edit <name> applies --name/--color/--description and outputs edit: ok + the resulting name
  • label edit/label delete on an unknown name yield VALIDATION_ERROR (exit 2)
  • label delete <name> outputs delete: ok + label: <name>
  • Fixture-server tests cover create, idempotent re-create, edit, delete, and the unknown-name refusals

Implementation Notes

Built the label group in src/commands/label.ts, wired into src/cli.ts (dispatcher plus the two most-common entries in the top-level help), following the sibling issue/pr command patterns.

Deviations and decisions:

  • label edit requires at least one change. The spec/gh-axi reference leaves all edit flags optional, but sending an empty PATCH is a pointless call, so an edit with none of --name/--color/--description is refused with VALIDATION_ERROR — mirroring issue edit's "requires at least one change" guard for consistency within gitea-axi.
  • Resulting name for edit/create/delete comes from the API response (edited.name, label.name), not the input, so the reported name is the server's canonical echo (correct casing, and the unchanged original when --name was omitted).
  • create vs created output keys. The success key is created: ok and the idempotent-hit key is create: already_exists — two different top-level keys. This is spec-mandated (spec lines 342343) rather than the already: true shape the dependency no-ops use; kept verbatim to match the fixed contract.
  • Flat renderObject output shape. Added renderObject(item, help) to src/render.ts because the label create/edit/delete outputs are flat top-level fields (created: ok / label: <name>), which the sibling renderDetail (nests under a noun: block) cannot produce. This is the spec's output shape, not a new convention chosen freely.
  • Shared lookup + positional helpers (cleanups from review). Extracted findLabel/resolveLabel and a shared labelNotFound message into src/lookup.ts, reused by the existing resolveLabelIds; and extracted parseSinglePositional in src/flags.ts, now shared by parsePositionalNumber and the label name positionals, removing the duplicated count-check/error scaffolding.
  • label list uses a single-page fetch with --limit (default 500), reading X-Total-Count for the count line, rather than the exhaustive pagination resolveLabel/resolveLabelIds use; the spec asks only for --limit, and a repo with >500 labels is signalled by the count: N of T total line.