#!/bin/bash -e # This script is manually run at end of release time (at eol) to # retire a branch. function print_help { echo "" echo "USAGE:" echo " ./eol_branch.sh [options] branch project [project [project [...]]]" echo "" echo "A tool for retiring old branches. Performs the following:" echo "1) Abandon stale reviews," echo "2) delete the branch from the remote" echo "" echo "Must be ran from a directory containing a recent checkout of the project[s]" echo "" echo "Options:" echo " -d, --dry-run Do not run any harmful commands" echo " -h, --help This help message" echo " -q, --quiet Turn off unimportant messages" echo " --remote Set the remote to delete branches from (default: gerrit)" echo " -w, --warn-exit Exit on any warnings" echo "" } OPTS=`getopt -o dhqw --long dry-run,help,quiet,remote:,warn-exit -n $0 -- "$@"` if [ $? != 0 ] ; then echo "Failed parsing options." >&2 print_help exit 1 fi eval set -- "$OPTS" set -e # Defaults: DEBUG= REMOTE=gerrit VERBOSE=true WARN_EXIT=false while true; do case "$1" in -d|--dry-run) DEBUG=echo shift ;; -h|--help) print_help exit 0 ;; -q|--quiet) VERBOSE=false shift ;; --remote) REMOTE=$2 shift shift ;; -w|--warn-exit) WARN_EXIT=true shift ;; --) shift break ;; esac done # First argument is the branch to delete BRANCH=$1 shift EOL_MESSAGE="This branch ${BRANCH} is at End Of Life" function abandon_reviews { project=$1 if [ $VERBOSE = true ]; then echo "Running query: status:open project:$project branch:$BRANCH" fi gerrit_query="--current-patch-set status:open project:$project branch:$BRANCH" revisions=($(ssh -p 29418 review.opendev.org gerrit query $gerrit_query | grep '^ revision: [a-f0-9]\{40\}$' | cut -b 15-)) for rev in "${revisions[@]}"; do if [ $VERBOSE = true ]; then echo "Found commit $rev to abandon" fi $DEBUG ssh -p 29418 review.opendev.org gerrit review --project $project --abandon --message \"$EOL_MESSAGE\" $rev done } function delete_branch { rev=`git rev-parse remotes/$REMOTE/$BRANCH` if [ $VERBOSE = true ]; then echo "About to delete the branch $BRANCH from $project (rev $rev)" fi $DEBUG git push $REMOTE --delete refs/heads/$BRANCH } function warning_message { echo "WARNING: $1" if [ $WARN_EXIT = true ]; then exit 1 fi } while (( "$#" )); do project=$1 shift if ! [ -d $project/.git ]; then if ! [ -d $project ]; then echo "$project not found on filesystem. Will attempt to clone" $DEBUG git clone https://opendev.org/$project $project else warning_message "$project is not a git repo" echo "skipping..." continue fi fi pushd $project if ! git config remote.$REMOTE.url >/dev/null 2>&1; then if ! [ -f .gitreview ]; then # Work around projects with missing .gitreview files. This usually # happens when a probject is no longer maintained. user=`git config --global gitreview.username` warning_message "Guessing remote manually" git remote add $REMOTE ssh://$user@review.opendev.org:29418/$project.git else git review -s fi fi # Add some hardening around incorrect looking remote url's remote_url=`git config --get remote.$REMOTE.url` if [[ $remote_url != *"$project.git" && $remote_url != *"$project" ]]; then warning_message "The url for remote $REMOTE does not end with $project or $project.git. This may be deliberate, but it's more likely that the project has a mis-configured .gitreview file pointing to the wrong repository. This is the case in many of the (now retired) deb-* packages where their remotes were set to the upstream project instead of their own deb repository." echo "skipping..." popd continue fi git remote update --prune if ! git rev-parse remotes/$REMOTE/$BRANCH >/dev/null 2>&1; then warning_message "$project does not have a branch $BRANCH" echo "skipping..." popd continue fi abandon_reviews $project delete_branch $project popd done