Skip to content

Commit 6a270f7

Browse files
committed
Require that PR head matches that of diff when merging
Due to the limitations imposed by by using both `pull_request_target` and `issue_comment` events to trigger the "Manage PRs" workflow, the PR diff used for the validation is procured via a GitHub API request. It is necessary to check that the pull request state matches that of the diff, which is achieved via the `sha` parameter of the GitHub API request used to merge. This can not be determined from the `github` context provided by GitHub Actions to the workflow for either of the trigger events, so the pull request metadata is requested from the GitHub API at the same time as the diff. This situation requires different handling by the `merge-fail` job. Fortunately, the two failure causes result in different values from the merge request workflow step's `status` output.
1 parent 03bdfa7 commit 6a270f7

File tree

1 file changed

+44
-9
lines changed

1 file changed

+44
-9
lines changed

.github/workflows/manage-prs.yml

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,20 @@ jobs:
4242
artifact: ${{ steps.configuration.outputs.artifact }}
4343
path: ${{ steps.configuration.outputs.path }}
4444
filename: ${{ steps.configuration.outputs.filename }}
45+
head: ${{ steps.head.outputs.head }}
46+
47+
env:
48+
# See: https://docs.github.com/en/rest/reference/pulls#custom-media-types-for-pull-requests
49+
DIFF_IDENTIFIER: diff
50+
JSON_IDENTIFIER: raw+json
4551

4652
steps:
4753
- name: Set configuration outputs
4854
id: configuration
4955
run: |
5056
echo "::set-output name=artifact::diff"
5157
echo "::set-output name=path::${{ runner.temp }}"
52-
echo "::set-output name=filename::diff.txt"
58+
echo "::set-output name=filename::${{ env.DIFF_IDENTIFIER }}"
5359
5460
- name: Comment on comment trigger to provide feedback
5561
if: github.event_name == 'issue_comment'
@@ -67,18 +73,29 @@ jobs:
6773
|
6874
Hello! I'm checking your submission again.
6975
70-
- name: Get PR diff
76+
- name: Get PR data
7177
env:
7278
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
7379
run: |
80+
# Two API requests are necessary, one for the PR diff and another for the metadata.
7481
# It's necessary to reference both pull_request.number and issue.number because only one of the two are
7582
# defined depending on whether the workflow is triggered by PR or comment event.
76-
curl \
77-
--fail \
78-
--output "${{ steps.configuration.outputs.path }}/${{ steps.configuration.outputs.filename }}" \
79-
--header "Authorization: token $GITHUB_TOKEN" \
80-
--header "Accept: application/vnd.github.v3.diff" \
81-
https://api.github.com/repos/${{ github.repository_owner }}/${{ github.event.repository.name }}/pulls/${{ github.event.pull_request.number }}${{ github.event.issue.number }}
83+
parallel \
84+
' \
85+
curl \
86+
--fail \
87+
--output "${{ steps.configuration.outputs.path }}/{}" \
88+
--header "Authorization: token $GITHUB_TOKEN" \
89+
--header "Accept: application/vnd.github.v3.{}" \
90+
https://api.github.com/repos/${{ github.repository_owner }}/${{ github.event.repository.name }}/pulls/${{ github.event.pull_request.number }}${{ github.event.issue.number }}
91+
' \
92+
::: \
93+
${{ env.DIFF_IDENTIFIER }} \
94+
${{ env.JSON_IDENTIFIER }}
95+
96+
- name: Get head SHA of diff
97+
id: head
98+
run: echo "::set-output name=head::$(jq -c .head.sha "${{ steps.configuration.outputs.path }}/${{ env.JSON_IDENTIFIER }}")"
8299

83100
- name: Upload diff file to workflow artifact
84101
uses: actions/upload-artifact@v2
@@ -399,6 +416,7 @@ jobs:
399416
400417
merge:
401418
needs:
419+
- diff
402420
- parse
403421
- check-submissions-result
404422
# Only merge submissions that passed all checks
@@ -433,6 +451,7 @@ jobs:
433451
owner: ${{ github.repository_owner }}
434452
repo: ${{ github.event.repository.name }}
435453
pull_number: ${{ github.event.pull_request.number }}${{ github.event.issue.number }}
454+
sha: ${{ needs.diff.outputs.head }}
436455
merge_method: squash
437456

438457
- name: Checkout index source branch
@@ -502,8 +521,24 @@ jobs:
502521
503522
Once that is done, it will be merged automatically.
504523
524+
- name: Comment on diff head/PR head mismatch
525+
if: needs.merge.outputs.status == '409'
526+
uses: octokit/[email protected]
527+
env:
528+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
529+
with:
530+
route: POST /repos/{owner}/{repo}/issues/{issue_number}/comments
531+
owner: ${{ github.repository_owner }}
532+
repo: ${{ github.event.repository.name }}
533+
issue_number: ${{ github.event.pull_request.number }}${{ github.event.issue.number }}
534+
body: |
535+
|
536+
It looks like there may have been an update to the pull request. If so, I'll check it again now.
537+
505538
- name: Fail on unidentified merge failure
506-
if: needs.merge.outputs.status != '405'
539+
if: >
540+
needs.merge.outputs.status != '405' &&
541+
needs.merge.outputs.status != '409'
507542
run: exit 1 # Trigger the `unexpected-fail` job
508543

509544
not-submission:

0 commit comments

Comments
 (0)