Automerge #8161
This file contains 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/${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 can not 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 can not 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}"'."}' | |
;; | |
*) | |
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 can not 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" |