mirror of https://github.com/zulip/zulip.git
integrations: Allow PR updates to multiple stories for Clubhouse.
The fixture "story_update_add_github_pull_request" is changed here as it doesn't make sense to link a story to a PR without having "pull_request_ids" changed. The previous example is likely a mistake which occurs when you try to add a PR that has already been added to a story. This commit also allows comments under the PR that link it to a story to be sent to the stream. Fixes: #18022
This commit is contained in:
parent
41543fabb8
commit
f5528c38c2
|
@ -36,6 +36,11 @@
|
||||||
"new":true,
|
"new":true,
|
||||||
"old":false
|
"old":false
|
||||||
},
|
},
|
||||||
|
"pull_request_ids": {
|
||||||
|
"adds": [
|
||||||
|
500000032
|
||||||
|
]
|
||||||
|
},
|
||||||
"workflow_state_id":{
|
"workflow_state_id":{
|
||||||
"new":500000010,
|
"new":500000010,
|
||||||
"old":500000008
|
"old":500000008
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from typing import Any, Callable, Dict, Optional
|
from typing import Any, Callable, Dict, Generator, Optional
|
||||||
|
|
||||||
from django.http import HttpRequest, HttpResponse
|
from django.http import HttpRequest, HttpResponse
|
||||||
|
|
||||||
|
@ -52,12 +52,12 @@ STORY_UPDATE_TYPE_TEMPLATE = (
|
||||||
)
|
)
|
||||||
DELETE_TEMPLATE = "The {entity_type} **{name}** was deleted."
|
DELETE_TEMPLATE = "The {entity_type} **{name}** was deleted."
|
||||||
STORY_UPDATE_OWNER_TEMPLATE = "New owner added to the story {name_template}."
|
STORY_UPDATE_OWNER_TEMPLATE = "New owner added to the story {name_template}."
|
||||||
|
TRAILING_WORKFLOW_STATE_CHANGE_TEMPLATE = " ({old} -> {new})"
|
||||||
STORY_GITHUB_PR_TEMPLATE = (
|
STORY_GITHUB_PR_TEMPLATE = (
|
||||||
"New GitHub PR [#{name}]({url}) opened for story {name_template} ({old} -> {new})."
|
"New GitHub PR [#{name}]({url}) opened for story {name_template}{workflow_state_template}."
|
||||||
)
|
|
||||||
STORY_GITHUB_BRANCH_TEMPLATE = (
|
|
||||||
"New GitHub branch [{name}]({url}) associated with story {name_template} ({old} -> {new})."
|
|
||||||
)
|
)
|
||||||
|
STORY_GITHUB_COMMENT_PR_TEMPLATE = "Existing GitHub PR [#{name}]({url}) associated with story {name_template}{workflow_state_template}."
|
||||||
|
STORY_GITHUB_BRANCH_TEMPLATE = "New GitHub branch [{name}]({url}) associated with story {name_template}{workflow_state_template}."
|
||||||
|
|
||||||
|
|
||||||
def get_action_with_primary_id(payload: Dict[str, Any]) -> Dict[str, Any]:
|
def get_action_with_primary_id(payload: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
|
@ -341,30 +341,46 @@ def get_reference_by_id(payload: Dict[str, Any], ref_id: int) -> Dict[str, Any]:
|
||||||
return ref
|
return ref
|
||||||
|
|
||||||
|
|
||||||
|
def get_secondary_actions_with_param(
|
||||||
|
payload: Dict[str, Any], entity: str, changed_attr: str
|
||||||
|
) -> Generator[Dict[str, Any], None, None]:
|
||||||
|
# This function is a generator for secondary actions that have the required changed attributes,
|
||||||
|
# i.e.: "story" that has "pull-request_ids" changed.
|
||||||
|
for action in payload["actions"]:
|
||||||
|
if action["entity_type"] == entity and action["changes"].get(changed_attr) is not None:
|
||||||
|
yield action
|
||||||
|
|
||||||
|
|
||||||
def get_story_create_github_entity_body(
|
def get_story_create_github_entity_body(
|
||||||
payload: Dict[str, Any], action: Dict[str, Any], entity: str
|
payload: Dict[str, Any], action: Dict[str, Any], entity: str
|
||||||
) -> str:
|
) -> str:
|
||||||
story: Dict[str, Any] = {}
|
pull_request_action: Dict[str, Any] = get_action_with_primary_id(payload)
|
||||||
for a in payload["actions"]:
|
|
||||||
if a["entity_type"] == "story" and a["changes"].get("workflow_state_id") is not None:
|
|
||||||
story = a
|
|
||||||
|
|
||||||
new_state_id = story["changes"]["workflow_state_id"]["new"]
|
|
||||||
old_state_id = story["changes"]["workflow_state_id"]["old"]
|
|
||||||
new_state = get_reference_by_id(payload, new_state_id)["name"]
|
|
||||||
old_state = get_reference_by_id(payload, old_state_id)["name"]
|
|
||||||
|
|
||||||
kwargs = {
|
kwargs = {
|
||||||
"name_template": STORY_NAME_TEMPLATE.format(**story),
|
"name_template": STORY_NAME_TEMPLATE.format(**action),
|
||||||
"name": action.get("number") if entity == "pull-request" else action.get("name"),
|
"name": pull_request_action.get("number")
|
||||||
"url": action["url"],
|
if entity == "pull-request" or entity == "pull-request-comment"
|
||||||
"new": new_state,
|
else pull_request_action.get("name"),
|
||||||
"old": old_state,
|
"url": pull_request_action["url"],
|
||||||
|
"workflow_state_template": "",
|
||||||
}
|
}
|
||||||
|
|
||||||
template = (
|
# Sometimes the workflow state of the story will not be changed when linking to a PR.
|
||||||
STORY_GITHUB_PR_TEMPLATE if entity == "pull-request" else STORY_GITHUB_BRANCH_TEMPLATE
|
if action["changes"].get("workflow_state_id") is not None:
|
||||||
|
new_state_id = action["changes"]["workflow_state_id"]["new"]
|
||||||
|
old_state_id = action["changes"]["workflow_state_id"]["old"]
|
||||||
|
new_state = get_reference_by_id(payload, new_state_id)["name"]
|
||||||
|
old_state = get_reference_by_id(payload, old_state_id)["name"]
|
||||||
|
kwargs["workflow_state_template"] = TRAILING_WORKFLOW_STATE_CHANGE_TEMPLATE.format(
|
||||||
|
new=new_state, old=old_state
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if entity == "pull-request":
|
||||||
|
template = STORY_GITHUB_PR_TEMPLATE
|
||||||
|
elif entity == "pull-request-comment":
|
||||||
|
template = STORY_GITHUB_COMMENT_PR_TEMPLATE
|
||||||
|
else:
|
||||||
|
template = STORY_GITHUB_BRANCH_TEMPLATE
|
||||||
return template.format(**kwargs)
|
return template.format(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@ -515,6 +531,9 @@ EVENT_BODY_FUNCTION_MAPPER: Dict[str, Callable[[Dict[str, Any], Dict[str, Any]],
|
||||||
"epic_update_archived": partial(get_update_archived_body, entity="epic"),
|
"epic_update_archived": partial(get_update_archived_body, entity="epic"),
|
||||||
"story_create": get_story_create_body,
|
"story_create": get_story_create_body,
|
||||||
"pull-request_create": partial(get_story_create_github_entity_body, entity="pull-request"),
|
"pull-request_create": partial(get_story_create_github_entity_body, entity="pull-request"),
|
||||||
|
"pull-request_comment": partial(
|
||||||
|
get_story_create_github_entity_body, entity="pull-request-comment"
|
||||||
|
),
|
||||||
"branch_create": partial(get_story_create_github_entity_body, entity="branch"),
|
"branch_create": partial(get_story_create_github_entity_body, entity="branch"),
|
||||||
"story_delete": get_delete_body,
|
"story_delete": get_delete_body,
|
||||||
"epic_delete": get_delete_body,
|
"epic_delete": get_delete_body,
|
||||||
|
@ -553,6 +572,21 @@ IGNORED_EVENTS = {
|
||||||
"story-comment_update",
|
"story-comment_update",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EVENTS_SECONDARY_ACTIONS_FUNCTION_MAPPER: Dict[
|
||||||
|
str, Callable[[Dict[str, Any]], Generator[Dict[str, Any], None, None]]
|
||||||
|
] = {
|
||||||
|
"pull-request_create": partial(
|
||||||
|
get_secondary_actions_with_param, entity="story", changed_attr="pull_request_ids"
|
||||||
|
),
|
||||||
|
"branch_create": partial(
|
||||||
|
get_secondary_actions_with_param, entity="story", changed_attr="branch_ids"
|
||||||
|
),
|
||||||
|
"pull-request_comment": partial(
|
||||||
|
get_secondary_actions_with_param, entity="story", changed_attr="pull_request_ids"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@webhook_view("ClubHouse")
|
@webhook_view("ClubHouse")
|
||||||
@has_request_variables
|
@has_request_variables
|
||||||
def api_clubhouse_webhook(
|
def api_clubhouse_webhook(
|
||||||
|
@ -579,6 +613,11 @@ def api_clubhouse_webhook(
|
||||||
if event is None:
|
if event is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if event in EVENTS_SECONDARY_ACTIONS_FUNCTION_MAPPER:
|
||||||
|
sec_actions_func = EVENTS_SECONDARY_ACTIONS_FUNCTION_MAPPER[event]
|
||||||
|
for sec_action in sec_actions_func(payload):
|
||||||
|
send_stream_messages_for_actions(request, user_profile, payload, sec_action, event)
|
||||||
|
else:
|
||||||
send_stream_messages_for_actions(request, user_profile, payload, primary_action, event)
|
send_stream_messages_for_actions(request, user_profile, payload, primary_action, event)
|
||||||
|
|
||||||
return json_success()
|
return json_success()
|
||||||
|
|
Loading…
Reference in New Issue