11name : PR Comment Slack Notification
22
33on :
4+ pull_request :
5+ types : [opened, reopened]
46 issue_comment :
57 types : [created]
68 pull_request_review_comment :
1012 notify-slack :
1113 # For issue_comment, only run if the comment is on a pull request
1214 if : >
15+ github.event_name == 'pull_request' ||
1316 github.event_name == 'pull_request_review_comment' ||
1417 (github.event_name == 'issue_comment' && github.event.issue.pull_request)
1518 runs-on : ubuntu-latest
@@ -24,14 +27,27 @@ jobs:
2427 COMMENTER : ${{ github.event.comment.user.login }}
2528 COMMENTER_AVATAR : ${{ github.event.comment.user.avatar_url }}
2629 REPO : ${{ github.repository }}
30+ # pull_request event
31+ PR_URL_PR : ${{ github.event.pull_request.html_url }}
32+ PR_TITLE_PR : ${{ github.event.pull_request.title }}
33+ PR_NUMBER_PR : ${{ github.event.pull_request.number }}
34+ PR_AUTHOR_PR : ${{ github.event.pull_request.user.login }}
35+ PR_AUTHOR_AVATAR_PR : ${{ github.event.pull_request.user.avatar_url }}
36+ # pull_request_review_comment event
2737 PR_URL_REVIEW : ${{ github.event.pull_request.html_url }}
2838 PR_TITLE_REVIEW : ${{ github.event.pull_request.title }}
2939 PR_NUMBER_REVIEW : ${{ github.event.pull_request.number }}
40+ # issue_comment event
3041 PR_URL_ISSUE : ${{ github.event.issue.pull_request.html_url }}
3142 PR_TITLE_ISSUE : ${{ github.event.issue.title }}
3243 PR_NUMBER_ISSUE : ${{ github.event.issue.number }}
3344 run : |
34- if [ "$EVENT_NAME" = "pull_request_review_comment" ]; then
45+ # Determine PR details based on event type
46+ if [ "$EVENT_NAME" = "pull_request" ]; then
47+ PR_URL="$PR_URL_PR"
48+ PR_TITLE="$PR_TITLE_PR"
49+ PR_NUMBER="$PR_NUMBER_PR"
50+ elif [ "$EVENT_NAME" = "pull_request_review_comment" ]; then
3551 PR_URL="$PR_URL_REVIEW"
3652 PR_TITLE="$PR_TITLE_REVIEW"
3753 PR_NUMBER="$PR_NUMBER_REVIEW"
@@ -41,65 +57,117 @@ jobs:
4157 PR_NUMBER="$PR_NUMBER_ISSUE"
4258 fi
4359
44- # Extract repo short name from "owner/repo"
4560 REPO_SHORT="${REPO#*/}"
4661
47- # Truncate comment body to 200 chars and add ellipsis if needed
48- if [ ${#COMMENT_BODY} -gt 200 ]; then
49- TRUNCATED_BODY="${COMMENT_BODY:0:200}..."
50- else
51- TRUNCATED_BODY="$COMMENT_BODY"
52- fi
53-
5462 # Ensure bot has joined the channel
5563 curl -s -X POST "https://slack.com/api/conversations.join" \
5664 -H "Authorization: Bearer $SLACK_BOT_TOKEN" \
5765 -H "Content-Type: application/json" \
58- -d "{\"channel\": \"$SLACK_CHANNEL_ID\"}"
66+ -d "{\"channel\": \"$SLACK_CHANNEL_ID\"}" > /dev/null
67+
68+ # Search channel history for an existing thread about this PR
69+ find_thread_ts() {
70+ HISTORY=$(curl -s "https://slack.com/api/conversations.history?channel=$SLACK_CHANNEL_ID&limit=200" \
71+ -H "Authorization: Bearer $SLACK_BOT_TOKEN")
5972
60- # Build JSON payload to match GitHub's native Slack notification style
61- PAYLOAD=$(jq -n \
62- --arg channel "$SLACK_CHANNEL_ID" \
63- --arg repo_short "$REPO_SHORT" \
64- --arg pr_url "$PR_URL" \
65- --arg pr_number "$PR_NUMBER" \
66- --arg pr_title "$PR_TITLE" \
67- --arg commenter "$COMMENTER" \
68- --arg comment_body "$TRUNCATED_BODY" \
69- --arg comment_url "$COMMENT_URL" \
70- --arg avatar "$COMMENTER_AVATAR" \
71- '{
72- "channel": $channel,
73- "username": $commenter,
74- "icon_url": $avatar,
75- "text": ($commenter + " commented on [" + $repo_short + "#" + $pr_number + "] <" + $pr_url + "|" + $pr_title + ">"),
76- "unfurl_links": false,
77- "blocks": [
78- {
79- "type": "section",
80- "text": {
81- "type": "mrkdwn",
82- "text": ($commenter + " commented on [" + $repo_short + "#" + $pr_number + "] <" + $pr_url + "|" + $pr_title + ">")
73+ # Look for a message containing this PR's URL
74+ THREAD_TS=$(echo "$HISTORY" | jq -r --arg pr_url "$PR_URL" '
75+ .messages[]
76+ | select(.text != null and (.text | contains($pr_url)))
77+ | .ts' | tail -1)
78+
79+ if [ -n "$THREAD_TS" ] && [ "$THREAD_TS" != "null" ]; then
80+ echo "$THREAD_TS"
81+ fi
82+ }
83+
84+ if [ "$EVENT_NAME" = "pull_request" ]; then
85+ # PR opened/reopened — post a new top-level thread-starting message
86+ PAYLOAD=$(jq -n \
87+ --arg channel "$SLACK_CHANNEL_ID" \
88+ --arg repo_short "$REPO_SHORT" \
89+ --arg pr_url "$PR_URL" \
90+ --arg pr_number "$PR_NUMBER" \
91+ --arg pr_title "$PR_TITLE" \
92+ --arg author "$PR_AUTHOR_PR" \
93+ --arg avatar "$PR_AUTHOR_AVATAR_PR" \
94+ '{
95+ "channel": $channel,
96+ "username": $author,
97+ "icon_url": $avatar,
98+ "text": ("New pull request [" + $repo_short + "#" + $pr_number + "] <" + $pr_url + "|" + $pr_title + "> by " + $author),
99+ "unfurl_links": false,
100+ "blocks": [
101+ {
102+ "type": "section",
103+ "text": {
104+ "type": "mrkdwn",
105+ "text": ("New pull request [" + $repo_short + "#" + $pr_number + "] <" + $pr_url + "|" + $pr_title + "> by " + $author)
106+ }
83107 }
84- },
85- {
86- "type": "rich_text",
87- "elements": [
88- {
89- "type": "rich_text_quote",
90- "elements": [
91- {
92- "type": "text",
93- "text": $comment_body
94- }
95- ]
108+ ]
109+ }')
110+
111+ curl -s -X POST "https://slack.com/api/chat.postMessage" \
112+ -H "Authorization: Bearer $SLACK_BOT_TOKEN" \
113+ -H "Content-Type: application/json" \
114+ -d "$PAYLOAD"
115+ else
116+ # Comment event — try to find existing thread, then reply in it
117+ THREAD_TS=$(find_thread_ts)
118+
119+ # Truncate comment body to 200 chars
120+ if [ ${#COMMENT_BODY} -gt 200 ]; then
121+ TRUNCATED_BODY="${COMMENT_BODY:0:200}..."
122+ else
123+ TRUNCATED_BODY="$COMMENT_BODY"
124+ fi
125+
126+ PAYLOAD=$(jq -n \
127+ --arg channel "$SLACK_CHANNEL_ID" \
128+ --arg repo_short "$REPO_SHORT" \
129+ --arg pr_url "$PR_URL" \
130+ --arg pr_number "$PR_NUMBER" \
131+ --arg pr_title "$PR_TITLE" \
132+ --arg commenter "$COMMENTER" \
133+ --arg comment_body "$TRUNCATED_BODY" \
134+ --arg comment_url "$COMMENT_URL" \
135+ --arg avatar "$COMMENTER_AVATAR" \
136+ --arg thread_ts "$THREAD_TS" \
137+ '{
138+ "channel": $channel,
139+ "username": $commenter,
140+ "icon_url": $avatar,
141+ "text": ($commenter + " commented on [" + $repo_short + "#" + $pr_number + "] <" + $pr_url + "|" + $pr_title + ">"),
142+ "unfurl_links": false,
143+ "blocks": [
144+ {
145+ "type": "section",
146+ "text": {
147+ "type": "mrkdwn",
148+ "text": ($commenter + " commented on [" + $repo_short + "#" + $pr_number + "] <" + $pr_url + "|" + $pr_title + ">")
96149 }
97- ]
98- }
99- ]
100- }')
150+ },
151+ {
152+ "type": "rich_text",
153+ "elements": [
154+ {
155+ "type": "rich_text_quote",
156+ "elements": [
157+ {
158+ "type": "text",
159+ "text": $comment_body
160+ }
161+ ]
162+ }
163+ ]
164+ }
165+ ]
166+ }
167+ | if $thread_ts != "" then .thread_ts = $thread_ts else . end')
101168
102- curl -X POST "https://slack.com/api/chat.postMessage" \
103- -H "Authorization: Bearer $SLACK_BOT_TOKEN" \
104- -H "Content-Type: application/json" \
105- -d "$PAYLOAD"
169+ curl -s -X POST "https://slack.com/api/chat.postMessage" \
170+ -H "Authorization: Bearer $SLACK_BOT_TOKEN" \
171+ -H "Content-Type: application/json" \
172+ -d "$PAYLOAD"
173+ fi
0 commit comments