From 304e9626b7203df083e3fc76bdf5cb76b41e1abb Mon Sep 17 00:00:00 2001 From: mokrzesa Date: Fri, 14 May 2021 15:07:57 +0200 Subject: [PATCH 1/4] feature: improvements to generate one report "to rule them all" in pdf --- .my-work-resources/collect_lines_modified.py | 25 ++++ .my-work-resources/generate_report.py | 39 ++++++ .my-work-resources/report-template.css | 16 +++ .my-work-resources/report-template.j2 | 20 +++ README.md | 51 ++++++++ my-work.sh | 121 ++++++++++++------- 6 files changed, 229 insertions(+), 43 deletions(-) create mode 100644 .my-work-resources/collect_lines_modified.py create mode 100644 .my-work-resources/generate_report.py create mode 100644 .my-work-resources/report-template.css create mode 100644 .my-work-resources/report-template.j2 create mode 100644 README.md diff --git a/.my-work-resources/collect_lines_modified.py b/.my-work-resources/collect_lines_modified.py new file mode 100644 index 0000000..c09efa7 --- /dev/null +++ b/.my-work-resources/collect_lines_modified.py @@ -0,0 +1,25 @@ +# credits to OG: Piotr Karkut + +import subprocess +import sys +from collections import Counter + +data = Counter() +directory, date, gituser = sys.argv[1], sys.argv[2], sys.argv[3] + +log = subprocess.check_output(f'git -C ./{directory} log --all --after="{date}-01 00:00" --before="{date}-31 23:59" --author={gituser} --pretty=format:"%h"', shell=True) + +for commit in log.splitlines(): + commit = commit.decode() + try: + stats = subprocess.check_output(f'git -C ./{directory} diff %s^ %s --numstat' % (commit, commit), shell=True, stderr=open('/dev/null')) + except Exception: + stats = subprocess.check_output(f'git -C ./{directory} diff 4b825dc642cb6eb9a060e54bf8d69288fbee4904 %s --numstat' % commit, shell=True) + for stat in stats.splitlines(): + ins, dels, f = stat.split(None, 2) + try: + data[f.decode()] += (int(ins) + int(dels)) + except Exception: + pass + +print("('{0}', {1})".format(directory, list(data.items()) or [])) diff --git a/.my-work-resources/generate_report.py b/.my-work-resources/generate_report.py new file mode 100644 index 0000000..77f878c --- /dev/null +++ b/.my-work-resources/generate_report.py @@ -0,0 +1,39 @@ +import sys +import os + +from weasyprint import HTML, CSS +from ast import literal_eval +from jinja2 import Environment, FileSystemLoader + + +current_directory = os.path.dirname(os.path.abspath(__file__)) +env = Environment(loader=FileSystemLoader(current_directory)) + + +def render_template(_name_and_surname, _report_date, _report_data): + return env.get_template("report-template.j2").render( + name_and_surname=_name_and_surname, + report_date=_report_date, + report_data=_report_data, + ) + + +name_and_surname, report_date, report_data_raw = sys.argv[1], sys.argv[2], sys.argv[3] + +# HACK: from bash array to Python list :facepalm: +report_data = literal_eval("[" + report_data_raw.replace(")(", "), (") + "]") +report_data = [entry for entry in report_data if entry[1]] + +html_text = render_template( + _name_and_surname=name_and_surname, + _report_date=report_date, + _report_data=report_data, +) + +html = HTML(string=html_text) +css = CSS(f'/{current_directory}/report-template.css') + +html.write_pdf( + f'/{current_directory}/../my-work-reports/{report_date}.pdf', + stylesheets=[css], +) diff --git a/.my-work-resources/report-template.css b/.my-work-resources/report-template.css new file mode 100644 index 0000000..b508967 --- /dev/null +++ b/.my-work-resources/report-template.css @@ -0,0 +1,16 @@ +@page { + margin-bottom: 2.5cm; + @bottom-center{ + content: "Strona " counter(page) " z " counter(pages); + } + + @bottom-left { + content: "Podpis pracownika:"; + margin-bottom: 5em; + } + + @bottom-right { + content: "Podpis pracodawcy:"; + margin-bottom: 5em; + } +} diff --git a/.my-work-resources/report-template.j2 b/.my-work-resources/report-template.j2 new file mode 100644 index 0000000..822a948 --- /dev/null +++ b/.my-work-resources/report-template.j2 @@ -0,0 +1,20 @@ + + + + raport-pracy-tworczej-{{ report_date }} + + +

