VENV_NAME ?= venv VENV_ACTIVATE=. $(VENV_NAME)/bin/activate PYTHON = $(VENV_NAME)/bin/python3 PIP = $(VENV_NAME)/bin/pip3 PYTEST = $(VENV_NAME)/bin/pytest PYLINT = $(VENV_NAME)/bin/pylint TWINE = $(VENV_NAME)/bin/twine YAPF = $(VENV_NAME)/bin/yapf ISORT = $(VENV_NAME)/bin/isort MYPY = $(VENV_NAME)/bin/mypy DOCKER_VENV_NAME ?= /tmp/dockerenv BUILD_VENV_NAME ?= /tmp/buildenv DEPS_VENV_NAME ?= /tmp/depsenv WHEELHOUSE ?= wheels # Set AWS ECR address if your tools is going to be executed in a cloud REGISTRY ?= $(APP) REVISION ?= $(shell git rev-parse --short=8 HEAD) VERSION ?= $(shell git rev-parse --abbrev-ref HEAD) BUILDTIME = $(shell date -u +"%Y%m%d%H%M%S") TEST_MARKS ?= "not integration" TEST_ID = $(subst .,_,${VERSION}) PG_CONTAINER_NAME = PG__${TEST_ID} NETWORK = ${PACKAGE}__${TEST_ID} TEST_IMAGE = 475275892927.dkr.ecr.us-east-1.amazonaws.com/python:3.10-aws2-testing DOCKER_PIP_ARGS ?= --find-links=/app/$(WHEELHOUSE) PG_IMAGE = postgres:12.6 SLZ_DB_SCHEMA_IMAGE = 475275892927.dkr.ecr.us-east-1.amazonaws.com/delphi/slz-db-schema:0.105.0 .DEFAULT_GOAL := help ## - ## Local commands: ## venv - create local virtual env (base.pip dependencies) $(VENV_NAME)/bin/activate: python3.10 -m venv $(VENV_NAME) $(VENV_NAME): $(VENV_NAME)/bin/activate setup.py @echo "Creating virtial environment" @cp pip.conf $(VENV_NAME)/ $(PIP) install -U pip $(PIP) install -e . ## testenv - create local virtual env (test.pip dependencies) .PHONY:testenv testenv: $(VENV_NAME) @echo "Installing test reqirements" $(PIP) install $(PIP_ARGS) -r requirements/test.pip ## devenv - create local virtual env (dev.pip dependencies) .PHONY:devenv devenv: $(VENV_NAME) @echo "Installing dev requirements" $(PIP) install -r requirements/dev.pip ## depsenv - create local virtual env for dependencies management .PHONY:depsenv depsenv: python3 -m venv $(DEPS_VENV_NAME) @cp pip.conf $(DEPS_VENV_NAME) ## test - run tests .PHONY:test test: testenv @echo "Running tests" $(PYTEST) --junitxml=./junitreport.xml --cov=$(APP) --cov-report=xml -m ${TEST_MARKS} ./tests ## lint - run pylint check .PHONY:lint lint: testenv @echo "Running linter" $(PYLINT) $(APP) $(PYLINT) tests ## typecheck - run mypy check .PHONY:typecheck typecheck: testenv @echo "Running typecheck" $(MYPY) $(APP) ## fmt - reformat code with yapf .PHONY:fmt fmt: devenv $(ISORT) $(APP) $(YAPF) $(APP) --recursive --verbose --in-place --parallel $(ISORT) tests $(YAPF) tests --recursive --verbose --in-place --parallel ## fmtcheck - dry run isort & yapf .PHONY:fmtcheck fmtcheck: devenv $(ISORT) $(APP) --check-only && $(YAPF) $(APP) --recursive --verbose --diff --parallel $(ISORT) tests --check-only && $(YAPF) tests --recursive --verbose --diff --parallel ## build - build package .PHONY:build build: clean $(VENV_NAME) @echo "Building python package" @cp pip.conf $(VENV_NAME)/ && \ $(PYTHON) setup.py bdist_wheel ## upload - upload package on PyPI .PHONY:upload upload: build @echo "Uploading python package to PyPI" @cp pip.conf $(VENV_NAME)/ && \ $(TWINE) upload -r pypi --config-file .pypirc ./dist/* ## deps - build wheels of dependencies and upload to PyPI .PHONY: deps deps: clean @echo "Building python dependencies" python3 -m venv $(BUILD_VENV_NAME) @cp pip.conf $(BUILD_VENV_NAME) $(BUILD_VENV_NAME)/bin/pip install -U 'pip<22' wheel setuptools twine && \ GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS=8 \ $(BUILD_VENV_NAME)/bin/pip wheel -r requirements/base.pip -w $(WHEELHOUSE) && \ $(BUILD_VENV_NAME)/bin/pip wheel -r requirements/test.pip -w $(WHEELHOUSE) @echo "Uploading wheels" $(BUILD_VENV_NAME)/bin/twine upload -r pypi --config-file .pypirc $(WHEELHOUSE)/* @rm -rf $(BUILD_VENV_NAME) ## deps/freeze - freeze dependencies deps/freeze: depsenv @echo "Freezing dependencies" @rm -f reqiurements/*.pip $(DEPS_VENV_NAME)/bin/pip install -U 'pip<22' pip-tools && \ $(DEPS_VENV_NAME)/bin/pip-compile --no-emit-index-url requirements/base.in --output-file requirements/base.pip && \ $(DEPS_VENV_NAME)/bin/pip-compile --no-emit-index-url requirements/test.in --output-file requirements/test.pip && \ $(DEPS_VENV_NAME)/bin/pip-compile --no-emit-index-url requirements/dev.in --output-file requirements/dev.pip @rm -rf $(DEPS_VENV_NAME) ## deps/upgrade - upgrade dependencies deps/upgrade: depsenv @echo "Upgrading dependencies" $(DEPS_VENV_NAME)/bin/pip install -U 'pip<22' pip-tools && \ $(DEPS_VENV_NAME)/bin/pip-compile --upgrade --no-emit-index-url requirements/base.in --output-file requirements/base.pip && \ $(DEPS_VENV_NAME)/bin/pip-compile --upgrade --no-emit-index-url requirements/test.in --output-file requirements/test.pip && \ $(DEPS_VENV_NAME)/bin/pip-compile --upgrade --no-emit-index-url requirements/dev.in --output-file requirements/dev.pip @rm -rf $(DEPS_VENV_NAME) ## clean - delete unnecessary files .PHONY: clean clean: @echo "Deleting unnecessary files" @rm -rf build/ @rm -rf dist/ @rm -rf $(WHEELHOUSE)/ @rm -rf *.egg-info @rm -rf *.pyc @rm -f $(PACKAGE)-*.tar.gz @rm -rf .*_cache @rm -rf __pycache__/ @find . -name '*.pyc' -delete @find . -name '__pycache__' -delete ## - ## Docker commands: ## docker/login - login to AWS docker, aws configuration need to be set first .PHONY: docker/login docker/login: @echo "Docker login" $$(aws ecr get-login --no-include-email --region us-east-1) ## docker/pg/start - start test pg instance .PHONY: docker/pg/start docker/pg/start: docker network create ${NETWORK} docker run -d \ --network ${NETWORK} \ -e POSTGRES_USER=admin \ -e POSTGRES_PASSWORD=admin \ -e POSTGRES_DB=slz \ --name=${PG_CONTAINER_NAME} ${PG_IMAGE} docker exec ${PG_CONTAINER_NAME} sh -c 'until pg_isready -U postgres; do sleep 1; done' docker run --rm --network ${NETWORK} \ -e CREATE_USERS=1 \ -e LIQUIBASE_URL=jdbc:postgresql://${PG_CONTAINER_NAME}:5432/slz \ -e LIQUIBASE_USERNAME=admin \ -e LIQUIBASE_PASSWORD=admin \ -e LIQUIBASE_CHANGELOG=/liquibase/db.changelog-master.xml \ ${SLZ_DB_SCHEMA_IMAGE} update ## docker/pg/stop - shutdown test pg instance .PHONY: docker/pg/stop docker/pg/stop: -docker kill ${PG_CONTAINER_NAME} -docker rm ${PG_CONTAINER_NAME} -docker network rm ${NETWORK} ## docker/integration - run integration tests .PHONY: docker/integration docker/integration: docker/pg/stop $(MAKE) docker/pg/start docker run --rm \ -v $(PWD)/../Makefile.inc:/Makefile.inc \ -v /app/$(DOCKER_VENV_NAME) \ -v $(PWD)/:/$(APP)/ \ -w /$(APP)/ \ -e PG_HOST=${PG_CONTAINER_NAME} \ -e PG_PORT=5432 \ -e PG_USER=admin \ -e PG_PASSWORD=admin \ -e PG_DB=slz \ -e STAGE=$(STAGE) \ --network=${NETWORK} \ ${TEST_IMAGE} make VENV_NAME=$(DOCKER_VENV_NAME) TEST_MARKS="integration" test $(MAKE) docker/pg/stop ## docker/test/image - pull image used for tests execution .PHONY: docker/test/image docker/test/image: docker/login @echo "Pulling image for running tests" docker pull ${TEST_IMAGE} ## docker/image/build - build lambda package for each environment and put all of them into one docker container .PHONY: docker/image/build docker/image/build: docker/login @echo "Building docker image" cp ../Makefile.inc ./Makefile.inc docker build \ --no-cache \ --build-arg REVISION=$(REVISION) \ --build-arg BUILDTIME=$(BUILDTIME) \ --build-arg APP=$(APP) \ --build-arg PACKAGE=$(PACKAGE) \ -t $(REGISTRY):$(VERSION) \ -t $(REGISTRY):$(REVISION) . rm ./Makefile.inc ## docker/image/pull - pull an image from a registry .PHONY: docker/image/pull docker/image/pull: docker/login @echo "Pulling docker image" docker pull $(REGISTRY):$(VERSION) ## docker/image/push - push an image to a registry .PHONY: docker/image/push docker/image/push: docker/login @echo "Pushing docker image" docker push $(REGISTRY):$(VERSION) docker push $(REGISTRY):$(REVISION) ## docker/ - universal docker wrapper for local targets docker/%: docker/login docker run --rm \ -v $(PWD)/../Makefile.inc:/Makefile.inc \ -v $(PWD)/:/$(APP)/ \ -w /$(APP)/ \ -e STAGE=$(STAGE) \ ${TEST_IMAGE} make VENV_NAME=$(DOCKER_VENV_NAME) PIP_ARGS=$(DOCKER_PIP_ARGS) $* ## - ## help - this message .PHONY: help help: Makefile @echo "Application: ${APP}\n" @echo "Run command:\n make \n" @grep -E -h '^## .*' $(MAKEFILE_LIST) | sed -n 's/^##//p' | column -t -s '-' | sed -e 's/^/ /'