feat: add Forgejo as a source control provider#3028
Conversation
Git status reported `unknown` for self-hosted hosts with no canonical hostname (Forgejo, self-hosted GitLab), so the UI showed generic "change request" wording instead of "pull request"/"merge request". Fall back to the registry's refined resolution (fj auth list / glab auth status) when static hostname detection can't classify the remote, so status terminology and icons match what PR operations actually target.
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
ApprovabilityVerdict: Needs human review This PR adds a complete new source control provider (Forgejo) with API client, authentication, credential management, and UI integration. New integrations of this scope warrant human review. Additionally, an open review comment identifies a potential bug where status provider detection and PR lookup may use inconsistent provider resolution. You can customize Macroscope's approvability policy. Learn more. |
- resolveRepository now applies the sole-logged-in-host fallback (like createRepository) so a bare `owner/repo` spec works in the add-project clone flow, which runs in a directory with no git remotes. - Match Forgejo host identities port-insensitively for credential lookup, host-list matching, and unknown-remote refinement, since `fj` keys its login store and `fj auth list` by bare hostname while remote URLs can carry a `:port`. API base URLs still keep the port.
Forgejo's pulls list cannot filter by head branch, so listPullRequests fetched the caller's `limit` rows and filtered in memory — with status passing limit=1, the branch's PR was almost always hidden behind unrelated recently-updated PRs. Fetch a full page (API max) and apply the caller's limit to the branch-filtered matches instead.
listPullRequests filtered only on head branch name, so an `owner:branch` selector could match a same-named branch from a different fork. Also match the head repository owner (falling back to the base repo owner for same-repo PRs) so cross-repository PR lookups resolve the intended fork.
parseForgejoRepositorySpec split on `/` only, so a pasted `https://host/owner/repo` (or `git@host:owner/repo`) clone URL produced a bogus host like `https:/host`. Detect scheme/`git@` specs and parse them via parseForgejoRemoteUrl instead.
resolveHostingProvider fell back to resolveHandle (origin-based) to refine self-hosted "unknown" remotes, so a logged-in Forgejo host on a non-origin upstream stayed unknown in git status. Add a registry refineRemoteProvider that refines a specific remote URL, and use it with the branch's resolved remote so status reflects that remote (still Forgejo-only).
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 1dfd06b. Configure here.
| const refined = yield* sourceControlProviders | ||
| .refineRemoteProvider({ cwd, remoteName, remoteUrl }) | ||
| .pipe(Effect.orElseSucceed(() => null)); | ||
| return refined?.kind === "forgejo" ? refined : detected; |
There was a problem hiding this comment.
Status provider mismatches PR lookup
Medium Severity
resolveHostingProvider can refine the branch’s tracking remote to forgejo and attach that as sourceControlProvider on local status, but findLatestPr still calls sourceControlProviders.resolve({ cwd }), which picks a provider from remotes (preferring origin) without the same branch-aware Forgejo refinement. Repos with a non-Forgejo origin and a Forgejo upstream can show Forgejo in the UI while open-PR lookup hits the wrong provider and misses the PR.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 1dfd06b. Configure here.
There was a problem hiding this comment.
Leaving this as-is intentionally.
Git status resolves the hosting provider from the current branch's tracking remote (branch-aware, with Forgejo refinement), while PR lookup (findOpenPr → resolve({ cwd })) resolves origin-first. These can only diverge in a multi-remote setup where origin points at a non-Forgejo host and the branch's upstream is a separate Forgejo remote.
In the common case — a Forgejo repo whose origin is the Forgejo instance — both paths resolve to Forgejo and agree. Fully reconciling the multi-remote case would require making the provider registry (and every PR operation) branch-aware, which changes remote selection for all providers; that's out of scope for this PR and noted as a potential follow-up.
apiUrl hardcoded https://, so plain-http (local/LAN) Forgejo instances had every REST call target the wrong scheme. Thread the scheme through the repository locator (from the remote/clone URL; https default for SSH and bare specs) and build API URLs from it.


Closes #2536.
Summary
Adds Forgejo (Gitea-compatible) as a first-class source control provider alongside GitHub, GitLab, Bitbucket, and Azure DevOps.
Forgejo has no canonical hostname — every instance is self-hosted — so the provider:
https://<host>/api/v1/...), mirroring the existing Bitbucket provider.fjCLI's login store:fj auth list(a CLI discovery spec) detects which self-hosted hosts are Forgejo, andkeys.jsonsupplies the per-host token.fjstays the tool you log in with; t3code never parses its human-readable output.keys.jsonholds every logged-in instance and the API base URL is resolved per-repository from the git remote.What's included
forgejoprovider kind, presentation ("pull request" terminology), and the official Forgejo logo (web + mobile).ForgejoKeyStore(readsfj'skeys.json),ForgejoApi(per-host REST client),forgejoPullRequests(schemas + normalization), andForgejoSourceControlProvider(wrapper +fjCLI discovery), with unit tests.host/owner/repo), and the Source Control settings list.fj auth listso the UI shows "pull request" and the Forgejo icon (scoped to Forgejo only).Notes
fjCLI for detection/auth (fj auth login <host>); the API calls themselves are over HTTP.Note
Medium Risk
Touches git hosting resolution and a new authenticated HTTP provider path; behavior is scoped so only Forgejo refinement changes unknown remotes, with broad test coverage.
Overview
Adds Forgejo as a first-class source control provider (alongside GitHub, GitLab, Bitbucket, and Azure DevOps), aimed at self-hosted instances with no single canonical hostname.
The server introduces a Forgejo stack: REST client (
ForgejoApi), credentials from thefjCLIkeys.json(ForgejoKeyStore), PR schemas/normalization, and a provider wired into the registry and server/ws layers. CLI discovery viafj auth listmarks logged-in hosts;refineRemoteProvideron the registry (used fromGitManager.resolveHostingProvider) upgrades remotes that static URL detection leaves asunknownto Forgejo when the host matches an authenticatedfjsession.Contracts and shared add the
forgejokind, PR terminology/icons, and heuristics for Codeberg/forgejoin hostnames while arbitrary self-hosted hosts stayunknownuntil refinement.Web, mobile, and client-runtime expose Forgejo in add-project clone (
host/owner/repo), command palette, source control settings, and shared readiness checks, with a Forgejo logo in UI components.Reviewed by Cursor Bugbot for commit f58be49. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add Forgejo as a source control provider
fjCLI.ForgejoApifor authenticated HTTP to Forgejo instances andForgejoKeyStorefor readingfjcredentials from the platform-specifickeys.jsonfile.ForgejoSourceControlProviderwired into theSourceControlProviderRegistry, including CLI-based discovery viafj auth listand refinement of unknown remotes to Forgejo when the host matches a logged-in account.sourceControl.ts; Codeberg is labeled separately from generic Forgejo hosts.ForgejoIconto web and mobile UIs and registersforgejoas a validSourceControlProviderKindin contracts, client runtime, and command palette.Macroscope summarized f58be49.