Skip to content

DevOps Pipelines

Weixian edited this page May 25, 2026 · 7 revisions

GitHub Actions Pipeline


  • Proposed 3 GitHub Action workflows to support continuous delivery with our branching strategy.
Azure / GitHub Environment Git Branch Workflow Name Approval Required Description
SIT main MBS - Main Branch to SIT Environment No Continuous integration environment where feature branches are merged and validated through automated build, unit testing, and integration testing before release preparation.
UAT release/1.4 RBUPP - Release Branch - UAT, Pre-production, Production Yes User Acceptance Testing environment used for business validation and sign-off of the scoped release version before promotion to higher environments.
Pre-Production release/1.4 1. RBUPP - Release Branch - UAT, Pre-production, Production

2. Hotfix Branch - Pre-production, Production
Yes Production-like staging environment used for final regression testing, deployment verification, and operational readiness checks before go-live.
Production release/1.4 1. RBUPP - Release Branch - UAT, Pre-production, Production

2. Hotfix Branch - Pre-production, Production
Yes Production environment

Main Branch to SIT Environment

name: Main branch to SIT

on:
  push:
    branches:
      - main

permissions:
  contents: read
  id-token: write   # required for Azure OIDC login

env:
  APP_NAME: my-app
  ACR_NAME: myacr                          # e.g. myacr (without .azurecr.io)
  ACR_LOGIN_SERVER: myacr.azurecr.io
  RESOURCE_GROUP: rg-sit
  CONTAINER_APP_NAME: my-app-sit
  CONTAINER_APP_ENV: cae-sit               # Container Apps environment name

concurrency:
  group: main-sit-deploy
  cancel-in-progress: true

jobs:
  # -------------------------
  # 1. BUILD & PUSH IMAGE
  # -------------------------
  build:
    name: Build, Test & Push Image
    runs-on: ubuntu-latest
    outputs:
      image_tag: ${{ steps.vars.outputs.image_tag }}
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Install dependencies
        run: echo "install dependencies"

      - name: Run unit tests
        run: echo "run tests"

      - name: Set image tag
        id: vars
        run: echo "image_tag=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT

      - name: Azure Login (OIDC)
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

      - name: Log in to ACR
        run: az acr login --name ${{ env.ACR_NAME }}

      - name: Build and push Docker image
        run: |
          docker build -t ${{ env.ACR_LOGIN_SERVER }}/${{ env.APP_NAME }}:${{ steps.vars.outputs.image_tag }} .
          docker push ${{ env.ACR_LOGIN_SERVER }}/${{ env.APP_NAME }}:${{ steps.vars.outputs.image_tag }}

  # -------------------------
  # 2. DEPLOY TO SIT (AUTO)
  # -------------------------
  deploy-sit:
    name: Deploy to SIT
    needs: build
    runs-on: ubuntu-latest
    environment: sit   # no approval
    steps:
      - name: Azure Login (OIDC)
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

      - name: Deploy to Azure Container Apps
        uses: azure/container-apps-deploy-action@v2
        with:
          resourceGroup: ${{ env.RESOURCE_GROUP }}
          containerAppName: ${{ env.CONTAINER_APP_NAME }}
          containerAppEnvironment: ${{ env.CONTAINER_APP_ENV }}
          imageToDeploy: ${{ env.ACR_LOGIN_SERVER }}/${{ env.APP_NAME }}:${{ needs.build.outputs.image_tag }}
          targetPort: 8080
          ingress: external

      - name: Smoke Test
        run: |
          echo "Running smoke tests on SIT..."
          FQDN=$(az containerapp show -n ${{ env.CONTAINER_APP_NAME }} -g ${{ env.RESOURCE_GROUP }} --query properties.configuration.ingress.fqdn -o tsv)
          curl -fsSL "https://${FQDN}/health" || exit 1

RBUPP - Release Branch - UAT, Pre-Production, Production

name: Release branch → UAT → pre-prod → production
on:
  push:
    branches:
      - 'release/*'
permissions:
  contents: write   # needed for tagging
  id-token: write   # needed for Azure OIDC login
env:
  APP_NAME: my-app
  ACR_NAME: myacr                       # without .azurecr.io
  ACR_LOGIN_SERVER: myacr.azurecr.io
  TARGET_PORT: 8080
