Skip to content

Commit 057ee61

Browse files
committed
up
1 parent f14bb49 commit 057ee61

8 files changed

Lines changed: 651 additions & 54 deletions

File tree

.github/workflows/k6-load-tests.yml

Lines changed: 55 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,26 @@ name: k6 Load Tests
33
on:
44
pull_request:
55
branches: [main, develop, '**-harden-**']
6+
paths:
7+
- 'src/app/api/checkout/**'
8+
- 'src/app/api/orders/**'
9+
- 'src/services/checkout-service.ts'
10+
- 'src/services/pricing-service.ts'
11+
- 'src/services/export-service.ts'
12+
- 'src/services/payment-service.ts'
13+
- 'tests/performance/**'
14+
- '.github/workflows/k6-load-tests.yml'
615
push:
716
branches: ['**-harden-**']
17+
paths:
18+
- 'src/app/api/checkout/**'
19+
- 'src/app/api/orders/**'
20+
- 'src/services/checkout-service.ts'
21+
- 'src/services/pricing-service.ts'
22+
- 'src/services/export-service.ts'
23+
- 'src/services/payment-service.ts'
24+
- 'tests/performance/**'
25+
- '.github/workflows/k6-load-tests.yml'
826
workflow_dispatch:
927
schedule:
1028
# Run load tests daily at 2 AM UTC
@@ -65,6 +83,7 @@ jobs:
6583
sudo apt-get install k6
6684
6785
- name: 🚀 Run k6 Load Test - Checkout
86+
id: k6-checkout-run
6887
run: k6 run tests/performance/checkout-load-test.js
6988
env:
7089
K6_OUT: json=checkout-results.json
@@ -80,7 +99,9 @@ jobs:
8099
- name: ❌ Fail if thresholds breached
81100
if: failure()
82101
run: |
83-
echo "::error::k6 load test thresholds breached for checkout flow"
102+
echo "::error::❌ k6 load test FAILED - Thresholds breached for checkout flow"
103+
echo "::error::Thresholds: API p95 < 500ms, Checkout p95 < 650ms, Error rate < 1%, Success rate > 99%"
104+
echo "::error::See artifacts for detailed metrics"
84105
exit 1
85106
86107
k6-export:
@@ -134,6 +155,7 @@ jobs:
134155
sudo apt-get install k6
135156
136157
- name: 🚀 Run k6 Load Test - Export
158+
id: k6-export-run
137159
run: k6 run tests/performance/orders-export-load-test.js
138160
env:
139161
K6_OUT: json=export-results.json
@@ -149,24 +171,28 @@ jobs:
149171
- name: ❌ Fail if thresholds breached
150172
if: failure()
151173
run: |
152-
echo "::error::k6 load test thresholds breached for orders export"
174+
echo "::error::❌ k6 load test FAILED - Thresholds breached for orders export"
175+
echo "::error::Thresholds: Streaming p95 < 5s, Async enqueue p95 < 500ms, Error rate < 2%, Success rate > 98%"
176+
echo "::error::See artifacts for detailed metrics"
153177
exit 1
154178
155179
k6-comment:
156180
name: Comment PR with k6 Results
157181
runs-on: ubuntu-latest
158182
needs: [k6-checkout, k6-export]
159-
if: github.event_name == 'pull_request'
183+
if: always() && github.event_name == 'pull_request'
160184

161185
steps:
162186
- name: 📥 Download checkout results
163187
uses: actions/download-artifact@v4
188+
continue-on-error: true
164189
with:
165190
name: k6-checkout-results
166191
path: ./k6-checkout
167192

