-
Notifications
You must be signed in to change notification settings - Fork 10
feat: add GitHub support #140
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: add GitHub support #140
Conversation
fabienfleureau
commented
Nov 19, 2025
- Introduce unified provider abstraction and models for GitLab/GitHub
- Implement GitHub provider (API client + webhooks) and extend GitLab provider
- Add approval & pipeline info (fetchApprovalInfo, UnifiedApprovalInfo, PR.pipeline)
- Improve review messages with pipeline/mergeable emojis and accurate approval counts
- Restore project threshold warnings and add GitHub project channel counting
|
Hello @M0nkeySan I tried to cherry-pick what I did to enable github support, maybe some changes are not necessary for MM context. |
3f8fc12 to
16f53c1
Compare
- Introduce unified provider abstraction and models for GitLab/GitHub - Implement GitHub provider (API client + webhooks) and extend GitLab provider - Add approval & pipeline info (fetchApprovalInfo, UnifiedApprovalInfo, PR.pipeline) - Improve review messages with pipeline/mergeable emojis and accurate approval counts - Restore project threshold warnings and add GitHub project channel counting
16f53c1 to
ddd1ff1
Compare
|
Hello @fabienfleureau, I will review your PR asap. In the mean time, can you fix the test failing in the pipeline ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This part (line 22) need to be adapted to handle github hook body :
const { merge_request, object_attributes, project } = req.body as {
merge_request: {
author_id: number;
iid: number;
};
object_attributes: { author_id: number; note: string; url: string };
project: GitlabProjectDetails;
};
This is payload I received for an issue comment webhook event :
{
"action": "created",
"issue": {
"url": "https://api.github.com/repos/M0nkeySan/homer/issues/1",
"repository_url": "https://api.github.com/repos/M0nkeySan/homer",
"labels_url": "https://api.github.com/repos/M0nkeySan/homer/issues/1/labels{/name}",
"comments_url": "https://api.github.com/repos/M0nkeySan/homer/issues/1/comments",
"events_url": "https://api.github.com/repos/M0nkeySan/homer/issues/1/events",
"html_url": "https://github.com/M0nkeySan/homer/pull/1",
"id": 3642028010,
"node_id": "PR_kwDONH_Bn860USOp",
"number": 1,
"title": "Automatic mr review",
"user": {
"login": "M0nkeySan",
"id": 10235926,
"node_id": "MDQ6VXNlcjEwMjM1OTI2",
"avatar_url": "https://avatars.githubusercontent.com/u/10235926?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/M0nkeySan",
"html_url": "https://github.com/M0nkeySan",
"followers_url": "https://api.github.com/users/M0nkeySan/followers",
"following_url": "https://api.github.com/users/M0nkeySan/following{/other_user}",
"gists_url": "https://api.github.com/users/M0nkeySan/gists{/gist_id}",
"starred_url": "https://api.github.com/users/M0nkeySan/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/M0nkeySan/subscriptions",
"organizations_url": "https://api.github.com/users/M0nkeySan/orgs",
"repos_url": "https://api.github.com/users/M0nkeySan/repos",
"events_url": "https://api.github.com/users/M0nkeySan/events{/privacy}",
"received_events_url": "https://api.github.com/users/M0nkeySan/received_events",
"type": "User",
"user_view_type": "public",
"site_admin": false
},
"labels": [
{
"id": 9675882250,
"node_id": "LA_kwDONH_Bn88AAAACQLo_Cg",
"url": "https://api.github.com/repos/M0nkeySan/homer/labels/homer-review",
"name": "homer-review",
"color": "DCEEF1",
"default": false,
"description": ""
}
],
"state": "open",
"locked": false,
"assignee": null,
"assignees": [],
"milestone": null,
"comments": 2,
"created_at": "2025-11-19T10:14:49Z",
"updated_at": "2025-11-19T10:18:17Z",
"closed_at": null,
"author_association": "OWNER",
"active_lock_reason": null,
"draft": false,
"pull_request": {
"url": "https://api.github.com/repos/M0nkeySan/homer/pulls/1",
"html_url": "https://github.com/M0nkeySan/homer/pull/1",
"diff_url": "https://github.com/M0nkeySan/homer/pull/1.diff",
"patch_url": "https://github.com/M0nkeySan/homer/pull/1.patch",
"merged_at": null
},
"body": null,
"reactions": {
"url": "https://api.github.com/repos/M0nkeySan/homer/issues/1/reactions",
"total_count": 0,
"+1": 0,
"-1": 0,
"laugh": 0,
"hooray": 0,
"confused": 0,
"heart": 0,
"rocket": 0,
"eyes": 0
},
"timeline_url": "https://api.github.com/repos/M0nkeySan/homer/issues/1/timeline",
"performed_via_github_app": null,
"state_reason": null
},
"comment": {
"url": "https://api.github.com/repos/M0nkeySan/homer/issues/comments/3551915836",
"html_url": "https://github.com/M0nkeySan/homer/pull/1#issuecomment-3551915836",
"issue_url": "https://api.github.com/repos/M0nkeySan/homer/issues/1",
"id": 3551915836,
"node_id": "IC_kwDONH_Bn87Tte88",
"user": {
"login": "M0nkeySan",
"id": 10235926,
"node_id": "MDQ6VXNlcjEwMjM1OTI2",
"avatar_url": "https://avatars.githubusercontent.com/u/10235926?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/M0nkeySan",
"html_url": "https://github.com/M0nkeySan",
"followers_url": "https://api.github.com/users/M0nkeySan/followers",
"following_url": "https://api.github.com/users/M0nkeySan/following{/other_user}",
"gists_url": "https://api.github.com/users/M0nkeySan/gists{/gist_id}",
"starred_url": "https://api.github.com/users/M0nkeySan/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/M0nkeySan/subscriptions",
"organizations_url": "https://api.github.com/users/M0nkeySan/orgs",
"repos_url": "https://api.github.com/users/M0nkeySan/repos",
"events_url": "https://api.github.com/users/M0nkeySan/events{/privacy}",
"received_events_url": "https://api.github.com/users/M0nkeySan/received_events",
"type": "User",
"user_view_type": "public",
"site_admin": false
},
"created_at": "2025-11-19T10:18:17Z",
"updated_at": "2025-11-19T10:18:17Z",
"body": "test",
"author_association": "OWNER",
"reactions": {
"url": "https://api.github.com/repos/M0nkeySan/homer/issues/comments/3551915836/reactions",
"total_count": 0,
"+1": 0,
"-1": 0,
"laugh": 0,
"hooray": 0,
"confused": 0,
"heart": 0,
"rocket": 0,
"eyes": 0
},
"performed_via_github_app": null
},
"repository": {
"id": 880787871,
"node_id": "R_kgDONH_Bnw",
"name": "homer",
"full_name": "M0nkeySan/homer",
"private": false,
"owner": {
"login": "M0nkeySan",
"id": 10235926,
"node_id": "MDQ6VXNlcjEwMjM1OTI2",
"avatar_url": "https://avatars.githubusercontent.com/u/10235926?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/M0nkeySan",
"html_url": "https://github.com/M0nkeySan",
"followers_url": "https://api.github.com/users/M0nkeySan/followers",
"following_url": "https://api.github.com/users/M0nkeySan/following{/other_user}",
"gists_url": "https://api.github.com/users/M0nkeySan/gists{/gist_id}",
"starred_url": "https://api.github.com/users/M0nkeySan/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/M0nkeySan/subscriptions",
"organizations_url": "https://api.github.com/users/M0nkeySan/orgs",
"repos_url": "https://api.github.com/users/M0nkeySan/repos",
"events_url": "https://api.github.com/users/M0nkeySan/events{/privacy}",
"received_events_url": "https://api.github.com/users/M0nkeySan/received_events",
"type": "User",
"user_view_type": "public",
"site_admin": false
},
"html_url": "https://github.com/M0nkeySan/homer",
"description": "Homer is a Slack bot intended to help you to easily share and follow Gitlab merge requests.",
"fork": true,
"url": "https://api.github.com/repos/M0nkeySan/homer",
"forks_url": "https://api.github.com/repos/M0nkeySan/homer/forks",
"keys_url": "https://api.github.com/repos/M0nkeySan/homer/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/M0nkeySan/homer/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/M0nkeySan/homer/teams",
"hooks_url": "https://api.github.com/repos/M0nkeySan/homer/hooks",
"issue_events_url": "https://api.github.com/repos/M0nkeySan/homer/issues/events{/number}",
"events_url": "https://api.github.com/repos/M0nkeySan/homer/events",
"assignees_url": "https://api.github.com/repos/M0nkeySan/homer/assignees{/user}",
"branches_url": "https://api.github.com/repos/M0nkeySan/homer/branches{/branch}",
"tags_url": "https://api.github.com/repos/M0nkeySan/homer/tags",
"blobs_url": "https://api.github.com/repos/M0nkeySan/homer/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/M0nkeySan/homer/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/M0nkeySan/homer/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/M0nkeySan/homer/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/M0nkeySan/homer/statuses/{sha}",
"languages_url": "https://api.github.com/repos/M0nkeySan/homer/languages",
"stargazers_url": "https://api.github.com/repos/M0nkeySan/homer/stargazers",
"contributors_url": "https://api.github.com/repos/M0nkeySan/homer/contributors",
"subscribers_url": "https://api.github.com/repos/M0nkeySan/homer/subscribers",
"subscription_url": "https://api.github.com/repos/M0nkeySan/homer/subscription",
"commits_url": "https://api.github.com/repos/M0nkeySan/homer/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/M0nkeySan/homer/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/M0nkeySan/homer/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/M0nkeySan/homer/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/M0nkeySan/homer/contents/{+path}",
"compare_url": "https://api.github.com/repos/M0nkeySan/homer/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/M0nkeySan/homer/merges",
"archive_url": "https://api.github.com/repos/M0nkeySan/homer/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/M0nkeySan/homer/downloads",
"issues_url": "https://api.github.com/repos/M0nkeySan/homer/issues{/number}",
"pulls_url": "https://api.github.com/repos/M0nkeySan/homer/pulls{/number}",
"milestones_url": "https://api.github.com/repos/M0nkeySan/homer/milestones{/number}",
"notifications_url": "https://api.github.com/repos/M0nkeySan/homer/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/M0nkeySan/homer/labels{/name}",
"releases_url": "https://api.github.com/repos/M0nkeySan/homer/releases{/id}",
"deployments_url": "https://api.github.com/repos/M0nkeySan/homer/deployments",
"created_at": "2024-10-30T11:07:28Z",
"updated_at": "2025-10-17T13:04:09Z",
"pushed_at": "2025-10-21T12:25:34Z",
"git_url": "git://github.com/M0nkeySan/homer.git",
"ssh_url": "[email protected]:M0nkeySan/homer.git",
"clone_url": "https://github.com/M0nkeySan/homer.git",
"svn_url": "https://github.com/M0nkeySan/homer",
"homepage": "",
"size": 2061,
"stargazers_count": 0,
"watchers_count": 0,
"language": "TypeScript",
"has_issues": false,
"has_projects": true,
"has_downloads": true,
"has_wiki": false,
"has_pages": false,
"has_discussions": false,
"forks_count": 0,
"mirror_url": null,
"archived": false,
"disabled": false,
"open_issues_count": 1,
"license": {
"key": "mit",
"name": "MIT License",
"spdx_id": "MIT",
"url": "https://api.github.com/licenses/mit",
"node_id": "MDc6TGljZW5zZTEz"
},
"allow_forking": true,
"is_template": false,
"web_commit_signoff_required": false,
"topics": [],
"visibility": "public",
"forks": 0,
"open_issues": 1,
"watchers": 0,
"default_branch": "main"
},
"sender": {
"login": "M0nkeySan",
"id": 10235926,
"node_id": "MDQ6VXNlcjEwMjM1OTI2",
"avatar_url": "https://avatars.githubusercontent.com/u/10235926?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/M0nkeySan",
"html_url": "https://github.com/M0nkeySan",
"followers_url": "https://api.github.com/users/M0nkeySan/followers",
"following_url": "https://api.github.com/users/M0nkeySan/following{/other_user}",
"gists_url": "https://api.github.com/users/M0nkeySan/gists{/gist_id}",
"starred_url": "https://api.github.com/users/M0nkeySan/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/M0nkeySan/subscriptions",
"organizations_url": "https://api.github.com/users/M0nkeySan/orgs",
"repos_url": "https://api.github.com/users/M0nkeySan/repos",
"events_url": "https://api.github.com/users/M0nkeySan/events{/privacy}",
"received_events_url": "https://api.github.com/users/M0nkeySan/received_events",
"type": "User",
"user_view_type": "public",
"site_admin": false
}
}
| { | ||
| text: { | ||
| type: 'plain_text', | ||
| text: 'Create a pipeline', | ||
| }, | ||
| value: injectActionsParameters( | ||
| 'review-create-pipeline', | ||
| projectId, | ||
| pullRequest.sourceBranch, | ||
| ), | ||
| }, | ||
| { | ||
| text: { | ||
| type: 'plain_text', | ||
| text: 'Rebase source branch', | ||
| }, | ||
| value: injectActionsParameters( | ||
| 'review-rebase-source-branch', | ||
| projectId, | ||
| pullRequest.iid, | ||
| ), | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should remove this 2 actions for Github because they are not implemented yet.
| // 'commented' state - treat as update | ||
| action = 'update'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it wanted to handle the commented state here ?
Because with this behaviour, we don't have the comments send to the slack thread.
|
Can't wait to see github support from my beloved Homer bot :) |
| */ | ||
|
|
||
| describe('UnifiedModels Type Definitions', () => { | ||
| it('should pass TypeScript compilation', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need this test?
|
Hi, I didn't have time to check your comment yet! I'l do it asap |