diff --git a/.bin/check-db-changes.sh b/.bin/check-db-changes.sh new file mode 100755 index 0000000000..6305cf79a7 --- /dev/null +++ b/.bin/check-db-changes.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +# Check if there are changes in the db folder +if git diff --quiet HEAD^ HEAD -- db; then + echo "No changes in the db folder. Skipping sqitch tag." +else + echo "Changes detected in the db folder. Running sqitch tag." + docker pull sqitch/sqitch + curl -L https://git.io/JJKCn -o sqitch && chmod +x sqitch + ./sqitch --chdir db tag "$1" -m "release v$1" +fi diff --git a/.github/actions/dev-env-setup/action.yml b/.github/actions/dev-env-setup/action.yml index 4ac050e2e5..07df7f3331 100644 --- a/.github/actions/dev-env-setup/action.yml +++ b/.github/actions/dev-env-setup/action.yml @@ -3,33 +3,7 @@ description: 'Sets up asdf, perl and configures the cache' runs: using: composite steps: - - name: asdf setup - uses: asdf-vm/actions/setup@v2 - - uses: shogo82148/actions-setup-perl@v1 - - name: install pg perl library - run: sudo apt-get install -y libpq-dev libdbd-pg-perl libreadline-dev uuid-dev - shell: bash - - name: set perl env variables - shell: bash - run: | # pragma: allowlist secret - echo "PERL5LIB=/home/runner/perl5/lib/perl5" >> $GITHUB_ENV - echo "PERL_LOCAL_LIB_ROOT=/home/runner/perl5" >> $GITHUB_ENV - echo "PERL_MB_OPT=--install_base '/home/runner/perl5'" >> $GITHUB_ENV - echo "PERL_MM_OPT=INSTALL_BASE=/home/runner/perl5" >> $GITHUB_ENV - echo "/home/runner/perl5/bin" >> $GITHUB_PATH - - uses: actions/cache@v3 - id: asdf-cache - with: - path: | - ~/.asdf - key: ${{ runner.os }}-asdf-cache-${{ hashFiles('.tool-versions') }}-v2 - - uses: actions/cache@v3 - id: perl-cache - with: - path: | - ~/perl5 - key: ${{ runner.os }}-perl-cache-${{ hashFiles('cpanfile') }}-v2 - - uses: actions/cache@v3 + - uses: actions/cache@v4 id: yarn-cache with: path: | diff --git a/.github/actions/local-app-run/action.yaml b/.github/actions/local-app-run/action.yaml index 32836e5a17..4a7c2c703a 100644 --- a/.github/actions/local-app-run/action.yaml +++ b/.github/actions/local-app-run/action.yaml @@ -5,9 +5,29 @@ runs: steps: - name: start postgres and create database shell: bash - run: make start_pg && make drop_db && make create_db + env: + PGPASSWORD: mysecretpassword + run: | + docker run --rm -p 5432:5432 -e POSTGRES_PASSWORD=mysecretpassword -d postgres:15 + # Wait for PostgreSQL to be ready + until docker exec $(docker ps -q -f ancestor=postgres:15) pg_isready -U postgres; do + echo "Waiting for PostgreSQL to be ready..." + sleep 2 + done + # Additional wait to ensure PostgreSQL is fully ready + sleep 5 + # Check PostgreSQL readiness from the host one more time + until pg_isready -h localhost -p 5432 -U postgres; do + echo "Waiting for PostgreSQL to be ready from the host..." + sleep 2 + done + make drop_db PSQL="psql -h localhost -U postgres" + make create_db PSQL="psql -h localhost -U postgres" - name: deploy migrations shell: bash + env: + PGUSER: postgres + PGPASSWORD: mysecretpassword run: | cd db docker pull sqitch/sqitch @@ -15,6 +35,9 @@ runs: ./sqitch deploy - name: deploy mock schema shell: bash + env: + PGUSER: postgres + PGPASSWORD: mysecretpassword run: | cd mocks_schema docker pull sqitch/sqitch @@ -22,4 +45,4 @@ runs: ./sqitch deploy - name: start app shell: bash - run: docker run -d --network=host -e "PGUSER=postgres" -e "ENABLE_MOCK_AUTH=true" -e "ENABLE_MOCK_COOKIES=true" -e "NEXT_PUBLIC_GROWTHBOOK_API_KEY=dev_MIjxKii1kycPLz7CSjBYui0uERkFRSn7AXbu6oROCRQ" -p 3000:3000 ghcr.io/bcgov/conn-ccbc-portal/ccbc-app:sha-${{ github.sha }} + run: docker run -d --network=host -e "PGUSER=postgres" -e "PGPASSWORD=mysecretpassword" -e "ENABLE_MOCK_AUTH=true" -e "ENABLE_MOCK_COOKIES=true" -e "NEXT_PUBLIC_GROWTHBOOK_API_KEY=dev_MIjxKii1kycPLz7CSjBYui0uERkFRSn7AXbu6oROCRQ" -p 3000:3000 ghcr.io/bcgov/conn-ccbc-portal/ccbc-app:sha-${{ github.sha }} diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 5d887297c4..635837f041 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -20,22 +20,33 @@ jobs: strategy: matrix: include: + # build app image on every push - image: ghcr.io/bcgov/conn-ccbc-portal/ccbc-app context: . dockerfile: app/Dockerfile name: app + build_only_on_main: false + # build db image only on main, helper image, does not change + # will use cache from registry - image: ghcr.io/bcgov/conn-ccbc-portal/ccbc-db context: . dockerfile: db/Dockerfile name: db - - image: ghcr.io/bcgov/conn-ccbc-portal/ccbc-cron-sp - context: . - dockerfile: cron/sp/Dockerfile - name: cron-sp + build_only_on_main: true + # build shp image only on main, cron image, does not change + # will use cache from registry - image: ghcr.io/bcgov/conn-ccbc-portal/ccbc-cron-shp context: . dockerfile: cron/shp/Dockerfile name: cron-shp + build_only_on_main: true + # build unit test db only on main, testing image, does not change + # will use cache from registry + - image: ghcr.io/bcgov/conn-ccbc-portal/ccbc-unit-test-db + context: . + dockerfile: local_setup/unit_tests/Dockerfile + name: db-unit-test + build_only_on_main: true permissions: contents: read packages: write @@ -63,6 +74,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push Docker image + if: ${{ matrix.build_only_on_main != true || github.ref == 'refs/heads/main' || matrix.name == 'app' }} uses: docker/build-push-action@v6 with: context: ${{ matrix.context }} diff --git a/.github/workflows/deploy_feature.yaml b/.github/workflows/deploy_feature.yaml index 9aeda8fd66..f9abf20746 100644 --- a/.github/workflows/deploy_feature.yaml +++ b/.github/workflows/deploy_feature.yaml @@ -47,7 +47,6 @@ on: types: [submitted] env: - TAG: sha-${{ github.sha }} FEATURE_NAME: ${{ github.event.pull_request.head.ref }} jobs: @@ -81,6 +80,14 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + - name: Set TAG based on event type + id: set-tag + run: | + if [[ "${{ github.event_name }}" == "pull_request_review" ]]; then + echo "TAG=sha-${{ github.event.pull_request.head.sha }}" >> $GITHUB_ENV + else + echo "TAG=sha-${{ github.sha }}" >> $GITHUB_ENV + fi - name: Deploy uses: ./.github/actions/feature with: @@ -208,7 +215,7 @@ jobs: echo "::set-output name=status::$status" - name: Transition Issue - if: steps.pr_approval.outputs.result == 'true' && steps.get_status.outputs.status != 'SPRINT Done' && steps.get_status.outputs.status != 'Closed' + if: steps.pr_approval.outputs.result == 'true' && steps.get_status.outputs.status != 'SPRINT Done' && steps.get_status.outputs.status != 'Closed' && steps.get_status.outputs.status != 'In Progress (DRAFT PR)' run: | curl -X POST \ -H "Authorization: Basic ${{ secrets.JIRA_AUTH }}" \ diff --git a/.github/workflows/install-env.yaml b/.github/workflows/install-env.yaml index 822fa50c90..36cc685a39 100644 --- a/.github/workflows/install-env.yaml +++ b/.github/workflows/install-env.yaml @@ -19,7 +19,7 @@ jobs: - uses: actions/checkout@v4 - name: dev env setup uses: ./.github/actions/dev-env-setup - - run: make install_dev_tools - - run: make stop_pg # cleanly stop the database, otherwise it will complain in the subsequent jobs + # - run: make install_dev_tools + # - run: make stop_pg # cleanly stop the database, otherwise it will complain in the subsequent jobs - run: yarn install --frozen-lockfile --check-files working-directory: ./app diff --git a/.github/workflows/jira-feat.yaml b/.github/workflows/jira-feat.yaml index eb46ff1b36..8ec91476fd 100644 --- a/.github/workflows/jira-feat.yaml +++ b/.github/workflows/jira-feat.yaml @@ -81,7 +81,7 @@ jobs: echo "::set-output name=status::$status" - name: Transition Issue - if: github.event.review.state == 'approved' && steps.get_status.outputs.status != 'SPRINT Done' && steps.get_status.outputs.status != 'Closed' + if: github.event.review.state == 'approved' && steps.get_status.outputs.status != 'SPRINT Done' && steps.get_status.outputs.status != 'Closed' && steps.get_status.outputs.status != 'In Progress (DRAFT PR)' run: | curl -X POST \ -H "Authorization: Basic ${{ secrets.JIRA_AUTH }}" \ diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 09d94ad417..d5858614d8 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -27,6 +27,10 @@ jobs: uses: ./.github/workflows/test-code.yaml secrets: inherit + test-db: + uses: ./.github/workflows/test-db.yaml + secrets: inherit + test-checks: uses: ./.github/workflows/test-checks.yaml secrets: inherit @@ -41,7 +45,7 @@ jobs: RENOVATE_PRIVATE_KEY: ${{ secrets.RENOVATE_PRIVATE_KEY }} test-zap: - needs: [build, install-env] + needs: [build] uses: ./.github/workflows/test-zap.yaml test-e2e: @@ -155,17 +159,18 @@ jobs: run: | echo "tagVersion=$( git tag --merged ${{ github.sha }} --no-merged ${{ github.event.before }} | grep v*)" >>$GITHUB_OUTPUT - ensure-sqitch-plan-ends-with-tag: - runs-on: ubuntu-latest - needs: [is-tagged-release] - if: contains(needs.is-tagged-release.outputs.tagVersion, 'v') - steps: - - uses: actions/checkout@v4 - - run: ./.bin/sqitch-last-change-is-tag.sh db + # sqitch plans will no longer always end in tags, so this is no longer necessary + # ensure-sqitch-plan-ends-with-tag: + # runs-on: ubuntu-latest + # needs: [is-tagged-release] + # if: contains(needs.is-tagged-release.outputs.tagVersion, 'v') + # steps: + # - uses: actions/checkout@v4 + # - run: ./.bin/sqitch-last-change-is-tag.sh db deploy: if: github.event.ref == 'refs/heads/main' - needs: [test-code, test-containers] + needs: [build] uses: ./.github/workflows/deploy.yaml secrets: OPENSHIFT_SERVER: ${{ secrets.OPENSHIFT_SERVER }} diff --git a/.github/workflows/release-process.yaml b/.github/workflows/release-process.yaml index b4a30cd797..e56babb5be 100644 --- a/.github/workflows/release-process.yaml +++ b/.github/workflows/release-process.yaml @@ -97,8 +97,10 @@ jobs: - name: Setup Sqitch User if: steps.checkbox.outputs.result == 'true' && steps.up_to_date.outputs.result == 'true' && steps.pr_approval.outputs.result == 'true' && !github.event.pull_request.draft run: | - sqitch config --user user.name 'CCBC Service Account' - sqitch config --user user.email 'ccbc@button.is' + docker pull sqitch/sqitch + curl -L https://git.io/JJKCn -o sqitch && chmod +x sqitch + ./sqitch config --user user.name 'CCBC Service Account' + ./sqitch config --user user.email 'ccbc@button.is' - name: Make Release if: steps.checkbox.outputs.result == 'true' && steps.up_to_date.outputs.result == 'true' && steps.pr_approval.outputs.result == 'true' && !github.event.pull_request.draft run: | diff --git a/.github/workflows/test-code.yaml b/.github/workflows/test-code.yaml index b6b2713ca6..90449d5709 100644 --- a/.github/workflows/test-code.yaml +++ b/.github/workflows/test-code.yaml @@ -2,7 +2,7 @@ name: test code env: - PGPASSWORD: postgres + PGPASSWORD: mysecretpassword PGUSER: postgres PGDATABASE: ccbc @@ -31,7 +31,7 @@ jobs: attempt_limit: 2 attempt_delay: 2000 - name: SonarCloud Scan - uses: sonarsource/sonarcloud-github-action@master + uses: SonarSource/sonarqube-scan-action@v4.2.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} @@ -73,36 +73,27 @@ jobs: - name: dev env setup uses: ./.github/actions/dev-env-setup - name: deploy db migrations - run: make start_pg && make drop_db && make deploy_db_migrations + run: | + docker run --rm -p 5432:5432 -e POSTGRES_PASSWORD=mysecretpassword -d postgres:15 + # Wait for PostgreSQL to be ready + until docker exec $(docker ps -q -f ancestor=postgres:15) pg_isready -U postgres; do + echo "Waiting for PostgreSQL to be ready..." + sleep 2 + done + # Additional wait to ensure PostgreSQL is fully ready + sleep 5 + # Check PostgreSQL readiness from the host one more time + until pg_isready -h localhost -p 5432 -U postgres; do + echo "Waiting for PostgreSQL to be ready from the host..." + sleep 2 + done + make drop_db PSQL="psql -h localhost -U postgres" + make create_db PSQL="psql -h localhost -U postgres" + # Deploy migrations + docker pull sqitch/sqitch + curl -L https://git.io/JJKCn -o sqitch && chmod +x sqitch + ./sqitch --chdir db deploy - run: yarn build:schema working-directory: ./app - name: Check for inconsistency between graphql schema and commit schema run: git diff --exit-code || (echo 'The contents of the `schema` folder are out of sync with `app/schema/schema.graphql`. Did you forget to \"yarn build:schema\"?' && false) - - reverts: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: dev env setup - uses: ./.github/actions/dev-env-setup - - name: deploy db migrations - run: make start_pg && make drop_db && make deploy_db_migrations - - name: revert db migrations - run: make revert_db_migrations - - name: re-deploy db migrations - run: make deploy_db_migrations - - pgtap: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - name: dev env setup - uses: ./.github/actions/dev-env-setup - - name: Run Database Unit Tests - run: make db_unit_tests - - name: Run Database Style Tests - run: make db_style_tests diff --git a/.github/workflows/test-containers.yaml b/.github/workflows/test-containers.yaml index e057b24369..2ff6c9ceb1 100644 --- a/.github/workflows/test-containers.yaml +++ b/.github/workflows/test-containers.yaml @@ -45,6 +45,7 @@ jobs: run: echo "results-length=$(cat trivy-results.sarif | jq '.runs[0].results | length')" >> $GITHUB_OUTPUT trivy-scan-db: + if: github.event.ref == 'refs/heads/main' runs-on: ubuntu-latest outputs: results-length: ${{ steps.scan-results-length.outputs.results-length }} @@ -81,7 +82,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 - name: Self-hosted Renovate - uses: renovatebot/github-action@v41.0.12 + uses: renovatebot/github-action@v41.0.13 with: configurationFile: ./.github/renovate.json token: ${{ secrets.RENOVATE_GITHUB_TOKEN }} diff --git a/.github/workflows/test-db.yaml b/.github/workflows/test-db.yaml new file mode 100644 index 0000000000..d6cd0a736f --- /dev/null +++ b/.github/workflows/test-db.yaml @@ -0,0 +1,80 @@ +# Tests for db that do not require any node_modules +name: test db + +env: + PGPASSWORD: mysecretpassword + PGUSER: postgres + PGDATABASE: ccbc + +on: + workflow_call: + +concurrency: + group: test-db-${{ github.ref }} + cancel-in-progress: true + +jobs: + reverts: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: deploy db migrations + run: | + docker run --name ccbc-db -p 5432:5432 -e POSTGRES_PASSWORD=mysecretpassword -d postgres:15 + # Wait for PostgreSQL to be ready + until docker exec ccbc-db pg_isready -U postgres; do + echo "Waiting for PostgreSQL to be ready..." + sleep 2 + done + # Additional wait to ensure PostgreSQL is fully ready + sleep 5 + # Check PostgreSQL readiness from the host one more time + until pg_isready -h localhost -p 5432 -U postgres; do + echo "Waiting for PostgreSQL to be ready from the host..." + sleep 2 + done + make drop_db PSQL="psql -h localhost -U postgres" + make create_db PSQL="psql -h localhost -U postgres" + # Deploy migrations + docker pull sqitch/sqitch + curl -L https://git.io/JJKCn -o sqitch && chmod +x sqitch + ./sqitch --chdir db deploy + ./sqitch --chdir mocks_schema deploy + - name: revert db migrations + run: | + docker pull sqitch/sqitch + curl -L https://git.io/JJKCn -o sqitch && chmod +x sqitch + ./sqitch --chdir db revert + ./sqitch --chdir mocks_schema revert + - name: re-deploy db migrations + run: | + docker pull sqitch/sqitch + curl -L https://git.io/JJKCn -o sqitch && chmod +x sqitch + ./sqitch --chdir db deploy + ./sqitch --chdir mocks_schema deploy + docker stop ccbc-db + + pgtap: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: Run Database Unit Tests + run: | + docker run --rm --name ccbc-pgtap -p 5432:5432 -d ghcr.io/bcgov/conn-ccbc-portal/ccbc-unit-test-db:latest + sleep 5 + docker pull sqitch/sqitch + curl -L https://git.io/JJKCn -o sqitch && chmod +x sqitch + make create_test_db PSQL="docker exec ccbc-pgtap psql -h localhost -U postgres" + make deploy_test_db_migrations PSQL="docker exec ccbc-pgtap psql -h localhost -U postgres" SQITCH="./sqitch -u postgres" + docker pull itheory/pg_prove:latest + curl -L https://git.io/JUdgg -o pg_prove && chmod +x pg_prove + script -q -c "./pg_prove -h localhost -U postgres --failures -d ccbc_test db/test/unit/**/*_test.sql" + script -q -c "./pg_prove --no-psqlrc -h localhost -U postgres --failures -d ccbc_test mocks_schema/test/**/*_test.sql" + - name: Run Database Style Tests + run: | + script -q -c "./pg_prove -h localhost -U postgres --failures -d ccbc_test mocks_schema/test/**/*_test.sql" + docker stop ccbc-pgtap diff --git a/.github/workflows/test-e2e.yaml b/.github/workflows/test-e2e.yaml index dc8396e9a7..6d14583eb3 100644 --- a/.github/workflows/test-e2e.yaml +++ b/.github/workflows/test-e2e.yaml @@ -15,6 +15,7 @@ concurrency: env: PGUSER: postgres + PGPASSWORD: mysecretpassword jobs: check-changes: @@ -38,69 +39,50 @@ jobs: echo "Changes detected in app or db folders." echo "changes-detected=true" >> $GITHUB_OUTPUT fi - yarn-test-e2e-applicant: - needs: check-changes - if: ${{ needs.check-changes.outputs.changes-detected == 'true' }} + generate-matrix: runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: dev env setup - uses: ./.github/actions/dev-env-setup - - name: run app locally - uses: ./.github/actions/local-app-run - - run: yarn install --frozen-lockfile - working-directory: ./app - - name: run e2e tests - env: - HAPPO_API_KEY: ${{ secrets.HAPPO_API_KEY }} - HAPPO_API_SECRET: ${{ secrets.HAPPO_API_SECRET }} - HAPPO_NONCE: ${{ github.sha }} - run: yarn test:e2e:applicant - working-directory: ./app - - yarn-test-e2e-admin: needs: check-changes - if: ${{ needs.check-changes.outputs.changes-detected == 'true' }} - runs-on: ubuntu-latest + outputs: + files: ${{ steps.set-matrix.outputs.files }} steps: - - uses: actions/checkout@v4 - - name: dev env setup - uses: ./.github/actions/dev-env-setup - - name: run app locally - uses: ./.github/actions/local-app-run - - run: yarn install --frozen-lockfile - working-directory: ./app - - name: run e2e tests - env: - HAPPO_API_KEY: ${{ secrets.HAPPO_API_KEY }} - HAPPO_API_SECRET: ${{ secrets.HAPPO_API_SECRET }} - HAPPO_NONCE: ${{ github.sha }} - run: yarn test:e2e:admin - working-directory: ./app + - name: Checkout repository + uses: actions/checkout@v4 - yarn-test-e2e-analyst: - needs: check-changes - if: ${{ needs.check-changes.outputs.changes-detected == 'true' }} + - name: Find test files + id: set-matrix + run: | + FILES=$(find cypress/e2e -type f -name "*.cy.js" ! -name "setup.cy.js" | jq -R -s -c 'split("\n")[:-1]') + echo "files=$FILES" >> $GITHUB_OUTPUT + working-directory: ./app + run-tests: + needs: generate-matrix runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + file: ${{ fromJson(needs.generate-matrix.outputs.files) }} steps: - - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v4 - name: dev env setup uses: ./.github/actions/dev-env-setup - name: run app locally uses: ./.github/actions/local-app-run - run: yarn install --frozen-lockfile working-directory: ./app - - name: run e2e tests + - name: Run Cypress Test env: HAPPO_API_KEY: ${{ secrets.HAPPO_API_KEY }} HAPPO_API_SECRET: ${{ secrets.HAPPO_API_SECRET }} HAPPO_NONCE: ${{ github.sha }} - run: yarn test:e2e:analyst + run: | + echo "Running Cypress test for ${{ matrix.file }}" + yarn run test:e2e --spec '${{ matrix.file }}' working-directory: ./app yarn-test-e2e-finalize: runs-on: ubuntu-latest - needs: [yarn-test-e2e-applicant, yarn-test-e2e-admin, yarn-test-e2e-analyst] + needs: [run-tests] steps: - uses: actions/checkout@v4 - name: dev env setup diff --git a/.github/workflows/test-zap.yaml b/.github/workflows/test-zap.yaml index 13feaef80c..375fb4c0b4 100644 --- a/.github/workflows/test-zap.yaml +++ b/.github/workflows/test-zap.yaml @@ -16,8 +16,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: dev env setup - uses: ./.github/actions/dev-env-setup + # - name: dev env setup + # uses: ./.github/actions/dev-env-setup - name: run app locally uses: ./.github/actions/local-app-run - name: ZAP Full Scan diff --git a/CHANGELOG.md b/CHANGELOG.md index 2da6bf5549..fcab9a27fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +# [1.243.0](https://github.com/bcgov/CONN-CCBC-portal/compare/v1.242.1...v1.243.0) (2025-02-11) + +### Features + +- add geo name id to dashboard export ([1f39c4d](https://github.com/bcgov/CONN-CCBC-portal/commit/1f39c4d4caf9f370878ebfc48f3501bbbd6880b1)) + +## [1.242.1](https://github.com/bcgov/CONN-CCBC-portal/compare/v1.242.0...v1.242.1) (2025-02-11) + +### Bug Fixes + +- sow communities not showing up ([3466997](https://github.com/bcgov/CONN-CCBC-portal/commit/34669979a58648ddb0b0277dae0e829c9aa953aa)) +- update sonarqube scan ([6036799](https://github.com/bcgov/CONN-CCBC-portal/commit/6036799222559a547acaf16951be30094142c089)) + # [1.242.0](https://github.com/bcgov/CONN-CCBC-portal/compare/v1.240.0...v1.242.0) (2025-02-10) ### Bug Fixes diff --git a/app/backend/lib/dashboard/column_options.ts b/app/backend/lib/dashboard/column_options.ts index 38570aa65b..279f825909 100644 --- a/app/backend/lib/dashboard/column_options.ts +++ b/app/backend/lib/dashboard/column_options.ts @@ -49,41 +49,43 @@ const columnOptions: Columns = [ {}, // column 24 (Geographic Names) {}, - // column 25 (Total communities and locales) + // column 25 geo ids {}, - // column 26 (Indigenous communities) + // column 26 (Total communities and locales) {}, - // column 27 (Household count) + // column 27 (Indigenous communities) {}, - // column 28 (Transport KM) + // column 28 (Household count) {}, - // column 29 (Highway KM) + // column 29 (Transport KM) {}, - // column 30 (Rest Areas) + // column 30 (Highway KM) {}, - // column 31 (bc funding) + // column 31 (Rest Areas) + {}, + // column 32 (bc funding) { width: 24 }, - // column 32 (applicant amount) + // column 33 (applicant amount) { width: 24 }, - // column 33 (other funds requested) + // column 34 (other funds requested) { width: 24 }, - // column 34 (total fnha funding) + // column 35 (total fnha funding) { width: 24 }, - // column 35 (total budget) + // column 36 (total budget) { width: 24 }, - // column 36 (announced by bc/ised) + // column 37 (announced by bc/ised) {}, - // column 37 (Date application received) + // column 38 (Date application received) {}, - // column 38 (Date conditionally approved) + // column 39 (Date conditionally approved) {}, - // column 39 (date agreement signed) + // column 40 (date agreement signed) {}, - // column 40 (Proposed start date) + // column 41 (Proposed start date) {}, - // column 41 (% Project milestone completion) + // column 42 (% Project milestone completion) {}, - // column 42 (Construction completed on) + // column 43 (Construction completed on) {}, ]; diff --git a/app/backend/lib/dashboard/dashboard.ts b/app/backend/lib/dashboard/dashboard.ts index e37f460d04..2d71fe4f7d 100644 --- a/app/backend/lib/dashboard/dashboard.ts +++ b/app/backend/lib/dashboard/dashboard.ts @@ -263,11 +263,19 @@ export const generateDashboardExport = async (applicationData, cbcData) => { const benefitingCommunities = handleCcbcCommunities( summaryData?.formData?.locations?.benefitingCommunities - ) || ''; + ) || null; + const benefitingCommunitiesNames = + benefitingCommunities?.map((c) => c?.name) || []; + const benefitingCommunitiesIds = + benefitingCommunities?.map((c) => c?.id) || []; const benefitingIndigenousCommunities = handleCcbcCommunities( summaryData?.formData?.locations?.benefitingIndigenousCommunities - ) || ''; + ) || null; + const benefitingIndigenousCommunitiesNames = + benefitingIndigenousCommunities?.map((c) => c?.name) || []; + const benefitingIndigenousCommunitiesIds = + benefitingIndigenousCommunities?.map((c) => c?.id) || []; const row: Row = [ // program { value: data?.applicationByRowId?.program }, @@ -340,7 +348,10 @@ export const generateDashboardExport = async (applicationData, cbcData) => { }, // geographic names { - value: `${benefitingCommunities} ${benefitingIndigenousCommunities} ${summaryData.formDataSource.benefitingCommunities || summaryData.formDataSource.benefitingIndigenousCommunities ? `(${summaryData.formDataSource.benefitingCommunities})` : ''}`, + value: `${benefitingCommunitiesNames.join(',')} ${benefitingIndigenousCommunitiesNames.join(',')} ${summaryData.formDataSource.benefitingCommunities || summaryData.formDataSource.benefitingIndigenousCommunities ? `(${summaryData.formDataSource.benefitingCommunities})` : ''}`, + }, + { + value: `${benefitingCommunitiesIds.join(',')} ${benefitingIndigenousCommunitiesIds.join(',')}`, }, // total communities and locales { @@ -525,6 +536,8 @@ export const generateDashboardExport = async (applicationData, cbcData) => { { value: communities.regionalDistricts }, // geographic names { value: communities.bcGeographicNames }, + // geo ids + { value: communities.bcGeographicIds }, // total communities and locales { value: communities.totalCount }, // indigenous communities diff --git a/app/backend/lib/dashboard/header.ts b/app/backend/lib/dashboard/header.ts index 586106afe5..a2714f699d 100644 --- a/app/backend/lib/dashboard/header.ts +++ b/app/backend/lib/dashboard/header.ts @@ -170,6 +170,13 @@ const HEADER_ROW: Row = [ height: 95, wrap: true, }, + { + value: 'Geographic IDs', + fontWeight: 'bold', + type: String, + height: 95, + wrap: true, + }, { value: 'Total Communities and Locales', fontWeight: 'bold', diff --git a/app/backend/lib/dashboard/util.ts b/app/backend/lib/dashboard/util.ts index 4138593d79..7c54bb243a 100644 --- a/app/backend/lib/dashboard/util.ts +++ b/app/backend/lib/dashboard/util.ts @@ -4,6 +4,7 @@ export const handleCbcCommunities = (cbcCommunities) => { const economicRegions = new Set(); const regionalDistricts = new Set(); const bcGeographicNames = new Set(); + const bcGeographicIds = new Set(); cbcCommunities.forEach((community) => { const sourceData = community.communitiesSourceDataByCommunitiesSourceDataId; @@ -11,6 +12,7 @@ export const handleCbcCommunities = (cbcCommunities) => { economicRegions.add(sourceData.economicRegion); regionalDistricts.add(sourceData.regionalDistrict); bcGeographicNames.add(sourceData.bcGeographicName); + bcGeographicIds.add(sourceData.geographicNameId); } }); @@ -18,6 +20,7 @@ export const handleCbcCommunities = (cbcCommunities) => { economicRegions: Array.from(economicRegions), regionalDistricts: Array.from(regionalDistricts), bcGeographicNames: Array.from(bcGeographicNames), + bcGeographicIds: Array.from(bcGeographicIds), totalCount: cbcCommunities.length, }; }; @@ -26,7 +29,10 @@ export const handleCcbcCommunities = (ccbcCommunities) => { if (!ccbcCommunities) { return null; } - return ccbcCommunities.map((community) => community.name); + return ccbcCommunities.map((community) => ({ + name: community.name, + id: community.id, + })); }; export const convertStatus = (status: string): string => { diff --git a/app/components/AnalystDashboard/AllDashboard.tsx b/app/components/AnalystDashboard/AllDashboard.tsx index 036c6cd9f8..8ca491a25b 100644 --- a/app/components/AnalystDashboard/AllDashboard.tsx +++ b/app/components/AnalystDashboard/AllDashboard.tsx @@ -216,7 +216,7 @@ const AllDashboardTable: React.FC = ({ query }) => { zones status applicationSowDataByApplicationId( - condition: { isAmendment: false } + condition: { archivedAt: null } last: 1 ) { totalCount @@ -224,7 +224,7 @@ const AllDashboardTable: React.FC = ({ query }) => { id jsonData rowId - sowTab8SBySowId(condition: { archivedAt: null }) { + sowTab8SBySowId { nodes { rowId jsonData diff --git a/app/cypress/e2e/analyst/cbc/[cbcId].cy.js b/app/cypress/e2e/analyst/cbc/[cbcId].cy.js index 941a2f002a..134c157de3 100644 --- a/app/cypress/e2e/analyst/cbc/[cbcId].cy.js +++ b/app/cypress/e2e/analyst/cbc/[cbcId].cy.js @@ -17,10 +17,10 @@ describe('The cbc project view', () => { const mockedDateString = '2024-01-03'; const mockedDate = new Date(mockedDateString); cy.useMockedTime(mockedDate); - cy.sqlFixture('e2e/reset_db'); + cy.sqlFixture('e2e/reset_db_all'); cy.sqlFixture('e2e/001_intake'); - cy.sqlFixture('e2e/001_application'); - cy.sqlFixture('e2e/001_application_received'); + cy.sqlFixture('e2e/001_received_applications'); + cy.sqlFixture('e2e/001_cbc_project'); cy.sqlFixture('e2e/001_analyst'); }); describe('cbc load tests for each role', () => { diff --git a/app/lib/helpers/ccbcSummaryGenerateFormData.ts b/app/lib/helpers/ccbcSummaryGenerateFormData.ts index ec72d6bcb2..86f2790aae 100644 --- a/app/lib/helpers/ccbcSummaryGenerateFormData.ts +++ b/app/lib/helpers/ccbcSummaryGenerateFormData.ts @@ -117,6 +117,7 @@ const getCommunitiesTemplateNine = (communities) => { benefitingCommunities.push({ name: community?.geoName, link: community?.mapLink, + id: community?.geoNameId, }); } } @@ -125,6 +126,7 @@ const getCommunitiesTemplateNine = (communities) => { benefitingIndigenousCommunities.push({ name: community?.geoName, link: community?.mapLink, + id: community?.geoNameId, }); } } @@ -163,6 +165,7 @@ const getCommunities = (communities) => { benefitingCommunities.push({ name: community?.bcGeoName, link: community?.mapLink, + id: community?.geoNameId, }); } } @@ -175,6 +178,7 @@ const getCommunities = (communities) => { benefitingIndigenousCommunities.push({ name: community?.bcGeoName, link: community?.mapLink, + id: community?.geoNameId, }); } } diff --git a/app/package.json b/app/package.json index c945430f87..5d2c8490b2 100644 --- a/app/package.json +++ b/app/package.json @@ -45,7 +45,7 @@ "@graphile/persisted-operations": "^0.1.1", "@growthbook/growthbook-react": "^1.3.1", "@mui/base": "^5.0.0-beta.69", - "@mui/icons-material": "^5.16.12", + "@mui/icons-material": "^5.16.14", "@mui/material": "^5.16.14", "@mui/x-date-pickers": "^6.16.2", "@rjsf/core": "5.18.0", @@ -139,7 +139,7 @@ "@types/cookie-parser": "^1.4.8", "@types/debug": "^4.1.12", "@types/express": "^4.17.21", - "@types/jest": "^28.1.6", + "@types/jest": "^29.5.14", "@types/json-diff": "^1.0.3", "@types/leaflet": "^1.9.15", "@types/lodash.isequal": "^4.5.8", diff --git a/app/yarn.lock b/app/yarn.lock index 80926513d0..ddbef8d200 100644 --- a/app/yarn.lock +++ b/app/yarn.lock @@ -2756,13 +2756,6 @@ strip-ansi "^6.0.0" v8-to-istanbul "^9.0.1" -"@jest/schemas@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-28.1.3.tgz#ad8b86a66f11f33619e3d7e1dcddd7f2d40ff905" - integrity sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg== - dependencies: - "@sinclair/typebox" "^0.24.1" - "@jest/schemas@^29.6.3": version "29.6.3" resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" @@ -2966,10 +2959,10 @@ resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.14.tgz#e6536f1b6caa873f7915fbf9703fdc840a5a98d9" integrity sha512-sbjXW+BBSvmzn61XyTMun899E7nGPTXwqD9drm1jBUAvWEhJpPFIRxwQQiATWZnd9rvdxtnhhdsDxEGWI0jxqA== -"@mui/icons-material@^5.16.12": - version "5.16.12" - resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.16.12.tgz#c4e06c4fd50fc3ac3333cec4a31ddaef88cc3bd1" - integrity sha512-4Ocmbl1uzkWxAdYYARCLySJNqALgrJ+Fdr95FLpKZV7zMZxyoJRdPTO/CgUxjFjlj9Sy2Gi7j3HX4f5HS2GLeQ== +"@mui/icons-material@^5.16.14": + version "5.16.14" + resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.16.14.tgz#4fdecb05c15b1696f6f668fc29d549875544c892" + integrity sha512-heL4S+EawrP61xMXBm59QH6HODsu0gxtZi5JtnXF2r+rghzyU/3Uftlt1ij8rmJh+cFdKTQug1L9KkZB5JgpMQ== dependencies: "@babel/runtime" "^7.23.9" @@ -3792,11 +3785,6 @@ resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== -"@sinclair/typebox@^0.24.1": - version "0.24.27" - resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.27.tgz#d55643516a1546174e10da681a8aaa81e757452d" - integrity sha512-K7C7IlQ3zLePEZleUN21ceBA2aLcMnLHTLph8QWk1JK37L90obdpY+QGY8bXMKxf1ht1Z0MNewvXxWv0oGDYFg== - "@sinclair/typebox@^0.27.8": version "0.27.8" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" @@ -5059,13 +5047,13 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@^28.1.6": - version "28.1.6" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-28.1.6.tgz#d6a9cdd38967d2d746861fb5be6b120e38284dd4" - integrity sha512-0RbGAFMfcBJKOmqRazM8L98uokwuwD5F8rHrv/ZMbrZBwVOWZUyPG6VFNscjYr/vjM3Vu4fRrCPbOs42AfemaQ== +"@types/jest@^29.5.14": + version "29.5.14" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.14.tgz#2b910912fa1d6856cadcd0c1f95af7df1d6049e5" + integrity sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ== dependencies: - jest-matcher-utils "^28.0.0" - pretty-format "^28.0.0" + expect "^29.0.0" + pretty-format "^29.0.0" "@types/jsdom@^20.0.0": version "20.0.1" @@ -7516,11 +7504,6 @@ dezalgo@^1.0.4: asap "^2.0.0" wrappy "1" -diff-sequences@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-28.1.1.tgz#9989dc731266dc2903457a70e996f3a041913ac6" - integrity sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw== - diff-sequences@^29.6.3: version "29.6.3" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" @@ -8451,7 +8434,7 @@ exit@^0.1.2: resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= -expect@^29.7.0: +expect@^29.0.0, expect@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== @@ -10431,16 +10414,6 @@ jest-config@^29.7.0: slash "^3.0.0" strip-json-comments "^3.1.1" -jest-diff@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-28.1.3.tgz#948a192d86f4e7a64c5264ad4da4877133d8792f" - integrity sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw== - dependencies: - chalk "^4.0.0" - diff-sequences "^28.1.1" - jest-get-type "^28.0.2" - pretty-format "^28.1.3" - jest-diff@^29.0.0, jest-diff@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" @@ -10503,11 +10476,6 @@ jest-extended@^4.0.2: jest-diff "^29.0.0" jest-get-type "^29.0.0" -jest-get-type@^28.0.2: - version "28.0.2" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-28.0.2.tgz#34622e628e4fdcd793d46db8a242227901fcf203" - integrity sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA== - jest-get-type@^29.0.0, jest-get-type@^29.6.3: version "29.6.3" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" @@ -10540,16 +10508,6 @@ jest-leak-detector@^29.7.0: jest-get-type "^29.6.3" pretty-format "^29.7.0" -jest-matcher-utils@^28.0.0: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz#5a77f1c129dd5ba3b4d7fc20728806c78893146e" - integrity sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw== - dependencies: - chalk "^4.0.0" - jest-diff "^28.1.3" - jest-get-type "^28.0.2" - pretty-format "^28.1.3" - jest-matcher-utils@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" @@ -12582,17 +12540,7 @@ pretty-format@^27.0.2: ansi-styles "^5.0.0" react-is "^17.0.1" -pretty-format@^28.0.0, pretty-format@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-28.1.3.tgz#c9fba8cedf99ce50963a11b27d982a9ae90970d5" - integrity sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q== - dependencies: - "@jest/schemas" "^28.1.3" - ansi-regex "^5.0.1" - ansi-styles "^5.0.0" - react-is "^18.0.0" - -pretty-format@^29.7.0: +pretty-format@^29.0.0, pretty-format@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== diff --git a/helm/feature/templates/db-pre-job.yaml b/helm/feature/templates/db-pre-job.yaml index ab76df2fbc..393278f038 100644 --- a/helm/feature/templates/db-pre-job.yaml +++ b/helm/feature/templates/db-pre-job.yaml @@ -18,7 +18,7 @@ spec: containers: - env: {{ include "ccbc.postgresPgEnv" . | nindent 16 }} name: {{ template "ccbc.fullname" . }}-db-pre - image: {{ .Values.image.db.repository }}:{{ .Values.image.db.tag }} + image: {{ .Values.image.db.repository }}:latest imagePullPolicy: {{ .Values.image.db.pullPolicy }} resources: requests: diff --git a/helm/feature/templates/deployment.yaml b/helm/feature/templates/deployment.yaml index f905f50483..f91701ff95 100644 --- a/helm/feature/templates/deployment.yaml +++ b/helm/feature/templates/deployment.yaml @@ -112,7 +112,7 @@ spec: apiVersion: v1 fieldPath: metadata.namespace name: {{ template "ccbc.fullname" . }}-wait-for-migrations - image: {{ .Values.image.db.repository }}:{{ .Values.image.db.tag }} + image: {{ .Values.image.db.repository }}:latest imagePullPolicy: {{ .Values.image.db.pullPolicy }} resources: requests: @@ -136,7 +136,7 @@ spec: apiVersion: v1 fieldPath: metadata.namespace name: {{ template "ccbc.fullname" . }}-deploy-data - image: {{ .Values.image.db.repository }}:{{ .Values.image.db.tag }} + image: {{ .Values.image.db.repository }}:latest imagePullPolicy: {{ .Values.image.db.pullPolicy }} resources: requests: diff --git a/lib/feature_envs/create_feature_db.sh b/lib/feature_envs/create_feature_db.sh index 08cce81aec..3a4131e320 100755 --- a/lib/feature_envs/create_feature_db.sh +++ b/lib/feature_envs/create_feature_db.sh @@ -61,3 +61,6 @@ OPENSHIFT_NAMESPACE=$3 # Patch the Custom Resource oc -n $3 patch PostgresCluster "$PG_CLUSTER_NAME" --type=merge --patch="$PATCH_CONTENT" + +# Give the cluster 15 seconds to create the new database +sleep 15 diff --git a/local_setup/unit_tests/Dockerfile b/local_setup/unit_tests/Dockerfile index b6bf964793..701fd859ae 100644 --- a/local_setup/unit_tests/Dockerfile +++ b/local_setup/unit_tests/Dockerfile @@ -1,12 +1,12 @@ -# Use the official PostgreSQL 14 image as the base image -FROM postgres:14 +# Use the official PostgreSQL 15 image as the base image +FROM postgres:15 # Set environment variables for PostgreSQL -ENV POSTGRES_PASSWORD mysecretpassword +ENV POSTGRES_PASSWORD=mysecretpassword # Install required dependencies and tools RUN apt-get update \ - && apt-get install -y git build-essential postgresql-server-dev-14 \ + && apt-get install -y git build-essential postgresql-server-dev-15 \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* diff --git a/package.json b/package.json index 60155de47d..412531b62e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "CONN-CCBC-portal", - "version": "1.242.0", + "version": "1.243.0", "main": "index.js", "repository": "https://github.com/bcgov/CONN-CCBC-portal.git", "author": "Romer, Meherzad CITZ:EX ", @@ -27,7 +27,7 @@ } }, "hooks": { - "before:bump": "sqitch --chdir db tag ${version} -m 'release v${version}'", + "before:bump": "./.bin/check-db-changes.sh ${version}", "before:git:beforeRelease": "./.bin/pre-commit-format.sh CHANGELOG.md" } }