VENV_NAME ?= venv VENV_ACTIVATE=. $(VENV_NAME)/bin/activate PYTHON = $(VENV_NAME)/bin/python3 PIP = $(PYTHON) -m pip PYTEST = $(VENV_NAME)/bin/pytest PYLINT = $(VENV_NAME)/bin/pylint TWINE = $(VENV_NAME)/bin/twine MYPY = $(VENV_NAME)/bin/mypy YAPF = $(VENV_NAME)/bin/yapf ISORT = $(VENV_NAME)/bin/isort DOCKER_VENV_NAME ?= dockerenv DEPS_VENV_NAME ?= /tmp/depsenv WHEELHOUSE ?= wheels # Set AWS ECR address if your tools is going to be executed in a cloud AWS_PROFILE?=gdb-delphi-dev REGISTRY ?= 475275892927.dkr.ecr.us-east-1.amazonaws.com/delphi/lambda/$(PACKAGE) 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_ID = $(subst .,_,${VERSION}) PG_CONTAINER_NAME = PG__${TEST_ID} NETWORK = ${PACKAGE}__${TEST_ID} TEST_MARKS ?= "not integration" PG_IMAGE = postgres:12.6 SLZ_DB_SCHEMA_IMAGE = 475275892927.dkr.ecr.us-east-1.amazonaws.com/delphi/slz-db-schema:0.139.0 TEST_IMAGE = 475275892927.dkr.ecr.us-east-1.amazonaws.com/python:3.10-aws2-testing DOCKER_PIP_ARGS ?= --find-links=/app/$(WHEELHOUSE) .DEFAULT_GOAL := help $(VENV_NAME)/bin/activate: python3.10 -m venv $(VENV_NAME) ## - ## Local commands: ## venv - create local virtual env (base.pip dependencies) $(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 -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-report=xml --cov=$(APP) -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/* ## clean - delete unnecessary files .PHONY: clean clean: @echo "Deleting unnecessary files" @rm -rf build/ @rm -rf dist/ @rm -rf *.egg-info @rm -f $(PACKAGE)-*.tar.gz @rm -f $(APP)-*.zip @rm -rf .*_cache @rm -rf __pycache__/ @rm -rf ./$(DOCKER_VENV_NAME)/ ## deps/freeze - freeze dependencies deps/freeze: depsenv @echo "Freezing dependencies" @rm -f reqiurements/*.pip $(DEPS_VENV_NAME)/bin/pip install -U pip 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 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) ## - ## 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_test \ --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_test \ -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_test \ -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) ## STAGE= docker/image/deploy - deploy lambda from built image .PHONY: docker/image/deploy docker/image/deploy: docker/login @echo "Deploying" docker run -it --rm \ -e STAGE=$(STAGE) \ -v ~/.aws:/app/.aws:ro \ $(REGISTRY):$(VERSION) ## docker/ - universal docker wrapper for local targets docker/%: docker/login docker run --rm \ -v $(PWD)/../Makefile.inc:/Makefile.inc \ -v /app/$(DOCKER_VENV_NAME) \ -v $(PWD)/:/$(APP)/ \ -w /$(APP)/ \ -v ~/.aws:/root/.aws:ro \ ${TEST_IMAGE} make STAGE=$(STAGE) VENV_NAME=$(DOCKER_VENV_NAME) PIP_ARGS=$(DOCKER_PIP_ARGS) $* ## - ## Lambda commands: ## STAGE= lambda/package - build lambda package with zappa, one for selected environment .PHONY:lambda/package lambda/package:$(VENV_NAME) @echo "Building lambda package" $(VENV_ACTIVATE) && zappa package -o $(APP)-$(STAGE).zip $(STAGE) ## STAGE= lambda/update - update deployed lambda .PHONY:lambda/update lambda/update:$(VENV_NAME) @echo "Updating lambda" $(VENV_ACTIVATE) && zappa update -z $(APP)-$(STAGE).zip $(STAGE) ## STAGE= lambda/deploy - deploy lambda .PHONY:lambda/deploy lambda/deploy:$(VENV_NAME) @echo "Deploying lambda" $(VENV_ACTIVATE) && zappa deploy -z $(APP)-$(STAGE).zip $(STAGE) ## STAGE= lambda/undeploy - rollback deployed lambda .PHONY:lambda/undeploy lambda/undeploy:$(VENV_NAME) @echo "Undeploying lambda" $(VENV_ACTIVATE) && zappa undeploy -y $(STAGE) ## STAGE= lambda/schedule - schedule lambda invocation .PHONY:lambda/schedule lambda/schedule:$(VENV_NAME) @echo "Scheduling lambda" $(VENV_ACTIVATE) && zappa schedule $(STAGE) ## STAGE= lambda/unschedule - unschedule lambda invocation .PHONY:lambda/unschedule lambda/unschedule:$(VENV_NAME) @echo "Unscheduling lambda" $(VENV_ACTIVATE) && zappa unschedule $(STAGE) ## check current lambda status .PHONY:lambda/status lambda/status: @echo "Checking lambda status for $(STAGE)" $(VENV_ACTIVATE) && zappa status $(STAGE) ## lambda/ - universal zappa command wrapper lambda/%: $(VENV_NAME) $(VENV_ACTIVATE) && zappa $* $(STAGE) ## - ## 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/^/ /'