Spike: Gitea/Forgejo SDK vs thin hand-written client #3

Closed
opened 2026-10-01 21:55:15 -05:00 by deadstyle · 1 comment
Owner

Problem

The gitea adapter (Gitea + Forgejo) needs an HTTP client. Options are an existing SDK (Gitea's code.gitea.io/sdk/gitea, or a Forgejo SDK) or a thin hand-written client over the endpoints we actually use. This is a dependency decision that shapes the adapter, so it needs evidence before the adapter ticket starts.

Plan

Time-boxed (half a day). Opus decides via engineering-decision, with the result recorded as an ADR.

Evaluate each candidate against our instance:

  • coverage of the v1 operations (repos by activity, PRs, issues, merge, approve, comments, edit issue body, releases) and the Actions endpoints from the Actions spike
  • Forgejo compatibility (Forgejo has diverged from Gitea since v8; check version detection and any failures against our instance)
  • maintenance activity and release cadence
  • control over context.Context, timeouts, pagination and error types (our go-development rules require all four)
  • dependency weight

Build a throwaway prototype for the top candidate: list repos sorted by activity and list open PRs, run against git.bobparsons.dev.

Deliverable

docs/adr/0004-… with the decision, and the prototype findings in a comment. The prototype is not merged.

Context

  • ADR 0002 (one adapter for Gitea + Forgejo, version checks where they diverge).
  • go-development → Dependencies (new modules require an engineering decision) and I/O rules.
  • The Actions spike covers Actions endpoint availability; this spike only checks whether candidates support whatever exists.
## Problem The gitea adapter (Gitea + Forgejo) needs an HTTP client. Options are an existing SDK (Gitea's `code.gitea.io/sdk/gitea`, or a Forgejo SDK) or a thin hand-written client over the endpoints we actually use. This is a dependency decision that shapes the adapter, so it needs evidence before the adapter ticket starts. ## Plan Time-boxed (half a day). Opus decides via `engineering-decision`, with the result recorded as an ADR. Evaluate each candidate against our instance: - coverage of the v1 operations (repos by activity, PRs, issues, merge, approve, comments, edit issue body, releases) and the Actions endpoints from the Actions spike - Forgejo compatibility (Forgejo has diverged from Gitea since v8; check version detection and any failures against our instance) - maintenance activity and release cadence - control over `context.Context`, timeouts, pagination and error types (our `go-development` rules require all four) - dependency weight Build a throwaway prototype for the top candidate: list repos sorted by activity and list open PRs, run against git.bobparsons.dev. ## Deliverable `docs/adr/0004-…` with the decision, and the prototype findings in a comment. The prototype is not merged. ## Context - ADR 0002 (one adapter for Gitea + Forgejo, version checks where they diverge). - `go-development` → Dependencies (new modules require an engineering decision) and I/O rules. - The Actions spike covers Actions endpoint availability; this spike only checks whether candidates support whatever exists.
Author
Owner

🤖 Decided (Opus): thin hand-written client, recorded as ADR 0005 on spike/3-forgejo-client (60ce59c). MR to follow once SSH on :2222 is back.

Prototype findings against git.bobparsons.dev (Forgejo 16.0.5+gitea-1.22.0), all unauthenticated GETs:

gitea SDK v0.25.1 forgejo-sdk v3.0.0 thin client
v1 core ops incl. merge head_commit_id all all ~10 endpoints to write
Per-call context.Context no (client-wide SetContext) no yes
Actions on Forgejo jobs: cannot unmarshal array into ... ActionWorkflowJobsResponse; runs decode with empty head_sha/conclusion; gates pass wrongly (parses 16.0.5 as semver) runs only, no jobs/logs written to Forgejo's real shapes
Errors strings, status via resp same sentinels, errors.Is works
Modules added 15 48 0
Binary 10.26 MB 11.65 MB 9.36 MB

Both prototypes returned the same data (36 repos, PR #18 head 5f5b724, combined status success). Thin client: 93 lines including transport, four sentinels, pagination and two calls. Deciding reason: per-call cancellation is a hard rule in go-development, and neither SDK supports it. Prototype not merged, as planned.

🤖 Decided (Opus): thin hand-written client, recorded as ADR 0005 on `spike/3-forgejo-client` (60ce59c). MR to follow once SSH on :2222 is back. Prototype findings against git.bobparsons.dev (Forgejo 16.0.5+gitea-1.22.0), all unauthenticated GETs: | | gitea SDK v0.25.1 | forgejo-sdk v3.0.0 | thin client | |---|---|---|---| | v1 core ops incl. merge `head_commit_id` | all | all | ~10 endpoints to write | | Per-call `context.Context` | no (client-wide `SetContext`) | no | yes | | Actions on Forgejo | jobs: `cannot unmarshal array into ... ActionWorkflowJobsResponse`; runs decode with empty `head_sha`/`conclusion`; gates pass wrongly (parses 16.0.5 as semver) | runs only, no jobs/logs | written to Forgejo's real shapes | | Errors | strings, status via resp | same | sentinels, `errors.Is` works | | Modules added | 15 | 48 | 0 | | Binary | 10.26 MB | 11.65 MB | 9.36 MB | Both prototypes returned the same data (36 repos, PR #18 head 5f5b724, combined status success). Thin client: 93 lines including transport, four sentinels, pagination and two calls. Deciding reason: per-call cancellation is a hard rule in go-development, and neither SDK supports it. Prototype not merged, as planned.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
deadstyle/lazyforge#3
No description provided.