Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] webhooks/codebase: Implementing Codebase Webhook using Event Hook API. #12260

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified static/images/integrations/codebase/001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions zerver/lib/integrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ def __init__(self, name: str, *args: Any, **kwargs: Any) -> None:
WebhookIntegration('circleci', ['continuous-integration'], display_name='CircleCI'),
WebhookIntegration('clubhouse', ['project-management']),
WebhookIntegration('codeship', ['continuous-integration', 'deployment']),
WebhookIntegration('codebase', ['project-management'], display_name='Codebase'),
WebhookIntegration('crashlytics', ['monitoring']),
WebhookIntegration('dialogflow', ['customer-support'], display_name='Dialogflow'),
WebhookIntegration('delighted', ['customer-support', 'marketing'], display_name='Delighted'),
Expand Down
Empty file.
16 changes: 16 additions & 0 deletions zerver/webhooks/codebase/doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Get Zulip notifications for your for Codebase events!

1. {!create-stream.md!}

1. {!create-bot-construct-url-indented.md!}

1. Go to your Codebase Dashboard, and click on the settings icon in
the top-right corner. Click on **Event Hooks**.
Now, click **New Event Webhook**.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would join the last two sentences together, Click on **Event Hooks**, and click **New Event Webhook**. It reads better, imo!


1. Set **Payload URL** to the URL constructed above, and click
**Create**.

{!congrats.md!}

![](/static/images/integrations/codebase/001.png)
4 changes: 4 additions & 0 deletions zerver/webhooks/codebase/fixtures/ticket_creation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type": "ticket_creation",
"payload": "{\"id\":2,\"summary\":\"Adding the brand new feature of auto tuning to my webapp\",\"status\":{\"name\":\"New\",\"colour\":\"green\",\"closed\":false},\"milestone\":null,\"priority\":{\"name\":\"High\",\"colour\":\"orange\"},\"assignee\":{\"name\":\"Sameer Choubey\",\"username\":\"sameer-choubey-89\",\"email_address\":\"inadaptabl@firamax.club\"},\"reporter\":{\"name\":\"Sameer Choubey\",\"username\":\"sameer-choubey-89\",\"email_address\":\"inadaptabl@firamax.club\"},\"type\":{\"name\":\"Enhancement\",\"icon\":\"hat\"},\"category\":\"General\",\"description\":\"We'll first start with making a list of ideas that needed to be implemented.\",\"project\":{\"name\":\"Adding support for checking events.\",\"url\":\"http://travelalittle.codebasehq.com/projects/adding-support-for-checking-events\",\"status\":\"active\",\"account\":{\"name\":\"TravelAlIttle\",\"url\":\"https://travelalittle.codebasehq.com\",\"email\":\"inadaptabl@firamax.club\"}},\"url\":\"http://travelalittle.codebasehq.com/projects/adding-support-for-checking-events/tickets/2\"}"
}
4 changes: 4 additions & 0 deletions zerver/webhooks/codebase/fixtures/ticket_update.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type": "ticket_update",
"payload": "{\"ticket\":{\"id\":2,\"summary\":\"Adding the brand new feature of auto tuning to my webapp\",\"status\":{\"name\":\"In Progress\",\"colour\":\"blue\",\"closed\":false},\"milestone\":null,\"priority\":{\"name\":\"Normal\",\"colour\":\"blue\"},\"assignee\":{\"name\":\"Sameer Choubey\",\"username\":\"sameer-choubey-89\",\"email_address\":\"inadaptabl@firamax.club\"},\"reporter\":{\"name\":\"Sameer Choubey\",\"username\":\"sameer-choubey-89\",\"email_address\":\"inadaptabl@firamax.club\"},\"type\":{\"name\":\"Feature\",\"icon\":\"construction\"},\"category\":\"Refactoring\",\"description\":\"We'll first start with making a list of ideas that needed to be implemented.\",\"project\":{\"name\":\"Adding support for checking events.\",\"url\":\"http://travelalittle.codebasehq.com/projects/adding-support-for-checking-events\",\"status\":\"active\",\"account\":{\"name\":\"TravelAlIttle\",\"url\":\"https://travelalittle.codebasehq.com\",\"email\":\"inadaptabl@firamax.club\"}},\"url\":\"http://travelalittle.codebasehq.com/projects/adding-support-for-checking-events/tickets/2\"},\"user\":{\"name\":\"Sameer Choubey\",\"username\":\"sameer-choubey-89\",\"email_address\":\"inadaptabl@firamax.club\"},\"content\":\"The second step is to outline the new idea with the help of block statements.\",\"changes\":{\"priority_id\":[\"High\",\"Normal\"],\"ticket_type_id\":[\"Enhancement\",\"Feature\"],\"category_id\":[\"General\",\"Refactoring\"],\"status_id\":[\"New\",\"In Progress\"]},\"commit\":null,\"attachments\":[]}"
}
18 changes: 18 additions & 0 deletions zerver/webhooks/codebase/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from zerver.lib.test_classes import WebhookTestCase

