1#!/bin/sh 2 3set -xe 4 5OWNER=$1 6REPOSITORY=$2 7shift 2 8 9UPSTREAM=origin 10DEFAULT_BRANCH=main 11 12COMMIT_QUEUE_LABEL="commit-queue" 13COMMIT_QUEUE_FAILED_LABEL="commit-queue-failed" 14 15commit_queue_failed() { 16 pr=$1 17 18 gh pr edit "$pr" --add-label "${COMMIT_QUEUE_FAILED_LABEL}" 19 20 # shellcheck disable=SC2154 21 cqurl="${GITHUB_SERVER_URL}/${OWNER}/${REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" 22 body="<details><summary>Commit Queue failed</summary><pre>$(cat output)</pre><a href='$cqurl'>$cqurl</a></details>" 23 echo "$body" 24 25 gh pr comment "$pr" --body "$body" 26 27 rm output 28} 29 30# TODO(mmarchini): should this be set with whoever added the label for each PR? 31git config --local user.email "github-bot@iojs.org" 32git config --local user.name "Node.js GitHub Bot" 33 34for pr in "$@"; do 35 gh pr view "$pr" --json labels --jq ".labels" > labels.json 36 # Skip PR if CI was requested 37 if jq -e 'map(.name) | index("request-ci")' < labels.json; then 38 echo "pr ${pr} skipped, waiting for CI to start" 39 continue 40 fi 41 42 # Skip PR if CI is still running 43 if gh pr checks "$pr" | grep -q "\spending\s"; then 44 echo "pr ${pr} skipped, CI still running" 45 continue 46 fi 47 48 # Delete the commit queue label 49 gh pr edit "$pr" --remove-label "$COMMIT_QUEUE_LABEL" 50 51 if jq -e 'map(.name) | index("commit-queue-squash")' < labels.json; then 52 MULTIPLE_COMMIT_POLICY="--fixupAll" 53 elif jq -e 'map(.name) | index("commit-queue-rebase")' < labels.json; then 54 MULTIPLE_COMMIT_POLICY="" 55 else 56 MULTIPLE_COMMIT_POLICY="--oneCommitMax" 57 fi 58 59 git node land --autorebase --yes $MULTIPLE_COMMIT_POLICY "$pr" >output 2>&1 || echo "Failed to land #${pr}" 60 # cat here otherwise we'll be supressing the output of git node land 61 cat output 62 63 # TODO(mmarchini): workaround for ncu not returning the expected status code, 64 # if the "Landed in..." message was not on the output we assume land failed 65 if ! grep -q '. Post "Landed in .*/pull/'"${pr}" output; then 66 commit_queue_failed "$pr" 67 # If `git node land --abort` fails, we're in unknown state. Better to stop 68 # the script here, current PR was removed from the queue so it shouldn't 69 # interfere again in the future. 70 git node land --abort --yes 71 continue 72 fi 73 74 if [ -z "$MULTIPLE_COMMIT_POLICY" ]; then 75 start_sha=$(git rev-parse $UPSTREAM/$DEFAULT_BRANCH) 76 end_sha=$(git rev-parse HEAD) 77 commits="${start_sha}...${end_sha}" 78 79 if ! git push $UPSTREAM $DEFAULT_BRANCH >> output 2>&1; then 80 commit_queue_failed "$pr" 81 continue 82 fi 83 else 84 # If there's only one commit, we can use the Squash and Merge feature from GitHub. 85 # TODO: use `gh pr merge` when the GitHub CLI allows to customize the commit title (https://github.com/cli/cli/issues/1023). 86 commit_title=$(git log -1 --pretty='format:%s') 87 commit_body=$(git log -1 --pretty='format:%b') 88 commit_head=$(grep 'Fetched commits as' output | cut -d. -f3 | xargs git rev-parse) 89 90 jq -n \ 91 --arg title "${commit_title}" \ 92 --arg body "${commit_body}" \ 93 --arg head "${commit_head}" \ 94 '{merge_method:"squash",commit_title:$title,commit_message:$body,sha:$head}' > output.json 95 cat output.json 96 if ! gh api -X PUT "repos/${OWNER}/${REPOSITORY}/pulls/${pr}/merge" --input output.json > output; then 97 commit_queue_failed "$pr" 98 continue 99 fi 100 cat output 101 if ! commits="$(jq -r 'if .merged then .sha else error("not merged") end' < output)"; then 102 commit_queue_failed "$pr" 103 continue 104 fi 105 rm output.json 106 fi 107 108 rm output 109 110 gh pr comment "$pr" --body "Landed in $commits" 111 112 [ -z "$MULTIPLE_COMMIT_POLICY" ] && gh pr close "$pr" 113done 114 115rm -f labels.json 116