diff --git a/docs/devel/cherry-picks.md b/docs/devel/cherry-picks.md index 5fbada99482..2708db93b8a 100644 --- a/docs/devel/cherry-picks.md +++ b/docs/devel/cherry-picks.md @@ -8,7 +8,7 @@ Kubernetes projects. Any contributor can propose a cherry pick of any pull request, like so: ``` -hack/cherry_pick_pull.sh 98765 upstream/release-3.14 +hack/cherry_pick_pull.sh upstream/release-3.14 98765 ``` This will walk you through the steps to propose an automated cherry pick of pull diff --git a/hack/cherry_pick_pull.sh b/hack/cherry_pick_pull.sh index 167b57f3dc5..0eca37b7a0a 100755 --- a/hack/cherry_pick_pull.sh +++ b/hack/cherry_pick_pull.sh @@ -28,12 +28,13 @@ cd "${KUBE_ROOT}" declare -r STARTINGBRANCH=$(git symbolic-ref --short HEAD) declare -r REBASEMAGIC="${KUBE_ROOT}/.git/rebase-apply" -if [[ "$#" -ne 2 ]]; then - echo "${0} : cherry pick onto and leave instructions for proposing pull request" +if [[ "$#" -lt 2 ]]; then + echo "${0} ...: cherry pick one or more onto and leave instructions for proposing pull request" echo "" - echo " Checks out and handles the cherry-pick of for you." - echo " Example:" - echo " $0 12345 upstream/release-3.14" + echo " Checks out and handles the cherry-pick of (possibly multiple) for you." + echo " Examples:" + echo " $0 upstream/release-3.14 12345 # Cherry-picks PR 12345 onto upstream/release-3.14 and proposes that as a PR." + echo " $0 upstream/release-3.14 12345 56789 # Cherry-picks PR 12345, then 56789 and proposes the combination as a single PR." exit 2 fi @@ -47,8 +48,14 @@ if [[ -e "${REBASEMAGIC}" ]]; then exit 1 fi -declare -r PULL="${1}" -declare -r BRANCH="${2}" +declare -r BRANCH="$1" +shift 1 +declare -r PULLS=( "$@" ) + +function join { local IFS="$1"; shift; echo "$*"; } +declare -r PULLDASH=$(join - "${PULLS[@]/#/\#}") # Generates something like "#12345-#56789" +declare -r PULLSUBJ=$(join " " "${PULLS[@]/#/\#}") # Generates something like "#12345 #56789" + echo "+++ Updating remotes..." git remote update @@ -58,11 +65,8 @@ if ! git log -n1 --format=%H "${BRANCH}" >/dev/null 2>&1; then exit 1 fi -echo "+++ Downloading patch to /tmp/${PULL}.patch (in case you need to do this again)" - -curl -o "/tmp/${PULL}.patch" -sSL "https://github.com/GoogleCloudPlatform/kubernetes/pull/${PULL}.patch" - -declare -r NEWBRANCH="$(echo automated-cherry-pick-of-#${PULL}-on-${BRANCH} | sed 's/\//-/g')" +declare -r NEWBRANCHREQ="automated-cherry-pick-of-${PULLDASH}" # "Required" portion for tools. +declare -r NEWBRANCH="$(echo ${NEWBRANCHREQ}-${BRANCH} | sed 's/\//-/g')" declare -r NEWBRANCHUNIQ="${NEWBRANCH}-$(date +%s)" echo "+++ Creating local branch ${NEWBRANCHUNIQ}" @@ -84,35 +88,39 @@ trap return_to_kansas EXIT git checkout -b "${NEWBRANCHUNIQ}" "${BRANCH}" cleanbranch="${NEWBRANCHUNIQ}" -echo -echo "+++ About to attempt cherry pick of PR. To reattempt:" -echo " $ git am -3 /tmp/${PULL}.patch" -echo gitamcleanup=true -git am -3 "/tmp/${PULL}.patch" || { - conflicts=false - while unmerged=$(git status --porcelain | grep ^U) && [[ -n ${unmerged} ]] \ - || [[ -e "${REBASEMAGIC}" ]]; do - conflicts=true # <-- We should have detected conflicts once - echo - echo "+++ Conflicts detected:" - echo - (git status --porcelain | grep ^U) || echo "!!! None. Did you git am --continue?" - echo - echo "+++ Please resolve the conflicts in another window (and remember to 'git add / git am --continue')" - read -p "+++ Proceed (anything but 'y' aborts the cherry-pick)? [y/n] " -r - echo - if ! [[ "${REPLY}" =~ ^[yY]$ ]]; then - echo "Aborting." >&2 +for pull in "${PULLS[@]}"; do + echo "+++ Downloading patch to /tmp/${pull}.patch (in case you need to do this again)" + curl -o "/tmp/${pull}.patch" -sSL "https://github.com/GoogleCloudPlatform/kubernetes/pull/${pull}.patch" + echo + echo "+++ About to attempt cherry pick of PR. To reattempt:" + echo " $ git am -3 /tmp/${pull}.patch" + echo + git am -3 "/tmp/${pull}.patch" || { + conflicts=false + while unmerged=$(git status --porcelain | grep ^U) && [[ -n ${unmerged} ]] \ + || [[ -e "${REBASEMAGIC}" ]]; do + conflicts=true # <-- We should have detected conflicts once + echo + echo "+++ Conflicts detected:" + echo + (git status --porcelain | grep ^U) || echo "!!! None. Did you git am --continue?" + echo + echo "+++ Please resolve the conflicts in another window (and remember to 'git add / git am --continue')" + read -p "+++ Proceed (anything but 'y' aborts the cherry-pick)? [y/n] " -r + echo + if ! [[ "${REPLY}" =~ ^[yY]$ ]]; then + echo "Aborting." >&2 + exit 1 + fi + done + + if [[ "${conflicts}" != "true" ]]; then + echo "!!! git am failed, likely because of an in-progress 'git am' or 'git rebase'" exit 1 fi - done - - if [[ "${conflicts}" != "true" ]]; then - echo "!!! git am failed, likely because of an in-progress 'git am' or 'git rebase'" - exit 1 - fi -} + } +done gitamcleanup=false if git remote -v | grep ^origin | grep GoogleCloudPlatform/kubernetes.git; then @@ -123,7 +131,10 @@ if git remote -v | grep ^origin | grep GoogleCloudPlatform/kubernetes.git; then echo echo "where REMOTE is your personal fork (maybe 'upstream'? Consider swapping those.)." echo "Then propose ${NEWBRANCH} as a pull against ${BRANCH} (NOT MASTER)." - echo "Use this exact subject: 'Automated cherry pick of #${PULL}' and include a justification." + echo "Use this subject: 'Automated cherry pick of ${PULLSUBJ}' and include a justification." + echo "" + echo "Note: the tools actually scrape the branch name you just pushed, so don't worry about" + echo "the subject too much, but DO keep at least ${NEWBRANCHREQ} in the remote branch name." cleanbranch="" exit 0 fi @@ -143,5 +154,8 @@ git push origin -f "${NEWBRANCHUNIQ}:${NEWBRANCH}" echo echo "+++ Now you must propose ${NEWBRANCH} as a pull against ${BRANCH} (NOT MASTER)." -echo " You must use this exact subject: 'Automated cherry pick of #${PULL}' and include a justification." +echo " Use this subject: 'Automated cherry pick of ${PULLSUBJ}' and include a justification." +echo "" +echo " Note: the tools actually scrape the branch name you just pushed, so don't worry about" +echo " the subject too much, but DO keep at least ${NEWBRANCHREQ} in the remote branch name." echo