Observing workflow run status on Github
It is sometimes useful to get notified about the completion of a job executed on your CI service. When talking about manually triggered, long-running workflows, it could be easy to forget about them – when instead of waiting and watching the output log, you just start working on a different task.
GitHub doesn’t share an API that makes it possible to do this easily and efficiently. We are going to use an old-school technique called “short polling.” This fancy name means nothing more than just executing requests in an indefinite loop with a delay in between.
Repository workflow runs list request will be the core of our observer. Take a closer look at the documentation; using query parameters you can filter the results at this early stage. For example: list only workflows triggered by yourself with the actor
parameter, specify event
which triggered the run or specific branch
.
We will just focus on the last run, whatever triggered it, and whoever did it.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
GITHUB_TOKEN="$(gopass show github-token)" # stored in a password manager REPO="eclipsesource/tabris-js-hello-world" TEMP_FILE="temp.json" curl \ --silent \ --location \ --request GET \ --header 'Accept: application/vnd.github.everest-preview+json' \ --header 'Content-Type: application/json' \ --header "Authorization: token $GITHUB_TOKEN" \ --header 'cache-control: no-cache' \ "https://api.github.com/repos/${REPO}/actions/runs" > $TEMP_FILE |
JQ is a JSON parser with CLI, we will use it to extract the status of the last run. jqplay is a playground where you can test your queries. Ours will consist of:
– .workflow_runs
– peek into the array with the list of runs
– sort_by( .created_at )
– order items by creation date
– .[-1]
– select the last one from the list
– .status
– extract status
Value of the status
property can be one of: “queued”, “in_progress”, or “completed”. When it’s “completed,” it makes sense to check if it finished successfully. We need a value of the conclusion
property. Can be one of the “success”, “failure”, “neutral”, “cancelled”, “skipped”, “timed_out”, or “action_required”.
1 2 |
STATUS=$(jq -r ".workflow_runs | .[-1] | .status" $TEMP_FILE) CONCLUSION=$(jq -r ".workflow_runs | .[-1] | .conclusion" $TEMP_FILE) |
Let’s wrap it in a loop, as we want to know when it finishes, not only what’s the current state.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
#!/usr/bin/env bash # exit if any command exits with non-zero status set -e # token is stored in a password manager GITHUB_TOKEN="$(gopass show github-token)" REPO="$1" TEMP_FILE="temp.json" SLEEP_INTERVAL=30 echo "Checking conclusion of the last executed run in \"$REPO_OWNER/$REPO_NAME\" repository:" while true; do curl \ --silent \ --location \ --request GET \ --header 'Accept: application/vnd.github.everest-preview+json' \ --header 'Content-Type: application/json' \ --header "Authorization: token $GITHUB_TOKEN" \ --header 'cache-control: no-cache' \ "https://api.github.com/repos/${REPO}/actions/runs" > $TEMP_FILE STATUS=$(jq -r ".workflow_runs | sort_by( .created_at ) | .[-1] | .status" $TEMP_FILE) echo "Check suite state: ${STATUS}" if [ "$STATUS" = "completed" ]; then CONCLUSION=$(jq -r ".workflow_runs | sort_by( .created_at ) | .[-1] | .conclusion" $TEMP_FILE) echo "Check suite conclusion: ${CONCLUSION}" break; fi sleep $SLEEP_INTERVAL done rm $TEMP_FILE || true |
How does it look like in practice?
1 2 3 4 5 6 7 8 |
$ ./check_suite_state.sh eclipsesource/tabris-js-hello-world Checking conclusion of the last executed run in "eclipsesource/tabris-js-hello-world" repository: Check suite state: in_progress Check suite state: in_progress (...) Check suite state: in_progress Check suite state: completed Check suite conclusion: success |
Some services allow you to easily send push notifications to your mobile devices. You might want to use one to catch your attention. Or if it’s enough, then just play a system sound. Just choose an appropriate one – depending on the conclusion
! ;)
1 2 3 4 5 6 |
# macOS only: if [ "$CONCLUSION" = "success" ]; then afplay /System/Library/Sounds/Glass.aiff else afplay /System/Library/Sounds/Basso.aiff fi |
Feedback is welcome!
Want to join the discussion?Feel free to contribute!