github-merge-pr: add option to use SSH key for github auth
[maintainer-tools.git] / github-merge-pr.sh
1 #!/bin/bash
2
3 # Github repository, just the name/repo part, no .git suffix, no base url!
4 REPO="openwrt/openwrt"
5
6 # Your repository token, generate this token at your profile page:
7 # - Navigate to https://github.com/settings/tokens
8 # - Click on "Generate new token"
9 # - Enter a description, e.g. "pr.sh" and pick the "repo" scope
10 # - Hit "Generate token"
11 #TOKEN="d41d8cd98f00b204e9800998ecf8427e"
12 #
13 # Uncomment this line to use SSH key to rebase PR branch
14 # USE_SSH=1
15
16 PRID="$1"
17 BRANCH="${2:-master}"
18 DRY_RUN="$3"
19 GIT=git
20
21 yesno() {
22 local prompt="$1"
23 local default="${2:-n}"
24 local input
25
26 while [ 1 ]; do
27 printf "%s y/n [%s] > " "$prompt" "$default"
28 read input
29 case "${input:-$default}" in
30 y*) return 0 ;;
31 n*) return 1 ;;
32 esac
33 done
34 }
35
36 if ! command -v jq &> /dev/null; then
37 echo "jq could not be found! This script require jq!"
38 exit 1
39 fi
40
41 if [ -z "$PRID" -o -n "${PRID//[0-9]*/}" ]; then
42 echo "Usage: $0 <PR-ID> [rebase-branch] [dry-run]" >&2
43 exit 1
44 fi
45
46 if [ -n "$DRY_RUN" ]; then
47 GIT="echo git"
48 fi
49
50 if [ -z "$(git branch --list "$BRANCH")" ]; then
51 echo "Given rebase branch '$BRANCH' does not exist!" >&2
52 exit 2
53 fi
54
55 if ! PR_INFO="$(curl -f -s "https://api.github.com/repos/$REPO/pulls/$PRID")"; then
56 echo "Failed fetch PR #$PRID info" >&2
57 exit 3
58 fi
59
60 if [ "$(echo "$PR_INFO" | jq -r ".maintainer_can_modify")" == "false" ]; then
61 echo "PR #$PRID can't be force pushed by maintainers. Trying to merge as is!" >&2
62 fi
63
64 if [ "$(echo "$PR_INFO" | jq -r ".mergeable")" == "false" ]; then
65 echo "PR #$PRID is not mergeable for Github.com. Check the PR!" >&2
66 exit 5
67 fi
68
69 echo "Pulling current $BRANCH from origin"
70 $GIT checkout $BRANCH
71 $GIT fetch origin $BRANCH
72
73 if ! $GIT rebase origin/$BRANCH; then
74 echo "Failed to rebase $BRANCH with origin/$BRANCH" >&2
75 exit 7
76 fi
77
78 PR_USER="$(echo "$PR_INFO" | jq -r ".head.user.login")"
79 PR_BRANCH="$(echo "$PR_INFO" | jq -r ".head.ref")"
80 LOCAL_PR_BRANCH="$PR_BRANCH"-"$PR_USER"
81 if [ "$USE_SSH" = "1" ]; then
82 PR_REPO="$(echo "$PR_INFO" | jq -r ".head.repo.ssh_url")"
83 else
84 PR_REPO="$(echo "$PR_INFO" | jq -r ".head.repo.html_url")"
85 fi
86
87 if ! $GIT remote get-url $PR_USER &> /dev/null || [ -n "$DRY_RUN" ]; then
88 echo "Adding $PR_USER with repo $PR_REPO to remote"
89 $GIT remote add $PR_USER $PR_REPO
90 fi
91
92 echo "Fetching remote $PR_USER"
93 $GIT fetch $PR_USER $PR_BRANCH
94
95 if [ "$(echo "$PR_INFO" | jq -r ".maintainer_can_modify")" == "true" ]; then
96 echo "Creating branch $LOCAL_PR_BRANCH for $PR_BRANCH"
97 if ! $GIT checkout -b $LOCAL_PR_BRANCH $PR_USER/$PR_BRANCH; then
98 echo "Failed to checkout new branch $PR_BRANCH from $PR_USER/$PR_BRANCH" >&2
99 exit 8
100 fi
101
102 echo "Rebasing $LOCAL_PR_BRANCH on top of $BRANCH"
103 if ! $GIT rebase origin/$BRANCH; then
104 echo "Failed to rebase $PR_BRANCH with origin/$BRANCH" >&2
105 exit 9
106 fi
107
108 echo "Force pushing $LOCAL_PR_BRANCH to HEAD:$PR_BRANCH for $PR_USER"
109 if ! $GIT push $PR_USER HEAD:$PR_BRANCH --force; then
110 echo "Failed to force push HEAD to $PR_USER" >&2
111 exit 10
112 fi
113
114 echo "Returning to $BRANCH"
115 $GIT checkout $BRANCH
116 fi
117
118 if [ -n "$($GIT log origin/$BRANCH..HEAD)" ]; then
119 echo "Working on dirty branch for $BRANCH! Please reset $BRANCH to origin/$BRANCH" >&2
120 exit 11
121 fi
122
123 echo "Actually merging the PR #$PRID from branch $PR_USER/$PR_BRANCH"
124 if ! $GIT merge --ff-only $PR_USER/$PR_BRANCH; then
125 echo "Failed to merge $PR_USER/$PR_BRANCH on $BRANCH" >&2
126 else
127 if yesno "Push to openwrt $BRANCH" "y"; then
128 echo "Pushing to openwrt git server"
129 if ! $GIT push; then
130 echo "Failed to push to $BRANCH but left branch as is." >&2
131 exit 12
132 fi
133
134 # Default close comment
135 COMMENT="Thanks! Rebased on top of $BRANCH and merged!"
136
137 if [ -n "$TOKEN" ] && [ -z "$DRY_RUN" ]; then
138 echo ""
139 echo "Enter a comment and hit <enter> to close the PR at Github automatically now."
140 echo "Hit <ctrl>-<c> to exit."
141 echo ""
142 echo "If you do not provide a comment, the default will be: "
143 echo "[$COMMENT]"
144
145 echo -n "Comment > "
146 read usercomment
147
148 echo "Sending message to PR..."
149
150 comment="${usercomment:-$COMMENT}"
151 comment="${comment//\\/\\\\}"
152 comment="${comment//\"/\\\"}"
153 comment="$(printf '{"body":"%s"}' "$comment")"
154
155 if ! curl -s -o /dev/null -w "%{http_code} %{url_effective}\\n" --user "$TOKEN:x-oauth-basic" --request POST --data "$comment" "https://api.github.com/repos/$REPO/issues/$PRID/comments" || \
156 ! curl -s -o /dev/null -w "%{http_code} %{url_effective}\\n" --user "$TOKEN:x-oauth-basic" --request PATCH --data '{"state":"closed"}' "https://api.github.com/repos/$REPO/pulls/$PRID"
157 then
158 echo "" >&2
159 echo "Something failed while sending comment to the PR via ">&2
160 echo "the Github API, please review the state manually at " >&2
161 echo "https://github.com/$REPO/pull/$PRID" >&2
162 exit 6
163 fi
164 fi
165
166 echo -e "\n"
167 echo "The PR has been merged!"
168 echo -e "\n"
169 fi
170 fi
171
172 if [ "$(echo "$PR_INFO" | jq -r ".maintainer_can_modify")" == "true" ]; then
173 echo "Deleting branch $LOCAL_PR_BRANCH"
174 $GIT branch -D $LOCAL_PR_BRANCH
175 fi
176
177 exit 0