#!/bin/bash # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # This script assumes that your remote is called "origin" # and that your local master branch is called "master". # I am sure it could be made more abstract but these are the defaults. # Edit this line to point to your default directory, # or always pass a directory to the script. DEFAULT_DIR="EDIT_ME" function print_usage { cat << __EOF $0: A script to manage your Apache HBase Git repository. If run with no arguments, it reads the DEFAULT_DIR variable, which you can specify by editing the script. Usage: $0 [-d ] $0 -h -h Show this screen. -d The absolute or relative directory of your Git repository. __EOF } function get_all_branches { # Gets all git branches present locally all_branches=() for i in `git branch --list | sed -e "s/\*//g"`; do all_branches+=("$(echo $i | awk '{print($1)}')") done } function get_tracking_branches { # Gets all branches with a remote tracking branch tracking_branches=() for i in `git branch -lvv | grep "\[origin/" | sed -e 's/\*//g' | awk {'print $1'}`; do tracking_branches+=("$(echo $i | awk '{print($1)}')") done } function check_git_branch_status { # Checks the current Git branch to see if it's dirty # Returns 1 if the branch is dirty git_dirty=$(git diff --shortstat 2> /dev/null | wc -l|awk {'print $1'}) if [ "$git_dirty" -ne 0 ]; then echo "Git status is dirty. Commit locally first." >&2 exit 1 fi } function get_jira_status { # This function expects as an argument the JIRA ID, # and returns 99 if resolved and 1 if it couldn't # get the status. # The JIRA status looks like this in the HTML: # span id="resolution-val" class="value resolved" > # The following is a bit brittle, but filters for lines with # resolution-val returns 99 if it's resolved jira_url='https://issues.apache.org/jira/rest/api/2/issue' jira_id="$1" curl -s "$jira_url/$jira_id?fields=resolution" |grep -q '{"resolution":null}' status=$? if [ $status -ne 0 -a $status -ne 1 ]; then echo "Could not get JIRA status. Check your network." >&2 exit 1 fi if [ $status -ne 0 ]; then return 99 fi } # Process the arguments while getopts ":hd:" opt; do case $opt in d) # A directory was passed in dir="$OPTARG" if [ ! -d "$dir/.git/" ]; then echo "$dir does not exist or is not a Git repository." >&2 exit 1 fi ;; h) # Print usage instructions print_usage exit 0 ;; *) echo "Invalid argument: $OPTARG" >&2 print_usage >&2 exit 1 ;; esac done if [ -z "$dir" ]; then # No directory was passed in dir="$DEFAULT_DIR" if [ "$dir" = "EDIT_ME" ]; then echo "You need to edit the DEFAULT_DIR in $0." >&2 $0 -h exit 1 elif [ ! -d "$DEFAULT_DIR/.git/" ]; then echo "Default directory $DEFAULT_DIR is not a Git repository." >&2 exit 1 fi fi cd "$dir" # For each tracking branch, check it out and make sure it's fresh # This function creates tracking_branches array and stores the tracking branches in it get_tracking_branches for i in "${tracking_branches[@]}"; do git checkout -q "$i" # Exit if git status is dirty check_git_branch_status git pull -q --rebase status=$? if [ "$status" -ne 0 ]; then echo "Unable to pull changes in $i: $status Exiting." >&2 exit 1 fi echo "Refreshed $i from remote." done # Run the function to get the list of all branches # The function creates array all_branches and stores the branches in it get_all_branches # Declare array to hold deleted branch info deleted_branches=() for i in "${all_branches[@]}"; do # Check JIRA status to see if we still need this branch # JIRA expects uppercase jira_id="$(echo $i | awk '{print toupper($0)'})" if [[ "$jira_id" == HBASE-* ]]; then # Returns 1 if the JIRA is closed, 0 otherwise get_jira_status "$jira_id" jira_status=$? if [ $jira_status -eq 99 ]; then # the JIRA seems to be resolved or is at least not unresolved deleted_branches+=("$i") fi fi git checkout -q "$i" # Exit if git status is dirty check_git_branch_status # If this branch has a remote, don't rebase it # If it has a remote, it has a log with at least one entry git log -n 1 origin/"$i" > /dev/null 2>&1 status=$? if [ $status -eq 128 ]; then # Status 128 means there is no remote branch # Try to rebase against master echo "Rebasing $i on origin/master" git rebase -q origin/master > /dev/null 2>&1 if [ $? -ne 0 ]; then echo "Failed. Rolling back. Rebase $i manually." git rebase --abort fi elif [ $status -ne 0 ]; then # If status is 0 it means there is a remote branch, we already took care of it echo "Unknown error: $?" >&2 exit 1 fi done # Offer to clean up all deleted branches for i in "${deleted_branches[@]}"; do read -p "$i's JIRA is resolved. Delete? " yn case $yn in [Yy]) git branch -D $i ;; *) echo "To delete it manually, run git branch -D $deleted_branches" ;; esac done git checkout -q master exit 0