zerver/webhooks: Use python 3 syntax for typing.

Tweaked by tabbott to fix various line-wrapping issues.
This commit is contained in:
rht
2017-11-04 07:47:46 +01:00
committed by Tim Abbott
parent 68b0a419ec
commit 969cc506d2
80 changed files with 797 additions and 1508 deletions

View File

@@ -6,8 +6,7 @@ class AirbrakeHookTests(WebhookTestCase):
URL_TEMPLATE = u"/api/v1/external/airbrake?stream={stream}&api_key={api_key}"
FIXTURE_DIR_NAME = 'airbrake'
def test_airbrake_error_message(self):
# type: () -> None
def test_airbrake_error_message(self) -> None:
expected_subject = u"ZulipIntegrationTest"
expected_message = u"[ZeroDivisionError](https://zulip.airbrake.io/projects/125209/groups/1705190192091077626): \"Error message from logger\" occurred."
self.send_and_test_stream_message('error_message', expected_subject, expected_message)

View File

@@ -23,12 +23,10 @@ def api_airbrake_webhook(request, user_profile,
stream, subject, body)
return json_success()
def get_subject(payload):
# type: (Dict[str, Any]) -> str
def get_subject(payload: Dict[str, Any]) -> str:
return AIRBRAKE_SUBJECT_TEMPLATE.format(project_name=payload['error']['project']['name'])
def get_body(payload):
# type: (Dict[str, Any]) -> str
def get_body(payload: Dict[str, Any]) -> str:
data = {
'error_url': payload['airbrake_error_url'],
'error_class': payload['error']['error_class'],

View File

@@ -9,16 +9,14 @@ class AppFollowHookTests(WebhookTestCase):
STREAM_NAME = 'appfollow'
URL_TEMPLATE = u"/api/v1/external/appfollow?stream={stream}&api_key={api_key}"
def test_sample(self):
# type: () -> None
def test_sample(self) -> None:
expected_subject = "Webhook integration was successful."
expected_message = u"""Webhook integration was successful.
Test User / Acme (Google Play)"""
self.send_and_test_stream_message('sample', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_reviews(self):
# type: () -> None
def test_reviews(self) -> None:
expected_subject = "Acme - Group chat"
expected_message = u"""Acme - Group chat
App Store, Acme Technologies, Inc.
@@ -30,20 +28,16 @@ Acme enables me to manage the flow of information quite well. I only wish I coul
self.send_and_test_stream_message('review', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def get_body(self, fixture_name):
# type: (Text) -> Text
def get_body(self, fixture_name: Text) -> Text:
return self.fixture_data("appfollow", fixture_name, file_type="json")
class ConvertMarkdownTest(TestCase):
def test_convert_bold(self):
# type: () -> None
def test_convert_bold(self) -> None:
self.assertEqual(convert_markdown("*test message*"), "**test message**")
def test_convert_italics(self):
# type: () -> None
def test_convert_italics(self) -> None:
self.assertEqual(convert_markdown("_test message_"), "*test message*")
self.assertEqual(convert_markdown("_ spaced message _"), " *spaced message* ")
def test_convert_strikethrough(self):
# type: () -> None
def test_convert_strikethrough(self) -> None:
self.assertEqual(convert_markdown("~test message~"), "~~test message~~")

View File

@@ -24,8 +24,7 @@ def api_appfollow_webhook(request, user_profile, stream=REQ(default="appfollow")
app_name, convert_markdown(message))
return json_success()
def convert_markdown(text):
# type: (Text) -> Text
def convert_markdown(text: Text) -> Text:
# Converts Slack-style markdown to Zulip format
# Implemented mainly for AppFollow messages
# Not ready for general use as some edge-cases not handled

View File

@@ -8,156 +8,125 @@ class BasecampHookTests(WebhookTestCase):
FIXTURE_DIR_NAME = 'basecamp'
EXPECTED_SUBJECT = "Zulip HQ"
def test_basecamp_makes_doc_active(self):
# type: () -> None
def test_basecamp_makes_doc_active(self) -> None:
expected_message = u"Tomasz activated the document [New doc](https://3.basecamp.com/3688623/buckets/2957043/documents/432522214)"
self._send_and_test_message('doc_active', expected_message)
def test_basecamp_makes_doc_archived(self):
# type: () -> None
def test_basecamp_makes_doc_archived(self) -> None:
expected_message = u"Tomasz archived the document [new doc](https://3.basecamp.com/3688623/buckets/2957043/documents/434455988)"
self._send_and_test_message('doc_archived', expected_message)
def test_basecamp_makes_doc_changed_content(self):
# type: () -> None
def test_basecamp_makes_doc_changed_content(self) -> None:
expected_message = u"Tomasz changed content of the document [New doc edit](https://3.basecamp.com/3688623/buckets/2957043/documents/432522214)"
self._send_and_test_message('doc_content_changed', expected_message)
def test_basecamp_makes_doc_changed_title(self):
# type: () -> None
def test_basecamp_makes_doc_changed_title(self) -> None:
expected_message = u"Tomasz changed title of the document [New doc edit](https://3.basecamp.com/3688623/buckets/2957043/documents/432522214)"
self._send_and_test_message('doc_title_changed', expected_message)
def test_basecamp_makes_doc_publicized(self):
# type: () -> None
def test_basecamp_makes_doc_publicized(self) -> None:
expected_message = u"Tomasz publicized the document [new doc](https://3.basecamp.com/3688623/buckets/2957043/documents/434455988)"
self._send_and_test_message('doc_publicized', expected_message)
def test_basecamp_makes_doc_created(self):
# type: () -> None
def test_basecamp_makes_doc_created(self) -> None:
expected_message = u"Tomasz created the document [new doc](https://3.basecamp.com/3688623/buckets/2957043/documents/434455988)"
self._send_and_test_message('doc_created', expected_message)
def test_basecamp_makes_doc_trashed(self):
# type: () -> None
def test_basecamp_makes_doc_trashed(self) -> None:
expected_message = u"Tomasz trashed the document [new doc](https://3.basecamp.com/3688623/buckets/2957043/documents/434455988)"
self._send_and_test_message('doc_trashed', expected_message)
def test_basecamp_makes_doc_unarchived(self):
# type: () -> None
def test_basecamp_makes_doc_unarchived(self) -> None:
expected_message = u"Tomasz unarchived the document [new doc](https://3.basecamp.com/3688623/buckets/2957043/documents/434455988)"
self._send_and_test_message('doc_unarchive', expected_message)
def test_basecamp_makes_questions_answer_archived(self):
# type: () -> None
def test_basecamp_makes_questions_answer_archived(self) -> None:
expected_message = u"Tomasz archived the [answer](https://3.basecamp.com/3688623/buckets/2957043/questions/432527747/answers/2017-03-16#__recording_432529636) of the question [Question](https://3.basecamp.com/3688623/buckets/2957043/questions/432527747)"
self._send_and_test_message('questions_answer_archived', expected_message)
def test_basecamp_makes_questions_answer_content_changed(self):
# type: () -> None
def test_basecamp_makes_questions_answer_content_changed(self) -> None:
expected_message = u"Tomasz changed content of the [answer](https://3.basecamp.com/3688623/buckets/2957043/questions/432527747/answers/2017-03-16#__recording_432529636) of the question [Question](https://3.basecamp.com/3688623/buckets/2957043/questions/432527747)"
self._send_and_test_message('questions_answer_content_changed', expected_message)
def test_basecamp_makes_questions_answer_created(self):
# type: () -> None
def test_basecamp_makes_questions_answer_created(self) -> None:
expected_message = u"Tomasz created the [answer](https://3.basecamp.com/3688623/buckets/2957043/questions/432527747/answers/2017-03-16#__recording_432529636) of the question [Question](https://3.basecamp.com/3688623/buckets/2957043/questions/432527747)"
self._send_and_test_message('questions_answer_created', expected_message)
def test_basecamp_makes_questions_answer_trashed(self):
# type: () -> None
def test_basecamp_makes_questions_answer_trashed(self) -> None:
expected_message = u"Tomasz trashed the [answer](https://3.basecamp.com/3688623/buckets/2957043/question_answers/432529636) of the question [Question](https://3.basecamp.com/3688623/buckets/2957043/questions/432527747)"
self._send_and_test_message('questions_answer_trashed', expected_message)
def test_basecamp_makes_questions_answer_unarchived(self):
# type: () -> None
def test_basecamp_makes_questions_answer_unarchived(self) -> None:
expected_message = u"Tomasz unarchived the [answer](https://3.basecamp.com/3688623/buckets/2957043/questions/432527747/answers/2017-03-16#__recording_432529636) of the question [Question](https://3.basecamp.com/3688623/buckets/2957043/questions/432527747)"
self._send_and_test_message('questions_answer_unarchived', expected_message)
def test_basecamp_makes_question_archived(self):
# type: () -> None
def test_basecamp_makes_question_archived(self) -> None:
expected_message = u"Tomasz archived the question [Question](https://3.basecamp.com/3688623/buckets/2957043/questions/432527747)"
self._send_and_test_message('question_archived', expected_message)
def test_basecamp_makes_question_created(self):
# type: () -> None
def test_basecamp_makes_question_created(self) -> None:
expected_message = u"Tomasz created the question [Question](https://3.basecamp.com/3688623/buckets/2957043/questions/432527747)"
self._send_and_test_message('question_created', expected_message)
def test_basecamp_makes_question_trashed(self):
# type: () -> None
def test_basecamp_makes_question_trashed(self) -> None:
expected_message = u"Tomasz trashed the question [Question](https://3.basecamp.com/3688623/buckets/2957043/questions/432527747)"
self._send_and_test_message('question_trashed', expected_message)
def test_basecamp_makes_question_unarchived(self):
# type: () -> None
def test_basecamp_makes_question_unarchived(self) -> None:
expected_message = u"Tomasz unarchived the question [Question](https://3.basecamp.com/3688623/buckets/2957043/questions/432527747)"
self._send_and_test_message('question_unarchived', expected_message)
def test_basecamp_makes_message_archived(self):
# type: () -> None
def test_basecamp_makes_message_archived(self) -> None:
expected_message = u"Tomasz archived the message [Message Title new](https://3.basecamp.com/3688623/buckets/2957043/messages/430680605)"
self._send_and_test_message('message_archived', expected_message)
def test_basecamp_makes_message_content_change(self):
# type: () -> None
def test_basecamp_makes_message_content_change(self) -> None:
expected_message = u"Tomasz changed content of the message [Message Title new](https://3.basecamp.com/3688623/buckets/2957043/messages/430680605)"
self._send_and_test_message('message_content_changed', expected_message)
def test_basecamp_makes_message_created(self):
# type: () -> None
def test_basecamp_makes_message_created(self) -> None:
expected_message = u"Tomasz created the message [Message Title](https://3.basecamp.com/3688623/buckets/2957043/messages/430680605)"
self._send_and_test_message('message_created', expected_message)
def test_basecamp_makes_message_title_change(self):
# type: () -> None
def test_basecamp_makes_message_title_change(self) -> None:
expected_message = u"Tomasz changed subject of the message [Message Title new](https://3.basecamp.com/3688623/buckets/2957043/messages/430680605)"
self._send_and_test_message('message_title_changed', expected_message)
def test_basecamp_makes_message_trashed(self):
# type: () -> None
def test_basecamp_makes_message_trashed(self) -> None:
expected_message = u"Tomasz trashed the message [Message Title new](https://3.basecamp.com/3688623/buckets/2957043/messages/430680605)"
self._send_and_test_message('message_trashed', expected_message)
def test_basecamp_makes_message_unarchived(self):
# type: () -> None
def test_basecamp_makes_message_unarchived(self) -> None:
expected_message = u"Tomasz unarchived the message [Message Title new](https://3.basecamp.com/3688623/buckets/2957043/messages/430680605)"
self._send_and_test_message('message_unarchived', expected_message)
def test_basecamp_makes_todo_list_created(self):
# type: () -> None
def test_basecamp_makes_todo_list_created(self) -> None:
expected_message = u"Tomasz created the todo list [NEW TO DO LIST](https://3.basecamp.com/3688623/buckets/2957043/todolists/427050190)"
self._send_and_test_message('todo_list_created', expected_message)
def test_basecamp_makes_todo_list_description_changed(self):
# type: () -> None
def test_basecamp_makes_todo_list_description_changed(self) -> None:
expected_message = u"Tomasz changed description of the todo list [NEW TO DO LIST](https://3.basecamp.com/3688623/buckets/2957043/todolists/427050190)"
self._send_and_test_message('todo_list_description_changed', expected_message)
def test_basecamp_makes_todo_list_modified(self):
# type: () -> None
def test_basecamp_makes_todo_list_modified(self) -> None:
expected_message = u"Tomasz changed name of the todo list [NEW Name TO DO LIST](https://3.basecamp.com/3688623/buckets/2957043/todolists/427050190)"
self._send_and_test_message('todo_list_name_changed', expected_message)
def test_basecamp_makes_todo_assignment_changed(self):
# type: () -> None
def test_basecamp_makes_todo_assignment_changed(self) -> None:
expected_message = u"Tomasz changed assignment of the todo task [New task](https://3.basecamp.com/3688623/buckets/2957043/todos/427055624)"
self._send_and_test_message('todo_assignment_changed', expected_message)
def test_basecamp_makes_todo_completed(self):
# type: () -> None
def test_basecamp_makes_todo_completed(self) -> None:
expected_message = u"Tomasz completed the todo task [New task](https://3.basecamp.com/3688623/buckets/2957043/todos/427055624)"
self._send_and_test_message('todo_completed', expected_message)
def test_basecamp_makes_todo_created(self):
# type: () -> None
def test_basecamp_makes_todo_created(self) -> None:
expected_message = u"Tomasz created the todo task [New task](https://3.basecamp.com/3688623/buckets/2957043/todos/427055624)"
self._send_and_test_message('todo_created', expected_message)
def test_basecamp_makes_comment_created(self):
# type: () -> None
def test_basecamp_makes_comment_created(self) -> None:
expected_message = u"Tomasz created the [comment](https://3.basecamp.com/3688623/buckets/2957043/todos/427055624#__recording_427058780) of the task [New task](https://3.basecamp.com/3688623/buckets/2957043/todos/427055624)"
self._send_and_test_message('comment_created', expected_message)
def _send_and_test_message(self, fixture_name, expected_message):
# type: (Text, Text) -> None
def _send_and_test_message(self, fixture_name: Text, expected_message: Text) -> None:
self.send_and_test_stream_message(fixture_name, self.EXPECTED_SUBJECT, expected_message)

View File

@@ -55,28 +55,22 @@ def api_basecamp_webhook(request, user_profile, payload=REQ(argument_type='body'
stream, subject, body)
return json_success()
def get_project_name(payload):
# type: (Dict[str, Any]) -> Text
def get_project_name(payload: Dict[str, Any]) -> Text:
return payload['recording']['bucket']['name']
def get_event_type(payload):
# type: (Dict[str, Any]) -> Text
def get_event_type(payload: Dict[str, Any]) -> Text:
return payload['kind']
def get_event_creator(payload):
# type: (Dict[str, Any]) -> Text
def get_event_creator(payload: Dict[str, Any]) -> Text:
return payload['creator']['name']
def get_subject_url(payload):
# type: (Dict[str, Any]) -> Text
def get_subject_url(payload: Dict[str, Any]) -> Text:
return payload['recording']['app_url']
def get_subject_title(payload):
# type: (Dict[str, Any]) -> Text
def get_subject_title(payload: Dict[str, Any]) -> Text:
return payload['recording']['title']
def get_verb(event, prefix):
# type: (Text, Text) -> Text
def get_verb(event: Text, prefix: Text) -> Text:
verb = event.replace(prefix, '')
if verb == 'active':
return 'activated'
@@ -86,12 +80,10 @@ def get_verb(event, prefix):
return "changed {} of".format(matched.group('subject'))
return verb
def get_document_body(event, payload):
# type: (Text, Dict[str, Any]) -> Text
def get_document_body(event: Text, payload: Dict[str, Any]) -> Text:
return get_generic_body(event, payload, 'document_', DOCUMENT_TEMPLATE)
def get_questions_answer_body(event, payload):
# type: (Text, Dict[str, Any]) -> Text
def get_questions_answer_body(event: Text, payload: Dict[str, Any]) -> Text:
verb = get_verb(event, 'question_answer_')
question = payload['recording']['parent']
@@ -103,8 +95,7 @@ def get_questions_answer_body(event, payload):
question_url=question['app_url']
)
def get_comment_body(event, payload):
# type: (Text, Dict[str, Any]) -> Text
def get_comment_body(event: Text, payload: Dict[str, Any]) -> Text:
verb = get_verb(event, 'comment_')
task = payload['recording']['parent']
@@ -116,24 +107,19 @@ def get_comment_body(event, payload):
task_url=task['app_url']
)
def get_questions_body(event, payload):
# type: (Text, Dict[str, Any]) -> Text
def get_questions_body(event: Text, payload: Dict[str, Any]) -> Text:
return get_generic_body(event, payload, 'question_', QUESTION_TEMPLATE)
def get_message_body(event, payload):
# type: (Text, Dict[str, Any]) -> Text
def get_message_body(event: Text, payload: Dict[str, Any]) -> Text:
return get_generic_body(event, payload, 'message_', MESSAGE_TEMPLATE)
def get_todo_list_body(event, payload):
# type: (Text, Dict[str, Any]) -> Text
def get_todo_list_body(event: Text, payload: Dict[str, Any]) -> Text:
return get_generic_body(event, payload, 'todolist_', TODO_LIST_TEMPLATE)
def get_todo_body(event, payload):
# type: (Text, Dict[str, Any]) -> Text
def get_todo_body(event: Text, payload: Dict[str, Any]) -> Text:
return get_generic_body(event, payload, 'todo_', TODO_TEMPLATE)
def get_generic_body(event, payload, prefix, template):
# type: (Text, Dict[str, Any], Text, Text) -> Text
def get_generic_body(event: Text, payload: Dict[str, Any], prefix: Text, template: Text) -> Text:
verb = get_verb(event, prefix)
return template.format(

View File

@@ -9,8 +9,7 @@ class BeanstalkHookTests(WebhookTestCase):
STREAM_NAME = 'commits'
URL_TEMPLATE = u"/api/v1/external/beanstalk"
def test_git_single(self):
# type: () -> None
def test_git_single(self) -> None:
expected_subject = "work-test / master"
expected_message = """Leo Franchi [pushed](http://lfranchi-svn.beanstalkapp.com/work-test) 1 commit to branch master.
@@ -19,8 +18,7 @@ class BeanstalkHookTests(WebhookTestCase):
content_type=None,
**self.api_auth(self.TEST_USER_EMAIL))
def test_git_single_filtered_by_branches(self):
# type: () -> None
def test_git_single_filtered_by_branches(self) -> None:
self.url = self.build_webhook_url(branches='master,development')
expected_subject = "work-test / master"
expected_message = """Leo Franchi [pushed](http://lfranchi-svn.beanstalkapp.com/work-test) 1 commit to branch master.
@@ -30,8 +28,7 @@ class BeanstalkHookTests(WebhookTestCase):
content_type=None,
**self.api_auth(self.TEST_USER_EMAIL))
def test_git_multiple_committers(self):
# type: () -> None
def test_git_multiple_committers(self) -> None:
expected_subject = "work-test / master"
expected_message = """Leo Franchi [pushed](http://lfranchi-svn.beanstalkapp.com/work-test) 3 commits to branch master. Commits by Leo Franchi (2) and Tomasz Kolek (1).
@@ -42,8 +39,7 @@ class BeanstalkHookTests(WebhookTestCase):
content_type=None,
**self.api_auth(self.TEST_USER_EMAIL))
def test_git_multiple_committers_filtered_by_branches(self):
# type: () -> None
def test_git_multiple_committers_filtered_by_branches(self) -> None:
self.url = self.build_webhook_url(branches='master,development')
expected_subject = "work-test / master"
expected_message = """Leo Franchi [pushed](http://lfranchi-svn.beanstalkapp.com/work-test) 3 commits to branch master. Commits by Leo Franchi (2) and Tomasz Kolek (1).
@@ -55,8 +51,7 @@ class BeanstalkHookTests(WebhookTestCase):
content_type=None,
**self.api_auth(self.TEST_USER_EMAIL))
def test_git_multiple(self):
# type: () -> None
def test_git_multiple(self) -> None:
expected_subject = "work-test / master"
expected_message = """Leo Franchi [pushed](http://lfranchi-svn.beanstalkapp.com/work-test) 3 commits to branch master.
@@ -67,8 +62,7 @@ class BeanstalkHookTests(WebhookTestCase):
content_type=None,
**self.api_auth(self.TEST_USER_EMAIL))
def test_git_multiple_filtered_by_branches(self):
# type: () -> None
def test_git_multiple_filtered_by_branches(self) -> None:
self.url = self.build_webhook_url(branches='master,development')
expected_subject = "work-test / master"
expected_message = """Leo Franchi [pushed](http://lfranchi-svn.beanstalkapp.com/work-test) 3 commits to branch master.
@@ -80,8 +74,7 @@ class BeanstalkHookTests(WebhookTestCase):
content_type=None,
**self.api_auth(self.TEST_USER_EMAIL))
def test_git_more_than_limit(self):
# type: () -> None
def test_git_more_than_limit(self) -> None:
commits_info = "* add some stuff ([e50508d](http://lfranchi-svn.beanstalkapp.com/work-test/changesets/e50508df))\n"
expected_subject = "work-test / master"
expected_message = """Leo Franchi [pushed](http://lfranchi-svn.beanstalkapp.com/work-test) 50 commits to branch master.
@@ -91,8 +84,7 @@ class BeanstalkHookTests(WebhookTestCase):
content_type=None,
**self.api_auth(self.TEST_USER_EMAIL))
def test_git_more_than_limit_filtered_by_branches(self):
# type: () -> None
def test_git_more_than_limit_filtered_by_branches(self) -> None:
self.url = self.build_webhook_url(branches='master,development')
commits_info = "* add some stuff ([e50508d](http://lfranchi-svn.beanstalkapp.com/work-test/changesets/e50508df))\n"
expected_subject = "work-test / master"
@@ -104,8 +96,7 @@ class BeanstalkHookTests(WebhookTestCase):
**self.api_auth(self.TEST_USER_EMAIL))
@patch('zerver.webhooks.beanstalk.view.check_send_stream_message')
def test_git_single_filtered_by_branches_ignore(self, check_send_stream_message_mock):
# type: (MagicMock) -> None
def test_git_single_filtered_by_branches_ignore(self, check_send_stream_message_mock: MagicMock) -> None:
self.url = self.build_webhook_url(branches='changes,development')
payload = self.get_body('git_singlecommit')
result = self.client_post(self.url, payload,
@@ -146,8 +137,7 @@ class BeanstalkHookTests(WebhookTestCase):
self.assertFalse(check_send_stream_message_mock.called)
self.assert_json_success(result)
def test_svn_addremove(self):
# type: () -> None
def test_svn_addremove(self) -> None:
expected_subject = "svn r3"
expected_message = """Leo Franchi pushed [revision 3](http://lfranchi-svn.beanstalkapp.com/work-test/changesets/3):
@@ -156,8 +146,7 @@ class BeanstalkHookTests(WebhookTestCase):
content_type=None,
**self.api_auth(self.TEST_USER_EMAIL))
def test_svn_changefile(self):
# type: () -> None
def test_svn_changefile(self) -> None:
expected_subject = "svn r2"
expected_message = """Leo Franchi pushed [revision 2](http://lfranchi-svn.beanstalkapp.com/work-test/changesets/2):
@@ -166,6 +155,5 @@ class BeanstalkHookTests(WebhookTestCase):
content_type=None,
**self.api_auth(self.TEST_USER_EMAIL))
def get_body(self, fixture_name):
# type: (Text) -> Dict[str, Text]
def get_body(self, fixture_name: Text) -> Dict[str, Text]:
return {'payload': self.fixture_data('beanstalk', fixture_name)}

View File

@@ -21,11 +21,9 @@ ViewFuncT = TypeVar('ViewFuncT', bound=Callable[..., HttpResponse])
# Beanstalk's web hook UI rejects url with a @ in the username section of a url
# So we ask the user to replace them with %40
# We manually fix the username here before passing it along to @authenticated_rest_api_view
def beanstalk_decoder(view_func):
# type: (ViewFuncT) -> ViewFuncT
def beanstalk_decoder(view_func: ViewFuncT) -> ViewFuncT:
@wraps(view_func)
def _wrapped_view_func(request, *args, **kwargs):
# type: (HttpRequest, *Any, **Any) -> HttpResponse
def _wrapped_view_func(request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
try:
auth_type, encoded_value = request.META['HTTP_AUTHORIZATION'].split() # type: str, str
if auth_type.lower() == "basic":

View File

@@ -11,16 +11,14 @@ class BitbucketHookTests(WebhookTestCase):
EXPECTED_SUBJECT = u"Repository name"
EXPECTED_SUBJECT_BRANCH_EVENTS = u"Repository name / master"
def test_bitbucket_on_push_event(self):
# type: () -> None
def test_bitbucket_on_push_event(self) -> None:
fixture_name = 'push'
self.url = self.build_webhook_url(payload=self.get_body(fixture_name))
commit_info = u'* c ([25f93d2](https://bitbucket.org/kolaszek/repository-name/commits/25f93d22b719e2d678a7ad5ee0ef0d1fcdf39c12))'
expected_message = u"kolaszek pushed 1 commit to branch master.\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
def test_bitbucket_on_push_event_filtered_by_branches(self) -> None:
fixture_name = 'push'
self.url = self.build_webhook_url(payload=self.get_body(fixture_name),
branches='master,development')
@@ -28,16 +26,14 @@ class BitbucketHookTests(WebhookTestCase):
expected_message = u"kolaszek pushed 1 commit to branch master.\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
def test_bitbucket_on_push_commits_above_limit_event(self) -> None:
fixture_name = 'push_commits_above_limit'
self.url = self.build_webhook_url(payload=self.get_body(fixture_name))
commit_info = u'* c ([25f93d2](https://bitbucket.org/kolaszek/repository-name/commits/25f93d22b719e2d678a7ad5ee0ef0d1fcdf39c12))\n'
expected_message = u"kolaszek pushed 50 commits to branch master.\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
def test_bitbucket_on_push_commits_above_limit_event_filtered_by_branches(self) -> None:
fixture_name = 'push_commits_above_limit'
self.url = self.build_webhook_url(payload=self.get_body(fixture_name),
branches='master,development')
@@ -45,16 +41,14 @@ class BitbucketHookTests(WebhookTestCase):
expected_message = u"kolaszek pushed 50 commits to branch master.\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
def test_bitbucket_on_force_push_event(self) -> None:
fixture_name = 'force_push'
self.url = self.build_webhook_url(payload=self.get_body(fixture_name))
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_stream_message')
def test_bitbucket_on_push_event_filtered_by_branches_ignore(self, check_send_stream_message_mock):
# type: (MagicMock) -> None
def test_bitbucket_on_push_event_filtered_by_branches_ignore(self, check_send_stream_message_mock: MagicMock) -> None:
fixture_name = 'push'
payload = self.get_body(fixture_name)
self.url = self.build_webhook_url(payload=payload,
@@ -79,6 +73,5 @@ class BitbucketHookTests(WebhookTestCase):
self.assertFalse(check_send_stream_message_mock.called)
self.assert_json_success(result)
def get_body(self, fixture_name):
# type: (Text) -> Union[Text, Dict[str, Text]]
def get_body(self, fixture_name: Text) -> Union[Text, Dict[str, Text]]:
return self.fixture_data(self.FIXTURE_DIR_NAME, fixture_name)

View File

@@ -13,55 +13,47 @@ class Bitbucket2HookTests(WebhookTestCase):
EXPECTED_SUBJECT_ISSUE_EVENTS = u"Repository name / Issue #1 Bug"
EXPECTED_SUBJECT_BRANCH_EVENTS = u"Repository name / master"
def test_bitbucket2_on_push_event(self):
# type: () -> None
def test_bitbucket2_on_push_event(self) -> None:
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.\n\n{}".format(commit_info)
self.send_and_test_stream_message('push', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message)
def test_bitbucket2_on_push_commits_multiple_committers(self):
# type: () -> None
def test_bitbucket2_on_push_commits_multiple_committers(self) -> None:
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 zbenjamin (2) and kolaszek (1).\n\n{}* first commit ([84b96ad](https://bitbucket.org/kolaszek/repository-name/commits/84b96adc644a30fd6465b3d196369d880762afed))""".format(commit_info*2)
self.send_and_test_stream_message('push_multiple_committers', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message)
def test_bitbucket2_on_push_commits_multiple_committers_with_others(self):
# type: () -> None
def test_bitbucket2_on_push_commits_multiple_committers_with_others(self) -> None:
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 james (3), Brendon (2), Tomasz (2) and others (3).\n\n{}* first commit ([84b96ad](https://bitbucket.org/kolaszek/repository-name/commits/84b96adc644a30fd6465b3d196369d880762afed))""".format(commit_info*9)
self.send_and_test_stream_message('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
def test_bitbucket2_on_push_commits_multiple_committers_filtered_by_branches(self) -> 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 zbenjamin (2) and kolaszek (1).\n\n{}* first commit ([84b96ad](https://bitbucket.org/kolaszek/repository-name/commits/84b96adc644a30fd6465b3d196369d880762afed))""".format(commit_info*2)
self.send_and_test_stream_message('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
def test_bitbucket2_on_push_commits_multiple_committers_with_others_filtered_by_branches(self) -> 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 james (3), Brendon (2), Tomasz (2) and others (3).\n\n{}* first commit ([84b96ad](https://bitbucket.org/kolaszek/repository-name/commits/84b96adc644a30fd6465b3d196369d880762afed))""".format(commit_info*9)
self.send_and_test_stream_message('push_multiple_committers_with_others', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message)
def test_bitbucket2_on_push_event_filtered_by_branches(self):
# type: () -> None
def test_bitbucket2_on_push_event_filtered_by_branches(self) -> 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.\n\n{}".format(commit_info)
self.send_and_test_stream_message('push', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message)
def test_bitbucket2_on_push_commits_above_limit_event(self):
# type: () -> None
def test_bitbucket2_on_push_commits_above_limit_event(self) -> None:
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('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
def test_bitbucket2_on_push_commits_above_limit_filtered_by_branches(self) -> 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(
@@ -69,142 +61,121 @@ class Bitbucket2HookTests(WebhookTestCase):
)
self.send_and_test_stream_message('push_commits_above_limit', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message)
def test_bitbucket2_on_force_push_event(self):
# type: () -> None
def test_bitbucket2_on_force_push_event(self) -> 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('force_push', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message)
def test_bitbucket2_on_force_push_event_filtered_by_branches(self):
# type: () -> None
def test_bitbucket2_on_force_push_event_filtered_by_branches(self) -> 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('force_push', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message)
def test_bitbucket2_on_remove_branch_event(self):
# type: () -> None
def test_bitbucket2_on_remove_branch_event(self) -> None:
expected_message = u"kolaszek deleted branch master"
self.send_and_test_stream_message('remove_branch', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message)
def test_bitbucket2_on_fork_event(self):
# type: () -> None
def test_bitbucket2_on_fork_event(self) -> None:
expected_message = u"User Tomasz(login: kolaszek) forked the repository into [kolaszek/repository-name2](https://bitbucket.org/kolaszek/repository-name2)."
self.send_and_test_stream_message('fork', self.EXPECTED_SUBJECT, expected_message)
def test_bitbucket2_on_commit_comment_created_event(self):
# type: () -> None
def test_bitbucket2_on_commit_comment_created_event(self) -> None:
expected_message = u"kolaszek [commented](https://bitbucket.org/kolaszek/repository-name/commits/32c4ea19aa3af10acd08e419e2c354941a365d74#comment-3354963) on [32c4ea1](https://bitbucket.org/kolaszek/repository-name/commits/32c4ea19aa3af10acd08e419e2c354941a365d74)\n~~~ quote\nNice fix!\n~~~"
self.send_and_test_stream_message('commit_comment_created', self.EXPECTED_SUBJECT, expected_message)
def test_bitbucket2_on_commit_status_changed_event(self):
# type: () -> None
def test_bitbucket2_on_commit_status_changed_event(self) -> None:
expected_message = u"[System mybuildtool](https://my-build-tool.com/builds/MY-PROJECT/BUILD-777) changed status of https://bitbucket.org/kolaszek/repository-name/9fec847784abb10b2fa567ee63b85bd238955d0e to SUCCESSFUL."
self.send_and_test_stream_message('commit_status_changed', self.EXPECTED_SUBJECT, expected_message)
def test_bitbucket2_on_issue_created_event(self):
# type: () -> None
def test_bitbucket2_on_issue_created_event(self) -> None:
expected_message = u"kolaszek created [Issue #1](https://bitbucket.org/kolaszek/repository-name/issues/2/bug)(assigned to kolaszek)\n\n~~~ quote\nSuch a bug\n~~~"
self.send_and_test_stream_message('issue_created', self.EXPECTED_SUBJECT_ISSUE_EVENTS, expected_message)
def test_bitbucket2_on_issue_updated_event(self):
# type: () -> None
def test_bitbucket2_on_issue_updated_event(self) -> None:
expected_message = u"kolaszek updated [Issue #1](https://bitbucket.org/kolaszek/repository-name/issues/2/bug)"
self.send_and_test_stream_message('issue_updated', self.EXPECTED_SUBJECT_ISSUE_EVENTS, expected_message)
def test_bitbucket2_on_issue_commented_event(self):
# type: () -> None
def test_bitbucket2_on_issue_commented_event(self) -> None:
expected_message = u"kolaszek [commented](https://bitbucket.org/kolaszek/repository-name/issues/2#comment-28973596) on [Issue #1](https://bitbucket.org/kolaszek/repository-name/issues/2/bug)"
self.send_and_test_stream_message('issue_commented', self.EXPECTED_SUBJECT_ISSUE_EVENTS, expected_message)
def test_bitbucket2_on_pull_request_created_event(self):
# type: () -> None
def test_bitbucket2_on_pull_request_created_event(self) -> None:
expected_message = u"kolaszek created [PR #1](https://bitbucket.org/kolaszek/repository-name/pull-requests/1)(assigned to tkolek)\nfrom `new-branch` to `master`\n\n~~~ quote\ndescription\n~~~"
kwargs = {
"HTTP_X_EVENT_KEY": 'pullrequest:created'
}
self.send_and_test_stream_message('pull_request_created_or_updated', self.EXPECTED_SUBJECT_PR_EVENTS, expected_message, **kwargs)
def test_bitbucket2_on_pull_request_updated_event(self):
# type: () -> None
def test_bitbucket2_on_pull_request_updated_event(self) -> None:
expected_message = u"kolaszek updated [PR #1](https://bitbucket.org/kolaszek/repository-name/pull-requests/1)(assigned to tkolek)\nfrom `new-branch` to `master`\n\n~~~ quote\ndescription\n~~~"
kwargs = {
"HTTP_X_EVENT_KEY": 'pullrequest:updated'
}
self.send_and_test_stream_message('pull_request_created_or_updated', self.EXPECTED_SUBJECT_PR_EVENTS, expected_message, **kwargs)
def test_bitbucket2_on_pull_request_approved_event(self):
# type: () -> None
def test_bitbucket2_on_pull_request_approved_event(self) -> None:
expected_message = u"kolaszek approved [PR #1](https://bitbucket.org/kolaszek/repository-name/pull-requests/1)"
kwargs = {
"HTTP_X_EVENT_KEY": 'pullrequest:approved'
}
self.send_and_test_stream_message('pull_request_approved_or_unapproved', self.EXPECTED_SUBJECT_PR_EVENTS, expected_message, **kwargs)
def test_bitbucket2_on_pull_request_unapproved_event(self):
# type: () -> None
def test_bitbucket2_on_pull_request_unapproved_event(self) -> None:
expected_message = u"kolaszek unapproved [PR #1](https://bitbucket.org/kolaszek/repository-name/pull-requests/1)"
kwargs = {
"HTTP_X_EVENT_KEY": 'pullrequest:unapproved'
}
self.send_and_test_stream_message('pull_request_approved_or_unapproved', self.EXPECTED_SUBJECT_PR_EVENTS, expected_message, **kwargs)
def test_bitbucket2_on_pull_request_declined_event(self):
# type: () -> None
def test_bitbucket2_on_pull_request_declined_event(self) -> None:
expected_message = u"kolaszek rejected [PR #1](https://bitbucket.org/kolaszek/repository-name/pull-requests/1)"
kwargs = {
"HTTP_X_EVENT_KEY": 'pullrequest:rejected'
}
self.send_and_test_stream_message('pull_request_fulfilled_or_rejected', self.EXPECTED_SUBJECT_PR_EVENTS, expected_message, **kwargs)
def test_bitbucket2_on_pull_request_fulfilled_event(self):
# type: () -> None
def test_bitbucket2_on_pull_request_fulfilled_event(self) -> None:
expected_message = u"kolaszek merged [PR #1](https://bitbucket.org/kolaszek/repository-name/pull-requests/1)"
kwargs = {
"HTTP_X_EVENT_KEY": 'pullrequest:fulfilled'
}
self.send_and_test_stream_message('pull_request_fulfilled_or_rejected', self.EXPECTED_SUBJECT_PR_EVENTS, expected_message, **kwargs)
def test_bitbucket2_on_pull_request_comment_created_event(self):
# type: () -> None
def test_bitbucket2_on_pull_request_comment_created_event(self) -> None:
expected_message = u"kolaszek [commented](https://bitbucket.org/kolaszek/repository-name/pull-requests/3/_/diff#comment-20576503) on [PR #1](https://bitbucket.org/kolaszek/repository-name/pull-requests/3)\n\n~~~ quote\nComment1\n~~~"
kwargs = {
"HTTP_X_EVENT_KEY": 'pullrequest:comment_created'
}
self.send_and_test_stream_message('pull_request_comment_action', self.EXPECTED_SUBJECT_PR_EVENTS, expected_message, **kwargs)
def test_bitbucket2_on_pull_request_comment_updated_event(self):
# type: () -> None
def test_bitbucket2_on_pull_request_comment_updated_event(self) -> None:
expected_message = u"kolaszek updated a [comment](https://bitbucket.org/kolaszek/repository-name/pull-requests/3/_/diff#comment-20576503) on [PR #1](https://bitbucket.org/kolaszek/repository-name/pull-requests/3)\n\n~~~ quote\nComment1\n~~~"
kwargs = {
"HTTP_X_EVENT_KEY": 'pullrequest:comment_updated'
}
self.send_and_test_stream_message('pull_request_comment_action', self.EXPECTED_SUBJECT_PR_EVENTS, expected_message, **kwargs)
def test_bitbucket2_on_pull_request_comment_deleted_event(self):
# type: () -> None
def test_bitbucket2_on_pull_request_comment_deleted_event(self) -> None:
expected_message = u"kolaszek deleted a [comment](https://bitbucket.org/kolaszek/repository-name/pull-requests/3/_/diff#comment-20576503) on [PR #1](https://bitbucket.org/kolaszek/repository-name/pull-requests/3)\n\n~~~ quote\nComment1\n~~~"
kwargs = {
"HTTP_X_EVENT_KEY": 'pullrequest:comment_deleted'
}
self.send_and_test_stream_message('pull_request_comment_action', self.EXPECTED_SUBJECT_PR_EVENTS, expected_message, **kwargs)
def test_bitbucket2_on_push_one_tag_event(self):
# type: () -> None
def test_bitbucket2_on_push_one_tag_event(self) -> None:
expected_message = u"kolaszek pushed tag [a](https://bitbucket.org/kolaszek/repository-name/commits/tag/a)"
kwargs = {
"HTTP_X_EVENT_KEY": 'pullrequest:push'
}
self.send_and_test_stream_message('push_one_tag', self.EXPECTED_SUBJECT, expected_message, **kwargs)
def test_bitbucket2_on_push_remove_tag_event(self):
# type: () -> None
def test_bitbucket2_on_push_remove_tag_event(self) -> None:
expected_message = u"kolaszek removed tag [a](https://bitbucket.org/kolaszek/repository-name/commits/tag/a)"
kwargs = {
"HTTP_X_EVENT_KEY": 'pullrequest:push'
}
self.send_and_test_stream_message('push_remove_tag', self.EXPECTED_SUBJECT, expected_message, **kwargs)
def test_bitbucket2_on_push_more_than_one_tag_event(self):
# type: () -> None
def test_bitbucket2_on_push_more_than_one_tag_event(self) -> None:
expected_message = u"kolaszek pushed tag [{name}](https://bitbucket.org/kolaszek/repository-name/commits/tag/{name})"
kwargs = {
"HTTP_X_EVENT_KEY": 'pullrequest:push'
@@ -217,8 +188,7 @@ class Bitbucket2HookTests(WebhookTestCase):
self.do_test_subject(msg, self.EXPECTED_SUBJECT)
self.do_test_message(msg, expected_message.format(name='a'))
def test_bitbucket2_on_more_than_one_push_event(self):
# type: () -> None
def test_bitbucket2_on_more_than_one_push_event(self) -> None:
kwargs = {
"HTTP_X_EVENT_KEY": 'pullrequest:push'
}
@@ -230,8 +200,7 @@ class Bitbucket2HookTests(WebhookTestCase):
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
def test_bitbucket2_on_more_than_one_push_event_filtered_by_branches(self) -> None:
self.url = self.build_webhook_url(branches='master,development')
kwargs = {
"HTTP_X_EVENT_KEY": 'pullrequest:push'
@@ -244,8 +213,7 @@ class Bitbucket2HookTests(WebhookTestCase):
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
def test_bitbucket2_on_more_than_one_push_event_filtered_by_branches_ignore(self) -> None:
self.url = self.build_webhook_url(branches='changes,development')
kwargs = {
"HTTP_X_EVENT_KEY": 'pullrequest:push'

View File

@@ -62,15 +62,13 @@ def api_bitbucket2_webhook(request, user_profile, payload=REQ(argument_type='bod
stream, subject, body)
return json_success()
def get_subject_for_branch_specified_events(payload, branch_name=None):
# type: (Dict[str, Any], Optional[Text]) -> Text
def get_subject_for_branch_specified_events(payload: Dict[str, Any], branch_name: Optional[Text]=None) -> Text:
return SUBJECT_WITH_BRANCH_TEMPLATE.format(
repo=get_repository_name(payload['repository']),
branch=get_branch_name_for_push_event(payload) if branch_name is None else branch_name
)
def get_push_subjects(payload):
# type: (Dict[str, Any]) -> List[str]
def get_push_subjects(payload: Dict[str, Any]) -> List[str]:
subjects_list = []
for change in payload['push']['changes']:
potential_tag = (change['new'] or change['old'] or {}).get('type')
@@ -84,13 +82,11 @@ def get_push_subjects(payload):
subjects_list.append(str(get_subject_for_branch_specified_events(payload, branch_name)))
return subjects_list
def get_subject(payload):
# type: (Dict[str, Any]) -> str
def get_subject(payload: Dict[str, Any]) -> str:
assert(payload['repository'] is not None)
return BITBUCKET_SUBJECT_TEMPLATE.format(repository_name=get_repository_name(payload['repository']))
def get_subject_based_on_type(payload, type):
# type: (Dict[str, Any], str) -> Text
def get_subject_based_on_type(payload: Dict[str, Any], type: str) -> Text:
if type.startswith('pull_request'):
return SUBJECT_WITH_PR_OR_ISSUE_INFO_TEMPLATE.format(
repo=get_repository_name(payload['repository']),
@@ -107,8 +103,7 @@ def get_subject_based_on_type(payload, type):
)
return get_subject(payload)
def get_type(request, payload):
# type: (HttpRequest, Dict[str, Any]) -> str
def get_type(request: HttpRequest, payload: Dict[str, Any]) -> str:
event_key = request.META.get("HTTP_X_EVENT_KEY")
if payload.get('push'):
return 'push'
@@ -133,14 +128,12 @@ def get_type(request, payload):
return pull_request_template.format(action)
raise UnknownTriggerType("We don't support {} event type".format(event_key))
def get_body_based_on_type(type):
# type: (str) -> Callable[[Dict[str, Any]], Text]
def get_body_based_on_type(type: str) -> Callable[[Dict[str, Any]], Text]:
fn = GET_SINGLE_MESSAGE_BODY_DEPENDING_ON_TYPE_MAPPER.get(type)
assert callable(fn) # type parameter should be pre-checked, so not None
return fn
def get_push_bodies(payload):
# type: (Dict[str, Any]) -> List[Text]
def get_push_bodies(payload: Dict[str, Any]) -> List[Text]:
messages_list = []
for change in payload['push']['changes']:
potential_tag = (change['new'] or change['old'] or {}).get('type')
@@ -154,15 +147,13 @@ def get_push_bodies(payload):
messages_list.append(get_normal_push_body(payload, change))
return messages_list
def get_remove_branch_push_body(payload, change):
# type: (Dict[str, Any], Dict[str, Any]) -> Text
def get_remove_branch_push_body(payload: Dict[str, Any], change: Dict[str, Any]) -> Text:
return get_remove_branch_event_message(
get_user_username(payload),
change['old']['name'],
)
def get_force_push_body(payload, change):
# type: (Dict[str, Any], Dict[str, Any]) -> Text
def get_force_push_body(payload: Dict[str, Any], change: Dict[str, Any]) -> Text:
return get_force_push_commits_event_message(
get_user_username(payload),
change['links']['html']['href'],
@@ -170,14 +161,12 @@ def get_force_push_body(payload, change):
change['new']['target']['hash']
)
def get_commit_author_name(commit):
# type: (Dict[str, Any]) -> Text
def get_commit_author_name(commit: Dict[str, Any]) -> Text:
if commit['author'].get('user'):
return commit['author']['user'].get('username')
return commit['author']['raw'].split()[0]
def get_normal_push_body(payload, change):
# type: (Dict[str, Any], Dict[str, Any]) -> Text
def get_normal_push_body(payload: Dict[str, Any], change: Dict[str, Any]) -> Text:
commits_data = [{
'name': get_commit_author_name(commit),
'sha': commit.get('hash'),
@@ -193,8 +182,7 @@ def get_normal_push_body(payload, change):
is_truncated=change['truncated']
)
def get_fork_body(payload):
# type: (Dict[str, Any]) -> str
def get_fork_body(payload: Dict[str, Any]) -> str:
return BITBUCKET_FORK_BODY.format(
display_name=get_user_display_name(payload),
username=get_user_username(payload),
@@ -202,8 +190,7 @@ def get_fork_body(payload):
fork_url=get_repository_url(payload['fork'])
)
def get_commit_comment_body(payload):
# type: (Dict[str, Any]) -> Text
def get_commit_comment_body(payload: Dict[str, Any]) -> Text:
comment = payload['comment']
action = u'[commented]({})'.format(comment['links']['html']['href'])
return get_commits_comment_action_message(
@@ -214,8 +201,7 @@ def get_commit_comment_body(payload):
comment['content']['raw'],
)
def get_commit_status_changed_body(payload):
# type: (Dict[str, Any]) -> str
def get_commit_status_changed_body(payload: Dict[str, Any]) -> str:
commit_id = re.match('.*/commit/(?P<commit_id>[A-Za-z0-9]*$)', payload['commit_status']['links']['commit']['href'])
if commit_id:
commit_info = "{}/{}".format(get_repository_url(payload['repository']), commit_id.group('commit_id'))
@@ -229,13 +215,11 @@ def get_commit_status_changed_body(payload):
status=payload['commit_status']['state']
)
def get_issue_commented_body(payload):
# type: (Dict[str, Any]) -> Text
def get_issue_commented_body(payload: Dict[str, Any]) -> Text:
action = '[commented]({}) on'.format(payload['comment']['links']['html']['href'])
return get_issue_action_body(payload, action)
def get_issue_action_body(payload, action):
# type: (Dict[str, Any], str) -> Text
def get_issue_action_body(payload: Dict[str, Any], action: str) -> Text:
issue = payload['issue']
assignee = None
message = None
@@ -253,8 +237,7 @@ def get_issue_action_body(payload, action):
assignee
)
def get_pull_request_action_body(payload, action):
# type: (Dict[str, Any], str) -> Text
def get_pull_request_action_body(payload: Dict[str, Any], action: str) -> Text:
pull_request = payload['pullrequest']
return get_pull_request_event_message(
get_user_username(payload),
@@ -263,8 +246,7 @@ def get_pull_request_action_body(payload, action):
pull_request.get('id')
)
def get_pull_request_created_or_updated_body(payload, action):
# type: (Dict[str, Any], str) -> Text
def get_pull_request_created_or_updated_body(payload: Dict[str, Any], action: str) -> Text:
pull_request = payload['pullrequest']
assignee = None
if pull_request.get('reviewers'):
@@ -281,18 +263,15 @@ def get_pull_request_created_or_updated_body(payload, action):
assignee=assignee
)
def get_pull_request_comment_created_action_body(payload):
# type: (Dict[str, Any]) -> Text
def get_pull_request_comment_created_action_body(payload: Dict[str, Any]) -> Text:
action = '[commented]({})'.format(payload['comment']['links']['html']['href'])
return get_pull_request_comment_action_body(payload, action)
def get_pull_request_deleted_or_updated_comment_action_body(payload, action):
# type: (Dict[str, Any], Text) -> Text
def get_pull_request_deleted_or_updated_comment_action_body(payload: Dict[str, Any], action: Text) -> Text:
action = "{} a [comment]({})".format(action, payload['comment']['links']['html']['href'])
return get_pull_request_comment_action_body(payload, action)
def get_pull_request_comment_action_body(payload, action):
# type: (Dict[str, Any], str) -> Text
def get_pull_request_comment_action_body(payload: Dict[str, Any], action: str) -> Text:
action += ' on'
return get_pull_request_event_message(
get_user_username(payload),
@@ -302,8 +281,7 @@ def get_pull_request_comment_action_body(payload, action):
message=payload['comment']['content']['raw']
)
def get_push_tag_body(payload, change):
# type: (Dict[str, Any], Dict[str, Any]) -> Text
def get_push_tag_body(payload: Dict[str, Any], change: Dict[str, Any]) -> Text:
if change.get('created'):
tag = change['new']
action = 'pushed' # type: Optional[Text]
@@ -320,36 +298,28 @@ def get_push_tag_body(payload, change):
action=action
)
def get_pull_request_title(pullrequest_payload):
# type: (Dict[str, Any]) -> str
def get_pull_request_title(pullrequest_payload: Dict[str, Any]) -> str:
return pullrequest_payload['title']
def get_pull_request_url(pullrequest_payload):
# type: (Dict[str, Any]) -> str
def get_pull_request_url(pullrequest_payload: Dict[str, Any]) -> str:
return pullrequest_payload['links']['html']['href']
def get_repository_url(repository_payload):
# type: (Dict[str, Any]) -> str
def get_repository_url(repository_payload: Dict[str, Any]) -> str:
return repository_payload['links']['html']['href']
def get_repository_name(repository_payload):
# type: (Dict[str, Any]) -> str
def get_repository_name(repository_payload: Dict[str, Any]) -> str:
return repository_payload['name']
def get_repository_full_name(repository_payload):
# type: (Dict[str, Any]) -> str
def get_repository_full_name(repository_payload: Dict[str, Any]) -> str:
return repository_payload['full_name']
def get_user_display_name(payload):
# type: (Dict[str, Any]) -> str
def get_user_display_name(payload: Dict[str, Any]) -> str:
return payload['actor']['display_name']
def get_user_username(payload):
# type: (Dict[str, Any]) -> str
def get_user_username(payload: Dict[str, Any]) -> str:
return payload['actor']['username']
def get_branch_name_for_push_event(payload):
# type: (Dict[str, Any]) -> Optional[str]
def get_branch_name_for_push_event(payload: Dict[str, Any]) -> Optional[str]:
change = payload['push']['changes'][-1]
potential_tag = (change['new'] or change['old'] or {}).get('type')
if potential_tag == 'tag':

View File

@@ -6,26 +6,22 @@ class CircleCiHookTests(WebhookTestCase):
URL_TEMPLATE = u"/api/v1/external/circleci?stream={stream}&api_key={api_key}"
FIXTURE_DIR_NAME = 'circleci'
def test_circleci_build_in_success_status(self):
# type: () -> None
def test_circleci_build_in_success_status(self) -> None:
expected_subject = u"RepoName"
expected_message = u"[Build](https://circleci.com/gh/username/project/build_number) triggered by username on master branch succeeded."
self.send_and_test_stream_message('build_passed', expected_subject, expected_message)
def test_circleci_build_in_failed_status(self):
# type: () -> None
def test_circleci_build_in_failed_status(self) -> None:
expected_subject = u"RepoName"
expected_message = u"[Build](https://circleci.com/gh/username/project/build_number) triggered by username on master branch failed."
self.send_and_test_stream_message('build_failed', expected_subject, expected_message)
def test_circleci_build_in_failed_status_when_previous_build_failed_too(self):
# type: () -> None
def test_circleci_build_in_failed_status_when_previous_build_failed_too(self) -> None:
expected_subject = u"RepoName"
expected_message = u"[Build](https://circleci.com/gh/username/project/build_number) triggered by username on master branch is still failing."
self.send_and_test_stream_message('build_failed_when_previous_build_failed', expected_subject, expected_message)
def test_circleci_build_in_success_status_when_previous_build_failed_too(self):
# type: () -> None
def test_circleci_build_in_success_status_when_previous_build_failed_too(self) -> None:
expected_subject = u"RepoName"
expected_message = u"[Build](https://circleci.com/gh/username/project/build_number) triggered by username on master branch fixed."
self.send_and_test_stream_message('build_passed_when_previous_build_failed', expected_subject, expected_message)

View File

@@ -29,12 +29,10 @@ def api_circleci_webhook(request, user_profile, payload=REQ(argument_type='body'
check_send_stream_message(user_profile, request.client, stream, subject, body)
return json_success()
def get_subject(payload):
# type: (Dict[str, Any]) -> Text
def get_subject(payload: Dict[str, Any]) -> Text:
return CIRCLECI_SUBJECT_TEMPLATE.format(repository_name=payload['reponame'])
def get_body(payload):
# type: (Dict[str, Any]) -> Text
def get_body(payload: Dict[str, Any]) -> Text:
data = {
'build_url': payload['build_url'],
'username': payload['username'],
@@ -43,8 +41,7 @@ def get_body(payload):
}
return CIRCLECI_MESSAGE_TEMPLATE.format(**data)
def get_status(payload):
# type: (Dict[str, Any]) -> Text
def get_status(payload: Dict[str, Any]) -> Text:
status = payload['status']
if payload['previous'] and payload['previous']['status'] == FAILED_STATUS and status == FAILED_STATUS:
return u'is still failing'

View File

@@ -7,32 +7,28 @@ class CodeshipHookTests(WebhookTestCase):
SUBJECT = u"codeship/docs"
FIXTURE_DIR_NAME = 'codeship'
def test_codeship_build_in_testing_status_message(self):
# type: () -> None
def test_codeship_build_in_testing_status_message(self) -> None:
"""
Tests if codeship testing status is mapped correctly
"""
expected_message = u"[Build](https://www.codeship.com/projects/10213/builds/973711) triggered by beanieboi on master branch started."
self.send_and_test_stream_message('testing_build', self.SUBJECT, expected_message)
def test_codeship_build_in_error_status_message(self):
# type: () -> None
def test_codeship_build_in_error_status_message(self) -> None:
"""
Tests if codeship error status is mapped correctly
"""
expected_message = u"[Build](https://www.codeship.com/projects/10213/builds/973711) triggered by beanieboi on master branch failed."
self.send_and_test_stream_message('error_build', self.SUBJECT, expected_message)
def test_codeship_build_in_success_status_message(self):
# type: () -> None
def test_codeship_build_in_success_status_message(self) -> None:
"""
Tests if codeship success status is mapped correctly
"""
expected_message = u"[Build](https://www.codeship.com/projects/10213/builds/973711) triggered by beanieboi on master branch succeeded."
self.send_and_test_stream_message('success_build', self.SUBJECT, expected_message)
def test_codeship_build_in_other_status_status_message(self):
# type: () -> None
def test_codeship_build_in_other_status_status_message(self) -> None:
"""
Tests if codeship other status is mapped correctly
"""

View File

@@ -37,13 +37,11 @@ def api_codeship_webhook(request, user_profile, payload=REQ(argument_type='body'
return json_success()
def get_subject_for_http_request(payload):
# type: (Dict[str, Any]) -> str
def get_subject_for_http_request(payload: Dict[str, Any]) -> str:
return CODESHIP_SUBJECT_TEMPLATE.format(project_name=payload['project_name'])
def get_body_for_http_request(payload):
# type: (Dict[str, Any]) -> str
def get_body_for_http_request(payload: Dict[str, Any]) -> str:
return CODESHIP_MESSAGE_TEMPLATE.format(
build_url=payload['build_url'],
committer=payload['committer'],
@@ -52,7 +50,6 @@ def get_body_for_http_request(payload):
)
def get_status_message(payload):
# type: (Dict[str, Any]) -> str
def get_status_message(payload: Dict[str, Any]) -> str:
build_status = payload['status']
return CODESHIP_STATUS_MAPPER.get(build_status, CODESHIP_DEFAULT_STATUS.format(status=build_status))

View File

@@ -6,14 +6,12 @@ class CrashlyticsHookTests(WebhookTestCase):
URL_TEMPLATE = u"/api/v1/external/crashlytics?stream={stream}&api_key={api_key}"
FIXTURE_DIR_NAME = 'crashlytics'
def test_crashlytics_verification_message(self):
# type: () -> None
def test_crashlytics_verification_message(self) -> None:
expected_subject = u"Setup"
expected_message = u"Webhook has been successfully configured."
self.send_and_test_stream_message('verification', expected_subject, expected_message)
def test_crashlytics_build_in_success_status(self):
# type: () -> None
def test_crashlytics_build_in_success_status(self) -> None:
expected_subject = u"123: Issue Title"
expected_message = u"[Issue](http://crashlytics.com/full/url/to/issue) impacts at least 16 device(s)."
self.send_and_test_stream_message('issue_message', expected_subject, expected_message)

View File

@@ -7,8 +7,7 @@ class DelightedHookTests(WebhookTestCase):
URL_TEMPLATE = "/api/v1/external/delighted?stream={stream}&api_key={api_key}"
FIXTURE_DIR_NAME = 'delighted'
def test_feedback_message_promoter(self):
# type: () -> None
def test_feedback_message_promoter(self) -> None:
expected_subject = "Survey Response"
expected_message = ("Kudos! You have a new promoter.\n"
">Score of 9/10 from charlie_gravis@example.com"
@@ -19,8 +18,7 @@ class DelightedHookTests(WebhookTestCase):
expected_message,
content_type="application/x-www-form-urlencoded")
def test_feedback_message_non_promoter(self):
# type: () -> None
def test_feedback_message_non_promoter(self) -> None:
expected_subject = "Survey Response"
expected_message = ("Great! You have new feedback.\n"
">Score of 5/10 from paul_gravis@example.com"
@@ -32,6 +30,5 @@ class DelightedHookTests(WebhookTestCase):
expected_message,
content_type="application/x-www-form-urlencoded")
def get_body(self, fixture_name):
# type: (Text) -> Text
def get_body(self, fixture_name: Text) -> Text:
return self.fixture_data("delighted", fixture_name, file_type="json")

View File

@@ -9,8 +9,7 @@ from django.http import HttpRequest, HttpResponse
from six import text_type
from typing import Dict, Any, Optional
def body_template(score):
# type: (int) -> str
def body_template(score: int) -> str:
if score >= 7:
return 'Kudos! You have a new promoter.\n>Score of {score}/10 from {email}\n>{comment}'
else:

View File

@@ -17,8 +17,7 @@ class DeskDotComHookTests(WebhookTestCase):
URL_TEMPLATE = "/api/v1/external/deskdotcom"
FIXTURE_DIR_NAME = 'deskdotcom'
def test_static_text_message(self):
# type: () -> None
def test_static_text_message(self) -> None:
expected_subject = u"static text notification"
expected_message = u"This is a custom action."
@@ -27,8 +26,7 @@ class DeskDotComHookTests(WebhookTestCase):
content_type="application/x-www-form-urlencoded",
**self.api_auth(self.TEST_USER_EMAIL))
def test_case_updated_message(self):
# type: () -> None
def test_case_updated_message(self) -> None:
expected_subject = u"case updated notification"
expected_message = (u"Case 2 updated. "
u"Link: <a href='https://deskdotcomtest.desk.com/web/agent/case/2'>"
@@ -38,8 +36,7 @@ class DeskDotComHookTests(WebhookTestCase):
content_type="application/x-www-form-urlencoded",
**self.api_auth(self.TEST_USER_EMAIL))
def test_unicode_text_italian(self):
# type: () -> None
def test_unicode_text_italian(self) -> None:
expected_subject = u"case updated notification"
expected_message = (u"Case 2 updated. "
@@ -50,8 +47,7 @@ class DeskDotComHookTests(WebhookTestCase):
content_type="application/x-www-form-urlencoded",
**self.api_auth(self.TEST_USER_EMAIL))
def test_unicode_text_japanese(self):
# type: () -> None
def test_unicode_text_japanese(self) -> None:
expected_subject = u"case updated notification"
expected_message = (u"Case 2 updated. "
@@ -62,6 +58,5 @@ class DeskDotComHookTests(WebhookTestCase):
content_type="application/x-www-form-urlencoded",
**self.api_auth(self.TEST_USER_EMAIL))
def get_body(self, fixture_name):
# type: (Text) -> Text
def get_body(self, fixture_name: Text) -> Text:
return self.fixture_data("deskdotcom", fixture_name, file_type="txt")

View File

@@ -6,8 +6,7 @@ class FreshdeskHookTests(WebhookTestCase):
STREAM_NAME = 'freshdesk'
URL_TEMPLATE = u"/api/v1/external/freshdesk?stream={stream}"
def test_ticket_creation(self):
# type: () -> None
def test_ticket_creation(self) -> None:
"""
Messages are generated on ticket creation through Freshdesk's
"Dispatch'r" service.
@@ -24,8 +23,7 @@ Priority: **High**
Status: **Pending**"""
self.send_and_test_stream_message('ticket_created', expected_subject, expected_message, content_type="application/x-www-form-urlencoded", **self.api_auth(self.TEST_USER_EMAIL))
def test_status_change(self):
# type: () -> None
def test_status_change(self) -> None:
"""
Messages are generated when a ticket's status changes through
Freshdesk's "Observer" service.
@@ -38,8 +36,7 @@ Status: **Resolved** => **Waiting on Customer**"""
content_type="application/x-www-form-urlencoded",
**self.api_auth(self.TEST_USER_EMAIL))
def test_priority_change(self):
# type: () -> None
def test_priority_change(self) -> None:
"""
Messages are generated when a ticket's priority changes through
Freshdesk's "Observer" service.
@@ -52,8 +49,7 @@ Priority: **High** => **Low**"""
content_type="application/x-www-form-urlencoded",
**self.api_auth(self.TEST_USER_EMAIL))
def note_change(self, fixture, note_type):
# type: (Text, Text) -> None
def note_change(self, fixture: Text, note_type: Text) -> None:
"""
Messages are generated when a note gets added to a ticket through
Freshdesk's "Observer" service.
@@ -64,16 +60,13 @@ Priority: **High** => **Low**"""
content_type="application/x-www-form-urlencoded",
**self.api_auth(self.TEST_USER_EMAIL))
def test_private_note_change(self):
# type: () -> None
def test_private_note_change(self) -> None:
self.note_change("private_note", "private")
def test_public_note_change(self):
# type: () -> None
def test_public_note_change(self) -> None:
self.note_change("public_note", "public")
def test_inline_image(self):
# type: () -> None
def test_inline_image(self) -> None:
"""
Freshdesk sends us descriptions as HTML, so we have to make the
descriptions Zulip markdown-friendly while still doing our best to
@@ -85,6 +78,5 @@ Priority: **High** => **Low**"""
content_type="application/x-www-form-urlencoded",
**self.api_auth(self.TEST_USER_EMAIL))
def get_body(self, fixture_name):
# type: (Text) -> Text
def get_body(self, fixture_name: Text) -> Text:
return self.fixture_data("freshdesk", fixture_name, file_type="json")

View File

@@ -22,16 +22,14 @@ class TicketDict(dict):
an object where each of the keys is an attribute for easy access.
"""
def __getattr__(self, field):
# type: (str) -> Any
def __getattr__(self, field: str) -> Any:
if "_" in field:
return self.get(field)
else:
return self.get("ticket_" + field)
def property_name(property, index):
# type: (str, int) -> str
def property_name(property: str, index: int) -> str:
"""The Freshdesk API is currently pretty broken: statuses are customizable
but the API will only tell you the number associated with the status, not
the name. While we engage the Freshdesk developers about exposing this
@@ -50,8 +48,7 @@ def property_name(property, index):
raise ValueError("Unknown property")
def parse_freshdesk_event(event_string):
# type: (str) -> List[str]
def parse_freshdesk_event(event_string: str) -> List[str]:
"""These are always of the form "{ticket_action:created}" or
"{status:{from:4,to:6}}". Note the lack of string quoting: this isn't
valid JSON so we have to parse it ourselves.
@@ -70,8 +67,7 @@ def parse_freshdesk_event(event_string):
property_name(property, int(to_state))]
def format_freshdesk_note_message(ticket, event_info):
# type: (TicketDict, List[str]) -> str
def format_freshdesk_note_message(ticket: TicketDict, event_info: List[str]) -> str:
"""There are public (visible to customers) and private note types."""
note_type = event_info[1]
content = "%s <%s> added a %s note to [ticket #%s](%s)." % (
@@ -81,8 +77,7 @@ def format_freshdesk_note_message(ticket, event_info):
return content
def format_freshdesk_property_change_message(ticket, event_info):
# type: (TicketDict, List[str]) -> str
def format_freshdesk_property_change_message(ticket: TicketDict, event_info: List[str]) -> str:
"""Freshdesk will only tell us the first event to match our webhook
configuration, so if we change multiple properties, we only get the before
and after data for the first one.
@@ -96,8 +91,7 @@ def format_freshdesk_property_change_message(ticket, event_info):
return content
def format_freshdesk_ticket_creation_message(ticket):
# type: (TicketDict) -> str
def format_freshdesk_ticket_creation_message(ticket: TicketDict) -> str:
"""They send us the description as HTML."""
cleaned_description = convert_html_to_markdown(ticket.description)
content = "%s <%s> created [ticket #%s](%s):\n\n" % (

View File

@@ -9,43 +9,37 @@ class GoogleCodeInTests(WebhookTestCase):
URL_TEMPLATE = "/api/v1/external/gci?&api_key={api_key}&stream={stream}"
FIXTURE_DIR_NAME = 'gci'
def test_abandon_event_message(self):
# type: () -> None
def test_abandon_event_message(self) -> None:
expected_subject = u'Task: Sails unspread it stopped at kearney'
expected_message = u'**student-yqqtag** abandoned the task [Sails unspread it stopped at kearney](https://0.0.0.0:8000/dashboard/tasks/6694926301528064/).'
self.send_and_test_stream_message('task_abandoned_by_student',
expected_subject, expected_message)
def test_comment_event_message(self):
# type: () -> None
def test_comment_event_message(self) -> None:
expected_subject = u'Task: Sails unspread it stopped at kearney'
expected_message = u'**student-yqqtag** commented on the task [Sails unspread it stopped at kearney](https://0.0.0.0:8000/dashboard/tasks/6694926301528064/).'
self.send_and_test_stream_message('student_commented_on_task',
expected_subject, expected_message)
def test_submit_event_message(self):
# type: () -> None
def test_submit_event_message(self) -> None:
expected_subject = u'Task: Sails unspread it stopped at kearney'
expected_message = u'**student-yqqtag** submitted the task [Sails unspread it stopped at kearney](https://0.0.0.0:8000/dashboard/tasks/6694926301528064/).'
self.send_and_test_stream_message('task_submitted_by_student',
expected_subject, expected_message)
def test_claim_event_message(self):
# type: () -> None
def test_claim_event_message(self) -> None:
expected_subject = u'Task: Sails unspread it stopped at kearney'
expected_message = u'**student-yqqtag** claimed the task [Sails unspread it stopped at kearney](https://0.0.0.0:8000/dashboard/tasks/6694926301528064/).'
self.send_and_test_stream_message('task_claimed_by_student',
expected_subject, expected_message)
def test_approve_event_message(self):
# type: () -> None
def test_approve_event_message(self) -> None:
expected_subject = u'Task: Sails unspread it stopped at kearney'
expected_message = u'**eeshangarg** approved the task [Sails unspread it stopped at kearney](https://0.0.0.0:8000/dashboard/tasks/6694926301528064/).'
self.send_and_test_stream_message('task_approved_by_mentor',
expected_subject, expected_message)
def test_needswork_event_message(self):
# type: () -> None
def test_needswork_event_message(self) -> None:
expected_subject = u'Task: Sails unspread it stopped at kearney'
expected_message = u'**eeshangarg** submitted the task [Sails unspread it stopped at kearney](http://localhost:8080/dashboard/tasks/6051711999279104/) for more work.'
self.send_and_test_stream_message('task_submitted_by_mentor_for_more_work',

View File

@@ -15,8 +15,7 @@ GCI_SUBJECT_TEMPLATE = u'Task: {task_name}'
class UnknownEventType(Exception):
pass
def get_abandon_event_body(payload):
# type: (Dict[Text, Any]) -> Text
def get_abandon_event_body(payload: Dict[Text, Any]) -> Text:
return GCI_MESSAGE_TEMPLATE.format(
actor=payload['task_claimed_by'],
action='{}ed'.format(payload['event_type']),
@@ -24,8 +23,7 @@ def get_abandon_event_body(payload):
task_url=payload['task_definition_url'],
)
def get_submit_event_body(payload):
# type: (Dict[Text, Any]) -> Text
def get_submit_event_body(payload: Dict[Text, Any]) -> Text:
return GCI_MESSAGE_TEMPLATE.format(
actor=payload['task_claimed_by'],
action='{}ted'.format(payload['event_type']),
@@ -33,8 +31,7 @@ def get_submit_event_body(payload):
task_url=payload['task_definition_url'],
)
def get_comment_event_body(payload):
# type: (Dict[Text, Any]) -> Text
def get_comment_event_body(payload: Dict[Text, Any]) -> Text:
return GCI_MESSAGE_TEMPLATE.format(
actor=payload['author'],
action='{}ed on'.format(payload['event_type']),
@@ -42,8 +39,7 @@ def get_comment_event_body(payload):
task_url=payload['task_definition_url'],
)
def get_claim_event_body(payload):
# type: (Dict[Text, Any]) -> Text
def get_claim_event_body(payload: Dict[Text, Any]) -> Text:
return GCI_MESSAGE_TEMPLATE.format(
actor=payload['task_claimed_by'],
action='{}ed'.format(payload['event_type']),
@@ -51,8 +47,7 @@ def get_claim_event_body(payload):
task_url=payload['task_definition_url'],
)
def get_approve_event_body(payload):
# type: (Dict[Text, Any]) -> Text
def get_approve_event_body(payload: Dict[Text, Any]) -> Text:
return GCI_MESSAGE_TEMPLATE.format(
actor=payload['author'],
action='{}d'.format(payload['event_type']),
@@ -60,8 +55,7 @@ def get_approve_event_body(payload):
task_url=payload['task_definition_url'],
)
def get_needswork_event_body(payload):
# type: (Dict[Text, Any]) -> Text
def get_needswork_event_body(payload: Dict[Text, Any]) -> Text:
template = "{} for more work.".format(GCI_MESSAGE_TEMPLATE.rstrip('.'))
return template.format(
actor=payload['author'],
@@ -95,14 +89,12 @@ EVENTS_FUNCTION_MAPPER = {
'submit': get_submit_event_body,
}
def get_event(payload):
# type: (Dict[Text, Any]) -> Optional[Text]
def get_event(payload: Dict[Text, Any]) -> Optional[Text]:
event = payload['event_type']
if event in EVENTS_FUNCTION_MAPPER:
return event
raise UnknownEventType(u"Event '{}' is unknown and cannot be handled".format(event)) # nocoverage
def get_body_based_on_event(event):
# type: (Text) -> Any
def get_body_based_on_event(event: Text) -> Any:
return EVENTS_FUNCTION_MAPPER[event]

View File

@@ -18,8 +18,7 @@ class GithubV1HookTests(WebhookTestCase):
* Baz needs to be longer ([06ebe5f](https://github.com/zbenjamin/zulip-test/commit/06ebe5f472a32f6f31fd2a665f0c7442b69cce72))
* Final edit to baz, I swear ([b954491](https://github.com/zbenjamin/zulip-test/commit/b95449196980507f08209bdfdc4f1d611689b7a8))"""
def test_spam_branch_is_ignored(self):
# type: () -> None
def test_spam_branch_is_ignored(self) -> None:
self.SEND_STREAM = True
self.STREAM_NAME = 'commits'
self.BRANCHES = 'dev,staging'
@@ -38,8 +37,7 @@ class GithubV1HookTests(WebhookTestCase):
after_count = Message.objects.count()
self.assertEqual(prior_count, after_count)
def get_body(self, fixture_name):
# type: (Text) -> Dict[str, Text]
def get_body(self, fixture_name: Text) -> Dict[str, Text]:
api_key = self.test_user.api_key
data = ujson.loads(self.fixture_data(self.FIXTURE_DIR_NAME, 'v1_' + fixture_name))
data.update({'email': self.TEST_USER_EMAIL,
@@ -52,31 +50,28 @@ class GithubV1HookTests(WebhookTestCase):
data['branches'] = self.BRANCHES
return data
def basic_test(self, fixture_name, stream_name, expected_subject, expected_content, send_stream=False, branches=None):
# type: (Text, Text, Text, Text, bool, Optional[Text]) -> None
def basic_test(self, fixture_name: Text, stream_name: Text,
expected_subject: Text, expected_content: Text,
send_stream: bool=False, branches: Optional[Text]=None) -> None:
self.STREAM_NAME = stream_name
self.SEND_STREAM = send_stream
self.BRANCHES = branches
self.send_and_test_stream_message(fixture_name, expected_subject, expected_content, content_type=None)
def test_user_specified_branches(self):
# type: () -> None
def test_user_specified_branches(self) -> None:
self.basic_test('push', 'my_commits', 'zulip-test / master', self.push_content,
send_stream=True, branches="master,staging")
def test_user_specified_stream(self):
# type: () -> None
def test_user_specified_stream(self) -> None:
"""Around May 2013 the github webhook started to specify the stream.
Before then, the stream was hard coded to "commits"."""
self.basic_test('push', 'my_commits', 'zulip-test / master', self.push_content,
send_stream=True)
def test_legacy_hook(self):
# type: () -> None
def test_legacy_hook(self) -> None:
self.basic_test('push', 'commits', 'zulip-test / master', self.push_content)
def test_push_multiple_commits(self):
# type: () -> None
def test_push_multiple_commits(self) -> None:
commit_info = "* Add baz ([48c329a](https://github.com/zbenjamin/zulip-test/commit/48c329a0b68a9a379ff195ee3f1c1f4ab0b2a89e))\n"
expected_subject = "zbenjamin [pushed](https://github.com/zbenjamin/zulip-test/compare/4f9adc4777d5...b95449196980) 50 commits to branch master.\n\n{}[and {} more commit(s)]".format(
commit_info * COMMITS_LIMIT,
@@ -84,63 +79,53 @@ class GithubV1HookTests(WebhookTestCase):
)
self.basic_test('push_commits_more_than_limit', 'commits', 'zulip-test / master', expected_subject)
def test_issues_opened(self):
# type: () -> None
def test_issues_opened(self) -> None:
self.basic_test('issues_opened', 'issues',
"zulip-test / Issue #5 The frobnicator doesn't work",
"zbenjamin opened [Issue #5](https://github.com/zbenjamin/zulip-test/issues/5)\n\n~~~ quote\nI tried changing the widgets, but I got:\r\n\r\nPermission denied: widgets are immutable\n~~~")
def test_issue_comment(self):
# type: () -> None
def test_issue_comment(self) -> None:
self.basic_test('issue_comment', 'issues',
"zulip-test / Issue #5 The frobnicator doesn't work",
"zbenjamin [commented](https://github.com/zbenjamin/zulip-test/issues/5#issuecomment-23374280) on [Issue #5](https://github.com/zbenjamin/zulip-test/issues/5)\n\n~~~ quote\nWhoops, I did something wrong.\r\n\r\nI'm sorry.\n~~~")
def test_issues_closed(self):
# type: () -> None
def test_issues_closed(self) -> None:
self.basic_test('issues_closed', 'issues',
"zulip-test / Issue #5 The frobnicator doesn't work",
"zbenjamin closed [Issue #5](https://github.com/zbenjamin/zulip-test/issues/5)")
def test_pull_request_opened(self):
# type: () -> None
def test_pull_request_opened(self) -> None:
self.basic_test('pull_request_opened', 'commits',
"zulip-test / PR #7 Counting is hard.",
"lfaraone opened [PR #7](https://github.com/zbenjamin/zulip-test/pull/7)(assigned to lfaraone)\nfrom `patch-2` to `master`\n\n~~~ quote\nOmitted something I think?\n~~~")
def test_pull_request_closed(self):
# type: () -> None
def test_pull_request_closed(self) -> None:
self.basic_test('pull_request_closed', 'commits',
"zulip-test / PR #7 Counting is hard.",
"zbenjamin closed [PR #7](https://github.com/zbenjamin/zulip-test/pull/7)")
def test_pull_request_synchronize(self):
# type: () -> None
def test_pull_request_synchronize(self) -> None:
self.basic_test('pull_request_synchronize', 'commits',
"zulip-test / PR #13 Even more cowbell.",
"zbenjamin synchronized [PR #13](https://github.com/zbenjamin/zulip-test/pull/13)")
def test_pull_request_comment(self):
# type: () -> None
def test_pull_request_comment(self) -> None:
self.basic_test('pull_request_comment', 'commits',
"zulip-test / PR #9 Less cowbell.",
"zbenjamin [commented](https://github.com/zbenjamin/zulip-test/pull/9#issuecomment-24771110) on [PR #9](https://github.com/zbenjamin/zulip-test/pull/9)\n\n~~~ quote\nYeah, who really needs more cowbell than we already have?\n~~~")
def test_pull_request_comment_user_specified_stream(self):
# type: () -> None
def test_pull_request_comment_user_specified_stream(self) -> None:
self.basic_test('pull_request_comment', 'my_commits',
"zulip-test / PR #9 Less cowbell.",
"zbenjamin [commented](https://github.com/zbenjamin/zulip-test/pull/9#issuecomment-24771110) on [PR #9](https://github.com/zbenjamin/zulip-test/pull/9)\n\n~~~ quote\nYeah, who really needs more cowbell than we already have?\n~~~",
send_stream=True)
def test_commit_comment(self):
# type: () -> None
def test_commit_comment(self) -> None:
self.basic_test('commit_comment', 'commits',
"zulip-test",
"zbenjamin [commented](https://github.com/zbenjamin/zulip-test/commit/7c994678d2f98797d299abed852d3ff9d0834533#commitcomment-4252302) on [7c99467](https://github.com/zbenjamin/zulip-test/commit/7c994678d2f98797d299abed852d3ff9d0834533)\n~~~ quote\nAre we sure this is enough cowbell?\n~~~")
def test_commit_comment_line(self):
# type: () -> None
def test_commit_comment_line(self) -> None:
self.basic_test('commit_comment_line', 'commits',
"zulip-test",
"zbenjamin [commented](https://github.com/zbenjamin/zulip-test/commit/7c994678d2f98797d299abed852d3ff9d0834533#commitcomment-4252307) on [7c99467](https://github.com/zbenjamin/zulip-test/commit/7c994678d2f98797d299abed852d3ff9d0834533)\n~~~ quote\nThis line adds /unlucky/ cowbell (because of its line number). We should remove it.\n~~~")
@@ -158,8 +143,7 @@ class GithubV2HookTests(WebhookTestCase):
* Baz needs to be longer ([06ebe5f](https://github.com/zbenjamin/zulip-test/commit/06ebe5f472a32f6f31fd2a665f0c7442b69cce72))
* Final edit to baz, I swear ([b954491](https://github.com/zbenjamin/zulip-test/commit/b95449196980507f08209bdfdc4f1d611689b7a8))"""
def test_spam_branch_is_ignored(self):
# type: () -> None
def test_spam_branch_is_ignored(self) -> None:
self.SEND_STREAM = True
self.STREAM_NAME = 'commits'
self.BRANCHES = 'dev,staging'
@@ -178,8 +162,7 @@ class GithubV2HookTests(WebhookTestCase):
after_count = Message.objects.count()
self.assertEqual(prior_count, after_count)
def get_body(self, fixture_name):
# type: (Text) -> Dict[str, Text]
def get_body(self, fixture_name: Text) -> Dict[str, Text]:
api_key = self.test_user.api_key
data = ujson.loads(self.fixture_data(self.FIXTURE_DIR_NAME, 'v2_' + fixture_name))
data.update({'email': self.TEST_USER_EMAIL,
@@ -192,27 +175,25 @@ class GithubV2HookTests(WebhookTestCase):
data['branches'] = self.BRANCHES
return data
def basic_test(self, fixture_name, stream_name, expected_subject, expected_content, send_stream=False, branches=None):
# type: (Text, Text, Text, Text, bool, Optional[Text]) -> None
def basic_test(self, fixture_name: Text, stream_name: Text,
expected_subject: Text, expected_content: Text,
send_stream: bool=False, branches: Optional[Text]=None) -> None:
self.STREAM_NAME = stream_name
self.SEND_STREAM = send_stream
self.BRANCHES = branches
self.send_and_test_stream_message(fixture_name, expected_subject, expected_content, content_type=None)
def test_user_specified_branches(self):
# type: () -> None
def test_user_specified_branches(self) -> None:
self.basic_test('push', 'my_commits', 'zulip-test / master', self.push_content,
send_stream=True, branches="master,staging")
def test_user_specified_stream(self):
# type: () -> None
def test_user_specified_stream(self) -> None:
"""Around May 2013 the github webhook started to specify the stream.
Before then, the stream was hard coded to "commits"."""
self.basic_test('push', 'my_commits', 'zulip-test / master', self.push_content,
send_stream=True)
def test_push_multiple_commits(self):
# type: () -> None
def test_push_multiple_commits(self) -> None:
commit_info = "* Add baz ([48c329a](https://github.com/zbenjamin/zulip-test/commit/48c329a0b68a9a379ff195ee3f1c1f4ab0b2a89e))\n"
expected_subject = "zbenjamin [pushed](https://github.com/zbenjamin/zulip-test/compare/4f9adc4777d5...b95449196980) 50 commits to branch master.\n\n{}[and {} more commit(s)]".format(
commit_info * COMMITS_LIMIT,
@@ -220,80 +201,67 @@ class GithubV2HookTests(WebhookTestCase):
)
self.basic_test('push_commits_more_than_limit', 'commits', 'zulip-test / master', expected_subject)
def test_push_multiple_committers(self):
# type: () -> None
def test_push_multiple_committers(self) -> None:
commit_info = "* Add baz ([48c329a](https://github.com/zbenjamin/zulip-test/commit/48c329a0b68a9a379ff195ee3f1c1f4ab0b2a89e))\n"
expected_subject = "zbenjamin [pushed](https://github.com/zbenjamin/zulip-test/compare/4f9adc4777d5...b95449196980) 6 commits to branch master. Commits by tomasz (3), baxthehacker (2) and zbenjamin (1).\n\n{}* Add baz ([48c329a](https://github.com/zbenjamin/zulip-test/commit/48c329a0b68a9a379ff195ee3f1c1f4ab0b2a89e))".format(commit_info * 5)
self.basic_test('push_multiple_committers', 'commits', 'zulip-test / master', expected_subject)
def test_push_multiple_committers_with_others(self):
# type: () -> None
def test_push_multiple_committers_with_others(self) -> None:
commit_info = "* Final edit to baz, I swear ([b954491](https://github.com/zbenjamin/zulip-test/commit/b95449196980507f08209bdfdc4f1d611689b7a8))\n"
expected_subject = "zbenjamin [pushed](https://github.com/zbenjamin/zulip-test/compare/4f9adc4777d5...b95449196980) 10 commits to branch master. Commits by baxthehacker (4), James (3), Tomasz (2) and others (1).\n\n{}* Final edit to baz, I swear ([b954491](https://github.com/zbenjamin/zulip-test/commit/b95449196980507f08209bdfdc4f1d611689b7a8))".format(commit_info * 9)
self.basic_test('push_multiple_committers_with_others', 'commits', 'zulip-test / master', expected_subject)
def test_legacy_hook(self):
# type: () -> None
def test_legacy_hook(self) -> None:
self.basic_test('push', 'commits', 'zulip-test / master', self.push_content)
def test_issues_opened(self):
# type: () -> None
def test_issues_opened(self) -> None:
self.basic_test('issues_opened', 'issues',
"zulip-test / Issue #5 The frobnicator doesn't work",
"zbenjamin opened [Issue #5](https://github.com/zbenjamin/zulip-test/issues/5)\n\n~~~ quote\nI tried changing the widgets, but I got:\r\n\r\nPermission denied: widgets are immutable\n~~~")
def test_issue_comment(self):
# type: () -> None
def test_issue_comment(self) -> None:
self.basic_test('issue_comment', 'issues',
"zulip-test / Issue #5 The frobnicator doesn't work",
"zbenjamin [commented](https://github.com/zbenjamin/zulip-test/issues/5#issuecomment-23374280) on [Issue #5](https://github.com/zbenjamin/zulip-test/issues/5)\n\n~~~ quote\nWhoops, I did something wrong.\r\n\r\nI'm sorry.\n~~~")
def test_issues_closed(self):
# type: () -> None
def test_issues_closed(self) -> None:
self.basic_test('issues_closed', 'issues',
"zulip-test / Issue #5 The frobnicator doesn't work",
"zbenjamin closed [Issue #5](https://github.com/zbenjamin/zulip-test/issues/5)")
def test_pull_request_opened(self):
# type: () -> None
def test_pull_request_opened(self) -> None:
self.basic_test('pull_request_opened', 'commits',
"zulip-test / PR #7 Counting is hard.",
"lfaraone opened [PR #7](https://github.com/zbenjamin/zulip-test/pull/7)(assigned to lfaraone)\nfrom `patch-2` to `master`\n\n~~~ quote\nOmitted something I think?\n~~~")
def test_pull_request_closed(self):
# type: () -> None
def test_pull_request_closed(self) -> None:
self.basic_test('pull_request_closed', 'commits',
"zulip-test / PR #7 Counting is hard.",
"zbenjamin closed [PR #7](https://github.com/zbenjamin/zulip-test/pull/7)")
def test_pull_request_synchronize(self):
# type: () -> None
def test_pull_request_synchronize(self) -> None:
self.basic_test('pull_request_synchronize', 'commits',
"zulip-test / PR #13 Even more cowbell.",
"zbenjamin synchronized [PR #13](https://github.com/zbenjamin/zulip-test/pull/13)")
def test_pull_request_comment(self):
# type: () -> None
def test_pull_request_comment(self) -> None:
self.basic_test('pull_request_comment', 'commits',
"zulip-test / PR #9 Less cowbell.",
"zbenjamin [commented](https://github.com/zbenjamin/zulip-test/pull/9#issuecomment-24771110) on [PR #9](https://github.com/zbenjamin/zulip-test/pull/9)\n\n~~~ quote\nYeah, who really needs more cowbell than we already have?\n~~~")
def test_pull_request_comment_user_specified_stream(self):
# type: () -> None
def test_pull_request_comment_user_specified_stream(self) -> None:
self.basic_test('pull_request_comment', 'my_commits',
"zulip-test / PR #9 Less cowbell.",
"zbenjamin [commented](https://github.com/zbenjamin/zulip-test/pull/9#issuecomment-24771110) on [PR #9](https://github.com/zbenjamin/zulip-test/pull/9)\n\n~~~ quote\nYeah, who really needs more cowbell than we already have?\n~~~",
send_stream=True)
def test_commit_comment(self):
# type: () -> None
def test_commit_comment(self) -> None:
self.basic_test('commit_comment', 'commits',
"zulip-test",
"zbenjamin [commented](https://github.com/zbenjamin/zulip-test/commit/7c994678d2f98797d299abed852d3ff9d0834533#commitcomment-4252302) on [7c99467](https://github.com/zbenjamin/zulip-test/commit/7c994678d2f98797d299abed852d3ff9d0834533)\n~~~ quote\nAre we sure this is enough cowbell?\n~~~")
def test_commit_comment_line(self):
# type: () -> None
def test_commit_comment_line(self) -> None:
self.basic_test('commit_comment_line', 'commits',
"zulip-test",
"zbenjamin [commented](https://github.com/zbenjamin/zulip-test/commit/7c994678d2f98797d299abed852d3ff9d0834533#commitcomment-4252307) on [7c99467](https://github.com/zbenjamin/zulip-test/commit/7c994678d2f98797d299abed852d3ff9d0834533)\n~~~ quote\nThis line adds /unlucky/ cowbell (because of its line number). We should remove it.\n~~~")

View File

@@ -22,15 +22,13 @@ from django.http import HttpRequest, HttpResponse
ZULIP_TEST_REPO_NAME = 'zulip-test'
ZULIP_TEST_REPO_ID = 6893087
def is_test_repository(repository):
# type: (Mapping[Text, Any]) -> bool
def is_test_repository(repository: Mapping[Text, Any]) -> bool:
return repository['name'] == ZULIP_TEST_REPO_NAME and repository['id'] == ZULIP_TEST_REPO_ID
class UnknownEventType(Exception):
pass
def github_pull_request_content(payload):
# type: (Mapping[Text, Any]) -> Text
def github_pull_request_content(payload: Mapping[Text, Any]) -> Text:
pull_request = payload['pull_request']
action = get_pull_request_or_issue_action(payload)
@@ -52,8 +50,7 @@ def github_pull_request_content(payload):
pull_request['number']
)
def github_issues_content(payload):
# type: (Mapping[Text, Any]) -> Text
def github_issues_content(payload: Mapping[Text, Any]) -> Text:
issue = payload['issue']
action = get_pull_request_or_issue_action(payload)
@@ -73,8 +70,7 @@ def github_issues_content(payload):
issue['number'],
)
def github_object_commented_content(payload, type):
# type: (Mapping[Text, Any], Text) -> Text
def github_object_commented_content(payload: Mapping[Text, Any], type: Text) -> Text:
comment = payload['comment']
issue = payload['issue']
action = u'[commented]({}) on'.format(comment['html_url'])
@@ -88,19 +84,18 @@ def github_object_commented_content(payload, type):
type=type
)
def get_pull_request_or_issue_action(payload):
# type: (Mapping[Text, Any]) -> Text
def get_pull_request_or_issue_action(payload: Mapping[Text, Any]) -> Text:
return 'synchronized' if payload['action'] == 'synchronize' else payload['action']
def get_pull_request_or_issue_assignee(object_payload):
# type: (Mapping[Text, Any]) -> Optional[Text]
def get_pull_request_or_issue_assignee(object_payload: Mapping[Text, Any]) -> Optional[Text]:
assignee_dict = object_payload.get('assignee')
if assignee_dict:
return assignee_dict.get('login')
return None
def get_pull_request_or_issue_subject(repository, payload_object, type):
# type: (Mapping[Text, Any], Mapping[Text, Any], Text) -> Text
def get_pull_request_or_issue_subject(repository: Mapping[Text, Any],
payload_object: Mapping[Text, Any],
type: Text) -> Text:
return SUBJECT_WITH_PR_OR_ISSUE_INFO_TEMPLATE.format(
repo=repository['name'],
type=type,
@@ -108,13 +103,16 @@ def get_pull_request_or_issue_subject(repository, payload_object, type):
title=payload_object['title']
)
def github_generic_subject(noun, topic_focus, blob):
# type: (Text, Text, Mapping[Text, Any]) -> Text
def github_generic_subject(noun: Text, topic_focus: Text, blob: Mapping[Text, Any]) -> Text:
# issue and pull_request objects have the same fields we're interested in
return u'%s: %s %d: %s' % (topic_focus, noun, blob['number'], blob['title'])
def api_github_v1(user_profile, event, payload, branches, stream, **kwargs):
# type: (UserProfile, Text, Mapping[Text, Any], Text, Text, **Any) -> Tuple[Text, Text, Text]
def api_github_v1(user_profile: UserProfile,
event: Text,
payload: Mapping[Text, Any],
branches: Text,
stream: Text,
**kwargs: Any) -> Tuple[Text, Text, Text]:
"""
processes github payload with version 1 field specification
`payload` comes in unmodified from github
@@ -298,8 +296,7 @@ def build_message_from_gitlog(user_profile, name, ref, commits, before, after,
return subject, content
def _transform_commits_list_to_common_format(commits):
# type: (List[Dict[str, Any]]) -> List[Dict[str, str]]
def _transform_commits_list_to_common_format(commits: List[Dict[str, Any]]) -> List[Dict[str, str]]:
new_commits_list = []
for commit in commits:
new_commits_list.append({

View File

@@ -6,8 +6,7 @@ from .github.view import api_github_landing
# Since this dispatcher is an API-style endpoint, it needs to be
# explicitly marked as CSRF-exempt
@csrf_exempt
def api_github_webhook_dispatch(request):
# type: (HttpRequest) -> HttpResponse
def api_github_webhook_dispatch(request: HttpRequest) -> HttpResponse:
if request.META.get('HTTP_X_GITHUB_EVENT'):
return api_github_webhook(request)
else:

View File

@@ -18,82 +18,69 @@ class GithubWebhookTest(WebhookTestCase):
EXPECTED_SUBJECT_BRANCH_EVENTS = u"public-repo / changes"
EXPECTED_SUBJECT_WIKI_EVENTS = u"public-repo / Wiki Pages"
def test_ping_event(self):
# type: () -> None
def test_ping_event(self) -> None:
expected_message = u"GitHub webhook has been successfully configured by TomaszKolek"
self.send_and_test_stream_message('ping', self.EXPECTED_SUBJECT_REPO_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='ping')
def test_ping_organization_event(self):
# type: () -> None
def test_ping_organization_event(self) -> None:
expected_message = u"GitHub webhook has been successfully configured by eeshangarg"
self.send_and_test_stream_message('ping_organization', 'zulip-test-org', expected_message, HTTP_X_GITHUB_EVENT='ping')
def test_push_delete_branch(self):
# type: () -> None
def test_push_delete_branch(self) -> None:
expected_message = u"eeshangarg [deleted](https://github.com/eeshangarg/public-repo/compare/2e8cf535fb38...000000000000) the branch feature."
self.send_and_test_stream_message('push_delete_branch', u"public-repo / feature", expected_message, HTTP_X_GITHUB_EVENT='push')
def test_push_local_branch_without_commits(self):
# type: () -> None
def test_push_local_branch_without_commits(self) -> None:
expected_message = u"eeshangarg [pushed](https://github.com/eeshangarg/public-repo/compare/feature) the branch feature."
self.send_and_test_stream_message('push_local_branch_without_commits', u"public-repo / feature", expected_message, HTTP_X_GITHUB_EVENT='push')
def test_push_1_commit(self):
# type: () -> None
def test_push_1_commit(self) -> None:
expected_message = u"baxterthehacker [pushed](https://github.com/baxterthehacker/public-repo/compare/9049f1265b7d...0d1a26e67d8f) 1 commit to branch changes.\n\n* Update README.md ([0d1a26e](https://github.com/baxterthehacker/public-repo/commit/0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c))"
self.send_and_test_stream_message('push_1_commit', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='push')
def test_push_1_commit_without_username(self):
# type: () -> None
def test_push_1_commit_without_username(self) -> None:
expected_message = u"eeshangarg [pushed](https://github.com/eeshangarg/public-repo/compare/0383613da871...2e8cf535fb38) 1 commit to branch changes. Commits by John Snow (1).\n\n* Update the README ([2e8cf53](https://github.com/eeshangarg/public-repo/commit/2e8cf535fb38a3dab2476cdf856efda904ad4c94))"
self.send_and_test_stream_message('push_1_commit_without_username', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='push')
def test_push_1_commit_filtered_by_branches(self):
# type: () -> None
def test_push_1_commit_filtered_by_branches(self) -> None:
self.url = self.build_webhook_url('master,changes')
expected_message = u"baxterthehacker [pushed](https://github.com/baxterthehacker/public-repo/compare/9049f1265b7d...0d1a26e67d8f) 1 commit to branch changes.\n\n* Update README.md ([0d1a26e](https://github.com/baxterthehacker/public-repo/commit/0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c))"
self.send_and_test_stream_message('push_1_commit', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='push')
def test_push_multiple_comitters(self):
# type: () -> None
def test_push_multiple_comitters(self) -> None:
commits_info = u'* Update README.md ([0d1a26e](https://github.com/baxterthehacker/public-repo/commit/0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c))\n'
expected_message = u"""baxterthehacker [pushed](https://github.com/baxterthehacker/public-repo/compare/9049f1265b7d...0d1a26e67d8f) 6 commits to branch changes. Commits by Tomasz (3), Ben (2) and baxterthehacker (1).\n\n{}* Update README.md ([0d1a26e](https://github.com/baxterthehacker/public-repo/commit/0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c))""".format(commits_info * 5)
self.send_and_test_stream_message('push_multiple_committers', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='push')
def test_push_multiple_comitters_with_others(self):
# type: () -> None
def test_push_multiple_comitters_with_others(self) -> None:
commits_info = u'* Update README.md ([0d1a26e](https://github.com/baxterthehacker/public-repo/commit/0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c))\n'
expected_message = u"""baxterthehacker [pushed](https://github.com/baxterthehacker/public-repo/compare/9049f1265b7d...0d1a26e67d8f) 10 commits to branch changes. Commits by Tomasz (4), Ben (3), James (2) and others (1).\n\n{}* Update README.md ([0d1a26e](https://github.com/baxterthehacker/public-repo/commit/0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c))""".format(commits_info * 9)
self.send_and_test_stream_message('push_multiple_committers_with_others', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='push')
def test_push_multiple_comitters_filtered_by_branches(self):
# type: () -> None
def test_push_multiple_comitters_filtered_by_branches(self) -> None:
self.url = self.build_webhook_url('master,changes')
commits_info = u'* Update README.md ([0d1a26e](https://github.com/baxterthehacker/public-repo/commit/0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c))\n'
expected_message = u"""baxterthehacker [pushed](https://github.com/baxterthehacker/public-repo/compare/9049f1265b7d...0d1a26e67d8f) 6 commits to branch changes. Commits by Tomasz (3), Ben (2) and baxterthehacker (1).\n\n{}* Update README.md ([0d1a26e](https://github.com/baxterthehacker/public-repo/commit/0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c))""".format(commits_info * 5)
self.send_and_test_stream_message('push_multiple_committers', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='push')
def test_push_multiple_comitters_with_others_filtered_by_branches(self):
# type: () -> None
def test_push_multiple_comitters_with_others_filtered_by_branches(self) -> None:
self.url = self.build_webhook_url('master,changes')
commits_info = u'* Update README.md ([0d1a26e](https://github.com/baxterthehacker/public-repo/commit/0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c))\n'
expected_message = u"""baxterthehacker [pushed](https://github.com/baxterthehacker/public-repo/compare/9049f1265b7d...0d1a26e67d8f) 10 commits to branch changes. Commits by Tomasz (4), Ben (3), James (2) and others (1).\n\n{}* Update README.md ([0d1a26e](https://github.com/baxterthehacker/public-repo/commit/0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c))""".format(commits_info * 9)
self.send_and_test_stream_message('push_multiple_committers_with_others', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='push')
def test_push_50_commits(self):
# type: () -> None
def test_push_50_commits(self) -> None:
commit_info = "* Update README.md ([0d1a26e](https://github.com/baxterthehacker/public-repo/commit/0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c))\n"
expected_message = u"baxterthehacker [pushed](https://github.com/baxterthehacker/public-repo/compare/9049f1265b7d...0d1a26e67d8f) 50 commits to branch changes.\n\n{}[and 30 more commit(s)]".format(
commit_info * COMMITS_LIMIT
)
self.send_and_test_stream_message('push_50_commits', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='push')
def test_push_50_commits_filtered_by_branches(self):
# type: () -> None
def test_push_50_commits_filtered_by_branches(self) -> None:
self.url = self.build_webhook_url(branches='master,changes')
commit_info = "* Update README.md ([0d1a26e](https://github.com/baxterthehacker/public-repo/commit/0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c))\n"
expected_message = u"baxterthehacker [pushed](https://github.com/baxterthehacker/public-repo/compare/9049f1265b7d...0d1a26e67d8f) 50 commits to branch changes.\n\n{}[and 30 more commit(s)]".format(
@@ -101,145 +88,117 @@ class GithubWebhookTest(WebhookTestCase):
)
self.send_and_test_stream_message('push_50_commits', self.EXPECTED_SUBJECT_BRANCH_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='push')
def test_commit_comment_msg(self):
# type: () -> None
def test_commit_comment_msg(self) -> None:
expected_message = u"baxterthehacker [commented](https://github.com/baxterthehacker/public-repo/commit/9049f1265b7d61be4a8904a9a27120d2064dab3b#commitcomment-11056394) on [9049f12](https://github.com/baxterthehacker/public-repo/commit/9049f1265b7d61be4a8904a9a27120d2064dab3b)\n~~~ quote\nThis is a really good change! :+1:\n~~~"
self.send_and_test_stream_message('commit_comment', self.EXPECTED_SUBJECT_REPO_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='commit_comment')
def test_create_msg(self):
# type: () -> None
def test_create_msg(self) -> None:
expected_message = u"baxterthehacker created tag 0.0.1"
self.send_and_test_stream_message('create', self.EXPECTED_SUBJECT_REPO_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='create')
def test_delete_msg(self):
# type: () -> None
def test_delete_msg(self) -> None:
expected_message = u"baxterthehacker deleted tag simple-tag"
self.send_and_test_stream_message('delete', self.EXPECTED_SUBJECT_REPO_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='delete')
def test_deployment_msg(self):
# type: () -> None
def test_deployment_msg(self) -> None:
expected_message = u"baxterthehacker created new deployment"
self.send_and_test_stream_message('deployment', self.EXPECTED_SUBJECT_DEPLOYMENT_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='deployment')
def test_deployment_status_msg(self):
# type: () -> None
def test_deployment_status_msg(self) -> None:
expected_message = u"Deployment changed status to success"
self.send_and_test_stream_message('deployment_status', self.EXPECTED_SUBJECT_DEPLOYMENT_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='deployment_status')
def test_fork_msg(self):
# type: () -> None
def test_fork_msg(self) -> None:
expected_message = u"baxterandthehackers forked [public-repo](https://github.com/baxterandthehackers/public-repo)"
self.send_and_test_stream_message('fork', self.EXPECTED_SUBJECT_REPO_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='fork')
def test_issue_comment_msg(self):
# type: () -> None
def test_issue_comment_msg(self) -> None:
expected_message = u"baxterthehacker [commented](https://github.com/baxterthehacker/public-repo/issues/2#issuecomment-99262140) on [Issue #2](https://github.com/baxterthehacker/public-repo/issues/2)\n\n~~~ quote\nYou are totally right! I'll get this fixed right away.\n~~~"
self.send_and_test_stream_message('issue_comment', self.EXPECTED_SUBJECT_ISSUE_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='issue_comment')
def test_issue_msg(self):
# type: () -> None
def test_issue_msg(self) -> None:
expected_message = u"baxterthehacker opened [Issue #2](https://github.com/baxterthehacker/public-repo/issues/2)\n\n~~~ quote\nIt looks like you accidently spelled 'commit' with two 't's.\n~~~"
self.send_and_test_stream_message('issue', self.EXPECTED_SUBJECT_ISSUE_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='issues')
def test_membership_msg(self):
# type: () -> None
def test_membership_msg(self) -> None:
expected_message = u"baxterthehacker added [kdaigle](https://github.com/kdaigle) to Contractors team"
self.send_and_test_stream_message('membership', self.EXPECTED_SUBJECT_ORGANIZATION_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='membership')
def test_member_msg(self):
# type: () -> None
def test_member_msg(self) -> None:
expected_message = u"baxterthehacker added [octocat](https://github.com/octocat) to [public-repo](https://github.com/baxterthehacker/public-repo)"
self.send_and_test_stream_message('member', self.EXPECTED_SUBJECT_REPO_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='member')
def test_pull_request_opened_msg(self):
# type: () -> None
def test_pull_request_opened_msg(self) -> None:
expected_message = u"baxterthehacker opened [PR](https://github.com/baxterthehacker/public-repo/pull/1)\nfrom `changes` to `master`\n\n~~~ quote\nThis is a pretty simple change that we need to pull into master.\n~~~"
self.send_and_test_stream_message('opened_pull_request', self.EXPECTED_SUBJECT_PR_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='pull_request')
def test_pull_request_synchronized_msg(self):
# type: () -> None
def test_pull_request_synchronized_msg(self) -> None:
expected_message = u"baxterthehacker updated [PR](https://github.com/baxterthehacker/public-repo/pull/1)\nfrom `changes` to `master`"
self.send_and_test_stream_message('synchronized_pull_request', self.EXPECTED_SUBJECT_PR_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='pull_request')
def test_pull_request_closed_msg(self):
# type: () -> None
def test_pull_request_closed_msg(self) -> None:
expected_message = u"baxterthehacker closed without merge [PR](https://github.com/baxterthehacker/public-repo/pull/1)"
self.send_and_test_stream_message('closed_pull_request', self.EXPECTED_SUBJECT_PR_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='pull_request')
def test_pull_request_merged_msg(self):
# type: () -> None
def test_pull_request_merged_msg(self) -> None:
expected_message = u"baxterthehacker merged [PR](https://github.com/baxterthehacker/public-repo/pull/1)"
self.send_and_test_stream_message('merged_pull_request', self.EXPECTED_SUBJECT_PR_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='pull_request')
def test_public_msg(self):
# type: () -> None
def test_public_msg(self) -> None:
expected_message = u"baxterthehacker made [the repository](https://github.com/baxterthehacker/public-repo) public"
self.send_and_test_stream_message('public', self.EXPECTED_SUBJECT_REPO_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='public')
def test_wiki_pages_msg(self):
# type: () -> None
def test_wiki_pages_msg(self) -> None:
expected_message = u"jasonrudolph:\n* created [Home](https://github.com/baxterthehacker/public-repo/wiki/Home)\n* created [Home](https://github.com/baxterthehacker/public-repo/wiki/Home)"
self.send_and_test_stream_message('wiki_pages', self.EXPECTED_SUBJECT_WIKI_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='gollum')
def test_watch_msg(self):
# type: () -> None
def test_watch_msg(self) -> None:
expected_message = u"baxterthehacker starred [the repository](https://github.com/baxterthehacker/public-repo)"
self.send_and_test_stream_message('watch_repository', self.EXPECTED_SUBJECT_REPO_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='watch')
def test_repository_msg(self):
# type: () -> None
def test_repository_msg(self) -> None:
expected_message = u"baxterthehacker created [the repository](https://github.com/baxterandthehackers/public-repo)"
self.send_and_test_stream_message('repository', self.EXPECTED_SUBJECT_REPO_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='repository')
def test_team_add_msg(self):
# type: () -> None
def test_team_add_msg(self) -> None:
expected_message = u"[The repository](https://github.com/baxterandthehackers/public-repo) was added to team github"
self.send_and_test_stream_message('team_add', self.EXPECTED_SUBJECT_REPO_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='team_add')
def test_release_msg(self):
# type: () -> None
def test_release_msg(self) -> None:
expected_message = u"baxterthehacker published [the release](https://github.com/baxterthehacker/public-repo/releases/tag/0.0.1)"
self.send_and_test_stream_message('release', self.EXPECTED_SUBJECT_REPO_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='release')
def test_page_build_msg(self):
# type: () -> None
def test_page_build_msg(self) -> None:
expected_message = u"Github Pages build, trigerred by baxterthehacker, is built"
self.send_and_test_stream_message('page_build', self.EXPECTED_SUBJECT_REPO_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='page_build')
def test_status_msg(self):
# type: () -> None
def test_status_msg(self) -> None:
expected_message = u"[9049f12](https://github.com/baxterthehacker/public-repo/commit/9049f1265b7d61be4a8904a9a27120d2064dab3b) changed its status to success"
self.send_and_test_stream_message('status', self.EXPECTED_SUBJECT_REPO_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='status')
def test_pull_request_review_msg(self):
# type: () -> None
def test_pull_request_review_msg(self) -> None:
expected_message = u"baxterthehacker submitted [PR Review](https://github.com/baxterthehacker/public-repo/pull/1#pullrequestreview-2626884)"
self.send_and_test_stream_message('pull_request_review', self.EXPECTED_SUBJECT_PR_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='pull_request_review')
def test_pull_request_review_comment_msg(self):
# type: () -> None
def test_pull_request_review_comment_msg(self) -> None:
expected_message = u"baxterthehacker created [PR Review Comment](https://github.com/baxterthehacker/public-repo/pull/1#discussion_r29724692)\n\n~~~ quote\nMaybe you should use more emojji on this line.\n~~~"
self.send_and_test_stream_message('pull_request_review_comment', self.EXPECTED_SUBJECT_PR_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='pull_request_review_comment')
def test_push_tag_msg(self):
# type: () -> None
def test_push_tag_msg(self) -> None:
expected_message = u"baxterthehacker pushed tag abc"
self.send_and_test_stream_message('push_tag', self.EXPECTED_SUBJECT_REPO_EVENTS, expected_message, HTTP_X_GITHUB_EVENT='push')
def test_pull_request_edited_msg(self):
# type: () -> None
def test_pull_request_edited_msg(self) -> None:
expected_message = u"baxterthehacker edited [PR](https://github.com/baxterthehacker/public-repo/pull/1)\nfrom `changes` to `master`"
self.send_and_test_stream_message('edited_pull_request', self.EXPECTED_SUBJECT_PR_EVENTS, expected_message,
HTTP_X_GITHUB_EVENT='pull_request')
def test_pull_request_assigned_msg(self):
# type: () -> None
def test_pull_request_assigned_msg(self) -> None:
expected_message = u"baxterthehacker assigned [PR](https://github.com/baxterthehacker/public-repo/pull/1) to baxterthehacker"
self.send_and_test_stream_message('assigned_pull_request', self.EXPECTED_SUBJECT_PR_EVENTS, expected_message,
HTTP_X_GITHUB_EVENT='pull_request')
def test_pull_request_unassigned_msg(self):
# type: () -> None
def test_pull_request_unassigned_msg(self) -> None:
expected_message = u"eeshangarg unassigned [PR](https://github.com/zulip-test-org/helloworld/pull/1)"
self.send_and_test_stream_message(
'unassigned_pull_request',
@@ -249,40 +208,40 @@ class GithubWebhookTest(WebhookTestCase):
)
@patch('zerver.webhooks.github_webhook.view.check_send_stream_message')
def test_pull_request_labeled_ignore(self, check_send_stream_message_mock):
# type: (MagicMock) -> None
def test_pull_request_labeled_ignore(
self, check_send_stream_message_mock: MagicMock) -> None:
payload = self.get_body('labeled_pull_request')
result = self.client_post(self.url, payload, HTTP_X_GITHUB_EVENT='pull_request', content_type="application/json")
self.assertFalse(check_send_stream_message_mock.called)
self.assert_json_success(result)
@patch('zerver.webhooks.github_webhook.view.check_send_stream_message')
def test_pull_request_unlabeled_ignore(self, check_send_stream_message_mock):
# type: (MagicMock) -> None
def test_pull_request_unlabeled_ignore(
self, check_send_stream_message_mock: MagicMock) -> None:
payload = self.get_body('unlabeled_pull_request')
result = self.client_post(self.url, payload, HTTP_X_GITHUB_EVENT='pull_request', content_type="application/json")
self.assertFalse(check_send_stream_message_mock.called)
self.assert_json_success(result)
@patch('zerver.webhooks.github_webhook.view.check_send_stream_message')
def test_pull_request_request_review_ignore(self, check_send_stream_message_mock):
# type: (MagicMock) -> None
def test_pull_request_request_review_ignore(
self, check_send_stream_message_mock: MagicMock) -> None:
payload = self.get_body('request_review_pull_request')
result = self.client_post(self.url, payload, HTTP_X_GITHUB_EVENT='pull_request', content_type="application/json")
self.assertFalse(check_send_stream_message_mock.called)
self.assert_json_success(result)
@patch('zerver.webhooks.github_webhook.view.check_send_stream_message')
def test_pull_request_request_review_remove_ignore(self, check_send_stream_message_mock):
# type: (MagicMock) -> None
def test_pull_request_request_review_remove_ignore(
self, check_send_stream_message_mock: MagicMock) -> None:
payload = self.get_body('request_review_removed_pull_request')
result = self.client_post(self.url, payload, HTTP_X_GITHUB_EVENT='pull_request', content_type="application/json")
self.assertFalse(check_send_stream_message_mock.called)
self.assert_json_success(result)
@patch('zerver.webhooks.github_webhook.view.check_send_stream_message')
def test_push_1_commit_filtered_by_branches_ignore(self, check_send_stream_message_mock):
# type: (MagicMock) -> None
def test_push_1_commit_filtered_by_branches_ignore(
self, check_send_stream_message_mock: MagicMock) -> None:
self.url = self.build_webhook_url(branches='master,development')
payload = self.get_body('push_1_commit')
result = self.client_post(self.url, payload, HTTP_X_GITHUB_EVENT='push', content_type="application/json")
@@ -290,8 +249,8 @@ class GithubWebhookTest(WebhookTestCase):
self.assert_json_success(result)
@patch('zerver.webhooks.github_webhook.view.check_send_stream_message')
def test_push_50_commits_filtered_by_branches_ignore(self, check_send_stream_message_mock):
# type: (MagicMock) -> None
def test_push_50_commits_filtered_by_branches_ignore(
self, check_send_stream_message_mock: MagicMock) -> None:
self.url = self.build_webhook_url(branches='master,development')
payload = self.get_body('push_50_commits')
result = self.client_post(self.url, payload, HTTP_X_GITHUB_EVENT='push', content_type="application/json")
@@ -299,8 +258,8 @@ class GithubWebhookTest(WebhookTestCase):
self.assert_json_success(result)
@patch('zerver.webhooks.github_webhook.view.check_send_stream_message')
def test_push_multiple_comitters_filtered_by_branches_ignore(self, check_send_stream_message_mock):
# type: (MagicMock) -> None
def test_push_multiple_comitters_filtered_by_branches_ignore(
self, check_send_stream_message_mock: MagicMock) -> None:
self.url = self.build_webhook_url(branches='master,development')
payload = self.get_body('push_multiple_committers')
result = self.client_post(self.url, payload, HTTP_X_GITHUB_EVENT='push', content_type="application/json")
@@ -308,8 +267,8 @@ class GithubWebhookTest(WebhookTestCase):
self.assert_json_success(result)
@patch('zerver.webhooks.github_webhook.view.check_send_stream_message')
def test_push_multiple_comitters_with_others_filtered_by_branches_ignore(self, check_send_stream_message_mock):
# type: (MagicMock) -> None
def test_push_multiple_comitters_with_others_filtered_by_branches_ignore(
self, check_send_stream_message_mock: MagicMock) -> None:
self.url = self.build_webhook_url(branches='master,development')
payload = self.get_body('push_multiple_committers_with_others')
result = self.client_post(self.url, payload, HTTP_X_GITHUB_EVENT='push', content_type="application/json")

View File

@@ -18,8 +18,7 @@ from zerver.lib.webhooks.git import get_issue_event_message, SUBJECT_WITH_PR_OR_
class UnknownEventType(Exception):
pass
def get_opened_or_update_pull_request_body(payload):
# type: (Dict[str, Any]) -> Text
def get_opened_or_update_pull_request_body(payload: Dict[str, Any]) -> Text:
pull_request = payload['pull_request']
action = payload['action']
if action == 'synchronize':
@@ -38,8 +37,7 @@ def get_opened_or_update_pull_request_body(payload):
assignee=assignee
)
def get_assigned_or_unassigned_pull_request_body(payload):
# type: (Dict[str, Any]) -> Text
def get_assigned_or_unassigned_pull_request_body(payload: Dict[str, Any]) -> Text:
pull_request = payload['pull_request']
assignee = pull_request.get('assignee')
if assignee is not None:
@@ -54,8 +52,7 @@ def get_assigned_or_unassigned_pull_request_body(payload):
return "{} to {}".format(base_message, assignee)
return base_message
def get_closed_pull_request_body(payload):
# type: (Dict[str, Any]) -> Text
def get_closed_pull_request_body(payload: Dict[str, Any]) -> Text:
pull_request = payload['pull_request']
action = 'merged' if pull_request['merged'] else 'closed without merge'
return get_pull_request_event_message(
@@ -64,8 +61,7 @@ def get_closed_pull_request_body(payload):
pull_request['html_url'],
)
def get_membership_body(payload):
# type: (Dict[str, Any]) -> Text
def get_membership_body(payload: Dict[str, Any]) -> Text:
action = payload['action']
member = payload['member']
scope = payload['scope']
@@ -80,8 +76,7 @@ def get_membership_body(payload):
scope
)
def get_member_body(payload):
# type: (Dict[str, Any]) -> Text
def get_member_body(payload: Dict[str, Any]) -> Text:
return u"{} {} [{}]({}) to [{}]({})".format(
get_sender_name(payload),
payload['action'],
@@ -91,8 +86,7 @@ def get_member_body(payload):
payload['repository']['html_url']
)
def get_issue_body(payload):
# type: (Dict[str, Any]) -> Text
def get_issue_body(payload: Dict[str, Any]) -> Text:
action = payload['action']
issue = payload['issue']
assignee = issue['assignee']
@@ -105,8 +99,7 @@ def get_issue_body(payload):
assignee=assignee['login'] if assignee else None
)
def get_issue_comment_body(payload):
# type: (Dict[str, Any]) -> Text
def get_issue_comment_body(payload: Dict[str, Any]) -> Text:
action = payload['action']
comment = payload['comment']
issue = payload['issue']
@@ -125,8 +118,7 @@ def get_issue_comment_body(payload):
comment['body'],
)
def get_fork_body(payload):
# type: (Dict[str, Any]) -> Text
def get_fork_body(payload: Dict[str, Any]) -> Text:
forkee = payload['forkee']
return u"{} forked [{}]({})".format(
get_sender_name(payload),
@@ -134,20 +126,17 @@ def get_fork_body(payload):
forkee['html_url']
)
def get_deployment_body(payload):
# type: (Dict[str, Any]) -> Text
def get_deployment_body(payload: Dict[str, Any]) -> Text:
return u'{} created new deployment'.format(
get_sender_name(payload),
)
def get_change_deployment_status_body(payload):
# type: (Dict[str, Any]) -> Text
def get_change_deployment_status_body(payload: Dict[str, Any]) -> Text:
return u'Deployment changed status to {}'.format(
payload['deployment_status']['state'],
)
def get_create_or_delete_body(payload, action):
# type: (Dict[str, Any], Text) -> Text
def get_create_or_delete_body(payload: Dict[str, Any], action: Text) -> Text:
ref_type = payload['ref_type']
return u'{} {} {} {}'.format(
get_sender_name(payload),
@@ -156,8 +145,7 @@ def get_create_or_delete_body(payload, action):
payload['ref']
).rstrip()
def get_commit_comment_body(payload):
# type: (Dict[str, Any]) -> Text
def get_commit_comment_body(payload: Dict[str, Any]) -> Text:
comment = payload['comment']
comment_url = comment['html_url']
commit_url = comment_url.split('#', 1)[0]
@@ -170,16 +158,14 @@ def get_commit_comment_body(payload):
comment['body'],
)
def get_push_tags_body(payload):
# type: (Dict[str, Any]) -> Text
def get_push_tags_body(payload: Dict[str, Any]) -> Text:
return get_push_tag_event_message(
get_sender_name(payload),
get_tag_name_from_ref(payload['ref']),
action='pushed' if payload.get('created') else 'removed'
)
def get_push_commits_body(payload):
# type: (Dict[str, Any]) -> Text
def get_push_commits_body(payload: Dict[str, Any]) -> Text:
commits_data = [{
'name': (commit.get('author').get('username') or
commit.get('author').get('name')),
@@ -195,15 +181,13 @@ def get_push_commits_body(payload):
deleted=payload['deleted']
)
def get_public_body(payload):
# type: (Dict[str, Any]) -> Text
def get_public_body(payload: Dict[str, Any]) -> Text:
return u"{} made [the repository]({}) public".format(
get_sender_name(payload),
payload['repository']['html_url'],
)
def get_wiki_pages_body(payload):
# type: (Dict[str, Any]) -> Text
def get_wiki_pages_body(payload: Dict[str, Any]) -> Text:
wiki_page_info_template = u"* {action} [{title}]({url})\n"
wiki_info = u''
for page in payload['pages']:
@@ -214,37 +198,32 @@ def get_wiki_pages_body(payload):
)
return u"{}:\n{}".format(get_sender_name(payload), wiki_info.rstrip())
def get_watch_body(payload):
# type: (Dict[str, Any]) -> Text
def get_watch_body(payload: Dict[str, Any]) -> Text:
return u"{} starred [the repository]({})".format(
get_sender_name(payload),
payload['repository']['html_url']
)
def get_repository_body(payload):
# type: (Dict[str, Any]) -> Text
def get_repository_body(payload: Dict[str, Any]) -> Text:
return u"{} {} [the repository]({})".format(
get_sender_name(payload),
payload.get('action'),
payload['repository']['html_url']
)
def get_add_team_body(payload):
# type: (Dict[str, Any]) -> Text
def get_add_team_body(payload: Dict[str, Any]) -> Text:
return u"[The repository]({}) was added to team {}".format(
payload['repository']['html_url'],
payload['team']['name']
)
def get_release_body(payload):
# type: (Dict[str, Any]) -> Text
def get_release_body(payload: Dict[str, Any]) -> Text:
return u"{} published [the release]({})".format(
get_sender_name(payload),
payload['release']['html_url'],
)
def get_page_build_body(payload):
# type: (Dict[str, Any]) -> Text
def get_page_build_body(payload: Dict[str, Any]) -> Text:
build = payload['build']
action = build['status']
if action == 'null':
@@ -262,8 +241,7 @@ def get_page_build_body(payload):
action
)
def get_status_body(payload):
# type: (Dict[str, Any]) -> Text
def get_status_body(payload: Dict[str, Any]) -> Text:
if payload['target_url']:
status = '[{}]({})'.format(
payload['state'],
@@ -277,8 +255,7 @@ def get_status_body(payload):
status
)
def get_pull_request_review_body(payload):
# type: (Dict[str, Any]) -> Text
def get_pull_request_review_body(payload: Dict[str, Any]) -> Text:
return get_pull_request_event_message(
get_sender_name(payload),
'submitted',
@@ -286,8 +263,7 @@ def get_pull_request_review_body(payload):
type='PR Review'
)
def get_pull_request_review_comment_body(payload):
# type: (Dict[str, Any]) -> Text
def get_pull_request_review_comment_body(payload: Dict[str, Any]) -> Text:
action = payload['action']
message = None
if action == 'created':
@@ -301,36 +277,28 @@ def get_pull_request_review_comment_body(payload):
type='PR Review Comment'
)
def get_ping_body(payload):
# type: (Dict[str, Any]) -> Text
def get_ping_body(payload: Dict[str, Any]) -> Text:
return get_setup_webhook_message('GitHub', get_sender_name(payload))
def get_repository_name(payload):
# type: (Dict[str, Any]) -> Text
def get_repository_name(payload: Dict[str, Any]) -> Text:
return payload['repository']['name']
def get_organization_name(payload):
# type: (Dict[str, Any]) -> Text
def get_organization_name(payload: Dict[str, Any]) -> Text:
return payload['organization']['login']
def get_sender_name(payload):
# type: (Dict[str, Any]) -> Text
def get_sender_name(payload: Dict[str, Any]) -> Text:
return payload['sender']['login']
def get_branch_name_from_ref(ref_string):
# type: (Text) -> Text
def get_branch_name_from_ref(ref_string: Text) -> Text:
return re.sub(r'^refs/heads/', '', ref_string)
def get_tag_name_from_ref(ref_string):
# type: (Text) -> Text
def get_tag_name_from_ref(ref_string: Text) -> Text:
return re.sub(r'^refs/tags/', '', ref_string)
def is_commit_push_event(payload):
# type: (Dict[str, Any]) -> bool
def is_commit_push_event(payload: Dict[str, Any]) -> bool:
return bool(re.match(r'^refs/heads/', payload['ref']))
def get_subject_based_on_type(payload, event):
# type: (Dict[str, Any], Text) -> Text
def get_subject_based_on_type(payload: Dict[str, Any], event: Text) -> Text:
if 'pull_request' in event:
return SUBJECT_WITH_PR_OR_ISSUE_INFO_TEMPLATE.format(
repo=get_repository_name(payload),
@@ -409,8 +377,7 @@ def api_github_webhook(
check_send_stream_message(user_profile, request.client, stream, subject, body)
return json_success()
def get_event(request, payload, branches):
# type: (HttpRequest, Dict[str, Any], Text) -> Optional[str]
def get_event(request: HttpRequest, payload: Dict[str, Any], branches: Text) -> Optional[str]:
event = request.META['HTTP_X_GITHUB_EVENT']
if event == 'pull_request':
action = payload['action']
@@ -436,6 +403,5 @@ def get_event(request, payload, branches):
logging.warning(u'Event {} is unknown and cannot be handled'.format(event))
return None
def get_body_function_based_on_type(type):
# type: (str) -> Any
def get_body_function_based_on_type(type: str) -> Any:
return EVENT_FUNCTION_MAPPER.get(type)

View File

@@ -10,40 +10,34 @@ class GitlabHookTests(WebhookTestCase):
URL_TEMPLATE = "/api/v1/external/gitlab?&api_key={api_key}&stream={stream}"
FIXTURE_DIR_NAME = 'gitlab'
def test_push_event_message(self):
# type: () -> None
def test_push_event_message(self) -> None:
expected_subject = u"my-awesome-project / tomek"
expected_message = u"Tomasz Kolek [pushed](https://gitlab.com/tomaszkolek0/my-awesome-project/compare/5fcdd5551fc3085df79bece2c32b1400802ac407...eb6ae1e591e0819dc5bf187c6bfe18ec065a80e9) 2 commits to branch tomek.\n\n* b ([66abd2d](https://gitlab.com/tomaszkolek0/my-awesome-project/commit/66abd2da28809ffa128ed0447965cf11d7f863a7))\n* c ([eb6ae1e](https://gitlab.com/tomaszkolek0/my-awesome-project/commit/eb6ae1e591e0819dc5bf187c6bfe18ec065a80e9))"
self.send_and_test_stream_message('push', expected_subject, expected_message, HTTP_X_GITLAB_EVENT="Push Hook")
def test_push_local_branch_without_commits(self):
# type: () -> None
def test_push_local_branch_without_commits(self) -> None:
expected_subject = u"my-awesome-project / changes"
expected_message = u"Eeshan Garg [pushed](https://gitlab.com/eeshangarg/my-awesome-project/compare/0000000000000000000000000000000000000000...68d7a5528cf423dfaac37dd62a56ac9cc8a884e3) the branch changes."
self.send_and_test_stream_message('push_local_branch_without_commits', expected_subject, expected_message, HTTP_X_GITLAB_EVENT="Push Hook")
def test_push_event_message_filtered_by_branches(self):
# type: () -> None
def test_push_event_message_filtered_by_branches(self) -> None:
self.url = self.build_webhook_url(branches='master,tomek')
expected_subject = u"my-awesome-project / tomek"
expected_message = u"Tomasz Kolek [pushed](https://gitlab.com/tomaszkolek0/my-awesome-project/compare/5fcdd5551fc3085df79bece2c32b1400802ac407...eb6ae1e591e0819dc5bf187c6bfe18ec065a80e9) 2 commits to branch tomek.\n\n* b ([66abd2d](https://gitlab.com/tomaszkolek0/my-awesome-project/commit/66abd2da28809ffa128ed0447965cf11d7f863a7))\n* c ([eb6ae1e](https://gitlab.com/tomaszkolek0/my-awesome-project/commit/eb6ae1e591e0819dc5bf187c6bfe18ec065a80e9))"
self.send_and_test_stream_message('push', expected_subject, expected_message, HTTP_X_GITLAB_EVENT="Push Hook")
def test_push_multiple_committers(self):
# type: () -> None
def test_push_multiple_committers(self) -> None:
expected_subject = u"my-awesome-project / tomek"
expected_message = u"Tomasz Kolek [pushed](https://gitlab.com/tomaszkolek0/my-awesome-project/compare/5fcdd5551fc3085df79bece2c32b1400802ac407...eb6ae1e591e0819dc5bf187c6bfe18ec065a80e9) 2 commits to branch tomek. Commits by Ben (1) and Tomasz Kolek (1).\n\n* b ([66abd2d](https://gitlab.com/tomaszkolek0/my-awesome-project/commit/66abd2da28809ffa128ed0447965cf11d7f863a7))\n* c ([eb6ae1e](https://gitlab.com/tomaszkolek0/my-awesome-project/commit/eb6ae1e591e0819dc5bf187c6bfe18ec065a80e9))"
self.send_and_test_stream_message('push_multiple_committers', expected_subject, expected_message, HTTP_X_GITLAB_EVENT="Push Hook")
def test_push_multiple_committers_with_others(self):
# type: () -> None
def test_push_multiple_committers_with_others(self) -> None:
expected_subject = u"my-awesome-project / tomek"
commit_info = u"* b ([eb6ae1e](https://gitlab.com/tomaszkolek0/my-awesome-project/commit/eb6ae1e591e0819dc5bf187c6bfe18ec065a80e9))\n"
expected_message = u"Tomasz Kolek [pushed](https://gitlab.com/tomaszkolek0/my-awesome-project/compare/5fcdd5551fc3085df79bece2c32b1400802ac407...eb6ae1e591e0819dc5bf187c6bfe18ec065a80e9) 7 commits to branch tomek. Commits by Ben (3), baxterthehacker (2), James (1) and others (1).\n\n{}* b ([eb6ae1e](https://gitlab.com/tomaszkolek0/my-awesome-project/commit/eb6ae1e591e0819dc5bf187c6bfe18ec065a80e9))".format(commit_info * 6)
self.send_and_test_stream_message('push_multiple_committers_with_others', expected_subject, expected_message, HTTP_X_GITLAB_EVENT="Push Hook")
def test_push_commits_more_than_limit_event_message(self):
# type: () -> None
def test_push_commits_more_than_limit_event_message(self) -> None:
expected_subject = u"my-awesome-project / tomek"
commits_info = u'* b ([66abd2d](https://gitlab.com/tomaszkolek0/my-awesome-project/commit/66abd2da28809ffa128ed0447965cf11d7f863a7))\n'
expected_message = u"Tomasz Kolek [pushed](https://gitlab.com/tomaszkolek0/my-awesome-project/compare/5fcdd5551fc3085df79bece2c32b1400802ac407...eb6ae1e591e0819dc5bf187c6bfe18ec065a80e9) 50 commits to branch tomek.\n\n{}[and {} more commit(s)]".format(
@@ -52,8 +46,7 @@ class GitlabHookTests(WebhookTestCase):
)
self.send_and_test_stream_message('push_commits_more_than_limit', expected_subject, expected_message, HTTP_X_GITLAB_EVENT="Push Hook")
def test_push_commits_more_than_limit_message_filtered_by_branches(self):
# type: () -> None
def test_push_commits_more_than_limit_message_filtered_by_branches(self) -> None:
self.url = self.build_webhook_url(branches='master,tomek')
expected_subject = u"my-awesome-project / tomek"
commits_info = u'* b ([66abd2d](https://gitlab.com/tomaszkolek0/my-awesome-project/commit/66abd2da28809ffa128ed0447965cf11d7f863a7))\n'
@@ -63,15 +56,13 @@ class GitlabHookTests(WebhookTestCase):
)
self.send_and_test_stream_message('push_commits_more_than_limit', expected_subject, expected_message, HTTP_X_GITLAB_EVENT="Push Hook")
def test_remove_branch_event_message(self):
# type: () -> None
def test_remove_branch_event_message(self) -> None:
expected_subject = u"my-awesome-project / tomek"
expected_message = u"Tomasz Kolek deleted branch tomek"
self.send_and_test_stream_message('remove_branch', expected_subject, expected_message, HTTP_X_GITLAB_EVENT="Push Hook")
def test_add_tag_event_message(self):
# type: () -> None
def test_add_tag_event_message(self) -> None:
expected_subject = u"my-awesome-project"
expected_message = u"Tomasz Kolek pushed tag xyz"
@@ -82,8 +73,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Tag Push Hook",
)
def test_remove_tag_event_message(self):
# type: () -> None
def test_remove_tag_event_message(self) -> None:
expected_subject = u"my-awesome-project"
expected_message = u"Tomasz Kolek removed tag xyz"
@@ -94,8 +84,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Tag Push Hook"
)
def test_create_issue_without_assignee_event_message(self):
# type: () -> None
def test_create_issue_without_assignee_event_message(self) -> None:
expected_subject = u"my-awesome-project / Issue #1 Issue title"
expected_message = u"Tomasz Kolek created [Issue #1](https://gitlab.com/tomaszkolek0/my-awesome-project/issues/1)\n\n~~~ quote\nIssue description\n~~~"
@@ -106,8 +95,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Issue Hook"
)
def test_create_issue_with_assignee_event_message(self):
# type: () -> None
def test_create_issue_with_assignee_event_message(self) -> None:
expected_subject = u"my-awesome-project / Issue #1 Issue title"
expected_message = u"Tomasz Kolek created [Issue #1](https://gitlab.com/tomaszkolek0/my-awesome-project/issues/1)(assigned to Tomasz Kolek)\n\n~~~ quote\nIssue description\n~~~"
@@ -118,8 +106,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Issue Hook"
)
def test_update_issue_event_message(self):
# type: () -> None
def test_update_issue_event_message(self) -> None:
expected_subject = u"my-awesome-project / Issue #1 Issue title_new"
expected_message = u"Tomasz Kolek updated [Issue #1](https://gitlab.com/tomaszkolek0/my-awesome-project/issues/1)"
@@ -130,8 +117,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Issue Hook"
)
def test_close_issue_event_message(self):
# type: () -> None
def test_close_issue_event_message(self) -> None:
expected_subject = u"my-awesome-project / Issue #1 Issue title_new"
expected_message = u"Tomasz Kolek closed [Issue #1](https://gitlab.com/tomaszkolek0/my-awesome-project/issues/1)"
@@ -142,8 +128,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Issue Hook"
)
def test_reopen_issue_event_message(self):
# type: () -> None
def test_reopen_issue_event_message(self) -> None:
expected_subject = u"my-awesome-project / Issue #1 Issue title_new"
expected_message = u"Tomasz Kolek reopened [Issue #1](https://gitlab.com/tomaszkolek0/my-awesome-project/issues/1)"
@@ -154,8 +139,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Issue Hook"
)
def test_note_commit_event_message(self):
# type: () -> None
def test_note_commit_event_message(self) -> None:
expected_subject = u"my-awesome-project"
expected_message = u"Tomasz Kolek [commented](https://gitlab.com/tomaszkolek0/my-awesome-project/commit/66abd2da28809ffa128ed0447965cf11d7f863a7#note_14169211) on [66abd2d](https://gitlab.com/tomaszkolek0/my-awesome-project/commit/66abd2da28809ffa128ed0447965cf11d7f863a7)\n~~~ quote\nnice commit\n~~~"
@@ -166,8 +150,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Note Hook"
)
def test_note_merge_request_event_message(self):
# type: () -> None
def test_note_merge_request_event_message(self) -> None:
expected_subject = u"my-awesome-project / MR #1 Tomek"
expected_message = u"Tomasz Kolek [commented](https://gitlab.com/tomaszkolek0/my-awesome-project/merge_requests/1#note_14171860) on [MR #1](https://gitlab.com/tomaszkolek0/my-awesome-project/merge_requests/1)\n\n~~~ quote\nNice merge request!\n~~~"
@@ -178,8 +161,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Note Hook"
)
def test_note_issue_event_message(self):
# type: () -> None
def test_note_issue_event_message(self) -> None:
expected_subject = u"my-awesome-project / Issue #2 abc"
expected_message = u"Tomasz Kolek [commented](https://gitlab.com/tomaszkolek0/my-awesome-project/issues/2#note_14172057) on [Issue #2](https://gitlab.com/tomaszkolek0/my-awesome-project/issues/2)\n\n~~~ quote\nNice issue\n~~~"
@@ -190,8 +172,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Note Hook"
)
def test_note_snippet_event_message(self):
# type: () -> None
def test_note_snippet_event_message(self) -> None:
expected_subject = u"my-awesome-project / Snippet #2 test"
expected_message = u"Tomasz Kolek [commented](https://gitlab.com/tomaszkolek0/my-awesome-project/snippets/2#note_14172058) on [Snippet #2](https://gitlab.com/tomaszkolek0/my-awesome-project/snippets/2)\n\n~~~ quote\nNice snippet\n~~~"
@@ -202,8 +183,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Note Hook"
)
def test_merge_request_created_without_assignee_event_message(self):
# type: () -> None
def test_merge_request_created_without_assignee_event_message(self) -> None:
expected_subject = u"my-awesome-project / MR #2 NEW MR"
expected_message = u"Tomasz Kolek created [MR #2](https://gitlab.com/tomaszkolek0/my-awesome-project/merge_requests/2)\nfrom `tomek` to `master`\n\n~~~ quote\ndescription of merge request\n~~~"
@@ -214,8 +194,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Merge Request Hook"
)
def test_merge_request_created_with_assignee_event_message(self):
# type: () -> None
def test_merge_request_created_with_assignee_event_message(self) -> None:
expected_subject = u"my-awesome-project / MR #3 New Merge Request"
expected_message = u"Tomasz Kolek created [MR #3](https://gitlab.com/tomaszkolek0/my-awesome-project/merge_requests/3)(assigned to Tomasz Kolek)\nfrom `tomek` to `master`\n\n~~~ quote\ndescription of merge request\n~~~"
self.send_and_test_stream_message(
@@ -225,8 +204,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Merge Request Hook"
)
def test_merge_request_closed_event_message(self):
# type: () -> None
def test_merge_request_closed_event_message(self) -> None:
expected_subject = u"my-awesome-project / MR #2 NEW MR"
expected_message = u"Tomasz Kolek closed [MR #2](https://gitlab.com/tomaszkolek0/my-awesome-project/merge_requests/2)"
@@ -237,8 +215,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Merge Request Hook"
)
def test_merge_request_reopened_event_message(self):
# type: () -> None
def test_merge_request_reopened_event_message(self) -> None:
expected_subject = u"my-awesome-project / MR #1 Update the README with author ..."
expected_message = u"Eeshan Garg reopened [MR #1](https://gitlab.com/eeshangarg/my-awesome-project/merge_requests/1)"
@@ -249,8 +226,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Merge Request Hook"
)
def test_merge_request_updated_event_message(self):
# type: () -> None
def test_merge_request_updated_event_message(self) -> None:
expected_subject = u"my-awesome-project / MR #3 New Merge Request"
expected_message = u"Tomasz Kolek updated [MR #3](https://gitlab.com/tomaszkolek0/my-awesome-project/merge_requests/3)(assigned to Tomasz Kolek)\nfrom `tomek` to `master`\n\n~~~ quote\nupdated desc\n~~~"
self.send_and_test_stream_message(
@@ -260,8 +236,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Merge Request Hook"
)
def test_merge_request_added_commit_event_message(self):
# type: () -> None
def test_merge_request_added_commit_event_message(self) -> None:
expected_subject = u"my-awesome-project / MR #3 New Merge Request"
expected_message = u"Tomasz Kolek added commit(s) to [MR #3](https://gitlab.com/tomaszkolek0/my-awesome-project/merge_requests/3)"
self.send_and_test_stream_message(
@@ -271,8 +246,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Merge Request Hook"
)
def test_merge_request_merged_event_message(self):
# type: () -> None
def test_merge_request_merged_event_message(self) -> None:
expected_subject = u"my-awesome-project / MR #3 New Merge Request"
expected_message = u"Tomasz Kolek merged [MR #3](https://gitlab.com/tomaszkolek0/my-awesome-project/merge_requests/3)"
@@ -283,8 +257,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Merge Request Hook"
)
def test_wiki_page_opened_event_message(self):
# type: () -> None
def test_wiki_page_opened_event_message(self) -> None:
expected_subject = u"my-awesome-project"
expected_message = u"Tomasz Kolek created [Wiki Page \"how to\"](https://gitlab.com/tomaszkolek0/my-awesome-project/wikis/how-to)."
@@ -295,8 +268,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Wiki Page Hook"
)
def test_wiki_page_edited_event_message(self):
# type: () -> None
def test_wiki_page_edited_event_message(self) -> None:
expected_subject = u"my-awesome-project"
expected_message = u"Tomasz Kolek updated [Wiki Page \"how to\"](https://gitlab.com/tomaszkolek0/my-awesome-project/wikis/how-to)."
@@ -307,8 +279,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Wiki Page Hook"
)
def test_build_created_event_message(self):
# type: () -> None
def test_build_created_event_message(self) -> None:
expected_subject = u"my-awesome-project / master"
expected_message = u"Build job_name from test stage was created."
@@ -319,8 +290,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Build Hook"
)
def test_build_started_event_message(self):
# type: () -> None
def test_build_started_event_message(self) -> None:
expected_subject = u"my-awesome-project / master"
expected_message = u"Build job_name from test stage started."
@@ -331,8 +301,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Build Hook"
)
def test_build_succeeded_event_message(self):
# type: () -> None
def test_build_succeeded_event_message(self) -> None:
expected_subject = u"my-awesome-project / master"
expected_message = u"Build job_name from test stage changed status to success."
@@ -343,8 +312,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Build Hook"
)
def test_pipeline_succeeded_event_message(self):
# type: () -> None
def test_pipeline_succeeded_event_message(self) -> None:
expected_subject = u"my-awesome-project / master"
expected_message = u"Pipeline changed status to success with build(s):\n* job_name2 - success\n* job_name - success."
@@ -355,8 +323,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Pipeline Hook"
)
def test_pipeline_started_event_message(self):
# type: () -> None
def test_pipeline_started_event_message(self) -> None:
expected_subject = u"my-awesome-project / master"
expected_message = u"Pipeline started with build(s):\n* job_name - running\n* job_name2 - pending."
@@ -367,8 +334,7 @@ class GitlabHookTests(WebhookTestCase):
HTTP_X_GITLAB_EVENT="Pipeline Hook"
)
def test_pipeline_pending_event_message(self):
# type: () -> None
def test_pipeline_pending_event_message(self) -> None:
expected_subject = u"my-awesome-project / master"
expected_message = u"Pipeline was created with build(s):\n* job_name2 - pending\n* job_name - created."

