status-react/scripts/merge-external-pr.sh
Mikhail Gusarov 279ebc3173
[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>
2017-12-26 02:15:15 +01:00

153 lines
3.2 KiB
Bash
Executable File

#!/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 "$@"