From 063cb02e93a5b6851460d56a5fe5ed5e41cfb430 Mon Sep 17 00:00:00 2001 From: Kevin Date: Wed, 15 May 2024 15:10:00 +0200 Subject: [PATCH] build(Github): Refactors main workflow and adds Dry Run mode and environment override --- .../build-and-deploy-cloud-run/action.yml | 84 +++++ .../generate-env-file-from-json/action.yml | 62 ++++ .github/workflows/deploy.yml | 322 ------------------ .github/workflows/main.yml | 209 +++++++++++- client/public/.delete | 0 cms/.yarnrc.yml | 1 + cms/package.json | 1 + 7 files changed, 351 insertions(+), 328 deletions(-) create mode 100644 .github/actions/build-and-deploy-cloud-run/action.yml create mode 100644 .github/actions/generate-env-file-from-json/action.yml delete mode 100644 .github/workflows/deploy.yml create mode 100644 client/public/.delete diff --git a/.github/actions/build-and-deploy-cloud-run/action.yml b/.github/actions/build-and-deploy-cloud-run/action.yml new file mode 100644 index 0000000..ba68562 --- /dev/null +++ b/.github/actions/build-and-deploy-cloud-run/action.yml @@ -0,0 +1,84 @@ +name: Build And Deploy to Cloud Run +description: Build And Deploy to Cloud Run +inputs: + GCP_SA_KEY: + description: "Service Account Key to log into GCP" + required: true + REPOSITORY: + description: "Repository" + required: true + SERVICE: + description: "Service" + required: true + PROJECT_ID: + description: "GCP Project Id" + required: true + GAR_LOCATION: + description: "GCP Artifact Registry url" + required: true + ENVIRONMENT_NAME: + description: "Environment name (PRODUCTION, STAGING)" + required: true + REGION: + description: "GCP Region" + required: true + COMPONENT_PATH: + description: "Component path of the component to be deployed (./cms, ./client ...)" + required: true + DRY_RUN: + description: "Makes the action work in Dry Run Mode" + required: false + default: "false" # WARNING Input type is not supported in composite actions. Must treat it as a string + +#NOTE Actions needs to specify the shell to use on every action https://stackoverflow.com/questions/71041836/github-actions-required-property-is-missing-shell + +outputs: + url: + description: url + value: ${{steps.deploy.output}} + +runs: + using: "composite" + steps: + - name: Google Auth + id: auth + uses: 'google-github-actions/auth@v1' + with: + credentials_json: "${{ inputs.GCP_SA_KEY }}" + token_format: 'access_token' + + # Authenticate Docker to Google Cloud Artifact Registry via credentials json + - name: Docker Auth + id: docker-auth + uses: 'docker/login-action@v3' + with: + registry: ${{ inputs.GAR_LOCATION }}-docker.pkg.dev + username: _json_key + password: ${{ inputs.GCP_SA_KEY }} + + - name: Build Container + shell: bash + run: |- + docker build -f ${{ inputs.COMPONENT_PATH }}/Dockerfile.prod -t "${{ inputs.GAR_LOCATION }}-docker.pkg.dev/${{ inputs.PROJECT_ID }}/${{ inputs.REPOSITORY }}/${{ inputs.SERVICE }}:${{ github.sha }}" ${{ inputs.COMPONENT_PATH }} + + - name: Push Container + if: ${{ inputs.DRY_RUN == 'false' }} + shell: bash + run: |- + docker push "${{ inputs.GAR_LOCATION }}-docker.pkg.dev/${{ inputs.PROJECT_ID }}/${{ inputs.REPOSITORY }}/${{ inputs.SERVICE }}:${{ github.sha }}" + # tag as "latest" + docker tag "${{ inputs.GAR_LOCATION }}-docker.pkg.dev/${{ inputs.PROJECT_ID }}/${{ inputs.REPOSITORY }}/${{ inputs.SERVICE }}:${{ github.sha }}" "${{ inputs.GAR_LOCATION }}-docker.pkg.dev/${{ inputs.PROJECT_ID }}/${{ inputs.REPOSITORY }}/${{ inputs.SERVICE }}:latest" + docker push "${{ inputs.GAR_LOCATION }}-docker.pkg.dev/${{ inputs.PROJECT_ID }}/${{ inputs.REPOSITORY }}/${{ inputs.SERVICE }}:latest" + + - name: Deploy to Cloud Run + if: ${{ inputs.DRY_RUN == 'false' }} + id: deploy + uses: google-github-actions/deploy-cloudrun@v1 + with: + service: ${{ inputs.SERVICE }} + region: ${{ inputs.REGION }} + image: ${{ inputs.GAR_LOCATION }}-docker.pkg.dev/${{ inputs.PROJECT_ID }}/${{ inputs.REPOSITORY }}/${{ inputs.SERVICE }}:${{ github.sha }} + # NOTE: You can also set env variables here: + # env_vars: | + # NODE_ENV=production + # TOKEN_EXPIRE=6400 diff --git a/.github/actions/generate-env-file-from-json/action.yml b/.github/actions/generate-env-file-from-json/action.yml new file mode 100644 index 0000000..1eb88a9 --- /dev/null +++ b/.github/actions/generate-env-file-from-json/action.yml @@ -0,0 +1,62 @@ +name: Generate Env file from JSON secret/variable collection +description: Takes a set of GH variables and secrets in JSON format and generates an env file for the docker image building step for the relevant environment and component (CMS, client, etc) + +inputs: + secrets_json: + description: "The GH Secrets collection in JSON format" + required: true + vars_json: + description: "The GH Variables collection in JSON format" + required: true + ENVIRONMENT: + description: "Environment name" + required: true + APP_ENV_PREFIX: + description: "Something" + required: true + +outputs: + env_file: + description: "The env file contents" + value: ${{steps.env_entries_stripped.outputs.entries_stripped}} + +runs: + using: "composite" + steps: + - name: Output secrets and vars as key=value entries + # Use jq to convert JSON to key=value entries + # 1. to_entries converts JSON to array of key/value pairs + # 2. map(.key + "=" + .value) converts each key/value pair to key=value + # 3. .[] flattens array to key=value entries + id: env_entries_all + shell: bash + run: | + { + echo 'entries_all<> $GITHUB_OUTPUT + + + - name: Strip environment and application prefixes from secret and var names + # Use sed to strip environment and application prefixes from secret and var names + id: env_entries_stripped + shell: bash + run: | + { + echo 'entries_stripped<> $GITHUB_OUTPUT diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index ec3b4f9..0000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,322 +0,0 @@ -# The workflow processes GH secrets and variables managed by Terraform or manually, some of them for general usage in -# the github jobs, and some which component-relevant (cms, client, etc), used to build the .env files for the containers. -# These follow the naming convention: -# - TF_[PRODUCTION|]_[CLIENT_ENV|CMS_ENV|]_* - managed by Terraform -# - [PRODUCTION|]_[CLIENT_ENV|CMS_ENV|]_* - managed manually - -name: Run deploy to GCP - -on: - workflow_dispatch: - push: - branches: - - main - - staging - - paths: - - 'client/**' - - 'cms/**' - - '.github/workflows/*' - - 'infrastructure/**' - -env: - PROJECT_ID: ${{ secrets.TF_GCP_PROJECT_ID }} - GAR_LOCATION: ${{ secrets.TF_GCP_REGION }} - REGION: ${{ secrets.TF_GCP_REGION }} - -jobs: - deploy_client: - # Add 'id-token' with the intended permissions for workload identity federation - permissions: - contents: 'read' - id-token: 'write' - - runs-on: ubuntu-latest - env: - APP_ENV_PREFIX: CLIENT_ENV - APP_ENV_PATH: client/.env.local - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - uses: dorny/paths-filter@v3 - id: client-changes - with: - filters: | - client: - - 'client/**' - - '.github/workflows/**' - - name: Extract branch name - if: ${{ github.event_name == 'workflow_dispatch' || steps.client-changes.outputs.client == 'true' }} - run: | - { - branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}} - echo "branch=${branch}" - echo "branch_upper=${branch^^}" - } >> $GITHUB_OUTPUT - id: extract_branch - - - name: Set environment name - if: ${{ github.event_name == 'workflow_dispatch' || steps.client-changes.outputs.client == 'true' }} - id: environment_name - run: | - { - echo "ENVIRONMENT=${{ steps.extract_branch.outputs.branch == 'main' && 'PRODUCTION' || steps.extract_branch.outputs.branch_upper }}" - } >> $GITHUB_ENV - - - - name: Output secrets and vars as JSON - if: ${{ github.event_name == 'workflow_dispatch' || steps.client-changes.outputs.client == 'true' }} - # Use GH Actions toJSON function to convert secrets and vars to JSON; in case no values present, output null (otherwise jq will fail) - run: | - { - echo 'secrets<> $GITHUB_OUTPUT - id: env_json - - - name: Output secrets and vars as key=value entries - if: ${{ github.event_name == 'workflow_dispatch' || steps.client-changes.outputs.client == 'true' }} - # Use jq to convert JSON to key=value entries - # 1. to_entries converts JSON to array of key/value pairs - # 2. map(.key + "=" + .value) converts each key/value pair to key=value - # 3. .[] flattens array to key=value entries - run: | - { - echo 'entries_all<> $GITHUB_OUTPUT - id: env_entries_filtered - - - name: Strip environment and application prefixes from secret and var names - if: ${{ github.event_name == 'workflow_dispatch' || steps.client-changes.outputs.client == 'true' }} - # Use sed to strip environment and application prefixes from secret and var names - run: | - { - echo 'entries_stripped<> $GITHUB_OUTPUT - id: env_entries_stripped - - - name: Save .env file - if: ${{ github.event_name == 'workflow_dispatch' || steps.client-changes.outputs.client == 'true' }} - run: | - echo '${{ steps.env_entries_stripped.outputs.entries_stripped }}' >> $APP_ENV_PATH - cat $APP_ENV_PATH - - #- name: Google Auth authentication via credentials json - - name: Google Auth - if: ${{ github.event_name == 'workflow_dispatch' || steps.client-changes.outputs.client == 'true' }} - id: auth - uses: 'google-github-actions/auth@v1' - with: - credentials_json: "${{ secrets[format('TF_{0}_GCP_SA_KEY', steps.environment_name.outputs.ENVIRONMENT)] }}" - token_format: 'access_token' - - # Authenticate Docker to Google Cloud Artifact Registry via credentials json - - name: Docker Auth - if: ${{ github.event_name == 'workflow_dispatch' || steps.client-changes.outputs.client == 'true' }} - id: docker-auth - uses: 'docker/login-action@v3' - with: - registry: ${{ env.GAR_LOCATION }}-docker.pkg.dev - username: _json_key - password: ${{ secrets[format('TF_{0}_GCP_SA_KEY', steps.environment_name.outputs.ENVIRONMENT)] }} - - - name: Build and Push Container - if: ${{ github.event_name == 'workflow_dispatch' || steps.client-changes.outputs.client == 'true' }} - env: - REPOSITORY: ${{ secrets[format('TF_{0}_CLIENT_REPOSITORY', steps.environment_name.outputs.ENVIRONMENT)] }} - SERVICE: ${{ secrets[format('TF_{0}_CLIENT_SERVICE', steps.environment_name.outputs.ENVIRONMENT)] }} - run: |- - docker build -f client/Dockerfile.prod -t "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:${{ github.sha }}" ./client - docker push "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:${{ github.sha }}" - # tag as "latest" - docker tag "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:${{ github.sha }}" "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:latest" - docker push "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:latest" - - - name: Deploy to Cloud Run - if: ${{ github.event_name == 'workflow_dispatch' || steps.client-changes.outputs.client == 'true' }} - env: - REPOSITORY: ${{ secrets[format('TF_{0}_CLIENT_REPOSITORY', steps.environment_name.outputs.ENVIRONMENT)] }} - SERVICE: ${{ secrets[format('TF_{0}_CLIENT_SERVICE', steps.environment_name.outputs.ENVIRONMENT)] }} - id: deploy - uses: google-github-actions/deploy-cloudrun@v1 - with: - service: ${{ env.SERVICE }} - region: ${{ env.REGION }} - image: ${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:${{ github.sha }} - # NOTE: You can also set env variables here: - # env_vars: | - # NODE_ENV=production - # TOKEN_EXPIRE=6400 - - # If required, use the Cloud Run url output in later steps - - name: Show Output - run: echo ${{ steps.deploy.outputs.url }} - - deploy_cms: - # Add 'id-token' with the intended permissions for workload identity federation - permissions: - contents: 'read' - id-token: 'write' - - runs-on: ubuntu-latest - env: - APP_ENV_PREFIX: CMS_ENV - APP_ENV_PATH: cms/.env - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - uses: dorny/paths-filter@v3 - id: cms-changes - with: - filters: | - cms: - - 'cms/**' - - '.github/workflows/**' - - - name: Extract branch name - if: ${{ github.event_name == 'workflow_dispatch' || steps.cms-changes.outputs.cms == 'true' }} - run: | - { - branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}} - echo "branch=${branch}" - echo "branch_upper=${branch^^}" - } >> $GITHUB_OUTPUT - id: extract_branch - - - name: Set environment name - if: ${{ github.event_name == 'workflow_dispatch' || steps.cms-changes.outputs.cms == 'true' }} - id: environment_name - run: | - { - echo "ENVIRONMENT=${{ steps.extract_branch.outputs.branch == 'main' && 'PRODUCTION' || steps.extract_branch.outputs.branch_upper }}" - } >> $GITHUB_ENV - - - name: Output secrets and vars as JSON - if: ${{ github.event_name == 'workflow_dispatch' || steps.cms-changes.outputs.cms == 'true' }} - # Use GH Actions toJSON function to convert secrets and vars to JSON; in case no values present, output null (otherwise jq will fail) - run: | - { - echo 'secrets<> $GITHUB_OUTPUT - id: env_json - - - name: Output secrets and vars as key=value entries - if: ${{ github.event_name == 'workflow_dispatch' || steps.cms-changes.outputs.cms == 'true' }} - # Use jq to convert JSON to key=value entries - # 1. to_entries converts JSON to array of key/value pairs - # 2. map(.key + "=" + .value) converts each key/value pair to key=value - # 3. .[] flattens array to key=value entries - run: | - { - echo 'entries_all<> $GITHUB_OUTPUT - id: env_entries_filtered - - - name: Strip environment and application prefixes from secret and var names - if: ${{ github.event_name == 'workflow_dispatch' || steps.cms-changes.outputs.cms == 'true' }} - # Use sed to strip environment and application prefixes from secret and var names - run: | - { - echo 'entries_stripped<> $GITHUB_OUTPUT - id: env_entries_stripped - - - name: Save .env file - if: ${{ github.event_name == 'workflow_dispatch' || steps.cms-changes.outputs.cms == 'true' }} - run: | - echo '${{ steps.env_entries_stripped.outputs.entries_stripped }}' >> $APP_ENV_PATH - cat $APP_ENV_PATH - - - name: Google Auth - if: ${{ github.event_name == 'workflow_dispatch' || steps.cms-changes.outputs.cms == 'true' }} - id: auth - uses: 'google-github-actions/auth@v1' - with: - credentials_json: "${{ secrets[format('TF_{0}_GCP_SA_KEY', steps.environment_name.outputs.ENVIRONMENT)] }}" - token_format: 'access_token' - - # Authenticate Docker to Google Cloud Artifact Registry via credentials json - - name: Docker Auth - if: ${{ github.event_name == 'workflow_dispatch' || steps.cms-changes.outputs.cms == 'true' }} - id: docker-auth - uses: 'docker/login-action@v3' - with: - registry: ${{ env.GAR_LOCATION }}-docker.pkg.dev - username: _json_key - password: ${{ secrets[format('TF_{0}_GCP_SA_KEY', steps.environment_name.outputs.ENVIRONMENT)] }} - - - name: Build and Push Container - if: ${{ github.event_name == 'workflow_dispatch' || steps.cms-changes.outputs.cms == 'true' }} - env: - REPOSITORY: ${{ secrets[format('TF_{0}_CMS_REPOSITORY', steps.environment_name.outputs.ENVIRONMENT)] }} - SERVICE: ${{ secrets[format('TF_{0}_CMS_SERVICE', steps.environment_name.outputs.ENVIRONMENT)] }} - run: |- - docker build -f cms/Dockerfile.prod -t "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:${{ github.sha }}" ./cms - docker push "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:${{ github.sha }}" - # tag as "latest" - docker tag "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:${{ github.sha }}" "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:latest" - docker push "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:latest" - - - name: Deploy to Cloud Run - if: ${{ github.event_name == 'workflow_dispatch' || steps.cms-changes.outputs.cms == 'true' }} - env: - REPOSITORY: ${{ secrets[format('TF_{0}_CMS_REPOSITORY', steps.environment_name.outputs.ENVIRONMENT)] }} - SERVICE: ${{ secrets[format('TF_{0}_CMS_SERVICE', steps.environment_name.outputs.ENVIRONMENT)] }} - id: deploy - uses: google-github-actions/deploy-cloudrun@v1 - with: - service: ${{ env.SERVICE }} - region: ${{ env.REGION }} - image: ${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:${{ github.sha }} - # NOTE: You can also set env variables here: - # env_vars: | - # NODE_ENV=production - # TOKEN_EXPIRE=6400 - - # If required, use the Cloud Run url output in later steps - - name: Show Output - if: ${{ github.event_name == 'workflow_dispatch' || steps.cms-changes.outputs.cms == 'true' }} - run: echo ${{ steps.deploy.outputs.url }} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 81542ea..fc3dd78 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,3 +1,8 @@ +# The workflow processes GH secrets and variables managed by Terraform or manually, some of them for general usage in +# the github jobs, and some which component-relevant (cms, client, etc), used to build the .env files for the containers. +# These follow the naming convention: +# - TF_[PRODUCTION|]_[CLIENT_ENV|CMS_ENV|]_* - managed by Terraform +# - [PRODUCTION|]_[CLIENT_ENV|CMS_ENV|]_* - managed manually name: Run deploy to GCP @@ -5,11 +10,11 @@ on: workflow_dispatch: inputs: ENVIRONMENT_NAME_OVERRIDE: - description: "Environment name to override the environment used in the workflow" + description: "Environment name to override" required: false type: string dry_run: - description: "Makes the workflow trigger in dry run mode (no components will be published or deployed to the actual environment infrastructure)" + description: "Dry Run (No deployment)" required: false default: false type: boolean @@ -25,10 +30,202 @@ on: - '.github/workflows/*' - 'infrastructure/**' - +env: + PROJECT_ID: ${{ secrets.TF_GCP_PROJECT_ID }} + GAR_LOCATION: ${{ secrets.TF_GCP_REGION }} + REGION: ${{ secrets.TF_GCP_REGION }} + jobs: - hello-world: + deploy_client: + # Add 'id-token' with the intended permissions for workload identity federation + permissions: + contents: 'read' + id-token: 'write' + runs-on: ubuntu-latest + env: + APP_ENV_PREFIX: CLIENT_ENV + APP_ENV_PATH: client/.env.local + steps: - - name: Hello World - run: echo "Hello World" + - name: Checkout + uses: actions/checkout@v4 + + - uses: dorny/paths-filter@v3 + id: client-changes + with: + filters: | + client: + - 'client/**' + - '.github/workflows/**' + + - name: Applicable check + id: applicable_check + run: | + { + echo "flag=${{ github.event_name == 'workflow_dispatch' || steps.client-changes.outputs.client == 'true' }}" + } >> $GITHUB_OUTPUT + + - name: Extract branch name + if: ${{ steps.applicable_check.outputs.flag }} + run: | + { + branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}} + echo "branch=${branch}" + echo "branch_upper=${branch^^}" + } >> $GITHUB_OUTPUT + id: extract_branch + + - name: Set environment name + if: ${{ steps.applicable_check.outputs.flag }} + id: environment_name + run: | + { + echo "ENVIRONMENT=${{ inputs.ENVIRONMENT_NAME_OVERRIDE || steps.extract_branch.outputs.branch == 'main' && 'PRODUCTION' || steps.extract_branch.outputs.branch_upper }}" + } >> $GITHUB_ENV + + - name: Output secrets and vars as JSON + if: ${{ steps.applicable_check.outputs.flag }} + # Use GH Actions toJSON function to convert secrets and vars to JSON; in case no values present, output null (otherwise jq will fail) + run: | + { + echo 'secrets<> $GITHUB_OUTPUT + id: env_json + + - name: Generate Env file from Secrets/Vars + id: generate_env_file + if: ${{ steps.applicable_check.outputs.flag }} + uses: ./.github/actions/generate-env-file-from-json + with: + ENVIRONMENT: ${{ env.ENVIRONMENT }} + APP_ENV_PREFIX: ${{ env.APP_ENV_PREFIX }} + secrets_json: ${{ steps.env_json.outputs.secrets }} + vars_json: ${{ steps.env_json.outputs.vars }} + + - name: Save .env file + if: ${{ steps.applicable_check.outputs.flag }} + run: | + echo '${{ steps.generate_env_file.outputs.env_file }}' >> $APP_ENV_PATH + cat $APP_ENV_PATH + + - name: Build and Deploy + if: ${{ steps.applicable_check.outputs.flag }} + id: build_and_deploy + uses: ./.github/actions/build-and-deploy-cloud-run + with: + GCP_SA_KEY: ${{ secrets[format('TF_{0}_GCP_SA_KEY', env.ENVIRONMENT)] }} + COMPONENT_PATH: "./client" + ENVIRONMENT_NAME: ${{ env.ENVIRONMENT }} + GAR_LOCATION: ${{ env.GAR_LOCATION }} + PROJECT_ID: ${{ env.PROJECT_ID }} + REGION: ${{ env.REGION }} + REPOSITORY: ${{ secrets[format('TF_{0}_CMS_REPOSITORY', env.ENVIRONMENT)] }} + SERVICE: ${{ secrets[format('TF_{0}_CMS_SERVICE', env.ENVIRONMENT)] }} + DRY_RUN: ${{ inputs.dry_run }} + + # If required, use the Cloud Run url output in later steps + - name: Show Output + run: echo ${{ steps.build_and_deploy.outputs.url || 'No URL generated' }} + + deploy_cms: + # Add 'id-token' with the intended permissions for workload identity federation + permissions: + contents: 'read' + id-token: 'write' + + runs-on: ubuntu-latest + env: + APP_ENV_PREFIX: CMS_ENV + APP_ENV_PATH: cms/.env + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - uses: dorny/paths-filter@v3 + id: cms-changes + with: + filters: | + cms: + - 'cms/**' + - '.github/workflows/**' + - name: Applicable check + id: applicable_check + run: | + { + echo "flag=${{ github.event_name == 'workflow_dispatch' || steps.cms-changes.outputs.cms == 'true' }}" + } >> $GITHUB_OUTPUT + + - name: Extract branch name + if: ${{ steps.applicable_check.outputs.flag }} + run: | + { + branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}} + echo "branch=${branch}" + echo "branch_upper=${branch^^}" + } >> $GITHUB_OUTPUT + id: extract_branch + + - name: Set environment name + if: ${{ steps.applicable_check.outputs.flag }} + id: environment_name + run: | + { + echo "ENVIRONMENT=${{ inputs.ENVIRONMENT_NAME_OVERRIDE ||steps.extract_branch.outputs.branch == 'main' && 'PRODUCTION' || steps.extract_branch.outputs.branch_upper }}" + } >> $GITHUB_ENV + + - name: Output secrets and vars as JSON + if: ${{ steps.applicable_check.outputs.flag }} + # Use GH Actions toJSON function to convert secrets and vars to JSON; in case no values present, output null (otherwise jq will fail) + run: | + { + echo 'secrets<> $GITHUB_OUTPUT + id: env_json + + - name: Generate Env file from Secrets/Vars + id: generate_env_file + if: ${{ steps.applicable_check.outputs.flag }} + uses: ./.github/actions/generate-env-file-from-json + with: + ENVIRONMENT: ${{ env.ENVIRONMENT }} + APP_ENV_PREFIX: ${{ env.APP_ENV_PREFIX }} + secrets_json: ${{ steps.env_json.outputs.secrets }} + vars_json: ${{ steps.env_json.outputs.vars }} + + - name: Save .env file + if: ${{ steps.applicable_check.outputs.flag }} + run: | + echo '${{ steps.generate_env_file.outputs.env_file }}' >> $APP_ENV_PATH + cat $APP_ENV_PATH + + - name: Build and Deploy + if: ${{ steps.applicable_check.outputs.flag }} + id: build_and_deploy + uses: ./.github/actions/build-and-deploy-cloud-run + with: + GCP_SA_KEY: ${{ secrets[format('TF_{0}_GCP_SA_KEY', env.ENVIRONMENT)] }} + COMPONENT_PATH: "./cms" + ENVIRONMENT_NAME: ${{ env.ENVIRONMENT }} + GAR_LOCATION: ${{ env.GAR_LOCATION }} + PROJECT_ID: ${{ env.PROJECT_ID }} + REGION: ${{ env.REGION }} + REPOSITORY: ${{ secrets[format('TF_{0}_CMS_REPOSITORY', env.ENVIRONMENT)] }} + SERVICE: ${{ secrets[format('TF_{0}_CMS_SERVICE', env.ENVIRONMENT)] }} + DRY_RUN: ${{ inputs.dry_run }} + + # If required, use the Cloud Run url output in later steps + - name: Show Output + if: ${{ steps.applicable_check.outputs.flag }} + run: echo ${{ steps.build_and_deploy.outputs.url || 'No URL generated' }} diff --git a/client/public/.delete b/client/public/.delete new file mode 100644 index 0000000..e69de29 diff --git a/cms/.yarnrc.yml b/cms/.yarnrc.yml index 78e2987..a0d278e 100644 --- a/cms/.yarnrc.yml +++ b/cms/.yarnrc.yml @@ -1 +1,2 @@ yarnPath: .yarn/releases/yarn-4.2.1.cjs +nodeLinker: node-modules diff --git a/cms/package.json b/cms/package.json index 79cec6d..281164b 100644 --- a/cms/package.json +++ b/cms/package.json @@ -3,6 +3,7 @@ "private": true, "version": "0.1.0", "description": "A Strapi application", + "packageManager": "yarn@4.2.1", "scripts": { "develop": "strapi develop", "start": "strapi start",