Skip to content
Closed
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
218 changes: 147 additions & 71 deletions .github/workflows/integration-env.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,30 @@ name: Integration Environment

on:
pull_request:
branches: [integration]
types: [closed]
branches: [ integration ]
types: [ closed ]
workflow_dispatch:
inputs:
create-release:
description: "Create release"
required: true
default: false
type: boolean

env:
AWS_REGION: eu-west-2
PREVIEW_PREFIX: int-
PYTHON_VERSION: 3.14
LAMBDA_RUNTIME: python3.14
LAMBDA_HANDLER: lambda_handler.handler
MTLS_SECRET_NAME: ${{ vars.PREVIEW_ENV_MTLS_SECRET_NAME }}
MTLS_SECRET_NAME: ${{ vars.INT_MTLS_SECRET_NAME }}
PROXYGEN_KEY_ID: ${{ vars.PREVIEW_ENV_PROXYGEN_KEY_ID }}
PROXYGEN_CLIENT_ID: ${{ vars.PREVIEW_ENV_PROXYGEN_CLIENT_ID }}
PROXYGEN_API_NAME: ${{ vars.PROXYGEN_API_NAME }}
BASE_URL: "https://internal-dev.api.service.nhs.uk/${{ vars.PROXYGEN_API_NAME }}-integration"
BASE_URL: "https://int.api.service.nhs.uk/pathology-laboratory-reporting"
ENV: "remote"
HOST: "internal-dev.api.service.nhs.uk"
HOST: "int.api.service.nhs.uk"
PROXY_ENV: "int"

jobs:
integration-environment:
Expand Down Expand Up @@ -103,7 +110,7 @@ jobs:
echo "int_url=$URL" >> "$GITHUB_OUTPUT"

# ---------- Handle application with int ----------
- name: Create or update preview Lambda with int
- name: Create or update preview Lambda in int
env:
MOCK_URL: ${{ steps.names.outputs.int_url }}
TOKEN_EXPIRY_THRESHOLD: ${{ secrets.APIM_TOKEN_EXPIRY_THRESHOLD }}
Expand All @@ -114,6 +121,9 @@ jobs:
API_MTLS_KEY: ${{ secrets.API_MTLS_KEY }}
APIM_KEY_ID: ${{ secrets.APIM_KEY_ID }}
CLIENT_REQUEST_TIMEOUT: ${{ secrets.CLIENT_REQUEST_TIMEOUT }}
APIM_TOKEN_URL: "https://int.api.service.nhs.uk/oauth2/token"
MNS_EVENT_URL: "https://int.api.service.nhs.uk/multicast-notification-service/events"
PDM_BUNDLE_URL: "https://int.api.service.nhs.uk/patient-data-manager/FHIR/R4/Bundle"
run: |
cd pathology-api/target/
FN="${{ steps.names.outputs.function_name }}"
Expand All @@ -123,7 +133,10 @@ jobs:
API_KEY="${APIM_APIKEY:-/cds/pathology/int/apim/api-key}"
MTLS_CERT="${API_MTLS_CERT:-/cds/pathology/int/mtls/client1-key-public}"
MTLS_KEY="${API_MTLS_KEY:-/cds/pathology/int/mtls/client1-key-secret}"
KEY_ID="${APIM_KEY_ID:-DEV-1}"
KEY_ID="${APIM_KEY_ID:-INT-1}"
APIM_TOKEN_URL="${APIM_TOKEN_URL}"
MNS_EVENT_URL="${MNS_EVENT_URL}"
PDM_BUNDLE_URL="${PDM_BUNDLE_URL}"
CLIENT_TIMEOUT="${CLIENT_REQUEST_TIMEOUT:-10s}"
echo "Deploying preview function: $FN"
wait_for_lambda_ready() {
Expand Down Expand Up @@ -154,9 +167,9 @@ jobs:
APIM_MTLS_CERT_NAME=$MTLS_CERT, \
APIM_MTLS_KEY_NAME=$MTLS_KEY, \
APIM_KEY_ID=$KEY_ID, \
APIM_TOKEN_URL=$MOCK_URL/apim/oauth2/token, \
PDM_BUNDLE_URL=$MOCK_URL/apim/check_auth, \
MNS_EVENT_URL=$MOCK_URL/mns, \
APIM_TOKEN_URL=$APIM_TOKEN_URL, \
PDM_BUNDLE_URL=$PDM_BUNDLE_URL, \
MNS_EVENT_URL=$MNS_EVENT_URL, \
CLIENT_TIMEOUT=$CLIENT_TIMEOUT, \
JWKS_SECRET_NAME=$JWKS_SECRET}" || true
wait_for_lambda_ready
Expand All @@ -177,16 +190,16 @@ jobs:
APIM_KEY_ID=$KEY_ID, \
APIM_MTLS_CERT_NAME=$MTLS_CERT, \
APIM_MTLS_KEY_NAME=$MTLS_KEY, \
APIM_TOKEN_URL=$MOCK_URL/apim/oauth2/token, \
PDM_BUNDLE_URL=$MOCK_URL/apim/check_auth, \
MNS_EVENT_URL=$MOCK_URL/mns, \
APIM_TOKEN_URL=$APIM_TOKEN_URL, \
PDM_BUNDLE_URL=$PDM_BUNDLE_URL, \
MNS_EVENT_URL=$MNS_EVENT_URL, \
CLIENT_TIMEOUT=$CLIENT_TIMEOUT, \
JWKS_SECRET_NAME=$JWKS_SECRET}" \
--publish
wait_for_lambda_ready
fi

