44 push :
55 branches :
66 - main
7- paths-ignore :
8- - ' **.md'
9- - ' docs/**'
107
118concurrency :
129 group : ${{ github.workflow }}-${{ github.ref }}
1310 cancel-in-progress : true
1411
1512jobs :
13+ detect-changes :
14+ runs-on : ubuntu-latest
15+ outputs :
16+ is_content_only : ${{ steps.check.outputs.content_only }}
17+ steps :
18+ - uses : actions/checkout@v6
19+ with :
20+ fetch-depth : 10
21+ - name : Detect content-only changes
22+ id : check
23+ run : |
24+ BEFORE=${{ github.event.before }}
25+ if [ "$BEFORE" = "0000000000000000000000000000000000000000" ]; then
26+ echo "content_only=false" >> "$GITHUB_OUTPUT"
27+ exit 0
28+ fi
29+ if ! git cat-file -e "$BEFORE" 2>/dev/null; then
30+ echo "content_only=false" >> "$GITHUB_OUTPUT"
31+ exit 0
32+ fi
33+ CHANGED_FILES=$(git diff --name-only "$BEFORE" HEAD)
34+ echo "Changed files:"
35+ echo "$CHANGED_FILES"
36+ CONTENT_ONLY=true
37+ while IFS= read -r file; do
38+ case "$file" in
39+ content/blog/*.txt|content/kanban/*.md|content/kanban/**/*.md) ;;
40+ src/generated/*) ;;
41+ public/rss.xml|public/sitemap.xml|public/atom.xml) ;;
42+ public/og-images/*) ;;
43+ .claude/*|*.md) ;;
44+ *) CONTENT_ONLY=false; break ;;
45+ esac
46+ done <<< "$CHANGED_FILES"
47+ echo "content_only=$CONTENT_ONLY" >> "$GITHUB_OUTPUT"
48+
1649 build-and-test :
1750 runs-on : ubuntu-latest
51+ needs : detect-changes
1852 steps :
1953 - name : Checkout source
2054 uses : actions/checkout@v6
@@ -36,26 +70,37 @@ jobs:
3670 restore-keys : |
3771 mdx-
3872
73+ - name : Build mode
74+ run : |
75+ if [ "${{ needs.detect-changes.outputs.is_content_only }}" = "true" ]; then
76+ echo "::notice::Fast-path content-only deploy"
77+ else
78+ echo "::notice::Full build and test pipeline"
79+ fi
80+
3981 - name : Cache Playwright browsers
82+ if : needs.detect-changes.outputs.is_content_only != 'true'
4083 id : playwright-cache
4184 uses : actions/cache@v5
4285 with :
4386 path : ~/.cache/ms-playwright
4487 key : ${{ runner.os }}-playwright-${{ hashFiles('package-lock.json') }}
4588
4689 - name : Install Playwright browsers
47- if : steps.playwright-cache.outputs.cache-hit != 'true'
90+ if : needs.detect-changes.outputs.is_content_only != 'true' && steps.playwright-cache.outputs.cache-hit != 'true'
4891 run : npx playwright install chromium --with-deps
4992
5093 - name : Install Playwright deps only
51- if : steps.playwright-cache.outputs.cache-hit == 'true'
94+ if : needs.detect-changes.outputs.is_content_only != 'true' && steps.playwright-cache.outputs.cache-hit == 'true'
5295 run : npx playwright install-deps chromium
5396
5497 - name : Security audit
98+ if : needs.detect-changes.outputs.is_content_only != 'true'
5599 run : npm audit --audit-level=high --omit=dev
56100 continue-on-error : true
57101
58102 - name : Run unit tests
103+ if : needs.detect-changes.outputs.is_content_only != 'true'
59104 run : npm test
60105
61106 - name : Build site
64109 GITHUB_SHA : ${{ github.sha }}
65110
66111 - name : Upload source maps to Sentry
112+ if : needs.detect-changes.outputs.is_content_only != 'true'
67113 env :
68114 SENTRY_AUTH_TOKEN : ${{ secrets.SENTRY_AUTH_TOKEN }}
69115 SENTRY_ORG : ${{ secrets.SENTRY_ORG }}
@@ -74,12 +120,14 @@ jobs:
74120 npx sentry-cli releases finalize ${{ github.sha }}
75121
76122 - name : Remove source maps from build
123+ if : needs.detect-changes.outputs.is_content_only != 'true'
77124 run : find ./dist -name '*.map' -delete
78125
79126 # Bundle size check uses raw (uncompressed) file sizes as a build guard.
80127 # This catches accidental bloat from new dependencies or unoptimized code.
81128 # Actual transfer sizes are ~70% smaller due to gzip/brotli compression.
82129 - name : Check bundle size budget
130+ if : needs.detect-changes.outputs.is_content_only != 'true'
83131 run : |
84132 node -e "
85133 const fs = require('fs');
@@ -135,14 +183,17 @@ jobs:
135183 "
136184
137185 - name : Start preview server
186+ if : needs.detect-changes.outputs.is_content_only != 'true'
138187 run : npm run preview &
139188 env :
140189 CI : true
141190
142191 - name : Wait for server to be ready
192+ if : needs.detect-changes.outputs.is_content_only != 'true'
143193 run : npx wait-on http://localhost:4173 --timeout 30000
144194
145195 - name : Run smoke tests
196+ if : needs.detect-changes.outputs.is_content_only != 'true'
146197 run : BASE_URL=http://localhost:4173 npx playwright test --grep @smoke
147198 env :
148199 CI : true
@@ -155,7 +206,7 @@ jobs:
155206 retention-days : 1
156207
157208 - name : Upload test results
158- if : failure()
209+ if : failure() && needs.detect-changes.outputs.is_content_only != 'true'
159210 uses : actions/upload-artifact@v6
160211 with :
161212 name : playwright-test-results
0 commit comments