jobs:
  # -------------------------
  # 1. BUILD ONCE & PUSH IMAGE
  # -------------------------
  build:
    name: Build & Push Image
    runs-on: ubuntu-latest
    # Skip if the commit is a merge of a hotfix (avoid re-deploying hotfix merges to UAT)
    if: ${{ !(contains(toLowerCase(github.event.head_commit.message), 'merge') && contains(toLowerCase(github.event.head_commit.message), 'hotfix')) }}
    outputs:
      version: ${{ steps.extract_version.outputs.version }}
      image: ${{ steps.image.outputs.image }}
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Extract version from branch
        id: extract_version
        run: |
          BRANCH_NAME=${GITHUB_REF#refs/heads/}
          VERSION=${BRANCH_NAME#release/}
          echo "version=$VERSION" >> $GITHUB_OUTPUT
      - name: Compute image reference
        id: image
        run: |
          SHORT_SHA=${GITHUB_SHA::7}
          IMAGE="${{ env.ACR_LOGIN_SERVER }}/${{ env.APP_NAME }}:${{ steps.extract_version.outputs.version }}-${SHORT_SHA}"
          echo "image=$IMAGE" >> $GITHUB_OUTPUT
      - name: Azure Login (OIDC)
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
      - name: Log in to ACR
        run: az acr login --name ${{ env.ACR_NAME }}
      - name: Build and push Docker image
        run: |
          docker build -t ${{ steps.image.outputs.image }} .
          docker push ${{ steps.image.outputs.image }}
  # -------------------------
  # 2. DEPLOY TO UAT (AUTO)
  # -------------------------
  deploy-uat:
    name: Deploy to UAT
    needs: build
    runs-on: ubuntu-latest
    environment: uat   # no approval
    env:
      RESOURCE_GROUP: rg-uat
      CONTAINER_APP_NAME: my-app-uat
      CONTAINER_APP_ENV: cae-uat
    steps:
      - name: Azure Login (OIDC)
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
      - name: Deploy to Azure Container Apps (UAT)
        uses: azure/container-apps-deploy-action@v2
        with:
          resourceGroup: ${{ env.RESOURCE_GROUP }}
          containerAppName: ${{ env.CONTAINER_APP_NAME }}
          containerAppEnvironment: ${{ env.CONTAINER_APP_ENV }}
          imageToDeploy: ${{ needs.build.outputs.image }}
          targetPort: ${{ env.TARGET_PORT }}
          ingress: external
      - name: Smoke Test (UAT)

HBPP - Hotfix branch - Pre-Production, Production

name: Hotfix branch → Pre-production → Prod

on:
  push:
    branches:
      - 'hotfix/*'   # ONLY triggers on hotfix branches

permissions:
  contents: write   # needed for tagging
  id-token: write   # needed for Azure OIDC login

env:
  APP_NAME: my-app
  ACR_NAME: myacr                       # without .azurecr.io
  ACR_LOGIN_SERVER: myacr.azurecr.io
  TARGET_PORT: 8080

jobs:
  # -------------------------
  # 1. BUILD ONCE & PUSH IMAGE
  # -------------------------
  build-and-test-hotfix:
    name: Build & Verify Hotfix
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.extract_version.outputs.version }}
      image: ${{ steps.image.outputs.image }}
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Extract hotfix version from branch
        id: extract_version
        run: |
          BRANCH_NAME=${GITHUB_REF#refs/heads/}
          VERSION=${BRANCH_NAME#hotfix/}
          echo "version=$VERSION" >> $GITHUB_OUTPUT

      - name: Run hotfix tests
        run: echo "Running unit tests for hotfix..."

      - name: Compute image reference
        id: image
        run: |
          SHORT_SHA=${GITHUB_SHA::7}
          IMAGE="${{ env.ACR_LOGIN_SERVER }}/${{ env.APP_NAME }}:hotfix-${{ steps.extract_version.outputs.version }}-${SHORT_SHA}"
          echo "image=$IMAGE" >> $GITHUB_OUTPUT

      - name: Azure Login (OIDC)
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

      - name: Log in to ACR
        run: az acr login --name ${{ env.ACR_NAME }}

      - name: Build and push Docker image
        run: |
          docker build -t ${{ steps.image.outputs.image }} .
          docker push ${{ steps.image.outputs.image }}

  # -------------------------
  # 2. DEPLOY TO PRE-PROD (MANUAL APPROVAL)
  # -------------------------
  deploy-preprod:
    name: Deploy to Pre-Prod
    needs: build-and-test-hotfix
    runs-on: ubuntu-latest
    environment: preprod   # approval in GitHub UI
    env:
      RESOURCE_GROUP: rg-preprod
      CONTAINER_APP_NAME: my-app-preprod
      CONTAINER_APP_ENV: cae-preprod
    steps:
  1. Agile Delivery
    1. Product Requirement Template
    2. Documenting Product Requirements
    3. Estimation & Sizing
  2. DevOps
    1. Gitlab Flow with Release Branches
    2. DevOps Pipelines
  3. Software Architecture Design
    1. Agent Engineering
    2. Logging
  4. Tech Stack
  5. Testing & Quality
  6. Observability & Operations

Clone this wiki locally