168193
- name: 📥 Download export results
169194
uses: actions/download-artifact@v4
195+
continue-on-error: true
170196
with:
171197
name: k6-export-results
172198
path: ./k6-export
@@ -177,42 +203,38 @@ jobs:
177203
script: |
178204
const fs = require('fs');
179205
180-
let checkoutResults = {};
181-
let exportResults = {};
206+
// Check job statuses
207+
const checkoutPassed = '${{ needs.k6-checkout.result }}' === 'success';
208+
const exportPassed = '${{ needs.k6-export.result }}' === 'success';
182209
183-
try {
184-
const checkoutData = fs.readFileSync('./k6-checkout/checkout-results.json', 'utf8');
185-
checkoutResults = JSON.parse(checkoutData.split('\n').filter(line => line.includes('"type":"Point"')).pop() || '{}');
186-
} catch (e) {
187-
console.log('Could not parse checkout results');
188-
}
210+
const overallStatus = checkoutPassed && exportPassed ? '✅ PASSED' : '❌ FAILED';
211+
const emoji = checkoutPassed && exportPassed ? '✅' : '❌';
189212
190-
try {
191-
const exportData = fs.readFileSync('./k6-export/export-results.json', 'utf8');
192-
exportResults = JSON.parse(exportData.split('\n').filter(line => line.includes('"type":"Point"')).pop() || '{}');
193-
} catch (e) {
194-
console.log('Could not parse export results');
195-
}
213+
const comment = `## 🚀 k6 Load Test Results - ${overallStatus}
196214
197-
const comment = `## 🚀 k6 Load Test Results
215+
### Checkout Flow (50 VUs, 2 min) ${checkoutPassed ? '✅' : '❌'}
216+
**Thresholds** (Constitution §118-120):
217+
- ✓ API Response (p95): < 500ms
218+
- ✓ Checkout Complete (p95): < 650ms
219+
- ✓ Error Rate: < 1%
220+
- ✓ Success Rate: > 99%
198221
199-
### Checkout Flow (50 VUs, 2 min)
200-
- **Status**: ${checkoutResults.metric ? '✅ Passed' : '⚠️ See artifacts'}
201-
- **Thresholds**:
202-
- API Response (p95): < 500ms
203-
- Checkout Complete (p95): < 650ms
204-
- Error Rate: < 1%
205-
- Success Rate: > 99%
222+
${checkoutPassed ? '✅ All thresholds passed' : '❌ **BLOCKING**: Thresholds breached - see artifacts for details'}
206223
207-
### Orders Export (20 VUs, 1.5 min)
208-
- **Status**: ${exportResults.metric ? '✅ Passed' : '⚠️ See artifacts'}
209-
- **Thresholds**:
210-
- Streaming Export (p95): < 5s
211-
- Async Enqueue (p95): < 500ms
212-
- Error Rate: < 2%
213-
- Success Rate: > 98%
224+
### Orders Export (20 VUs, 1.5 min) ${exportPassed ? '✅' : '❌'}
225+
**Thresholds**:
226+
- ✓ Streaming Export (p95): < 5s
227+
- ✓ Async Enqueue (p95): < 500ms
228+
- ✓ Error Rate: < 2%
229+
- ✓ Success Rate: > 98%
214230
215-
See artifacts for detailed metrics and timings.
231+
${exportPassed ? '✅ All thresholds passed' : '❌ **BLOCKING**: Thresholds breached - see artifacts for details'}
232+
233+
---
234+
235+
${emoji} **${overallStatus}** - ${checkoutPassed && exportPassed ? 'Merge allowed' : '**MERGE BLOCKED** - Fix performance issues before merging'}
236+
237+
📊 Download artifacts for detailed metrics and timings.
216238
`;
217239
218240
github.rest.issues.createComment({

.github/workflows/lighthouse.yml

Lines changed: 82 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,28 @@ name: Lighthouse CI
33
on:
44
pull_request:
55
branches: [main, develop, '**-harden-**']
6+
paths:
7+
- 'src/app/(storefront)/**'
8+
- 'src/app/(dashboard)/**'
9+
- 'src/app/api/**'
10+
- 'src/components/**'
11+
- 'src/app/layout.tsx'
12+
- 'src/app/page.tsx'
13+
- 'public/**'
14+
- 'lighthouserc*.js'
15+
- '.github/workflows/lighthouse.yml'
616
push:
717
branches: ['**-harden-**']
18+
paths:
19+
- 'src/app/(storefront)/**'
20+
- 'src/app/(dashboard)/**'
21+
- 'src/app/api/**'
22+
- 'src/components/**'
23+
- 'src/app/layout.tsx'
24+
- 'src/app/page.tsx'
25+
- 'public/**'
26+
- 'lighthouserc*.js'
27+
- '.github/workflows/lighthouse.yml'
828
workflow_dispatch:
929

1030
concurrency:
@@ -53,9 +73,10 @@ jobs:
5373
run: npx wait-on http://localhost:3000 -t 60000
5474

5575
- name: 💡 Run Lighthouse CI (Desktop)
76+
id: lhci-desktop
5677
run: |
5778
npm install -g @lhci/cli@0.13.x
58-
lhci autorun --config=lighthouserc.js
79+
lhci autorun --config=lighthouserc.js || exit 1
5980
env:
6081
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
6182

@@ -66,6 +87,15 @@ jobs:
6687
name: lighthouse-desktop-results
6788
path: .lighthouseci
6889
retention-days: 30
90+
91+
- name: ❌ Fail if budgets breached
92+
if: failure()
93+
run: |
94+
echo "::error::❌ Lighthouse CI FAILED (Desktop) - Performance budgets breached"
95+
echo "::error::Constitution budgets: LCP < 2.0s, CLS < 0.1, FID < 100ms, TTI < 3.0s"
96+
echo "::error::Performance score ≥ 90, Accessibility ≥ 90, Bundle < 200KB"
97+
echo "::error::See artifacts for detailed reports"
98+
exit 1
6999
70100
lighthouse-mobile:
71101
name: Lighthouse (Mobile)
@@ -108,9 +138,10 @@ jobs:
108138
run: npx wait-on http://localhost:3000 -t 60000
109139

110140
- name: 💡 Run Lighthouse CI (Mobile)
141+
id: lhci-mobile
111142
run: |
112143
npm install -g @lhci/cli@0.13.x
113-
lhci autorun --config=lighthouserc.mobile.js
144+
lhci autorun --config=lighthouserc.mobile.js || exit 1
114145
env:
115146
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
116147

@@ -121,22 +152,33 @@ jobs:
121152
name: lighthouse-mobile-results
122153
path: .lighthouseci
123154
retention-days: 30
155+
156+
- name: ❌ Fail if budgets breached
157+
if: failure()
158+
run: |
159+
echo "::error::❌ Lighthouse CI FAILED (Mobile) - Performance budgets breached"
160+
echo "::error::Constitution budgets: LCP < 2.5s, CLS < 0.1, FID < 100ms, TTI < 3.0s"
161+
echo "::error::Performance score ≥ 90, Accessibility ≥ 90, Bundle < 200KB"
162+
echo "::error::See artifacts for detailed reports"
163+
exit 1
124164
125165
lighthouse-comment:
126166
name: Comment PR with Lighthouse Results
127167
runs-on: ubuntu-latest
128168
needs: [lighthouse-desktop, lighthouse-mobile]
129-
if: github.event_name == 'pull_request'
169+
if: always() && github.event_name == 'pull_request'
130170

131171
steps:
132172
- name: 📥 Download desktop results
133173
uses: actions/download-artifact@v4
174+
continue-on-error: true
134175
with:
135176
name: lighthouse-desktop-results
136177
path: ./lighthouse-desktop
137178

138179
- name: 📥 Download mobile results
139180
uses: actions/download-artifact@v4
181+
continue-on-error: true
140182
with:
141183
name: lighthouse-mobile-results
142184
path: ./lighthouse-mobile
@@ -147,26 +189,48 @@ jobs:
147189
script: |
148190
const fs = require('fs');
149191
150-
// Read results (simplified - actual implementation would parse JSON)
151-
const desktopPassed = fs.existsSync('./lighthouse-desktop');
152-
const mobilePassed = fs.existsSync('./lighthouse-mobile');
192+
// Check job statuses
193+
const desktopPassed = '${{ needs.lighthouse-desktop.result }}' === 'success';
194+
const mobilePassed = '${{ needs.lighthouse-mobile.result }}' === 'success';
195+
196+
const overallStatus = desktopPassed && mobilePassed ? '✅ PASSED' : '❌ FAILED';
197+
const emoji = desktopPassed && mobilePassed ? '✅' : '❌';
198+
199+
const comment = `## 💡 Lighthouse CI Results - ${overallStatus}
200+
201+
### Desktop ${desktopPassed ? '✅' : '❌'}
202+
**Performance Budgets** (Constitution §128-134):
203+
- ✓ LCP (Largest Contentful Paint): < 2.0s
204+
- ✓ FID (First Input Delay): < 100ms
205+
- ✓ CLS (Cumulative Layout Shift): < 0.1
206+
- ✓ TTI (Time to Interactive): < 3.0s
207+
- ✓ TBT (Total Blocking Time): < 300ms
208+
- ✓ JavaScript Bundle: < 200KB (gzipped)
209+
- ✓ Performance Score: ≥ 90
210+
- ✓ Accessibility Score: ≥ 90
211+
212+
${desktopPassed ? '✅ All budgets passed' : '❌ **BLOCKING**: Budgets breached - see artifacts for details'}
213+
214+
### Mobile ${mobilePassed ? '✅' : '❌'}
215+
**Performance Budgets**:
216+
- ✓ LCP (Largest Contentful Paint): < 2.5s
217+
- ✓ FID (First Input Delay): < 100ms
218+
- ✓ CLS (Cumulative Layout Shift): < 0.1
219+
- ✓ TTI (Time to Interactive): < 3.0s
220+
- ✓ TBT (Total Blocking Time): < 300ms
221+
- ✓ JavaScript Bundle: < 200KB (gzipped)
222+
- ✓ Performance Score: ≥ 90
223+
- ✓ Accessibility Score: ≥ 90
153224
154-
const comment = `## 💡 Lighthouse CI Results
225+
${mobilePassed ? '✅ All budgets passed' : '❌ **BLOCKING**: Budgets breached - see artifacts for details'}
155226
156-
### Desktop
157-
${desktopPassed ? '✅ Passed' : '❌ Failed'}
227+
---
158228
159-
### Mobile
160-
${mobilePassed ? '✅ Passed' : '❌ Failed'}
229+
${emoji} **${overallStatus}** - ${desktopPassed && mobilePassed ? 'Merge allowed' : '**MERGE BLOCKED** - Fix performance/accessibility issues before merging'}
161230
162-
**Performance Budgets:**
163-
- LCP < 2.0s (desktop), < 2.5s (mobile)
164-
- FID < 100ms
165-
- CLS < 0.1
166-
- TTI < 3.0s
167-
- JS Bundle < 200KB (gzipped)
231+
📊 Download artifacts for detailed Lighthouse reports.
168232
169-
See artifacts for detailed reports.
233+
**Constitution Reference**: Performance requirements in §118-134, §177-195
170234
`;
171235
172236
github.rest.issues.createComment({

0 commit comments

Comments
 (0)