git calendar

This is a script I wrote to render GitHub/GitLab like contributions calendar for local repositories, it should render something like this

file: git_calendar.sh

1#!/bin/bash
2
3PROJECTS_DIR="$( dirname $PWD )"
4AUTHOR_EMAIL="$( git config --get --global user.email )"
5OUTPUT_FILE="$( realpath static/images/git_calendar.svg )"
6
7TEMP_FILE="$( mktemp )"
8
9for REPO in $( find "${PROJECTS_DIR}" \
10 -type d -name '.git' -printf '%h\n' )
11do
12 cd "${REPO}"
13 git log --all --format=tformat:%as --author="${AUTHOR_EMAIL}" \
14 >> "${TEMP_FILE}"
15done
16
17cd "${PROJECTS_DIR}"
18
19cat << SVG_BEGIN_BLOCK > "${OUTPUT_FILE}"
20<svg width="840" height="168" version="1.1" viewBox="0 0 840 168" xmlns="http://www.w3.org/2000/svg">
21<style>
22 .dt { font: 12px monospace }
23 .sq { width: 12px; height: 12px; rx: 2px; ry: 2px; }
24 .f0 { fill: rgb(245,245,255); }
25 .f1 { fill: rgb(205,205,255); }
26 .f2 { fill: rgb(155,155,255); }
27 .f3 { fill: rgb(105,105,255); }
28 .f4 { fill: rgb(55,55,255); }
29 .f5 { fill: rgb(5,5,255); }
30</style>
31<text x="20" y="60" class="dt">Sun</text>
32<text x="20" y="88" class="dt">Tue</text>
33<text x="20" y="116" class="dt">Thu</text>
34SVG_BEGIN_BLOCK
35
36TODAY="$( date +'%w:%a, %d %B %Y' )"
37LASTYEAR="$( date -d 'last year' +'%w:%a, %d %B %Y' )"
38TOMORROW="$( date -d 'tomorrow' +'%w:%a, %d %B %Y' )"
39
40DATE_POINTER="${LASTYEAR}"
41MONTH_TAG=""
42COLUMN=0
43while [ "${DATE_POINTER}" != "${TOMORROW}" ]; do
44 ROW=$(( ( ${DATE_POINTER%:*} + 1 ) % 7 ))
45 MONTH="$( date -d "${DATE_POINTER#*:}" +'%b' )"
46 if [ $ROW -eq 0 ] && [ "${MONTH_TAG}" != "${MONTH}" ]; then
47 MONTH_TAG="${MONTH}"
48 printf '<text x="%s" y="32" class="dt">%s</text>' \
49 "$(( ( COLUMN * 14 ) + 48 ))" \
50 "${MONTH_TAG}" >> "${OUTPUT_FILE}"
51 fi
52 printf '<rect class="sq %s" x="%s" y="%s"><title>%s commits on %s</title></rect>\n' \
53 "f0" \
54 "$(( ( COLUMN * 14 ) + 48 ))" \
55 "$(( ( ROW * 14 ) + 36 ))" \
56 "No" \
57 "${DATE_POINTER#*:}" >> "${OUTPUT_FILE}"
58 [ $ROW -eq 6 ] && (( COLUMN++ ))
59 DATE_POINTER="$( date -d "${DATE_POINTER#*:} + 1 day" +'%w:%a, %d %B %Y' )"
60done
61
62sort "${TEMP_FILE}" | uniq -c | while read COMMITS DATE; do
63LEVEL=$(( ( COMMITS / 5 ) + 1 ))
64[ ${LEVEL} -gt 5 ] && LEVEL=5
65LEVEL="f${LEVEL}"
66DATE_STR="$( date -d "${DATE}" +'%a, %d %B %Y' )"
67sed -i -E "s/(^.*)(f0)(.*)(No)(.*)(${DATE_STR})(.*$)/\1${LEVEL}\3${COMMITS}\5\6\7/" "${OUTPUT_FILE}"
68done
69
70cat << SVG_END_BLOCK >> "${OUTPUT_FILE}"
71<text x="20" y="150" class="dt">Generated ${TODAY#*:}</text>
72<text x="480" y="150" class="dt">Hover on the boxes for details</text>
73<rect class="sq f0" x="720" y="140"><title>No commits</title></rect>
74<rect class="sq f1" x="734" y="140"><title>1 to 5 commits</title></rect>
75<rect class="sq f2" x="748" y="140"><title>6 to 10 commits</title></rect>
76<rect class="sq f3" x="762" y="140"><title>11 to 15 commits</title></rect>
77<rect class="sq f4" x="776" y="140"><title>15 to 20 commits</title></rect>
78<rect class="sq f5" x="790" y="140"><title>21+ commits</title></rect>
79</svg>
80SVG_END_BLOCK
81
82rm "${TEMP_FILE}"
83