Skip to content

chore: add review enforcement workflow#534

Open
john-weiler wants to merge 1 commit into
mainfrom
chore/review-enforcement-workflow
Open

chore: add review enforcement workflow#534
john-weiler wants to merge 1 commit into
mainfrom
chore/review-enforcement-workflow

Conversation

@john-weiler

@john-weiler john-weiler commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

User description

Summary

This PR adds review enforcement workflow to support automatic merging of Dependabot PRs when CI passes, with automatic review request escalation when CI fails.

The workflow ensures:

  • Non-Dependabot PRs require explicit approval from a team member
  • Dependabot PRs are auto-approved and merged when CI passes
  • On CI failure, a random team member is requested for review

The team for review requests is configured per-repo:

  • Product team repos → rungalileo/product
  • Platform team repos → rungalileo/platform
  • UI team repos → rungalileo/ui

Test plan

  • Merge this PR
  • CI should run and pass
  • Dependabot PRs will be auto-merged when CI passes
  • CI failures will trigger a review request to the appropriate team

Generated description

Below is a concise technical summary of the changes proposed in this PR:
Add a review enforcement workflow that tracks approvals and blocks non-Dependabot pull requests until a non-baz-reviewer team member signs off. Add Dependabot automation that leverages getDependabotPr and request-team-reviewer helpers to auto-approve/merge passing Dependabot PRs and to escalate failures with random team reviewers.

TopicDetails
Review Enforcement Enforce non-Dependabot PR approvals via the review policy job that watches pull_request and pull_request_review events, retries review fetches, and requires a non-baz-reviewer User approval before allowing progress.
Modified files (1)
  • .github/workflows/review-enforcement.yml
Latest Contributors(0)
UserCommitDate
Dependabot Automation Auto-handle Dependabot PRs using getDependabotPr and request-team-reviewer to approve and merge successful CI runs or to pick a random team reviewer when CI fails, including random team selection safeguards and auto-merge state handling.
Modified files (3)
  • .github/scripts/get-dependabot-pr.js
  • .github/scripts/request-team-reviewer.js
  • .github/workflows/review-enforcement.yml
Latest Contributors(0)
UserCommitDate
This pull request is reviewed by Baz. Review like a pro on (Baz).

Comment on lines +164 to +168
if (mergeablePr.mergeable === false || mergeablePr.mergeable_state === 'dirty') {
core.info(`PR #${prNumber} is not mergeable (state: ${mergeablePr.mergeable_state}) - requesting human review.`);
const requestProductReviewer = require('./.github/scripts/request-product-reviewer.js');
await requestProductReviewer({ github, context, core, prNumber, teamSlug: '"product"' });
return;

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.

dependabot-auto-merge requires ./.github/scripts/request-product-reviewer.js which doesn't exist and throws Cannot find module — should we add the missing helper or remove the import?

Finding type: Logical Bugs | Severity: 🔴 High


Want Baz to fix this for you? Activate Fixer

Other fix methods

Fix in Cursor

Prompt for AI Agents:

Before applying, verify this suggestion against the current code. In
.github/workflows/review-enforcement.yml around lines 164-168, the dependabot-auto-merge
job calls require('./.github/scripts/request-product-reviewer.js') but that module
doesn't exist, causing the job to throw. Add a new file
.github/scripts/request-product-reviewer.js that exports an async function with
signature ({ github, context, core, prNumber, teamSlug }) which selects a reviewer
(e.g., a random member from the given teamSlug or a deterministic fallback), requests a
review via github.rest.pulls.requestReview or github.rest.teams.listMembers +
pulls.requestReview, and returns when the request is created; ensure the module uses
module.exports = requestProductReviewer so require() works. Alternatively, if you prefer
not to add a file, modify the workflow at those lines to inline the reviewer-request
logic instead of requiring a non-existent module.

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.

Commit 549b297 addressed this comment by introducing .github/scripts/request-team-reviewer.js (which exports the required reviewer helper) and updating the dependabot jobs to require that existing script instead of the missing request-product-reviewer.js.

@codecov

codecov Bot commented Apr 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 82.76%. Comparing base (6afaa04) to head (7567416).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #534      +/-   ##
==========================================
+ Coverage   82.67%   82.76%   +0.09%     
==========================================
  Files         119      119              
  Lines        9725     9750      +25     
==========================================
+ Hits         8040     8070      +30     
+ Misses       1685     1680       -5     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@john-weiler john-weiler force-pushed the chore/review-enforcement-workflow branch 3 times, most recently from 549b297 to 470668c Compare April 3, 2026 17:53
Comment on lines +57 to +68
// Fetch reviews with retry for eventual consistency
let reviews;
let attempts = 0;
while (attempts < 3) {
const result = await github.rest.pulls.listReviews({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr.number
});
reviews = result.data;

// If we have reviews or this is not a review event, stop retrying

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.

listReviews returns full history but filtering state === 'APPROVED' without deduping by reviewer lets approvals and hasNonBazApproval stay true after later negative reviews — should we collapse reviews to each reviewer's latest review or ignore approvals superseded by a non-APPROVED state before deciding the policy is satisfied?

Finding type: Logical Bugs | Severity: 🔴 High


Want Baz to fix this for you? Activate Fixer

Other fix methods

Fix in Cursor

Prompt for AI Agents:

Before applying, verify this suggestion against the current code. In
.github/workflows/review-enforcement.yml around lines 57 to 95, the
review-fetching/approval-check logic incorrectly treats every APPROVED entry in the
review history the same and does not deduplicate by reviewer, so an older approval can
be counted even if that reviewer later submitted CHANGES_REQUESTED or had their approval
dismissed. Change the logic to collapse reviews to each reviewer's latest review (use
submitted_at or the most recent entry) before computing approvals — build a map keyed
by reviewer login selecting the latest review, then derive approvals from that
deduplicated set and check for a non-baz-reviewer APPROVED state. Ensure DISMISSED and
CHANGES_REQUESTED override earlier APPROVED entries so they are not counted.

@john-weiler john-weiler force-pushed the chore/review-enforcement-workflow branch from 470668c to 671e78b Compare April 3, 2026 18:05
@john-weiler john-weiler enabled auto-merge (squash) April 3, 2026 18:14
@john-weiler john-weiler force-pushed the chore/review-enforcement-workflow branch from 671e78b to 7567416 Compare April 3, 2026 18:16
Comment on lines +45 to +53
const { data: reviewRequests } =
await github.rest.pulls.listRequestedReviewers({
owner,
repo,
pull_number: prNumber
});
const hasPendingTeamReview = reviewRequests.users.some((u) =>
teamMemberSet.has(u.login)
);

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.

request-team-reviewer only checks reviewRequests.users for a member login — should we treat an existing entry in reviewRequests.teams for the requested slug as already requested before selecting a random member?

Finding type: Logical Bugs | Severity: 🔴 High


Want Baz to fix this for you? Activate Fixer

Other fix methods

Fix in Cursor

Prompt for AI Agents:

Before applying, verify this suggestion against the current code. In
.github/scripts/request-team-reviewer.js around lines 45 to 53, the logic that
determines whether a team review is already requested only checks reviewRequests.users
and ignores reviewRequests.teams. Update this block to also inspect reviewRequests.teams
and treat an existing team request for the same team slug (or a team entry whose slug
equals teamSlug or whose name/full_name equals `rungalileo/${teamSlug}`) as already
requested; if found, log the skip and return without selecting a random member. Ensure
the check works whether the API returns a slug property or a full/team name.

@galileo-automation

Copy link
Copy Markdown
Contributor

No activity for 30 days — this PR will be closed in 5 days unless updated.

1 similar comment
@galileo-automation

Copy link
Copy Markdown
Contributor

No activity for 30 days — this PR will be closed in 5 days unless updated.

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