Skip to content

Commit e6b0658

Browse files
Kikolatorclaude
andauthored
ci: optimize GitHub Actions to reduce minute usage (#104)
## Summary - Add `dorny/paths-filter` to detect changed files and conditionally skip expensive CI jobs - E2E tests only run on PRs targeting `main` (saves ~6 min per dev PR) - DB Lint and Migration Dry Run only run when migration files change (saves ~4 min) - Lint, Type-check, Build, and Test skip entirely for non-code changes like SVGs/config (saves ~8 min) - Schema drift detection moved from CI to `deploy-dev` workflow (informational, not a PR gate) - Skipped jobs satisfy GitHub ruleset required status checks Reduces typical dev PR cost from ~22 min to ~9 min, roughly doubling monthly CI capacity within the 3,000 minute limit. ## Test plan - [x] Verify CI triggers and all required checks pass on this PR - [x] Confirm skipped jobs show as "skipped" (not "failed") in the checks tab - [ ] Verify schema drift appears in deploy-dev summary after merging 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent cd13ffa commit e6b0658

File tree

2 files changed

+87
-43
lines changed

2 files changed

+87
-43
lines changed

.github/workflows/ci.yml

Lines changed: 50 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# CI pipeline — runs on every PR to main and dev
22
# Validates code quality, types, build, tests, and database integrity
3+
#
4+
# Minute-saving strategy:
5+
# - Path-based filtering skips expensive jobs when irrelevant files change
6+
# - E2E only runs on PRs to main (most expensive job at ~6 min)
7+
# - DB jobs only run when migration files change
8+
# - Schema drift detection moved to deploy-dev (informational only)
9+
# - Skipped jobs satisfy required status checks in GitHub rulesets
310
name: CI
411

512
on:
@@ -18,14 +25,42 @@ env:
1825
TURBO_FILTER: --filter=...[origin/${{ github.base_ref }}]
1926

2027
jobs:
28+
# ─── Detect what changed ─────────────────────────────────────
29+
changes:
30+
name: Detect Changes
31+
runs-on: ubuntu-latest
32+
outputs:
33+
src: ${{ steps.filter.outputs.src }}
34+
migrations: ${{ steps.filter.outputs.migrations }}
35+
web: ${{ steps.filter.outputs.web }}
36+
steps:
37+
- uses: actions/checkout@v4
38+
- uses: dorny/paths-filter@v3
39+
id: filter
40+
with:
41+
filters: |
42+
src:
43+
- 'apps/**/*.{ts,tsx,js,jsx,css}'
44+
- 'packages/**/*.{ts,tsx,js,jsx}'
45+
- '**/package.json'
46+
- '**/tsconfig*.json'
47+
- 'turbo.json'
48+
migrations:
49+
- 'packages/db/supabase/migrations/**'
50+
- 'packages/db/supabase/seed.sql'
51+
web:
52+
- 'apps/web/**'
53+
- 'packages/**'
54+
2155
# ─── Lint & Type-check (parallel) ─────────────────────────────
2256
lint:
2357
name: Lint
58+
needs: [changes]
59+
if: needs.changes.outputs.src == 'true'
2460
runs-on: ubuntu-latest
2561
steps:
2662
- uses: actions/checkout@v4
2763
with:
28-
# Fetch base branch so turbo filter can diff against it
2964
fetch-depth: 0
3065

3166
- uses: actions/setup-node@v4
@@ -44,6 +79,8 @@ jobs:
4479

4580
typecheck:
4681
name: Type-check
82+
needs: [changes]
83+
if: needs.changes.outputs.src == 'true'
4784
runs-on: ubuntu-latest
4885
steps:
4986
- uses: actions/checkout@v4
@@ -67,7 +104,8 @@ jobs:
67104
# ─── Build & Test (parallel, after lint+typecheck) ────────────
68105
build:
69106
name: Build
70-
needs: [lint, typecheck]
107+
needs: [changes, lint, typecheck]
108+
if: needs.changes.outputs.src == 'true'
71109
runs-on: ubuntu-latest
72110
steps:
73111
- uses: actions/checkout@v4
@@ -90,7 +128,8 @@ jobs:
90128

91129
test:
92130
name: Test
93-
needs: [lint, typecheck]
131+
needs: [changes, lint, typecheck]
132+
if: needs.changes.outputs.src == 'true'
94133
runs-on: ubuntu-latest
95134
steps:
96135
- uses: actions/checkout@v4
@@ -128,10 +167,11 @@ jobs:
128167
if: always()
129168
run: echo "### Test ${{ job.status == 'success' && '✅' || '❌' }}" >> "$GITHUB_STEP_SUMMARY"
130169

131-
# ─── E2E (after lint+typecheck) ───────────────────────────────
170+
# ─── E2E (main PRs only — most expensive job) ────────────────
132171
e2e:
133172
name: E2E
134-
needs: [lint, typecheck]
173+
needs: [changes, lint, typecheck]
174+
if: github.base_ref == 'main' && needs.changes.outputs.web == 'true'
135175
runs-on: ubuntu-latest
136176
timeout-minutes: 15
137177
steps:
@@ -217,9 +257,11 @@ jobs:
217257
if: always()
218258
run: echo "### E2E ${{ job.status == 'success' && '✅' || '❌' }}" >> "$GITHUB_STEP_SUMMARY"
219259

220-
# ─── Supabase database checks ────────────────────────────────
260+
# ─── Supabase database checks (only when migrations change) ──
221261
db-lint:
222262
name: DB Lint
263+
needs: [changes]
264+
if: needs.changes.outputs.migrations == 'true'
223265
runs-on: ubuntu-latest
224266
steps:
225267
- uses: actions/checkout@v4
@@ -244,43 +286,10 @@ jobs:
244286
if: always()
245287
run: echo "### DB Lint ${{ job.status == 'success' && '✅' || '❌' }}" >> "$GITHUB_STEP_SUMMARY"
246288

247-
schema-drift:
248-
name: Schema Drift Detection
249-
runs-on: ubuntu-latest
250-
steps:
251-
- uses: actions/checkout@v4
252-
253-
- uses: supabase/setup-cli@v1
254-
with:
255-
version: latest
256-
257-
- name: Link to dev project
258-
run: supabase link --project-ref "${{ secrets.SUPABASE_DEV_PROJECT_REF }}"
259-
working-directory: packages/db
260-
env:
261-
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
262-
263-
- name: Check for schema drift
264-
# Warn-only — non-zero exit is informational, not blocking
265-
continue-on-error: true
266-
run: |
267-
OUTPUT=$(supabase db diff --linked 2>&1) || true
268-
if [ -n "$OUTPUT" ] && [ "$OUTPUT" != "No changes found" ]; then
269-
echo "::warning::Schema drift detected against dev project"
270-
echo "### ⚠️ Schema Drift Detected" >> "$GITHUB_STEP_SUMMARY"
271-
echo '```sql' >> "$GITHUB_STEP_SUMMARY"
272-
echo "$OUTPUT" >> "$GITHUB_STEP_SUMMARY"
273-
echo '```' >> "$GITHUB_STEP_SUMMARY"
274-
else
275-
echo "### Schema Drift — None ✅" >> "$GITHUB_STEP_SUMMARY"
276-
fi
277-
working-directory: packages/db
278-
env:
279-
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
280-
SUPABASE_DB_PASSWORD: ${{ secrets.SUPABASE_DEV_DB_PASSWORD }}
281-
282289
migration-dry-run:
283290
name: Migration Dry Run
291+
needs: [changes]
292+
if: needs.changes.outputs.migrations == 'true'
284293
runs-on: ubuntu-latest
285294
steps:
286295
- uses: actions/checkout@v4
@@ -290,7 +299,6 @@ jobs:
290299
version: latest
291300

292301
- name: Start local Supabase (db only)
293-
# Only start the db service — skip realtime, storage, studio, etc. for speed
294302
run: supabase start -x realtime,storage,imgproxy,inbucket,postgrest,gotrue,studio,edge-runtime,logflare,vector,supavisor
295303
working-directory: packages/db
296304

.github/workflows/deploy-dev.yml

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,41 @@ jobs:
4040
if: always()
4141
run: echo "### Migrate ${{ job.status == 'success' && '✅' || '❌' }}" >> "$GITHUB_STEP_SUMMARY"
4242

43+
schema-drift:
44+
name: Schema Drift Detection
45+
needs: [migrate]
46+
continue-on-error: true
47+
runs-on: ubuntu-latest
48+
steps:
49+
- uses: actions/checkout@v4
50+
51+
- uses: supabase/setup-cli@v1
52+
with:
53+
version: latest
54+
55+
- name: Link to dev project
56+
run: supabase link --project-ref "${{ secrets.SUPABASE_DEV_PROJECT_REF }}"
57+
working-directory: packages/db
58+
env:
59+
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
60+
61+
- name: Check for schema drift
62+
run: |
63+
OUTPUT=$(supabase db diff --linked 2>&1) || true
64+
if [ -n "$OUTPUT" ] && [ "$OUTPUT" != "No changes found" ]; then
65+
echo "::warning::Schema drift detected against dev project"
66+
echo "### Schema Drift Detected" >> "$GITHUB_STEP_SUMMARY"
67+
echo '```sql' >> "$GITHUB_STEP_SUMMARY"
68+
echo "$OUTPUT" >> "$GITHUB_STEP_SUMMARY"
69+
echo '```' >> "$GITHUB_STEP_SUMMARY"
70+
else
71+
echo "### Schema Drift — None" >> "$GITHUB_STEP_SUMMARY"
72+
fi
73+
working-directory: packages/db
74+
env:
75+
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
76+
SUPABASE_DB_PASSWORD: ${{ secrets.SUPABASE_DEV_DB_PASSWORD }}
77+
4378
generate-types:
4479
name: Generate Types
4580
needs: [migrate]
@@ -93,7 +128,7 @@ jobs:
93128
94129
summary:
95130
name: Summary
96-
needs: [migrate, generate-types]
131+
needs: [migrate, schema-drift, generate-types]
97132
if: always()
98133
runs-on: ubuntu-latest
99134
steps:
@@ -105,5 +140,6 @@ jobs:
105140
| Job | Status |
106141
|-----|--------|
107142
| Migrations | ${{ needs.migrate.result }} |
143+
| Schema Drift | ${{ needs.schema-drift.result }} |
108144
| Generate Types | ${{ needs.generate-types.result }} |
109145
EOF

0 commit comments

Comments
 (0)