-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improve Asana integration for failed PR checks
- Loading branch information
Showing
4 changed files
with
308 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
name: Report Failed PR Checks to Asana | ||
description: Integrates with Asana to report failed PR checks as a task. | ||
inputs: | ||
asana-access-token: | ||
description: "Asana access token" | ||
required: true | ||
type: string | ||
asana-section-id: | ||
description: "Asana project's section ID" | ||
required: true | ||
type: string | ||
action: | ||
description: "Action to perform: choose between 'create-task' and 'close-task'" | ||
required: true | ||
type: string | ||
commit-author: | ||
description: "Last commit author's GitHub handle" | ||
required: false | ||
type: string | ||
runs: | ||
using: "composite" | ||
steps: | ||
- env: | ||
WORKFLOW_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} | ||
GITHUB_REF_NAME: ${{ github.ref_name }} | ||
GITHUB_RUN_ID: ${{ github.run_id }} | ||
ASANA_SECTION_ID: ${{ inputs.asana-section-id }} | ||
ASANA_ACCESS_TOKEN: ${{ inputs.asana-access-token }} | ||
shell: bash | ||
run: | | ||
case "${{ inputs.action }}" in | ||
"create-task") | ||
if [[ -n "${{ inputs.commit-author }}" ]]; then | ||
export ASANA_ASSIGNEE=$(jq -r .${{ inputs.commit-author }} < ${{ github.action_path }}/user_ids.json) | ||
fi | ||
${{ github.action_path }}/report-failed-pr-checks.sh create-task \ | ||
-t "PR Check is failing on ${{ env.GITHUB_REF_NAME }}" \ | ||
-d "PR Checks conducted after merging have failed. See ${{ env.WORKFLOW_URL }}. Follow the steps on https://app.asana.com/0/1202500774821704/1205317064731691 to resolve this issue." | ||
;; | ||
"close-task") | ||
${{ github.action_path }}/report-failed-pr-checks.sh close-task \ | ||
-m "Closing this one as checks are passing after a re-run. See ${{ env.WORKFLOW_URL }}/attempts/${{ github.run_attempt }} for details." | ||
;; | ||
*) | ||
echo "::error::Invalid action '${{ inputs.action }}'." | ||
exit 1 | ||
;; | ||
esac |
192 changes: 192 additions & 0 deletions
192
.github/actions/asana-failed-pr-checks/report-failed-pr-checks.sh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
#!/bin/bash | ||
|
||
set -eo pipefail | ||
|
||
workspace_id="137249556945" | ||
project_id="1205237866452338" | ||
workflow_id_custom_field_id="1205563320492190" | ||
asana_api_url="https://app.asana.com/api/1.0" | ||
|
||
print_usage_and_exit() { | ||
local reason=$1 | ||
|
||
cat <<- EOF | ||
Usage: | ||
$ $(basename "$0") <create-task|close-task> [-h] [-t <title>] [-d <description>] [-m <closing_comment_message>] | ||
Actions: | ||
create-task Create a new task in Asana | ||
close-task Close an existing Asana task for the workflow ID provided in environment variable WORKFLOW_ID | ||
Options (only used for create-task): | ||
-t <title> Asana task title | ||
-d <description> Asana task description | ||
-m <closing_comment_message> Closing comment message | ||
Note: This script is intended for CI use only. You shouldn't call it directly. | ||
EOF | ||
|
||
echo "${reason}" | ||
exit 1 | ||
} | ||
|
||
read_command_line_arguments() { | ||
action="$1" | ||
case "${action}" in | ||
create-task) | ||
;; | ||
close-task) | ||
;; | ||
*) | ||
print_usage_and_exit "Unknown action '${action}'" | ||
;; | ||
esac | ||
|
||
shift 1 | ||
|
||
case "${action}" in | ||
create-task) | ||
if (( $# < 2 )); then | ||
print_usage_and_exit "Missing arguments" | ||
fi | ||
;; | ||
close-task) | ||
if (( $# < 1 )); then | ||
print_usage_and_exit "Missing message argument" | ||
fi | ||
;; | ||
esac | ||
|
||
while getopts 'd:hm:t:' OPTION; do | ||
case "${OPTION}" in | ||
d) | ||
description="${OPTARG}" | ||
;; | ||
h) | ||
print_usage_and_exit | ||
;; | ||
m) | ||
message="${OPTARG}" | ||
;; | ||
t) | ||
title="${OPTARG}" | ||
;; | ||
*) | ||
print_usage_and_exit "Unknown option '${OPTION}'" | ||
;; | ||
esac | ||
done | ||
|
||
shift $((OPTIND-1)) | ||
} | ||
|
||
create_task() { | ||
local task_name=$1 | ||
local description | ||
local task_id | ||
local assignee_param | ||
description=$(sed -E -e 's/\\/\\\\/g' -e 's/"/\\"/g' <<< "$2") | ||
if [[ -n "${assignee}" ]]; then | ||
assignee_param="\"${assignee}\"" | ||
else | ||
assignee_param="null" | ||
fi | ||
|
||
task_id=$(curl -X POST -s "${asana_api_url}/tasks?opt_fields=gid" \ | ||
-H "Authorization: Bearer ${asana_personal_access_token}" \ | ||
-H 'content-type: application/json' \ | ||
-d "{ | ||
\"data\": { | ||
\"assignee\": ${assignee_param}, | ||
\"name\": \"${task_name}\", | ||
\"resource_subtype\": \"default_task\", | ||
\"notes\": \"${description}\", | ||
\"projects\": [ | ||
\"${project_id}\" | ||
], | ||
\"custom_fields\": { | ||
\"${workflow_id_custom_field_id}\": \"${workflow_id}\" | ||
} | ||
} | ||
}" \ | ||
| jq -r '.data.gid') | ||
|
||
return_code="$(curl -X POST -s "${asana_api_url}/sections/${section_id}/addTask" \ | ||
-H "Authorization: Bearer ${asana_personal_access_token}" \ | ||
-H 'content-type: application/json' \ | ||
--write-out '%{http_code}' \ | ||
--output /dev/null \ | ||
-d "{\"data\": {\"task\": \"${task_id}\"}}")" | ||
|
||
[[ ${return_code} -eq 200 ]] | ||
} | ||
|
||
find_task_for_workflow_id() { | ||
local workflow_id=$1 | ||
curl -s "${asana_api_url}/workspaces/${workspace_id}/tasks/search?opt_fields=gid&resource_subtype=default_task&projects.any=${project_id}&limit=1&custom_fields.${workflow_id_custom_field_id}.value=${workflow_id}" \ | ||
-H "Authorization: Bearer ${asana_personal_access_token}" \ | ||
| jq -r "if (.data | length) != 0 then .data[0].gid else empty end" | ||
} | ||
|
||
add_comment_to_task() { | ||
local task_id=$1 | ||
local message | ||
local return_code | ||
message=$(sed -E -e 's/\\/\\\\/g' -e 's/"/\\"/g' <<< "$2") | ||
|
||
return_code="$(curl -X POST -s "${asana_api_url}/tasks/${task_id}/stories" \ | ||
-H "Authorization: Bearer ${asana_personal_access_token}" \ | ||
-H 'content-type: application/json' \ | ||
--write-out '%{http_code}' \ | ||
--output /dev/null \ | ||
-d "{\"data\": {\"text\": \"${message}\"}}")" | ||
|
||
[[ ${return_code} -eq 201 ]] | ||
} | ||
|
||
close_task() { | ||
local task_id=$1 | ||
local return_code | ||
|
||
return_code="$(curl -X PUT -s "${asana_api_url}/tasks/${task_id}" \ | ||
-H "Authorization: Bearer ${asana_personal_access_token}" \ | ||
-H 'content-type: application/json' \ | ||
--write-out '%{http_code}' \ | ||
--output /dev/null \ | ||
-d "{\"data\": {\"completed\": true}}")" | ||
|
||
[[ ${return_code} -eq 200 ]] | ||
} | ||
|
||
main() { | ||
local asana_personal_access_token="${ASANA_ACCESS_TOKEN}" | ||
local section_id="${ASANA_SECTION_ID}" | ||
local assignee="${ASANA_ASSIGNEE}" | ||
local workflow_id="${GITHUB_RUN_ID}" | ||
local action | ||
local title | ||
local description | ||
local message | ||
|
||
read_command_line_arguments "$@" | ||
|
||
case "${action}" in | ||
create-task) | ||
create_task "${title}" "${description}" | ||
;; | ||
close-task) | ||
task_id=$(find_task_for_workflow_id "${workflow_id}") | ||
if [[ -n "${task_id}" ]]; then | ||
add_comment_to_task "${task_id}" "${message}" | ||
close_task "${task_id}" | ||
else | ||
echo "No task found for workflow ID '${workflow_id}'" | ||
fi | ||
;; | ||
*) | ||
print_usage_and_exit "Unknown action '${action}'" | ||
;; | ||
esac | ||
} | ||
|
||
main "$@" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
{ | ||
"afterxleep": "1204051006248670", | ||
"amddg44": "1201462886802326", | ||
"ayoy": "1201621708108816", | ||
"brindy": "392891325557408", | ||
"bwaresiak": "856498667309057", | ||
"Bunn": "1201011656765575", | ||
"dharb": "246491496396030", | ||
"diegoreymendez": "1203108348814444", | ||
"GioSensation": "1144596633302696", | ||
"graeme": "1202926619868495", | ||
"jaceklyp": "1201392122286920", | ||
"jonathanKingston": "1199237043596759", | ||
"jotaemepereira": "1203972458584425", | ||
"ladamski": "1171671347221380", | ||
"mallexxx": "1202406491309505", | ||
"miasma13": "1200848783436158", | ||
"muodov": "1201807839802870", | ||
"samsymons": "1193060753408019", | ||
"shakyShane": "1201141132927824", | ||
"SabrinaTardio": "1204024359086954", | ||
"THISISDINOSAUR": "1187352150811184", | ||
"tomasstrba": "1148564399176232", | ||
"viktorjansson": "970019368055267", | ||
"vinay-nadig-0042": "1202096681833210" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters