Skip to content

CI/CD deploy

CI/CD deploy #23

Workflow file for this run

# Deploys a given tag to a given environment and tags for semantic versioning
# creates semantic release
name: "CI/CD deploy"
concurrency:
group: terraform-deploy-${{ github.event.inputs.environment }}
cancel-in-progress: false
on:
workflow_dispatch:
inputs:
tag:
description: "This is the tag that is going to be deployed"
required: true
default: "latest"
environment:
description: "Target environment (e.g., test, preprod or prod)"
required: true
type: choice
options:
- test
- preprod
- prod
release_type:
description: "Version bump type (patch, minor, major)"
required: false
default: "patch"
type: choice
options:
- patch
- minor
- major
jobs:
metadata:
name: "Set CI/CD metadata"
runs-on: ubuntu-latest
timeout-minutes: 1
outputs:
build_datetime: ${{ steps.variables.outputs.build_datetime }}
build_timestamp: ${{ steps.variables.outputs.build_timestamp }}
build_epoch: ${{ steps.variables.outputs.build_epoch }}
nodejs_version: ${{ steps.variables.outputs.nodejs_version }}
python_version: ${{ steps.variables.outputs.python_version }}
terraform_version: ${{ steps.variables.outputs.terraform_version }}
version: ${{ steps.variables.outputs.version }}
tag: ${{ steps.variables.outputs.tag }}
steps:
- name: "Checkout tag"
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.tag }}
- name: "Set CI/CD variables"
id: variables
run: |
datetime=$(date -u +'%Y-%m-%dT%H:%M:%S%z')
echo "build_datetime=$datetime" >> $GITHUB_OUTPUT
echo "build_timestamp=$(date --date=$datetime -u +'%Y%m%d%H%M%S')" >> $GITHUB_OUTPUT
echo "build_epoch=$(date --date=$datetime -u +'%s')" >> $GITHUB_OUTPUT
echo "nodejs_version=$(grep "^nodejs" .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT
echo "python_version=$(grep "^nodejs" .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT
echo "terraform_version=$(grep "^terraform" .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT
# TODO: Get the version, but it may not be the .version file as this should come from the CI/CD Pull Request Workflow
echo "version=$(head -n 1 .version 2> /dev/null || echo unknown)" >> $GITHUB_OUTPUT
echo "tag=${{ github.event.inputs.tag }}" >> $GITHUB_OUTPUT
- name: "List variables"
run: |
export BUILD_DATETIME="${{ steps.variables.outputs.build_datetime }}"
export BUILD_TIMESTAMP="${{ steps.variables.outputs.build_timestamp }}"
export BUILD_EPOCH="${{ steps.variables.outputs.build_epoch }}"
export NODEJS_VERSION="${{ steps.variables.outputs.nodejs_version }}"
export PYTHON_VERSION="${{ steps.variables.outputs.python_version }}"
export TERRAFORM_VERSION="${{ steps.variables.outputs.terraform_version }}"
export VERSION="${{ steps.variables.outputs.version }}"
export TAG="${{ steps.variables.outputs.tag }}"
make list-variables
deploy:
name: "Deploy to an environment"
runs-on: ubuntu-latest
needs: [metadata]
environment: ${{ inputs.environment }}
timeout-minutes: 10
permissions:
id-token: write
contents: write
steps:
- name: "Setup Terraform"
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ needs.metadata.outputs.terraform_version }}
- name: "Set up Python"
uses: actions/setup-python@v5
with:
python-version: "3.13"
- name: "Checkout Repository"
uses: actions/checkout@v4
- name: "Build lambda artefact"
run: |
make dependencies install-python
make build
- name: "Upload lambda artefact"
uses: actions/upload-artifact@v4
with:
name: lambda
path: dist/lambda.zip
- name: "Download Built Lambdas"
uses: actions/download-artifact@v4
with:
name: lambda
path: ./build
- name: "Configure AWS Credentials"
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/service-roles/github-actions-api-deployment-role
aws-region: eu-west-2
- name: "Terraform Apply"
env:
ENVIRONMENT: ${{ inputs.environment }}
WORKSPACE: "default"
TF_VAR_API_CA_CERT: ${{ secrets.API_CA_CERT }}
TF_VAR_API_CLIENT_CERT: ${{ secrets.API_CLIENT_CERT }}
TF_VAR_API_PRIVATE_KEY_CERT: ${{ secrets.API_PRIVATE_KEY_CERT }}
# just planning for now for safety and until review
run: |
mkdir -p ./build
echo "Running: make terraform env=$ENVIRONMENT workspace=$WORKSPACE stack=networking tf-command=apply"
make terraform env=$ENVIRONMENT stack=networking tf-command=apply workspace=$WORKSPACE
echo "Running: make terraform env=$ENVIRONMENT workspace=$WORKSPACE stack=api-layer tf-command=apply"
make terraform env=$ENVIRONMENT stack=api-layer tf-command=apply workspace=$WORKSPACE
working-directory: ./infrastructure
- name: "Tag the deployment using incremental semantic versioning"
id: next_tag
run: |
# Fetch all tags and sort them semantically
git fetch --tags
latest_tag=$(git tag --list 'v*' | sort -V | tail -n 1)
echo "Latest tag: $latest_tag"
if [[ -z "$latest_tag" ]]; then
next_tag="v0.1.0"
else
# Extract the version numbers
IFS='.' read -r major minor patch <<< "${latest_tag#v}"
case "${{ github.event.inputs.release_type }}" in
major)
major=$((major + 1))
minor=0
patch=0
;;
minor)
minor=$((minor + 1))
patch=0
;;
patch|*)
patch=$((patch + 1))
;;
esac
next_tag="v${major}.${minor}.${patch}"
fi
echo "Next tag: $next_tag"
echo "tag=$next_tag" >> $GITHUB_OUTPUT
- name: "Create GitHub Release"
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ steps.next_tag.outputs.tag }}
release_name: Release ${{ steps.next_tag.outputs.tag }}
body: |
Auto-release created during deployment.
draft: false
prerelease: ${{ inputs.environment == 'preprod' }}
# TODO: complete notify step
# success:
# name: "Success notification"
# runs-on: ubuntu-latest
# needs: [deploy]
# steps:
# - name: "Check prerequisites for notification"
# id: check
# run: echo "secret_exist=${{ secrets.TEAMS_NOTIFICATION_WEBHOOK_URL != '' }}" >> $GITHUB_OUTPUT
# - name: "Notify on deployment to an environment"
# if: steps.check.outputs.secret_exist == 'true'
# uses: nhs-england-tools/notify-msteams-action@v0.0.4
# with:
# github-token: ${{ secrets.GITHUB_TOKEN }}
# teams-webhook-url: ${{ secrets.TEAMS_NOTIFICATION_WEBHOOK_URL }}
# message-title: "Notification title"
# message-text: "This is a notification body"
# link: ${{ github.event.pull_request.html_url }}