Create the forgejo-client gem for the Forgejo REST API #855
Labels
No labels
P0
P1
P2
P3
bug
category/code-change
category/cross-repo
category/eval-run
category/investigation
category/no-test-target
category/owner-ruling
category/prose-artifact
category/recurring-chore
category/structure
category/umbrella
crc-refactor
create
delete
enhancement
filed-by/agent
filed-by/user
frozen
lint-rule
needs-info
needs-triage
next
plugin/cc-architect
plugin/os
plugin/os-adr
plugin/os-aidd-lint
plugin/os-backlog
plugin/os-context
plugin/os-doc-hygiene
plugin/os-sdlc
plugin/os-vault
project/cc-os
ready-for-agent
ready-for-human
recurring
review
rule-proposal
update
waiting
wayfinder:grilling
wayfinder:map
wayfinder:map
wayfinder:research
wayfinder:task
wayfinder:task
wontfix
worklist/deviations
worklist/lint-rule
worklist/new-implement-build
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
jared/cc-os#855
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
Problem
ADR-0256 moves the Forgejo tracker backend from the
teaCLI to the Forgejo REST API. os-backlog and os-sdlc both need the same small client, and neither plugin may depend on the other. No such client exists yet.Reproduce
n/a: new component.
Approach
Create a new gem
forgejo-clientin its own repository,~/dev/forgejo-client, with a private Forgejo remote. It usesNet::HTTPfrom the standard library and has no runtime dependencies. It covers only the endpoints that os-backlog and os-sdlc use today (all under/api/v1):issue(slug, number)GET /repos/{o}/{r}/issues/{index}issues(slug, state: "open")GET /repos/{o}/{r}/issues?state=&type=issues(all pages)create_issue(slug, title:, body:, labels: [])POST /repos/{o}/{r}/issues(label names resolved to IDs)update_issue(slug, number, **fields)PATCH /repos/{o}/{r}/issues/{index}(title,body,state,assignees)labels(slug)GET /repos/{o}/{r}/labelscomments(slug, number)GET /repos/{o}/{r}/issues/{index}/commentsadd_comment(slug, number, body)POST /repos/{o}/{r}/issues/{index}/commentsadd_labels(slug, number, names)POST /repos/{o}/{r}/issues/{index}/labels(names resolved to IDs)remove_label(slug, number, name)DELETE /repos/{o}/{r}/issues/{index}/labels/{id}Each method returns parsed JSON (Hash or Array). A non-2xx response raises
Forgejo::Errorwith the HTTP status and the response message. The client takeshost:andtoken:. It never reads the environment; the caller passesENV.fetch("FORGEJO_TOKEN"). Tests use webmock; no test calls a real server.Required work:
Rejected: generate a full client from
/swagger.v1.jsonwith api-wrapper (ADR-0256: large and mostly unused).Acceptance criteria
issue("jared/cc-os", 845)runs, then it returns that issue's number, title, body, state, and labels.--label, whencreate_issueruns, then the request body is JSON and carries the text unchanged, and the method returns the new issue'snumberandhtml_url.create_issueoradd_labelsruns, then the request carries the matching label IDs.create_issueruns, then it raises an error that names the missing label and sends no create request.issuesruns, then it returns the issues from every page.Forgejo::Errorwith the status and the server message.Authorization: token <token>and goes tohttps://<host>/api/v1/....Owner sketch
Non-goals
Origin
issues createhas no--output json) ← DESIGN: ADR-0123, now amended by ADR-0256.Work started: building the gem locally at ~/dev/forgejo-client (TDD). No remote yet.
Status 2026-09-30: gem built locally at ~/dev/forgejo-client, commit 162daf7 (no remote). 7 runs, 18 assertions, 0 failures; rubocop clean. Live read test returned HTTP 401 (the FORGEJO_TOKEN value is not a valid token on forgejo.swansoncloud.com); waiting for a new token.
Defect found in the live test, must be fixed before any plugin uses the gem: on 401 Forgejo puts token material in the response body ("task with token ..."), and
Connection#failure_messagecopies that body into theForgejo::Errormessage. For 401 and 403, the error message must carry only the status and a fixed text, never the server body. Also still open: tests forupdate_issueandremove_label, and Net::HTTP timeouts.--label test: this comment starts with a flag-like word and was posted by forgejo-client (POST /issues/855/comments). Live checks 2026-09-30: issue, labels (41), issues (131, paginated), comments, add_comment all passed with the new FORGEJO_TOKEN. Gem commits 162daf7, 3ec5a02 (401/403 bodies never echoed; 10 s timeouts). Open before plugins adopt it: a Forgejo remote for the gem, and how plugins load it.
Resolution
Done: The Forgejo REST client exists as the generated forgejo-api gem (485 Forgejo 16.0.5 operations) in the private repo jared/forgejo-api, replacing the hand-written forgejo-client. 401/403 exception messages carry no server text. ADR-0257 records the change.
Evidence: forgejo-api commit a9ad21d pushed to ssh://git@forgejo.swansoncloud.com:2222/jared/forgejo-api.git (ls-remote main = a9ad21d); 731 runs, 0 failures, 7 skips (integration, no cassettes); rubocop 0 offenses; live: repo created and read back through the gem (me.create_repo, repo.get private=true, 404 mapped to NotFoundError); cc-os ADR-0257 commit
b68750db.Follow-ups: Record forgejo-api integration cassettes: filed on jared/forgejo-api #1. ~/dev/forgejo-client retirement: left to the user (local-only repo, deletion is irreversible). Adoption: #856, #858 (existing).