feat: multi-forge support — adapter pattern + Gitea#2842
Conversation
|
@setchy I think this is a good first implementation with two forges. Now, if we want to expand this, then the login flow needs a bit of a rework. I don't mind giving it a go, but I'd rather work on that after the core implementation is there. |
… when unsupported
Adds the first non-GitHub forge adapter under the new ForgeAdapter contract: client (fetch-based, no Octokit), types, transform, and adapter registration. Wires Gitea PAT login into the Login and Accounts routes, exposes the Gitea platform icon, and gates unsupported actions (mark-as-done, unsubscribe, GraphQL enrichment) via capability flags. Adapted from work originally proposed in #2787. Co-authored-by: bircni <75789103+bircni@users.noreply.github.com>
Awesome work @afonsojramos - love the adapter pattern (i was thinking similar, borrowing from Renovates platform implementation). I'm going to pull this branch down and run it locally. We can do this in follow up PRs, but what are you initial thoughts about the reorganizing required for Also, do you think we should flag the non-GitHub forges as |
37bf36f to
4d9e45f
Compare
setchy
left a comment
There was a problem hiding this comment.
Shall we add a section into README.md that outlines our forge adapter support matrix? we could convey current support and future potential forges perhaps
Agree with your hunch.
I’d say just go for it, given the simplicity of Gitea’s notification system. It’s nearly a strict subset of GitHub’s, so not much room to surprise people. Future forges with weirder shapes (GitLab todos, Bitbucket reviews) can land behind an |
- docs(contributing): list Gitea among currently supported forges
- fix(forges): reject unknown forge IDs during legacy account migration
rather than passing through any persisted value
- fix(forges/gitea): tighten PAT validator to /^[a-f0-9]{40}$/ to match
what gitea.com actually issues
- refactor(auth): coerce missing user.name to null instead of casting
the field to a wider type
- refactor(types): make GitifyNotification.display optional and drop
the `undefined as unknown as ...` cast in both forge transforms;
UI components guard or use optional chaining
- refactor(forges): relocate notification handlers under
forges/github/handlers since they are GitHub-shaped (Octokit GraphQL
fragment types). Detail enrichment becomes an optional adapter
method (`enrichNotifications?`) so the shared notification
orchestrator stays adapter-agnostic, and the redundant
`capabilities.enrichment` flag is removed.
…itise persisted accounts
…invalidation through adapter
…dd toLink helper, cross-link adapters
|
Split GitifyNotification into RawGitifyNotification (pre-format, no display) and GitifyNotification (required display), with formatNotification as the single widening boundary. Threaded RawGitifyNotification through the pipeline (transform → filter → enrich → filter), adapters, handlers, filter modules, and loggers; UI components drop their ?.display?. guards. This is a good win since |
…at format boundary
…stays forge-agnostic
|



Summary
Pivots Gitify from GitHub-only to multi-forge by introducing a
ForgeAdaptercontract (src/renderer/utils/forges/) that all forge-specific code routes through, then ports the existing GitHub modules intoforges/github/and lands a Gitea adapter as the first non-GitHub citizen.Account.forgeis a required field with a one-shot legacy-state migration; capabilities (mark-as-done, unsubscribe, GraphQL enrichment) are surfaced per-adapter so unsupported actions hide gracefully instead of silently no-op'ing.CONTRIBUTING.mdreplaces the "no other forges" stance with a multi-forge policy andMAINTAINERS.mdlists per-forge owners (Gitea: @bircni and myself). Lint is clean and 944/944 tests pass; Gitea PAT login verified end-to-end against gitea.com.Note: Gitea's notification model is absurdly simple
Closes #2786