From 9cf01c086ea720846dc7d1f6ba1ee03af01f3070 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Fri, 30 Aug 2024 15:10:13 +0200 Subject: [PATCH 1/5] tools: add util scripts to land and rebase PRs --- tools/actions/merge.sh | 61 +++++++++++++++++++++++++++++++++++++++++ tools/actions/rebase.sh | 8 ++++++ 2 files changed, 69 insertions(+) create mode 100755 tools/actions/merge.sh create mode 100755 tools/actions/rebase.sh diff --git a/tools/actions/merge.sh b/tools/actions/merge.sh new file mode 100755 index 00000000000000..a01eec12be7d00 --- /dev/null +++ b/tools/actions/merge.sh @@ -0,0 +1,61 @@ +#!/bin/sh + +# Requires [gh](https://cli.github.com/), [jq](https://jqlang.github.io), awk, git, and sed. + +# This script can be used to "purple-merge" PRs that are supposed to land as a single commit, using the "Squash and Merge" feature of GitHub. +# To land a PR with this tool: +# 1. Run `git node land --fixupAll` +# 2. Copy the hash of the commit at the top of the PR branch. +# 3. Run `tools/actions/merge.sh `. + +set -xe + +pr=$1 +commit_head=$2 +shift 2 || (echo "Expected two arguments" && exit 1) + +commit_queue_failed() { + pr=$1 + + echo "Failed to merge $pr" + cat output + + rm output +} + +OWNER=nodejs +REPOSITORY=node + +if expr "X$pr" : 'Xhttps://github.com/[^/]\{1,\}/[^/]\{1,\}/pull/[0-9]\{1,\}' >/dev/null; then + OWNER="$(echo "$pr" | awk 'BEGIN { FS = "/" } ; { print $4 }')" + REPOSITORY="$(echo "$pr" | awk 'BEGIN { FS = "/" } ; { print $5 }')" + pr="$(echo "$pr" | awk 'BEGIN { FS = "/" } ; { print $7 }')" +else if ! expr "X$pr" : 'X[0-9]\{1,\}' >/dev/null; then + echo "The first argument should be the PR ID or URL" +fi +fi + +[ -z "$(git log -1 --pretty='format:%B' | git interpret-trailers --parse --no-divider | sed -n -e "/^PR-URL: https:\x2F\x2Fgithub.com\x2F$OWNER\x2F$REPOSITORY\x2Fpull\x2F$pr$/p")" ] && echo "Invalid PR-URL trailer" && exit 1 +[ -n "$(git log -1 HEAD^ --pretty='format:%B' | git interpret-trailers --parse --no-divider | sed -n -e "/^PR-URL: https:\x2F\x2Fgithub.com\x2F$OWNER\x2F$REPOSITORY\x2Fpull\x2F$pr$/p")" ] && echo "Refuse to squash and merge a PR landing in more than one commit" && exit 1 + +commit_title=$(git log -1 --pretty='format:%s') +commit_body=$(git log -1 --pretty='format:%b') + +jq -n \ + --arg title "${commit_title}" \ + --arg body "${commit_body}" \ + --arg head "${commit_head}" \ + '{merge_method:"squash",commit_title:$title,commit_message:$body,sha:$head}' > output.json +cat output.json +if ! gh api -X PUT "repos/${OWNER}/${REPOSITORY}/pulls/${pr}/merge" --input output.json > output; then + commit_queue_failed "$pr" + exit 1 +fi +cat output +if ! commits="$(jq -r 'if .merged then .sha else error("not merged") end' < output)"; then + commit_queue_failed "$pr" + exit 1 +fi +rm output.json output + +gh pr comment "$pr" --body "Landed in $commits" diff --git a/tools/actions/rebase.sh b/tools/actions/rebase.sh new file mode 100755 index 00000000000000..ad855227d0baea --- /dev/null +++ b/tools/actions/rebase.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +gh api graphql -F "prID=$(gh pr view "$1" --json id --jq .id)" -f query=' +mutation RebasePR($prID: ID!) { + updatePullRequestBranch(input:{pullRequestId:$prID,updateMethod:REBASE}) { + clientMutationId + } +}' From 8b27b0ee92b5eb2ee8a592c03eee32241cc9297c Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Fri, 30 Aug 2024 16:14:59 +0200 Subject: [PATCH 2/5] fixup! tools: add util scripts to land and rebase PRs --- tools/actions/merge.sh | 9 ++++----- tools/actions/rebase.sh | 5 ++++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tools/actions/merge.sh b/tools/actions/merge.sh index a01eec12be7d00..0125e66860b93f 100755 --- a/tools/actions/merge.sh +++ b/tools/actions/merge.sh @@ -1,6 +1,6 @@ #!/bin/sh -# Requires [gh](https://cli.github.com/), [jq](https://jqlang.github.io), awk, git, and sed. +# Requires [gh](https://cli.github.com/), [jq](https://jqlang.github.io), git, and grep. Also awk if you pass a URL. # This script can be used to "purple-merge" PRs that are supposed to land as a single commit, using the "Squash and Merge" feature of GitHub. # To land a PR with this tool: @@ -30,13 +30,12 @@ if expr "X$pr" : 'Xhttps://github.com/[^/]\{1,\}/[^/]\{1,\}/pull/[0-9]\{1,\}' >/ OWNER="$(echo "$pr" | awk 'BEGIN { FS = "/" } ; { print $4 }')" REPOSITORY="$(echo "$pr" | awk 'BEGIN { FS = "/" } ; { print $5 }')" pr="$(echo "$pr" | awk 'BEGIN { FS = "/" } ; { print $7 }')" -else if ! expr "X$pr" : 'X[0-9]\{1,\}' >/dev/null; then +elif ! expr "X$pr" : 'X[0-9]\{1,\}' >/dev/null; then echo "The first argument should be the PR ID or URL" fi -fi -[ -z "$(git log -1 --pretty='format:%B' | git interpret-trailers --parse --no-divider | sed -n -e "/^PR-URL: https:\x2F\x2Fgithub.com\x2F$OWNER\x2F$REPOSITORY\x2Fpull\x2F$pr$/p")" ] && echo "Invalid PR-URL trailer" && exit 1 -[ -n "$(git log -1 HEAD^ --pretty='format:%B' | git interpret-trailers --parse --no-divider | sed -n -e "/^PR-URL: https:\x2F\x2Fgithub.com\x2F$OWNER\x2F$REPOSITORY\x2Fpull\x2F$pr$/p")" ] && echo "Refuse to squash and merge a PR landing in more than one commit" && exit 1 +git log -1 HEAD --pretty='format:%B' | git interpret-trailers --parse --no-divider | grep -q -x "^PR-URL: https://github.com/$OWNER/$REPOSITORY/pull/$pr$" || (echo "Invalid PR-URL trailer" && exit 1) +git log -1 HEAD^ --pretty='format:%B' | git interpret-trailers --parse --no-divider | grep -q -x "^PR-URL: https://github.com/$OWNER/$REPOSITORY/pull/$pr$" && echo "Refuse to squash and merge a PR landing in more than one commit" && exit 1 commit_title=$(git log -1 --pretty='format:%s') commit_body=$(git log -1 --pretty='format:%b') diff --git a/tools/actions/rebase.sh b/tools/actions/rebase.sh index ad855227d0baea..6fdf07af0b81cf 100755 --- a/tools/actions/rebase.sh +++ b/tools/actions/rebase.sh @@ -1,6 +1,9 @@ #!/bin/sh -gh api graphql -F "prID=$(gh pr view "$1" --json id --jq .id)" -f query=' +set -xe + +# shellcheck disable=SC2016 +gh api graphql -F "prID=$(gh pr view "$1" --json id --jq .id || true)" -f query=' mutation RebasePR($prID: ID!) { updatePullRequestBranch(input:{pullRequestId:$prID,updateMethod:REBASE}) { clientMutationId From 720f53f5d77c16856838728a7b2c76d43b9b8cbf Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sun, 1 Sep 2024 22:25:22 +0200 Subject: [PATCH 3/5] Apply suggestions from code review Co-authored-by: Livia Medeiros --- tools/actions/merge.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/actions/merge.sh b/tools/actions/merge.sh index 0125e66860b93f..61a08b438098fa 100755 --- a/tools/actions/merge.sh +++ b/tools/actions/merge.sh @@ -12,7 +12,7 @@ set -xe pr=$1 commit_head=$2 -shift 2 || (echo "Expected two arguments" && exit 1) +shift 2 || { echo "Expected two arguments"; exit 1; } commit_queue_failed() { pr=$1 @@ -34,8 +34,8 @@ elif ! expr "X$pr" : 'X[0-9]\{1,\}' >/dev/null; then echo "The first argument should be the PR ID or URL" fi -git log -1 HEAD --pretty='format:%B' | git interpret-trailers --parse --no-divider | grep -q -x "^PR-URL: https://github.com/$OWNER/$REPOSITORY/pull/$pr$" || (echo "Invalid PR-URL trailer" && exit 1) -git log -1 HEAD^ --pretty='format:%B' | git interpret-trailers --parse --no-divider | grep -q -x "^PR-URL: https://github.com/$OWNER/$REPOSITORY/pull/$pr$" && echo "Refuse to squash and merge a PR landing in more than one commit" && exit 1 +git log -1 HEAD --pretty='format:%B' | git interpret-trailers --parse --no-divider | grep -q -x "^PR-URL: https://github.com/$OWNER/$REPOSITORY/pull/$pr$" || { echo "Invalid PR-URL trailer"; exit 1; } +git log -1 HEAD^ --pretty='format:%B' | git interpret-trailers --parse --no-divider | grep -q -x "^PR-URL: https://github.com/$OWNER/$REPOSITORY/pull/$pr$" && { echo "Refuse to squash and merge a PR landing in more than one commit"; exit 1; } commit_title=$(git log -1 --pretty='format:%s') commit_body=$(git log -1 --pretty='format:%b') From 39f5dea0a1db825dde3f380136099c217cb6d769 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sun, 1 Sep 2024 22:29:46 +0200 Subject: [PATCH 4/5] remove `commit_queue_failed` --- tools/actions/merge.sh | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/tools/actions/merge.sh b/tools/actions/merge.sh index 61a08b438098fa..6c7f267c95e55f 100755 --- a/tools/actions/merge.sh +++ b/tools/actions/merge.sh @@ -14,15 +14,6 @@ pr=$1 commit_head=$2 shift 2 || { echo "Expected two arguments"; exit 1; } -commit_queue_failed() { - pr=$1 - - echo "Failed to merge $pr" - cat output - - rm output -} - OWNER=nodejs REPOSITORY=node @@ -34,8 +25,16 @@ elif ! expr "X$pr" : 'X[0-9]\{1,\}' >/dev/null; then echo "The first argument should be the PR ID or URL" fi -git log -1 HEAD --pretty='format:%B' | git interpret-trailers --parse --no-divider | grep -q -x "^PR-URL: https://github.com/$OWNER/$REPOSITORY/pull/$pr$" || { echo "Invalid PR-URL trailer"; exit 1; } -git log -1 HEAD^ --pretty='format:%B' | git interpret-trailers --parse --no-divider | grep -q -x "^PR-URL: https://github.com/$OWNER/$REPOSITORY/pull/$pr$" && { echo "Refuse to squash and merge a PR landing in more than one commit"; exit 1; } +git log -1 HEAD --pretty='format:%B' | git interpret-trailers --parse --no-divider | \ + grep -q -x "^PR-URL: https://github.com/$OWNER/$REPOSITORY/pull/$pr$" || { + echo "Invalid PR-URL trailer" + exit 1 + } +git log -1 HEAD^ --pretty='format:%B' | git interpret-trailers --parse --no-divider | \ + grep -q -x "^PR-URL: https://github.com/$OWNER/$REPOSITORY/pull/$pr$" && { + echo "Refuse to squash and merge a PR landing in more than one commit" + exit 1 + } commit_title=$(git log -1 --pretty='format:%s') commit_body=$(git log -1 --pretty='format:%b') @@ -47,12 +46,15 @@ jq -n \ '{merge_method:"squash",commit_title:$title,commit_message:$body,sha:$head}' > output.json cat output.json if ! gh api -X PUT "repos/${OWNER}/${REPOSITORY}/pulls/${pr}/merge" --input output.json > output; then - commit_queue_failed "$pr" + cat output + echo "Failed to merge $pr" + rm output output.json exit 1 fi cat output if ! commits="$(jq -r 'if .merged then .sha else error("not merged") end' < output)"; then - commit_queue_failed "$pr" + echo "Failed to merge $pr" + rm output output.json exit 1 fi rm output.json output From cf05d2a85bbbdacca170140fdec76393d493d1f0 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Mon, 2 Sep 2024 17:37:48 +0200 Subject: [PATCH 5/5] Update tools/actions/merge.sh --- tools/actions/merge.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/actions/merge.sh b/tools/actions/merge.sh index 6c7f267c95e55f..898e9e59ea3ea1 100755 --- a/tools/actions/merge.sh +++ b/tools/actions/merge.sh @@ -59,4 +59,4 @@ if ! commits="$(jq -r 'if .merged then .sha else error("not merged") end' < outp fi rm output.json output -gh pr comment "$pr" --body "Landed in $commits" +gh pr comment "$pr" --repo "$OWNER/$REPOSITORY" --body "Landed in $commits"