Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/erssup 69733 #1156

Draft
wants to merge 6 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 103 additions & 13 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,25 +1,90 @@
SHELL=/bin/bash -euo pipefail

install: install-node install-poetry install-hooks
containerName := ers-apim-referrals-build
networkName := ers-apim-referrals-network

# Detect if we should be running commands within the container by looking to see if the container is running locally.
USING_CONTAINER := $(shell docker container inspect -f '{{.State.Running}}' $(containerName))
# Whether or not docker commands should be executed with an interactive shell. Can be overridden by supplying INTERACTIVE_SHELL=false when running commands.
INTERACTIVE_SHELL := true

# Manage working within container and outside the container.
ifeq ($(USING_CONTAINER),true)

# Either run commands interactively or not depending on INTERACTIVE_SHELL (defaults to true).
ifeq ($(INTERACTIVE_SHELL),true)

define dexec
@docker exec -it $(containerName) sh -c "$1"
endef

else

define dexec
@docker exec $(containerName) $1
endef

endif

# Routes targets to the container where they can be exected as normal.
define dmake
@echo "Running $1 within container..."
$(call dexec,make $1)
@echo "$1 completed successfully within container."
endef

install-poetry:
$(call dmake,install-poetry)

install-npm:
$(call dmake,install-npm)

lint:
$(call dmake,lint)

format-changes:
$(call dmake,format-changes)

clean:
$(call dmake,clean)

publish:
$(call dmake,publish)

copy-examples:
$(call dmake,copy-examples)

serve:
$(call dmake,serve)

bash:
$(MAKE) -C docker/build-container bash

stop-container:
$(MAKE) -C docker/build-container stop

python: install-poetry ##D Opens a python interpreter within Poetry's virtual environment.
$(MAKE) -C docker/build-container python

else

install-poetry:
poetry install

install-node:
install-npm:
npm install
cd sandbox && npm install

install-hooks:
cp scripts/pre-commit .git/hooks/pre-commit
chmod u+x .git/hooks/pre-commit

