Automerge #13120
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Automerge | |
on: | |
workflow_run: | |
workflows: | |
- Check | |
types: | |
- completed | |
jobs: | |
test: | |
name: Renovate | |
if: github.event.workflow_run.conclusion == 'success' | |
permissions: | |
issues: write | |
pull-requests: write | |
contents: write | |
actions: write | |
runs-on: ubuntu-24.04 | |
steps: | |
- name: Install uniget | |
uses: uniget-org/uniget-action@v1 | |
with: | |
prefix: helper | |
tools: gojq | |
- name: Test | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
REF: ${{ github.event.workflow_run.head_branch }} | |
run: | | |
set -o errexit -o pipefail | |
echo "Running on branch: ${REF}" | |
PR_JSON="$( | |
curl --silent --show-error --fail --header "Authorization: token ${GITHUB_TOKEN}" \ | |
--url "https://api.github.com/repos/${GITHUB_REPOSITORY}/pulls?state=open&head=uniget-org:${REF}" \ | |
| jq '.[]' | |
)" | |
PR="$( jq --raw-output '.number' <<<"${PR_JSON}" )" | |
if test -z "${PR}"; then | |
echo "ERROR: Failed to retrieve PR number from event payload" | |
exit 1 | |
fi | |
echo "PR ${PR} uses branch ${REF}" | |
if ! jq --raw-output '.labels[].name' <<<"${PR_JSON}" | grep -q "^type/renovate$"; then | |
echo "PR ${PR} does not have label type/renovate. Canceling" | |
curl --silent --show-error --fail --header "Authorization: token ${GITHUB_TOKEN}" \ | |
--request POST \ | |
--url "https://api.github.com/repos/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/cancel" | |
fi | |
RUN_URL="$( | |
curl --silent --show-error --location --fail \ | |
--url "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" \ | |
| jq --raw-output '.html_url' | |
)" | |
echo "Extracted HTML URL for this run: ${RUN_URL}." | |
curl --silent --show-error --fail \ | |
--request POST \ | |
--header "Authorization: Bearer ${GITHUB_TOKEN}" \ | |
--url "https://api.github.com/repos/${GITHUB_REPOSITORY}/issues/${PR}/comments" \ | |
--data '{"body": "Attempting automerge. See '"${RUN_URL}"'."}' | |
MERGEABLE_STATE="$( jq --raw-output '.mergeable_state' <<<"${PR_JSON}" )" | |
while test "${MERGEABLE_STATE}" == "unknown" || test "${MERGEABLE_STATE}" == "null"; do | |
echo "Got mergeable state: ${MERGEABLE_STATE}" | |
PR_JSON="$( | |
curl --silent --show-error --fail \ | |
--header "Authorization: token ${GITHUB_TOKEN}" \ | |
--url "https://api.github.com/repos/${ 761A GITHUB_REPOSITORY}/pulls/${PR}" \ | |
| jq --compact-output '.' | |
)" | |
MERGEABLE_STATE="$( jq --raw-output '.mergeable_state' <<<"${PR_JSON}" )" | |
done | |
case "${MERGEABLE_STATE}" in | |
blocked) | |
echo "PR ${PR} is blocked and cannot be merged" | |
curl --silent --show-error --fail \ | |
--request POST \ | |
--header "Authorization: Bearer ${GITHUB_TOKEN}" \ | |
--url "https://api.github.com/repos/${GITHUB_REPOSITORY}/issues/${PR}/comments" \ | |
--data '{"body": "PR is blocked and cannot be merged. See '"${RUN_URL}"'."}' | |
echo "Aborting workflow" | |
exit 1 | |
;; | |
clean) | |
echo "PR ${PR} is clean and can be merged" | |
curl --silent --show-error --fail \ | |
--request POST \ | |
--header "Authorization: Bearer ${GITHUB_TOKEN}" \ | |
--url "https://api.github.com/repos/${GITHUB_REPOSITORY}/issues/${PR}/comments" \ | |
--data '{"body": "PR is clean and can be merged. See '"${RUN_URL}"'."}' | |
;; | |
unstable) | |
echo "PR ${PR} is unstable and cannot be merged" | |
curl --silent --show-error --fail \ | |
--request POST \ | |
--header "Authorization: Bearer ${GITHUB_TOKEN}" \ | |
--url "https://api.github.com/repos/${GITHUB_REPOSITORY}/issues/${PR}/comments" \ | |
--data '{"body": "PR is unstable and cannot be merged. See '"${RUN_URL}"'."}' | |
;; | |
*) | |
echo "ERROR: Unknown mergeable_state ${MERGEABLE_STATE} for PR ${PR}" | |
curl --silent --show-error --fail \ | |
--request POST \ | |
--header "Authorization: Bearer ${GITHUB_TOKEN}" \ | |
--url "https://api.github.com/repos/${GITHUB_REPOSITORY}/issues/${PR}/comments" \ | |
--data '{"body": "PR has unknown mergeable_state ('"${MERGEABLE_STATE}"') and cannot be merged. See '"${RUN_URL}"'."}' | |
echo "Aborting workflow" | |
exit 1 | |
;; | |
esac | |
echo "PR ${PR} is ready for auto-merge" | |
echo "Merging PR ${PR}..." | |
http_code="405" | |
merged=false | |
max_attempts=3 | |
attempt=1 | |
while true; do | |
echo " Attempt ${attempt}" | |
http_code="$( | |
curl --silent --request PUT --header "Authorization: token ${GITHUB_TOKEN}" \ | |
--url "https://api.github.com/repos/${GITHUB_REPOSITORY}/pulls/${PR}/merge" \ | |
--data '{"merge_method": "rebase"}' \ | |
--output merge.json \ | |
--write-out "${http_code}" | |
)" | |
if jq --exit-status 'select(.merged != null) | select(.merged == true)' merge.json >/dev/null; then | |
echo " Merged" | |
merged=true | |
break | |
fi | |
echo " Got HTTP code ${http_code}" | |
if test "${attempt}" -eq "${max_attempts}"; then | |
echo " Max attempt reached" | |
break | |
elif test "${http_code}" -eq 405; then | |
echo " Sleeping" | |
cat merge.json | |
sleep 5 | |
else | |
echo " Non-405 code" | |
break | |
fi | |
attempt=$(( attempt + 1 )) | |
done | |
if ! ${merged}; then | |
echo "ERROR: Unable to merge PR ${PR}" | |
exit 1 | |
fi | |
echo "PR ${PR} has been merged" | |
echo "Deleting branch ${REF}..." | |
if ! curl --silent --show-error --fail --request DELETE --header "Authorization: token ${GITHUB_TOKEN}" \ | |
--url "https://api.github.com/repos/${GITHUB_REPOSITORY}/git/refs/heads/${REF}"; then | |
echo "ERROR: Unable to delete branch ${REF} from PR ${PR}" | |
exit 1 | |
fi | |
echo "Branch ${REF} has been deleted" |