Midday / .github /workflows /production.yml
Jules
Final deployment with all fixes and verified content
c09f67c
name: Production
permissions:
contents: read
on:
push:
branches:
- main
concurrency:
group: production-${{ github.workflow }}
cancel-in-progress: false
env:
TURBO_TOKEN: ${{ secrets.VERCEL_TOKEN }}
TURBO_TEAM: ${{ secrets.VERCEL_ORG_ID }}
jobs:
# ---------------------------------------------------------------------------
# Detect which services are affected (turbo dependency graph)
# ---------------------------------------------------------------------------
detect-changes:
name: Detect changes
runs-on: blacksmith-2vcpu-ubuntu-2404
timeout-minutes: 5
env:
TURBO_SCM_BASE: ${{ github.event.before }}
outputs:
api: ${{ steps.affected.outputs.api }}
dashboard: ${{ steps.affected.outputs.dashboard }}
worker: ${{ steps.affected.outputs.worker }}
engine: ${{ steps.affected.outputs.engine }}
website: ${{ steps.affected.outputs.website }}
email: ${{ steps.affected.outputs.email }}
jobs: ${{ steps.affected.outputs.jobs }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 50
- uses: ./.github/actions/setup
- name: Detect affected services
id: affected
run: |
AFFECTED=$(bunx turbo build --affected --dry-run=json 2>/dev/null | jq -r '.packages[]' 2>/dev/null || echo "")
echo "Affected packages: $AFFECTED"
echo "api=$(echo "$AFFECTED" | grep -q '@midday/api' && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT
echo "dashboard=$(echo "$AFFECTED" | grep -q '@midday/dashboard' && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT
echo "worker=$(echo "$AFFECTED" | grep -q '@midday/worker' && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT
echo "engine=$(echo "$AFFECTED" | grep -q '@midday/engine' && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT
echo "website=$(echo "$AFFECTED" | grep -q '@midday/website' && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT
echo "email=$(echo "$AFFECTED" | grep -q '@midday/email' && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT
echo "jobs=$(echo "$AFFECTED" | grep -q '@midday/jobs' && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT
# ---------------------------------------------------------------------------
# Validate — runs in parallel with detect-changes
# ---------------------------------------------------------------------------
validate:
name: Validate
runs-on: blacksmith-16vcpu-ubuntu-2404
timeout-minutes: 20
env:
NODE_OPTIONS: "--max-old-space-size=8192"
TURBO_SCM_BASE: ${{ github.event.before }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 50
- uses: ./.github/actions/setup
- name: Lint
run: bunx turbo lint --affected
- name: Build required type dependencies
run: bunx turbo build --filter=workbench --filter=@midday/engine
- name: Typecheck
run: bunx turbo typecheck --affected
- name: Test
run: bunx turbo test --affected
# ---------------------------------------------------------------------------
# Deploy API to Railway
# ---------------------------------------------------------------------------
deploy-api:
name: Deploy API
needs: [detect-changes, validate]
if: >-
always() &&
needs.validate.result == 'success' &&
needs.detect-changes.outputs.api == 'true'
runs-on: blacksmith-2vcpu-ubuntu-2404
timeout-minutes: 20
concurrency: railway-api-production
steps:
- uses: actions/checkout@v4
- name: Stamp git SHA for Docker build
run: echo "${{ github.sha }}" > .git-commit-sha
- name: Deploy to Railway
run: npx @railway/cli up --service api
env:
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
# ---------------------------------------------------------------------------
# Deploy Dashboard to Railway (waits for API when both change)
# ---------------------------------------------------------------------------
deploy-dashboard:
name: Deploy Dashboard
needs: [detect-changes, validate, deploy-api]
if: >-
always() &&
needs.validate.result == 'success' &&
needs.detect-changes.outputs.dashboard == 'true' &&
(needs.deploy-api.result == 'success' || needs.deploy-api.result == 'skipped')
runs-on: blacksmith-2vcpu-ubuntu-2404
timeout-minutes: 20
concurrency: railway-dashboard-production
steps:
- uses: actions/checkout@v4
- name: Stamp git SHA for Docker build
run: echo "${{ github.sha }}" > .git-commit-sha
- name: Deploy to Railway
run: npx @railway/cli up --service dashboard
env:
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
# ---------------------------------------------------------------------------
# Deploy Worker to Railway (waits for API when both change)
# ---------------------------------------------------------------------------
deploy-worker:
name: Deploy Worker
needs: [detect-changes, validate, deploy-api]
if: >-
always() &&
needs.validate.result == 'success' &&
needs.detect-changes.outputs.worker == 'true' &&
(needs.deploy-api.result == 'success' || needs.deploy-api.result == 'skipped')
runs-on: blacksmith-2vcpu-ubuntu-2404
timeout-minutes: 20
concurrency: railway-worker-production
steps:
- uses: actions/checkout@v4
- name: Stamp git SHA for Docker build
run: echo "${{ github.sha }}" > .git-commit-sha
- name: Deploy to Railway
run: npx @railway/cli up --service worker
env:
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
# ---------------------------------------------------------------------------
# Deploy Engine to Cloudflare
# ---------------------------------------------------------------------------
deploy-engine:
name: Deploy Engine
needs: [detect-changes, validate]
if: >-
always() &&
needs.validate.result == 'success' &&
needs.detect-changes.outputs.engine == 'true'
runs-on: blacksmith-2vcpu-ubuntu-2404
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup
- name: Deploy to Cloudflare
uses: cloudflare/wrangler-action@v3
with:
packageManager: bun
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
workingDirectory: "apps/engine"
wranglerVersion: "4.33.2"
command: deploy --minify src/index.ts --env production
# ---------------------------------------------------------------------------
# Deploy Website to Vercel
# ---------------------------------------------------------------------------
deploy-website:
name: Deploy Website
needs: [detect-changes, validate]
if: >-
always() &&
needs.validate.result == 'success' &&
needs.detect-changes.outputs.website == 'true'
runs-on: blacksmith-2vcpu-ubuntu-2404
timeout-minutes: 20
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_WEBSITE }}
NODE_OPTIONS: "--max-old-space-size=4096"
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup
- name: Pull Vercel environment
run: bunx vercel env pull .env --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
- name: Pull Vercel project config
run: bunx vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
- name: Build
run: bunx vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}
- name: Deploy
run: |
bunx vercel deploy --prebuilt --prod --archive=tgz --token=${{ secrets.VERCEL_TOKEN }} > domain.txt
bunx vercel alias --scope=${{ secrets.VERCEL_ORG_ID }} --token=${{ secrets.VERCEL_TOKEN }} set $(cat domain.txt) midday.ai
# ---------------------------------------------------------------------------
# Deploy Email to Vercel
# ---------------------------------------------------------------------------
deploy-email:
name: Deploy Email
needs: [detect-changes, validate]
if: >-
always() &&
needs.validate.result == 'success' &&
needs.detect-changes.outputs.email == 'true'
runs-on: blacksmith-2vcpu-ubuntu-2404
timeout-minutes: 10
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_EMAIL }}
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup
- name: Pull Vercel environment
run: bunx vercel env pull .env --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
- name: Pull Vercel project config
run: bunx vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
- name: Build
run: bunx vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}
- name: Deploy
run: |
bunx vercel deploy --prebuilt --prod --archive=tgz --token=${{ secrets.VERCEL_TOKEN }} > domain.txt
bunx vercel alias --scope=${{ secrets.VERCEL_ORG_ID }} --token=${{ secrets.VERCEL_TOKEN }} set $(cat domain.txt) email.midday.ai
# ---------------------------------------------------------------------------
# Deploy Jobs to Trigger.dev
# ---------------------------------------------------------------------------
deploy-jobs:
name: Deploy Jobs
needs: [detect-changes, validate]
if: >-
always() &&
needs.validate.result == 'success' &&
needs.detect-changes.outputs.jobs == 'true'
runs-on: blacksmith-2vcpu-ubuntu-2404
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup
- name: Deploy to Trigger.dev
env:
TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN }}
run: |
TRIGGER_PROJECT_ID=${{ secrets.TRIGGER_PROJECT_ID }} bunx trigger.dev@4.1.2 deploy
working-directory: packages/jobs