Repository: zulip/zulip

Issue:
Exclude label/unlabel events in GitHub integration (at least optionally)
The GitHub integration sends a message when an issue (or PR, presumably) gets a label added, or a label removed.

This can get extremely spammy. For example see today's messages it sent about the zulip-flutter repo, starting [here](https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/zulip-flutter/near/1578003) and running for most of the next 100 messages. (But [not all of them](https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/zulip-flutter/near/1578145)! As usual, one consequence of spam is that it becomes easy to miss the other, more interesting stuff.)

---

I think it's probable that nobody ever actually wants this behavior. One piece of evidence for that: as is, these messages are completely useless.
* They repeat the entire issue description.
* They *don't* specify what label it was that was added or removed.

So truly zero people are relying on these messages today; and the lack of clamor to fix them is evidence that nobody is excited about having even an improved version of them.

In principle we could make it configurable whether to include these events. But given that it's probable that nobody actually wants them, I think it'd make sense instead to keep things simple and just skip them entirely.



Discussion:
Hello @zulip/server-integrations members, this issue was labeled with the "area: integrations" label, so you may want to check it out!

<!-- areaLabelAddition -->

BTW these events are also spammy even when nobody's going and labeling things en masse. For example, whenever someone opens an issue there's also an event for any labels they add, like [here](https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/zulip-flutter/near/1578032). (That was a label I added before even hitting submit to create the issue — so it's not avoidable by doing that.)

@sbansal1999 making sure you see this issue and https://github.com/zulip/zulip/issues/25793.
This one probably comes up more often. The argument for these events being useless makes sense to me.
Thanks for tagging me on this one! I will add this to my todo list for the week.
So I investigated the webhooks that are sent when labels are added/removed from an issue (or PR). Every time when a label is assigned / unassigned one event is fired. So suppose if in an issue 2 labels were added and 1 other label was removed then we would receive a total of 3 events.

> - They repeat the entire issue description.
> - They don't specify what label it was that was added or removed.

I think it's possible to fix both of the above-mentioned problems. So I am not sure if excluding those events at all is really required.

So something like this can be sent when a label is added to an issue:

> Issue #9 was labeled bug by sbansal1999.

Let me know what you guys think about this one.

 
I think a short message like that which doesn't repeat the entire issue description and has the label that changed would likely be worth trying.
Certainly we should do that if we're going to keep sending messages for these events at all. But it wouldn't make them all that much less spammy than they are now — in particular it'd still be the same number of messages on the same occasions. For example:

> This can get extremely spammy. For example see today's messages it sent about the zulip-flutter repo, starting [here](https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/zulip-flutter/near/1578003) and running for most of the next 100 messages. (But [not all of them](https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/zulip-flutter/near/1578145)! As usual, one consequence of spam is that it becomes easy to miss the other, more interesting stuff.)

So I expect that they'd still feel pretty spammy and it'd be better to leave them out entirely.

The fact that these messages are currently as broken as they are is informative because it's evidence that there is literally nobody who is currently relying on them and might be sad if we just removed them.

You are right, the number of messages will still be the same. So some spam would still be there. I will get on and add this to my to-do list.
@zulipbot claim

Resolving patch:
diff --git a/zerver/lib/webhooks/git.py b/zerver/lib/webhooks/git.py
--- a/zerver/lib/webhooks/git.py
+++ b/zerver/lib/webhooks/git.py
@@ -50,6 +50,9 @@
 CREATE_BRANCH_WITHOUT_URL_MESSAGE_TEMPLATE = "{user_name} created {branch_name} branch."
 REMOVE_BRANCH_MESSAGE_TEMPLATE = "{user_name} deleted branch {branch_name}."
 
+ISSUE_LABELED_OR_UNLABELED_MESSAGE_TEMPLATE = "[{user_name}]({user_url}) {action} the [{label_name}]({label_url}) label {preposition} [Issue #{id}]({url})."
+ISSUE_LABELED_OR_UNLABELED_MESSAGE_TEMPLATE_WITH_TITLE = "[{user_name}]({user_url}) {action} the [{label_name}]({label_url}) label {preposition} [Issue #{id} {title}]({url})."
+
 PULL_REQUEST_OR_ISSUE_MESSAGE_TEMPLATE = "{user_name} {action} [{type}{id}]({url})"
 PULL_REQUEST_OR_ISSUE_MESSAGE_TEMPLATE_WITH_TITLE = (
     "{user_name} {action} [{type}{id} {title}]({url})"
@@ -273,6 +276,32 @@ def get_issue_event_message(
     )
 
 
+def get_issue_labeled_or_unlabeled_event_message(
+    user_name: str,
+    action: str,
+    url: str,
+    number: int,
+    label_name: str,
+    label_url: str,
+    user_url: str,
+    title: Optional[str] = None,
+) -> str:
+    args = {
+        "user_name": user_name,
+        "action": action,
+        "url": url,
+        "id": number,
+        "label_name": label_name,
+        "label_url": label_url,
+        "user_url": user_url,
+        "title": title,
+        "preposition": "to" if action == "added" else "from",
+    }
+    if title is not None:
+        return ISSUE_LABELED_OR_UNLABELED_MESSAGE_TEMPLATE_WITH_TITLE.format(**args)
+    return ISSUE_LABELED_OR_UNLABELED_MESSAGE_TEMPLATE.format(**args)
+
+
 def get_push_tag_event_message(
     user_name: str, tag_name: str, tag_url: Optional[str] = None, action: str = "pushed"
 ) -> str:
diff --git a/zerver/webhooks/github/view.py b/zerver/webhooks/github/view.py
--- a/zerver/webhooks/github/view.py
+++ b/zerver/webhooks/github/view.py
@@ -28,6 +28,7 @@
     TOPIC_WITH_PR_OR_ISSUE_INFO_TEMPLATE,
     get_commits_comment_action_message,
     get_issue_event_message,
+    get_issue_labeled_or_unlabeled_event_message,
     get_pull_request_event_message,
     get_push_commits_event_message,
     get_push_tag_event_message,
@@ -204,6 +205,23 @@ def get_issue_comment_body(helper: Helper) -> str:
     )
 
 
+def get_issue_labeled_or_unlabeled_body(helper: Helper) -> str:
+    payload = helper.payload
+    include_title = helper.include_title
+    issue = payload["issue"]
+
+    return get_issue_labeled_or_unlabeled_event_message(
+        user_name=get_sender_name(payload),
+        action="added" if payload["action"].tame(check_string) == "labeled" else "removed",
+        url=issue["html_url"].tame(check_string),
+        number=issue["number"].tame(check_int),
+        label_name=payload["label"]["name"].tame(check_string),
+        label_url=payload["label"]["url"].tame(check_string),
+        user_url=get_sender_url(payload),
+        title=issue["title"].tame(check_string) if include_title else None,
+    )
+
+
 def get_fork_body(helper: Helper) -> str:
     payload = helper.payload
     forkee = payload["forkee"]
@@ -710,6 +728,7 @@ def get_subject_based_on_type(payload: WildValue, event: str) -> str:
     "fork": get_fork_body,
     "gollum": get_wiki_pages_body,
     "issue_comment": get_issue_comment_body,
+    "issue_labeled_or_unlabeled": get_issue_labeled_or_unlabeled_body,
     "issues": get_issue_body,
     "member": get_member_body,
     "membership": get_membership_body,
@@ -862,6 +881,12 @@ def get_zulip_event_name(
             # this means GH has actually added new actions since September 2020,
             # so it's a bit more cause for alarm
             raise UnsupportedWebhookEventTypeError(f"unsupported team action {action}")
+    elif header_event == "issues":
+        action = payload["action"].tame(check_string)
+        if action in ("labeled", "unlabeled"):
+            return "issue_labeled_or_unlabeled"
+        else:
+            return "issues"
     elif header_event in list(EVENT_FUNCTION_MAPPER.keys()):
         return header_event
     elif header_event in IGNORED_EVENTS:


Test patch:
diff --git a/zerver/webhooks/github/tests.py b/zerver/webhooks/github/tests.py
--- a/zerver/webhooks/github/tests.py
+++ b/zerver/webhooks/github/tests.py
@@ -177,6 +177,22 @@ def test_issue_unassigned_with_custom_topic_in_url(self) -> None:
         expected_message = "sbansal1999 unassigned sbansal1999 from [issue #9 idk man](https://github.com/sbansal1999/testing-gh/issues/9)."
         self.check_webhook("issues__unassigned", expected_topic, expected_message)
 
+    def test_issue_labeled(self) -> None:
+        expected_topic = "testing-gh / issue #9 idk man"
+        expected_message = "[sbansal1999](https://github.com/sbansal1999) added the [bug](https://api.github.com/repos/sbansal1999/testing-gh/labels/bug) label to [Issue #9](https://github.com/sbansal1999/testing-gh/issues/9)."
+        self.check_webhook("issues__labeled", expected_topic, expected_message)
+
+    def test_issue_labeled_with_custom_topic_in_url(self) -> None:
+        self.url = self.build_webhook_url(topic="notifications")
+        expected_topic = "notifications"
+        expected_message = "[sbansal1999](https://github.com/sbansal1999) added the [bug](https://api.github.com/repos/sbansal1999/testing-gh/labels/bug) label to [Issue #9 idk man](https://github.com/sbansal1999/testing-gh/issues/9)."
+        self.check_webhook("issues__labeled", expected_topic, expected_message)
+
+    def test_issue_unlabeled(self) -> None:
+        expected_topic = "testing-gh / issue #9 idk man"
+        expected_message = "[sbansal1999](https://github.com/sbansal1999) removed the [bug](https://api.github.com/repos/sbansal1999/testing-gh/labels/bug) label from [Issue #9](https://github.com/sbansal1999/testing-gh/issues/9)."
+        self.check_webhook("issues__unlabeled", expected_topic, expected_message)
+
     def test_membership_msg(self) -> None:
         expected_message = (
             "baxterthehacker added [kdaigle](https://github.com/kdaigle) to the Contractors team."