Compare commits

..

25 Commits
2.4.0 ... 2.5.5

Author SHA1 Message Date
Tom Ice
00d13c0b79 Merge pull request #164 from tomice/master
Handle error where BSD date is being used
Create new repo if running tests in non-git area
2024-04-27 13:43:51 -04:00
Tom Ice
b525ed3b5c Create new repo if running tests in non-git area
* When running "make test" in the root directory of this codebase,
  an error will occur as this shell script requires a repo to be
  initialized before it can properly execute.

  This was done in the past, but at some point, it was removed.
  This adds the feature back, tests if we are in a git directory
  by using a built-in git command, and only performs this action
  if a git repo doesn't already exist. All actions are sent to
  /dev/null so the testing should look opaque to the end user.

  Note that tests will still fail if a user is missing a required
  utility to perform the functionality of git-quick-stats.

* Fixed a typo in the man page

Fixes #162
2024-04-20 17:31:12 -04:00
Tom Ice
41a8542aaa Handle error where BSD date is being used
* Users on macOS and other older distributions of Linux and Unix
  cannot fully utilize this application as a handful of date/time
  strings in here are specific to the GNU utility found on most
  modern version of Linux.

  Until every date/time case is handled between the BSD version of
  date and the GNU version of date, let's error out akin to how we
  do it if the user doesn't have every utility installed to run
  this script.

  Users can get around this by using package managers on macOS such
  as homebrew, macports, etc and making sure that 'date' points to
  the GNU version of date instead of the BSD version. Linux and
  Unix users can get around this by installing the GNU version of
  date, as well.

* Removed checking OSTYPE in the format_date() function as checking
  if someone is on a machine that identifies as Darwin is not enough
  to handle other edge cases where an older version of BSD date
  might be present on the system.
2024-04-20 14:15:07 -04:00
arzzen
7b1e0b2a65 Merge pull request #157 from Dica-Developer/41
calculate the day before the given since date
2024-01-10 08:13:40 +01:00
Martin Schaaf
43bc82520e calculate the day before the given since date as it excludes the given daten the inclusion is wanted 2024-01-09 16:40:28 +01:00
arzzen
d33ede9bcc Merge pull request #142 from cam-rod/timezone-format
Update formatting and sort commits by timezone
2023-12-22 16:18:52 +01:00
arzzen
7f24d202b9 Merge pull request #155 from fox-forks/hyperupcall-document-defualt-git-limit
docs: Document default `_GIT_LIMIT` value
2023-12-22 16:17:22 +01:00
Edwin Kofler
62b128a3ce docs: Document default _GIT_LIMIT value 2023-11-18 17:44:29 -08:00
arzzen
8515fe3a94 cleanup 2023-10-24 18:13:00 +02:00
arzzen
37bfde67ed Merge pull request #153 from arzzen/arzzen-patch-1 2023-10-24 15:33:53 +02:00
arzzen
d886facadf fix format date 2023-10-24 14:52:00 +02:00
arzzen
aa6619508a Update git-quick-stats
fix #152
2023-10-24 09:34:29 +02:00
arzzen
a813846c9f Merge pull request #151 from YDX-2147483647/patch-1
fix: Ubuntu does not support `date -j`
2023-10-17 06:26:33 +02:00
Y.D.X
22bf354da4 fix: Ubuntu does not support date -j
This is required for changelogs.

Resolves #147
2023-10-09 17:29:08 +08:00
arzzen
0fea0323a4 Merge pull request #150 from riderius/master 2023-10-04 20:50:24 +02:00
riderius
4fcf8f5fef test: fix a typo in the 1st test
Signed-off-by: riderius <riderius.help@gmail.com>
2023-10-04 18:27:38 +03:00
arzzen
374aa2ef72 Merge pull request #145 from s-okita/master
Add stats by author per weekday functionality
2023-06-23 15:01:04 +02:00
s-okita
33dca7f3ed Update git-quick-stats.1 2023-06-23 17:07:18 +09:00
s-okita
2ecb296442 Merge branch 'arzzen:master' into master 2023-06-07 02:42:22 +09:00
arzzen
428d25d0ef Merge pull request #144 from jgtoriginal/master
add day name to date
2023-06-06 14:58:29 +02:00
s-okita
c3110e985e Add stats by author per weekday functionality
* Added the ability to see git stats both per weekday, as well as
  by author per weekday. It should respect all global options.

