Skip to content
name: deploy-staging-and-create-release
concurrency:
group: deploy-staging
cancel-in-progress: true
on:
push:
branches:
- main
workflow_dispatch:
permissions:
id-token: write # required for OIDC connectiong to AWS
contents: write # This is required to create a release
jobs:
detect-changes:
runs-on: ubuntu-latest
environment: staging
outputs:
deploy-iac: ${{ steps.check.outputs.deploy-iac }}
deploy-backend: ${{ steps.check.outputs.deploy-backend }}
deploy-frontend: ${{ steps.check.outputs.deploy-frontend }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: check
with:
filters: |
deploy-iac:
- 'tofu/modules/**'
- 'tofu/environments/stage/**'
- '.github/workflows/deploy-staging.yml'
deploy-backend:
- 'backend/**'
- 'tofu/modules/services/backend-service/**'
- 'tofu/environments/stage/services/backend-service/**'
- '.github/workflows/deploy-staging.yml'
deploy-frontend:
- 'frontend/**'
- 'tofu/modules/services/frontend-infra/**'
- 'tofu/environments/stage/services/frontend-infra/**'
- '.github/workflows/deploy-staging.yml'
deploy-stage-iac:
needs: detect-changes
if: needs.detect-changes.outputs.deploy-iac == 'true'
environment: staging
runs-on: ubuntu-latest
env:
TF_VAR_region: us-east-1
TF_VAR_environment: ${{ vars.ENV_SHORT_NAME }}
TF_VAR_name_prefix: "tb-${{ vars.PROJECT_SHORT_NAME }}-${{ vars.ENV_SHORT_NAME }}"
TF_VAR_frontend_url: ${{ vars.FRONTEND_URL }}
TF_VAR_ssl_cert_arn: ${{ vars.SSL_CERT_ARN }}
steps:
- uses: actions/checkout@v4
- name: AWS login with DEV credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.INSTALLER_DEV_AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.INSTALLER_DEV_AWS_SECRET_KEY }}
aws-region: us-east-1
- name: Log into CodeArtifact
id: codeartifact-login
run: |
CODEARTIFACT_AUTH_TOKEN=$(aws codeartifact get-authorization-token --domain energysage --domain-owner 659694780082 --query authorizationToken --output text)
echo "CODEARTIFACT_AUTH_TOKEN=$CODEARTIFACT_AUTH_TOKEN" >> $GITHUB_OUTPUT
- name: install opentofu
uses: opentofu/setup-opentofu@v1
with:
tofu_version: ${{ vars.TF_VERSION }}
tofu_wrapper: false
- name: install terragrunt
run: |
sudo wget -q -O /bin/terragrunt "https://github.com/gruntwork-io/terragrunt/releases/download/v${{ vars.TG_VERSION }}/terragrunt_linux_amd64"
sudo chmod +x /bin/terragrunt
terragrunt -v
- name: vpc
working-directory: ./tofu/environments/stage/network/vpc
run: |
terragrunt init -upgrade
terragrunt validate
terragrunt plan -out tfplan
terragrunt apply tfplan
- name: backend-infra
working-directory: ./tofu/environments/stage/services/backend-infra
run: |
terragrunt init -upgrade
terragrunt validate
terragrunt plan -out tfplan
terragrunt apply tfplan
- name: cache
working-directory: ./tofu/environments/stage/data-store/cache
run: |
terragrunt init -upgrade
terragrunt validate
terragrunt plan -out tfplan
terragrunt apply tfplan
- name: database
working-directory: ./tofu/environments/stage/data-store/database
run: |
terragrunt init -upgrade
terragrunt validate
terragrunt plan -out tfplan
terragrunt apply tfplan
- name: frontend-infra
working-directory: ./tofu/environments/stage/services/frontend-infra
run: |
terragrunt init -upgrade
terragrunt validate
terragrunt plan -out tfplan
terragrunt apply tfplan
build-and-deploy-stage-frontend:
needs:
- detect-changes
- deploy-stage-iac
if: |
always() &&
(needs.deploy-stage-iac.result == 'success' || needs.deploy-stage-iac.result == 'skipped') &&
needs.detect-changes.outputs.deploy-frontend == 'true'
environment: staging
runs-on: ubuntu-latest
env:
TF_VAR_region: ${{ vars.AWS_REGION }}
TF_VAR_environment: ${{ vars.ENV_SHORT_NAME }}
TF_VAR_name_prefix: "tb-${{ vars.PROJECT_SHORT_NAME }}-${{ vars.ENV_SHORT_NAME }}"
TF_VAR_frontend_url: ${{ vars.FRONTEND_URL }}
TF_VAR_ssl_cert_arn: ${{ vars.SSL_CERT_ARN }}
steps:
- uses: actions/checkout@v4
- name: Setup NPM
uses: actions/setup-node@v4
with:
node-version: '20.x'
- name: AWS login with DEV credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.INSTALLER_DEV_AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.INSTALLER_DEV_AWS_SECRET_KEY }}
aws-region: us-east-1
- name: Log into CodeArtifact
id: codeartifact-login
run: |
CODEARTIFACT_AUTH_TOKEN=$(aws codeartifact get-authorization-token --domain energysage --domain-owner 659694780082 --query authorizationToken --output text)
echo "CODEARTIFACT_AUTH_TOKEN=$CODEARTIFACT_AUTH_TOKEN" >> $GITHUB_OUTPUT
- name: Install dependencies
run: cd frontend && npm install
- name: Build stage frontend
run: |
cp frontend/.env.stage.example frontend/.env.stage
cd frontend && npm run build -- --mode ${{ vars.APP_ENV }}
- name: install opentofu
uses: opentofu/setup-opentofu@v1
with:
tofu_version: ${{ vars.TF_VERSION }}
tofu_wrapper: false
- name: install terragrunt
run: |
sudo wget -q -O /bin/terragrunt "https://github.com/gruntwork-io/terragrunt/releases/download/v${{ vars.TG_VERSION }}/terragrunt_linux_amd64"
sudo chmod +x /bin/terragrunt
terragrunt -v
- name: Install AWS CLI
uses: unfor19/install-aws-cli-action@v1
with:
version: 2
arch: amd64
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.INSTALLER_DEV_AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.INSTALLER_DEV_AWS_SECRET_KEY }}
aws-region: us-east-1
- name: Get frontend bucket & distribution
id: get-frontend-resources
working-directory: ./tofu/environments/stage/services/frontend-infra
run: |
terragrunt init -upgrade
echo "bucket=$(terragrunt output bucket_name | tr -d '"')" >> $GITHUB_OUTPUT
echo "distribution=$(terragrunt output cloudfront_id)" >> $GITHUB_OUTPUT
- name: Deploy frontend to S3
run: |
aws s3 sync frontend/dist "s3://${{ steps.get-frontend-resources.outputs.bucket }}"
aws cloudfront create-invalidation --distribution-id ${{ steps.get-frontend-resources.outputs.distribution }} --paths "/*"
build-backend-image:
needs:
- detect-changes
environment: staging
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: AWS login with DEV credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.INSTALLER_DEV_AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.INSTALLER_DEV_AWS_SECRET_KEY }}
aws-region: us-east-1
- name: Log into CodeArtifact
id: codeartifact-login
run: |
CODEARTIFACT_AUTH_TOKEN=$(aws codeartifact get-authorization-token --domain energysage --domain-owner 659694780082 --query authorizationToken --output text)
echo "CODEARTIFACT_AUTH_TOKEN=$CODEARTIFACT_AUTH_TOKEN" >> $GITHUB_OUTPUT
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
with:
mask-password: 'true'
- name: Build, tag, and push backend image to Amazon ECR
id: build-backend
env:
ECR_TAG: '${{ steps.login-ecr.outputs.registry }}/${{ vars.PROJECT }}:backend-${{ github.sha }}'
RELEASE_VERSION: ${{ github.sha }}
run: |
# Build a docker container and
# push it to ECR so that it can
# be deployed to ECS.
docker build --build-arg "RELEASE_VERSION=$RELEASE_VERSION" -t $ECR_TAG ./backend -f ./backend/deploy.dockerfile
docker push $ECR_TAG
echo "image_backend=$ECR_TAG" >> $GITHUB_OUTPUT
echo $ECR_TAG > ecr_tag.txt
zip ecr_tag.zip ecr_tag.txt
- name: Archive ECR tag
uses: actions/upload-artifact@v4
with:
name: ecr_tag
path: ecr_tag.zip
deploy-stage-backend:
needs:
- build-backend-image
- detect-changes
- deploy-stage-iac
if: |
always() &&
(needs.deploy-stage-iac.result == 'success' || needs.deploy-stage-iac.result == 'skipped') &&
needs.detect-changes.outputs.deploy-backend == 'true'
environment: staging
runs-on: ubuntu-latest
env:
TF_VAR_region: ${{ vars.AWS_REGION }}
TF_VAR_environment: ${{ vars.ENV_SHORT_NAME }}
TF_VAR_name_prefix: "tb-${{ vars.PROJECT_SHORT_NAME }}-${{ vars.ENV_SHORT_NAME }}"
TF_VAR_app_env: ${{ vars.APP_ENV }}
TF_VAR_db_enc_secret: ${{ vars.DB_ENCRYPTED_SECRET }}
TF_VAR_frontend_url: ${{ vars.FRONTEND_URL }}
TF_VAR_fxa_secret: ${{ vars.FXA_SECRET }}
TF_VAR_google_oauth_secret: ${{ vars.GOOGLE_OAUTH_SECRET }}
TF_VAR_log_level: ${{ vars.LOG_LEVEL }}
TF_VAR_short_base_url: ${{ vars.SHORT_BASE_URL }}
TF_VAR_smtp_secret: ${{ vars.SMTP_SECRET }}
TF_VAR_zoom_callback: ${{ vars.ZOOM_CALLBACK }}
TF_VAR_zoom_secret: ${{ vars.ZOOM_SECRET }}
TF_VAR_sentry_dsn: ${{ vars.SENTRY_DSN }}
TF_VAR_ssl_cert_arn: ${{ vars.SSL_CERT_ARN }}
steps:
- uses: actions/checkout@v4
- name: AWS login with DEV credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.INSTALLER_DEV_AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.INSTALLER_DEV_AWS_SECRET_KEY }}
aws-region: us-east-1
- name: Log into CodeArtifact
id: codeartifact-login
run: |
CODEARTIFACT_AUTH_TOKEN=$(aws codeartifact get-authorization-token --domain energysage --domain-owner 659694780082 --query authorizationToken --output text)
echo "CODEARTIFACT_AUTH_TOKEN=$CODEARTIFACT_AUTH_TOKEN" >> $GITHUB_OUTPUT
- name: install opentofu
uses: opentofu/setup-opentofu@v1
with:
tofu_version: ${{ vars.TF_VERSION }}
tofu_wrapper: false
- name: install terragrunt
run: |
sudo wget -q -O /bin/terragrunt "https://github.com/gruntwork-io/terragrunt/releases/download/v${{ vars.TG_VERSION }}/terragrunt_linux_amd64"
sudo chmod +x /bin/terragrunt
terragrunt -v
- name: download ecr tag
uses: actions/download-artifact@v4
with:
name:
ecr_tag
- name: Unzip ECR tag
id: get_ecr_tag
run: |
unzip ecr_tag.zip
output=$(cat ecr_tag.txt)
echo ecr_tag=$output >> $GITHUB_OUTPUT
- name: AWS login with DEV credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.INSTALLER_DEV_AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.INSTALLER_DEV_AWS_SECRET_KEY }}
aws-region: us-east-1
- run: |-
aws codeartifact login --tool pip --domain energysage --domain-owner 659694780082 --repository cloud-engineering
aws codeartifact login --tool npm --domain energysage --domain-owner 659694780082 --repository cloud-engineering
poetry config http-basic.codeartifact aws $(aws codeartifact get-authorization-token --domain energysage --domain-owner 659694780082 --query authorizationToken --output text)
- name: deploy backend-service
working-directory: ./tofu/environments/stage/services/backend-service
run: |
terragrunt init -upgrade
terragrunt validate
terragrunt plan -var 'image=${{ steps.get_ecr_tag.outputs.ecr_tag }}' -out tfplan
terragrunt apply tfplan
create-release:
needs:
- build-backend-image
- build-and-deploy-stage-frontend
- deploy-stage-iac
- deploy-stage-backend
if: |
always() &&
contains(join(needs.*.result, ','), 'success') &&
! contains(join(needs.*.result, ','), 'failure')
environment: production
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup NPM
uses: actions/setup-node@v4
with:
node-version: '20.x'
- name: Install dependencies
run: cd frontend && npm install
- name: Build prod frontend
run: |
cp frontend/.env.prod.example frontend/.env.prod
cd frontend && npm run build -- --mode ${{ vars.APP_ENV }}
zip -r ../frontend.zip dist
- name: download ecr tag
uses: actions/download-artifact@v4
with:
name:
ecr_tag
- name: Zip IaC
run: zip -r iac.zip tofu -x "tofu/environments/stage/*" "tofu/environments/prod/*/*/.terragrunt-cache/*"
- name: create release tag
id: create-release-tag
run: echo "tag_name=r-$(printf %04d $GITHUB_RUN_NUMBER)" >> $GITHUB_OUTPUT
- name: create draft release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.create-release-tag.outputs.tag_name }}
name: Release ${{ steps.create-release-tag.outputs.tag_name }}
body: |
## Info
Commit ${{ github.sha }} was deployed to `stage`. [See code diff](${{ github.event.compare }}).
It was initialized by [${{ github.event.sender.login }}](${{ github.event.sender.html_url }}).
## How to Promote?
In order to promote this to prod, edit the draft and press **"Publish release"**.
draft: true
files: |
ecr_tag.zip
frontend.zip
iac.zip