@theholocron/astromech 4.17.1 → 4.17.2
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 +13 -0
- package/dist/index.d.mts +45 -1
- package/dist/index.mjs +105 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -91,6 +91,7 @@ const astromech = createAstromech({ cwd, config, orgContext: { org, domain } });
|
|
|
91
91
|
astromech.thinCallers(); // Map<"<name>.yml", yaml> — one per templated, ci-enabled task
|
|
92
92
|
astromech.packageScripts(); // { holocron: "holocron", lint: "holocron run lint", … }
|
|
93
93
|
astromech.requiredChecks(); // ["Lint / Conclusion", "codecov/patch", …] — branch-protection contexts
|
|
94
|
+
astromech.codecovConfig(existing); // codecov.yml content — merges into `existing`, or scaffolds fresh when null
|
|
94
95
|
astromech.ci({ scope: "required" }); // CiReport — run the gating checks locally, in CI order
|
|
95
96
|
```
|
|
96
97
|
|
|
@@ -122,6 +123,18 @@ only.
|
|
|
122
123
|
`holocron run` itself does not read the config yet — that (and
|
|
123
124
|
`holocron ci`) come in later phases (epic #581).
|
|
124
125
|
|
|
126
|
+
### `codecov.yml`
|
|
127
|
+
|
|
128
|
+
`codecovConfig(existing)` generates this repo's `codecov.yml` — component
|
|
129
|
+
`paths` derived from `packages/*`, same manifest-derived category as
|
|
130
|
+
`thinCallers()`. Pass the current file's content (or `null`) and it either
|
|
131
|
+
merges the `individual_components` list in (preserving everything else in the
|
|
132
|
+
file — thresholds, flags, custom rules) or scaffolds a fresh file from the
|
|
133
|
+
base template. `holocron setup` writes the result via the `source` capability;
|
|
134
|
+
this method never touches the filesystem beyond reading `packages/*` under
|
|
135
|
+
`cwd`. Moved here from `@theholocron/cli` (#650) — the coverage setup tracks
|
|
136
|
+
the `test` task, the same way required checks track `tasks`.
|
|
137
|
+
|
|
125
138
|
## Lint parity
|
|
126
139
|
|
|
127
140
|
One linter list drives both CI and local — no asymmetry. Source: the
|
package/dist/index.d.mts
CHANGED
|
@@ -363,9 +363,53 @@ interface Astromech {
|
|
|
363
363
|
* the list; this method is policy-free (manifest only).
|
|
364
364
|
*/
|
|
365
365
|
requiredChecks(): string[];
|
|
366
|
+
/**
|
|
367
|
+
* This repo's `codecov.yml` — component `paths` derived from `packages/*`.
|
|
368
|
+
* Pass the current file's content (`null` if none exists yet) to either
|
|
369
|
+
* merge the component list in or scaffold a fresh file. Policy-free same
|
|
370
|
+
* as {@link requiredChecks} — `holocron setup` owns writing the result.
|
|
371
|
+
*/
|
|
372
|
+
codecovConfig(existing: string | null): string;
|
|
366
373
|
}
|
|
367
374
|
declare function createAstromech(options: AstromechOptions): Astromech;
|
|
368
375
|
//#endregion
|
|
376
|
+
//#region src/codecov.d.ts
|
|
377
|
+
/**
|
|
378
|
+
* `codecov.yml` generation — a manifest-derived artifact (component `paths`
|
|
379
|
+
* come from workspace packages; the status targets track the `test` task's
|
|
380
|
+
* coverage setup), the same category as the reusable `test.yml` this package
|
|
381
|
+
* also generates. Moved out of `@theholocron/cli` (theholocron/holocron#650)
|
|
382
|
+
* — `holocron setup`'s codecov step now calls {@link codecovConfig} instead
|
|
383
|
+
* of importing this logic directly.
|
|
384
|
+
*/
|
|
385
|
+
interface WorkspacePackage {
|
|
386
|
+
slug: string;
|
|
387
|
+
name: string;
|
|
388
|
+
}
|
|
389
|
+
declare function codecovComponentBlock(packages: WorkspacePackage[]): string;
|
|
390
|
+
/**
|
|
391
|
+
* Ensure every codecov status default carries `if_not_found: success`, so an
|
|
392
|
+
* infra-only PR (dep bump, config, lockfile — no coverable change) passes
|
|
393
|
+
* instead of hanging forever on a required check codecov never posts.
|
|
394
|
+
*
|
|
395
|
+
* Injects the key on the line after each `target:` that sits inside a status
|
|
396
|
+
* block (`coverage.status.*.default` or a `statuses:` list item — indent ≥ 8,
|
|
397
|
+
* or ≥ 8 for a `- type:` list entry), when the immediate sibling lines do not
|
|
398
|
+
* already declare it.
|
|
399
|
+
*/
|
|
400
|
+
declare function ensureIfNotFound(yaml: string): string;
|
|
401
|
+
declare function mergeCodecovComponents(existing: string, packages: WorkspacePackage[]): string;
|
|
402
|
+
/** Every public `packages/*` workspace, sorted by slug. `[]` when there's no `packages/` dir. */
|
|
403
|
+
declare function readWorkspacePackages(repoRoot: string): WorkspacePackage[];
|
|
404
|
+
/** A brand-new `codecov.yml` — the scaffold header + the base template + this repo's component list. */
|
|
405
|
+
declare function createCodecovConfig(packages: WorkspacePackage[]): string;
|
|
406
|
+
/**
|
|
407
|
+
* The full pipeline `holocron setup` needs: read this repo's public
|
|
408
|
+
* `packages/*`, then either merge them into an `existing` `codecov.yml` or
|
|
409
|
+
* scaffold a new one.
|
|
410
|
+
*/
|
|
411
|
+
declare function codecovConfig(repoRoot: string, existing: string | null): string;
|
|
412
|
+
//#endregion
|
|
369
413
|
//#region src/linters.d.ts
|
|
370
414
|
/**
|
|
371
415
|
* The linter registry — one list of linter names (from `config.tasks`'
|
|
@@ -539,4 +583,4 @@ declare const WORKFLOW_TEMPLATE_PROPERTIES: Record<string, string>;
|
|
|
539
583
|
*/
|
|
540
584
|
declare function reusableTemplates(): Map<string, string>;
|
|
541
585
|
//#endregion
|
|
542
|
-
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 };
|
|
586
|
+
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, type WorkspacePackage, baselineSuperLinterEnv, codecovComponentBlock, codecovConfig, createAstromech, createCodecovConfig, deriveDeployPaths, ensureIfNotFound, extractPreviewConfig, generateCombinedDeployContent, generateThinCallerContent, lintThinCallerWith, mergeCodecovComponents, normalizeWorkflowWith, readWorkspacePackages, requiredChecks, resolveLinters, reusableTemplates, runCi, runTask, superLinterConfig };
|
package/dist/index.mjs
CHANGED
|
@@ -931,6 +931,108 @@ function taskName(item) {
|
|
|
931
931
|
return typeof item === "string" ? item : item.name;
|
|
932
932
|
}
|
|
933
933
|
//#endregion
|
|
934
|
+
//#region src/templates/codecov/codecov.yml
|
|
935
|
+
var codecov_default = "codecov:\n require_ci_to_pass: true\n\ncoverage:\n precision: 2\n round: down\n status:\n project:\n default:\n target: auto\n threshold: 2%\n # Infra-only PRs (dep bumps, config, lockfile) touch no coverable code,\n # so codecov produces no report to compare. Pass instead of blocking\n # forever on a required check that will never post.\n if_not_found: success\n patch:\n default:\n target: 80%\n if_not_found: success\n\ncomment:\n layout: \"reach,diff,flags,components\"\n behavior: default\n require_changes: true\n\ncomponent_management:\n default_rules:\n statuses:\n - type: patch\n target: 80%\n if_not_found: success\n individual_components:\n";
|
|
936
|
+
//#endregion
|
|
937
|
+
//#region src/codecov.ts
|
|
938
|
+
/**
|
|
939
|
+
* `codecov.yml` generation — a manifest-derived artifact (component `paths`
|
|
940
|
+
* come from workspace packages; the status targets track the `test` task's
|
|
941
|
+
* coverage setup), the same category as the reusable `test.yml` this package
|
|
942
|
+
* also generates. Moved out of `@theholocron/cli` (theholocron/holocron#650)
|
|
943
|
+
* — `holocron setup`'s codecov step now calls {@link codecovConfig} instead
|
|
944
|
+
* of importing this logic directly.
|
|
945
|
+
*/
|
|
946
|
+
const INDIVIDUAL_COMPONENTS_MARKER = " individual_components:";
|
|
947
|
+
function scaffoldHeader() {
|
|
948
|
+
return [
|
|
949
|
+
`# Scaffolded by holocron setup — edit this file freely.`,
|
|
950
|
+
`# Source: theholocron/holocron · packages/astromech/src/codecov.ts`,
|
|
951
|
+
``
|
|
952
|
+
].join("\n");
|
|
953
|
+
}
|
|
954
|
+
function codecovComponentBlock(packages) {
|
|
955
|
+
if (packages.length === 0) return "\n []\n";
|
|
956
|
+
return "\n" + packages.flatMap(({ slug }) => [
|
|
957
|
+
` - component_id: ${slug}`,
|
|
958
|
+
` name: "${slug}"`,
|
|
959
|
+
` paths:`,
|
|
960
|
+
` - packages/${slug}/**`,
|
|
961
|
+
``
|
|
962
|
+
]).join("\n");
|
|
963
|
+
}
|
|
964
|
+
/**
|
|
965
|
+
* Ensure every codecov status default carries `if_not_found: success`, so an
|
|
966
|
+
* infra-only PR (dep bump, config, lockfile — no coverable change) passes
|
|
967
|
+
* instead of hanging forever on a required check codecov never posts.
|
|
968
|
+
*
|
|
969
|
+
* Injects the key on the line after each `target:` that sits inside a status
|
|
970
|
+
* block (`coverage.status.*.default` or a `statuses:` list item — indent ≥ 8,
|
|
971
|
+
* or ≥ 8 for a `- type:` list entry), when the immediate sibling lines do not
|
|
972
|
+
* already declare it.
|
|
973
|
+
*/
|
|
974
|
+
function ensureIfNotFound(yaml) {
|
|
975
|
+
const lines = yaml.split("\n");
|
|
976
|
+
const out = [];
|
|
977
|
+
for (let i = 0; i < lines.length; i++) {
|
|
978
|
+
const line = lines[i];
|
|
979
|
+
out.push(line);
|
|
980
|
+
const m = /^(\s{8,})target:\s+\S+\s*$/.exec(line);
|
|
981
|
+
if (!m) continue;
|
|
982
|
+
const indent = m[1];
|
|
983
|
+
let alreadySet = false;
|
|
984
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
985
|
+
const sib = lines[j];
|
|
986
|
+
if (sib.trim() === "") continue;
|
|
987
|
+
const sibIndent = sib.match(/^\s*/)[0].length;
|
|
988
|
+
if (sibIndent < indent.length) break;
|
|
989
|
+
if (sibIndent === indent.length && /^\s*if_not_found\s*:/.test(sib)) {
|
|
990
|
+
alreadySet = true;
|
|
991
|
+
break;
|
|
992
|
+
}
|
|
993
|
+
if (sibIndent === indent.length && /^\s*(- |\w)/.test(sib) && !/^\s*(threshold|flags|paths|branches)\s*:/.test(sib)) break;
|
|
994
|
+
}
|
|
995
|
+
if (!alreadySet) out.push(`${indent}if_not_found: success`);
|
|
996
|
+
}
|
|
997
|
+
return out.join("\n");
|
|
998
|
+
}
|
|
999
|
+
function mergeCodecovComponents(existing, packages) {
|
|
1000
|
+
const idx = existing.indexOf(INDIVIDUAL_COMPONENTS_MARKER);
|
|
1001
|
+
if (idx === -1) return ensureIfNotFound(existing);
|
|
1002
|
+
return ensureIfNotFound(existing.slice(0, idx + 24)) + codecovComponentBlock(packages);
|
|
1003
|
+
}
|
|
1004
|
+
/** Every public `packages/*` workspace, sorted by slug. `[]` when there's no `packages/` dir. */
|
|
1005
|
+
function readWorkspacePackages(repoRoot) {
|
|
1006
|
+
const packagesDir = join(repoRoot, "packages");
|
|
1007
|
+
if (!existsSync(packagesDir)) return [];
|
|
1008
|
+
const packages = [];
|
|
1009
|
+
for (const entry of readdirSync(packagesDir, { withFileTypes: true })) {
|
|
1010
|
+
if (!entry.isDirectory()) continue;
|
|
1011
|
+
try {
|
|
1012
|
+
const raw = readFileSync(join(packagesDir, entry.name, "package.json"), "utf8");
|
|
1013
|
+
const pkg = JSON.parse(raw);
|
|
1014
|
+
if (typeof pkg.name === "string") packages.push({
|
|
1015
|
+
slug: entry.name,
|
|
1016
|
+
name: pkg.name
|
|
1017
|
+
});
|
|
1018
|
+
} catch {}
|
|
1019
|
+
}
|
|
1020
|
+
return packages.sort((a, b) => a.slug.localeCompare(b.slug));
|
|
1021
|
+
}
|
|
1022
|
+
/** A brand-new `codecov.yml` — the scaffold header + the base template + this repo's component list. */
|
|
1023
|
+
function createCodecovConfig(packages) {
|
|
1024
|
+
return `${scaffoldHeader()}${codecov_default.trimEnd()}${codecovComponentBlock(packages)}`;
|
|
1025
|
+
}
|
|
1026
|
+
/**
|
|
1027
|
+
* The full pipeline `holocron setup` needs: read this repo's public
|
|
1028
|
+
* `packages/*`, then either merge them into an `existing` `codecov.yml` or
|
|
1029
|
+
* scaffold a new one.
|
|
1030
|
+
*/
|
|
1031
|
+
function codecovConfig(repoRoot, existing) {
|
|
1032
|
+
const packages = readWorkspacePackages(repoRoot);
|
|
1033
|
+
return existing != null ? mergeCodecovComponents(existing, packages) : createCodecovConfig(packages);
|
|
1034
|
+
}
|
|
1035
|
+
//#endregion
|
|
934
1036
|
//#region src/required-checks.ts
|
|
935
1037
|
/**
|
|
936
1038
|
* `requiredChecks(config)` — the branch-protection required-status-check list,
|
|
@@ -1238,8 +1340,9 @@ function createAstromech(options) {
|
|
|
1238
1340
|
rootFiles: rootFiles()
|
|
1239
1341
|
}),
|
|
1240
1342
|
reusableTemplates: () => reusableTemplates(),
|
|
1241
|
-
requiredChecks: () => requiredChecks(options.config ?? {})
|
|
1343
|
+
requiredChecks: () => requiredChecks(options.config ?? {}),
|
|
1344
|
+
codecovConfig: (existing) => codecovConfig(options.cwd, existing)
|
|
1242
1345
|
};
|
|
1243
1346
|
}
|
|
1244
1347
|
//#endregion
|
|
1245
|
-
export { CI_ORDER, KNOWN_TASKS, KNOWN_WORKFLOWS, LINTERS, LINTER_NAMES, REUSABLE_ACTIONS, REUSABLE_WORKFLOWS, TASKS, WORKFLOW_CHECK_CONTEXTS, WORKFLOW_TEMPLATES, WORKFLOW_TEMPLATE_PROPERTIES, baselineSuperLinterEnv, createAstromech, deriveDeployPaths, extractPreviewConfig, generateCombinedDeployContent, generateThinCallerContent, lintThinCallerWith, normalizeWorkflowWith, requiredChecks, resolveLinters, reusableTemplates, runCi, runTask, superLinterConfig };
|
|
1348
|
+
export { CI_ORDER, KNOWN_TASKS, KNOWN_WORKFLOWS, LINTERS, LINTER_NAMES, REUSABLE_ACTIONS, REUSABLE_WORKFLOWS, TASKS, WORKFLOW_CHECK_CONTEXTS, WORKFLOW_TEMPLATES, WORKFLOW_TEMPLATE_PROPERTIES, baselineSuperLinterEnv, codecovComponentBlock, codecovConfig, createAstromech, createCodecovConfig, deriveDeployPaths, ensureIfNotFound, extractPreviewConfig, generateCombinedDeployContent, generateThinCallerContent, lintThinCallerWith, mergeCodecovComponents, normalizeWorkflowWith, readWorkspacePackages, requiredChecks, resolveLinters, reusableTemplates, runCi, runTask, superLinterConfig };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theholocron/astromech",
|
|
3
|
-
"version": "4.17.
|
|
3
|
+
"version": "4.17.2",
|
|
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.17.
|
|
40
|
+
"@theholocron/datapad": "4.17.2"
|
|
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.17.
|
|
56
|
+
"@theholocron/rollup-plugin-transform-template": "4.17.2"
|
|
57
57
|
},
|
|
58
58
|
"engines": {
|
|
59
59
|
"node": ">=22"
|