Skip to content

Commit

Permalink
Report failed unit tests to Asana (duckduckgo#1979)
Browse files Browse the repository at this point in the history
Task/Issue URL: https://app.asana.com/0/1203301625297703/1205419026232021/f

Description:
Update PR Checks workflow so that it searches JUnit test report for failed test cases, and reports every single
failed test case as new task in Asana (or a subtask in case of duplicates).
  • Loading branch information
ayoy authored Sep 6, 2023
1 parent b2e8d10 commit 3b48fea
Show file tree
Hide file tree
Showing 2 changed files with 198 additions and 0 deletions.
13 changes: 13 additions & 0 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,19 @@ jobs:
with:
report_paths: unittests.xml

- name: Update Asana with failed unit tests
if: always() # always run even if the previous step fails
env:
ASANA_ACCESS_TOKEN: ${{ secrets.ASANA_ACCESS_TOKEN }}
WORKFLOW_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
# Extract failed tests from the junit report
# Only keep failures unique by classname and name (column 1 and 2 of the yq output)
yq < unittests.xml -p xml -o json -r \
$'[.testsuites.testsuite[].testcase] | flatten | map(select(.failure) | .+@classname + " " + .+@name + " \'" + .failure.+@message + "\' ${{ env.WORKFLOW_URL }}") | .[]' \
| sort -u -k 1,2 \
| xargs -L 1 ./scripts/report-failed-unit-test.sh -s ${{ vars.APPLE_CI_FAILING_TESTS_FAILED_TESTS_SECTION_ID }}
release-build:

name: Make Release Build
Expand Down
185 changes: 185 additions & 0 deletions scripts/report-failed-unit-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
#!/bin/bash

set -eo pipefail

print_usage_and_exit() {
local reason=$1

cat <<- EOF
Usage:
$ $(basename "$0") [-h] -s <section_gid> <class_name> <testcase_name> <message> <workflow_url>
Options:
<class_name> Name of the failing test case class
<testcase_name> Name of the failing test case
<message> Failure message
<workflow_url> URL of the workflow that failed
-h Print this message
-s <section_gid> Section GID to add the task to
Note: This script is intended for CI use only. You shouldn't call it directly.
EOF

echo "${reason}"
exit 1
}

read_command_line_arguments() {
while getopts 'hs:' OPTION; do
case "${OPTION}" in
h)
print_usage_and_exit
;;
s)
failing_tests_section_id="${OPTARG}"
;;
*)
print_usage_and_exit "Unknown option '${OPTION}'"
;;
esac
done

if [[ -z "${failing_tests_section_id}" ]]; then
print_usage_and_exit "Missing Section GID"
fi

shift $((OPTIND-1))

if (( $# < 4 )); then
print_usage_and_exit "Missing arguments"
fi

class_name=$1
testcase_name=$2
message=$3
workflow_url=$4

shift 4
}

workspace_id="137249556945"
project_id="1205237866452338"
occurrences_custom_field_id="1205237866452341"
asana_api_url="https://app.asana.com/api/1.0"

find_task_and_occurrences() {
local task_name=$1
curl -s "${asana_api_url}/workspaces/${workspace_id}/tasks/search?text=${task_name}&opt_fields=custom_fields.number_value&resource_subtype=default_task&projects.any=${project_id}&is_subtask=false" \
-H "Authorization: Bearer ${asana_personal_access_token}" \
| jq -r "if (.data | length) != 0 then [.data[0].gid, (.data[0].custom_fields[] | select(.gid == \"${occurrences_custom_field_id}\") | (.number_value // 0))] | join(\" \") else empty end"
}

update_task() {
local task_id=$1
local occurrences=$2
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\": false,
\"custom_fields\": {
\"${occurrences_custom_field_id}\": \"${occurrences}\"
},
\"due_on\": \"${due_date}\"
}
}")"

[[ ${return_code} -eq 200 ]]
}

create_task() {
local task_name=$1
local workflow_url=$2
local message
local occurrences=1
local task_id
message=$(sed -E -e 's/\\/\\\\/g' -e 's/"/\\"/g' <<< "$3")

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\": {
\"custom_fields\": {
\"${occurrences_custom_field_id}\": \"${occurrences}\"
},
\"due_date\": \"${due_date}\",
\"name\": \"${task_name}\",
\"resource_subtype\": \"default_task\",
\"notes\": \"Workflow URL: ${workflow_url}\n\n${message}\",
\"projects\": [
\"${project_id}\"
],
\"workspace\": \"${workspace_id}\"
}
}" \
| jq -r '.data.gid')

curl -X POST -s "${asana_api_url}/sections/${failing_tests_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}\"}}"
}

add_subtask() {
local parent_task_id=$1
local task_name=$2
local workflow_url=$3
local message="${4//\"/\\\"}"
local return_code

return_code=$(curl -X POST -s "${asana_api_url}/tasks/${parent_task_id}/subtasks" \
-H "Authorization: Bearer ${asana_personal_access_token}" \
-H 'content-type: application/json' \
--write-out '%{http_code}' \
--output /dev/null \
-d "{
\"data\": {
\"name\": \"${task_name}\",
\"resource_subtype\": \"default_task\",
\"notes\": \"Workflow URL: ${workflow_url}\n\n${message}\"
}
}
")

[[ ${return_code} -eq 201 ]]
}

main() {
local asana_personal_access_token="${ASANA_ACCESS_TOKEN}"
local class_name
local testcase_name
local message
local workflow_url
local due_date
due_date=$(date -v +30d +%Y-%m-%d)

read_command_line_arguments "$@"

local task_name="${class_name}.${testcase_name}"
echo "Processing ${task_name}"

local task_and_occurrences
task_and_occurrences=$(find_task_and_occurrences "${task_name}")
if [[ -n "${task_and_occurrences}" ]]; then
local task_id
local occurrences
task_id=$(cut -d ' ' -f 1 <<< "${task_and_occurrences}")
occurrences=$(cut -d ' ' -f 2 <<< "${task_and_occurrences}")
occurrences=$((occurrences+1))

update_task "${task_id}" "${occurrences}"
add_subtask "${task_id}" "${task_name}" "${workflow_url}" "${message}"
else
create_task "${task_name}" "${workflow_url}" "${message}"
fi
}

main "$@"

0 comments on commit 3b48fea

Please sign in to comment.