class CobebaseHookTests(WebhookTestCase):
STREAM_NAME = 'codebase'
URL_TEMPLATE = "/api/v1/external/codebase?&api_key={api_key}&stream={stream}"
FIXTURE_DIR_NAME = 'codebase'


def test_ticket_creation(self) -> None:
expected_topic = u"Adding the brand new feature of auto tuning to my webapp"
expected_message = u"A ticket of **[Enhancement](http://travelalittle.codebasehq.com/projects/adding-support-for-checking-events/tickets/2)** type and category **General** has been created by **Sameer Choubey**"

self.send_and_test_stream_message('ticket_creation', expected_topic, expected_message)

def test_ticket_update(self) -> None:
expected_topic = u"Adding the brand new feature of auto tuning to my webapp"
expected_message = u"Ticket with ID **[2](http://travelalittle.codebasehq.com/projects/adding-support-for-checking-events)**, category **Refactoring** has been updated by **Sameer Choubey**"
self.send_and_test_stream_message('ticket_update', expected_topic, expected_message)
83 changes: 83 additions & 0 deletions zerver/webhooks/codebase/view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import json
from typing import Any, Dict, Iterable

from django.http import HttpRequest, HttpResponse
from zerver.decorator import api_key_only_webhook_view
from zerver.lib.webhooks.common import check_send_webhook_message, \
UnexpectedWebhookEventType
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_success
from zerver.models import UserProfile

def get_event_type(payload: Dict[str, Any]):
return (payload['type'])

def get_topic_type(payload: Dict[str, Any]):

if payload['type'] == "ticket_update":
payload = payload['payload']
payload = json.loads(payload)

return payload['ticket']['summary']
else:
payload = payload['payload']
payload = json.loads(payload)

return payload['summary']

def ticket_creation(payload: Dict[str, Any], user_profile: UserProfile):

payload = payload['payload']
payload = json.loads(payload)

type = payload['type']['name']
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type is a reserved Python keyword, I would replace this with something like ticket_type.

name = payload['assignee']['name']
category = payload['category']
url = payload['url']

body = "A ticket of **[{}]({})** type and category **{}** has been created by **{}**".format(type, url, category, name)

return body

def ticket_update(payload: Dict[str, Any], user_profile: UserProfile):
payload = payload['payload']
payload = json.loads(payload)

id = payload['ticket']['id']
type = payload['ticket']['category']
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both id and type are reserved keywords in Python, it is a good habit to use descriptive alternatives such as ticket_type or ticket_id instead!

name = payload['user']['name']
url = payload['ticket']['project']['url']

body = "Ticket with ID **[{}]({})**, category **{}** has been updated by **{}**".format(id, url, type, name)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of things:

  • I would move both body template strings to the top of the file with all uppercase names, such as TICKET_UPDATE_TEMPLATE. I would also use named format arguments, such as "has been updated by {author}".format(author=author)
  • Also, I would recommend ending all messages with proper punctuation, i.e., a period. I am currently doing an audit to make sure we use proper punctuation across all of our webhooks.


return body

CODEBASE_EVENT_MAPPER = {
"ticket_creation": ticket_creation,
"ticket_update": ticket_update
}

@api_key_only_webhook_view('CodeBase')
@has_request_variables
def api_codebase_webhook(
request: HttpRequest, user_profile: UserProfile,
payload: Dict[str, Iterable[Dict[str, Any]]]=REQ(argument_type='body')
) -> HttpResponse:

if payload is None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm.. is the payload every actually None? I would be surprised if it is.

return json_success()

event = get_event_type(payload)
topic = get_topic_type(payload)

if event is not None:
body_func = CODEBASE_EVENT_MAPPER.get(event)

if body_func is None:
raise UnexpectedWebhookEventType('Cobdebase', event)

body = body_func(payload, user_profile) # type : str

check_send_webhook_message(request, user_profile, topic, body)

return json_success()