mirror of
https://github.com/supabase/supabase.git
synced 2026-05-07 01:10:15 -04:00
03660838ef
This pull request refactors the GitHub Actions workflow for notifying about stale Dashboard PRs by replacing custom JavaScript scripts and the `actions/github-script` action with new TypeScript scripts that communicate via standard input/output. This simplifies the workflow, improves maintainability, and adds better error handling, especially for API rate limits. The Slack notification script is also rewritten in TypeScript and now reads PR data from stdin, making the workflow steps more composable.
141 lines
3.7 KiB
TypeScript
141 lines
3.7 KiB
TypeScript
const SLACK_WEBHOOK_URL = process.env.SLACK_WEBHOOK_URL
|
|
|
|
if (!SLACK_WEBHOOK_URL) {
|
|
console.error('SLACK_WEBHOOK_URL environment variable is required')
|
|
process.exit(1)
|
|
}
|
|
|
|
interface StalePR {
|
|
number: number
|
|
title: string
|
|
url: string
|
|
author: string
|
|
createdAt: string
|
|
hoursOld: number
|
|
daysOld: number
|
|
fileCount: number
|
|
reviewStatus: string
|
|
reviewEmoji: string
|
|
mergeableStatus: string
|
|
mergeableEmoji: string
|
|
}
|
|
|
|
function escapeSlack(text: string) {
|
|
return text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
|
}
|
|
|
|
async function sendSlackNotification(stalePRs: StalePR[]) {
|
|
const count = stalePRs.length
|
|
|
|
const prBlocks = stalePRs.map((pr) => {
|
|
const remainingHours = pr.hoursOld % 24
|
|
const ageText = pr.daysOld > 0 ? `${pr.daysOld}d ${remainingHours}h` : `${pr.hoursOld}h`
|
|
|
|
const maxTitleLength = 200
|
|
const safeTitle =
|
|
pr.title.length > maxTitleLength
|
|
? escapeSlack(pr.title.substring(0, maxTitleLength) + '...')
|
|
: escapeSlack(pr.title)
|
|
|
|
const reviewStatusText =
|
|
pr.reviewStatus === 'approved'
|
|
? 'Approved'
|
|
: pr.reviewStatus === 'changes-requested'
|
|
? 'Changes Requested'
|
|
: pr.reviewStatus === 'commented'
|
|
? 'Commented'
|
|
: 'Needs Review'
|
|
|
|
const mergeableStatusText =
|
|
pr.mergeableStatus === 'ready'
|
|
? 'Ready to Merge'
|
|
: pr.mergeableStatus === 'conflicts'
|
|
? 'Has Conflicts'
|
|
: pr.mergeableStatus === 'blocked'
|
|
? 'Blocked'
|
|
: pr.mergeableStatus === 'unstable'
|
|
? 'Unstable'
|
|
: pr.mergeableStatus === 'behind'
|
|
? 'Behind Base'
|
|
: pr.mergeableStatus === 'draft'
|
|
? 'Draft'
|
|
: 'Unknown'
|
|
|
|
return {
|
|
type: 'section',
|
|
text: {
|
|
type: 'mrkdwn',
|
|
text: `*<${pr.url}|#${pr.number}: ${safeTitle}>*\n:bust_in_silhouette: @${pr.author} • :clock3: ${ageText} old • :file_folder: ${pr.fileCount} Dashboard files\n${pr.reviewEmoji} ${reviewStatusText} • ${pr.mergeableEmoji} ${mergeableStatusText}`,
|
|
},
|
|
}
|
|
})
|
|
|
|
const MAX_PRS_TO_SHOW = 47
|
|
const prBlocksToShow = prBlocks.slice(0, MAX_PRS_TO_SHOW)
|
|
const hasMorePRs = prBlocks.length > MAX_PRS_TO_SHOW
|
|
|
|
const slackMessage = {
|
|
text: 'Dashboard PRs needing attention',
|
|
blocks: [
|
|
{
|
|
type: 'header',
|
|
text: {
|
|
type: 'plain_text',
|
|
text: 'Dashboard PRs Older Than 24 Hours',
|
|
},
|
|
},
|
|
{
|
|
type: 'section',
|
|
text: {
|
|
type: 'mrkdwn',
|
|
text: `There are *${count}* open PRs affecting /apps/studio/ that are older than 24 hours:${hasMorePRs ? ` (showing first ${MAX_PRS_TO_SHOW})` : ''}`,
|
|
},
|
|
},
|
|
{
|
|
type: 'divider',
|
|
},
|
|
...prBlocksToShow,
|
|
],
|
|
}
|
|
|
|
const response = await fetch(SLACK_WEBHOOK_URL!, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(slackMessage),
|
|
})
|
|
|
|
if (!response.ok) {
|
|
const errorText = await response.text()
|
|
throw new Error(
|
|
`Slack notification failed: ${response.status} ${response.statusText}\n${errorText}`
|
|
)
|
|
}
|
|
|
|
console.error('Slack notification sent successfully!')
|
|
}
|
|
|
|
// Read JSON from stdin
|
|
async function readStdin(): Promise<string> {
|
|
const chunks: Buffer[] = []
|
|
for await (const chunk of process.stdin) {
|
|
chunks.push(chunk)
|
|
}
|
|
return Buffer.concat(chunks).toString('utf-8')
|
|
}
|
|
|
|
readStdin()
|
|
.then(async (input) => {
|
|
const stalePRs: StalePR[] = JSON.parse(input)
|
|
|
|
if (stalePRs.length === 0) {
|
|
console.error('No stale PRs to notify about')
|
|
return
|
|
}
|
|
|
|
await sendSlackNotification(stalePRs)
|
|
})
|
|
.catch((error) => {
|
|
console.error('Error:', error.message)
|
|
process.exit(1)
|
|
})
|