Skip to content

Instantly share code, notes, and snippets.

@dhalperi
Forked from davorbonaci/beam_merge_pr.sh
Last active January 19, 2017 23:42
Show Gist options
  • Save dhalperi/42184e11773c426e41f2aad134a2d6c9 to your computer and use it in GitHub Desktop.
Save dhalperi/42184e11773c426e41f2aad134a2d6c9 to your computer and use it in GitHub Desktop.
#!/bin/bash
# This is a utility script to merge pull requests into Apache Beam
# repositories. It supports both repositories, source and website.
#
# Usage:
# merge_pr.sh [repository] [branch] pull_request_number
#
# Where:
# repository: { beam | beam-site }
# Default: beam.
# branch: { master | asf-site | any_other_branch }
# Default: master or asf-site, depending on the repository.
# ******************************************************************************
# This function gets called to clean up temporary files and
# revert back to the original state.
function clean_up
{
# Print final status message.
echo $1
# Optionally, clean up temporary state.
read -r -p "Do you want to clean up temporary files? [Y/n] " response
if ! [[ $response =~ ^([nN][oO]|[nN])$ ]] ; then
git branch -D finish-pr-${PR_NUM} >/dev/null 2>/dev/null || true
rm -fr ${ROOT_DIR}
else
echo "Temporary workspace left at: ${ROOT_DIR}"
fi
# Return back to the original directory.
popd >/dev/null 2>/dev/null
exit 0
}
TARGET_REMOTE=apache
SOURCE_REMOTE=github
# Argument parsing.
if [[ $# -eq 1 ]] ; then
# One argument for pull request number; default others.
REPOSITORY=beam
TARGET_BRANCH=master
PR_NUM=$1
elif [[ $# -eq 2 ]] ; then
# Two arguments; attempt to figure out whether the user specified repository
# or branch.
if [[ "$1" = "beam" ]] ; then
REPOSITORY=$1
TARGET_BRANCH=master
PR_NUM=$2
elif [[ "$1" = "beam-site" ]] ; then
REPOSITORY=$1
TARGET_BRANCH=asf-site
PR_NUM=$2
else
REPOSITORY=beam
TARGET_BRANCH=$1
PR_NUM=$2
fi
elif [[ $# -eq 3 ]] ; then
# All arguments provided.
REPOSITORY=$1
TARGET_BRANCH=$2
PR_NUM=$3
else
# Unexpected number of flags. Print usage information.
echo "Usage: merge_pr.sh [repository] [branch] pull_request_number"
echo ""
echo " repository: { beam | beam-site }"
echo " Default: beam."
echo " branch: { master | asf-site | any_other_branch }"
echo " Default: master or asf-site, depending on the repository."
exit 1
fi
# Echo display what we are about to do.
echo "Attempting to merge pull request #${PR_NUM} to the branch "`
`"\"${TARGET_BRANCH}\" in the repository \"${REPOSITORY}\"."
# Create temporary directory for this work.
pushd . >/dev/null 2>/dev/null
ROOT_DIR=`mktemp -d`
cd $ROOT_DIR
# Clone the repository and configure it.
git clone --single-branch -b ${TARGET_BRANCH} https://github.com/apache/${REPOSITORY}.git --depth 10 \
|| clean_up "ERROR: Failed to clone GitHub repository."
cd ${REPOSITORY}
git remote add ${TARGET_REMOTE} \
https://dhalperi@git-wip-us.apache.org/repos/asf/${REPOSITORY}.git
git remote rename origin ${SOURCE_REMOTE}
git config --local --add remote.${SOURCE_REMOTE}.fetch \
"+refs/pull/*/head:refs/remotes/${SOURCE_REMOTE}/pr/*"
# Fetch everything to make sure we have the last state of the branch.
git fetch ${SOURCE_REMOTE} pull/${PR_NUM}/head \
|| clean_up "ERROR: Failed to fetch remote repositories."
git fetch ${TARGET_REMOTE} ${TARGET_BRANCH} \
|| clean_up "ERROR: Failed to fetch remote repositories."
# Checkout the pull request for merging
git checkout -b finish-pr-${PR_NUM} ${SOURCE_REMOTE}/pr/${PR_NUM} \
|| clean_up "ERROR: Failed to checkout pull request number #${PR_NUM}."
# Infinite loop to iterate on the pull request.
while :
do
# Rebase the pull request on the target branch.
git rebase -i ${TARGET_REMOTE}/${TARGET_BRANCH} \
|| clean_up "ERROR: Failed to rebase on top of ${TARGET_REMOTE}/${TARGET_BRANCH}."
# If the rebase included an interactive command (eg., edit) open a shell to
# complete it
while [ -d ".git/rebase-merge" -o -d ".git/rebase-apply" ]; do
echo "Interactive rebase in progress. Starting a shell shell to finish.\n"`
`"To resume, complete the rebase and run \"exit\"."
$SHELL -i
if [ -d ".git/rebase-merge" -o -d ".git/rebase-apply" ]; then
read -r -p "Rebase still in progress. Do you want to abort the rebase" \
response
if [[ $response =~ ^([yY][eE][sS]|[yY])$ ]]; then
git rebase --abort;
fi
fi
done
# Open 'gitk' to review the state of this branch.
gitk
# Ask the user whether we should proceed.
read -r -p "Are you happy with how this branch looks? [y/N] " response
if [[ $response =~ ^([yY][eE][sS]|[yY])$ ]] ; then
break
fi
done
# If website repository, offer to regenerate the site.
if [[ "${REPOSITORY}" = "beam-site" ]] ; then
read -r -p "Do you want to regenerate the website? [y/N] " \
response
if [[ $response =~ ^([yY][eE][sS]|[yY])$ ]] ; then
bundle exec jekyll build \
|| clean_up "ERROR: Building the website failed. Make sure your "`
`"environment is correctly set up for building the website."
git add --all -- content
git commit -m "Regenerate website" \
|| clean_up "ERROR: Couldn't commit the website."
fi
fi
# At this point, we are happy how the pull request branch looks like.
# Merge it on the target branch.
git checkout ${TARGET_REMOTE}/${TARGET_BRANCH} \
|| clean_up "ERROR: Failed to checkout target branch "`
`"\"${TARGET_REMOTE}/${TARGET_BRANCH}\"."
git merge --no-ff -m $"This closes #${PR_NUM}" finish-pr-${PR_NUM} \
|| clean_up "ERROR: Failed to merge local branch "`
`"\"finish-pr-${PR_NUM}\" to the target branch."
# Open 'gitk' to review the state of this branch.
gitk
# Run 'mvn clean verify', as one more final validation.
if [[ "${REPOSITORY}" = "beam" ]] ; then
read -r -p "Do you want to run 'mvn clean verify' locally? [y/N] " \
response
if [[ $response =~ ^([yY][eE][sS]|[yY])$ ]] ; then
mvn clean verify \
|| clean_up "ERROR: Maven test failed. Please fix it before pushing."
fi
fi
# Ask the user whether we should proceed.
echo "CAUTION -- This is the point of no return! CAUTION!"
read -r -p "Do you want to push this branch? [y/N] " response
if [[ $response =~ ^([yY][eE][sS]|[yY])$ ]] ; then
git push ${TARGET_REMOTE} HEAD:${TARGET_BRANCH} \
|| clean_up "ERROR: Failed to push to \"${TARGET_REMOTE}\" remote.\n"`
`"Run \"git push ${TARGET_REMOTE} HEAD:${TARGET_BRANCH}\" to retry."
fi
clean_up "SUCCESS."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment