From 632e1a7a906108cc9d7cb22bff365ebad10d892e Mon Sep 17 00:00:00 2001 From: tiffany-kobiton Date: Thu, 13 Aug 2026 16:27:33 -0400 Subject: [PATCH 1/7] Scaffold for daily docs digest --- docs-review-digest.js | 299 ++++++++++++++++++++++++++++++++++++++++ docs-review-digest.yaml | 53 +++++++ 2 files changed, 352 insertions(+) create mode 100644 docs-review-digest.js create mode 100644 docs-review-digest.yaml diff --git a/docs-review-digest.js b/docs-review-digest.js new file mode 100644 index 00000000..b896b228 --- /dev/null +++ b/docs-review-digest.js @@ -0,0 +1,299 @@ +#!/usr/bin/env node + +const REQUIRED_ENV = ["GITHUB_TOKEN", "GITHUB_REPOSITORY"]; + +const READY_LABEL = process.env.READY_LABEL || "ready for review"; +const REVIEWED_LABEL = process.env.REVIEWED_LABEL || "✅ REVIEWED ✅"; +const CHANGES_NEEDED_LABEL = process.env.CHANGES_NEEDED_LABEL || "changes needed"; +const REVIEW_ACTIVITY_WINDOW_HOURS = Number(process.env.REVIEW_ACTIVITY_WINDOW_HOURS || "48"); + +function requireEnv() { + for (const key of REQUIRED_ENV) { + if (!process.env[key]) { + console.error(`Missing required env var: ${key}`); + process.exit(1); + } + } +} + +function daysBetween(startDate, endDate) { + const msPerDay = 24 * 60 * 60 * 1000; + return Math.floor((endDate.getTime() - startDate.getTime()) / msPerDay); +} + +function hoursBetween(startDate, endDate) { + const msPerHour = 60 * 60 * 1000; + return Math.floor((endDate.getTime() - startDate.getTime()) / msPerHour); +} + +function hasLabel(pr, labelName) { + return pr.labels.nodes.some((label) => label.name === labelName); +} + +function latestReviewDate(pr) { + const reviewDates = pr.reviews.nodes.map((review) => new Date(review.submittedAt)); + const commentDates = pr.reviewThreads.nodes.flatMap((thread) => + thread.comments.nodes.map((comment) => new Date(comment.createdAt)) + ); + + const allDates = [...reviewDates, ...commentDates].filter((date) => !Number.isNaN(date.getTime())); + + if (allDates.length === 0) { + return null; + } + + return new Date(Math.max(...allDates.map((date) => date.getTime()))); +} + +function hasApproval(pr) { + return pr.reviews.nodes.some((review) => review.state === "APPROVED"); +} + +function bucketForAge(daysReady) { + if (daysReady >= 14) { + return "very_stale"; + } + + if (daysReady >= 7) { + return "stale"; + } + + if (daysReady >= 5) { + return "needs_attention"; + } + + if (daysReady >= 3) { + return "coming_up"; + } + + return null; +} + +async function githubGraphql(query, variables) { + const response = await fetch("https://api.github.com/graphql", { + method: "POST", + headers: { + Authorization: `Bearer ${process.env.GITHUB_TOKEN}`, + "Content-Type": "application/json", + "User-Agent": "docs-review-digest" + }, + body: JSON.stringify({ query, variables }) + }); + + const body = await response.json(); + + if (!response.ok || body.errors) { + throw new Error(`GitHub GraphQL query failed: ${JSON.stringify(body, null, 2)}`); + } + + return body.data; +} + +async function fetchOpenPullRequests(owner, repo) { + const query = ` + query($owner: String!, $repo: String!, $cursor: String) { + repository(owner: $owner, name: $repo) { + pullRequests( + states: OPEN + first: 50 + after: $cursor + orderBy: { field: CREATED_AT, direction: DESC } + ) { + pageInfo { + hasNextPage + endCursor + } + nodes { + number + title + url + author { + login + } + createdAt + isDraft + labels(first: 20) { + nodes { + name + } + } + reviewRequests(first: 20) { + nodes { + requestedReviewer { + ... on User { + login + } + ... on Team { + name + } + } + } + } + reviews(first: 50, states: [APPROVED, CHANGES_REQUESTED, COMMENTED], author: null) { + nodes { + state + submittedAt + author { + login + } + } + } + reviewThreads(first: 50) { + nodes { + comments(first: 20) { + nodes { + createdAt + author { + login + } + } + } + } + } + timelineItems(first: 100, itemTypes: [LABELED_EVENT]) { + nodes { + ... on LabeledEvent { + createdAt + label { + name + } + } + } + } + } + } + } + } + `; + + const prs = []; + let cursor = null; + + do { + const data = await githubGraphql(query, { owner, repo, cursor }); + const page = data.repository.pullRequests; + + prs.push(...page.nodes); + + cursor = page.pageInfo.hasNextPage ? page.pageInfo.endCursor : null; + } while (cursor); + + return prs; +} + +function getReadyForReviewDate(pr) { + const readyLabelEvents = pr.timelineItems.nodes + .filter((item) => item.label?.name === READY_LABEL) + .map((item) => new Date(item.createdAt)) + .filter((date) => !Number.isNaN(date.getTime())); + + if (readyLabelEvents.length === 0) { + return new Date(pr.createdAt); + } + + return new Date(Math.max(...readyLabelEvents.map((date) => date.getTime()))); +} + +function mapReviewerNames(pr) { + const reviewers = pr.reviewRequests.nodes + .map((request) => request.requestedReviewer?.login || request.requestedReviewer?.name) + .filter(Boolean); + + return reviewers.length > 0 ? reviewers : ["Unassigned"]; +} + +function buildDigest(prs) { + const now = new Date(); + + const digest = { + source: "github", + repository: process.env.GITHUB_REPOSITORY, + queried_at: now.toISOString(), + criteria: { + ready_label: READY_LABEL, + reviewed_label: REVIEWED_LABEL, + changes_needed_label: CHANGES_NEEDED_LABEL, + review_activity_window_hours: REVIEW_ACTIVITY_WINDOW_HOURS + }, + total_count: 0, + buckets: { + coming_up: [], + needs_attention: [], + stale: [], + very_stale: [] + } + }; + + for (const pr of prs) { + if (pr.isDraft) { + continue; + } + + if (!hasLabel(pr, READY_LABEL)) { + continue; + } + + if (hasLabel(pr, REVIEWED_LABEL)) { + continue; + } + + if (hasApproval(pr)) { + continue; + } + + const latestReview = latestReviewDate(pr); + if (latestReview) { + const hoursSinceReview = hoursBetween(latestReview, now); + + if (hoursSinceReview < REVIEW_ACTIVITY_WINDOW_HOURS) { + continue; + } + } + + const readyForReviewAt = getReadyForReviewDate(pr); + const daysReady = daysBetween(readyForReviewAt, now); + const bucket = bucketForAge(daysReady); + + if (!bucket) { + continue; + } + + const item = { + number: pr.number, + title: pr.title, + url: pr.url, + author: pr.author?.login || "unknown", + reviewers: mapReviewerNames(pr), + ready_for_review_at: readyForReviewAt.toISOString(), + days_ready: daysReady, + latest_review_activity_at: latestReview ? latestReview.toISOString() : null, + labels: pr.labels.nodes.map((label) => label.name) + }; + + digest.buckets[bucket].push(item); + digest.total_count += 1; + } + + return digest; +} + +async function main() { + requireEnv(); + + const [owner, repo] = process.env.GITHUB_REPOSITORY.split("/"); + + if (!owner || !repo) { + throw new Error(`Invalid GITHUB_REPOSITORY value: ${process.env.GITHUB_REPOSITORY}`); + } + + const prs = await fetchOpenPullRequests(owner, repo); + const digest = buildDigest(prs); + + console.log(JSON.stringify(digest, null, 2)); +} + +main().catch((error) => { + console.error("Failed to build docs review digest."); + console.error(error); + process.exit(1); +}); \ No newline at end of file diff --git a/docs-review-digest.yaml b/docs-review-digest.yaml new file mode 100644 index 00000000..cba3fcb9 --- /dev/null +++ b/docs-review-digest.yaml @@ -0,0 +1,53 @@ +name: Dinner Bell + +on: + workflow_dispatch: + + schedule: + # 10:00 AM Eastern during daylight saving time. + # GitHub cron uses UTC. + - cron: "0 14 * * 1-5" + + permissions: + contents: read + pull-requests: read + issues: read + + jobs: + docs-review-digest: + runs-on: ubuntu-latest + + steps: + - name: Check out docs repo + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Build docs review digest + run: node .github/scripts/docs-review-digest.js > ${{ runner.temp }}/docs-review-digest.json + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_REPOSITORY: ${{ github.repository }} + READY_LABEL: "ready for review" + REVIEWED_LABEL: "✅ REVIEWED ✅" + CHANGES_NEEDED_LABEL: "changes needed" + REVIEW_ACTIVITY_WINDOW_HOURS: "48" + + - name: Show digest summary + run: | + echo "Digest file created:" + ls -lh ${{ runner.temp }}/docs-review-digest.json + echo "Digest summary:" + node -e "const fs=require('fs'); const d=JSON.parse(fs.readFileSync(process.env.DIGEST_FILE,'utf8')); console.log('Total PRs:', d.total_count); console.log('3-4 days:', d.buckets.coming_up.length); console.log('5-6 days:', d.buckets.needs_attention.length); console.log('7-13 days:', d.buckets.stale.length); console.log('14+ days:', d.buckets.very_stale.length);" + env: + DIGEST_FILE: ${{ runner.temp }}/docs-review-digest.json + + - name: Upload digest artifact + uses: actions/upload-artifact@v5 + with: + name: docs-review-digest + path: ${{ runner.temp }}/docs-review-digest.json + retention-days: 7 \ No newline at end of file From af5c641e9c59d130bb8bd87df1783fcf55d7defd Mon Sep 17 00:00:00 2001 From: tiffany-kobiton Date: Thu, 13 Aug 2026 16:35:17 -0400 Subject: [PATCH 2/7] Disable schedule runs, move to scripts dir --- .../scripts/docs-review-digest.js | 0 .../scripts/docs-review-digest.yaml | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename docs-review-digest.js => .github/scripts/docs-review-digest.js (100%) rename docs-review-digest.yaml => .github/scripts/docs-review-digest.yaml (97%) diff --git a/docs-review-digest.js b/.github/scripts/docs-review-digest.js similarity index 100% rename from docs-review-digest.js rename to .github/scripts/docs-review-digest.js diff --git a/docs-review-digest.yaml b/.github/scripts/docs-review-digest.yaml similarity index 97% rename from docs-review-digest.yaml rename to .github/scripts/docs-review-digest.yaml index cba3fcb9..66c4f911 100644 --- a/docs-review-digest.yaml +++ b/.github/scripts/docs-review-digest.yaml @@ -3,10 +3,10 @@ name: Dinner Bell on: workflow_dispatch: - schedule: +# schedule: # 10:00 AM Eastern during daylight saving time. # GitHub cron uses UTC. - - cron: "0 14 * * 1-5" +# - cron: "0 14 * * 1-5" permissions: contents: read From aa60a185ee5a74b9e4b9d0c21cb28d669698bbf5 Mon Sep 17 00:00:00 2001 From: tiffany-kobiton Date: Thu, 13 Aug 2026 16:53:34 -0400 Subject: [PATCH 3/7] Fix paths --- .github/scripts/docs-review-digest.yaml | 53 --------------------- .github/workflows/docs-review-digest.yaml | 58 +++++++++++++++++++++++ 2 files changed, 58 insertions(+), 53 deletions(-) delete mode 100644 .github/scripts/docs-review-digest.yaml create mode 100644 .github/workflows/docs-review-digest.yaml diff --git a/.github/scripts/docs-review-digest.yaml b/.github/scripts/docs-review-digest.yaml deleted file mode 100644 index 66c4f911..00000000 --- a/.github/scripts/docs-review-digest.yaml +++ /dev/null @@ -1,53 +0,0 @@ -name: Dinner Bell - -on: - workflow_dispatch: - -# schedule: - # 10:00 AM Eastern during daylight saving time. - # GitHub cron uses UTC. -# - cron: "0 14 * * 1-5" - - permissions: - contents: read - pull-requests: read - issues: read - - jobs: - docs-review-digest: - runs-on: ubuntu-latest - - steps: - - name: Check out docs repo - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: "20" - - - name: Build docs review digest - run: node .github/scripts/docs-review-digest.js > ${{ runner.temp }}/docs-review-digest.json - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GITHUB_REPOSITORY: ${{ github.repository }} - READY_LABEL: "ready for review" - REVIEWED_LABEL: "✅ REVIEWED ✅" - CHANGES_NEEDED_LABEL: "changes needed" - REVIEW_ACTIVITY_WINDOW_HOURS: "48" - - - name: Show digest summary - run: | - echo "Digest file created:" - ls -lh ${{ runner.temp }}/docs-review-digest.json - echo "Digest summary:" - node -e "const fs=require('fs'); const d=JSON.parse(fs.readFileSync(process.env.DIGEST_FILE,'utf8')); console.log('Total PRs:', d.total_count); console.log('3-4 days:', d.buckets.coming_up.length); console.log('5-6 days:', d.buckets.needs_attention.length); console.log('7-13 days:', d.buckets.stale.length); console.log('14+ days:', d.buckets.very_stale.length);" - env: - DIGEST_FILE: ${{ runner.temp }}/docs-review-digest.json - - - name: Upload digest artifact - uses: actions/upload-artifact@v5 - with: - name: docs-review-digest - path: ${{ runner.temp }}/docs-review-digest.json - retention-days: 7 \ No newline at end of file diff --git a/.github/workflows/docs-review-digest.yaml b/.github/workflows/docs-review-digest.yaml new file mode 100644 index 00000000..63fa9456 --- /dev/null +++ b/.github/workflows/docs-review-digest.yaml @@ -0,0 +1,58 @@ +name: Dinner Bell + +on: + workflow_dispatch: + + pull_request: + paths: + - ".github/workflows/docs-review-digest.yml" + - ".github/scripts/docs-review-digest.js" + +# schedule: + # 10:00 AM Eastern during daylight saving time. + # GitHub cron uses UTC. +# - cron: "0 14 * * 1-5" + +permissions: + contents: read + pull-requests: read + issues: read + +jobs: + docs-review-digest: + runs-on: ubuntu-latest + + steps: + - name: Check out docs repo + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Build docs review digest + run: node .github/scripts/docs-review-digest.js > ${{ runner.temp }}/docs-review-digest.json + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_REPOSITORY: ${{ github.repository }} + READY_LABEL: "ready for review" + REVIEWED_LABEL: "✅ REVIEWED ✅" + CHANGES_NEEDED_LABEL: "changes needed" + REVIEW_ACTIVITY_WINDOW_HOURS: "48" + + - name: Show digest summary + run: | + echo "Digest file created:" + ls -lh ${{ runner.temp }}/docs-review-digest.json + echo "Digest summary:" + node -e "const fs=require('fs'); const d=JSON.parse(fs.readFileSync(process.env.DIGEST_FILE,'utf8')); console.log('Total PRs:', d.total_count); console.log('3-4 days:', d.buckets.coming_up.length); console.log('5-6 days:', d.buckets.needs_attention.length); console.log('7-13 days:', d.buckets.stale.length); console.log('14+ days:', d.buckets.very_stale.length);" + env: + DIGEST_FILE: ${{ runner.temp }}/docs-review-digest.json + + - name: Upload digest artifact + uses: actions/upload-artifact@v5 + with: + name: docs-review-digest + path: ${{ runner.temp }}/docs-review-digest.json + retention-days: 7 \ No newline at end of file From 3890a7940a856cfc03b9f7ff8f7884eb8885b4ed Mon Sep 17 00:00:00 2001 From: tiffany-kobiton Date: Tue, 18 Aug 2026 15:27:24 -0400 Subject: [PATCH 4/7] Update names, fix paths --- .../scripts/{docs-review-digest.js => check-review-status.js} | 0 .../workflows/{docs-review-digest.yaml => status-digest.yaml} | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename .github/scripts/{docs-review-digest.js => check-review-status.js} (100%) rename .github/workflows/{docs-review-digest.yaml => status-digest.yaml} (94%) diff --git a/.github/scripts/docs-review-digest.js b/.github/scripts/check-review-status.js similarity index 100% rename from .github/scripts/docs-review-digest.js rename to .github/scripts/check-review-status.js diff --git a/.github/workflows/docs-review-digest.yaml b/.github/workflows/status-digest.yaml similarity index 94% rename from .github/workflows/docs-review-digest.yaml rename to .github/workflows/status-digest.yaml index 63fa9456..414fda53 100644 --- a/.github/workflows/docs-review-digest.yaml +++ b/.github/workflows/status-digest.yaml @@ -5,8 +5,8 @@ on: pull_request: paths: - - ".github/workflows/docs-review-digest.yml" - - ".github/scripts/docs-review-digest.js" + - ".github/workflows/status-digest.yaml" + - ".github/scripts/check-review-status.js" # schedule: # 10:00 AM Eastern during daylight saving time. From 6f9551b33cd707ec6d292d490b96f931a00188e7 Mon Sep 17 00:00:00 2001 From: tiffany-kobiton Date: Wed, 19 Aug 2026 15:55:42 -0400 Subject: [PATCH 5/7] Normalize names --- ...{check-review-status.js => docs-review-digest.js} | 0 .github/workflows/status-digest.yaml | 12 ++++++------ 2 files changed, 6 insertions(+), 6 deletions(-) rename .github/scripts/{check-review-status.js => docs-review-digest.js} (100%) diff --git a/.github/scripts/check-review-status.js b/.github/scripts/docs-review-digest.js similarity index 100% rename from .github/scripts/check-review-status.js rename to .github/scripts/docs-review-digest.js diff --git a/.github/workflows/status-digest.yaml b/.github/workflows/status-digest.yaml index 414fda53..d44b6398 100644 --- a/.github/workflows/status-digest.yaml +++ b/.github/workflows/status-digest.yaml @@ -6,12 +6,12 @@ on: pull_request: paths: - ".github/workflows/status-digest.yaml" - - ".github/scripts/check-review-status.js" + - ".github/scripts/docs-review-digest.js" -# schedule: - # 10:00 AM Eastern during daylight saving time. - # GitHub cron uses UTC. -# - cron: "0 14 * * 1-5" + # schedule: + # # 10:00 AM Eastern during daylight saving time. + # # GitHub cron uses UTC. + # - cron: "0 14 * * 1-5" permissions: contents: read @@ -29,7 +29,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: "20" + node-version: "24" - name: Build docs review digest run: node .github/scripts/docs-review-digest.js > ${{ runner.temp }}/docs-review-digest.json From a74ec3f52a5d08461d87622eac60c8ba67a56cf6 Mon Sep 17 00:00:00 2001 From: tiffany-kobiton Date: Wed, 19 Aug 2026 16:08:01 -0400 Subject: [PATCH 6/7] Add Slack artifact generation --- .github/scripts/render-docs-review-digest.js | 90 ++++++++++++++++++++ .github/workflows/status-digest.yaml | 14 +++ 2 files changed, 104 insertions(+) create mode 100644 .github/scripts/render-docs-review-digest.js diff --git a/.github/scripts/render-docs-review-digest.js b/.github/scripts/render-docs-review-digest.js new file mode 100644 index 00000000..60552619 --- /dev/null +++ b/.github/scripts/render-docs-review-digest.js @@ -0,0 +1,90 @@ +#!/usr/bin/env node + +const fs = require("fs"); + +const inputFile = process.env.DIGEST_FILE; +const outputFile = process.env.SLACK_MESSAGE_FILE; + +if (!inputFile) { + console.error("Missing DIGEST_FILE."); + process.exit(1); +} + +if (!outputFile) { + console.error("Missing SLACK_MESSAGE_FILE."); + process.exit(1); +} + +const digest = JSON.parse(fs.readFileSync(inputFile, "utf8")); + +const bucketLabels = [ + ["needs_attention", "Needs attention, 5-6 days"], + ["stale", "Stale, 7-13 days"], + ["very_stale", "Very stale, 14+ days"], + ["coming_up", "Coming up, 3-4 days"], +]; + +function pluralize(count, singular, plural = `${singular}s`) { + return count === 1 ? singular : plural; +} + +function formatReviewers(reviewers) { + if (!reviewers || reviewers.length === 0) { + return "No requested reviewers"; + } + + return reviewers.join(", "); +} + +function formatPr(pr) { + const latestActivity = pr.latest_review_activity_at + ? `Latest review activity: ${pr.latest_review_activity_at}` + : "No recorded review activity"; + + return [ + `• <${pr.url}|#${pr.number} ${pr.title}>`, + ` Author: ${pr.author}`, + ` Reviewers: ${formatReviewers(pr.reviewers)}`, + ` Ready for review: ${pr.days_ready} ${pluralize(pr.days_ready, "day")}`, + ` ${latestActivity}`, + ].join("\n"); +} + +const lines = []; + +lines.push("🔔 *Dinner Bell: Docs PRs waiting for review*"); +lines.push(""); +lines.push( + "These PRs are labeled `ready for review` and do not appear to have approval or recent review activity." +); +lines.push(""); +lines.push( + "Please review, approve, or comment with blockers. If these PRs should not move forward, please say so in the PR so docs can close the loop." +); +lines.push(""); +lines.push(`Total waiting: ${digest.total_count}`); + +for (const [bucketKey, bucketTitle] of bucketLabels) { + const prs = digest.buckets[bucketKey] || []; + + if (prs.length === 0) { + continue; + } + + lines.push(""); + lines.push(`*${bucketTitle}*`); + lines.push(""); + + for (const pr of prs) { + lines.push(formatPr(pr)); + lines.push(""); + } +} + +if (digest.total_count === 0) { + lines.push(""); + lines.push("No docs PRs need review right now."); +} + +fs.writeFileSync(outputFile, `${lines.join("\n").trim()}\n`); +console.log(`Wrote Slack message to ${outputFile}`); \ No newline at end of file diff --git a/.github/workflows/status-digest.yaml b/.github/workflows/status-digest.yaml index d44b6398..e078dc26 100644 --- a/.github/workflows/status-digest.yaml +++ b/.github/workflows/status-digest.yaml @@ -7,6 +7,7 @@ on: paths: - ".github/workflows/status-digest.yaml" - ".github/scripts/docs-review-digest.js" + - ".github/scripts/render-docs-review-digest.js" # schedule: # # 10:00 AM Eastern during daylight saving time. @@ -55,4 +56,17 @@ jobs: with: name: docs-review-digest path: ${{ runner.temp }}/docs-review-digest.json + retention-days: 7 + + - name: Render Slack digest message + run: node .github/scripts/render-docs-review-digest.js + env: + DIGEST_FILE: ${{ runner.temp }}/docs-review-digest.json + SLACK_MESSAGE_FILE: ${{ runner.temp }}/docs-review-digest-slack.txt + + - name: Upload Slack digest artifact + uses: actions/upload-artifact@v5 + with: + name: docs-review-digest-slack + path: ${{ runner.temp }}/docs-review-digest-slack.txt retention-days: 7 \ No newline at end of file From 1f5173bcf47578c81289278a9156b539da045cc7 Mon Sep 17 00:00:00 2001 From: tiffany-kobiton Date: Wed, 19 Aug 2026 16:48:58 -0400 Subject: [PATCH 7/7] Add Slack webhook placeholder --- .github/workflows/status-digest.yaml | 29 +++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/.github/workflows/status-digest.yaml b/.github/workflows/status-digest.yaml index e078dc26..c3c81d32 100644 --- a/.github/workflows/status-digest.yaml +++ b/.github/workflows/status-digest.yaml @@ -2,6 +2,15 @@ name: Dinner Bell on: workflow_dispatch: + inputs: + post_to_slack: + description: "Post the digest to Slack" + required: false + default: "false" + type: choice + options: + - "true" + - "false" pull_request: paths: @@ -69,4 +78,22 @@ jobs: with: name: docs-review-digest-slack path: ${{ runner.temp }}/docs-review-digest-slack.txt - retention-days: 7 \ No newline at end of file + retention-days: 7 + + - name: Post Slack digest + if: ${{ github.event_name == 'workflow_dispatch' && inputs.post_to_slack == 'true' }} + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + SLACK_MESSAGE_FILE: ${{ runner.temp }}/docs-review-digest-slack.txt + run: | + if [ -z "$SLACK_WEBHOOK_URL" ]; then + echo "Missing SLACK_WEBHOOK_URL." + exit 1 + fi + + MESSAGE="$(cat "$SLACK_MESSAGE_FILE")" + + curl -X POST \ + -H "Content-type: application/json" \ + --data "$(jq -n --arg text "$MESSAGE" '{text: $text}')" \ + "$SLACK_WEBHOOK_URL" \ No newline at end of file