2016-08-16 17:51:52 +01:00
.DEFAULT_GOAL := help
SHELL := /bin/bash
DATE = $( shell date +%Y-%m-%d:%H:%M:%S)
PIP_ACCEL_CACHE ?= ${ CURDIR } /cache/pip-accel
APP_VERSION_FILE = app/version.py
2016-08-26 16:18:04 +01:00
GIT_BRANCH ?= $( shell git symbolic-ref --short HEAD 2> /dev/null || echo "detached" )
2016-08-16 17:51:52 +01:00
GIT_COMMIT ?= $( shell git rev-parse HEAD)
2016-12-08 12:12:45 +00:00
DOCKER_IMAGE_TAG := $( shell cat docker/VERSION)
DOCKER_BUILDER_IMAGE_NAME = govuk/notify-api-builder:${ DOCKER_IMAGE_TAG }
2017-01-12 14:38:08 +00:00
DOCKER_TTY ?= $( if ${ JENKINS_HOME } ,,t)
2016-08-16 17:51:52 +01:00
BUILD_TAG ?= notifications-api-manual
BUILD_NUMBER ?= 0
DEPLOY_BUILD_NUMBER ?= ${ BUILD_NUMBER }
BUILD_URL ?=
DOCKER_CONTAINER_PREFIX = ${ USER } -${ BUILD_TAG }
2016-12-08 12:12:45 +00:00
CF_API ?= api.cloud.service.gov.uk
CF_ORG ?= govuk-notify
CF_SPACE ?= ${ DEPLOY_ENV }
2017-02-28 12:32:01 +00:00
CF_HOME ?= ${ HOME }
$( eval export CF_HOME )
2016-12-08 12:12:45 +00:00
2017-02-13 18:04:08 +00:00
CF_MANIFEST_FILE = manifest-$( firstword $( subst -, ,$( subst notify-,,${ CF_APP } ) ) ) -${ CF_SPACE } .yml
2016-08-16 17:51:52 +01:00
.PHONY : help
help :
@cat $( MAKEFILE_LIST) | grep -E '^[a-zA-Z_-]+:.*?## .*$$' | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
.PHONY : venv
venv : venv /bin /activate ## Create virtualenv if it does not exist
venv/bin/activate :
2016-12-08 12:12:45 +00:00
test -d venv || virtualenv venv -p python3
. venv/bin/activate && pip install pip-accel
2016-08-16 17:51:52 +01:00
.PHONY : check -env -vars
check-env-vars : ## Check mandatory environment variables
$( if ${ DEPLOY_ENV } ,,$( error Must specify DEPLOY_ENV) )
$( if ${ DNS_NAME } ,,$( error Must specify DNS_NAME) )
$( if ${ AWS_ACCESS_KEY_ID } ,,$( error Must specify AWS_ACCESS_KEY_ID) )
$( if ${ AWS_SECRET_ACCESS_KEY } ,,$( error Must specify AWS_SECRET_ACCESS_KEY) )
2016-12-08 12:12:45 +00:00
.PHONY : sandbox
sandbox : ## Set environment to sandbox
$( eval export DEPLOY_ENV = sandbox)
$( eval export DNS_NAME = "cloudapps.digital" )
@true
2016-08-24 15:55:29 +01:00
.PHONY : preview
preview : ## Set environment to preview
$( eval export DEPLOY_ENV = preview)
2016-08-16 17:51:52 +01:00
$( eval export DNS_NAME = "notify.works" )
@true
.PHONY : staging
staging : ## Set environment to staging
$( eval export DEPLOY_ENV = staging)
$( eval export DNS_NAME = "staging-notify.works" )
@true
.PHONY : production
production : ## Set environment to production
$( eval export DEPLOY_ENV = production)
$( eval export DNS_NAME = "notifications.service.gov.uk" )
@true
.PHONY : dependencies
dependencies : venv ## Install build dependencies
mkdir -p ${ PIP_ACCEL_CACHE }
2016-12-08 12:12:45 +00:00
. venv/bin/activate && PIP_ACCEL_CACHE = ${ PIP_ACCEL_CACHE } pip-accel install -r requirements_for_test.txt
2016-08-16 17:51:52 +01:00
.PHONY : generate -version -file
generate-version-file : ## Generates the app version file
@echo -e " __travis_commit__ = \" ${ GIT_COMMIT } \"\n__time__ = \" ${ DATE } \"\n__travis_job_number__ = \" ${ BUILD_NUMBER } \"\n__travis_job_url__ = \" ${ BUILD_URL } \" " > ${ APP_VERSION_FILE }
.PHONY : build
build : dependencies generate -version -file ## Build project
2017-07-21 14:26:59 +01:00
. venv/bin/activate && PIP_ACCEL_CACHE = ${ PIP_ACCEL_CACHE } pip-accel install -r requirements.txt
2016-12-08 12:12:45 +00:00
.PHONY : cf -build
cf-build : dependencies generate -version -file ## Build project for PAAS
2016-08-16 17:51:52 +01:00
.PHONY : build -codedeploy -artifact
build-codedeploy-artifact : ## Build the deploy artifact for CodeDeploy
2017-02-20 10:09:59 +00:00
rm -rf target
2016-08-16 17:51:52 +01:00
mkdir -p target
2017-02-20 10:09:59 +00:00
zip -y -q -r -x@deploy-exclude.lst target/notifications-api.zip ./
2016-08-16 17:51:52 +01:00
2016-09-20 11:49:01 +01:00
rm -rf build/db-migration-codedeploy
mkdir -p build/db-migration-codedeploy
unzip target/notifications-api.zip -d build/db-migration-codedeploy
cd build/db-migration-codedeploy && \
mv -f appspec-db-migration.yml appspec.yml && \
2017-02-20 10:09:59 +00:00
zip -y -q -r -x@deploy-exclude.lst ../../target/notifications-api-db-migration.zip ./
2016-09-20 11:49:01 +01:00
2016-08-16 17:51:52 +01:00
.PHONY : upload -codedeploy -artifact ## Upload the deploy artifact for CodeDeploy
upload-codedeploy-artifact : check -env -vars
2017-02-28 10:47:11 +00:00
$( if ${ DEPLOY_BUILD_NUMBER } ,,$( error Must specify DEPLOY_BUILD_NUMBER) )
2016-12-05 16:58:20 +00:00
aws s3 cp --region eu-west-1 --sse AES256 target/notifications-api.zip s3://${ DNS_NAME } -codedeploy/notifications-api-${ DEPLOY_BUILD_NUMBER } .zip
aws s3 cp --region eu-west-1 --sse AES256 target/notifications-api-db-migration.zip s3://${ DNS_NAME } -codedeploy/notifications-api-db-migration-${ DEPLOY_BUILD_NUMBER } .zip
2016-08-16 17:51:52 +01:00
2017-02-28 10:47:11 +00:00
.PHONY : build -paas -artifact
build-paas-artifact : build -codedeploy -artifact ## Build the deploy artifact for PaaS
.PHONY : upload -paas -artifact ## Upload the deploy artifact for PaaS
upload-paas-artifact :
$( if ${ DEPLOY_BUILD_NUMBER } ,,$( error Must specify DEPLOY_BUILD_NUMBER) )
$( if ${ JENKINS_S3_BUCKET } ,,$( error Must specify JENKINS_S3_BUCKET) )
aws s3 cp --region eu-west-1 --sse AES256 target/notifications-api.zip s3://${ JENKINS_S3_BUCKET } /build/notifications-api/${ DEPLOY_BUILD_NUMBER } .zip
2016-08-16 17:51:52 +01:00
.PHONY : test
2016-08-23 12:17:53 +01:00
test : venv generate -version -file ## Run tests
2016-08-16 17:51:52 +01:00
./scripts/run_tests.sh
.PHONY : deploy -api
deploy-api : check -env -vars ## Trigger CodeDeploy for the api
aws deploy create-deployment --application-name notify-api --deployment-config-name CodeDeployDefault.OneAtATime --deployment-group-name notify-api --s3-location bucket = ${ DNS_NAME } -codedeploy,key= notifications-api-${ DEPLOY_BUILD_NUMBER } .zip,bundleType= zip --region eu-west-1
2016-09-20 11:49:01 +01:00
.PHONY : deploy -api
deploy-api-db-migration : check -env -vars ## Trigger CodeDeploy for the api db migration
aws deploy create-deployment --application-name notify-api-db-migration --deployment-config-name CodeDeployDefault.OneAtATime --deployment-group-name notify-api-db-migration --s3-location bucket = ${ DNS_NAME } -codedeploy,key= notifications-api-db-migration-${ DEPLOY_BUILD_NUMBER } .zip,bundleType= zip --region eu-west-1
2016-08-16 17:51:52 +01:00
.PHONY : deploy -admin -api
deploy-admin-api : check -env -vars ## Trigger CodeDeploy for the admin api
aws deploy create-deployment --application-name notify-admin-api --deployment-config-name CodeDeployDefault.OneAtATime --deployment-group-name notify-admin-api --s3-location bucket = ${ DNS_NAME } -codedeploy,key= notifications-api-${ DEPLOY_BUILD_NUMBER } .zip,bundleType= zip --region eu-west-1
.PHONY : deploy -delivery
deploy-delivery : check -env -vars ## Trigger CodeDeploy for the delivery app
aws deploy create-deployment --application-name notify-delivery --deployment-config-name CodeDeployDefault.OneAtATime --deployment-group-name notify-delivery --s3-location bucket = ${ DNS_NAME } -codedeploy,key= notifications-api-${ DEPLOY_BUILD_NUMBER } .zip,bundleType= zip --region eu-west-1
2017-01-16 17:06:26 +00:00
.PHONY : check -aws -vars
check-aws-vars : ## Check if AWS access keys are set
$( if ${ AWS_ACCESS_KEY_ID } ,,$( error Must specify AWS_ACCESS_KEY_ID) )
$( if ${ AWS_SECRET_ACCESS_KEY } ,,$( error Must specify AWS_SECRET_ACCESS_KEY) )
.PHONY : deploy -suspend -autoscaling -processes
deploy-suspend-autoscaling-processes : check -aws -vars ## Suspend launch and terminate processes for the auto-scaling group
$( if ${ CODEDEPLOY_APP_NAME } ,,$( error Must specify CODEDEPLOY_APP_NAME) )
aws autoscaling suspend-processes --region eu-west-1 --auto-scaling-group-name ${ CODEDEPLOY_APP_NAME } --scaling-processes "Launch" "Terminate"
.PHONY : deploy -resume -autoscaling -processes
deploy-resume-autoscaling-processes : check -aws -vars ## Resume launch and terminate processes for the auto-scaling group
$( if ${ CODEDEPLOY_APP_NAME } ,,$( error Must specify CODEDEPLOY_APP_NAME) )
aws autoscaling resume-processes --region eu-west-1 --auto-scaling-group-name ${ CODEDEPLOY_APP_NAME } --scaling-processes "Launch" "Terminate"
.PHONY : deploy -check -autoscaling -processes
deploy-check-autoscaling-processes : check -aws -vars ## Returns with the number of instances with active autoscaling events
$( if ${ CODEDEPLOY_APP_NAME } ,,$( error Must specify CODEDEPLOY_APP_NAME) )
@aws autoscaling describe-auto-scaling-groups --region eu-west-1 --auto-scaling-group-names ${ CODEDEPLOY_APP_NAME } | jq '.AutoScalingGroups[0].Instances|map(select(.LifecycleState != "InService"))|length'
2016-08-16 17:51:52 +01:00
.PHONY : coverage
coverage : venv ## Create coverage report
2016-12-08 12:12:45 +00:00
. venv/bin/activate && coveralls
2016-08-16 17:51:52 +01:00
.PHONY : prepare -docker -build -image
prepare-docker-build-image : ## Prepare the Docker builder image
mkdir -p ${ PIP_ACCEL_CACHE }
2016-12-08 12:12:45 +00:00
make -C docker build
2016-08-16 17:51:52 +01:00
.PHONY : build -with -docker
build-with-docker : prepare -docker -build -image ## Build inside a Docker container
2017-01-12 14:38:08 +00:00
@docker run -i${ DOCKER_TTY } --rm \
2016-08-16 17:51:52 +01:00
--name " ${ DOCKER_CONTAINER_PREFIX } -build " \
2017-01-09 10:31:45 +00:00
-v "`pwd`:/var/project" \
-v " ${ PIP_ACCEL_CACHE } :/var/project/cache/pip-accel " \
2017-01-12 14:38:08 +00:00
-e UID = $( shell id -u) \
-e GID = $( shell id -g) \
2016-08-23 13:35:48 +01:00
-e GIT_COMMIT = ${ GIT_COMMIT } \
-e BUILD_NUMBER = ${ BUILD_NUMBER } \
-e BUILD_URL = ${ BUILD_URL } \
2016-11-30 15:57:08 +00:00
-e http_proxy = " ${ HTTP_PROXY } " \
-e HTTP_PROXY = " ${ HTTP_PROXY } " \
-e https_proxy = " ${ HTTPS_PROXY } " \
-e HTTPS_PROXY = " ${ HTTPS_PROXY } " \
-e NO_PROXY = " ${ NO_PROXY } " \
2016-08-16 17:51:52 +01:00
${ DOCKER_BUILDER_IMAGE_NAME } \
2017-01-12 14:38:08 +00:00
gosu hostuser make build
2016-08-16 17:51:52 +01:00
2016-12-08 12:12:45 +00:00
.PHONY : cf -build -with -docker
cf-build-with-docker : prepare -docker -build -image ## Build inside a Docker container
2017-01-12 14:38:08 +00:00
@docker run -i${ DOCKER_TTY } --rm \
2016-08-16 17:51:52 +01:00
--name " ${ DOCKER_CONTAINER_PREFIX } -build " \
2016-12-08 12:12:45 +00:00
-v "`pwd`:/var/project" \
-v " ${ PIP_ACCEL_CACHE } :/var/project/cache/pip-accel " \
2017-01-12 14:38:08 +00:00
-e UID = $( shell id -u) \
-e GID = $( shell id -g) \
2016-08-23 13:35:48 +01:00
-e GIT_COMMIT = ${ GIT_COMMIT } \
-e BUILD_NUMBER = ${ BUILD_NUMBER } \
-e BUILD_URL = ${ BUILD_URL } \
2016-11-30 15:57:08 +00:00
-e http_proxy = " ${ HTTP_PROXY } " \
-e HTTP_PROXY = " ${ HTTP_PROXY } " \
-e https_proxy = " ${ HTTPS_PROXY } " \
-e HTTPS_PROXY = " ${ HTTPS_PROXY } " \
-e NO_PROXY = " ${ NO_PROXY } " \
2016-08-16 17:51:52 +01:00
${ DOCKER_BUILDER_IMAGE_NAME } \
2017-01-12 14:38:08 +00:00
gosu hostuser make cf-build
2016-08-16 17:51:52 +01:00
.PHONY : test -with -docker
test-with-docker : prepare -docker -build -image create -docker -test -db ## Run tests inside a Docker container
2017-01-12 14:38:08 +00:00
@docker run -i${ DOCKER_TTY } --rm \
2016-08-16 17:51:52 +01:00
--name " ${ DOCKER_CONTAINER_PREFIX } -test " \
--link " ${ DOCKER_CONTAINER_PREFIX } -db:postgres " \
2017-01-12 14:38:08 +00:00
-e UID = $( shell id -u) \
-e GID = $( shell id -g) \
2016-08-16 17:51:52 +01:00
-e TEST_DATABASE = postgresql://postgres:postgres@postgres/test_notification_api \
2016-08-23 13:35:48 +01:00
-e GIT_COMMIT = ${ GIT_COMMIT } \
-e BUILD_NUMBER = ${ BUILD_NUMBER } \
-e BUILD_URL = ${ BUILD_URL } \
2016-11-30 15:57:08 +00:00
-e http_proxy = " ${ HTTP_PROXY } " \
-e HTTP_PROXY = " ${ HTTP_PROXY } " \
-e https_proxy = " ${ HTTPS_PROXY } " \
-e HTTPS_PROXY = " ${ HTTPS_PROXY } " \
-e NO_PROXY = " ${ NO_PROXY } " \
2017-01-09 10:31:45 +00:00
-v "`pwd`:/var/project" \
2016-08-16 17:51:52 +01:00
${ DOCKER_BUILDER_IMAGE_NAME } \
2017-01-12 14:38:08 +00:00
gosu hostuser make test
2016-08-16 17:51:52 +01:00
.PHONY : test -with -docker
create-docker-test-db : ## Start the test database in a Docker container
docker rm -f ${ DOCKER_CONTAINER_PREFIX } -db 2> /dev/null || true
2016-08-26 16:18:04 +01:00
@docker run -d \
2016-08-16 17:51:52 +01:00
--name " ${ DOCKER_CONTAINER_PREFIX } -db " \
-e POSTGRES_PASSWORD = "postgres" \
-e POSTGRES_DB = test_notification_api \
postgres:9.5
sleep 3
2016-08-26 16:18:04 +01:00
# FIXME: CIRCLECI=1 is an ugly hack because the coveralls-python library sends the PR link only this way
2016-08-16 17:51:52 +01:00
.PHONY : coverage -with -docker
coverage-with-docker : prepare -docker -build -image ## Generates coverage report inside a Docker container
2017-01-12 14:38:08 +00:00
@docker run -i${ DOCKER_TTY } --rm \
2016-08-16 17:51:52 +01:00
--name " ${ DOCKER_CONTAINER_PREFIX } -coverage " \
2017-01-09 10:31:45 +00:00
-v "`pwd`:/var/project" \
2017-01-12 14:38:08 +00:00
-e UID = $( shell id -u) \
-e GID = $( shell id -g) \
2016-08-26 16:18:04 +01:00
-e COVERALLS_REPO_TOKEN = ${ COVERALLS_REPO_TOKEN } \
-e CIRCLECI = 1 \
-e CI_NAME = ${ CI_NAME } \
-e CI_BUILD_NUMBER = ${ BUILD_NUMBER } \
-e CI_BUILD_URL = ${ BUILD_URL } \
-e CI_BRANCH = ${ GIT_BRANCH } \
-e CI_PULL_REQUEST = ${ CI_PULL_REQUEST } \
2016-11-30 15:57:08 +00:00
-e http_proxy = " ${ HTTP_PROXY } " \
-e HTTP_PROXY = " ${ HTTP_PROXY } " \
-e https_proxy = " ${ HTTPS_PROXY } " \
-e HTTPS_PROXY = " ${ HTTPS_PROXY } " \
-e NO_PROXY = " ${ NO_PROXY } " \
2016-08-16 17:51:52 +01:00
${ DOCKER_BUILDER_IMAGE_NAME } \
2017-01-12 14:38:08 +00:00
gosu hostuser make coverage
2016-08-16 17:51:52 +01:00
2016-08-26 16:18:04 +01:00
.PHONY : clean -docker -containers
clean-docker-containers : ## Clean up any remaining docker containers
docker rm -f $( shell docker ps -q -f " name= ${ DOCKER_CONTAINER_PREFIX } " ) 2> /dev/null || true
2016-12-08 12:12:45 +00:00
.PHONY : clean
2016-08-16 17:51:52 +01:00
clean :
2017-07-21 14:26:59 +01:00
rm -rf node_modules cache target venv .coverage build tests/.cache
2016-12-08 12:12:45 +00:00
.PHONY : cf -login
cf-login : ## Log in to Cloud Foundry
$( if ${ CF_USERNAME } ,,$( error Must specify CF_USERNAME) )
$( if ${ CF_PASSWORD } ,,$( error Must specify CF_PASSWORD) )
$( if ${ CF_SPACE } ,,$( error Must specify CF_SPACE) )
@echo " Logging in to Cloud Foundry on ${ CF_API } "
@cf login -a " ${ CF_API } " -u ${ CF_USERNAME } -p " ${ CF_PASSWORD } " -o " ${ CF_ORG } " -s " ${ CF_SPACE } "
2017-02-13 18:04:08 +00:00
.PHONY : cf -deploy
cf-deploy : ## Deploys the app to Cloud Foundry
$( if ${ CF_SPACE } ,,$( error Must specify CF_SPACE) )
$( if ${ CF_APP } ,,$( error Must specify CF_APP) )
@cf app --guid ${ CF_APP } || exit 1
cf rename ${ CF_APP } ${ CF_APP } -rollback
cf push ${ CF_APP } -f ${ CF_MANIFEST_FILE }
cf scale -i $$ ( cf curl /v2/apps/$$ ( cf app --guid ${ CF_APP } -rollback) | jq -r ".entity.instances" 2>/dev/null || echo "1" ) ${ CF_APP }
cf stop ${ CF_APP } -rollback
cf delete -f ${ CF_APP } -rollback
2016-12-08 12:12:45 +00:00
.PHONY : cf -deploy -api -db -migration
2017-02-13 18:04:08 +00:00
cf-deploy-api-db-migration :
$( if ${ CF_SPACE } ,,$( error Must specify CF_SPACE) )
cf push notify-api-db-migration -f manifest-api-${ CF_SPACE } .yml
2017-03-23 17:45:16 +00:00
cf run-task notify-api-db-migration "python db.py db upgrade" --name api_db_migration
2016-12-08 12:12:45 +00:00
2017-02-28 12:32:01 +00:00
.PHONY : cf -check -api -db -migration -task
cf-check-api-db-migration-task : ## Get the status for the last notify-api-db-migration task
@cf curl /v3/apps/` cf app --guid notify-api-db-migration` /tasks?order_by= -created_at | jq -r ".resources[0].state"
2017-02-13 18:04:08 +00:00
.PHONY : cf -rollback
cf-rollback : ## Rollbacks the app to the previous release
2016-12-08 12:12:45 +00:00
$( if ${ CF_APP } ,,$( error Must specify CF_APP) )
2017-02-13 18:04:08 +00:00
@cf app --guid ${ CF_APP } -rollback || exit 1
2017-03-16 12:33:06 +00:00
@[ $$ ( cf curl /v2/apps/` cf app --guid ${ CF_APP } -rollback` | jq -r ".entity.state" ) = "STARTED" ] || ( echo " Error: rollback is not possible because ${ CF_APP } -rollback is not in a started state " && exit 1)
2017-02-13 18:04:08 +00:00
cf delete -f ${ CF_APP } || true
cf rename ${ CF_APP } -rollback ${ CF_APP }
.PHONY : cf -push
cf-push :
2017-02-23 11:22:58 +00:00
$( if ${ CF_APP } ,,$( error Must specify CF_APP) )
2017-02-13 18:04:08 +00:00
cf push ${ CF_APP } -f ${ CF_MANIFEST_FILE }
2017-05-26 16:44:23 +01:00
.PHONY : check -if -migrations -to -run
check-if-migrations-to-run :
2017-05-31 15:38:57 +01:00
@echo $( shell python3 scripts/check_if_new_migration.py)
2017-05-26 16:44:23 +01:00