#!/usr/bin/env bash # Code modified from https://github.com/kamranahmedse/git-standup, # under the MIT LICENSE. usage() { cat <] [-w |-d ] [-m ] [-D date-format] [-L] [-h] [-f] [-B] [-n ] -a - Specify author to restrict search to, default to current git user. Use "-a all" if you don't want the restriction. -w - Specify weekday range to limit search to -m - Specify the depth of recursive directory search -L - Toggle inclusion of symbolic links in recursive directory search -d - Specify the number of days back to include -D - Specify the date format for "git log" (default: relative) -h - Display this help screen -f - Fetch the latest commits beforehand -B - Display the commits in branch groups -n - Limit the number of commits displayed per group -F gpg - Show if commit is GPG signed (G) or not (N) -F authordate - Print author date instead of commit date Examples: git standup -a "John Doe" -w "MON-FRI" -m 3 EOS } warn() { >&2 echo "${BOLD}${RED}WARNING: $1${NORMAL}" } git rev-parse --show-toplevel > /dev/null 2>&1 in_git_repo=$? # Use colors, but only if connected to a terminal, and that terminal # supports them. if command -v tput >/dev/null 2>&1; then ncolors=$(tput colors) fi if [[ -t 1 ]] && [[ -n "$ncolors" ]] && [[ "$ncolors" -ge 8 ]] ; then RED="$(tput setaf 1)" GREEN="$(tput setaf 2)" YELLOW="$(tput setaf 3)" BOLD="$(tput bold)" NORMAL="$(tput sgr0)" BOLD=$(tput bold) UNDERLINE=$(tput smul) NORMAL=$(tput sgr0) COLOR=always else RED="" GREEN="" YELLOW="" BOLD="" NORMAL="" BOLD="" UNDERLINE="" NORMAL="" COLOR=never fi # Only enable exit-on-error after the non-critical colorization stuff, # which may fail on systems lacking tput or terminfo set -e RANGE_SPECIFIED= COMMIT_DATE_FORMAT=%cd USE_GPG_FORMAT=no while getopts "hgfF:Bd:a:w:m:D:n:L" opt; do case $opt in h) usage exit 0 ;; a) if [[ "$OPTARG" = 'all' ]] ; then AUTHOR=".*" else AUTHOR="$OPTARG" fi ;; d) test -n "$RANGE_SPECIFIED" && warn "-d option is conflict with -w" RANGE_SPECIFIED=yes if [ "$OPTARG" -lt 1 ]; then >&2 echo "Specify days less than one is invalid" exit 1 fi SINCE="$OPTARG days ago" ;; w) if [ -n "$RANGE_SPECIFIED" ]; then warn "-w option is conflict with -d" continue fi RANGE_SPECIFIED=yes week_range=${OPTARG} week_start="${week_range%%-*}" week_start="${week_start:="Mon"}" week_end="${week_range##*-}" week_end=${week_end:="Fri"} ## In case it is the start of week, we need to ## show the commits since the last weekend shopt -s nocasematch if [[ "$week_start" == "$(LC_ALL=C date +%a)" ]] ; then SINCE="last $week_end"; fi ;; f) FETCH_LAST_COMMIT=true ;; m) MAXDEPTH=$((OPTARG + 1)) if [ "$MAXDEPTH" -lt 1 ]; then >&2 echo "Specify depth less than one is invalid" exit 1 fi ;; L) INCLUDE_LINKS=-L ;; D) GIT_DATE_FORMAT=${OPTARG} ;; g) warn "-g option is deprecated, use '-F gpg' instead" USE_GPG_FORMAT=yes ;; B) GROUP_BY_BRANCHES=true ;; n) MAX_COMMIT_NUM=${OPTARG} ;; F) case $OPTARG in gpg) USE_GPG_FORMAT=yes ;; authordate) COMMIT_DATE_FORMAT=%ad ;; *) warn "Invalid argument for -F: $OPTARG" usage exit 1 ;; esac ;; \?) usage exit 1 ;; esac done shift $((OPTIND-1)) if [[ $# -gt 0 ]]; then warn "please upgrade to new-style interface. Run 'git help standup' to get more info." if [[ $# -gt 3 ]] ; then usage exit 1 fi AUTHOR=$1 SINCE=$2 UNTIL=$3 fi AUTHOR=${AUTHOR:="$(git config user.name || echo '')"} if [ -z "${AUTHOR}" ]; then warn "please configure an author with 'git config user.name' or specify an author via '-a'" exit 1 fi FETCH_LAST_COMMIT=${FETCH_LAST_COMMIT:=false} MAXDEPTH=${MAXDEPTH:=2} GIT_PRETTY_FORMAT="%Cred%h%Creset - %s %Cgreen(${COMMIT_DATE_FORMAT}) %C(bold blue)<%an>%Creset" GIT_DATE_FORMAT=${GIT_DATE_FORMAT:=relative} if [[ "$USE_GPG_FORMAT" == 'yes' ]]; then GIT_PRETTY_FORMAT="$GIT_PRETTY_FORMAT %C(yellow)gpg: %G?%Creset" fi # Handle config of implicit week IMPLICIT_WEEK=$(git config --get git-extras.standup.implicit-week || echo '') if [[ -z "$RANGE_SPECIFIED" ]] && [[ -n "${IMPLICIT_WEEK}" ]]; then week_start=${IMPLICIT_WEEK%%-*} week_end=${IMPLICIT_WEEK##*-} shopt -s nocasematch if [[ "$week_start" == "$(LC_ALL=C date +%a)" ]]; then SINCE="last $week_end" fi UNTIL=today else SINCE=${SINCE:=yesterday} UNTIL=${UNTIL:=today} fi GIT_LOG_COMMAND="git --no-pager log \ --no-merges --since \"$SINCE\" --until \"$UNTIL\" --author=\"$AUTHOR\" --abbrev-commit --oneline --color=$COLOR --pretty=format:'$GIT_PRETTY_FORMAT' --date='$GIT_DATE_FORMAT'" if [[ -n "$MAX_COMMIT_NUM" ]]; then GIT_LOG_COMMAND="$GIT_LOG_COMMAND --max-count=$MAX_COMMIT_NUM" fi git_output() { if [ "$GROUP_BY_BRANCHES" = true ]; then local branches branches=$(git branch --sort=-committerdate | awk '{print substr($0, 3)}') for branch in $branches; do # shellcheck disable=SC2086 if output=$(eval $GIT_LOG_COMMAND "$branch"); then if [[ -n "$output" ]] ; then echo "${GREEN}${branch}${NORMAL}" echo "$output" echo "" fi fi # TODO optimize:return if the latest commit of a branch is earlier than the 'since' day done else # shellcheck disable=SC2086 eval $GIT_LOG_COMMAND --all fi } ## For when the command has been run in a non-repo directory if [[ $in_git_repo != 0 ]]; then ## Set delimiter to newline for the loop IFS=$'\n' ## Recursively search for git repositories # shellcheck disable=SC2086 PROJECT_DIRS=$(find $INCLUDE_LINKS . -maxdepth "$MAXDEPTH" -mindepth 0 -name .git) # Fetch the latest commits, if required if [ "$FETCH_LAST_COMMIT" = true ]; then echo "${BOLD}${GREEN}Fetching commits ..${NORMAL}" # Foreach of the project directories, fetch the commits for DIR in $PROJECT_DIRS; do DIR="$(dirname "$DIR")" pushd "$DIR" > /dev/null if [[ -d ".git" ]] ; then echo " ${YELLOW}$(basename "$DIR")${NORMAL}" git fetch --all > /dev/null 2>&1 fi popd > /dev/null done fi # Get the standup details for each of the projects for DIR in $PROJECT_DIRS; do DIR="$(dirname "$DIR")" pushd "$DIR" > /dev/null ## Show the detail only if it is a git repository if [[ -d ".git" || -f ".git" ]] ; then if GITOUT=$(git_output); then ## Only output if there is some activities if [[ -n "$GITOUT" ]] ; then echo "${BOLD}${UNDERLINE}${YELLOW}$(basename "$DIR")${NORMAL}" echo "$GITOUT" echo "" fi else echo "Repository under $DIR could not be queried." >&2 fi fi popd > /dev/null done else if [ "$FETCH_LAST_COMMIT" = true ]; then echo "${GREEN}Fetching commits ..${NORMAL}" git fetch --all > /dev/null 2>&1 fi if GITOUT=$(git_output); then if [[ -n "$GITOUT" ]] ; then echo "$GITOUT" else if [[ $AUTHOR = '.*' ]] ; then AUTHOR="all the contributors" fi echo "${YELLOW}Seems like $AUTHOR did nothing!${NORMAL}" fi fi fi