@paths.design/caws-cli 7.0.1 → 7.0.3
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.
- package/dist/budget-derivation.js +5 -4
- package/dist/commands/diagnose.js +26 -20
- package/dist/commands/init.js +72 -5
- package/dist/commands/specs.js +40 -1
- package/dist/commands/status.js +2 -2
- package/dist/commands/templates.js +10 -0
- package/dist/commands/tool.js +2 -3
- package/dist/commands/validate.js +12 -0
- package/dist/config/index.js +17 -8
- package/dist/generators/working-spec.js +42 -9
- package/dist/index.js +3 -1
- package/dist/scaffold/cursor-hooks.js +10 -2
- package/dist/scaffold/git-hooks.js +189 -32
- package/dist/scaffold/index.js +105 -17
- package/dist/templates/.caws/tools/README.md +20 -0
- package/dist/templates/.cursor/README.md +311 -0
- package/dist/templates/.cursor/hooks/audit.sh +55 -0
- package/dist/templates/.cursor/hooks/block-dangerous.sh +83 -0
- package/dist/templates/.cursor/hooks/caws-quality-check.sh +52 -0
- package/dist/templates/.cursor/hooks/caws-scope-guard.sh +130 -0
- package/dist/templates/.cursor/hooks/caws-tool-validation.sh +121 -0
- package/dist/templates/.cursor/hooks/format.sh +38 -0
- package/dist/templates/.cursor/hooks/naming-check.sh +64 -0
- package/dist/templates/.cursor/hooks/scan-secrets.sh +46 -0
- package/dist/templates/.cursor/hooks/scope-guard.sh +52 -0
- package/dist/templates/.cursor/hooks/validate-spec.sh +83 -0
- package/dist/templates/.cursor/hooks.json +59 -0
- package/dist/templates/.cursor/rules/00-claims-verification.mdc +144 -0
- package/dist/templates/.cursor/rules/01-working-style.mdc +50 -0
- package/dist/templates/.cursor/rules/02-quality-gates.mdc +370 -0
- package/dist/templates/.cursor/rules/03-naming-and-refactor.mdc +33 -0
- package/dist/templates/.cursor/rules/04-logging-language-style.mdc +23 -0
- package/dist/templates/.cursor/rules/05-safe-defaults-guards.mdc +23 -0
- package/dist/templates/.cursor/rules/06-typescript-conventions.mdc +36 -0
- package/dist/templates/.cursor/rules/07-process-ops.mdc +20 -0
- package/dist/templates/.cursor/rules/08-solid-and-architecture.mdc +16 -0
- package/dist/templates/.cursor/rules/09-docstrings.mdc +89 -0
- package/dist/templates/.cursor/rules/10-documentation-quality-standards.mdc +390 -0
- package/dist/templates/.cursor/rules/11-scope-management-waivers.mdc +385 -0
- package/dist/templates/.cursor/rules/12-implementation-completeness.mdc +516 -0
- package/dist/templates/.cursor/rules/13-language-agnostic-standards.mdc +588 -0
- package/dist/templates/.cursor/rules/README.md +148 -0
- package/dist/templates/.github/copilot/instructions.md +311 -0
- package/dist/templates/.idea/runConfigurations/CAWS_Evaluate.xml +5 -0
- package/dist/templates/.idea/runConfigurations/CAWS_Validate.xml +5 -0
- package/dist/templates/.vscode/launch.json +56 -0
- package/dist/templates/.vscode/settings.json +93 -0
- package/dist/templates/.windsurf/workflows/caws-guided-development.md +92 -0
- package/dist/templates/COMMIT_CONVENTIONS.md +86 -0
- package/dist/templates/OIDC_SETUP.md +300 -0
- package/dist/templates/agents.md +1047 -0
- package/dist/templates/codemod/README.md +1 -0
- package/dist/templates/codemod/test.js +93 -0
- package/dist/templates/docs/README.md +150 -0
- package/dist/templates/scripts/quality-gates/check-god-objects.js +146 -0
- package/dist/templates/scripts/quality-gates/run-quality-gates.js +50 -0
- package/dist/templates/scripts/v3/analysis/todo_analyzer.py +1997 -0
- package/dist/tool-loader.js +6 -1
- package/dist/tool-validator.js +8 -2
- package/dist/utils/detection.js +34 -6
- package/dist/utils/git-lock.js +118 -0
- package/dist/utils/gitignore-updater.js +148 -0
- package/dist/utils/quality-gates.js +47 -7
- package/dist/utils/spec-resolver.js +23 -3
- package/dist/utils/yaml-validation.js +155 -0
- package/dist/validation/spec-validation.js +105 -2
- package/package.json +2 -2
- package/templates/.caws/schemas/waivers.schema.json +30 -0
- package/templates/.caws/schemas/working-spec.schema.json +133 -0
- package/templates/.caws/templates/working-spec.template.yml +74 -0
- package/templates/.caws/tools/README.md +20 -0
- package/templates/.caws/tools/scope-guard.js +208 -0
- package/templates/.caws/tools-allow.json +331 -0
- package/templates/.caws/waivers.yml +19 -0
- package/templates/.cursor/hooks/scope-guard.sh +2 -2
- package/templates/.cursor/hooks/validate-spec.sh +42 -7
- package/templates/apps/tools/caws/COMPLETION_REPORT.md +0 -331
- package/templates/apps/tools/caws/MIGRATION_SUMMARY.md +0 -360
- package/templates/apps/tools/caws/README.md +0 -463
- package/templates/apps/tools/caws/TEST_STATUS.md +0 -365
- package/templates/apps/tools/caws/attest.js +0 -357
- package/templates/apps/tools/caws/ci-optimizer.js +0 -642
- package/templates/apps/tools/caws/config.ts +0 -245
- package/templates/apps/tools/caws/cross-functional.js +0 -876
- package/templates/apps/tools/caws/dashboard.js +0 -1112
- package/templates/apps/tools/caws/flake-detector.ts +0 -362
- package/templates/apps/tools/caws/gates.js +0 -198
- package/templates/apps/tools/caws/gates.ts +0 -271
- package/templates/apps/tools/caws/language-adapters.ts +0 -381
- package/templates/apps/tools/caws/language-support.d.ts +0 -367
- package/templates/apps/tools/caws/language-support.d.ts.map +0 -1
- package/templates/apps/tools/caws/language-support.js +0 -585
- package/templates/apps/tools/caws/legacy-assessment.ts +0 -408
- package/templates/apps/tools/caws/legacy-assessor.js +0 -764
- package/templates/apps/tools/caws/mutant-analyzer.js +0 -734
- package/templates/apps/tools/caws/perf-budgets.ts +0 -349
- package/templates/apps/tools/caws/prompt-lint.js.backup +0 -274
- package/templates/apps/tools/caws/property-testing.js +0 -707
- package/templates/apps/tools/caws/provenance.d.ts +0 -14
- package/templates/apps/tools/caws/provenance.d.ts.map +0 -1
- package/templates/apps/tools/caws/provenance.js +0 -132
- package/templates/apps/tools/caws/provenance.js.backup +0 -73
- package/templates/apps/tools/caws/provenance.ts +0 -211
- package/templates/apps/tools/caws/security-provenance.ts +0 -483
- package/templates/apps/tools/caws/shared/base-tool.ts +0 -281
- package/templates/apps/tools/caws/shared/config-manager.ts +0 -366
- package/templates/apps/tools/caws/shared/gate-checker.ts +0 -849
- package/templates/apps/tools/caws/shared/types.ts +0 -444
- package/templates/apps/tools/caws/shared/validator.ts +0 -305
- package/templates/apps/tools/caws/shared/waivers-manager.ts +0 -174
- package/templates/apps/tools/caws/spec-test-mapper.ts +0 -391
- package/templates/apps/tools/caws/test-quality.js +0 -578
- package/templates/apps/tools/caws/validate.js +0 -76
- package/templates/apps/tools/caws/validate.ts +0 -228
- package/templates/apps/tools/caws/waivers.js +0 -344
- /package/{templates/apps/tools/caws → dist/templates/.caws}/schemas/waivers.schema.json +0 -0
- /package/{templates/apps/tools/caws → dist/templates/.caws}/schemas/working-spec.schema.json +0 -0
- /package/{templates/apps/tools/caws → dist/templates/.caws}/templates/working-spec.template.yml +0 -0
- /package/{templates/apps/tools/caws → dist/templates/.caws/tools}/scope-guard.js +0 -0
- /package/{templates/apps/tools/caws → dist/templates/.caws}/tools-allow.json +0 -0
- /package/{templates/apps/tools/caws → dist/templates/.caws}/waivers.yml +0 -0
|
@@ -1,362 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env tsx
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* CAWS Flake Detection System
|
|
5
|
-
*
|
|
6
|
-
* Monitors test variance and quarantines intermittently failing tests.
|
|
7
|
-
* This tool analyzes test run variance and identifies flaky tests for quarantine.
|
|
8
|
-
*
|
|
9
|
-
* @author @darianrosebrook
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
13
|
-
import { dirname } from 'path';
|
|
14
|
-
import { fileURLToPath } from 'url';
|
|
15
|
-
|
|
16
|
-
interface TestResult {
|
|
17
|
-
title: string;
|
|
18
|
-
fullName: string;
|
|
19
|
-
status: 'passed' | 'failed' | 'pending' | 'skipped';
|
|
20
|
-
duration: number;
|
|
21
|
-
failureMessages: string[];
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
interface TestSuiteResult {
|
|
25
|
-
name: string;
|
|
26
|
-
status: 'passed' | 'failed';
|
|
27
|
-
testResults: TestResult[];
|
|
28
|
-
startTime: number;
|
|
29
|
-
endTime: number;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
interface FlakeDetectionResult {
|
|
33
|
-
flakyTests: string[];
|
|
34
|
-
varianceScore: number;
|
|
35
|
-
totalRuns: number;
|
|
36
|
-
recommendations: string[];
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
interface HistoricalTestData {
|
|
40
|
-
runs: TestRun[];
|
|
41
|
-
quarantined: Set<string>;
|
|
42
|
-
lastUpdated: string;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
interface TestRun {
|
|
46
|
-
timestamp: number;
|
|
47
|
-
results: Map<string, TestResult>;
|
|
48
|
-
variance: number;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Flake Detection Service
|
|
53
|
-
* Analyzes test run variance and identifies flaky tests
|
|
54
|
-
*/
|
|
55
|
-
class FlakeDetectionService {
|
|
56
|
-
private readonly HISTORY_FILE = '.caws/flake-history.json';
|
|
57
|
-
private readonly QUARANTINE_FILE = '.caws/quarantined-tests.json';
|
|
58
|
-
private readonly VARIANCE_THRESHOLD = 0.05; // 5% variance threshold
|
|
59
|
-
private readonly MIN_RUNS_FOR_ANALYSIS = 3;
|
|
60
|
-
private readonly QUARANTINE_THRESHOLD = 0.15; // 15% flake rate triggers quarantine
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Analyze test variance and detect flaky tests
|
|
64
|
-
*/
|
|
65
|
-
async detectFlakes(currentResults: TestSuiteResult[]): Promise<FlakeDetectionResult> {
|
|
66
|
-
const history = this.loadHistory();
|
|
67
|
-
const currentRun = this.createCurrentRun(currentResults);
|
|
68
|
-
|
|
69
|
-
history.runs.push(currentRun);
|
|
70
|
-
this.saveHistory(history);
|
|
71
|
-
|
|
72
|
-
if (history.runs.length < this.MIN_RUNS_FOR_ANALYSIS) {
|
|
73
|
-
return {
|
|
74
|
-
flakyTests: [],
|
|
75
|
-
varianceScore: 0,
|
|
76
|
-
totalRuns: history.runs.length,
|
|
77
|
-
recommendations: [
|
|
78
|
-
`Need ${this.MIN_RUNS_FOR_ANALYSIS - history.runs.length} more test runs for analysis`,
|
|
79
|
-
],
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const flakyTests = this.identifyFlakyTests(history);
|
|
84
|
-
const varianceScore = this.calculateVarianceScore(history);
|
|
85
|
-
|
|
86
|
-
const recommendations = this.generateRecommendations(flakyTests, varianceScore);
|
|
87
|
-
|
|
88
|
-
return {
|
|
89
|
-
flakyTests,
|
|
90
|
-
varianceScore,
|
|
91
|
-
totalRuns: history.runs.length,
|
|
92
|
-
recommendations,
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Quarantine flaky tests
|
|
98
|
-
*/
|
|
99
|
-
quarantineTests(testNames: string[]): void {
|
|
100
|
-
const history = this.loadHistory();
|
|
101
|
-
testNames.forEach((testName) => history.quarantined.add(testName));
|
|
102
|
-
history.lastUpdated = new Date().toISOString();
|
|
103
|
-
this.saveHistory(history);
|
|
104
|
-
|
|
105
|
-
// Save quarantined tests list
|
|
106
|
-
const quarantinedData = {
|
|
107
|
-
quarantined: Array.from(history.quarantined),
|
|
108
|
-
quarantinedAt: history.lastUpdated,
|
|
109
|
-
reason: 'Automated flake detection',
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
writeFileSync(this.QUARANTINE_FILE, JSON.stringify(quarantinedData, null, 2));
|
|
113
|
-
console.log(`🚫 Quarantined ${testNames.length} flaky tests`);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Get currently quarantined tests
|
|
118
|
-
*/
|
|
119
|
-
getQuarantinedTests(): string[] {
|
|
120
|
-
const history = this.loadHistory();
|
|
121
|
-
return Array.from(history.quarantined);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Release tests from quarantine (manual override)
|
|
126
|
-
*/
|
|
127
|
-
releaseFromQuarantine(testNames: string[]): void {
|
|
128
|
-
const history = this.loadHistory();
|
|
129
|
-
testNames.forEach((testName) => history.quarantined.delete(testName));
|
|
130
|
-
history.lastUpdated = new Date().toISOString();
|
|
131
|
-
this.saveHistory(history);
|
|
132
|
-
console.log(`✅ Released ${testNames.length} tests from quarantine`);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
private loadHistory(): HistoricalTestData {
|
|
136
|
-
if (!existsSync(this.HISTORY_FILE)) {
|
|
137
|
-
return {
|
|
138
|
-
runs: [],
|
|
139
|
-
quarantined: new Set(),
|
|
140
|
-
lastUpdated: new Date().toISOString(),
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
try {
|
|
145
|
-
const data = JSON.parse(readFileSync(this.HISTORY_FILE, 'utf-8'));
|
|
146
|
-
return {
|
|
147
|
-
runs: data.runs || [],
|
|
148
|
-
quarantined: new Set(data.quarantined || []),
|
|
149
|
-
lastUpdated: data.lastUpdated || new Date().toISOString(),
|
|
150
|
-
};
|
|
151
|
-
} catch {
|
|
152
|
-
return {
|
|
153
|
-
runs: [],
|
|
154
|
-
quarantined: new Set(),
|
|
155
|
-
lastUpdated: new Date().toISOString(),
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
private saveHistory(history: HistoricalTestData): void {
|
|
161
|
-
const data = {
|
|
162
|
-
runs: history.runs,
|
|
163
|
-
quarantined: Array.from(history.quarantined),
|
|
164
|
-
lastUpdated: history.lastUpdated,
|
|
165
|
-
};
|
|
166
|
-
writeFileSync(this.HISTORY_FILE, JSON.stringify(data, null, 2));
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
private createCurrentRun(results: TestSuiteResult[]): TestRun {
|
|
170
|
-
const testMap = new Map<string, TestResult>();
|
|
171
|
-
|
|
172
|
-
results.forEach((suite) => {
|
|
173
|
-
suite.testResults.forEach((test) => {
|
|
174
|
-
const key = this.getTestKey(test);
|
|
175
|
-
testMap.set(key, test);
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
const variance = this.calculateRunVariance(testMap, results);
|
|
180
|
-
return {
|
|
181
|
-
timestamp: Date.now(),
|
|
182
|
-
results: testMap,
|
|
183
|
-
variance,
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
private getTestKey(test: TestResult): string {
|
|
188
|
-
return test.fullName;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
private identifyFlakyTests(history: HistoricalTestData): string[] {
|
|
192
|
-
const flakyTests = new Set<string>();
|
|
193
|
-
const recentRuns = history.runs.slice(-5); // Analyze last 5 runs
|
|
194
|
-
|
|
195
|
-
// Find tests that have inconsistent results
|
|
196
|
-
for (const run of recentRuns) {
|
|
197
|
-
for (const [testName, result] of run.results) {
|
|
198
|
-
if (result.status !== 'passed') {
|
|
199
|
-
// Check if this test has passed in other recent runs
|
|
200
|
-
const passedInOtherRuns = recentRuns
|
|
201
|
-
.filter((r) => r !== run)
|
|
202
|
-
.some((r) => r.results.get(testName)?.status === 'passed');
|
|
203
|
-
|
|
204
|
-
if (passedInOtherRuns) {
|
|
205
|
-
flakyTests.add(testName);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Check against quarantine threshold
|
|
212
|
-
for (const testName of flakyTests) {
|
|
213
|
-
const flakeRate = this.calculateFlakeRate(testName, recentRuns);
|
|
214
|
-
if (flakeRate < this.QUARANTINE_THRESHOLD) {
|
|
215
|
-
flakyTests.delete(testName);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
return Array.from(flakyTests);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
private calculateFlakeRate(testName: string, runs: TestRun[]): number {
|
|
223
|
-
const results = runs.map((run) => run.results.get(testName)?.status).filter(Boolean);
|
|
224
|
-
const failures = results.filter((status) => status !== 'passed').length;
|
|
225
|
-
return failures / results.length;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
private calculateVarianceScore(history: HistoricalTestData): number {
|
|
229
|
-
if (history.runs.length < 2) return 0;
|
|
230
|
-
|
|
231
|
-
const recentRuns = history.runs.slice(-5);
|
|
232
|
-
const varianceSum = recentRuns.reduce((sum, run) => sum + run.variance, 0);
|
|
233
|
-
return varianceSum / recentRuns.length;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
private calculateRunVariance(
|
|
237
|
-
testMap: Map<string, TestResult>,
|
|
238
|
-
_suites: TestSuiteResult[]
|
|
239
|
-
): number {
|
|
240
|
-
const totalTests = testMap.size;
|
|
241
|
-
const failedTests = Array.from(testMap.values()).filter((t) => t.status !== 'passed').length;
|
|
242
|
-
return totalTests > 0 ? failedTests / totalTests : 0;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
private generateRecommendations(flakyTests: string[], varianceScore: number): string[] {
|
|
246
|
-
const recommendations: string[] = [];
|
|
247
|
-
|
|
248
|
-
if (flakyTests.length > 0) {
|
|
249
|
-
recommendations.push(`Quarantine ${flakyTests.length} flaky tests for investigation`);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
if (varianceScore > this.VARIANCE_THRESHOLD) {
|
|
253
|
-
recommendations.push('High test variance detected - consider test environment stability');
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
if (varianceScore === 0) {
|
|
257
|
-
recommendations.push('Excellent test stability - no flakes detected');
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
return recommendations;
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* CLI Interface
|
|
266
|
-
*/
|
|
267
|
-
async function main() {
|
|
268
|
-
const args = process.argv.slice(2);
|
|
269
|
-
|
|
270
|
-
if (args.length === 0) {
|
|
271
|
-
console.log('🔍 CAWS Flake Detection Tool');
|
|
272
|
-
console.log('Usage: flake-detector.ts <command> [options]');
|
|
273
|
-
console.log('');
|
|
274
|
-
console.log('Commands:');
|
|
275
|
-
console.log(' detect - Analyze test variance and detect flaky tests');
|
|
276
|
-
console.log(' quarantine - Quarantine specified flaky tests');
|
|
277
|
-
console.log(' release - Release tests from quarantine');
|
|
278
|
-
console.log(' status - Show current flake detection status');
|
|
279
|
-
console.log('');
|
|
280
|
-
console.log('Examples:');
|
|
281
|
-
console.log(' flake-detector.ts detect');
|
|
282
|
-
console.log(' flake-detector.ts quarantine "test name"');
|
|
283
|
-
console.log(' flake-detector.ts release "test name"');
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
const command = args[0];
|
|
288
|
-
const detector = new FlakeDetectionService();
|
|
289
|
-
|
|
290
|
-
try {
|
|
291
|
-
switch (command) {
|
|
292
|
-
case 'detect': {
|
|
293
|
-
console.log('🔍 Analyzing test variance...');
|
|
294
|
-
// In a real implementation, you'd read test results from files
|
|
295
|
-
// For now, we'll simulate with mock data
|
|
296
|
-
const mockResults: TestSuiteResult[] = [];
|
|
297
|
-
const result = await detector.detectFlakes(mockResults);
|
|
298
|
-
|
|
299
|
-
console.log(`📊 Flake Detection Results:`);
|
|
300
|
-
console.log(` Variance Score: ${(result.varianceScore * 100).toFixed(2)}%`);
|
|
301
|
-
console.log(` Total Runs Analyzed: ${result.totalRuns}`);
|
|
302
|
-
console.log(` Flaky Tests Found: ${result.flakyTests.length}`);
|
|
303
|
-
|
|
304
|
-
if (result.flakyTests.length > 0) {
|
|
305
|
-
console.log('\n🚨 Flaky Tests:');
|
|
306
|
-
result.flakyTests.forEach((test) => console.log(` - ${test}`));
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
result.recommendations.forEach((rec) => console.log(`💡 ${rec}`));
|
|
310
|
-
break;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
case 'quarantine': {
|
|
314
|
-
const testNames = args.slice(1);
|
|
315
|
-
if (testNames.length === 0) {
|
|
316
|
-
console.log('❌ Please specify test names to quarantine');
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
319
|
-
detector.quarantineTests(testNames);
|
|
320
|
-
break;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
case 'release': {
|
|
324
|
-
const testNames = args.slice(1);
|
|
325
|
-
if (testNames.length === 0) {
|
|
326
|
-
console.log('❌ Please specify test names to release');
|
|
327
|
-
return;
|
|
328
|
-
}
|
|
329
|
-
detector.releaseFromQuarantine(testNames);
|
|
330
|
-
break;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
case 'status': {
|
|
334
|
-
const quarantined = detector.getQuarantinedTests();
|
|
335
|
-
console.log('🚫 Currently Quarantined Tests:');
|
|
336
|
-
if (quarantined.length === 0) {
|
|
337
|
-
console.log(' None - all tests are active');
|
|
338
|
-
} else {
|
|
339
|
-
quarantined.forEach((test) => console.log(` - ${test}`));
|
|
340
|
-
}
|
|
341
|
-
break;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
default:
|
|
345
|
-
console.log(`❌ Unknown command: ${command}`);
|
|
346
|
-
process.exit(1);
|
|
347
|
-
}
|
|
348
|
-
} catch (error) {
|
|
349
|
-
console.error('❌ Error:', error);
|
|
350
|
-
process.exit(1);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
// Run CLI if this file is executed directly
|
|
355
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
356
|
-
const __dirname = dirname(__filename);
|
|
357
|
-
|
|
358
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
359
|
-
main().catch(console.error);
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
export { FlakeDetectionService };
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @fileoverview CAWS Gates Tool - Enhanced Implementation
|
|
5
|
-
* @author @darianrosebrook
|
|
6
|
-
*
|
|
7
|
-
* Note: For enhanced TypeScript version with full gate checking, use gates.ts
|
|
8
|
-
* This .js version provides basic gate enforcement for backward compatibility
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
// Tier policies for quality gates
|
|
12
|
-
const TIER_POLICIES = {
|
|
13
|
-
1: {
|
|
14
|
-
branch_coverage: 0.9,
|
|
15
|
-
mutation_score: 0.7,
|
|
16
|
-
max_files: 40,
|
|
17
|
-
max_loc: 1500,
|
|
18
|
-
trust_score: 85,
|
|
19
|
-
},
|
|
20
|
-
2: {
|
|
21
|
-
branch_coverage: 0.8,
|
|
22
|
-
mutation_score: 0.5,
|
|
23
|
-
max_files: 25,
|
|
24
|
-
max_loc: 1000,
|
|
25
|
-
trust_score: 82,
|
|
26
|
-
},
|
|
27
|
-
3: {
|
|
28
|
-
branch_coverage: 0.7,
|
|
29
|
-
mutation_score: 0.3,
|
|
30
|
-
max_files: 15,
|
|
31
|
-
max_loc: 500,
|
|
32
|
-
trust_score: 75,
|
|
33
|
-
},
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Show tier policy
|
|
38
|
-
* @param {number} tier - Risk tier (1-3)
|
|
39
|
-
*/
|
|
40
|
-
function showTierPolicy(tier = 1) {
|
|
41
|
-
const policy = TIER_POLICIES[tier];
|
|
42
|
-
if (!policy) {
|
|
43
|
-
console.error(`❌ Unknown tier: ${tier}`);
|
|
44
|
-
process.exit(1);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
console.log(`📋 Tier ${tier} Policy:`);
|
|
48
|
-
console.log(`Branch Coverage: ≥${policy.branch_coverage * 100}%`);
|
|
49
|
-
console.log(`Mutation Score: ≥${policy.mutation_score * 100}%`);
|
|
50
|
-
console.log(`Max Files: ${policy.max_files}`);
|
|
51
|
-
console.log(`Max LOC: ${policy.max_loc}`);
|
|
52
|
-
console.log(`Trust Score: ≥${policy.trust_score}`);
|
|
53
|
-
console.log('Requires Contracts: true');
|
|
54
|
-
console.log('Manual Review: Required');
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Enforce coverage gate
|
|
59
|
-
* @param {number} coverage - Coverage value to test
|
|
60
|
-
* @param {number} threshold - Threshold to test against
|
|
61
|
-
*/
|
|
62
|
-
function enforceCoverageGate(coverage, threshold = 0.8) {
|
|
63
|
-
if (coverage >= threshold) {
|
|
64
|
-
console.log(`✅ Branch coverage gate passed: ${coverage} >= ${threshold}`);
|
|
65
|
-
return true;
|
|
66
|
-
} else {
|
|
67
|
-
console.log(`❌ Branch coverage gate failed: ${coverage} < ${threshold}`);
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Enforce mutation gate
|
|
74
|
-
* @param {number} score - Mutation score to test
|
|
75
|
-
* @param {number} threshold - Threshold to test against
|
|
76
|
-
*/
|
|
77
|
-
function enforceMutationGate(score, threshold = 0.5) {
|
|
78
|
-
if (score >= threshold) {
|
|
79
|
-
console.log(`✅ Mutation gate passed: ${score} >= ${threshold}`);
|
|
80
|
-
return true;
|
|
81
|
-
} else {
|
|
82
|
-
console.log(`❌ Mutation gate failed: ${score} < ${threshold}`);
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Enforce trust score gate
|
|
89
|
-
* @param {number} score - Trust score to test
|
|
90
|
-
* @param {number} threshold - Threshold to test against
|
|
91
|
-
*/
|
|
92
|
-
function enforceTrustScoreGate(score, threshold = 82) {
|
|
93
|
-
if (score >= threshold) {
|
|
94
|
-
console.log(`✅ Trust score gate passed: ${score} >= ${threshold}`);
|
|
95
|
-
return true;
|
|
96
|
-
} else {
|
|
97
|
-
console.log(`❌ Trust score gate failed: ${score} < ${threshold}`);
|
|
98
|
-
return false;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Enforce budget gate
|
|
104
|
-
* @param {number} files - File count to test
|
|
105
|
-
* @param {number} loc - Lines of code to test
|
|
106
|
-
* @param {number} maxFiles - Maximum allowed files
|
|
107
|
-
* @param {number} maxLoc - Maximum allowed LOC
|
|
108
|
-
*/
|
|
109
|
-
function enforceBudgetGate(files, loc, maxFiles = 25, maxLoc = 1000) {
|
|
110
|
-
const filesOk = files <= maxFiles;
|
|
111
|
-
const locOk = loc <= maxLoc;
|
|
112
|
-
|
|
113
|
-
if (filesOk && locOk) {
|
|
114
|
-
console.log(`✅ Budget gate passed: ${files} files, ${loc} LOC`);
|
|
115
|
-
return true;
|
|
116
|
-
} else {
|
|
117
|
-
if (!filesOk) {
|
|
118
|
-
console.log(`❌ Budget gate failed: ${files} files > ${maxFiles} max files`);
|
|
119
|
-
}
|
|
120
|
-
if (!locOk) {
|
|
121
|
-
console.log(`❌ Budget gate failed: ${loc} LOC > ${maxLoc} max LOC`);
|
|
122
|
-
}
|
|
123
|
-
return false;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Main command handler
|
|
129
|
-
*/
|
|
130
|
-
function main() {
|
|
131
|
-
const command = process.argv[2];
|
|
132
|
-
|
|
133
|
-
switch (command) {
|
|
134
|
-
case 'tier':
|
|
135
|
-
const tier = parseInt(process.argv[3]) || 1;
|
|
136
|
-
showTierPolicy(tier);
|
|
137
|
-
break;
|
|
138
|
-
|
|
139
|
-
case 'coverage':
|
|
140
|
-
const coverage = parseFloat(process.argv[3]) || 0.85;
|
|
141
|
-
const coverageThreshold = 0.8;
|
|
142
|
-
if (!enforceCoverageGate(coverage, coverageThreshold)) {
|
|
143
|
-
throw new Error(`Coverage gate failed: ${coverage} < ${coverageThreshold}`);
|
|
144
|
-
}
|
|
145
|
-
break;
|
|
146
|
-
|
|
147
|
-
case 'mutation':
|
|
148
|
-
const mutationScore = parseFloat(process.argv[3]) || 0.6;
|
|
149
|
-
const mutationThreshold = 0.5;
|
|
150
|
-
if (!enforceMutationGate(mutationScore, mutationThreshold)) {
|
|
151
|
-
throw new Error(`Mutation gate failed: ${mutationScore} < ${mutationThreshold}`);
|
|
152
|
-
}
|
|
153
|
-
break;
|
|
154
|
-
|
|
155
|
-
case 'trust':
|
|
156
|
-
const trustScore = parseInt(process.argv[3]) || 85;
|
|
157
|
-
const trustThreshold = 82;
|
|
158
|
-
if (!enforceTrustScoreGate(trustScore, trustThreshold)) {
|
|
159
|
-
throw new Error(`Trust score gate failed: ${trustScore} < ${trustThreshold}`);
|
|
160
|
-
}
|
|
161
|
-
break;
|
|
162
|
-
|
|
163
|
-
case 'budget':
|
|
164
|
-
const files = parseInt(process.argv[3]) || 20;
|
|
165
|
-
const loc = parseInt(process.argv[4]) || 800;
|
|
166
|
-
if (!enforceBudgetGate(files, loc, 25, 1000)) {
|
|
167
|
-
throw new Error(`Budget gate failed: ${files} files or ${loc} LOC exceeds limits`);
|
|
168
|
-
}
|
|
169
|
-
break;
|
|
170
|
-
|
|
171
|
-
default:
|
|
172
|
-
console.log('CAWS Gates Tool - Quality Gate Enforcement');
|
|
173
|
-
console.log('');
|
|
174
|
-
console.log('Commands:');
|
|
175
|
-
console.log(' tier <tier> - Show tier policy');
|
|
176
|
-
console.log(' coverage <score> - Enforce coverage gate');
|
|
177
|
-
console.log(' mutation <score> - Enforce mutation gate');
|
|
178
|
-
console.log(' trust <score> - Enforce trust score gate');
|
|
179
|
-
console.log(' budget <files> <loc> - Enforce budget gate');
|
|
180
|
-
console.log('');
|
|
181
|
-
console.log('Note: For enhanced features, use gates.ts with: npx tsx gates.ts');
|
|
182
|
-
process.exit(1);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Handle direct script execution
|
|
187
|
-
if (require.main === module) {
|
|
188
|
-
main();
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
module.exports = {
|
|
192
|
-
showTierPolicy,
|
|
193
|
-
enforceCoverageGate,
|
|
194
|
-
enforceMutationGate,
|
|
195
|
-
enforceTrustScoreGate,
|
|
196
|
-
enforceBudgetGate,
|
|
197
|
-
TIER_POLICIES,
|
|
198
|
-
};
|