Created
November 7, 2025 08:15
-
-
Save lexisother/6aa5cf62c87645d5a91dec9127e5e95e to your computer and use it in GitHub Desktop.
Build Slack messages using shell scripts
This file contains hidden or 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
| #!/usr/bin/env bash | |
| # Constants | |
| readonly NETWORK_TIMEOUT=10 | |
| # Utils {{{ | |
| ansi_reset="$(tput sgr0 || true)" | |
| ansi_red="$(tput setaf 1 || true)" | |
| log_error() { echo >&2 "${ansi_red}[ERROR]${ansi_reset}" "$@"; } | |
| # Use the log_error function to indicate where an error occurs | |
| trap 'log_error line $LINENO' ERR | |
| command_exists() { command -v "$1" &>/dev/null; } | |
| curl() { | |
| command curl --location --fail --max-time "$NETWORK_TIMEOUT" "$@" | |
| } | |
| function post_to_slack() { | |
| curl -X POST -H "Content-Type: application/json" --data "$1" "$SLACK_WEBHOOK" | |
| } | |
| # JSON-specific | |
| function build_json_array() { | |
| local json="[]" | |
| while (($# > 0)); do | |
| if [[ "$1" == "" ]]; then | |
| shift | |
| continue | |
| fi | |
| json=$(jq -c --argjson item "$1" '. += [$item]' <<<"$json") | |
| shift | |
| done | |
| echo "$json" | |
| } | |
| # }}} | |
| # Preliminary checks {{{ | |
| if [ -z "$SLACK_WEBHOOK" ]; then | |
| log_error "Variable \$SLACK_WEBHOOK wasn't found. Bailing!" | |
| exit 1 | |
| fi | |
| if ! command_exists jq; then | |
| log_error "jq isn't installed. Bailing!" | |
| exit 1 | |
| fi | |
| # }}} | |
| function create_divider() { | |
| jq -n '{ type: "divider" }' | |
| } | |
| function create_text_object() { | |
| local text="$1" | |
| local type="${2:-mrkdwn}" | |
| jq -n \ | |
| --arg text "$text" \ | |
| --arg type "$type" \ | |
| '{ | |
| type: $type, | |
| text: $text | |
| }' | |
| } | |
| function create_header() { | |
| local text="$1" | |
| local text_obj | |
| text_obj=$(create_text_object "$text" "plain_text") | |
| jq -n \ | |
| --argjson text "$text_obj" \ | |
| '{ | |
| type: "header", | |
| text: $text | |
| }' | |
| } | |
| function create_context() { | |
| local text="$1" | |
| local type="${2:-mrkdwn}" | |
| local text_obj | |
| text_obj=$(create_text_object "$text" "$type") | |
| # this supports multiple elements (which will be placed horizontally next to | |
| # eachother or under eachother depending on screen size) but i only really | |
| # need one. adjust if required | |
| elements=$(build_json_array "$text_obj") | |
| jq -n \ | |
| --argjson elements "$elements" \ | |
| '{ | |
| type: "context", | |
| elements: $elements | |
| }' | |
| } | |
| function create_section() { | |
| local text="${1:-null}" | |
| local text_type="${2:-mrkdwn}" | |
| local fields="${3:-null}" | |
| local accessory="${4:-null}" | |
| local text_obj | |
| text_obj=null | |
| if [[ "$text" != null ]]; then | |
| text_obj=$(create_text_object "$text" "$text_type") | |
| fi | |
| jq -n \ | |
| --arg textval "$text" \ | |
| --argjson text "$text_obj" \ | |
| --argjson fields "$fields" \ | |
| --argjson accessory "$accessory" \ | |
| '{ | |
| type: "section", | |
| } | |
| + if $text then { | |
| text: $text | |
| } else {} end | |
| + if $fields then { | |
| fields: $fields | |
| } else {} end | |
| + if $accessory then { | |
| accessory: $accessory | |
| } else {} end' | |
| } | |
| function create_action() { | |
| local elements="$1" | |
| jq -n \ | |
| --argjson elements "$elements" \ | |
| '{ | |
| type: "actions", | |
| elements: $elements | |
| }' | |
| } | |
| function create_button() { | |
| local text="$1" | |
| local style="${2:-}" | |
| local url="${3:-}" | |
| local text_obj | |
| text_obj=$(create_text_object "$text" "plain_text") | |
| jq -n \ | |
| --arg style "$style" \ | |
| --arg url "$url" \ | |
| --argjson text "$text_obj" \ | |
| '{ | |
| type: "button", | |
| text: $text, | |
| } | |
| + if $style != "" then { | |
| style: $style | |
| } else {} end | |
| + if $url != "" then { | |
| url: $url | |
| } else {} end' | |
| } | |
| function create_slack_payload() { | |
| local sections_json="$1" | |
| jq -n \ | |
| --argjson sections "$sections_json" \ | |
| '{ | |
| blocks: $sections | |
| }' | |
| } | |
| # usage: | |
| divider=$(create_divider) | |
| header=$(create_header "I am a header") | |
| ctx_line_1=$(create_context "Some context below header") | |
| ctx_line_2=$(create_context "Some more context") | |
| line_1=$(create_section "This is a paragraph") | |
| button_1=$(create_button "Primary Button" "primary" "https://google.com") | |
| button_2=$(create_button "Secondary Button" "" "https://google.com") | |
| footer_actions=$(create_action "$( | |
| build_json_array \ | |
| "$sandbox_button" \ | |
| "$pipeline_button" | |
| )") | |
| elements=$( | |
| build_json_array \ | |
| "$header" \ | |
| "$ctx_line_1" \ | |
| "$ctx_line_2" \ | |
| "$divider" \ | |
| "$line_1" \ | |
| "$footer_actions" | |
| ) | |
| # it's also possible to add elements conditionally: | |
| elements=$( | |
| build_json_array \ | |
| "$header" \ | |
| "$([ "$SOME_VAR" == "some value" ] && echo "$ctx_line_1" || echo "")" | |
| ) | |
| payload=$(create_slack_payload "$elements") | |
| if [[ "$DEBUG" == 1 ]]; then | |
| echo "$payload" | jq . | |
| else | |
| post_to_slack "$payload" | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment