Skip to content

feat: multi-forge support — adapter pattern + Gitea#2842

Open
afonsojramos wants to merge 27 commits intomainfrom
multi-platform-support
Open

feat: multi-forge support — adapter pattern + Gitea#2842
afonsojramos wants to merge 27 commits intomainfrom
multi-platform-support

Conversation

@afonsojramos
Copy link
Copy Markdown
Member

@afonsojramos afonsojramos commented May 6, 2026

Summary

Pivots Gitify from GitHub-only to multi-forge by introducing a ForgeAdapter contract (src/renderer/utils/forges/) that all forge-specific code routes through, then ports the existing GitHub modules into forges/github/ and lands a Gitea adapter as the first non-GitHub citizen. Account.forge is 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.md replaces the "no other forges" stance with a multi-forge policy and MAINTAINERS.md lists 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

@github-actions github-actions Bot added the enhancement New feature or enhancement to existing functionality label May 6, 2026
@afonsojramos afonsojramos linked an issue May 6, 2026 that may be closed by this pull request
@afonsojramos
Copy link
Copy Markdown
Member Author

@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.

afonsojramos and others added 20 commits May 6, 2026 16:02
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>
@setchy
Copy link
Copy Markdown
Member

setchy commented May 6, 2026

@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.

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 Settings, Accounts and Filters? My hunch is Accounts and Filters should be mostly OK, but some of the Settings config options are GitHub specific.

Also, do you think we should flag the non-GitHub forges as experimental for a period of time, or, just go for it!

@afonsojramos afonsojramos force-pushed the multi-platform-support branch from 37bf36f to 4d9e45f Compare May 6, 2026 14:03
Comment thread MAINTAINERS.md
Copy link
Copy Markdown
Member

@setchy setchy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@afonsojramos
Copy link
Copy Markdown
Member Author

afonsojramos commented May 6, 2026

what are your initial thoughts about the reorganizing required for Settings, Accounts and Filters?

Agree with your hunch.

  • Accounts: already adapter-driven after this PR: the “add new account” overlay iterates listAdapters(), dev-settings opens via getAdapter(account).getDeveloperSettingsUrl(account), and the scopes pill short-circuits for non-GitHub. Remaining GitHub-flavored bits (the scopes warning UI in particular) are inert for Gitea, which is fine for now.

  • Filters: structurally nothing to do: they operate on normalized GitifyNotification. The data is just narrower from Gitea today (we map all reasons to subscribed, owner type to User, etc.).

  • Settings: this is where it actually leaks. participating, detailedNotifications, markAsDoneOnOpen and markAsDoneOnUnsubscribe only mean something on GitHub. Three options as I see it:

  1. Keep them global, label as (GitHub) where relevant - smallest change.
  2. Hide them when no GitHub account is configured.
  3. Per-account overrides - I'd say it would be over-complicating the solution.
    I'd lean towards 1 for now and revisit when a third forge lands.

do you think we should flag the non-GitHub forges as experimental?

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 experimental: true flag on the adapter; capability-gating should already be the natural place to thread it through.

Comment thread README.md
Comment thread README.md Outdated
Comment thread src/renderer/utils/auth/scopes.ts
Comment thread CONTRIBUTING.md Outdated
@setchy setchy mentioned this pull request May 6, 2026
Comment thread src/renderer/utils/notifications/handlers/commit.ts Outdated
Comment thread src/renderer/utils/forges/gitea/adapter.ts Outdated
Comment thread src/renderer/context/App.tsx Outdated
Comment thread src/renderer/utils/forges/gitea/transform.ts Outdated
Comment thread src/renderer/utils/auth/utils.ts Outdated
- 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.
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 6, 2026

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or enhancement to existing functionality

Development

Successfully merging this pull request may close these issues.

docs: exploring multi git platform support Add compatibility with Gitea

3 participants