From bf9cd3a582616edded89947a9087e7cdac5a6161 Mon Sep 17 00:00:00 2001 From: Vishwajit Nagulkar <119565952+VishwajitNagulkar@users.noreply.github.com> Date: Thu, 13 Jul 2023 23:48:38 +0530 Subject: [PATCH 1/5] Feature: Updated SST Workflow with Add-ons --- .github/workflows/sst_workflow.yml | 140 ++++++++++++++++++++++------- 1 file changed, 110 insertions(+), 30 deletions(-) diff --git a/.github/workflows/sst_workflow.yml b/.github/workflows/sst_workflow.yml index 9269dc2a..c1011f77 100644 --- a/.github/workflows/sst_workflow.yml +++ b/.github/workflows/sst_workflow.yml @@ -1,65 +1,145 @@ -name: Shared workflow- SST APP +name: Shared Workflow - SST Deploy on: workflow_call: inputs: app-env: - description: 'Application environment' + description: 'application environment' + required: true + type: string + preview: + description: 'create or destroy preview env' required: false type: string + default: false working-directory: - description: 'Working directory in the repository' - required: true + description: 'working directory in repo' + required: false + type: string + default: ./ + stack-name: + description: 'stack name' + required: false + default: "" type: string + yarn-cache: + description: 'cache required or not for yarn install' + type: string + default: false + deploy: + description: 'default deploy otherwise run diff command to detect changes in stacks' + type: string + default: true + self-hosted: + description: 'deploy stack with github self hosted runner or not' + type: string + default: true secrets: - aws-access-key-id: - description: 'AWS Access Key ID' - required: true - aws-secret-access-key: - description: 'AWS Secret Access Key' + token: + description: 'GitHub Token' + required: false + env-vars: + description: 'environment-variables to store in .env file' + required: false + build-role: + description: 'assume role arn' required: true + jobs: - deploy: - runs-on: ubuntu-20.04 - environment: - name: ${{ github.head_ref }} - url: ${{ env.API_ENDPOINT_URL }} + setup: + runs-on: ubuntu-latest + outputs: + runner: ${{ steps.step1.outputs.runner }} + steps: + - name: Check branch + id: step1 + run: | + if [ ${{ inputs.self-hosted }} == 'true' ]; then + echo "runner=flo-${{ inputs.app-env }}" >> "$GITHUB_OUTPUT" + else + echo "runner=ubuntu-latest" >> "$GITHUB_OUTPUT" + fi + sst-deploy: + needs: [setup] + runs-on: ${{ needs.setup.outputs.runner }} + environment: + name: ${{ (((github.event.action == 'opened' || github.event.action == 'synchronize') && inputs.preview == 'true') || (github.event.pull_request.merged == true && inputs.preview == 'false' && inputs.app-env == 'staging') || (inputs.app-env == 'production' && startsWith(github.ref, 'refs/tags/v'))) && ((inputs.preview == 'true' && (inputs.stack-name != '' && github.head_ref-inputs.stack-name || github.head_ref) || inputs.app-env)) || '' }} + url: ${{ ((github.event.action == 'opened' && inputs.preview == 'true') || (github.event.action == 'synchronize' && inputs.preview == 'true') || (github.event.pull_request.merged == true && inputs.preview == 'false' && inputs.app-env == 'staging') || (inputs.app-env == 'production' && startsWith(github.ref, 'refs/tags/v'))) && env.API_ENDPOINT_URL }} defaults: run: working-directory: ${{ inputs.working-directory }} - name: Deploy SST APP + name: Run sst-deploy steps: - name: Checkout git repo uses: actions/checkout@v3 - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v2 + - name: update environment variable in .env file + run: | + if [ -n "${{ secrets.env-vars }}" ]; then + echo -e "${{ secrets.env-vars }}" > ./.env + fi + + - name: Configure AWS Creds via role + uses: aws-actions/configure-aws-credentials@v1-node16 with: - aws-access-key-id: ${{ secrets.aws-access-key-id }} - aws-secret-access-key: ${{ secrets.aws-secret-access-key }} - aws-region: us-east-2 + aws-region: us-west-2 + role-to-assume: ${{ secrets.build-role }} + role-duration-seconds: 900 + role-skip-session-tagging: true + + - name: Install yarn + run: sudo npm install -g yarn - - name: Install dependencies (yarn install) - run: yarn install - - - name: Extract branch name + - name: Install dependencies + if: ${{ inputs.yarn-cache != 'true' }} + run: yarn install --frozen-lockfile + + - name: Install dependencies with yarn cache + if: ${{ inputs.yarn-cache == 'true' }} + uses: ./.github/actions/yarn-nm-install + + - name: Set branch name run: | - BRANCH_NAME=$(echo "${{ github.head_ref }}" | cut -d'/' -f3) + BRANCH_NAME=$(echo "${{ github.head_ref }}" | cut -d'|' -f2) echo "BRANCH_NAME=${BRANCH_NAME}" SLUG_BRANCH_NAME=$(echo "${BRANCH_NAME}" | sed 's/[^[:alnum:]]/-/g' | tr -s '-' | tr A-Z a-z) echo "SLUG_BRANCH_NAME=${SLUG_BRANCH_NAME}" echo "GITHUB_HEAD_REF_SLUG=${SLUG_BRANCH_NAME}" >> $GITHUB_ENV + - name: check diffrence in deployed and local stacks + if: ${{ inputs.deploy != 'true' }} + run: yarn sst diff --stage ${{ inputs.app-env }} + - name: Deploy and get API endpoint - if: ${{ (github.event.action == 'opened' || github.event.action == 'synchronize' && inputs.app-env == 'preview') || ( github.event.pull_request.merged == true && (inputs.app-env == 'prod' || inputs.app-env == 'stage')) }} + if: ${{ inputs.deploy == 'true' && ((github.event.action == 'opened' && inputs.preview == 'true') || (github.event.action == 'synchronize' && inputs.preview == 'true') || (github.event.pull_request.merged == true && inputs.preview == 'false' && inputs.app-env == 'staging') || (inputs.app-env == 'production' && startsWith(github.ref, 'refs/tags/v'))) }} run: | - api_endpoint=$(yarn sst deploy --stage pr-${{ github.event.number }}-${{ env.GITHUB_HEAD_REF_SLUG }} | egrep "ApiEndpoint|SiteUrl" | awk '{print $2}') + if [[ ${{ inputs.preview }} == true ]]; then + if [[ -n "${{ inputs.stack-name }}" ]]; then + yarn sst deploy --stage pr-${{ github.event.number }}-${{ env.GITHUB_HEAD_REF_SLUG }} ${{ inputs.stack-name }} | tee deploy-output.log + else + yarn sst deploy --stage pr-${{ github.event.number }}-${{ env.GITHUB_HEAD_REF_SLUG }} | tee deploy-output.log + fi + else + if [[ -n "${{ inputs.stack-name }}" ]]; then + yarn sst deploy --stage ${{ inputs.app-env }} ${{ inputs.stack-name }} | tee deploy-output.log + else + yarn sst deploy --stage ${{ inputs.app-env }} | tee deploy-output.log + fi + fi + api_endpoint=$(cat deploy-output.log | egrep "ApiEndpoint|SiteUrl" | awk '{print $2}') echo "API endpoint: $api_endpoint" echo "API_ENDPOINT_URL=$api_endpoint" >> $GITHUB_ENV - - - name: Destroy SST App for Preview app environment - if: ${{ ( github.event.action == 'labeled' && github.event.label.name == 'destroy' && inputs.app-env == 'preview' ) || (github.event.action == 'closed' && inputs.app-env == 'preview' || github.event.pull_request.merged == true && inputs.app-env == 'preview') }} + + - name: Destroy preview env + if: ${{ ( github.event.action == 'labeled' && github.event.label.name == 'destroy' && inputs.preview == 'true' ) || (github.event.action == 'closed' && inputs.preview == 'true' || github.event.pull_request.merged == true && inputs.preview == 'true' ) }} run: yarn sst remove --stage pr-${{ github.event.number }}-${{ env.GITHUB_HEAD_REF_SLUG }} + + - name: Cleanup preview env deployment + if: ${{ ( github.event.action == 'labeled' && github.event.label.name == 'destroy' && inputs.preview == 'true' ) || (github.event.action == 'closed' && inputs.preview == 'true' || github.event.pull_request.merged == true && inputs.preview == 'true' ) }} + uses: strumwolf/delete-deployment-environment@v2.3.0 + with: + token: ${{ secrets.token }} + environment: ${{ github.head_ref }} From 89323b19e84e90cf44c3ff1936893cc075f079b5 Mon Sep 17 00:00:00 2001 From: Vishwajit Nagulkar <119565952+VishwajitNagulkar@users.noreply.github.com> Date: Thu, 13 Jul 2023 23:51:03 +0530 Subject: [PATCH 2/5] Feature: added functionality of use yarn-cache --- .github/actions/yarn-nm-install | 53 +++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 .github/actions/yarn-nm-install diff --git a/.github/actions/yarn-nm-install b/.github/actions/yarn-nm-install new file mode 100644 index 00000000..ad00ab81 --- /dev/null +++ b/.github/actions/yarn-nm-install @@ -0,0 +1,53 @@ +######################################################################################## +# "yarn install" composite action for yarn 2/3/4+ and "nodeLinker: node-modules" # +#--------------------------------------------------------------------------------------# +# Cache: # +# - Downloaded zip archive (multi-arch, preserved across yarn.lock changes) # +# - Yarn install state (discarded on yarn.lock changes) # +# References: # +# - bench: https://gist.github.com/belgattitude/0ecd26155b47e7be1be6163ecfbb0f0b # +# - vs @setup/node: https://github.com/actions/setup-node/issues/325 # +######################################################################################## + +name: 'Yarn install' +description: 'Run yarn install with node_modules linker and cache enabled' + +runs: + using: 'composite' + steps: + - name: Expose yarn config as "$GITHUB_OUTPUT" + id: yarn-config + shell: bash + run: | + echo "CACHE_FOLDER=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT + + # Yarn rotates the downloaded cache archives, @see https://github.com/actions/setup-node/issues/325 + # Yarn cache is also reusable between arch and os. + - name: Restore yarn cache + uses: actions/cache@v3 + id: yarn-download-cache + with: + path: ${{ steps.yarn-config.outputs.CACHE_FOLDER }} + key: yarn-download-cache-${{ hashFiles('yarn.lock') }} + restore-keys: | + yarn-download-cache- + + # Invalidated on yarn.lock changes + - name: Restore yarn install state + id: yarn-install-state-cache + uses: actions/cache@v3 + with: + path: .yarn/ci-cache/ + key: ${{ runner.os }}-yarn-install-state-cache-${{ hashFiles('yarn.lock', '.yarnrc.yml') }} + + - name: Install dependencies + shell: bash + run: | + yarn install --immutable --inline-builds + env: + # CI optimizations. Overrides yarnrc.yml options (or their defaults) in the CI action. + YARN_ENABLE_GLOBAL_CACHE: 'false' # Use local cache folder to keep downloaded archives + YARN_NM_MODE: 'hardlinks-local' # Hardlinks-(local|global) reduces io / node_modules size + YARN_INSTALL_STATE_PATH: .yarn/ci-cache/install-state.gz # Very small speedup when lock does not change + # Other environment variables + HUSKY: '0' # By default do not run HUSKY install From 163343cae79d2a6e3595f921bcd9ffeb33d4c3bd Mon Sep 17 00:00:00 2001 From: Vishwajit Nagulkar <119565952+VishwajitNagulkar@users.noreply.github.com> Date: Fri, 14 Jul 2023 00:01:04 +0530 Subject: [PATCH 3/5] Format: uppercase secrets name --- .github/workflows/helm.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/helm.yml b/.github/workflows/helm.yml index d9f867e4..ae92da92 100644 --- a/.github/workflows/helm.yml +++ b/.github/workflows/helm.yml @@ -58,10 +58,10 @@ on: type: string description: 'Environment name for rollback' secrets: - aws-access-key-id: + AWS_ACCESS_KEY_ID: description: 'AWS Access Key ID' required: false - aws-secret-access-key: + AWS_SECRET_ACCESS_KEY: description: 'AWS Secret Access Key' required: false AZURE_CREDENTIALS: @@ -79,8 +79,8 @@ jobs: if: ${{ inputs.provider == 'aws' }} uses: aws-actions/configure-aws-credentials@v2 with: - aws-access-key-id: ${{ secrets.aws-access-key-id }} - aws-secret-access-key: ${{ secrets.aws-secret-access-key }} + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: ${{ inputs.aws-region }} - name: Install Azure CLI From 9bba108dee41da51a5d4bc410eb03bd02ec1ea10 Mon Sep 17 00:00:00 2001 From: Vishwajit Nagulkar <119565952+VishwajitNagulkar@users.noreply.github.com> Date: Fri, 14 Jul 2023 00:27:46 +0530 Subject: [PATCH 4/5] feat: updated readme for sst workflow usage --- docs/sst.md | 70 +++++++++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/docs/sst.md b/docs/sst.md index 3d29d220..3e121e71 100644 --- a/docs/sst.md +++ b/docs/sst.md @@ -1,44 +1,50 @@ ## [SST Workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/.github/workflows/sst_workflow.yml) -This workflow is used to deploy serverless stack (SST) application on AWS environment. Workflows have been added in `.github/workflows/sst_workflow.yml`. +This workflow is used to deploy or destroy serverless stack (SST) application on AWS environment. Workflows have been added in `.github/workflows/sst_workflow.yml`. #### Usage -Below workflow can be used to deploy SST in preview environment when pull request generated and it destroys the preview environment when pull request closed, merged and labeled as destroy, similarly staging and production is deployed using there defined branches. +The following workflow can be used to deploy the SST application in the staging environment when a pull request is generated on the base branch named "master". It will deploy the SST application in the production environment when a new tag is released. Additionally, it will destroy the preview environment when a pull request is closed, merged, and labeled as "destroy". -```yaml -name: SST Workflow - -on: - pull_request: - types: [closed, merged, labeled] - workflow_dispatch: -jobs: - preview: - uses: clouddrove/github-shared-workflows/.github/workflows/sst_workflow.yml@master - secrets: - AWS_ACCESS_KEY_ID: # AWS Access Key ID for preview - AWS_SECRET_ACCESS_KEY: # AWS Secret Access Key for preview - with: - app-env: # preview - working-directory: # specify your working folder from repo +Inputs: +| Input name | Type | Required | Default | Comment | +|---|---|---|---|---| +| app-env | string | true | | Staging or Production | +| preview | string | false | false | If true SST deployed in preview environment | +| working-directory | string | false | ./ | SST code location path | +| stack-name | string | false | | Specify stack name for deployment | +| yarn-cache | string | false | false | Yarn stores packages in global cache | +| deploy | string | false | true | Plan app stacks or deploy. | +| self-hosted | string | false | true | Deploy stack with github runner or without it. | - staging: - if: ${{ github.base_ref == 'stage' }} +Secrets: +| Secret name | Required | Comment | +|---|---|---| +| token | false | GitHub token for environment deletion | +| env-vars | false | Stack environment variables | +| build-role | true | | AWS authentication role | + +```yaml + staging-workflow: + if: ${{ github.event.pull_request.base.ref == 'master' }} uses: clouddrove/github-shared-workflows/.github/workflows/sst_workflow.yml@master - secrets: - AWS_ACCESS_KEY_ID: # AWS Access Key ID for Stage - AWS_SECRET_ACCESS_KEY: # AWS Secret Access Key for stage with: - app-env: # stage - working-directory: # specify your working folder from repo + app-env: staging - production: - if: ${{ github.base_ref == 'master' }} + production-workflow: + if: startsWith(github.event.ref, 'refs/tags/v') uses: clouddrove/github-shared-workflows/.github/workflows/sst_workflow.yml@master - secrets: - AWS_ACCESS_KEY_ID: # AWS Access Key ID for prod - AWS_SECRET_ACCESS_KEY: # AWS Secret Access Key for prod with: - app-env: # prod - working-directory: # specify your working folder from repo + app-env: production ``` + + +##### Path: `clouddrove/github-shared-workflows/.github/workflows/sst_workflow.yml@master` + +Should be used with `on: pull_request`. Includes the following: +1. Adds SST Deployed application link into the description of a pull request. +2. Appends Pull Request number and head branch name for the stage name when the preview environment is set to true. + +Handles the following branch naming styles : +- `feature-123` +- `feature_123` +- `feature-123/feature-description` From e495b23be92766d0a9ee47b5e2696a7325905cbf Mon Sep 17 00:00:00 2001 From: Vishwajit Nagulkar <119565952+VishwajitNagulkar@users.noreply.github.com> Date: Fri, 14 Jul 2023 00:41:59 +0530 Subject: [PATCH 5/5] feat: updated runner configuration --- .github/workflows/sst_workflow.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/sst_workflow.yml b/.github/workflows/sst_workflow.yml index c1011f77..aa9550f9 100644 --- a/.github/workflows/sst_workflow.yml +++ b/.github/workflows/sst_workflow.yml @@ -4,34 +4,34 @@ on: workflow_call: inputs: app-env: - description: 'application environment' + description: 'Application environment' required: true type: string preview: - description: 'create or destroy preview env' + description: 'Create or destroy preview env' required: false type: string default: false working-directory: - description: 'working directory in repo' + description: 'Working directory in repo' required: false type: string default: ./ stack-name: - description: 'stack name' + description: 'Stack name' required: false default: "" type: string yarn-cache: - description: 'cache required or not for yarn install' + description: 'Cache required or not for yarn install' type: string default: false deploy: - description: 'default deploy otherwise run diff command to detect changes in stacks' + description: 'Default deploy otherwise run diff command to detect changes in stacks' type: string default: true self-hosted: - description: 'deploy stack with github self hosted runner or not' + description: 'Deploy stack with github self hosted runner or not' type: string default: true @@ -40,10 +40,10 @@ on: description: 'GitHub Token' required: false env-vars: - description: 'environment-variables to store in .env file' + description: 'Environment-variables to store in .env file' required: false build-role: - description: 'assume role arn' + description: 'Assume role arn' required: true @@ -57,7 +57,7 @@ jobs: id: step1 run: | if [ ${{ inputs.self-hosted }} == 'true' ]; then - echo "runner=flo-${{ inputs.app-env }}" >> "$GITHUB_OUTPUT" + echo "runner=${{ inputs.app-env }}" >> "$GITHUB_OUTPUT" else echo "runner=ubuntu-latest" >> "$GITHUB_OUTPUT" fi