name: "Check cherry-picks" on: pull_request: paths: - .github/workflows/check-cherry-picks.yml pull_request_target: branches: - 'release-**' - 'staging-**' - '!staging-next' concurrency: group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true permissions: pull-requests: write jobs: check: name: cherry-pick-check runs-on: ubuntu-24.04-arm steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 filter: tree:0 path: trusted - name: Check cherry-picks id: check continue-on-error: true env: BASE_SHA: ${{ github.event.pull_request.base.sha }} HEAD_SHA: ${{ github.event.pull_request.head.sha }} run: | ./trusted/ci/check-cherry-picks.sh "$BASE_SHA" "$HEAD_SHA" checked-cherry-picks.md - name: Prepare review if: steps.check.outcome == 'failure' uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: script: | const { readFile, writeFile } = require('node:fs/promises') const job_url = (await github.rest.actions.listJobsForWorkflowRun({ owner: context.repo.owner, repo: context.repo.repo, run_id: context.runId })).data.jobs[0].html_url + '?pr=' + context.payload.pull_request.number const header = await readFile('trusted/ci/check-cherry-picks.md') const body = await readFile('checked-cherry-picks.md') const footer = `\n_Hint: The full diffs are also available in the [runner logs](${job_url}) with slightly better highlighting._` const review = header + body + footer await writeFile('review.md', review) core.summary.addRaw(review) core.summary.write() - name: Request changes if: ${{ github.event_name == 'pull_request_target' && steps.check.outcome == 'failure' }} uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: script: | const { readFile } = require('node:fs/promises') const body = await readFile('review.md', 'utf-8') const pendingReview = (await github.paginate(github.rest.pulls.listReviews, { owner: context.repo.owner, repo: context.repo.repo, pull_number: context.payload.pull_request.number })).find(review => review.user.login == 'github-actions[bot]' && ( // If a review is still pending, we can just update this instead // of posting a new one. review.state == 'CHANGES_REQUESTED' || // No need to post a new review, if an older one with the exact // same content had already been dismissed. review.body == body ) ) // Either of those two requests could fail for very long comments. This can only happen // with multiple commits all hitting the truncation limit for the diff. If you ever hit // this case, consider just splitting up those commits into multiple PRs. if (pendingReview) { await github.rest.pulls.updateReview({ owner: context.repo.owner, repo: context.repo.repo, pull_number: context.payload.pull_request.number, review_id: pendingReview.id, body }) } else { await github.rest.pulls.createReview({ owner: context.repo.owner, repo: context.repo.repo, pull_number: context.payload.pull_request.number, event: 'REQUEST_CHANGES', body }) } - name: Dismiss old reviews if: ${{ github.event_name == 'pull_request_target' && steps.check.outcome == 'success' }} uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: script: | await Promise.all( (await github.paginate(github.rest.pulls.listReviews, { owner: context.repo.owner, repo: context.repo.repo, pull_number: context.payload.pull_request.number })).filter(review => review.user.login == 'github-actions[bot]' ).map(async (review) => { if (review.state == 'CHANGES_REQUESTED') { await github.rest.pulls.dismissReview({ owner: context.repo.owner, repo: context.repo.repo, pull_number: context.payload.pull_request.number, review_id: review.id, message: 'All cherry-picks are good now, thank you!' }) } await github.graphql(`mutation($node_id:ID!) { minimizeComment(input: { classifier: RESOLVED, subjectId: $node_id }) { clientMutationId } }`, { node_id: review.node_id }) }) )