integrations: Create incoming webhook for GitHub Sponsors.

Creates an incoming webhook integration for Github Sponsors. The
main use case is getting notifications when new sponsors sign up.

Fixes #18320.
This commit is contained in:
David Rosa 2023-12-19 15:43:09 -08:00 committed by Tim Abbott
parent ea89a4c6f7
commit d29cd04387
12 changed files with 707 additions and 6 deletions

View File

@ -8,4 +8,5 @@ pnpm-lock.yaml
/web/third /web/third
/zerver/tests/fixtures /zerver/tests/fixtures
/zerver/webhooks/*/doc.md /zerver/webhooks/*/doc.md
/zerver/webhooks/github/githubsponsors.md
/zerver/webhooks/*/fixtures /zerver/webhooks/*/fixtures

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -197,6 +197,7 @@ class WebhookIntegration(Integration):
stream_name: Optional[str] = None, stream_name: Optional[str] = None,
legacy: bool = False, legacy: bool = False,
config_options: Sequence[Tuple[str, str, OptionValidator]] = [], config_options: Sequence[Tuple[str, str, OptionValidator]] = [],
dir_name: Optional[str] = None,
) -> None: ) -> None:
if client_name is None: if client_name is None:
client_name = self.DEFAULT_CLIENT_NAME.format(name=name.title()) client_name = self.DEFAULT_CLIENT_NAME.format(name=name.title())
@ -229,9 +230,12 @@ class WebhookIntegration(Integration):
if doc is None: if doc is None:
doc = self.DEFAULT_DOC_PATH.format(name=name, ext="md") doc = self.DEFAULT_DOC_PATH.format(name=name, ext="md")
self.doc = doc self.doc = doc
if dir_name is None:
dir_name = self.name
self.dir_name = dir_name
@property @property
def url_object(self) -> URLResolver: def url_object(self) -> URLResolver:
assert self.function is not None assert self.function is not None
@ -266,7 +270,7 @@ def get_fixture_and_image_paths(
integration: Integration, screenshot_config: BaseScreenshotConfig integration: Integration, screenshot_config: BaseScreenshotConfig
) -> Tuple[str, str]: ) -> Tuple[str, str]:
if isinstance(integration, WebhookIntegration): if isinstance(integration, WebhookIntegration):
fixture_dir = os.path.join("zerver", "webhooks", integration.name, "fixtures") fixture_dir = os.path.join("zerver", "webhooks", integration.dir_name, "fixtures")
else: else:
fixture_dir = os.path.join("zerver", "integration_fixtures", integration.name) fixture_dir = os.path.join("zerver", "integration_fixtures", integration.name)
fixture_path = os.path.join(fixture_dir, screenshot_config.fixture_name) fixture_path = os.path.join(fixture_dir, screenshot_config.fixture_name)
@ -401,6 +405,16 @@ WEBHOOK_INTEGRATIONS: List[WebhookIntegration] = [
function="zerver.webhooks.github.view.api_github_webhook", function="zerver.webhooks.github.view.api_github_webhook",
stream_name="github", stream_name="github",
), ),
WebhookIntegration(
"githubsponsors",
["financial"],
display_name="GitHub Sponsors",
logo="images/integrations/logos/github.svg",
dir_name="github",
function="zerver.webhooks.github.view.api_github_webhook",
doc="github/githubsponsors.md",
stream_name="github",
),
WebhookIntegration("gitlab", ["version-control"], display_name="GitLab"), WebhookIntegration("gitlab", ["version-control"], display_name="GitLab"),
WebhookIntegration("gocd", ["continuous-integration"], display_name="GoCD"), WebhookIntegration("gocd", ["continuous-integration"], display_name="GoCD"),
WebhookIntegration("gogs", ["version-control"], stream_name="commits"), WebhookIntegration("gogs", ["version-control"], stream_name="commits"),
@ -739,6 +753,7 @@ DOC_SCREENSHOT_CONFIG: Dict[str, List[BaseScreenshotConfig]] = {
"gci": [ScreenshotConfig("task_abandoned_by_student.json")], "gci": [ScreenshotConfig("task_abandoned_by_student.json")],
"gitea": [ScreenshotConfig("pull_request__merged.json")], "gitea": [ScreenshotConfig("pull_request__merged.json")],
"github": [ScreenshotConfig("push__1_commit.json")], "github": [ScreenshotConfig("push__1_commit.json")],
"githubsponsors": [ScreenshotConfig("created.json")],
"gitlab": [ScreenshotConfig("push_hook__push_local_branch_without_commits.json")], "gitlab": [ScreenshotConfig("push_hook__push_local_branch_without_commits.json")],
"gocd": [ScreenshotConfig("pipeline.json")], "gocd": [ScreenshotConfig("pipeline.json")],
"gogs": [ScreenshotConfig("pull_request__opened.json")], "gogs": [ScreenshotConfig("pull_request__opened.json")],
@ -836,8 +851,9 @@ DOC_SCREENSHOT_CONFIG: Dict[str, List[BaseScreenshotConfig]] = {
def get_all_event_types_for_integration(integration: Integration) -> Optional[List[str]]: def get_all_event_types_for_integration(integration: Integration) -> Optional[List[str]]:
integration = INTEGRATIONS[integration.name] integration = INTEGRATIONS[integration.name]
if isinstance(integration, WebhookIntegration) and hasattr( if isinstance(integration, WebhookIntegration):
integration.function, "_all_event_types" if integration.name == "githubsponsors":
): return import_string("zerver.webhooks.github.view.SPONSORS_EVENT_TYPES")
return integration.function._all_event_types if hasattr(integration.function, "_all_event_types"):
return integration.function._all_event_types
return None return None

View File

@ -0,0 +1,78 @@
{
"action": "cancelled",
"sponsorship": {
"node_id": "MDExOlNwb25zb3JzaGlwMQ==",
"created_at": "2019-12-20T19:24:46+00:00",
"sponsorable": {
"login": "octocat",
"id": 5,
"node_id": "MDQ6VXNlcjU=",
"avatar_url": "https://avatars2.githubusercontent.com/u/5?",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": false
},
"sponsor": {
"login": "monalisa",
"id": 2,
"node_id": "MDQ6VXNlcjI=",
"avatar_url": "https://avatars2.githubusercontent.com/u/2?",
"gravatar_id": "",
"url": "https://api.github.com/users/monalisa",
"html_url": "https://github.com/monalisa",
"followers_url": "https://api.github.com/users/monalisa/followers",
"following_url": "https://api.github.com/users/monalisa/following{/other_user}",
"gists_url": "https://api.github.com/users/monalisa/gists{/gist_id}",
"starred_url": "https://api.github.com/users/monalisa/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/monalisa/subscriptions",
"organizations_url": "https://api.github.com/users/monalisa/orgs",
"repos_url": "https://api.github.com/users/monalisa/repos",
"events_url": "https://api.github.com/users/monalisa/events{/privacy}",
"received_events_url": "https://api.github.com/users/monalisa/received_events",
"type": "User",
"site_admin": true
},
"privacy_level": "private",
"tier": {
"node_id": "MDEyOlNwb25zb3JzVGllcjE=",
"created_at": "2019-12-20T19:17:05Z",
"description": "foo",
"monthly_price_in_cents": 500,
"monthly_price_in_dollars": 5,
"name": "$5 a month",
"is_one_time": false,
"is_custom_amount": false
}
},
"sender": {
"login": "monalisa",
"id": 2,
"node_id": "MDQ6VXNlcjI=",
"avatar_url": "https://avatars2.githubusercontent.com/u/2?",
"gravatar_id": "",
"url": "https://api.github.com/users/monalisa",
"html_url": "https://github.com/monalisa",
"followers_url": "https://api.github.com/users/monalisa/followers",
"following_url": "https://api.github.com/users/monalisa/following{/other_user}",
"gists_url": "https://api.github.com/users/monalisa/gists{/gist_id}",
"starred_url": "https://api.github.com/users/monalisa/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/monalisa/subscriptions",
"organizations_url": "https://api.github.com/users/monalisa/orgs",
"repos_url": "https://api.github.com/users/monalisa/repos",
"events_url": "https://api.github.com/users/monalisa/events{/privacy}",
"received_events_url": "https://api.github.com/users/monalisa/received_events",
"type": "User",
"site_admin": true
}
}

View File

@ -0,0 +1,78 @@
{
"action": "created",
"sponsorship": {
"node_id": "MDExOlNwb25zb3JzaGlwMQ==",
"created_at": "2019-12-20T19:24:46+00:00",
"sponsorable": {
"login": "octocat",
"id": 5,
"node_id": "MDQ6VXNlcjU=",
"avatar_url": "https://avatars2.githubusercontent.com/u/5?",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": false
},
"sponsor": {
"login": "monalisa",
"id": 2,
"node_id": "MDQ6VXNlcjI=",
"avatar_url": "https://avatars2.githubusercontent.com/u/2?",
"gravatar_id": "",
"url": "https://api.github.com/users/monalisa",
"html_url": "https://github.com/monalisa",
"followers_url": "https://api.github.com/users/monalisa/followers",
"following_url": "https://api.github.com/users/monalisa/following{/other_user}",
"gists_url": "https://api.github.com/users/monalisa/gists{/gist_id}",
"starred_url": "https://api.github.com/users/monalisa/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/monalisa/subscriptions",
"organizations_url": "https://api.github.com/users/monalisa/orgs",
"repos_url": "https://api.github.com/users/monalisa/repos",
"events_url": "https://api.github.com/users/monalisa/events{/privacy}",
"received_events_url": "https://api.github.com/users/monalisa/received_events",
"type": "User",
"site_admin": true
},
"privacy_level": "public",
"tier": {
"node_id": "MDEyOlNwb25zb3JzVGllcjE=",
"created_at": "2019-12-20T19:17:05Z",
"description": "foo",
"monthly_price_in_cents": 500,
"monthly_price_in_dollars": 5,
"name": "$5 a month",
"is_one_time": false,
"is_custom_amount": false
}
},
"sender": {
"login": "monalisa",
"id": 2,
"node_id": "MDQ6VXNlcjI=",
"avatar_url": "https://avatars2.githubusercontent.com/u/2?",
"gravatar_id": "",
"url": "https://api.github.com/users/monalisa",
"html_url": "https://github.com/monalisa",
"followers_url": "https://api.github.com/users/monalisa/followers",
"following_url": "https://api.github.com/users/monalisa/following{/other_user}",
"gists_url": "https://api.github.com/users/monalisa/gists{/gist_id}",
"starred_url": "https://api.github.com/users/monalisa/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/monalisa/subscriptions",
"organizations_url": "https://api.github.com/users/monalisa/orgs",
"repos_url": "https://api.github.com/users/monalisa/repos",
"events_url": "https://api.github.com/users/monalisa/events{/privacy}",
"received_events_url": "https://api.github.com/users/monalisa/received_events",
"type": "User",
"site_admin": true
}
}

View File

@ -0,0 +1,83 @@
{
"action": "edited",
"sponsorship": {
"node_id": "MDExOlNwb25zb3JzaGlwMQ==",
"created_at": "2019-12-20T19:24:46+00:00",
"sponsorable": {
"login": "octocat",
"id": 5,
"node_id": "MDQ6VXNlcjU=",
"avatar_url": "https://avatars2.githubusercontent.com/u/5?",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": false
},
"sponsor": {
"login": "monalisa",
"id": 2,
"node_id": "MDQ6VXNlcjI=",
"avatar_url": "https://avatars2.githubusercontent.com/u/2?",
"gravatar_id": "",
"url": "https://api.github.com/users/monalisa",
"html_url": "https://github.com/monalisa",
"followers_url": "https://api.github.com/users/monalisa/followers",
"following_url": "https://api.github.com/users/monalisa/following{/other_user}",
"gists_url": "https://api.github.com/users/monalisa/gists{/gist_id}",
"starred_url": "https://api.github.com/users/monalisa/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/monalisa/subscriptions",
"organizations_url": "https://api.github.com/users/monalisa/orgs",
"repos_url": "https://api.github.com/users/monalisa/repos",
"events_url": "https://api.github.com/users/monalisa/events{/privacy}",
"received_events_url": "https://api.github.com/users/monalisa/received_events",
"type": "User",
"site_admin": true
},
"privacy_level": "private",
"tier": {
"node_id": "MDEyOlNwb25zb3JzVGllcjE=",
"created_at": "2019-12-20T19:17:05Z",
"description": "foo",
"monthly_price_in_cents": 500,
"monthly_price_in_dollars": 5,
"name": "$5 a month",
"is_one_time": false,
"is_custom_amount": false
}
},
"changes": {
"privacy_level": {
"from": "public"
}
},
"sender": {
"login": "monalisa",
"id": 2,
"node_id": "MDQ6VXNlcjI=",
"avatar_url": "https://avatars2.githubusercontent.com/u/2?",
"gravatar_id": "",
"url": "https://api.github.com/users/monalisa",
"html_url": "https://github.com/monalisa",
"followers_url": "https://api.github.com/users/monalisa/followers",
"following_url": "https://api.github.com/users/monalisa/following{/other_user}",
"gists_url": "https://api.github.com/users/monalisa/gists{/gist_id}",
"starred_url": "https://api.github.com/users/monalisa/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/monalisa/subscriptions",
"organizations_url": "https://api.github.com/users/monalisa/orgs",
"repos_url": "https://api.github.com/users/monalisa/repos",
"events_url": "https://api.github.com/users/monalisa/events{/privacy}",
"received_events_url": "https://api.github.com/users/monalisa/received_events",
"type": "User",
"site_admin": true
}
}

View File

@ -0,0 +1,91 @@
{
"action": "pending_cancellation",
"sponsorship": {
"node_id": "MDExOlNwb25zb3JzaGlwMQ==",
"created_at": "2019-12-30T19:24:46+00:00",
"sponsorable": {
"login": "octocat",
"id": 5,
"node_id": "MDQ6VXNlcjU=",
"avatar_url": "https://avatars2.githubusercontent.com/u/5?",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": false
},
"sponsor": {
"login": "monalisa",
"id": 2,
"node_id": "MDQ6VXNlcjI=",
"avatar_url": "https://avatars2.githubusercontent.com/u/2?",
"gravatar_id": "",
"url": "https://api.github.com/users/monalisa",
"html_url": "https://github.com/monalisa",
"followers_url": "https://api.github.com/users/monalisa/followers",
"following_url": "https://api.github.com/users/monalisa/following{/other_user}",
"gists_url": "https://api.github.com/users/monalisa/gists{/gist_id}",
"starred_url": "https://api.github.com/users/monalisa/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/monalisa/subscriptions",
"organizations_url": "https://api.github.com/users/monalisa/orgs",
"repos_url": "https://api.github.com/users/monalisa/repos",
"events_url": "https://api.github.com/users/monalisa/events{/privacy}",
"received_events_url": "https://api.github.com/users/monalisa/received_events",
"type": "User",
"site_admin": true
},
"privacy_level": "private",
"tier": {
"node_id": "MDEyOlNwb25zb3JzVGllcjE=",
"created_at": "2019-12-30T19:17:05Z",
"description": "foo",
"monthly_price_in_cents": 500,
"monthly_price_in_dollars": 5,
"name": "$5 a month",
"is_one_time": false,
"is_custom_amount": false
}
},
"changes": {
"tier": {
"from": {
"node_id": "MDEyOlNwb25zb3JzVGllcjI=",
"created_at": "2019-12-30T19:26:26Z",
"description": "bar",
"monthly_price_in_cents": 1000,
"monthly_price_in_dollars": 10,
"name": "$10 a month"
}
}
},
"effective_date": "2020-01-05T00:00:00+00:00",
"sender": {
"login": "monalisa",
"id": 2,
"node_id": "MDQ6VXNlcjI=",
"avatar_url": "https://avatars2.githubusercontent.com/u/2?",
"gravatar_id": "",
"url": "https://api.github.com/users/monalisa",
"html_url": "https://github.com/monalisa",
"followers_url": "https://api.github.com/users/monalisa/followers",
"following_url": "https://api.github.com/users/monalisa/following{/other_user}",
"gists_url": "https://api.github.com/users/monalisa/gists{/gist_id}",
"starred_url": "https://api.github.com/users/monalisa/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/monalisa/subscriptions",
"organizations_url": "https://api.github.com/users/monalisa/orgs",
"repos_url": "https://api.github.com/users/monalisa/repos",
"events_url": "https://api.github.com/users/monalisa/events{/privacy}",
"received_events_url": "https://api.github.com/users/monalisa/received_events",
"type": "User",
"site_admin": true
}
}

View File

@ -0,0 +1,91 @@
{
"action": "pending_tier_change",
"sponsorship": {
"node_id": "MDExOlNwb25zb3JzaGlwMQ==",
"created_at": "2019-12-20T19:24:46+00:00",
"sponsorable": {
"login": "octocat",
"id": 5,
"node_id": "MDQ6VXNlcjU=",
"avatar_url": "https://avatars2.githubusercontent.com/u/5?",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": false
},
"sponsor": {
"login": "monalisa",
"id": 2,
"node_id": "MDQ6VXNlcjI=",
"avatar_url": "https://avatars2.githubusercontent.com/u/2?",
"gravatar_id": "",
"url": "https://api.github.com/users/monalisa",
"html_url": "https://github.com/monalisa",
"followers_url": "https://api.github.com/users/monalisa/followers",
"following_url": "https://api.github.com/users/monalisa/following{/other_user}",
"gists_url": "https://api.github.com/users/monalisa/gists{/gist_id}",
"starred_url": "https://api.github.com/users/monalisa/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/monalisa/subscriptions",
"organizations_url": "https://api.github.com/users/monalisa/orgs",
"repos_url": "https://api.github.com/users/monalisa/repos",
"events_url": "https://api.github.com/users/monalisa/events{/privacy}",
"received_events_url": "https://api.github.com/users/monalisa/received_events",
"type": "User",
"site_admin": true
},
"privacy_level": "private",
"tier": {
"node_id": "MDEyOlNwb25zb3JzVGllcjE=",
"created_at": "2019-12-20T19:17:05Z",
"description": "foo",
"monthly_price_in_cents": 500,
"monthly_price_in_dollars": 5,
"name": "$5 a month",
"is_one_time": false,
"is_custom_amount": false
}
},
"changes": {
"tier": {
"from": {
"node_id": "MDEyOlNwb25zb3JzVGllcjI=",
"created_at": "2019-12-20T19:26:26Z",
"description": "bar",
"monthly_price_in_cents": 1000,
"monthly_price_in_dollars": 10,
"name": "$10 a month"
}
}
},
"effective_date": "2019-12-30T00:00:00+00:00",
"sender": {
"login": "monalisa",
"id": 2,
"node_id": "MDQ6VXNlcjI=",
"avatar_url": "https://avatars2.githubusercontent.com/u/2?",
"gravatar_id": "",
"url": "https://api.github.com/users/monalisa",
"html_url": "https://github.com/monalisa",
"followers_url": "https://api.github.com/users/monalisa/followers",
"following_url": "https://api.github.com/users/monalisa/following{/other_user}",
"gists_url": "https://api.github.com/users/monalisa/gists{/gist_id}",
"starred_url": "https://api.github.com/users/monalisa/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/monalisa/subscriptions",
"organizations_url": "https://api.github.com/users/monalisa/orgs",
"repos_url": "https://api.github.com/users/monalisa/repos",
"events_url": "https://api.github.com/users/monalisa/events{/privacy}",
"received_events_url": "https://api.github.com/users/monalisa/received_events",
"type": "User",
"site_admin": true
}
}

View File

@ -0,0 +1,90 @@
{
"action": "tier_changed",
"sponsorship": {
"node_id": "MDExOlNwb25zb3JzaGlwMQ==",
"created_at": "2019-12-30T19:24:46+00:00",
"sponsorable": {
"login": "octocat",
"id": 5,
"node_id": "MDQ6VXNlcjU=",
"avatar_url": "https://avatars2.githubusercontent.com/u/5?",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": false
},
"sponsor": {
"login": "monalisa",
"id": 2,
"node_id": "MDQ6VXNlcjI=",
"avatar_url": "https://avatars2.githubusercontent.com/u/2?",
"gravatar_id": "",
"url": "https://api.github.com/users/monalisa",
"html_url": "https://github.com/monalisa",
"followers_url": "https://api.github.com/users/monalisa/followers",
"following_url": "https://api.github.com/users/monalisa/following{/other_user}",
"gists_url": "https://api.github.com/users/monalisa/gists{/gist_id}",
"starred_url": "https://api.github.com/users/monalisa/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/monalisa/subscriptions",
"organizations_url": "https://api.github.com/users/monalisa/orgs",
"repos_url": "https://api.github.com/users/monalisa/repos",
"events_url": "https://api.github.com/users/monalisa/events{/privacy}",
"received_events_url": "https://api.github.com/users/monalisa/received_events",
"type": "User",
"site_admin": true
},
"privacy_level": "private",
"tier": {
"node_id": "MDEyOlNwb25zb3JzVGllcjE=",
"created_at": "2019-12-30T19:17:05Z",
"description": "foo",
"monthly_price_in_cents": 500,
"monthly_price_in_dollars": 5,
"name": "$5 a month",
"is_one_time": false,
"is_custom_amount": false
}
},
"changes": {
"tier": {
"from": {
"node_id": "MDEyOlNwb25zb3JzVGllcjI=",
"created_at": "2019-12-30T19:26:26Z",
"description": "bar",
"monthly_price_in_cents": 1000,
"monthly_price_in_dollars": 10,
"name": "$10 a month"
}
}
},
"sender": {
"login": "monalisa",
"id": 2,
"node_id": "MDQ6VXNlcjI=",
"avatar_url": "https://avatars2.githubusercontent.com/u/2?",
"gravatar_id": "",
"url": "https://api.github.com/users/monalisa",
"html_url": "https://github.com/monalisa",
"followers_url": "https://api.github.com/users/monalisa/followers",
"following_url": "https://api.github.com/users/monalisa/following{/other_user}",
"gists_url": "https://api.github.com/users/monalisa/gists{/gist_id}",
"starred_url": "https://api.github.com/users/monalisa/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/monalisa/subscriptions",
"organizations_url": "https://api.github.com/users/monalisa/orgs",
"repos_url": "https://api.github.com/users/monalisa/repos",
"events_url": "https://api.github.com/users/monalisa/events{/privacy}",
"received_events_url": "https://api.github.com/users/monalisa/received_events",
"type": "User",
"site_admin": true
}
}

View File

@ -0,0 +1,22 @@
Get GitHub Sponsors notifications in Zulip!
1. {!create-stream.md!}
1. {!create-an-incoming-webhook.md!}
1. {!generate-integration-url.md!}
You can refer to GitHub's documentation for [webhook events](https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#sponsorship).
1. Go to your profile on GitHub and click on **Sponsors dashboard**.
Select **Webhooks**. Click on **Add webhook**. GitHub may prompt
you for your password.
1. Set **Payload URL** to the URL constructed above. Set **Content type**
to `application/json` and click **Create webhook**.
{!congrats.md!}
![](/static/images/integrations/githubsponsors/001.png)
See also the [GitHub integration](/integrations/doc/github).

View File

@ -13,6 +13,7 @@ TOPIC_ORGANIZATION = "baxterandthehackers organization"
TOPIC_BRANCH = "public-repo / changes" TOPIC_BRANCH = "public-repo / changes"
TOPIC_WIKI = "public-repo / wiki pages" TOPIC_WIKI = "public-repo / wiki pages"
TOPIC_DISCUSSION = "testing-gh discussion #20: Lets discuss" TOPIC_DISCUSSION = "testing-gh discussion #20: Lets discuss"
TOPIC_SPONSORS = "sponsors"
class GitHubWebhookTest(WebhookTestCase): class GitHubWebhookTest(WebhookTestCase):
@ -591,3 +592,59 @@ A temporary team so that I can get some webhook fixtures!
def test_discussion_comment_edited_msg(self) -> None: def test_discussion_comment_edited_msg(self) -> None:
expected_message = "sbansal1999 edited a [comment](https://github.com/sbansal1999/testing-gh/discussions/20#discussioncomment-6332416) on [discussion #20](https://github.com/sbansal1999/testing-gh/discussions/20):\n\n~~~ quote\nsome random comment edited\n~~~" expected_message = "sbansal1999 edited a [comment](https://github.com/sbansal1999/testing-gh/discussions/20#discussioncomment-6332416) on [discussion #20](https://github.com/sbansal1999/testing-gh/discussions/20):\n\n~~~ quote\nsome random comment edited\n~~~"
self.check_webhook("discussion_comment__edited", TOPIC_DISCUSSION, expected_message) self.check_webhook("discussion_comment__edited", TOPIC_DISCUSSION, expected_message)
class GitHubSponsorsHookTests(WebhookTestCase):
STREAM_NAME = "github"
URL_TEMPLATE = "/api/v1/external/githubsponsors?stream={stream}&api_key={api_key}"
WEBHOOK_DIR_NAME = "github"
def test_cancelled_message(self) -> None:
expected_message = "monalisa cancelled their $5 a month subscription."
self.check_webhook(
"cancelled",
TOPIC_SPONSORS,
expected_message,
)
def test_created_message(self) -> None:
expected_message = "monalisa subscribed for $5 a month."
self.check_webhook(
"created",
TOPIC_SPONSORS,
expected_message,
)
def test_pending_cancellation_message(self) -> None:
expected_message = (
"monalisa's $5 a month subscription will be cancelled on January 05, 2020."
)
self.check_webhook(
"pending_cancellation",
TOPIC_SPONSORS,
expected_message,
)
def test_pending_tier_change_message(self) -> None:
expected_message = "monalisa's subscription will change from $10 a month to $5 a month on December 30, 2019."
self.check_webhook(
"pending_tier_change",
TOPIC_SPONSORS,
expected_message,
)
def test_tier_changed_message(self) -> None:
expected_message = "monalisa changed their subscription from $10 a month to $5 a month."
self.check_webhook(
"tier_changed",
TOPIC_SPONSORS,
expected_message,
)
def test_edited_message(self) -> None:
expected_message = "monalisa changed who can see their sponsorship from public to private."
self.check_webhook(
"edited",
TOPIC_SPONSORS,
expected_message,
)

View File

@ -1,4 +1,5 @@
import re import re
from datetime import datetime, timezone
from typing import Callable, Dict, Optional from typing import Callable, Dict, Optional
from django.http import HttpRequest, HttpResponse from django.http import HttpRequest, HttpResponse
@ -637,6 +638,82 @@ def get_ping_body(helper: Helper) -> str:
return get_setup_webhook_message("GitHub", get_sender_name(payload)) return get_setup_webhook_message("GitHub", get_sender_name(payload))
def get_cancelled_body(helper: Helper) -> str:
payload = helper.payload
template = "{user_name} cancelled their {subscription} subscription."
return template.format(
user_name=get_sender_name(payload),
subscription=get_subscription(payload),
).rstrip()
def get_created_body(helper: Helper) -> str:
payload = helper.payload
template = "{user_name} subscribed for {subscription}."
return template.format(
user_name=get_sender_name(payload),
subscription=get_subscription(payload),
).rstrip()
def get_edited_body(helper: Helper) -> str:
payload = helper.payload
template = "{user_name} changed who can see their sponsorship from {prior_privacy_level} to {privacy_level}."
return template.format(
user_name=get_sender_name(payload),
prior_privacy_level=payload["changes"]["privacy_level"]["from"].tame(check_string),
privacy_level=payload["sponsorship"]["privacy_level"].tame(check_string),
).rstrip()
def get_pending_cancellation_body(helper: Helper) -> str:
payload = helper.payload
template = "{user_name}'s {subscription} subscription will be cancelled on {effective_date}."
return template.format(
user_name=get_sender_name(payload),
subscription=get_subscription(payload),
effective_date=get_effective_date(payload),
).rstrip()
def get_pending_tier_change_body(helper: Helper) -> str:
payload = helper.payload
template = "{user_name}'s subscription will change from {prior_subscription} to {subscription} on {effective_date}."
return template.format(
user_name=get_sender_name(payload),
prior_subscription=get_prior_subscription(payload),
subscription=get_subscription(payload),
effective_date=get_effective_date(payload),
).rstrip()
def get_tier_changed_body(helper: Helper) -> str:
payload = helper.payload
template = "{user_name} changed their subscription from {prior_subscription} to {subscription}."
return template.format(
user_name=get_sender_name(payload),
prior_subscription=get_prior_subscription(payload),
subscription=get_subscription(payload),
).rstrip()
def get_subscription(payload: WildValue) -> str:
return payload["sponsorship"]["tier"]["name"].tame(check_string)
def get_effective_date(payload: WildValue) -> str:
effective_date = payload["effective_date"].tame(check_string)[:10]
return (
datetime.strptime(effective_date, "%Y-%m-%d")
.replace(tzinfo=timezone.utc)
.strftime("%B %d, %Y")
)
def get_prior_subscription(payload: WildValue) -> str:
return payload["changes"]["tier"]["from"]["name"].tame(check_string)
def get_repository_name(payload: WildValue) -> str: def get_repository_name(payload: WildValue) -> str:
return payload["repository"]["name"].tame(check_string) return payload["repository"]["name"].tame(check_string)
@ -728,6 +805,8 @@ def get_topic_based_on_type(payload: WildValue, event: str) -> str:
number=payload["discussion"]["number"].tame(check_int), number=payload["discussion"]["number"].tame(check_int),
title=payload["discussion"]["title"].tame(check_string), title=payload["discussion"]["title"].tame(check_string),
) )
elif event in SPONSORS_EVENT_TYPES:
return "sponsors"
return get_repository_name(payload) return get_repository_name(payload)
@ -770,8 +849,23 @@ EVENT_FUNCTION_MAPPER: Dict[str, Callable[[Helper], str]] = {
"team": get_team_body, "team": get_team_body,
"team_add": get_add_team_body, "team_add": get_add_team_body,
"watch": get_watch_body, "watch": get_watch_body,
"cancelled": get_cancelled_body,
"created": get_created_body,
"edited": get_edited_body,
"pending_cancellation": get_pending_cancellation_body,
"pending_tier_change": get_pending_tier_change_body,
"tier_changed": get_tier_changed_body,
} }
SPONSORS_EVENT_TYPES = [
"cancelled",
"created",
"edited",
"pending_cancellation",
"pending_tier_change",
"tier_changed",
]
IGNORED_EVENTS = [ IGNORED_EVENTS = [
"check_suite", "check_suite",
"label", "label",