diff --git a/docs/overview/changelog.md b/docs/overview/changelog.md index b9526ba3a6..4bb673032e 100644 --- a/docs/overview/changelog.md +++ b/docs/overview/changelog.md @@ -30,7 +30,7 @@ in bursts. **Full feature changelog:** -- New integrations: ErrBot, Google Code-In, Opbeat, Groove, Raygun, +- New integrations: ErrBot, GoCD, Google Code-In, Opbeat, Groove, Raygun, Insping, Dropbox, Front, Intercom, Statuspage.io, Flock and Beeminder. - The local uploads backend now does the same security checks that the S3 backend did before serving files to users. diff --git a/static/images/integrations/gocd/001.png b/static/images/integrations/gocd/001.png new file mode 100644 index 0000000000..cb6f9d073d Binary files /dev/null and b/static/images/integrations/gocd/001.png differ diff --git a/static/images/integrations/logos/gocd.png b/static/images/integrations/logos/gocd.png new file mode 100644 index 0000000000..8983baacf5 Binary files /dev/null and b/static/images/integrations/logos/gocd.png differ diff --git a/zerver/lib/integrations.py b/zerver/lib/integrations.py index feed9a3ff7..00fd5176ff 100644 --- a/zerver/lib/integrations.py +++ b/zerver/lib/integrations.py @@ -315,6 +315,7 @@ WEBHOOK_INTEGRATIONS = [ stream_name='github' ), WebhookIntegration('gitlab', ['version-control'], display_name='GitLab'), + WebhookIntegration('gocd', ['continuous-integration'], display_name='GoCD'), WebhookIntegration('gogs', ['version-control'], stream_name='commits'), WebhookIntegration('gosquared', ['marketing'], display_name='GoSquared'), WebhookIntegration('greenhouse', ['hr'], display_name='Greenhouse'), diff --git a/zerver/webhooks/gocd/__init__.py b/zerver/webhooks/gocd/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/zerver/webhooks/gocd/doc.md b/zerver/webhooks/gocd/doc.md new file mode 100644 index 0000000000..97eba14bc3 --- /dev/null +++ b/zerver/webhooks/gocd/doc.md @@ -0,0 +1,22 @@ +Zulip supports integration with GoCD and can notify you of +your build statuses. + +1. {!create-stream.md!} + +1. {!create-bot-construct-url-indented.md!} + +1. Add the following to your `Config.XML` file. + + ``` + + + ... + + ``` + + Push this change to your repository. For further information, + see [GoCD's documentation](https://docs.gocd.org/current/integration/). + +{!congrats.md!} + +![](/static/images/integrations/gocd/001.png) diff --git a/zerver/webhooks/gocd/fixtures/build_details.json b/zerver/webhooks/gocd/fixtures/build_details.json new file mode 100644 index 0000000000..b178832a96 --- /dev/null +++ b/zerver/webhooks/gocd/fixtures/build_details.json @@ -0,0 +1,18 @@ +{ + "build_details": { + "_links": { + "job": { + "href": "https://ci.example.com/go/tab/build/detail/pipelineName/pipelineCounter/stageName/stageCounter/jobName" + }, + "stage": { + "href": "https://ci.example.com/go/pipelines/pipelineName/pipelineCounter/stageName/stageCounter" + }, + "pipeline": { + "href": "https://ci.example.com/go/tab/pipeline/history/pipelineName" + } + }, + "pipeline_name": "pipelineName", + "stage_name": "stageName", + "job_name": "jobName" + } +} diff --git a/zerver/webhooks/gocd/fixtures/pipeline.json b/zerver/webhooks/gocd/fixtures/pipeline.json new file mode 100644 index 0000000000..9a5969aa0f --- /dev/null +++ b/zerver/webhooks/gocd/fixtures/pipeline.json @@ -0,0 +1,59 @@ +{ + "build_cause": { + "approver": "", + "material_revisions": [ + { + "modifications": [ + { + "email_address": null, + "id": 7225, + "modified_time": 1435728005000, + "user_name": "Balaji B ", + "comment": "my hola mundo changes", + "revision": "a788f1876e2e1f6e5a1e91006e75cd1d467a0edb" + } + ], + "material": { + "description": "URL: https://github.com/gocd/gocd, Branch: master", + "fingerprint": "61e2da369d0207a7ef61f326eed837f964471b35072340a03f8f55d993afe01d", + "type": "Git", + "id": 4 + }, + "changed": true + } + ], + "trigger_forced": false, + "trigger_message": "modified by Balaji " + }, + "name": "PipelineName", + "natural_order": 1, + "can_run": false, + "comment": null, + "stages": [ + { + "name": "stage1", + "approved_by": "changes", + "jobs": [ + { + "name": "jsunit", + "result": "Passed", + "state": "Completed", + "id": 1, + "scheduled_date": 1398332981981 + } + ], + "can_run": false, + "result": "Passed", + "approval_type": "success", + "counter": "1", + "id": 1, + "operate_permission": false, + "rerun_of_counter": null, + "scheduled": true + } + ], + "counter": 1, + "id": 1, + "preparing_to_schedule": false, + "label": "14.1.0.1-b14a81825d081411993853ea5ea45266ced578b4" +} diff --git a/zerver/webhooks/gocd/fixtures/pipeline_failed.json b/zerver/webhooks/gocd/fixtures/pipeline_failed.json new file mode 100644 index 0000000000..17c33d94d6 --- /dev/null +++ b/zerver/webhooks/gocd/fixtures/pipeline_failed.json @@ -0,0 +1,59 @@ +{ + "build_cause": { + "approver": "anonymous", + "material_revisions": [ + { + "modifications": [ + { + "email_address": null, + "id": 1998, + "modified_time": 1434957613000, + "user_name": "User Name ", + "comment": "my hola mundo changes", + "revision": "f6e7a3899c55e1682ffb00383bdf8f882bcee2141e79a8728254190a1fddcf4f" + } + ], + "material": { + "description": "URL: https://github.com/gocd/gocd, Branch: master", + "fingerprint": "61e2da369d0207a7ef61f326eed837f964471b35072340a03f8f55d993afe01d", + "type": "Git", + "id": 4 + }, + "changed": true + } + ], + "trigger_forced": false, + "trigger_message": "modified by User Name " + }, + "name": "PipelineName", + "natural_order": 8, + "can_run": false, + "comment": null, + "stages": [ + { + "name": "stage1", + "approved_by": "changes", + "jobs": [ + { + "name": "job123", + "result": "Failed", + "state": "Completed", + "id": 21, + "scheduled_date": 1436172201081 + } + ], + "can_run": false, + "result": "Failed", + "approval_type": "success", + "counter": "1", + "id": 21, + "operate_permission": false, + "rerun_of_counter": null, + "scheduled": true + } + ], + "counter": 1, + "id": 21, + "preparing_to_schedule": false, + "label": "6" +} diff --git a/zerver/webhooks/gocd/tests.py b/zerver/webhooks/gocd/tests.py new file mode 100644 index 0000000000..f2da248295 --- /dev/null +++ b/zerver/webhooks/gocd/tests.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +import urllib +from typing import Text + +from zerver.lib.test_classes import WebhookTestCase +from zerver.models import get_realm, get_user + +class GocdHookTests(WebhookTestCase): + STREAM_NAME = 'gocd' + URL_TEMPLATE = "/api/v1/external/gocd?stream={stream}&api_key={api_key}" + FIXTURE_DIR_NAME = 'gocd' + TOPIC = 'https://github.com/gocd/gocd' + + def test_gocd_message(self) -> None: + expected_message = (u"Author: Balaji B \n" + u"Build status: Passed :thumbs_up:\n" + u"Details: [build log](https://ci.example.com" + u"/go/tab/pipeline/history/pipelineName)\n" + u"Comment: my hola mundo changes") + + self.send_and_test_stream_message( + 'pipeline', + self.TOPIC, + expected_message, + content_type="application/x-www-form-urlencoded" + ) + + def test_failed_message(self) -> None: + expected_message = (u"Author: User Name \n" + u"Build status: Failed :thumbs_down:\n" + u"Details: [build log](https://ci.example.com" + u"/go/tab/pipeline/history/pipelineName)\n" + u"Comment: my hola mundo changes") + + self.send_and_test_stream_message( + 'pipeline_failed', + self.TOPIC, + expected_message, + content_type="application/x-www-form-urlencoded" + ) + + def get_body(self, fixture_name: Text) -> Text: + return self.fixture_data("gocd", fixture_name, file_type="json") diff --git a/zerver/webhooks/gocd/view.py b/zerver/webhooks/gocd/view.py new file mode 100644 index 0000000000..dda43b1723 --- /dev/null +++ b/zerver/webhooks/gocd/view.py @@ -0,0 +1,58 @@ +# Webhooks for external integrations. + +import json +import os + +from typing import Any, Dict, Iterable, Optional, Text + +from django.http import HttpRequest, HttpResponse +from django.utils.translation import ugettext as _ + +from zerver.decorator import api_key_only_webhook_view +from zerver.lib.request import REQ, has_request_variables +from zerver.lib.response import json_error, json_success +from zerver.lib.webhooks.common import check_send_webhook_message +from zerver.lib.validator import check_dict, check_string +from zerver.models import UserProfile + +MESSAGE_TEMPLATE = ( + u'Author: {}\n' + u'Build status: {} {}\n' + u'Details: [build log]({})\n' + u'Comment: {}' +) + +@api_key_only_webhook_view('Gocd') +@has_request_variables +def api_gocd_webhook(request: HttpRequest, user_profile: UserProfile, + payload: Dict[str, Any]=REQ(argument_type='body'), + ) -> HttpResponse: + + modifications = payload['build_cause']['material_revisions'][0]['modifications'][0] + result = payload['stages'][0]['result'] + material = payload['build_cause']['material_revisions'][0]['material'] + + if result == "Passed": + emoji = ':thumbs_up:' + elif result == "Failed": + emoji = ':thumbs_down:' + + build_details_file = os.path.join(os.path.dirname(__file__), 'fixtures/build_details.json') + + with open(build_details_file, 'r') as f: + contents = json.load(f) + build_link = contents["build_details"]["_links"]["pipeline"]["href"] + + body = MESSAGE_TEMPLATE.format( + modifications['user_name'], + result, + emoji, + build_link, + modifications['comment'] + ) + branch = material['description'].split(",") + topic = branch[0].split(" ")[1] + + check_send_webhook_message(request, user_profile, topic, body) + + return json_success()