Merge pull request #71 from tomice/master

Added ability to save log as a JSON formatted file
This commit is contained in:
Tom Ice 2019-05-26 10:27:58 -04:00 committed by GitHub
commit c11bce17bd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 141 additions and 87 deletions

9
.gitignore vendored Normal file
View file

@ -0,0 +1,9 @@
*.json
*.db
.DS_Store*
._*
.*.swp
.*.swo
.Spotlight*
.Trash*
**/*~

View file

@ -5,7 +5,7 @@
> Any git repository contains tons of information about commits, contributors, and files. Extracting this information is not always trivial, mostly because of a gadzillion options to a gadzillion git commands I dont think there is a single person alive who knows them all. Probably not even [Linus Torvalds](https://github.com/torvalds) himself :).
![mainMenuScreenshot](https://user-images.githubusercontent.com/8818630/57629726-4704f080-756a-11e9-89cc-f8bdeea3c982.png)
![mainMenuScreenshot](https://user-images.githubusercontent.com/8818630/58364013-61e53800-7e7b-11e9-87f9-790d6744fbd5.png)
## Table of Contents
@ -35,9 +35,9 @@
## Screenshots
![commitsByWeekdayScreenshot](https://user-images.githubusercontent.com/8818630/57629719-42d8d300-756a-11e9-8031-8132e14aa10f.png)
![commitsByWeekdayScreenshot](https://user-images.githubusercontent.com/8818630/58364011-61e53800-7e7b-11e9-9417-16cbb241ac2e.png)
![commitsByHourScreenshot](https://user-images.githubusercontent.com/8818630/57629717-40767900-756a-11e9-97d4-301ffe7535c7.png)
![commitsByHourScreenshot](https://user-images.githubusercontent.com/8818630/58364010-61e53800-7e7b-11e9-8711-a40b50aebf52.png)
## Usage
@ -83,6 +83,8 @@ Possible arguments in short and long form:
see changelogs
-L, --changelogs-by-author
see changelogs by author
-j, --json-output
save git log as a JSON formatted file to a specified area
-h, -?, --help
display this help text in the terminal
```
@ -122,7 +124,7 @@ You can change to the legacy color scheme by toggling the variable `_MENU_THEME`
```bash
export _MENU_THEME=legacy
```
![legacyThemeScreenshot](https://user-images.githubusercontent.com/8818630/57629724-453b2d00-756a-11e9-9ffc-6a7f53c5fc49.png)
![legacyThemeScreenshot](https://user-images.githubusercontent.com/8818630/58364012-61e53800-7e7b-11e9-910a-aaff836260eb.png)
## Installation

View file

@ -33,8 +33,8 @@ _theme="${_MENU_THEME:=default}"
# ARGS: None
# OUTS: None
################################################################################
function check_utils() {
local msg="not found. Please make sure this is installed and in PATH."
function checkUtils() {
local -r msg="not found. Please make sure this is installed and in PATH."
command -v awk >/dev/null 2>&1 || { echo >&2 "awk ${msg}"; exit 1; }
command -v basename >/dev/null 2>&1 || { echo >&2 "basename ${msg}"; exit 1; }
@ -58,7 +58,7 @@ function check_utils() {
# OUTS: None
################################################################################
function usage() {
local program=$(basename "$0")
local -r program=$(basename "$0")
echo "
NAME
@ -106,6 +106,8 @@ OPTIONS
see changelogs
-L, --changelogs-by-author
see changelogs by author
-j, --json-output
save git log as a JSON formatted file to a specified area
-h, -?, --help
display this help text in the terminal
@ -125,13 +127,13 @@ ADDITIONAL USAGE
# ARGS: None
# OUTS: $opt: Option selected by the user based on menu choice
################################################################################
function show_menu() {
local normal=$(tput sgr0)
local cyan=$(tput setaf 6)
local bold=$(tput bold)
local red=$(tput setaf 1)
local yellow=$(tput setaf 3)
local white=$(tput setaf 7)
function showMenu() {
local -r normal=$(tput sgr0)
local -r cyan=$(tput setaf 6)
local -r bold=$(tput bold)
local -r red=$(tput setaf 1)
local -r yellow=$(tput setaf 3)
local -r white=$(tput setaf 7)
local titles=""
local text=""
local nums=""
@ -140,37 +142,38 @@ function show_menu() {
# Adjustable color menu option
if [[ "${_theme}" == "legacy" ]]; then
titles="${bold}${red}"
text="${normal}${cyan}"
nums="${bold}${yellow}"
help_txt="${normal}${yellow}"
exit_txt="${bold}${red}"
titles="${bold}${red}" && readonly titles
text="${normal}${cyan}" && readonly text
nums="${bold}${yellow}" && readonly nums
help_txt="${normal}${yellow}" && readonly help_txt
exit_txt="${bold}${red}" && readonly exit_txt
else
titles="${bold}${cyan}"
text="${normal}${white}"
nums="${normal}${bold}${white}"
help_txt="${normal}${cyan}"
exit_txt="${bold}${cyan}"
titles="${bold}${cyan}" && readonly titles
text="${normal}${white}" && readonly text
nums="${normal}${bold}${white}" && readonly nums
help_txt="${normal}${cyan}" && readonly help_txt
exit_txt="${bold}${cyan}" && readonly exit_txt
fi
echo -e "\n${titles} Generate:${normal}"
echo -e "${nums} 1)${text} Contribution stats (by author)"
echo -e "${nums} 2)${text} Contribution stats (by author) on a specific branch"
echo -e "${nums} 3)${text} Git changelogs (last $_limit days)"
echo -e "${nums} 4)${text} Git changelogs by author"
echo -e "${nums} 5)${text} My daily status"
echo -e "${nums} 6)${text} Save git log output in JSON format"
echo -e "\n${titles} List:"
echo -e "${nums} 6)${text} Branch tree view (last $_limit)"
echo -e "${nums} 7)${text} All branches (sorted by most recent commit)"
echo -e "${nums} 8)${text} All contributors (sorted by name)"
echo -e "${nums} 9)${text} Git commits per author"
echo -e "${nums} 10)${text} Git commits per date"
echo -e "${nums} 11)${text} Git commits per month"
echo -e "${nums} 12)${text} Git commits per weekday"
echo -e "${nums} 13)${text} Git commits per hour"
echo -e "${nums} 14)${text} Git commits by author per hour"
echo -e "${nums} 7)${text} Branch tree view (last $_limit)"
echo -e "${nums} 8)${text} All branches (sorted by most recent commit)"
echo -e "${nums} 9)${text} All contributors (sorted by name)"
echo -e "${nums} 10)${text} Git commits per author"
echo -e "${nums} 11)${text} Git commits per date"
echo -e "${nums} 12)${text} Git commits per month"
echo -e "${nums} 13)${text} Git commits per weekday"
echo -e "${nums} 14)${text} Git commits per hour"
echo -e "${nums} 15)${text} Git commits by author per hour"
echo -e "\n${titles} Suggest:"
echo -e "${nums} 15)${text} Code reviewers (based on git history)"
echo -e "${nums} 16)${text} Code reviewers (based on git history)"
echo -e "\n${help_txt}Please enter a menu option or ${exit_txt}press Enter to exit."
echo -n "${text}> ${normal}"
read -r opt
@ -181,10 +184,10 @@ function show_menu() {
# ARGS: $* (required): String to print (usually provided by other functions)
# OUTS: None
################################################################################
function option_picked() {
local bold=$(tput bold)
local red=$(tput setaf 1)
local reset=$(tput sgr0)
function optionPicked() {
local -r bold=$(tput bold)
local -r red=$(tput setaf 1)
local -r reset=$(tput sgr0)
local msg=${*:-"${reset}Error: No message passed"}
echo -e "${bold}${red}${msg}${reset}\n"
@ -193,7 +196,8 @@ function option_picked() {
################################################################################
# DESC: Shows detailed contribution stats per author by parsing every commit in
# the repo and outputting their contribution stats
# ARGS: None
# ARGS: $branch (optional): Users can specify an alternative branch instead of
# the current default one
# OUTS: None
################################################################################
function detailedGitStats() {
@ -214,12 +218,12 @@ function detailedGitStats() {
fi
# Prompt message
if [[ $is_branch_existing && -n "${_branch}" ]]; then
option_picked "Contribution stats (by author) on ${_branch} branch:"
if [[ "${is_branch_existing}" && -n "${_branch}" ]]; then
optionPicked "Contribution stats (by author) on ${_branch} branch:"
elif [[ -n "${branch}" && -z "${_branch}" ]]; then
option_picked "Branch \"${branch}\" does not exist.\nContribution stats (by author) on the current branch:"
optionPicked "Branch ${branch} does not exist.\nContribution stats (by author) on the current branch:"
else
option_picked "Contribution stats (by author) on the current branch:"
optionPicked "Contribution stats (by author) on the current branch:"
fi
git -c log.showSignature=false log ${_branch} --use-mailmap --no-merges --numstat \
@ -296,7 +300,7 @@ function detailedGitStats() {
# OUTS: None
################################################################################
function suggestReviewers() {
option_picked "Suggested code reviewers (based on git history):"
optionPicked "Suggested code reviewers (based on git history):"
git -c log.showSignature=false log --use-mailmap --no-merges $_since $_until \
--pretty=%aN $_pathspec | head -n 100 | sort | uniq -c | sort -nr | LC_ALL=C awk '
{ args[NR] = $0; }
@ -307,13 +311,28 @@ function suggestReviewers() {
}' | column -t -s,
}
################################################################################
# DESC: Saves the git log output in a JSON format
# ARGS: $json_path (required): Path to where the file is saved
# OUTS: A JSON formatted file
################################################################################
function jsonOutput() {
optionPicked "Output log saved to file at: ${json_path:?}/output.json"
git -c log.showSignature=false log --use-mailmap --no-merges $_since $_until \
--pretty=format:'{%n "commit": "%H",%n "abbreviated_commit": "%h",%n "tree": "%T",%n "abbreviated_tree": "%t",%n "parent": "%P",%n "abbreviated_parent": "%p",%n "refs": "%D",%n "encoding": "%e",%n "subject": "%s",%n "sanitized_subject_line": "%f",%n "body": "%b",%n "commit_notes": "%N",%n "author": {%n "name": "%aN",%n "email": "%aE",%n "date": "%aD"%n },%n "commiter": {%n "name": "%cN",%n "email": "%cE",%n "date": "%cD"%n }%n},' \
| sed "$ s/,$//" \
| sed ':a;N;$!ba;s/\r\n\([^{]\)/\\n\1/g' \
| awk 'BEGIN { print("[") } { print($0) } END { print("]") }' \
> "${json_path:?}"/output.json
}
################################################################################
# DESC: Displays a horizontal bar graph based on total commits per month
# ARGS: None
# OUTS: None
################################################################################
function commitsByMonth() {
option_picked "Git commits by month:"
optionPicked "Git commits by month:"
echo -e "\tmonth\tsum"
for i in Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
do
@ -344,7 +363,7 @@ function commitsByMonth() {
# OUTS: None
################################################################################
function commitsByWeekday() {
option_picked "Git commits by weekday:"
optionPicked "Git commits by weekday:"
echo -e "\tday\tsum"
for i in Mon Tue Wed Thu Fri Sat Sun
do
@ -384,10 +403,10 @@ function commitsByHour() {
local _author=""
if [[ -z "${author}" ]]; then
option_picked "Git commits by hour:"
optionPicked "Git commits by hour:"
_author="--author=**"
else
option_picked "Git commits by hour for author '${author}':"
optionPicked "Git commits by hour for author '${author}':"
_author="--author=${author}"
fi
echo -e "\thour\tsum"
@ -421,7 +440,7 @@ function commitsByHour() {
# OUTS: None
################################################################################
function commitsPerDay() {
option_picked "Git commits per date:";
optionPicked "Git commits per date:";
git -c log.showSignature=false log --use-mailmap --no-merges $_since $_until \
--date=short --format='%ad' $_pathspec | sort | uniq -c
}
@ -433,7 +452,7 @@ function commitsPerDay() {
# OUTS: None
################################################################################
function commitsPerAuthor() {
option_picked "Git commits per author:"
optionPicked "Git commits per author:"
git -c log.showSignature=false shortlog $_since $_until --no-merges -n -s \
| sort -nr | LC_ALL=C awk '
{ args[NR] = $0; sum += $0 }
@ -450,7 +469,7 @@ function commitsPerAuthor() {
# OUTS: None
################################################################################
function myDailyStats() {
option_picked "My daily status:"
optionPicked "My daily status:"
git diff --shortstat '@{0 day ago}' | sort -nr | tr ',' '\n' | LC_ALL=C awk '
{ args[NR] = $0; }
END {
@ -472,7 +491,7 @@ function myDailyStats() {
# OUTS: None
################################################################################
function contributors() {
option_picked "All contributors (sorted by name):"
optionPicked "All contributors (sorted by name):"
git -c log.showSignature=false log --use-mailmap --no-merges $_since $_until \
--format='%aN' $_pathspec | sort -u | cat -n
}
@ -483,7 +502,7 @@ function contributors() {
# OUTS: None
################################################################################
function branchTree() {
option_picked "Branching tree view:"
optionPicked "Branching tree view:"
git -c log.showSignature=false log --use-mailmap --graph --abbrev-commit \
$_since $_until --decorate \
--format=format:'--+ Commit: %h %n | Date: %aD (%ar) %n'' | Message: %s %d %n'' + Author: %aN %n' \
@ -496,7 +515,7 @@ function branchTree() {
# OUTS: None
################################################################################
function branchesByDate() {
option_picked "All branches (sorted by most recent commit):"
optionPicked "All branches (sorted by most recent commit):"
git for-each-ref --sort=committerdate refs/heads/ \
--format='[%(authordate:relative)] %(authorname) %(refname:short)' | cat -n
}
@ -509,36 +528,37 @@ function branchesByDate() {
function changelogs() {
local author="${1:-}"
local _author=""
local next=$(date +%F)
if [[ -z "${author}" ]]; then
option_picked "Git changelogs:"
optionPicked "Git changelogs:"
_author="--author=**"
else
option_picked "Git changelogs for author '${author}':"
optionPicked "Git changelogs for author '${author}':"
_author="--author=${author}"
fi
NEXT=$(date +%F)
git -c log.showSignature=false log \
--use-mailmap \
--no-merges \
--format="%cd" \
--date=short "${_author}" $_since $_until $_pathspec \
| sort -u -r | head -n $_limit | while read DATE; do
echo -e "\n[$DATE]"
GIT_PAGER=cat git -c log.showSignature=false log \
--use-mailmap --no-merges \
--format=" * %s (%aN)" "${_author}" \
--since=$DATE --until=$NEXT
NEXT=$DATE
done
| sort -u -r | head -n $_limit \
| while read DATE; do
echo -e "\n[$DATE]"
GIT_PAGER=cat git -c log.showSignature=false log \
--use-mailmap --no-merges \
--format=" * %s (%aN)" "${_author}" \
--since=$DATE --until=$next
next=$DATE
done
}
################################################################################
# MAIN
# Check to make sure all utilities required for this script are installed
check_utils
checkUtils
# Check if we are currently in a git repo.
git rev-parse --is-inside-work-tree > /dev/null
@ -576,6 +596,16 @@ if [[ "$#" -eq 1 ]]; then
done
commitsByHour "${author}";;
-m|--commits-by-month) commitsByMonth;;
-j|--json-output)
json_path=""
while [[ -z "${json_path}" ]]; do
read -r -p "Path to save JSON file: " json_path
if [[ ! -w "${json_path}" ]]; then
echo "Invalid path or permission denied to write to given area."
json_path=""
fi
done
jsonOutput "${json_path}";;
-h|-\?|--help) usage;;
*) echo "Invalid argument"; usage; exit 1;;
esac
@ -585,39 +615,48 @@ fi
# Parse interactive commands
clear
show_menu
showMenu
while [[ "${opt}" != "" ]]; do
clear
case "${opt}" in
1) detailedGitStats; show_menu;;
1) detailedGitStats; showMenu;;
2) branch=""
while [[ -z "${branch}" ]]; do
read -r -p "Which branch? " branch
done
detailedGitStats "${branch}"; show_menu;;
3) changelogs; show_menu;;
detailedGitStats "${branch}"; showMenu;;
3) changelogs; showMenu;;
4) author=""
while [[ -z "${author}" ]]; do
read -r -p "Which author? " author
done
changelogs "${author}"; show_menu;;
5) myDailyStats; show_menu;;
6) branchTree; show_menu;;
7) branchesByDate; show_menu;;
8) contributors; show_menu;;
9) commitsPerAuthor; show_menu;;
10) commitsPerDay; show_menu;;
11) commitsByMonth; show_menu;;
12) commitsByWeekday; show_menu;;
13) commitsByHour; show_menu;;
14) author=""
changelogs "${author}"; showMenu;;
5) myDailyStats; showMenu;;
6) json_path=""
while [[ -z "${json_path}" ]]; do
read -r -p "Path to save JSON file: " json_path
if [[ ! -w "${json_path}" ]]; then
echo "Invalid path or permission denied to write to given area."
json_path=""
fi
done
jsonOutput "${json_path}"; showMenu;;
7) branchTree; showMenu;;
8) branchesByDate; showMenu;;
9) contributors; showMenu;;
10) commitsPerAuthor; showMenu;;
11) commitsPerDay; showMenu;;
12) commitsByMonth; showMenu;;
13) commitsByWeekday; showMenu;;
14) commitsByHour; showMenu;;
15) author=""
while [[ -z "${author}" ]]; do
read -r -p "Which author? " author
done
commitsByHour "${author}"; show_menu;;
15) suggestReviewers; show_menu;;
commitsByHour "${author}"; showMenu;;
16) suggestReviewers; showMenu;;
q|"\n") exit;;
*) clear; option_picked "Pick an option from the menu"; show_menu;;
*) clear; optionPicked "Pick an option from the menu"; showMenu;;
esac
done

View file

@ -94,6 +94,11 @@ see changelogs
see changelogs by author
.HP
.PP
\fB\-j\fR, \fB\-\-json\-output\fR
.IP
save git log as a JSON formatted file to a specified area
.HP
.PP
\fB\-h\fR, \-?, \fB\-\-help\fR
.IP
display this help text in the terminal

View file

@ -3,8 +3,7 @@
. tests/assert.sh -v
src="./git-quick-stats"
#assert "$src fail" "Invalid argument\n\nNAME\n git-quick-stats - Simple and efficient way to access various stats in a git repo\n\nSYNOPSIS\n For non-interactive mode: git-quick-stats [OPTIONS]\n For interactive mode: git-quick-stats\n\nDESCRIPTION\n Any git repository contains tons of information about commits, contributors,\n and files. Extracting this information is not always trivial, mostly because\n of a gadzillion options to a gadzillion git commands.\n\n This program allows you to see detailed information about a git repository.\n\nOPTIONS\n suggestReviewers - see best people to contact to review code\n detailedGitStats - displays a detailed list of git status\n commitsPerDay - displays a list of commits per day\n commitsByMonth - displays a list of commits per month\n commitsByWeekday - displays a list of commits per weekday\n commitsByHour - displays a list of commits per hour\n commitsByAuthorByHour - see a list of commits per hour by author\n commitsPerAuthor - displays a list of commits per author\n myDailyStats - see your current daily stats\n contributors - see a list of all contributors\n branchTree - see an ASCII graph of the git repo\n branchesByDate - show branches by date\n changelogs - see changelogs\n changelogsByAuthor - see changelogs by author\n\nADDITIONAL USAGE\n You can set _GIT_SINCE and _GIT_UNTIL to limit the git time log\n ex: export _GIT_SINCE=2017-01-20\n You can set _GIT_LIMIT for limited output log\n ex: export _GIT_LIMIT=20\n You can exclude a directory from the stats by using pathspec\n ex: export _GIT_PATHSPEC=':!directory'\n \nCONTRIBUTION\n For details regarding contribution, please see the contribution.md document\n\nLICENSE\n This is under the MIT license. See LICENSE in the repo for more info"
assert "$src fail" "Invalid argument\n\nNAME\n git-quick-stats - Simple and efficient way to access various stats in a git repo\n\nSYNOPSIS\n For non-interactive mode: git-quick-stats [OPTIONS]\n For interactive mode: git-quick-stats\n\nDESCRIPTION\n Any git repository contains tons of information about commits, contributors,\n and files. Extracting this information is not always trivial, mostly because\n of a gadzillion options to a gadzillion git commands.\n\n This program allows you to see detailed information about a git repository.\n\nOPTIONS\n -r, --suggest-reviewers\n show the best people to contact to review code\n -T, --detailed-git-stats\n give a detailed list of git stats\n -R, --git-stats-by-branch\n see detailed list of git stats by branch\n -d, --commits-per-day\n displays a list of commits per day\n -m, --commits-by-month\n displays a list of commits per month\n -w, --commits-by-weekday\n displays a list of commits per weekday\n -o, --commits-by-hour\n displays a list of commits per hour\n -A, --commits-by-author-by-hour\n displays a list of commits per hour by author\n -a, --commits-per-author\n displays a list of commits per author\n -S, --my-daily-stats\n see your current daily stats\n -C, --contributors\n see a list of everyone who contributed to the repo\n -b, --branch-tree\n show an ASCII graph of the git repo branch history\n -D, --branches-by-date\n show branches by date\n -c, --changelogs\n see changelogs\n -L, --changelogs-by-author\n see changelogs by author\n -h, -?, --help\n display this help text in the terminal\n\nADDITIONAL USAGE\n You can set _GIT_SINCE and _GIT_UNTIL to limit the git time log\n ex: export _GIT_SINCE=\"2017-01-20\"\n You can set _GIT_LIMIT for limited output log\n ex: export _GIT_LIMIT=20\n You can exclude a directory from the stats by using pathspec\n ex: export _GIT_PATHSPEC=':!directory'\n You can set _MENU_THEME to display the legacy color scheme\n ex: export _MENU_THEME=legacy"
assert "$src fail" "Invalid argument\n\nNAME\n git-quick-stats - Simple and efficient way to access various stats in a git repo\n\nSYNOPSIS\n For non-interactive mode: git-quick-stats [OPTIONS]\n For interactive mode: git-quick-stats\n\nDESCRIPTION\n Any git repository contains tons of information about commits, contributors,\n and files. Extracting this information is not always trivial, mostly because\n of a gadzillion options to a gadzillion git commands.\n\n This program allows you to see detailed information about a git repository.\n\nOPTIONS\n -r, --suggest-reviewers\n show the best people to contact to review code\n -T, --detailed-git-stats\n give a detailed list of git stats\n -R, --git-stats-by-branch\n see detailed list of git stats by branch\n -d, --commits-per-day\n displays a list of commits per day\n -m, --commits-by-month\n displays a list of commits per month\n -w, --commits-by-weekday\n displays a list of commits per weekday\n -o, --commits-by-hour\n displays a list of commits per hour\n -A, --commits-by-author-by-hour\n displays a list of commits per hour by author\n -a, --commits-per-author\n displays a list of commits per author\n -S, --my-daily-stats\n see your current daily stats\n -C, --contributors\n see a list of everyone who contributed to the repo\n -b, --branch-tree\n show an ASCII graph of the git repo branch history\n -D, --branches-by-date\n show branches by date\n -c, --changelogs\n see changelogs\n -L, --changelogs-by-author\n see changelogs by author\n -j, --json-output\n save git log as a JSON formatted file to a specified area\n -h, -?, --help\n display this help text in the terminal\n\nADDITIONAL USAGE\n You can set _GIT_SINCE and _GIT_UNTIL to limit the git time log\n ex: export _GIT_SINCE=\"2017-01-20\"\n You can set _GIT_LIMIT for limited output log\n ex: export _GIT_LIMIT=20\n You can exclude a directory from the stats by using pathspec\n ex: export _GIT_PATHSPEC=':!directory'\n You can set _MENU_THEME to display the legacy color scheme\n ex: export _MENU_THEME=legacy"
assert_raises "$src fail" 1
assert_contains "$src --suggest-reviewers" "Suggested code reviewers (based on git history)" 127