codeflow-hook 2.0.1 → 2.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/bin/codeflow-hook.js +1 -1
- package/lib/cli-integration/src/index.ts +111 -6
- package/lib/cli-integration/src/simulationEngine.ts +118 -4
- package/package.json +1 -1
- package/lib/cli-integration/dist/index.d.ts +0 -128
- package/lib/cli-integration/dist/index.js +0 -585
- package/lib/cli-integration/dist/pipelineConfigs.d.ts +0 -60
- package/lib/cli-integration/dist/pipelineConfigs.js +0 -549
- package/lib/cli-integration/dist/simulationEngine.d.ts +0 -86
- package/lib/cli-integration/dist/simulationEngine.js +0 -475
- package/lib/cli-integration/dist/types.d.ts +0 -156
- package/lib/cli-integration/dist/types.js +0 -15
|
@@ -1,475 +0,0 @@
|
|
|
1
|
-
import { StageStatus, SimulationMode } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Advanced Simulation Engine for configurable CI/CD pipelines
|
|
4
|
-
* Provides realistic simulation behaviors with probabilistic outcomes,
|
|
5
|
-
* resource usage simulation, and comprehensive error handling.
|
|
6
|
-
*/
|
|
7
|
-
export class SimulationEngine {
|
|
8
|
-
constructor() {
|
|
9
|
-
this.context = null;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Execute a pipeline configuration with realistic simulation
|
|
13
|
-
*/
|
|
14
|
-
async executePipeline(config) {
|
|
15
|
-
const executionId = this.generateExecutionId();
|
|
16
|
-
const startTime = Date.now();
|
|
17
|
-
this.context = {
|
|
18
|
-
pipelineId: config.id,
|
|
19
|
-
executionId,
|
|
20
|
-
startTime,
|
|
21
|
-
config,
|
|
22
|
-
variables: { ...config.environment },
|
|
23
|
-
artifacts: new Map()
|
|
24
|
-
};
|
|
25
|
-
const logs = [];
|
|
26
|
-
const stageExecutions = [];
|
|
27
|
-
try {
|
|
28
|
-
logs.push(`[${new Date().toISOString()}] 🚀 Starting pipeline: ${config.name} (v${config.version})`);
|
|
29
|
-
logs.push(`[${new Date().toISOString()}] 📋 Execution ID: ${executionId}`);
|
|
30
|
-
logs.push(`[${new Date().toISOString()}] 🎯 Mode: ${config.settings.mode}`);
|
|
31
|
-
// Build dependency graph
|
|
32
|
-
const stages = config.stages || [];
|
|
33
|
-
const dependencyGraph = this.buildDependencyGraph(stages);
|
|
34
|
-
const executionOrder = this.resolveExecutionOrder(dependencyGraph, stages);
|
|
35
|
-
// Execute stages respecting dependencies and concurrency limits
|
|
36
|
-
const results = await this.executeStagesWithDependencies(executionOrder, config, logs);
|
|
37
|
-
stageExecutions.push(...results);
|
|
38
|
-
// Calculate pipeline metrics
|
|
39
|
-
const metrics = this.calculatePipelineMetrics(stageExecutions, config);
|
|
40
|
-
// Determine overall status
|
|
41
|
-
const failedStages = stageExecutions.filter(s => s.status === StageStatus.Failed);
|
|
42
|
-
let status = 'success';
|
|
43
|
-
if (failedStages.length > 0) {
|
|
44
|
-
status = config.settings.failFast ? 'failed' : 'partial';
|
|
45
|
-
}
|
|
46
|
-
const endTime = Date.now();
|
|
47
|
-
logs.push(`[${new Date().toISOString()}] ✅ Pipeline completed in ${(endTime - startTime) / 1000}s`);
|
|
48
|
-
return {
|
|
49
|
-
id: this.generateResultId(),
|
|
50
|
-
pipelineId: config.id,
|
|
51
|
-
executionId,
|
|
52
|
-
startTime: new Date(startTime),
|
|
53
|
-
endTime: new Date(endTime),
|
|
54
|
-
status,
|
|
55
|
-
stages: stageExecutions,
|
|
56
|
-
metrics,
|
|
57
|
-
artifacts: Array.from(this.context.artifacts.values()),
|
|
58
|
-
config,
|
|
59
|
-
logs
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
catch (error) {
|
|
63
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
64
|
-
logs.push(`[${new Date().toISOString()}] ❌ Pipeline failed: ${errorMessage}`);
|
|
65
|
-
return {
|
|
66
|
-
id: this.generateResultId(),
|
|
67
|
-
pipelineId: config.id,
|
|
68
|
-
executionId,
|
|
69
|
-
startTime: new Date(startTime),
|
|
70
|
-
endTime: new Date(),
|
|
71
|
-
status: 'failed',
|
|
72
|
-
stages: stageExecutions,
|
|
73
|
-
metrics: this.calculatePipelineMetrics(stageExecutions, config),
|
|
74
|
-
artifacts: Array.from(this.context.artifacts.values()),
|
|
75
|
-
config,
|
|
76
|
-
logs
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Execute stages respecting dependencies and concurrency limits
|
|
82
|
-
*/
|
|
83
|
-
async executeStagesWithDependencies(executionOrder, config, logs) {
|
|
84
|
-
const results = [];
|
|
85
|
-
const completedStages = new Set();
|
|
86
|
-
const runningStages = new Set();
|
|
87
|
-
for (const level of executionOrder) {
|
|
88
|
-
// Execute stages in this level concurrently, respecting maxConcurrency
|
|
89
|
-
const levelPromises = level
|
|
90
|
-
.filter(stage => this.canExecuteStage(stage, completedStages))
|
|
91
|
-
.slice(0, config.settings.maxConcurrency)
|
|
92
|
-
.map(stage => this.executeStage(stage, config, logs));
|
|
93
|
-
const levelResults = await Promise.all(levelPromises);
|
|
94
|
-
results.push(...levelResults);
|
|
95
|
-
// Update completed stages
|
|
96
|
-
levelResults.forEach(result => {
|
|
97
|
-
if (result.status === StageStatus.Success || result.status === StageStatus.Failed) {
|
|
98
|
-
completedStages.add(result.id);
|
|
99
|
-
}
|
|
100
|
-
runningStages.delete(result.id);
|
|
101
|
-
});
|
|
102
|
-
// Handle fail-fast behavior
|
|
103
|
-
if (config.settings.failFast) {
|
|
104
|
-
const failedInLevel = levelResults.filter((r) => r.status === StageStatus.Failed);
|
|
105
|
-
if (failedInLevel.length > 0) {
|
|
106
|
-
// Mark remaining stages as skipped
|
|
107
|
-
const remainingStages = executionOrder
|
|
108
|
-
.slice(executionOrder.indexOf(level) + 1)
|
|
109
|
-
.flat()
|
|
110
|
-
.filter(stage => !completedStages.has(stage.id));
|
|
111
|
-
for (const stage of remainingStages) {
|
|
112
|
-
results.push({
|
|
113
|
-
id: stage.id,
|
|
114
|
-
status: StageStatus.Skipped,
|
|
115
|
-
logs: [`[${new Date().toISOString()}] ⏭️ Skipped due to previous failure`],
|
|
116
|
-
duration: 0
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
break;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
return results;
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Execute a single stage with realistic simulation
|
|
127
|
-
*/
|
|
128
|
-
async executeStage(stageConfig, pipelineConfig, logs) {
|
|
129
|
-
const startTime = Date.now();
|
|
130
|
-
const stageLogs = [];
|
|
131
|
-
const errors = [];
|
|
132
|
-
stageLogs.push(`[${new Date().toISOString()}] 🎬 Starting stage: ${stageConfig.name}`);
|
|
133
|
-
try {
|
|
134
|
-
// Simulate stage execution based on configuration
|
|
135
|
-
const result = await this.simulateStageExecution(stageConfig, pipelineConfig);
|
|
136
|
-
// Update logs and metrics
|
|
137
|
-
stageLogs.push(...result.logs);
|
|
138
|
-
if (result.errors) {
|
|
139
|
-
errors.push(...result.errors);
|
|
140
|
-
}
|
|
141
|
-
const duration = Date.now() - startTime;
|
|
142
|
-
const status = result.success ? StageStatus.Success : StageStatus.Failed;
|
|
143
|
-
stageLogs.push(`[${new Date().toISOString()}] ${result.success ? '✅' : '❌'} Stage ${stageConfig.name} completed in ${duration}ms`);
|
|
144
|
-
const executionResult = {
|
|
145
|
-
id: stageConfig.id,
|
|
146
|
-
status,
|
|
147
|
-
logs: stageLogs,
|
|
148
|
-
duration,
|
|
149
|
-
metrics: result.metrics
|
|
150
|
-
};
|
|
151
|
-
if (errors.length > 0) {
|
|
152
|
-
executionResult.errors = errors;
|
|
153
|
-
}
|
|
154
|
-
return executionResult;
|
|
155
|
-
}
|
|
156
|
-
catch (error) {
|
|
157
|
-
const duration = Date.now() - startTime;
|
|
158
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
159
|
-
stageLogs.push(`[${new Date().toISOString()}] 💥 Stage ${stageConfig.name} failed: ${errorMessage}`);
|
|
160
|
-
errors.push({
|
|
161
|
-
type: 'execution_error',
|
|
162
|
-
message: errorMessage,
|
|
163
|
-
timestamp: Date.now(),
|
|
164
|
-
recoverable: false,
|
|
165
|
-
context: { stageId: stageConfig.id }
|
|
166
|
-
});
|
|
167
|
-
return {
|
|
168
|
-
id: stageConfig.id,
|
|
169
|
-
status: StageStatus.Failed,
|
|
170
|
-
logs: stageLogs,
|
|
171
|
-
duration,
|
|
172
|
-
errors
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Simulate realistic stage execution with probabilistic outcomes
|
|
178
|
-
*/
|
|
179
|
-
async simulateStageExecution(stageConfig, pipelineConfig) {
|
|
180
|
-
// Calculate realistic duration based on simulation mode
|
|
181
|
-
const duration = this.calculateStageDuration(stageConfig, pipelineConfig);
|
|
182
|
-
// Simulate resource usage
|
|
183
|
-
const metrics = this.simulateResourceUsage(stageConfig, duration);
|
|
184
|
-
// Determine if stage should succeed based on success rate
|
|
185
|
-
const successRoll = Math.random();
|
|
186
|
-
const shouldSucceed = successRoll <= stageConfig.successRate;
|
|
187
|
-
// Simulate the stage behavior
|
|
188
|
-
switch (stageConfig.type) {
|
|
189
|
-
case 'trigger':
|
|
190
|
-
return this.simulateTriggerStage(stageConfig, shouldSucceed, duration, metrics);
|
|
191
|
-
case 'ai-review':
|
|
192
|
-
return this.simulateAiReviewStage(stageConfig, shouldSucceed, duration, metrics);
|
|
193
|
-
case 'docker-build':
|
|
194
|
-
return this.simulateDockerBuildStage(stageConfig, shouldSucceed, duration, metrics);
|
|
195
|
-
case 'unit-tests':
|
|
196
|
-
return this.simulateUnitTestStage(stageConfig, shouldSucceed, duration, metrics);
|
|
197
|
-
case 'deploy':
|
|
198
|
-
return this.simulateDeployStage(stageConfig, shouldSucceed, duration, metrics);
|
|
199
|
-
default:
|
|
200
|
-
return this.simulateGenericStage(stageConfig, shouldSucceed, duration, metrics);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* Calculate realistic stage duration based on configuration and mode
|
|
205
|
-
*/
|
|
206
|
-
calculateStageDuration(stageConfig, pipelineConfig) {
|
|
207
|
-
const { min, max, baseMultiplier } = stageConfig.durationRange;
|
|
208
|
-
// Base duration calculation
|
|
209
|
-
let baseDuration = (min + max) / 2;
|
|
210
|
-
// Apply simulation mode multipliers
|
|
211
|
-
switch (pipelineConfig.settings.mode) {
|
|
212
|
-
case SimulationMode.Fast:
|
|
213
|
-
baseDuration *= 0.3;
|
|
214
|
-
break;
|
|
215
|
-
case SimulationMode.Realistic:
|
|
216
|
-
// Add some randomness
|
|
217
|
-
baseDuration *= (0.8 + Math.random() * 0.4);
|
|
218
|
-
break;
|
|
219
|
-
case SimulationMode.Chaotic:
|
|
220
|
-
// High variability
|
|
221
|
-
baseDuration *= (0.2 + Math.random() * 2.0);
|
|
222
|
-
break;
|
|
223
|
-
case SimulationMode.Deterministic:
|
|
224
|
-
// Consistent timing
|
|
225
|
-
break;
|
|
226
|
-
}
|
|
227
|
-
// Apply base multiplier (could be based on codebase size)
|
|
228
|
-
baseDuration *= baseMultiplier;
|
|
229
|
-
// Ensure within bounds
|
|
230
|
-
return Math.max(min, Math.min(max, baseDuration));
|
|
231
|
-
}
|
|
232
|
-
/**
|
|
233
|
-
* Simulate resource usage for a stage
|
|
234
|
-
*/
|
|
235
|
-
simulateResourceUsage(stageConfig, _duration) {
|
|
236
|
-
// Simulate realistic resource usage patterns
|
|
237
|
-
const baseCpu = 20 + Math.random() * 60; // 20-80% CPU
|
|
238
|
-
const baseMemory = 100 + Math.random() * 400; // 100-500MB
|
|
239
|
-
return {
|
|
240
|
-
cpuUsage: Math.round(baseCpu),
|
|
241
|
-
memoryUsage: Math.round(baseMemory),
|
|
242
|
-
networkIO: Math.round(_duration * (0.1 + Math.random() * 0.9)), // KB/s
|
|
243
|
-
diskIO: Math.round(_duration * (0.05 + Math.random() * 0.15)), // KB/s
|
|
244
|
-
duration: Math.round(_duration),
|
|
245
|
-
success: true // Will be overridden
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
/**
|
|
249
|
-
* Simulate trigger stage (git push detection)
|
|
250
|
-
*/
|
|
251
|
-
simulateTriggerStage(stageConfig, success, duration, metrics) {
|
|
252
|
-
const logs = [];
|
|
253
|
-
if (success) {
|
|
254
|
-
logs.push(`[${new Date().toISOString()}] 📡 Git push detected on branch \`${stageConfig.config.branch || 'main'}\``);
|
|
255
|
-
logs.push(`[${new Date().toISOString()}] 👤 Commit \`${stageConfig.config.commitMessage || 'feat: update codebase'}\` by \`${stageConfig.config.author || 'developer@example.com'}\``);
|
|
256
|
-
logs.push(`[${new Date().toISOString()}] ✅ Workflow triggered successfully`);
|
|
257
|
-
}
|
|
258
|
-
else {
|
|
259
|
-
logs.push(`[${new Date().toISOString()}] ❌ Failed to detect git push - invalid webhook payload`);
|
|
260
|
-
}
|
|
261
|
-
return { success, logs, metrics };
|
|
262
|
-
}
|
|
263
|
-
/**
|
|
264
|
-
* Simulate AI review stage
|
|
265
|
-
*/
|
|
266
|
-
simulateAiReviewStage(_stageConfig, success, _duration, metrics) {
|
|
267
|
-
const logs = [];
|
|
268
|
-
logs.push(`[${new Date().toISOString()}] 🧠 Analyzing code changes...`);
|
|
269
|
-
logs.push(`[${new Date().toISOString()}] 📊 Processing ${_stageConfig.config.fileCount || 5} files`);
|
|
270
|
-
if (success) {
|
|
271
|
-
logs.push(`[${new Date().toISOString()}] ✅ Analysis complete - ${_stageConfig.config.issueCount || 0} issues found`);
|
|
272
|
-
logs.push(`[${new Date().toISOString()}] 📈 Code quality score: ${85 + Math.random() * 10}/100`);
|
|
273
|
-
}
|
|
274
|
-
else {
|
|
275
|
-
logs.push(`[${new Date().toISOString()}] ❌ Analysis failed - API timeout`);
|
|
276
|
-
}
|
|
277
|
-
return { success, logs, metrics };
|
|
278
|
-
}
|
|
279
|
-
/**
|
|
280
|
-
* Simulate Docker build stage
|
|
281
|
-
*/
|
|
282
|
-
simulateDockerBuildStage(stageConfig, success, _duration, metrics) {
|
|
283
|
-
const logs = [];
|
|
284
|
-
logs.push(`[${new Date().toISOString()}] 🐳 Building Docker image \`${stageConfig.config.imageName || 'app:latest'}\``);
|
|
285
|
-
logs.push(`[${new Date().toISOString()}] 📦 Step 1/8 : FROM ${stageConfig.config.baseImage || 'node:18-alpine'}`);
|
|
286
|
-
if (success) {
|
|
287
|
-
logs.push(`[${new Date().toISOString()}] 📦 Step 8/8 : CMD ["npm", "start"]`);
|
|
288
|
-
logs.push(`[${new Date().toISOString()}] ✅ Successfully built ${stageConfig.config.imageId || 'a1b2c3d4e5f6'}`);
|
|
289
|
-
logs.push(`[${new Date().toISOString()}] 🔍 Image size: ${50 + Math.random() * 200}MB`);
|
|
290
|
-
// Create artifact
|
|
291
|
-
if (this.context) {
|
|
292
|
-
this.context.artifacts.set(`${stageConfig.id}-image`, {
|
|
293
|
-
name: `${stageConfig.config.imageName || 'app'}.tar.gz`,
|
|
294
|
-
type: 'docker-image',
|
|
295
|
-
size: Math.round(50 + Math.random() * 200) * 1024 * 1024,
|
|
296
|
-
path: `/artifacts/${stageConfig.id}`,
|
|
297
|
-
metadata: { imageId: stageConfig.config.imageId || 'a1b2c3d4e5f6' }
|
|
298
|
-
});
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
else {
|
|
302
|
-
logs.push(`[${new Date().toISOString()}] ❌ Build failed at step ${Math.floor(Math.random() * 8) + 1}`);
|
|
303
|
-
}
|
|
304
|
-
return { success, logs, metrics };
|
|
305
|
-
}
|
|
306
|
-
/**
|
|
307
|
-
* Simulate unit test stage
|
|
308
|
-
*/
|
|
309
|
-
simulateUnitTestStage(stageConfig, success, _duration, metrics) {
|
|
310
|
-
const logs = [];
|
|
311
|
-
const testCount = stageConfig.config.testCount || 50;
|
|
312
|
-
logs.push(`[${new Date().toISOString()}] 🧪 Running ${testCount} unit tests`);
|
|
313
|
-
if (success) {
|
|
314
|
-
logs.push(`[${new Date().toISOString()}] ✅ Tests passed: ${testCount}/${testCount}`);
|
|
315
|
-
logs.push(`[${new Date().toISOString()}] 📊 Coverage: ${85 + Math.random() * 10}%`);
|
|
316
|
-
}
|
|
317
|
-
else {
|
|
318
|
-
const failed = Math.floor(Math.random() * 5) + 1;
|
|
319
|
-
logs.push(`[${new Date().toISOString()}] ❌ Tests failed: ${failed}/${testCount}`);
|
|
320
|
-
logs.push(`[${new Date().toISOString()}] 🔍 Failed tests: ${Array.from({ length: failed }, (_, i) => `test_${i + 1}`).join(', ')}`);
|
|
321
|
-
}
|
|
322
|
-
return { success, logs, metrics };
|
|
323
|
-
}
|
|
324
|
-
/**
|
|
325
|
-
* Simulate deploy stage
|
|
326
|
-
*/
|
|
327
|
-
simulateDeployStage(stageConfig, success, _duration, metrics) {
|
|
328
|
-
const logs = [];
|
|
329
|
-
logs.push(`[${new Date().toISOString()}] 🚀 Deploying to ${stageConfig.config.environment || 'staging'}`);
|
|
330
|
-
logs.push(`[${new Date().toISOString()}] ☸️ Applying Kubernetes deployment`);
|
|
331
|
-
if (success) {
|
|
332
|
-
logs.push(`[${new Date().toISOString()}] ✅ Deployment successful`);
|
|
333
|
-
logs.push(`[${new Date().toISOString()}] 🌐 Service available at ${stageConfig.config.url || 'https://staging.example.com'}`);
|
|
334
|
-
}
|
|
335
|
-
else {
|
|
336
|
-
logs.push(`[${new Date().toISOString()}] ❌ Deployment failed - pod readiness timeout`);
|
|
337
|
-
}
|
|
338
|
-
return { success, logs, metrics };
|
|
339
|
-
}
|
|
340
|
-
/**
|
|
341
|
-
* Simulate generic stage
|
|
342
|
-
*/
|
|
343
|
-
simulateGenericStage(stageConfig, success, _duration, metrics) {
|
|
344
|
-
const logs = [];
|
|
345
|
-
logs.push(`[${new Date().toISOString()}] 🔧 Executing ${stageConfig.type} stage`);
|
|
346
|
-
if (success) {
|
|
347
|
-
logs.push(`[${new Date().toISOString()}] ✅ Stage completed successfully`);
|
|
348
|
-
}
|
|
349
|
-
else {
|
|
350
|
-
logs.push(`[${new Date().toISOString()}] ❌ Stage failed`);
|
|
351
|
-
}
|
|
352
|
-
return { success, logs, metrics };
|
|
353
|
-
}
|
|
354
|
-
/**
|
|
355
|
-
* Build dependency graph from stage configurations
|
|
356
|
-
*/
|
|
357
|
-
buildDependencyGraph(stages) {
|
|
358
|
-
const graph = new Map();
|
|
359
|
-
for (const stage of stages) {
|
|
360
|
-
graph.set(stage.id, stage.dependencies || []);
|
|
361
|
-
}
|
|
362
|
-
return graph;
|
|
363
|
-
}
|
|
364
|
-
/**
|
|
365
|
-
* Resolve execution order respecting dependencies
|
|
366
|
-
*/
|
|
367
|
-
resolveExecutionOrder(dependencyGraph, stages) {
|
|
368
|
-
const visited = new Set();
|
|
369
|
-
const visiting = new Set();
|
|
370
|
-
const stageMap = new Map();
|
|
371
|
-
// Build stage map for quick lookup
|
|
372
|
-
for (const stage of stages) {
|
|
373
|
-
stageMap.set(stage.id, stage);
|
|
374
|
-
}
|
|
375
|
-
// This is a simplified topological sort - in production you'd want a more robust implementation
|
|
376
|
-
const sorted = [];
|
|
377
|
-
const processStage = (stageId) => {
|
|
378
|
-
if (visited.has(stageId))
|
|
379
|
-
return;
|
|
380
|
-
if (visiting.has(stageId))
|
|
381
|
-
throw new Error(`Circular dependency detected: ${stageId}`);
|
|
382
|
-
visiting.add(stageId);
|
|
383
|
-
const dependencies = dependencyGraph.get(stageId) || [];
|
|
384
|
-
for (const dep of dependencies) {
|
|
385
|
-
processStage(dep);
|
|
386
|
-
}
|
|
387
|
-
visiting.delete(stageId);
|
|
388
|
-
visited.add(stageId);
|
|
389
|
-
sorted.push(stageId);
|
|
390
|
-
};
|
|
391
|
-
// Process all stages
|
|
392
|
-
for (const stageId of Array.from(dependencyGraph.keys())) {
|
|
393
|
-
if (!visited.has(stageId)) {
|
|
394
|
-
processStage(stageId);
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
// Group into levels (simplified - no parallel execution consideration)
|
|
398
|
-
const result = [];
|
|
399
|
-
for (const stageId of sorted) {
|
|
400
|
-
const stage = stageMap.get(stageId);
|
|
401
|
-
if (stage) {
|
|
402
|
-
if (result.length === 0 || this.hasDependencyInPreviousLevel(stage, result[result.length - 1])) {
|
|
403
|
-
result.push([stage]);
|
|
404
|
-
}
|
|
405
|
-
else {
|
|
406
|
-
result[result.length - 1].push(stage);
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
return result;
|
|
411
|
-
}
|
|
412
|
-
/**
|
|
413
|
-
* Check if stage can be executed (all dependencies completed)
|
|
414
|
-
*/
|
|
415
|
-
canExecuteStage(stage, completedStages) {
|
|
416
|
-
return stage.dependencies.every(dep => completedStages.has(dep));
|
|
417
|
-
}
|
|
418
|
-
/**
|
|
419
|
-
* Check if stage has dependencies in the previous level
|
|
420
|
-
*/
|
|
421
|
-
hasDependencyInPreviousLevel(stage, previousLevel) {
|
|
422
|
-
return stage.dependencies.some(dep => previousLevel.some(s => s.id === dep));
|
|
423
|
-
}
|
|
424
|
-
/**
|
|
425
|
-
* Calculate comprehensive pipeline metrics
|
|
426
|
-
*/
|
|
427
|
-
calculatePipelineMetrics(stages, _config) {
|
|
428
|
-
const successful = stages.filter(s => s.status === StageStatus.Success);
|
|
429
|
-
const failed = stages.filter(s => s.status === StageStatus.Failed);
|
|
430
|
-
const skipped = stages.filter(s => s.status === StageStatus.Skipped);
|
|
431
|
-
const totalDuration = stages.reduce((sum, s) => sum + (s.duration || 0), 0);
|
|
432
|
-
const avgStageDuration = stages.length > 0 ? totalDuration / stages.length : 0;
|
|
433
|
-
// Find bottleneck (longest running stage)
|
|
434
|
-
const bottleneck = stages.reduce((max, s) => (s.duration || 0) > (max?.duration || 0) ? s : max);
|
|
435
|
-
// Calculate resource utilization
|
|
436
|
-
const metricsWithData = stages.filter(s => s.metrics);
|
|
437
|
-
const avgCpu = metricsWithData.length > 0
|
|
438
|
-
? metricsWithData.reduce((sum, s) => sum + s.metrics.cpuUsage, 0) / metricsWithData.length
|
|
439
|
-
: 0;
|
|
440
|
-
const avgMemory = metricsWithData.length > 0
|
|
441
|
-
? metricsWithData.reduce((sum, s) => sum + s.metrics.memoryUsage, 0) / metricsWithData.length
|
|
442
|
-
: 0;
|
|
443
|
-
const peakCpu = Math.max(...metricsWithData.map(s => s.metrics.cpuUsage), 0);
|
|
444
|
-
const peakMemory = Math.max(...metricsWithData.map(s => s.metrics.memoryUsage), 0);
|
|
445
|
-
return {
|
|
446
|
-
totalDuration,
|
|
447
|
-
stageCount: stages.length,
|
|
448
|
-
successCount: successful.length,
|
|
449
|
-
failureCount: failed.length,
|
|
450
|
-
skippedCount: skipped.length,
|
|
451
|
-
averageStageDuration: avgStageDuration,
|
|
452
|
-
bottleneckStage: bottleneck?.id,
|
|
453
|
-
resourceUtilization: {
|
|
454
|
-
avgCpu: Math.round(avgCpu),
|
|
455
|
-
avgMemory: Math.round(avgMemory),
|
|
456
|
-
peakCpu,
|
|
457
|
-
peakMemory
|
|
458
|
-
}
|
|
459
|
-
};
|
|
460
|
-
}
|
|
461
|
-
/**
|
|
462
|
-
* Generate unique execution ID
|
|
463
|
-
*/
|
|
464
|
-
generateExecutionId() {
|
|
465
|
-
return `exec_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
466
|
-
}
|
|
467
|
-
/**
|
|
468
|
-
* Generate unique result ID
|
|
469
|
-
*/
|
|
470
|
-
generateResultId() {
|
|
471
|
-
return `result_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
// Export singleton instance
|
|
475
|
-
export const simulationEngine = new SimulationEngine();
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
export declare enum StageStatus {
|
|
2
|
-
Pending = "PENDING",
|
|
3
|
-
Running = "RUNNING",
|
|
4
|
-
Success = "SUCCESS",
|
|
5
|
-
Failed = "FAILED",
|
|
6
|
-
Skipped = "SKIPPED"
|
|
7
|
-
}
|
|
8
|
-
export declare enum SimulationMode {
|
|
9
|
-
Realistic = "REALISTIC",
|
|
10
|
-
Fast = "FAST",
|
|
11
|
-
Deterministic = "DETERMINISTIC",
|
|
12
|
-
Chaotic = "CHAOTIC"
|
|
13
|
-
}
|
|
14
|
-
export interface PipelineStageInfo {
|
|
15
|
-
id: string;
|
|
16
|
-
name: string;
|
|
17
|
-
description: string;
|
|
18
|
-
}
|
|
19
|
-
export interface StageExecution {
|
|
20
|
-
id: string;
|
|
21
|
-
status: StageStatus;
|
|
22
|
-
logs: string[];
|
|
23
|
-
duration?: number;
|
|
24
|
-
metrics?: StageMetrics;
|
|
25
|
-
errors?: ErrorInfo[];
|
|
26
|
-
}
|
|
27
|
-
export interface CodeReviewIssue {
|
|
28
|
-
line: number;
|
|
29
|
-
type: string;
|
|
30
|
-
description: string;
|
|
31
|
-
link?: string;
|
|
32
|
-
}
|
|
33
|
-
export interface CodeReviewFileResult {
|
|
34
|
-
fileName: string;
|
|
35
|
-
status: 'PASS' | 'FAIL';
|
|
36
|
-
score: number;
|
|
37
|
-
issues: CodeReviewIssue[];
|
|
38
|
-
suggestions: string[];
|
|
39
|
-
}
|
|
40
|
-
export interface CodeReviewResult {
|
|
41
|
-
overallStatus: 'PASS' | 'FAIL';
|
|
42
|
-
summary: string;
|
|
43
|
-
files: CodeReviewFileResult[];
|
|
44
|
-
}
|
|
45
|
-
export interface RetryPolicy {
|
|
46
|
-
maxAttempts: number;
|
|
47
|
-
backoffMultiplier: number;
|
|
48
|
-
initialDelay: number;
|
|
49
|
-
}
|
|
50
|
-
export interface StageConfig {
|
|
51
|
-
id: string;
|
|
52
|
-
name: string;
|
|
53
|
-
type: string;
|
|
54
|
-
description: string;
|
|
55
|
-
config: Record<string, any>;
|
|
56
|
-
dependencies: string[];
|
|
57
|
-
timeout: number;
|
|
58
|
-
retryPolicy: RetryPolicy;
|
|
59
|
-
successRate: number;
|
|
60
|
-
durationRange: {
|
|
61
|
-
min: number;
|
|
62
|
-
max: number;
|
|
63
|
-
baseMultiplier: number;
|
|
64
|
-
};
|
|
65
|
-
failureModes: FailureMode[];
|
|
66
|
-
}
|
|
67
|
-
export interface FailureMode {
|
|
68
|
-
type: string;
|
|
69
|
-
probability: number;
|
|
70
|
-
message: string;
|
|
71
|
-
recoverable: boolean;
|
|
72
|
-
recoveryTime?: number;
|
|
73
|
-
}
|
|
74
|
-
export interface PipelineConfig {
|
|
75
|
-
id: string;
|
|
76
|
-
name: string;
|
|
77
|
-
description: string;
|
|
78
|
-
version: string;
|
|
79
|
-
stages: StageConfig[];
|
|
80
|
-
environment: Record<string, any>;
|
|
81
|
-
settings: PipelineSettings;
|
|
82
|
-
metadata: PipelineMetadata;
|
|
83
|
-
}
|
|
84
|
-
export interface PipelineSettings {
|
|
85
|
-
mode: SimulationMode;
|
|
86
|
-
maxConcurrency: number;
|
|
87
|
-
failFast: boolean;
|
|
88
|
-
enableMetrics: boolean;
|
|
89
|
-
enableArtifacts: boolean;
|
|
90
|
-
timeout: number;
|
|
91
|
-
}
|
|
92
|
-
export interface PipelineMetadata {
|
|
93
|
-
author: string;
|
|
94
|
-
created: string;
|
|
95
|
-
updated: string;
|
|
96
|
-
tags: string[];
|
|
97
|
-
category: string;
|
|
98
|
-
}
|
|
99
|
-
export interface StageMetrics {
|
|
100
|
-
cpuUsage: number;
|
|
101
|
-
memoryUsage: number;
|
|
102
|
-
networkIO: number;
|
|
103
|
-
diskIO: number;
|
|
104
|
-
duration: number;
|
|
105
|
-
success: boolean;
|
|
106
|
-
}
|
|
107
|
-
export interface PipelineMetrics {
|
|
108
|
-
totalDuration: number;
|
|
109
|
-
stageCount: number;
|
|
110
|
-
successCount: number;
|
|
111
|
-
failureCount: number;
|
|
112
|
-
skippedCount: number;
|
|
113
|
-
averageStageDuration: number;
|
|
114
|
-
bottleneckStage?: string;
|
|
115
|
-
resourceUtilization: {
|
|
116
|
-
avgCpu: number;
|
|
117
|
-
avgMemory: number;
|
|
118
|
-
peakCpu: number;
|
|
119
|
-
peakMemory: number;
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
export interface ErrorInfo {
|
|
123
|
-
type: string;
|
|
124
|
-
message: string;
|
|
125
|
-
timestamp: number;
|
|
126
|
-
recoverable: boolean;
|
|
127
|
-
context: Record<string, any>;
|
|
128
|
-
}
|
|
129
|
-
export interface SimulationResult {
|
|
130
|
-
id: string;
|
|
131
|
-
pipelineId: string;
|
|
132
|
-
executionId: string;
|
|
133
|
-
startTime: Date;
|
|
134
|
-
endTime: Date;
|
|
135
|
-
status: 'success' | 'failed' | 'partial' | 'cancelled';
|
|
136
|
-
stages: StageExecution[];
|
|
137
|
-
metrics: PipelineMetrics;
|
|
138
|
-
artifacts: ArtifactInfo[];
|
|
139
|
-
config: PipelineConfig;
|
|
140
|
-
logs: string[];
|
|
141
|
-
}
|
|
142
|
-
export interface ArtifactInfo {
|
|
143
|
-
name: string;
|
|
144
|
-
type: string;
|
|
145
|
-
size: number;
|
|
146
|
-
path: string;
|
|
147
|
-
metadata: Record<string, any>;
|
|
148
|
-
}
|
|
149
|
-
export interface SimulationContext {
|
|
150
|
-
pipelineId: string;
|
|
151
|
-
executionId: string;
|
|
152
|
-
startTime: number;
|
|
153
|
-
config: PipelineConfig;
|
|
154
|
-
variables: Record<string, any>;
|
|
155
|
-
artifacts: Map<string, ArtifactInfo>;
|
|
156
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export var StageStatus;
|
|
2
|
-
(function (StageStatus) {
|
|
3
|
-
StageStatus["Pending"] = "PENDING";
|
|
4
|
-
StageStatus["Running"] = "RUNNING";
|
|
5
|
-
StageStatus["Success"] = "SUCCESS";
|
|
6
|
-
StageStatus["Failed"] = "FAILED";
|
|
7
|
-
StageStatus["Skipped"] = "SKIPPED";
|
|
8
|
-
})(StageStatus || (StageStatus = {}));
|
|
9
|
-
export var SimulationMode;
|
|
10
|
-
(function (SimulationMode) {
|
|
11
|
-
SimulationMode["Realistic"] = "REALISTIC";
|
|
12
|
-
SimulationMode["Fast"] = "FAST";
|
|
13
|
-
SimulationMode["Deterministic"] = "DETERMINISTIC";
|
|
14
|
-
SimulationMode["Chaotic"] = "CHAOTIC";
|
|
15
|
-
})(SimulationMode || (SimulationMode = {}));
|