scripts-orchestrator 2.8.0 ā 2.10.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.
- package/README.md +73 -0
- package/index.js +16 -1
- package/lib/logger.js +13 -0
- package/lib/orchestrator.js +56 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,6 +26,7 @@ npm install --save-dev scripts-orchestrator
|
|
|
26
26
|
## Features
|
|
27
27
|
|
|
28
28
|
- **Parallel Execution**: Runs multiple commands concurrently for faster execution
|
|
29
|
+
- **Sequential Mode**: Option to run all commands sequentially for low CPU machines
|
|
29
30
|
- **Dependency Management**: Handles command dependencies and ensures proper execution order
|
|
30
31
|
- **Background Processes**: Supports running commands in the background with health checks
|
|
31
32
|
- **Retry Mechanism**: Configurable retry attempts for failed commands
|
|
@@ -256,6 +257,15 @@ The orchestrator doesn't care what the commands do - it just ensures they run (i
|
|
|
256
257
|
|
|
257
258
|
# Run with verbose logging
|
|
258
259
|
npm run scripts-orchestrator -- --verbose
|
|
260
|
+
|
|
261
|
+
# Run in sequential mode (for low CPU machines)
|
|
262
|
+
npm run scripts-orchestrator -- --sequential
|
|
263
|
+
|
|
264
|
+
# Specify a custom log folder
|
|
265
|
+
npm run scripts-orchestrator -- --logFolder ./custom-logs
|
|
266
|
+
|
|
267
|
+
# Force execution even if git state is unchanged
|
|
268
|
+
npm run scripts-orchestrator -- --force
|
|
259
269
|
```
|
|
260
270
|
|
|
261
271
|
### Starting from a Specific Phase
|
|
@@ -338,6 +348,29 @@ npm run scripts-orchestrator -- --phases "build,test,optional-e2e,optional-perfo
|
|
|
338
348
|
- The orchestrator validates that all specified phases exist
|
|
339
349
|
- Commands in skipped optional phases are marked as "skipped" in the final summary
|
|
340
350
|
|
|
351
|
+
### Sequential Mode
|
|
352
|
+
|
|
353
|
+
By default, the orchestrator runs commands within each phase in parallel for optimal performance. However, you can use the `--sequential` flag to run all commands sequentially, which is useful for low CPU machines or when you need to reduce resource consumption.
|
|
354
|
+
|
|
355
|
+
#### Usage
|
|
356
|
+
```bash
|
|
357
|
+
# Run all commands sequentially instead of in parallel
|
|
358
|
+
npm run scripts-orchestrator -- --sequential
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
When running in sequential mode:
|
|
362
|
+
- Commands within each phase are executed one at a time
|
|
363
|
+
- Phases still run sequentially (as they always do)
|
|
364
|
+
- If a command fails, the remaining commands in that phase are skipped
|
|
365
|
+
- Lower CPU and memory usage compared to parallel execution
|
|
366
|
+
- Longer total execution time
|
|
367
|
+
|
|
368
|
+
This is particularly useful for:
|
|
369
|
+
- CI/CD environments with limited resources
|
|
370
|
+
- Development machines with low CPU/memory
|
|
371
|
+
- Debugging individual command failures
|
|
372
|
+
- Avoiding resource contention between commands
|
|
373
|
+
|
|
341
374
|
## Error Handling
|
|
342
375
|
|
|
343
376
|
- The script tracks failed and skipped commands
|
|
@@ -348,10 +381,35 @@ npm run scripts-orchestrator -- --phases "build,test,optional-e2e,optional-perfo
|
|
|
348
381
|
## Logging
|
|
349
382
|
|
|
350
383
|
- Each command's output is logged to `scripts-orchestrator-logs/<command>.log` in the current working directory
|
|
384
|
+
- Main orchestrator logs are saved to `scripts-orchestrator-logs/orchestrator-main-<timestamp>.log`
|
|
351
385
|
- Git commit hash is cached in `scripts-orchestrator-logs/.git-hash-cache` for skip detection
|
|
352
386
|
- Provides real-time status updates during execution
|
|
353
387
|
- Summarizes results at the end of execution
|
|
354
388
|
|
|
389
|
+
### Custom Log Folder
|
|
390
|
+
|
|
391
|
+
You can customize the log folder location using either the command line or configuration file:
|
|
392
|
+
|
|
393
|
+
#### Method 1: Command Line Argument
|
|
394
|
+
```bash
|
|
395
|
+
# Use a custom log folder
|
|
396
|
+
npm run scripts-orchestrator -- --logFolder ./my-custom-logs
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
#### Method 2: Configuration File
|
|
400
|
+
```javascript
|
|
401
|
+
export default {
|
|
402
|
+
log_folder: './my-custom-logs', // Custom log folder
|
|
403
|
+
phases: [
|
|
404
|
+
// ... your phases
|
|
405
|
+
]
|
|
406
|
+
};
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
**Note**: Command line arguments take precedence over configuration file settings.
|
|
410
|
+
|
|
411
|
+
All logs (command logs, main orchestrator logs, and git cache) will be stored in the specified folder.
|
|
412
|
+
|
|
355
413
|
## Git-Based Caching
|
|
356
414
|
|
|
357
415
|
The orchestrator automatically tracks the git commit hash and repository state to optimize execution:
|
|
@@ -367,6 +425,21 @@ This feature is particularly useful in CI/CD pipelines where the same commit mig
|
|
|
367
425
|
|
|
368
426
|
**Note**: The cache is only updated on successful execution. Failed runs will not update the cache, ensuring subsequent runs will retry.
|
|
369
427
|
|
|
428
|
+
### Force Execution
|
|
429
|
+
|
|
430
|
+
You can bypass the git cache check and force execution even when the git state is unchanged by using the `--force` flag:
|
|
431
|
+
|
|
432
|
+
```bash
|
|
433
|
+
# Force execution regardless of git state
|
|
434
|
+
npm run scripts-orchestrator -- --force
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
This is useful when you want to:
|
|
438
|
+
- Re-run commands without making code changes
|
|
439
|
+
- Test configuration changes
|
|
440
|
+
- Debug issues without modifying the codebase
|
|
441
|
+
- Override the cache in CI/CD pipelines
|
|
442
|
+
|
|
370
443
|
## Exit Codes
|
|
371
444
|
|
|
372
445
|
- `0`: All commands executed successfully
|
package/index.js
CHANGED
|
@@ -31,6 +31,14 @@ const argv = yargs(hideBin(process.argv))
|
|
|
31
31
|
type: 'string',
|
|
32
32
|
description: 'Specify the directory for log files',
|
|
33
33
|
})
|
|
34
|
+
.option('sequential', {
|
|
35
|
+
type: 'boolean',
|
|
36
|
+
description: 'Run all commands sequentially instead of in parallel (for low CPU machines)',
|
|
37
|
+
})
|
|
38
|
+
.option('force', {
|
|
39
|
+
type: 'boolean',
|
|
40
|
+
description: 'Force execution even if git state is unchanged',
|
|
41
|
+
})
|
|
34
42
|
.help()
|
|
35
43
|
.alias('h', 'help')
|
|
36
44
|
.parse();
|
|
@@ -41,6 +49,8 @@ const configPath = args[0] || './scripts-orchestrator.config.js';
|
|
|
41
49
|
let startPhase = argv.phase;
|
|
42
50
|
let logFolder = argv.logFolder;
|
|
43
51
|
const phases = argv.phases ? argv.phases.split(',').map(p => p.trim()) : null;
|
|
52
|
+
const sequential = argv.sequential || false;
|
|
53
|
+
const force = argv.force || false;
|
|
44
54
|
|
|
45
55
|
// Validate config file exists
|
|
46
56
|
if (!fs.existsSync(configPath)) {
|
|
@@ -64,8 +74,13 @@ if (!logFolder && commandsConfig.log_folder) {
|
|
|
64
74
|
logFolder = commandsConfig.log_folder;
|
|
65
75
|
}
|
|
66
76
|
|
|
77
|
+
// Set the log folder for the main orchestrator logs if specified
|
|
78
|
+
if (logFolder) {
|
|
79
|
+
log.setLogFolder(logFolder);
|
|
80
|
+
}
|
|
81
|
+
|
|
67
82
|
// Create and run the orchestrator
|
|
68
|
-
const orchestrator = new Orchestrator(commandsConfig, startPhase, logFolder, phases);
|
|
83
|
+
const orchestrator = new Orchestrator(commandsConfig, startPhase, logFolder, phases, sequential, force);
|
|
69
84
|
|
|
70
85
|
// Enhanced signal handlers
|
|
71
86
|
const handleSignal = async (signal) => {
|
package/lib/logger.js
CHANGED
|
@@ -66,6 +66,19 @@ class Logger {
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
setLogFolder(newLogFolder) {
|
|
70
|
+
// Close existing stream if it exists
|
|
71
|
+
if (this.logStream) {
|
|
72
|
+
this.logStream.end();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Update log folder
|
|
76
|
+
this.logFolder = newLogFolder;
|
|
77
|
+
|
|
78
|
+
// Reinitialize with new folder
|
|
79
|
+
this.initializeLogFile();
|
|
80
|
+
}
|
|
81
|
+
|
|
69
82
|
writeToFile(message) {
|
|
70
83
|
if (this.logStream) {
|
|
71
84
|
// Strip ANSI color codes for file output
|
package/lib/orchestrator.js
CHANGED
|
@@ -4,11 +4,13 @@ import { log } from './logger.js';
|
|
|
4
4
|
import { GitCache } from './git-cache.js';
|
|
5
5
|
|
|
6
6
|
export class Orchestrator {
|
|
7
|
-
constructor(config, startPhase = null, logFolder = null, phases = null) {
|
|
7
|
+
constructor(config, startPhase = null, logFolder = null, phases = null, sequential = false, force = false) {
|
|
8
8
|
this.config = config;
|
|
9
9
|
this.startPhase = startPhase;
|
|
10
10
|
this.logFolder = logFolder;
|
|
11
11
|
this.phases = phases;
|
|
12
|
+
this.sequential = sequential;
|
|
13
|
+
this.force = force;
|
|
12
14
|
this.processManager = processManager;
|
|
13
15
|
this.healthCheck = healthCheck;
|
|
14
16
|
this.logger = log;
|
|
@@ -239,11 +241,16 @@ export class Orchestrator {
|
|
|
239
241
|
|
|
240
242
|
async run() {
|
|
241
243
|
try {
|
|
242
|
-
// Check if we should skip execution based on git state
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
244
|
+
// Check if we should skip execution based on git state (unless forced)
|
|
245
|
+
if (!this.force) {
|
|
246
|
+
const shouldSkip = await this.gitCache.shouldSkipExecution();
|
|
247
|
+
if (shouldSkip) {
|
|
248
|
+
this.logger.success('š No changes detected, skipping execution!');
|
|
249
|
+
this.logger.info('š” To force execution, use: --force');
|
|
250
|
+
process.exit(0);
|
|
251
|
+
}
|
|
252
|
+
} else {
|
|
253
|
+
this.logger.info('ā” Force execution enabled, skipping git cache check');
|
|
247
254
|
}
|
|
248
255
|
|
|
249
256
|
let hasFailures = false;
|
|
@@ -252,14 +259,31 @@ export class Orchestrator {
|
|
|
252
259
|
|
|
253
260
|
// Handle both old array format and new phases format
|
|
254
261
|
if (Array.isArray(this.config)) {
|
|
255
|
-
// Legacy: Run all commands in parallel
|
|
256
|
-
|
|
257
|
-
this.
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
262
|
+
// Legacy: Run all commands in parallel or sequential based on flag
|
|
263
|
+
if (this.sequential) {
|
|
264
|
+
this.logger.info('š Running in sequential mode');
|
|
265
|
+
const results = [];
|
|
266
|
+
for (const commandConfig of this.config) {
|
|
267
|
+
const result = await this.executeCommand(commandConfig);
|
|
268
|
+
results.push(result);
|
|
269
|
+
if (!result) {
|
|
270
|
+
hasFailures = true;
|
|
271
|
+
break; // Stop on first failure in sequential mode
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
} else {
|
|
275
|
+
const tasks = this.config.map((commandConfig) =>
|
|
276
|
+
this.executeCommand(commandConfig),
|
|
277
|
+
);
|
|
278
|
+
const results = await Promise.all(tasks);
|
|
279
|
+
hasFailures = results.some(result => !result);
|
|
280
|
+
}
|
|
261
281
|
} else if (this.config.phases) {
|
|
262
|
-
// New: Run phases sequentially, commands within phases in parallel
|
|
282
|
+
// New: Run phases sequentially, commands within phases in parallel or sequential based on flag
|
|
283
|
+
if (this.sequential) {
|
|
284
|
+
this.logger.info('š Running in sequential mode');
|
|
285
|
+
}
|
|
286
|
+
|
|
263
287
|
for (const phase of this.config.phases) {
|
|
264
288
|
// Check if we should start from this phase
|
|
265
289
|
if (this.startPhase && !startPhaseFound) {
|
|
@@ -298,11 +322,26 @@ export class Orchestrator {
|
|
|
298
322
|
|
|
299
323
|
this.logger.info(`\nš Starting phase: ${phase.name}`);
|
|
300
324
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
325
|
+
let results;
|
|
326
|
+
if (this.sequential) {
|
|
327
|
+
// Run commands sequentially
|
|
328
|
+
results = [];
|
|
329
|
+
for (const commandConfig of phase.parallel) {
|
|
330
|
+
const result = await this.executeCommand(commandConfig);
|
|
331
|
+
results.push(result);
|
|
332
|
+
if (!result) {
|
|
333
|
+
// In sequential mode, stop phase execution on first failure
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
} else {
|
|
338
|
+
// Run commands in parallel
|
|
339
|
+
const tasks = phase.parallel.map((commandConfig) =>
|
|
340
|
+
this.executeCommand(commandConfig),
|
|
341
|
+
);
|
|
342
|
+
results = await Promise.all(tasks);
|
|
343
|
+
}
|
|
304
344
|
|
|
305
|
-
const results = await Promise.all(tasks);
|
|
306
345
|
const phaseHasFailures = results.some(result => !result);
|
|
307
346
|
|
|
308
347
|
if (phaseHasFailures) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "scripts-orchestrator",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.0",
|
|
4
4
|
"description": "A powerful script orchestrator for running parallel commands with dependency management, background processes, and health checks",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"type": "module",
|