3 # How to setup the repository to make this correctly work
4 # 1. Clone repo and make sure you can correctly push to that
5 # (example with openwrt main repo you need to use ssh remote url)
6 # 2. Make sure you can correctly push and force push to the github
9 # Usage: github-merge-pr.sh PR_NUMBER BRANCH REPO_NAME
11 # BRANCH is optional and defaults to main.
12 # REPO_NAME is optional and defaults to openwrt. It does
13 # describe the repository name to use to pull PR info from.
15 # Script .config variables
16 # Github repository owner or organization name.
17 # By default set to openwrt, set this line in .config to overwrite
19 GITHUB_REPO_OWNER
="openwrt"
21 # Your repository token, generate this token at your profile page:
22 # - Navigate to https://github.com/settings/tokens
23 # - Click on "Generate new token"
24 # - Enter a description, e.g. "pr.sh" and pick the "repo" scope
25 # - Hit "Generate token"
26 # Set this line in .config to provide a GITHUB_TOKEN and add comments
27 #GITHUB_TOKEN="d41d8cd98f00b204e9800998ecf8427e"
29 # Set this line in .config to use SSH key to rebase PR branch
32 SCRIPT_DIR
="$(dirname $0)"
33 [ -h $0 ] && SCRIPT_DIR
="$(dirname $(readlink $0))"
35 # Everything in .config will overwrite the default values set up
36 [ -f "$SCRIPT_DIR/.config" ] && source "$SCRIPT_DIR"/.config
40 GITHUB_REPO_NAME
="${3:-openwrt}"
44 REPO
="$GITHUB_REPO_OWNER"/"$GITHUB_REPO_NAME"
48 local default
="${2:-n}"
52 printf "%s y/n [%s] > " "$prompt" "$default"
54 case "${input:-$default}" in
61 if ! command -v jq
&> /dev
/null
; then
62 echo "jq could not be found! This script require jq!"
66 if [ -z "$PRID" -o -n "${PRID//[0-9]*/}" ]; then
67 echo "Usage: $0 <PR-ID> [rebase-branch] [dry-run]" >&2
71 if [ -n "$DRY_RUN" ]; then
75 if [ -z "$(git branch --list "$BRANCH")" ]; then
76 echo "Given rebase branch '$BRANCH' does not exist!" >&2
80 if ! PR_INFO
="$(curl -f -s "https
://api.github.com
/repos
/$REPO/pulls
/$PRID")"; then
81 echo "Failed fetch PR #$PRID info" >&2
85 if [ "$(echo "$PR_INFO" | jq -r ".maintainer_can_modify
")" == "false" ]; then
86 echo "PR #$PRID can't be force pushed by maintainers. Trying to merge as is!" >&2
89 if [ "$(echo "$PR_INFO" | jq -r ".mergeable
")" == "false" ]; then
90 echo "PR #$PRID is not mergeable for Github.com. Check the PR!" >&2
94 echo "Pulling current $BRANCH from origin"
96 $GIT fetch origin
$BRANCH
98 if ! $GIT rebase origin
/$BRANCH; then
99 echo "Failed to rebase $BRANCH with origin/$BRANCH" >&2
103 PR_USER
="$(echo "$PR_INFO" | jq -r ".
head.user.login
")"
104 PR_BRANCH
="$(echo "$PR_INFO" | jq -r ".
head.ref
")"
105 LOCAL_PR_BRANCH
="$PR_BRANCH"-"$PR_USER"
106 if [ "$GITHUB_USE_SSH" = "1" ]; then
107 PR_REPO
="$(echo "$PR_INFO" | jq -r ".
head.repo.ssh_url
")"
109 PR_REPO
="$(echo "$PR_INFO" | jq -r ".
head.repo.html_url
")"
112 if ! $GIT remote get-url
$PR_USER &> /dev
/null ||
[ -n "$DRY_RUN" ]; then
113 echo "Adding $PR_USER with repo $PR_REPO to remote"
114 $GIT remote add
$PR_USER $PR_REPO
117 echo "Fetching remote $PR_USER"
118 $GIT fetch
$PR_USER $PR_BRANCH
120 if [ "$(echo "$PR_INFO" | jq -r ".maintainer_can_modify
")" == "true" ]; then
121 echo "Creating branch $LOCAL_PR_BRANCH for $PR_BRANCH"
122 if ! $GIT checkout
-b $LOCAL_PR_BRANCH $PR_USER/$PR_BRANCH; then
123 echo "Failed to checkout new branch $PR_BRANCH from $PR_USER/$PR_BRANCH" >&2
127 echo "Rebasing $LOCAL_PR_BRANCH on top of $BRANCH"
128 if ! $GIT rebase origin
/$BRANCH; then
129 echo "Failed to rebase $PR_BRANCH with origin/$BRANCH" >&2
133 # Add to each commit Link: https://github.com/$REPO/pull/$PRID
134 if ! $GIT filter-repo
--message-callback "
135 return message + b\"Link: https://github.com/$REPO/pull/$PRID\"
136 " --refs $BRANCH..
$LOCAL_PR_BRANCH --force; then
137 echo "Failed to add Link: Pull Request tag" >&2
141 # Remove any previous SoB tag if the Pull Request Author and Committer match
142 if ! $GIT filter-repo
--message-callback "
143 return message.replace(b\"Signed-off-by: $(git config user.name) <$(git config user.email)>\n\",b\"\")
144 " --refs $BRANCH..
$LOCAL_PR_BRANCH --force; then
145 echo "Failed to remove previous Committer SoB tag" >&2
149 # Add Committer SoB to better reference who merged the thing last
150 if ! $GIT rebase origin
/$BRANCH $LOCAL_PR_BRANCH --exec "git commit -s --amend -C HEAD"; then
151 echo "Failed to add Committer SoB tag" >&2
155 echo "Force pushing $LOCAL_PR_BRANCH to HEAD:$PR_BRANCH for $PR_USER"
156 if ! $GIT push
$PR_USER HEAD
:$PR_BRANCH --force; then
157 echo "Failed to force push HEAD to $PR_USER" >&2
161 echo "Returning to $BRANCH"
162 $GIT checkout
$BRANCH
165 if [ -n "$($GIT log origin/$BRANCH..HEAD)" ]; then
166 echo "Working on dirty branch for $BRANCH! Please reset $BRANCH to origin/$BRANCH" >&2
170 echo "Actually merging the PR #$PRID from branch $PR_USER/$PR_BRANCH"
171 if ! $GIT merge
--ff-only $PR_USER/$PR_BRANCH; then
172 echo "Failed to merge $PR_USER/$PR_BRANCH on $BRANCH" >&2
174 if yesno
"Push to openwrt $BRANCH" "y"; then
175 echo "Pushing to openwrt git server"
177 echo "Failed to push to $BRANCH but left branch as is." >&2
181 # Default close comment
182 COMMENT
="Thanks! Rebased on top of $BRANCH and merged!"
184 if [ -n "$GITHUB_TOKEN" ] && [ -z "$DRY_RUN" ]; then
186 echo "Enter a comment and hit <enter> to close the PR at Github automatically now."
187 echo "Hit <ctrl>-<c> to exit."
189 echo "If you do not provide a comment, the default will be: "
195 echo "Sending message to PR..."
197 comment
="${usercomment:-$COMMENT}"
198 comment
="${comment//\\/\\\\}"
199 comment
="${comment//\"/\\\"}"
200 comment
="$(printf '{"body
":"%s
"}' "$comment")"
202 if ! curl
-s -o /dev
/null
-w "%{http_code} %{url_effective}\\n" --user "$GITHUB_TOKEN:x-oauth-basic" --request POST
--data "$comment" "https://api.github.com/repos/$REPO/issues/$PRID/comments" || \
203 ! curl
-s -o /dev
/null
-w "%{http_code} %{url_effective}\\n" --user "$GITHUB_TOKEN:x-oauth-basic" --request PATCH
--data '{"state":"closed"}' "https://api.github.com/repos/$REPO/pulls/$PRID"
206 echo "Something failed while sending comment to the PR via ">&2
207 echo "the Github API, please review the state manually at " >&2
208 echo "https://github.com/$REPO/pull/$PRID" >&2
214 echo "The PR has been merged!"
219 if [ "$(echo "$PR_INFO" | jq -r ".maintainer_can_modify
")" == "true" ]; then
220 echo "Deleting branch $LOCAL_PR_BRANCH"
221 $GIT branch
-D $LOCAL_PR_BRANCH