View File

@@ -17,14 +17,12 @@ class UnknownEventType(Exception):
pass
def get_push_event_body(payload):
# type: (Dict[str, Any]) -> Text
def get_push_event_body(payload: Dict[str, Any]) -> Text:
if payload.get('after') == EMPTY_SHA:
return get_remove_branch_event_body(payload)
return get_normal_push_event_body(payload)
def get_normal_push_event_body(payload):
# type: (Dict[str, Any]) -> Text
def get_normal_push_event_body(payload: Dict[str, Any]) -> Text:
compare_url = u'{}/compare/{}...{}'.format(
get_repository_homepage(payload),
payload['before'],
@@ -48,23 +46,20 @@ def get_normal_push_event_body(payload):
commits
)
def get_remove_branch_event_body(payload):
# type: (Dict[str, Any]) -> Text
def get_remove_branch_event_body(payload: Dict[str, Any]) -> Text:
return get_remove_branch_event_message(
get_user_name(payload),
get_branch_name(payload)
)
def get_tag_push_event_body(payload):
# type: (Dict[str, Any]) -> Text
def get_tag_push_event_body(payload: Dict[str, Any]) -> Text:
return get_push_tag_event_message(
get_user_name(payload),
get_tag_name(payload),
action="pushed" if payload.get('checkout_sha') else "removed"
)
def get_issue_created_event_body(payload):
# type: (Dict[str, Any]) -> Text
def get_issue_created_event_body(payload: Dict[str, Any]) -> Text:
return get_issue_event_message(
get_issue_user_name(payload),
'created',
@@ -74,8 +69,7 @@ def get_issue_created_event_body(payload):
get_objects_assignee(payload)
)
def get_issue_event_body(payload, action):
# type: (Dict[str, Any], Text) -> Text
def get_issue_event_body(payload: Dict[str, Any], action: Text) -> Text:
return get_issue_event_message(
get_issue_user_name(payload),
action,
@@ -83,14 +77,12 @@ def get_issue_event_body(payload, action):
payload['object_attributes'].get('iid'),
)
def get_merge_request_updated_event_body(payload):
# type: (Dict[str, Any]) -> Text
def get_merge_request_updated_event_body(payload: Dict[str, Any]) -> Text:
if payload['object_attributes'].get('oldrev'):
return get_merge_request_event_body(payload, "added commit(s) to")
return get_merge_request_open_or_updated_body(payload, "updated")
def get_merge_request_event_body(payload, action):
# type: (Dict[str, Any], Text) -> Text
def get_merge_request_event_body(payload: Dict[str, Any], action: Text) -> Text:
pull_request = payload['object_attributes']
return get_pull_request_event_message(
get_issue_user_name(payload),
@@ -100,8 +92,7 @@ def get_merge_request_event_body(payload, action):
type='MR',
)
def get_merge_request_open_or_updated_body(payload, action):
# type: (Dict[str, Any], Text) -> Text
def get_merge_request_open_or_updated_body(payload: Dict[str, Any], action: Text) -> Text:
pull_request = payload['object_attributes']
return get_pull_request_event_message(
get_issue_user_name(payload),
@@ -115,15 +106,13 @@ def get_merge_request_open_or_updated_body(payload, action):
type='MR',
)
def get_objects_assignee(payload):
# type: (Dict[str, Any]) -> Optional[Text]
def get_objects_assignee(payload: Dict[str, Any]) -> Optional[Text]:
assignee_object = payload.get('assignee')
if assignee_object:
return assignee_object.get('name')
return None
def get_commented_commit_event_body(payload):
# type: (Dict[str, Any]) -> Text
def get_commented_commit_event_body(payload: Dict[str, Any]) -> Text:
comment = payload['object_attributes']
action = u'[commented]({})'.format(comment['url'])
return get_commits_comment_action_message(
@@ -134,8 +123,7 @@ def get_commented_commit_event_body(payload):
comment['note'],
)
def get_commented_merge_request_event_body(payload):
# type: (Dict[str, Any]) -> Text
def get_commented_merge_request_event_body(payload: Dict[str, Any]) -> Text:
comment = payload['object_attributes']
action = u'[commented]({}) on'.format(comment['url'])
url = u'{}/merge_requests/{}'.format(
@@ -151,8 +139,7 @@ def get_commented_merge_request_event_body(payload):
type='MR'
)
def get_commented_issue_event_body(payload):
# type: (Dict[str, Any]) -> Text
def get_commented_issue_event_body(payload: Dict[str, Any]) -> Text:
comment = payload['object_attributes']
action = u'[commented]({}) on'.format(comment['url'])
url = u'{}/issues/{}'.format(
@@ -168,8 +155,7 @@ def get_commented_issue_event_body(payload):
type='Issue'
)
def get_commented_snippet_event_body(payload):
# type: (Dict[str, Any]) -> Text
def get_commented_snippet_event_body(payload: Dict[str, Any]) -> Text:
comment = payload['object_attributes']
action = u'[commented]({}) on'.format(comment['url'])
url = u'{}/snippets/{}'.format(
@@ -185,8 +171,7 @@ def get_commented_snippet_event_body(payload):
type='Snippet'
)
def get_wiki_page_event_body(payload, action):
# type: (Dict[str, Any], Text) -> Text
def get_wiki_page_event_body(payload: Dict[str, Any], action: Text) -> Text:
return u"{} {} [Wiki Page \"{}\"]({}).".format(
get_issue_user_name(payload),
action,
@@ -194,8 +179,7 @@ def get_wiki_page_event_body(payload, action):
payload['object_attributes'].get('url'),
)
def get_build_hook_event_body(payload):
# type: (Dict[str, Any]) -> Text
def get_build_hook_event_body(payload: Dict[str, Any]) -> Text:
build_status = payload.get('build_status')
if build_status == 'created':
action = 'was created'
@@ -209,8 +193,7 @@ def get_build_hook_event_body(payload):
action
)
def get_pipeline_event_body(payload):
# type: (Dict[str, Any]) -> Text
def get_pipeline_event_body(payload: Dict[str, Any]) -> Text:
pipeline_status = payload['object_attributes'].get('status')
if pipeline_status == 'pending':
action = 'was created'
@@ -224,36 +207,28 @@ def get_pipeline_event_body(payload):
builds_status += u"* {} - {}\n".format(build.get('name'), build.get('status'))
return u"Pipeline {} with build(s):\n{}.".format(action, builds_status[:-1])
def get_repo_name(payload):
# type: (Dict[str, Any]) -> Text
def get_repo_name(payload: Dict[str, Any]) -> Text:
return payload['project']['name']
def get_user_name(payload):
# type: (Dict[str, Any]) -> Text
def get_user_name(payload: Dict[str, Any]) -> Text:
return payload['user_name']
def get_issue_user_name(payload):
# type: (Dict[str, Any]) -> Text
def get_issue_user_name(payload: Dict[str, Any]) -> Text:
return payload['user']['name']
def get_repository_homepage(payload):
# type: (Dict[str, Any]) -> Text
def get_repository_homepage(payload: Dict[str, Any]) -> Text:
return payload['repository']['homepage']
def get_branch_name(payload):
# type: (Dict[str, Any]) -> Text
def get_branch_name(payload: Dict[str, Any]) -> Text:
return payload['ref'].replace('refs/heads/', '')
def get_tag_name(payload):
# type: (Dict[str, Any]) -> Text
def get_tag_name(payload: Dict[str, Any]) -> Text:
return payload['ref'].replace('refs/tags/', '')
def get_object_iid(payload):
# type: (Dict[str, Any]) -> Text
def get_object_iid(payload: Dict[str, Any]) -> Text:
return payload['object_attributes']['iid']
def get_object_url(payload):
# type: (Dict[str, Any]) -> Text
def get_object_url(payload: Dict[str, Any]) -> Text:
return payload['object_attributes']['url']
EVENT_FUNCTION_MAPPER = {
@@ -292,12 +267,10 @@ def api_gitlab_webhook(request, user_profile,
check_send_stream_message(user_profile, request.client, stream, subject, body)
return json_success()
def get_body_based_on_event(event):
# type: (str) -> Any
def get_body_based_on_event(event: str) -> Any:
return EVENT_FUNCTION_MAPPER[event]
def get_subject_based_on_event(event, payload):
# type: (str, Dict[str, Any]) -> Text
def get_subject_based_on_event(event: str, payload: Dict[str, Any]) -> Text:
if event == 'Push Hook':
return u"{} / {}".format(get_repo_name(payload), get_branch_name(payload))
elif event == 'Build Hook':
@@ -344,8 +317,7 @@ def get_subject_based_on_event(event, payload):
)
return get_repo_name(payload)
def get_event(request, payload, branches):
# type: (HttpRequest, Dict[str, Any], Optional[Text]) -> Optional[str]
def get_event(request: HttpRequest, payload: Dict[str, Any], branches: Optional[Text]) -> Optional[str]:
event = request.META['HTTP_X_GITLAB_EVENT']
if event == 'Issue Hook':
action = payload['object_attributes'].get('action')

View File

@@ -11,31 +11,27 @@ class GogsHookTests(WebhookTestCase):
URL_TEMPLATE = "/api/v1/external/gogs?&api_key={api_key}"
FIXTURE_DIR_NAME = 'gogs'
def test_push(self):
# type: () -> None
def test_push(self) -> None:
expected_subject = u"try-git / master"
expected_message = u"""john [pushed](http://localhost:3000/john/try-git/compare/479e6b772b7fba19412457483f50b201286d0103...d8fce16c72a2ff56a5afc8a08645a6ce45491794) 1 commit to branch master. Commits by John (1).
* Webhook Test ([d8fce16](http://localhost:3000/john/try-git/commit/d8fce16c72a2ff56a5afc8a08645a6ce45491794))"""
self.send_and_test_stream_message('push', expected_subject, expected_message, HTTP_X_GOGS_EVENT='push')
def test_push_multiple_committers(self):
# type: () -> None
def test_push_multiple_committers(self) -> None:
commit_info = u'* Webhook Test ([d8fce16](http://localhost:3000/john/try-git/commit/d8fce16c72a2ff56a5afc8a08645a6ce45491794))\n'
expected_subject = u"try-git / master"
expected_message = u"""john [pushed](http://localhost:3000/john/try-git/compare/479e6b772b7fba19412457483f50b201286d0103...d8fce16c72a2ff56a5afc8a08645a6ce45491794) 2 commits to branch master. Commits by Benjamin (1) and John (1).\n\n{}* Webhook Test ([d8fce16](http://localhost:3000/john/try-git/commit/d8fce16c72a2ff56a5afc8a08645a6ce45491794))""".format(commit_info)
self.send_and_test_stream_message('push_commits_multiple_committers', expected_subject, expected_message, HTTP_X_GOGS_EVENT='push')
def test_push_multiple_committers_filtered_by_branches(self):
# type: () -> None
def test_push_multiple_committers_filtered_by_branches(self) -> None:
self.url = self.build_webhook_url(branches='master,development')
commit_info = u'* Webhook Test ([d8fce16](http://localhost:3000/john/try-git/commit/d8fce16c72a2ff56a5afc8a08645a6ce45491794))\n'
expected_subject = u"try-git / master"
expected_message = u"""john [pushed](http://localhost:3000/john/try-git/compare/479e6b772b7fba19412457483f50b201286d0103...d8fce16c72a2ff56a5afc8a08645a6ce45491794) 2 commits to branch master. Commits by Benjamin (1) and John (1).\n\n{}* Webhook Test ([d8fce16](http://localhost:3000/john/try-git/commit/d8fce16c72a2ff56a5afc8a08645a6ce45491794))""".format(commit_info)
self.send_and_test_stream_message('push_commits_multiple_committers', expected_subject, expected_message, HTTP_X_GOGS_EVENT='push')
def test_push_filtered_by_branches(self):
# type: () -> None
def test_push_filtered_by_branches(self) -> None:
self.url = self.build_webhook_url(branches='master,development')
expected_subject = u"try-git / master"
expected_message = u"""john [pushed](http://localhost:3000/john/try-git/compare/479e6b772b7fba19412457483f50b201286d0103...d8fce16c72a2ff56a5afc8a08645a6ce45491794) 1 commit to branch master. Commits by John (1).
@@ -43,8 +39,7 @@ class GogsHookTests(WebhookTestCase):
* Webhook Test ([d8fce16](http://localhost:3000/john/try-git/commit/d8fce16c72a2ff56a5afc8a08645a6ce45491794))"""
self.send_and_test_stream_message('push', expected_subject, expected_message, HTTP_X_GOGS_EVENT='push')
def test_push_commits_more_than_limits(self):
# type: () -> None
def test_push_commits_more_than_limits(self) -> None:
expected_subject = u"try-git / master"
commits_info = "* Webhook Test ([d8fce16](http://localhost:3000/john/try-git/commit/d8fce16c72a2ff56a5afc8a08645a6ce45491794))\n"
expected_message = u"john [pushed](http://localhost:3000/john/try-git/compare/479e6b772b7fba19412457483f50b201286d0103...d8fce16c72a2ff56a5afc8a08645a6ce45491794) 30 commits to branch master. Commits by John (30).\n\n{}[and {} more commit(s)]".format(
@@ -53,8 +48,7 @@ class GogsHookTests(WebhookTestCase):
)
self.send_and_test_stream_message('push_commits_more_than_limits', expected_subject, expected_message, HTTP_X_GOGS_EVENT='push')
def test_push_commits_more_than_limits_filtered_by_branches(self):
# type: () -> None
def test_push_commits_more_than_limits_filtered_by_branches(self) -> None:
self.url = self.build_webhook_url(branches='master,development')
expected_subject = u"try-git / master"
commits_info = "* Webhook Test ([d8fce16](http://localhost:3000/john/try-git/commit/d8fce16c72a2ff56a5afc8a08645a6ce45491794))\n"
@@ -64,36 +58,31 @@ class GogsHookTests(WebhookTestCase):
)
self.send_and_test_stream_message('push_commits_more_than_limits', expected_subject, expected_message, HTTP_X_GOGS_EVENT='push')
def test_new_branch(self):
# type: () -> None
def test_new_branch(self) -> None:
expected_subject = u"try-git / my_feature"
expected_message = u"john created [my_feature](http://localhost:3000/john/try-git/src/my_feature) branch"
self.send_and_test_stream_message('branch', expected_subject, expected_message, HTTP_X_GOGS_EVENT='create')
def test_pull_request_opened(self):
# type: () -> None
def test_pull_request_opened(self) -> None:
expected_subject = u"try-git / PR #1 Title Text for Pull Request"
expected_message = u"""john opened [PR #1](http://localhost:3000/john/try-git/pulls/1)
from `feature` to `master`"""
self.send_and_test_stream_message('pull_request_opened', expected_subject, expected_message, HTTP_X_GOGS_EVENT='pull_request')
def test_pull_request_closed(self):
# type: () -> None
def test_pull_request_closed(self) -> None:
expected_subject = u"try-git / PR #1 Title Text for Pull Request"
expected_message = u"""john closed [PR #1](http://localhost:3000/john/try-git/pulls/1)
from `feature` to `master`"""
self.send_and_test_stream_message('pull_request_closed', expected_subject, expected_message, HTTP_X_GOGS_EVENT='pull_request')
def test_pull_request_merged(self):
# type: () -> None
def test_pull_request_merged(self) -> None:
expected_subject = u"try-git / PR #2 Title Text for Pull Request"
expected_message = u"""john merged [PR #2](http://localhost:3000/john/try-git/pulls/2)
from `feature` to `master`"""
self.send_and_test_stream_message('pull_request_merged', expected_subject, expected_message, HTTP_X_GOGS_EVENT='pull_request')
@patch('zerver.webhooks.gogs.view.check_send_stream_message')
def test_push_filtered_by_branches_ignore(self, check_send_stream_message_mock):
# type: (MagicMock) -> None
def test_push_filtered_by_branches_ignore(self, check_send_stream_message_mock: MagicMock) -> None:
self.url = self.build_webhook_url(branches='changes,development')
payload = self.get_body('push')
result = self.client_post(self.url, payload, HTTP_X_GOGS_EVENT='push',

View File

@@ -13,8 +13,7 @@ from zerver.models import UserProfile
from django.http import HttpRequest, HttpResponse
from typing import Dict, Any, Iterable, Optional, Text
def format_push_event(payload):
# type: (Dict[str, Any]) -> Text
def format_push_event(payload: Dict[str, Any]) -> Text:
for commit in payload['commits']:
commit['sha'] = commit['id']
@@ -30,8 +29,7 @@ def format_push_event(payload):
return get_push_commits_event_message(**data)
def format_new_branch_event(payload):
# type: (Dict[str, Any]) -> Text
def format_new_branch_event(payload: Dict[str, Any]) -> Text:
branch_name = payload['ref']
url = '{}/src/{}'.format(payload['repository']['html_url'], branch_name)
@@ -43,8 +41,7 @@ def format_new_branch_event(payload):
}
return get_create_branch_event_message(**data)
def format_pull_request_event(payload):
# type: (Dict[str, Any]) -> Text
def format_pull_request_event(payload: Dict[str, Any]) -> Text:
data = {
'user_name': payload['pull_request']['user']['username'],

View File

@@ -8,14 +8,12 @@ class GoSquaredHookTests(WebhookTestCase):
FIXTURE_DIR_NAME = 'gosquared'
# Note: Include a test function per each distinct message condition your integration supports
def test_traffic_message(self):
# type: () -> None
def test_traffic_message(self) -> None:
expected_subject = "GoSquared - requestb.in"
expected_message = u"[requestb.in](https://www.gosquared.com/now/GSN-595854-T) has 33 visitors online."
self.send_and_test_stream_message('traffic_spike', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def get_body(self, fixture_name):
# type: (Text) -> Text
def get_body(self, fixture_name: Text) -> Text:
return self.fixture_data("gosquared", fixture_name, file_type="json")

View File

@@ -8,8 +8,7 @@ class GreenhouseHookTests(WebhookTestCase):
FIXTURE_DIR_NAME = 'greenhouse'
CONTENT_TYPE = "application/x-www-form-urlencoded"
def test_message_candidate_hired(self):
# type: () -> None
def test_message_candidate_hired(self) -> None:
expected_subject = "Hire Candidate - 19"
expected_message = ("Hire Candidate\n>Johnny Smith\nID: 19"
"\nApplying for role:\nDeveloper\n**Emails:**"
@@ -21,8 +20,7 @@ class GreenhouseHookTests(WebhookTestCase):
expected_message,
content_type=self.CONTENT_TYPE)
def test_message_candidate_rejected(self):
# type: () -> None
def test_message_candidate_rejected(self) -> None:
expected_subject = "Reject Candidate - 265788"
expected_message = ("Reject Candidate\n>Hector Porter\nID: "
"265788\nApplying for role:\nDesigner"
@@ -35,8 +33,7 @@ class GreenhouseHookTests(WebhookTestCase):
expected_message,
content_type=self.CONTENT_TYPE)
def test_message_candidate_stage_change(self):
# type: () -> None
def test_message_candidate_stage_change(self) -> None:
expected_subject = "Candidate Stage Change - 265772"
expected_message = ("Candidate Stage Change\n>Giuseppe Hurley"
"\nID: 265772\nApplying for role:\n"
@@ -51,8 +48,7 @@ class GreenhouseHookTests(WebhookTestCase):
expected_message,
content_type=self.CONTENT_TYPE)
def test_message_prospect_created(self):
# type: () -> None
def test_message_prospect_created(self) -> None:
expected_subject = "New Prospect Application - 968190"
expected_message = ("New Prospect Application\n>Trisha Troy"
"\nID: 968190\nApplying for role:\n"
@@ -65,6 +61,5 @@ class GreenhouseHookTests(WebhookTestCase):
expected_message,
content_type=self.CONTENT_TYPE)
def get_body(self, fixture_name):
# type: (Text) -> Text
def get_body(self, fixture_name: Text) -> Text:
return self.fixture_data("greenhouse", fixture_name, file_type="json")

View File

@@ -12,8 +12,7 @@ import ujson
MESSAGE_TEMPLATE = "Applying for role:\n{}\n**Emails:**\n{}\n\n>**Attachments:**\n{}"
def dict_list_to_string(some_list):
# type: (List[Any]) -> str
def dict_list_to_string(some_list: List[Any]) -> str:
internal_template = ''
for item in some_list:
item_type = item.get('type', '').title()
@@ -25,8 +24,7 @@ def dict_list_to_string(some_list):
internal_template += "[{}]({})\n".format(item_type, item_url)
return internal_template
def message_creator(action, application):
# type: (str, Dict[str, Any]) -> str
def message_creator(action: str, application: Dict[str, Any]) -> str:
message = MESSAGE_TEMPLATE.format(
application['jobs'][0]['name'],
dict_list_to_string(application['candidate']['email_addresses']),

View File

@@ -7,16 +7,14 @@ class HelloSignHookTests(WebhookTestCase):
URL_TEMPLATE = "/api/v1/external/hellosign?stream={stream}&api_key={api_key}"
FIXTURE_DIR_NAME = 'hellosign'
def test_signatures_message(self):
# type: () -> None
def test_signatures_message(self) -> None:
expected_subject = "NDA with Acme Co."
expected_message = ("The NDA with Acme Co. is awaiting the signature of "
"Jack and was just signed by Jill.")
self.send_and_test_stream_message('signatures', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_signatures_message_with_own_subject(self):
# type: () -> None
def test_signatures_message_with_own_subject(self) -> None:
expected_subject = "Our own subject."
self.url = self.build_webhook_url(topic=expected_subject)
expected_message = ("The NDA with Acme Co. is awaiting the signature of "
@@ -24,6 +22,5 @@ class HelloSignHookTests(WebhookTestCase):
self.send_and_test_stream_message('signatures_with_own_subject', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded", topic=expected_subject)
def get_body(self, fixture_name):
# type: (Text) -> Text
def get_body(self, fixture_name: Text) -> Text:
return self.fixture_data("hellosign", fixture_name, file_type="json")

View File

@@ -10,10 +10,8 @@ from django.http import HttpRequest, HttpResponse
from six import text_type
from typing import Any, Dict, List
def format_body(signatories, model_payload):
# type: (List[Dict[str, Any]], Dict[str, Any]) -> str
def append_separator(i):
# type: (int) -> None
def format_body(signatories: List[Dict[str, Any]], model_payload: Dict[str, Any]) -> str:
def append_separator(i: int) -> None:
if i + 1 == len(signatories):
result.append('.')
elif i + 2 == len(signatories):
@@ -33,8 +31,8 @@ def format_body(signatories, model_payload):
append_separator(i)
return ''.join(result)
def ready_payload(signatories, payload):
# type: (List[Dict[str, Any]], Dict[str, Dict[str, Any]]) -> Dict[str, Any]
def ready_payload(signatories: List[Dict[str, Any]],
payload: Dict[str, Dict[str, Any]]) -> Dict[str, Any]:
model_payload = {'contract_title': payload['signature_request']['title']}
for i, signatory in enumerate(signatories):
model_payload['name_{}'.format(i)] = signatory['signer_name']

View File

@@ -8,8 +8,7 @@ class HelloWorldHookTests(WebhookTestCase):
FIXTURE_DIR_NAME = 'hello'
# Note: Include a test function per each distinct message condition your integration supports
def test_hello_message(self):
# type: () -> None
def test_hello_message(self) -> None:
expected_subject = u"Hello World"
expected_message = u"Hello! I am happy to be here! :smile:\nThe Wikipedia featured article for today is **[Marilyn Monroe](https://en.wikipedia.org/wiki/Marilyn_Monroe)**"
@@ -17,8 +16,7 @@ class HelloWorldHookTests(WebhookTestCase):
self.send_and_test_stream_message('hello', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_goodbye_message(self):
# type: () -> None
def test_goodbye_message(self) -> None:
expected_subject = u"Hello World"
expected_message = u"Hello! I am happy to be here! :smile:\nThe Wikipedia featured article for today is **[Goodbye](https://en.wikipedia.org/wiki/Goodbye)**"
@@ -26,6 +24,5 @@ class HelloWorldHookTests(WebhookTestCase):
self.send_and_test_stream_message('goodbye', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def get_body(self, fixture_name):
# type: (Text) -> Text
def get_body(self, fixture_name: Text) -> Text:
return self.fixture_data("helloworld", fixture_name, file_type="json")

View File

@@ -6,8 +6,7 @@ class HerokuHookTests(WebhookTestCase):
STREAM_NAME = 'heroku'
URL_TEMPLATE = u"/api/v1/external/heroku?stream={stream}&api_key={api_key}"
def test_deployment(self):
# type: () -> None
def test_deployment(self) -> None:
expected_subject = "sample-project"
expected_message = u"""user@example.com deployed version 3eb5f44 of \
[sample-project](http://sample-project.herokuapp.com)
@@ -15,6 +14,5 @@ class HerokuHookTests(WebhookTestCase):
self.send_and_test_stream_message('deploy', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def get_body(self, fixture_name):
# type: (Text) -> Text
def get_body(self, fixture_name: Text) -> Text:
return self.fixture_data("heroku", fixture_name, file_type="txt")

View File

@@ -6,22 +6,19 @@ class HomeAssistantHookTests(WebhookTestCase):
URL_TEMPLATE = "/api/v1/external/homeassistant?&api_key={api_key}"
FIXTURE_DIR_NAME = 'homeassistant'
def test_simplereq(self):
# type: () -> None
def test_simplereq(self) -> None:
expected_subject = "homeassistant"
expected_message = "The sun will be shining today!"
self.send_and_test_stream_message('simplereq', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_req_with_title(self):
# type: () -> None
def test_req_with_title(self) -> None:
expected_subject = "Weather forecast"
expected_message = "It will be 30 degrees Celsius out there today!"
self.send_and_test_stream_message('reqwithtitle', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def get_body(self, fixture_name):
# type: (Text) -> Text
def get_body(self, fixture_name: Text) -> Text:
return self.fixture_data("homeassistant", fixture_name, file_type="json")

View File

@@ -6,8 +6,7 @@ class IFTTTHookTests(WebhookTestCase):
URL_TEMPLATE = "/api/v1/external/ifttt?stream={stream}&api_key={api_key}"
FIXTURE_DIR_NAME = 'ifttt'
def test_ifttt_when_subject_and_body_are_correct(self):
# type: () -> None
def test_ifttt_when_subject_and_body_are_correct(self) -> None:
expected_subject = u"Email sent from email@email.com"
expected_message = u"Email subject: Subject"
self.send_and_test_stream_message('correct_subject_and_body', expected_subject, expected_message)

View File

@@ -6,8 +6,7 @@ class JiraHookTests(WebhookTestCase):
STREAM_NAME = 'jira'
URL_TEMPLATE = u"/api/v1/external/jira?api_key={api_key}"
def test_unknown(self):
# type: () -> None
def test_unknown(self) -> None:
url = self.build_webhook_url()
result = self.client_post(url,
@@ -24,8 +23,7 @@ class JiraHookTests(WebhookTestCase):
self.assert_json_success(result)
def test_custom_stream(self):
# type: () -> None
def test_custom_stream(self) -> None:
api_key = self.test_user.api_key
url = "/api/v1/external/jira?api_key=%s&stream=jira_custom" % (api_key,)
msg = self.send_json_payload(self.test_user,
@@ -38,8 +36,7 @@ class JiraHookTests(WebhookTestCase):
> New bug with hook""")
def test_created(self):
# type: () -> None
def test_created(self) -> None:
expected_subject = "BUG-15: New bug with hook"
expected_message = """Leo Franchi **created** [BUG-15](http://lfranchi.com:8080/browse/BUG-15) priority Major, assigned to **no one**:
@@ -47,8 +44,7 @@ class JiraHookTests(WebhookTestCase):
self.send_and_test_stream_message('created_v1', expected_subject, expected_message)
self.send_and_test_stream_message('created_v2', expected_subject, expected_message)
def test_created_with_unicode(self):
# type: () -> None
def test_created_with_unicode(self) -> None:
expected_subject = u"BUG-15: New bug with à hook"
expected_message = u"""Leo Franchià **created** [BUG-15](http://lfranchi.com:8080/browse/BUG-15) priority Major, assigned to **no one**:
@@ -56,8 +52,7 @@ class JiraHookTests(WebhookTestCase):
self.send_and_test_stream_message('created_with_unicode_v1', expected_subject, expected_message)
self.send_and_test_stream_message('created_with_unicode_v2', expected_subject, expected_message)
def test_created_assignee(self):
# type: () -> None
def test_created_assignee(self) -> None:
expected_subject = "TEST-4: Test Created Assignee"
expected_message = """Leonardo Franchi [Administrator] **created** [TEST-4](https://zulipp.atlassian.net/browse/TEST-4) priority Major, assigned to **Leonardo Franchi [Administrator]**:
@@ -65,8 +60,7 @@ class JiraHookTests(WebhookTestCase):
self.send_and_test_stream_message('created_assignee_v1', expected_subject, expected_message)
self.send_and_test_stream_message('created_assignee_v2', expected_subject, expected_message)
def test_commented(self):
# type: () -> None
def test_commented(self) -> None:
expected_subject = "BUG-15: New bug with hook"
expected_message = """Leo Franchi **added comment to** [BUG-15](http://lfranchi.com:8080/browse/BUG-15) (assigned to **Othello, the Moor of Venice**):
@@ -75,8 +69,7 @@ Adding a comment. Oh, what a comment it is!"""
self.send_and_test_stream_message('commented_v1', expected_subject, expected_message)
self.send_and_test_stream_message('commented_v2', expected_subject, expected_message)
def test_comment_edited(self):
# type: () -> None
def test_comment_edited(self) -> None:
expected_subject = "BUG-15: New bug with hook"
expected_message = """Leo Franchi **edited comment on** [BUG-15](http://lfranchi.com:8080/browse/BUG-15) (assigned to **Othello, the Moor of Venice**):
@@ -84,28 +77,24 @@ Adding a comment. Oh, what a comment it is!"""
Adding a comment. Oh, what a comment it is!"""
self.send_and_test_stream_message('comment_edited_v2', expected_subject, expected_message)
def test_comment_deleted(self):
# type: () -> None
def test_comment_deleted(self) -> None:
expected_subject = "TOM-1: New Issue"
expected_message = "Tomasz Kolek **deleted comment from** [TOM-1](https://zuliptomek.atlassian.net/browse/TOM-1) (assigned to **kolaszek@go2.pl**)"
self.send_and_test_stream_message('comment_deleted_v2', expected_subject, expected_message)
def test_commented_markup(self):
# type: () -> None
def test_commented_markup(self) -> None:
expected_subject = "TEST-7: Testing of rich text"
expected_message = """Leonardo Franchi [Administrator] **added comment to** [TEST-7](https://zulipp.atlassian.net/browse/TEST-7):\n\n\nThis is a comment that likes to **exercise** a lot of _different_ `conventions` that `jira uses`.\r\n\r\n~~~\n\r\nthis code is not highlighted, but monospaced\r\n\n~~~\r\n\r\n~~~\n\r\ndef python():\r\n print "likes to be formatted"\r\n\n~~~\r\n\r\n[http://www.google.com](http://www.google.com) is a bare link, and [Google](http://www.google.com) is given a title.\r\n\r\nThanks!\r\n\r\n~~~ quote\n\r\nSomeone said somewhere\r\n\n~~~"""
self.send_and_test_stream_message('commented_markup_v1', expected_subject, expected_message)
self.send_and_test_stream_message('commented_markup_v2', expected_subject, expected_message)
def test_deleted(self):
# type: () -> None
def test_deleted(self) -> None:
expected_subject = "BUG-15: New bug with hook"
expected_message = "Leo Franchi **deleted** [BUG-15](http://lfranchi.com:8080/browse/BUG-15)!"
self.send_and_test_stream_message('deleted_v1', expected_subject, expected_message)
self.send_and_test_stream_message('deleted_v2', expected_subject, expected_message)
def test_reassigned(self):
# type: () -> None
def test_reassigned(self) -> None:
expected_subject = "BUG-15: New bug with hook"
expected_message = """Leo Franchi **updated** [BUG-15](http://lfranchi.com:8080/browse/BUG-15) (assigned to **Othello, the Moor of Venice**):
@@ -113,8 +102,7 @@ Adding a comment. Oh, what a comment it is!"""
self.send_and_test_stream_message('reassigned_v1', expected_subject, expected_message)
self.send_and_test_stream_message('reassigned_v2', expected_subject, expected_message)
def test_priority_updated(self):
# type: () -> None
def test_priority_updated(self) -> None:
expected_subject = "TEST-1: Fix That"
expected_message = """Leonardo Franchi [Administrator] **updated** [TEST-1](https://zulipp.atlassian.net/browse/TEST-1) (assigned to **leo@zulip.com**):
@@ -122,8 +110,7 @@ Adding a comment. Oh, what a comment it is!"""
self.send_and_test_stream_message('updated_priority_v1', expected_subject, expected_message)
self.send_and_test_stream_message('updated_priority_v2', expected_subject, expected_message)
def test_status_changed(self):
# type: () -> None
def test_status_changed(self) -> None:
expected_subject = "TEST-1: Fix That"
expected_message = """Leonardo Franchi [Administrator] **updated** [TEST-1](https://zulipp.atlassian.net/browse/TEST-1):
@@ -131,6 +118,5 @@ Adding a comment. Oh, what a comment it is!"""
self.send_and_test_stream_message('change_status_v1', expected_subject, expected_message)
self.send_and_test_stream_message('change_status_v2', expected_subject, expected_message)
def get_body(self, fixture_name):
# type: (Text) -> Text
def get_body(self, fixture_name: Text) -> Text:
return self.fixture_data('jira', fixture_name)

View File

@@ -23,8 +23,7 @@ IGNORED_EVENTS = [
'comment_deleted', # we handle issue_update event instead
]
def guess_zulip_user_from_jira(jira_username, realm):
# type: (Text, Realm) -> Optional[UserProfile]
def guess_zulip_user_from_jira(jira_username: Text, realm: Realm) -> Optional[UserProfile]:
try:
# Try to find a matching user in Zulip
# We search a user's full name, short name,
@@ -39,8 +38,7 @@ def guess_zulip_user_from_jira(jira_username, realm):
except IndexError:
return None
def convert_jira_markup(content, realm):
# type: (Text, Realm) -> Text
def convert_jira_markup(content: Text, realm: Realm) -> Text:
# Attempt to do some simplistic conversion of JIRA
# formatting to Markdown, for consumption in Zulip
@@ -91,8 +89,7 @@ def convert_jira_markup(content, realm):
return content
def get_in(payload, keys, default=''):
# type: (Dict[str, Any], List[str], Text) -> Any
def get_in(payload: Dict[str, Any], keys: List[str], default: Text='') -> Any:
try:
for key in keys:
payload = payload[key]
@@ -100,8 +97,7 @@ def get_in(payload, keys, default=''):
return default
return payload
def get_issue_string(payload, issue_id=None):
# type: (Dict[str, Any], Text) -> Text
def get_issue_string(payload: Dict[str, Any], issue_id: Text=None) -> Text:
# Guess the URL as it is not specified in the payload
# We assume that there is a /browse/BUG-### page
# from the REST url of the issue itself
@@ -114,8 +110,7 @@ def get_issue_string(payload, issue_id=None):
else:
return issue_id
def get_assignee_mention(assignee_email, realm):
# type: (Text, Realm) -> Text
def get_assignee_mention(assignee_email: Text, realm: Realm) -> Text:
if assignee_email != '':
try:
assignee_name = get_user(assignee_email, realm).full_name
@@ -124,24 +119,19 @@ def get_assignee_mention(assignee_email, realm):
return u"**{}**".format(assignee_name)
return ''
def get_issue_author(payload):
# type: (Dict[str, Any]) -> Text
def get_issue_author(payload: Dict[str, Any]) -> Text:
return get_in(payload, ['user', 'displayName'])
def get_issue_id(payload):
# type: (Dict[str, Any]) -> Text
def get_issue_id(payload: Dict[str, Any]) -> Text:
return get_in(payload, ['issue', 'key'])
def get_issue_title(payload):
# type: (Dict[str, Any]) -> Text
def get_issue_title(payload: Dict[str, Any]) -> Text:
return get_in(payload, ['issue', 'fields', 'summary'])
def get_issue_subject(payload):
# type: (Dict[str, Any]) -> Text
def get_issue_subject(payload: Dict[str, Any]) -> Text:
return u"{}: {}".format(get_issue_id(payload), get_issue_title(payload))
def get_sub_event_for_update_issue(payload):
# type: (Dict[str, Any]) -> Text
def get_sub_event_for_update_issue(payload: Dict[str, Any]) -> Text:
sub_event = payload.get('issue_event_type_name', '')
if sub_event == '':
if payload.get('comment'):
@@ -150,15 +140,13 @@ def get_sub_event_for_update_issue(payload):
return 'issue_transited'
return sub_event
def get_event_type(payload):
# type: (Dict[str, Any]) -> Optional[Text]
def get_event_type(payload: Dict[str, Any]) -> Optional[Text]:
event = payload.get('webhookEvent')
if event is None and payload.get('transition'):
event = 'jira:issue_updated'
return event
def add_change_info(content, field, from_field, to_field):
# type: (Text, Text, Text, Text) -> Text
def add_change_info(content: Text, field: Text, from_field: Text, to_field: Text) -> Text:
content += u"* Changed {}".format(field)
if from_field:
content += u" from **{}**".format(from_field)
@@ -166,8 +154,7 @@ def add_change_info(content, field, from_field, to_field):
content += u" to {}\n".format(to_field)
return content
def handle_updated_issue_event(payload, user_profile):
# type: (Dict[str, Any], UserProfile) -> Text
def handle_updated_issue_event(payload: Dict[str, Any], user_profile: UserProfile) -> Text:
# Reassigned, commented, reopened, and resolved events are all bundled
# into this one 'updated' event type, so we try to extract the meaningful
# event that happened
@@ -223,8 +210,7 @@ def handle_updated_issue_event(payload, user_profile):
return content
def handle_created_issue_event(payload):
# type: (Dict[str, Any]) -> Text
def handle_created_issue_event(payload: Dict[str, Any]) -> Text:
return u"{} **created** {} priority {}, assigned to **{}**:\n\n> {}".format(
get_issue_author(payload),
get_issue_string(payload),
@@ -233,8 +219,7 @@ def handle_created_issue_event(payload):
get_issue_title(payload)
)
def handle_deleted_issue_event(payload):
# type: (Dict[str, Any]) -> Text
def handle_deleted_issue_event(payload: Dict[str, Any]) -> Text:
return u"{} **deleted** {}!".format(get_issue_author(payload), get_issue_string(payload))
@api_key_only_webhook_view("JIRA")

View File

@@ -9,39 +9,33 @@ class LibratoHookTests(WebhookTestCase):
FIXTURE_DIR_NAME = 'librato'
IS_ATTACHMENT = False
def get_body(self, fixture_name):
# type: (Text) -> Text
def get_body(self, fixture_name: Text) -> Text:
if self.IS_ATTACHMENT:
return self.fixture_data("librato", fixture_name, file_type='json')
return urllib.parse.urlencode({'payload': self.fixture_data("librato", fixture_name, file_type='json')})
def test_alert_message_with_default_topic(self):
# type: () -> None
def test_alert_message_with_default_topic(self) -> None:
expected_subject = 'Alert alert.name'
expected_message = "Alert [alert_name](https://metrics.librato.com/alerts#/6294535) has triggered! [Reaction steps](http://www.google.pl)\n>Metric `librato.cpu.percent.idle`, sum was below 44 by 300s, recorded at 2016-03-31 09:11:42 UTC\n>Metric `librato.swap.swap.cached`, average was absent by 300s, recorded at 2016-03-31 09:11:42 UTC\n>Metric `librato.swap.swap.cached`, derivative was above 9 by 300s, recorded at 2016-03-31 09:11:42 UTC"
self.send_and_test_stream_message('alert', expected_subject, expected_message, content_type="application/x-www-form-urlencoded")
def test_alert_message_with_custom_topic(self):
# type: () -> None
def test_alert_message_with_custom_topic(self) -> None:
custom_topic = 'custom_name'
self.url = self.build_webhook_url(topic=custom_topic)
expected_message = "Alert [alert_name](https://metrics.librato.com/alerts#/6294535) has triggered! [Reaction steps](http://www.google.pl)\n>Metric `librato.cpu.percent.idle`, sum was below 44 by 300s, recorded at 2016-03-31 09:11:42 UTC\n>Metric `librato.swap.swap.cached`, average was absent by 300s, recorded at 2016-03-31 09:11:42 UTC\n>Metric `librato.swap.swap.cached`, derivative was above 9 by 300s, recorded at 2016-03-31 09:11:42 UTC"
self.send_and_test_stream_message('alert', custom_topic, expected_message, content_type="application/x-www-form-urlencoded")
def test_three_conditions_alert_message(self):
# type: () -> None
def test_three_conditions_alert_message(self) -> None:
expected_message = "Alert [alert_name](https://metrics.librato.com/alerts#/6294535) has triggered! [Reaction steps](http://www.use.water.pl)\n>Metric `collectd.interface.eth0.if_octets.tx`, absolute_value was above 4 by 300s, recorded at 2016-04-11 20:40:14 UTC\n>Metric `collectd.load.load.longterm`, max was above 99, recorded at 2016-04-11 20:40:14 UTC\n>Metric `librato.swap.swap.cached`, average was absent by 60s, recorded at 2016-04-11 20:40:14 UTC"
expected_subject = 'Alert ToHighTemeprature'
self.send_and_test_stream_message('three_conditions_alert', expected_subject, expected_message, content_type="application/x-www-form-urlencoded")
def test_alert_clear(self):
# type: () -> None
def test_alert_clear(self) -> None:
expected_subject = 'Alert Alert_name'
expected_message = "Alert [alert_name](https://metrics.librato.com/alerts#/6309313) has cleared at 2016-04-12 13:11:44 UTC!"
self.send_and_test_stream_message('alert_cleared', expected_subject, expected_message, content_type="application/x-www-form-urlencoded")
def test_snapshot(self):
# type: () -> None
def test_snapshot(self) -> None:
self.IS_ATTACHMENT = True
expected_subject = 'Snapshots'
expected_message = "**Hamlet** sent a [snapshot](http://snapshots.librato.com/chart/nr5l3n0c-82162.png) of [metric](https://metrics.librato.com/s/spaces/167315/explore/1731491?duration=72039&end_time=1460569409)"

View File

@@ -21,54 +21,45 @@ SNAPSHOT = 'image_url'
class LibratoWebhookParser(object):
ALERT_URL_TEMPLATE = "https://metrics.librato.com/alerts#/{alert_id}"
def __init__(self, payload, attachments):
# type: (Dict[str, Any], List[Dict[str, Any]]) -> None
def __init__(self, payload: Dict[str, Any], attachments: List[Dict[str, Any]]) -> None:
self.payload = payload
self.attachments = attachments
def generate_alert_url(self, alert_id):
# type: (int) -> Text
def generate_alert_url(self, alert_id: int) -> Text:
return self.ALERT_URL_TEMPLATE.format(alert_id=alert_id)
def parse_alert(self):
# type: () -> Tuple[int, Text, Text, Text]
def parse_alert(self) -> Tuple[int, Text, Text, Text]:
alert = self.payload['alert']
alert_id = alert['id']
return alert_id, alert['name'], self.generate_alert_url(alert_id), alert['runbook_url']
def parse_condition(self, condition):
# type: (Dict[str, Any]) -> Tuple[Text, Text, Text, Text]
def parse_condition(self, condition: Dict[str, Any]) -> Tuple[Text, Text, Text, Text]:
summary_function = condition['summary_function']
threshold = condition.get('threshold', '')
condition_type = condition['type']
duration = condition.get('duration', '')
return summary_function, threshold, condition_type, duration
def parse_violation(self, violation):
# type: (Dict[str, Any]) -> Tuple[Text, Text]
def parse_violation(self, violation: Dict[str, Any]) -> Tuple[Text, Text]:
metric_name = violation['metric']
recorded_at = datetime.fromtimestamp((violation['recorded_at']),
tz=timezone_utc).strftime('%Y-%m-%d %H:%M:%S')
return metric_name, recorded_at
def parse_conditions(self):
# type: () -> List[Dict[str, Any]]
def parse_conditions(self) -> List[Dict[str, Any]]:
conditions = self.payload['conditions']
return conditions
def parse_violations(self):
# type: () -> List[Dict[str, Any]]
def parse_violations(self) -> List[Dict[str, Any]]:
violations = self.payload['violations']['test-source']
return violations
def parse_snapshot(self, snapshot):
# type: (Dict[str, Any]) -> Tuple[Text, Text, Text]
def parse_snapshot(self, snapshot: Dict[str, Any]) -> Tuple[Text, Text, Text]:
author_name, image_url, title = snapshot['author_name'], snapshot['image_url'], snapshot['title']
return author_name, image_url, title
class LibratoWebhookHandler(LibratoWebhookParser):
def __init__(self, payload, attachments):
# type: (Dict[str, Any], List[Dict[str, Any]]) -> None
def __init__(self, payload: Dict[str, Any], attachments: List[Dict[str, Any]]) -> None:
super().__init__(payload, attachments)
self.payload_available_types = {
ALERT_CLEAR: self.handle_alert_clear_message,
@@ -79,8 +70,7 @@ class LibratoWebhookHandler(LibratoWebhookParser):
SNAPSHOT: self.handle_snapshots
}
def find_handle_method(self):
# type: () -> Callable[[], Text]
def find_handle_method(self) -> Callable[[], Text]:
for available_type in self.payload_available_types:
if self.payload.get(available_type):
return self.payload_available_types[available_type]
@@ -89,20 +79,17 @@ class LibratoWebhookHandler(LibratoWebhookParser):
return self.attachments_available_types[available_type]
raise Exception("Unexcepted message type")
def handle(self):
# type: () -> Text
def handle(self) -> Text:
return self.find_handle_method()()
def generate_topic(self):
# type: () -> Text
def generate_topic(self) -> Text:
if self.attachments:
return "Snapshots"
topic_template = "Alert {alert_name}"
alert_id, alert_name, alert_url, alert_runbook_url = self.parse_alert()
return topic_template.format(alert_name=alert_name)
def handle_alert_clear_message(self):
# type: () -> Text
def handle_alert_clear_message(self) -> Text:
alert_clear_template = "Alert [alert_name]({alert_url}) has cleared at {trigger_time} UTC!"
trigger_time = datetime.fromtimestamp((self.payload['trigger_time']),
tz=timezone_utc).strftime('%Y-%m-%d %H:%M:%S')
@@ -110,22 +97,19 @@ class LibratoWebhookHandler(LibratoWebhookParser):
content = alert_clear_template.format(alert_name=alert_name, alert_url=alert_url, trigger_time=trigger_time)
return content
def handle_snapshots(self):
# type: () -> Text
def handle_snapshots(self) -> Text:
content = u''
for attachment in self.attachments:
content += self.handle_snapshot(attachment)
return content
def handle_snapshot(self, snapshot):
# type: (Dict[str, Any]) -> Text
def handle_snapshot(self, snapshot: Dict[str, Any]) -> Text:
snapshot_template = u"**{author_name}** sent a [snapshot]({image_url}) of [metric]({title})"
author_name, image_url, title = self.parse_snapshot(snapshot)
content = snapshot_template.format(author_name=author_name, image_url=image_url, title=title)
return content
def handle_alert_violation_message(self):
# type: () -> Text
def handle_alert_violation_message(self) -> Text:
alert_violation_template = u"Alert [alert_name]({alert_url}) has triggered! "
alert_id, alert_name, alert_url, alert_runbook_url = self.parse_alert()
content = alert_violation_template.format(alert_name=alert_name, alert_url=alert_url)
@@ -135,8 +119,7 @@ class LibratoWebhookHandler(LibratoWebhookParser):
content += self.generate_conditions_and_violations()
return content
def generate_conditions_and_violations(self):
# type: () -> Text
def generate_conditions_and_violations(self) -> Text:
conditions = self.parse_conditions()
violations = self.parse_violations()
content = u""
@@ -144,8 +127,7 @@ class LibratoWebhookHandler(LibratoWebhookParser):
content += self.generate_violated_metric_condition(violation, condition)
return content
def generate_violated_metric_condition(self, violation, condition):
# type: (Dict[str, Any], Dict[str, Any]) -> Text
def generate_violated_metric_condition(self, violation: Dict[str, Any], condition: Dict[str, Any]) -> Text:
summary_function, threshold, condition_type, duration = self.parse_condition(condition)
metric_name, recorded_at = self.parse_violation(violation)
metric_condition_template = u"\n>Metric `{metric_name}`, {summary_function} was {condition_type} {threshold}"

View File

@@ -7,8 +7,7 @@ class MentionHookTests(WebhookTestCase):
URL_TEMPLATE = "/api/v1/external/mention?api_key={api_key}&stream={stream}"
FIXTURE_DIR_NAME = 'mention'
def test_mention_webfeed(self):
# type: () -> None
def test_mention_webfeed(self) -> None:
expected_topic = u"news"
expected_message = (u"**[Historical Sexual Abuse (Football): 29 Nov 2016: House of Commons debates - TheyWorkForYou]"
u"(https://www.theyworkforyou.com/debates/?id=2016-11-29b.1398.7&p=24887)**:\n"
@@ -21,6 +20,5 @@ class MentionHookTests(WebhookTestCase):
self.send_and_test_stream_message('webfeeds', expected_topic, expected_message,
content_type="application/x-www-form-urlencoded")
def get_body(self, fixture_name):
# type: (Text) -> Text
def get_body(self, fixture_name: Text) -> Text:
return self.fixture_data("mention", fixture_name, file_type="json")

View File

@@ -6,8 +6,7 @@ class NewRelicHookTests(WebhookTestCase):
STREAM_NAME = 'newrelic'
URL_TEMPLATE = u"/api/v1/external/newrelic?stream={stream}&api_key={api_key}"
def test_alert(self):
# type: () -> None
def test_alert(self) -> None:
expected_subject = "Apdex score fell below critical level of 0.90"
expected_message = 'Alert opened on [application name]: \
Apdex score fell below critical level of 0.90\n\
@@ -15,14 +14,12 @@ Apdex score fell below critical level of 0.90\n\
self.send_and_test_stream_message('alert', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_deployment(self):
# type: () -> None
def test_deployment(self) -> None:
expected_subject = 'Test App deploy'
expected_message = '`1242` deployed by **Zulip Test**\n\
Description sent via curl\n\nChangelog string'
self.send_and_test_stream_message('deployment', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def get_body(self, fixture_name):
# type: (Text) -> Text
def get_body(self, fixture_name: Text) -> Text:
return self.fixture_data("newrelic", fixture_name, file_type="txt")

View File

@@ -7,8 +7,7 @@ class OpsGenieHookTests(WebhookTestCase):
URL_TEMPLATE = "/api/v1/external/opsgenie?&api_key={api_key}"
FIXTURE_DIR_NAME = 'opsgenie'
def test_acknowledge_alert(self):
# type: () -> None
def test_acknowledge_alert(self) -> None:
expected_subject = u"Integration1"
expected_message = (u"**OpsGenie: [Alert for Integration1.](https://app.opsgenie.com/alert/V2#/show/052652ac-5d1c-464a-812a-7dd18bbfba8c)**\n"
u"Type: *Acknowledge*\n"
@@ -18,8 +17,7 @@ class OpsGenieHookTests(WebhookTestCase):
self.send_and_test_stream_message('acknowledge', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_addnote_alert(self):
# type: () -> None
def test_addnote_alert(self) -> None:
expected_subject = u"Integration1"
expected_message = (u"**OpsGenie: [Alert for Integration1.](https://app.opsgenie.com/alert/V2#/show/052652ac-5d1c-464a-812a-7dd18bbfba8c)**\n"
u"Type: *AddNote*\n"
@@ -30,8 +28,7 @@ class OpsGenieHookTests(WebhookTestCase):
self.send_and_test_stream_message('addnote', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_addrecipient_alert(self):
# type: () -> None
def test_addrecipient_alert(self) -> None:
expected_subject = u"Integration1"
expected_message = (u"**OpsGenie: [Alert for Integration1.](https://app.opsgenie.com/alert/V2#/show/052652ac-5d1c-464a-812a-7dd18bbfba8c)**\n"
u"Type: *AddRecipient*\n"
@@ -43,8 +40,7 @@ class OpsGenieHookTests(WebhookTestCase):
self.send_and_test_stream_message('addrecipient', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_addtags_alert(self):
# type: () -> None
def test_addtags_alert(self) -> None:
expected_subject = u"Integration1"
expected_message = (u"**OpsGenie: [Alert for Integration1.](https://app.opsgenie.com/alert/V2#/show/052652ac-5d1c-464a-812a-7dd18bbfba8c)**\n"
u"Type: *AddTags*\n"
@@ -55,8 +51,7 @@ class OpsGenieHookTests(WebhookTestCase):
self.send_and_test_stream_message('addtags', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_addteam_alert(self):
# type: () -> None
def test_addteam_alert(self) -> None:
expected_subject = u"Integration1"
expected_message = (u"**OpsGenie: [Alert for Integration1.](https://app.opsgenie.com/alert/V2#/show/052652ac-5d1c-464a-812a-7dd18bbfba8c)**\n"
u"Type: *AddTeam*\n"
@@ -67,8 +62,7 @@ class OpsGenieHookTests(WebhookTestCase):
self.send_and_test_stream_message('addteam', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_assignownership_alert(self):
# type: () -> None
def test_assignownership_alert(self) -> None:
expected_subject = u"Integration1"
expected_message = (u"**OpsGenie: [Alert for Integration1.](https://app.opsgenie.com/alert/V2#/show/052652ac-5d1c-464a-812a-7dd18bbfba8c)**\n"
u"Type: *AssignOwnership*\n"
@@ -79,8 +73,7 @@ class OpsGenieHookTests(WebhookTestCase):
self.send_and_test_stream_message('assignownership', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_close_alert(self):
# type: () -> None
def test_close_alert(self) -> None:
expected_subject = u"Integration1"
expected_message = (u"**OpsGenie: [Alert for Integration1.](https://app.opsgenie.com/alert/V2#/show/052652ac-5d1c-464a-812a-7dd18bbfba8c)**\n"
u"Type: *Close*\n"
@@ -89,8 +82,7 @@ class OpsGenieHookTests(WebhookTestCase):
self.send_and_test_stream_message('close', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_create_alert(self):
# type: () -> None
def test_create_alert(self) -> None:
expected_subject = u"Webhook"
expected_message = (u"**OpsGenie: [Alert for Webhook.](https://app.opsgenie.com/alert/V2#/show/ec03dad6-62c8-4c94-b38b-d88f398e900f)**\n"
u"Type: *Create*\n"
@@ -100,8 +92,7 @@ class OpsGenieHookTests(WebhookTestCase):
self.send_and_test_stream_message('create', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_customaction_alert(self):
# type: () -> None
def test_customaction_alert(self) -> None:
expected_subject = u"Integration1"
expected_message = (u"**OpsGenie: [Alert for Integration1.](https://app.opsgenie.com/alert/V2#/show/052652ac-5d1c-464a-812a-7dd18bbfba8c)**\n"
u"Type: *TestAction*\n"
@@ -111,8 +102,7 @@ class OpsGenieHookTests(WebhookTestCase):
self.send_and_test_stream_message('customaction', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_delete_alert(self):
# type: () -> None
def test_delete_alert(self) -> None:
expected_subject = u"Integration1"
expected_message = (u"**OpsGenie: [Alert for Integration1.](https://app.opsgenie.com/alert/V2#/show/052652ac-5d1c-464a-812a-7dd18bbfba8c)**\n"
u"Type: *Delete*\n"
@@ -121,8 +111,7 @@ class OpsGenieHookTests(WebhookTestCase):
self.send_and_test_stream_message('delete', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_escalate_alert(self):
# type: () -> None
def test_escalate_alert(self) -> None:
expected_subject = u"Webhook_Test"
expected_message = (u"**OpsGenie: [Alert for Webhook_Test.](https://app.opsgenie.com/alert/V2#/show/7ba97e3a-d328-4b5e-8f9a-39e945a3869a)**\n"
u"Type: *Escalate*\n"
@@ -131,8 +120,7 @@ class OpsGenieHookTests(WebhookTestCase):
self.send_and_test_stream_message('escalate', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_removetags_alert(self):
# type: () -> None
def test_removetags_alert(self) -> None:
expected_subject = u"Integration1"
expected_message = (u"**OpsGenie: [Alert for Integration1.](https://app.opsgenie.com/alert/V2#/show/052652ac-5d1c-464a-812a-7dd18bbfba8c)**\n"
u"Type: *RemoveTags*\n"
@@ -143,8 +131,7 @@ class OpsGenieHookTests(WebhookTestCase):
self.send_and_test_stream_message('removetags', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_takeownership_alert(self):
# type: () -> None
def test_takeownership_alert(self) -> None:
expected_subject = u"Webhook"
expected_message = (u"**OpsGenie: [Alert for Webhook.](https://app.opsgenie.com/alert/V2#/show/8a745a79-3ed3-4044-8427-98e067c0623c)**\n"
u"Type: *TakeOwnership*\n"
@@ -154,8 +141,7 @@ class OpsGenieHookTests(WebhookTestCase):
self.send_and_test_stream_message('takeownership', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_unacknowledge_alert(self):
# type: () -> None
def test_unacknowledge_alert(self) -> None:
expected_subject = u"Integration1"
expected_message = (u"**OpsGenie: [Alert for Integration1.](https://app.opsgenie.com/alert/V2#/show/052652ac-5d1c-464a-812a-7dd18bbfba8c)**\n"
u"Type: *UnAcknowledge*\n"
@@ -165,6 +151,5 @@ class OpsGenieHookTests(WebhookTestCase):
self.send_and_test_stream_message('unacknowledge', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def get_body(self, fixture_name):
# type: (Text) -> Text
def get_body(self, fixture_name: Text) -> Text:
return self.fixture_data("opsgenie", fixture_name, file_type="json")

View File

@@ -7,42 +7,34 @@ class PagerDutyHookTests(WebhookTestCase):
URL_TEMPLATE = u"/api/v1/external/pagerduty?api_key={api_key}&stream={stream}"
FIXTURE_DIR_NAME = 'pagerduty'
def test_trigger(self):
# type: () -> None
def test_trigger(self) -> None:
expected_message = ':imp: Incident [3](https://zulip-test.pagerduty.com/incidents/P140S4Y) triggered by [Test service](https://zulip-test.pagerduty.com/services/PIL5CUQ) and assigned to [armooo@](https://zulip-test.pagerduty.com/users/POBCFRJ)\n\n>foo'
self.send_and_test_stream_message('trigger', u"incident 3", expected_message)
def test_unacknowledge(self):
# type: () -> None
def test_unacknowledge(self) -> None:
expected_message = ':imp: Incident [3](https://zulip-test.pagerduty.com/incidents/P140S4Y) unacknowledged by [Test service](https://zulip-test.pagerduty.com/services/PIL5CUQ) and assigned to [armooo@](https://zulip-test.pagerduty.com/users/POBCFRJ)\n\n>foo'
self.send_and_test_stream_message('unacknowledge', u"incident 3", expected_message)
def test_resolved(self):
# type: () -> None
def test_resolved(self) -> None:
expected_message = ':grinning: Incident [1](https://zulip-test.pagerduty.com/incidents/PO1XIJ5) resolved by [armooo@](https://zulip-test.pagerduty.com/users/POBCFRJ)\n\n>It is on fire'
self.send_and_test_stream_message('resolved', u"incident 1", expected_message)
def test_auto_resolved(self):
# type: () -> None
def test_auto_resolved(self) -> None:
expected_message = ':grinning: Incident [2](https://zulip-test.pagerduty.com/incidents/PX7K9J2) resolved\n\n>new'
self.send_and_test_stream_message('auto_resolved', u"incident 2", expected_message)
def test_acknowledge(self):
# type: () -> None
def test_acknowledge(self) -> None:
expected_message = ':no_good: Incident [1](https://zulip-test.pagerduty.com/incidents/PO1XIJ5) acknowledged by [armooo@](https://zulip-test.pagerduty.com/users/POBCFRJ)\n\n>It is on fire'
self.send_and_test_stream_message('acknowledge', u"incident 1", expected_message)
def test_no_subject(self):
# type: () -> None
def test_no_subject(self) -> None:
expected_message = u':grinning: Incident [48219](https://dropbox.pagerduty.com/incidents/PJKGZF9) resolved\n\n>mp_error_block_down_critical\u2119\u01b4'
self.send_and_test_stream_message('mp_fail', u"incident 48219", expected_message)
def test_bad_message(self):
# type: () -> None
def test_bad_message(self) -> None:
expected_message = 'Unknown pagerduty message\n```\n{\n "type":"incident.triggered"\n}\n```'
self.send_and_test_stream_message('bad_message_type', u"pagerduty", expected_message)
def test_unknown_message_type(self):
# type: () -> None
def test_unknown_message_type(self) -> None:
expected_message = 'Unknown pagerduty message\n```\n{\n "type":"foo"\n}\n```'
self.send_and_test_stream_message('unknown_message_type', u"pagerduty", expected_message)

View File

@@ -23,8 +23,7 @@ PAGER_DUTY_EVENT_NAMES = {
'incident.delegate': 'delineated',
}
def build_pagerduty_formatdict(message):
# type: (Dict[str, Any]) -> Dict[str, Any]
def build_pagerduty_formatdict(message: Dict[str, Any]) -> Dict[str, Any]:
# Normalize the message dict, after this all keys will exist. I would
# rather some strange looking messages than dropping pages.
@@ -69,8 +68,11 @@ def build_pagerduty_formatdict(message):
return format_dict
def send_raw_pagerduty_json(user_profile, client, stream, message, topic):
# type: (UserProfile, Client, Text, Dict[str, Any], Optional[Text]) -> None
def send_raw_pagerduty_json(user_profile: UserProfile,
client: Client,
stream: Text,
message: Dict[str, Any],
topic: Optional[Text]) -> None:
subject = topic or 'pagerduty'
body = (
u'Unknown pagerduty message\n'
@@ -80,8 +82,12 @@ def send_raw_pagerduty_json(user_profile, client, stream, message, topic):
check_send_stream_message(user_profile, client, stream, subject, body)
def send_formated_pagerduty(user_profile, client, stream, message_type, format_dict, topic):
# type: (UserProfile, Client, Text, Text, Dict[str, Any], Optional[Text]) -> None
def send_formated_pagerduty(user_profile: UserProfile,
client: Client,
stream: Text,
message_type: Text,
format_dict: Dict[str, Any],
topic: Optional[Text]) -> None:
if message_type in ('incident.trigger', 'incident.unacknowledge'):
template = (u':imp: Incident '
u'[{incident_num}]({incident_url}) {action} by '

View File

@@ -7,8 +7,7 @@ class PapertrailHookTests(WebhookTestCase):
FIXTURE_DIR_NAME = 'papertrail'
# Note: Include a test function per each distinct message condition your integration supports
def test_short_message(self):
# type: () -> None
def test_short_message(self) -> None:
expected_subject = u"logs"
expected_message = u'''**"Important stuff"** search found **2** matches - https://papertrailapp.com/searches/42
```
@@ -22,8 +21,7 @@ May 18 20:30:02 server1 cron OR server1:
self.send_and_test_stream_message('short_post', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_long_message(self):
# type: () -> None
def test_long_message(self) -> None:
expected_subject = u"logs"
expected_message = u'''**"Important stuff"** search found **5** matches - https://papertrailapp.com/searches/42
```
@@ -41,6 +39,5 @@ May 18 20:30:02 abc cron OR server1:
self.send_and_test_stream_message('long_post', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def get_body(self, fixture_name):
# type: (Text) -> Text
def get_body(self, fixture_name: Text) -> Text:
return self.fixture_data("papertrail", fixture_name, file_type="json")

View File

@@ -6,32 +6,28 @@ class PingdomHookTests(WebhookTestCase):
URL_TEMPLATE = u"/api/v1/external/pingdom?stream={stream}&api_key={api_key}"
FIXTURE_DIR_NAME = 'pingdom'
def test_pingdom_from_up_to_down_http_check_message(self):
# type: () -> None
def test_pingdom_from_up_to_down_http_check_message(self) -> None:
"""
Tests if pingdom http check from up to down is handled correctly
"""
expected_message = u"Service someurl.com changed its HTTP status from UP to DOWN.\nDescription: Non-recoverable failure in name resolution."
self.send_and_test_stream_message('http_up_to_down', u"Test check status.", expected_message)
def test_pingdom_from_up_to_down_smtp_check_message(self):
# type: () -> None
def test_pingdom_from_up_to_down_smtp_check_message(self) -> None:
"""
Tests if pingdom smtp check from up to down is handled correctly
"""
expected_message = u"Service smtp.someurl.com changed its SMTP status from UP to DOWN.\nDescription: Connection refused."
self.send_and_test_stream_message('smtp_up_to_down', u"SMTP check status.", expected_message)
def test_pingdom_from_up_to_down_imap_check_message(self):
# type: () -> None
def test_pingdom_from_up_to_down_imap_check_message(self) -> None:
"""
Tests if pingdom imap check from up to down is handled correctly
"""
expected_message = u"Service imap.someurl.com changed its IMAP status from UP to DOWN.\nDescription: Invalid hostname, address or socket."
self.send_and_test_stream_message('imap_up_to_down', u"IMAP check status.", expected_message)
def test_pingdom_from_down_to_up_imap_check_message(self):
# type: () -> None
def test_pingdom_from_down_to_up_imap_check_message(self) -> None:
"""
Tests if pingdom imap check from down to up is handled correctly
"""

View File

@@ -49,13 +49,11 @@ def api_pingdom_webhook(request, user_profile, payload=REQ(argument_type='body')
return json_success()
def get_subject_for_http_request(payload):
# type: (Dict[str, Any]) -> Text
def get_subject_for_http_request(payload: Dict[str, Any]) -> Text:
return PINGDOM_SUBJECT_TEMPLATE.format(name=payload['check_name'])
def get_body_for_http_request(payload):
# type: (Dict[str, Any]) -> Text
def get_body_for_http_request(payload: Dict[str, Any]) -> Text:
current_state = payload['current_state']
previous_state = payload['previous_state']
@@ -72,6 +70,5 @@ def get_body_for_http_request(payload):
return body
def get_check_type(payload):
# type: (Dict[str, Any]) -> Text
def get_check_type(payload: Dict[str, Any]) -> Text:
return payload['check_type']

View File

@@ -6,95 +6,82 @@ class PivotalV3HookTests(WebhookTestCase):
STREAM_NAME = 'pivotal'
URL_TEMPLATE = u"/api/v1/external/pivotal?stream={stream}&api_key={api_key}"
def test_accepted(self):
# type: () -> None
def test_accepted(self) -> None:
expected_subject = 'My new Feature story'
expected_message = 'Leo Franchi accepted "My new Feature story" \
[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48276573)'
self.send_and_test_stream_message('accepted', expected_subject, expected_message, content_type="application/xml")
def test_commented(self):
# type: () -> None
def test_commented(self) -> None:
expected_subject = 'Comment added'
expected_message = 'Leo Franchi added comment: "FIX THIS NOW" \
[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48276573)'
self.send_and_test_stream_message('commented', expected_subject, expected_message, content_type="application/xml")
def test_created(self):
# type: () -> None
def test_created(self) -> None:
expected_subject = 'My new Feature story'
expected_message = 'Leo Franchi added "My new Feature story" \
(unscheduled feature):\n\n~~~ quote\nThis is my long description\n~~~\n\n \
[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48276573)'
self.send_and_test_stream_message('created', expected_subject, expected_message, content_type="application/xml")
def test_delivered(self):
# type: () -> None
def test_delivered(self) -> None:
expected_subject = 'Another new story'
expected_message = 'Leo Franchi delivered "Another new story" \
[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48278289)'
self.send_and_test_stream_message('delivered', expected_subject, expected_message, content_type="application/xml")
def test_finished(self):
# type: () -> None
def test_finished(self) -> None:
expected_subject = 'Another new story'
expected_message = 'Leo Franchi finished "Another new story" \
[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48278289)'
self.send_and_test_stream_message('finished', expected_subject, expected_message, content_type="application/xml")
def test_moved(self):
# type: () -> None
def test_moved(self) -> None:
expected_subject = 'My new Feature story'
expected_message = 'Leo Franchi edited "My new Feature story" \
[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48276573)'
self.send_and_test_stream_message('moved', expected_subject, expected_message, content_type="application/xml")
def test_rejected(self):
# type: () -> None
def test_rejected(self) -> None:
expected_subject = 'Another new story'
expected_message = 'Leo Franchi rejected "Another new story" with comments: \
"Not good enough, sorry" [(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48278289)'
self.send_and_test_stream_message('rejected', expected_subject, expected_message, content_type="application/xml")
def test_started(self):
# type: () -> None
def test_started(self) -> None:
expected_subject = 'Another new story'
expected_message = 'Leo Franchi started "Another new story" \
[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48278289)'
self.send_and_test_stream_message('started', expected_subject, expected_message, content_type="application/xml")
def test_created_estimate(self):
# type: () -> None
def test_created_estimate(self) -> None:
expected_subject = 'Another new story'
expected_message = 'Leo Franchi added "Another new story" \
(unscheduled feature worth 2 story points):\n\n~~~ quote\nSome loong description\n~~~\n\n \
[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48278289)'
self.send_and_test_stream_message('created_estimate', expected_subject, expected_message, content_type="application/xml")
def test_type_changed(self):
# type: () -> None
def test_type_changed(self) -> None:
expected_subject = 'My new Feature story'
expected_message = 'Leo Franchi edited "My new Feature story" \
[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48276573)'
self.send_and_test_stream_message('type_changed', expected_subject, expected_message, content_type="application/xml")
def get_body(self, fixture_name):
# type: (Text) -> Text
def get_body(self, fixture_name: Text) -> Text:
return self.fixture_data('pivotal', fixture_name, file_type='xml')
class PivotalV5HookTests(WebhookTestCase):
STREAM_NAME = 'pivotal'
URL_TEMPLATE = u"/api/v1/external/pivotal?stream={stream}&api_key={api_key}"
def test_accepted(self):
# type: () -> None
def test_accepted(self) -> None:
expected_subject = '#63486316: Story of the Year'
expected_message = """Leo Franchi updated [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Story of the Year](http://www.pivotaltracker.com/story/show/63486316):
* state changed from **unstarted** to **accepted**"""
self.send_and_test_stream_message('accepted', expected_subject, expected_message, content_type="application/xml")
def test_commented(self):
# type: () -> None
def test_commented(self) -> None:
expected_subject = '#63486316: Story of the Year'
expected_message = """Leo Franchi added a comment to [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Story of the Year](http://www.pivotaltracker.com/story/show/63486316):
~~~quote
@@ -102,8 +89,7 @@ A comment on the story
~~~"""
self.send_and_test_stream_message('commented', expected_subject, expected_message, content_type="application/xml")
def test_created(self):
# type: () -> None
def test_created(self) -> None:
expected_subject = '#63495662: Story that I created'
expected_message = """Leo Franchi created bug: [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Story that I created](http://www.pivotaltracker.com/story/show/63495662)
* State is **unscheduled**
@@ -112,28 +98,24 @@ A comment on the story
> What a description"""
self.send_and_test_stream_message('created', expected_subject, expected_message, content_type="application/xml")
def test_delivered(self):
# type: () -> None
def test_delivered(self) -> None:
expected_subject = '#63486316: Story of the Year'
expected_message = """Leo Franchi updated [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Story of the Year](http://www.pivotaltracker.com/story/show/63486316):
* state changed from **accepted** to **delivered**"""
self.send_and_test_stream_message('delivered', expected_subject, expected_message, content_type="application/xml")
def test_finished(self):
# type: () -> None
def test_finished(self) -> None:
expected_subject = '#63486316: Story of the Year'
expected_message = """Leo Franchi updated [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Story of the Year](http://www.pivotaltracker.com/story/show/63486316):
* state changed from **delivered** to **accepted**"""
self.send_and_test_stream_message('finished', expected_subject, expected_message, content_type="application/xml")
def test_moved(self):
# type: () -> None
def test_moved(self) -> None:
expected_subject = '#63496066: Pivotal Test'
expected_message = """Leo Franchi moved [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Pivotal Test](http://www.pivotaltracker.com/story/show/63496066) from **unstarted** to **unscheduled**"""
self.send_and_test_stream_message('moved', expected_subject, expected_message, content_type="application/xml")
def test_rejected(self):
# type: () -> None
def test_rejected(self) -> None:
expected_subject = '#63486316: Story of the Year'
expected_message = """Leo Franchi updated [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Story of the Year](http://www.pivotaltracker.com/story/show/63486316):
* Comment added:
@@ -143,28 +125,24 @@ Try again next time
* state changed from **delivered** to **rejected**"""
self.send_and_test_stream_message('rejected', expected_subject, expected_message, content_type="application/xml")
def test_started(self):
# type: () -> None
def test_started(self) -> None:
expected_subject = '#63495972: Fresh Story'
expected_message = """Leo Franchi updated [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Fresh Story](http://www.pivotaltracker.com/story/show/63495972):
* state changed from **unstarted** to **started**"""
self.send_and_test_stream_message('started', expected_subject, expected_message, content_type="application/xml")
def test_created_estimate(self):
# type: () -> None
def test_created_estimate(self) -> None:
expected_subject = '#63496066: Pivotal Test'
expected_message = """Leo Franchi updated [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Pivotal Test](http://www.pivotaltracker.com/story/show/63496066):
* estimate is now **3 points**"""
self.send_and_test_stream_message('created_estimate', expected_subject, expected_message, content_type="application/xml")
def test_type_changed(self):
# type: () -> None
def test_type_changed(self) -> None:
expected_subject = '#63496066: Pivotal Test'
expected_message = """Leo Franchi updated [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Pivotal Test](http://www.pivotaltracker.com/story/show/63496066):
* estimate changed from 3 to **0 points**
* type changed from **feature** to **bug**"""
self.send_and_test_stream_message('type_changed', expected_subject, expected_message, content_type="application/xml")
def get_body(self, fixture_name):
# type: (Text) -> Text
def get_body(self, fixture_name: Text) -> Text:
return self.fixture_data('pivotal', "v5_{}".format(fixture_name), file_type='json')

View File

@@ -17,12 +17,11 @@ import ujson
from typing import Dict, List, Optional, Tuple, Text
def api_pivotal_webhook_v3(request, user_profile, stream):
# type: (HttpRequest, UserProfile, Text) -> Tuple[Text, Text]
def api_pivotal_webhook_v3(request: HttpRequest, user_profile: UserProfile,
stream: Text) -> Tuple[Text, Text]:
payload = xml_fromstring(request.body)
def get_text(attrs):
# type: (List[str]) -> str
def get_text(attrs: List[str]) -> str:
start = payload
try:
for attr in attrs:
@@ -72,8 +71,8 @@ def api_pivotal_webhook_v3(request, user_profile, stream):
more_info)
return subject, content
def api_pivotal_webhook_v5(request, user_profile, stream):
# type: (HttpRequest, UserProfile, Text) -> Tuple[Text, Text]
def api_pivotal_webhook_v5(request: HttpRequest, user_profile: UserProfile,
stream: Text) -> Tuple[Text, Text]:
payload = ujson.loads(request.body)
event_type = payload["kind"]
@@ -97,8 +96,7 @@ def api_pivotal_webhook_v5(request, user_profile, stream):
content = ""
subject = "#%s: %s" % (story_id, story_name)
def extract_comment(change):
# type: (Dict[str, Dict]) -> Optional[Text]
def extract_comment(change: Dict[str, Dict]) -> Optional[Text]:
if change.get("kind") == "comment":
return change.get("new_values", {}).get("text", None)
return None
@@ -162,8 +160,7 @@ def api_pivotal_webhook_v5(request, user_profile, stream):
@api_key_only_webhook_view("Pivotal")
@has_request_variables
def api_pivotal_webhook(request, user_profile, stream=REQ()):
# type: (HttpRequest, UserProfile, Text) -> HttpResponse
def api_pivotal_webhook(request: HttpRequest, user_profile: UserProfile, stream: Text=REQ()) -> HttpResponse:
subject = content = None
try:
subject, content = api_pivotal_webhook_v3(request, user_profile, stream)

View File

@@ -10,22 +10,19 @@ class SemaphoreHookTests(WebhookTestCase):
# contain information on the repo and branch, and the message has links and
# details about the build, deploy, server, author, and commit
def test_semaphore_build(self):
# type: () -> None
def test_semaphore_build(self) -> None:
expected_subject = u"knighthood/master" # repo/branch
expected_message = u"""[build 314](https://semaphoreci.com/donquixote/knighthood/branches/master/builds/314): passed
!avatar(don@lamancha.com) [`a490b8d`](https://github.com/donquixote/knighthood/commit/a490b8d508ebbdab1d77a5c2aefa35ceb2d62daf): Create user account for Rocinante :horse:."""
self.send_and_test_stream_message('build', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_semaphore_deploy(self):
# type: () -> None
def test_semaphore_deploy(self) -> None:
expected_subject = u"knighthood/master"
expected_message = u"""[deploy 17](https://semaphoreci.com/donquixote/knighthood/servers/lamancha-271/deploys/17) of [build 314](https://semaphoreci.com/donquixote/knighthood/branches/master/builds/314) on server lamancha-271: passed
!avatar(don@lamancha.com) [`a490b8d`](https://github.com/donquixote/knighthood/commit/a490b8d508ebbdab1d77a5c2aefa35ceb2d62daf): Create user account for Rocinante :horse:."""
self.send_and_test_stream_message('deploy', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def get_body(self, fixture_name):
# type: (Text) -> Text
def get_body(self, fixture_name: Text) -> Text:
return self.fixture_data("semaphore", fixture_name, file_type="json")

View File

@@ -6,8 +6,7 @@ class SentryHookTests(WebhookTestCase):
URL_TEMPLATE = "/api/v1/external/sentry?&api_key={api_key}"
FIXTURE_DIR_NAME = 'sentry'
def test_error_issue_message(self):
# type: () -> None
def test_error_issue_message(self) -> None:
expected_subject = u"zulip"
expected_message = u"New ERROR [issue](https://sentry.io/zulip/zulip/issues/156699934/): This is an example python exception."
self.send_and_test_stream_message(

View File

@@ -8,16 +8,14 @@ class SlackWebhookTests(WebhookTestCase):
URL_TEMPLATE = "/api/v1/external/slack?stream={stream}&api_key={api_key}"
FIXTURE_DIR_NAME = 'slack'
def test_slack_channel_to_topic(self):
# type: () -> None
def test_slack_channel_to_topic(self) -> None:
expected_subject = u"channel: general"
expected_message = u"**slack_user**: `test\n`"
self.send_and_test_stream_message('message_info', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_slack_channel_to_stream(self):
# type: () -> None
def test_slack_channel_to_stream(self) -> None:
self.STREAM_NAME = 'general'
self.url = "{}{}".format(self.url, "&channels_map_to_topics=0")
@@ -26,39 +24,34 @@ class SlackWebhookTests(WebhookTestCase):
self.send_and_test_stream_message('message_info', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_missing_data_user_name(self):
# type: () -> None
def test_missing_data_user_name(self) -> None:
payload = self.get_body('message_info_missing_user_name')
url = self.build_webhook_url()
result = self.client_post(url, payload, content_type="application/x-www-form-urlencoded")
self.assert_json_error(result, "Missing 'user_name' argument")
def test_missing_data_channel_name(self):
# type: () -> None
def test_missing_data_channel_name(self) -> None:
payload = self.get_body('message_info_missing_channel_name')
url = self.build_webhook_url()
result = self.client_post(url, payload, content_type="application/x-www-form-urlencoded")
self.assert_json_error(result, "Missing 'channel_name' argument")
def test_missing_data_text(self):
# type: () -> None
def test_missing_data_text(self) -> None:
payload = self.get_body('message_info_missing_text')
url = self.build_webhook_url()
result = self.client_post(url, payload, content_type="application/x-www-form-urlencoded")
self.assert_json_error(result, "Missing 'text' argument")
def test_invalid_channels_map_to_topics(self):
# type: () -> None
def test_invalid_channels_map_to_topics(self) -> None:
payload = self.get_body('message_info')
url = "{}{}".format(self.url, "&channels_map_to_topics=abc")
result = self.client_post(url, payload, content_type="application/x-www-form-urlencoded")
self.assert_json_error(result, 'Error: channels_map_to_topics parameter other than 0 or 1')
def get_body(self, fixture_name):
# type: (text_type) -> text_type
def get_body(self, fixture_name: text_type) -> text_type:
return self.fixture_data("slack", fixture_name, file_type="txt")

View File

@@ -8,8 +8,7 @@ class SolanoHookTests(WebhookTestCase):
URL_TEMPLATE = u"/api/v1/external/solano?api_key={api_key}"
FIXTURE_DIR_NAME = 'solano'
def test_solano_message_001(self):
# type: () -> None
def test_solano_message_001(self) -> None:
"""
Build notifications are generated by Solano Labs after build completes.
"""
@@ -23,8 +22,7 @@ class SolanoHookTests(WebhookTestCase):
self.send_and_test_stream_message('build_001', expected_topic, expected_message,
content_type="application/x-www-form-urlencoded")
def test_solano_message_002(self):
# type: () -> None
def test_solano_message_002(self) -> None:
"""
Build notifications are generated by Solano Labs after build completes.
"""
@@ -37,8 +35,7 @@ class SolanoHookTests(WebhookTestCase):
self.send_and_test_stream_message('build_002', expected_topic, expected_message,
content_type="application/x-www-form-urlencoded")
def test_solano_message_received(self):
# type: () -> None
def test_solano_message_received(self) -> None:
"""
Build notifications are generated by Solano Labs after build completes.
"""
@@ -52,14 +49,12 @@ class SolanoHookTests(WebhookTestCase):
self.send_and_test_stream_message('received', expected_topic, expected_message,
content_type="application/x-www-form-urlencoded")
def test_solano_test_message(self):
# type: () -> None
def test_solano_test_message(self) -> None:
expected_topic = u'build update'
expected_message = "Solano webhook set up correctly"
self.send_and_test_stream_message('test', expected_topic, expected_message,
content_type="application/x-www-form-urlencoded")
def get_body(self, fixture_name):
# type: (Text) -> Text
def get_body(self, fixture_name: Text) -> Text:
return self.fixture_data(self.FIXTURE_DIR_NAME, fixture_name, file_type="json")

View File

@@ -65,8 +65,8 @@ def api_solano_webhook(request, user_profile,
check_send_stream_message(user_profile, request.client, stream, topic, body)
return json_success()
def handle_test_event(user_profile, client, stream, topic):
# type: (UserProfile, Client, str, str) -> HttpResponse
def handle_test_event(user_profile: UserProfile, client: Client, stream: str,
topic: str) -> HttpResponse:
body = 'Solano webhook set up correctly'
check_send_stream_message(user_profile, client, stream, topic, body)
return json_success()

View File

@@ -8,8 +8,7 @@ class SplunkHookTests(WebhookTestCase):
URL_TEMPLATE = "/api/v1/external/splunk?api_key={api_key}&stream={stream}"
FIXTURE_DIR_NAME = 'splunk'
def test_splunk_search_one_result(self):
# type: () -> None
def test_splunk_search_one_result(self) -> None:
self.url = self.build_webhook_url(topic=u"New Search Alert")
# define the expected message contents
@@ -22,8 +21,7 @@ class SplunkHookTests(WebhookTestCase):
expected_message,
content_type="application/x-www-form-urlencoded")
def test_splunk_short_search_name(self):
# type: () -> None
def test_splunk_short_search_name(self) -> None:
# don't provide a topic so the search name is used instead
expected_subject = u"This search's name isn't that long"
@@ -34,8 +32,7 @@ class SplunkHookTests(WebhookTestCase):
expected_message,
content_type="application/x-www-form-urlencoded")
def test_splunk_long_search_name(self):
# type: () -> None
def test_splunk_long_search_name(self) -> None:
# don't provide a topic so the search name is used instead
expected_subject = u"this-search's-got-47-words-37-sentences-58-words-we-wanna..."
@@ -46,8 +43,7 @@ class SplunkHookTests(WebhookTestCase):
expected_message,
content_type="application/x-www-form-urlencoded")
def test_splunk_missing_results_link(self):
# type: () -> None
def test_splunk_missing_results_link(self) -> None:
self.url = self.build_webhook_url(topic=u"New Search Alert")
@@ -59,8 +55,7 @@ class SplunkHookTests(WebhookTestCase):
expected_message,
content_type="application/x-www-form-urlencoded")
def test_splunk_missing_search_name(self):
# type: () -> None
def test_splunk_missing_search_name(self) -> None:
self.url = self.build_webhook_url(topic=u"New Search Alert")
@@ -72,8 +67,7 @@ class SplunkHookTests(WebhookTestCase):
expected_message,
content_type="application/x-www-form-urlencoded")
def test_splunk_missing_host(self):
# type: () -> None
def test_splunk_missing_host(self) -> None:
self.url = self.build_webhook_url(topic=u"New Search Alert")
@@ -85,8 +79,7 @@ class SplunkHookTests(WebhookTestCase):
expected_message,
content_type="application/x-www-form-urlencoded")
def test_splunk_missing_source(self):
# type: () -> None
def test_splunk_missing_source(self) -> None:
self.url = self.build_webhook_url(topic=u"New Search Alert")
@@ -98,8 +91,7 @@ class SplunkHookTests(WebhookTestCase):
expected_message,
content_type="application/x-www-form-urlencoded")
def test_splunk_missing_raw(self):
# type: () -> None
def test_splunk_missing_raw(self) -> None:
self.url = self.build_webhook_url(topic=u"New Search Alert")
@@ -111,6 +103,5 @@ class SplunkHookTests(WebhookTestCase):
expected_message,
content_type="application/x-www-form-urlencoded")
def get_body(self, fixture_name):
# type: (Text) -> Text
def get_body(self, fixture_name: Text) -> Text:
return self.fixture_data("splunk", fixture_name, file_type="json")

View File

@@ -9,8 +9,7 @@ class StripeHookTests(WebhookTestCase):
URL_TEMPLATE = "/api/v1/external/stripe?&api_key={api_key}"
FIXTURE_DIR_NAME = 'stripe'
def test_charge_dispute_closed(self):
# type: () -> None
def test_charge_dispute_closed(self) -> None:
expected_subject = u"Charge ch_00000000000000"
expected_message = u"A charge dispute for **10.01aud** has been closed as **won**.\nThe charge in dispute was **[ch_00000000000000](https://dashboard.stripe.com/payments/ch_00000000000000)**."
@@ -18,8 +17,7 @@ class StripeHookTests(WebhookTestCase):
self.send_and_test_stream_message('charge_dispute_closed', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_charge_dispute_created(self):
# type: () -> None
def test_charge_dispute_created(self) -> None:
expected_subject = u"Charge ch_00000000000000"
expected_message = u"A charge dispute for **1000jpy** has been created.\nThe charge in dispute is **[ch_00000000000000](https://dashboard.stripe.com/payments/ch_00000000000000)**."
@@ -27,8 +25,7 @@ class StripeHookTests(WebhookTestCase):
self.send_and_test_stream_message('charge_dispute_created', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_charge_failed(self):
# type: () -> None
def test_charge_failed(self) -> None:
expected_subject = u"Charge ch_00000000000000"
expected_message = u"A charge with id **[ch_00000000000000](https://dashboard.stripe.com/payments/ch_00000000000000)** for **1.00aud** has failed."
@@ -36,8 +33,7 @@ class StripeHookTests(WebhookTestCase):
self.send_and_test_stream_message('charge_failed', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_charge_succeeded(self):
# type: () -> None
def test_charge_succeeded(self) -> None:
expected_subject = u"Charge ch_00000000000000"
expected_message = u"A charge with id **[ch_00000000000000](https://dashboard.stripe.com/payments/ch_00000000000000)** for **1.00aud** has succeeded."
@@ -45,8 +41,7 @@ class StripeHookTests(WebhookTestCase):
self.send_and_test_stream_message('charge_succeeded', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_customer_created_email(self):
# type: () -> None
def test_customer_created_email(self) -> None:
expected_subject = u"Customer cus_00000000000000"
expected_message = u"A new customer with id **[cus_00000000000000](https://dashboard.stripe.com/customers/cus_00000000000000)** and email **example@abc.com** has been created."
@@ -54,8 +49,7 @@ class StripeHookTests(WebhookTestCase):
self.send_and_test_stream_message('customer_created_email', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_customer_created(self):
# type: () -> None
def test_customer_created(self) -> None:
expected_subject = u"Customer cus_00000000000000"
expected_message = u"A new customer with id **[cus_00000000000000](https://dashboard.stripe.com/customers/cus_00000000000000)** has been created."
@@ -63,8 +57,7 @@ class StripeHookTests(WebhookTestCase):
self.send_and_test_stream_message('customer_created', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_customer_deleted(self):
# type: () -> None
def test_customer_deleted(self) -> None:
expected_subject = u"Customer cus_00000000000000"
expected_message = u"A customer with id **[cus_00000000000000](https://dashboard.stripe.com/customers/cus_00000000000000)** has been deleted."
@@ -72,8 +65,7 @@ class StripeHookTests(WebhookTestCase):
self.send_and_test_stream_message('customer_deleted', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_customer_subscription_created(self):
# type: () -> None
def test_customer_subscription_created(self) -> None:
expected_subject = u"Customer sub_00000000000000"
expected_message = u"A new customer subscription for **20.00aud** every **month** has been created.\nThe subscription has id **[sub_00000000000000](https://dashboard.stripe.com/subscriptions/sub_00000000000000)**."
@@ -81,8 +73,7 @@ class StripeHookTests(WebhookTestCase):
self.send_and_test_stream_message('customer_subscription_created', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_customer_subscription_deleted(self):
# type: () -> None
def test_customer_subscription_deleted(self) -> None:
expected_subject = u"Customer sub_00000000000000"
expected_message = u"The customer subscription with id **[sub_00000000000000](https://dashboard.stripe.com/subscriptions/sub_00000000000000)** was deleted."
@@ -90,8 +81,7 @@ class StripeHookTests(WebhookTestCase):
self.send_and_test_stream_message('customer_subscription_deleted', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_customer_subscription_trial_will_end(self):
# type: () -> None
def test_customer_subscription_trial_will_end(self) -> None:
expected_subject = u"Customer sub_00000000000000"
expected_message = u"The customer subscription trial with id **[sub_00000000000000](https://dashboard.stripe.com/subscriptions/sub_00000000000000)** will end in 3 days."
@@ -102,8 +92,7 @@ class StripeHookTests(WebhookTestCase):
expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_invoice_payment_failed(self):
# type: () -> None
def test_invoice_payment_failed(self) -> None:
expected_subject = u"Invoice in_00000000000000"
expected_message = u"An invoice payment on invoice with id **[in_00000000000000](https://dashboard.stripe.com/invoices/in_00000000000000)** and with **0.00aud** due has failed."
@@ -111,8 +100,7 @@ class StripeHookTests(WebhookTestCase):
self.send_and_test_stream_message('invoice_payment_failed', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_order_payment_failed(self):
# type: () -> None
def test_order_payment_failed(self) -> None:
expected_subject = u"Order or_00000000000000"
expected_message = u"An order payment on order with id **[or_00000000000000](https://dashboard.stripe.com/orders/or_00000000000000)** for **15.00aud** has failed."
@@ -120,8 +108,7 @@ class StripeHookTests(WebhookTestCase):
self.send_and_test_stream_message('order_payment_failed', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_order_payment_succeeded(self):
# type: () -> None
def test_order_payment_succeeded(self) -> None:
expected_subject = u"Order or_00000000000000"
expected_message = u"An order payment on order with id **[or_00000000000000](https://dashboard.stripe.com/orders/or_00000000000000)** for **15.00aud** has succeeded."
@@ -129,8 +116,7 @@ class StripeHookTests(WebhookTestCase):
self.send_and_test_stream_message('order_payment_succeeded', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_order_updated(self):
# type: () -> None
def test_order_updated(self) -> None:
expected_subject = u"Order or_00000000000000"
expected_message = u"The order with id **[or_00000000000000](https://dashboard.stripe.com/orders/or_00000000000000)** for **15.00aud** has been updated."
@@ -138,8 +124,7 @@ class StripeHookTests(WebhookTestCase):
self.send_and_test_stream_message('order_updated', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_transfer_failed(self):
# type: () -> None
def test_transfer_failed(self) -> None:
expected_subject = u"Transfer tr_00000000000000"
expected_message = u"The transfer with description **Transfer to test@example.com** and id **[tr_00000000000000](https://dashboard.stripe.com/transfers/tr_00000000000000)** for amount **11.00aud** has failed."
@@ -147,8 +132,7 @@ class StripeHookTests(WebhookTestCase):
self.send_and_test_stream_message('transfer_failed', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def test_transfer_paid(self):
# type: () -> None
def test_transfer_paid(self) -> None:
expected_subject = u"Transfer tr_00000000000000"
expected_message = u"The transfer with description **Transfer to test@example.com** and id **[tr_00000000000000](https://dashboard.stripe.com/transfers/tr_00000000000000)** for amount **11.00aud** has been paid."
@@ -156,6 +140,5 @@ class StripeHookTests(WebhookTestCase):
self.send_and_test_stream_message('transfer_paid', expected_subject, expected_message,
content_type="application/x-www-form-urlencoded")
def get_body(self, fixture_name):
# type: (Text) -> Text
def get_body(self, fixture_name: Text) -> Text:
return self.fixture_data("stripe", fixture_name, file_type="json")

View File

@@ -164,8 +164,7 @@ def api_stripe_webhook(request, user_profile,
return json_success()
def amount(amount, currency):
# type: (int, str) -> str
def amount(amount: int, currency: str) -> str:
# zero-decimal currencies
zero_decimal_currencies = ["bif", "djf", "jpy", "krw", "pyg", "vnd", "xaf",
"xpf", "clp", "gnf", "kmf", "mga", "rwf", "vuv", "xof"]

View File

@@ -8,281 +8,225 @@ class TaigaHookTests(WebhookTestCase):
URL_TEMPLATE = u"/api/v1/external/taiga?stream={stream}&api_key={api_key}"
FIXTURE_DIR_NAME = 'taiga'
def setUp(self):
# type: () -> None
def setUp(self) -> None:
self.url = self.build_webhook_url(topic=self.TOPIC)
def test_taiga_userstory_deleted(self):
# type: () -> None
def test_taiga_userstory_deleted(self) -> None:
message = u':x: TomaszKolek deleted user story **New userstory**.'
self.send_and_test_stream_message("userstory_deleted", u'subject', message)
def test_taiga_userstory_created(self):
# type: () -> None
def test_taiga_userstory_created(self) -> None:
message = u':package: TomaszKolek created user story **New userstory**.'
self.send_and_test_stream_message("userstory_created", u'subject', message)
def test_taiga_userstory_changed_unblocked(self):
# type: () -> None
def test_taiga_userstory_changed_unblocked(self) -> None:
message = u':unlock: TomaszKolek unblocked user story **UserStory**.'
self.send_and_test_stream_message("userstory_changed_unblocked", u'subject', message)
def test_taiga_userstory_changed_subject(self):
# type: () -> None
def test_taiga_userstory_changed_subject(self) -> None:
message = u':notebook: TomaszKolek renamed user story from UserStory to **UserStoryNewSubject**.'
self.send_and_test_stream_message("userstory_changed_subject", u'subject', message)
def test_taiga_userstory_changed_status(self):
# type: () -> None
def test_taiga_userstory_changed_status(self) -> None:
message = u':chart_with_upwards_trend: TomaszKolek changed status of user story **UserStory** from Ready to In progress.'
self.send_and_test_stream_message("userstory_changed_status", u'subject', message)
def test_taiga_userstory_changed_reassigned(self):
# type: () -> None
def test_taiga_userstory_changed_reassigned(self) -> None:
message = u':busts_in_silhouette: TomaszKolek reassigned user story **UserStory** from TomaszKolek to HanSolo.'
self.send_and_test_stream_message("userstory_changed_reassigned", u'subject', message)
def test_taiga_userstory_changed_unassigned(self):
# type: () -> None
def test_taiga_userstory_changed_unassigned(self) -> None:
message = u':busts_in_silhouette: TomaszKolek unassigned user story **UserStory**.'
self.send_and_test_stream_message("userstory_changed_unassigned", u'subject', message)
def test_taiga_userstory_changed_points(self):
# type: () -> None
def test_taiga_userstory_changed_points(self) -> None:
message = u':game_die: TomaszKolek changed estimation of user story **UserStory**.'
self.send_and_test_stream_message("userstory_changed_points", u'subject', message)
def test_taiga_userstory_changed_new_sprint(self):
# type: () -> None
def test_taiga_userstory_changed_new_sprint(self) -> None:
message = u':calendar: TomaszKolek added user story **UserStory** to sprint Sprint1.'
self.send_and_test_stream_message("userstory_changed_new_sprint", u'subject', message)
def test_taiga_userstory_changed_sprint(self):
# type: () -> None
def test_taiga_userstory_changed_sprint(self) -> None:
message = u':calendar: TomaszKolek changed sprint of user story **UserStory** from Sprint1 to Sprint2.'
self.send_and_test_stream_message("userstory_changed_sprint", u'subject', message)
def test_taiga_userstory_changed_remove_sprint(self):
# type: () -> None
def test_taiga_userstory_changed_remove_sprint(self) -> None:
message = u':calendar: TomaszKolek removed user story **UserStory** from sprint Sprint2.'
self.send_and_test_stream_message("userstory_changed_remove_sprint", u'subject', message)
def test_taiga_userstory_changed_description(self):
# type: () -> None
def test_taiga_userstory_changed_description(self) -> None:
message = u':notebook: TomaszKolek updated description of user story **UserStory**.'
self.send_and_test_stream_message("userstory_changed_description", u'subject', message)
def test_taiga_userstory_changed_closed(self):
# type: () -> None
def test_taiga_userstory_changed_closed(self) -> None:
message = u':chart_with_upwards_trend: TomaszKolek changed status of user story **UserStory** from New to Done.\n:checkered_flag: TomaszKolek closed user story **UserStory**.'
self.send_and_test_stream_message("userstory_changed_closed", u'subject', message)
def test_taiga_userstory_changed_reopened(self):
# type: () -> None
def test_taiga_userstory_changed_reopened(self) -> None:
message = u':chart_with_upwards_trend: TomaszKolek changed status of user story **UserStory** from Done to Ready.\n:package: TomaszKolek reopened user story **UserStory**.'
self.send_and_test_stream_message("userstory_changed_reopened", u'subject', message)
def test_taiga_userstory_changed_blocked(self):
# type: () -> None
def test_taiga_userstory_changed_blocked(self) -> None:
message = u':lock: TomaszKolek blocked user story **UserStory**.'
self.send_and_test_stream_message("userstory_changed_blocked", u'subject', message)
def test_taiga_userstory_changed_assigned(self):
# type: () -> None
def test_taiga_userstory_changed_assigned(self) -> None:
message = u':busts_in_silhouette: TomaszKolek assigned user story **UserStory** to TomaszKolek.'
self.send_and_test_stream_message("userstory_changed_assigned", u'subject', message)
def test_taiga_userstory_comment_added(self):
# type: () -> None
def test_taiga_userstory_comment_added(self) -> None:
message = u':thought_balloon: TomaszKolek commented on user story **UserStory**.'
self.send_and_test_stream_message("userstory_changed_comment_added", u'subject', message)
def test_taiga_task_created(self):
# type: () -> None
def test_taiga_task_created(self) -> None:
message = u':clipboard: TomaszKolek created task **New Task**.'
self.send_and_test_stream_message("task_created", u'subject', message)
def test_taiga_task_changed_status(self):
# type: () -> None
def test_taiga_task_changed_status(self) -> None:
message = u':chart_with_upwards_trend: TomaszKolek changed status of task **New Task** from New to In progress.'
self.send_and_test_stream_message("task_changed_status", u'subject', message)
def test_taiga_task_changed_blocked(self):
# type: () -> None
def test_taiga_task_changed_blocked(self) -> None:
message = u':lock: TomaszKolek blocked task **New Task**.'
self.send_and_test_stream_message("task_changed_blocked", u'subject', message)
def test_taiga_task_changed_unblocked(self):
# type: () -> None
def test_taiga_task_changed_unblocked(self) -> None:
message = u':unlock: TomaszKolek unblocked task **New Task**.'
self.send_and_test_stream_message("task_changed_unblocked", u'subject', message)
def test_taiga_task_changed_assigned(self):
# type: () -> None
def test_taiga_task_changed_assigned(self) -> None:
message = u':busts_in_silhouette: TomaszKolek assigned task **New Task** to TomaszKolek.'
self.send_and_test_stream_message("task_changed_assigned", u'subject', message)
def test_taiga_task_changed_reassigned(self):
# type: () -> None
def test_taiga_task_changed_reassigned(self) -> None:
message = u':busts_in_silhouette: TomaszKolek reassigned task **New Task** from HanSolo to TomaszKolek.'
self.send_and_test_stream_message("task_changed_reassigned", u'subject', message)
def test_taiga_task_changed_subject(self):
# type: () -> None
def test_taiga_task_changed_subject(self) -> None:
message = u':notebook: TomaszKolek renamed task New Task to **New Task Subject**.'
self.send_and_test_stream_message("task_changed_subject", u'subject', message)
def test_taiga_task_changed_description(self):
# type: () -> None
def test_taiga_task_changed_description(self) -> None:
message = u':notebook: TomaszKolek updated description of task **New Task**.'
self.send_and_test_stream_message("task_changed_description", u'subject', message)
def test_taiga_task_deleted(self):
# type: () -> None
def test_taiga_task_deleted(self) -> None:
message = u':x: TomaszKolek deleted task **New Task**.'
self.send_and_test_stream_message("task_deleted", u'subject', message)
def test_taiga_task_changed_comment_added(self):
# type: () -> None
def test_taiga_task_changed_comment_added(self) -> None:
message = u':thought_balloon: TomaszKolek commented on task **New Task**.'
self.send_and_test_stream_message("task_changed_comment_added", u'subject', message)
def test_taiga_sprint_created(self):
# type: () -> None
def test_taiga_sprint_created(self) -> None:
message = u':calendar: TomaszKolek created sprint **New sprint**.'
self.send_and_test_stream_message("sprint_created", u'subject', message)
def test_taiga_sprint_deleted(self):
# type: () -> None
def test_taiga_sprint_deleted(self) -> None:
message = u':x: TomaszKolek deleted sprint **New name**.'
self.send_and_test_stream_message("sprint_deleted", u'subject', message)
def test_taiga_sprint_changed_time(self):
# type: () -> None
def test_taiga_sprint_changed_time(self) -> None:
message = u':calendar: TomaszKolek changed estimated finish of sprint **New sprint** from 2017-01-24 to 2017-01-25.'
self.send_and_test_stream_message("sprint_changed_time", u'subject', message)
def test_taiga_sprint_changed_name(self):
# type: () -> None
def test_taiga_sprint_changed_name(self) -> None:
message = u':notebook: TomaszKolek renamed sprint from New sprint to **New name**.'
self.send_and_test_stream_message("sprint_changed_name", u'subject', message)
def test_taiga_issue_created(self):
# type: () -> None
def test_taiga_issue_created(self) -> None:
message = u':bulb: TomaszKolek created issue **New issue**.'
self.send_and_test_stream_message("issue_created", u'subject', message)
def test_taiga_issue_deleted(self):
# type: () -> None
def test_taiga_issue_deleted(self) -> None:
message = u':x: TomaszKolek deleted issue **New issue**.'
self.send_and_test_stream_message("issue_deleted", u'subject', message)
def test_taiga_issue_changed_assigned(self):
# type: () -> None
def test_taiga_issue_changed_assigned(self) -> None:
message = u':busts_in_silhouette: TomaszKolek assigned issue **New issue** to TomaszKolek.'
self.send_and_test_stream_message("issue_changed_assigned", u'subject', message)
def test_taiga_issue_changed_reassigned(self):
# type: () -> None
def test_taiga_issue_changed_reassigned(self) -> None:
message = u':busts_in_silhouette: TomaszKolek reassigned issue **New issue** from TomaszKolek to HanSolo.'
self.send_and_test_stream_message("issue_changed_reassigned", u'subject', message)
def test_taiga_issue_changed_subject(self):
# type: () -> None
def test_taiga_issue_changed_subject(self) -> None:
message = u':notebook: TomaszKolek renamed issue New issue to **New issueNewSubject**.'
self.send_and_test_stream_message("issue_changed_subject", u'subject', message)
def test_taiga_issue_changed_description(self):
# type: () -> None
def test_taiga_issue_changed_description(self) -> None:
message = u':notebook: TomaszKolek updated description of issue **New issue**.'
self.send_and_test_stream_message("issue_changed_description", u'subject', message)
def test_taiga_issue_changed_type(self):
# type: () -> None
def test_taiga_issue_changed_type(self) -> None:
message = u':bulb: TomaszKolek changed type of issue **New issue** from Bug to Question.'
self.send_and_test_stream_message("issue_changed_type", u'subject', message)
def test_taiga_issue_changed_status(self):
# type: () -> None
def test_taiga_issue_changed_status(self) -> None:
message = u':chart_with_upwards_trend: TomaszKolek changed status of issue **New issue** from New to In progress.'
self.send_and_test_stream_message("issue_changed_status", u'subject', message)
def test_taiga_issue_changed_severity(self):
# type: () -> None
def test_taiga_issue_changed_severity(self) -> None:
message = u':warning: TomaszKolek changed severity of issue **New issue** from Normal to Minor.'
self.send_and_test_stream_message("issue_changed_severity", u'subject', message)
def test_taiga_issue_changed_priority(self):
# type: () -> None
def test_taiga_issue_changed_priority(self) -> None:
message = u':rocket: TomaszKolek changed priority of issue **New issue** from Normal to Low.'
self.send_and_test_stream_message("issue_changed_priority", u'subject', message)
def test_taiga_issue_changed_comment_added(self):
# type: () -> None
def test_taiga_issue_changed_comment_added(self) -> None:
message = u':thought_balloon: TomaszKolek commented on issue **New issue**.'
self.send_and_test_stream_message("issue_changed_comment_added", u'subject', message)
def test_taiga_epic_created(self):
# type: () -> None
def test_taiga_epic_created(self) -> None:
message = u':package: Eeshan Garg created epic **Zulip is awesome!**'
self.send_and_test_stream_message("epic_created", u'subject', message)
def test_taiga_epic_changed_assigned(self):
# type: () -> None
def test_taiga_epic_changed_assigned(self) -> None:
message = u':busts_in_silhouette: Eeshan Garg assigned epic **Zulip is awesome!** to Eeshan Garg.'
self.send_and_test_stream_message("epic_changed_assigned", u'subject', message)
def test_taiga_epic_changed_unassigned(self):
# type: () -> None
def test_taiga_epic_changed_unassigned(self) -> None:
message = u':busts_in_silhouette: Eeshan Garg unassigned epic **Zulip is awesome!**'
self.send_and_test_stream_message("epic_changed_unassigned", u'subject', message)
def test_taiga_epic_changed_reassigned(self):
# type: () -> None
def test_taiga_epic_changed_reassigned(self) -> None:
message = u':busts_in_silhouette: Eeshan Garg reassigned epic **Zulip is awesome!** from Eeshan Garg to Angela Johnson.'
self.send_and_test_stream_message("epic_changed_reassigned", u'subject', message)
def test_taiga_epic_changed_blocked(self):
# type: () -> None
def test_taiga_epic_changed_blocked(self) -> None:
message = u':lock: Eeshan Garg blocked epic **Zulip is awesome!**'
self.send_and_test_stream_message("epic_changed_blocked", u'subject', message)
def test_taiga_epic_changed_unblocked(self):
# type: () -> None
def test_taiga_epic_changed_unblocked(self) -> None:
message = u':unlock: Eeshan Garg unblocked epic **Zulip is awesome!**'
self.send_and_test_stream_message("epic_changed_unblocked", u'subject', message)
def test_taiga_epic_changed_status(self):
# type: () -> None
def test_taiga_epic_changed_status(self) -> None:
message = u':chart_increasing: Eeshan Garg changed status of epic **Zulip is awesome!** from New to In progress.'
self.send_and_test_stream_message("epic_changed_status", u'subject', message)
def test_taiga_epic_changed_renamed(self):
# type: () -> None
def test_taiga_epic_changed_renamed(self) -> None:
message = u':notebook: Eeshan Garg renamed epic from **Zulip is awesome!** to **Zulip is great!**'
self.send_and_test_stream_message("epic_changed_renamed", u'subject', message)
def test_taiga_epic_changed_description(self):
# type: () -> None
def test_taiga_epic_changed_description(self) -> None:
message = u':notebook: Eeshan Garg updated description of epic **Zulip is great!**'
self.send_and_test_stream_message("epic_changed_description", u'subject', message)
def test_taiga_epic_changed_commented(self):
# type: () -> None
def test_taiga_epic_changed_commented(self) -> None:
message = u':thought_balloon: Eeshan Garg commented on epic **Zulip is great!**'
self.send_and_test_stream_message("epic_changed_commented", u'subject', message)
def test_taiga_epic_deleted(self):
# type: () -> None
def test_taiga_epic_deleted(self) -> None:
message = u':cross_mark: Eeshan Garg deleted epic **Zulip is great!**'
self.send_and_test_stream_message("epic_deleted", u'subject', message)
def test_taiga_relateduserstory_created(self):
# type: () -> None
def test_taiga_relateduserstory_created(self) -> None:
message = u':package: Eeshan Garg added a related user story **A related user story** to the epic **This is Epic!**'
self.send_and_test_stream_message("relateduserstory_created", u'subject', message)
def test_taiga_relateduserstory_deleted(self):
# type: () -> None
def test_taiga_relateduserstory_deleted(self) -> None:
message = u':cross_mark: Eeshan Garg removed a related user story **A related user story, which is epic** from the epic **This is Epic!**'
self.send_and_test_stream_message("relateduserstory_deleted", u'subject', message)

View File

@@ -139,8 +139,9 @@ templates = {
}
def get_old_and_new_values(change_type, message):
# type: (str, Mapping[str, Any]) -> Tuple[Optional[Dict[str, Any]], Optional[Dict[str, Any]]]
return_type = Tuple[Optional[Dict[str, Any]], Optional[Dict[str, Any]]]
def get_old_and_new_values(change_type: str,
message: Mapping[str, Any]) -> return_type:
""" Parses the payload and finds previous and current value of change_type."""
if change_type in ['subject', 'name', 'estimated_finish', 'estimated_start']:
old = message["change"]["diff"][change_type]["from"]
@@ -160,8 +161,7 @@ def get_old_and_new_values(change_type, message):
return old, new
def parse_comment(message):
# type: (Mapping[str, Any]) -> Dict[str, Any]
def parse_comment(message: Mapping[str, Any]) -> Dict[str, Any]:
""" Parses the comment to issue, task or US. """
return {
'event': 'commented',
@@ -172,8 +172,7 @@ def parse_comment(message):
}
}
def parse_create_or_delete(message):
# type: (Mapping[str, Any]) -> Dict[str, Any]
def parse_create_or_delete(message: Mapping[str, Any]) -> Dict[str, Any]:
""" Parses create or delete event. """
if message["type"] == 'relateduserstory':
return {
@@ -196,8 +195,7 @@ def parse_create_or_delete(message):
}
def parse_change_event(change_type, message):
# type: (str, Mapping[str, Any]) -> Optional[Dict[str, Any]]
def parse_change_event(change_type: str, message: Mapping[str, Any]) -> Optional[Dict[str, Any]]:
""" Parses change event. """
evt = {} # type: Dict[str, Any]
values = {
@@ -264,8 +262,7 @@ def parse_change_event(change_type, message):
return evt
def parse_message(message):
# type: (Mapping[str, Any]) -> List[Dict[str, Any]]
def parse_message(message: Mapping[str, Any]) -> List[Dict[str, Any]]:
""" Parses the payload by delegating to specialized functions. """
events = []
if message["action"] in ['create', 'delete']:
@@ -281,16 +278,13 @@ def parse_message(message):
return events
def generate_content(data):
# type: (Mapping[str, Any]) -> str
def generate_content(data: Mapping[str, Any]) -> str:
""" Gets the template string and formats it with parsed data. """
return templates[data['type']][data['event']] % data['values']
def get_owner_name(message):
# type: (Mapping[str, Any]) -> str
def get_owner_name(message: Mapping[str, Any]) -> str:
return message["by"]["full_name"]
def get_subject(message):
# type: (Mapping[str, Any]) -> str
def get_subject(message: Mapping[str, Any]) -> str:
data = message["data"]
return data.get("subject", data.get("name"))

View File

@@ -9,28 +9,23 @@ class TeamcityHookTests(WebhookTestCase):
SUBJECT = u"Project :: Compile"
FIXTURE_DIR_NAME = 'teamcity'
def test_teamcity_success(self):
# type: () -> None
def test_teamcity_success(self) -> None:
expected_message = u"Project :: Compile build 5535 - CL 123456 was successful! :thumbsup:\nDetails: [changes](http://teamcity/viewLog.html?buildTypeId=Project_Compile&buildId=19952&tab=buildChangesDiv), [build log](http://teamcity/viewLog.html?buildTypeId=Project_Compile&buildId=19952)"
self.send_and_test_stream_message('success', self.SUBJECT, expected_message)
def test_teamcity_broken(self):
# type: () -> None
def test_teamcity_broken(self) -> None:
expected_message = u"Project :: Compile build 5535 - CL 123456 is broken with status Exit code 1 (new)! :thumbsdown:\nDetails: [changes](http://teamcity/viewLog.html?buildTypeId=Project_Compile&buildId=19952&tab=buildChangesDiv), [build log](http://teamcity/viewLog.html?buildTypeId=Project_Compile&buildId=19952)"
self.send_and_test_stream_message('broken', self.SUBJECT, expected_message)
def test_teamcity_failure(self):
# type: () -> None
def test_teamcity_failure(self) -> None:
expected_message = u"Project :: Compile build 5535 - CL 123456 is still broken with status Exit code 1! :thumbsdown:\nDetails: [changes](http://teamcity/viewLog.html?buildTypeId=Project_Compile&buildId=19952&tab=buildChangesDiv), [build log](http://teamcity/viewLog.html?buildTypeId=Project_Compile&buildId=19952)"
self.send_and_test_stream_message('failure', self.SUBJECT, expected_message)
def test_teamcity_fixed(self):
# type: () -> None
def test_teamcity_fixed(self) -> None:
expected_message = u"Project :: Compile build 5535 - CL 123456 has been fixed! :thumbsup:\nDetails: [changes](http://teamcity/viewLog.html?buildTypeId=Project_Compile&buildId=19952&tab=buildChangesDiv), [build log](http://teamcity/viewLog.html?buildTypeId=Project_Compile&buildId=19952)"
self.send_and_test_stream_message('fixed', self.SUBJECT, expected_message)
def test_teamcity_personal(self):
# type: () -> None
def test_teamcity_personal(self) -> None:
expected_message = u"Your personal build of Project :: Compile build 5535 - CL 123456 is broken with status Exit code 1 (new)! :thumbsdown:\nDetails: [changes](http://teamcity/viewLog.html?buildTypeId=Project_Compile&buildId=19952&tab=buildChangesDiv), [build log](http://teamcity/viewLog.html?buildTypeId=Project_Compile&buildId=19952)"
payload = ujson.dumps(ujson.loads(self.fixture_data(self.FIXTURE_DIR_NAME, 'personal')))
self.client_post(self.url, payload, content_type="application/json")

View File

@@ -13,8 +13,7 @@ from zerver.models import UserProfile, Realm
import logging
import ujson
def guess_zulip_user_from_teamcity(teamcity_username, realm):
# type: (str, Realm) -> Optional[UserProfile]
def guess_zulip_user_from_teamcity(teamcity_username: str, realm: Realm) -> Optional[UserProfile]:
try:
# Try to find a matching user in Zulip
# We search a user's full name, short name,
@@ -29,8 +28,7 @@ def guess_zulip_user_from_teamcity(teamcity_username, realm):
except IndexError:
return None
def get_teamcity_property_value(property_list, name):
# type: (List[Dict[str, str]], str) -> Optional[str]
def get_teamcity_property_value(property_list: List[Dict[str, str]], name: str) -> Optional[str]:
for property in property_list:
if property['name'] == name:
return property['value']

View File

@@ -14,8 +14,7 @@ class TransifexHookTests(WebhookTestCase):
RESOURCE = 'file'
REVIEWED = True
def test_transifex_reviewed_message(self):
# type: () -> None
def test_transifex_reviewed_message(self) -> None:
self.REVIEWED = True
expected_subject = "{} in {}".format(self.PROJECT, self.LANGUAGE)
expected_message = "Resource {} fully reviewed.".format(self.RESOURCE)
@@ -27,8 +26,7 @@ class TransifexHookTests(WebhookTestCase):
)
self.send_and_test_stream_message("", expected_subject, expected_message)
def test_transifex_translated_message(self):
# type: () -> None
def test_transifex_translated_message(self) -> None:
self.REVIEWED = False
expected_subject = "{} in {}".format(self.PROJECT, self.LANGUAGE)
expected_message = "Resource {} fully translated.".format(self.RESOURCE)
@@ -40,6 +38,5 @@ class TransifexHookTests(WebhookTestCase):
)
self.send_and_test_stream_message("", expected_subject, expected_message)
def get_body(self, fixture_name):
# type: (Text) -> Dict[str, Any]
def get_body(self, fixture_name: Text) -> Dict[str, Any]:
return {}

View File

@@ -10,8 +10,7 @@ class TravisHookTests(WebhookTestCase):
FIXTURE_DIR_NAME = 'travis'
TOPIC = 'builds'
def test_travis_message(self):
# type: () -> None
def test_travis_message(self) -> None:
"""
Build notifications are generated by Travis after build completes.
@@ -30,8 +29,7 @@ class TravisHookTests(WebhookTestCase):
content_type="application/x-www-form-urlencoded"
)
def test_ignore_travis_pull_request_by_default(self):
# type: () -> None
def test_ignore_travis_pull_request_by_default(self) -> None:
self.subscribe(self.test_user, self.STREAM_NAME)
result = self.client_post(
self.url,
@@ -42,8 +40,7 @@ class TravisHookTests(WebhookTestCase):
msg = self.get_last_message()
self.assertNotEquals(msg.subject, self.TOPIC)
def test_travis_pull_requests_are_not_ignored_when_applicable(self):
# type: () -> None
def test_travis_pull_requests_are_not_ignored_when_applicable(self) -> None:
self.url = "{}&ignore_pull_requests=false".format(self.build_webhook_url())
expected_message = (u"Author: josh_mandel\nBuild status: Passed :thumbsup:\n"
u"Details: [changes](https://github.com/hl7-fhir/fhir-sv"
@@ -57,6 +54,5 @@ class TravisHookTests(WebhookTestCase):
content_type="application/x-www-form-urlencoded"
)
def get_body(self, fixture_name):
# type: (Text) -> Text
def get_body(self, fixture_name: Text) -> Text:
return urllib.parse.urlencode({'payload': self.fixture_data("travis", fixture_name, file_type="json")})

View File

@@ -7,103 +7,83 @@ class TrelloHookTests(WebhookTestCase):
URL_TEMPLATE = u"/api/v1/external/trello?stream={stream}&api_key={api_key}"
FIXTURE_DIR_NAME = 'trello'
def test_trello_confirmation_request(self):
# type: () -> None
def test_trello_confirmation_request(self) -> None:
response = self.client_head(self.build_webhook_url())
self.assertEqual(response.status_code, 200, response)
def test_trello_webhook_when_card_was_moved_to_another_list(self):
# type: () -> None
def test_trello_webhook_when_card_was_moved_to_another_list(self) -> None:
expected_message = u"TomaszKolek moved [This is a card.](https://trello.com/c/r33ylX2Z) from Basics to Intermediate."
self.send_and_test_stream_message('changing_cards_list', u"Welcome Board", expected_message)
def test_trello_webhook_when_card_was_renamed(self):
# type: () -> None
def test_trello_webhook_when_card_was_renamed(self) -> None:
expected_message = u"TomaszKolek renamed the card from \"Old name\" to [New name](https://trello.com/c/r33ylX2Z)."
self.send_and_test_stream_message('renaming_card', u"Welcome Board", expected_message)
def test_trello_webhook_when_label_was_added_to_card(self):
# type: () -> None
def test_trello_webhook_when_label_was_added_to_card(self) -> None:
expected_message = u"TomaszKolek added a green label with \"text value\" to [Card name](https://trello.com/c/r33ylX2Z)."
self.send_and_test_stream_message('adding_label_to_card', u"Welcome Board", expected_message)
def test_trello_webhook_when_label_was_removing_from_card(self):
# type: () -> None
def test_trello_webhook_when_label_was_removing_from_card(self) -> None:
expected_message = u"TomaszKolek removed a green label with \"text value\" from [New Card](https://trello.com/c/r33ylX2Z)."
self.send_and_test_stream_message('removing_label_from_card', u"Welcome Board", expected_message)
def test_trello_webhook_when_member_was_added_to_card(self):
# type: () -> None
def test_trello_webhook_when_member_was_added_to_card(self) -> None:
expected_message = u"TomaszKolek added TomaszKolek to [Card name](https://trello.com/c/9BduUcVQ)."
self.send_and_test_stream_message('adding_member_to_card', u"Welcome Board", expected_message)
def test_trello_webhook_when_member_was_removed_from_card(self):
# type: () -> None
def test_trello_webhook_when_member_was_removed_from_card(self) -> None:
expected_message = u"TomaszKolek removed Trello from [Card name](https://trello.com/c/9BduUcVQ)."
self.send_and_test_stream_message('removing_member_from_card', u"Welcome Board", expected_message)
def test_trello_webhook_when_due_date_was_set(self):
# type: () -> None
def test_trello_webhook_when_due_date_was_set(self) -> None:
expected_message = u"TomaszKolek set due date for [Card name](https://trello.com/c/9BduUcVQ) to 2016-05-11 10:00:00 UTC."
self.send_and_test_stream_message('setting_due_date_to_card', u"Welcome Board", expected_message)
def test_trello_webhook_when_due_date_was_changed(self):
# type: () -> None
def test_trello_webhook_when_due_date_was_changed(self) -> None:
expected_message = u"TomaszKolek changed due date for [Card name](https://trello.com/c/9BduUcVQ) from 2016-05-11 10:00:00 UTC to 2016-05-24 10:00:00 UTC."
self.send_and_test_stream_message('changing_due_date_on_card', u"Welcome Board", expected_message)
def test_trello_webhook_when_due_date_was_removed(self):
# type: () -> None
def test_trello_webhook_when_due_date_was_removed(self) -> None:
expected_message = u"TomaszKolek removed the due date from [Card name](https://trello.com/c/9BduUcVQ)."
self.send_and_test_stream_message('removing_due_date_from_card', u"Welcome Board", expected_message)
def test_trello_webhook_when_card_was_archived(self):
# type: () -> None
def test_trello_webhook_when_card_was_archived(self) -> None:
expected_message = u"TomaszKolek archived [Card name](https://trello.com/c/9BduUcVQ)."
self.send_and_test_stream_message('archiving_card', u"Welcome Board", expected_message)
def test_trello_webhook_when_card_was_reopened(self):
# type: () -> None
def test_trello_webhook_when_card_was_reopened(self) -> None:
expected_message = u"TomaszKolek reopened [Card name](https://trello.com/c/9BduUcVQ)."
self.send_and_test_stream_message('reopening_card', u"Welcome Board", expected_message)
def test_trello_webhook_when_card_was_created(self):
# type: () -> None
def test_trello_webhook_when_card_was_created(self) -> None:
expected_message = u"TomaszKolek created [New card](https://trello.com/c/5qrgGdD5)."
self.send_and_test_stream_message('creating_card', u"Welcome Board", expected_message)
def test_trello_webhook_when_attachment_was_added_to_card(self):
# type: () -> None
def test_trello_webhook_when_attachment_was_added_to_card(self) -> None:
expected_message = u"TomaszKolek added [attachment_name](http://url.com) to [New card](https://trello.com/c/xPKXoSTQ)."
self.send_and_test_stream_message('adding_attachment_to_card', u"Welcome Board", expected_message)
def test_trello_webhook_when_checklist_was_added_to_card(self):
# type: () -> None
def test_trello_webhook_when_checklist_was_added_to_card(self) -> None:
expected_message = u"TomaszKolek added the Checklist checklist to [New card](https://trello.com/c/xPKXoSTQ)."
self.send_and_test_stream_message('adding_checklist_to_card', u"Welcome Board", expected_message)
def test_trello_webhook_when_member_was_removed_from_board(self):
# type: () -> None
def test_trello_webhook_when_member_was_removed_from_board(self) -> None:
expected_message = u"TomaszKolek removed Trello from [Welcome Board](https://trello.com/b/iqXXzYEj)."
self.send_and_test_stream_message('removing_member_from_board', u"Welcome Board", expected_message)
def test_trello_webhook_when_member_was_added_to_board(self):
# type: () -> None
def test_trello_webhook_when_member_was_added_to_board(self) -> None:
expected_message = u"TomaszKolek added Trello to [Welcome Board](https://trello.com/b/iqXXzYEj)."
self.send_and_test_stream_message('adding_member_to_board', u"Welcome Board", expected_message)
def test_trello_webhook_when_list_was_added_to_board(self):
# type: () -> None
def test_trello_webhook_when_list_was_added_to_board(self) -> None:
expected_message = u"TomaszKolek added New list list to [Welcome Board](https://trello.com/b/iqXXzYEj)."
self.send_and_test_stream_message('adding_new_list_to_board', u"Welcome Board", expected_message)
def test_trello_webhook_when_comment_was_added_to_card(self):
# type: () -> None
def test_trello_webhook_when_comment_was_added_to_card(self) -> None:
expected_message = u"TomaszKolek commented on [New card](https://trello.com/c/xPKXoSTQ)\n~~~ quote\nNew comment\n~~~"
self.send_and_test_stream_message('adding_comment_to_card', u"Welcome Board", expected_message)
def test_trello_webhook_when_board_was_renamed(self):
# type: () -> None
def test_trello_webhook_when_board_was_renamed(self) -> None:
expected_message = u"TomaszKolek renamed the board from Welcome Board to [New name](https://trello.com/b/iqXXzYEj)."
self.send_and_test_stream_message('renaming_board', u"New name", expected_message)
@@ -125,17 +105,14 @@ class TrelloHookTests(WebhookTestCase):
self.assertFalse(check_send_stream_message_mock.called)
self.assert_json_success(result)
def test_trello_webhook_when_description_was_added_to_card(self):
# type: () -> None
def test_trello_webhook_when_description_was_added_to_card(self) -> None:
expected_message = u"Marco Matarazzo set description for [New Card](https://trello.com/c/P2r0z66z) to\n~~~ quote\nNew Description\n~~~"
self.send_and_test_stream_message('adding_description_to_card', u"Welcome Board", expected_message)
def test_trello_webhook_when_description_was_removed_from_card(self):
# type: () -> None
def test_trello_webhook_when_description_was_removed_from_card(self) -> None:
expected_message = u"Marco Matarazzo removed description from [New Card](https://trello.com/c/P2r0z66z)."
self.send_and_test_stream_message('removing_description_from_card', u"Welcome Board", expected_message)
def test_trello_webhook_when_description_was_changed_on_card(self):
# type: () -> None
def test_trello_webhook_when_description_was_changed_on_card(self) -> None:
expected_message = u"Marco Matarazzo changed description for [New Card](https://trello.com/c/P2r0z66z) from\n~~~ quote\nNew Description\n~~~\nto\n~~~ quote\nChanged Description\n~~~"
self.send_and_test_stream_message('changing_description_on_card', u"Welcome Board", expected_message)

View File

@@ -16,8 +16,10 @@ from .exceptions import UnsupportedAction
@api_key_only_webhook_view('Trello')
@return_success_on_head_request
@has_request_variables
def api_trello_webhook(request, user_profile, payload=REQ(argument_type='body'), stream=REQ(default='trello')):
# type: (HttpRequest, UserProfile, Mapping[str, Any], Text) -> HttpResponse
def api_trello_webhook(request: HttpRequest,
user_profile: UserProfile,
payload: Mapping[str, Any]=REQ(argument_type='body'),
stream: Text=REQ(default='trello')) -> HttpResponse:
payload = ujson.loads(request.body)
action_type = payload['action'].get('type')
try:
@@ -32,8 +34,7 @@ def api_trello_webhook(request, user_profile, payload=REQ(argument_type='body'),
check_send_stream_message(user_profile, request.client, stream, subject, body)
return json_success()
def get_subject_and_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Optional[Tuple[Text, Text]]
def get_subject_and_body(payload: Mapping[str, Any], action_type: Text) -> Optional[Tuple[Text, Text]]:
if action_type in SUPPORTED_CARD_ACTIONS:
return process_card_action(payload, action_type)
if action_type in SUPPORTED_BOARD_ACTIONS:

View File

@@ -22,15 +22,14 @@ ACTIONS_TO_MESSAGE_MAPPER = {
CHANGE_NAME: u'renamed the board from {old_name} to {board_url_template}.'
}
def process_board_action(payload, action_type):
# type: (Mapping[str, Any], Optional[Text]) -> Optional[Tuple[Text, Text]]
def process_board_action(payload: Mapping[str, Any],
action_type: Optional[Text]) -> Optional[Tuple[Text, Text]]:
action_type = get_proper_action(payload, action_type)
if action_type is not None:
return get_subject(payload), get_body(payload, action_type)
return None
def get_proper_action(payload, action_type):
# type: (Mapping[str, Any], Optional[Text]) -> Optional[Text]
def get_proper_action(payload: Mapping[str, Any], action_type: Optional[Text]) -> Optional[Text]:
if action_type == 'updateBoard':
data = get_action_data(payload)
# we don't support events for when a board's background
@@ -42,63 +41,54 @@ def get_proper_action(payload, action_type):
raise UnknownUpdateBoardAction()
return action_type
def get_subject(payload):
# type: (Mapping[str, Any]) -> Text
def get_subject(payload: Mapping[str, Any]) -> Text:
return get_action_data(payload)['board']['name']
def get_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
def get_body(payload: Mapping[str, Any], action_type: Text) -> Text:
message_body = ACTIONS_TO_FILL_BODY_MAPPER[action_type](payload, action_type)
creator = payload['action']['memberCreator']['fullName']
return u'{full_name} {rest}'.format(full_name=creator, rest=message_body)
def get_managed_member_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
def get_managed_member_body(payload: Mapping[str, Any], action_type: Text) -> Text:
data = {
'member_name': payload['action']['member']['fullName'],
}
return fill_appropriate_message_content(payload, action_type, data)
def get_create_list_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
def get_create_list_body(payload: Mapping[str, Any], action_type: Text) -> Text:
data = {
'list_name': get_action_data(payload)['list']['name'],
}
return fill_appropriate_message_content(payload, action_type, data)
def get_change_name_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
def get_change_name_body(payload: Mapping[str, Any], action_type: Text) -> Text:
data = {
'old_name': get_action_data(payload)['old']['name']
}
return fill_appropriate_message_content(payload, action_type, data)
def fill_appropriate_message_content(payload, action_type, data=None):
# type: (Mapping[str, Any], Text, Optional[Dict[str, Any]]) -> Text
def fill_appropriate_message_content(payload: Mapping[str, Any],
action_type: Text,
data: Optional[Dict[str, Any]]=None) -> Text:
data = {} if data is None else data
data['board_url_template'] = data.get('board_url_template', get_filled_board_url_template(payload))
message_body = get_message_body(action_type)
return message_body.format(**data)
def get_filled_board_url_template(payload):
# type: (Mapping[str, Any]) -> Text
def get_filled_board_url_template(payload: Mapping[str, Any]) -> Text:
return TRELLO_BOARD_URL_TEMPLATE.format(board_name=get_board_name(payload), board_url=get_board_url(payload))
def get_board_name(payload):
# type: (Mapping[str, Any]) -> Text
def get_board_name(payload: Mapping[str, Any]) -> Text:
return get_action_data(payload)['board']['name']
def get_board_url(payload):
# type: (Mapping[str, Any]) -> Text
def get_board_url(payload: Mapping[str, Any]) -> Text:
return u'https://trello.com/b/{}'.format(get_action_data(payload)['board']['shortLink'])
def get_message_body(action_type):
# type: (Text) -> Text
def get_message_body(action_type: Text) -> Text:
return ACTIONS_TO_MESSAGE_MAPPER[action_type]
def get_action_data(payload):
# type: (Mapping[str, Any]) -> Mapping[str, Any]
def get_action_data(payload: Mapping[str, Any]) -> Mapping[str, Any]:
return payload['action']['data']
ACTIONS_TO_FILL_BODY_MAPPER = {

View File

@@ -57,19 +57,16 @@ ACTIONS_TO_MESSAGE_MAPPER = {
COMMENT: u'commented on {card_url_template}\n~~~ quote\n{text}\n~~~\n'
}
def prettify_date(date_string):
# type: (str) -> str
def prettify_date(date_string: str) -> str:
return date_string.replace('T', ' ').replace('.000', '').replace('Z', ' UTC')
def process_card_action(payload, action_type):
# type: (Mapping[str, Any], Text) -> Optional[Tuple[Text, Text]]
def process_card_action(payload: Mapping[str, Any], action_type: Text) -> Optional[Tuple[Text, Text]]:
proper_action = get_proper_action(payload, action_type)
if proper_action is not None:
return get_subject(payload), get_body(payload, proper_action)
return None
def get_proper_action(payload, action_type):
# type: (Mapping[str, Any], Text) -> Optional[Text]
def get_proper_action(payload: Mapping[str, Any], action_type: Text) -> Optional[Text]:
if action_type == 'updateCard':
data = get_action_data(payload)
old_data = data['old']
@@ -104,33 +101,28 @@ def get_proper_action(payload, action_type):
return action_type
def get_subject(payload):
# type: (Mapping[str, Any]) -> Text
def get_subject(payload: Mapping[str, Any]) -> Text:
return get_action_data(payload)['board'].get('name')
def get_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
def get_body(payload: Mapping[str, Any], action_type: Text) -> Text:
message_body = ACTIONS_TO_FILL_BODY_MAPPER[action_type](payload, action_type)
creator = payload['action']['memberCreator'].get('fullName')
return u'{full_name} {rest}'.format(full_name=creator, rest=message_body)
def get_added_checklist_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
def get_added_checklist_body(payload: Mapping[str, Any], action_type: Text) -> Text:
data = {
'checklist_name': get_action_data(payload)['checklist'].get('name'),
}
return fill_appropriate_message_content(payload, action_type, data)
def get_added_attachment_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
def get_added_attachment_body(payload: Mapping[str, Any], action_type: Text) -> Text:
data = {
'attachment_url': get_action_data(payload)['attachment'].get('url'),
'attachment_name': get_action_data(payload)['attachment'].get('name'),
}
return fill_appropriate_message_content(payload, action_type, data)
def get_updated_card_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
def get_updated_card_body(payload: Mapping[str, Any], action_type: Text) -> Text:
data = {
'card_name': get_card_name(payload),
'old_list': get_action_data(payload)['listBefore'].get('name'),
@@ -138,8 +130,7 @@ def get_updated_card_body(payload, action_type):
}
return fill_appropriate_message_content(payload, action_type, data)
def get_renamed_card_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
def get_renamed_card_body(payload: Mapping[str, Any], action_type: Text) -> Text:
data = {
'old_name': get_action_data(payload)['old'].get('name'),
@@ -147,87 +138,75 @@ def get_renamed_card_body(payload, action_type):
}
return fill_appropriate_message_content(payload, action_type, data)
def get_added_label_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
def get_added_label_body(payload: Mapping[str, Any], action_type: Text) -> Text:
data = {
'color': get_action_data(payload).get('value'),
'text': get_action_data(payload).get('text'),
}
return fill_appropriate_message_content(payload, action_type, data)
def get_managed_member_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
def get_managed_member_body(payload: Mapping[str, Any], action_type: Text) -> Text:
data = {
'member_name': payload['action']['member'].get('fullName')
}
return fill_appropriate_message_content(payload, action_type, data)
def get_comment_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
def get_comment_body(payload: Mapping[str, Any], action_type: Text) -> Text:
data = {
'text': get_action_data(payload)['text'],
}
return fill_appropriate_message_content(payload, action_type, data)
def get_managed_due_date_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
def get_managed_due_date_body(payload: Mapping[str, Any], action_type: Text) -> Text:
data = {
'due_date': prettify_date(get_action_data(payload)['card'].get('due'))
}
return fill_appropriate_message_content(payload, action_type, data)
def get_changed_due_date_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
def get_changed_due_date_body(payload: Mapping[str, Any], action_type: Text) -> Text:
data = {
'due_date': prettify_date(get_action_data(payload)['card'].get('due')),
'old_due_date': prettify_date(get_action_data(payload)['old'].get('due'))
}
return fill_appropriate_message_content(payload, action_type, data)
def get_managed_desc_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
def get_managed_desc_body(payload: Mapping[str, Any], action_type: Text) -> Text:
data = {
'desc': prettify_date(get_action_data(payload)['card']['desc'])
}
return fill_appropriate_message_content(payload, action_type, data)
def get_changed_desc_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
def get_changed_desc_body(payload: Mapping[str, Any], action_type: Text) -> Text:
data = {
'desc': prettify_date(get_action_data(payload)['card']['desc']),
'old_desc': prettify_date(get_action_data(payload)['old']['desc'])
}
return fill_appropriate_message_content(payload, action_type, data)
def get_body_by_action_type_without_data(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
def get_body_by_action_type_without_data(payload: Mapping[str, Any], action_type: Text) -> Text:
return fill_appropriate_message_content(payload, action_type)
def fill_appropriate_message_content(payload, action_type, data=None):
# type: (Mapping[str, Any], Text, Optional[Dict[str, Any]]) -> Text
def fill_appropriate_message_content(payload: Mapping[str, Any],
action_type: Text,
data: Optional[Dict[str, Any]]=None) -> Text:
data = {} if data is None else data
data['card_url_template'] = data.get('card_url_template', get_filled_card_url_template(payload))
message_body = get_message_body(action_type)
return message_body.format(**data)
def get_filled_card_url_template(payload):
# type: (Mapping[str, Any]) -> Text
def get_filled_card_url_template(payload: Mapping[str, Any]) -> Text:
return TRELLO_CARD_URL_TEMPLATE.format(card_name=get_card_name(payload), card_url=get_card_url(payload))
def get_card_url(payload):
# type: (Mapping[str, Any]) -> Text
def get_card_url(payload: Mapping[str, Any]) -> Text:
return u'https://trello.com/c/{}'.format(get_action_data(payload)['card'].get('shortLink'))
def get_message_body(action_type):
# type: (Text) -> Text
def get_message_body(action_type: Text) -> Text:
return ACTIONS_TO_MESSAGE_MAPPER[action_type]
def get_card_name(payload):
# type: (Mapping[str, Any]) -> Text
def get_card_name(payload: Mapping[str, Any]) -> Text:
return get_action_data(payload)['card'].get('name')
def get_action_data(payload):
# type: (Mapping[str, Any]) -> Mapping[str, Any]
def get_action_data(payload: Mapping[str, Any]) -> Mapping[str, Any]:
return payload['action'].get('data')
ACTIONS_TO_FILL_BODY_MAPPER = {

View File

@@ -6,26 +6,22 @@ class UpdownHookTests(WebhookTestCase):
URL_TEMPLATE = u"/api/v1/external/updown?stream={stream}&api_key={api_key}"
FIXTURE_DIR_NAME = 'updown'
def test_updown_check_down_event(self):
# type: () -> None
def test_updown_check_down_event(self) -> None:
expected_subject = u"https://updown.io"
expected_message = u"Service is `down`. It returned a 500 error at 2016-02-07 13:11:43 UTC."
self.send_and_test_stream_message('check_down_one_event', expected_subject, expected_message)
def test_updown_check_up_again_event(self):
# type: () -> None
def test_updown_check_up_again_event(self) -> None:
expected_subject = u"https://updown.io"
expected_message = u"Service is `up` again after 4 minutes 25 seconds."
self.send_and_test_stream_message('check_up_again_one_event', expected_subject, expected_message)
def test_updown_check_up_event(self):
# type: () -> None
def test_updown_check_up_event(self) -> None:
expected_subject = u"https://updown.io"
expected_message = u"Service is `up`."
self.send_and_test_stream_message('check_up_first_time', expected_subject, expected_message)
def test_updown_check_up_multiple_events(self):
# type: () -> None
def test_updown_check_up_multiple_events(self) -> None:
first_message_expected_subject = u"https://updown.io"
first_message_expected_message = u"Service is `up` again after 1 second."

View File

@@ -14,15 +14,14 @@ from zerver.models import UserProfile, Client
SUBJECT_TEMPLATE = "{service_url}"
def send_message_for_event(event, user_profile, client, stream):
# type: (Dict[str, Any], UserProfile, Client, str) -> None
def send_message_for_event(event: Dict[str, Any], user_profile: UserProfile,
client: Client, stream: str) -> None:
event_type = get_event_type(event)
subject = SUBJECT_TEMPLATE.format(service_url=event['check']['url'])
body = EVENT_TYPE_BODY_MAPPER[event_type](event)
check_send_stream_message(user_profile, client, stream, subject, body)
def get_body_for_up_event(event):
# type: (Dict[str, Any]) -> str
def get_body_for_up_event(event: Dict[str, Any]) -> str:
body = "Service is `up`"
event_downtime = event['downtime']
if event_downtime['started_at']:
@@ -32,8 +31,7 @@ def get_body_for_up_event(event):
body = "{} after {}".format(body, string_date)
return "{}.".format(body)
def get_time_string_based_on_duration(duration):
# type: (int) -> str
def get_time_string_based_on_duration(duration: int) -> str:
days, reminder = divmod(duration, 86400)
hours, reminder = divmod(reminder, 3600)
minutes, seconds = divmod(reminder, 60)
@@ -45,16 +43,14 @@ def get_time_string_based_on_duration(duration):
string_date += add_time_part_to_string_date_if_needed(seconds, 'second')
return string_date.rstrip()
def add_time_part_to_string_date_if_needed(value, text_name):
# type: (int, str) -> str
def add_time_part_to_string_date_if_needed(value: int, text_name: str) -> str:
if value == 1:
return "1 {} ".format(text_name)
if value > 1:
return "{} {}s ".format(value, text_name)
return ''
def get_body_for_down_event(event):
# type: (Dict[str, Any]) -> str
def get_body_for_down_event(event: Dict[str, Any]) -> str:
return "Service is `down`. It returned a {} error at {}.".format(
event['downtime']['error'],
event['downtime']['started_at'].replace('T', ' ').replace('Z', ' UTC'))
@@ -74,8 +70,7 @@ EVENT_TYPE_BODY_MAPPER = {
'down': get_body_for_down_event
}
def get_event_type(event):
# type: (Dict[str, Any]) -> str
def get_event_type(event: Dict[str, Any]) -> str:
event_type_match = re.match('check.(.*)', event['event'])
if event_type_match:
event_type = event_type_match.group(1)

View File

@@ -8,8 +8,7 @@ class WordPressHookTests(WebhookTestCase):
URL_TEMPLATE = "/api/v1/external/wordpress?api_key={api_key}"
FIXTURE_DIR_NAME = 'wordpress'
def test_publish_post(self):
# type: () -> None
def test_publish_post(self) -> None:
expected_topic = u"WordPress Post"
expected_message = u"New post published.\n[New Blog Post](http://example.com\n)"
@@ -17,8 +16,7 @@ class WordPressHookTests(WebhookTestCase):
self.send_and_test_stream_message('publish_post', expected_topic, expected_message,
content_type="application/x-www-form-urlencoded")
def test_publish_post_type_not_provided(self):
# type: () -> None
def test_publish_post_type_not_provided(self) -> None:
expected_topic = u"WordPress Post"
expected_message = u"New post published.\n[New Blog Post](http://example.com\n)"
@@ -27,8 +25,7 @@ class WordPressHookTests(WebhookTestCase):
expected_topic, expected_message,
content_type="application/x-www-form-urlencoded")
def test_publish_post_no_data_provided(self):
# type: () -> None
def test_publish_post_no_data_provided(self) -> None:
# Note: the fixture includes 'hook=publish_post' because it's always added by HookPress
expected_topic = u"WordPress Notification"
@@ -38,8 +35,7 @@ class WordPressHookTests(WebhookTestCase):
expected_topic, expected_message,
content_type="application/x-www-form-urlencoded")
def test_publish_page(self):
# type: () -> None
def test_publish_page(self) -> None:
expected_topic = u"WordPress Page"
expected_message = u"New page published.\n" + "[New Blog Page](http://example.com\n)"
@@ -47,8 +43,7 @@ class WordPressHookTests(WebhookTestCase):
self.send_and_test_stream_message('publish_page', expected_topic, expected_message,
content_type="application/x-www-form-urlencoded")
def test_user_register(self):
# type: () -> None
def test_user_register(self) -> None:
expected_topic = u"New Blog Users"
expected_message = u"New blog user registered.\nName: test_user\nemail: test_user@example.com"
@@ -56,8 +51,7 @@ class WordPressHookTests(WebhookTestCase):
self.send_and_test_stream_message('user_register', expected_topic, expected_message,
content_type="application/x-www-form-urlencoded")
def test_wp_login(self):
# type: () -> None
def test_wp_login(self) -> None:
expected_topic = u"New Login"
expected_message = u"User testuser logged in."
@@ -65,8 +59,7 @@ class WordPressHookTests(WebhookTestCase):
self.send_and_test_stream_message('wp_login', expected_topic, expected_message,
content_type="application/x-www-form-urlencoded")
def test_unknown_action_no_data(self):
# type: () -> None
def test_unknown_action_no_data(self) -> None:
# Mimic send_and_test_stream_message() to manually execute a negative test.
# Otherwise its call to send_json_payload() would assert on the non-success
@@ -84,8 +77,7 @@ class WordPressHookTests(WebhookTestCase):
# check that we got the expected error message
self.assert_json_error(result, "Unknown WordPress webhook action: WordPress Action")
def test_unknown_action_no_hook_provided(self):
# type: () -> None
def test_unknown_action_no_hook_provided(self) -> None:
# Similar to unknown_action_no_data, except the fixture contains valid blog post
# params but without the hook parameter. This should also return an error.
@@ -97,6 +89,5 @@ class WordPressHookTests(WebhookTestCase):
self.assert_json_error(result, "Unknown WordPress webhook action: WordPress Action")
def get_body(self, fixture_name):
# type: (text_type) -> text_type
def get_body(self, fixture_name: text_type) -> text_type:
return self.fixture_data("wordpress", fixture_name, file_type="txt")

View File

@@ -7,8 +7,7 @@ class YoHookTests(WebhookTestCase):
URL_TEMPLATE = u"/api/v1/external/yo?api_key={api_key}"
FIXTURE_DIR_NAME = 'yo'
def test_yo_message(self):
# type: () -> None
def test_yo_message(self) -> None:
"""
Yo App sends notification whenever user receives a new Yo from another user.
"""
@@ -21,6 +20,5 @@ class YoHookTests(WebhookTestCase):
self.send_and_test_private_message('', expected_message=expected_message,
content_type="application/x-www-form-urlencoded")
def get_body(self, fixture_name):
# type: (Text) -> Dict[str, Any]
def get_body(self, fixture_name: Text) -> Dict[str, Any]:
return {}

View File

@@ -6,14 +6,12 @@ class ZapierHookTests(WebhookTestCase):
URL_TEMPLATE = "/api/v1/external/zapier?stream={stream}&api_key={api_key}"
FIXTURE_DIR_NAME = 'zapier'
def test_zapier_when_subject_and_body_are_correct(self):
# type: () -> None
def test_zapier_when_subject_and_body_are_correct(self) -> None:
expected_subject = u"New email from zulip@zulip.com"
expected_message = u"Your email content is: \nMy Email content."
self.send_and_test_stream_message('correct_subject_and_body', expected_subject, expected_message)
def test_zapier_weather_update(self):
# type: () -> None
def test_zapier_weather_update(self) -> None:
expected_subject = u"Here is your weather update for the day:"
expected_message = u"Foggy in the morning.\nMaximum temperature to be 24.\nMinimum temperature to be 12"
self.send_and_test_stream_message('weather_update', expected_subject, expected_message)

View File

@@ -16,8 +16,7 @@ class ZenDeskHookTests(WebhookTestCase):
DEFAULT_MESSAGE = 'Message'
MESSAGE = DEFAULT_MESSAGE
def get_body(self, fixture_name):
# type: (Text) -> Dict[str, Any]
def get_body(self, fixture_name: Text) -> Dict[str, Any]:
return {
'ticket_title': self.TICKET_TITLE,
'ticket_id': self.TICKET_ID,
@@ -25,27 +24,23 @@ class ZenDeskHookTests(WebhookTestCase):
'stream': self.STREAM_NAME,
}
def do_test(self, expected_subject=None, expected_message=None):
# type: (Optional[Text], Optional[Text]) -> None
def do_test(self, expected_subject: Optional[Text]=None, expected_message: Optional[Text]=None) -> None:
self.send_and_test_stream_message("", expected_subject, expected_message,
content_type=None, **self.api_auth(self.TEST_USER_EMAIL))
self.TICKET_TITLE = self.DEFAULT_TICKET_TITLE
self.TICKET_ID = self.DEFAULT_TICKET_ID
self.MESSAGE = self.DEFAULT_MESSAGE
def test_subject(self):
# type: () -> None
def test_subject(self) -> None:
self.TICKET_ID = 4
self.TICKET_TITLE = "Test ticket"
self.do_test(expected_subject='#4: Test ticket')
def test_long_subject(self):
# type: () -> None
def test_long_subject(self) -> None:
self.TICKET_ID = 4
self.TICKET_TITLE = "Test ticket" + '!' * 80
self.do_test(expected_subject='#4: Test ticket' + '!' * 42 + '...')
def test_content(self):
# type: () -> None
def test_content(self) -> None:
self.MESSAGE = 'New comment:\n> It is better\n* here'
self.do_test(expected_message='New comment:\n> It is better\n* here')

View File

@@ -7,8 +7,7 @@ from zerver.models import get_client, UserProfile
from django.http import HttpRequest, HttpResponse
from typing import Text
def truncate(string, length):
# type: (Text, int) -> Text
def truncate(string: Text, length: int) -> Text:
if len(string) > length:
string = string[:length-3] + '...'
return string