Skip to content

Add daily PR review alerts workflow#3102

Merged
wwwillchen merged 1 commit intodyad-sh:mainfrom
wwwillchen-bot:add-pr-review-alerts-workflow
Mar 30, 2026
Merged

Add daily PR review alerts workflow#3102
wwwillchen merged 1 commit intodyad-sh:mainfrom
wwwillchen-bot:add-pr-review-alerts-workflow

Conversation

@wwwillchen
Copy link
Copy Markdown
Collaborator

@wwwillchen wwwillchen commented Mar 30, 2026

Sends a daily email (8AM Pacific / 15:00 UTC) listing open PRs requesting review from wwwillchen across all dyad-sh org repos. Also supports manual workflow_dispatch trigger.


Open with Devin

Sends a daily email (8AM Pacific / 15:00 UTC) listing open PRs
requesting review from wwwillchen across all dyad-sh org repos.
Also supports manual workflow_dispatch trigger.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@wwwillchen
Copy link
Copy Markdown
Collaborator Author

@BugBot run

@wwwillchen wwwillchen merged commit 0ee6447 into dyad-sh:main Mar 30, 2026
8 of 10 checks passed
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 3 additional findings.

Open in Devin Review

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

`Failed to send PR review alert email: ${response.status} ${body}`,
);
}
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Six utility functions duplicated from existing script

Low Severity

Six utility functions (requireEnv, parseRecipients, readResponseBody, escapeHtml, appendStepSummary, sendMailgunEmail) and the MAILGUN_API_BASE_URL constant are copied verbatim from scripts/github-security-advisory-alert.mjs. Extracting these into a shared module would avoid the maintenance burden of keeping two copies in sync — a bug fix in one file could easily be missed in the other.

Additional Locations (1)
Fix in Cursor Fix in Web

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an automated GitHub Actions workflow that emails a daily digest of open PRs requesting review from a specific user across the dyad-sh org.

Changes:

  • Introduces a Node.js script to query GitHub Search for PRs needing review and send a Mailgun email (plain text + HTML).
  • Adds a scheduled + manual GitHub Actions workflow to run the script daily and on demand.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
