main > main: init
This commit is contained in:
259
justfile
Normal file
259
justfile
Normal file
@@ -0,0 +1,259 @@
|
||||
# set shell := [ "bash", "-uc" ]
|
||||
_default:
|
||||
@- just --unsorted --list
|
||||
menu:
|
||||
@- just --unsorted --choose
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# Justfile
|
||||
# NOTE: Do not change the contents of this file!
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# VARIABLES
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
OS := if os_family() == "windows" { "windows" } else { "linux" }
|
||||
PYTHON := if os_family() == "windows" { "py -3" } else { "python3" }
|
||||
GEN_MODELS := "datamodel-codegen"
|
||||
GEN_MODELS_DOCUMENTATION := "openapi-generator"
|
||||
PORT := "8000"
|
||||
URL_API := "http://127.0.0.1:8000/docs"
|
||||
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# Macros
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
_create-file-if-not-exists fname:
|
||||
@touch "{{fname}}";
|
||||
|
||||
_create-folder-if-not-exists path:
|
||||
@if ! [[ -d "{{path}}" ]]; then mkdir -p "{{path}}"; fi
|
||||
|
||||
_delete-if-file-exists fname:
|
||||
@if [[ -f "{{fname}}" ]]; then rm "{{fname}}"; fi
|
||||
|
||||
_delete-if-folder-exists path:
|
||||
@if [[ -d "{{path}}" ]]; then rm -rf "{{path}}"; fi
|
||||
|
||||
_clean-all-files path pattern:
|
||||
@find {{path}} -type f -name "{{pattern}}" -exec basename {} \; 2> /dev/null
|
||||
@- find {{path}} -type f -name "{{pattern}}" -exec rm {} \; 2> /dev/null
|
||||
|
||||
_clean-all-folders path pattern:
|
||||
@find {{path}} -type d -name "{{pattern}}" -exec basename {} \; 2> /dev/null
|
||||
@- find {{path}} -type d -name "{{pattern}}" -exec rm -rf {} \; 2> /dev/null
|
||||
|
||||
_copy-file-if-not-exists path_from path_to:
|
||||
@- cp -n "{{path_from}}" "{{path_to}}"
|
||||
|
||||
_check-python-tool tool name:
|
||||
#!/usr/bin/env bash
|
||||
success=false
|
||||
{{tool}} --help >> /dev/null 2> /dev/null && success=true;
|
||||
# NOTE: if exitcode is 251 (= help or print version), then render success.
|
||||
[[ "$?" == "251" ]] && success=true;
|
||||
# FAIL tool not installed
|
||||
if ( $success ); then
|
||||
echo -e "Tool \x1b[2;3m{{tool}}\x1b[0m installed correctly.";
|
||||
exit 0;
|
||||
else
|
||||
echo -e "Tool \x1b[2;3m{{tool}}\x1b[0m did not work." >> /dev/stderr;
|
||||
echo -e "Ensure that \x1b[2;3m{{name}}\x1b[0m (-> \x1b[1mjust build\x1b[0m) installed correctly and system paths are set." >> /dev/stderr;
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
_generate-models path name:
|
||||
@{{GEN_MODELS}} \
|
||||
--input-file-type openapi \
|
||||
--encoding "UTF-8" \
|
||||
--disable-timestamp \
|
||||
--use-schema-description \
|
||||
--allow-population-by-field-name \
|
||||
--snake-case-field \
|
||||
--strict-nullable \
|
||||
--target-python-version 3.10 \
|
||||
--input {{path}}/{{name}}-schema.yaml \
|
||||
--output {{path}}/generated/{{name}}.py
|
||||
|
||||
_generate-models-documentation path_schema path_docs name:
|
||||
@{{GEN_MODELS_DOCUMENTATION}} generate \
|
||||
--input-spec {{path_schema}}/{{name}}-schema.yaml \
|
||||
--generator-name markdown \
|
||||
--output "{{path_docs}}/{{name}}"
|
||||
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# TARGETS
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# TARGETS: build
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
build:
|
||||
@just build-misc
|
||||
@just build-requirements
|
||||
@just _check-system-requirements
|
||||
@just build-models
|
||||
build-misc:
|
||||
@# create database if not exists:
|
||||
@just _create-folder-if-not-exists "data"
|
||||
@# copy template of configs to setup if not exists:
|
||||
@just _create-folder-if-not-exists "setup"
|
||||
@just _copy-file-if-not-exists "templates/template-config.yaml" "setup/config.yaml"
|
||||
@just _copy-file-if-not-exists "templates/template.env" ".env"
|
||||
build-requirements:
|
||||
@{{PYTHON}} -m pip install --disable-pip-version-check -r requirements.txt
|
||||
build-models:
|
||||
@echo "Generate data models from schemata."
|
||||
@just _delete-if-folder-exists "models/generated"
|
||||
@just _create-folder-if-not-exists "models/generated"
|
||||
@- #just _generate-models "models" "config"
|
||||
build-documentation:
|
||||
@echo "Generate documentations data models from schemata."
|
||||
@just _delete-if-folder-exists "docs"
|
||||
@just _create-folder-if-not-exists "docs"
|
||||
@- #just _generate-models-documentation "models" "docs" "config"
|
||||
@- just _clean-all-files "." .openapi-generator*
|
||||
@- just _clean-all-folders "." .openapi-generator*
|
||||
dist:
|
||||
@just build
|
||||
@just build-documentation
|
||||
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# TARGETS: run
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
# runs using commandline interface
|
||||
run:
|
||||
@# create config/data folders if missing:
|
||||
@just build-misc
|
||||
@# run source code als cli
|
||||
@{{PYTHON}} main.py
|
||||
|
||||
# runs python notebook (in browser)
|
||||
notebook name="main":
|
||||
@# create config/data folders if missing:
|
||||
@just build-misc
|
||||
@# run notebook
|
||||
@{{PYTHON}} -m jupyter notebook notebooks/{{name}}.ipynb
|
||||
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# TARGETS: tests
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
tests: tests-unit tests-integration
|
||||
tests-logs:
|
||||
@just _create-logs
|
||||
@- just tests
|
||||
@just _display-logs
|
||||
tests-unit-logs:
|
||||
@just _create-logs
|
||||
@- just tests-unit
|
||||
@just _display-logs
|
||||
tests-integration-logs:
|
||||
@just _create-logs
|
||||
@- just tests-integration
|
||||
@just _display-logs
|
||||
tests-unit:
|
||||
@{{PYTHON}} -m pytest tests \
|
||||
--ignore=tests/integration \
|
||||
--cov-reset \
|
||||
--cov=. \
|
||||
2> /dev/null
|
||||
tests-integration:
|
||||
@{{PYTHON}} -m pytest tests/integration 2> /dev/null
|
||||
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# TARGETS: qa
|
||||
# NOTE: use for development only.
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
qa:
|
||||
@{{PYTHON}} -m coverage report -m
|
||||
coverage source_path tests_path:
|
||||
@just _create-logs
|
||||
@-just _coverage-no-logs "{{source_path}}" "{{tests_path}}"
|
||||
@just _display-logs
|
||||
_coverage-no-logs source_path tests_path:
|
||||
@{{PYTHON}} -m pytest {{tests_path}} \
|
||||
--ignore=tests/integration \
|
||||
--cov-reset \
|
||||
--cov={{source_path}} \
|
||||
--capture=tee-sys \
|
||||
2> /dev/null
|
||||
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# TARGETS: clean
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
clean:
|
||||
@just clean-basic
|
||||
@just pre-commit
|
||||
pre-commit:
|
||||
@echo "Clean python notebooks."
|
||||
@{{PYTHON}} -m jupyter nbconvert --clear-output --inplace **/*.ipynb
|
||||
@- {{PYTHON}} -m jupytext --update-metadata '{"vscode":""}' **/*.ipynb 2> /dev/null
|
||||
@- {{PYTHON}} -m jupytext --update-metadata '{"vscode":null}' **/*.ipynb 2> /dev/null
|
||||
clean-basic:
|
||||
@echo "All system artefacts will be force removed."
|
||||
@- just _clean-all-files "." ".DS_Store" 2> /dev/null
|
||||
@echo "All build artefacts will be force removed."
|
||||
@- just _clean-all-folders "." "__pycache__" 2> /dev/null
|
||||
@- just _delete-if-folder-exists "models/generated" 2> /dev/null
|
||||
@echo "All test artefacts will be force removed."
|
||||
@- just _clean-all-folders "." ".pytest_cache" 2> /dev/null
|
||||
@- just _delete-if-file-exists ".coverage" 2> /dev/null
|
||||
@- just _delete-if-folder-exists "logs" 2> /dev/null
|
||||
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# TARGETS: logging
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
_create-logs:
|
||||
@# For logging purposes (since stdout is rechanneled):
|
||||
@just _delete-if-file-exists "logs/debug.log"
|
||||
@just _create-folder-if-not-exists "logs"
|
||||
@just _create-file-if-not-exists "logs/debug.log"
|
||||
_display-logs:
|
||||
@echo ""
|
||||
@echo "Content of logs/debug.log:"
|
||||
@echo "----------------"
|
||||
@echo ""
|
||||
@- cat logs/debug.log
|
||||
@echo ""
|
||||
@echo "----------------"
|
||||
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# TARGETS: processes
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
api-process:
|
||||
#!/usr/bin/env bash
|
||||
if [[ "{{OS}}" == "linux" ]]; then
|
||||
ps aux | grep "uvicorn src.api:app"
|
||||
else
|
||||
netstat -ano | findstr "uvicorn src.api:app"
|
||||
fi
|
||||
kill-api-process:
|
||||
#!/usr/bin/env bash
|
||||
# NOTE: only need to do this for linux.
|
||||
if [[ "{{OS}}" == "linux" ]]; then
|
||||
echo "Terminating all processes associated to app and port {{PORT}}."
|
||||
while read pid; do
|
||||
if [[ "$pid" == "" ]]; then continue; fi
|
||||
echo "- killing process $pid:"
|
||||
kill -9 ${pid};
|
||||
done <<< $( pgrep -f "uvicorn src.api:app --port {{PORT}}" )
|
||||
fi
|
||||
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# TARGETS: requirements
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
_check-system:
|
||||
@echo "Operating System detected: {{os_family()}}."
|
||||
@echo "Python command used: {{PYTHON}}."
|
||||
|
||||
_check-system-requirements:
|
||||
@just _check-python-tool "{{GEN_MODELS}}" "datamodel-code-generator"
|
||||
@just _check-python-tool "{{GEN_MODELS_DOCUMENTATION}}" "openapi-code-generator"
|
||||
Reference in New Issue
Block a user