-
Notifications
You must be signed in to change notification settings - Fork 984
/
merge-pr.sh
executable file
·174 lines (151 loc) · 3.74 KB
/
merge-pr.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#!/usr/bin/env bash
set -eof pipefail
trap cleanup EXIT
fatal() {
echo "FATAL: $@" >&2
exit 1
}
warn() {
echo "$@"
}
confirm() {
read -p "$1 (type 'yes' to continue) " r
if [[ $r != yes ]]; then
exit 3
fi
}
load_config() {
[[ -f merge-pr.conf ]] && . merge-pr.conf
: ${OWNER:=status-im}
: ${REPO:=status-mobile}
: ${REMOTE:=origin}
: ${BRANCH:=develop}
}
check_pr_prereq() {
if ! command -v jq >/dev/null; then
fatal "jq(1) is not found, PR cannot be queried."
fi
if ! command -v curl >/dev/null; then
fatal "curl(1) is not found, PR cannot be queried."
fi
}
check_sync() {
git fetch
if [ -n "$(git rev-list $BRANCH..$REMOTE/$BRANCH)" ]; then
warn "the local branch $BRANCH is behind $REMOTE/$BRANCH."
echo "Do you want to cancel or do you prefer to abandon your work and reset local $BRANCH to $REMOTE/$BRANCH ?"
echo "cancel/reset"
read response;
if [ "$response" = "reset" ]; then
git fetch $REMOTE
git checkout $BRANCH
git reset --hard $REMOTE/$BRANCH
else
fatal "the local branch $BRANCH is behind $REMOTE/$BRANCH."
fi
fi
}
GH_URL_BASE="https://api.github.com"
get_pr_info() {
echo '[ Reading PR info ]'
local pr=$1
local pr_info_url="$GH_URL_BASE/repos/${OWNER}/${REPO}/pulls/$pr"
set +e
local pr_info
pr_info=$(curl -fsS "$pr_info_url")
if [ $? -ne 0 ]; then
fatal "Unable to get PR info from $pr_info_url"
fi
set -e
if [[ $(echo "$pr_info" | jq -r .state) == closed ]]; then
fatal "PR $pr is closed, will not merge"
fi
if [[ ($(echo "$pr_info" | jq -r .maintainer_can_modify) == true) ||\
($(echo "$pr_info" | jq -r .author_association) == MEMBER) ||\
($(echo "$pr_info" | jq -r .author_association) == OWNER)]]; then
RW_PR_REPO=1
else
warn "PR does not allow 'edits from maintainers', so it will be kept open"
fi
PR_URL=$(echo "$pr_info" | jq -r .head.repo.ssh_url)
PR_REMOTE_NAME=pr-$pr
PR_BRANCH=$(echo "$pr_info" | jq -r .head.ref)
PR_LOCAL_BRANCH=pr-$pr
}
fetch_pr() {
echo '[ Fetching PR ]'
git remote add $PR_REMOTE_NAME $PR_URL
git fetch $PR_REMOTE_NAME $PR_BRANCH
}
refresh_base_branch() {
git fetch $REMOTE $BRANCH
}
rebase_pr() {
git checkout -B $PR_LOCAL_BRANCH $PR_REMOTE_NAME/$PR_BRANCH
git rebase $BRANCH
}
check_is_pr_single_commit() {
if [[ $(git rev-list $BRANCH..$PR_LOCAL_BRANCH | wc -l) -ne 1 ]] ;then
confirm "PR has multiple commits, continue merging without squashing them?"
fi
}
request_to_squash() {
if [[ $(git rev-list $BRANCH..$PR_LOCAL_BRANCH | wc -l) -gt 1 ]] ;then
confirm "PR has multiple commits, do interactive rebase?"
git rebase -i $BRANCH
fi
}
confirm_pr() {
git log -p $BRANCH..$PR_LOCAL_BRANCH
confirm "Do you like this PR?"
}
sign_pr() {
git commit --amend --gpg-sign --signoff
}
verify_pr() {
git show --show-signature $PR_LOCAL_BRANCH
confirm "Is the signature on the commit correct?"
}
merge_pr() {
# If PR is specified and can be pushed into, do it to mark PR as closed
if [[ -n $RW_PR_REPO ]]; then
git push -f $PR_REMOTE_NAME $PR_LOCAL_BRANCH:$PR_BRANCH
fi
git checkout $BRANCH
git merge --ff-only $PR_LOCAL_BRANCH
git push $REMOTE $BRANCH
}
cleanup() {
if [[ -z $DEBUG ]]; then
git checkout -q $BRANCH
git branch -q -D $PR_LOCAL_BRANCH 2>/dev/null || :
git remote remove $PR_REMOTE_NAME 2>/dev/null || :
fi
}
run() {
if [[ $# -ne 1 ]] ; then
cat <<EOF >&2
Requirements:
jq
curl
Usage:
./merge-pr.sh <PR-ID>
EOF
exit 2
fi
load_config
check_pr_prereq
check_sync
get_pr_info "$@"
cleanup
fetch_pr
refresh_base_branch
rebase_pr
request_to_squash
check_is_pr_single_commit
confirm_pr
sign_pr
verify_pr
merge_pr
}
run "$@"