Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 15 additions & 116 deletions .github/cursor-review/slack-notify.sh
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
#!/bin/bash

# Generic Slack notification script for GitHub Actions
# Usage: ./slack-notify.sh <status> <title> <message> [details_file] [channel]
# Slack DM notification script for GitHub Actions
# Usage: ./slack-notify.sh <status> <title> <message>
#
# Delivery modes (checked in order):
# DM mode: set SLACK_BOT_TOKEN + DM_GITHUB_USER
# Resolves {DM_GITHUB_USER}@comfy.org to a Slack user ID and sends a DM.
# Falls back silently (exit 0) if the user can't be resolved.
# Webhook mode: set SLACK_WEBHOOK_URL
# Posts to the channel the webhook is configured for.
# Delivery: set SLACK_BOT_TOKEN + DM_GITHUB_USER. Resolves
# {DM_GITHUB_USER}@comfy.org to a Slack user ID and sends a DM. No-ops
# silently (exit 0) when either is unset or the user can't be resolved;
# only a bad token/scopes (a lookup error that isn't users_not_found)
# exits non-zero.

set -e

STATUS="${1:-failure}"
TITLE="${2:-GitHub Action Notification}"
MESSAGE="${3:-No details provided}"
DETAILS_FILE="${4:-}"
CHANNEL="${5:-#prod-alerts}"
WEBHOOK_URL="${SLACK_WEBHOOK_URL}"

# Determine color based on status
if [ "$STATUS" = "success" ]; then
Expand All @@ -28,12 +24,6 @@ else
COLOR="danger"
fi

# Read additional details if file provided
ADDITIONAL_DETAILS=""
if [ -n "$DETAILS_FILE" ] && [ -f "$DETAILS_FILE" ]; then
ADDITIONAL_DETAILS=$(head -c 3000 "$DETAILS_FILE")
fi

# ── DM mode ────────────────────────────────────────────────────────────────────
if [ -n "${SLACK_BOT_TOKEN:-}" ] && [ -n "${DM_GITHUB_USER:-}" ]; then
# GitHub handle β†’ comfy.org email-prefix overrides for anyone whose GitHub
Expand Down Expand Up @@ -81,17 +71,11 @@ if [ -n "${SLACK_BOT_TOKEN:-}" ] && [ -n "${DM_GITHUB_USER:-}" ]; then

RUN_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"

DM_TEXT="$MESSAGE"
if [ -n "$ADDITIONAL_DETAILS" ]; then
DM_TEXT="${MESSAGE}
\`\`\`${ADDITIONAL_DETAILS}\`\`\`"
fi

PAYLOAD=$(jq -n \
--arg channel "$SLACK_USER_ID" \
--arg color "$COLOR" \
--arg title "$TITLE" \
--arg text "$DM_TEXT" \
--arg text "$MESSAGE" \
--arg repo "${GITHUB_REPOSITORY:-}" \
--arg run_url "$RUN_URL" \
'{
Expand Down Expand Up @@ -127,95 +111,10 @@ if [ -n "${SLACK_BOT_TOKEN:-}" ] && [ -n "${DM_GITHUB_USER:-}" ]; then
fi
fi

# ── Webhook mode ───────────────────────────────────────────────────────────────
if [ -z "$WEBHOOK_URL" ]; then
echo "❌ No delivery method configured: set SLACK_BOT_TOKEN+DM_GITHUB_USER or SLACK_WEBHOOK_URL"
exit 1
fi

# Optional top-level mention (webhook mode only).
MENTION_TEXT=""
if [ -n "${MENTION_USER_ID:-}" ]; then
MENTION_TEXT=$(jq -nr --arg u "$MENTION_USER_ID" '"<@" + $u + ">"')
fi

RUN_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"

# Build the full Slack payload via jq so every interpolated value (PR titles
# containing quotes, branches with special chars, ADDITIONAL_DETAILS captured
# from arbitrary command output) is properly JSON-escaped. The previous
# heredoc-with-${var} approach generated invalid JSON whenever a value
# contained `"` or `\`, which then tripped the `jq empty` validator below
# and silently dropped notifications.
SLACK_MESSAGE=$(jq -n \
--arg channel "$CHANNEL" \
--arg mention_text "$MENTION_TEXT" \
--arg color "$COLOR" \
--arg title "$TITLE" \
--arg message "$MESSAGE" \
--arg repository "${GITHUB_REPOSITORY:-}" \
--arg workflow "${GITHUB_WORKFLOW:-}" \
--arg run_url "$RUN_URL" \
--arg event_name "${GITHUB_EVENT_NAME:-}" \
--arg ref_name "${GITHUB_REF_NAME:-}" \
--arg actor "${GITHUB_ACTOR:-}" \
--arg details "$ADDITIONAL_DETAILS" \
--argjson ts "$(date +%s)" \
'{
channel: $channel,
attachments: (
[{
color: $color,
title: $title,
text: $message,
fields: [
{ title: "Repository", value: $repository, short: true },
{ title: "Workflow", value: $workflow, short: true },
{ title: "Run", value: ("<" + $run_url + "|View Details>"), short: true },
{ title: "Trigger", value: $event_name, short: true },
{ title: "Branch", value: $ref_name, short: true },
{ title: "Actor", value: $actor, short: true }
],
footer: "GitHub Actions",
ts: $ts
}]
+ (if ($details | length) > 0 then [{
color: $color,
title: "Details",
text: ("```" + $details + "```"),
mrkdwn_in: ["text"]
}] else [] end)
)
}
+ (if ($mention_text | length) > 0 then { text: $mention_text } else {} end)')

# Validate JSON before sending
echo "πŸ” Validating JSON payload..."
if ! echo "$SLACK_MESSAGE" | jq empty 2>/dev/null; then
echo "❌ Invalid JSON payload generated"
echo "Payload:"
echo "$SLACK_MESSAGE"
exit 1
fi

# Send to Slack and capture response
echo "πŸ“€ Sending notification to Slack..."
RESPONSE=$(curl -X POST -H 'Content-type: application/json' \
--data "$SLACK_MESSAGE" \
"$WEBHOOK_URL" \
--silent --show-error --write-out "\n%{http_code}")

# Extract HTTP status code and body
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
BODY=$(echo "$RESPONSE" | head -n-1)

# Check if Slack accepted the message
if [ "$BODY" = "ok" ] && [ "$HTTP_CODE" = "200" ]; then
echo "βœ… Slack notification sent successfully"
exit 0
else
echo "❌ Slack notification failed"
echo "HTTP Code: $HTTP_CODE"
echo "Response: $BODY"
exit 1
fi
# ── No DM target ───────────────────────────────────────────────────────────────
# SLACK_BOT_TOKEN and/or DM_GITHUB_USER is unset. That is a designed-for case,
# not an error: a bot-authored PR whose triggerer resolves to empty, or a caller
# that never configured the token. These notifications are best-effort, so
# no-op green (matching this directory's README) rather than failing the step.
echo "Slack DM not configured (needs SLACK_BOT_TOKEN + DM_GITHUB_USER) β€” skipping"
exit 0
Loading