feat: CISandbox v1.0.0 — Interactive CI Pipeline Debugger with Local Env Sync
This commit is contained in:
Vendored
+49
@@ -0,0 +1,49 @@
|
||||
import { readFileSync } from 'fs';
|
||||
import { resolve } from 'path';
|
||||
import yaml from 'js-yaml';
|
||||
export function parseWorkflow(filePath) {
|
||||
const fullPath = resolve(filePath);
|
||||
const content = readFileSync(fullPath, 'utf-8');
|
||||
const parsed = yaml.load(content);
|
||||
if (!parsed || typeof parsed !== 'object') {
|
||||
throw new Error(`Invalid YAML in ${filePath}: not an object`);
|
||||
}
|
||||
if (!parsed.jobs || typeof parsed.jobs !== 'object') {
|
||||
throw new Error(`Invalid workflow in ${filePath}: missing 'jobs' field`);
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
export function listJobs(workflow) {
|
||||
return Object.entries(workflow.jobs).map(([name, job]) => ({ name, job }));
|
||||
}
|
||||
export function pickJob(workflow, jobName) {
|
||||
const jobs = listJobs(workflow);
|
||||
if (jobs.length === 0) {
|
||||
throw new Error('Workflow has no jobs');
|
||||
}
|
||||
if (jobName) {
|
||||
const found = jobs.find(j => j.name === jobName);
|
||||
if (!found) {
|
||||
throw new Error(`Job "${jobName}" not found. Available: ${jobs.map(j => j.name).join(', ')}`);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
// Return first job if only one exists
|
||||
if (jobs.length === 1) {
|
||||
return jobs[0];
|
||||
}
|
||||
throw new Error(`Multiple jobs found: ${jobs.map(j => j.name).join(', ')}. Use --job to specify one.`);
|
||||
}
|
||||
export function normalizeRunsOn(runsOn) {
|
||||
const mapping = {
|
||||
'ubuntu-latest': 'node:20-slim',
|
||||
'ubuntu-24.04': 'node:20-slim',
|
||||
'ubuntu-22.04': 'node:20-slim',
|
||||
'ubuntu-20.04': 'node:18-slim',
|
||||
'node-latest': 'node:22-slim',
|
||||
'node-20': 'node:20-slim',
|
||||
'node-18': 'node:18-slim',
|
||||
};
|
||||
return mapping[runsOn] ?? runsOn;
|
||||
}
|
||||
//# sourceMappingURL=parser.js.map
|
||||
Reference in New Issue
Block a user