@paths.design/caws-cli 3.0.0 ā 3.1.1
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/README.md +295 -150
- package/dist/budget-derivation.d.ts +35 -0
- package/dist/budget-derivation.d.ts.map +1 -0
- package/dist/budget-derivation.js +204 -0
- package/dist/cicd-optimizer.d.ts +142 -0
- package/dist/cicd-optimizer.d.ts.map +1 -0
- package/dist/cicd-optimizer.js +504 -0
- package/dist/commands/burnup.d.ts +6 -0
- package/dist/commands/burnup.d.ts.map +1 -0
- package/dist/commands/burnup.js +90 -0
- package/dist/commands/init.d.ts +5 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +514 -0
- package/dist/commands/provenance.d.ts +22 -0
- package/dist/commands/provenance.d.ts.map +1 -0
- package/dist/commands/provenance.js +594 -0
- package/dist/commands/tool.d.ts +13 -0
- package/dist/commands/tool.d.ts.map +1 -0
- package/dist/commands/tool.js +138 -0
- package/dist/commands/validate.d.ts +7 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +80 -0
- package/dist/config/index.d.ts +29 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +132 -0
- package/dist/error-handler.d.ts +50 -0
- package/dist/error-handler.d.ts.map +1 -0
- package/dist/error-handler.js +253 -0
- package/dist/generators/working-spec.d.ts +13 -0
- package/dist/generators/working-spec.d.ts.map +1 -0
- package/dist/generators/working-spec.js +204 -0
- package/dist/index-new.d.ts +5 -0
- package/dist/index-new.d.ts.map +1 -0
- package/dist/index-new.js +317 -0
- package/dist/index.d.ts +3 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +100 -1659
- package/dist/index.js.backup +4711 -0
- package/dist/scaffold/cursor-hooks.d.ts +7 -0
- package/dist/scaffold/cursor-hooks.d.ts.map +1 -0
- package/dist/scaffold/cursor-hooks.js +152 -0
- package/dist/scaffold/index.d.ts +20 -0
- package/dist/scaffold/index.d.ts.map +1 -0
- package/dist/scaffold/index.js +486 -0
- package/dist/test-analysis.d.ts +182 -0
- package/dist/test-analysis.d.ts.map +1 -0
- package/dist/test-analysis.js +580 -0
- package/dist/tool-interface.d.ts +236 -0
- package/dist/tool-interface.d.ts.map +1 -0
- package/dist/tool-interface.js +314 -0
- package/dist/tool-loader.d.ts +77 -0
- package/dist/tool-loader.d.ts.map +1 -0
- package/dist/tool-loader.js +298 -0
- package/dist/tool-validator.d.ts +72 -0
- package/dist/tool-validator.d.ts.map +1 -0
- package/dist/tool-validator.js +387 -0
- package/dist/utils/detection.d.ts +7 -0
- package/dist/utils/detection.d.ts.map +1 -0
- package/dist/utils/detection.js +174 -0
- package/dist/utils/finalization.d.ts +17 -0
- package/dist/utils/finalization.d.ts.map +1 -0
- package/dist/utils/finalization.js +229 -0
- package/dist/utils/project-analysis.d.ts +14 -0
- package/dist/utils/project-analysis.d.ts.map +1 -0
- package/dist/utils/project-analysis.js +105 -0
- package/dist/validation/spec-validation.d.ts +29 -0
- package/dist/validation/spec-validation.d.ts.map +1 -0
- package/dist/validation/spec-validation.js +376 -0
- package/dist/waivers-manager.d.ts +167 -0
- package/dist/waivers-manager.d.ts.map +1 -0
- package/dist/waivers-manager.js +549 -0
- package/package.json +10 -12
- package/templates/.cursor/README.md +311 -0
- package/templates/.cursor/hooks/audit.sh +55 -0
- package/templates/.cursor/hooks/block-dangerous.sh +77 -0
- package/templates/.cursor/hooks/caws-quality-check.sh +52 -0
- package/templates/.cursor/hooks/caws-scope-guard.sh +74 -0
- package/templates/.cursor/hooks/caws-tool-validation.sh +121 -0
- package/templates/.cursor/hooks/format.sh +38 -0
- package/templates/.cursor/hooks/naming-check.sh +64 -0
- package/templates/.cursor/hooks/scan-secrets.sh +46 -0
- package/templates/.cursor/hooks/scope-guard.sh +52 -0
- package/templates/.cursor/hooks/validate-spec.sh +38 -0
- package/templates/.cursor/hooks.json +59 -0
- package/templates/.github/copilot/instructions.md +311 -0
- package/templates/.idea/runConfigurations/CAWS_Evaluate.xml +5 -0
- package/templates/.idea/runConfigurations/CAWS_Validate.xml +5 -0
- package/templates/.vscode/launch.json +56 -0
- package/templates/.vscode/settings.json +93 -0
- package/templates/.windsurf/workflows/caws-guided-development.md +92 -0
- package/templates/apps/tools/caws/README.md +1 -1
- package/templates/apps/tools/caws/prompt-lint.js.backup +274 -0
- package/templates/apps/tools/caws/provenance.js.backup +73 -0
- package/templates/apps/tools/caws/schemas/working-spec.schema.json +21 -3
- package/templates/codemod/test.js +93 -1
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CAWS CI/CD Optimizer
|
|
3
|
+
*
|
|
4
|
+
* Optimizes CI/CD pipelines with tier-based conditional execution,
|
|
5
|
+
* parallel processing, and smart caching strategies.
|
|
6
|
+
*
|
|
7
|
+
* @author @darianrosebrook
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const crypto = require('crypto');
|
|
13
|
+
|
|
14
|
+
class CICDOptimizer {
|
|
15
|
+
constructor(options = {}) {
|
|
16
|
+
this.projectRoot = options.projectRoot || process.cwd();
|
|
17
|
+
this.cacheDir = path.join(this.projectRoot, '.caws', 'cache');
|
|
18
|
+
this.optimizationConfig = path.join(this.projectRoot, '.caws', 'cicd-config.yaml');
|
|
19
|
+
|
|
20
|
+
// Ensure cache directory exists
|
|
21
|
+
if (!fs.existsSync(this.cacheDir)) {
|
|
22
|
+
fs.mkdirSync(this.cacheDir, { recursive: true });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Analyze project and generate CI/CD optimization recommendations
|
|
28
|
+
*/
|
|
29
|
+
async analyzeProject(specPath = '.caws/working-spec.yaml') {
|
|
30
|
+
const analysis = {
|
|
31
|
+
project_tier: 'unknown',
|
|
32
|
+
recommended_optimizations: [],
|
|
33
|
+
cache_strategy: {},
|
|
34
|
+
parallel_groups: [],
|
|
35
|
+
conditional_execution: {},
|
|
36
|
+
estimated_savings: {},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
// Load working spec to determine tier
|
|
41
|
+
if (fs.existsSync(specPath)) {
|
|
42
|
+
const yaml = require('js-yaml');
|
|
43
|
+
const spec = yaml.load(fs.readFileSync(specPath, 'utf8'));
|
|
44
|
+
analysis.project_tier = spec.risk_tier || 2;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Analyze current project structure
|
|
48
|
+
analysis.recommended_optimizations = await this.analyzeOptimizationOpportunities(
|
|
49
|
+
analysis.project_tier
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
// Generate cache strategy
|
|
53
|
+
analysis.cache_strategy = await this.generateCacheStrategy();
|
|
54
|
+
|
|
55
|
+
// Create parallel execution groups
|
|
56
|
+
analysis.parallel_groups = await this.createParallelGroups();
|
|
57
|
+
|
|
58
|
+
// Define conditional execution rules
|
|
59
|
+
analysis.conditional_execution = this.generateConditionalExecutionRules(
|
|
60
|
+
analysis.project_tier
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
// Estimate time savings
|
|
64
|
+
analysis.estimated_savings = this.estimateTimeSavings(analysis);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.warn('Warning: Could not complete full analysis:', error.message);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return analysis;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Generate tier-based conditional execution rules
|
|
74
|
+
*/
|
|
75
|
+
generateConditionalExecutionRules(tier) {
|
|
76
|
+
const rules = {
|
|
77
|
+
coverage_required: tier <= 2,
|
|
78
|
+
mutation_required: tier === 1,
|
|
79
|
+
contract_testing: tier <= 2,
|
|
80
|
+
accessibility_check: tier <= 2,
|
|
81
|
+
performance_budget: tier === 1,
|
|
82
|
+
security_scan: true, // Always required
|
|
83
|
+
lint_strict: tier <= 2,
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// Add tier-specific rules
|
|
87
|
+
if (tier === 1) {
|
|
88
|
+
rules.integration_tests = true;
|
|
89
|
+
rules.load_testing = true;
|
|
90
|
+
rules.manual_review = true;
|
|
91
|
+
} else if (tier === 2) {
|
|
92
|
+
rules.integration_tests = true;
|
|
93
|
+
rules.smoke_tests = true;
|
|
94
|
+
} else {
|
|
95
|
+
rules.unit_tests_only = true;
|
|
96
|
+
rules.fast_feedback = true;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return rules;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Analyze what optimizations are beneficial for this tier
|
|
104
|
+
*/
|
|
105
|
+
async analyzeOptimizationOpportunities(tier) {
|
|
106
|
+
const opportunities = [];
|
|
107
|
+
|
|
108
|
+
// Tier-based optimizations
|
|
109
|
+
if (tier === 3) {
|
|
110
|
+
opportunities.push({
|
|
111
|
+
type: 'fast_feedback',
|
|
112
|
+
description: 'Skip heavy analysis for quick feedback',
|
|
113
|
+
impact: 'high',
|
|
114
|
+
effort: 'low',
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (tier <= 2) {
|
|
119
|
+
opportunities.push({
|
|
120
|
+
type: 'parallel_execution',
|
|
121
|
+
description: 'Run independent quality gates in parallel',
|
|
122
|
+
impact: 'high',
|
|
123
|
+
effort: 'medium',
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Always beneficial optimizations
|
|
128
|
+
opportunities.push({
|
|
129
|
+
type: 'smart_caching',
|
|
130
|
+
description: 'Cache dependencies and build artifacts',
|
|
131
|
+
impact: 'medium',
|
|
132
|
+
effort: 'low',
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
opportunities.push({
|
|
136
|
+
type: 'test_selection',
|
|
137
|
+
description: 'Run only tests affected by changes',
|
|
138
|
+
impact: 'high',
|
|
139
|
+
effort: 'medium',
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
opportunities.push({
|
|
143
|
+
type: 'early_failure',
|
|
144
|
+
description: 'Fail fast on critical issues',
|
|
145
|
+
impact: 'medium',
|
|
146
|
+
effort: 'low',
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
return opportunities;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Generate intelligent caching strategy
|
|
154
|
+
*/
|
|
155
|
+
async generateCacheStrategy() {
|
|
156
|
+
const strategy = {
|
|
157
|
+
node_modules: {
|
|
158
|
+
key: 'node-modules-${{ hashFiles("package-lock.json") }}',
|
|
159
|
+
paths: ['node_modules'],
|
|
160
|
+
restore_keys: ['node-modules-'],
|
|
161
|
+
},
|
|
162
|
+
build_artifacts: {
|
|
163
|
+
key: 'build-${{ github.sha }}',
|
|
164
|
+
paths: ['dist', 'build', '.next'],
|
|
165
|
+
restore_keys: [],
|
|
166
|
+
},
|
|
167
|
+
test_cache: {
|
|
168
|
+
key: 'test-cache-${{ github.sha }}',
|
|
169
|
+
paths: ['.jest/cache', '.nyc_output'],
|
|
170
|
+
restore_keys: ['test-cache-'],
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
// Check for specific frameworks and add framework-specific caches
|
|
175
|
+
const packageJson = path.join(this.projectRoot, 'package.json');
|
|
176
|
+
if (fs.existsSync(packageJson)) {
|
|
177
|
+
try {
|
|
178
|
+
const pkg = JSON.parse(fs.readFileSync(packageJson, 'utf8'));
|
|
179
|
+
|
|
180
|
+
if (pkg.dependencies && pkg.dependencies.next) {
|
|
181
|
+
strategy.next_cache = {
|
|
182
|
+
key: 'next-cache-${{ github.sha }}',
|
|
183
|
+
paths: ['.next/cache'],
|
|
184
|
+
restore_keys: [],
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (pkg.devDependencies && pkg.devDependencies.jest) {
|
|
189
|
+
strategy.jest_cache = {
|
|
190
|
+
key: 'jest-${{ hashFiles("jest.config.js") }}',
|
|
191
|
+
paths: ['.jest'],
|
|
192
|
+
restore_keys: ['jest-'],
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
} catch (error) {
|
|
196
|
+
// Ignore package.json parsing errors
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return strategy;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Create parallel execution groups for quality gates
|
|
205
|
+
*/
|
|
206
|
+
async createParallelGroups() {
|
|
207
|
+
const groups = [
|
|
208
|
+
{
|
|
209
|
+
name: 'fast-feedback',
|
|
210
|
+
description: 'Quick checks that provide immediate feedback',
|
|
211
|
+
jobs: ['lint', 'type-check', 'unit-tests-fast'],
|
|
212
|
+
max_parallel: 3,
|
|
213
|
+
timeout: 5,
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
name: 'quality-gates',
|
|
217
|
+
description: 'Comprehensive quality checks',
|
|
218
|
+
jobs: ['coverage', 'mutation', 'security-scan'],
|
|
219
|
+
max_parallel: 2,
|
|
220
|
+
timeout: 15,
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
name: 'integration',
|
|
224
|
+
description: 'Integration and contract testing',
|
|
225
|
+
jobs: ['contract-tests', 'integration-tests', 'accessibility'],
|
|
226
|
+
max_parallel: 1,
|
|
227
|
+
timeout: 20,
|
|
228
|
+
},
|
|
229
|
+
];
|
|
230
|
+
|
|
231
|
+
return groups;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Analyze changed files to determine what tests to run
|
|
236
|
+
*/
|
|
237
|
+
async analyzeChangedFiles(changedFiles = []) {
|
|
238
|
+
const affectedTests = {
|
|
239
|
+
unit: [],
|
|
240
|
+
integration: [],
|
|
241
|
+
contract: [],
|
|
242
|
+
e2e: [],
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
// Simple heuristic - in production, this would use dependency analysis
|
|
246
|
+
for (const file of changedFiles) {
|
|
247
|
+
if (file.includes('src/') || file.includes('lib/')) {
|
|
248
|
+
// Source file changes - run related unit tests
|
|
249
|
+
affectedTests.unit.push(`test-${path.basename(file, path.extname(file))}`);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (file.includes('api/') || file.includes('routes/')) {
|
|
253
|
+
// API changes - run integration tests
|
|
254
|
+
affectedTests.integration.push('api-integration');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (file.includes('.contract.') || file.includes('contracts/')) {
|
|
258
|
+
// Contract changes - run contract tests
|
|
259
|
+
affectedTests.contract.push('contract-validation');
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return affectedTests;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Estimate time savings from optimizations
|
|
268
|
+
*/
|
|
269
|
+
estimateTimeSavings(analysis) {
|
|
270
|
+
const baseTimes = {
|
|
271
|
+
1: 45, // High tier - comprehensive checks
|
|
272
|
+
2: 25, // Medium tier - standard checks
|
|
273
|
+
3: 10, // Low tier - basic checks
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const baseTime = baseTimes[analysis.project_tier] || 25;
|
|
277
|
+
let optimizedTime = baseTime;
|
|
278
|
+
|
|
279
|
+
// Apply optimizations
|
|
280
|
+
if (analysis.recommended_optimizations.some((opt) => opt.type === 'parallel_execution')) {
|
|
281
|
+
optimizedTime *= 0.7; // 30% improvement from parallelization
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (analysis.recommended_optimizations.some((opt) => opt.type === 'smart_caching')) {
|
|
285
|
+
optimizedTime *= 0.85; // 15% improvement from caching
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (analysis.recommended_optimizations.some((opt) => opt.type === 'test_selection')) {
|
|
289
|
+
optimizedTime *= 0.6; // 40% improvement from selective testing
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const savings = {
|
|
293
|
+
original_minutes: baseTime,
|
|
294
|
+
optimized_minutes: Math.round(optimizedTime),
|
|
295
|
+
savings_percent: Math.round((1 - optimizedTime / baseTime) * 100),
|
|
296
|
+
monthly_savings_hours: Math.round((((baseTime - optimizedTime) * 30) / 60) * 10) / 10, // Assuming 30 runs/month
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
return savings;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Generate optimized CI/CD configuration
|
|
304
|
+
*/
|
|
305
|
+
async generateOptimizedConfig(platform = 'github') {
|
|
306
|
+
const analysis = await this.analyzeProject();
|
|
307
|
+
|
|
308
|
+
if (platform === 'github') {
|
|
309
|
+
return this.generateGitHubActionsConfig(analysis);
|
|
310
|
+
} else if (platform === 'gitlab') {
|
|
311
|
+
return this.generateGitLabCIConfig(analysis);
|
|
312
|
+
} else if (platform === 'jenkins') {
|
|
313
|
+
return this.generateJenkinsConfig(analysis);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
throw new Error(`Unsupported CI/CD platform: ${platform}`);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Generate optimized GitHub Actions workflow
|
|
321
|
+
*/
|
|
322
|
+
generateGitHubActionsConfig(analysis) {
|
|
323
|
+
const config = {
|
|
324
|
+
name: 'CAWS Quality Gates',
|
|
325
|
+
on: {
|
|
326
|
+
push: { branches: ['main', 'develop'] },
|
|
327
|
+
pull_request: { branches: ['main'] },
|
|
328
|
+
},
|
|
329
|
+
jobs: {},
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
// Fast feedback job
|
|
333
|
+
config.jobs.fast_feedback = {
|
|
334
|
+
name: 'Fast Feedback',
|
|
335
|
+
'runs-on': 'ubuntu-latest',
|
|
336
|
+
steps: [
|
|
337
|
+
{ uses: 'actions/checkout@v3' },
|
|
338
|
+
{
|
|
339
|
+
name: 'Setup Node.js',
|
|
340
|
+
uses: 'actions/setup-node@v3',
|
|
341
|
+
with: { 'node-version': '18', cache: 'npm' },
|
|
342
|
+
},
|
|
343
|
+
{ run: 'npm ci' },
|
|
344
|
+
{ run: 'npm run lint', continue_on_error: analysis.project_tier === 3 },
|
|
345
|
+
{ run: 'npm run type-check' },
|
|
346
|
+
{
|
|
347
|
+
run: 'npm run test:unit',
|
|
348
|
+
continue_on_error: analysis.project_tier === 3,
|
|
349
|
+
},
|
|
350
|
+
],
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
// Quality gates job (conditional based on tier)
|
|
354
|
+
if (analysis.conditional_execution.coverage_required) {
|
|
355
|
+
config.jobs.quality_gates = {
|
|
356
|
+
name: 'Quality Gates',
|
|
357
|
+
'runs-on': 'ubuntu-latest',
|
|
358
|
+
needs: ['fast_feedback'],
|
|
359
|
+
steps: [
|
|
360
|
+
{ uses: 'actions/checkout@v3' },
|
|
361
|
+
{
|
|
362
|
+
name: 'Setup Node.js',
|
|
363
|
+
uses: 'actions/setup-node@v3',
|
|
364
|
+
with: { 'node-version': '18', cache: 'npm' },
|
|
365
|
+
},
|
|
366
|
+
{ run: 'npm ci' },
|
|
367
|
+
{ run: 'npm run test:coverage' },
|
|
368
|
+
...(analysis.conditional_execution.security_scan
|
|
369
|
+
? [{ run: 'npm run security-scan' }]
|
|
370
|
+
: []),
|
|
371
|
+
...(analysis.conditional_execution.contract_testing
|
|
372
|
+
? [{ run: 'npm run test:contract' }]
|
|
373
|
+
: []),
|
|
374
|
+
],
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Integration tests (only for T1/T2)
|
|
379
|
+
if (analysis.conditional_execution.integration_tests) {
|
|
380
|
+
config.jobs.integration = {
|
|
381
|
+
name: 'Integration Tests',
|
|
382
|
+
'runs-on': 'ubuntu-latest',
|
|
383
|
+
needs: ['quality_gates'],
|
|
384
|
+
steps: [
|
|
385
|
+
{ uses: 'actions/checkout@v3' },
|
|
386
|
+
{
|
|
387
|
+
name: 'Setup Node.js',
|
|
388
|
+
uses: 'actions/setup-node@v3',
|
|
389
|
+
with: { 'node-version': '18', cache: 'npm' },
|
|
390
|
+
},
|
|
391
|
+
{ run: 'npm ci' },
|
|
392
|
+
{ run: 'npm run test:integration' },
|
|
393
|
+
],
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
return config;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Generate GitLab CI configuration
|
|
402
|
+
*/
|
|
403
|
+
generateGitLabCIConfig(analysis) {
|
|
404
|
+
const config = {
|
|
405
|
+
stages: ['fast_feedback', 'quality_gates', 'integration'],
|
|
406
|
+
cache: {
|
|
407
|
+
key: '${CI_COMMIT_REF_SLUG}',
|
|
408
|
+
paths: ['node_modules/', '.cache/'],
|
|
409
|
+
},
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
// Fast feedback job
|
|
413
|
+
config['lint_and_test'] = {
|
|
414
|
+
stage: 'fast_feedback',
|
|
415
|
+
image: 'node:18',
|
|
416
|
+
before_script: ['npm ci'],
|
|
417
|
+
script: ['npm run lint', 'npm run type-check', 'npm run test:unit'],
|
|
418
|
+
allow_failure: analysis.project_tier === 3,
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
// Quality gates
|
|
422
|
+
if (analysis.conditional_execution.coverage_required) {
|
|
423
|
+
config['quality_gates'] = {
|
|
424
|
+
stage: 'quality_gates',
|
|
425
|
+
image: 'node:18',
|
|
426
|
+
before_script: ['npm ci'],
|
|
427
|
+
script: [
|
|
428
|
+
'npm run test:coverage',
|
|
429
|
+
...(analysis.conditional_execution.security_scan ? ['npm run security-scan'] : []),
|
|
430
|
+
...(analysis.conditional_execution.contract_testing ? ['npm run test:contract'] : []),
|
|
431
|
+
],
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
return config;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Generate Jenkins pipeline configuration
|
|
440
|
+
*/
|
|
441
|
+
generateJenkinsConfig(analysis) {
|
|
442
|
+
return `
|
|
443
|
+
pipeline {
|
|
444
|
+
agent any
|
|
445
|
+
|
|
446
|
+
stages {
|
|
447
|
+
stage('Fast Feedback') {
|
|
448
|
+
steps {
|
|
449
|
+
sh 'npm ci'
|
|
450
|
+
sh 'npm run lint'
|
|
451
|
+
sh 'npm run type-check'
|
|
452
|
+
sh 'npm run test:unit'
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
${
|
|
457
|
+
analysis.conditional_execution.coverage_required
|
|
458
|
+
? `
|
|
459
|
+
stage('Quality Gates') {
|
|
460
|
+
steps {
|
|
461
|
+
sh 'npm run test:coverage'
|
|
462
|
+
${analysis.conditional_execution.security_scan ? `sh 'npm run security-scan'` : ''}
|
|
463
|
+
${analysis.conditional_execution.contract_testing ? `sh 'npm run test:contract'` : ''}
|
|
464
|
+
}
|
|
465
|
+
}`
|
|
466
|
+
: ''
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
${
|
|
470
|
+
analysis.conditional_execution.integration_tests
|
|
471
|
+
? `
|
|
472
|
+
stage('Integration Tests') {
|
|
473
|
+
steps {
|
|
474
|
+
sh 'npm run test:integration'
|
|
475
|
+
}
|
|
476
|
+
}`
|
|
477
|
+
: ''
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
post {
|
|
482
|
+
always {
|
|
483
|
+
junit 'test-results/*.xml'
|
|
484
|
+
publishCoverage adapters: [istanbulCoberturaAdapter('coverage/cobertura-coverage.xml')]
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}`;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Create hash for cache invalidation
|
|
492
|
+
*/
|
|
493
|
+
createCacheHash(files) {
|
|
494
|
+
const hasher = crypto.createHash('sha256');
|
|
495
|
+
files.forEach((file) => {
|
|
496
|
+
if (fs.existsSync(file)) {
|
|
497
|
+
hasher.update(fs.readFileSync(file));
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
return hasher.digest('hex').substring(0, 16);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
module.exports = CICDOptimizer;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"burnup.d.ts","sourceRoot":"","sources":["../../src/commands/burnup.js"],"names":[],"mappings":"AAaA;;;GAGG;AACH,wCAFW,MAAM,iBAsEhB"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Burn-up Command Handler
|
|
3
|
+
* Generates budget burn-up reports for scope visibility
|
|
4
|
+
* @author @darianrosebrook
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs-extra');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const yaml = require('js-yaml');
|
|
10
|
+
const chalk = require('chalk');
|
|
11
|
+
|
|
12
|
+
const { deriveBudget, generateBurnupReport } = require('../budget-derivation');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Burn-up command handler
|
|
16
|
+
* @param {string} specFile - Path to spec file
|
|
17
|
+
*/
|
|
18
|
+
async function burnupCommand(specFile) {
|
|
19
|
+
try {
|
|
20
|
+
let specPath = specFile || path.join('.caws', 'working-spec.yaml');
|
|
21
|
+
|
|
22
|
+
if (!fs.existsSync(specPath)) {
|
|
23
|
+
console.error(chalk.red(`ā Spec file not found: ${specPath}`));
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const specContent = fs.readFileSync(specPath, 'utf8');
|
|
28
|
+
const spec = yaml.load(specContent);
|
|
29
|
+
|
|
30
|
+
console.log(chalk.cyan('š Generating CAWS budget burn-up report...'));
|
|
31
|
+
|
|
32
|
+
// Derive budget
|
|
33
|
+
const derivedBudget = deriveBudget(spec, path.dirname(specPath));
|
|
34
|
+
|
|
35
|
+
// Mock current stats - in real implementation this would analyze actual git changes
|
|
36
|
+
const mockStats = {
|
|
37
|
+
files_changed: 50, // This would be calculated from actual changes
|
|
38
|
+
lines_changed: 5000,
|
|
39
|
+
risk_tier: spec.risk_tier,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Generate report
|
|
43
|
+
const report = generateBurnupReport(derivedBudget, mockStats);
|
|
44
|
+
|
|
45
|
+
console.log(report);
|
|
46
|
+
|
|
47
|
+
// Show detailed breakdown
|
|
48
|
+
console.log(chalk.gray('\nš Detailed Budget Analysis:'));
|
|
49
|
+
console.log(
|
|
50
|
+
chalk.gray(
|
|
51
|
+
` Baseline (Tier ${spec.risk_tier}): ${derivedBudget.baseline.max_files} files, ${derivedBudget.baseline.max_loc} LOC`
|
|
52
|
+
)
|
|
53
|
+
);
|
|
54
|
+
console.log(
|
|
55
|
+
chalk.gray(
|
|
56
|
+
` Effective Budget: ${derivedBudget.effective.max_files} files, ${derivedBudget.effective.max_loc} LOC`
|
|
57
|
+
)
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
if (derivedBudget.waivers_applied.length > 0) {
|
|
61
|
+
console.log(chalk.yellow(` Waivers Applied: ${derivedBudget.waivers_applied.join(', ')}`));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
console.log(
|
|
65
|
+
chalk.gray(
|
|
66
|
+
` Current Usage: ${mockStats.files_changed} files, ${mockStats.lines_changed} LOC`
|
|
67
|
+
)
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
const filePercent = Math.round(
|
|
71
|
+
(mockStats.files_changed / derivedBudget.effective.max_files) * 100
|
|
72
|
+
);
|
|
73
|
+
const locPercent = Math.round(
|
|
74
|
+
(mockStats.lines_changed / derivedBudget.effective.max_loc) * 100
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
if (filePercent > 90 || locPercent > 90) {
|
|
78
|
+
console.log(chalk.yellow('\nā ļø WARNING: Approaching budget limits'));
|
|
79
|
+
} else {
|
|
80
|
+
console.log(chalk.green('\nā
Within budget limits'));
|
|
81
|
+
}
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error(chalk.red('ā Error generating burn-up report:'), error.message);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
module.exports = {
|
|
89
|
+
burnupCommand,
|
|
90
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.js"],"names":[],"mappings":"AAoBA;;GAEG;AACH,2EAseC"}
|