- name: Output function name with mock
- name: Output function name for int
run: |
echo "function = ${{ steps.names.outputs.function_name }}"
echo "url = ${{ steps.names.outputs.int_url }}"
Expand Down Expand Up @@ -258,7 +271,7 @@ jobs:
secret-ids: /cds/pathology/int/proxygen/proxygen-key-secret
name-transformation: lowercase

- name: Deploy preview API proxy
- name: Deploy integration API proxy
uses: ./.github/actions/proxy/deploy-proxy
with:
mtls-secret-name: ${{ env.MTLS_SECRET_NAME }}
Expand All @@ -268,6 +281,7 @@ jobs:
proxygen-key-id: ${{ env.PROXYGEN_KEY_ID }}
proxygen-client-id: ${{ env.PROXYGEN_CLIENT_ID }}
proxygen-api-name: ${{ env.PROXYGEN_API_NAME }}
proxygen-environment: ${{ env.PROXY_ENV }}

- name: Retrieve Apigee Token
id: apigee-token
Expand All @@ -293,87 +307,149 @@ jobs:

# ---------- Test suites ----------
- name: "Run unit tests"
continue-on-error: true
uses: ./.github/actions/run-test-suite
with:
test-type: unit
env: local

- name: "Run contract tests"
continue-on-error: true
uses: ./.github/actions/run-test-suite
with:
test-type: contract
apigee-access-token: ${{ steps.apigee-token.outputs.apigee-access-token }}

- name: "Run schema validation tests"
uses: ./.github/actions/run-test-suite
with:
test-type: schema
apigee-access-token: ${{ steps.apigee-token.outputs.apigee-access-token }}
# - name: "Run schema validation tests"
# uses: ./.github/actions/run-test-suite
# with:
# test-type: schema
# apigee-access-token: ${{ steps.apigee-token.outputs.apigee-access-token }}

- name: "Run integration tests"
continue-on-error: true
uses: ./.github/actions/run-test-suite
with:
test-type: integration
apigee-access-token: ${{ steps.apigee-token.outputs.apigee-access-token }}

- name: "Run acceptance tests"
continue-on-error: true
uses: ./.github/actions/run-test-suite
with:
test-type: acceptance
apigee-access-token: ${{ steps.apigee-token.outputs.apigee-access-token }}

# ---------- Coverage & reporting ----------
- name: "Download all test coverage artefacts"
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
# - name: "Download all test coverage artefacts"
# uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
# with:
# path: pathology-api/test-artefacts/
# merge-multiple: false
# - name: "Download mock test coverage artefacts"
# uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
# with:
# path: mocks/test-artefacts/
# merge-multiple: false
# - name: "Merge coverage data"
# run: make test-coverage
# - name: "Rename coverage XML with unique name"
# run: |
# cd pathology-api/test-artefacts
# mv coverage-merged.xml "${{ steps.create-name.outputs.artefact-name }}.xml"
# cd ../..
# cd mocks/test-artefacts
# mv coverage-merged.xml ${{ steps.create-name.outputs.artefact-name }}-mocks.xml
# - name: "Upload combined coverage report"
# uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
# with:
# name: ${{ steps.create-name.outputs.artefact-name }}
# path: pathology-api/test-artefacts
# retention-days: 30
# - name: "Upload mocks coverage report"
# uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
# with:
# name: ${{ steps.create-name.outputs.artefact-name }}-mocks
# path: mocks/test-artefacts
# retention-days: 30
# - name: "Download merged coverage report"
# uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
# with:
# name: ${{ steps.create-name.outputs.artefact-name }}
# path: coverage-reports/
# - name: "Download mock coverage report"
# uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
# with:
# name: ${{ steps.create-name.outputs.artefact-name }}-mocks
# path: coverage-reports/
# - name: "SonarCloud Scan"
# uses: SonarSource/sonarqube-scan-action@299e4b793aaa83bf2aba7c9c14bedbb485688ec4 #7.1.0
# env:
# SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
# with:
# args: >
# -Dsonar.organization=${{ vars.SONAR_ORGANISATION_KEY }}
# -Dsonar.projectKey=${{ vars.SONAR_PROJECT_KEY }}
# -Dsonar.python.coverage.reportPaths=coverage-reports/${{
# steps.create-name.outputs.artefact-name }}.xml,coverage-reports/${{
# steps.create-name.outputs.artefact-name }}-mocks.xml
# ---------- Perform vuln scan and notify ----------
# - name: Filesystem vuln scan
# - name: SBOM generation

