Deploy TeachRepo automatically on every push to main, run type checks and E2E tests on pull requests, and apply database migrations safely.
Save as .github/workflows/deploy.yml in your fork root:
name: CI / Deploy
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
WORKING_DIR: startup-91-lean-launch-plan-repo-to-course-git-native-paywall/apps/web
jobs:
# ── 1. Type-check ─────────────────────────────────────────────
typecheck:
name: Type-check
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ env.WORKING_DIR }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: ${{ env.WORKING_DIR }}/package-lock.json
- run: npm ci
- run: npm run type-check
# ── 2. Deploy to Vercel ────────────────────────────────────────
deploy:
name: Deploy
runs-on: ubuntu-latest
needs: typecheck
defaults:
run:
working-directory: ${{ env.WORKING_DIR }}
outputs:
deployment-url: ${{ steps.deploy.outputs.url }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: ${{ env.WORKING_DIR }}/package-lock.json
- run: npm ci
- run: npm install -g vercel@latest
- name: Pull Vercel environment
run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
- name: Build
run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}
- name: Deploy to production
id: deploy
if: github.ref == 'refs/heads/main'
run: |
URL=$(vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }})
echo "url=$URL" >> $GITHUB_OUTPUT
echo "Deployed: $URL"
- name: Deploy preview (PR)
if: github.event_name == 'pull_request'
run: vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }}
# ── 3. E2E tests ─────────────────────────────────────────────
e2e:
name: E2E tests
runs-on: ubuntu-latest
needs: deploy
if: always() && needs.deploy.result == 'success'
defaults:
run:
working-directory: ${{ env.WORKING_DIR }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: ${{ env.WORKING_DIR }}/package-lock.json
- run: npm ci
- name: Install Playwright browsers
run: npx playwright install chromium --with-deps
- name: Run E2E tests
env:
BASE_URL: ${{ needs.deploy.outputs.deployment-url }}
TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }}
TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
run: npx playwright test --reporter=dot
- uses: actions/upload-artifact@v4
if: failure()
with:
name: playwright-report
path: ${{ env.WORKING_DIR }}/playwright-report/
retention-days: 7Settings → Secrets and variables → Actions → New repository secret:
| Secret | Required? | Where to get it |
|---|---|---|
| VERCEL_TOKEN | Yes | Vercel → Account Settings → Tokens |
| VERCEL_ORG_ID | Yes | Vercel dashboard URL or .vercel/project.json |
| VERCEL_PROJECT_ID | Yes | .vercel/project.json after vercel link |
| TEST_USER_EMAIL | For E2E | Your test account email |
| TEST_USER_PASSWORD | For E2E | Your test account password |
| SLACK_WEBHOOK_URL | Optional | Slack → Incoming Webhooks app |
vercel pull in the workflow — you do not need to duplicate them as GitHub secrets.Schema changes are plain SQL files in supabase/migrations/. Apply them from CI using the Supabase CLI:
# Add to your deploy job, before the Vercel build step:
- name: Apply DB migrations
env:
SUPABASE_PROJECT_ID: ${{ secrets.SUPABASE_PROJECT_ID }}
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
run: |
# Install Supabase CLI
npm install -g supabase
# Link to project (non-interactive)
supabase link --project-ref $SUPABASE_PROJECT_ID
# Push any pending migrations
supabase db push --linkedAdd SUPABASE_PROJECT_ID (the short ref, e.g. zkwyfjrg) and SUPABASE_ACCESS_TOKEN (from supabase.com/account/tokens) as GitHub secrets.
Add this workflow to your course repository (not the app repo) to auto-publish whenever you push to main:
# .github/workflows/publish-course.yml
name: Publish course to TeachRepo
on:
push:
branches: [main]
workflow_dispatch:
inputs:
label:
description: Version label (e.g. v1.2)
required: false
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # needed for version history
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Install TeachRepo CLI
run: npm install -g @teachrepo/cli
- name: Push course
env:
TEACHREPO_TOKEN: ${{ secrets.TEACHREPO_TOKEN }}
TEACHREPO_URL: ${{ secrets.TEACHREPO_URL }}
run: |
teachrepo push \
--url "$TEACHREPO_URL" \
--token "$TEACHREPO_TOKEN" \
${{ github.event.inputs.label && format('--label {0}', github.event.inputs.label) || '' }}Get your TEACHREPO_TOKEN from /dashboard/settings → API tokens.
# Add as a final step in the deploy job:
- name: Notify Slack on deploy
if: github.ref == 'refs/heads/main' && success()
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
run: |
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H 'Content-Type: application/json' \
-d '{
"text": "✅ TeachRepo deployed to production",
"attachments": [{
"color": "good",
"fields": [
{"title": "Commit", "value": "${{ github.sha }}", "short": true},
{"title": "Author", "value": "${{ github.actor }}", "short": true},
{"title": "URL", "value": "${{ needs.deploy.outputs.deployment-url }}", "short": false}
]
}]
}'