mirror of
https://github.com/zulip/zulip.git
synced 2025-10-27 18:13:58 +00:00
webhooks: Filter specific BitBucket Git branches.
This is the last of the Git integrations that didn't have this feature. Fixes #4327.
This commit is contained in:
@@ -21,8 +21,14 @@
|
||||
|
||||
<p>
|
||||
In the URL field, enter
|
||||
<code>{{ external_uri_scheme }}bot_email:bot_api_key@{{ external_api_path_subdomain }}/v1/external/bitbucket</code>:
|
||||
<code>{{ external_uri_scheme }}bot_email:bot_api_key@{{ external_api_path_subdomain }}/v1/external/bitbucket</code>
|
||||
</p>
|
||||
<p>
|
||||
Or, you can also limit the notifications you receive to specific
|
||||
branches by specifying them in a comma-separated list at the end
|
||||
of the URL, like so:
|
||||
</p>
|
||||
<p><code>{{ external_uri_scheme }}bot_email:bot_api_key@{{ external_api_path_subdomain }}/v1/external/bitbucket?branches=master,development</code></p>
|
||||
<img class="screenshot" src="/static/images/integrations/bitbucket/001.png"/>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from six import text_type
|
||||
from typing import Dict, Union
|
||||
from mock import patch, MagicMock
|
||||
from typing import Dict, Union, Text, Optional
|
||||
|
||||
from zerver.lib.test_classes import WebhookTestCase
|
||||
|
||||
class BitbucketHookTests(WebhookTestCase):
|
||||
@@ -18,6 +19,15 @@ class BitbucketHookTests(WebhookTestCase):
|
||||
expected_message = u"kolaszek pushed 1 commit to branch master. Commits by kolaszek(1)\n\n{}".format(commit_info)
|
||||
self.send_and_test_stream_message(fixture_name, self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message, **self.api_auth(self.TEST_USER_EMAIL))
|
||||
|
||||
def test_bitbucket_on_push_event_filtered_by_branches(self):
|
||||
# type: () -> None
|
||||
fixture_name = 'push'
|
||||
self.url = self.build_webhook_url(payload=self.get_body(fixture_name),
|
||||
branches='master,development')
|
||||
commit_info = u'* c ([25f93d2](https://bitbucket.org/kolaszek/repository-name/commits/25f93d22b719e2d678a7ad5ee0ef0d1fcdf39c12))'
|
||||
expected_message = u"kolaszek pushed 1 commit to branch master. Commits by kolaszek(1)\n\n{}".format(commit_info)
|
||||
self.send_and_test_stream_message(fixture_name, self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message, **self.api_auth(self.TEST_USER_EMAIL))
|
||||
|
||||
def test_bitbucket_on_push_commits_above_limit_event(self):
|
||||
# type: () -> None
|
||||
fixture_name = 'push_commits_above_limit'
|
||||
@@ -26,6 +36,15 @@ class BitbucketHookTests(WebhookTestCase):
|
||||
expected_message = u"kolaszek pushed 50 commits to branch master. Commits by kolaszek(50)\n\n{}[and 30 more commit(s)]".format(commit_info * 20)
|
||||
self.send_and_test_stream_message(fixture_name, self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message, **self.api_auth(self.TEST_USER_EMAIL))
|
||||
|
||||
def test_bitbucket_on_push_commits_above_limit_event_filtered_by_branches(self):
|
||||
# type: () -> None
|
||||
fixture_name = 'push_commits_above_limit'
|
||||
self.url = self.build_webhook_url(payload=self.get_body(fixture_name),
|
||||
branches='master,development')
|
||||
commit_info = u'* c ([25f93d2](https://bitbucket.org/kolaszek/repository-name/commits/25f93d22b719e2d678a7ad5ee0ef0d1fcdf39c12))\n'
|
||||
expected_message = u"kolaszek pushed 50 commits to branch master. Commits by kolaszek(50)\n\n{}[and 30 more commit(s)]".format(commit_info * 20)
|
||||
self.send_and_test_stream_message(fixture_name, self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message, **self.api_auth(self.TEST_USER_EMAIL))
|
||||
|
||||
def test_bitbucket_on_force_push_event(self):
|
||||
# type: () -> None
|
||||
fixture_name = 'force_push'
|
||||
@@ -33,6 +52,33 @@ class BitbucketHookTests(WebhookTestCase):
|
||||
expected_message = u"kolaszek [force pushed](https://bitbucket.org/kolaszek/repository-name)"
|
||||
self.send_and_test_stream_message(fixture_name, self.EXPECTED_SUBJECT, expected_message, **self.api_auth(self.TEST_USER_EMAIL))
|
||||
|
||||
@patch('zerver.webhooks.bitbucket.view.check_send_message')
|
||||
def test_bitbucket_on_push_event_filtered_by_branches_ignore(self, check_send_message_mock):
|
||||
# type: (MagicMock) -> None
|
||||
fixture_name = 'push'
|
||||
payload = self.get_body(fixture_name)
|
||||
self.url = self.build_webhook_url(payload=payload,
|
||||
branches='changes,development')
|
||||
result = self.client_post(self.url, payload,
|
||||
content_type="application/json,",
|
||||
**self.api_auth(self.TEST_USER_EMAIL))
|
||||
self.assertFalse(check_send_message_mock.called)
|
||||
self.assert_json_success(result)
|
||||
|
||||
@patch('zerver.webhooks.bitbucket.view.check_send_message')
|
||||
def test_bitbucket_push_commits_above_limit_filtered_by_branches_ignore(
|
||||
self, check_send_message_mock):
|
||||
# type: (MagicMock) -> None
|
||||
fixture_name = 'push_commits_above_limit'
|
||||
payload = self.get_body(fixture_name)
|
||||
self.url = self.build_webhook_url(payload=payload,
|
||||
branches='changes,development')
|
||||
result = self.client_post(self.url, payload,
|
||||
content_type="application/json,",
|
||||
**self.api_auth(self.TEST_USER_EMAIL))
|
||||
self.assertFalse(check_send_message_mock.called)
|
||||
self.assert_json_success(result)
|
||||
|
||||
def get_body(self, fixture_name):
|
||||
# type: (text_type) -> Union[text_type, Dict[str, text_type]]
|
||||
# type: (Text) -> Union[Text, Dict[str, Text]]
|
||||
return self.fixture_data(self.FIXTURE_DIR_NAME, fixture_name)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from typing import Any, Mapping, Text
|
||||
from typing import Any, Mapping, Text, Optional
|
||||
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
|
||||
@@ -15,8 +15,8 @@ from zerver.lib.webhooks.git import get_push_commits_event_message, SUBJECT_WITH
|
||||
@authenticated_rest_api_view(is_webhook=True)
|
||||
@has_request_variables
|
||||
def api_bitbucket_webhook(request, user_profile, payload=REQ(validator=check_dict([])),
|
||||
stream=REQ(default='commits')):
|
||||
# type: (HttpRequest, UserProfile, Mapping[Text, Any], Text) -> HttpResponse
|
||||
stream=REQ(default='commits'), branches=REQ(default=None)):
|
||||
# type: (HttpRequest, UserProfile, Mapping[Text, Any], Text, Optional[Text]) -> HttpResponse
|
||||
repository = payload['repository']
|
||||
|
||||
commits = [
|
||||
@@ -41,6 +41,8 @@ def api_bitbucket_webhook(request, user_profile, payload=REQ(validator=check_dic
|
||||
payload['canon_url'] + repository['absolute_url']))
|
||||
else:
|
||||
branch = payload['commits'][-1]['branch']
|
||||
if branches is not None and branches.find(branch) == -1:
|
||||
return json_success()
|
||||
content = get_push_commits_event_message(payload.get('user'), None, branch, commits)
|
||||
subject = SUBJECT_WITH_BRANCH_TEMPLATE.format(repo=repository['name'], branch=branch)
|
||||
|
||||
|
||||
@@ -14,12 +14,17 @@
|
||||
|
||||
<p>The URL you create will be in the following format:</p>
|
||||
<p><code>{{ external_api_uri_subdomain }}/v1/external/bitbucket2?api_key=abcdefgh&stream=bitbucket</code></p>
|
||||
|
||||
<p>
|
||||
where <code>api_key</code> is the API key of your Zulip bot,
|
||||
and <code>stream</code> is the stream name you want the
|
||||
notifications sent to.
|
||||
</p>
|
||||
<p>
|
||||
You can also limit the notifications you receive to specific
|
||||
branches by specifying them in a comma-separated list at the end
|
||||
of the URL, like so:
|
||||
</p>
|
||||
<p><code>{{ external_api_uri_subdomain }}/v1/external/bitbucket2?api_key=abcdefgh&stream=bitbucket&branches=master,development</code></p>
|
||||
|
||||
<p>
|
||||
Next, from your repository's web page, go to the Settings page and choose Webhooks on the left-hand side.
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from mock import patch, MagicMock
|
||||
from typing import Optional, Text
|
||||
|
||||
from zerver.lib.test_classes import WebhookTestCase
|
||||
|
||||
class Bitbucket2HookTests(WebhookTestCase):
|
||||
@@ -28,6 +31,27 @@ class Bitbucket2HookTests(WebhookTestCase):
|
||||
expected_message = u"""kolaszek [pushed](https://bitbucket.org/kolaszek/repository-name/branch/master) 10 commits to branch master. Commits by Tomasz(4), James(3), Brendon(2) and others(1)\n\n{}* first commit ([84b96ad](https://bitbucket.org/kolaszek/repository-name/commits/84b96adc644a30fd6465b3d196369d880762afed))""".format(commit_info*9)
|
||||
self.send_and_test_stream_message('v2_push_multiple_committers_with_others', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message)
|
||||
|
||||
def test_bitbucket2_on_push_commits_multiple_committers_filtered_by_branches(self):
|
||||
# type: () -> None
|
||||
self.url = self.build_webhook_url(branches='master,development')
|
||||
commit_info = u'* first commit ([84b96ad](https://bitbucket.org/kolaszek/repository-name/commits/84b96adc644a30fd6465b3d196369d880762afed))\n'
|
||||
expected_message = u"""kolaszek [pushed](https://bitbucket.org/kolaszek/repository-name/branch/master) 3 commits to branch master. Commits by Benjamin(2) and Tomasz(1)\n\n{}* first commit ([84b96ad](https://bitbucket.org/kolaszek/repository-name/commits/84b96adc644a30fd6465b3d196369d880762afed))""".format(commit_info*2)
|
||||
self.send_and_test_stream_message('v2_push_multiple_committers', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message)
|
||||
|
||||
def test_bitbucket2_on_push_commits_multiple_committers_with_others_filtered_by_branches(self):
|
||||
# type: () -> None
|
||||
self.url = self.build_webhook_url(branches='master,development')
|
||||
commit_info = u'* first commit ([84b96ad](https://bitbucket.org/kolaszek/repository-name/commits/84b96adc644a30fd6465b3d196369d880762afed))\n'
|
||||
expected_message = u"""kolaszek [pushed](https://bitbucket.org/kolaszek/repository-name/branch/master) 10 commits to branch master. Commits by Tomasz(4), James(3), Brendon(2) and others(1)\n\n{}* first commit ([84b96ad](https://bitbucket.org/kolaszek/repository-name/commits/84b96adc644a30fd6465b3d196369d880762afed))""".format(commit_info*9)
|
||||
self.send_and_test_stream_message('v2_push_multiple_committers_with_others', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message)
|
||||
|
||||
def test_bitbucket2_on_push_event_filtered_by_branches(self):
|
||||
# type: () -> None
|
||||
self.url = self.build_webhook_url(branches='master,development')
|
||||
commit_info = u'* first commit ([84b96ad](https://bitbucket.org/kolaszek/repository-name/commits/84b96adc644a30fd6465b3d196369d880762afed))'
|
||||
expected_message = u"kolaszek [pushed](https://bitbucket.org/kolaszek/repository-name/branch/master) 1 commit to branch master. Commits by Tomasz(1)\n\n{}".format(commit_info)
|
||||
self.send_and_test_stream_message('v2_push', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message)
|
||||
|
||||
def test_bitbucket2_on_push_commits_above_limit_event(self):
|
||||
# type: () -> None
|
||||
commit_info = '* a ([6f161a7](https://bitbucket.org/kolaszek/repository-name/commits/6f161a7bced94430ac8947d87dbf45c6deee3fb0))\n'
|
||||
@@ -36,11 +60,26 @@ class Bitbucket2HookTests(WebhookTestCase):
|
||||
)
|
||||
self.send_and_test_stream_message('v2_push_commits_above_limit', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message)
|
||||
|
||||
def test_bitbucket2_on_push_commits_above_limit_filtered_by_branches(self):
|
||||
# type: () -> None
|
||||
self.url = self.build_webhook_url(branches='master,development')
|
||||
commit_info = '* a ([6f161a7](https://bitbucket.org/kolaszek/repository-name/commits/6f161a7bced94430ac8947d87dbf45c6deee3fb0))\n'
|
||||
expected_message = u"kolaszek [pushed](https://bitbucket.org/kolaszek/repository-name/branches/compare/6f161a7bced94430ac8947d87dbf45c6deee3fb0..1221f2fda6f1e3654b09f1f3a08390e4cb25bb48) 5 commits to branch master. Commits by Tomasz(5)\n\n{}[and more commit(s)]".format(
|
||||
(commit_info * 5),
|
||||
)
|
||||
self.send_and_test_stream_message('v2_push_commits_above_limit', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message)
|
||||
|
||||
def test_bitbucket2_on_force_push_event(self):
|
||||
# type: () -> None
|
||||
expected_message = u"kolaszek [force pushed](https://bitbucket.org/kolaszek/repository-name/branch/master) to branch master. Head is now 25f93d22b719e2d678a7ad5ee0ef0d1fcdf39c12"
|
||||
self.send_and_test_stream_message('v2_force_push', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message)
|
||||
|
||||
def test_bitbucket2_on_force_push_event_filtered_by_branches(self):
|
||||
# type: () -> None
|
||||
self.url = self.build_webhook_url(branches='master,development')
|
||||
expected_message = u"kolaszek [force pushed](https://bitbucket.org/kolaszek/repository-name/branch/master) to branch master. Head is now 25f93d22b719e2d678a7ad5ee0ef0d1fcdf39c12"
|
||||
self.send_and_test_stream_message('v2_force_push', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message)
|
||||
|
||||
def test_bitbucket2_on_remove_branch_event(self):
|
||||
# type: () -> None
|
||||
expected_message = u"kolaszek deleted branch master"
|
||||
@@ -190,3 +229,78 @@ class Bitbucket2HookTests(WebhookTestCase):
|
||||
msg = self.get_last_message()
|
||||
self.do_test_message(msg, 'kolaszek pushed tag [a](https://bitbucket.org/kolaszek/repository-name/commits/tag/a)')
|
||||
self.do_test_subject(msg, self.EXPECTED_SUBJECT)
|
||||
|
||||
def test_bitbucket2_on_more_than_one_push_event_filtered_by_branches(self):
|
||||
# type: () -> None
|
||||
self.url = self.build_webhook_url(branches='master,development')
|
||||
kwargs = {
|
||||
"HTTP_X_EVENT_KEY": 'pullrequest:push'
|
||||
}
|
||||
self.send_and_test_stream_message('v2_more_than_one_push_event', **kwargs)
|
||||
msg = self.get_second_to_last_message()
|
||||
self.do_test_message(msg, 'kolaszek [pushed](https://bitbucket.org/kolaszek/repository-name/branch/master) 1 commit to branch master. Commits by Tomasz(1)\n\n* first commit ([84b96ad](https://bitbucket.org/kolaszek/repository-name/commits/84b96adc644a30fd6465b3d196369d880762afed))')
|
||||
self.do_test_subject(msg, self.EXPECTED_SUBJECT_BRANCH_EVENTS)
|
||||
msg = self.get_last_message()
|
||||
self.do_test_message(msg, 'kolaszek pushed tag [a](https://bitbucket.org/kolaszek/repository-name/commits/tag/a)')
|
||||
self.do_test_subject(msg, self.EXPECTED_SUBJECT)
|
||||
|
||||
def test_bitbucket2_on_more_than_one_push_event_filtered_by_branches_ignore(self):
|
||||
# type: () -> None
|
||||
self.url = self.build_webhook_url(branches='changes,development')
|
||||
kwargs = {
|
||||
"HTTP_X_EVENT_KEY": 'pullrequest:push'
|
||||
}
|
||||
expected_message = u"kolaszek pushed tag [a](https://bitbucket.org/kolaszek/repository-name/commits/tag/a)"
|
||||
self.send_and_test_stream_message('v2_more_than_one_push_event',
|
||||
self.EXPECTED_SUBJECT,
|
||||
expected_message, **kwargs)
|
||||
|
||||
@patch('zerver.webhooks.bitbucket2.view.check_send_message')
|
||||
def test_bitbucket2_on_push_event_filtered_by_branches_ignore(
|
||||
self, check_send_message_mock):
|
||||
# type: (MagicMock) -> None
|
||||
self.url = self.build_webhook_url(branches='changes,devlopment')
|
||||
payload = self.get_body('v2_push')
|
||||
result = self.client_post(self.url, payload, content_type="application/json")
|
||||
self.assertFalse(check_send_message_mock.called)
|
||||
self.assert_json_success(result)
|
||||
|
||||
@patch('zerver.webhooks.bitbucket2.view.check_send_message')
|
||||
def test_bitbucket2_on_push_commits_above_limit_filtered_by_branches_ignore(
|
||||
self, check_send_message_mock):
|
||||
# type: (MagicMock) -> None
|
||||
self.url = self.build_webhook_url(branches='changes,devlopment')
|
||||
payload = self.get_body('v2_push_commits_above_limit')
|
||||
result = self.client_post(self.url, payload, content_type="application/json")
|
||||
self.assertFalse(check_send_message_mock.called)
|
||||
self.assert_json_success(result)
|
||||
|
||||
@patch('zerver.webhooks.bitbucket2.view.check_send_message')
|
||||
def test_bitbucket2_on_force_push_event_filtered_by_branches_ignore(
|
||||
self, check_send_message_mock):
|
||||
# type: (MagicMock) -> None
|
||||
self.url = self.build_webhook_url(branches='changes,devlopment')
|
||||
payload = self.get_body('v2_force_push')
|
||||
result = self.client_post(self.url, payload, content_type="application/json")
|
||||
self.assertFalse(check_send_message_mock.called)
|
||||
self.assert_json_success(result)
|
||||
|
||||
@patch('zerver.webhooks.bitbucket2.view.check_send_message')
|
||||
def test_bitbucket2_on_push_multiple_committers_filtered_by_branches_ignore(
|
||||
self, check_send_message_mock):
|
||||
# type: (MagicMock) -> None
|
||||
self.url = self.build_webhook_url(branches='changes,devlopment')
|
||||
payload = self.get_body('v2_push_multiple_committers')
|
||||
result = self.client_post(self.url, payload, content_type="application/json")
|
||||
self.assertFalse(check_send_message_mock.called)
|
||||
self.assert_json_success(result)
|
||||
|
||||
@patch('zerver.webhooks.bitbucket2.view.check_send_message')
|
||||
def test_bitbucket2_on_push_multiple_committers_with_others_filtered_by_branches_ignore(
|
||||
self, check_send_message_mock):
|
||||
# type: (MagicMock) -> None
|
||||
self.url = self.build_webhook_url(branches='changes,devlopment')
|
||||
payload = self.get_body('v2_push_multiple_committers_with_others')
|
||||
result = self.client_post(self.url, payload, content_type="application/json")
|
||||
self.assertFalse(check_send_message_mock.called)
|
||||
self.assert_json_success(result)
|
||||
|
||||
@@ -42,8 +42,8 @@ class UnknownTriggerType(Exception):
|
||||
@api_key_only_webhook_view('Bitbucket2')
|
||||
@has_request_variables
|
||||
def api_bitbucket2_webhook(request, user_profile, client, payload=REQ(argument_type='body'),
|
||||
stream=REQ(default='bitbucket')):
|
||||
# type: (HttpRequest, UserProfile, Client, Dict[str, Any], str) -> HttpResponse
|
||||
stream=REQ(default='bitbucket'), branches=REQ(default=None)):
|
||||
# type: (HttpRequest, UserProfile, Client, Dict[str, Any], str, Optional[Text]) -> HttpResponse
|
||||
try:
|
||||
type = get_type(request, payload)
|
||||
if type != 'push':
|
||||
@@ -51,6 +51,10 @@ def api_bitbucket2_webhook(request, user_profile, client, payload=REQ(argument_t
|
||||
body = get_body_based_on_type(type)(payload)
|
||||
check_send_message(user_profile, client, 'stream', [stream], subject, body)
|
||||
else:
|
||||
branch = get_branch_name_for_push_event(payload)
|
||||
if branch and branches:
|
||||
if branches.find(branch) == -1:
|
||||
return json_success()
|
||||
subjects = get_push_subjects(payload)
|
||||
bodies_list = get_push_bodies(payload)
|
||||
for body, subject in zip(bodies_list, subjects):
|
||||
@@ -339,12 +343,13 @@ def get_user_username(payload):
|
||||
return payload['actor']['username']
|
||||
|
||||
def get_branch_name_for_push_event(payload):
|
||||
# type: (Dict[str, Any]) -> str
|
||||
# type: (Dict[str, Any]) -> Optional[str]
|
||||
change = payload['push']['changes'][-1]
|
||||
if change.get('new'):
|
||||
return change['new']['name']
|
||||
potential_tag = (change['new'] or change['old'] or {}).get('type')
|
||||
if potential_tag == 'tag':
|
||||
return None
|
||||
else:
|
||||
return change['old']['name']
|
||||
return (change['new'] or change['old']).get('name')
|
||||
|
||||
GET_SINGLE_MESSAGE_BODY_DEPENDING_ON_TYPE_MAPPER = {
|
||||
'fork': get_fork_body,
|
||||
|
||||
Reference in New Issue
Block a user