Last active
March 28, 2019 00:25
-
-
Save davorbonaci/16f1c588e0d2140e5be3af1c5f756a55 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 =~ ^([yY][eE][sS]|[yY])$ ]] ; 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" \ | |
|| clean_up "ERROR: Failed to clone GitHub repository." | |
cd "${REPOSITORY}" | |
git remote add ${TARGET_REMOTE} \ | |
"https://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 source pull request." | |
git fetch ${TARGET_REMOTE} "${TARGET_BRANCH}" \ | |
|| clean_up "ERROR: Failed to fetch target branch." | |
# 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." | |
echo "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 skip running '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