Makefile

Summary

Maintainability
Test Coverage
# Makefile for common development tasks.
#
# Copyright (c) 2022-2023 Wibowo Arindrarto <contact@arindrarto.dev>
# SPDX-License-Identifier: BSD-3-Clause
#
# This file is part of volt <https://github.com/bow/volt>.

APP_NAME := volt
DOCS_DIR := $(CURDIR)/docs
RTD_BUILD_API_URL := https://readthedocs.org/api/v3/projects/volt/versions/latest/builds/


all: help


.PHONY: build
build:  ## Build wheel and source dist.
    poetry build


.PHONY: clean
clean:  ## Remove build and test artifacts, including built Docker images.
    rm -rf build/ dist/ wheels/ \
            .coverage .coverage.xml .junit.xml htmlcov/ .cache/ .mypy_cache/ .pytest_cache/ \
            ./tests/fixtures/ok_minimal/target \
            ./tests/fixtures/ok_extended/target \
            result \
        && (docker rmi ghcr.io/bow/$(APP_NAME) 2> /dev/null || true)


.PHONY: dev
dev:  ## Configure local development environment with nix and direnv.
    @if command -v nix-env > /dev/null && command -v direnv > /dev/null; then \
        printf "Configuring a local dev environment and setting up git pre-commit hooks...\n" >&2 \
            && direnv allow . > /dev/null \
            && DIRENV_LOG_FORMAT="" direnv exec $(CURDIR) pre-commit install \
            && printf "Done.\n" >&2; \
    elif command -v nix-env > /dev/null; then \
        printf "Error: direnv seems to be unconfigured or missing\n" >&2 && exit 1; \
    elif command -v direnv > /dev/null; then \
        printf "Error: nix seems to be unconfigured or missing\n" >&2 && exit 1; \
    else \
        printf "Error: both direnv and nix seem to be unconfigured and/or missing" >&2 && exit 1; \
    fi


.PHONY: dev-reset
dev-reset:  ## Resets the local development environment.
    rm -rf .venv .direnv && direnv reload


.PHONY: docs-html
docs-html:  ## Build HTML documentation.
    cd $(DOCS_DIR) && LC_ALL=C.UTF_8 make html


.PHONY: docs-html-serve
docs-html-serve:  ## Build HTML documentation and serve it.
    @if command -v entr > /dev/null 2>&1; then \
        find $(DOCS_DIR) -not \( -path "$(DOCS_DIR)/_build" -prune \) \
            | entr -rcdns '$(MAKE) -B docs-html && python -m http.server -d $(DOCS_DIR)/_build/html'; \
    else \
        make -B docs-html && python -m http.server -d $(DOCS_DIR)/_build/html; \
    fi


.PHONY: fmt
fmt:  ## Apply Black.
    black -t py312 volt tests


.PHONY: help
help:  ## Show this help.
    $(eval PADLEN=$(shell grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \
        | cut -d':' -f1 \
        | awk '{cur = length($$0); lengths[cur] = lengths[cur] $$0 ORS; max=(cur > max ? cur : max)} END {printf "%s", max}' \
        || (true && echo 0)))
    @(grep --version > /dev/null 2>&1 || (>&2 "error: GNU grep not installed"; exit 1)) \
        && printf "\033[36m◉ %s dev console\033[0m\n" "$(APP_NAME)" >&2 \
        && grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \
            | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m» \033[33m%-*s\033[0m \033[36m· \033[0m%s\n", $(PADLEN), $$1, $$2}' \
            | sort


.PHONY: img
img:  ## Build a docker image and load it into a running daemon.
    nix build .#dockerArchiveStreamer && ./result | docker image load


.PHONY: lint
lint:  lint-types lint-style lint-metrics  ## Lint the code.


.PHONY: lint-types
lint-types:  ## Lint the type hints.
    mypy volt tests


.PHONY: lint-style
lint-style:  ## Lint style conventions.
    flake8 --statistics volt tests && black -t py312 --check volt tests


.PHONY: lint-metrics
lint-metrics:  ## Lint various metrics.
    python -m radon cc --total-average --show-closures --show-complexity --min C volt


.PHONY: scan-sec
scan-sec: scan-sec-ast scan-sec-deps  ## Perform all security analyses.


.PHONY: scan-sec-ast
scan-sec-ast:  ## Perform static security analysis on the AST.
    bandit -r crimson


.PHONY: scan-sec-deps
scan-sec-deps:  ## Scan dependencies for reported vulnerabilities.
    poetry export --without-hashes -f requirements.txt -o /dev/stdout | safety check --full-report --stdin


.PHONY: test
test:  ## Run the test suite.
    py.test --junitxml=.junit.xml --cov=volt --cov-report=term-missing --cov-report=xml:.coverage.xml --cov-report=html:htmlcov volt tests