Skip to content

Insert Distribution 16 #8717

Insert Distribution 16

Insert Distribution 16 #8717

Workflow file for this run

name: CI
on:
merge_group:
pull_request:
workflow_dispatch:
concurrency:
group: ci-${{ github.ref }}-${{ github.event_name }}
cancel-in-progress: true
jobs:
build_next_image:
name: Build Next.js Docker Image
# Only build images for PRs and manual triggers, not for pushes to main/dev (handled by deploy workflows)
if: ${{ github.event_name != 'push' }}
# runs-on: ubuntu-latest
runs-on: arc-runner-set
permissions:
contents: read
outputs:
image-tar: ${{ steps.output-tar.outputs.path }}
image-name: next-app
image-tag: ${{ steps.image-tag.outputs.tag }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set Environment Variables from Template
run: |
cp .env.local.template .env.local
# fix for dockerized mode
sed -i 's/localhost/host.docker.internal/g' .env.local
# except NEXT_PUBLIC_URL
sed -i 's/NEXT_PUBLIC_URL=http:\/\/host.docker.internal/NEXT_PUBLIC_URL=http:\/\/localhost/g' .env.local
cat .env.local
- name: Extract build args from environment file
id: build-args
run: |
# Extract env vars and format them for docker build-args
echo "args<<EOF" >> $GITHUB_OUTPUT
cat .env.local | grep -v '^#' | grep -v '^$' >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Generate unique image tag
id: image-tag
run: echo "tag=next-app-$(echo $GITHUB_SHA | cut -c1-7)" >> $GITHUB_OUTPUT
- name: Build Docker image
id: build
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
target: next-app-runner
push: false
load: true
tags: ${{ steps.image-tag.outputs.tag }}
build-args: |
PACKAGE=next-app
${{ steps.build-args.outputs.args }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Export Docker image to tarball
run: docker save ${{ steps.image-tag.outputs.tag }} > next-app-image.tar
- name: Upload Docker image as artifact
id: upload-artifact
uses: actions/upload-artifact@v4
with:
name: next-app-image
path: next-app-image.tar
retention-days: 1
- name: Output tarball path
id: output-tar
run: echo "path=next-app-image.tar" >> $GITHUB_OUTPUT
supabase-schema-drift-check:
name: Supabase Schema Drift Check
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Check for Schema Drift
uses: ./.github/actions/supabase-schema-drift-check
unit-tests:
name: Unit Tests
runs-on: ubuntu-latest
permissions:
contents: read
env:
ANVIL_MAINNET_FORK_URL: ${{ secrets.CI_ANVIL_MAINNET_FORK_URL }}
ANVIL_BASE_FORK_URL: ${{ secrets.CI_ANVIL_BASE_FORK_URL }}
FOUNDRY_BASE_SEPOLIA_RPC_URL: ${{ secrets.CI_FOUNDRY_BASE_SEPOLIA_RPC_URL }}
YARN_ENABLE_HARDENED_MODE: 0
steps:
- name: Add hosts to /etc/hosts
run: |
sudo su
if grep -q "host.docker.internal" /etc/hosts; then
echo "Hosts file already contains host.docker.internal"
else
echo "127.0.0.1 host.docker.internal" | sudo tee -a /etc/hosts
fi
- uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 2
- name: Setup Environment
uses: ./.github/actions/setup-env
env:
YARN_ENABLE_HARDENED_MODE: 0
with:
yarn-install: false
- name: Tilt CI
id: tilt-ci
shell: bash
run: tilt ci unit-tests --timeout=15m
# Since we use ephemeral containers, we don't need to clean up anymore
# - name: Tilt Down
# # always run tilt down if tilt ci started
# if: always() && steps.tilt-ci.outcome != 'skipped'
# shell: bash
# run: tilt down
# @todo anvil fixtures cause dirty repo, but only in github actions 😢
- name: All Changes Committed
shell: bash
run: git diff # --exit-code
lint:
name: Lint
runs-on: ubuntu-latest
permissions:
contents: read
env:
ANVIL_MAINNET_FORK_URL: ${{ secrets.CI_ANVIL_MAINNET_FORK_URL }}
ANVIL_BASE_FORK_URL: ${{ secrets.CI_ANVIL_BASE_FORK_URL }}
FOUNDRY_BASE_SEPOLIA_RPC_URL: ${{ secrets.CI_FOUNDRY_BASE_SEPOLIA_RPC_URL }}
YARN_ENABLE_HARDENED_MODE: 0
steps:
- name: Add hosts to /etc/hosts
run: |
sudo su
if grep -q "host.docker.internal" /etc/hosts; then
echo "Hosts file already contains host.docker.internal"
else
echo "127.0.0.1 host.docker.internal" | sudo tee -a /etc/hosts
fi
- uses: actions/checkout@v4
with:
submodules: recursive
filter: 'blob:none'
fetch-depth: 0
- name: Setup Environment
uses: ./.github/actions/setup-env
env:
YARN_ENABLE_HARDENED_MODE: 0
with:
build-nextjs: 'false'
yarn-install: false
- name: Lint deps
shell: bash
run: |
tilt ci lint:deps
- name: Set Workers Count
id: workers
shell: bash
run: |
# set to max workers 1 until we figure out which task is causing the runner to disconnect
workers=$(MAX_WORKERS=1 node ./.devops/bin/worker-count)
echo "workers=$workers" >> $GITHUB_OUTPUT
- name: Lint
run: |
npx turbo run lint --affected --concurrency=${{ steps.workers.outputs.workers }}
env:
# app:lint is heavy on memory, so we need to increase the limit
NODE_OPTIONS: --max_old_space_size=8192
TURBO_SCM_BASE: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.before }}
playwright-tests:
name: Playwright Tests (Shard ${{ matrix.shard }}/4)
needs: [build_next_image]
# Only run playwright tests when we build the image (PRs and manual triggers)
if: ${{ github.event_name != 'push' }}
# arc-runner-set had a good run
runs-on: arc-runner-set
# runs-on: ubuntu-latest
strategy:
# Don't stop all shards if one fails
fail-fast: false
matrix:
shard: [1, 2, 3, 4]
env:
ANVIL_MAINNET_FORK_URL: ${{ secrets.CI_ANVIL_MAINNET_FORK_URL }}
ANVIL_BASE_FORK_URL: ${{ secrets.CI_ANVIL_BASE_FORK_URL }}
YARN_ENABLE_HARDENED_MODE: 0
NEXT_APP_IMAGE_TAG: ${{ needs.build_next_image.outputs.image-tag }}
# for writing PR comments
permissions:
contents: read
pull-requests: write
timeout-minutes: 60
steps:
- name: Add hosts to /etc/hosts
run: |
sudo su
if grep -q "host.docker.internal" /etc/hosts; then
echo "Hosts file already contains host.docker.internal"
else
echo "127.0.0.1 host.docker.internal" | sudo tee -a /etc/hosts
fi
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Environment
uses: ./.github/actions/setup-env
# yarn-install is now handled below
env:
YARN_ENABLE_HARDENED_MODE: 0
- name: Yarn Install
shell: bash
run: yarn install --immutable
- name: Download Docker image artifact
uses: actions/download-artifact@v4
with:
name: next-app-image
path: ./
- name: Load Docker image
run: |
docker load < next-app-image.tar
echo "Loaded Docker image: ${{ env.NEXT_APP_IMAGE_TAG }}"
docker images
# @todo anvil fixtures cause dirty repo, but only in github actions 😢
# - name: All Changes Committed
# shell: bash
# run: git diff --exit-code
- name: Install Playwright Dependencies
run: yarn playwright playwright install --with-deps > /dev/null
- name: Start Playwright Dependencies
shell: bash
run: |
export DEBUG="api:*,app:*,test:*,-test:fixtures:snaplet:*"
# Use the skip_docker_compose flag to not manage docker compose in tilt
nohup tilt up playwright:deps -- --skip_docker_compose &
tilt_pid=$!
echo "Tilt process started with PID: $tilt_pid"
echo waiting for tilt to be ready
for i in {1..10}; do
curl -s http://localhost:10350 > /dev/null && break || echo "Attempt $i failed, trying again..."
sleep 1
done
sleep 1
echo tilt is ready
max_attempts=90
wait_timeout=10
for ((i=1; i<=max_attempts; i++)); do
echo "Attempt $i: Waiting for tilt with timeout ${wait_timeout}s"
# Check if the Tilt process is still running
if ! ps -p $tilt_pid > /dev/null; then
echo "Tilt process (PID: $tilt_pid) is no longer running, exiting"
exit 1
fi
# Check if any targets are in error
has_errors=$(tilt dump engine | jq '
.ManifestTargets
| to_entries
| map(
select(
.value.State.RuntimeState.Status == "error" or
(.value.State.BuildHistory | length > 0 and .[0].Error != null)
)
)
| length > 0
')
if [ "$has_errors" = "true" ]; then
echo "There are targets in error status:"
tilt dump engine | jq '
.ManifestTargets
| to_entries
| map(
select(
.value.State.RuntimeState.Status == "error" or
(.value.State.BuildHistory | length > 0 and .[0].Error != null)
)
)
| map(.key)
'
exit 1
fi
if tilt wait --timeout "${wait_timeout}s" --for=condition=Ready "uiresource/playwright:deps"; then
echo "Tilt is ready"
break
else
echo "Tilt not ready, retrying..."
if [ "${{runner.debug}}" == "1" ]; then
tilt dump engine | jq '
.ManifestTargets
| to_entries
| map({key: (.value.State.RuntimeState.Status // "in_progress"), value: .key})
| group_by(.key)
| map({key: .[0].key, value: map(.value)})
| from_entries
'
fi
fi
if ((i == max_attempts)); then
echo "Reached maximum attempts, exiting"
exit 1
fi
done
- name: Start Next App
shell: bash
run: |
export NEXT_APP_PORT=0.0.0.0:3000
docker compose --env-file ./.env.local up -d next-app
# wait for next app to be ready
started=0
for i in {1..30}; do
if curl -s http://localhost:3000 > /dev/null; then
started=1
break
fi
echo "Attempt $i failed, trying again..."
sleep 1
done
if [ $started -eq 0 ]; then
echo "Next app did not start"
exit 1
fi
- name: Playwright Tests
id: playwright
shell: bash
run: |
docker compose logs -f --no-log-prefix next-app &
yarn playwright test --shard=${{ matrix.shard }}/4
- name: Tilt Down
# always run tilt down if tilt ci started
if: always() && steps.playwright.outcome != 'skipped'
shell: bash
run: tilt down
- name: Upload blob report to GitHub Actions Artifacts
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4
with:
name: blob-report-${{ matrix.shard }}
path: packages/playwright/blob-report/
retention-days: 1
playwright-merge-reports:
name: Playwright Merge Reports
runs-on: ubuntu-latest
if: ${{ !cancelled() }}
needs: [playwright-tests]
# for writing PR comments
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
- name: Setup Environment
uses: ./.github/actions/setup-env
env:
YARN_ENABLE_HARDENED_MODE: 0
with:
build-nextjs: false
yarn-install: false
- name: Download blob reports from GitHub Actions Artifacts
uses: actions/download-artifact@v4
with:
path: all-blob-reports
pattern: blob-report-*
merge-multiple: true
- name: Merge into HTML Report
run: npx playwright merge-reports --reporter html ./all-blob-reports
- name: Upload HTML report
uses: actions/upload-artifact@v4
with:
name: html-report--attempt-${{ github.run_attempt }}
path: playwright-report
retention-days: 14
- name: Merge into JSON Report
run: npx playwright merge-reports --reporter json ./all-blob-reports > playwright-report/report.json
- name: Playwright Markdown Report
if: always() # Always run regardless of previous step outcome
id: playwright-md-report
shell: bash
run: |
echo "------------------"
if [ ! -f "$PLAYWRIGHT_REPORT_PATH" ]; then
echo -e "# Playwright Test Results\n\n## No test results available\n\nNo test results were found. This could be because tests failed to run or artifacts were not uploaded." > playwright-report.md
else
bun run packages/playwright/bin/report-markdown.ts > playwright-report.md || echo -e "# Playwright Test Results\n\n## Error generating report\n\nThere was an error generating the test report." > playwright-report.md
fi
cat playwright-report.md
echo "------------------"
env:
PLAYWRIGHT_REPORT_PATH: playwright-report/report.json
- uses: mshick/add-pr-comment@v2
if: ${{ !cancelled() && github.event_name == 'pull_request' }} # Only comment on PRs
with:
message-id: playwright-report # Use the same ID to update the comment
refresh-message-position: true
message-path: |
playwright-report.md
vercel-deploy-preview:
# **always** skip if on dev and main since it will be deployed with another workflow
if: ${{ github.ref != 'refs/heads/dev' && github.ref != 'refs/heads/main' && github.head_ref != 'dev' && github.head_ref != 'main' }}
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Environment
uses: ./.github/actions/setup-env
env:
YARN_ENABLE_HARDENED_MODE: 0
- name: Extract branch name
id: extract-branch
uses: ./.github/actions/extract-branch
- name: Set Public Hostname
id: public-hostname
run: echo "public-hostname=sendapp-${{steps.extract-branch.outputs.branch}}-0xsend.vercel.app" >> $GITHUB_OUTPUT
- name: Vercel Deploy Preview with Supabase Branch
if: github.base_ref == 'dev'
id: vercel-deploy-with-branch
uses: ./.github/actions/vercel-deploy
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
public-hostname: ${{ steps.public-hostname.outputs.public-hostname }}
deploy-preview-extra-args: >-
-e SUPABASE_DB_URL="${{ secrets.STAGING_SUPABASE_DB_URL }}"
-e SUPABASE_JWT_SECRET="${{ secrets.STAGING_SUPABASE_JWT_SECRET }}"
-e SUPABASE_SERVICE_ROLE="${{ secrets.STAGING_SUPABASE_SERVICE_ROLE }}"
-e NEXT_PUBLIC_SUPABASE_URL="https://${{ secrets.STAGING_SUPABASE_PROJECT_ID }}.supabase.co"
-e NEXT_PUBLIC_SUPABASE_PROJECT_ID="${{ secrets.STAGING_SUPABASE_PROJECT_ID }}"
-e NEXT_PUBLIC_SUPABASE_GRAPHQL_URL="https://${{ secrets.STAGING_SUPABASE_PROJECT_ID }}.supabase.co/graphql"
-e NEXT_PUBLIC_BASE_CHAIN_ID="84532"
-e NEXT_PUBLIC_MAINNET_CHAIN_ID="11155111"
-e NEXT_PUBLIC_BASE_RPC_URL="${{ secrets.BASE_SEPOLIA_RPC_URL }}"
-e NEXT_PUBLIC_MAINNET_RPC_URL="https://ethereum-sepolia-rpc.publicnode.com"
-e NEXT_PUBLIC_SUPABASE_ANON_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InVncXRvdWxleGh2YWhldnN5c3VxIiwicm9sZSI6ImFub24iLCJpYXQiOjE2OTMwOTE5MzUsImV4cCI6MjAwODY2NzkzNX0.RL8W-jw2rsDhimYl8KklF2B9bNTPQ-Kj5zZA0XlufUA"
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
VERCEL_GIT_COMMIT_SHA: ${{ github.sha }}
VERCEL_GIT_COMMIT_REF: ${{ github.head_ref }}
VERCEL_GIT_PULL_REQUEST_ID: ${{ github.event.pull_request.number }}
SUPABASE_DB_URL: ${{ secrets.STAGING_SUPABASE_DB_URL }}
SUPABASE_JWT_SECRET: ${{ secrets.STAGING_SUPABASE_JWT_SECRET }}
SUPABASE_SERVICE_ROLE: ${{ secrets.STAGING_SUPABASE_SERVICE_ROLE }}
NEXT_PUBLIC_SUPABASE_URL: https://${{ secrets.STAGING_SUPABASE_PROJECT_ID }}.supabase.co
NEXT_PUBLIC_SUPABASE_PROJECT_ID: ${{ secrets.STAGING_SUPABASE_PROJECT_ID }}
NEXT_PUBLIC_SUPABASE_GRAPHQL_URL: https://${{ secrets.STAGING_SUPABASE_PROJECT_ID }}.supabase.co/graphql
NEXT_PUBLIC_BASE_CHAIN_ID: 84532
NEXT_PUBLIC_MAINNET_CHAIN_ID: 11155111
NEXT_PUBLIC_BASE_RPC_URL: ${{ secrets.BASE_SEPOLIA_RPC_URL }}
NEXT_PUBLIC_MAINNET_RPC_URL: https://ethereum-sepolia-rpc.publicnode.com
NEXT_PUBLIC_SUPABASE_ANON_KEY: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InVncXRvdWxleGh2YWhldnN5c3VxIiwicm9sZSI6ImFub24iLCJpYXQiOjE2OTMwOTE5MzUsImV4cCI6MjAwODY2NzkzNX0.RL8W-jw2rsDhimYl8KklF2B9bNTPQ-Kj5zZA0XlufUA
- name: Vercel Deploy Preview
if: github.base_ref != 'dev'
id: vercel-deploy-preview
uses: ./.github/actions/vercel-deploy
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
public-hostname: ${{ steps.public-hostname.outputs.public-hostname }}
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
VERCEL_GIT_COMMIT_SHA: ${{ github.sha }}
VERCEL_GIT_COMMIT_REF: ${{ github.head_ref }}
VERCEL_GIT_PULL_REQUEST_ID: ${{ github.event.pull_request.number }}
- uses: mshick/add-pr-comment@v2
if: github.base_ref == 'dev'
with:
message-id: vercel-preview-url
refresh-message-position: true
message: |
Vercel Unique URL: [${{ steps.vercel-deploy-with-branch.outputs.deployment-url }}](${{ steps.vercel-deploy-with-branch.outputs.deployment-url }})
Vercel Preview URL: [${{ steps.public-hostname.outputs.public-hostname }}](https://${{ steps.public-hostname.outputs.public-hostname }}/)
Last Commit: ${{ github.event.pull_request.head.sha }}
- uses: mshick/add-pr-comment@v2
if: github.base_ref != 'dev'
with:
message-id: vercel-preview-url
refresh-message-position: true
message: |
Vercel Unique URL: [${{ steps.vercel-deploy-preview.outputs.deployment-url }}](${{ steps.vercel-deploy-preview.outputs.deployment-url }})
Vercel Preview URL: [${{ steps.public-hostname.outputs.public-hostname }}](https://${{ steps.public-hostname.outputs.public-hostname }}/)
Last Commit: ${{ github.event.pull_request.head.sha }}