Skip to content

feat: enhance appendEventToGoogleSheets to prevent value duplication … #39721

feat: enhance appendEventToGoogleSheets to prevent value duplication …

feat: enhance appendEventToGoogleSheets to prevent value duplication … #39721

Workflow file for this run

name: App Deploy
on:
push:
branches: [main, stage]
pull_request:
branches: [main, feature/*]
merge_group:
branches: [main]
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
affected:
runs-on: blacksmith-2vcpu-ubuntu-2204
strategy:
matrix:
node-version: [22]
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- uses: actions/setup-node@v5
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- uses: nrwl/nx-set-shas@v4
- id: set-matrix
name: set matrix app to affected array
run: |
matrix=$(pnpm -s exec ts-node tools/scripts/deploy-apps.ts --projects "apps/*" --exclude "apps/arclight")
echo "matrix=${matrix}" >> "$GITHUB_OUTPUT"
cat "$GITHUB_OUTPUT"
deploy-preview:
name: Deploy Preview
needs: affected
# if branch is not main or is a pull request
if: |
needs.affected.outputs.matrix != '[]' &&
needs.affected.outputs.matrix != '' &&
github.event_name != 'merge_group' && (
github.ref != 'refs/heads/main' || github.event_name == 'pull_request'
)
strategy:
fail-fast: false
matrix:
app: ${{fromJson(needs.affected.outputs.matrix)}}
github-ref-name: ['${{ github.ref_name }}']
github-event-name: ['${{ github.event_name }}']
node-version: [22]
exclude:
# handled by production job below
- app: journeys
github-ref-name: stage
github-event-name: push
# handled by production job below
- app: short-links
github-ref-name: stage
github-event-name: push
# handled by ecs-frontend-deploy-stage
- app: journeys-admin
github-ref-name: stage
github-event-name: push
runs-on: blacksmith-2vcpu-ubuntu-2204
env:
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
outputs:
url: ${{ steps.deployment-url.outputs.deployment-url }}
permissions:
pull-requests: write
deployments: write
contents: write
steps:
- name: start deployment
uses: chrnorm/deployment-action@v2
id: deployment
with:
token: ${{ secrets.GITHUB_TOKEN }}
environment: Preview - ${{ matrix.app }}
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- uses: actions/setup-node@v5
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- uses: nrwl/nx-set-shas@v4
- name: vercel deployment
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
ARCLIGHT_VERCEL_PROJECT_ID: ${{ secrets.ARCLIGHT_VERCEL_PROJECT_ID }}
DOCS_VERCEL_PROJECT_ID: ${{ secrets.DOCS_VERCEL_PROJECT_ID }}
JOURNEYS_VERCEL_PROJECT_ID: ${{ secrets.JOURNEYS_STAGE_VERCEL_PROJECT_ID }}
JOURNEYS_ADMIN_VERCEL_PROJECT_ID: ${{ secrets.JOURNEYS_ADMIN_VERCEL_PROJECT_ID }}
PLAYER_VERCEL_PROJECT_ID: ${{ secrets.PLAYER_VERCEL_PROJECT_ID }}
SHORT_LINKS_VERCEL_PROJECT_ID: ${{ secrets.SHORT_LINKS_STAGE_VERCEL_PROJECT_ID }}
VIDEOS_ADMIN_VERCEL_PROJECT_ID: ${{ secrets.VIDEOS_ADMIN_VERCEL_PROJECT_ID }}
WATCH_VERCEL_PROJECT_ID: ${{ secrets.WATCH_VERCEL_PROJECT_ID }}
WATCH_MODERN_VERCEL_PROJECT_ID: ${{ secrets.WATCH_MODERN_VERCEL_PROJECT_ID }}
RESOURCES_VERCEL_PROJECT_ID: ${{ secrets.RESOURCES_VERCEL_PROJECT_ID }}
NEXT_PUBLIC_VERCEL_ENV: ${{ github.event_name == 'push' && github.ref == 'refs/heads/stage' && 'stage' || 'preview' }}
NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA: ${{ github.sha }}
# use run-namy to avoid case where deploy command doesn't exist for a project
run: pnpm exec nx run-many --target=deploy --projects=${{ matrix.app }}
- name: upload sourcemaps to datadog
env:
GIT_COMMIT_SHA: ${{ github.sha }}
DATADOG_API_KEY: ${{ secrets.DATADOG_API_KEY }}
run: pnpm exec nx run-many --target=upload-sourcemaps --projects=${{ matrix.app }}
- name: vercel set alias
if: ${{ github.event_name == 'pull_request' }}
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
PR_NUMBER: ${{ github.event.number }}
# use run-namy to avoid case where deploy command doesn't exist for a project
run: pnpm exec nx run-many --target=vercel-alias --projects=${{ matrix.app }}
- name: Generate GitHub deployment comment
id: deployment-url
env:
APP: ${{ matrix.app }}
run: ./tools/scripts/generate-deployment-comment.sh
- id: get-comment-body
run: |
body="$(cat .github/deployment_comment.md)"
delimiter="$(openssl rand -hex 8)"
echo "body<<$delimiter" >> $GITHUB_OUTPUT
echo "$body" >> $GITHUB_OUTPUT
echo "$delimiter" >> $GITHUB_OUTPUT
- uses: mshick/add-pr-comment@v2
if: ${{ github.event_name == 'pull_request' }}
name: add deployment comment to pull request
with:
message: ${{ steps.get-comment-body.outputs.body }}
message-id: ${{ matrix.app }}
- name: add deployment comment to commit
if: ${{ github.event_name != 'pull_request' }}
uses: peter-evans/commit-comment@v3
with:
body: ${{ steps.get-comment-body.outputs.body }}
- name: update deployment status
uses: chrnorm/deployment-status@v2
if: always()
with:
token: ${{ secrets.GITHUB_TOKEN }}
state: ${{ job.status }}
environment-url: ${{ steps.deployment-url.outputs.deployment-url }}
deployment-id: ${{ steps.deployment.outputs.deployment_id }}
- name: Prepare E2E input file
run: |
mkdir -p e2e-input
echo "${{ steps.deployment-url.outputs.deployment-url }}" > e2e-input/${{ matrix.app }}.txt
- name: Upload E2E input artifact
uses: actions/upload-artifact@v4
with:
name: e2e-input-${{ matrix.app }}
path: e2e-input/${{ matrix.app }}.txt
if-no-files-found: ignore
overwrite: true
retention-days: 2
deploy-status:
runs-on: blacksmith-2vcpu-ubuntu-2204
needs: [affected, deploy-preview]
if: ${{ always() && github.event_name == 'pull_request' }}
steps:
- name: Successful deploy
if: ${{ !(contains(needs.*.result, 'failure')) }}
run: exit 0
- name: Failing deploy
if: ${{ contains(needs.*.result, 'failure') }}
run: exit 1
build-e2e-matrix:
name: Build E2E Matrix
needs: [affected, deploy-preview]
if: ${{ github.event_name != 'merge_group' && needs.deploy-preview.result == 'success' && !(github.event_name == 'push' && github.ref == 'refs/heads/stage') && (github.event_name != 'pull_request' || !github.event.pull_request.draft) }}
permissions:
actions: read
contents: read
runs-on: blacksmith-2vcpu-ubuntu-2204
outputs:
include: ${{ steps.build.outputs.include }}
apps: ${{ steps.build.outputs.apps }}
steps:
- name: Download all E2E input artifacts
uses: actions/download-artifact@v4
with:
path: e2e-input
pattern: e2e-input-*
merge-multiple: true
- name: Build matrix from deployments
id: build
run: |
set -euo pipefail
include='[]'
if [ ! -d e2e-input ]; then
echo "include=${include}" >> $GITHUB_OUTPUT
echo "apps=[]" >> $GITHUB_OUTPUT
exit 0
fi
shopt -s nullglob
files=(e2e-input/*.txt)
echo "E2E input files found: ${files[*]:-none}"
if [ ${#files[@]} -eq 0 ]; then
echo "include=${include}" >> $GITHUB_OUTPUT
echo "apps=[]" >> $GITHUB_OUTPUT
exit 0
fi
for f in "${files[@]}"; do
app=$(basename "${f}" .txt)
url=$(cat "${f}")
echo "Adding app=${app} url=${url}"
if [ -n "${url}" ]; then
include=$(jq -c --arg app "${app}" --arg url "${url}" '. + [{app:$app, url:$url}]' <<<"${include}")
fi
done
apps=$(jq -c '[.[] | .app]' <<<"${include}")
echo "Final E2E include: ${include}"
echo "include=${include}" >> $GITHUB_OUTPUT
echo "apps=${apps}" >> $GITHUB_OUTPUT
e2e:
name: Playwright E2E (${{ matrix.app }})
needs: [build-e2e-matrix]
# Only run if ALL deploy-preview matrix entries succeeded and we have URLs
if: ${{ github.event_name != 'merge_group' && needs.build-e2e-matrix.result == 'success' && needs.build-e2e-matrix.outputs.apps != '[]' && needs.build-e2e-matrix.outputs.apps != '' && !(github.event_name == 'push' && github.ref == 'refs/heads/stage') && (github.event_name != 'pull_request' || !github.event.pull_request.draft) }}
permissions:
contents: read
runs-on: blacksmith-4vcpu-ubuntu-2204
env:
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
strategy:
fail-fast: false
matrix:
app: ${{ fromJson(needs.build-e2e-matrix.outputs.apps) }}
node-version: [22]
include: ${{ fromJson(needs.build-e2e-matrix.outputs.include) }}
steps:
- uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- uses: actions/setup-node@v5
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-node-${{ matrix.node-version }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-node-${{ matrix.node-version }}-playwright-
- name: Install Playwright Browsers
run: pnpm exec playwright install --with-deps
- name: Run Playwright tests
run: pnpm exec nx run ${{ matrix.app }}-e2e:e2e
env:
DEPLOYMENT_URL: ${{ matrix.url }}
PLAYWRIGHT_USER: ${{ secrets.PLAYWRIGHT_USER }}
PLAYWRIGHT_TEAM_NAME: ${{ secrets.PLAYWRIGHT_TEAM_NAME }}
EXAMPLE_EMAIL_TOKEN: ${{ secrets.EXAMPLE_EMAIL_TOKEN }}
PLAYWRIGHT_EMAIL: ${{ secrets.PLAYWRIGHT_EMAIL }}
PLAYWRIGHT_PASSWORD: ${{ secrets.PLAYWRIGHT_PASSWORD }}
PLAYWRIGHT_EMAIL2: ${{ secrets.PLAYWRIGHT_EMAIL2 }}
PLAYWRIGHT_PASSWORD2: ${{ secrets.PLAYWRIGHT_PASSWORD2 }}
PLAYWRIGHT_EMAIL3: ${{ secrets.PLAYWRIGHT_EMAIL3 }}
PLAYWRIGHT_PASSWORD3: ${{ secrets.PLAYWRIGHT_PASSWORD3 }}
PLAYWRIGHT_EMAIL4: ${{ secrets.PLAYWRIGHT_EMAIL4 }}
PLAYWRIGHT_PASSWORD4: ${{ secrets.PLAYWRIGHT_PASSWORD4 }}
PLAYWRIGHT_EMAIL5: ${{ secrets.PLAYWRIGHT_EMAIL5 }}
PLAYWRIGHT_PASSWORD5: ${{ secrets.PLAYWRIGHT_PASSWORD5 }}
- uses: actions/upload-artifact@v4
if: always()
with:
name: ${{ matrix.app }}-playwright-report
path: |
playwright-report/
retention-days: 30
deploy-production:
name: Deploy Production
# if push to main or stage
if: |
needs.affected.outputs.matrix != '[]' &&
needs.affected.outputs.matrix != '' &&
github.event_name == 'push' &&
(github.ref == 'refs/heads/main' || github.ref == 'refs/heads/stage')
needs: affected
strategy:
fail-fast: false
matrix:
app: ${{fromJson(needs.affected.outputs.matrix)}}
github-ref-name: ['${{ github.ref_name }}']
node-version: [22]
exclude:
# handled by ecs-frontend-deploy-prod
- app: journeys-admin
# handled by deploy-preview job above
- github-ref-name: stage
include:
- app: journeys
github-ref-name: stage
- app: short-links
github-ref-name: stage
runs-on: blacksmith-2vcpu-ubuntu-2204
permissions:
deployments: write
contents: write
outputs:
url: ${{ steps.deployment-url.outputs.deployment-url }}
steps:
- name: start deployment
uses: chrnorm/deployment-action@v2
id: deployment
with:
token: ${{ secrets.GITHUB_TOKEN }}
environment: Production - ${{ matrix.app }}
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- uses: actions/setup-node@v5
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- uses: nrwl/nx-set-shas@v4
- name: vercel deployment
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
ARCLIGHT_VERCEL_PROJECT_ID: ${{ secrets.ARCLIGHT_VERCEL_PROJECT_ID }}
DOCS_VERCEL_PROJECT_ID: ${{ secrets.DOCS_VERCEL_PROJECT_ID }}
JOURNEYS_VERCEL_PROJECT_ID: ${{ github.ref == 'refs/heads/stage' && secrets.JOURNEYS_STAGE_VERCEL_PROJECT_ID || secrets.JOURNEYS_VERCEL_PROJECT_ID }}
JOURNEYS_ADMIN_VERCEL_PROJECT_ID: ${{ secrets.JOURNEYS_ADMIN_VERCEL_PROJECT_ID }}
PLAYER_VERCEL_PROJECT_ID: ${{ secrets.PLAYER_VERCEL_PROJECT_ID }}
SHORT_LINKS_VERCEL_PROJECT_ID: ${{ github.ref == 'refs/heads/stage' && secrets.SHORT_LINKS_STAGE_VERCEL_PROJECT_ID || secrets.SHORT_LINKS_VERCEL_PROJECT_ID }}
VIDEOS_ADMIN_VERCEL_PROJECT_ID: ${{ secrets.VIDEOS_ADMIN_VERCEL_PROJECT_ID }}
WATCH_VERCEL_PROJECT_ID: ${{ secrets.WATCH_VERCEL_PROJECT_ID }}
WATCH_MODERN_VERCEL_PROJECT_ID: ${{ secrets.WATCH_MODERN_VERCEL_PROJECT_ID }}
RESOURCES_VERCEL_PROJECT_ID: ${{ secrets.RESOURCES_VERCEL_PROJECT_ID }}
NEXT_PUBLIC_VERCEL_ENV: prod
NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA: ${{ github.sha }}
# use run-namy to avoid case where deploy command doesn't exist for a project
run: pnpm exec nx run-many --target=deploy --projects=${{ matrix.app }} --prod
- name: upload sourcemaps to datadog
env:
GIT_COMMIT_SHA: ${{ github.sha }}
DATADOG_API_KEY: ${{ secrets.DATADOG_API_KEY }}
run: pnpm exec nx run-many --target=upload-sourcemaps --projects=${{ matrix.app }}
- name: Generate GitHub comment
id: deployment-url
env:
APP: ${{ matrix.app }}
run: ./tools/scripts/generate-deployment-comment.sh
- id: get-comment-body
run: |
body="$(cat .github/deployment_comment.md)"
delimiter="$(openssl rand -hex 8)"
echo "body<<$delimiter" >> $GITHUB_OUTPUT
echo "$body" >> $GITHUB_OUTPUT
echo "$delimiter" >> $GITHUB_OUTPUT
- name: add deployment comment to commit
if: ${{ github.event_name != 'pull_request' }}
uses: peter-evans/commit-comment@v3
with:
body: ${{ steps.get-comment-body.outputs.body }}
- name: update deployment status
uses: chrnorm/deployment-status@v2
if: always()
with:
token: ${{ secrets.GITHUB_TOKEN }}
state: ${{ job.status }}
environment-url: ${{ steps.deployment-url.outputs.deployment-url }}
deployment-id: ${{ steps.deployment.outputs.deployment_id }}