[FIX #2636] Add script for merging external contributions

Pulls, rebases, displays, signs and pushes external contributions.

If jq(1) and curl(1) are available, can pull data from GitHub and
mark PRs as closed, otherwise only code merging works.

Signed-off-by: Oskar Thoren <ot@oskarthoren.com>
This commit is contained in:
Mikhail Gusarov 2017-12-17 01:53:54 +03:00 committed by Oskar Thoren
parent 1c85797121
commit 279ebc3173
No known key found for this signature in database
GPG Key ID: 5128AB0637CD85AF
1 changed files with 152 additions and 0 deletions

152
scripts/merge-external-pr.sh Executable file
View File

@ -0,0 +1,152 @@
#!/bin/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-external-pr.conf ]] && . merge-external-pr.conf
: ${OWNER:=status-im}
: ${REPO:=status-react}
: ${REMOTE:=origin}
: ${BRANCH:=develop}
}
check_pr_prereq() {
if ! command -v jq >/dev/null; then
fatal "jq(1) is not found, PR cannot be queried. Use REPO BRANCH"
fi
if ! command -v curl >/dev/null; then
fatal "curl(1) is not found, PR cannot be queried. Use REPO BRANCH"
fi
}
GH_URL_BASE="https://api.github.com"
get_pr_info() {
echo '[ Reading PR info ]'
if [ $# -eq 1 ]; then
check_pr_prereq
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 ]]; 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
else
PR_URL="$1"
PR_REMOTE_NAME=${PR_URL##*/}
PR_REMOTE_NAME=pr-${PR_REMOTE_NAME%.git}
PR_REMOTE_NAME=pr-${PR_REPO_NAME}
PR_BRANCH="$2"
PR_LOCAL_BRANCH=pr-${PR_REPO_NAME}
fi
}
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_BRACNCH | wc -l) -ne 1 ]] ;then
fatal "Only squashed/single-commit PRs can be merged"
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 [[ $# -lt 1 ]] || [[ $# -gt 2 ]]; then
cat <<EOF >&2
Usage:
./merge-external-pr.sh REPO_URL BRANCH
./merge-external.pr.sh PR (if jq(1) and curl(1) are available)
EOF
exit 2
fi
load_config
get_pr_info "$@"
cleanup
fetch_pr
refresh_base_branch
rebase_pr
check_is_pr_single_commit
confirm_pr
sign_pr
verify_pr
merge_pr
}
run "$@"