Files
notifications-admin/Makefile

219 lines
7.5 KiB
Makefile
Raw Normal View History

.DEFAULT_GOAL := help
SHELL := /bin/bash
DATE = $(shell date +%Y-%m-%dT%H:%M:%S)
APP_VERSION_FILE = app/version.py
2016-08-26 16:18:13 +01:00
GIT_BRANCH ?= $(shell git symbolic-ref --short HEAD 2> /dev/null || echo "detached")
2017-02-01 15:44:10 +00:00
GIT_COMMIT ?= $(shell git rev-parse HEAD 2> /dev/null || echo "")
2016-12-08 16:50:37 +00:00
DOCKER_IMAGE_TAG := $(shell cat docker/VERSION)
DOCKER_BUILDER_IMAGE_NAME = govuk/notify-admin-builder:${DOCKER_IMAGE_TAG}
BUILD_TAG ?= notifications-admin-manual
BUILD_NUMBER ?= 0
DEPLOY_BUILD_NUMBER ?= ${BUILD_NUMBER}
BUILD_URL ?=
DOCKER_CONTAINER_PREFIX = ${USER}-${BUILD_TAG}
2016-12-08 16:50:37 +00:00
CF_API ?= api.cloud.service.gov.uk
CF_ORG ?= govuk-notify
CF_SPACE ?= ${DEPLOY_ENV}
CF_HOME ?= ${HOME}
CF_APP ?= notify-admin
$(eval export CF_HOME)
2016-12-08 16:50:37 +00:00
NOTIFY_CREDENTIALS ?= ~/.notify-credentials
2020-03-03 12:05:56 +00:00
## DEVELOPMENT
.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: dependencies
dependencies: ## Install build dependencies
npm set progress=false
npm install
npm rebuild node-sass
pip install -r requirements_for_test.txt
.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
npm run build
pip install -r requirements.txt
.PHONY: test
test: ## Run tests
./scripts/run_tests.sh
.PHONY: fix-imports
fix-imports:
isort -rc ./app ./tests
.PHONY: freeze-requirements
freeze-requirements:
rm -rf venv-freeze
virtualenv -p python3 venv-freeze
$$(pwd)/venv-freeze/bin/pip install -r requirements-app.txt
echo '# pyup: ignore file' > requirements.txt
echo '# This file is autogenerated. Do not edit it manually.' >> requirements.txt
cat requirements-app.txt >> requirements.txt
echo '' >> requirements.txt
$$(pwd)/venv-freeze/bin/pip freeze -r <(sed '/^--/d' requirements-app.txt) | sed -n '/The following requirements were added by pip freeze/,$$p' >> requirements.txt
rm -rf venv-freeze
.PHONY: test-requirements
test-requirements:
@diff requirements-app.txt requirements.txt | grep '<' \
&& { echo "requirements.txt doesn't match requirements-app.txt."; \
echo "Run 'make freeze-requirements' to update."; exit 1; } \
|| { echo "requirements.txt is up to date"; exit 0; }
.PHONY: prepare-docker-build-image
prepare-docker-build-image: ## Prepare the Docker builder image
2016-12-08 16:50:37 +00:00
make -C docker build
2016-12-08 16:50:37 +00:00
define run_docker_container
2020-03-03 12:04:32 +00:00
@docker run -it --rm \
2016-12-08 16:50:37 +00:00
--name "${DOCKER_CONTAINER_PREFIX}-${1}" \
-v "`pwd`:/var/project" \
-e UID=$(shell id -u) \
-e GID=$(shell id -g) \
-e GIT_COMMIT=${GIT_COMMIT} \
-e BUILD_NUMBER=${BUILD_NUMBER} \
-e BUILD_URL=${BUILD_URL} \
2016-11-30 15:57:20 +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-26 16:18:13 +01:00
-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-12-08 16:50:37 +00:00
-e CF_API="${CF_API}" \
-e CF_USERNAME="${CF_USERNAME}" \
-e CF_PASSWORD="${CF_PASSWORD}" \
-e CF_ORG="${CF_ORG}" \
-e CF_SPACE="${CF_SPACE}" \
${DOCKER_BUILDER_IMAGE_NAME} \
2016-12-08 16:50:37 +00:00
${2}
endef
.PHONY: build-with-docker
build-with-docker: prepare-docker-build-image ## Build inside a Docker container
$(call run_docker_container,build,gosu hostuser make build)
2016-12-08 16:50:37 +00:00
.PHONY: test-with-docker
test-with-docker: prepare-docker-build-image ## Run tests inside a Docker container
$(call run_docker_container,test,gosu hostuser make test)
2016-12-08 16:50:37 +00: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 16:50:37 +00:00
.PHONY: clean
clean:
2019-12-24 15:25:34 +00:00
rm -rf node_modules cache target
2016-12-08 16:50:37 +00:00
2020-03-03 12:05:56 +00:00
## DEPLOYMENT
.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))
.PHONY: preview
preview: ## Set environment to preview
$(eval export DEPLOY_ENV=preview)
$(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
2016-12-08 16:50:37 +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}"
.PHONY: generate-manifest
generate-manifest:
$(if ${CF_APP},,$(error Must specify CF_APP))
$(if ${CF_SPACE},,$(error Must specify CF_SPACE))
$(if $(shell which gpg2), $(eval export GPG=gpg2), $(eval export GPG=gpg))
$(if ${GPG_PASSPHRASE_TXT}, $(eval export DECRYPT_CMD=echo -n $$$${GPG_PASSPHRASE_TXT} | ${GPG} --quiet --batch --passphrase-fd 0 --pinentry-mode loopback -d), $(eval export DECRYPT_CMD=${GPG} --quiet --batch -d))
@jinja2 --strict manifest.yml.j2 \
-D environment=${CF_SPACE} \
-D CF_APP=${CF_APP} \
--format=yaml \
<(${DECRYPT_CMD} ${NOTIFY_CREDENTIALS}/credentials/${CF_SPACE}/paas/environment-variables.gpg) 2>&1
.PHONY: upload-static ## Upload the static files to be served from S3
upload-static:
aws s3 cp --region eu-west-1 --recursive --cache-control max-age=315360000,immutable ./app/static s3://${DNS_NAME}-static
2016-12-08 16:50:37 +00:00
.PHONY: cf-deploy
cf-deploy: ## Deploys the app to Cloud Foundry
2017-02-14 16:17:30 +00:00
$(if ${CF_SPACE},,$(error Must specify CF_SPACE))
@cf app --guid notify-admin || exit 1
# cancel any existing deploys to ensure we can apply manifest (if a deploy is in progress you'll see ScaleDisabledDuringDeployment)
cf v3-cancel-zdt-push ${CF_APP} || true
cf v3-apply-manifest ${CF_APP} -f <(make -s generate-manifest)
CF_STARTUP_TIMEOUT=10 cf v3-zdt-push ${CF_APP} --wait-for-deploy-complete # fails after 5 mins if deploy doesn't work
2017-02-14 16:17:30 +00:00
Add config to deploy a prototype version of admin Sometimes we want to make changes to the admin app for doing user research that we don’t want all users to see (because we’re not sure if they’re the right changes to be making). Previously this meant doing the research using a team member’s computer, with the app running locally. This was bad for three reasons: - requires the time of someone who has the code running locally - requires the participant to use an unfamiliar computer - means the participant doesn’t have access to their own Notify account (or an account that we’ve set up for doing user research with) The dream* would be to have two versions of the frontend app running side by side in production. This commit makes the dream real – the two versions of admin are: - the normal admin app, accessible on `www.notifications.service.gov.uk` - a prototype version meant to be pushed to from a developer’s local machine**, on a `cloudapps.digital` subdomain Both of these apps share the same backing services, eg config, API instance, queues, etc, etc. Which means that the prototype version can be logged into with the same username and password, and the user will see their service and all their templates when they do so. Ideally this wouldn’t mean creating a separate base manifest. However it’s a feature of Cloud Foundry that you can override the application name. Which means a separate base manifest and a bit of duplication. 😞 * actually the real dream would be to have a version of admin deployed for each branch of the admin app, but this might get a bit resource intensive. ** by running `CF_SPACE=preview make preview cf-deploy-prototype`, where `preview` is the name of the space you want to deploy to
2017-05-05 08:41:55 +01:00
.PHONY: cf-deploy-prototype
cf-deploy-prototype: cf-target ## Deploys the first prototype to Cloud Foundry
cf push -f <(CF_APP=notify-admin-prototype make -s generate-manifest)
Add config to deploy a prototype version of admin Sometimes we want to make changes to the admin app for doing user research that we don’t want all users to see (because we’re not sure if they’re the right changes to be making). Previously this meant doing the research using a team member’s computer, with the app running locally. This was bad for three reasons: - requires the time of someone who has the code running locally - requires the participant to use an unfamiliar computer - means the participant doesn’t have access to their own Notify account (or an account that we’ve set up for doing user research with) The dream* would be to have two versions of the frontend app running side by side in production. This commit makes the dream real – the two versions of admin are: - the normal admin app, accessible on `www.notifications.service.gov.uk` - a prototype version meant to be pushed to from a developer’s local machine**, on a `cloudapps.digital` subdomain Both of these apps share the same backing services, eg config, API instance, queues, etc, etc. Which means that the prototype version can be logged into with the same username and password, and the user will see their service and all their templates when they do so. Ideally this wouldn’t mean creating a separate base manifest. However it’s a feature of Cloud Foundry that you can override the application name. Which means a separate base manifest and a bit of duplication. 😞 * actually the real dream would be to have a version of admin deployed for each branch of the admin app, but this might get a bit resource intensive. ** by running `CF_SPACE=preview make preview cf-deploy-prototype`, where `preview` is the name of the space you want to deploy to
2017-05-05 08:41:55 +01:00
2018-02-07 17:28:04 +00:00
.PHONY: cf-deploy-prototype-2
cf-deploy-prototype-2: cf-target ## Deploys the second prototype to Cloud Foundry
cf push -f <(CF_APP=notify-admin-prototype-2 make -s generate-manifest)
2018-02-07 17:28:04 +00:00
2017-02-14 16:17:30 +00:00
.PHONY: cf-rollback
cf-rollback: cf-target ## Rollbacks the app to the previous release
cf v3-cancel-zdt-push ${CF_APP}
2016-12-08 16:50:37 +00:00
.PHONY: cf-target
cf-target: check-env-vars
@cf target -o ${CF_ORG} -s ${CF_SPACE}
.PHONY: cf-failwhale-deployed
cf-failwhale-deployed:
@cf app notify-admin-failwhale --guid || (echo "notify-admin-failwhale is not deployed on ${CF_SPACE}" && exit 1)
.PHONY: enable-failwhale
enable-failwhale: cf-target cf-failwhale-deployed ## Enable the failwhale app and disable admin
@cf map-route notify-admin-failwhale ${DNS_NAME} --hostname www
@cf unmap-route notify-admin ${DNS_NAME} --hostname www
@echo "Failwhale is enabled"
.PHONY: disable-failwhale
disable-failwhale: cf-target cf-failwhale-deployed ## Disable the failwhale app and enable admin
@cf map-route notify-admin ${DNS_NAME} --hostname www
@cf unmap-route notify-admin-failwhale ${DNS_NAME} --hostname www
@echo "Failwhale is disabled"