|
1 | 1 | name: Notify Slack Jobs Result |
2 | | -description: Will send a notification in Slack for the result of a GitHub action run, typically for test results |
| 2 | +description: Posts a compact Slack notification for a workflow job result |
| 3 | + (status, job name, link to run, slack_channel_id and slack_bot_token). |
3 | 4 | inputs: |
4 | | - github_token: |
5 | | - description: "The GitHub token to use for authentication (usually github.token)" |
| 5 | + status: |
| 6 | + description: "Job conclusion, e.g. success, failure, cancelled, skipped |
| 7 | + (typically needs.<job>.result)" |
6 | 8 | required: true |
7 | | - github_repository: |
8 | | - description: "The GitHub owner/repository to use for authentication (usually github.repository))" |
| 9 | + job_name: |
| 10 | + description: "Display name for the job in the message" |
9 | 11 | required: true |
10 | | - workflow_run_id: |
11 | | - description: "The workflow run ID to get the results from (usually github.run_id)" |
12 | | - required: true |
13 | | - github_job_name_regex: |
14 | | - description: "The regex to use to match 1..many job name(s) to collect results from. Should include a capture group named 'cap' for the part of the job name you want to display in the Slack message (e.g. ^Client Compatability Test (?<cap>.*?)$)" |
15 | | - required: true |
16 | | - message_title: |
17 | | - description: "The title of the Slack message" |
| 12 | + run_url: |
| 13 | + description: "URL to the workflow run (e.g. |
| 14 | + format('https://github.com/{0}/actions/runs/{1}', github.repository, |
| 15 | + github.run_id))" |
18 | 16 | required: true |
| 17 | + slack_thread_ts: |
| 18 | + description: "Optional Slack thread timestamp to reply in a thread" |
| 19 | + required: false |
| 20 | + default: "" |
19 | 21 | slack_channel_id: |
20 | | - description: "The Slack channel ID to post the message to" |
| 22 | + description: "Slack channel ID to post to" |
21 | 23 | required: true |
22 | 24 | slack_bot_token: |
23 | | - description: "The Slack bot token to use for authentication which needs permission and an installed app in the channel" |
| 25 | + description: "Slack bot token to use for posting" |
24 | 26 | required: true |
25 | | - slack_thread_ts: |
26 | | - description: "The Slack thread timestamp to post the message to, handy for keeping multiple related results in a single thread" |
27 | | - required: false |
28 | | - base64_parsed_results: |
29 | | - description: "Base64 encoded parsed results to use" |
30 | | - required: false |
31 | 27 |
|
32 | 28 | runs: |
33 | 29 | using: composite |
34 | 30 | steps: |
35 | | - - name: Get Results |
| 31 | + - name: Build Slack payload |
| 32 | + id: slack-payload |
36 | 33 | shell: bash |
37 | | - id: test-results |
| 34 | + env: |
| 35 | + STATUS: ${{ inputs.status }} |
| 36 | + JOB_NAME: ${{ inputs.job_name }} |
| 37 | + RUN_URL: ${{ inputs.run_url }} |
| 38 | + THREAD_TS: ${{ inputs.slack_thread_ts }} |
| 39 | + SLACK_CHANNEL_ID: ${{ inputs.slack_channel_id }} |
38 | 40 | run: | |
39 | | - if [ -n "${{ inputs.base64_parsed_results }}" ]; then |
40 | | - echo "Using base64 parsed results" |
41 | | - PARSED_RESULTS=$(echo "${{ inputs.base64_parsed_results }}" | base64 -d) |
42 | | - else |
43 | | - go install github.com/smartcontractkit/chainlink-testing-framework/tools/workflowresultparser@v1.0.0 |
44 | | - PATH=$PATH:$(go env GOPATH)/bin |
45 | | - export PATH |
46 | | - |
47 | | - workflowresultparser -workflowRunID ${{ inputs.workflow_run_id }} -githubToken ${{ inputs.github_token }} -githubRepo "${{ inputs.github_repository }}" -jobNameRegex "${{ inputs.github_job_name_regex }}" -outputFile=output.json |
48 | | - |
49 | | - if [ ! -f output.json ]; then |
50 | | - PARSED_RESULTS='""' |
51 | | - else |
52 | | - PARSED_RESULTS=$(cat output.json | jq -c "select(has(\"results\")) | .results[]") |
53 | | - fi |
54 | | - |
55 | | - fi |
56 | | - |
57 | | - echo "Parsed Results:" |
58 | | - echo $PARSED_RESULTS |
59 | | - |
60 | | - ALL_SUCCESS=true |
61 | | - |
62 | | - if [ "$PARSED_RESULTS" != '""' ]; then |
63 | | - echo "Checking for failures" |
64 | | - echo "$PARSED_RESULTS" | jq -s | jq -r '.[] | select(.conclusion != ":white_check_mark:")' |
65 | | - for row in $(echo "$PARSED_RESULTS" | jq -s | jq -r '.[] | select(.conclusion != ":white_check_mark:")'); do |
66 | | - ALL_SUCCESS=false |
67 | | - break |
68 | | - done |
69 | | - echo "Success: $ALL_SUCCESS" |
70 | | - |
71 | | - echo all_success=$ALL_SUCCESS >> $GITHUB_OUTPUT |
72 | | - |
73 | | - FORMATTED_RESULTS=$(echo $PARSED_RESULTS | jq -s '[.[] |
74 | | - | { |
75 | | - conclusion: .conclusion, |
76 | | - cap: .cap, |
77 | | - html_url: .html_url |
78 | | - } |
79 | | - ] |
80 | | - | map("{\"type\": \"section\", \"text\": {\"type\": \"mrkdwn\", \"text\": \"<\(.html_url)|\(.cap)>: \(.conclusion)\"}}") |
81 | | - | join(",")') |
82 | | - else |
83 | | - echo "Nothing to post, no results found" |
84 | | - exit 0 |
85 | | - fi |
86 | | - |
87 | | - echo "Formatted Results:" |
88 | | - echo $FORMATTED_RESULTS |
| 41 | + set -euo pipefail |
89 | 42 |
|
90 | | - # Cleans out backslashes and quotes from jq |
91 | | - CLEAN_RESULTS=$(echo "$FORMATTED_RESULTS" | sed 's/\\\"/"/g' | sed 's/^"//;s/"$//') |
| 43 | + case "${STATUS}" in |
| 44 | + success) EMOJI="✅" ;; |
| 45 | + failure) EMOJI="❌" ;; |
| 46 | + cancelled) EMOJI="⚠️" ;; |
| 47 | + skipped) EMOJI="⏭️" ;; |
| 48 | + *) EMOJI="❔" ;; |
| 49 | + esac |
92 | 50 |
|
93 | | - echo "Clean Results" |
94 | | - echo $CLEAN_RESULTS |
| 51 | + PAYLOAD_FILE="${RUNNER_TEMP:-/tmp}/notify-slack-jobs-result.json" |
95 | 52 |
|
96 | | - echo results=$CLEAN_RESULTS >> $GITHUB_OUTPUT |
97 | | - - name: Post Results |
98 | | - uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0 |
99 | | - if: steps.test-results.outputs.results != '' |
100 | | - env: |
101 | | - SLACK_BOT_TOKEN: ${{ inputs.slack_bot_token }} |
102 | | - with: |
103 | | - channel-id: ${{ inputs.slack_channel_id }} |
104 | | - payload: | |
105 | | - { |
106 | | - "thread_ts": "${{ inputs.slack_thread_ts }}", |
107 | | - "attachments": [ |
| 53 | + jq -n \ |
| 54 | + --arg channel "${SLACK_CHANNEL_ID}" \ |
| 55 | + --arg job "$JOB_NAME" \ |
| 56 | + --arg emoji "$EMOJI" \ |
| 57 | + --arg status "$STATUS" \ |
| 58 | + --arg url "$RUN_URL" \ |
| 59 | + --arg thread "$THREAD_TS" \ |
| 60 | + --arg text "${JOB_NAME} — ${STATUS}" \ |
| 61 | + '{ |
| 62 | + channel: $channel, |
| 63 | + text: $text, |
| 64 | + blocks: [ |
| 65 | + { |
| 66 | + type: "header", |
| 67 | + text: { |
| 68 | + type: "plain_text", |
| 69 | + text: ($job + " " + $emoji), |
| 70 | + emoji: true |
| 71 | + } |
| 72 | + }, |
108 | 73 | { |
109 | | - "color": "${{ steps.test-results.outputs.all_success == 'true' && '#2E7D32' || '#C62828' }}", |
110 | | - "blocks": [ |
111 | | - { |
112 | | - "type": "header", |
113 | | - "text": { |
114 | | - "type": "plain_text", |
115 | | - "text": "${{ inputs.message_title }} ${{ steps.test-results.outputs.all_success == 'true' && ':white_check_mark:' || ':x:'}}", |
116 | | - "emoji": true |
117 | | - } |
118 | | - }, |
119 | | - { |
120 | | - "type": "divider" |
121 | | - }, |
122 | | - ${{ steps.test-results.outputs.results }} |
123 | | - ] |
| 74 | + type: "section", |
| 75 | + text: { |
| 76 | + type: "mrkdwn", |
| 77 | + text: ("Status: `" + $status + "`\n<" + $url + "|View workflow run>") |
| 78 | + } |
124 | 79 | } |
125 | 80 | ] |
126 | 81 | } |
| 82 | + | if $thread != "" then .thread_ts = $thread else . end' \ |
| 83 | + > "$PAYLOAD_FILE" |
| 84 | +
|
| 85 | + echo "file=$PAYLOAD_FILE" >> "$GITHUB_OUTPUT" |
| 86 | +
|
| 87 | + - name: Post to Slack |
| 88 | + uses: slackapi/slack-github-action@485a9d42d3a73031f12ec201c457e2162c45d02d # v2.0.0 |
| 89 | + with: |
| 90 | + errors: "true" |
| 91 | + method: chat.postMessage |
| 92 | + token: ${{ inputs.slack_bot_token }} |
| 93 | + payload-file-path: ${{ steps.slack-payload.outputs.file }} |
0 commit comments