From 4c47bc4ebb573843bed6d183a81bd2c990029a27 Mon Sep 17 00:00:00 2001 From: nourshoreibah Date: Mon, 9 Feb 2026 00:08:47 -0500 Subject: [PATCH 1/2] improved bot --- .github/workflows/pr-review-status.yml | 169 +++++++++++++++-------- .github/workflows/pr-reviewer-assign.yml | 162 +++++++++++++--------- 2 files changed, 210 insertions(+), 121 deletions(-) diff --git a/.github/workflows/pr-review-status.yml b/.github/workflows/pr-review-status.yml index a41d7a4..bd7dfe6 100644 --- a/.github/workflows/pr-review-status.yml +++ b/.github/workflows/pr-review-status.yml @@ -66,27 +66,7 @@ jobs: const prData = JSON.parse(fs.readFileSync(prFilePath, 'utf8')); - // Check if reviewer is one of the assigned reviewers - const isMainReviewer = reviewer.toLowerCase() === prData.main_reviewer.toLowerCase(); - const isSecondReviewer = prData.second_reviewer && - reviewer.toLowerCase() === prData.second_reviewer.toLowerCase(); - const isAssignedReviewer = isMainReviewer || isSecondReviewer; - - if (!isAssignedReviewer) { - console.log(`${reviewer} is not an assigned reviewer for PR #${prNumber}. Skipping state update.`); - } - - // ── Determine emoji and label ──────────────────────────────────── - let emoji, label; - if (reviewState === 'approved') { - emoji = ':white_check_mark:'; - label = 'Approved'; - } else { - emoji = ':arrows_counterclockwise:'; - label = 'Changes Requested'; - } - - // ── Helper: call Slack API ─────────────────────────────────────── + // ── Slack helpers ─────────────────────────────────────── async function slackApi(method, body) { try { const resp = await fetch(`https://slack.com/api/${method}`, { @@ -106,8 +86,63 @@ jobs: } } - // ── Check if all assigned reviewers are now done ───────────────── - // We need to query all reviews to know full status + const STATUS_EMOJI = { + pending: ':hourglass_flowing_sand:', + approved: ':white_check_mark:', + changes_requested: ':arrows_counterclockwise:', + commented: ':speech_balloon:', + }; + const STATUS_LABEL = { + pending: 'Pending', + approved: 'Approved', + changes_requested: 'Changes Requested', + commented: 'Commented', + }; + + function buildBlocks({ prUrl, prNumber, prTitle, prAuthor, reviewers, alwaysReviewer }) { + const allDone = reviewers.every(r => r.status !== 'pending') + && (!alwaysReviewer || alwaysReviewer.status !== 'pending'); + const anyChangesRequested = reviewers.some(r => r.status === 'changes_requested') + || (alwaysReviewer && alwaysReviewer.status === 'changes_requested'); + + let headerText; + if (allDone && !anyChangesRequested) { + headerText = ':white_check_mark: All Reviews Complete'; + } else if (allDone && anyChangesRequested) { + headerText = ':arrows_counterclockwise: Changes Requested'; + } else { + headerText = ':evergreen_tree: Review Requested'; + } + + const reviewerLines = reviewers.map(r => + `${STATUS_EMOJI[r.status]} <@${r.slack}> — ${STATUS_LABEL[r.status]}` + ); + if (alwaysReviewer) { + reviewerLines.push(`${STATUS_EMOJI[alwaysReviewer.status]} <@${alwaysReviewer.slack}> — ${STATUS_LABEL[alwaysReviewer.status]}`); + } + + const infoText = allDone + ? `*<${prUrl}|#${prNumber} ${prTitle}>*\nAuthor: *${prAuthor}*` + : `*<${prUrl}|#${prNumber} ${prTitle}>*\nAuthor: *${prAuthor}*\n_Please review as soon as you can! Thank you!_`; + + return [ + { + type: 'header', + text: { type: 'plain_text', text: headerText, emoji: true }, + }, + { + type: 'section', + text: { type: 'mrkdwn', text: infoText }, + }, + { type: 'divider' }, + { + type: 'section', + text: { type: 'mrkdwn', text: reviewerLines.join('\n') }, + }, + ]; + } + + // ── Fetch all reviews to get current state of each reviewer ────── let allReviews = []; try { const resp = await github.rest.pulls.listReviews({ @@ -121,58 +156,74 @@ jobs: } const REVIEW_STATES = ['APPROVED', 'CHANGES_REQUESTED', 'COMMENTED']; - const hasReviewed = (login) => allReviews.some( - r => r.user.login.toLowerCase() === login.toLowerCase() && REVIEW_STATES.includes(r.state) - ); - - const mainDone = hasReviewed(prData.main_reviewer); - const secondDone = !prData.second_reviewer || hasReviewed(prData.second_reviewer); - const allDone = mainDone && secondDone; - - // ── Update the original Slack message if all reviewers are done ── - if (prData.slack_thread_ts && allDone && isAssignedReviewer) { - // Build reviewer status lines - const reviewerLines = []; - const mainStatus = mainDone ? ':white_check_mark:' : ':hourglass_flowing_sand:'; - reviewerLines.push(`${mainStatus} *${prData.main_reviewer}* <@${prData.main_reviewer_slack}>`); - if (prData.second_reviewer) { - const secondStatus = secondDone ? ':white_check_mark:' : ':hourglass_flowing_sand:'; - reviewerLines.push(`${secondStatus} *${prData.second_reviewer}* <@${prData.second_reviewer_slack}>`); + + function getLatestStatus(login) { + const userReviews = allReviews.filter( + r => r.user.login.toLowerCase() === login.toLowerCase() && + REVIEW_STATES.includes(r.state) + ); + if (userReviews.length === 0) return 'pending'; + return userReviews[userReviews.length - 1].state.toLowerCase(); + } + + // ── Build per-reviewer status ──────────────────────────────────── + const mainStatus = getLatestStatus(prData.main_reviewer); + const reviewerObjs = [{ login: prData.main_reviewer, slack: prData.main_reviewer_slack, status: mainStatus }]; + + let secondStatus = null; + if (prData.second_reviewer) { + secondStatus = getLatestStatus(prData.second_reviewer); + reviewerObjs.push({ login: prData.second_reviewer, slack: prData.second_reviewer_slack, status: secondStatus }); + } + + const authorSlackId = config.github_to_slack[prData.author]; + const authorIsAlways = authorSlackId === config.always_reviewer_slack; + + // Look up always-reviewer's GitHub username to get their review status + let alwaysReviewerObj = null; + if (!authorIsAlways) { + const alwaysEntry = Object.entries(config.github_to_slack).find( + ([, slackId]) => slackId === config.always_reviewer_slack + ); + if (alwaysEntry) { + const alwaysStatus = getLatestStatus(alwaysEntry[0]); + alwaysReviewerObj = { slack: config.always_reviewer_slack, status: alwaysStatus }; } + } + + const mainDone = mainStatus !== 'pending'; + const secondDone = !prData.second_reviewer || secondStatus !== 'pending'; + const alwaysDone = !alwaysReviewerObj || alwaysReviewerObj.status !== 'pending'; + const allDone = mainDone && secondDone && alwaysDone; + + // ── Update original Slack message with current statuses ────────── + if (prData.slack_thread_ts) { + const blocks = buildBlocks({ + prUrl, prNumber, prTitle, prAuthor: prData.author, + reviewers: reviewerObjs, + alwaysReviewer: alwaysReviewerObj, + }); await slackApi('chat.update', { channel: config.slack_channel_id, ts: prData.slack_thread_ts, - text: `${label}: <${prUrl}|#${prNumber} ${prTitle}>`, - blocks: [ - { - type: 'section', - text: { - type: 'mrkdwn', - text: `${emoji} *${label}*\n*<${prUrl}|#${prNumber} ${prTitle}>*\nAuthor: *${prData.author}*`, - }, - }, - { - type: 'section', - text: { - type: 'mrkdwn', - text: reviewerLines.join('\n'), - }, - }, - ], + text: `PR #${prNumber}: ${allDone ? 'reviews complete' : 'review in progress'}`, + blocks, }); - console.log(`Updated original Slack message for PR #${prNumber}`); + console.log(`Updated Slack message for PR #${prNumber}`); } // ── Post a thread reply for visibility ─────────────────────────── if (prData.slack_thread_ts) { const reviewerSlack = config.github_to_slack[reviewer]; const mention = reviewerSlack ? `<@${reviewerSlack}>` : `*${reviewer}*`; + const emoji = reviewState === 'approved' ? ':white_check_mark:' : ':arrows_counterclockwise:'; + const verb = reviewState === 'approved' ? 'approved' : 'requested changes on'; await slackApi('chat.postMessage', { channel: config.slack_channel_id, thread_ts: prData.slack_thread_ts, - text: `${emoji} ${mention} ${reviewState === 'approved' ? 'approved' : 'requested changes on'} <${prData.pr_url}|PR #${prNumber}>`, + text: `${emoji} ${mention} ${verb} <${prData.pr_url}|PR #${prNumber}>`, }); } diff --git a/.github/workflows/pr-reviewer-assign.yml b/.github/workflows/pr-reviewer-assign.yml index be4314b..18a5ecc 100644 --- a/.github/workflows/pr-reviewer-assign.yml +++ b/.github/workflows/pr-reviewer-assign.yml @@ -63,27 +63,80 @@ jobs: fs.mkdirSync(prsDir, { recursive: true }); } - // ── Helper: post a Slack message ───────────────────────── - async function postSlack(msg) { + // ── Slack helpers ─────────────────────────────────────── + async function slackApi(method, body) { try { - const resp = await fetch('https://slack.com/api/chat.postMessage', { + const resp = await fetch(`https://slack.com/api/${method}`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${process.env.SLACK_BOT_TOKEN}`, }, - body: JSON.stringify(msg), + body: JSON.stringify(body), }); const data = await resp.json(); - if (data.ok) { - console.log(`Slack message posted (ts: ${data.ts})`); - return data.ts; - } - console.log(`Slack error: ${data.error}`); + if (!data.ok) console.log(`Slack ${method} error: ${data.error}`); + return data; } catch (err) { - console.log(`Slack post failed: ${err.message}`); + console.log(`Slack ${method} failed: ${err.message}`); + return { ok: false }; } - return null; + } + + const STATUS_EMOJI = { + pending: ':hourglass_flowing_sand:', + approved: ':white_check_mark:', + changes_requested: ':arrows_counterclockwise:', + commented: ':speech_balloon:', + }; + const STATUS_LABEL = { + pending: 'Pending', + approved: 'Approved', + changes_requested: 'Changes Requested', + commented: 'Commented', + }; + + function buildBlocks({ prUrl, prNumber, prTitle, prAuthor, reviewers, alwaysReviewer }) { + const allDone = reviewers.every(r => r.status !== 'pending') + && (!alwaysReviewer || alwaysReviewer.status !== 'pending'); + const anyChangesRequested = reviewers.some(r => r.status === 'changes_requested') + || (alwaysReviewer && alwaysReviewer.status === 'changes_requested'); + + let headerText; + if (allDone && !anyChangesRequested) { + headerText = ':white_check_mark: All Reviews Complete'; + } else if (allDone && anyChangesRequested) { + headerText = ':arrows_counterclockwise: Changes Requested'; + } else { + headerText = ':evergreen_tree: Review Requested'; + } + + const reviewerLines = reviewers.map(r => + `${STATUS_EMOJI[r.status]} <@${r.slack}> — ${STATUS_LABEL[r.status]}` + ); + if (alwaysReviewer) { + reviewerLines.push(`${STATUS_EMOJI[alwaysReviewer.status]} <@${alwaysReviewer.slack}> — ${STATUS_LABEL[alwaysReviewer.status]}`); + } + + const infoText = allDone + ? `*<${prUrl}|#${prNumber} ${prTitle}>*\nAuthor: *${prAuthor}*` + : `*<${prUrl}|#${prNumber} ${prTitle}>*\nAuthor: *${prAuthor}*\n_Please review as soon as you can! Thank you!_`; + + return [ + { + type: 'header', + text: { type: 'plain_text', text: headerText, emoji: true }, + }, + { + type: 'section', + text: { type: 'mrkdwn', text: infoText }, + }, + { type: 'divider' }, + { + type: 'section', + text: { type: 'mrkdwn', text: reviewerLines.join('\n') }, + }, + ]; } // ── Idempotency: PR already tracked ────────────────────── @@ -100,38 +153,39 @@ jobs: existing.status = 'open'; existing.last_reminded_at = null; + const reopenReviewers = [existing.main_reviewer]; + if (existing.second_reviewer) reopenReviewers.push(existing.second_reviewer); + try { await github.rest.pulls.requestReviewers({ owner: context.repo.owner, repo: context.repo.repo, pull_number: prNumber, - reviewers: [existing.main_reviewer], + reviewers: reopenReviewers, }); } catch (err) { - console.log(`Warning: could not re-request review from ${existing.main_reviewer}: ${err.message}`); + console.log(`Warning: could not re-request reviewers: ${err.message}`); } - const ts = await postSlack({ + const authorSlackId = config.github_to_slack[prAuthor]; + const authorIsAlways = authorSlackId === config.always_reviewer_slack; + const reviewerObjs = [{ login: existing.main_reviewer, slack: existing.main_reviewer_slack, status: 'pending' }]; + if (existing.second_reviewer) { + reviewerObjs.push({ login: existing.second_reviewer, slack: existing.second_reviewer_slack, status: 'pending' }); + } + + const blocks = buildBlocks({ + prUrl, prNumber, prTitle, prAuthor, + reviewers: reviewerObjs, + alwaysReviewer: authorIsAlways ? null : { slack: config.always_reviewer_slack, status: 'pending' }, + }); + + const res = await slackApi('chat.postMessage', { channel: config.slack_channel_id, - text: `PR reopened: <${prUrl}|#${prNumber} ${prTitle}>`, - blocks: [ - { - type: 'section', - text: { - type: 'mrkdwn', - text: `*Reopened:* *<${prUrl}|#${prNumber} ${prTitle}>*\nAuthor: *${prAuthor}*`, - }, - }, - { - type: 'section', - text: { - type: 'mrkdwn', - text: `:mag: *Main reviewer:* <@${existing.main_reviewer_slack}>\n:eyes: *Also reviewing:* <@${config.always_reviewer_slack}>`, - }, - }, - ], + text: `PR reopened: #${prNumber} ${prTitle}`, + blocks, }); - if (ts) existing.slack_thread_ts = ts; + if (res.ok) existing.slack_thread_ts = res.ts; fs.writeFileSync(prFilePath, JSON.stringify(existing, null, 2) + '\n'); return; @@ -181,11 +235,7 @@ jobs: } const secondReviewerSlack = secondReviewer ? config.github_to_slack[secondReviewer] : null; - if (authorIsAlwaysReviewer) { - console.log(`Author is always-reviewer — assigning ${pickedReviewers.join(' + ')} to PR #${prNumber} (cursor: ${cursor} → ${newCursor})`); - } else { - console.log(`Assigning ${mainReviewer} to PR #${prNumber} (author: ${prAuthor}, cursor: ${cursor} → ${newCursor})`); - } + console.log(`Assigning ${pickedReviewers.join(' + ')} to PR #${prNumber} (author: ${prAuthor}, cursor: ${cursor} → ${newCursor})`); // ── Request review on GitHub ───────────────────────────── try { @@ -201,35 +251,23 @@ jobs: } // ── Post Slack notification ────────────────────────────── - let reviewerLines; - if (authorIsAlwaysReviewer && secondReviewer) { - // Author is the always-reviewer, so show two round-robin picks - reviewerLines = `:mag: *Reviewer 1:* <@${mainReviewerSlack}>\n:mag: *Reviewer 2:* <@${secondReviewerSlack}>`; - } else { - // Normal case: one main reviewer + always-reviewer - reviewerLines = `:mag: *Main reviewer:* <@${mainReviewerSlack}>\n:eyes: *Also reviewing:* <@${config.always_reviewer_slack}>`; + const reviewerObjs = [{ login: mainReviewer, slack: mainReviewerSlack, status: 'pending' }]; + if (secondReviewer) { + reviewerObjs.push({ login: secondReviewer, slack: secondReviewerSlack, status: 'pending' }); } - const slackTs = await postSlack({ + const blocks = buildBlocks({ + prUrl, prNumber, prTitle, prAuthor, + reviewers: reviewerObjs, + alwaysReviewer: authorIsAlwaysReviewer ? null : { slack: config.always_reviewer_slack, status: 'pending' }, + }); + + const slackRes = await slackApi('chat.postMessage', { channel: config.slack_channel_id, - text: `New PR for review: <${prUrl}|#${prNumber} ${prTitle}>`, - blocks: [ - { - type: 'section', - text: { - type: 'mrkdwn', - text: `*<${prUrl}|#${prNumber} ${prTitle}>*\nAuthor: *${prAuthor}*`, - }, - }, - { - type: 'section', - text: { - type: 'mrkdwn', - text: reviewerLines, - }, - }, - ], + text: `New PR for review: #${prNumber} ${prTitle}`, + blocks, }); + const slackTs = slackRes.ok ? slackRes.ts : null; // ── Persist state (only state.json + per-PR file) ──────── state.cursor = newCursor; From a5e4371df5ca117b3a5c0005af69e997c807ffa6 Mon Sep 17 00:00:00 2001 From: nourshoreibah Date: Mon, 9 Feb 2026 00:13:33 -0500 Subject: [PATCH 2/2] more improvements --- .github/workflows/pr-closed.yml | 220 +++++++++++++++++++++++ .github/workflows/pr-review-status.yml | 12 +- .github/workflows/pr-reviewer-assign.yml | 10 +- 3 files changed, 231 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/pr-closed.yml diff --git a/.github/workflows/pr-closed.yml b/.github/workflows/pr-closed.yml new file mode 100644 index 0000000..7c85038 --- /dev/null +++ b/.github/workflows/pr-closed.yml @@ -0,0 +1,220 @@ +name: PR Closed / Merged + +on: + pull_request: + types: [closed] + +concurrency: + group: pr-closed-${{ github.event.pull_request.number }} + cancel-in-progress: true + +permissions: + contents: write + pull-requests: read + +jobs: + update-status: + runs-on: ubuntu-latest + steps: + - name: Checkout bot-state branch + uses: actions/checkout@v4 + with: + ref: bot-state + path: bot-state + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Update Slack message and bot state + uses: actions/github-script@v7 + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} + with: + script: | + const fs = require('fs'); + const path = require('path'); + + const BOT_STATE_DIR = 'bot-state'; + const configPath = path.join(BOT_STATE_DIR, 'config.json'); + const prsDir = path.join(BOT_STATE_DIR, 'prs'); + + const pr = context.payload.pull_request; + const prNumber = pr.number; + const prUrl = pr.html_url; + const prTitle = pr.title; + const wasMerged = pr.merged; + + console.log(`PR #${prNumber} ${wasMerged ? 'merged' : 'closed'}`); + + // ── Load config ────────────────────────────────────────── + if (!fs.existsSync(configPath)) { + console.log('config.json not found. Skipping.'); + return; + } + const config = JSON.parse(fs.readFileSync(configPath, 'utf8')); + + // ── Find per-PR file ───────────────────────────────────── + const prFileKey = `${context.repo.owner}_${context.repo.repo}_${prNumber}`; + const prFilePath = path.join(prsDir, `${prFileKey}.json`); + + if (!fs.existsSync(prFilePath)) { + console.log(`No per-PR file for #${prNumber}. Not tracked by the bot.`); + return; + } + + const prData = JSON.parse(fs.readFileSync(prFilePath, 'utf8')); + + if (['merged', 'closed'].includes(prData.status)) { + console.log(`PR #${prNumber} already in status "${prData.status}". Skipping.`); + return; + } + + // ── Slack helper ───────────────────────────────────────── + async function slackApi(method, body) { + try { + const resp = await fetch(`https://slack.com/api/${method}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${process.env.SLACK_BOT_TOKEN}`, + }, + body: JSON.stringify(body), + }); + const data = await resp.json(); + if (!data.ok) console.log(`Slack ${method} error: ${data.error}`); + return data; + } catch (err) { + console.log(`Slack ${method} failed: ${err.message}`); + return { ok: false }; + } + } + + // ── Fetch reviews for final reviewer statuses ──────────── + const STATUS_EMOJI = { + pending: ':hourglass_flowing_sand:', + approved: ':approved:', + changes_requested: ':git-request-changes:', + commented: ':git-comment:', + }; + const STATUS_LABEL = { + pending: 'Pending', + approved: 'Approved', + changes_requested: 'Changes Requested', + commented: 'Commented', + }; + + let allReviews = []; + try { + const resp = await github.rest.pulls.listReviews({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: prNumber, + }); + allReviews = resp.data; + } catch (err) { + console.log(`Could not fetch reviews: ${err.message}`); + } + + const REVIEW_STATES = ['APPROVED', 'CHANGES_REQUESTED', 'COMMENTED']; + function getLatestStatus(login) { + const userReviews = allReviews.filter( + r => r.user.login.toLowerCase() === login.toLowerCase() && + REVIEW_STATES.includes(r.state) + ); + if (userReviews.length === 0) return 'pending'; + return userReviews[userReviews.length - 1].state.toLowerCase(); + } + + // Build reviewer status lines + const mainStatus = getLatestStatus(prData.main_reviewer); + const reviewerObjs = [{ login: prData.main_reviewer, slack: prData.main_reviewer_slack, status: mainStatus }]; + + if (prData.second_reviewer) { + const secondStatus = getLatestStatus(prData.second_reviewer); + reviewerObjs.push({ login: prData.second_reviewer, slack: prData.second_reviewer_slack, status: secondStatus }); + } + + const authorSlackId = config.github_to_slack[prData.author]; + const authorIsAlways = authorSlackId === config.always_reviewer_slack; + + let alwaysReviewerObj = null; + if (!authorIsAlways) { + const alwaysEntry = Object.entries(config.github_to_slack).find( + ([, slackId]) => slackId === config.always_reviewer_slack + ); + if (alwaysEntry) { + const alwaysStatus = getLatestStatus(alwaysEntry[0]); + alwaysReviewerObj = { slack: config.always_reviewer_slack, status: alwaysStatus }; + } + } + + const reviewerLines = reviewerObjs.map(r => + `${STATUS_EMOJI[r.status]} <@${r.slack}> — ${STATUS_LABEL[r.status]}` + ); + if (alwaysReviewerObj) { + reviewerLines.push(`${STATUS_EMOJI[alwaysReviewerObj.status]} <@${alwaysReviewerObj.slack}> — ${STATUS_LABEL[alwaysReviewerObj.status]}`); + } + + // ── Update original Slack message ──────────────────────── + if (prData.slack_thread_ts) { + const headerText = wasMerged + ? ':merged: Merged' + : ':x: Closed'; + + const blocks = [ + { + type: 'header', + text: { type: 'plain_text', text: headerText, emoji: true }, + }, + { + type: 'section', + text: { + type: 'mrkdwn', + text: `~<${prUrl}|#${prNumber} ${prTitle}>~\nAuthor: *${prData.author}*`, + }, + }, + { type: 'divider' }, + { + type: 'section', + text: { type: 'mrkdwn', text: reviewerLines.join('\n') }, + }, + ]; + + await slackApi('chat.update', { + channel: config.slack_channel_id, + ts: prData.slack_thread_ts, + text: `PR #${prNumber} ${wasMerged ? 'merged' : 'closed'}`, + blocks, + }); + console.log(`Updated Slack message for PR #${prNumber}`); + } + + // ── Update bot state ───────────────────────────────────── + prData.status = wasMerged ? 'merged' : 'closed'; + prData.resolved_at = new Date().toISOString(); + fs.writeFileSync(prFilePath, JSON.stringify(prData, null, 2) + '\n'); + console.log(`Marked PR #${prNumber} as ${prData.status}`); + + - name: Commit and push bot-state + working-directory: bot-state + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + git add -A + if git diff --cached --quiet; then + echo "No changes to commit" + exit 0 + fi + + git commit -m "bot: mark PR #${{ github.event.pull_request.number }} as ${{ github.event.pull_request.merged && 'merged' || 'closed' }}" + + for attempt in 1 2 3; do + if git pull --rebase origin bot-state && git push origin bot-state; then + echo "Push succeeded (attempt $attempt)" + exit 0 + fi + echo "Push attempt $attempt failed, retrying in 2s…" + sleep 2 + done + + echo "::error::Failed to push bot-state after 3 attempts" + exit 1 diff --git a/.github/workflows/pr-review-status.yml b/.github/workflows/pr-review-status.yml index bd7dfe6..b76bcb9 100644 --- a/.github/workflows/pr-review-status.yml +++ b/.github/workflows/pr-review-status.yml @@ -88,9 +88,9 @@ jobs: const STATUS_EMOJI = { pending: ':hourglass_flowing_sand:', - approved: ':white_check_mark:', - changes_requested: ':arrows_counterclockwise:', - commented: ':speech_balloon:', + approved: ':approved:', + changes_requested: ':git-request-changes:', + commented: ':git-comment:', }; const STATUS_LABEL = { pending: 'Pending', @@ -107,9 +107,9 @@ jobs: let headerText; if (allDone && !anyChangesRequested) { - headerText = ':white_check_mark: All Reviews Complete'; + headerText = ':approved: All Reviews Complete'; } else if (allDone && anyChangesRequested) { - headerText = ':arrows_counterclockwise: Changes Requested'; + headerText = ':git-request-changes: Changes Requested'; } else { headerText = ':evergreen_tree: Review Requested'; } @@ -217,7 +217,7 @@ jobs: if (prData.slack_thread_ts) { const reviewerSlack = config.github_to_slack[reviewer]; const mention = reviewerSlack ? `<@${reviewerSlack}>` : `*${reviewer}*`; - const emoji = reviewState === 'approved' ? ':white_check_mark:' : ':arrows_counterclockwise:'; + const emoji = reviewState === 'approved' ? ':approved:' : ':git-request-changes:'; const verb = reviewState === 'approved' ? 'approved' : 'requested changes on'; await slackApi('chat.postMessage', { diff --git a/.github/workflows/pr-reviewer-assign.yml b/.github/workflows/pr-reviewer-assign.yml index 18a5ecc..c7f51a2 100644 --- a/.github/workflows/pr-reviewer-assign.yml +++ b/.github/workflows/pr-reviewer-assign.yml @@ -85,9 +85,9 @@ jobs: const STATUS_EMOJI = { pending: ':hourglass_flowing_sand:', - approved: ':white_check_mark:', - changes_requested: ':arrows_counterclockwise:', - commented: ':speech_balloon:', + approved: ':approved:', + changes_requested: ':git-request-changes:', + commented: ':git-comment:', }; const STATUS_LABEL = { pending: 'Pending', @@ -104,9 +104,9 @@ jobs: let headerText; if (allDone && !anyChangesRequested) { - headerText = ':white_check_mark: All Reviews Complete'; + headerText = ':approved: All Reviews Complete'; } else if (allDone && anyChangesRequested) { - headerText = ':arrows_counterclockwise: Changes Requested'; + headerText = ':git-request-changes: Changes Requested'; } else { headerText = ':evergreen_tree: Review Requested'; }