#!/bin/bash # Parses Subversion repository log messages and outputs authors and their # respective number of commits. # # Output can be sorted: # # -a sort output by author name # -c sort output by number of commits # # Output can also be limited to commits from the last year: # # -y display only commits from the last 365 days # # Will run on first 'path' parameter, or on current working directory if no # path is supplied. # # TODO: # - Add option to bin authors and commits by year # - Convert to using XML output from SVN log (i.e. `svn log --xml`) ## Functions # function display_help { echo "usage: ${script_name} [option] [path]" >&2 case "${uname_out}" in Linux*) display_help_linux ;; Darwin*) display_help_mac ;; *) ;; esac } function display_help_mac { echo " -h diplay help" echo " -a sort output by author name" echo " -c sort output by number of commits" echo " -y display only commits from the last 365 days" } function display_help_linux { echo " -h | --help diplay help" echo " -a | --authors sort output by author name" echo " -c | --commits sort output by number of commits" echo " -y | --year display only commits from the last 365 days" } function print_authors { i=0 until [[ $i -eq "${#authors[@]}" ]]; do printf "%-15s %i\n" "${authors[$i]}" "${commits[$i]}" (( i++ )) done } function print_authors_sorted_by_author { local i=0 until [[ $i -eq "${#authors[@]}" ]]; do printf "%-15s %i\n" "${authors[$i]}" "${commits[$i]}" (( i++ )) done | sort -n -k1 } function print_authors_sorted_by_commits { local i=0 until [[ $i -eq "${#authors[@]}" ]]; do printf "%-15s %i\n" "${authors[$i]}" "${commits[$i]}" (( i++ )) done | sort -rn -k2 } ## Initialize conditional variables # one_year_ago="" sort_by_author=0 sort_by_commits=0 today="" # Retrieve script name script_name=$(basename "$0") ## Retrieve OS # uname_out=$(uname -s) case "${uname_out}" in Linux*) options=$(getopt -n ${script_name} -o hacy --long help,author,commits,year -- "$@") ;; Darwin*) options=$(getopt hacy $*) ;; *) printf "operating system %s not currently supported\n" "${uname_out}" >&2 exit 1 ;; esac ## Handle options # valid_options=$? if [[ $valid_options -ne 0 ]]; then display_help exit 1 fi #echo $options # Uncomment for debugging set -- $options while : do case "$1" in -h | --help) display_help exit 0 ;; -a | --author) sort_by_author=1 shift ;; -c | --commits) sort_by_commits=1 shift ;; -y | --year) today=$(date +%Y-%m-%d) one_year_ago=$(date -v -1y -v +1d +%Y-%m-%d) # Date adjusted 365 days shift ;; --) shift break ;; *) break ;; esac done ## Retrieve path # # If no path was given, use current working directory; if one or more were # given, just use the first one. # path="." num_args=${#@} if [[ $num_args -gt 0 ]]; then path=$1 fi authors=() commits=() # Get entire log once if [[ $one_year_ago != "" ]]; then log=$(svn log -r "{${today}}:{${one_year_ago}}" "${path}") else log=$(svn log "${path}") fi data_lines=$(echo "${log}" | egrep "r[0-9]+") # Get only lines from log that contain info we care about while IFS= read line; do author=$(echo "${line}" | awk -F "|" '{print $2}' | tr -d ' ') # Uncomment if we want to treat blank author as "unknown" if [[ "$author" == "" ]]; then author="unknown" fi have_seen_author=0 for (( i=0; i<${#authors[@]}; ++i )); do if [[ "${authors[$i]}" == "$author" ]]; then have_seen_author=1 break fi done if [[ $have_seen_author -eq 0 ]]; then authors+=("${author}") commits+=(1) else (( commits[$i]++ )) fi done <<< "${data_lines}" ## Print results (sorted, if requested) # # NOTE: If multiple sort options are specified, the order or precedence is # specified as follows. # if [ $sort_by_commits -eq 1 ]; then print_authors_sorted_by_commits elif [ $sort_by_author -eq 1 ]; then print_authors_sorted_by_author else print_authors fi