scripts/pr-review-alert.mjs Implements PR search, grouping/formatting, and Mailgun email delivery.
.github/workflows/pr-review-alerts.yml Schedules and runs the alert script with GitHub App auth + Mailgun configuration.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +133 to +134
const match = htmlUrl.match(/github\.com\/([^/]+\/[^/]+)\//);
return match ? match[1] : "unknown";
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

formatRepoName is hard-coded to github.com, so on GitHub Enterprise / non-standard hosts (or if the API returns URLs with a different hostname) every PR will be grouped under unknown. Consider parsing htmlUrl via new URL(htmlUrl).pathname and extracting the first two path segments (owner/repo), independent of hostname.

Suggested change
const match = htmlUrl.match(/github\.com\/([^/]+\/[^/]+)\//);
return match ? match[1] : "unknown";
try {
const { pathname } = new URL(htmlUrl);
const parts = pathname.replace(/^\/+|\/+$/g, "").split("/");
if (parts.length >= 2) {
return `${parts[0]}/${parts[1]}`;
}
} catch {
// Ignore URL parsing errors and fall through to "unknown"
}
return "unknown";

Copilot uses AI. Check for mistakes.
Comment on lines +62 to +95
while (true) {
const url = new URL(`${apiBaseUrl}/search/issues`);
url.searchParams.set("q", query);
url.searchParams.set("per_page", "100");
url.searchParams.set("page", String(page));

const response = await fetch(url, {
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/vnd.github+json",
"X-GitHub-Api-Version": GITHUB_API_VERSION,
},
});

if (!response.ok) {
const body = await readResponseBody(response);
throw new Error(
`Failed to search PRs needing review: ${response.status} ${body}`,
);
}

const data = await response.json();
if (!data.items || !Array.isArray(data.items)) {
throw new Error("Unexpected search response shape");
}

allPRs.push(...data.items);

if (allPRs.length >= data.total_count || data.items.length === 0) {
break;
}

page++;
}
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GitHub Search API only supports paging through the first 1000 results (10 pages at per_page=100). This loop can keep incrementing page when total_count is larger, leading to wasted API calls, potential 422 errors, and avoidable rate-limit burn. Consider capping the page count (and optionally surfacing in the summary/email that results may be truncated).

Copilot uses AI. Check for mistakes.
Comment on lines +5 to +6
# Daily at 15:00 UTC (8 AM Pacific Daylight Time)
- cron: "0 15 * * *"
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment (and PR description) imply this runs at "8 AM Pacific / 15:00 UTC", but 15:00 UTC is 8 AM only during PDT (it’s 7 AM during PST). Please either adjust the cron to match the intended local time, or clarify the comment to reflect the DST behavior (fixed UTC time).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files

Confidence score: 4/5

  • Minor workflow runtime mismatch: .github/workflows/pr-review-alerts.yml uses a Node version below the repo’s supported >=24, which could cause the alert script to behave differently than in the project target environment.
  • Overall risk is low since this is confined to CI tooling rather than product code, but aligning the version reduces uncertainty.
  • Pay close attention to .github/workflows/pr-review-alerts.yml - ensure Node version matches the repo’s supported runtime.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name=".github/workflows/pr-review-alerts.yml">

<violation number="1" location=".github/workflows/pr-review-alerts.yml:40">
P2: Use the repository’s supported Node version (>=24) so the alert script runs under the same runtime the project targets.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 22
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Use the repository’s supported Node version (>=24) so the alert script runs under the same runtime the project targets.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/pr-review-alerts.yml, line 40:

<comment>Use the repository’s supported Node version (>=24) so the alert script runs under the same runtime the project targets.</comment>

<file context>
@@ -0,0 +1,54 @@
+      - name: Setup Node
+        uses: actions/setup-node@v4
+        with:
+          node-version: 22
+
+      - name: Send PR review alert email
</file context>
Fix with Cubic

@dyad-assistant
Copy link
Copy Markdown
Contributor

🔍 Dyadbot Code Review Summary

Verdict: ✅ YES - Ready to merge

Reviewed by 3 independent agents: Correctness Expert, Code Health Expert, UX Wizard.

Issues Summary

No HIGH or MEDIUM issues confirmed after validation.

🟢 Low Priority Notes (4 items)
  • Cron comment only accurate during PDT.github/workflows/pr-review-alerts.yml:6 — 15:00 UTC is 8 AM PDT but 7 AM PST (Nov–Mar). Consider: # 15:00 UTC (8 AM PDT / 7 AM PST)
  • Hardcoded GitHub username.github/workflows/pr-review-alerts.yml:49PR_REVIEW_GITHUB_USER is hardcoded to wwwillchen while all other config uses vars/secrets. Could move to ${{ vars.PR_REVIEW_GITHUB_USER }} for consistency
  • readResponseBody name understates truncationscripts/pr-review-alert.mjs:36 — Function silently truncates to 500 chars; a name like readResponseBodyPreview would better communicate intent
  • Plain-text email could use better repo separationscripts/pr-review-alert.mjs:170 — A separator line between repo groups would improve scanability in plain-text email clients
🚫 Dropped False Positives (5 items)
  • escapeHtml is broken / double-encodes — Dropped: The function correctly replaces &&amp;, <&lt;, etc. Agent was confused by entity rendering in the review prompt
  • Pagination infinite loop risk — Dropped: GitHub search API caps at 1000 results; a single reviewer will realistically never hit this. The existing data.items.length === 0 guard prevents true infinite loops
  • Broken URL if GITHUB_REPOSITORY is empty — Dropped: Both GITHUB_REPOSITORY and GITHUB_RUN_ID are always set by GitHub Actions when running in CI
  • No PR age/wait time in email — Dropped: Feature request, not a code defect
  • API error messages not actionable for end users — Dropped: Errors surface in GitHub Actions logs for developers, not in emails to end users

Generated by Dyadbot multi-agent code review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new script, scripts/pr-review-alert.mjs, which automates the process of notifying users about open pull requests awaiting their review. The script fetches relevant PRs from the GitHub API, groups them by repository, and sends a summary email via Mailgun in both plain text and HTML formats. Review feedback suggests enhancing the script's robustness by updating the repository name extraction regex to handle URLs without trailing slashes and quoting the GitHub username in the search query to prevent potential parsing errors.

};

const formatRepoName = (htmlUrl) => {
const match = htmlUrl.match(/github\.com\/([^/]+\/[^/]+)\//);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The regular expression used to extract the repository name requires a trailing slash after the repository name to match. While GitHub Pull Request URLs typically include a path after the repository (e.g., /pull/123), this regex would fail to match a base repository URL like https://github.com/dyad-sh/dyad. Removing the mandatory trailing slash makes the utility more robust.

  const match = htmlUrl.match(/github\.com\/([^/]+\/[^/]+)/);

};

const fetchPRsNeedingReview = async ({ apiBaseUrl, token, username }) => {
const query = `is:open is:pr review-requested:${username} org:dyad-sh`;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The GitHub search query for review-requested might fail if the username contains special characters or spaces (though rare for GitHub handles, it's possible for team names if this script were adapted). It is safer to wrap the username in quotes to ensure the query is parsed correctly by the GitHub Search API.

  const query = 'is:open is:pr review-requested:"' + username + '" org:dyad-sh';

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants