BUILD_NUMBER?=1
PROJECT?=atlas-um

PYPI_INDEX_URL ?= https://pypi.org/simple

REVISION  ?= $(shell git rev-parse --short=8 HEAD)
BUILDTIME ?= $(shell date -u +"%Y%m%d%H%M%S")
VERSION   ?= build-$(BUILDTIME).$(REVISION)
SEMVER    ?=$(shell cat VERSION)

BASE_AWS_PROFILE    = gdb-infra-dev
BASE_AWS_ACCOUNT_ID = 483193324480
BASE_AWS_REGION     = us-east-1
BASE_ECR_REGISTRY   = $(BASE_AWS_ACCOUNT_ID).dkr.ecr.$(BASE_AWS_REGION).amazonaws.com

AWS_PROFILE    ?= gdb-core-dev
AWS_ACCOUNT_ID ?= 582412345909
AWS_REGION     ?= us-east-1

ECR_REGISTRY        ?= $(AWS_ACCOUNT_ID).dkr.ecr.$(AWS_REGION).amazonaws.com
ECR_REPOSITORY_NAME ?= core/atlas-um
ECR_REGISTRY_URI    ?= $(ECR_REGISTRY)/$(ECR_REPOSITORY_NAME)

SQITCH_ECR_REPOSITORY_NAME ?= core/atlas-um-sqitch
SQITCH_ECR_REGISTRY_URI   ?= $(ECR_REGISTRY)/$(SQITCH_ECR_REPOSITORY_NAME)

## -
## Local commands:

##   clean - remove temporary and unnecessary files
.PHONY: clean
clean:
	@echo "Deleting unnecessary files"
	@rm -rf build/
	@rm -rf dist/
	@rm -rf *.egg-info
	@rm -rf *.pyc
	@rm -rf .*_cache
	@rm -rf __pycache__/
	@find . -name '*.pyc' -delete
	@find . -name '__pycache__' -delete

##   venv/init - create virtual environment if it doesn't exist
.PHONY: venv/init
venv/init:
	@test -d venv || python3 -m venv venv

##   venv/activate - activate virtual environment and install dependencies
.PHONY: venv/activate
venv/activate: venv/init
	@source venv/bin/activate; pip install -r requirements/dev.txt

##   local/init - install dependencies locally
.PHONY: local/init
local/init: ## install bumpversion via pip
	@pip install --user --upgrade bumpversion

## -
## Version management

##   version/patch - increment version patch
.PHONY: version/patch
version/patch:
	@bumpversion \
		--config-file .bumpversion.cfg \
		--current-version ${SEMVER} \
		patch VERSION --allow-dirty

##   version/minor - increment version minor
.PHONY: version/minor
version/minor:
	@bumpversion \
		--config-file .bumpversion.cfg \
		--current-version ${SEMVER} \
		minor VERSION --allow-dirty

##   version/major - increment version major
.PHONY: version/major
version/major:
	@bumpversion \
		--config-file .bumpversion.cfg \
		--current-version ${SEMVER} \
		major VERSION --allow-dirty

## -
## Docker commands:

##   docker/login/base - login to AWS ECR registry using docker, aws configuration need to be set first
.PHONY:docker/login/base
docker/login/base:
	@aws ecr get-login \
		--profile ${BASE_AWS_PROFILE} \
		--no-include-email \
		--region ${BASE_AWS_REGION} | awk '{print $$6}' | \
		docker login -u AWS --password-stdin https://$(BASE_ECR_REGISTRY) || aws ecr get-login-password \
			--profile ${BASE_AWS_PROFILE} \
			--region ${BASE_AWS_REGION} | \
			docker login --username AWS --password-stdin https://$(BASE_ECR_REGISTRY)

##   docker/login - login to AWS ECR registry using docker, aws configuration need to be set first
.PHONY:docker/login
docker/login:
	@aws ecr get-login \
		--profile ${AWS_PROFILE} \
		--no-include-email \
		--region ${AWS_REGION} | awk '{print $$6}' | \
		docker login -u AWS --password-stdin https://$(ECR_REGISTRY) || aws ecr get-login-password \
			--profile ${AWS_PROFILE} \
			--region ${AWS_REGION} | \
			docker login --username AWS --password-stdin https://$(ECR_REGISTRY)

##   docker/base/image/pull - pull base image from ECR
docker/base/image/pull: docker/login/base
	docker pull $(BASE_ECR_REGISTRY)/python:3.10-slim-buster
	docker pull $(BASE_ECR_REGISTRY)/node:14.17.3-alpine

##   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/base
	@echo "Building docker image"
	docker build \
		--build-arg VERSION=$(VERSION) \
		--build-arg REVISION=$(REVISION) \
		--build-arg BUILDTIME=$(BUILDTIME) \
		--build-arg PYPI_INDEX_URL=$(PYPI_INDEX_URL) \
		--target deploy \
		-t $(ECR_REGISTRY_URI):$(VERSION) \
		-t $(ECR_REGISTRY_URI):$(REVISION) .

##   docker/sqitch/build - build lambda package for each environment and put all of them into one docker container
.PHONY: docker/sqitch/build
docker/sqitch/build: docker/login/base
	@echo "Building docker image"
	docker build \
		--build-arg VERSION=$(VERSION) \
		--build-arg REVISION=$(REVISION) \
		--build-arg BUILDTIME=$(BUILDTIME) \
		-t $(SQITCH_ECR_REGISTRY_URI):$(VERSION) \
		-t $(SQITCH_ECR_REGISTRY_URI):$(REVISION) \
		-f migrations/Dockerfile \
		.

##   docker/image/push - push an image to a registry
.PHONY: docker/image/push
docker/image/push: docker/login
	@echo "Pushing docker image"
	docker push $(ECR_REGISTRY_URI):$(VERSION)
	docker push $(ECR_REGISTRY_URI):$(REVISION)

##   docker/image/push - push an image to a registry
.PHONY: docker/sqitch/push
docker/sqitch/push: docker/login
	@echo "Pushing docker image"
	docker push $(SQITCH_ECR_REGISTRY_URI):$(VERSION)
	docker push $(SQITCH_ECR_REGISTRY_URI):$(REVISION)

##   docker/run/local - run local image as a server
.PHONY:docker/run/local
docker/run/local: docker/login/base docker/pg/migrate
	@echo "Run docker image locally"
	docker-compose up -d --build

##   docker/run/rebuild - rebuild run image without cache
.PHONY:docker/run/rebuild
docker/run/rebuild:
	@echo "Rebuild docker run image without cache"
	docker-compose build --no-cache

##   docker/pg/add - add migration
.PHONY:docker/pg/add
docker/pg/add:
	@echo "Add database migration"; \
	 read -p "Enter migration name (no spaces): " MIGRATION_NAME; \
	 read -p "Enter previous required migration: " MIGRATION_REQUIRES; \
	 docker-compose run --rm pg_m --command=add -- "$${MIGRATION_NAME}" -n "$${MIGRATION_NAME}" -r "$${MIGRATION_REQUIRES}"

##   docker/pg/migrate - migrate pgdb container to match current database schema
.PHONY:docker/pg/migrate
docker/pg/migrate:
	@echo "Migrate docker Postgres database"
	docker-compose up --build --abort-on-container-exit pg_m

##   docker/pg/revert - revert pgdb container
.PHONY:docker/pg/revert
docker/pg/revert:
	@echo "Revert docker Postgres database"
	docker-compose run --rm pg_m --command=revert -- -y

##   docker/test/rebuild - rebuild test image without cache
.PHONY:docker/test/rebuild
docker/test/rebuild:
	@echo "Rebuild docker test image without cache"
	docker-compose -f docker-compose.test.yml -p ${PROJECT}_test build --no-cache

##   docker/test/unit - run tests with docker-compose
.PHONY:docker/test/unit
docker/test/unit:
	@echo "Run unit tests in a docker image"
	docker-compose -f docker-compose.test.yml -p ${PROJECT}_test up --build --abort-on-container-exit pg_m
	docker-compose -f docker-compose.test.yml -p ${PROJECT}_test run --rm app python -m pytest --cov=atlas_um --no-cov-on-fail --cov-report=term-missing tests
	docker-compose -f docker-compose.test.yml -p ${PROJECT}_test run --rm pg_m --command=revert -- -y
	docker-compose -f docker-compose.test.yml -p ${PROJECT}_test run --rm app coverage report

##   docker/test/feat - run features with docker-compose
.PHONY:docker/test/feat
docker/test/feat:
	@echo "Run features in a docker image"
	docker-compose -f docker-compose.test.yml -p ${PROJECT}_test up --build --abort-on-container-exit pg_m
	docker-compose -f docker-compose.test.yml -p ${PROJECT}_test run -e LOGLEVEL=WARNING --rm app behave --no-logcapture
	docker-compose -f docker-compose.test.yml -p ${PROJECT}_test run --rm pg_m --command=revert -- -y

##   docker/test - test all the things including up and down migrations
.PHONY:docker/test
docker/test: docker/test/unit docker/test/feat

##   docker/lint - run Flake8 checks with docker-compose
.PHONY:docker/lint
docker/lint:
	@echo "Run Black and Flake8 checks in a docker image"
	docker-compose -f docker-compose.test.yml -p ${PROJECT}_test build
	docker-compose -f docker-compose.test.yml -p ${PROJECT}_test run --rm app sh -c "flake8 /atlas-um"

##   docker/format - run Black formatter with docker-compose
.PHONY:docker/format
docker/format:
	@echo "Run Black in a docker image"
	docker-compose -f docker-compose.test.yml -p ${PROJECT}_test build
	docker-compose -f docker-compose.test.yml -p ${PROJECT}_test run --rm app  sh -c "black --config /atlas-um/pyproject.toml /atlas-um /tests"

##   docker/dependencies-check - run pip-audit check with docker-compose
.PHONY:docker/dependencies-check
docker/dependencies-check:
	@echo "Run pip-audit in a docker image"
	 touch .env && docker-compose -f docker-compose.test.yml -p ${PROJECT}_test build && docker-compose -f docker-compose.test.yml -p ${PROJECT}_test run --rm app sh -c "pip-audit --cache-dir /tmp --ignore PYSEC-2022-42969 --ignore GHSA-8fww-64cx-x8p5 --ignore PYSEC-2021-13 --ignore PYSEC-2022-43017" # ignored py(PYSEC-2022-42969), redis(GHSA-8fww-64cx-x8p5), flask-caching(PYSEC-2021-13), wheel(PYSEC-2022-43017)

##   docker/bandit - run Bandit check with docker-compose
.PHONY:docker/bandit
docker/bandit:
	@echo "Run Bandit in a docker image"
	docker-compose -f docker-compose.test.yml -p ${PROJECT}_test build
	docker-compose -f docker-compose.test.yml -p ${PROJECT}_test run --rm app sh -c "bandit -r atlas_um/"

.PHONY:pre-commit
pre-commit:
	make docker/format && make docker/lint && make docker/test && make docker/dependencies-check && make docker/bandit

##   docker/clean - stop containers and clean up docker
.PHONY:docker/clean
docker/clean:
	docker-compose -f docker-compose.test.yml -p ${PROJECT}_test down

## -
## help - this message
.PHONY: help
help: Makefile
	@echo "Application: ${APP}\n"
	@echo "Run command:\n  make <target>\n"
	@grep -E -h '^## .*' $(MAKEFILE_LIST) | sed -n 's/^##//p'  | column -t -s '-' |  sed -e 's/^/ /'
