-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
🚨 v2: Create v2.0.0 of howl (#15)
**Breaking change**: The previous input parameter `SLACK_TOKEN` and `CHANNEL` cannot be used anymore. Use `SLACK_WEBHOOK_URL` and `SLACK_CHANNEL` instead. `howl` can now be used as GitHub Action with `with` inputs: howl-on-failure: steps: - uses: foxygoat/howl@v2 with: slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }} slack-channel: C0000000000 # optional; channel ID slack-text: <!here> # optional; text or @-mention discord-webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }} discord-text: @here # optional; text or @-mention Discord integration has been added. GitHub Releases are now created on every merge to `master` distributing the `howl` script to be used with hermit. This merges the following commits: * howl: Rename slack-notify.sh to howl * bash: Convert local variable names to lowercase * howl: Use SLACK_WEBHOOK_URL as input * howl: Rework Slack message format * howl: Add discord integration * action: Adapt howl for GitHub actions input * release: Upload howl script on release * docs: Add v2.0.0 release notes .github/workflows/ci-cd.yaml | 10 +-- Makefile | 8 +- README.md | 122 ++++++++++++++++-------------- action.yml | 17 ++++- docs/release-notes/v2.0.0.md | 24 ++++++ howl | 142 +++++++++++++++++++++++++++++++++++ slack-notify.sh | 90 ---------------------- 7 files changed, 257 insertions(+), 156 deletions(-) Pull-Request: #15
- Loading branch information
Showing
7 changed files
with
257 additions
and
156 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
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
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 |
---|---|---|
@@ -1,81 +1,93 @@ | ||
<a href="https://commons.wikimedia.org/wiki/File:DSC09108_-_Guyanan_Red_Howler_Monkey_(36384553204).jpg" title="Howler Monkey on Wikipedia"> | ||
<img align="right" width="100" height="150" src="howler.jpeg" alt="Howler monkey"> | ||
</a> | ||
|
||
# Howl | ||
|
||
Because somebody should yell at you when your `master` build breaks. | ||
|
||
Howl is a GitHub Action. It writes a custom Slack message with an | ||
optional `@here` or `@project-owners` to your preferred Slack channel. | ||
`howl` is a tool that sends messages to Slack or Discord when your default | ||
branch build fails, typically on `main` or `master`. It is designed to be | ||
triggered on your CI (continuous integration) system when a failure occurs on | ||
your default branch. You can use it as a GitHub Action or as a standalone | ||
program, which can be installed with [Hermit]. | ||
|
||
[Hermit]: https://cashapp.github.io/hermit | ||
|
||
## Slack setup | ||
|
||
Set up a [GitHub secret] called `SLACK_WEBHOOK_URL` with your | ||
[Slack Webhook] URL, for example | ||
|
||
https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX | ||
|
||
[Slack Webhook]: https://api.slack.com/messaging/webhooks | ||
[GitHub secret]: https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions | ||
|
||
### Optional inputs | ||
|
||
To use a channel other than the default channel set up in the Slack App bound | ||
to the webhook, set the `SLACK_CHANNEL` environment variable, for example | ||
|
||
export SLACK_CHANNEL=C0000000000 | ||
|
||
For a more customized message or @-mentions, set the `SLACK_TEXT` environment | ||
variable, for example | ||
|
||
export SLACK_TEXT="<!here> 🚒" | ||
|
||
## Discord setup | ||
|
||
<div style="text-align:center;width:100%"> | ||
<img src="howler.jpeg" alt="Howler Monkey"/> | ||
<br/> | ||
<sub>Howler Monkey - | ||
<a href="https://commons.wikimedia.org/wiki/File:DSC09108_-_Guyanan_Red_Howler_Monkey_(36384553204).jpg"> | ||
Wikimedia, CC BY-SA 2.0 | ||
</a> | ||
</sub> | ||
</div> | ||
Set up a [GitHub secret] called `DISCORD_WEBHOOK_URL` with your | ||
[Discord Webhook] URL for the target discord channel, for example | ||
|
||
## Set up Slack token | ||
https://discord.com/api/webhooks/1000000000000000000/XXXXXXXX-xxxxxxxxxxxxxxxxx | ||
|
||
Set up a repository or organisation secrets with your [Incoming Slack | ||
Webhook] token. Use, for instance, `SLACK_TOKEN`. The content should | ||
look similar to | ||
[Discord Webhook]: https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks | ||
[GitHub secret]: https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions | ||
|
||
T01A*******/B0259*****/GcXTiEux******************* | ||
### Optional inputs | ||
|
||
Taken from the Slack provided Incoming Webhook URL: | ||
For a more customized message or @-mentions, set the `DISCORD_TEXT` environment | ||
variable, for example | ||
|
||
https://hooks.slack.com/services/T01A*******/B0259*****/GcXTiEux******************* | ||
export DISCORD_TEXT="@here 🚒" | ||
|
||
[Incoming Slack Webhook]: https://slack.com/intl/en-au/help/articles/115005265063-Incoming-webhooks-for-Slack | ||
## Local Testing | ||
|
||
## Use with GitHub Action Workflow | ||
You can test the integration locally with | ||
|
||
export SLACK_WEBHOOK_URL=https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX | ||
export DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/1000000000000000000/XXXXXXXX-xxxxxxxxxxxxxxxxx' | ||
howl | ||
|
||
## GitHub Action usage | ||
|
||
Use the `foxygoat/howl@v2` in you GitHub Actions Workflow that runs on the | ||
default branch, for example: | ||
|
||
```yaml | ||
name: ci | ||
on: | ||
push: | ||
branches: [master] | ||
pull_request: | ||
branches: [main] | ||
|
||
jobs: | ||
ci: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
run: make | ||
howl-on-failure: | ||
- uses: actions/checkout@v4 | ||
run: make ci | ||
howl-on-fail: | ||
runs-on: ubuntu-latest | ||
needs: [ci] | ||
if: always && github.event_name == 'push' && needs.ci.result == 'failure' | ||
steps: | ||
- uses: foxygoat/howl@v1 | ||
env: | ||
SLACK_TOKEN: ${{ secrets.SLACK_TOKEN }} | ||
SLACK_TEXT: <!here> # optional; text or @-mention project owners by slack member ID, e.g. <@U0LAN0Z89> | ||
#CHANNEL: D01J5K3RLQJ # optional; use if different from slack webhook setup, take from channel URL | ||
``` | ||
|
||
## Use with external CI system | ||
|
||
```yaml | ||
name: slack-notify | ||
on: | ||
# choose one of status, check_run, check_suite | ||
status: | ||
check_run: | ||
types: [completed] | ||
check_suite: | ||
types: [completed] | ||
jobs: | ||
slack-notify: | ||
runs-on: ubuntu-latest | ||
if: always() && contains(join(needs.*.result, ','), 'failure') | ||
steps: | ||
- if: ${{ contains(github.event.branches.*.name, 'master') && (github.event.state == 'failure' || github.event.state == 'error')}} | ||
uses: foxygoat/howl@v1 | ||
env: | ||
SLACK_TOKEN: ${{ secrets.SLACK_TOKEN }} | ||
BUILD_URL: ${{ github.event.target_url }} | ||
#SLACK_TEXT: <!here> # optional; text or @-mention project owners by slack member ID, e.g. <@U0LAN0Z89> | ||
#CHANNEL: D01J5K3RLQJ # optional; use if different from slack webhook setup, take from channel URL | ||
- uses: foxygoat/howl@v2 | ||
with: | ||
slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }} | ||
slack-channel: C0000000000 # optional; channel ID | ||
slack-text: <!here> # optional; text or @-mention | ||
discord-webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }} | ||
discord-text: @here # optional; text or @-mention | ||
``` |
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 |
---|---|---|
@@ -1,7 +1,18 @@ | ||
name: 'Slack Howler' | ||
name: 'Howl' | ||
description: 'Send slack message on failed build' | ||
inputs: | ||
slack-webhook-url: | ||
description: 'Slack Webhook URL, e.g. https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX' | ||
slack-text: | ||
description: 'Prepend text to Slack message, e.g.: <!here>' | ||
slack-channel: | ||
description: 'Channel to send Slack message to, e.g.: C0000000000' | ||
discord-webhook-url: | ||
description: 'Discord Webhook URL, e.g. https://discord.com/api/webhooks/1000000000000000000/XXXXXXXX-xxxxxxxxxxxxxxxxx' | ||
discord-text: | ||
description: 'Prepend text to Discord message, e.g.: @here' | ||
runs: | ||
using: "composite" | ||
using: 'composite' | ||
steps: | ||
- run: ${{ github.action_path }}/slack-notify.sh | ||
- run: ${{ github.action_path }}/howl | ||
shell: bash |
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,24 @@ | ||
## API Changes and Discord Integration | ||
|
||
**Breaking change**: the previous input parameter `SLACK_TOKEN` and `CHANNEL` | ||
cannot be used anymore. Use `SLACK_WEBHOOK_URL` and `SLACK_CHANNEL` | ||
instead. | ||
|
||
`howl` can now be used as GitHub Action with `with` inputs: | ||
|
||
```yaml | ||
howl-on-failure: | ||
steps: | ||
- uses: foxygoat/howl@v2 | ||
with: | ||
slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }} | ||
slack-channel: C0000000000 # optional; channel ID | ||
slack-text: <!here> # optional; text or @-mention | ||
discord-webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }} | ||
discord-text: @here # optional; text or @-mention | ||
``` | ||
Discord integration has been added. | ||
GitHub Releases are now created on every merge to `master` distributing the | ||
`howl` script to be used with hermit. |
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,142 @@ | ||
#!/usr/bin/env bash | ||
|
||
set -euo pipefail | ||
trap 'echo failed: line $LINENO: $BASH_COMMAND' ERR | ||
|
||
# GitHub actions inputs starting with `INPUT_` take precedence over | ||
# un-prefixed environment variables. GitHub actions inputs are usually | ||
# written with kebab case which cannot be used in sh/bash so we're replacing | ||
# `-` with `_`. | ||
input() { | ||
upper="${1^^}" | ||
printenv "INPUT_${upper}" || printenv "${upper//-/_}" || echo | ||
} | ||
|
||
SLACK_WEBHOOK_URL=$(input slack-webhook-url) | ||
SLACK_TEXT=$(input slack-text) | ||
SLACK_CHANNEL=$(input slack-channel) | ||
DISCORD_WEBHOOK_URL=$(input discord-webhook-url) | ||
DISCORD_TEXT=$(input discord-text) | ||
|
||
if [[ -z "${SLACK_WEBHOOK_URL-}" && -z "${DISCORD_WEBHOOK_URL-}" ]]; then | ||
echo "At least one of SLACK_WEBHOOK_URL or DISCORD_WEBHOOK_URL must be set" | ||
exit 1 | ||
fi | ||
|
||
: "${GITHUB_SERVER_URL:=https://github.com}" | ||
: "${GITHUB_API_URL:=https://api.github.com}" | ||
: "${GITHUB_SHA:=$(git rev-parse HEAD)}" | ||
: "${PICTURE_BASE_URL:=https://github.com/foxygoat/howl/raw/master}" | ||
|
||
if [[ -z "${GITHUB_REPOSITORY-}" ]]; then | ||
repo_url=$(git remote get-url origin) | ||
GITHUB_REPOSITORY="${repo_url#"${GITHUB_SERVER_URL}"/}" | ||
else | ||
repo_url="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}" | ||
fi | ||
repo=${GITHUB_REPOSITORY#*/} | ||
|
||
: "${BUILD_URL:=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions${GITHUB_RUN_ID:+/runs/${GITHUB_RUN_ID}}}" | ||
: "${GITHUB_REF:=$(git symbolic-ref HEAD)}" | ||
branch=${GITHUB_REF#refs/heads/} | ||
branch_url="${repo_url}/tree/${branch}" | ||
|
||
# prop extracts property from JSON object. | ||
# prop '{"name": "Tricia", "age": 42}' age | ||
# 42 | ||
prop() { | ||
jq -r ".$2" <<<"$1" | ||
} | ||
|
||
curl_headers=(-H "Accept: application/vnd.github.groot-preview+json") | ||
if [[ -n "${GITHUB_TOKEN-}" ]]; then | ||
curl_headers+=(-H "Authorization: token ${GITHUB_TOKEN}") | ||
fi | ||
|
||
commit_url="${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/commits/${GITHUB_SHA}" | ||
pr=$(curl -fsSL "${curl_headers[@]}" "${commit_url}/pulls" | | ||
jq '.[0] | {url: .html_url, number, title, author: .user.login}' || echo '{}') | ||
if [[ $(prop "${pr}" number) != null ]]; then | ||
pr="${GITHUB_REPOSITORY}#$(prop "${pr}" number)" | ||
pr_url=$(prop "${pr}" url) | ||
pr_title=$(prop "${pr}" title) | ||
pr_author=$(prop "${pr}" author) | ||
else | ||
commit=$(curl -fsSL "${curl_headers[@]}" "${commit_url}" | | ||
jq '{url: .html_url, message: .commit.message, author: .author.login}' || echo '{}') | ||
pr="Commit \`${GITHUB_SHA::7}\`" | ||
if [[ $(prop "${commit}" url) != null ]]; then | ||
pr_url=$(prop "${commit}" url) | ||
pr_title=$(prop "${commit}" message | head -n 1) | ||
pr_author=$(prop "${commit}" author) | ||
else | ||
pr_url="${repo_url}" | ||
pr_title=$(git show -s --pretty=format:%s) | ||
pr_author=$(git show -s --pretty=format:%an) | ||
fi | ||
fi | ||
|
||
if [[ -n "${SLACK_WEBHOOK_URL-}" ]]; then | ||
channel="${SLACK_CHANNEL:+"\"channel\": \"${SLACK_CHANNEL}\","}" | ||
SLACK_TEXT="${SLACK_TEXT:+"\"text\": \"${SLACK_TEXT}\","}" | ||
|
||
curl -fsSL -d @- "${SLACK_WEBHOOK_URL}" <<EOF | ||
{ | ||
"icon_url": "${PICTURE_BASE_URL}/icon.png", | ||
${channel} | ||
"username": "${SLACK_USERNAME:-Howl}", | ||
${SLACK_TEXT} | ||
"attachments": [ | ||
{ | ||
"title": "🚨 Build Failure 🚨", | ||
"title_link": "${BUILD_URL}", | ||
"color": "danger", | ||
"fallback": "Build failure on ${branch}", | ||
"fields": [ | ||
{ | ||
"title": "PR", | ||
"value": "<${pr_url}|${pr}>\n${pr_title} \`@${pr_author}\`" | ||
}, | ||
{ | ||
"title": "Branch", | ||
"value": "<${branch_url}|${repo}:${branch}>" | ||
} | ||
], | ||
"footer": "<${repo_url}|${GITHUB_REPOSITORY}>", | ||
"footer_icon": "${PICTURE_BASE_URL}/footer.png" | ||
} | ||
] | ||
} | ||
EOF | ||
fi | ||
|
||
if [[ -n "${DISCORD_WEBHOOK_URL-}" ]]; then | ||
curl -fsSL -H "Content-Type:application/json" -d @- "${DISCORD_WEBHOOK_URL}" <<EOF | ||
{ | ||
"username": "Howl", | ||
"avatar_url": "${PICTURE_BASE_URL}/icon.png", | ||
"content": "${DISCORD_TEXT:-}", | ||
"embeds": [ | ||
{ | ||
"title": "🚨 Build Failure 🚨", | ||
"url": "${BUILD_URL}", | ||
"color": 16711680, | ||
"fields": [ | ||
{ | ||
"name": "PR", | ||
"value": "[${pr}](<${pr_url}>)\n${pr_title} \`@${pr_author}\`" | ||
}, | ||
{ | ||
"name": "Branch", | ||
"value": "[${repo}:${branch}](${branch_url})" | ||
} | ||
], | ||
"footer": { | ||
"text": "${GITHUB_REPOSITORY}", | ||
"icon_url": "${PICTURE_BASE_URL}/footer.png" | ||
} | ||
} | ||
] | ||
} | ||
EOF | ||
fi |
Oops, something went wrong.