Skip to content

Commit 10ce0f9

Browse files
masami-agentMasami
andauthored
feat: add Discord notification workflow for PR and Issue events (#106)
* feat: add Discord notification workflow for PR and Issue events * fix(ci): prevent script injection in notify-discord workflow Move all ${{ }} expressions to env: block to prevent script injection via user-controlled inputs (PR/issue titles). Use jq for safe JSON construction to handle special characters in titles. * fix(ci): address review nits — add reopened trigger, webhook guard, curl error check * fix(ci): differentiate reopened action types and sync docs - Use EVENT_ACTION to produce pr_reopened/issue_reopened (not just pr_opened) - Update docs/github-webhook-integration.md to match workflow changes: - issues trigger now includes reopened - Workflow example updated with secure env: pattern - Document supported event_type values --------- Co-authored-by: Masami <masami@agent> Co-authored-by: Masami <masami-agent@users.noreply.github.com>
1 parent ed50442 commit 10ce0f9

2 files changed

Lines changed: 86 additions & 16 deletions

File tree

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
name: Notify Discord
2+
3+
on:
4+
pull_request:
5+
types: [opened, reopened]
6+
issues:
7+
types: [opened, reopened]
8+
9+
jobs:
10+
notify:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Send to Discord
14+
env:
15+
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
16+
EVENT_NAME: ${{ github.event_name }}
17+
EVENT_ACTION: ${{ github.event.action }}
18+
PR_TITLE: ${{ github.event.pull_request.title }}
19+
PR_URL: ${{ github.event.pull_request.html_url }}
20+
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
21+
PR_NUMBER: ${{ github.event.pull_request.number }}
22+
ISSUE_TITLE: ${{ github.event.issue.title }}
23+
ISSUE_URL: ${{ github.event.issue.html_url }}
24+
ISSUE_AUTHOR: ${{ github.event.issue.user.login }}
25+
ISSUE_NUMBER: ${{ github.event.issue.number }}
26+
REPO: ${{ github.repository }}
27+
run: |
28+
[ -z "$DISCORD_WEBHOOK_URL" ] && { echo "::warning::DISCORD_WEBHOOK_URL not set"; exit 0; }
29+
30+
if [ "$EVENT_NAME" = "pull_request" ]; then
31+
TITLE="$PR_TITLE"
32+
URL="$PR_URL"
33+
AUTHOR="$PR_AUTHOR"
34+
NUM="$PR_NUMBER"
35+
TYPE="pr_${EVENT_ACTION}"
36+
LABEL="PR #${NUM}"
37+
else
38+
TITLE="$ISSUE_TITLE"
39+
URL="$ISSUE_URL"
40+
AUTHOR="$ISSUE_AUTHOR"
41+
NUM="$ISSUE_NUMBER"
42+
TYPE="issue_${EVENT_ACTION}"
43+
LABEL="Issue #${NUM}"
44+
fi
45+
46+
PAYLOAD=$(jq -n \
47+
--arg content "[GH-EVENT] repo:${REPO} action:${TYPE} ${LABEL}
48+
**${TITLE}**
49+
by ${AUTHOR}
50+
${URL}" \
51+
'{"content": $content}')
52+
curl --fail-with-body -s -H "Content-Type: application/json" -d "$PAYLOAD" "$DISCORD_WEBHOOK_URL"

docs/github-webhook-integration.md

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ on:
4646
pull_request:
4747
types: [opened, reopened]
4848
issues:
49-
types: [opened]
49+
types: [opened, reopened]
5050

5151
jobs:
5252
notify:
@@ -55,27 +55,43 @@ jobs:
5555
- name: Send to Discord
5656
env:
5757
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
58+
EVENT_NAME: ${{ github.event_name }}
59+
EVENT_ACTION: ${{ github.event.action }}
60+
PR_TITLE: ${{ github.event.pull_request.title }}
61+
PR_URL: ${{ github.event.pull_request.html_url }}
62+
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
63+
PR_NUMBER: ${{ github.event.pull_request.number }}
64+
ISSUE_TITLE: ${{ github.event.issue.title }}
65+
ISSUE_URL: ${{ github.event.issue.html_url }}
66+
ISSUE_AUTHOR: ${{ github.event.issue.user.login }}
67+
ISSUE_NUMBER: ${{ github.event.issue.number }}
68+
REPO: ${{ github.repository }}
5869
run: |
59-
if [ "${{ github.event_name }}" = "pull_request" ]; then
60-
TITLE="${{ github.event.pull_request.title }}"
61-
URL="${{ github.event.pull_request.html_url }}"
62-
AUTHOR="${{ github.event.pull_request.user.login }}"
63-
NUM="${{ github.event.pull_request.number }}"
64-
TYPE="pr_opened"
70+
[ -z "$DISCORD_WEBHOOK_URL" ] && { echo "::warning::DISCORD_WEBHOOK_URL not set"; exit 0; }
71+
72+
if [ "$EVENT_NAME" = "pull_request" ]; then
73+
TITLE="$PR_TITLE"
74+
URL="$PR_URL"
75+
AUTHOR="$PR_AUTHOR"
76+
NUM="$PR_NUMBER"
77+
TYPE="pr_${EVENT_ACTION}"
6578
LABEL="PR #${NUM}"
6679
else
67-
TITLE="${{ github.event.issue.title }}"
68-
URL="${{ github.event.issue.html_url }}"
69-
AUTHOR="${{ github.event.issue.user.login }}"
70-
NUM="${{ github.event.issue.number }}"
71-
TYPE="issue_opened"
80+
TITLE="$ISSUE_TITLE"
81+
URL="$ISSUE_URL"
82+
AUTHOR="$ISSUE_AUTHOR"
83+
NUM="$ISSUE_NUMBER"
84+
TYPE="issue_${EVENT_ACTION}"
7285
LABEL="Issue #${NUM}"
7386
fi
7487
75-
MSG="[GH-EVENT] repo:${{ github.repository }} action:${TYPE} ${LABEL}"
76-
MSG="${MSG}\n**${TITLE}**\nby ${AUTHOR}\n${URL}"
77-
PAYLOAD=$(printf '%s' "$MSG" | jq -Rs '{content: .}')
78-
curl -s -H "Content-Type: application/json" -d "$PAYLOAD" "$DISCORD_WEBHOOK_URL"
88+
PAYLOAD=$(jq -n \
89+
--arg content "[GH-EVENT] repo:${REPO} action:${TYPE} ${LABEL}
90+
**${TITLE}**
91+
by ${AUTHOR}
92+
${URL}" \
93+
'{"content": $content}')
94+
curl --fail-with-body -s -H "Content-Type: application/json" -d "$PAYLOAD" "$DISCORD_WEBHOOK_URL"
7995
```
8096
8197
## Message Format Convention
@@ -89,6 +105,8 @@ by {author}
89105
{url}
90106
```
91107

108+
Supported `event_type` values: `pr_opened`, `pr_reopened`, `issue_opened`, `issue_reopened`
109+
92110
Example:
93111
```
94112
[GH-EVENT] repo:openabdev/openab action:pr_opened PR #42

0 commit comments

Comments
 (0)