* Updated tests, README.md, and man page to reflect the new changes
2023-06-06 19:36:47 +09:00
jgtoriginal
ebbeb34837 add day name to date
when grouping by author -L, I found it hard to read YYYY-MM-DD, so added day name to that.
2023-05-25 01:14:05 +01:00
Cameron Rodriguez
6cdca7c7c7 Sort, use more stable formatting for commits by timezone
Switch to `git log` for formatting commits sorted by timezone, to avoid
odd formatting cases. Also sorts timezones from negative to positive.
2023-04-04 22:30:35 -04:00
Tom Ice
71d414eb4a Merge pull request #137 from pyxide/fix/json-format-output
fix: json format output with multiline content
2022-07-11 16:09:01 -04:00
pyxide
d8346210a4 fix: json format output with multiline content 2022-07-11 19:15:07 +02:00
6 changed files with 190 additions and 27 deletions

5
.gitignore vendored
View File

@@ -7,4 +7,7 @@
.Spotlight*
.Trash*
**/*~
nbproject/*
nbproject/*
/tests/test-git/.git/
#/tests/test-git/*
!/tests/test-git/resetgit

View File

@@ -1,5 +1,6 @@
# GIT quick statistics [![Backers on Open Collective](https://opencollective.com/git-quick-stats/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/git-quick-stats/sponsors/badge.svg)](#sponsors) [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Simple%20and%20efficient%20way%20to%20access%20various%20statistics%20in%20git%20repository&url=https://github.com/arzzen/git-quick-stat&via=arzzen&hashtags=git,stats,tool,statistics,developers) [![Travis](https://api.travis-ci.org/arzzen/git-quick-stats.svg?branch=master)](https://travis-ci.org/arzzen/git-quick-stats) [![Homebrew package](https://repology.org/badge/version-for-repo/homebrew/git-quick-stats.svg)](https://formulae.brew.sh/formula/git-quick-stats#default) [![Linuxbrew package](https://repology.org/badge/version-for-repo/linuxbrew/git-quick-stats.svg)](https://repology.org/metapackage/git-quick-stats/packages)
# GIT quick statistics [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Simple%20and%20efficient%20way%20to%20access%20various%20statistics%20in%20git%20repository&url=https://github.com/arzzen/git-quick-stat&via=arzzen&hashtags=git,stats,tool,statistics,developers)
[![Backers on Open Collective](https://opencollective.com/git-quick-stats/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/git-quick-stats/sponsors/badge.svg)](#sponsors) [![Homebrew package](https://repology.org/badge/version-for-repo/homebrew/git-quick-stats.svg)](https://formulae.brew.sh/formula/git-quick-stats#default)
> `git-quick-stats` is a simple and efficient way to access various statistics in a git repository.
>
@@ -126,6 +127,8 @@ LIST OPTIONS
displays a list of commits per month
-w, --commits-by-weekday
displays a list of commits per weekday
-W, --commits-by-author-by-weekday
displays a list of commits per weekday by author
-o, --commits-by-hour
displays a list of commits per hour
-A, --commits-by-author-by-hour
@@ -155,7 +158,7 @@ Once set, run `git quick-stats` as normal. Note that this affects all stats that
### Git log limit
You can set variable `_GIT_LIMIT` for limited output. It will affect the "changelogs" and "branch tree" options.
You can set variable `_GIT_LIMIT` for limited output. It will affect the "changelogs" and "branch tree" options. The default limit is `10`.
```bash
export _GIT_LIMIT=20
@@ -370,6 +373,3 @@ Support this project by becoming a sponsor. Your logo will show up here with a l
[![sponsor7](https://opencollective.com/git-quick-stats/sponsor/7/avatar.svg)](https://opencollective.com/git-quick-stats/sponsor/7/website)
[![sponsor8](https://opencollective.com/git-quick-stats/sponsor/8/avatar.svg)](https://opencollective.com/git-quick-stats/sponsor/8/website)
[![sponsor9](https://opencollective.com/git-quick-stats/sponsor/9/avatar.svg)](https://opencollective.com/git-quick-stats/sponsor/9/website)
[![61999966](https://user-images.githubusercontent.com/6382002/130024560-65bb49a6-c7e9-48f9-8427-a29d8ff2a3db.png)](https://quaestor.com/?utm_source=github&utm_category=sponsor)

View File

@@ -89,6 +89,21 @@ function checkUtils() {
do
command -v "$u" >/dev/null 2>&1 || { echo >&2 "$u ${MSG}"; exit 1; }
done
# NOTE: The --version flag is only available in GNU date which is required
# for how the current date/time strings are used in this shell script.
# To fully support the legacy BSD date found in a default install within
# macOS and older distributions of Linux and Unix, a handful of helper
# functions can probably be created to handle every case of incompatibility
# between the two. Until that's implemented, it is probably best to warn
# the user that this will not work rather than having it silently bomb out
# during runtime.
if ! date --version >/dev/null 2>&1; then
echo "ERROR: You must have GNU date installed."
echo "If you're on macOS, please use brew to install this utility."
echo "Make sure the GNU version of date is symlinked to 'date', too."
exit 1
fi
}
################################################################################
@@ -102,6 +117,24 @@ function optionPicked() {
echo -e "${msg}\n"
}
################################################################################
# DESC: Format date string
# ARGS: $* (required): String
# OUTS: String
################################################################################
function format_date() {
# NOTE: While this works where it's implemented within the changelogs()
# function the first time, it then bombs out when it reaches the -d flag
# in the second half of that same code as BSD date cannot handle -d, nor
# can it handle a string such as DATE - 1 day.
local date="${1}"
local outf="${2}"
local datef="${3:-"%b %d %H:%M:%S %Y %Z"}" # Tue Oct 24 13:34:22 2023 +0300
local resp="$(date -d "${date}" "+${outf}")"
printf "%s" "${resp}"
}
################################################################################
# DESC: Help information printed to stdout during non-interactive mode
# ARGS: None
@@ -158,6 +191,8 @@ LIST OPTIONS
displays a list of commits per year
-w, --commits-by-weekday
displays a list of commits per weekday
-W, --commits-by-author-by-weekday
displays a list of commits per weekday by author
-o, --commits-by-hour
displays a list of commits per hour
-A, --commits-by-author-by-hour
@@ -243,12 +278,13 @@ function showMenu() {
printf %b "${NUMS} 13)${TEXT} Git commits per month\\n"
printf %b "${NUMS} 14)${TEXT} Git commits per year\\n"
printf %b "${NUMS} 15)${TEXT} Git commits per weekday\\n"
printf %b "${NUMS} 16)${TEXT} Git commits per hour\\n"
printf %b "${NUMS} 17)${TEXT} Git commits per hour by author\\n"
printf %b "${NUMS} 18)${TEXT} Git commits per timezone\\n"
printf %b "${NUMS} 19)${TEXT} Git commits per timezone by author\\n"
printf %b "${NUMS} 16)${TEXT} Git commits per weekday by author\\n"
printf %b "${NUMS} 17)${TEXT} Git commits per hour\\n"
printf %b "${NUMS} 18)${TEXT} Git commits per hour by author\\n"
printf %b "${NUMS} 19)${TEXT} Git commits per timezone\\n"
printf %b "${NUMS} 20)${TEXT} Git commits per timezone by author\\n"
printf %b "\\n${TITLES} Suggest:\\n"
printf %b "${NUMS} 20)${TEXT} Code reviewers (based on git history)\\n"
printf %b "${NUMS} 21)${TEXT} Code reviewers (based on git history)\\n"
printf %b "\\n${HELP_TXT}Please enter a menu option or ${EXIT_TXT}press Enter to exit.\\n"
printf %b "${TEXT}> ${NORMAL}"
read -r opt
@@ -391,11 +427,12 @@ function changelogs() {
--date=short "${_author}" "$_since" "$_until" $_log_options $_pathspec \
| sort -u -r | head -n $_limit \
| while read DATE; do
echo -e "\n[$DATE]"
day=$(format_date "$DATE" "%A" "%Y-%m-%d")
echo -e "\n[$DATE - $day]"
GIT_PAGER=cat git -c log.showSignature=false log \
--use-mailmap $_merges \
--format=" * %s (%aN)" "${_author}" \
--since=$DATE --until=$next
--since==$(date -d "$DATE - 1 day" +"%Y-%m-%d") --until=$next
next=$DATE
done
}
@@ -519,6 +556,67 @@ function csvOutput() {
}'
}
################################################################################
# DESC: Transforms special multiline string sequence to a JSON string property.
# {propTag}{optional white space indentation}{property}
# {line1}
# {line2}
# ...
# {propTag}, (the final comma is optional)
# Generates: "{property}": "{line1}\n{line2}\n...",
# The final comma is added if present after the ending tag.
# Caveat: the content should not contain {propTag} at the
# beginning of a line.
# ARGS: $propTag (optional) : tag at the beginning of the line to mark the
# beginning and the end of a special sequence. It must not contain
# regular expression special characters, i.e. use [a-zA-Z0-9_]+.
# This tag should be sufficiently random to avoid collision with
# the actual content. Defaults to __JSONPROP__.
# OUTS: content with JSON string properties
################################################################################
function toJsonProp() {
local propTag="${1:-__JSONPROP__}"
sed -n -E '
# transforms the special sequence.
/^'"$propTag"'[^\r]/ {
# remove the special prefix, keep the property name followed by :
s/^'"$propTag"'([^\r]+)\r?$/\1:/g;
# hold in buffer, get the next line.
h;n
# loop
b eos
:eos {
# add in hold buffer and loop while the string is not finished.
/^'"$propTag"',?\r?$/ ! { H; n; b eos; }
# end of the string, flip buffer to current pattern.
# keeps the comma if any, or a space as an empty placeholder.
/,\r?$/ ! { x; s/\r?$/ / }
/,\r?$/ { x; s/\r?$/,/ }
}
# replace special JSON string chars.
s/["\\]/\\&/g;
# replace control chars, carriage returns, line feeds, tabulations, etc.
s/\x00/\\u0000/g; s/\x01/\\u0001/g; s/\x02/\\u0002/g; s/\x03/\\u0003/g;
s/\x04/\\u0004/g; s/\x05/\\u0005/g; s/\x06/\\u0006/g; s/\x07/\\u0007/g;
s/\x08/\\b/g; s/\x09/\\t/g; s/\x0a/\\n/g; s/\x0b/\\u000b/g;
s/\x0c/\\f/g; s/\x0d/\\r/g; s/\x0e/\\u000e/g; s/\x0f/\\u000f/g;
s/\x10/\\u0010/g; s/\x11/\\u0011/g; s/\x12/\\u0012/g; s/\x13/\\u0013/g;
s/\x14/\\u0014/g; s/\x15/\\u0015/g; s/\x16/\\u0016/g; s/\x17/\\u0017/g;
s/\x18/\\u0018/g; s/\x19/\\u0019/g; s/\x1a/\\u001a/g; s/\x1b/\\u001b/g;
s/\x1c/\\u001c/g; s/\x1d/\\u001d/g; s/\x1e/\\u001e/g; s/\x1f/\\u001f/g;
s/\x7f/\\u007f/g;
# format the JSON property name, optionally indented, open quote for value.
s/^(\s*)([^:]+):\\n/\1"\2": "/g;
# handle the final comma if present, and close the quote for value.
/,$/ { s/,$/",/g; }
# otherwise remove final space placeholder and close the quote for value.
/,$/ ! { s/ $/"/g; }
}
# print lines.
p'
}
################################################################################
# DESC: Saves the git log output in a JSON format
# ARGS: $json_path (required): Path to where the file is saved
@@ -526,10 +624,20 @@ function csvOutput() {
################################################################################
function jsonOutput() {
optionPicked "Output log saved to file at: ${json_path}/output.json"
# TODO: Can we shorten this pretty format line? Quick experiment shows that
# it does not properly respect \ and interprets them literally.
local propTag="__JSONPROP${RANDOM}__"
git -c log.showSignature=false log --use-mailmap $_merges "$_since" "$_until" $_log_options \
--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},' \
--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'\
"$propTag"' subject%n%s%n'"$propTag"',%n "sanitized_subject_line": "%f",%n'\
"$propTag"' body%n%b%n'"$propTag"',%n'\
"$propTag"' commit_notes%n%N%n'"$propTag"',%n "author": {%n'\
"$propTag"' name%n%aN%n'"$propTag"',%n'\
"$propTag"' email%n%aE%n'"$propTag"',%n'\
' "date": "%aD"%n },%n "commiter": {%n'\
"$propTag"' name%n%cN%n'"$propTag"',%n'\
"$propTag"' email%n%cE%n'"$propTag"',%n'\
' "date": "%cD"%n }%n},' \
| toJsonProp "$propTag" \
| sed "$ s/,$//" \
| sed ':a;N;$!ba;s/\r\n\([^{]\)/\\n\1/g' \
| awk 'BEGIN { print("[") } { print($0) } END { print("]") }' \
@@ -710,14 +818,24 @@ function commitsByMonth() {
# OUTS: None
################################################################################
function commitsByWeekday() {
optionPicked "Git commits by weekday:"
local author="${1:-}"
local _author=""
if [[ -z "${author}" ]]; then
optionPicked "Git commits by weekday:"
_author="--author=**"
else
optionPicked "Git commits by weekday for author '${author}':"
_author="--author=${author}"
fi
echo -e "\tday\tsum"
local i counter=1
for i in Mon Tue Wed Thu Fri Sat Sun
do
echo -en "\t$counter\t$i\t"
git -c log.showSignature=false shortlog -n $_merges --format='%ad %s' \
"$_since" "$_until" $_log_options |
"${_author}" "$_since" "$_until" $_log_options |
grep -cE "^ * $i \w\w\w [0-9]{1,2} " || continue
counter=$((counter+1))
done | awk '{
@@ -803,9 +921,9 @@ function commitsByTimezone() {
fi
echo -e "Commits\tTimeZone"
git -c log.showSignature=false shortlog -n $_merges --format='%ad %s' \
git -c log.showSignature=false log $_merges --format='%ad %s' \
"${_author}" "$_since" "$_until" --date=iso $_log_options $_pathspec \
| cut -d " " -f 12 | grep -v -e '^[[:space:]]*$' | sort | uniq -c
| cut -d " " -f 3 | grep -v -e '^[[:space:]]*$' | sort -n | uniq -c
}
################################################################################
@@ -890,6 +1008,12 @@ if [[ "$#" -eq 1 ]]; then
-Y|--commits-by-year ) commitsByYear;;
-m|--commits-by-month) commitsByMonth;;
-w|--commits-by-weekday) commitsByWeekday;;
-W|--commits-by-author-by-weekday)
author="${_GIT_AUTHOR:-}"
while [[ -z "${author}" ]]; do
read -r -p "Which author? " author
done
commitsByWeekday "${author}";;
-o|--commits-by-hour) commitsByHour;;
-A|--commits-by-author-by-hour)
author="${_GIT_AUTHOR:-}"
@@ -898,7 +1022,7 @@ if [[ "$#" -eq 1 ]]; then
done
commitsByHour "${author}";;
-z|--commits-by-timezone) commitsByTimezone;;
-Z|--commits-by-author-by-timezone)
-Z|--commits-by-author-by-timezone)
author="${_GIT_AUTHOR:-}"
while [[ -z "${author}" ]]; do
read -r -p "Which author? " author
@@ -963,19 +1087,24 @@ while [[ "${opt}" != "" ]]; do
13) commitsByMonth; showMenu;;
14) commitsByYear; showMenu;;
15) commitsByWeekday; showMenu;;
16) commitsByHour; showMenu;;
17) author=""
16) author=""
while [[ -z "${author}" ]]; do
read -r -p "Which author? " author
done
commitsByWeekday "${author}"; showMenu;;
17) commitsByHour; showMenu;;
18) author=""
while [[ -z "${author}" ]]; do
read -r -p "Which author? " author
done
commitsByHour "${author}"; showMenu;;
18) commitsByTimezone; showMenu;;
19) author=""
19) commitsByTimezone; showMenu;;
20) author=""
while [[ -z "${author}" ]]; do
read -r -p "Which author? " author
done
commitsByTimezone "${author}"; showMenu;;
20) suggestReviewers; showMenu;;
21) suggestReviewers; showMenu;;
q|"\n") exit;;
*) clear; optionPicked "Pick an option from the menu"; showMenu;;
esac

View File

@@ -1,4 +1,4 @@
.TH git-quick-stats "1" "June 2021" "git-quick-stats" "User Commands"
.TH git-quick-stats "1" "April 2024" "git-quick-stats" "User Commands"
.SH NAME
.B git\-quick\-stats
\- Simple and efficient way to access various stats in a git repository.
@@ -95,6 +95,11 @@ displays a list of commits per year
displays a list of commits per weekday
.HP
.PP
\fB\-W\fR, \fB\-\-commits\-by\-author\-by\-weekday\fR
.IP
displays a list of commits per weekday by author
.HP
.PP
\fB\-o\fR, \fB\-\-commits\-by\-hour\fR
.IP
displays a list of commits per hour

View File

@@ -1,5 +1,13 @@
#!/bin/bash
# Verify we are in a git repo. Create one if not
# FIXME: All the paths are hardcoded currently and will break if anything
# in this chain moves or gets executed elsewhere. Adjust all of these so
# pathing does not matter as much such as creating a TOP variable that
# does something like TOP=$(cd "$(dirname "$0")" || exit ; pwd -P)
# or maybe leverages Make to handle these as test targets
./tests/test-git/resetgit
. tests/assert.sh -v
src="./git-quick-stats"
@@ -52,6 +60,8 @@ LIST OPTIONS
displays a list of commits per year
-w, --commits-by-weekday
displays a list of commits per weekday
-W, --commits-by-author-by-weekday
displays a list of commits per weekday by author
-o, --commits-by-hour
displays a list of commits per hour
-A, --commits-by-author-by-hour

16
tests/test-git/resetgit Executable file
View File

@@ -0,0 +1,16 @@
#!/bin/sh
# Initialises a new local Git repo for test purpose if one does not exist already
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
{
git init
git config user.name "$(printf %s 'Test Git,\nfor test purpose')"
git config user.email "TestGit\o/@example.org"
printf 'test-git\n========\n' > README.md
git add README.md
git commit -m 'added readme (o\w/o)' -m 'in markdown, no \r\n, only \n' -m 'a very "simple" readme'
testChars="$(printf 'tab [%b] form feed [%b] line feed [%b] carriage return [%b]' '\x09' '\x0C' '\x0A' '\x0D')"
git notes add -m 'Some notes' -m 'out of ascii: été au cœur' -m "$testChars"
git log
} >/dev/null 2>&1
fi