agentic-team-templates 0.4.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,603 @@
1
+ # CI/CD Integration
2
+
3
+ Guidelines for integrating testing into continuous integration and deployment pipelines.
4
+
5
+ ## Pipeline Architecture
6
+
7
+ ### Test Stages
8
+
9
+ ```
10
+ ┌─────────────────────────────────────────────────────────────────┐
11
+ │ CI/CD Pipeline │
12
+ ├─────────────────────────────────────────────────────────────────┤
13
+ │ │
14
+ │ ┌─────────┐ ┌──────────┐ ┌─────────────┐ ┌───────────┐ │
15
+ │ │ Static │ → │ Unit │ → │ Integration │ → │ E2E │ │
16
+ │ │Analysis │ │ Tests │ │ Tests │ │ Tests │ │
17
+ │ └─────────┘ └──────────┘ └─────────────┘ └───────────┘ │
18
+ │ ↓ ↓ │
19
+ │ ┌─────────┐ ┌───────────┐ │
20
+ │ │ Quality │ │Performance│ │
21
+ │ │ Gates │ │ Tests │ │
22
+ │ └─────────┘ └───────────┘ │
23
+ │ │
24
+ └─────────────────────────────────────────────────────────────────┘
25
+ ```
26
+
27
+ ### Fast Feedback First
28
+
29
+ Order tests by speed and confidence:
30
+
31
+ 1. **Static Analysis** (seconds) - Catch obvious errors
32
+ 2. **Unit Tests** (seconds-minutes) - Fast, isolated
33
+ 3. **Integration Tests** (minutes) - Real dependencies
34
+ 4. **E2E Tests** (minutes-hours) - Full system
35
+ 5. **Performance Tests** (hours) - Load testing
36
+
37
+ ## GitHub Actions Configuration
38
+
39
+ ### Complete Test Pipeline
40
+
41
+ ```yaml
42
+ # .github/workflows/test.yml
43
+ name: Test Pipeline
44
+
45
+ on:
46
+ push:
47
+ branches: [main, develop]
48
+ pull_request:
49
+ branches: [main, develop]
50
+
51
+ concurrency:
52
+ group: test-${{ github.ref }}
53
+ cancel-in-progress: true
54
+
55
+ jobs:
56
+ # Stage 1: Static Analysis (fastest)
57
+ static-analysis:
58
+ runs-on: ubuntu-latest
59
+ steps:
60
+ - uses: actions/checkout@v4
61
+
62
+ - uses: actions/setup-node@v4
63
+ with:
64
+ node-version: '20'
65
+ cache: 'npm'
66
+
67
+ - run: npm ci
68
+
69
+ - name: Type Check
70
+ run: npm run type-check
71
+
72
+ - name: Lint
73
+ run: npm run lint
74
+
75
+ - name: Format Check
76
+ run: npm run format:check
77
+
78
+ # Stage 2: Unit Tests (fast)
79
+ unit-tests:
80
+ runs-on: ubuntu-latest
81
+ needs: static-analysis
82
+ steps:
83
+ - uses: actions/checkout@v4
84
+
85
+ - uses: actions/setup-node@v4
86
+ with:
87
+ node-version: '20'
88
+ cache: 'npm'
89
+
90
+ - run: npm ci
91
+
92
+ - name: Run Unit Tests
93
+ run: npm run test:unit -- --coverage --reporter=junit --outputFile=test-results/junit.xml
94
+
95
+ - name: Upload Coverage
96
+ uses: codecov/codecov-action@v4
97
+ with:
98
+ files: coverage/lcov.info
99
+ fail_ci_if_error: true
100
+
101
+ - name: Upload Test Results
102
+ if: always()
103
+ uses: actions/upload-artifact@v4
104
+ with:
105
+ name: unit-test-results
106
+ path: test-results/
107
+
108
+ # Stage 3: Integration Tests (medium)
109
+ integration-tests:
110
+ runs-on: ubuntu-latest
111
+ needs: unit-tests
112
+ services:
113
+ postgres:
114
+ image: postgres:16
115
+ env:
116
+ POSTGRES_PASSWORD: test
117
+ POSTGRES_DB: test
118
+ options: >-
119
+ --health-cmd pg_isready
120
+ --health-interval 10s
121
+ --health-timeout 5s
122
+ --health-retries 5
123
+ ports:
124
+ - 5432:5432
125
+
126
+ redis:
127
+ image: redis:7
128
+ ports:
129
+ - 6379:6379
130
+
131
+ steps:
132
+ - uses: actions/checkout@v4
133
+
134
+ - uses: actions/setup-node@v4
135
+ with:
136
+ node-version: '20'
137
+ cache: 'npm'
138
+
139
+ - run: npm ci
140
+
141
+ - name: Run Migrations
142
+ run: npm run db:migrate
143
+ env:
144
+ DATABASE_URL: postgres://postgres:test@localhost:5432/test
145
+
146
+ - name: Run Integration Tests
147
+ run: npm run test:integration -- --reporter=junit --outputFile=test-results/junit.xml
148
+ env:
149
+ DATABASE_URL: postgres://postgres:test@localhost:5432/test
150
+ REDIS_URL: redis://localhost:6379
151
+
152
+ - name: Upload Test Results
153
+ if: always()
154
+ uses: actions/upload-artifact@v4
155
+ with:
156
+ name: integration-test-results
157
+ path: test-results/
158
+
159
+ # Stage 4: E2E Tests (slow)
160
+ e2e-tests:
161
+ runs-on: ubuntu-latest
162
+ needs: integration-tests
163
+ steps:
164
+ - uses: actions/checkout@v4
165
+
166
+ - uses: actions/setup-node@v4
167
+ with:
168
+ node-version: '20'
169
+ cache: 'npm'
170
+
171
+ - run: npm ci
172
+
173
+ - name: Install Playwright
174
+ run: npx playwright install --with-deps chromium
175
+
176
+ - name: Build Application
177
+ run: npm run build
178
+
179
+ - name: Start Application
180
+ run: npm run start &
181
+ env:
182
+ NODE_ENV: test
183
+
184
+ - name: Wait for Application
185
+ run: npx wait-on http://localhost:3000 --timeout 60000
186
+
187
+ - name: Run E2E Tests
188
+ run: npm run test:e2e
189
+
190
+ - name: Upload Playwright Report
191
+ if: always()
192
+ uses: actions/upload-artifact@v4
193
+ with:
194
+ name: playwright-report
195
+ path: playwright-report/
196
+
197
+ - name: Upload Screenshots
198
+ if: failure()
199
+ uses: actions/upload-artifact@v4
200
+ with:
201
+ name: e2e-screenshots
202
+ path: test-results/
203
+
204
+ # Quality Gates
205
+ quality-gates:
206
+ runs-on: ubuntu-latest
207
+ needs: [unit-tests, integration-tests]
208
+ steps:
209
+ - uses: actions/checkout@v4
210
+
211
+ - uses: actions/setup-node@v4
212
+ with:
213
+ node-version: '20'
214
+ cache: 'npm'
215
+
216
+ - run: npm ci
217
+
218
+ - name: Check Coverage Threshold
219
+ run: |
220
+ npm run test:unit -- --coverage
221
+ COVERAGE=$(jq '.total.lines.pct' coverage/coverage-summary.json)
222
+ echo "Coverage: $COVERAGE%"
223
+ if (( $(echo "$COVERAGE < 80" | bc -l) )); then
224
+ echo "Coverage $COVERAGE% is below 80% threshold"
225
+ exit 1
226
+ fi
227
+
228
+ - name: Run Mutation Tests
229
+ run: npx stryker run
230
+ continue-on-error: true
231
+
232
+ - name: Upload Mutation Report
233
+ uses: actions/upload-artifact@v4
234
+ with:
235
+ name: mutation-report
236
+ path: reports/mutation/
237
+
238
+ # Performance Tests (main branch only)
239
+ performance-tests:
240
+ runs-on: ubuntu-latest
241
+ needs: e2e-tests
242
+ if: github.ref == 'refs/heads/main'
243
+ steps:
244
+ - uses: actions/checkout@v4
245
+
246
+ - name: Deploy to Staging
247
+ run: ./scripts/deploy-staging.sh
248
+
249
+ - name: Run Load Tests
250
+ uses: grafana/k6-action@v0.3.1
251
+ with:
252
+ filename: load-tests/smoke.js
253
+ flags: --out json=results.json
254
+
255
+ - name: Check Performance Thresholds
256
+ run: |
257
+ ERROR_RATE=$(jq '.metrics.http_req_failed.values.rate' results.json)
258
+ if (( $(echo "$ERROR_RATE > 0.01" | bc -l) )); then
259
+ echo "Error rate $ERROR_RATE exceeds 1% threshold"
260
+ exit 1
261
+ fi
262
+
263
+ - name: Upload Performance Results
264
+ uses: actions/upload-artifact@v4
265
+ with:
266
+ name: performance-results
267
+ path: results.json
268
+ ```
269
+
270
+ ### Parallel Test Execution
271
+
272
+ ```yaml
273
+ # Run tests in parallel across multiple jobs
274
+ integration-tests:
275
+ runs-on: ubuntu-latest
276
+ strategy:
277
+ fail-fast: false
278
+ matrix:
279
+ shard: [1, 2, 3, 4]
280
+
281
+ steps:
282
+ - uses: actions/checkout@v4
283
+
284
+ - run: npm ci
285
+
286
+ - name: Run Tests (Shard ${{ matrix.shard }}/4)
287
+ run: npm run test:integration -- --shard=${{ matrix.shard }}/4
288
+ ```
289
+
290
+ ### Test Caching
291
+
292
+ ```yaml
293
+ # Cache test dependencies and build artifacts
294
+ - name: Cache Dependencies
295
+ uses: actions/cache@v4
296
+ with:
297
+ path: |
298
+ ~/.npm
299
+ node_modules
300
+ key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
301
+ restore-keys: |
302
+ ${{ runner.os }}-node-
303
+
304
+ - name: Cache Build
305
+ uses: actions/cache@v4
306
+ with:
307
+ path: .next
308
+ key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.ts', '**/*.tsx') }}
309
+ restore-keys: |
310
+ ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-
311
+ ```
312
+
313
+ ## Pull Request Checks
314
+
315
+ ### Required Checks
316
+
317
+ ```yaml
318
+ # .github/workflows/pr-checks.yml
319
+ name: PR Checks
320
+
321
+ on: pull_request
322
+
323
+ jobs:
324
+ test-coverage-diff:
325
+ runs-on: ubuntu-latest
326
+ steps:
327
+ - uses: actions/checkout@v4
328
+ with:
329
+ fetch-depth: 0
330
+
331
+ - run: npm ci
332
+
333
+ - name: Get Changed Files
334
+ id: changed-files
335
+ uses: tj-actions/changed-files@v44
336
+ with:
337
+ files: |
338
+ src/**/*.ts
339
+ src/**/*.tsx
340
+
341
+ - name: Check New Code Has Tests
342
+ if: steps.changed-files.outputs.any_changed == 'true'
343
+ run: |
344
+ for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
345
+ if [[ "$file" == *.test.* ]]; then
346
+ continue
347
+ fi
348
+
349
+ TEST_FILE="${file%.ts}.test.ts"
350
+ if [[ ! -f "$TEST_FILE" ]]; then
351
+ echo "Missing test file for: $file"
352
+ # Warn but don't fail
353
+ fi
354
+ done
355
+
356
+ - name: Run Tests for Changed Files
357
+ run: |
358
+ npm run test:unit -- --changed --coverage
359
+
360
+ lint-commit-messages:
361
+ runs-on: ubuntu-latest
362
+ steps:
363
+ - uses: actions/checkout@v4
364
+ with:
365
+ fetch-depth: 0
366
+
367
+ - name: Lint Commit Messages
368
+ uses: wagoid/commitlint-github-action@v5
369
+ ```
370
+
371
+ ### PR Comment with Results
372
+
373
+ ```yaml
374
+ - name: Comment Test Results
375
+ uses: actions/github-script@v7
376
+ if: always() && github.event_name == 'pull_request'
377
+ with:
378
+ script: |
379
+ const fs = require('fs');
380
+
381
+ let coverage = 'N/A';
382
+ try {
383
+ const summary = JSON.parse(fs.readFileSync('coverage/coverage-summary.json'));
384
+ coverage = `${summary.total.lines.pct.toFixed(1)}%`;
385
+ } catch (e) {}
386
+
387
+ const body = `## Test Results
388
+
389
+ | Metric | Value |
390
+ |--------|-------|
391
+ | Coverage | ${coverage} |
392
+ | Status | ${{ job.status }} |
393
+
394
+ [View detailed report](${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID})
395
+ `;
396
+
397
+ github.rest.issues.createComment({
398
+ issue_number: context.issue.number,
399
+ owner: context.repo.owner,
400
+ repo: context.repo.repo,
401
+ body: body
402
+ });
403
+ ```
404
+
405
+ ## Test Environment Management
406
+
407
+ ### Docker Compose for Local CI
408
+
409
+ ```yaml
410
+ # docker-compose.test.yml
411
+ version: '3.8'
412
+
413
+ services:
414
+ app:
415
+ build: .
416
+ environment:
417
+ - NODE_ENV=test
418
+ - DATABASE_URL=postgres://postgres:test@db:5432/test
419
+ - REDIS_URL=redis://redis:6379
420
+ depends_on:
421
+ db:
422
+ condition: service_healthy
423
+ redis:
424
+ condition: service_started
425
+
426
+ db:
427
+ image: postgres:16
428
+ environment:
429
+ POSTGRES_PASSWORD: test
430
+ POSTGRES_DB: test
431
+ healthcheck:
432
+ test: ["CMD-SHELL", "pg_isready"]
433
+ interval: 10s
434
+ timeout: 5s
435
+ retries: 5
436
+
437
+ redis:
438
+ image: redis:7
439
+ ```
440
+
441
+ ### Testcontainers
442
+
443
+ ```ts
444
+ // test/setup.ts
445
+ import { PostgreSqlContainer, StartedPostgreSqlContainer } from '@testcontainers/postgresql';
446
+ import { RedisContainer, StartedRedisContainer } from '@testcontainers/redis';
447
+
448
+ let postgres: StartedPostgreSqlContainer;
449
+ let redis: StartedRedisContainer;
450
+
451
+ export async function setupTestContainers() {
452
+ postgres = await new PostgreSqlContainer()
453
+ .withDatabase('test')
454
+ .start();
455
+
456
+ redis = await new RedisContainer().start();
457
+
458
+ process.env.DATABASE_URL = postgres.getConnectionUri();
459
+ process.env.REDIS_URL = `redis://${redis.getHost()}:${redis.getPort()}`;
460
+ }
461
+
462
+ export async function teardownTestContainers() {
463
+ await postgres?.stop();
464
+ await redis?.stop();
465
+ }
466
+ ```
467
+
468
+ ## Reporting and Visibility
469
+
470
+ ### Test Report Generation
471
+
472
+ ```ts
473
+ // vitest.config.ts
474
+ export default {
475
+ test: {
476
+ reporters: [
477
+ 'default',
478
+ 'junit',
479
+ 'html',
480
+ ['vitest-sonar-reporter', { outputFile: 'sonar-report.xml' }],
481
+ ],
482
+ outputFile: {
483
+ junit: 'test-results/junit.xml',
484
+ html: 'test-results/report.html',
485
+ },
486
+ coverage: {
487
+ reporter: ['text', 'json', 'html', 'lcov'],
488
+ reportsDirectory: 'coverage',
489
+ },
490
+ },
491
+ };
492
+ ```
493
+
494
+ ### SonarQube Integration
495
+
496
+ ```yaml
497
+ - name: SonarQube Scan
498
+ uses: SonarSource/sonarqube-scan-action@master
499
+ env:
500
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
501
+ SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
502
+ ```
503
+
504
+ ```properties
505
+ # sonar-project.properties
506
+ sonar.projectKey=my-project
507
+ sonar.sources=src
508
+ sonar.tests=src
509
+ sonar.test.inclusions=**/*.test.ts
510
+ sonar.javascript.lcov.reportPaths=coverage/lcov.info
511
+ sonar.testExecutionReportPaths=sonar-report.xml
512
+ ```
513
+
514
+ ## Deployment Gates
515
+
516
+ ### Staging Deployment
517
+
518
+ ```yaml
519
+ deploy-staging:
520
+ needs: [e2e-tests]
521
+ runs-on: ubuntu-latest
522
+ environment:
523
+ name: staging
524
+ url: https://staging.example.com
525
+ steps:
526
+ - uses: actions/checkout@v4
527
+
528
+ - name: Deploy to Staging
529
+ run: ./scripts/deploy.sh staging
530
+
531
+ - name: Run Smoke Tests
532
+ run: npm run test:smoke -- --base-url=https://staging.example.com
533
+ ```
534
+
535
+ ### Production Deployment
536
+
537
+ ```yaml
538
+ deploy-production:
539
+ needs: [performance-tests]
540
+ runs-on: ubuntu-latest
541
+ if: github.ref == 'refs/heads/main'
542
+ environment:
543
+ name: production
544
+ url: https://example.com
545
+ steps:
546
+ - uses: actions/checkout@v4
547
+
548
+ - name: Deploy to Production
549
+ run: ./scripts/deploy.sh production
550
+
551
+ - name: Run Health Checks
552
+ run: |
553
+ for i in {1..30}; do
554
+ if curl -s https://example.com/health | grep -q "ok"; then
555
+ exit 0
556
+ fi
557
+ sleep 10
558
+ done
559
+ exit 1
560
+
561
+ - name: Notify Slack
562
+ if: always()
563
+ uses: slackapi/slack-github-action@v1
564
+ with:
565
+ payload: |
566
+ {
567
+ "text": "Deployment to production: ${{ job.status }}"
568
+ }
569
+ ```
570
+
571
+ ## Best Practices
572
+
573
+ ### 1. Fail Fast
574
+
575
+ Run fastest tests first. If static analysis fails, skip slower tests.
576
+
577
+ ### 2. Parallelize Everything
578
+
579
+ Split tests across workers and shards for faster execution.
580
+
581
+ ### 3. Cache Aggressively
582
+
583
+ Cache dependencies, build artifacts, and test databases.
584
+
585
+ ### 4. Isolate Test Environments
586
+
587
+ Each test run should have isolated resources.
588
+
589
+ ### 5. Artifact Everything
590
+
591
+ Upload test results, coverage, screenshots for debugging.
592
+
593
+ ### 6. Notify on Failure
594
+
595
+ Alert team immediately when tests fail on main branch.
596
+
597
+ ### 7. Track Metrics Over Time
598
+
599
+ Store test duration, coverage, flakiness metrics historically.
600
+
601
+ ### 8. Review Test Reports in PRs
602
+
603
+ Make test results visible and actionable in pull requests.