release-build:
name: "Build release on GIT"
runs-on: ubuntu-latest
needs: integration-environment
if: >
(github.event_name == 'pull_request' && github.event.pull_request.merged) || (github.event_name == 'workflow_dispatch' && inputs.create-release)

steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
path: pathology-api/test-artefacts/
merge-multiple: false
- name: "Download mock test coverage artefacts"
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
fetch-depth: 0
ref: integration

- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
with:
path: mocks/test-artefacts/
merge-multiple: false
- name: "Merge coverage data"
run: make test-coverage
- name: "Rename coverage XML with unique name"
python-version: "${{ env.PYTHON_VERSION }}"

- name: Install poetry
run: |
cd pathology-api/test-artefacts
mv coverage-merged.xml "${{ steps.create-name.outputs.artefact-name }}.xml"
cd ../..
cd mocks/test-artefacts
mv coverage-merged.xml ${{ steps.create-name.outputs.artefact-name }}-mocks.xml
- name: "Upload combined coverage report"
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: ${{ steps.create-name.outputs.artefact-name }}
path: pathology-api/test-artefacts
retention-days: 30
- name: "Upload mocks coverage report"
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: ${{ steps.create-name.outputs.artefact-name }}-mocks
path: mocks/test-artefacts
retention-days: 30
- name: "Download merged coverage report"
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ steps.create-name.outputs.artefact-name }}
path: coverage-reports/
- name: "Download mock coverage report"
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ steps.create-name.outputs.artefact-name }}-mocks
path: coverage-reports/
- name: "SonarCloud Scan"
uses: SonarSource/sonarqube-scan-action@299e4b793aaa83bf2aba7c9c14bedbb485688ec4 #7.1.0
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
args: >
-Dsonar.organization=${{ vars.SONAR_ORGANISATION_KEY }}
-Dsonar.projectKey=${{ vars.SONAR_PROJECT_KEY }}
-Dsonar.python.coverage.reportPaths=coverage-reports/${{ steps.create-name.outputs.artefact-name }}.xml,coverage-reports/${{ steps.create-name.outputs.artefact-name }}-mocks.xml
which poetry || true
ls -l pathology-api/target/ || true
pipx install poetry

# ---------- Perform vuln scan and notify ----------
# - name: Filesystem vuln scan
# - name: SBOM generation
- name: Build tag
id: version
run: |
BASE_VERSION="$(poetry version -s)"
TAG="v${BASE_VERSION}.${GITHUB_RUN_NUMBER}"
echo "base_version=$BASE_VERSION" >> "$GITHUB_OUTPUT"
echo "tag=$TAG" >> "$GITHUB_OUTPUT"

- name: Create git tag
run: |
if git rev-parse "${{ steps.version.outputs.tag }}" >/dev/null 2>&1; then
echo "Tag ${{ steps.version.outputs.tag }} already exists locally, skipping tag creation"
exit 0
fi

if git ls-remote --exit-code --tags origin "${{ steps.version.outputs.tag }}" >/dev/null 2>&1; then
echo "Tag ${{ steps.version.outputs.tag }} already exists on remote, skipping tag creation"
exit 0
else
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag -a "${{ steps.version.outputs.tag }}" -m "Release ${{ steps.version.outputs.tag }}"
git push origin "${{ steps.version.outputs.tag }}"
fi

- name: Create GitHub release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create "${{ steps.version.outputs.tag }}" \
--title "Release ${{ steps.version.outputs.tag }}" \
--generate-notes
Loading