EXIP deployment for UK-Export-Finance/exip #262
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This GHA is responsible for EXIP deployment. | |
# Deployment is initiated using `az cli` bash script. | |
# | |
# Standard Azure naming convention has been followed: | |
# https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-naming | |
# | |
# | |
# Following Azure services are consumed: | |
# 1. Azure resource group - https://learn.microsoft.com/en-us/cli/azure/group?view=azure-cli-latest#az-group-create | |
# 2. Azure container registry - https://learn.microsoft.com/en-us/cli/azure/acr?view=azure-cli-latest#az-acr-create | |
# 3. Azure WebApp - https://learn.microsoft.com/en-us/azure/app-service/overview | |
# | |
# | |
# Execution | |
# ********* | |
# GHA is only invoked when following conditions are satisfied: | |
# 1. Push to the `dev`, `staging` and `production` branches only. | |
# 2. Any modifications to atleast one of the `paths` targets. | |
name: Deployment 🚀 | |
run-name: EXIP deployment for ${{ github.repository }} | |
on: | |
push: | |
branches: | |
- dev | |
- staging | |
- production | |
paths: | |
- "src/**" | |
- "database/**" | |
- ".github/workflows/deployment.yml" | |
env: | |
PRODUCT: exip | |
ENVIRONMENT: ${{ github.ref_name }} | |
TIMEZONE: "Europe/London" | |
# Base artifact | |
FROM: latest | |
jobs: | |
setup: | |
name: Setup 🔧 | |
runs-on: [self-hosted, EXIP, deployment] | |
outputs: | |
product: ${{ env.PRODUCT }} | |
environment: ${{ env.ENVIRONMENT }} | |
timezone: ${{ env.TIMEZONE }} | |
steps: | |
- name: Environment 🧪 | |
run: echo "Environment set to ${{ env.ENVIRONMENT }}" | |
- name: Timezone 🌐 | |
run: echo "Timezone set to ${{ env.TIMEZONE }}" | |
db: | |
name: Database 💾 | |
needs: setup | |
environment: ${{ needs.setup.outputs.environment }} | |
env: | |
ENVIRONMENT: ${{ needs.setup.outputs.environment }} | |
runs-on: [self-hosted, EXIP, deployment] | |
steps: | |
- name: Repository 🗃️ | |
uses: actions/checkout@v4 | |
- name: Azure 🔐 | |
uses: azure/login@v2 | |
with: | |
creds: ${{ secrets.AZURE_CREDENTIALS }} | |
- name: Defaults ✨ | |
uses: azure/cli@v2 | |
with: | |
inlineScript: | | |
# Basic | |
az configure --defaults location=${{ vars.REGION }} | |
az configure --defaults group=rg-${{ env.PRODUCT }}-${{ github.ref_name }}-${{ vars.VERSION }} | |
- name: Extension ➕ | |
if: ${{ '1' == vars.DATABASE }} | |
uses: azure/cli@v2 | |
with: | |
inlineScript: | | |
az config set extension.use_dynamic_install=yes_without_prompt | |
az extension add --name rdbms-connect | |
- name: Import ⬇ | |
if: ${{ '1' == vars.DATABASE }} | |
uses: azure/cli@v2 | |
with: | |
inlineScript: | | |
az mysql flexible-server execute \ | |
--name sqldb-${{ env.PRODUCT }}-${{ github.ref_name }}-${{ vars.VERSION }} \ | |
--admin-user ${{ secrets.MYSQL_USER }} \ | |
--admin-password ${{ secrets.MYSQL_PASSWORD }} \ | |
--database-name ${{ env.PRODUCT }} \ | |
--file-path "database/exip.sql" | |
api: | |
name: API 📦️ | |
needs: setup | |
environment: ${{ needs.setup.outputs.environment }} | |
env: | |
NAME: api | |
ENVIRONMENT: ${{ needs.setup.outputs.environment }} | |
runs-on: [self-hosted, EXIP, deployment] | |
steps: | |
- name: Repository 🗃️ | |
uses: actions/checkout@v4 | |
- name: Azure 🔐 | |
uses: azure/login@v2 | |
with: | |
creds: ${{ secrets.AZURE_CREDENTIALS }} | |
- name: Defaults ✨ | |
uses: azure/cli@v2 | |
with: | |
inlineScript: | | |
# Basic | |
az configure --defaults location=${{ vars.REGION }} | |
az configure --defaults group=rg-${{ env.PRODUCT }}-${{ github.ref_name }}-${{ vars.VERSION }} | |
- name: CLI 📝 | |
run: | | |
echo ACR=$(az acr show -n $(az resource list --resource-type 'Microsoft.ContainerRegistry/registries' --query '[0].name' -o tsv) --query loginServer -o tsv) >> $GITHUB_ENV | |
echo ACR_USER=$(az acr show -n $(az resource list --resource-type 'Microsoft.ContainerRegistry/registries' --query '[0].name' -o tsv) --query name -o tsv) >> $GITHUB_ENV | |
echo WEBAPP=$(az resource list --resource-type 'Microsoft.Web/sites' --query '[?contains(name, `${{ env.NAME }}`)].name' -o tsv) >> $GITHUB_ENV | |
- name: ACR 🔐 | |
uses: azure/docker-login@v2 | |
with: | |
login-server: ${{ env.ACR }} | |
username: ${{ env.ACR_USER }} | |
password: ${{ secrets.ACR_PASSWORD }} | |
- name: Artifacts 🗃️ | |
working-directory: src/${{ env.NAME }} | |
run: | | |
# Build images | |
docker build . \ | |
-t ${{ env.ACR }}/${{ env.NAME }}:${{ github.sha }} \ | |
-t ${{ env.ACR }}/${{ env.NAME }}:${{ env.FROM }} \ | |
--build-arg NODE_ENV=${{ vars.NODE_ENV }} \ | |
--build-arg PORT=${{ vars.API_PORT }} \ | |
--build-arg SESSION_SECRET=${{ secrets.SESSION_SECRET }} \ | |
--build-arg GOV_NOTIFY_API_KEY=${{ secrets.GOV_NOTIFY_API_KEY }} | |
# Push images | |
docker push ${{ env.ACR }}/${{ env.NAME }}:${{ github.sha }} | |
docker push ${{ env.ACR }}/${{ env.NAME }}:${{ env.FROM }} | |
- name: Environment 🧱 | |
uses: azure/cli@v2 | |
with: | |
inlineScript: | | |
az webapp config appsettings set \ | |
--name app-${{ env.PRODUCT }}-${{ env.NAME }}-${{ github.ref_name }}-${{ vars.VERSION }} \ | |
--settings \ | |
TZ='${{ vars.TIMEZONE }}' \ | |
NODE_ENV='${{ vars.NODE_ENV }}' \ | |
PORT='${{ vars.API_PORT }}' \ | |
WEBSITES_PORT='${{ vars.API_PORT }}' \ | |
APIM_MDM_URL='${{ secrets.APIM_MDM_URL }}' \ | |
APIM_MDM_KEY='${{ secrets.APIM_MDM_KEY }}' \ | |
APIM_MDM_VALUE='${{ secrets.APIM_MDM_VALUE }}' \ | |
API_KEY='${{ secrets.API_KEY }}' \ | |
SESSION_SECRET='${{ secrets.SESSION_SECRET }}' \ | |
GOV_NOTIFY_API_KEY='${{ secrets.GOV_NOTIFY_API_KEY }}' \ | |
COMPANIES_HOUSE_API_URL='${{ secrets.COMPANIES_HOUSE_API_URL }}' \ | |
COMPANIES_HOUSE_API_KEY='${{ secrets.COMPANIES_HOUSE_API_KEY }}' \ | |
JWT_SIGNING_KEY='${{ secrets.JWT_SIGNING_KEY }}' \ | |
UNDERWRITING_TEAM_EMAIL='${{ secrets.UNDERWRITING_TEAM_EMAIL }}' \ | |
FEEDBACK_EMAIL_RECIPIENT='${{ secrets.FEEDBACK_EMAIL_RECIPIENT }}' \ | |
EXCELJS_PROTECTION_PASSWORD='${{ secrets.EXCELJS_PROTECTION_PASSWORD }}' | |
- name: Slot 🔀 | |
uses: azure/cli@v2 | |
with: | |
inlineScript: | | |
# Create new temporary slot | |
az webapp deployment slot create \ | |
--slot ${{ github.sha }} \ | |
--name ${{ env.WEBAPP }} \ | |
--configuration-source ${{ env.WEBAPP }} \ | |
--deployment-container-image-name ${{ env.ACR }}/${{ env.NAME }}:${{ env.FROM }} | |
# Swap slot | |
az webapp deployment slot swap \ | |
--slot ${{ github.sha }} \ | |
--name ${{ env.WEBAPP }} \ | |
--action swap | |
# Delete temporary slot | |
az webapp deployment slot delete \ | |
--slot ${{ github.sha }} \ | |
--name ${{ env.WEBAPP }} | |
- name: Reboot ♻️ | |
uses: azure/cli@v2 | |
with: | |
inlineScript: | | |
az webapp restart \ | |
--name ${{ env.WEBAPP }} | |
ui: | |
name: UI 📦️ | |
needs: setup | |
environment: ${{ needs.setup.outputs.environment }} | |
env: | |
NAME: ui | |
ENVIRONMENT: ${{ needs.setup.outputs.environment }} | |
runs-on: [self-hosted, EXIP, deployment] | |
steps: | |
- name: Repository 🗃️ | |
uses: actions/checkout@v4 | |
- name: Azure 🔐 | |
uses: azure/login@v2 | |
with: | |
creds: ${{ secrets.AZURE_CREDENTIALS }} | |
- name: Defaults ✨ | |
uses: azure/cli@v2 | |
with: | |
inlineScript: | | |
# Basic | |
az configure --defaults location=${{ vars.REGION }} | |
az configure --defaults group=rg-${{ env.PRODUCT }}-${{ github.ref_name }}-${{ vars.VERSION }} | |
- name: CLI 📝 | |
run: | | |
echo ACR=$(az acr show -n $(az resource list --resource-type 'Microsoft.ContainerRegistry/registries' --query '[0].name' -o tsv) --query loginServer -o tsv) >> $GITHUB_ENV | |
echo ACR_USER=$(az acr show -n $(az resource list --resource-type 'Microsoft.ContainerRegistry/registries' --query '[0].name' -o tsv) --query name -o tsv) >> $GITHUB_ENV | |
echo WEBAPP=$(az resource list --resource-type 'Microsoft.Web/sites' --query '[?contains(name, `${{ env.NAME }}`)].name' -o tsv) >> $GITHUB_ENV | |
- name: ACR 🔐 | |
uses: azure/docker-login@v2 | |
with: | |
login-server: ${{ env.ACR }} | |
username: ${{ env.ACR_USER }} | |
password: ${{ secrets.ACR_PASSWORD }} | |
- name: Artifacts 🗃️ | |
working-directory: src/${{ env.NAME }} | |
run: | | |
# Build images | |
docker build . \ | |
-t ${{ env.ACR }}/${{ env.NAME }}:${{ github.sha }} \ | |
-t ${{ env.ACR }}/${{ env.NAME }}:${{ env.FROM }} \ | |
--build-arg NODE_ENV=${{ vars.NODE_ENV }} \ | |
--build-arg PORT=${{ vars.UI_PORT }} | |
# Push images | |
docker push ${{ env.ACR }}/${{ env.NAME }}:${{ github.sha }} | |
docker push ${{ env.ACR }}/${{ env.NAME }}:${{ env.FROM }} | |
- name: Environment 🧱 | |
uses: azure/cli@v2 | |
with: | |
inlineScript: | | |
az webapp config appsettings set \ | |
--name app-${{ env.PRODUCT }}-${{ env.NAME }}-${{ github.ref_name }}-${{ vars.VERSION }} \ | |
--settings \ | |
TZ='${{ vars.TIMEZONE }}' \ | |
NODE_ENV='${{ vars.NODE_ENV }}' \ | |
PORT='${{ vars.UI_PORT }}' \ | |
WEBSITES_PORT='${{ vars.UI_PORT }}' \ | |
SESSION_SECRET='${{ secrets.SESSION_SECRET }}' \ | |
GOOGLE_ANALYTICS_ID='${{ secrets.GOOGLE_ANALYTICS_ID }}' \ | |
GOOGLE_TAG_MANAGER_ID='${{ secrets.GOOGLE_TAG_MANAGER_ID }}' \ | |
APIM_MDM_URL='${{ secrets.APIM_MDM_URL }}' \ | |
APIM_MDM_KEY='${{ secrets.APIM_MDM_KEY }}' \ | |
APIM_MDM_VALUE='${{ secrets.APIM_MDM_VALUE }}' \ | |
API_KEY='${{ secrets.API_KEY }}' | |
APIM_MDM_VALUE='${{ secrets.APIM_MDM_VALUE }}' \ | |
API_KEY='${{ secrets.API_KEY }}' | |
- name: Slot 🔀 | |
uses: azure/cli@v2 | |
with: | |
inlineScript: | | |
# Create new temporary slot | |
az webapp deployment slot create \ | |
--slot ${{ github.sha }} \ | |
--name ${{ env.WEBAPP }} \ | |
--configuration-source ${{ env.WEBAPP }} \ | |
--deployment-container-image-name ${{ env.ACR }}/${{ env.NAME }}:${{ env.FROM }} | |
# Swap slot | |
az webapp deployment slot swap \ | |
--slot ${{ github.sha }} \ | |
--name ${{ env.WEBAPP }} \ | |
--action swap | |
# Delete temporary slot | |
az webapp deployment slot delete \ | |
--slot ${{ github.sha }} \ | |
--name ${{ env.WEBAPP }} | |
- name: Reboot ♻️ | |
uses: azure/cli@v2 | |
with: | |
inlineScript: | | |
az webapp restart \ | |
--name ${{ env.WEBAPP }} |