From dde8d4f8028bce3a492fe6ceb71bb29405de6d26 Mon Sep 17 00:00:00 2001 From: nsaikiran777 Date: Wed, 23 Sep 2026 23:18:16 +1000 Subject: [PATCH 1/9] Enable continuous deployment to production --- .github/workflows/01-ci.yml | 4 +++ .github/workflows/02-deploy-staging.yml | 4 +-- .github/workflows/03-staging-test.yml | 5 ++-- .github/workflows/04-deploy-production.yml | 34 +++++++++++++++++----- 4 files changed, 34 insertions(+), 13 deletions(-) diff --git a/.github/workflows/01-ci.yml b/.github/workflows/01-ci.yml index 8206db43..2be8ff3c 100644 --- a/.github/workflows/01-ci.yml +++ b/.github/workflows/01-ci.yml @@ -1,6 +1,10 @@ name: 01 - CI on: + pull_request: + branches: + - main + # Trigger the workflow on push to main branch push: branches: diff --git a/.github/workflows/02-deploy-staging.yml b/.github/workflows/02-deploy-staging.yml index 006bb70d..77f0c4a8 100644 --- a/.github/workflows/02-deploy-staging.yml +++ b/.github/workflows/02-deploy-staging.yml @@ -14,9 +14,7 @@ jobs: name: Deploy to Staging runs-on: ubuntu-latest - if: > - ${{ github.event.workflow_run.conclusion == 'success' }} - + if: github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'push' environment: name: staging diff --git a/.github/workflows/03-staging-test.yml b/.github/workflows/03-staging-test.yml index 01daf5fa..9b2ec49d 100644 --- a/.github/workflows/03-staging-test.yml +++ b/.github/workflows/03-staging-test.yml @@ -14,9 +14,8 @@ jobs: name: Staging Smoke Test runs-on: ubuntu-latest - if: > - ${{ github.event.workflow_run.conclusion == 'success' }} - + if: github.event.workflow_run.conclusion == 'success' + environment: name: staging diff --git a/.github/workflows/04-deploy-production.yml b/.github/workflows/04-deploy-production.yml index 969d646b..36a08f34 100644 --- a/.github/workflows/04-deploy-production.yml +++ b/.github/workflows/04-deploy-production.yml @@ -1,6 +1,17 @@ name: 04 - Deploy to Production on: + # Continuous Deployment: promote to production automatically + # once the staging smoke test has passed for a commit on main + workflow_run: + workflows: + - "03 - Test Staging" + types: + - completed + branches: + - main + + # Kept for manual deployments / rollbacks to a specific image workflow_dispatch: inputs: image_tag: @@ -13,12 +24,21 @@ jobs: name: Deploy to Production runs-on: ubuntu-latest + # Only deploy if the staging tests succeeded (or when run manually) + if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' + environment: name: production + env: + # Automatic runs use the tested commit SHA; manual runs use the input + IMAGE_TAG: ${{ inputs.image_tag || github.event.workflow_run.head_sha }} + steps: - - name: Checkout repository + - name: Checkout tested commit uses: actions/checkout@v4 + with: + ref: ${{ env.IMAGE_TAG }} - name: Login to Azure uses: azure/login@v3 @@ -69,37 +89,37 @@ jobs: - name: Update frontend image run: | kubectl set image deployment/frontend \ - frontend=${{ vars.ACR_LOGIN_SERVER }}/koalatech-frontend:${{ inputs.image_tag }} \ + frontend=${{ vars.ACR_LOGIN_SERVER }}/koalatech-frontend:${{ env.IMAGE_TAG }} \ -n production - name: Update user-service image run: | kubectl set image deployment/user-service \ - user-service=${{ vars.ACR_LOGIN_SERVER }}/koalatech-user-service:${{ inputs.image_tag }} \ + user-service=${{ vars.ACR_LOGIN_SERVER }}/koalatech-user-service:${{ env.IMAGE_TAG }} \ -n production - name: Update student-service image run: | kubectl set image deployment/student-service \ - student-service=${{ vars.ACR_LOGIN_SERVER }}/koalatech-student-service:${{ inputs.image_tag }} \ + student-service=${{ vars.ACR_LOGIN_SERVER }}/koalatech-student-service:${{ env.IMAGE_TAG }} \ -n production - name: Update lecturer-service image run: | kubectl set image deployment/lecturer-service \ - lecturer-service=${{ vars.ACR_LOGIN_SERVER }}/koalatech-lecturer-service:${{ inputs.image_tag }} \ + lecturer-service=${{ vars.ACR_LOGIN_SERVER }}/koalatech-lecturer-service:${{ env.IMAGE_TAG }} \ -n production - name: Update course-service image run: | kubectl set image deployment/course-service \ - course-service=${{ vars.ACR_LOGIN_SERVER }}/koalatech-course-service:${{ inputs.image_tag }} \ + course-service=${{ vars.ACR_LOGIN_SERVER }}/koalatech-course-service:${{ env.IMAGE_TAG }} \ -n production - name: Update enrollment-service image run: | kubectl set image deployment/enrollment-service \ - enrollment-service=${{ vars.ACR_LOGIN_SERVER }}/koalatech-enrollment-service:${{ inputs.image_tag }} \ + enrollment-service=${{ vars.ACR_LOGIN_SERVER }}/koalatech-enrollment-service:${{ env.IMAGE_TAG }} \ -n production - name: Wait for frontend rollout From ef1aaca578a31761ea7e02001d91603fd04eafbe Mon Sep 17 00:00:00 2001 From: nsaikiran777 Date: Wed, 23 Sep 2026 23:55:56 +1000 Subject: [PATCH 2/9] Update header text to demonstrate continuous deployment --- frontend/src/components/Header.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/Header.jsx b/frontend/src/components/Header.jsx index d1a76071..7b5f5d46 100644 --- a/frontend/src/components/Header.jsx +++ b/frontend/src/components/Header.jsx @@ -43,7 +43,7 @@ const Header = () => { fontWeight: 600, }} > - KoalaTech University + KoalaTech University - Deployed by CD Date: Thu, 1 Oct 2026 19:07:54 +1000 Subject: [PATCH 3/9] Fix Docker build command --- .github/workflows/01-ci.yml | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/.github/workflows/01-ci.yml b/.github/workflows/01-ci.yml index 2be8ff3c..746c8381 100644 --- a/.github/workflows/01-ci.yml +++ b/.github/workflows/01-ci.yml @@ -154,17 +154,9 @@ jobs: creds: ${{ secrets.AZURE_CREDENTIALS }} - name: Login to Azure Container Registry - run: | - az acr login --name ${{ vars.ACR_NAME }} + run: az acr login --name ${{ vars.ACR_NAME }} - name: Build Docker image - run: | - docker build \ - --platform linux/amd64 \ - -t ${{ vars.ACR_LOGIN_SERVER }}/${{ matrix.image }}:${{ github.sha }} \ - ./${{ matrix.service }} - - - name: Push Docker image with commit SHA - run: | - docker push \ - ${{ vars.ACR_LOGIN_SERVER }}/${{ matrix.image }}:${{ github.sha }} + run: docker build --platform linux/amd64 -t "${{ vars.ACR_LOGIN_SERVER }}/${{ matrix.image }}:${{ github.sha }}" "./${{ matrix.service }}" + - name: Push Docker image + run: docker push "${{ vars.ACR_LOGIN_SERVER }}/${{ matrix.image }}:${{ github.sha }}" \ No newline at end of file From f79ddceddbdd2923eb9aa06afe54dd7220d4301b Mon Sep 17 00:00:00 2001 From: nsaikiran777 Date: Thu, 1 Oct 2026 20:12:43 +1000 Subject: [PATCH 4/9] Fix Docker build and push commands --- .github/workflows/01-ci.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/01-ci.yml b/.github/workflows/01-ci.yml index 746c8381..46a8aa87 100644 --- a/.github/workflows/01-ci.yml +++ b/.github/workflows/01-ci.yml @@ -157,6 +157,7 @@ jobs: run: az acr login --name ${{ vars.ACR_NAME }} - name: Build Docker image - run: docker build --platform linux/amd64 -t "${{ vars.ACR_LOGIN_SERVER }}/${{ matrix.image }}:${{ github.sha }}" "./${{ matrix.service }}" - - name: Push Docker image - run: docker push "${{ vars.ACR_LOGIN_SERVER }}/${{ matrix.image }}:${{ github.sha }}" \ No newline at end of file + run: docker build --platform linux/amd64 -t ${{ vars.ACR_LOGIN_SERVER }}/${{ matrix.image }}:${{ github.sha }} ./${{ matrix.service }} + + - name: Push Docker image with commit SHA + run: docker push ${{ vars.ACR_LOGIN_SERVER }}/${{ matrix.image }}:${{ github.sha }} \ No newline at end of file From a037bd632287afade927a33bb1d7ea4da229d843 Mon Sep 17 00:00:00 2001 From: nsaikiran777 Date: Thu, 1 Oct 2026 20:20:29 +1000 Subject: [PATCH 5/9] Fix Docker build and push commands --- .github/workflows/01-ci.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/01-ci.yml b/.github/workflows/01-ci.yml index 46a8aa87..77a5b634 100644 --- a/.github/workflows/01-ci.yml +++ b/.github/workflows/01-ci.yml @@ -157,7 +157,11 @@ jobs: run: az acr login --name ${{ vars.ACR_NAME }} - name: Build Docker image - run: docker build --platform linux/amd64 -t ${{ vars.ACR_LOGIN_SERVER }}/${{ matrix.image }}:${{ github.sha }} ./${{ matrix.service }} + run: | + docker build \ + --platform linux/amd64 \ + -t ${{ vars.ACR_LOGIN_SERVER }}/${{ matrix.image }}:${{ github.sha }} \ + ./${{ matrix.service }} - name: Push Docker image with commit SHA run: docker push ${{ vars.ACR_LOGIN_SERVER }}/${{ matrix.image }}:${{ github.sha }} \ No newline at end of file From 048875a42537769104b25835d25c979daeab7408 Mon Sep 17 00:00:00 2001 From: nsaikiran777 Date: Thu, 1 Oct 2026 20:58:47 +1000 Subject: [PATCH 6/9] Fix Docker build syntax --- .github/workflows/01-ci.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/01-ci.yml b/.github/workflows/01-ci.yml index 77a5b634..52549a22 100644 --- a/.github/workflows/01-ci.yml +++ b/.github/workflows/01-ci.yml @@ -157,11 +157,7 @@ jobs: run: az acr login --name ${{ vars.ACR_NAME }} - name: Build Docker image - run: | - docker build \ - --platform linux/amd64 \ - -t ${{ vars.ACR_LOGIN_SERVER }}/${{ matrix.image }}:${{ github.sha }} \ - ./${{ matrix.service }} + run: docker build --platform=linux/amd64 --tag="${{ vars.ACR_LOGIN_SERVER }}/${{ matrix.image }}:${{ github.sha }}" "./${{ matrix.service }}" - name: Push Docker image with commit SHA - run: docker push ${{ vars.ACR_LOGIN_SERVER }}/${{ matrix.image }}:${{ github.sha }} \ No newline at end of file + run: docker push "${{ vars.ACR_LOGIN_SERVER }}/${{ matrix.image }}:${{ github.sha }}" \ No newline at end of file From 5fbe98152bad2964f7fa8d3c391316a415357722 Mon Sep 17 00:00:00 2001 From: nsaikiran777 Date: Thu, 1 Oct 2026 21:21:31 +1000 Subject: [PATCH 7/9] Fix staging deployment condition --- .github/workflows/02-deploy-staging.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/02-deploy-staging.yml b/.github/workflows/02-deploy-staging.yml index 77f0c4a8..156ada95 100644 --- a/.github/workflows/02-deploy-staging.yml +++ b/.github/workflows/02-deploy-staging.yml @@ -14,7 +14,7 @@ jobs: name: Deploy to Staging runs-on: ubuntu-latest - if: github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'push' + if: github.event.workflow_run.conclusion == 'success' environment: name: staging From 50d67eaef53940046f0dae9ddc94c632cea88a50 Mon Sep 17 00:00:00 2001 From: nsaikiran777 Date: Thu, 1 Oct 2026 22:27:24 +1000 Subject: [PATCH 8/9] Enable manual staging deployment --- .github/workflows/02-deploy-staging.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/02-deploy-staging.yml b/.github/workflows/02-deploy-staging.yml index 156ada95..e751d4cc 100644 --- a/.github/workflows/02-deploy-staging.yml +++ b/.github/workflows/02-deploy-staging.yml @@ -8,13 +8,14 @@ on: - completed branches: - main + workflow_dispatch: jobs: deploy-staging: name: Deploy to Staging runs-on: ubuntu-latest - if: github.event.workflow_run.conclusion == 'success' + if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' environment: name: staging From 9ef7094d33d92e028e42214d071a94f20bf61049 Mon Sep 17 00:00:00 2001 From: nsaikiran777 Date: Fri, 2 Oct 2026 12:23:42 +1000 Subject: [PATCH 9/9] Fix staging deployment workflow --- .github/workflows/02-deploy-staging.yml | 71 +++++++++++++++++++------ 1 file changed, 54 insertions(+), 17 deletions(-) diff --git a/.github/workflows/02-deploy-staging.yml b/.github/workflows/02-deploy-staging.yml index e751d4cc..aa8bbd32 100644 --- a/.github/workflows/02-deploy-staging.yml +++ b/.github/workflows/02-deploy-staging.yml @@ -1,3 +1,4 @@ + name: 02 - Deploy to Staging on: @@ -8,41 +9,63 @@ on: - completed branches: - main - workflow_dispatch: + + workflow_dispatch: + inputs: + image_tag: + description: "Full commit SHA from a successful CI build" + required: true + type: string + +permissions: + contents: read jobs: deploy-staging: name: Deploy to Staging runs-on: ubuntu-latest - if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' - environment: - name: staging + if: >- + ${{ + github.event_name == 'workflow_dispatch' || + ( + github.event.workflow_run.conclusion == 'success' && + github.event.workflow_run.event == 'push' + ) + }} + + env: + IMAGE_TAG: ${{ inputs.image_tag || github.event.workflow_run.head_sha }} steps: + # 1. Checkout the tested commit - name: Checkout tested commit uses: actions/checkout@v4 with: - ref: ${{ github.event.workflow_run.head_sha }} + ref: ${{ env.IMAGE_TAG }} + # 2. Login to Azure - name: Login to Azure - uses: azure/login@v3 + uses: azure/login@v2 with: creds: ${{ secrets.AZURE_CREDENTIALS }} + # 3. Connect to AKS - name: Get AKS credentials run: | az aks get-credentials \ - --resource-group ${{ vars.AKS_RESOURCE_GROUP }} \ - --name ${{ vars.AKS_CLUSTER_NAME }} \ + --resource-group "${{ vars.AKS_RESOURCE_GROUP }}" \ + --name "${{ vars.AKS_CLUSTER_NAME }}" \ --overwrite-existing + # 4. Create staging namespace - name: Create staging namespace run: | kubectl create namespace staging \ --dry-run=client \ -o yaml | kubectl apply -f - + # 5. Create PostgreSQL secret - name: Create PostgreSQL secret run: | kubectl create secret generic postgres-secret \ @@ -52,6 +75,7 @@ jobs: --dry-run=client \ -o yaml | kubectl apply -f - + # 6. Create application secret - name: Create application secret run: | kubectl create secret generic application-secret \ @@ -66,85 +90,98 @@ jobs: --dry-run=client \ -o yaml | kubectl apply -f - + # 7. Apply Kubernetes manifests - name: Apply Kubernetes manifests run: | - kubectl apply \ - -f kubernetes/staging/ + kubectl apply -f kubernetes/staging/ + # 8. Update frontend image - name: Update frontend image run: | kubectl set image deployment/frontend \ - frontend=${{ vars.ACR_LOGIN_SERVER }}/koalatech-frontend:${{ github.event.workflow_run.head_sha }} \ + frontend="${{ vars.ACR_LOGIN_SERVER }}/koalatech-frontend:${IMAGE_TAG}" \ -n staging + # 9. Update user-service image - name: Update user-service image run: | kubectl set image deployment/user-service \ - user-service=${{ vars.ACR_LOGIN_SERVER }}/koalatech-user-service:${{ github.event.workflow_run.head_sha }} \ + user-service="${{ vars.ACR_LOGIN_SERVER }}/koalatech-user-service:${IMAGE_TAG}" \ -n staging + # 10. Update student-service image - name: Update student-service image run: | kubectl set image deployment/student-service \ - student-service=${{ vars.ACR_LOGIN_SERVER }}/koalatech-student-service:${{ github.event.workflow_run.head_sha }} \ + student-service="${{ vars.ACR_LOGIN_SERVER }}/koalatech-student-service:${IMAGE_TAG}" \ -n staging + # 11. Update lecturer-service image - name: Update lecturer-service image run: | kubectl set image deployment/lecturer-service \ - lecturer-service=${{ vars.ACR_LOGIN_SERVER }}/koalatech-lecturer-service:${{ github.event.workflow_run.head_sha }} \ + lecturer-service="${{ vars.ACR_LOGIN_SERVER }}/koalatech-lecturer-service:${IMAGE_TAG}" \ -n staging + # 12. Update course-service image - name: Update course-service image run: | kubectl set image deployment/course-service \ - course-service=${{ vars.ACR_LOGIN_SERVER }}/koalatech-course-service:${{ github.event.workflow_run.head_sha }} \ + course-service="${{ vars.ACR_LOGIN_SERVER }}/koalatech-course-service:${IMAGE_TAG}" \ -n staging + # 13. Update enrollment-service image - name: Update enrollment-service image run: | kubectl set image deployment/enrollment-service \ - enrollment-service=${{ vars.ACR_LOGIN_SERVER }}/koalatech-enrollment-service:${{ github.event.workflow_run.head_sha }} \ + enrollment-service="${{ vars.ACR_LOGIN_SERVER }}/koalatech-enrollment-service:${IMAGE_TAG}" \ -n staging + # 14. Verify frontend rollout - name: Wait for frontend rollout run: | kubectl rollout status deployment/frontend \ -n staging \ --timeout=300s + # 15. Verify user-service rollout - name: Wait for user-service rollout run: | kubectl rollout status deployment/user-service \ -n staging \ --timeout=300s + # 16. Verify student-service rollout - name: Wait for student-service rollout run: | kubectl rollout status deployment/student-service \ -n staging \ --timeout=300s + # 17. Verify lecturer-service rollout - name: Wait for lecturer-service rollout run: | kubectl rollout status deployment/lecturer-service \ -n staging \ --timeout=300s + # 18. Verify course-service rollout - name: Wait for course-service rollout run: | kubectl rollout status deployment/course-service \ -n staging \ --timeout=300s + # 19. Verify enrollment-service rollout - name: Wait for enrollment-service rollout run: | kubectl rollout status deployment/enrollment-service \ -n staging \ --timeout=300s + # 20. Display staging resources - name: Show staging resources run: | kubectl get pods -n staging kubectl get services -n staging - kubectl get pvc -n staging \ No newline at end of file + kubectl get pvc -n staging