scripts-orchestrator 2.4.2 ā 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -0
- package/index.js +33 -4
- package/lib/logger.js +8 -0
- package/lib/orchestrator.js +31 -1
- package/lib/process-manager.js +8 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -165,8 +165,41 @@ The orchestrator doesn't care what the commands do - it just ensures they run (i
|
|
|
165
165
|
|
|
166
166
|
# Or specify a custom config file
|
|
167
167
|
npm run scripts-orchestrator -- ./path/to/your/config.js
|
|
168
|
+
|
|
169
|
+
# Start from a specific phase
|
|
170
|
+
npm run scripts-orchestrator -- --phase "unit tests"
|
|
171
|
+
|
|
172
|
+
# Start from a specific phase with custom config
|
|
173
|
+
npm run scripts-orchestrator -- ./path/to/your/config.js --phase "playwright"
|
|
168
174
|
```
|
|
169
175
|
|
|
176
|
+
### Starting from a Specific Phase
|
|
177
|
+
|
|
178
|
+
You can start the orchestrator from a specific phase instead of running all phases from the beginning. This is useful for debugging or when you want to skip earlier phases that have already been completed.
|
|
179
|
+
|
|
180
|
+
#### Method 1: Command Line Argument
|
|
181
|
+
```bash
|
|
182
|
+
# Start from the "unit tests" phase
|
|
183
|
+
npm run scripts-orchestrator -- --phase "unit tests"
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
#### Method 2: Configuration File
|
|
187
|
+
```javascript
|
|
188
|
+
export default {
|
|
189
|
+
start_phase: "unit tests", // Start from this phase
|
|
190
|
+
phases: [
|
|
191
|
+
// ... your phases
|
|
192
|
+
]
|
|
193
|
+
};
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Note**: Command line arguments take precedence over configuration file settings.
|
|
197
|
+
|
|
198
|
+
When starting from a specific phase:
|
|
199
|
+
- All phases before the specified phase are skipped
|
|
200
|
+
- Commands in skipped phases are marked as "skipped" in the final summary
|
|
201
|
+
- The orchestrator validates that the specified phase exists and shows available phases if not found
|
|
202
|
+
|
|
170
203
|
## Error Handling
|
|
171
204
|
|
|
172
205
|
- The script tracks failed and skipped commands
|
package/index.js
CHANGED
|
@@ -10,13 +10,32 @@ import fs from 'fs';
|
|
|
10
10
|
import { Orchestrator } from './lib/index.js';
|
|
11
11
|
import { log } from './lib/logger.js';
|
|
12
12
|
|
|
13
|
-
//
|
|
14
|
-
const
|
|
13
|
+
// Parse command line arguments
|
|
14
|
+
const args = process.argv.slice(2);
|
|
15
|
+
let configPath = './scripts-orchestrator.config.js';
|
|
16
|
+
let startPhase = null;
|
|
17
|
+
let logFolder = null;
|
|
18
|
+
|
|
19
|
+
// Parse arguments
|
|
20
|
+
for (let i = 0; i < args.length; i++) {
|
|
21
|
+
const arg = args[i];
|
|
22
|
+
|
|
23
|
+
if (arg === '--phase' && i + 1 < args.length) {
|
|
24
|
+
startPhase = args[i + 1];
|
|
25
|
+
i++; // Skip the next argument since we consumed it
|
|
26
|
+
} else if (arg === '--logFolder' && i + 1 < args.length) {
|
|
27
|
+
logFolder = args[i + 1];
|
|
28
|
+
i++; // Skip the next argument since we consumed it
|
|
29
|
+
} else if (!arg.startsWith('--') && !configPath) {
|
|
30
|
+
// First non-flag argument is the config path
|
|
31
|
+
configPath = arg;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
15
34
|
|
|
16
35
|
// Validate config file exists
|
|
17
36
|
if (!fs.existsSync(configPath)) {
|
|
18
37
|
log.error(`Error: Config file not found at ${configPath}`);
|
|
19
|
-
log.error('Usage: scripts-orchestrator [path-to-config-file]');
|
|
38
|
+
log.error('Usage: scripts-orchestrator [path-to-config-file] [--phase <phase-name>] [--logFolder <log-directory>]');
|
|
20
39
|
process.exit(1);
|
|
21
40
|
}
|
|
22
41
|
|
|
@@ -25,8 +44,18 @@ const configFilePath = path.resolve(process.cwd(), configPath);
|
|
|
25
44
|
const fileUrl = new URL(`file://${configFilePath}`).href;
|
|
26
45
|
const commandsConfig = (await import(fileUrl)).default;
|
|
27
46
|
|
|
47
|
+
// Check for start_phase in config if not provided via command line
|
|
48
|
+
if (!startPhase && commandsConfig.start_phase) {
|
|
49
|
+
startPhase = commandsConfig.start_phase;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Check for log_folder in config if not provided via command line
|
|
53
|
+
if (!logFolder && commandsConfig.log_folder) {
|
|
54
|
+
logFolder = commandsConfig.log_folder;
|
|
55
|
+
}
|
|
56
|
+
|
|
28
57
|
// Create and run the orchestrator
|
|
29
|
-
const orchestrator = new Orchestrator(commandsConfig);
|
|
58
|
+
const orchestrator = new Orchestrator(commandsConfig, startPhase, logFolder);
|
|
30
59
|
|
|
31
60
|
// Enhanced signal handlers
|
|
32
61
|
const handleSignal = async (signal) => {
|
package/lib/logger.js
CHANGED
|
@@ -8,6 +8,14 @@ const argv = yargs(hideBin(process.argv))
|
|
|
8
8
|
type: 'boolean',
|
|
9
9
|
description: 'Run with verbose logging',
|
|
10
10
|
})
|
|
11
|
+
.option('phase', {
|
|
12
|
+
type: 'string',
|
|
13
|
+
description: 'Start execution from a specific phase',
|
|
14
|
+
})
|
|
15
|
+
.option('logFolder', {
|
|
16
|
+
type: 'string',
|
|
17
|
+
description: 'Specify the directory for log files',
|
|
18
|
+
})
|
|
11
19
|
.parse();
|
|
12
20
|
|
|
13
21
|
class Logger {
|
package/lib/orchestrator.js
CHANGED
|
@@ -3,8 +3,10 @@ import { healthCheck } from './health-check.js';
|
|
|
3
3
|
import { log } from './logger.js';
|
|
4
4
|
|
|
5
5
|
export class Orchestrator {
|
|
6
|
-
constructor(config) {
|
|
6
|
+
constructor(config, startPhase = null, logFolder = null) {
|
|
7
7
|
this.config = config;
|
|
8
|
+
this.startPhase = startPhase;
|
|
9
|
+
this.logFolder = logFolder;
|
|
8
10
|
this.processManager = processManager;
|
|
9
11
|
this.healthCheck = healthCheck;
|
|
10
12
|
this.logger = log;
|
|
@@ -12,6 +14,11 @@ export class Orchestrator {
|
|
|
12
14
|
this.skippedCommands = [];
|
|
13
15
|
this.commandTimings = new Map();
|
|
14
16
|
|
|
17
|
+
// Set the log folder in process manager
|
|
18
|
+
if (logFolder) {
|
|
19
|
+
this.processManager.setLogFolder(logFolder);
|
|
20
|
+
}
|
|
21
|
+
|
|
15
22
|
// Flatten commands for easier tracking
|
|
16
23
|
this.allCommands = this.flattenCommands(config);
|
|
17
24
|
}
|
|
@@ -226,6 +233,7 @@ export class Orchestrator {
|
|
|
226
233
|
try {
|
|
227
234
|
let hasFailures = false;
|
|
228
235
|
let phaseFailed = false;
|
|
236
|
+
let startPhaseFound = false;
|
|
229
237
|
|
|
230
238
|
// Handle both old array format and new phases format
|
|
231
239
|
if (Array.isArray(this.config)) {
|
|
@@ -238,6 +246,21 @@ export class Orchestrator {
|
|
|
238
246
|
} else if (this.config.phases) {
|
|
239
247
|
// New: Run phases sequentially, commands within phases in parallel
|
|
240
248
|
for (const phase of this.config.phases) {
|
|
249
|
+
// Check if we should start from this phase
|
|
250
|
+
if (this.startPhase && !startPhaseFound) {
|
|
251
|
+
if (phase.name === this.startPhase) {
|
|
252
|
+
startPhaseFound = true;
|
|
253
|
+
this.logger.info(`\nšÆ Starting from phase: ${phase.name}`);
|
|
254
|
+
} else {
|
|
255
|
+
// Mark all commands in previous phases as skipped
|
|
256
|
+
phase.parallel.forEach(({ command }) => {
|
|
257
|
+
this.skippedCommands.push(command);
|
|
258
|
+
this.commandTimings.set(command, 0);
|
|
259
|
+
});
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
241
264
|
if (phaseFailed) {
|
|
242
265
|
// Mark all commands in remaining phases as skipped
|
|
243
266
|
phase.parallel.forEach(({ command }) => {
|
|
@@ -266,6 +289,13 @@ export class Orchestrator {
|
|
|
266
289
|
}
|
|
267
290
|
}
|
|
268
291
|
|
|
292
|
+
// Validate start phase if specified
|
|
293
|
+
if (this.startPhase && !startPhaseFound) {
|
|
294
|
+
const availablePhases = this.config.phases.map(p => p.name).join(', ');
|
|
295
|
+
this.logger.error(`ā Start phase "${this.startPhase}" not found. Available phases: ${availablePhases}`);
|
|
296
|
+
process.exit(1);
|
|
297
|
+
}
|
|
298
|
+
|
|
269
299
|
// Check final status
|
|
270
300
|
hasFailures = hasFailures ||
|
|
271
301
|
this.failedCommands.length > 0 ||
|
package/lib/process-manager.js
CHANGED
|
@@ -10,6 +10,12 @@ export class ProcessManager {
|
|
|
10
10
|
this.logger = log;
|
|
11
11
|
this.backgroundProcesses = [];
|
|
12
12
|
this.backgroundProcessesDetails = [];
|
|
13
|
+
this.logFolder = 'scripts-orchestrator-logs'; // Default log folder
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
setLogFolder(logFolder) {
|
|
17
|
+
this.logFolder = logFolder;
|
|
18
|
+
this.logger.verbose(`Log folder set to: ${logFolder}`);
|
|
13
19
|
}
|
|
14
20
|
|
|
15
21
|
addBackgroundProcess({ command, url, startedByScript, process_tracking, kill_command }) {
|
|
@@ -24,7 +30,8 @@ export class ProcessManager {
|
|
|
24
30
|
}
|
|
25
31
|
|
|
26
32
|
async runCommand({ cmd, logFile, background = false, healthCheck = null, kill_command = null, isRetry = false }) {
|
|
27
|
-
const
|
|
33
|
+
const baseDir = this.logFolder ? path.resolve(this.logFolder) : process.cwd();
|
|
34
|
+
const LOGS_DIR = path.join(baseDir, 'scripts-orchestrator-logs');
|
|
28
35
|
const LOG_FILE = logFile || path.join(LOGS_DIR, `${cmd}.log`);
|
|
29
36
|
|
|
30
37
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "scripts-orchestrator",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.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",
|