mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-02-05 10:53:28 -05:00
So that browsers will cache them for as long as possible. We invalidate
this cache by adding the hash of each file to the query string.
There’s no way of doing this on a whole bucket; it has to be set on each
item. Adding this flag does so at the time of uploading the items.
Value of 10 years in seconds taken from:
0ee3bcb1ee/whitenoise/base.py (L19)
259 lines
9.6 KiB
Makefile
259 lines
9.6 KiB
Makefile
.DEFAULT_GOAL := help
|
|
SHELL := /bin/bash
|
|
DATE = $(shell date +%Y-%m-%dT%H:%M:%S)
|
|
|
|
PIP_ACCEL_CACHE ?= ${CURDIR}/cache/pip-accel
|
|
APP_VERSION_FILE = app/version.py
|
|
|
|
GIT_BRANCH ?= $(shell git symbolic-ref --short HEAD 2> /dev/null || echo "detached")
|
|
GIT_COMMIT ?= $(shell git rev-parse HEAD 2> /dev/null || echo "")
|
|
|
|
DOCKER_IMAGE_TAG := $(shell cat docker/VERSION)
|
|
DOCKER_BUILDER_IMAGE_NAME = govuk/notify-admin-builder:${DOCKER_IMAGE_TAG}
|
|
DOCKER_TTY ?= $(if ${JENKINS_HOME},,t)
|
|
|
|
BUILD_TAG ?= notifications-admin-manual
|
|
BUILD_NUMBER ?= 0
|
|
DEPLOY_BUILD_NUMBER ?= ${BUILD_NUMBER}
|
|
BUILD_URL ?=
|
|
|
|
DOCKER_CONTAINER_PREFIX = ${USER}-${BUILD_TAG}
|
|
|
|
CF_API ?= api.cloud.service.gov.uk
|
|
CF_ORG ?= govuk-notify
|
|
CF_SPACE ?= ${DEPLOY_ENV}
|
|
CF_HOME ?= ${HOME}
|
|
$(eval export CF_HOME)
|
|
|
|
CF_MANIFEST_FILE ?= manifest-${CF_SPACE}.yml
|
|
NOTIFY_CREDENTIALS ?= ~/.notify-credentials
|
|
|
|
.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:
|
|
test -d venv || virtualenv venv -p python3
|
|
. venv/bin/activate && pip install pip-accel
|
|
|
|
.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: sandbox
|
|
sandbox: ## Set environment to sandbox
|
|
$(eval export DEPLOY_ENV=sandbox)
|
|
$(eval export DNS_NAME="cloudapps.digital")
|
|
@true
|
|
|
|
.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
|
|
|
|
.PHONY: dependencies
|
|
dependencies: venv ## Install build dependencies
|
|
npm set progress=false
|
|
npm install
|
|
npm rebuild node-sass
|
|
mkdir -p ${PIP_ACCEL_CACHE}
|
|
. venv/bin/activate && PIP_ACCEL_CACHE=${PIP_ACCEL_CACHE} pip-accel 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
|
|
. venv/bin/activate && PIP_ACCEL_CACHE=${PIP_ACCEL_CACHE} pip-accel install -r requirements.txt
|
|
|
|
.PHONY: build-paas-artifact
|
|
build-paas-artifact: ## Build the deploy artifact for PaaS
|
|
rm -rf target
|
|
mkdir -p target
|
|
zip -y -q -r -x@deploy-exclude.lst target/notifications-admin.zip ./
|
|
|
|
.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-admin.zip s3://${JENKINS_S3_BUCKET}/build/notifications-admin/${DEPLOY_BUILD_NUMBER}.zip
|
|
|
|
.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
|
|
|
|
.PHONY: test
|
|
test: venv ## Run tests
|
|
./scripts/run_tests.sh
|
|
|
|
.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: coverage
|
|
coverage: venv ## Create coverage report
|
|
. venv/bin/activate && coveralls
|
|
|
|
.PHONY: prepare-docker-build-image
|
|
prepare-docker-build-image: ## Prepare the Docker builder image
|
|
mkdir -p ${PIP_ACCEL_CACHE}
|
|
make -C docker build
|
|
|
|
define run_docker_container
|
|
@docker run -i${DOCKER_TTY} --rm \
|
|
--name "${DOCKER_CONTAINER_PREFIX}-${1}" \
|
|
-v "`pwd`:/var/project" \
|
|
-v "${PIP_ACCEL_CACHE}:/var/project/cache/pip-accel" \
|
|
-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} \
|
|
-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}" \
|
|
-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} \
|
|
-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} \
|
|
${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)
|
|
|
|
.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)
|
|
|
|
# FIXME: CIRCLECI=1 is an ugly hack because the coveralls-python library sends the PR link only this way
|
|
.PHONY: coverage-with-docker
|
|
coverage-with-docker: prepare-docker-build-image ## Generates coverage report inside a Docker container
|
|
$(call run_docker_container,coverage,gosu hostuser make coverage)
|
|
|
|
.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
|
|
|
|
.PHONY: clean
|
|
clean:
|
|
rm -rf node_modules cache target venv .coverage
|
|
|
|
.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_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))
|
|
|
|
@./scripts/generate_manifest.py ${CF_MANIFEST_FILE} \
|
|
<(${DECRYPT_CMD} ${NOTIFY_CREDENTIALS}/credentials/${CF_SPACE}/paas/environment-variables.gpg)
|
|
|
|
.PHONY: cf-deploy
|
|
cf-deploy: ## Deploys the app to Cloud Foundry
|
|
$(if ${CF_SPACE},,$(error Must specify CF_SPACE))
|
|
@cf app --guid notify-admin || exit 1
|
|
cf rename notify-admin notify-admin-rollback
|
|
cf push -f <(make -s generate-manifest)
|
|
cf scale -i $$(cf curl /v2/apps/$$(cf app --guid notify-admin-rollback) | jq -r ".entity.instances" 2>/dev/null || echo "1") notify-admin
|
|
cf stop notify-admin-rollback
|
|
cf delete -f notify-admin-rollback
|
|
|
|
.PHONY: cf-deploy-prototype
|
|
cf-deploy-prototype: cf-target ## Deploys the app to Cloud Foundry
|
|
$(if ${CF_SPACE},,$(error Must specify CF_SPACE))
|
|
(make -s CF_MANIFEST_FILE=manifest-prototype-${CF_SPACE}.yml generate-manifest) > /tmp/admin_manifest.yml
|
|
cf push -f /tmp/admin_manifest.yml
|
|
rm /tmp/admin_manifest.yml
|
|
|
|
.PHONY: cf-deploy-prototype-2
|
|
cf-deploy-prototype-2: cf-target ## Deploys the app to Cloud Foundry
|
|
$(if ${CF_SPACE},,$(error Must specify CF_SPACE))
|
|
(make -s CF_MANIFEST_FILE=manifest-prototype-2-${CF_SPACE}.yml generate-manifest) > /tmp/admin_manifest.yml
|
|
cf push -f /tmp/admin_manifest.yml
|
|
rm /tmp/admin_manifest.yml
|
|
|
|
.PHONY: cf-rollback
|
|
cf-rollback: ## Rollbacks the app to the previous release
|
|
@cf app --guid notify-admin-rollback || exit 1
|
|
@[ $$(cf curl /v2/apps/`cf app --guid notify-admin-rollback` | jq -r ".entity.state") = "STARTED" ] || (echo "Error: rollback is not possible because notify-admin-rollback is not in a started state" && exit 1)
|
|
cf delete -f notify-admin || true
|
|
cf rename notify-admin-rollback notify-admin
|
|
|
|
.PHONY: cf-push
|
|
cf-push:
|
|
cf push -f <(make -s generate-manifest)
|
|
|
|
.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"
|