lint: copy-examples
npm run lint-oas
cd sandbox && make lint
poetry run python scripts/xml_validator.py
poetry run flake8 **/*.py
@printf "\nLinting passed.\n\n"

format-changes:
scripts/format_changes.sh

clean:
rm -rf build
rm -rf dist
Expand All @@ -34,16 +99,21 @@ publish: clean copy-examples
copy-examples:
scripts/copy_examples_from_sandbox.sh

serve:
serve: publish
npm run serve

endif

install: install-poetry install-npm install-hooks

install-hooks:
cp scripts/pre-commit .git/hooks/pre-commit
chmod u+x .git/hooks/pre-commit

check-licenses:
npm run check-licenses
scripts/check_python_licenses.sh

sandbox: publish
$(MAKE) -C sandbox/ build run

build-proxy:
scripts/build_proxy.sh

Expand All @@ -58,8 +128,8 @@ release: clean publish build-proxy
cp poetry.lock dist/poetry.lock
cp -R macros dist

test:
echo "TODO: add tests"
sandbox: create-docker-network publish
$(MAKE) -C sandbox/ build run network=${networkName}

setup-environment:
@if [ -e /usr/bin/yum ]; then \
Expand All @@ -79,4 +149,24 @@ clean-environment:
echo "Environment not Mac or RHEL"; \
fi

.PHONY: setup-environment clean-environment sandbox
create-docker-network:
@echo "Starting docker network ${networkName}...."
@docker network create -d bridge ${networkName} || true
@echo "${networkName} started."

start-container: create-docker-network
@echo "Attempting to start build container.."
$(MAKE) -C docker/build-container run sourceRoot=${PWD} network=${networkName}
# As USING_CONTAINER is computed when the make file is initially executed where the container won't have been running we need to
# run these make targets setting USING_CONTAINER to true for these targets to execute properly.
make USING_CONTAINER=true install-poetry install-npm

remove-container:
$(MAKE) -C docker/build-container clear

remove-docker-network:
@echo "Removing docker network ${networkName}..."
@docker network rm ${networkName}
@echo "${networkName} removed."

.PHONY: setup-environment clean-environment sandbox start-container remove-container stop-container bash python create-docker-network
35 changes: 35 additions & 0 deletions docker/build-container/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
FROM python:3.8.18-alpine3.18 as ers-apim-referrals-build-image

# Install general OS dependencies.
RUN apk add --update build-base \
git \
make \
libffi-dev \
openssl-dev \
bash

# Install nodejs and npm
RUN apk add --update nodejs=18.17.1-r0 \
npm=9.6.6-r0

COPY resources/ /usr/local/ers/resources/

WORKDIR /usr/local/ers
RUN pip install -r ./resources/requirements.txt

WORKDIR /usr/local/ers/referrals

# Expose port used by redocly for documentation preview.
EXPOSE 9001

# As the git repository is being added by a bind mount need to add this configuration so that git will trust the repository within the container.
RUN git config --global --add safe.directory /usr/local/ers/referrals

# Expose some environment variables required as part of running sandbox tests. Can be overriden at runtime to point at other deployments.
ENV ENVIRONMENT="local"
ENV SERVICE_BASE_PATH="localhost"

# Just a command to keep the container running indefinitely so it can be used for later builds.
CMD ["sleep", "infinity"]

ENTRYPOINT ["/usr/local/ers/resources/docker-entrypoint.sh"]
56 changes: 56 additions & 0 deletions docker/build-container/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
SHELL=/bin/bash -euo pipefail

containerName := ers-apim-referrals-build
imageName := ers-apim-referrals-build-image

# Add additional docker args as required.
ifdef ${environment}
dockerArgs := ${dockerArgs} -e ENVIRONMENT=${environment}
endif
ifdef ${serviceBasePath}
dockerArgs := ${dockerArgs} -e SERVICE_BASE_PATH=${serviceBasePath}
endif

.PHONY: build
build:
@echo "Building container: ${containerName}"
@docker build . --tag ${imageName} --target ${imageName}

.PHONY: run
run: build
@echo "Starting container. container: ${containerName} sourceRoot: ${sourceRoot}"
# Attempt to kill the container if it is currently running, otherwise continue.
@docker kill ${containerName} || true
# Remove the container locally if it already exists, otherwise continue.
@docker container rm ${containerName} || true
# Start the container, binding the local git repository to support builds and githook functionality.
@docker run -d -v ${sourceRoot}:/usr/local/ers/referrals \
-p 127.0.0.1:9001:9001 \
--network=${network} \
${dockerArgs} --name ${containerName} ${imageName}
@echo "Container up and running."

.PHONY: clear
clear:
@echo "Clearing down and removing build container. container: ${containerName}"
# Attempt to kill the container if it is currently running, otherwise continue.
@docker kill ${containerName} || true
# Remove the container locally if it exists, otherwise continue.
@docker container rm ${containerName} || true
@echo "Container removed."
@echo "Removing image..."
@docker rmi ${imageName} || true

.PHONY: bash
bash:
@docker exec -it ${containerName} sh

.PHONY: stop
stop:
@echo "Stopping the build container..."
@docker kill ${containerName}
@echo "Container stopped."

.PHONY: python
python:
@docker exec -it ${containerName} sh -c "poetry run python ${command}"
4 changes: 4 additions & 0 deletions docker/build-container/resources/docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh
set -e

exec "$@"
1 change: 1 addition & 0 deletions docker/build-container/resources/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
poetry==1.6.0
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"scripts": {
"lint-oas": "redocly lint specification/e-referrals-service-api.yaml",
"publish": "mkdir -p build && redocly bundle specification/e-referrals-service-api.yaml --dereferenced --remove-unused-components --ext json | poetry run python scripts/set_version.py | poetry run python scripts/populate_placeholders.py > build/e-referrals-service-api.json",
"serve": "redocly preview-docs -p 5000 build/e-referrals-service-api.json",
"serve": "redocly preview-docs -p 9001 -h 0.0.0.0 build/e-referrals-service-api.json",
"check-licenses": "node_modules/.bin/license-checker --failOn GPL --failOn LGPL"
},
"author": "NHS Digital",
Expand Down
25 changes: 17 additions & 8 deletions sandbox/Makefile
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
SHELL=/bin/bash -euo pipefail

containerName := e-referrals-service-api-sandbox
imageName := e-referrals-service-api-sandbox

.PHONY: install lint build run clean

install:
npm install
@npm install

lint:
npm run lint-js
@npm run lint-js

build:
docker build -t e-referrals-service-api-sandbox .
@docker build -t ${imageName} .

run:
docker run -p 9000:9000 e-referrals-service-api-sandbox:latest

# Attempt to kill the container if it is currently running, otherwise continue.
@docker kill ${containerName} || true
# Remove the container locally if it already exists, otherwise continue.
@docker container rm ${containerName} || true
@docker run -d --network=${network} -p 9000:9000 --name ${containerName} ${imageName}
clean:
docker stop $$(docker ps -a | awk '$$2 ~ /e-referrals-service-api-sandbox/ {print $$1}') || /bin/true
docker rm $$(docker ps -a | awk '$$2 ~ /e-referrals-service-api-sandbox/ {print $$1}') || /bin/true
docker rmi e-referrals-service-api-sandbox || /bin/true
# Attempt to kill the container if it is currently running, otherwise continue.
@docker kill ${containerName} || true
# Remove the container locally if it already exists, otherwise continue.
@docker container rm ${containerName} || true
# Remove the image if it exists, otherwise continue.
@docker rmi ${imageName} || true
16 changes: 10 additions & 6 deletions sandbox/src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@ const process = require('process')
const routes = require('./routes')

const addCommonHeaders = function (request, response) {
if (response.headers) {
if (request.headers["x-correlation-id"]) {
response.headers["X-Correlation-ID"] = request.headers["x-correlation-id"]
}
response.headers["X-Request-ID"] = '58621d65-d5ad-4c3a-959f-0438e355990e-1'
response.headers["Strict-Transport-Security"] = 'max-age=864000; includeSubDomains'
if (!response.headers)
{
response.headers = {}
}

if (request.headers["x-correlation-id"]) {
response.headers["X-Correlation-ID"] = request.headers["x-correlation-id"]
}

response.headers["X-Request-ID"] = '58621d65-d5ad-4c3a-959f-0438e355990e-1'
response.headers["Strict-Transport-Security"] = 'max-age=864000; includeSubDomains'
}

const preResponse = function (request, h) {
Expand Down
24 changes: 24 additions & 0 deletions scripts/format_changes.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/bin/sh
set -e

# select commmitted python and xml files (not deleted)
pythonFilesToFormat="$(git --no-pager diff --name-status --no-color --cached | awk '$1 ~ /^R[0-9]+$/ && $3 ~ /\.py/ {print $3; next}; $1 != "D" && $2 ~ /\.py/ {print $2}')"
xmlFilesToFormat="$(git --no-pager diff --name-status --no-color --cached | awk '$1 ~ /^R[0-9]+$/ && $3 ~ /\.xml/ {print $3; next}; $1 != "D" && $2 ~ /\.xml/ {print $2}')"

echo "Python files to format:"
echo "$pythonFilesToFormat"
for sourceFilePath in $pythonFilesToFormat
do
poetry run black "$(pwd)/$sourceFilePath"
git add $sourceFilePath
done

echo "XML files to format:"
echo "$xmlFilesToFormat"
for sourceFilePath in $xmlFilesToFormat
do
poetry run xmlformat --indent 4 --eof-newline --overwrite --selfclose --infile "$(pwd)/$sourceFilePath"
git add $sourceFilePath
done

printf "\n"
38 changes: 11 additions & 27 deletions scripts/pre-commit
Original file line number Diff line number Diff line change
@@ -1,27 +1,11 @@
#!/bin/sh
set -e

# select commmitted python and xml files (not deleted)
pythonFilesToFormat="$(git --no-pager diff --name-status --no-color --cached | awk '$1 ~ /^R[0-9]+$/ && $3 ~ /\.py/ {print $3; next}; $1 != "D" && $2 ~ /\.py/ {print $2}')"
xmlFilesToFormat="$(git --no-pager diff --name-status --no-color --cached | awk '$1 ~ /^R[0-9]+$/ && $3 ~ /\.xml/ {print $3; next}; $1 != "D" && $2 ~ /\.xml/ {print $2}')"

echo "Python files to format:"
echo "$pythonFilesToFormat"
for sourceFilePath in $pythonFilesToFormat
do
poetry run black "$(pwd)/$sourceFilePath"
git add $sourceFilePath
done

echo "XML files to format:"
echo "$xmlFilesToFormat"
for sourceFilePath in $xmlFilesToFormat
do
poetry run xmlformat --indent 4 --eof-newline --overwrite --selfclose --infile "$(pwd)/$sourceFilePath"
git add $sourceFilePath
done

printf "\n"

# run the linters
make lint
# If the build container isn't running attempt to start it.
if [ "$(docker container inspect -f '{{.State.Running}}' ers-apim-referrals-build)" != "true" ]; then
echo "Build container is not currently running, attempting to start it..."
make INTERACTIVE_SHELL=false start-container
echo "Build container started."
fi

# Run the formatters.
make INTERACTIVE_SHELL=false format-changes
# Run the linters.
make INTERACTIVE_SHELL=false lint
Loading