From 4e466853537b4d9f166a4e6f4cf818110df44102 Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Thu, 15 May 2025 16:33:40 -0700 Subject: [PATCH 01/28] update the format/sonar/test workflow configurations --- .github/workflows/format.yml | 2 +- .github/workflows/sonar.yml | 2 ++ .github/workflows/test.yml | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index cf55b4ecb..524e5c749 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -1,7 +1,7 @@ name: Check format of code base on: pull_request: - types: [opened, synchronize] + types: [opened, synchronize, reopened] jobs: premerge: diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index 7755a633a..3126db27f 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -3,6 +3,8 @@ on: push: branches: - master + - dev-env + - test-env pull_request: types: [opened, synchronize, reopened] jobs: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 263db0b99..17f28b774 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,6 +7,8 @@ on: pull_request: branches: + - dev-env + - test-env - master env: KEYCLOAK_LOCAL_USERNAME: 'test-admin' From 745798515b39e8e9322ea9aa8b9f4cd259877202 Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Tue, 20 May 2025 14:49:45 -0700 Subject: [PATCH 02/28] update the format/sonar/test workflow configurations (#1094) --- .github/workflows/format.yml | 2 +- .github/workflows/sonar.yml | 2 ++ .github/workflows/test.yml | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index cf55b4ecb..524e5c749 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -1,7 +1,7 @@ name: Check format of code base on: pull_request: - types: [opened, synchronize] + types: [opened, synchronize, reopened] jobs: premerge: diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index 7755a633a..3126db27f 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -3,6 +3,8 @@ on: push: branches: - master + - dev-env + - test-env pull_request: types: [opened, synchronize, reopened] jobs: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 263db0b99..17f28b774 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,6 +7,8 @@ on: pull_request: branches: + - dev-env + - test-env - master env: KEYCLOAK_LOCAL_USERNAME: 'test-admin' From d854cc1b4e8f6fbac93b2a2ec5d4d3aeb6648eee Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Tue, 20 May 2025 15:35:52 -0700 Subject: [PATCH 03/28] update the deployment workflow file for dev-env --- .github/workflows/{build.yml => promote-dev.yml} | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) rename .github/workflows/{build.yml => promote-dev.yml} (94%) diff --git a/.github/workflows/build.yml b/.github/workflows/promote-dev.yml similarity index 94% rename from .github/workflows/build.yml rename to .github/workflows/promote-dev.yml index 79a4c83be..4e781d430 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/promote-dev.yml @@ -1,12 +1,18 @@ # Build and Deploy to dev env. -# Trigger with tag dev +# Trigger with branch dev-env or tag dev # Connected with repo environment 'dev' -name: OpenShift Build and Deploy to Dev with OWSAP ZAP SCAN +name: OpenShift Deploy/Promotion to Dev with OWSAP ZAP SCAN on: + workflow_dispatch: + inputs: + reason: + description: 'Reason for manual deployment' + required: false + default: 'Manual deployment' push: branches: - - master + - dev-env tags: - dev From a06423b71e4e78b01bde73d91032aa117dd5a3b8 Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Tue, 20 May 2025 15:38:48 -0700 Subject: [PATCH 04/28] update the deployment workflow file for dev-env (#1095) * update the format/sonar/test workflow configurations * update the deployment workflow file for dev-env --- .github/workflows/{build.yml => promote-dev.yml} | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) rename .github/workflows/{build.yml => promote-dev.yml} (94%) diff --git a/.github/workflows/build.yml b/.github/workflows/promote-dev.yml similarity index 94% rename from .github/workflows/build.yml rename to .github/workflows/promote-dev.yml index 79a4c83be..4e781d430 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/promote-dev.yml @@ -1,12 +1,18 @@ # Build and Deploy to dev env. -# Trigger with tag dev +# Trigger with branch dev-env or tag dev # Connected with repo environment 'dev' -name: OpenShift Build and Deploy to Dev with OWSAP ZAP SCAN +name: OpenShift Deploy/Promotion to Dev with OWSAP ZAP SCAN on: + workflow_dispatch: + inputs: + reason: + description: 'Reason for manual deployment' + required: false + default: 'Manual deployment' push: branches: - - master + - dev-env tags: - dev From 4cfb56cee50fb9f22df2d2c3a1ae2edbdff2a88b Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Tue, 20 May 2025 16:07:24 -0700 Subject: [PATCH 05/28] update test deployment workflow --- .github/workflows/promote-dev.yml | 2 +- .github/workflows/promote-test.yml | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/promote-dev.yml b/.github/workflows/promote-dev.yml index 4e781d430..7163b584a 100644 --- a/.github/workflows/promote-dev.yml +++ b/.github/workflows/promote-dev.yml @@ -1,5 +1,5 @@ # Build and Deploy to dev env. -# Trigger with branch dev-env or tag dev +# Trigger with branch dev-env, tag dev, or manual dispatch # Connected with repo environment 'dev' name: OpenShift Deploy/Promotion to Dev with OWSAP ZAP SCAN diff --git a/.github/workflows/promote-test.yml b/.github/workflows/promote-test.yml index e09c6234c..6b6440de6 100644 --- a/.github/workflows/promote-test.yml +++ b/.github/workflows/promote-test.yml @@ -1,10 +1,18 @@ # Promotion to test env. -# Trigger with tag push +# Trigger with branch test-env, tag test, or manual dispatch # Connected with repo environment 'test' name: OpenShift Deploy/Promotion to Test on: + workflow_dispatch: + inputs: + reason: + description: 'Reason for manual deployment to test' + required: false + default: 'Manual test deployment' push: + branches: + - test-env tags: - test @@ -50,7 +58,7 @@ jobs: filters: | src: - 'openshift/**' - base: 'refs/tags/test' + base: ${{ github.ref }} - name: Dry run - Test env: @@ -83,7 +91,7 @@ jobs: filters: | src: - 'openshift/**' - base: 'refs/tags/test' + base: ${{ github.ref }} - name: Apply Changes env: OS_NAMESPACE_SUFFIX: test From 643cd99a972ec4f2f531eb634c5c924cf8920308 Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Tue, 20 May 2025 16:15:33 -0700 Subject: [PATCH 06/28] update test deployment workflow (#1096) * update the format/sonar/test workflow configurations * update the deployment workflow file for dev-env * update test deployment workflow --- .github/workflows/promote-dev.yml | 2 +- .github/workflows/promote-test.yml | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/promote-dev.yml b/.github/workflows/promote-dev.yml index 4e781d430..7163b584a 100644 --- a/.github/workflows/promote-dev.yml +++ b/.github/workflows/promote-dev.yml @@ -1,5 +1,5 @@ # Build and Deploy to dev env. -# Trigger with branch dev-env or tag dev +# Trigger with branch dev-env, tag dev, or manual dispatch # Connected with repo environment 'dev' name: OpenShift Deploy/Promotion to Dev with OWSAP ZAP SCAN diff --git a/.github/workflows/promote-test.yml b/.github/workflows/promote-test.yml index e09c6234c..6b6440de6 100644 --- a/.github/workflows/promote-test.yml +++ b/.github/workflows/promote-test.yml @@ -1,10 +1,18 @@ # Promotion to test env. -# Trigger with tag push +# Trigger with branch test-env, tag test, or manual dispatch # Connected with repo environment 'test' name: OpenShift Deploy/Promotion to Test on: + workflow_dispatch: + inputs: + reason: + description: 'Reason for manual deployment to test' + required: false + default: 'Manual test deployment' push: + branches: + - test-env tags: - test @@ -50,7 +58,7 @@ jobs: filters: | src: - 'openshift/**' - base: 'refs/tags/test' + base: ${{ github.ref }} - name: Dry run - Test env: @@ -83,7 +91,7 @@ jobs: filters: | src: - 'openshift/**' - base: 'refs/tags/test' + base: ${{ github.ref }} - name: Apply Changes env: OS_NAMESPACE_SUFFIX: test From 740b93e5994f3ff6ca2a0b819e023a7b1075b425 Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Tue, 20 May 2025 17:13:05 -0700 Subject: [PATCH 07/28] remove the auto deployment feture on test-env --- .github/workflows/promote-test.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/promote-test.yml b/.github/workflows/promote-test.yml index 6b6440de6..8bbe67083 100644 --- a/.github/workflows/promote-test.yml +++ b/.github/workflows/promote-test.yml @@ -1,5 +1,5 @@ # Promotion to test env. -# Trigger with branch test-env, tag test, or manual dispatch +# Trigger with manual dispatch or tag test # Connected with repo environment 'test' name: OpenShift Deploy/Promotion to Test @@ -7,12 +7,10 @@ on: workflow_dispatch: inputs: reason: - description: 'Reason for manual deployment to test' - required: false - default: 'Manual test deployment' + description: 'Reason for deployment to test (include ticket number)' + required: true + default: 'BCMOHAM-XXXXX: Test deployment' push: - branches: - - test-env tags: - test From 70710bd4454c6106505ae30211783025fb6f054a Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Tue, 20 May 2025 17:17:23 -0700 Subject: [PATCH 08/28] Remove the auto deployment feature on test-env (#1098) * update the format/sonar/test workflow configurations * update the deployment workflow file for dev-env * update test deployment workflow * remove the auto deployment feture on test-env --- .github/workflows/promote-test.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/promote-test.yml b/.github/workflows/promote-test.yml index 6b6440de6..8bbe67083 100644 --- a/.github/workflows/promote-test.yml +++ b/.github/workflows/promote-test.yml @@ -1,5 +1,5 @@ # Promotion to test env. -# Trigger with branch test-env, tag test, or manual dispatch +# Trigger with manual dispatch or tag test # Connected with repo environment 'test' name: OpenShift Deploy/Promotion to Test @@ -7,12 +7,10 @@ on: workflow_dispatch: inputs: reason: - description: 'Reason for manual deployment to test' - required: false - default: 'Manual test deployment' + description: 'Reason for deployment to test (include ticket number)' + required: true + default: 'BCMOHAM-XXXXX: Test deployment' push: - branches: - - test-env tags: - test From 4f1db6dc04937a9ad3d9a19d476d42cb8db2c5cf Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Wed, 21 May 2025 14:24:22 -0700 Subject: [PATCH 09/28] remove tags for dev&test deployments --- .github/workflows/promote-dev.yml | 36 ++++++++++++++++++++++++------ .github/workflows/promote-test.yml | 29 ++++++++++++++++++------ Makefile | 26 ++++++++++----------- 3 files changed, 63 insertions(+), 28 deletions(-) diff --git a/.github/workflows/promote-dev.yml b/.github/workflows/promote-dev.yml index 7163b584a..0a4011f1d 100644 --- a/.github/workflows/promote-dev.yml +++ b/.github/workflows/promote-dev.yml @@ -1,6 +1,18 @@ # Build and Deploy to dev env. -# Trigger with branch dev-env, tag dev, or manual dispatch -# Connected with repo environment 'dev' +# Trigger with branch dev-env or manual dispatch + +# Example Scenarios +# Automatic Deployment: +# Someone pushes to dev-env +# Workflow triggers automatically +# github.event.inputs.ref is empty +# Code is checked out from github.ref (dev-env branch) +# Manual Deployment from Feature Branch: +# User manually triggers workflow +# Selects "feature/feature-name" in the ref input +# Code is checked out from "feature/feature-name" +# Deployment proceeds with that code + name: OpenShift Deploy/Promotion to Dev with OWSAP ZAP SCAN on: @@ -8,13 +20,15 @@ on: inputs: reason: description: 'Reason for manual deployment' + required: true + default: 'Manual dev deployment' + ref: + description: 'Branch to deploy (default: dev-env)' required: false - default: 'Manual deployment' + default: 'dev-env' push: branches: - dev-env - tags: - - dev env: CLUSTER: https://api.silver.devops.gov.bc.ca:6443 @@ -31,6 +45,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref || github.ref }} - name: Install OpenShift CLI uses: redhat-actions/openshift-tools-installer@v1 @@ -52,6 +68,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref || github.ref }} - name: Install OpenShift CLI uses: redhat-actions/openshift-tools-installer@v1 @@ -64,7 +82,7 @@ jobs: filters: | src: - 'openshift/**' - base: ${{ github.ref }} + base: 'refs/heads/dev-env~1' #Compare against previous commit on dev-env branch - name: Dry run - Dev env: OS_NAMESPACE_SUFFIX: dev @@ -91,6 +109,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref || github.ref }} - name: Install OpenShift CLI uses: redhat-actions/openshift-tools-installer@v1 with: @@ -101,7 +121,7 @@ jobs: filters: | src: - 'openshift/**' - base: ${{ github.ref}} + base: 'refs/heads/dev-env~1' #Compare against previous commit on dev-env branch - name: Apply Changes env: OS_NAMESPACE_SUFFIX: dev @@ -121,6 +141,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref || github.ref }} - name: Install OpenShift CLI uses: redhat-actions/openshift-tools-installer@v1 with: diff --git a/.github/workflows/promote-test.yml b/.github/workflows/promote-test.yml index 8bbe67083..d156e8ce7 100644 --- a/.github/workflows/promote-test.yml +++ b/.github/workflows/promote-test.yml @@ -1,6 +1,14 @@ # Promotion to test env. -# Trigger with manual dispatch or tag test -# Connected with repo environment 'test' +# Trigger with manual dispatch + +# Example Scenarios +# Manual Deployment from Feature Branch: +# User manually triggers workflow +# Provides ticket number in the reason field +# Selects "feature/feature-name" in the ref input +# Code is checked out from "feature/feature-name" +# Deployment proceeds with that code + name: OpenShift Deploy/Promotion to Test on: @@ -10,9 +18,10 @@ on: description: 'Reason for deployment to test (include ticket number)' required: true default: 'BCMOHAM-XXXXX: Test deployment' - push: - tags: - - test + ref: + description: 'Branch to deploy (default: test-env)' + required: false + default: 'test-env' env: CLUSTER: https://api.silver.devops.gov.bc.ca:6443 @@ -27,6 +36,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref }} - name: Cache OpenShift CLI id: cache-oc @@ -56,7 +67,7 @@ jobs: filters: | src: - 'openshift/**' - base: ${{ github.ref }} + base: 'refs/heads/test-env~1' #Compare against previous commit on test-env branch - name: Dry run - Test env: @@ -83,13 +94,15 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref }} - uses: dorny/paths-filter@v2 id: changes with: filters: | src: - 'openshift/**' - base: ${{ github.ref }} + base: 'refs/heads/test-env~1' #Compare against previous commit on test-env branch - name: Apply Changes env: OS_NAMESPACE_SUFFIX: test @@ -109,6 +122,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref }} - name: Cache OpenShift CLI id: cache-oc diff --git a/Makefile b/Makefile index c15933dd7..3ce75d623 100644 --- a/Makefile +++ b/Makefile @@ -162,27 +162,25 @@ local-kc-arm-down: @echo "Stopping local app container" @docker-compose -f docker-compose.arm.test.yml down --remove-orphans -# Git Tagging Aliases - -tag-dev: +# Branch-based deployment commands +deploy-to-dev: #deploy the code on dev-env branch to DEV env on OpenShift ifdef ticket - @git tag -fa dev -m "Deploy $(ticket) to DEV env" + @echo "Creating branch dev-env from current branch with ticket $(ticket)" + @git checkout -B dev-env + @git push -f origin dev-env else - @echo -e '\nTicket name missing - Example :: make tag-dev ticket=HCAP-ABC \n' - @echo -e 'Falling Back to using branch name \n' - @git tag -fa dev -m "Deploy $(git rev-parse --abbrev-ref HEAD) to DEV env" + @echo -e '\nTicket name missing - Example :: make deploy-to-dev ticket=HCAP-ABC \n' endif - @git push --force origin refs/tags/dev:refs/tags/dev -tag-test: +prepare-test-branch: #For test, we don't automatically deploy, just prepare the branch ifdef ticket - @git tag -fa test -m "Deploy $(ticket) to TEST env" + @echo "Creating branch test-env from current branch with ticket $(ticket)" + @git checkout -B test-env + @git push -f origin test-env + @echo "Branch test-env updated. Use GitHub Actions workflow to deploy with proper RFC." else - @echo -e '\nTicket name missing - Example :: make tag-test ticket=HCAP-ABC \n' - @echo -e 'Falling Back to using branch name\n' - @git tag -fa test -m "Deploy $(git rev-parse --abbrev-ref HEAD) to TEST env" + @echo -e '\nTicket name missing - Example :: make prepare-test-branch ticket=HCAP-ABC \n' endif - @git push --force origin refs/tags/test:refs/tags/test tag-prod: ifdef ticket From fa1199a0fda8c4fa3d22a822d292a28d322ff1da Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Wed, 21 May 2025 14:27:09 -0700 Subject: [PATCH 10/28] remove tags for dev&test deployments (#1099) * update the format/sonar/test workflow configurations * update the deployment workflow file for dev-env * update test deployment workflow * remove the auto deployment feture on test-env * remove tags for dev&test deployments --- .github/workflows/promote-dev.yml | 36 ++++++++++++++++++++++++------ .github/workflows/promote-test.yml | 29 ++++++++++++++++++------ Makefile | 26 ++++++++++----------- 3 files changed, 63 insertions(+), 28 deletions(-) diff --git a/.github/workflows/promote-dev.yml b/.github/workflows/promote-dev.yml index 7163b584a..0a4011f1d 100644 --- a/.github/workflows/promote-dev.yml +++ b/.github/workflows/promote-dev.yml @@ -1,6 +1,18 @@ # Build and Deploy to dev env. -# Trigger with branch dev-env, tag dev, or manual dispatch -# Connected with repo environment 'dev' +# Trigger with branch dev-env or manual dispatch + +# Example Scenarios +# Automatic Deployment: +# Someone pushes to dev-env +# Workflow triggers automatically +# github.event.inputs.ref is empty +# Code is checked out from github.ref (dev-env branch) +# Manual Deployment from Feature Branch: +# User manually triggers workflow +# Selects "feature/feature-name" in the ref input +# Code is checked out from "feature/feature-name" +# Deployment proceeds with that code + name: OpenShift Deploy/Promotion to Dev with OWSAP ZAP SCAN on: @@ -8,13 +20,15 @@ on: inputs: reason: description: 'Reason for manual deployment' + required: true + default: 'Manual dev deployment' + ref: + description: 'Branch to deploy (default: dev-env)' required: false - default: 'Manual deployment' + default: 'dev-env' push: branches: - dev-env - tags: - - dev env: CLUSTER: https://api.silver.devops.gov.bc.ca:6443 @@ -31,6 +45,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref || github.ref }} - name: Install OpenShift CLI uses: redhat-actions/openshift-tools-installer@v1 @@ -52,6 +68,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref || github.ref }} - name: Install OpenShift CLI uses: redhat-actions/openshift-tools-installer@v1 @@ -64,7 +82,7 @@ jobs: filters: | src: - 'openshift/**' - base: ${{ github.ref }} + base: 'refs/heads/dev-env~1' #Compare against previous commit on dev-env branch - name: Dry run - Dev env: OS_NAMESPACE_SUFFIX: dev @@ -91,6 +109,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref || github.ref }} - name: Install OpenShift CLI uses: redhat-actions/openshift-tools-installer@v1 with: @@ -101,7 +121,7 @@ jobs: filters: | src: - 'openshift/**' - base: ${{ github.ref}} + base: 'refs/heads/dev-env~1' #Compare against previous commit on dev-env branch - name: Apply Changes env: OS_NAMESPACE_SUFFIX: dev @@ -121,6 +141,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref || github.ref }} - name: Install OpenShift CLI uses: redhat-actions/openshift-tools-installer@v1 with: diff --git a/.github/workflows/promote-test.yml b/.github/workflows/promote-test.yml index 8bbe67083..d156e8ce7 100644 --- a/.github/workflows/promote-test.yml +++ b/.github/workflows/promote-test.yml @@ -1,6 +1,14 @@ # Promotion to test env. -# Trigger with manual dispatch or tag test -# Connected with repo environment 'test' +# Trigger with manual dispatch + +# Example Scenarios +# Manual Deployment from Feature Branch: +# User manually triggers workflow +# Provides ticket number in the reason field +# Selects "feature/feature-name" in the ref input +# Code is checked out from "feature/feature-name" +# Deployment proceeds with that code + name: OpenShift Deploy/Promotion to Test on: @@ -10,9 +18,10 @@ on: description: 'Reason for deployment to test (include ticket number)' required: true default: 'BCMOHAM-XXXXX: Test deployment' - push: - tags: - - test + ref: + description: 'Branch to deploy (default: test-env)' + required: false + default: 'test-env' env: CLUSTER: https://api.silver.devops.gov.bc.ca:6443 @@ -27,6 +36,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref }} - name: Cache OpenShift CLI id: cache-oc @@ -56,7 +67,7 @@ jobs: filters: | src: - 'openshift/**' - base: ${{ github.ref }} + base: 'refs/heads/test-env~1' #Compare against previous commit on test-env branch - name: Dry run - Test env: @@ -83,13 +94,15 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref }} - uses: dorny/paths-filter@v2 id: changes with: filters: | src: - 'openshift/**' - base: ${{ github.ref }} + base: 'refs/heads/test-env~1' #Compare against previous commit on test-env branch - name: Apply Changes env: OS_NAMESPACE_SUFFIX: test @@ -109,6 +122,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref }} - name: Cache OpenShift CLI id: cache-oc diff --git a/Makefile b/Makefile index c15933dd7..3ce75d623 100644 --- a/Makefile +++ b/Makefile @@ -162,27 +162,25 @@ local-kc-arm-down: @echo "Stopping local app container" @docker-compose -f docker-compose.arm.test.yml down --remove-orphans -# Git Tagging Aliases - -tag-dev: +# Branch-based deployment commands +deploy-to-dev: #deploy the code on dev-env branch to DEV env on OpenShift ifdef ticket - @git tag -fa dev -m "Deploy $(ticket) to DEV env" + @echo "Creating branch dev-env from current branch with ticket $(ticket)" + @git checkout -B dev-env + @git push -f origin dev-env else - @echo -e '\nTicket name missing - Example :: make tag-dev ticket=HCAP-ABC \n' - @echo -e 'Falling Back to using branch name \n' - @git tag -fa dev -m "Deploy $(git rev-parse --abbrev-ref HEAD) to DEV env" + @echo -e '\nTicket name missing - Example :: make deploy-to-dev ticket=HCAP-ABC \n' endif - @git push --force origin refs/tags/dev:refs/tags/dev -tag-test: +prepare-test-branch: #For test, we don't automatically deploy, just prepare the branch ifdef ticket - @git tag -fa test -m "Deploy $(ticket) to TEST env" + @echo "Creating branch test-env from current branch with ticket $(ticket)" + @git checkout -B test-env + @git push -f origin test-env + @echo "Branch test-env updated. Use GitHub Actions workflow to deploy with proper RFC." else - @echo -e '\nTicket name missing - Example :: make tag-test ticket=HCAP-ABC \n' - @echo -e 'Falling Back to using branch name\n' - @git tag -fa test -m "Deploy $(git rev-parse --abbrev-ref HEAD) to TEST env" + @echo -e '\nTicket name missing - Example :: make prepare-test-branch ticket=HCAP-ABC \n' endif - @git push --force origin refs/tags/test:refs/tags/test tag-prod: ifdef ticket From 5c5b6a4962be91361bccf0768c6917a003a1ddd2 Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Wed, 21 May 2025 14:50:58 -0700 Subject: [PATCH 11/28] update the deployment workflow file for dev&test --- .github/workflows/promote-dev.yml | 10 ++++++++-- .github/workflows/promote-test.yml | 25 +++++++++++++------------ 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/.github/workflows/promote-dev.yml b/.github/workflows/promote-dev.yml index 0a4011f1d..89e1b377a 100644 --- a/.github/workflows/promote-dev.yml +++ b/.github/workflows/promote-dev.yml @@ -70,6 +70,7 @@ jobs: uses: actions/checkout@v2 with: ref: ${{ github.event.inputs.ref || github.ref }} + fetch-depth: 0 - name: Install OpenShift CLI uses: redhat-actions/openshift-tools-installer@v1 @@ -82,7 +83,9 @@ jobs: filters: | src: - 'openshift/**' - base: 'refs/heads/dev-env~1' #Compare against previous commit on dev-env branch + #github.event.before is the SHA of the commit before the push event (only available during push events) + #HEAD~1 is the commit right before the latest commit on dev-env + base: ${{ github.event.before || 'HEAD~1' }} - name: Dry run - Dev env: OS_NAMESPACE_SUFFIX: dev @@ -111,6 +114,7 @@ jobs: uses: actions/checkout@v2 with: ref: ${{ github.event.inputs.ref || github.ref }} + fetch-depth: 0 - name: Install OpenShift CLI uses: redhat-actions/openshift-tools-installer@v1 with: @@ -121,7 +125,9 @@ jobs: filters: | src: - 'openshift/**' - base: 'refs/heads/dev-env~1' #Compare against previous commit on dev-env branch + #github.event.before is the SHA of the commit before the push event (only available during push events) + #HEAD~1 is the commit right before the latest commit on dev-env + base: ${{ github.event.before || 'HEAD~1' }} - name: Apply Changes env: OS_NAMESPACE_SUFFIX: dev diff --git a/.github/workflows/promote-test.yml b/.github/workflows/promote-test.yml index d156e8ce7..8f9ddea79 100644 --- a/.github/workflows/promote-test.yml +++ b/.github/workflows/promote-test.yml @@ -1,14 +1,12 @@ # Promotion to test env. -# Trigger with manual dispatch - -# Example Scenarios -# Manual Deployment from Feature Branch: -# User manually triggers workflow -# Provides ticket number in the reason field -# Selects "feature/feature-name" in the ref input -# Code is checked out from "feature/feature-name" -# Deployment proceeds with that code - +# Trigger with manual dispatch only +# +# Deployment Process: +# User manually triggers workflow +# Provides ticket number in the reason field +# Workflow checks for OpenShift config changes +# Requires approval from environment protection rules +# Deploys the selected branch to test environment name: OpenShift Deploy/Promotion to Test on: @@ -38,6 +36,7 @@ jobs: uses: actions/checkout@v2 with: ref: ${{ github.event.inputs.ref }} + fetch-depth: 0 - name: Cache OpenShift CLI id: cache-oc @@ -67,7 +66,7 @@ jobs: filters: | src: - 'openshift/**' - base: 'refs/heads/test-env~1' #Compare against previous commit on test-env branch + base: 'HEAD~1' #The commit right before the latest commit on test-env - name: Dry run - Test env: @@ -96,13 +95,15 @@ jobs: uses: actions/checkout@v2 with: ref: ${{ github.event.inputs.ref }} + fetch-depth: 0 - uses: dorny/paths-filter@v2 id: changes with: filters: | src: - 'openshift/**' - base: 'refs/heads/test-env~1' #Compare against previous commit on test-env branch + base: 'HEAD~1' #The commit right before the latest commit on test-env + - name: Apply Changes env: OS_NAMESPACE_SUFFIX: test From 055eb489ebacc259336c3d5decc19fbcb543b236 Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Wed, 21 May 2025 14:54:06 -0700 Subject: [PATCH 12/28] update the deployment workflow file for dev&test (#1100) * update the format/sonar/test workflow configurations * update the deployment workflow file for dev-env * update test deployment workflow * remove the auto deployment feture on test-env * remove tags for dev&test deployments * update the deployment workflow file for dev&test --- .github/workflows/promote-dev.yml | 10 ++++++++-- .github/workflows/promote-test.yml | 25 +++++++++++++------------ 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/.github/workflows/promote-dev.yml b/.github/workflows/promote-dev.yml index 0a4011f1d..89e1b377a 100644 --- a/.github/workflows/promote-dev.yml +++ b/.github/workflows/promote-dev.yml @@ -70,6 +70,7 @@ jobs: uses: actions/checkout@v2 with: ref: ${{ github.event.inputs.ref || github.ref }} + fetch-depth: 0 - name: Install OpenShift CLI uses: redhat-actions/openshift-tools-installer@v1 @@ -82,7 +83,9 @@ jobs: filters: | src: - 'openshift/**' - base: 'refs/heads/dev-env~1' #Compare against previous commit on dev-env branch + #github.event.before is the SHA of the commit before the push event (only available during push events) + #HEAD~1 is the commit right before the latest commit on dev-env + base: ${{ github.event.before || 'HEAD~1' }} - name: Dry run - Dev env: OS_NAMESPACE_SUFFIX: dev @@ -111,6 +114,7 @@ jobs: uses: actions/checkout@v2 with: ref: ${{ github.event.inputs.ref || github.ref }} + fetch-depth: 0 - name: Install OpenShift CLI uses: redhat-actions/openshift-tools-installer@v1 with: @@ -121,7 +125,9 @@ jobs: filters: | src: - 'openshift/**' - base: 'refs/heads/dev-env~1' #Compare against previous commit on dev-env branch + #github.event.before is the SHA of the commit before the push event (only available during push events) + #HEAD~1 is the commit right before the latest commit on dev-env + base: ${{ github.event.before || 'HEAD~1' }} - name: Apply Changes env: OS_NAMESPACE_SUFFIX: dev diff --git a/.github/workflows/promote-test.yml b/.github/workflows/promote-test.yml index d156e8ce7..8f9ddea79 100644 --- a/.github/workflows/promote-test.yml +++ b/.github/workflows/promote-test.yml @@ -1,14 +1,12 @@ # Promotion to test env. -# Trigger with manual dispatch - -# Example Scenarios -# Manual Deployment from Feature Branch: -# User manually triggers workflow -# Provides ticket number in the reason field -# Selects "feature/feature-name" in the ref input -# Code is checked out from "feature/feature-name" -# Deployment proceeds with that code - +# Trigger with manual dispatch only +# +# Deployment Process: +# User manually triggers workflow +# Provides ticket number in the reason field +# Workflow checks for OpenShift config changes +# Requires approval from environment protection rules +# Deploys the selected branch to test environment name: OpenShift Deploy/Promotion to Test on: @@ -38,6 +36,7 @@ jobs: uses: actions/checkout@v2 with: ref: ${{ github.event.inputs.ref }} + fetch-depth: 0 - name: Cache OpenShift CLI id: cache-oc @@ -67,7 +66,7 @@ jobs: filters: | src: - 'openshift/**' - base: 'refs/heads/test-env~1' #Compare against previous commit on test-env branch + base: 'HEAD~1' #The commit right before the latest commit on test-env - name: Dry run - Test env: @@ -96,13 +95,15 @@ jobs: uses: actions/checkout@v2 with: ref: ${{ github.event.inputs.ref }} + fetch-depth: 0 - uses: dorny/paths-filter@v2 id: changes with: filters: | src: - 'openshift/**' - base: 'refs/heads/test-env~1' #Compare against previous commit on test-env branch + base: 'HEAD~1' #The commit right before the latest commit on test-env + - name: Apply Changes env: OS_NAMESPACE_SUFFIX: test From 73f3bb3f80088776c346ab716f9452ccadc72877 Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Wed, 21 May 2025 17:21:45 -0700 Subject: [PATCH 13/28] update README for deployment --- Makefile | 20 ++++------------ docs/deployment.md | 57 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index 3ce75d623..c97c9d657 100644 --- a/Makefile +++ b/Makefile @@ -163,23 +163,13 @@ local-kc-arm-down: @docker-compose -f docker-compose.arm.test.yml down --remove-orphans # Branch-based deployment commands -deploy-to-dev: #deploy the code on dev-env branch to DEV env on OpenShift +deploy-to-dev: #deploy the code on current branch to DEV env via dev-env branch ifdef ticket - @echo "Creating branch dev-env from current branch with ticket $(ticket)" - @git checkout -B dev-env - @git push -f origin dev-env + @echo "Deploying current branch to DEV with ticket $(ticket)" + @CURRENT_BRANCH=$(shell git rev-parse --abbrev-ref HEAD) && \ + git push origin $$CURRENT_BRANCH:dev-env -f else - @echo -e '\nTicket name missing - Example :: make deploy-to-dev ticket=HCAP-ABC \n' -endif - -prepare-test-branch: #For test, we don't automatically deploy, just prepare the branch -ifdef ticket - @echo "Creating branch test-env from current branch with ticket $(ticket)" - @git checkout -B test-env - @git push -f origin test-env - @echo "Branch test-env updated. Use GitHub Actions workflow to deploy with proper RFC." -else - @echo -e '\nTicket name missing - Example :: make prepare-test-branch ticket=HCAP-ABC \n' + @echo -e '\nTicket name missing - Example :: make deploy-to-dev ticket=BCMOHAM-12345 \n' endif tag-prod: diff --git a/docs/deployment.md b/docs/deployment.md index 3f9ffbf81..7d87efcde 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -1,6 +1,5 @@ # Deployment - ## OpenShift Application The Dockerized application is deployed to OpenShift using Makefile targets and YAML templates defined in the `openshift` directory. @@ -19,6 +18,62 @@ Route | Exposes a service to the Internet. Routes differ from services in that t Deployment Config | Defines how a new version of an application is to be deployed. Additionally, triggers for redeployment are defined within this object. For the HCAP application, we've used a rolling deployment triggered by new images pushed to the image stream and tagged with the `latest` tag. Secret |Defines values that can be used by pods within in the same namespace. While there are no secrets defined in our server application, there is a reference to a secret defined by the [MongoDB database template](openshift/mongo.yml). In order for the server to access the DB, it must be provided with `MONGODB_DATABASE` and `MONGODB_URI` environment variables. The definition for these environment variables can be found in the [server deployment config template](openshift/server.dc.yml). Note that they are referencing the `${APP_NAME}-mongodb` (resolves to `hcap-mongodb`) secret and the `mongo-url` and `database` keys within this secret. +## Deployment Process + +The application uses a branch-based deployment strategy for development and test environments, and a tag-based approach for production. + +### Development Environment + +Deployments to the development environment can be triggered by these 3 approaches: + +1. Creating and merging a PR to the `dev-env` branch +2. Manually triggering the "OpenShift Deploy/Promotion to Dev" workflow in GitHub Actions +3. Using the Makefile command for quick deployments without a PR: + +```bash +# Deploy your current branch to dev +make deploy-to-dev ticket=BCMOHAM-12345 +``` + +This command will: +- Get your current branch name +- Force push your current branch to the remote `dev-env` branch +- Trigger the GitHub Actions workflow for deployment to dev + +### Test Environment + +Deployments to the test environment follow a more controlled process: + +1. Create a PR from `dev-env` to `test-env` +2. Get the PR reviewed and approved by the team +3. Merge the approved PR to update the `test-env` branch +4. Go to GitHub Actions +5. Select "OpenShift Deploy/Promotion to Test" workflow +6. Click "Run workflow" +7. Enter the ticket number (e.g., BCMOHAM-12345) in the reason field +8. Select the branch (`test-env`) +9. Submit the workflow +10. Wait for environment approval and deployment completion + +Test deployments require: +- The ticket number +- PR approval from authorized team members +- Manual workflow trigger with proper documentation +- Final environment approval in GitHub Actions + +### Production Environment (TODO) + +Production deployments use a tag-based approach: + +```bash +# Use the Makefile command +make tag-prod ticket=HCAP-123 +``` + +This command will: +- Create a tag named `prod` pointing to your current commit +- Push it to the remote repository +- Trigger the GitHub Actions workflow for deployment to production ## Dev/Test Certificate Creation From 41223ae04f8e9e92ba5e5095d52f9c004fca259d Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Thu, 22 May 2025 10:04:30 -0700 Subject: [PATCH 14/28] Add separate branches (dev-env and test-env) for the development and test environments. (#1097) * update the format/sonar/test workflow configurations * update the format/sonar/test workflow configurations (#1094) * update the deployment workflow file for dev-env * update the deployment workflow file for dev-env (#1095) * update the format/sonar/test workflow configurations * update the deployment workflow file for dev-env * update test deployment workflow * update test deployment workflow (#1096) * update the format/sonar/test workflow configurations * update the deployment workflow file for dev-env * update test deployment workflow * remove the auto deployment feture on test-env * Remove the auto deployment feature on test-env (#1098) * update the format/sonar/test workflow configurations * update the deployment workflow file for dev-env * update test deployment workflow * remove the auto deployment feture on test-env * remove tags for dev&test deployments * remove tags for dev&test deployments (#1099) * update the format/sonar/test workflow configurations * update the deployment workflow file for dev-env * update test deployment workflow * remove the auto deployment feture on test-env * remove tags for dev&test deployments * update the deployment workflow file for dev&test * update the deployment workflow file for dev&test (#1100) * update the format/sonar/test workflow configurations * update the deployment workflow file for dev-env * update test deployment workflow * remove the auto deployment feture on test-env * remove tags for dev&test deployments * update the deployment workflow file for dev&test * update README for deployment --- .github/workflows/format.yml | 2 +- .../workflows/{build.yml => promote-dev.yml} | 50 +++++++++++++--- .github/workflows/promote-test.yml | 36 +++++++++--- .github/workflows/sonar.yml | 2 + .github/workflows/test.yml | 2 + Makefile | 24 ++------ docs/deployment.md | 57 ++++++++++++++++++- 7 files changed, 138 insertions(+), 35 deletions(-) rename .github/workflows/{build.yml => promote-dev.yml} (72%) diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index cf55b4ecb..524e5c749 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -1,7 +1,7 @@ name: Check format of code base on: pull_request: - types: [opened, synchronize] + types: [opened, synchronize, reopened] jobs: premerge: diff --git a/.github/workflows/build.yml b/.github/workflows/promote-dev.yml similarity index 72% rename from .github/workflows/build.yml rename to .github/workflows/promote-dev.yml index 79a4c83be..89e1b377a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/promote-dev.yml @@ -1,14 +1,34 @@ # Build and Deploy to dev env. -# Trigger with tag dev -# Connected with repo environment 'dev' -name: OpenShift Build and Deploy to Dev with OWSAP ZAP SCAN +# Trigger with branch dev-env or manual dispatch + +# Example Scenarios +# Automatic Deployment: +# Someone pushes to dev-env +# Workflow triggers automatically +# github.event.inputs.ref is empty +# Code is checked out from github.ref (dev-env branch) +# Manual Deployment from Feature Branch: +# User manually triggers workflow +# Selects "feature/feature-name" in the ref input +# Code is checked out from "feature/feature-name" +# Deployment proceeds with that code + +name: OpenShift Deploy/Promotion to Dev with OWSAP ZAP SCAN on: + workflow_dispatch: + inputs: + reason: + description: 'Reason for manual deployment' + required: true + default: 'Manual dev deployment' + ref: + description: 'Branch to deploy (default: dev-env)' + required: false + default: 'dev-env' push: branches: - - master - tags: - - dev + - dev-env env: CLUSTER: https://api.silver.devops.gov.bc.ca:6443 @@ -25,6 +45,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref || github.ref }} - name: Install OpenShift CLI uses: redhat-actions/openshift-tools-installer@v1 @@ -46,6 +68,9 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref || github.ref }} + fetch-depth: 0 - name: Install OpenShift CLI uses: redhat-actions/openshift-tools-installer@v1 @@ -58,7 +83,9 @@ jobs: filters: | src: - 'openshift/**' - base: ${{ github.ref }} + #github.event.before is the SHA of the commit before the push event (only available during push events) + #HEAD~1 is the commit right before the latest commit on dev-env + base: ${{ github.event.before || 'HEAD~1' }} - name: Dry run - Dev env: OS_NAMESPACE_SUFFIX: dev @@ -85,6 +112,9 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref || github.ref }} + fetch-depth: 0 - name: Install OpenShift CLI uses: redhat-actions/openshift-tools-installer@v1 with: @@ -95,7 +125,9 @@ jobs: filters: | src: - 'openshift/**' - base: ${{ github.ref}} + #github.event.before is the SHA of the commit before the push event (only available during push events) + #HEAD~1 is the commit right before the latest commit on dev-env + base: ${{ github.event.before || 'HEAD~1' }} - name: Apply Changes env: OS_NAMESPACE_SUFFIX: dev @@ -115,6 +147,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref || github.ref }} - name: Install OpenShift CLI uses: redhat-actions/openshift-tools-installer@v1 with: diff --git a/.github/workflows/promote-test.yml b/.github/workflows/promote-test.yml index e09c6234c..8f9ddea79 100644 --- a/.github/workflows/promote-test.yml +++ b/.github/workflows/promote-test.yml @@ -1,12 +1,25 @@ # Promotion to test env. -# Trigger with tag push -# Connected with repo environment 'test' +# Trigger with manual dispatch only +# +# Deployment Process: +# User manually triggers workflow +# Provides ticket number in the reason field +# Workflow checks for OpenShift config changes +# Requires approval from environment protection rules +# Deploys the selected branch to test environment name: OpenShift Deploy/Promotion to Test on: - push: - tags: - - test + workflow_dispatch: + inputs: + reason: + description: 'Reason for deployment to test (include ticket number)' + required: true + default: 'BCMOHAM-XXXXX: Test deployment' + ref: + description: 'Branch to deploy (default: test-env)' + required: false + default: 'test-env' env: CLUSTER: https://api.silver.devops.gov.bc.ca:6443 @@ -21,6 +34,9 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref }} + fetch-depth: 0 - name: Cache OpenShift CLI id: cache-oc @@ -50,7 +66,7 @@ jobs: filters: | src: - 'openshift/**' - base: 'refs/tags/test' + base: 'HEAD~1' #The commit right before the latest commit on test-env - name: Dry run - Test env: @@ -77,13 +93,17 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref }} + fetch-depth: 0 - uses: dorny/paths-filter@v2 id: changes with: filters: | src: - 'openshift/**' - base: 'refs/tags/test' + base: 'HEAD~1' #The commit right before the latest commit on test-env + - name: Apply Changes env: OS_NAMESPACE_SUFFIX: test @@ -103,6 +123,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref }} - name: Cache OpenShift CLI id: cache-oc diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index 7755a633a..3126db27f 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -3,6 +3,8 @@ on: push: branches: - master + - dev-env + - test-env pull_request: types: [opened, synchronize, reopened] jobs: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 263db0b99..17f28b774 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,6 +7,8 @@ on: pull_request: branches: + - dev-env + - test-env - master env: KEYCLOAK_LOCAL_USERNAME: 'test-admin' diff --git a/Makefile b/Makefile index c15933dd7..c97c9d657 100644 --- a/Makefile +++ b/Makefile @@ -162,27 +162,15 @@ local-kc-arm-down: @echo "Stopping local app container" @docker-compose -f docker-compose.arm.test.yml down --remove-orphans -# Git Tagging Aliases - -tag-dev: +# Branch-based deployment commands +deploy-to-dev: #deploy the code on current branch to DEV env via dev-env branch ifdef ticket - @git tag -fa dev -m "Deploy $(ticket) to DEV env" + @echo "Deploying current branch to DEV with ticket $(ticket)" + @CURRENT_BRANCH=$(shell git rev-parse --abbrev-ref HEAD) && \ + git push origin $$CURRENT_BRANCH:dev-env -f else - @echo -e '\nTicket name missing - Example :: make tag-dev ticket=HCAP-ABC \n' - @echo -e 'Falling Back to using branch name \n' - @git tag -fa dev -m "Deploy $(git rev-parse --abbrev-ref HEAD) to DEV env" -endif - @git push --force origin refs/tags/dev:refs/tags/dev - -tag-test: -ifdef ticket - @git tag -fa test -m "Deploy $(ticket) to TEST env" -else - @echo -e '\nTicket name missing - Example :: make tag-test ticket=HCAP-ABC \n' - @echo -e 'Falling Back to using branch name\n' - @git tag -fa test -m "Deploy $(git rev-parse --abbrev-ref HEAD) to TEST env" + @echo -e '\nTicket name missing - Example :: make deploy-to-dev ticket=BCMOHAM-12345 \n' endif - @git push --force origin refs/tags/test:refs/tags/test tag-prod: ifdef ticket diff --git a/docs/deployment.md b/docs/deployment.md index 3f9ffbf81..7d87efcde 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -1,6 +1,5 @@ # Deployment - ## OpenShift Application The Dockerized application is deployed to OpenShift using Makefile targets and YAML templates defined in the `openshift` directory. @@ -19,6 +18,62 @@ Route | Exposes a service to the Internet. Routes differ from services in that t Deployment Config | Defines how a new version of an application is to be deployed. Additionally, triggers for redeployment are defined within this object. For the HCAP application, we've used a rolling deployment triggered by new images pushed to the image stream and tagged with the `latest` tag. Secret |Defines values that can be used by pods within in the same namespace. While there are no secrets defined in our server application, there is a reference to a secret defined by the [MongoDB database template](openshift/mongo.yml). In order for the server to access the DB, it must be provided with `MONGODB_DATABASE` and `MONGODB_URI` environment variables. The definition for these environment variables can be found in the [server deployment config template](openshift/server.dc.yml). Note that they are referencing the `${APP_NAME}-mongodb` (resolves to `hcap-mongodb`) secret and the `mongo-url` and `database` keys within this secret. +## Deployment Process + +The application uses a branch-based deployment strategy for development and test environments, and a tag-based approach for production. + +### Development Environment + +Deployments to the development environment can be triggered by these 3 approaches: + +1. Creating and merging a PR to the `dev-env` branch +2. Manually triggering the "OpenShift Deploy/Promotion to Dev" workflow in GitHub Actions +3. Using the Makefile command for quick deployments without a PR: + +```bash +# Deploy your current branch to dev +make deploy-to-dev ticket=BCMOHAM-12345 +``` + +This command will: +- Get your current branch name +- Force push your current branch to the remote `dev-env` branch +- Trigger the GitHub Actions workflow for deployment to dev + +### Test Environment + +Deployments to the test environment follow a more controlled process: + +1. Create a PR from `dev-env` to `test-env` +2. Get the PR reviewed and approved by the team +3. Merge the approved PR to update the `test-env` branch +4. Go to GitHub Actions +5. Select "OpenShift Deploy/Promotion to Test" workflow +6. Click "Run workflow" +7. Enter the ticket number (e.g., BCMOHAM-12345) in the reason field +8. Select the branch (`test-env`) +9. Submit the workflow +10. Wait for environment approval and deployment completion + +Test deployments require: +- The ticket number +- PR approval from authorized team members +- Manual workflow trigger with proper documentation +- Final environment approval in GitHub Actions + +### Production Environment (TODO) + +Production deployments use a tag-based approach: + +```bash +# Use the Makefile command +make tag-prod ticket=HCAP-123 +``` + +This command will: +- Create a tag named `prod` pointing to your current commit +- Push it to the remote repository +- Trigger the GitHub Actions workflow for deployment to production ## Dev/Test Certificate Creation From c08fe420e51f9a196342c5101e01977766ac0503 Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Thu, 22 May 2025 17:14:22 -0700 Subject: [PATCH 15/28] update the manual trigger on dev&test deployment files --- .github/workflows/promote-dev.yml | 8 ++++---- .github/workflows/promote-test.yml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/promote-dev.yml b/.github/workflows/promote-dev.yml index 89e1b377a..56c21aa26 100644 --- a/.github/workflows/promote-dev.yml +++ b/.github/workflows/promote-dev.yml @@ -84,8 +84,8 @@ jobs: src: - 'openshift/**' #github.event.before is the SHA of the commit before the push event (only available during push events) - #HEAD~1 is the commit right before the latest commit on dev-env - base: ${{ github.event.before || 'HEAD~1' }} + #format('{0}~1', github.sha) is the commit that is one before the current commit that triggered this workflow. + base: ${{ github.event.before || format('{0}~1', github.sha) }} - name: Dry run - Dev env: OS_NAMESPACE_SUFFIX: dev @@ -126,8 +126,8 @@ jobs: src: - 'openshift/**' #github.event.before is the SHA of the commit before the push event (only available during push events) - #HEAD~1 is the commit right before the latest commit on dev-env - base: ${{ github.event.before || 'HEAD~1' }} + #format('{0}~1', github.sha) is the commit that is one before the current commit that triggered this workflow. + base: ${{ github.event.before || format('{0}~1', github.sha) }} - name: Apply Changes env: OS_NAMESPACE_SUFFIX: dev diff --git a/.github/workflows/promote-test.yml b/.github/workflows/promote-test.yml index 8f9ddea79..b99ad9301 100644 --- a/.github/workflows/promote-test.yml +++ b/.github/workflows/promote-test.yml @@ -66,7 +66,7 @@ jobs: filters: | src: - 'openshift/**' - base: 'HEAD~1' #The commit right before the latest commit on test-env + base: ${{ format('{0}~1', github.sha) }} #The commit right before the current commit - name: Dry run - Test env: @@ -102,7 +102,7 @@ jobs: filters: | src: - 'openshift/**' - base: 'HEAD~1' #The commit right before the latest commit on test-env + base: ${{ format('{0}~1', github.sha) }} #The commit right before the current commit - name: Apply Changes env: From 2b2aa75d1282fa7b40bbd3882b12f5f3ec183114 Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Thu, 22 May 2025 17:15:20 -0700 Subject: [PATCH 16/28] update the manual trigger on dev&test deployment files (#1102) --- .github/workflows/promote-dev.yml | 8 ++++---- .github/workflows/promote-test.yml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/promote-dev.yml b/.github/workflows/promote-dev.yml index 89e1b377a..56c21aa26 100644 --- a/.github/workflows/promote-dev.yml +++ b/.github/workflows/promote-dev.yml @@ -84,8 +84,8 @@ jobs: src: - 'openshift/**' #github.event.before is the SHA of the commit before the push event (only available during push events) - #HEAD~1 is the commit right before the latest commit on dev-env - base: ${{ github.event.before || 'HEAD~1' }} + #format('{0}~1', github.sha) is the commit that is one before the current commit that triggered this workflow. + base: ${{ github.event.before || format('{0}~1', github.sha) }} - name: Dry run - Dev env: OS_NAMESPACE_SUFFIX: dev @@ -126,8 +126,8 @@ jobs: src: - 'openshift/**' #github.event.before is the SHA of the commit before the push event (only available during push events) - #HEAD~1 is the commit right before the latest commit on dev-env - base: ${{ github.event.before || 'HEAD~1' }} + #format('{0}~1', github.sha) is the commit that is one before the current commit that triggered this workflow. + base: ${{ github.event.before || format('{0}~1', github.sha) }} - name: Apply Changes env: OS_NAMESPACE_SUFFIX: dev diff --git a/.github/workflows/promote-test.yml b/.github/workflows/promote-test.yml index 8f9ddea79..b99ad9301 100644 --- a/.github/workflows/promote-test.yml +++ b/.github/workflows/promote-test.yml @@ -66,7 +66,7 @@ jobs: filters: | src: - 'openshift/**' - base: 'HEAD~1' #The commit right before the latest commit on test-env + base: ${{ format('{0}~1', github.sha) }} #The commit right before the current commit - name: Dry run - Test env: @@ -102,7 +102,7 @@ jobs: filters: | src: - 'openshift/**' - base: 'HEAD~1' #The commit right before the latest commit on test-env + base: ${{ format('{0}~1', github.sha) }} #The commit right before the current commit - name: Apply Changes env: From b758344d71833813f70ad7511b8c66e35eeb929a Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Fri, 23 May 2025 10:36:15 -0700 Subject: [PATCH 17/28] update format('{0}~1', github.sha) to 'HEAD^' --- .github/workflows/promote-dev.yml | 8 ++++---- .github/workflows/promote-test.yml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/promote-dev.yml b/.github/workflows/promote-dev.yml index 56c21aa26..91c49440a 100644 --- a/.github/workflows/promote-dev.yml +++ b/.github/workflows/promote-dev.yml @@ -84,8 +84,8 @@ jobs: src: - 'openshift/**' #github.event.before is the SHA of the commit before the push event (only available during push events) - #format('{0}~1', github.sha) is the commit that is one before the current commit that triggered this workflow. - base: ${{ github.event.before || format('{0}~1', github.sha) }} + #'HEAD^' refers to the commit that is one before the current commit that triggered this workflow + base: ${{ github.event.before || 'HEAD^' }} - name: Dry run - Dev env: OS_NAMESPACE_SUFFIX: dev @@ -126,8 +126,8 @@ jobs: src: - 'openshift/**' #github.event.before is the SHA of the commit before the push event (only available during push events) - #format('{0}~1', github.sha) is the commit that is one before the current commit that triggered this workflow. - base: ${{ github.event.before || format('{0}~1', github.sha) }} + #'HEAD^' refers to the commit that is one before the current commit that triggered this workflow + base: ${{ github.event.before || 'HEAD^' }} - name: Apply Changes env: OS_NAMESPACE_SUFFIX: dev diff --git a/.github/workflows/promote-test.yml b/.github/workflows/promote-test.yml index b99ad9301..677ae6b9c 100644 --- a/.github/workflows/promote-test.yml +++ b/.github/workflows/promote-test.yml @@ -66,7 +66,7 @@ jobs: filters: | src: - 'openshift/**' - base: ${{ format('{0}~1', github.sha) }} #The commit right before the current commit + base: 'HEAD^' #The commit right before the current commit - name: Dry run - Test env: @@ -102,7 +102,7 @@ jobs: filters: | src: - 'openshift/**' - base: ${{ format('{0}~1', github.sha) }} #The commit right before the current commit + base: 'HEAD^' #The commit right before the current commit - name: Apply Changes env: From 1d4379b3cda00ef6f725785f6787567cb1929441 Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Fri, 23 May 2025 10:37:26 -0700 Subject: [PATCH 18/28] update format('{0}~1', github.sha) to 'HEAD^' (#1103) * update the manual trigger on dev&test deployment files * update format('{0}~1', github.sha) to 'HEAD^' --- .github/workflows/promote-dev.yml | 8 ++++---- .github/workflows/promote-test.yml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/promote-dev.yml b/.github/workflows/promote-dev.yml index 56c21aa26..91c49440a 100644 --- a/.github/workflows/promote-dev.yml +++ b/.github/workflows/promote-dev.yml @@ -84,8 +84,8 @@ jobs: src: - 'openshift/**' #github.event.before is the SHA of the commit before the push event (only available during push events) - #format('{0}~1', github.sha) is the commit that is one before the current commit that triggered this workflow. - base: ${{ github.event.before || format('{0}~1', github.sha) }} + #'HEAD^' refers to the commit that is one before the current commit that triggered this workflow + base: ${{ github.event.before || 'HEAD^' }} - name: Dry run - Dev env: OS_NAMESPACE_SUFFIX: dev @@ -126,8 +126,8 @@ jobs: src: - 'openshift/**' #github.event.before is the SHA of the commit before the push event (only available during push events) - #format('{0}~1', github.sha) is the commit that is one before the current commit that triggered this workflow. - base: ${{ github.event.before || format('{0}~1', github.sha) }} + #'HEAD^' refers to the commit that is one before the current commit that triggered this workflow + base: ${{ github.event.before || 'HEAD^' }} - name: Apply Changes env: OS_NAMESPACE_SUFFIX: dev diff --git a/.github/workflows/promote-test.yml b/.github/workflows/promote-test.yml index b99ad9301..677ae6b9c 100644 --- a/.github/workflows/promote-test.yml +++ b/.github/workflows/promote-test.yml @@ -66,7 +66,7 @@ jobs: filters: | src: - 'openshift/**' - base: ${{ format('{0}~1', github.sha) }} #The commit right before the current commit + base: 'HEAD^' #The commit right before the current commit - name: Dry run - Test env: @@ -102,7 +102,7 @@ jobs: filters: | src: - 'openshift/**' - base: ${{ format('{0}~1', github.sha) }} #The commit right before the current commit + base: 'HEAD^' #The commit right before the current commit - name: Apply Changes env: From bc4ae09bf84bf20de268460b385e3c492a70b039 Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Fri, 23 May 2025 13:35:17 -0700 Subject: [PATCH 19/28] add step to get previous commit --- .github/workflows/promote-dev.yml | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/.github/workflows/promote-dev.yml b/.github/workflows/promote-dev.yml index 91c49440a..77a79e3e8 100644 --- a/.github/workflows/promote-dev.yml +++ b/.github/workflows/promote-dev.yml @@ -77,15 +77,19 @@ jobs: with: oc: latest + - name: Get previous commit + id: get-prev-commit + run: echo "prev_commit=$(git rev-parse HEAD^)" >> $GITHUB_OUTPUT + - uses: dorny/paths-filter@v2 id: changes with: filters: | src: - 'openshift/**' - #github.event.before is the SHA of the commit before the push event (only available during push events) - #'HEAD^' refers to the commit that is one before the current commit that triggered this workflow - base: ${{ github.event.before || 'HEAD^' }} + # github.event.before is the SHA of the commit before the push event (only available during push events) + # steps.get-prev-commit.outputs.prev_commit contains the SHA of the parent commit (one before the current commit) + base: ${{ github.event.before || steps.get-prev-commit.outputs.prev_commit }} - name: Dry run - Dev env: OS_NAMESPACE_SUFFIX: dev @@ -119,15 +123,20 @@ jobs: uses: redhat-actions/openshift-tools-installer@v1 with: oc: latest + + - name: Get previous commit + id: get-prev-commit + run: echo "prev_commit=$(git rev-parse HEAD^)" >> $GITHUB_OUTPUT + - uses: dorny/paths-filter@v2 id: changes with: filters: | src: - 'openshift/**' - #github.event.before is the SHA of the commit before the push event (only available during push events) - #'HEAD^' refers to the commit that is one before the current commit that triggered this workflow - base: ${{ github.event.before || 'HEAD^' }} + # github.event.before is the SHA of the commit before the push event (only available during push events) + # steps.get-prev-commit.outputs.prev_commit contains the SHA of the parent commit (one before the current commit) + base: ${{ github.event.before || steps.get-prev-commit.outputs.prev_commit }} - name: Apply Changes env: OS_NAMESPACE_SUFFIX: dev From fcbbc01013a82b31ed74448d6f9b86cf6565e541 Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Fri, 23 May 2025 13:48:33 -0700 Subject: [PATCH 20/28] fix the issue getting the previous commit info --- .github/workflows/promote-test.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/promote-test.yml b/.github/workflows/promote-test.yml index 677ae6b9c..45422c889 100644 --- a/.github/workflows/promote-test.yml +++ b/.github/workflows/promote-test.yml @@ -60,13 +60,17 @@ jobs: - name: Verify OpenShift CLI installation run: oc version + - name: Get previous commit + id: get-prev-commit + run: echo "prev_commit=$(git rev-parse HEAD^)" >> $GITHUB_OUTPUT + - uses: dorny/paths-filter@v2 id: changes with: filters: | src: - 'openshift/**' - base: 'HEAD^' #The commit right before the current commit + base: ${{ steps.get-prev-commit.outputs.prev_commit }} #The commit right before the current commit - name: Dry run - Test env: @@ -96,13 +100,18 @@ jobs: with: ref: ${{ github.event.inputs.ref }} fetch-depth: 0 + + - name: Get previous commit + id: get-prev-commit + run: echo "prev_commit=$(git rev-parse HEAD^)" >> $GITHUB_OUTPUT + - uses: dorny/paths-filter@v2 id: changes with: filters: | src: - 'openshift/**' - base: 'HEAD^' #The commit right before the current commit + base: ${{ steps.get-prev-commit.outputs.prev_commit }} #The commit right before the current commit - name: Apply Changes env: From 1f189e19ca56afcc59bd03898e8f6cd9e0e0aeb8 Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Fri, 23 May 2025 14:33:56 -0700 Subject: [PATCH 21/28] fixing the method of getting the previous commit info on deployment workflow files (#1104) * update the format/sonar/test workflow configurations * update the format/sonar/test workflow configurations (#1094) * update the deployment workflow file for dev-env * update the deployment workflow file for dev-env (#1095) * update the format/sonar/test workflow configurations * update the deployment workflow file for dev-env * update test deployment workflow * update test deployment workflow (#1096) * update the format/sonar/test workflow configurations * update the deployment workflow file for dev-env * update test deployment workflow * remove the auto deployment feture on test-env * Remove the auto deployment feature on test-env (#1098) * update the format/sonar/test workflow configurations * update the deployment workflow file for dev-env * update test deployment workflow * remove the auto deployment feture on test-env * remove tags for dev&test deployments * remove tags for dev&test deployments (#1099) * update the format/sonar/test workflow configurations * update the deployment workflow file for dev-env * update test deployment workflow * remove the auto deployment feture on test-env * remove tags for dev&test deployments * update the deployment workflow file for dev&test * update the deployment workflow file for dev&test (#1100) * update the format/sonar/test workflow configurations * update the deployment workflow file for dev-env * update test deployment workflow * remove the auto deployment feture on test-env * remove tags for dev&test deployments * update the deployment workflow file for dev&test * update README for deployment * update the manual trigger on dev&test deployment files * update the manual trigger on dev&test deployment files (#1102) * update format('{0}~1', github.sha) to 'HEAD^' * update format('{0}~1', github.sha) to 'HEAD^' (#1103) * update the manual trigger on dev&test deployment files * update format('{0}~1', github.sha) to 'HEAD^' * add step to get previous commit * fix the issue getting the previous commit info --- .github/workflows/promote-dev.yml | 21 +++++++++++++++------ .github/workflows/promote-test.yml | 13 +++++++++++-- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/.github/workflows/promote-dev.yml b/.github/workflows/promote-dev.yml index 89e1b377a..77a79e3e8 100644 --- a/.github/workflows/promote-dev.yml +++ b/.github/workflows/promote-dev.yml @@ -77,15 +77,19 @@ jobs: with: oc: latest + - name: Get previous commit + id: get-prev-commit + run: echo "prev_commit=$(git rev-parse HEAD^)" >> $GITHUB_OUTPUT + - uses: dorny/paths-filter@v2 id: changes with: filters: | src: - 'openshift/**' - #github.event.before is the SHA of the commit before the push event (only available during push events) - #HEAD~1 is the commit right before the latest commit on dev-env - base: ${{ github.event.before || 'HEAD~1' }} + # github.event.before is the SHA of the commit before the push event (only available during push events) + # steps.get-prev-commit.outputs.prev_commit contains the SHA of the parent commit (one before the current commit) + base: ${{ github.event.before || steps.get-prev-commit.outputs.prev_commit }} - name: Dry run - Dev env: OS_NAMESPACE_SUFFIX: dev @@ -119,15 +123,20 @@ jobs: uses: redhat-actions/openshift-tools-installer@v1 with: oc: latest + + - name: Get previous commit + id: get-prev-commit + run: echo "prev_commit=$(git rev-parse HEAD^)" >> $GITHUB_OUTPUT + - uses: dorny/paths-filter@v2 id: changes with: filters: | src: - 'openshift/**' - #github.event.before is the SHA of the commit before the push event (only available during push events) - #HEAD~1 is the commit right before the latest commit on dev-env - base: ${{ github.event.before || 'HEAD~1' }} + # github.event.before is the SHA of the commit before the push event (only available during push events) + # steps.get-prev-commit.outputs.prev_commit contains the SHA of the parent commit (one before the current commit) + base: ${{ github.event.before || steps.get-prev-commit.outputs.prev_commit }} - name: Apply Changes env: OS_NAMESPACE_SUFFIX: dev diff --git a/.github/workflows/promote-test.yml b/.github/workflows/promote-test.yml index 8f9ddea79..45422c889 100644 --- a/.github/workflows/promote-test.yml +++ b/.github/workflows/promote-test.yml @@ -60,13 +60,17 @@ jobs: - name: Verify OpenShift CLI installation run: oc version + - name: Get previous commit + id: get-prev-commit + run: echo "prev_commit=$(git rev-parse HEAD^)" >> $GITHUB_OUTPUT + - uses: dorny/paths-filter@v2 id: changes with: filters: | src: - 'openshift/**' - base: 'HEAD~1' #The commit right before the latest commit on test-env + base: ${{ steps.get-prev-commit.outputs.prev_commit }} #The commit right before the current commit - name: Dry run - Test env: @@ -96,13 +100,18 @@ jobs: with: ref: ${{ github.event.inputs.ref }} fetch-depth: 0 + + - name: Get previous commit + id: get-prev-commit + run: echo "prev_commit=$(git rev-parse HEAD^)" >> $GITHUB_OUTPUT + - uses: dorny/paths-filter@v2 id: changes with: filters: | src: - 'openshift/**' - base: 'HEAD~1' #The commit right before the latest commit on test-env + base: ${{ steps.get-prev-commit.outputs.prev_commit }} #The commit right before the current commit - name: Apply Changes env: From ea8d64dc6debe4c7fe408b59a28524ab21541cad Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Mon, 9 Jun 2025 13:34:19 -0700 Subject: [PATCH 22/28] update keycloak-util to include moh_idp (#1105) --- client/src/utils/keycloak-util.js | 2 +- server/keycloak.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/utils/keycloak-util.js b/client/src/utils/keycloak-util.js index 287947108..fe1d17ac4 100644 --- a/client/src/utils/keycloak-util.js +++ b/client/src/utils/keycloak-util.js @@ -6,7 +6,7 @@ * @param idpHint keycloak idp hint */ export const createCustomLoginUrl = (kcInstance, route, idpHint) => { - const idps = ['idir', 'bceid_business']; + const idps = ['idir', 'bceid_business', 'moh_idp']; const loginUrl = kcInstance.createLoginUrl({ idpHint, diff --git a/server/keycloak.ts b/server/keycloak.ts index 2ed8e1668..5d731b141 100644 --- a/server/keycloak.ts +++ b/server/keycloak.ts @@ -10,7 +10,7 @@ import { FEATURE_KEYCLOAK_MIGRATION } from './services/feature-flags'; import { sanitize } from './utils'; const MAX_RETRY = 5; -const options = ['bceid', 'bceid_business', 'idir']; +const options = ['bceid', 'bceid_business', 'idir', 'moh_idp']; const regionMap = { region_fraser: 'Fraser', From 09e3f7fcc3e20d01d781172498d8049b2dbb1b92 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Pham <63203684+npham49@users.noreply.github.com> Date: Fri, 13 Jun 2025 09:24:47 -0700 Subject: [PATCH 23/28] BCMOHAM-26040: Adding script for extracting Business BCeID users' HA mapping (#1107) * initial work on the script, adding the core script and the make commands accordingly * updating git ignore and extraction path * updating comments and adding dir generation function * updating comments * initial work on the script, adding the core script and the make commands accordingly * updating git ignore and extraction path * updating comments and adding dir generation function * updating comments * removing duplicate command from rebasing * updating naming scheme to specifically target business_bceid --- .gitignore | 1 + Makefile | 7 ++ server/scripts/export-user-ha.ts | 143 +++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 server/scripts/export-user-ha.ts diff --git a/.gitignore b/.gitignore index 97ff29d0f..d7851a7a8 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ server/*.pdf server/pdfs/* server/db/.migrate server/build +server/scripts/output # Misc. Dockerrun.aws.json diff --git a/Makefile b/Makefile index c97c9d657..3f5ca28b8 100644 --- a/Makefile +++ b/Makefile @@ -162,6 +162,13 @@ local-kc-arm-down: @echo "Stopping local app container" @docker-compose -f docker-compose.arm.test.yml down --remove-orphans +# Local Scripts +local-export-business-bceid-has: + @npx ts-node ./server/scripts/export-user-ha.ts + +local-export-all-users-has: + @npx ts-node ./server/scripts/export-user-ha.ts --all + # Branch-based deployment commands deploy-to-dev: #deploy the code on current branch to DEV env via dev-env branch ifdef ticket diff --git a/server/scripts/export-user-ha.ts b/server/scripts/export-user-ha.ts new file mode 100644 index 000000000..c063b49f1 --- /dev/null +++ b/server/scripts/export-user-ha.ts @@ -0,0 +1,143 @@ +/* eslint-disable no-console, no-restricted-syntax, no-await-in-loop */ +import { PromisePool } from '@supercharge/promise-pool'; +import fs from 'fs'; +import path from 'path'; +import { AllRoles } from '../constants'; +import keycloak from '../keycloak'; +import { dbClient } from '../db'; +import { getUserSites } from '../services/user'; +import { EmployerSite } from '../services/employers'; + +type UserWithHAArray = { + id: string; + username: string; + firstName: string; + lastName: string; + email: string; + roles: string[]; + sites?: string[]; + HA?: string[]; +}; + +const HA_VALUES = ['Fraser', 'Interior', 'Vancouver Island', 'Northern', 'Vancouver Coastal']; + +// Function to cache BCeID user roles and sites +export const exportUserHAs = async (includeAll: boolean) => { + if (includeAll) { + console.info('Extracting all users'); + } + + const users = []; + + const keycloakUsers: { id: string }[] = await keycloak.getUsers(AllRoles); + await PromisePool.for(keycloakUsers) + .withConcurrency(10) + .process(async (user) => { + users.push({ ...user, roles: await keycloak.getUserRoles(user.id) }); + }); + + if (users.length > 0) { + await dbClient.connect(); + + // Check if the database client is initialized correctly + if (!('db' in dbClient) || !dbClient.db) throw new Error('Database failed to initialize!'); + + // For all users with BCeID roles, get their sites and health authorities + const usersWithSites: UserWithHAArray[] = await Promise.all( + users.map(async (user) => { + // Check if the user has a business BCeID or if we are including all users + if (!user.username.includes('@bceid_business') && !includeAll) { + return null; + } + // Get all sites for the user + const userSites = await getUserSites(user.id); + // Get the HAs for those sites + const HAs: string[] = userSites.map((site: EmployerSite) => site.healthAuthority); + if (user.roles.includes('ministry_of_health')) { + // If the user is a Ministry of Health user, they have access to all HAs + return { + ...user, + sites: userSites.map((site: EmployerSite) => site.siteId), + HA: HA_VALUES, + }; + } + return { + ...user, + sites: userSites.map((site: EmployerSite) => site.siteId), + HA: [...new Set(HAs)], + }; + }) + ).then((results) => results.filter((user) => user !== null)); + + console.info(`Found ${usersWithSites.length} users with sites`); + + const finalUserList: { + id: string; + username: string; + firstName: string; + lastName: string; + email: string; + roles: string[]; + sites?: string[]; + HA?: string; + }[] = []; + + usersWithSites.forEach((user) => { + if (user.HA.length === 0) { + finalUserList.push({ + id: user.id, + username: user.username, + firstName: user.firstName, + lastName: user.lastName, + email: user.email, + roles: user.roles, + sites: user.sites, + HA: '', + }); + return; + } + // Generate a row for each health authority the user has access to + // This allows users with access to multiple HAs to have multiple rows in the CSV + user.HA.forEach((ha) => { + finalUserList.push({ + id: user.id, + username: user.username, + firstName: user.firstName, + lastName: user.lastName, + email: user.email, + roles: user.roles, + sites: user.sites, + HA: ha, + }); + }); + }); + + // Create output directory if it doesn't exist + if (!fs.existsSync(path.join(__dirname, 'output'))) { + fs.mkdirSync(path.join(__dirname, 'output'), { recursive: true }); + } + // Write to CSV file + // Format: username,firstName,lastName,email,HA + const csv = finalUserList + .map((user) => `${user.username},${user.firstName},${user.lastName},${user.email},${user.HA}`) + .join('\n'); + await fs.promises + .writeFile(path.join(__dirname, 'output/business-bceid-users.csv'), csv) + .then(() => { + console.info( + 'Business BCeID users cached successfully to ./server/scripts/output/business-bceid-users.csv' + ); + }) + .catch((err) => { + console.error('Error writing to ./server/scripts/output/business-bceid-users.csv:', err); + }); + } +}; + +(async function main() { + if (require.main === module) { + const includeAll = process.argv.includes('--all'); + await keycloak.buildInternalIdMap(); + await exportUserHAs(includeAll); + } +})(); From f879fea1f89e187a5fd2b3f06e57c3f10540ca03 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Pham <63203684+npham49@users.noreply.github.com> Date: Mon, 16 Jun 2025 14:33:28 -0700 Subject: [PATCH 24/28] BCMOHAM-26040: Adding script for extracting Business BCeID users' HA mapping (#1107) (#1109) * initial work on the script, adding the core script and the make commands accordingly * updating git ignore and extraction path * updating comments and adding dir generation function * updating comments * initial work on the script, adding the core script and the make commands accordingly * updating git ignore and extraction path * updating comments and adding dir generation function * updating comments * removing duplicate command from rebasing * updating naming scheme to specifically target business_bceid --- .gitignore | 1 + Makefile | 7 ++ server/scripts/export-user-ha.ts | 143 +++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 server/scripts/export-user-ha.ts diff --git a/.gitignore b/.gitignore index 97ff29d0f..d7851a7a8 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ server/*.pdf server/pdfs/* server/db/.migrate server/build +server/scripts/output # Misc. Dockerrun.aws.json diff --git a/Makefile b/Makefile index c97c9d657..3f5ca28b8 100644 --- a/Makefile +++ b/Makefile @@ -162,6 +162,13 @@ local-kc-arm-down: @echo "Stopping local app container" @docker-compose -f docker-compose.arm.test.yml down --remove-orphans +# Local Scripts +local-export-business-bceid-has: + @npx ts-node ./server/scripts/export-user-ha.ts + +local-export-all-users-has: + @npx ts-node ./server/scripts/export-user-ha.ts --all + # Branch-based deployment commands deploy-to-dev: #deploy the code on current branch to DEV env via dev-env branch ifdef ticket diff --git a/server/scripts/export-user-ha.ts b/server/scripts/export-user-ha.ts new file mode 100644 index 000000000..c063b49f1 --- /dev/null +++ b/server/scripts/export-user-ha.ts @@ -0,0 +1,143 @@ +/* eslint-disable no-console, no-restricted-syntax, no-await-in-loop */ +import { PromisePool } from '@supercharge/promise-pool'; +import fs from 'fs'; +import path from 'path'; +import { AllRoles } from '../constants'; +import keycloak from '../keycloak'; +import { dbClient } from '../db'; +import { getUserSites } from '../services/user'; +import { EmployerSite } from '../services/employers'; + +type UserWithHAArray = { + id: string; + username: string; + firstName: string; + lastName: string; + email: string; + roles: string[]; + sites?: string[]; + HA?: string[]; +}; + +const HA_VALUES = ['Fraser', 'Interior', 'Vancouver Island', 'Northern', 'Vancouver Coastal']; + +// Function to cache BCeID user roles and sites +export const exportUserHAs = async (includeAll: boolean) => { + if (includeAll) { + console.info('Extracting all users'); + } + + const users = []; + + const keycloakUsers: { id: string }[] = await keycloak.getUsers(AllRoles); + await PromisePool.for(keycloakUsers) + .withConcurrency(10) + .process(async (user) => { + users.push({ ...user, roles: await keycloak.getUserRoles(user.id) }); + }); + + if (users.length > 0) { + await dbClient.connect(); + + // Check if the database client is initialized correctly + if (!('db' in dbClient) || !dbClient.db) throw new Error('Database failed to initialize!'); + + // For all users with BCeID roles, get their sites and health authorities + const usersWithSites: UserWithHAArray[] = await Promise.all( + users.map(async (user) => { + // Check if the user has a business BCeID or if we are including all users + if (!user.username.includes('@bceid_business') && !includeAll) { + return null; + } + // Get all sites for the user + const userSites = await getUserSites(user.id); + // Get the HAs for those sites + const HAs: string[] = userSites.map((site: EmployerSite) => site.healthAuthority); + if (user.roles.includes('ministry_of_health')) { + // If the user is a Ministry of Health user, they have access to all HAs + return { + ...user, + sites: userSites.map((site: EmployerSite) => site.siteId), + HA: HA_VALUES, + }; + } + return { + ...user, + sites: userSites.map((site: EmployerSite) => site.siteId), + HA: [...new Set(HAs)], + }; + }) + ).then((results) => results.filter((user) => user !== null)); + + console.info(`Found ${usersWithSites.length} users with sites`); + + const finalUserList: { + id: string; + username: string; + firstName: string; + lastName: string; + email: string; + roles: string[]; + sites?: string[]; + HA?: string; + }[] = []; + + usersWithSites.forEach((user) => { + if (user.HA.length === 0) { + finalUserList.push({ + id: user.id, + username: user.username, + firstName: user.firstName, + lastName: user.lastName, + email: user.email, + roles: user.roles, + sites: user.sites, + HA: '', + }); + return; + } + // Generate a row for each health authority the user has access to + // This allows users with access to multiple HAs to have multiple rows in the CSV + user.HA.forEach((ha) => { + finalUserList.push({ + id: user.id, + username: user.username, + firstName: user.firstName, + lastName: user.lastName, + email: user.email, + roles: user.roles, + sites: user.sites, + HA: ha, + }); + }); + }); + + // Create output directory if it doesn't exist + if (!fs.existsSync(path.join(__dirname, 'output'))) { + fs.mkdirSync(path.join(__dirname, 'output'), { recursive: true }); + } + // Write to CSV file + // Format: username,firstName,lastName,email,HA + const csv = finalUserList + .map((user) => `${user.username},${user.firstName},${user.lastName},${user.email},${user.HA}`) + .join('\n'); + await fs.promises + .writeFile(path.join(__dirname, 'output/business-bceid-users.csv'), csv) + .then(() => { + console.info( + 'Business BCeID users cached successfully to ./server/scripts/output/business-bceid-users.csv' + ); + }) + .catch((err) => { + console.error('Error writing to ./server/scripts/output/business-bceid-users.csv:', err); + }); + } +}; + +(async function main() { + if (require.main === module) { + const includeAll = process.argv.includes('--all'); + await keycloak.buildInternalIdMap(); + await exportUserHAs(includeAll); + } +})(); From f416fd5ca47a973bb53be2fec7a7054f5f095d84 Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Mon, 16 Jun 2025 15:24:32 -0700 Subject: [PATCH 25/28] update ROS report (#1108) --- .../services/reporting/milestones-report.ts | 168 +++++++----------- server/services/reporting/ros-entries.ts | 20 +-- 2 files changed, 69 insertions(+), 119 deletions(-) diff --git a/server/services/reporting/milestones-report.ts b/server/services/reporting/milestones-report.ts index 5bf09baf1..26f2d7a1f 100644 --- a/server/services/reporting/milestones-report.ts +++ b/server/services/reporting/milestones-report.ts @@ -22,16 +22,6 @@ export const getMohRosMilestonesReport = async () => { id: 'site_id', }, }, - participantStatusJoin: { - type: 'LEFT OUTER', - decomposeTo: 'object', - relation: collections.PARTICIPANTS_STATUS, - on: { - participant_id: 'participant_id', - current: true, - 'data.site': 'siteJoin.body.siteId', - }, - }, }) .find( {}, @@ -48,40 +38,35 @@ export const getMohRosMilestonesReport = async () => { if (!entries || entries.length === 0) { return []; } - // Get the ROS completion status for each participant - const participantIds = entries.map((entry) => entry.participant_id); - - const rosCompletionStatuses = await dbClient.db[collections.PARTICIPANTS_STATUS].find({ - participant_id: participantIds, - status: 'archived', - 'data.type': 'rosComplete', - 'data.confirmed': 'true', - current: true, - }); - - // Create a map of participant IDs to their ROS completion status - const rosCompletionMap = new Map(); - rosCompletionStatuses.forEach((status) => { - rosCompletionMap.set(status.participant_id, { - completed: true, - remainingInSectorOrRoleOrAnother: - status.data?.remainingInSectorOrRoleOrAnother || 'Unknown', - }); - }); - - // Enhance the entries with the ROS completion information - const enhancedEntries = entries.map((entry) => { - const rosCompletion = rosCompletionMap.get(entry.participant_id) || { - completed: false, - remainingInSectorOrRoleOrAnother: 'Unknown', - }; - - return { - ...entry, - rosCompleted: rosCompletion.completed ? 'TRUE' : 'FALSE', - remainingInSectorOrRoleOrAnother: rosCompletion.remainingInSectorOrRoleOrAnother, - }; - }); + + // Process each entry to get ROS completion status individually + const enhancedEntries = await Promise.all( + entries.map(async (entry) => { + // Get ROS completion status for this specific participant + const rosCompletionStatus = await dbClient.db[collections.PARTICIPANTS_STATUS].findOne( + { + participant_id: entry.participant_id, + status: 'archived', + 'data.type': 'rosComplete', + 'data.confirmed': 'true', + current: true, + }, + { + order: [{ field: 'id', direction: 'desc' }], + } + ); + + const rosCompleted = rosCompletionStatus ? 'TRUE' : 'FALSE'; + const remainingInSectorOrRoleOrAnother = + rosCompletionStatus?.data?.remainingInSectorOrRoleOrAnother || 'Unknown'; + + return { + ...entry, + rosCompleted, + remainingInSectorOrRoleOrAnother, + }; + }) + ); return mapRosEntries(enhancedEntries); } catch (error) { @@ -109,16 +94,6 @@ export const getHARosMilestonesReport = async (region: string) => { id: 'site_id', }, }, - participantStatusJoin: { - type: 'LEFT OUTER', - decomposeTo: 'object', - relation: collections.PARTICIPANTS_STATUS, - on: { - participant_id: 'participant_id', - current: true, - 'data.site': 'siteJoin.body.siteId', - }, - }, }) .find( { @@ -139,6 +114,9 @@ export const getHARosMilestonesReport = async (region: string) => { return []; } + // Get the IDs of entries we already have to avoid duplicates + const existingEntryIds = new Set(sameSiteRosEntries.map((entry) => entry.id)); + // HAs need only see the participants in their health region + participants who changed their health region and now assigned to a site withing HAs view // select participants outside HAs region for changed sites const editedEntries = await dbClient.db[collections.ROS_STATUS] @@ -158,16 +136,6 @@ export const getHARosMilestonesReport = async (region: string) => { id: 'site_id', }, }, - participantStatusJoin: { - type: 'LEFT OUTER', - decomposeTo: 'object', - relation: collections.PARTICIPANTS_STATUS, - on: { - participant_id: 'participant_id', - current: true, - 'data.site': 'siteJoin.body.siteId', - }, - }, }) .find({ participant_id: sameSiteRosEntries.map((entry) => entry.participant_id), @@ -175,49 +143,43 @@ export const getHARosMilestonesReport = async (region: string) => { 'data.user <>': 'NULL', }); - // see if we need to display this information for HA based on what participants are included - // if participants are already visible to HA - include information about their previous sites + // Filter out duplicates from editedEntries + const uniqueEditedEntries = editedEntries.filter((entry) => !existingEntryIds.has(entry.id)); + let rosEntries = sameSiteRosEntries; - if (editedEntries.length > 0) { - rosEntries = rosEntries.concat(editedEntries); + if (uniqueEditedEntries.length > 0) { + rosEntries = rosEntries.concat(uniqueEditedEntries); rosEntries.sort((a, b) => a.participant_id - b.participant_id); } - // Get all participant IDs from the combined entries - const participantIds = rosEntries.map((entry) => entry.participant_id); - - // Get ROS completion statuses for these participants - const rosCompletionStatuses = await dbClient.db[collections.PARTICIPANTS_STATUS].find({ - participant_id: participantIds, - status: 'archived', - 'data.type': 'rosComplete', - 'data.confirmed': 'true', - current: true, - }); - - // Create a map of participant IDs to their ROS completion status - const rosCompletionMap = new Map(); - rosCompletionStatuses.forEach((status) => { - rosCompletionMap.set(status.participant_id, { - completed: true, - remainingInSectorOrRoleOrAnother: - status.data?.remainingInSectorOrRoleOrAnother || 'Unknown', - }); - }); - - // Enhance the entries with the ROS completion information - const enhancedEntries = rosEntries.map((entry) => { - const rosCompletion = rosCompletionMap.get(entry.participant_id) || { - completed: false, - remainingInSectorOrRoleOrAnother: 'Unknown', - }; - - return { - ...entry, - rosCompleted: rosCompletion.completed ? 'TRUE' : 'FALSE', - remainingInSectorOrRoleOrAnother: rosCompletion.remainingInSectorOrRoleOrAnother, - }; - }); + // Process each entry to get ROS completion status individually + const enhancedEntries = await Promise.all( + rosEntries.map(async (entry) => { + // Get ROS completion status for this specific participant + const rosCompletionStatus = await dbClient.db[collections.PARTICIPANTS_STATUS].findOne( + { + participant_id: entry.participant_id, + status: 'archived', + 'data.type': 'rosComplete', + 'data.confirmed': 'true', + current: true, + }, + { + order: [{ field: 'id', direction: 'desc' }], // Get the most recent one + } + ); + + const rosCompleted = rosCompletionStatus ? 'TRUE' : 'FALSE'; + const remainingInSectorOrRoleOrAnother = + rosCompletionStatus?.data?.remainingInSectorOrRoleOrAnother || 'Unknown'; + + return { + ...entry, + rosCompleted, + remainingInSectorOrRoleOrAnother, + }; + }) + ); return mapRosEntries(enhancedEntries); } catch (error) { diff --git a/server/services/reporting/ros-entries.ts b/server/services/reporting/ros-entries.ts index de86204da..884cd663c 100644 --- a/server/services/reporting/ros-entries.ts +++ b/server/services/reporting/ros-entries.ts @@ -18,21 +18,14 @@ interface RosEntry { healthAuthority: string; }; }; - participantStatusJoin: { - status: string; - current: boolean; - data: { - type: string; - confirmed: boolean; - remainingInSectorOrRoleOrAnother: string; - }; - }; data: { date: Date | string; startDate: Date | string; positionType?: string; employmentType?: string; }; + rosCompleted: string; + remainingInSectorOrRoleOrAnother: string; } export const mapRosEntries = (rosEntries: RosEntry[]) => @@ -48,11 +41,6 @@ export const mapRosEntries = (rosEntries: RosEntry[]) => positionType: entry.data?.positionType || 'Unknown', healthRegion: entry.siteJoin?.body?.healthAuthority, employmentType: entry.data?.employmentType || 'Unknown', - rosCompleted: - entry.participantStatusJoin?.status === 'archived' && - entry.participantStatusJoin?.data?.type === 'rosComplete' && - entry.participantStatusJoin?.current && - entry.participantStatusJoin?.data?.confirmed, - remainingInSectorOrRoleOrAnother: - entry.participantStatusJoin?.data?.remainingInSectorOrRoleOrAnother ?? 'Unknown', + rosCompleted: entry.rosCompleted, + remainingInSectorOrRoleOrAnother: entry.remainingInSectorOrRoleOrAnother, })); From 883ce1876c6da502f04a7e039f781787f613f78a Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Tue, 17 Jun 2025 08:51:58 -0700 Subject: [PATCH 26/28] remove duplicates on ROS report (#1110) --- .../services/reporting/milestones-report.ts | 8 +++-- server/services/reporting/ros-entries.ts | 31 +++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/server/services/reporting/milestones-report.ts b/server/services/reporting/milestones-report.ts index 26f2d7a1f..bde3e027f 100644 --- a/server/services/reporting/milestones-report.ts +++ b/server/services/reporting/milestones-report.ts @@ -1,5 +1,5 @@ import { dbClient, collections } from '../../db'; -import { mapRosEntries } from './ros-entries'; +import { mapRosEntries, applyDistinct } from './ros-entries'; import logger from '../../logger'; export const getMohRosMilestonesReport = async () => { @@ -68,7 +68,8 @@ export const getMohRosMilestonesReport = async () => { }) ); - return mapRosEntries(enhancedEntries); + const mappedEntries = mapRosEntries(enhancedEntries); + return applyDistinct(mappedEntries); } catch (error) { logger.error(`Error generating MoH ROS milestones report: ${error.message}`); throw error; @@ -181,7 +182,8 @@ export const getHARosMilestonesReport = async (region: string) => { }) ); - return mapRosEntries(enhancedEntries); + const mappedEntries = mapRosEntries(enhancedEntries); + return applyDistinct(mappedEntries); } catch (error) { logger.error( `Error generating HA ROS milestones report for region ${region}: ${error.message}` diff --git a/server/services/reporting/ros-entries.ts b/server/services/reporting/ros-entries.ts index 884cd663c..96a3ab8c0 100644 --- a/server/services/reporting/ros-entries.ts +++ b/server/services/reporting/ros-entries.ts @@ -44,3 +44,34 @@ export const mapRosEntries = (rosEntries: RosEntry[]) => rosCompleted: entry.rosCompleted, remainingInSectorOrRoleOrAnother: entry.remainingInSectorOrRoleOrAnother, })); + +//A helper for the DISTINCT logic +export const applyDistinct = (entries) => { + const uniqueEntries = []; + const seenRecords = new Set(); + + entries.forEach((entry) => { + const distinctKey = JSON.stringify({ + participantId: entry.participantId, + firstName: entry.firstName, + lastName: entry.lastName, + program: entry.program, + startDate: entry.startDate, + endDate: entry.endDate, + siteStartDate: entry.siteStartDate, + positionType: entry.positionType, + employmentType: entry.employmentType, + site: entry.site, + healthRegion: entry.healthRegion, + rosCompleted: entry.rosCompleted, + remainingInSectorOrRoleOrAnother: entry.remainingInSectorOrRoleOrAnother, + }); + + if (!seenRecords.has(distinctKey)) { + seenRecords.add(distinctKey); + uniqueEntries.push(entry); + } + }); + + return uniqueEntries; +}; From fafc99ff2f725f1958e67e1ca9aa12076ab3f46c Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Tue, 17 Jun 2025 15:11:57 -0700 Subject: [PATCH 27/28] ROS report logic update (#1111) * update ROS report (#1108) * remove duplicates on ROS report (#1110) --- .../services/reporting/milestones-report.ts | 180 +++++++----------- server/services/reporting/ros-entries.ts | 51 +++-- 2 files changed, 107 insertions(+), 124 deletions(-) diff --git a/server/services/reporting/milestones-report.ts b/server/services/reporting/milestones-report.ts index 5bf09baf1..bde3e027f 100644 --- a/server/services/reporting/milestones-report.ts +++ b/server/services/reporting/milestones-report.ts @@ -1,5 +1,5 @@ import { dbClient, collections } from '../../db'; -import { mapRosEntries } from './ros-entries'; +import { mapRosEntries, applyDistinct } from './ros-entries'; import logger from '../../logger'; export const getMohRosMilestonesReport = async () => { @@ -22,16 +22,6 @@ export const getMohRosMilestonesReport = async () => { id: 'site_id', }, }, - participantStatusJoin: { - type: 'LEFT OUTER', - decomposeTo: 'object', - relation: collections.PARTICIPANTS_STATUS, - on: { - participant_id: 'participant_id', - current: true, - 'data.site': 'siteJoin.body.siteId', - }, - }, }) .find( {}, @@ -48,42 +38,38 @@ export const getMohRosMilestonesReport = async () => { if (!entries || entries.length === 0) { return []; } - // Get the ROS completion status for each participant - const participantIds = entries.map((entry) => entry.participant_id); - - const rosCompletionStatuses = await dbClient.db[collections.PARTICIPANTS_STATUS].find({ - participant_id: participantIds, - status: 'archived', - 'data.type': 'rosComplete', - 'data.confirmed': 'true', - current: true, - }); - - // Create a map of participant IDs to their ROS completion status - const rosCompletionMap = new Map(); - rosCompletionStatuses.forEach((status) => { - rosCompletionMap.set(status.participant_id, { - completed: true, - remainingInSectorOrRoleOrAnother: - status.data?.remainingInSectorOrRoleOrAnother || 'Unknown', - }); - }); - - // Enhance the entries with the ROS completion information - const enhancedEntries = entries.map((entry) => { - const rosCompletion = rosCompletionMap.get(entry.participant_id) || { - completed: false, - remainingInSectorOrRoleOrAnother: 'Unknown', - }; - - return { - ...entry, - rosCompleted: rosCompletion.completed ? 'TRUE' : 'FALSE', - remainingInSectorOrRoleOrAnother: rosCompletion.remainingInSectorOrRoleOrAnother, - }; - }); - - return mapRosEntries(enhancedEntries); + + // Process each entry to get ROS completion status individually + const enhancedEntries = await Promise.all( + entries.map(async (entry) => { + // Get ROS completion status for this specific participant + const rosCompletionStatus = await dbClient.db[collections.PARTICIPANTS_STATUS].findOne( + { + participant_id: entry.participant_id, + status: 'archived', + 'data.type': 'rosComplete', + 'data.confirmed': 'true', + current: true, + }, + { + order: [{ field: 'id', direction: 'desc' }], + } + ); + + const rosCompleted = rosCompletionStatus ? 'TRUE' : 'FALSE'; + const remainingInSectorOrRoleOrAnother = + rosCompletionStatus?.data?.remainingInSectorOrRoleOrAnother || 'Unknown'; + + return { + ...entry, + rosCompleted, + remainingInSectorOrRoleOrAnother, + }; + }) + ); + + const mappedEntries = mapRosEntries(enhancedEntries); + return applyDistinct(mappedEntries); } catch (error) { logger.error(`Error generating MoH ROS milestones report: ${error.message}`); throw error; @@ -109,16 +95,6 @@ export const getHARosMilestonesReport = async (region: string) => { id: 'site_id', }, }, - participantStatusJoin: { - type: 'LEFT OUTER', - decomposeTo: 'object', - relation: collections.PARTICIPANTS_STATUS, - on: { - participant_id: 'participant_id', - current: true, - 'data.site': 'siteJoin.body.siteId', - }, - }, }) .find( { @@ -139,6 +115,9 @@ export const getHARosMilestonesReport = async (region: string) => { return []; } + // Get the IDs of entries we already have to avoid duplicates + const existingEntryIds = new Set(sameSiteRosEntries.map((entry) => entry.id)); + // HAs need only see the participants in their health region + participants who changed their health region and now assigned to a site withing HAs view // select participants outside HAs region for changed sites const editedEntries = await dbClient.db[collections.ROS_STATUS] @@ -158,16 +137,6 @@ export const getHARosMilestonesReport = async (region: string) => { id: 'site_id', }, }, - participantStatusJoin: { - type: 'LEFT OUTER', - decomposeTo: 'object', - relation: collections.PARTICIPANTS_STATUS, - on: { - participant_id: 'participant_id', - current: true, - 'data.site': 'siteJoin.body.siteId', - }, - }, }) .find({ participant_id: sameSiteRosEntries.map((entry) => entry.participant_id), @@ -175,51 +144,46 @@ export const getHARosMilestonesReport = async (region: string) => { 'data.user <>': 'NULL', }); - // see if we need to display this information for HA based on what participants are included - // if participants are already visible to HA - include information about their previous sites + // Filter out duplicates from editedEntries + const uniqueEditedEntries = editedEntries.filter((entry) => !existingEntryIds.has(entry.id)); + let rosEntries = sameSiteRosEntries; - if (editedEntries.length > 0) { - rosEntries = rosEntries.concat(editedEntries); + if (uniqueEditedEntries.length > 0) { + rosEntries = rosEntries.concat(uniqueEditedEntries); rosEntries.sort((a, b) => a.participant_id - b.participant_id); } - // Get all participant IDs from the combined entries - const participantIds = rosEntries.map((entry) => entry.participant_id); - - // Get ROS completion statuses for these participants - const rosCompletionStatuses = await dbClient.db[collections.PARTICIPANTS_STATUS].find({ - participant_id: participantIds, - status: 'archived', - 'data.type': 'rosComplete', - 'data.confirmed': 'true', - current: true, - }); - - // Create a map of participant IDs to their ROS completion status - const rosCompletionMap = new Map(); - rosCompletionStatuses.forEach((status) => { - rosCompletionMap.set(status.participant_id, { - completed: true, - remainingInSectorOrRoleOrAnother: - status.data?.remainingInSectorOrRoleOrAnother || 'Unknown', - }); - }); - - // Enhance the entries with the ROS completion information - const enhancedEntries = rosEntries.map((entry) => { - const rosCompletion = rosCompletionMap.get(entry.participant_id) || { - completed: false, - remainingInSectorOrRoleOrAnother: 'Unknown', - }; - - return { - ...entry, - rosCompleted: rosCompletion.completed ? 'TRUE' : 'FALSE', - remainingInSectorOrRoleOrAnother: rosCompletion.remainingInSectorOrRoleOrAnother, - }; - }); - - return mapRosEntries(enhancedEntries); + // Process each entry to get ROS completion status individually + const enhancedEntries = await Promise.all( + rosEntries.map(async (entry) => { + // Get ROS completion status for this specific participant + const rosCompletionStatus = await dbClient.db[collections.PARTICIPANTS_STATUS].findOne( + { + participant_id: entry.participant_id, + status: 'archived', + 'data.type': 'rosComplete', + 'data.confirmed': 'true', + current: true, + }, + { + order: [{ field: 'id', direction: 'desc' }], // Get the most recent one + } + ); + + const rosCompleted = rosCompletionStatus ? 'TRUE' : 'FALSE'; + const remainingInSectorOrRoleOrAnother = + rosCompletionStatus?.data?.remainingInSectorOrRoleOrAnother || 'Unknown'; + + return { + ...entry, + rosCompleted, + remainingInSectorOrRoleOrAnother, + }; + }) + ); + + const mappedEntries = mapRosEntries(enhancedEntries); + return applyDistinct(mappedEntries); } catch (error) { logger.error( `Error generating HA ROS milestones report for region ${region}: ${error.message}` diff --git a/server/services/reporting/ros-entries.ts b/server/services/reporting/ros-entries.ts index de86204da..96a3ab8c0 100644 --- a/server/services/reporting/ros-entries.ts +++ b/server/services/reporting/ros-entries.ts @@ -18,21 +18,14 @@ interface RosEntry { healthAuthority: string; }; }; - participantStatusJoin: { - status: string; - current: boolean; - data: { - type: string; - confirmed: boolean; - remainingInSectorOrRoleOrAnother: string; - }; - }; data: { date: Date | string; startDate: Date | string; positionType?: string; employmentType?: string; }; + rosCompleted: string; + remainingInSectorOrRoleOrAnother: string; } export const mapRosEntries = (rosEntries: RosEntry[]) => @@ -48,11 +41,37 @@ export const mapRosEntries = (rosEntries: RosEntry[]) => positionType: entry.data?.positionType || 'Unknown', healthRegion: entry.siteJoin?.body?.healthAuthority, employmentType: entry.data?.employmentType || 'Unknown', - rosCompleted: - entry.participantStatusJoin?.status === 'archived' && - entry.participantStatusJoin?.data?.type === 'rosComplete' && - entry.participantStatusJoin?.current && - entry.participantStatusJoin?.data?.confirmed, - remainingInSectorOrRoleOrAnother: - entry.participantStatusJoin?.data?.remainingInSectorOrRoleOrAnother ?? 'Unknown', + rosCompleted: entry.rosCompleted, + remainingInSectorOrRoleOrAnother: entry.remainingInSectorOrRoleOrAnother, })); + +//A helper for the DISTINCT logic +export const applyDistinct = (entries) => { + const uniqueEntries = []; + const seenRecords = new Set(); + + entries.forEach((entry) => { + const distinctKey = JSON.stringify({ + participantId: entry.participantId, + firstName: entry.firstName, + lastName: entry.lastName, + program: entry.program, + startDate: entry.startDate, + endDate: entry.endDate, + siteStartDate: entry.siteStartDate, + positionType: entry.positionType, + employmentType: entry.employmentType, + site: entry.site, + healthRegion: entry.healthRegion, + rosCompleted: entry.rosCompleted, + remainingInSectorOrRoleOrAnother: entry.remainingInSectorOrRoleOrAnother, + }); + + if (!seenRecords.has(distinctKey)) { + seenRecords.add(distinctKey); + uniqueEntries.push(entry); + } + }); + + return uniqueEntries; +}; From 1986155307dd653b8c58aff666af2b7549bc862d Mon Sep 17 00:00:00 2001 From: chloe-yuu <84537348+chloe-yuu@users.noreply.github.com> Date: Tue, 17 Jun 2025 15:41:05 -0700 Subject: [PATCH 28/28] Trigger build for deployment