Skip to content

Share reviews

Share reviews #369

name: Connect CI
on:
push:
branches: [main]
paths:
- '.ebextensions*/**'
- '.ebstalk.apps.env/**'
- '.github/**'
- 'package.json'
- 'package-lock.json'
- 'apps/connect/**'
- 'apps/sunnyawards/**'
- '@connect-shared/**'
- 'abis/**'
- 'adapters/**'
- 'config/**'
- 'connectors/**'
- 'lib/**'
- 'hooks/**'
- 'models/**'
pull_request:
types: [labeled, opened, synchronize]
branches: ['**']
paths:
- '.ebextensions*/**'
- '.ebstalk.apps.env/**'
- '.github/**'
- 'package.json'
- 'package-lock.json'
- 'apps/connect/**'
- '@connect-shared/**'
- 'abis/**'
- 'adapters/**'
- 'config/**'
- 'connectors/**'
- 'lib/**'
- 'hooks/**'
- 'models/**'
workflow_dispatch:
inputs:
core_pkg_version:
description: 'Core pkg version to update to'
required: true
concurrency:
group: ci-connect-${{ github.event_name }}-${{ github.ref }}
jobs:
build-app:
name: Build apps
runs-on: ubuntu-latest
outputs:
head-commit-message: ${{ steps.get_head_commit_message.outputs.commit_message }}
steps:
- name: Print Triggering event context payload
env:
workflow_event_context: ${{ toJSON(github.event) }}
run: |
echo "$workflow_event_context"
echo "Workflow and code ref: ${{github.ref}}"
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install dependencies
uses: ./.github/actions/install
with:
core_pkg_version: ${{ inputs.core_pkg_version }}
commit_core_pkg_upgrade: true
save_cache: true
- name: Build apps
uses: ./.github/actions/build_connect
# source https://github.com/orgs/community/discussions/28474
- name: Print head git commit message
id: get_head_commit_message
run: echo "commit_message=$(git show -s --format=%s)" >> "$GITHUB_OUTPUT"
test-connect:
name: Test apps
runs-on: ubuntu-latest
needs: build-app
if: ${{ github.event.action != 'labeled' && !contains(needs.build-app.outputs.head-commit-message, 'skip-tests') }}
# Postgres setup copied from https://gist.github.com/2color/537f8ef13ecec80059abb007839a6878
services:
postgres:
image: postgres
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
--hostname postgres
ports:
# Maps tcp port 5432 on service container to the host
- 5432:5432
steps:
- uses: actions/checkout@v4
- name: Restore dependencies from cache
uses: ./.github/actions/install
- name: Setup test database
run: npx dotenv -e .env.test.local -- npm run prisma:reset
- name: Restore app from cache
uses: ./.github/actions/build_connect
- name: Validate Webapp
run: |
npm run lint -w apps/connect
npm run typecheck -w apps/connect
- name: Validate Connect API
run: |
npm run lint -w apps/connect-api
# We need to fix jest transpilation before we can run connect API tests
# - name: 'Test Connect API'
# run: 'npm run connect-api:test'
- name: Validate Sunny Awards
run: |
npm run lint -w apps/sunnyawards
npm run typecheck -w apps/sunnyawards
test-connect-e2e:
name: Test Connect e2e
runs-on: ubuntu-latest
needs: build-app
if: ${{ github.event.action != 'labeled' && !contains(needs.build-app.outputs.head-commit-message, 'skip-tests') }}
# Postgres setup copied from https://gist.github.com/2color/537f8ef13ecec80059abb007839a6878
services:
postgres:
image: postgres
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
--hostname postgres
ports:
# Maps tcp port 5432 on service container to the host
- 5432:5432
steps:
- uses: actions/checkout@v4
- name: Restore dependencies from cache
uses: ./.github/actions/install
- name: Setup test database
run: npx dotenv -e .env.test.local -- npm run prisma:reset
- name: Restore app from cache
uses: ./.github/actions/build_connect
- name: Start connect app
run: |
npm run connect:start:test:ci &> connect.log &
sleep_loop_ct=0
until curl localhost:3337/api/health || [[ $sleep_loop_ct > 30 ]]; do
echo "webapp not up in loop $sleep_loop_ct ... sleeping"
sleep_loop_ct=$((sleep_loop_ct + 1))
sleep 1
done
- name: Run Connect E2E tests
env:
REACT_APP_APP_ENV: 'test'
# we have to run docker command ourselves to set network=host so that playwright can access the server
run: |
[[ "${{ runner.debug }}" = "1" ]] && tail -f connect.log &
docker run --name mcrmicrosoftcomplaywrightv1343jammy_68c205 \
--workdir /github/workspace --rm \
-e "REACT_APP_APP_ENV" -e CI=true \
-v "/var/run/docker.sock":"/var/run/docker.sock" \
-v "/home/runner/work/_temp/_github_home":"/github/home" \
-v "/home/runner/work/_temp/_github_workflow":"/github/workflow" \
-v "/home/runner/work/_temp/_runner_file_commands":"/github/file_commands" \
-v "/home/runner/work/app.charmverse.io/app.charmverse.io":"/github/workspace" \
--network "host" \
--ipc=host \
mcr.microsoft.com/playwright:v1.42.1-jammy \
npm run connect:test:e2e:ci
test-sunnyawards-e2e:
name: Test Sunny Awards e2e
runs-on: ubuntu-latest
needs: build-app
if: ${{ github.event.action != 'labeled' && !contains(needs.build-app.outputs.head-commit-message, 'skip-tests') }}
# Postgres setup copied from https://gist.github.com/2color/537f8ef13ecec80059abb007839a6878
services:
postgres:
image: postgres
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
--hostname postgres
ports:
# Maps tcp port 5432 on service container to the host
- 5432:5432
steps:
- uses: actions/checkout@v4
- name: Restore dependencies from cache
uses: ./.github/actions/install
- name: Setup test database
run: npx dotenv -e .env.test.local -- npm run prisma:reset
- name: Restore app from cache
uses: ./.github/actions/build_connect
- name: Start Sunny Awards app
run: |
npm run sunnyawards:start:test:ci &> connect.log &
sleep_loop_ct=0
until curl localhost:3337/api/health || [[ $sleep_loop_ct > 30 ]]; do
echo "webapp not up in loop $sleep_loop_ct ... sleeping"
sleep_loop_ct=$((sleep_loop_ct + 1))
sleep 1
done
- name: Run Sunny Awards E2E tests
env:
REACT_APP_APP_ENV: 'test'
# we have to run docker command ourselves to set network=host so that playwright can access the server
run: |
[[ "${{ runner.debug }}" = "1" ]] && tail -f connect.log &
docker run --name mcrmicrosoftcomplaywrightv1343jammy_68c205 \
--workdir /github/workspace --rm \
-e "REACT_APP_APP_ENV" -e CI=true \
-v "/var/run/docker.sock":"/var/run/docker.sock" \
-v "/home/runner/work/_temp/_github_home":"/github/home" \
-v "/home/runner/work/_temp/_github_workflow":"/github/workflow" \
-v "/home/runner/work/_temp/_runner_file_commands":"/github/file_commands" \
-v "/home/runner/work/app.charmverse.io/app.charmverse.io":"/github/workspace" \
--network "host" \
--ipc=host \
mcr.microsoft.com/playwright:v1.42.1-jammy \
npm run sunnyawards:test:e2e:ci
upload-docker:
name: Upload Docker image
runs-on: ubuntu-latest
# run whether previous jobs were successful or skipped
if: |
github.ref == 'refs/heads/main' ||
(github.event.action == 'labeled' && github.event.label.name == ':rocket: deploy-connect') ||
(github.event.action == 'labeled' && github.event.label.name == ':rocket: deploy-sunnyawards') ||
(github.event.action != 'labeled' && (contains(github.event.pull_request.labels.*.name, ':rocket: deploy-connect') || contains(github.event.pull_request.labels.*.name, ':rocket: deploy-sunnyawards')))
needs: build-app
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install dependencies
uses: ./.github/actions/install
- name: Build app
uses: ./.github/actions/build_connect
- name: Update Dockerfile
run: |
rm Dockerfile && mv apps/connect/Dockerfile Dockerfile
- name: Build and Push Docker image
id: docker_build_push
uses: ./.github/actions/build_docker_image
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: us-east-1
with:
ecr_registry: charmverse-connect
upload-static-assets:
name: Upload assets in production
runs-on: ubuntu-latest
# run whether previous jobs were successful or skipped
if: github.ref == 'refs/heads/main' && !(failure() || cancelled())
needs: build-app
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install dependencies
uses: ./.github/actions/install
- name: Calculate Build ID
id: get_build_id
run: |
build_id=${{ hashFiles('package-lock.json', 'apps/**/*.[jt]s', 'lib/**/*.[jt]s') }}
echo "build_id=$build_id" >> $GITHUB_OUTPUT
- name: Build app
uses: ./.github/actions/build_connect
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Upload static assets to S3
run: |
aws s3 sync apps/connect/.next/static/ s3://charm.cdn/webapp-assets/_next/static/
aws s3 sync apps/sunnyawards/.next/static/ s3://charm.cdn/webapp-assets/_next/static/
- name: Upload JS source maps to Datadog
env:
DATADOG_API_KEY: ${{ secrets.DATADOG_API_KEY }}
run: |
npm install -g @datadog/datadog-ci
datadog-ci sourcemaps upload apps/connect/.next/static \
--service=connect \
--release-version=${{ steps.get_build_id.outputs.build_id }} \
--minified-path-prefix=https://cdn.charmverse.io/_next/static
deploy-production:
name: Deploy ${{ matrix.name }}
# run whether previous jobs were successful or skipped
if: github.ref == 'refs/heads/main' && !(failure() || cancelled())
needs: [test-connect, test-connect-e2e, test-sunnyawards-e2e, upload-docker, upload-static-assets]
runs-on: ubuntu-latest
strategy:
matrix:
include:
- name: Connect App
stack: prd-connect
ebextensions: .ebextensions_connect
- name: Connect API
stack: prd-connect-api
ebextensions: .ebextensions_connect_api
- name: Sunny Awards
stack: prd-sunnyawards
ebextensions: .ebextensions_sunnyawards
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Inject slug/short variables
uses: rlespinasse/[email protected]
with:
short-length: 7
# we need to bring back node_modules which includes tsconfig-paths which is used by CDK files
- name: Install dependencies
uses: ./.github/actions/install
- name: Set the docker compose env variables
uses: mikefarah/yq@master
with:
cmd: |
yq -I 4 -i '
with(.option_settings."aws:elasticbeanstalk:application:environment";
.IMGTAG = "${{ github.run_id }}-${{ env.GITHUB_SHA_SHORT }}")
' ${{ matrix.ebextensions }}/00_env_vars.config
rm -rf .ebextensions && mv ${{ matrix.ebextensions }} .ebextensions
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Package and deploy
run: |
cat files_to_zip.txt | zip --symlinks -r@ ${{ matrix.stack }}.zip
npx aws-cdk deploy --method=direct -c name=${{ matrix.stack }}
deploy-staging:
name: Deploy to staging
if: |
(github.event.action == 'labeled' && github.event.label.name == ':rocket: deploy-connect') ||
(github.event.action == 'labeled' && github.event.label.name == ':rocket: deploy-sunnyawards') ||
(github.event.action != 'labeled' && (contains(github.event.pull_request.labels.*.name, ':rocket: deploy-connect') || contains(github.event.pull_request.labels.*.name, ':rocket: deploy-sunnyawards')))
runs-on: ubuntu-latest
# prevent workflows running in parallel
concurrency: deploy-staging-${{ github.head_ref }}
needs: [upload-docker]
steps:
- uses: actions/checkout@v4
- name: Inject slug/short variables
uses: rlespinasse/[email protected]
with:
short-length: 7
- name: Calculate Stage env var
run: |
if ${{contains(github.event.pull_request.labels.*.name, ':rocket: deploy-connect')}}; then stack='stg-connect'; fi
if ${{contains(github.event.pull_request.labels.*.name, ':rocket: deploy-sunnyawards')}}; then stack='stg-sunnyawards'; fi
full_stage_name="$stack-${{ github.event.number }}-${{ env.GITHUB_HEAD_REF_SLUG }}"
# sanitize and trim string so that it can be used as a valid subdomain. Includes removing hyphens at the start and end of the name
stage_name=`echo "$full_stage_name" | sed -E -e 's/[^a-zA-Z0-9-]+//g' -e 's/(.{40}).*/\1/' -e 's/^-/0/' -e 's/-$/0/'`
# export the stage name so that it can be used in other steps
echo "STAGE_NAME=$stage_name" >> $GITHUB_ENV
# we need to bring back node_modules which includes tsconfig-paths which is used by CDK files
- name: Install dependencies
uses: ./.github/actions/install
- name: Replace env_var with staging settings
run: |
ebextension_files=$(ls .ebextensions*/00_env_vars.config)
ebstalk_apps_env_files=$(ls .ebstalk.apps.env/*)
for conf_file in $ebextension_files $ebstalk_apps_env_files; do
sed -i 's/prd/stg/g' $conf_file
sed -i 's/production/staging/g' $conf_file
done
# modifying cloudformation alarm to send alerts to test sns topic.
# leaving it in even if we're deleting the config before deploying
# Useful to avoid accidental triggering to system-status channel.
for conf_file in .ebextensions*/06_cloudwatch_alarm.config; do
sed -i 's/Production-Alerts/lambda-test-debug/g' $conf_file
done
rm .ebextensions*/06_cloudwatch_alarm.config
# substituting the connect api domain name
sed -i 's/REACT_APP_CONNECT_API_HOST=.*/REACT_APP_CONNECT_API_HOST=https:\/\/${{env.STAGE_NAME}}.charmverse.co:4000/g' .ebstalk.apps.env/connect.env
- name: Set the docker compose env variables
uses: mikefarah/yq@master
with:
cmd: |
yq -I 4 -i '
with(.option_settings."aws:elasticbeanstalk:application:environment";
.COMPOSE_PROJECT_NAME = "pr${{ github.event.number }}" |
.IMGTAG = "${{ github.run_id }}-${{ env.GITHUB_SHA_SHORT }}")
' .ebextensions_connect/00_env_vars.config
yq -I 4 -i '
with(.option_settings."aws:elasticbeanstalk:application:environment";
.COMPOSE_PROJECT_NAME = "pr${{ github.event.number }}" |
.IMGTAG = "${{ github.run_id }}-${{ env.GITHUB_SHA_SHORT }}")
' .ebextensions_sunnyawards/00_env_vars.config
- name: Parse compose profile to see if we need to enable datadog
id: get_compose_profiles
uses: mikefarah/yq@master
with:
cmd: yq -r '.option_settings."aws:elasticbeanstalk:application:environment".COMPOSE_PROFILES' .ebextensions/00_env_vars.config
- name: Set DDENABLED variable in environment for build and deploy steps
run: |
cat .ebextensions/00_env_vars.config
COMPOSE_PROFILES=${{ steps.get_compose_profiles.outputs.result }}
if [[ "$COMPOSE_PROFILES" =~ ddtst ]]; then
echo "DDENABLED=true" >> $GITHUB_ENV
fi
- name: Create a github deployment
uses: bobheadxi/deployments@v1
id: deployment
with:
step: start
token: ${{ secrets.GITHUB_TOKEN }}
env: ${{ env.STAGE_NAME }}
ref: ${{ github.head_ref }}
override: true
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Override config with Connect app
# wrap the condition in "${{}}" because the string includes a colon
# see https://github.com/actions/runner/issues/1019
if: "${{ contains(github.event.pull_request.labels.*.name, ':rocket: deploy-connect') }}"
# aws s3 sync apps/connect/.next/static/ s3://charm.cdn/webapp-assets/_next/static/
run: |
rm -rf .ebextensions && mv .ebextensions_connect .ebextensions
- name: Override config with Sunny Awards
if: "${{ contains(github.event.pull_request.labels.*.name, ':rocket: deploy-sunnyawards') }}"
# aws s3 sync apps/sunnyawards/.next/static/ s3://charm.cdn/webapp-assets/_next/static/
run: |
rm -rf .ebextensions && mv .ebextensions_sunnyawards .ebextensions
- name: Deploy to staging
id: cdk_deploy
run: |
cat files_to_zip.txt | zip --symlinks -r@ ${{env.STAGE_NAME}}.zip
npx aws-cdk deploy -c name=${{env.STAGE_NAME}} --method=direct --outputs-file cdk.out.json
env_url=$(jq --raw-output '.[$ENV.STAGE_NAME].DeploymentUrl' ./cdk.out.json)
echo "env_url=$env_url" >> $GITHUB_OUTPUT
- name: update the github deployment status
uses: bobheadxi/deployments@v1
if: always()
with:
env: ${{ steps.deployment.outputs.env }}
step: finish
override: false
token: ${{ secrets.GITHUB_TOKEN }}
status: ${{ job.status }}
deployment_id: ${{ steps.deployment.outputs.deployment_id }}
env_url: ${{ steps.cdk_deploy.outputs.env_url }}
discord-alert:
name: Notify Discord of failure
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' && failure()
# pass in all steps so we can check if any failed
needs:
[
test-connect,
test-connect-e2e,
test-sunnyawards-e2e,
upload-docker,
upload-static-assets,
upload-docker,
deploy-production
]
steps:
- name: If any of prev jobs failed notify discord
if: contains(needs.*.result, 'failure')
uses: sarisia/actions-status-discord@v1
with:
webhook: ${{ secrets.DISCORD_WARNINGS_WEBHOOK }}
status: 'failure'
content: 'Hey <@&1027309276454207519>'
title: 'Connect deploy workflow failed'
description: |
Failed workflow URL: https://github.com/charmverse/app.charmverse.io/actions/runs/${{ github.run_id }}
color: '16515843'
url: 'https://github.com/charmverse/app.charmverse.io/actions/runs/${{ github.run_id }}'
username: GitHub Actions
avatar_url: 'https://github.githubassets.com/images/modules/logos_page/Octocat.png'