From 9d08063208e799fe0a29eaa6645d09cbffa40bba Mon Sep 17 00:00:00 2001 From: Aditya Kumar Kasaudhan <74228301+Aditya8840@users.noreply.github.com> Date: Fri, 21 Feb 2025 20:55:48 +0530 Subject: [PATCH] webhooks/github: Added support for issue transferred events. On transferring an issue to another repository, GitHub sends - a "transferred" event to the old repository's webhook URL, - and an "opened event", containing links to the old issue, to the new repository's webhook URL. This commit adds support for both events independently. Fixes: #33450. --- .../fixtures/issues__opened_via_transfer.json | 376 ++++++++++++++++++ .../github/fixtures/issues__transferred.json | 375 +++++++++++++++++ zerver/webhooks/github/tests.py | 18 + zerver/webhooks/github/view.py | 37 +- 4 files changed, 803 insertions(+), 3 deletions(-) create mode 100644 zerver/webhooks/github/fixtures/issues__opened_via_transfer.json create mode 100644 zerver/webhooks/github/fixtures/issues__transferred.json diff --git a/zerver/webhooks/github/fixtures/issues__opened_via_transfer.json b/zerver/webhooks/github/fixtures/issues__opened_via_transfer.json new file mode 100644 index 0000000000..4215583c2a --- /dev/null +++ b/zerver/webhooks/github/fixtures/issues__opened_via_transfer.json @@ -0,0 +1,376 @@ +{ + "action": "opened", + "issue": { + "url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/issues/4", + "repository_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp", + "labels_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/issues/4/labels{/name}", + "comments_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/issues/4/comments", + "events_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/issues/4/events", + "html_url": "https://github.com/CrisisCollab/admin-frontend-mvp/issues/4", + "id": 2855393943, + "node_id": "I_kwDOKm4p7M6qMdqX", + "number": 4, + "title": "Fixture collection", + "user": { + "login": "devaditya-k", + "id": 199350900, + "node_id": "U_kgDOC-HadA", + "avatar_url": "https://avatars.githubusercontent.com/u/199350900?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/devaditya-k", + "html_url": "https://github.com/devaditya-k", + "followers_url": "https://api.github.com/users/devaditya-k/followers", + "following_url": "https://api.github.com/users/devaditya-k/following{/other_user}", + "gists_url": "https://api.github.com/users/devaditya-k/gists{/gist_id}", + "starred_url": "https://api.github.com/users/devaditya-k/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/devaditya-k/subscriptions", + "organizations_url": "https://api.github.com/users/devaditya-k/orgs", + "repos_url": "https://api.github.com/users/devaditya-k/repos", + "events_url": "https://api.github.com/users/devaditya-k/events{/privacy}", + "received_events_url": "https://api.github.com/users/devaditya-k/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "labels": [], + "state": "open", + "locked": false, + "assignee": null, + "assignees": [], + "milestone": null, + "comments": 0, + "created_at": "2025-02-15T10:13:33Z", + "updated_at": "2025-02-15T10:35:45Z", + "closed_at": null, + "author_association": "NONE", + "type": null, + "sub_issues_summary": { + "total": 0, + "completed": 0, + "percent_completed": 0 + }, + "active_lock_reason": null, + "body": "Fixture collection.", + "reactions": { + "url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/issues/4/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/CrisisCollab/admin-frontend-mvp/issues/4/timeline", + "performed_via_github_app": null, + "state_reason": null + }, + "changes": { + "old_issue": { + "url": "https://api.github.com/repos/CrisisCollab/TestWebhook/issues/4", + "repository_url": "https://api.github.com/repos/CrisisCollab/TestWebhook", + "labels_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/issues/4/labels{/name}", + "comments_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/issues/4/comments", + "events_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/issues/4/events", + "html_url": "https://github.com/CrisisCollab/TestWebhook/issues/4", + "id": 2855384286, + "node_id": "I_kwDOM0_enM6qMbTe", + "number": 4, + "title": "Fixture collection", + "user": { + "login": "devaditya-k", + "id": 199350900, + "node_id": "U_kgDOC-HadA", + "avatar_url": "https://avatars.githubusercontent.com/u/199350900?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/devaditya-k", + "html_url": "https://github.com/devaditya-k", + "followers_url": "https://api.github.com/users/devaditya-k/followers", + "following_url": "https://api.github.com/users/devaditya-k/following{/other_user}", + "gists_url": "https://api.github.com/users/devaditya-k/gists{/gist_id}", + "starred_url": "https://api.github.com/users/devaditya-k/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/devaditya-k/subscriptions", + "organizations_url": "https://api.github.com/users/devaditya-k/orgs", + "repos_url": "https://api.github.com/users/devaditya-k/repos", + "events_url": "https://api.github.com/users/devaditya-k/events{/privacy}", + "received_events_url": "https://api.github.com/users/devaditya-k/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "labels": [], + "state": "open", + "locked": false, + "assignee": null, + "assignees": [], + "milestone": null, + "comments": 0, + "created_at": "2025-02-15T10:13:33Z", + "updated_at": "2025-02-15T10:33:12Z", + "closed_at": null, + "author_association": "NONE", + "sub_issues_summary": { + "total": 0, + "completed": 0, + "percent_completed": 0 + }, + "active_lock_reason": null, + "body": "Fixture collection.", + "reactions": { + "url": "https://api.github.com/repos/CrisisCollab/TestWebhook/issues/4/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/CrisisCollab/TestWebhook/issues/4/timeline", + "performed_via_github_app": null, + "state_reason": null + }, + "old_repository": { + "id": 860872348, + "node_id": "R_kgDOM0_enA", + "name": "TestWebhook", + "full_name": "CrisisCollab/TestWebhook", + "private": false, + "owner": { + "login": "CrisisCollab", + "id": 147498334, + "node_id": "O_kgDOCMqlXg", + "avatar_url": "https://avatars.githubusercontent.com/u/147498334?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/CrisisCollab", + "html_url": "https://github.com/CrisisCollab", + "followers_url": "https://api.github.com/users/CrisisCollab/followers", + "following_url": "https://api.github.com/users/CrisisCollab/following{/other_user}", + "gists_url": "https://api.github.com/users/CrisisCollab/gists{/gist_id}", + "starred_url": "https://api.github.com/users/CrisisCollab/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/CrisisCollab/subscriptions", + "organizations_url": "https://api.github.com/users/CrisisCollab/orgs", + "repos_url": "https://api.github.com/users/CrisisCollab/repos", + "events_url": "https://api.github.com/users/CrisisCollab/events{/privacy}", + "received_events_url": "https://api.github.com/users/CrisisCollab/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "html_url": "https://github.com/CrisisCollab/TestWebhook", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/CrisisCollab/TestWebhook", + "forks_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/forks", + "keys_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/teams", + "hooks_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/hooks", + "issue_events_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/issues/events{/number}", + "events_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/events", + "assignees_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/assignees{/user}", + "branches_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/branches{/branch}", + "tags_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/tags", + "blobs_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/statuses/{sha}", + "languages_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/languages", + "stargazers_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/stargazers", + "contributors_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/contributors", + "subscribers_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/subscribers", + "subscription_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/subscription", + "commits_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/contents/{+path}", + "compare_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/merges", + "archive_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/downloads", + "issues_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/issues{/number}", + "pulls_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/pulls{/number}", + "milestones_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/milestones{/number}", + "notifications_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/labels{/name}", + "releases_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/releases{/id}", + "deployments_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/deployments", + "created_at": "2024-09-21T11:50:28Z", + "updated_at": "2024-09-21T11:57:26Z", + "pushed_at": "2024-09-21T11:57:22Z", + "git_url": "git://github.com/CrisisCollab/TestWebhook.git", + "ssh_url": "git@github.com:CrisisCollab/TestWebhook.git", + "clone_url": "https://github.com/CrisisCollab/TestWebhook.git", + "svn_url": "https://github.com/CrisisCollab/TestWebhook", + "homepage": null, + "size": 2, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "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": 3, + "license": null, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "public", + "forks": 0, + "open_issues": 3, + "watchers": 0, + "default_branch": "main" + } + }, + "repository": { + "id": 711862764, + "node_id": "R_kgDOKm4p7A", + "name": "admin-frontend-mvp", + "full_name": "CrisisCollab/admin-frontend-mvp", + "private": false, + "owner": { + "login": "CrisisCollab", + "id": 147498334, + "node_id": "O_kgDOCMqlXg", + "avatar_url": "https://avatars.githubusercontent.com/u/147498334?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/CrisisCollab", + "html_url": "https://github.com/CrisisCollab", + "followers_url": "https://api.github.com/users/CrisisCollab/followers", + "following_url": "https://api.github.com/users/CrisisCollab/following{/other_user}", + "gists_url": "https://api.github.com/users/CrisisCollab/gists{/gist_id}", + "starred_url": "https://api.github.com/users/CrisisCollab/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/CrisisCollab/subscriptions", + "organizations_url": "https://api.github.com/users/CrisisCollab/orgs", + "repos_url": "https://api.github.com/users/CrisisCollab/repos", + "events_url": "https://api.github.com/users/CrisisCollab/events{/privacy}", + "received_events_url": "https://api.github.com/users/CrisisCollab/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "html_url": "https://github.com/CrisisCollab/admin-frontend-mvp", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp", + "forks_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/forks", + "keys_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/teams", + "hooks_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/hooks", + "issue_events_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/issues/events{/number}", + "events_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/events", + "assignees_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/assignees{/user}", + "branches_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/branches{/branch}", + "tags_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/tags", + "blobs_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/statuses/{sha}", + "languages_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/languages", + "stargazers_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/stargazers", + "contributors_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/contributors", + "subscribers_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/subscribers", + "subscription_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/subscription", + "commits_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/contents/{+path}", + "compare_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/merges", + "archive_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/downloads", + "issues_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/issues{/number}", + "pulls_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/pulls{/number}", + "milestones_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/milestones{/number}", + "notifications_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/labels{/name}", + "releases_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/releases{/id}", + "deployments_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/deployments", + "created_at": "2023-10-30T10:24:23Z", + "updated_at": "2025-02-15T09:46:08Z", + "pushed_at": "2023-10-30T10:24:24Z", + "git_url": "git://github.com/CrisisCollab/admin-frontend-mvp.git", + "ssh_url": "git@github.com:CrisisCollab/admin-frontend-mvp.git", + "clone_url": "https://github.com/CrisisCollab/admin-frontend-mvp.git", + "svn_url": "https://github.com/CrisisCollab/admin-frontend-mvp", + "homepage": null, + "size": 0, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "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": null, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "public", + "forks": 0, + "open_issues": 1, + "watchers": 0, + "default_branch": "main", + "custom_properties": {} + }, + "organization": { + "login": "CrisisCollab", + "id": 147498334, + "node_id": "O_kgDOCMqlXg", + "url": "https://api.github.com/orgs/CrisisCollab", + "repos_url": "https://api.github.com/orgs/CrisisCollab/repos", + "events_url": "https://api.github.com/orgs/CrisisCollab/events", + "hooks_url": "https://api.github.com/orgs/CrisisCollab/hooks", + "issues_url": "https://api.github.com/orgs/CrisisCollab/issues", + "members_url": "https://api.github.com/orgs/CrisisCollab/members{/member}", + "public_members_url": "https://api.github.com/orgs/CrisisCollab/public_members{/member}", + "avatar_url": "https://avatars.githubusercontent.com/u/147498334?v=4", + "description": "" + }, + "sender": { + "login": "devaditya-k", + "id": 199350900, + "node_id": "U_kgDOC-HadA", + "avatar_url": "https://avatars.githubusercontent.com/u/199350900?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/devaditya-k", + "html_url": "https://github.com/devaditya-k", + "followers_url": "https://api.github.com/users/devaditya-k/followers", + "following_url": "https://api.github.com/users/devaditya-k/following{/other_user}", + "gists_url": "https://api.github.com/users/devaditya-k/gists{/gist_id}", + "starred_url": "https://api.github.com/users/devaditya-k/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/devaditya-k/subscriptions", + "organizations_url": "https://api.github.com/users/devaditya-k/orgs", + "repos_url": "https://api.github.com/users/devaditya-k/repos", + "events_url": "https://api.github.com/users/devaditya-k/events{/privacy}", + "received_events_url": "https://api.github.com/users/devaditya-k/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + } +} diff --git a/zerver/webhooks/github/fixtures/issues__transferred.json b/zerver/webhooks/github/fixtures/issues__transferred.json new file mode 100644 index 0000000000..2d14352cb6 --- /dev/null +++ b/zerver/webhooks/github/fixtures/issues__transferred.json @@ -0,0 +1,375 @@ +{ + "action": "transferred", + "issue": { + "url": "https://api.github.com/repos/CrisisCollab/TestWebhook/issues/4", + "repository_url": "https://api.github.com/repos/CrisisCollab/TestWebhook", + "labels_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/issues/4/labels{/name}", + "comments_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/issues/4/comments", + "events_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/issues/4/events", + "html_url": "https://github.com/CrisisCollab/TestWebhook/issues/4", + "id": 2855384286, + "node_id": "I_kwDOM0_enM6qMbTe", + "number": 4, + "title": "Fixture collection", + "user": { + "login": "devaditya-k", + "id": 199350900, + "node_id": "U_kgDOC-HadA", + "avatar_url": "https://avatars.githubusercontent.com/u/199350900?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/devaditya-k", + "html_url": "https://github.com/devaditya-k", + "followers_url": "https://api.github.com/users/devaditya-k/followers", + "following_url": "https://api.github.com/users/devaditya-k/following{/other_user}", + "gists_url": "https://api.github.com/users/devaditya-k/gists{/gist_id}", + "starred_url": "https://api.github.com/users/devaditya-k/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/devaditya-k/subscriptions", + "organizations_url": "https://api.github.com/users/devaditya-k/orgs", + "repos_url": "https://api.github.com/users/devaditya-k/repos", + "events_url": "https://api.github.com/users/devaditya-k/events{/privacy}", + "received_events_url": "https://api.github.com/users/devaditya-k/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "labels": [], + "state": "open", + "locked": false, + "assignee": null, + "assignees": [], + "milestone": null, + "comments": 0, + "created_at": "2025-02-15T10:13:33Z", + "updated_at": "2025-02-15T10:33:12Z", + "closed_at": null, + "author_association": "NONE", + "sub_issues_summary": { + "total": 0, + "completed": 0, + "percent_completed": 0 + }, + "active_lock_reason": null, + "body": "Fixture collection.", + "reactions": { + "url": "https://api.github.com/repos/CrisisCollab/TestWebhook/issues/4/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/CrisisCollab/TestWebhook/issues/4/timeline", + "performed_via_github_app": null, + "state_reason": null + }, + "changes": { + "new_issue": { + "url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/issues/4", + "repository_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp", + "labels_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/issues/4/labels{/name}", + "comments_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/issues/4/comments", + "events_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/issues/4/events", + "html_url": "https://github.com/CrisisCollab/admin-frontend-mvp/issues/4", + "id": 2855393943, + "node_id": "I_kwDOKm4p7M6qMdqX", + "number": 4, + "title": "Fixture collection", + "user": { + "login": "devaditya-k", + "id": 199350900, + "node_id": "U_kgDOC-HadA", + "avatar_url": "https://avatars.githubusercontent.com/u/199350900?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/devaditya-k", + "html_url": "https://github.com/devaditya-k", + "followers_url": "https://api.github.com/users/devaditya-k/followers", + "following_url": "https://api.github.com/users/devaditya-k/following{/other_user}", + "gists_url": "https://api.github.com/users/devaditya-k/gists{/gist_id}", + "starred_url": "https://api.github.com/users/devaditya-k/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/devaditya-k/subscriptions", + "organizations_url": "https://api.github.com/users/devaditya-k/orgs", + "repos_url": "https://api.github.com/users/devaditya-k/repos", + "events_url": "https://api.github.com/users/devaditya-k/events{/privacy}", + "received_events_url": "https://api.github.com/users/devaditya-k/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "labels": [], + "state": "open", + "locked": false, + "assignee": null, + "assignees": [], + "milestone": null, + "comments": 0, + "created_at": "2025-02-15T10:13:33Z", + "updated_at": "2025-02-15T10:35:45Z", + "closed_at": null, + "author_association": "NONE", + "sub_issues_summary": { + "total": 0, + "completed": 0, + "percent_completed": 0 + }, + "active_lock_reason": null, + "body": "Fixture collection.", + "reactions": { + "url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/issues/4/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/CrisisCollab/admin-frontend-mvp/issues/4/timeline", + "performed_via_github_app": null, + "state_reason": null + }, + "new_repository": { + "id": 711862764, + "node_id": "R_kgDOKm4p7A", + "name": "admin-frontend-mvp", + "full_name": "CrisisCollab/admin-frontend-mvp", + "private": false, + "owner": { + "login": "CrisisCollab", + "id": 147498334, + "node_id": "O_kgDOCMqlXg", + "avatar_url": "https://avatars.githubusercontent.com/u/147498334?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/CrisisCollab", + "html_url": "https://github.com/CrisisCollab", + "followers_url": "https://api.github.com/users/CrisisCollab/followers", + "following_url": "https://api.github.com/users/CrisisCollab/following{/other_user}", + "gists_url": "https://api.github.com/users/CrisisCollab/gists{/gist_id}", + "starred_url": "https://api.github.com/users/CrisisCollab/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/CrisisCollab/subscriptions", + "organizations_url": "https://api.github.com/users/CrisisCollab/orgs", + "repos_url": "https://api.github.com/users/CrisisCollab/repos", + "events_url": "https://api.github.com/users/CrisisCollab/events{/privacy}", + "received_events_url": "https://api.github.com/users/CrisisCollab/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "html_url": "https://github.com/CrisisCollab/admin-frontend-mvp", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp", + "forks_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/forks", + "keys_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/teams", + "hooks_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/hooks", + "issue_events_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/issues/events{/number}", + "events_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/events", + "assignees_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/assignees{/user}", + "branches_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/branches{/branch}", + "tags_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/tags", + "blobs_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/statuses/{sha}", + "languages_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/languages", + "stargazers_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/stargazers", + "contributors_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/contributors", + "subscribers_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/subscribers", + "subscription_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/subscription", + "commits_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/contents/{+path}", + "compare_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/merges", + "archive_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/downloads", + "issues_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/issues{/number}", + "pulls_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/pulls{/number}", + "milestones_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/milestones{/number}", + "notifications_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/labels{/name}", + "releases_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/releases{/id}", + "deployments_url": "https://api.github.com/repos/CrisisCollab/admin-frontend-mvp/deployments", + "created_at": "2023-10-30T10:24:23Z", + "updated_at": "2025-02-15T09:46:08Z", + "pushed_at": "2023-10-30T10:24:24Z", + "git_url": "git://github.com/CrisisCollab/admin-frontend-mvp.git", + "ssh_url": "git@github.com:CrisisCollab/admin-frontend-mvp.git", + "clone_url": "https://github.com/CrisisCollab/admin-frontend-mvp.git", + "svn_url": "https://github.com/CrisisCollab/admin-frontend-mvp", + "homepage": null, + "size": 0, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "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": null, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "public", + "forks": 0, + "open_issues": 1, + "watchers": 0, + "default_branch": "main" + } + }, + "repository": { + "id": 860872348, + "node_id": "R_kgDOM0_enA", + "name": "TestWebhook", + "full_name": "CrisisCollab/TestWebhook", + "private": false, + "owner": { + "login": "CrisisCollab", + "id": 147498334, + "node_id": "O_kgDOCMqlXg", + "avatar_url": "https://avatars.githubusercontent.com/u/147498334?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/CrisisCollab", + "html_url": "https://github.com/CrisisCollab", + "followers_url": "https://api.github.com/users/CrisisCollab/followers", + "following_url": "https://api.github.com/users/CrisisCollab/following{/other_user}", + "gists_url": "https://api.github.com/users/CrisisCollab/gists{/gist_id}", + "starred_url": "https://api.github.com/users/CrisisCollab/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/CrisisCollab/subscriptions", + "organizations_url": "https://api.github.com/users/CrisisCollab/orgs", + "repos_url": "https://api.github.com/users/CrisisCollab/repos", + "events_url": "https://api.github.com/users/CrisisCollab/events{/privacy}", + "received_events_url": "https://api.github.com/users/CrisisCollab/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "html_url": "https://github.com/CrisisCollab/TestWebhook", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/CrisisCollab/TestWebhook", + "forks_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/forks", + "keys_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/teams", + "hooks_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/hooks", + "issue_events_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/issues/events{/number}", + "events_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/events", + "assignees_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/assignees{/user}", + "branches_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/branches{/branch}", + "tags_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/tags", + "blobs_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/statuses/{sha}", + "languages_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/languages", + "stargazers_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/stargazers", + "contributors_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/contributors", + "subscribers_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/subscribers", + "subscription_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/subscription", + "commits_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/contents/{+path}", + "compare_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/merges", + "archive_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/downloads", + "issues_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/issues{/number}", + "pulls_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/pulls{/number}", + "milestones_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/milestones{/number}", + "notifications_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/labels{/name}", + "releases_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/releases{/id}", + "deployments_url": "https://api.github.com/repos/CrisisCollab/TestWebhook/deployments", + "created_at": "2024-09-21T11:50:28Z", + "updated_at": "2024-09-21T11:57:26Z", + "pushed_at": "2024-09-21T11:57:22Z", + "git_url": "git://github.com/CrisisCollab/TestWebhook.git", + "ssh_url": "git@github.com:CrisisCollab/TestWebhook.git", + "clone_url": "https://github.com/CrisisCollab/TestWebhook.git", + "svn_url": "https://github.com/CrisisCollab/TestWebhook", + "homepage": null, + "size": 2, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "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": 3, + "license": null, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "public", + "forks": 0, + "open_issues": 3, + "watchers": 0, + "default_branch": "main", + "custom_properties": {} + }, + "organization": { + "login": "CrisisCollab", + "id": 147498334, + "node_id": "O_kgDOCMqlXg", + "url": "https://api.github.com/orgs/CrisisCollab", + "repos_url": "https://api.github.com/orgs/CrisisCollab/repos", + "events_url": "https://api.github.com/orgs/CrisisCollab/events", + "hooks_url": "https://api.github.com/orgs/CrisisCollab/hooks", + "issues_url": "https://api.github.com/orgs/CrisisCollab/issues", + "members_url": "https://api.github.com/orgs/CrisisCollab/members{/member}", + "public_members_url": "https://api.github.com/orgs/CrisisCollab/public_members{/member}", + "avatar_url": "https://avatars.githubusercontent.com/u/147498334?v=4", + "description": "" + }, + "sender": { + "login": "Aditya8840", + "id": 74228301, + "node_id": "MDQ6VXNlcjc0MjI4MzAx", + "avatar_url": "https://avatars.githubusercontent.com/u/74228301?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/Aditya8840", + "html_url": "https://github.com/Aditya8840", + "followers_url": "https://api.github.com/users/Aditya8840/followers", + "following_url": "https://api.github.com/users/Aditya8840/following{/other_user}", + "gists_url": "https://api.github.com/users/Aditya8840/gists{/gist_id}", + "starred_url": "https://api.github.com/users/Aditya8840/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/Aditya8840/subscriptions", + "organizations_url": "https://api.github.com/users/Aditya8840/orgs", + "repos_url": "https://api.github.com/users/Aditya8840/repos", + "events_url": "https://api.github.com/users/Aditya8840/events{/privacy}", + "received_events_url": "https://api.github.com/users/Aditya8840/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + } +} diff --git a/zerver/webhooks/github/tests.py b/zerver/webhooks/github/tests.py index 949934d323..5016308ca5 100644 --- a/zerver/webhooks/github/tests.py +++ b/zerver/webhooks/github/tests.py @@ -226,6 +226,24 @@ class GitHubWebhookTest(WebhookTestCase): self.check_webhook("issues__demilestoned", expected_topic_name, expected_message) + def test_issue_transfer_transferred_message(self) -> None: + expected_message = "Aditya8840 transferred [issue #4 Fixture collection](https://github.com/CrisisCollab/TestWebhook/issues/4) to [CrisisCollab/admin-frontend-mvp/#4](https://github.com/CrisisCollab/admin-frontend-mvp/issues/4)." + expected_topic_name = "TestWebhook / issue #4 Fixture collection" + self.check_webhook( + "issues__transferred", + expected_topic_name, + expected_message, + ) + + def test_issue_transfer_opened_message(self) -> None: + expected_message = "[Issue #4 Fixture collection](https://github.com/CrisisCollab/admin-frontend-mvp/issues/4) was transferred from CrisisCollab/TestWebhook." + expected_topic_name = "admin-frontend-mvp / issue #4 Fixture collection" + self.check_webhook( + "issues__opened_via_transfer", + expected_topic_name, + expected_message, + ) + def test_membership_msg(self) -> None: expected_message = ( "baxterthehacker added [kdaigle](https://github.com/kdaigle) to the Contractors team." diff --git a/zerver/webhooks/github/view.py b/zerver/webhooks/github/view.py index 268d00f556..4978b15d17 100644 --- a/zerver/webhooks/github/view.py +++ b/zerver/webhooks/github/view.py @@ -163,9 +163,9 @@ def get_issue_body(helper: Helper) -> str: else issue["body"].tame(check_none_or(check_string)) ), title=issue["title"].tame(check_string) if include_title else None, - assignee_updated=payload["assignee"]["login"].tame(check_string) - if "assignee" in payload - else None, + assignee_updated=( + payload["assignee"]["login"].tame(check_string) if "assignee" in payload else None + ), ) @@ -687,6 +687,31 @@ def get_tier_changed_body(helper: Helper) -> str: ).rstrip() +def get_issue_transferred_body(helper: Helper) -> str: + payload = helper.payload + template = "{sender} transferred [issue #{old_issue_number} {title}]({old_issue_url}) to [{new_repo_full_name}/#{new_issue_number}]({new_issue_url})." + return template.format( + sender=get_sender_name(payload), + old_issue_number=payload["issue"]["number"].tame(check_int), + old_issue_url=payload["issue"]["html_url"].tame(check_string), + title=payload["issue"]["title"].tame(check_string), + new_repo_full_name=payload["changes"]["new_repository"]["full_name"].tame(check_string), + new_issue_number=payload["changes"]["new_issue"]["number"].tame(check_int), + new_issue_url=payload["changes"]["new_issue"]["html_url"].tame(check_string), + ) + + +def get_issue_opened_via_transfer_body(helper: Helper) -> str: + payload = helper.payload + template = "[Issue #{new_issue_number} {title}]({new_issue_url}) was transferred from {old_repo_full_name}." + return template.format( + new_issue_number=payload["issue"]["number"].tame(check_int), + new_issue_url=payload["issue"]["html_url"].tame(check_string), + title=payload["issue"]["title"].tame(check_string), + old_repo_full_name=payload["changes"]["old_repository"]["full_name"].tame(check_string), + ) + + def get_subscription(payload: WildValue) -> str: return payload["sponsorship"]["tier"]["name"].tame(check_string) @@ -816,6 +841,8 @@ EVENT_FUNCTION_MAPPER: dict[str, Callable[[Helper], str]] = { "issue_comment": get_issue_comment_body, "issue_labeled_or_unlabeled": get_issue_labeled_or_unlabeled_body, "issue_milestoned_or_demilestoned": get_issue_milestoned_or_demilestoned_body, + "issues_opened_via_transfer": get_issue_opened_via_transfer_body, + "issues_transferred": get_issue_transferred_body, "issues": get_issue_body, "member": get_member_body, "membership": get_membership_body, @@ -1027,6 +1054,10 @@ def get_zulip_event_name( return "issue_labeled_or_unlabeled" if action in ("milestoned", "demilestoned"): return "issue_milestoned_or_demilestoned" + if action == "transferred": + return "issues_transferred" + if action == "opened" and payload.get("changes", {}).get("old_issue"): + return "issues_opened_via_transfer" else: return "issues" elif header_event in EVENT_FUNCTION_MAPPER: