fix(github-actions): refresh approvals that the merge tooling still counts - #3844
fix(github-actions): refresh approvals that the merge tooling still counts#3844s2ongmo wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Code Review
This pull request updates the post-approval changes action to recognize reviews from trusted project members (MEMBER) and ensures that the minimum reviews validation requires at least one approval on the latest commit. Unit tests have been added to verify this behavior. The feedback points out a potential runtime crash in the validation logic if the commit object is null, suggesting the use of optional chaining (commit?.oid) to safely access the commit ID.
| ({authorAssociation, commit}) => | ||
| authorAssociation === 'MEMBER' && commit.oid === pullRequest.headRefOid, |
There was a problem hiding this comment.
In GitHub's GraphQL API, the commit field on a PullRequestReview is nullable (for example, if the commit has been garbage collected or is no longer available after a force-push). Destructuring commit and directly accessing commit.oid without a null/undefined check can lead to a runtime TypeError: Cannot read properties of null (reading 'oid') and crash the validation process.
Using optional chaining (commit?.oid) safely handles cases where commit might be null.
| ({authorAssociation, commit}) => | |
| authorAssociation === 'MEMBER' && commit.oid === pullRequest.headRefOid, | |
| ({authorAssociation, commit}) => | |
| authorAssociation === 'MEMBER' && commit?.oid === pullRequest.headRefOid, |
…ounts The post-approval changes action only kept reviews whose author is a member of the `googlers` organization, but `ng-dev`'s `assertMinimumReviews` accepts an approval from any repository `MEMBER`. The two checks used different trust sets, so an approval that makes a pull request merge-ready could be invisible here. When a member who is not in the `googlers` org approves an external contributor's pull request and marks it merge-ready, this action discards that review, finds no reviews at all, logs `Skipping check as their are no reviews on the pull request.` and returns. No review is requested when the contributor then pushes another commit, so the approval of the previous head keeps satisfying the merge validators for a head nobody reviewed. A `COMMENTED` review caused the same outcome through the other early return. Commenting after approving is common, and GitHub does not treat a comment as replacing an approval, but it was picked up here as the reviewer's latest review and the action returned at the non-approved state check. Meanwhile `assertMinimumReviews` reads `reviews(states: APPROVED)` and still counts the earlier approval. Recognize `MEMBER` reviews and ignore `COMMENTED` reviews when resolving each reviewer's latest review, so the approval is re-requested for the new head and `assertCompletedReviews` holds the merge until that review is completed. Post-approval updates performed by Googlers are unaffected, because the actor check above returns before any review is inspected.
3bd7b5f to
671e1f7
Compare
|
Rebased onto current What I dropped. The earlier version also bound What is left is the freshness action itself, where the trust sets disagree:
With both handled, the action re-requests the review for the new head,
Happy to reshape this however you prefer, including moving the head-binding invariant into a separate force-ignorable validation if you would like it as defence in depth. |
|
Rebased onto Only one file needs human review: The decision: should this action's reviewer set match the set the merge tooling already trusts?
So an approval that is sufficient to merge is not recognised as an approval worth refreshing. This reads as a migration artefact rather than an intended invariant. f556a9a created the action to "rerequest reviews for post approval changes for non-googlers", with a hardcoded allowlist that was effectively the Angular team. #1015 replaced that array with the The Googler path is untouched: the actor check at Happy to split this into two commits ( @josephperrott — you wrote the action and #1015, so you're best placed to rule on it. @alan-agius4 — cc. |
Summary
post-approval-changesand theng-devmerge validators recognize different reviewers, so an approval that makes a pull request merge ready can be invisible to the check that is supposed to refresh it. This aligns the action with the merge tooling:author_associationisMEMBER, not only members of thegooglersorgCOMMENTEDreviews when resolving a reviewer's latest reviewWhy
ng-dev'sassertMinimumReviewsaccepts an approval from any repositoryMEMBER. The action only keeps reviews fromgooglersorg members. When a member who is not in that org approves an external contributor's pull request and addsaction: merge, the action finds no reviews at all, logsSkipping check as their are no reviews on the pull request.and returns. No review is requested when the contributor pushes another commit, so the approval of the previous head keeps satisfying the merge validators for a head nobody reviewed.A
COMMENTEDreview by that reviewer produced the same outcome through the other early return: it was resolved as their latest review and tripped the non-approved state check. Commenting after approving is common, GitHub does not treat a comment as replacing an approval, andassertMinimumReviewsreadsreviews(states: APPROVED), so the earlier approval still counted.With both handled the action re-requests the review for the new head,
reviewRequests.totalCountbecomes non-zero, andassertCompletedReviewsholds the merge until that review is completed. Post-approval updates performed by Googlers are unaffected, because the actor check above returns before any review is inspected.Note on scope
An earlier version of this PR also bound
assertMinimumReviewstoheadRefOid. That validation iscanBeForceIgnored: falseand would have blocked merges this repository intentionally allows (a member updates an already approved pull request and the caretaker merges it): 6 of the last 40 mergedangular/angularpull requests were merged with the onlyMEMBERapproval pointing at an earlier commit. That part has been removed. It could be added later as a separate, force-ignorable validation if the team wants it as defence in depth.Validation
bazel run //github-actions/post-approval-changes:mainto regenerate the checked-in bundlebazel test //github-actions/post-approval-changes:all(main_test,main_prettierignore_test,lib_strict_deps_test) passes