-
Notifications
You must be signed in to change notification settings - Fork 6
376 lines (332 loc) · 14.5 KB
/
_notify-release.yml
File metadata and controls
376 lines (332 loc) · 14.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
name: Notify Release
# Reusable workflow for sending release notifications to multiple destinations.
# This workflow expects a pre-generated changelog and focuses solely on notification delivery.
#
# ARCHITECTURE:
# This workflow is intentionally simple and focused on a single responsibility: routing
# notifications to configured destinations. Changelog generation should be handled by the
# calling workflow using the _generate-changelog.yml reusable workflow.
#
# This workflow is designed to be generic and work with any repository type:
# - Monorepos (Nx, Turborepo, etc.) or single-package repos
# - npm packages, other language ecosystems, or non-package projects
# - Any branching strategy (main/develop, main/next, etc.)
#
# Supports routing to Slack, Notion, or both destinations based on configuration.
on:
workflow_call:
inputs:
changelog_slack:
description: |
Pre-generated Slack-formatted changelog from _generate-changelog.yml.
Required if "slack" in destinations and want formatted output.
If not provided but changelog_markdown is, will be auto-converted.
required: false
type: string
changelog_markdown:
description: |
Pre-generated markdown changelog from _generate-changelog.yml.
Required if "notion" in destinations.
Can be used for Slack if changelog_slack not provided.
required: false
type: string
destinations:
description: |
Comma-separated list of notification destinations.
Options: "slack", "notion", or "slack,notion"
- "slack": Send to Slack via webhook (requires SLACK_WEBHOOK_URL secret)
- "notion": Create page in Notion database (requires NOTION_API_KEY, RELEASE_NOTES_NOTION_DATABASE_ID)
At least one changelog input must be provided for each destination.
required: true
type: string
from_ref:
description: |
Starting git reference for display in notifications.
Example: "v1.0.0" or "abc123d"
required: true
type: string
to_ref:
description: |
Ending git reference for display in notifications.
Example: "v1.1.0" or "def456a"
required: true
type: string
branch:
description: |
Branch name that was released.
Example: "main", "next", "develop"
required: true
type: string
release_title:
description: |
Custom title for the release notification.
Used as Notion page title and Slack header.
Example: "Production Release v1.1.0"
Default: Generated from branch and ref range.
required: false
type: string
secrets:
SLACK_WEBHOOK_URL:
description: |
Slack incoming webhook URL for notifications.
Required if "slack" included in destinations input.
Format: https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX
required: false
NOTION_API_KEY:
description: |
Notion integration API key with write access to target database.
Required if "notion" included in destinations input.
Format: secret_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Obtain from: https://www.notion.so/my-integrations
required: false
RELEASE_NOTES_NOTION_DATABASE_ID:
description: |
Notion database ID where changelog pages will be created.
Required if "notion" included in destinations input.
Format: 32-character hex string (xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)
Extract from database URL: notion.so/{workspace}/{database_id}?v=...
required: false
jobs:
prepare:
runs-on: ubuntu-24.04
permissions:
contents: read
outputs:
emoji: ${{ steps.notification.outputs.emoji }}
title: ${{ steps.notification.outputs.title }}
description: ${{ steps.notification.outputs.description }}
final_title: ${{ steps.notification.outputs.final_title }}
changelog_for_slack: ${{ steps.prepare-changelogs.outputs.changelog_for_slack }}
changelog_for_notion: ${{ steps.prepare-changelogs.outputs.changelog_for_notion }}
steps:
- uses: bullfrogsec/bullfrog@1831f79cce8ad602eef14d2163873f27081ebfb3 # v0.8.4
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
fetch-depth: 0
- name: Validate required secrets
env:
INPUT_DESTINATIONS: ${{ inputs.destinations }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
NOTION_API_KEY: ${{ secrets.NOTION_API_KEY }}
RELEASE_NOTES_NOTION_DATABASE_ID: ${{ secrets.RELEASE_NOTES_NOTION_DATABASE_ID }}
run: |
MISSING_SECRETS=()
# Check Slack secrets if Slack destination is configured
if [[ "$INPUT_DESTINATIONS" == *"slack"* ]]; then
if [[ -z "$SLACK_WEBHOOK_URL" ]]; then
MISSING_SECRETS+=("SLACK_WEBHOOK_URL")
fi
fi
# Check Notion secrets if Notion destination is configured
if [[ "$INPUT_DESTINATIONS" == *"notion"* ]]; then
if [[ -z "$NOTION_API_KEY" ]]; then
MISSING_SECRETS+=("NOTION_API_KEY")
fi
if [[ -z "$RELEASE_NOTES_NOTION_DATABASE_ID" ]]; then
MISSING_SECRETS+=("RELEASE_NOTES_NOTION_DATABASE_ID")
fi
fi
# Fail if any required secrets are missing
if [[ ${#MISSING_SECRETS[@]} -gt 0 ]]; then
echo "❌ Missing required secrets for destinations: $INPUT_DESTINATIONS"
echo ""
echo "The following secrets are required but not configured:"
for secret in "${MISSING_SECRETS[@]}"; do
echo " - $secret"
done
echo ""
echo "Please configure these secrets in your repository settings:"
echo "Settings → Secrets and variables → Actions → New repository secret"
echo ""
echo "For more information, see:"
echo " - Slack webhook: https://api.slack.com/messaging/webhooks"
echo " - Notion API key: https://www.notion.so/my-integrations"
echo " - npm token: https://www.npmjs.com/settings/~/tokens"
exit 1
fi
echo "✅ All required secrets are configured"
- name: Determine notification details
id: notification
env:
INPUT_BRANCH: ${{ inputs.branch }}
INPUT_RELEASE_TITLE: ${{ inputs.release_title }}
INPUT_FROM_REF: ${{ inputs.from_ref }}
INPUT_TO_REF: ${{ inputs.to_ref }}
run: |
# Set emoji, title, and description based on branch
if [[ "$INPUT_BRANCH" == "next" ]]; then
echo "emoji=📦" >> $GITHUB_OUTPUT
echo "title=Next Branch Release" >> $GITHUB_OUTPUT
echo "description=Changes from the \`next\` branch have been released." >> $GITHUB_OUTPUT
else
echo "emoji=🚀" >> $GITHUB_OUTPUT
echo "title=Production Release" >> $GITHUB_OUTPUT
echo "description=Changes from the \`main\` branch have been released." >> $GITHUB_OUTPUT
fi
# Determine final title for notifications
if [[ -n "$INPUT_RELEASE_TITLE" ]]; then
FINAL_TITLE="$INPUT_RELEASE_TITLE"
else
FINAL_TITLE="Release $INPUT_BRANCH - $INPUT_FROM_REF → $INPUT_TO_REF"
fi
echo "final_title=$FINAL_TITLE" >> $GITHUB_OUTPUT
- name: Prepare changelogs for destinations
id: prepare-changelogs
env:
INPUT_DESTINATIONS: ${{ inputs.destinations }}
INPUT_CHANGELOG_SLACK: ${{ inputs.changelog_slack }}
INPUT_CHANGELOG_MARKDOWN: ${{ inputs.changelog_markdown }}
run: |
# Determine what we need
NEED_SLACK=false
NEED_NOTION=false
if [[ "$INPUT_DESTINATIONS" == *"slack"* ]]; then
NEED_SLACK=true
fi
if [[ "$INPUT_DESTINATIONS" == *"notion"* ]]; then
NEED_NOTION=true
fi
echo "Preparing changelogs for destinations: $INPUT_DESTINATIONS"
echo "Need Slack: $NEED_SLACK, Need Notion: $NEED_NOTION"
# Prepare Slack changelog
if [ "$NEED_SLACK" == "true" ]; then
if [[ -n "$INPUT_CHANGELOG_SLACK" ]]; then
# Use provided Slack format
SLACK_CHANGELOG="$INPUT_CHANGELOG_SLACK"
echo "Using provided Slack changelog"
elif [[ -n "$INPUT_CHANGELOG_MARKDOWN" ]]; then
# Convert markdown to Slack format (basic conversion)
# Replace markdown bullets with Slack bullets
SLACK_CHANGELOG=$(echo "$INPUT_CHANGELOG_MARKDOWN" | sed 's/^[*-] /• /g')
echo "Converted markdown to Slack format"
else
echo "Error: Slack destination requested but no changelog provided"
exit 1
fi
# Convert real newlines to \n for Slack's mrkdwn format
# Slack Block Kit requires explicit \n strings, not actual newline characters
SLACK_CHANGELOG_ESCAPED=$(echo "$SLACK_CHANGELOG" | awk '{printf "%s\\n", $0}' | sed 's/\\n$//')
echo "changelog_for_slack=$SLACK_CHANGELOG_ESCAPED" >> $GITHUB_OUTPUT
fi
# Prepare Notion changelog
if [ "$NEED_NOTION" == "true" ]; then
if [[ -n "$INPUT_CHANGELOG_MARKDOWN" ]]; then
# Use provided markdown format
NOTION_CHANGELOG="$INPUT_CHANGELOG_MARKDOWN"
echo "Using markdown changelog for Notion"
elif [[ -n "$INPUT_CHANGELOG_SLACK" ]]; then
# Use Slack format as fallback (Notion can handle basic markdown-like text)
NOTION_CHANGELOG="$INPUT_CHANGELOG_SLACK"
echo "Using Slack changelog for Notion (fallback)"
else
echo "Error: Notion destination requested but no changelog provided"
exit 1
fi
{
echo 'changelog_for_notion<<EOF'
echo "$NOTION_CHANGELOG"
echo 'EOF'
} >> $GITHUB_OUTPUT
fi
notify-slack:
needs: prepare
if: contains(inputs.destinations, 'slack')
runs-on: ubuntu-24.04
permissions:
contents: read
steps:
- uses: bullfrogsec/bullfrog@1831f79cce8ad602eef14d2163873f27081ebfb3 # v0.8.4
- name: Send Slack notification
continue-on-error: true
uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
with:
webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
webhook-type: incoming-webhook
payload: |
text: "${{ needs.prepare.outputs.emoji }} *${{ needs.prepare.outputs.title }}*"
blocks:
- type: "section"
text:
type: "mrkdwn"
text: "${{ needs.prepare.outputs.emoji }} *${{ needs.prepare.outputs.title }}*\n\n${{ needs.prepare.outputs.description }}"
- type: "section"
fields:
- type: "mrkdwn"
text: "*Branch:*\n`${{ inputs.branch }}`"
- type: "mrkdwn"
text: "*Commits:*\n`${{ inputs.from_ref }}` → `${{ inputs.to_ref }}`"
- type: "section"
text:
type: "mrkdwn"
text: "*What's Changed:*\n${{ needs.prepare.outputs.changelog_for_slack }}"
- type: "actions"
elements:
- type: "button"
text:
type: "plain_text"
text: "View Workflow Run"
url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
style: "primary"
notify-notion:
needs: prepare
if: contains(inputs.destinations, 'notion')
runs-on: ubuntu-24.04
permissions:
contents: read
steps:
- uses: bullfrogsec/bullfrog@1831f79cce8ad602eef14d2163873f27081ebfb3 # v0.8.4
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: Setup Node.js for Notion publishing
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: ${{ vars.NODE_VERSION }}
registry-url: 'https://registry.npmjs.org'
scope: '@uniswap'
- name: Publish to Notion
id: notion-publish
continue-on-error: true
run: |
# Pass multi-line content via environment variable to avoid command-line escaping issues
PAGE_URL=$(npx @uniswap/ai-toolkit-notion-publisher@latest \
--title "$TITLE" \
--content "$CONTENT" \
--from-ref "$FROM_REF" \
--to-ref "$TO_REF" \
--branch "$BRANCH")
echo "page-url=$PAGE_URL" >> $GITHUB_OUTPUT
env:
NOTION_API_KEY: ${{ secrets.NOTION_API_KEY }}
RELEASE_NOTES_NOTION_DATABASE_ID: ${{ secrets.RELEASE_NOTES_NOTION_DATABASE_ID }}
TITLE: ${{ needs.prepare.outputs.final_title }}
CONTENT: ${{ needs.prepare.outputs.changelog_for_notion }}
FROM_REF: ${{ inputs.from_ref }}
TO_REF: ${{ inputs.to_ref }}
BRANCH: ${{ inputs.branch }}
- name: Add Notion URL to summary
if: steps.notion-publish.outcome == 'success'
env:
NOTION_PAGE_URL: ${{ steps.notion-publish.outputs.page-url }}
run: |
cat <<SUMMARY_EOF >> $GITHUB_STEP_SUMMARY
## 📄 Notion Page Created
**Page URL**: $NOTION_PAGE_URL
[View in Notion]($NOTION_PAGE_URL)
SUMMARY_EOF
- name: Notion publishing failed
if: steps.notion-publish.outcome == 'failure'
run: |
echo "⚠️ Notion publishing failed (check logs above)"
cat <<SUMMARY_EOF >> $GITHUB_STEP_SUMMARY
## ⚠️ Notion Publishing Failed
The Notion page could not be created. Check the workflow logs for details.
Common issues:
- Invalid NOTION_API_KEY secret
- Invalid RELEASE_NOTES_NOTION_DATABASE_ID secret
- Notion integration doesn't have access to the database
- Database properties don't match expected schema
SUMMARY_EOF