π Deploying to release-2.3.1 #672
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
# Overview | |
# ******** | |
# This workflow automates the deployment of web apps and Azure Functions to Azure upon successful completion of a QAT workflow. | |
# Key Stages: | |
# | |
# 1. Setup | |
# ******** | |
# Sets environment variables for product, environment, and timezone. | |
# Outputs these variables for use in subsequent jobs. | |
# | |
# 2. SQL Migrations | |
# ***************** | |
# Runs new SQL migrations on the environment SQL database | |
# | |
# 3. WebApp | |
# ********* | |
# Runs sequentially for each web app defined in the matrix.webapp list. | |
# Sets the Dockerfile location based on the microservice (using the portal directory for portal-ui and the app's name for others). | |
# Builds and pushes Docker images using the root workspace as the context and the Dockerfile location specified for the microservice. | |
# Creates a temporary deployment slot using the FROM tag (latest by default). | |
# Swaps the slot to make the new image live. | |
# Cleans up the temporary slot. | |
# | |
# 4. Functions | |
# ************ | |
# Runs sequentially for each function defined in the matrix.functions list. | |
# Builds and pushes Docker images for each function. | |
# Creates a temporary deployment slot using the FROM tag. | |
# Swaps the slot to make the new image live. | |
# Cleans up the temporary slot. | |
# | |
# Key Points | |
# ********** | |
# Triggers on Completed QAT Workflow: The workflow only runs if the preceding QAT workflow completes successfully. | |
# Environment-Specific: Uses environment variables to tailor deployments for different environments (dev, feature, staging, prod). | |
# Matrix Strategies: Employs matrices to iterate through lists of web apps and functions for sequential deployment. | |
# Concurrency Control: Uses concurrency groups to prevent multiple deployments of the same web app or function from running concurrently. | |
# Fail-Fast Disabled: Allows all matrix jobs to complete even if some fail. | |
# Temporary Slots: Utilizes deployment slots to minimize downtime during deployments. | |
# Cleanup: Always removes temporary slots to maintain resource hygiene. | |
# | |
name: Deployment | |
run-name: π Deploying to ${{ github.event.workflow_run.head_branch }} | |
on: | |
workflow_run: | |
workflows: ['QAT'] | |
types: | |
- completed | |
branches: | |
- dev | |
- feature | |
- staging | |
- prod | |
- release-* | |
- '!release-please*' | |
env: | |
PRODUCT: dtfs | |
ENVIRONMENT: ${{ github.event.workflow_run.head_branch }} | |
TIMEZONE: ${{ vars.TIMEZONE }} | |
# Base artifact | |
FROM: latest | |
jobs: | |
setup: | |
name: Setup π§ | |
if: ${{ github.event.workflow_run.conclusion == 'success' }} | |
runs-on: [self-hosted, linux, deployment] | |
outputs: | |
product: ${{ env.PRODUCT }} | |
environment: ${{ steps.environment.outputs.environment }} | |
timezone: ${{ env.TIMEZONE }} | |
steps: | |
- name: Environment π§ͺ | |
id: environment | |
run: | | |
if [[ "${{ env.ENVIRONMENT }}" == *release* ]]; then | |
echo "environment=staging" >> "$GITHUB_OUTPUT" | |
else | |
echo "environment=${{ github.event.workflow_run.head_branch }}" >> "$GITHUB_OUTPUT" | |
fi | |
- name: Timezone π | |
run: echo "Timezone set to ${{ env.TIMEZONE }}" | |
database: | |
name: MSSQL ποΈ | |
if: ${{ github.event.workflow_run.conclusion == 'success' }} | |
needs: [setup] | |
environment: ${{ needs.setup.outputs.environment }} | |
runs-on: [self-hosted, DTFS, deployment] | |
env: | |
ENVIRONMENT: ${{ needs.setup.outputs.environment }} | |
SQL_DB_HOST: ${{ secrets.SQL_DB_HOST }} | |
SQL_DB_PORT: ${{ secrets.SQL_DB_PORT }} | |
SQL_DB_USERNAME: ${{ secrets.SQL_DB_USERNAME }} | |
SQL_DB_PASSWORD: ${{ secrets.SQL_DB_PASSWORD }} | |
SQL_DB_NAME: ${{ secrets.SQL_DB_NAME }} | |
SQL_DB_LOGGING_ENABLED: ${{ vars.SQL_DB_LOGGING_ENABLED }} | |
steps: | |
- name: Repository | |
uses: actions/checkout@v4 | |
- name: Node | |
uses: actions/setup-node@v4 | |
with: | |
node-version: ${{ vars.NODE_VERSION }} | |
- name: Dependencies | |
working-directory: ./libs/common | |
run: npm ci | |
- name: Migrate | |
working-directory: ./libs/common | |
run: npm run db:migrate | |
webapp: | |
name: WebApp π | |
if: ${{ github.event.workflow_run.conclusion == 'success' }} | |
needs: [setup] | |
environment: ${{ needs.setup.outputs.environment }} | |
runs-on: [self-hosted, DTFS, deployment] | |
env: | |
ENVIRONMENT: ${{ needs.setup.outputs.environment }} | |
strategy: | |
max-parallel: 1 | |
# Do not cancel in-progress jobs upon failure | |
fail-fast: false | |
# Single dimension matrix | |
matrix: | |
webapp: ['portal-ui', 'gef-ui', 'trade-finance-manager-ui', 'portal-api', 'dtfs-central-api', 'external-api', 'trade-finance-manager-api'] | |
concurrency: | |
group: deployment-webapp-${{ github.workflow }}-${{ github.workflow_ref }}-${{ matrix.webapp }} | |
cancel-in-progress: true | |
steps: | |
- name: Repository ποΈ | |
uses: actions/checkout@v4 | |
with: | |
ref: ${{ github.event.workflow_run.head_branch }} | |
- name: Defaults β¨ | |
uses: azure/cli@v2 | |
with: | |
inlineScript: | | |
# Basic | |
az configure --defaults location=${{ vars.REGION }} | |
az configure --defaults group=${{ secrets.RESOURCE_GROUP }} | |
- name: Azure π | |
uses: azure/login@v2 | |
with: | |
creds: ${{ secrets.AZURE_CREDENTIALS }} | |
- 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, `${{ matrix.webapp }}`)].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: Dockerfile π³ | |
if: ${{ 'portal-ui' == matrix.webapp }} | |
run: echo "DOCKERFILE=portal/Dockerfile" >> $GITHUB_ENV | |
- name: Dockerfile π³ | |
if: ${{ 'portal-ui' != matrix.webapp }} | |
run: echo "DOCKERFILE=${{ matrix.webapp }}/Dockerfile" >> $GITHUB_ENV | |
- name: Artifacts ποΈ | |
working-directory: . | |
run: | | |
# Build images | |
docker build -f ./${{ env.DOCKERFILE }} . \ | |
-t ${{ env.ACR }}/${{ matrix.webapp }}:${{ github.sha }} \ | |
-t ${{ env.ACR }}/${{ matrix.webapp }}:${{ env.FROM }} \ | |
--build-arg GITHUB_SHA=${{ github.sha }} | |
# Push images | |
docker push ${{ env.ACR }}/${{ matrix.webapp }}:${{ github.sha }} | |
docker push ${{ env.ACR }}/${{ matrix.webapp }}:${{ env.FROM }} | |
- 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 }}/${{ matrix.webapp }}:${{ env.FROM }} \ | |
--docker-registry-server-user ${{ env.ACR_USER }} \ | |
--docker-registry-server-password ${{ secrets.ACR_PASSWORD }} | |
# Swap slot | |
az webapp deployment slot swap \ | |
--slot ${{ github.sha }} \ | |
--name ${{ env.WEBAPP }} \ | |
--action swap | |
- name: Cleanup π§Ή | |
if: always() | |
uses: azure/cli@v2 | |
with: | |
inlineScript: | | |
# Delete temporary slot | |
az webapp deployment slot delete \ | |
--slot ${{ github.sha }} \ | |
--name ${{ env.WEBAPP }} | |
functions: | |
name: Functions β‘ | |
if: ${{ github.event.workflow_run.conclusion == 'success' }} | |
needs: [setup, webapp] | |
environment: ${{ needs.setup.outputs.environment }} | |
runs-on: [self-hosted, DTFS, deployment] | |
env: | |
ENVIRONMENT: ${{ needs.setup.outputs.environment }} | |
strategy: | |
max-parallel: 1 | |
# Do not cancel in-progress jobs upon failure | |
fail-fast: false | |
# Single dimension matrix | |
matrix: | |
functions: ['acbs-function'] | |
concurrency: | |
group: deployment-functions-${{ github.workflow }}-${{ github.workflow_ref }}-${{ matrix.functions }} | |
cancel-in-progress: true | |
steps: | |
- name: Repository ποΈ | |
uses: actions/checkout@v4 | |
with: | |
ref: ${{ github.event.workflow_run.head_branch }} | |
- name: Defaults β¨ | |
uses: azure/cli@v2 | |
with: | |
inlineScript: | | |
# Basic | |
az configure --defaults location=${{ vars.REGION }} | |
az configure --defaults group=${{ secrets.RESOURCE_GROUP }} | |
- name: Azure π | |
uses: azure/login@v2 | |
with: | |
creds: ${{ secrets.AZURE_CREDENTIALS }} | |
- name: Directory π | |
if: ${{ 'acbs-function' == matrix.functions }} | |
run: echo "NAME=acbs" >> $GITHUB_ENV | |
- 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 FUNCTION=$(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: ./azure-functions/${{ matrix.functions }} | |
run: | | |
# Build images | |
docker build . \ | |
-t ${{ env.ACR }}/${{ matrix.functions }}:${{ github.sha }} \ | |
-t ${{ env.ACR }}/${{ matrix.functions }}:${{ env.FROM }} | |
# Push images | |
docker push ${{ env.ACR }}/${{ matrix.functions }}:${{ github.sha }} | |
docker push ${{ env.ACR }}/${{ matrix.functions }}:${{ env.FROM }} | |
- name: Slot π | |
uses: azure/cli@v2 | |
with: | |
inlineScript: | | |
# Create new temporary slot | |
az functionapp deployment slot create \ | |
--slot ${{ github.sha }} \ | |
--name ${{ env.FUNCTION }} \ | |
--configuration-source ${{ env.FUNCTION }} \ | |
--deployment-container-image-name ${{ env.ACR }}/${{ matrix.functions }}:${{ env.FROM }} \ | |
--docker-registry-server-user ${{ env.ACR_USER }} \ | |
--docker-registry-server-password ${{ secrets.ACR_PASSWORD }} | |
# Swap slot | |
az functionapp deployment slot swap \ | |
--slot ${{ github.sha }} \ | |
--name ${{ env.FUNCTION }} \ | |
--action swap | |
- name: Cleanup π§Ή | |
if: always() | |
uses: azure/cli@v2 | |
with: | |
inlineScript: | | |
# Delete temporary slot | |
az functionapp deployment slot delete \ | |
--slot ${{ github.sha }} \ | |
--name ${{ env.FUNCTION }} |