feat(labels): repo label CRUD across CLI, MCP, and OpenCode #42
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/labels"
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?
Summary
listLabels,getLabel,createLabel,updateLabel,deleteLabel(plus theresolveLabelIdhelper).forgejoctl label {list,view,create,update,delete}.list_labels,get_label,create_label,update_label,delete_label.tool({})entries.LabelView { id, name, color, description }— upstreamexclusive,is_archived,urldeliberately omitted.Why
create_issue.labels(and thelist_issuesfilter); there is no way to manage the repo's label catalogue itself.fj,fgj). The newresolveLabelIdhelper does the name → id lookup once per call so the user never has to know the internal id.LabelSummaryView/LabelDetailView): the four fields we surface fit one view; YAGNI.--forceupsert, random color palette: deferrable. YAGNI.--coloragainst^#[0-9a-fA-F]{6}$: rejected. The API returns a clear 422; client-side validation duplicates policy.Verification
bun run lintbun run typecheckbun run testbun run build./dist/forgejoctl helplabelsubcommands./dist/forgejoctl label list(live)GET /repos/{owner}/{repo}/labelsCI runs the same gate plus
e2e-plugin-load(per.forgejo/workflows/ci.yaml).Out of scope
create_issue.labels, resolved via the existingresolveLabelIdshelper)./repos/{owner}/{repo}/label/templates).--forceupsert, random color palette, case-insensitive name fallback — all trivial follow-ups if a real caller asks.LabelSummaryView/LabelDetailViewsplit,exclusive/isArchived/urlfields — YAGNI; the four-field view matches both reference CLIs.Five new core operations plus a name→id resolver, all identified by label name (mirrors the reference CLIs 'fj' and 'fgj'): - listLabels: GET /repos/{owner}/{repo}/labels with optional sort, page, limit query params. - getLabel: name → resolveLabelId → GET /labels/{id}, returns LabelView. - createLabel: POST /labels with name, color (required) and optional description. - updateLabel: name → resolveLabelId → PATCH /labels/{id} with any subset of new_name, color, description. - deleteLabel: name → resolveLabelId → DELETE /labels/{id}. LabelView exposes id, name, color, description only; the upstream exclusive/is_archived/url fields are dropped to match the reference CLIs and to honour YAGNI. resolveLabelId lives alongside the existing resolveLabelIds helper for issue-side multi-name resolution. Issue-side label handling (list_issues filter, create_issue.labels) is unchanged.Wires the five new core operations through every adapter: - CLI: forgejoctl label {list,view,create,update,delete} with positional name for view/delete and --name/--color/--new-name/ --description flags for create/update. New argv branches in parseFlags (--color, --description, --new-name); new dispatch block mirroring the tag/release subcommand shape. - MCP server: list_labels, get_label, create_label, update_label, delete_label tools with JSON Schema inputs that mirror the existing issue/release tool contracts. Name is the primary identifier everywhere; color is the 6-char hex without '#' (no client-side validation, per the decision in the plan). - OpenCode plugin: matching tool({}) entries with the established description template ("Use when … — don't use when …"). The default-export test enumerates the new tools alphabetically. docs/GLOSSARY.md gains a Label entry documenting the name-first identifier convention and noting that issue-side label attach is unchanged.