This fixes a problem where each workflow would get their own merge commit. This happens frequently when the target branch is merged into a the same time, different workflows in the same run will run get-merge-commit at different times and thus have different merge commits. Since the jobs don't really depend on each other, this doesn't cause practical problems, yet. But it has already led to strange CI failures in a still unmerged PR, which can be prevented from happening with this clean approach. And yes, this saves a few API calls on every run.
96 lines
3.9 KiB
YAML
96 lines
3.9 KiB
YAML
name: Get merge commit
|
|
|
|
description: 'Checks whether the Pull Request is mergeable and checks out the repo at up to two commits: The result of a temporary merge of the head branch into the target branch ("merged"), and the parent of that commit on the target branch ("target"). Handles push events and merge conflicts gracefully.'
|
|
|
|
inputs:
|
|
mergedSha:
|
|
description: "The merge commit SHA, previously collected."
|
|
type: string
|
|
merged-as-untrusted:
|
|
description: "Whether to checkout the merge commit in the ./untrusted folder."
|
|
type: boolean
|
|
targetSha:
|
|
description: "The target commit SHA, previously collected."
|
|
type: string
|
|
target-as-trusted:
|
|
description: "Whether to checkout the target commit in the ./trusted folder."
|
|
type: boolean
|
|
|
|
outputs:
|
|
mergedSha:
|
|
description: "The merge commit SHA"
|
|
value: ${{ steps.commits.outputs.mergedSha }}
|
|
targetSha:
|
|
description: "The target commit SHA"
|
|
value: ${{ steps.commits.outputs.targetSha }}
|
|
|
|
runs:
|
|
using: composite
|
|
steps:
|
|
- id: commits
|
|
if: ${{ !inputs.mergedSha && !inputs.targetSha }}
|
|
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
|
with:
|
|
script: |
|
|
if (context.eventName == 'push') return core.setOutput('mergedSha', context.sha)
|
|
|
|
for (const retryInterval of [5, 10, 20, 40, 80]) {
|
|
console.log("Checking whether the pull request can be merged...")
|
|
const prInfo = (await github.rest.pulls.get({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
pull_number: context.payload.pull_request.number
|
|
})).data
|
|
|
|
if (prInfo.state != 'open') throw new Error ("PR is not open anymore.")
|
|
|
|
if (prInfo.mergeable == null) {
|
|
console.log(`GitHub is still computing whether this PR can be merged, waiting ${retryInterval} seconds before trying again...`)
|
|
await new Promise(resolve => setTimeout(resolve, retryInterval * 1000))
|
|
continue
|
|
}
|
|
|
|
let mergedSha, targetSha
|
|
|
|
if (prInfo.mergeable) {
|
|
console.log("The PR can be merged.")
|
|
|
|
mergedSha = prInfo.merge_commit_sha
|
|
targetSha = (await github.rest.repos.getCommit({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
ref: prInfo.merge_commit_sha
|
|
})).data.parents[0].sha
|
|
} else {
|
|
console.log("The PR has a merge conflict.")
|
|
|
|
mergedSha = prInfo.head.sha
|
|
targetSha = (await github.rest.repos.compareCommitsWithBasehead({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
basehead: `${prInfo.base.sha}...${prInfo.head.sha}`
|
|
})).data.merge_base_commit.sha
|
|
}
|
|
|
|
console.log(`Checking the commits:\nmerged:${mergedSha}\ntarget:${targetSha}`)
|
|
core.setOutput('mergedSha', mergedSha)
|
|
core.setOutput('targetSha', targetSha)
|
|
return
|
|
}
|
|
throw new Error("Not retrying anymore. It's likely that GitHub is having internal issues: check https://www.githubstatus.com.")
|
|
|
|
- if: inputs.merged-as-untrusted && (inputs.mergedSha || steps.commits.outputs.mergedSha)
|
|
# Would be great to do the checkouts in git worktrees of the existing spare checkout instead,
|
|
# but Nix is broken with them:
|
|
# https://github.com/NixOS/nix/issues/6073
|
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
with:
|
|
ref: ${{ inputs.mergedSha || steps.commits.outputs.mergedSha }}
|
|
path: untrusted
|
|
|
|
- if: inputs.target-as-trusted && (inputs.targetSha || steps.commits.outputs.targetSha)
|
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
with:
|
|
ref: ${{ inputs.targetSha || steps.commits.outputs.targetSha }}
|
|
path: trusted
|