[{{ name_and_surname }}] Zestawienie efektów pracy twórczej stanowiących utwór za okres {{ report_date }}

+

+ {% for project in report_data %} +

{{ project[0] }}

+ +
+ {% endfor %} +

+ + diff --git a/README.md b/README.md new file mode 100644 index 0000000..fe096ef --- /dev/null +++ b/README.md @@ -0,0 +1,51 @@ +# internal-tools +### Lokalny setup + +Projekt pozwala na proste generowanie raportów potrzebnych do rozliczania godzin pracy twórczej. +Aby narzędzie działało poprawnie należy spełnić podstawowe zależności: + - Python 3 + - poprawnie uporządkowane katalogi projektowe (przykład w zakładce #WSF (Wymagana Struktura Folderów)) + +### WSF (Wymagana Struktura Folderów) +Do poprawnego działania skyptu wymagana jest następująca folderów: + +``` + /folder-glowny (tutaj powinny znjdować się wszystkie projekty które chcemy uwzględnić w raporcie) + /projekt1 + /projekt2 + ... +``` + +W `/folder-glowny` nie powinien znajdować się plik `.git` - taka sytuacja mogłaby wskazywać na złe umiejscowienie pliku skryptu. + +### I w końcu - jak tego użyć :national_park: + +Skopiuj zawartość repozytorium do katalogu głównego: + +*Upewnij się, że jesteś w folderze głównym, a repozytorium `internal-tools` również zostało umieszczone pod nim. + +```bash +$ pwd +/.../folder-glowny +$ cp -r internal-tools/. . +$ ls +projekt1 projekt2 my-work.sh ... +``` + +Opcjonalnie można też usunąć plik README.md: + +```bash +$ pwd +/.../folder-glowny +$ rm -f README.md +``` + +### Uruchomienie skryptu + +```bash +$ ./my-work.sh +``` + +### Gdzie znajdę raport :thinking: + +Raporty będę dostępne w katalogu `my-work-reports` znajdującego się w katalogu `/folder-glowny` diff --git a/my-work.sh b/my-work.sh index a13c055..be054ee 100755 --- a/my-work.sh +++ b/my-work.sh @@ -1,54 +1,89 @@ #!/bin/sh +BASE_RESOURCE_PATH=./.my-work-resources/ +PROJECT_PYTHON_ENV_NAME=my-work-venv +LINES_MODIFIED_PATH=${BASE_RESOURCE_PATH}collect_lines_modified.py +REPORT_GENERATE_PATH=${BASE_RESOURCE_PATH}generate_report.py +CONFIG_FILE_PATH=${BASE_RESOURCE_PATH}.config +REPORT_MULTI_LINE_PROJECT_ARRAY=() + +is_git_repo() { + [[ -d .git ]] || git -C ${1} rev-parse --git-dir > /dev/null 2>&1 +} + +check_if_python_virtual_env_exits() { + [[ -f "${BASE_RESOURCE_PATH}${PROJECT_PYTHON_ENV_NAME}" ]] +} + +create_python_virtual_env() { + python3 -m venv ${BASE_RESOURCE_PATH}${PROJECT_PYTHON_ENV_NAME} +} + +check_if_weasyprint_installed() { + pip list --disable-pip-version-check | grep -c WeasyPrint +} + +check_if_jinja2_installed() { + pip list --disable-pip-version-check | grep -c Jinja2 +} + + +if ! [[ -f "$CONFIG_FILE_PATH" ]]; then + read -p "Imię i nazwisko: " name surname + name_and_surname="${name} ${surname}" + if ! [[ -z "$name_and_surname" ]]; then + touch "${CONFIG_FILE_PATH}" + echo "name_and_surname='${name_and_surname}'" > "${CONFIG_FILE_PATH}" + fi; else + . ${CONFIG_FILE_PATH} +fi + +if [[ -z "$name_and_surname" ]]; then + echo "Konieczne poprawne wprowadzenie: Imię i nazwisko" +fi + defdate=`date "+%Y-%m"` read -p "Data logu rrrr-mm [${defdate}]: " date > "${CONFIG_FILE_PATH}" fi -echo -echo - -echo "=========================================================================" -echo "ZAŁĄCZNIK A do Raportu wykonania zlecenia" -echo "Changes in ${PWD##*/} for date: ${date}, created by: ${gituser}" -echo - - -python > /dev/tty <<-EOF -import subprocess -from collections import Counter - -data = Counter() - -log = subprocess.check_output('git log --all --after="${date}-01 00:00" --before="${date}-31 23:59" --author=${gituser} --pretty=format:"%h"', shell=True) - -for commit in log.splitlines(): - commit = commit.decode() - try: - stats = subprocess.check_output('git diff %s^ %s --numstat' % (commit, commit), shell=True, stderr=open('/dev/null')) - except Exception: - stats = subprocess.check_output('git diff 4b825dc642cb6eb9a060e54bf8d69288fbee4904 %s --numstat' % commit, shell=True) - for stat in stats.splitlines(): - # print(stat.decode()) - ins, dels, f = stat.split(None, 2) - try: - data[f.decode()] += (int(ins) + int(dels)) - except Exception: - pass - -for f, ch in data.items(): - print("File %s, modified lines: %s" % (f, ch)) -EOF - -echo "............. .............." -echo "Zleceniodawca Zleceniobiorca" -echo "=========================================================================" + +mkdir -p my-work-reports + +if is_git_repo .; then + echo "'my-work.sh' should run in top directory" + exit 1 +fi + +if ! check_if_python_virtual_env_exits; then + create_python_virtual_env +fi + +source ${BASE_RESOURCE_PATH}${PROJECT_PYTHON_ENV_NAME}/bin/activate + +if [[ "$(check_if_weasyprint_installed)" -lt 1 || "$(check_if_jinja2_installed)" -lt 1 ]]; then + pip install weasyprint + pip install Jinja2 +fi + +for f in *; do + if [[ -d "$f" ]]; then + if is_git_repo "./$f"; then + REPORT_MULTI_LINE_PROJECT_ARRAY+="$(python ${LINES_MODIFIED_PATH} "$f" "$date" "$gituser")" + fi + fi +done + +python ${REPORT_GENERATE_PATH} "${name_and_surname}" "${date}" "${REPORT_MULTI_LINE_PROJECT_ARRAY[0]}" From 311b8f421cb33fee0a406860948f6b822789a4db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Wolak?= Date: Tue, 1 Feb 2022 09:10:16 +0100 Subject: [PATCH 2/4] adjustments to the pdf report --- .my-work-resources/report-template.css | 10 ---------- .my-work-resources/report-template.j2 | 10 ++++++++++ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.my-work-resources/report-template.css b/.my-work-resources/report-template.css index b508967..f55d343 100644 --- a/.my-work-resources/report-template.css +++ b/.my-work-resources/report-template.css @@ -3,14 +3,4 @@ @bottom-center{ content: "Strona " counter(page) " z " counter(pages); } - - @bottom-left { - content: "Podpis pracownika:"; - margin-bottom: 5em; - } - - @bottom-right { - content: "Podpis pracodawcy:"; - margin-bottom: 5em; - } } diff --git a/.my-work-resources/report-template.j2 b/.my-work-resources/report-template.j2 index 822a948..ca4b036 100644 --- a/.my-work-resources/report-template.j2 +++ b/.my-work-resources/report-template.j2 @@ -16,5 +16,15 @@
{% endfor %}

+
+
+ Podpis pracownika:

+ ........................................ +
+
+ Podpis pracodawcy:

+ ........................................ +
+
From 2d0471bfd94e9c8e616a62f413fe6ece06135a38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Wolak?= Date: Tue, 1 Feb 2022 11:34:56 +0100 Subject: [PATCH 3/4] fixes for handling on Windows --- .gitignore | 1 + .my-work-resources/generate_report.py | 6 ++++-- my-work.sh | 11 ++++++++--- 3 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..68618f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.my-work-resources/.config diff --git a/.my-work-resources/generate_report.py b/.my-work-resources/generate_report.py index 77f878c..f46baf8 100644 --- a/.my-work-resources/generate_report.py +++ b/.my-work-resources/generate_report.py @@ -18,8 +18,10 @@ def render_template(_name_and_surname, _report_date, _report_data): ) -name_and_surname, report_date, report_data_raw = sys.argv[1], sys.argv[2], sys.argv[3] - +name_and_surname, report_date, report_data_file = sys.argv[1], sys.argv[2], sys.argv[3] +with open(report_data_file, "r") as f: + report_data_raw = f.read() + # HACK: from bash array to Python list :facepalm: report_data = literal_eval("[" + report_data_raw.replace(")(", "), (") + "]") report_data = [entry for entry in report_data if entry[1]] diff --git a/my-work.sh b/my-work.sh index be054ee..159e56b 100755 --- a/my-work.sh +++ b/my-work.sh @@ -71,7 +71,11 @@ if ! check_if_python_virtual_env_exits; then create_python_virtual_env fi -source ${BASE_RESOURCE_PATH}${PROJECT_PYTHON_ENV_NAME}/bin/activate +if [ -f ${BASE_RESOURCE_PATH}${PROJECT_PYTHON_ENV_NAME}/bin/activate ]; then + source ${BASE_RESOURCE_PATH}${PROJECT_PYTHON_ENV_NAME}/bin/activate +else + source ${BASE_RESOURCE_PATH}${PROJECT_PYTHON_ENV_NAME}/Scripts/activate +fi if [[ "$(check_if_weasyprint_installed)" -lt 1 || "$(check_if_jinja2_installed)" -lt 1 ]]; then pip install weasyprint @@ -85,5 +89,6 @@ for f in *; do fi fi done - -python ${REPORT_GENERATE_PATH} "${name_and_surname}" "${date}" "${REPORT_MULTI_LINE_PROJECT_ARRAY[0]}" +echo ${REPORT_MULTI_LINE_PROJECT_ARRAY[0]} > ${BASE_RESOURCE_PATH}/tmp +python ${REPORT_GENERATE_PATH} "${name_and_surname}" "${date}" "${BASE_RESOURCE_PATH}/tmp" +rm ${BASE_RESOURCE_PATH}/tmp \ No newline at end of file From 0fe3301a19824fd09fd873e5f380b8a6aea135f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Wolak?= Date: Wed, 2 Feb 2022 12:27:21 +0100 Subject: [PATCH 4/4] fix paths on Windows --- .my-work-resources/generate_report.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.my-work-resources/generate_report.py b/.my-work-resources/generate_report.py index f46baf8..2e7934c 100644 --- a/.my-work-resources/generate_report.py +++ b/.my-work-resources/generate_report.py @@ -1,12 +1,13 @@ import sys -import os +from pathlib import Path from weasyprint import HTML, CSS from ast import literal_eval from jinja2 import Environment, FileSystemLoader -current_directory = os.path.dirname(os.path.abspath(__file__)) +current_directory = Path(__file__).parent + env = Environment(loader=FileSystemLoader(current_directory)) @@ -21,7 +22,7 @@ def render_template(_name_and_surname, _report_date, _report_data): name_and_surname, report_date, report_data_file = sys.argv[1], sys.argv[2], sys.argv[3] with open(report_data_file, "r") as f: report_data_raw = f.read() - + # HACK: from bash array to Python list :facepalm: report_data = literal_eval("[" + report_data_raw.replace(")(", "), (") + "]") report_data = [entry for entry in report_data if entry[1]] @@ -33,9 +34,9 @@ def render_template(_name_and_surname, _report_date, _report_data): ) html = HTML(string=html_text) -css = CSS(f'/{current_directory}/report-template.css') +css = CSS(str(current_directory / "report-template.css")) html.write_pdf( - f'/{current_directory}/../my-work-reports/{report_date}.pdf', + str(current_directory.parent / "my-work-reports" / f"{report_date}.pdf"), stylesheets=[css], )