@theholocron/astromech 4.10.3 → 4.11.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/dist/index.d.mts +43 -11
- package/dist/index.mjs +153 -12
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
import { r as TasksConfig } from "./schema-BegK4MsY.mjs";
|
|
2
2
|
//#region src/run.d.ts
|
|
3
3
|
/**
|
|
4
|
-
* `holocron run <task> [-- <passthrough>]` — run a registry task
|
|
4
|
+
* `holocron run <task> [job] [-- <passthrough>]` — run a registry task (or one
|
|
5
|
+
* of its sub-jobs) locally.
|
|
6
|
+
*
|
|
7
|
+
* A `job` argument only applies to tasks that declare `jobs` (today: `audit`);
|
|
8
|
+
* for any other task it is folded back into the passthrough (`holocron run
|
|
9
|
+
* build src/`). `holocron run audit performance` runs one job; `holocron run
|
|
10
|
+
* audit` runs every job in declared order.
|
|
5
11
|
*
|
|
6
12
|
* Resolution:
|
|
7
13
|
*
|
|
8
|
-
* 0. task === "lint"
|
|
14
|
+
* 0. task === "lint" (no job) → the linter aggregate (see below)
|
|
15
|
+
* J. job given → TASKS[task].jobs[job].local (unknown job → exit 1)
|
|
9
16
|
* 1. turbo.json defines the task → `turbo run <task>`
|
|
10
17
|
* 2. package.json has a `<task>` script → `<pm> run <task>`
|
|
11
18
|
* (unless it's the `holocron run …` thin caller — that recurses)
|
|
12
19
|
* 3. TASKS[task].local resolves → `<tool> <args> <org-flags> <passthrough>`
|
|
13
|
-
* 4. TASKS[task].
|
|
14
|
-
*
|
|
15
|
-
*
|
|
20
|
+
* 4. TASKS[task].jobs has entries → run each job in declared order
|
|
21
|
+
* 5. TASKS[task].local === null → "enforced in CI" (skip, even with --required)
|
|
22
|
+
* 5b. known task, nothing resolved → "no <task> task" (exit 0, or 1 with --required)
|
|
23
|
+
* 6. unknown task → "unknown task" (exit 1)
|
|
16
24
|
*
|
|
17
25
|
* `lint` runs the resolved linter set (`config.tasks` `linters`, else
|
|
18
26
|
* auto-detected): the eslint slot goes through the standard turbo / script /
|
|
@@ -49,6 +57,11 @@ interface RunDeps {
|
|
|
49
57
|
interface RunTaskInput extends RunDeps {
|
|
50
58
|
/** Registry task name, e.g. `"test"`. */
|
|
51
59
|
task: string;
|
|
60
|
+
/**
|
|
61
|
+
* Sub-job within the task, e.g. `"performance"` in `holocron run audit
|
|
62
|
+
* performance`. Ignored (folded into `passthrough`) for tasks with no `jobs`.
|
|
63
|
+
*/
|
|
64
|
+
job?: string;
|
|
52
65
|
/** Directory to run in. */
|
|
53
66
|
cwd: string;
|
|
54
67
|
/** Args after `--` on the command line, forwarded to the tool / turbo / script. */
|
|
@@ -290,6 +303,12 @@ interface AstromechOptions {
|
|
|
290
303
|
lookPath?: (cwd: string, bin: string) => string | null;
|
|
291
304
|
}
|
|
292
305
|
interface RunOptions {
|
|
306
|
+
/**
|
|
307
|
+
* Sub-job within the task — `performance` in `holocron run audit
|
|
308
|
+
* performance`. Only meaningful for tasks that declare `jobs` (`audit`);
|
|
309
|
+
* ignored otherwise. Omit to run every job the task has.
|
|
310
|
+
*/
|
|
311
|
+
job?: string;
|
|
293
312
|
/** Args after `--`, forwarded to the tool / turbo / script. */
|
|
294
313
|
passthrough?: string[];
|
|
295
314
|
/** Print the resolved command without running it. */
|
|
@@ -300,7 +319,7 @@ interface RunOptions {
|
|
|
300
319
|
filter?: string;
|
|
301
320
|
}
|
|
302
321
|
interface Astromech {
|
|
303
|
-
/** Run one task locally. */
|
|
322
|
+
/** Run one task — or one of its sub-jobs (`opts.job`) — locally. */
|
|
304
323
|
run(task: string, opts?: RunOptions): RunTaskReport;
|
|
305
324
|
/**
|
|
306
325
|
* Run the merge-gating checks locally, in CI order — "will CI pass?".
|
|
@@ -439,6 +458,18 @@ interface LocalRunner {
|
|
|
439
458
|
/** The task is already a holocron subcommand (`sync`, `sync-wiki`). */
|
|
440
459
|
command?: string;
|
|
441
460
|
}
|
|
461
|
+
/** One sub-job of a task — `performance` in `holocron run audit performance`. */
|
|
462
|
+
interface JobDef {
|
|
463
|
+
/** How the job runs locally; `null` → no local equivalent (enforced in CI). */
|
|
464
|
+
local: LocalRunner | null;
|
|
465
|
+
/**
|
|
466
|
+
* The CI status-check context this job reports as (`audit / Knip`) — every
|
|
467
|
+
* sub-job is a CI job. `holocron run audit` and `holocron ci` label each job
|
|
468
|
+
* line with it; the task-level `… / Conclusion` context lives in
|
|
469
|
+
* `WORKFLOW_CHECK_CONTEXTS`.
|
|
470
|
+
*/
|
|
471
|
+
checkContext: string;
|
|
472
|
+
}
|
|
442
473
|
interface TaskDef {
|
|
443
474
|
/**
|
|
444
475
|
* `null` — the registry has no built-in runner (CodeQL, deploys, audit's
|
|
@@ -448,10 +479,11 @@ interface TaskDef {
|
|
|
448
479
|
* is `required` (a CI-only check isn't a local one).
|
|
449
480
|
*/
|
|
450
481
|
local: LocalRunner | null;
|
|
451
|
-
/**
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
482
|
+
/**
|
|
483
|
+
* Sub-jobs, keyed by slug — `holocron run audit performance`. Declared order
|
|
484
|
+
* is run order: `holocron run audit` (no job) runs each in turn.
|
|
485
|
+
*/
|
|
486
|
+
jobs?: Record<string, JobDef>;
|
|
455
487
|
/** Org-default flags injected by tool name. Removed by a repo override. */
|
|
456
488
|
flags?: Record<string, string[]>;
|
|
457
489
|
/**
|
|
@@ -503,4 +535,4 @@ declare const WORKFLOW_TEMPLATE_PROPERTIES: Record<string, string>;
|
|
|
503
535
|
*/
|
|
504
536
|
declare function reusableTemplates(): Map<string, string>;
|
|
505
537
|
//#endregion
|
|
506
|
-
export { type Astromech, type AstromechOptions, CI_ORDER, type CiJobReport, type CiOptions, type CiReport, type ExecFn, KNOWN_TASKS, KNOWN_WORKFLOWS, LINTERS, LINTER_NAMES, type LinterDef, type LocalRunner, type OrgContext, type PreviewConfig, REUSABLE_ACTIONS, REUSABLE_WORKFLOWS, type RunLogger, type RunOptions, type RunTaskInput, type RunTaskReport, type SuperLinterConfig, TASKS, type TaskDef, WORKFLOW_CHECK_CONTEXTS, WORKFLOW_TEMPLATES, WORKFLOW_TEMPLATE_PROPERTIES, baselineSuperLinterEnv, createAstromech, deriveDeployPaths, extractPreviewConfig, generateCombinedDeployContent, generateThinCallerContent, lintThinCallerWith, normalizeWorkflowWith, requiredChecks, resolveLinters, reusableTemplates, runCi, runTask, superLinterConfig };
|
|
538
|
+
export { type Astromech, type AstromechOptions, CI_ORDER, type CiJobReport, type CiOptions, type CiReport, type ExecFn, type JobDef, KNOWN_TASKS, KNOWN_WORKFLOWS, LINTERS, LINTER_NAMES, type LinterDef, type LocalRunner, type OrgContext, type PreviewConfig, REUSABLE_ACTIONS, REUSABLE_WORKFLOWS, type RunLogger, type RunOptions, type RunTaskInput, type RunTaskReport, type SuperLinterConfig, TASKS, type TaskDef, WORKFLOW_CHECK_CONTEXTS, WORKFLOW_TEMPLATES, WORKFLOW_TEMPLATE_PROPERTIES, baselineSuperLinterEnv, createAstromech, deriveDeployPaths, extractPreviewConfig, generateCombinedDeployContent, generateThinCallerContent, lintThinCallerWith, normalizeWorkflowWith, requiredChecks, resolveLinters, reusableTemplates, runCi, runTask, superLinterConfig };
|
package/dist/index.mjs
CHANGED
|
@@ -45,7 +45,31 @@ const TASKS = {
|
|
|
45
45
|
] } },
|
|
46
46
|
sync: { local: { command: "sync" } },
|
|
47
47
|
wiki: { local: { command: "sync-wiki" } },
|
|
48
|
-
audit: {
|
|
48
|
+
audit: {
|
|
49
|
+
local: null,
|
|
50
|
+
jobs: {
|
|
51
|
+
"bundle-size": {
|
|
52
|
+
local: null,
|
|
53
|
+
checkContext: "audit / Audit the bundle size"
|
|
54
|
+
},
|
|
55
|
+
knip: {
|
|
56
|
+
local: { tool: "knip" },
|
|
57
|
+
checkContext: "audit / Knip"
|
|
58
|
+
},
|
|
59
|
+
performance: {
|
|
60
|
+
local: { detect: [{
|
|
61
|
+
when: /^lighthouse\.config\.(cjs|js|mjs|ts)$/,
|
|
62
|
+
tool: "lhci",
|
|
63
|
+
args: ["autorun"]
|
|
64
|
+
}, {
|
|
65
|
+
when: /^lighthouserc\.(cjs|js|mjs|json|yml|yaml)$/,
|
|
66
|
+
tool: "lhci",
|
|
67
|
+
args: ["autorun"]
|
|
68
|
+
}] },
|
|
69
|
+
checkContext: "audit / Audit the performance"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
},
|
|
49
73
|
codeql: { local: null },
|
|
50
74
|
deploy: { local: null }
|
|
51
75
|
};
|
|
@@ -197,18 +221,26 @@ function resolveLinters(opts) {
|
|
|
197
221
|
//#endregion
|
|
198
222
|
//#region src/run.ts
|
|
199
223
|
/**
|
|
200
|
-
* `holocron run <task> [-- <passthrough>]` — run a registry task
|
|
224
|
+
* `holocron run <task> [job] [-- <passthrough>]` — run a registry task (or one
|
|
225
|
+
* of its sub-jobs) locally.
|
|
226
|
+
*
|
|
227
|
+
* A `job` argument only applies to tasks that declare `jobs` (today: `audit`);
|
|
228
|
+
* for any other task it is folded back into the passthrough (`holocron run
|
|
229
|
+
* build src/`). `holocron run audit performance` runs one job; `holocron run
|
|
230
|
+
* audit` runs every job in declared order.
|
|
201
231
|
*
|
|
202
232
|
* Resolution:
|
|
203
233
|
*
|
|
204
|
-
* 0. task === "lint"
|
|
234
|
+
* 0. task === "lint" (no job) → the linter aggregate (see below)
|
|
235
|
+
* J. job given → TASKS[task].jobs[job].local (unknown job → exit 1)
|
|
205
236
|
* 1. turbo.json defines the task → `turbo run <task>`
|
|
206
237
|
* 2. package.json has a `<task>` script → `<pm> run <task>`
|
|
207
238
|
* (unless it's the `holocron run …` thin caller — that recurses)
|
|
208
239
|
* 3. TASKS[task].local resolves → `<tool> <args> <org-flags> <passthrough>`
|
|
209
|
-
* 4. TASKS[task].
|
|
210
|
-
*
|
|
211
|
-
*
|
|
240
|
+
* 4. TASKS[task].jobs has entries → run each job in declared order
|
|
241
|
+
* 5. TASKS[task].local === null → "enforced in CI" (skip, even with --required)
|
|
242
|
+
* 5b. known task, nothing resolved → "no <task> task" (exit 0, or 1 with --required)
|
|
243
|
+
* 6. unknown task → "unknown task" (exit 1)
|
|
212
244
|
*
|
|
213
245
|
* `lint` runs the resolved linter set (`config.tasks` `linters`, else
|
|
214
246
|
* auto-detected): the eslint slot goes through the standard turbo / script /
|
|
@@ -252,9 +284,36 @@ function makeRunOne(input) {
|
|
|
252
284
|
}
|
|
253
285
|
function runTask(input) {
|
|
254
286
|
const { print, logger, readFile, fileExists, listDir, task, cwd } = input;
|
|
255
|
-
const
|
|
287
|
+
const def = TASKS[task];
|
|
288
|
+
let job = input.job;
|
|
289
|
+
let passthrough = input.passthrough ?? [];
|
|
290
|
+
if (job !== void 0 && !def?.jobs) {
|
|
291
|
+
passthrough = [job, ...passthrough];
|
|
292
|
+
job = void 0;
|
|
293
|
+
}
|
|
294
|
+
if (job !== void 0) {
|
|
295
|
+
const jobDef = def.jobs[job];
|
|
296
|
+
if (!jobDef) {
|
|
297
|
+
const known = Object.keys(def.jobs).join(", ");
|
|
298
|
+
print(`✗ unknown job "${job}" for "${task}" (known: ${known})`);
|
|
299
|
+
logger.warn({
|
|
300
|
+
task,
|
|
301
|
+
job,
|
|
302
|
+
status: "unknown"
|
|
303
|
+
}, `run: ${task} ${job}`);
|
|
304
|
+
return {
|
|
305
|
+
status: "unknown",
|
|
306
|
+
message: `unknown job "${task} ${job}"`
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
const label = `${task} ${job}`;
|
|
310
|
+
return runUnit(input, label, jobDef.local, makeRunOne({
|
|
311
|
+
...input,
|
|
312
|
+
task: label
|
|
313
|
+
}), passthrough);
|
|
314
|
+
}
|
|
256
315
|
const run = makeRunOne(input);
|
|
257
|
-
if (task === "lint") return runLintAggregate(input);
|
|
316
|
+
if (task === "lint") return runLintAggregate(input, passthrough);
|
|
258
317
|
if (turboDefinesTask(cwd, task, readFile, fileExists)) {
|
|
259
318
|
const args = [
|
|
260
319
|
"run",
|
|
@@ -264,7 +323,6 @@ function runTask(input) {
|
|
|
264
323
|
];
|
|
265
324
|
return run(resolveBin(cwd, "turbo", fileExists), args);
|
|
266
325
|
}
|
|
267
|
-
const def = TASKS[task];
|
|
268
326
|
const script = packageJsonScript(cwd, task, readFile, fileExists);
|
|
269
327
|
if (script && !/^holocron run\b/.test(script.trim())) return run(packageManager(cwd, readFile, fileExists), [
|
|
270
328
|
"run",
|
|
@@ -287,6 +345,7 @@ function runTask(input) {
|
|
|
287
345
|
]);
|
|
288
346
|
}
|
|
289
347
|
}
|
|
348
|
+
if (def?.jobs && Object.keys(def.jobs).length > 0) return runAllJobs(input, def.jobs, passthrough);
|
|
290
349
|
if (def?.local === null) {
|
|
291
350
|
const msg = `no local equivalent for ${task} — enforced in CI`;
|
|
292
351
|
print(`· ${msg}`);
|
|
@@ -322,13 +381,94 @@ function runTask(input) {
|
|
|
322
381
|
};
|
|
323
382
|
}
|
|
324
383
|
/**
|
|
384
|
+
* Run one registry unit — a task's own runner or a single sub-job. Resolution
|
|
385
|
+
* is registry-only (`turbo` / `package.json` scripts are keyed by task, not
|
|
386
|
+
* `task/job`). `label` names the unit in messages (`audit performance`).
|
|
387
|
+
*
|
|
388
|
+
* `local: null` → CI-only by design, always a skip (never a failure, even with
|
|
389
|
+
* `--required`). A declared runner with no matching repo file, or whose tool
|
|
390
|
+
* isn't installed locally → a skip (`--required` turns it into a failure — the
|
|
391
|
+
* repo claims a check it can't back). Mirrors the lint aggregate: run what's
|
|
392
|
+
* here, flag the rest, let CI enforce.
|
|
393
|
+
*/
|
|
394
|
+
function runUnit(input, label, local, run, passthrough) {
|
|
395
|
+
const { print, logger, listDir, lookPath, cwd } = input;
|
|
396
|
+
const skip = (msg) => {
|
|
397
|
+
print(input.required ? `✗ ${msg} (required)` : `· ${msg}`);
|
|
398
|
+
logger[input.required ? "warn" : "debug"]({
|
|
399
|
+
task: label,
|
|
400
|
+
status: input.required ? "fail" : "skip"
|
|
401
|
+
}, `run: ${label}`);
|
|
402
|
+
return {
|
|
403
|
+
status: input.required ? "fail" : "skip",
|
|
404
|
+
message: msg
|
|
405
|
+
};
|
|
406
|
+
};
|
|
407
|
+
if (local) {
|
|
408
|
+
const runner = resolveRunner(local, cwd, listDir);
|
|
409
|
+
if (!runner) return skip(`no ${label} runner for this repo`);
|
|
410
|
+
const found = lookPath(cwd, runner.tool);
|
|
411
|
+
if (!found) return skip(`${runner.tool} not installed locally for ${label} — enforced in CI`);
|
|
412
|
+
return run(found, [...runner.args, ...passthrough]);
|
|
413
|
+
}
|
|
414
|
+
const msg = `no local equivalent for ${label} — enforced in CI`;
|
|
415
|
+
print(`· ${msg}`);
|
|
416
|
+
logger.debug({
|
|
417
|
+
task: label,
|
|
418
|
+
status: "skip"
|
|
419
|
+
}, `run: ${label}`);
|
|
420
|
+
return {
|
|
421
|
+
status: "skip",
|
|
422
|
+
message: msg
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* `holocron run <task>` for a task that is a container of sub-jobs (`audit`) —
|
|
427
|
+
* run each job in declared order. Status precedence: any `fail` → `fail`; else
|
|
428
|
+
* any `ok` → `ok`; else any `dry-run` → `dry-run`; else `skip` (nothing ran).
|
|
429
|
+
*/
|
|
430
|
+
function runAllJobs(input, jobs, passthrough) {
|
|
431
|
+
const { print, task } = input;
|
|
432
|
+
const perJob = {
|
|
433
|
+
...input,
|
|
434
|
+
required: false
|
|
435
|
+
};
|
|
436
|
+
const reports = [];
|
|
437
|
+
for (const [name, jobDef] of Object.entries(jobs)) {
|
|
438
|
+
const label = `${task} ${name}`;
|
|
439
|
+
print(`▶ ${jobDef.checkContext}`);
|
|
440
|
+
reports.push(runUnit(perJob, label, jobDef.local, makeRunOne({
|
|
441
|
+
...perJob,
|
|
442
|
+
task: label
|
|
443
|
+
}), passthrough));
|
|
444
|
+
}
|
|
445
|
+
const command = reports.map((r) => r.command).filter((c) => Boolean(c)).join(" && ");
|
|
446
|
+
const statuses = new Set(reports.map((r) => r.status));
|
|
447
|
+
if (statuses.has("fail")) return {
|
|
448
|
+
status: "fail",
|
|
449
|
+
command,
|
|
450
|
+
message: `one or more ${task} jobs failed`
|
|
451
|
+
};
|
|
452
|
+
if (statuses.has("ok")) return {
|
|
453
|
+
status: "ok",
|
|
454
|
+
command
|
|
455
|
+
};
|
|
456
|
+
if (statuses.has("dry-run")) return {
|
|
457
|
+
status: "dry-run",
|
|
458
|
+
command
|
|
459
|
+
};
|
|
460
|
+
return {
|
|
461
|
+
status: "skip",
|
|
462
|
+
message: `no ${task} job has a local equivalent — enforced in CI`
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
325
466
|
* `holocron run lint` — the resolved linter set, run natively. The eslint
|
|
326
467
|
* slot reuses turbo / the `lint` script / `eslint .`; the rest run their
|
|
327
468
|
* `localBin` when it resolves on PATH. Worst exit code wins.
|
|
328
469
|
*/
|
|
329
|
-
function runLintAggregate(input) {
|
|
470
|
+
function runLintAggregate(input, passthrough) {
|
|
330
471
|
const { print, logger, readFile, fileExists, listDir, lookPath, cwd } = input;
|
|
331
|
-
const passthrough = input.passthrough ?? [];
|
|
332
472
|
const dryRun = input.dryRun ?? false;
|
|
333
473
|
const runOne = makeRunOne(input);
|
|
334
474
|
const pass = passthrough.length ? ["--", ...passthrough] : [];
|
|
@@ -1026,11 +1166,12 @@ function createAstromech(options) {
|
|
|
1026
1166
|
...deps,
|
|
1027
1167
|
task,
|
|
1028
1168
|
cwd: options.cwd,
|
|
1169
|
+
...opts.job !== void 0 ? { job: opts.job } : {},
|
|
1029
1170
|
passthrough: opts.passthrough ?? [],
|
|
1030
1171
|
dryRun: opts.dryRun ?? false,
|
|
1031
1172
|
required: opts.required ?? false,
|
|
1032
1173
|
...opts.filter ? { filter: opts.filter } : {},
|
|
1033
|
-
...task === "lint" ? { linters: lintEntry()?.linters } : {}
|
|
1174
|
+
...task === "lint" && opts.job === void 0 ? { linters: lintEntry()?.linters } : {}
|
|
1034
1175
|
}),
|
|
1035
1176
|
ci: (opts = {}) => runCi({
|
|
1036
1177
|
...deps,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theholocron/astromech",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.11.0",
|
|
4
4
|
"description": "The Holocron task runner — one task manifest drives `holocron run`, `holocron ci`, the CI workflows, package.json scripts, linters, and required checks.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ci",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"dist"
|
|
38
38
|
],
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@theholocron/datapad": "4.
|
|
40
|
+
"@theholocron/datapad": "4.11.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@theholocron/eslint-config": "^8.0.0",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"tsdown": "^0.22.14",
|
|
54
54
|
"typescript": "^5.9.3",
|
|
55
55
|
"vitest": "^4.1.11",
|
|
56
|
-
"@theholocron/rollup-plugin-transform-template": "4.
|
|
56
|
+
"@theholocron/rollup-plugin-transform-template": "4.11.0"
|
|
57
57
|
},
|
|
58
58
|
"engines": {
|
|
59
59
|
"node": ">=22"
|