@bensandee/tooling 0.21.0 → 0.23.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/bin.mjs +86 -155
- package/package.json +5 -3
- package/tooling.schema.json +148 -0
package/dist/bin.mjs
CHANGED
|
@@ -7,9 +7,9 @@ import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, unlinkSync, w
|
|
|
7
7
|
import JSON5 from "json5";
|
|
8
8
|
import { parse } from "jsonc-parser";
|
|
9
9
|
import { z } from "zod";
|
|
10
|
+
import { FatalError, TransientError, UnexpectedError } from "@bensandee/common";
|
|
10
11
|
import { isMap, isScalar, isSeq, parse as parse$1, parseDocument, stringify } from "yaml";
|
|
11
12
|
import { execSync } from "node:child_process";
|
|
12
|
-
import { FatalError, TransientError, UnexpectedError } from "@bensandee/common";
|
|
13
13
|
import { tmpdir } from "node:os";
|
|
14
14
|
//#region src/types.ts
|
|
15
15
|
const LEGACY_TOOLS = [
|
|
@@ -201,7 +201,7 @@ function computeDefaults(targetDir) {
|
|
|
201
201
|
setupVitest: !isMonorepo && !detected.hasVitestConfig,
|
|
202
202
|
ci: detectCiPlatform(targetDir),
|
|
203
203
|
setupRenovate: true,
|
|
204
|
-
releaseStrategy:
|
|
204
|
+
releaseStrategy: "none",
|
|
205
205
|
projectType: isMonorepo ? "default" : detectProjectType(targetDir),
|
|
206
206
|
detectPackageTypes: true
|
|
207
207
|
};
|
|
@@ -493,7 +493,8 @@ const DockerCheckConfigSchema = z.object({
|
|
|
493
493
|
timeoutMs: z.number().int().positive().optional(),
|
|
494
494
|
pollIntervalMs: z.number().int().positive().optional()
|
|
495
495
|
});
|
|
496
|
-
const ToolingConfigSchema = z.
|
|
496
|
+
const ToolingConfigSchema = z.strictObject({
|
|
497
|
+
$schema: z.string().optional(),
|
|
497
498
|
structure: z.enum(["single", "monorepo"]).optional(),
|
|
498
499
|
useEslintPlugin: z.boolean().optional(),
|
|
499
500
|
formatter: z.enum(["oxfmt", "prettier"]).optional(),
|
|
@@ -524,17 +525,14 @@ const ToolingConfigSchema = z.object({
|
|
|
524
525
|
})).optional(),
|
|
525
526
|
dockerCheck: z.union([z.literal(false), DockerCheckConfigSchema]).optional()
|
|
526
527
|
});
|
|
527
|
-
/** Load saved tooling config from the target directory. Returns undefined if missing
|
|
528
|
+
/** Load saved tooling config from the target directory. Returns undefined if missing, throws on invalid. */
|
|
528
529
|
function loadToolingConfig(targetDir) {
|
|
529
530
|
const fullPath = path.join(targetDir, CONFIG_FILE);
|
|
530
531
|
if (!existsSync(fullPath)) return void 0;
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
} catch {
|
|
536
|
-
return;
|
|
537
|
-
}
|
|
532
|
+
const raw = readFileSync(fullPath, "utf-8");
|
|
533
|
+
const result = ToolingConfigSchema.safeParse(JSON.parse(raw));
|
|
534
|
+
if (!result.success) throw new FatalError(`Invalid .tooling.json:\n${result.error.issues.map((i) => ` ${i.path.join(".")}: ${i.message}`).join("\n")}`);
|
|
535
|
+
return result.data;
|
|
538
536
|
}
|
|
539
537
|
/** Config fields that can be overridden in .tooling.json. */
|
|
540
538
|
const OVERRIDE_KEYS = [
|
|
@@ -558,7 +556,7 @@ const MONOREPO_IGNORED_KEYS = new Set(["setupVitest", "projectType"]);
|
|
|
558
556
|
function saveToolingConfig(ctx, config) {
|
|
559
557
|
const defaults = computeDefaults(config.targetDir);
|
|
560
558
|
const isMonorepo = config.structure === "monorepo";
|
|
561
|
-
const overrides = {};
|
|
559
|
+
const overrides = { $schema: "node_modules/@bensandee/tooling/tooling.schema.json" };
|
|
562
560
|
for (const key of OVERRIDE_KEYS) {
|
|
563
561
|
if (isMonorepo && MONOREPO_IGNORED_KEYS.has(key)) continue;
|
|
564
562
|
if (config[key] !== defaults[key]) overrides[key] = config[key];
|
|
@@ -740,34 +738,6 @@ function ensureWorkflowConcurrency(existing, concurrency) {
|
|
|
740
738
|
};
|
|
741
739
|
}
|
|
742
740
|
}
|
|
743
|
-
function addWorkflowJob(existing, jobName, jobConfig) {
|
|
744
|
-
if (isToolingIgnored(existing)) return {
|
|
745
|
-
content: existing,
|
|
746
|
-
changed: false
|
|
747
|
-
};
|
|
748
|
-
try {
|
|
749
|
-
const doc = parseDocument(existing);
|
|
750
|
-
const jobs = doc.getIn(["jobs"]);
|
|
751
|
-
if (!isMap(jobs)) return {
|
|
752
|
-
content: existing,
|
|
753
|
-
changed: false
|
|
754
|
-
};
|
|
755
|
-
if (jobs.has(jobName)) return {
|
|
756
|
-
content: existing,
|
|
757
|
-
changed: false
|
|
758
|
-
};
|
|
759
|
-
jobs.set(jobName, doc.createNode(jobConfig));
|
|
760
|
-
return {
|
|
761
|
-
content: doc.toString(),
|
|
762
|
-
changed: true
|
|
763
|
-
};
|
|
764
|
-
} catch {
|
|
765
|
-
return {
|
|
766
|
-
content: existing,
|
|
767
|
-
changed: false
|
|
768
|
-
};
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
741
|
//#endregion
|
|
772
742
|
//#region src/generators/deploy-ci.ts
|
|
773
743
|
/** Build a GitHub Actions expression like `${{ expr }}` without triggering no-template-curly-in-string. */
|
|
@@ -1011,7 +981,7 @@ function getAddedDevDepNames(config) {
|
|
|
1011
981
|
const deps = { ...ROOT_DEV_DEPS };
|
|
1012
982
|
if (config.structure !== "monorepo") Object.assign(deps, PER_PACKAGE_DEV_DEPS);
|
|
1013
983
|
deps["@bensandee/config"] = "0.8.2";
|
|
1014
|
-
deps["@bensandee/tooling"] = "0.
|
|
984
|
+
deps["@bensandee/tooling"] = "0.23.0";
|
|
1015
985
|
if (config.formatter === "oxfmt") deps["oxfmt"] = "0.35.0";
|
|
1016
986
|
if (config.formatter === "prettier") deps["prettier"] = "3.8.1";
|
|
1017
987
|
addReleaseDeps(deps, config);
|
|
@@ -1036,7 +1006,7 @@ async function generatePackageJson(ctx) {
|
|
|
1036
1006
|
const devDeps = { ...ROOT_DEV_DEPS };
|
|
1037
1007
|
if (!isMonorepo) Object.assign(devDeps, PER_PACKAGE_DEV_DEPS);
|
|
1038
1008
|
devDeps["@bensandee/config"] = isWorkspacePackage(ctx, "@bensandee/config") ? "workspace:*" : "0.8.2";
|
|
1039
|
-
devDeps["@bensandee/tooling"] = isWorkspacePackage(ctx, "@bensandee/tooling") ? "workspace:*" : "0.
|
|
1009
|
+
devDeps["@bensandee/tooling"] = isWorkspacePackage(ctx, "@bensandee/tooling") ? "workspace:*" : "0.23.0";
|
|
1040
1010
|
if (ctx.config.useEslintPlugin) devDeps["@bensandee/eslint-plugin"] = isWorkspacePackage(ctx, "@bensandee/eslint-plugin") ? "workspace:*" : "0.9.2";
|
|
1041
1011
|
if (ctx.config.formatter === "oxfmt") devDeps["oxfmt"] = "0.35.0";
|
|
1042
1012
|
if (ctx.config.formatter === "prettier") devDeps["prettier"] = "3.8.1";
|
|
@@ -1522,25 +1492,26 @@ function actionsExpr$1(expr) {
|
|
|
1522
1492
|
}
|
|
1523
1493
|
const CI_CONCURRENCY = {
|
|
1524
1494
|
group: `ci-${actionsExpr$1("github.ref")}`,
|
|
1525
|
-
"cancel-in-progress":
|
|
1495
|
+
"cancel-in-progress": actionsExpr$1("github.ref != 'refs/heads/main'")
|
|
1526
1496
|
};
|
|
1527
1497
|
function hasEnginesNode$1(ctx) {
|
|
1528
1498
|
const raw = ctx.read("package.json");
|
|
1529
1499
|
if (!raw) return false;
|
|
1530
1500
|
return typeof parsePackageJson(raw)?.engines?.["node"] === "string";
|
|
1531
1501
|
}
|
|
1532
|
-
function ciWorkflow(nodeVersionYaml, isForgejo) {
|
|
1502
|
+
function ciWorkflow(nodeVersionYaml, isForgejo, isChangesets) {
|
|
1533
1503
|
const emailNotifications = isForgejo ? "\nenable-email-notifications: true\n" : "";
|
|
1504
|
+
const concurrencyBlock = isChangesets ? `
|
|
1505
|
+
concurrency:
|
|
1506
|
+
group: ci-${actionsExpr$1("github.ref")}
|
|
1507
|
+
cancel-in-progress: ${actionsExpr$1("github.ref != 'refs/heads/main'")}
|
|
1508
|
+
` : "";
|
|
1534
1509
|
return `${workflowSchemaComment(isForgejo ? "forgejo" : "github")}name: CI
|
|
1535
1510
|
${emailNotifications}on:
|
|
1536
1511
|
push:
|
|
1537
1512
|
branches: [main]
|
|
1538
1513
|
pull_request:
|
|
1539
|
-
|
|
1540
|
-
concurrency:
|
|
1541
|
-
group: ci-${actionsExpr$1("github.ref")}
|
|
1542
|
-
cancel-in-progress: true
|
|
1543
|
-
|
|
1514
|
+
${concurrencyBlock}
|
|
1544
1515
|
jobs:
|
|
1545
1516
|
check:
|
|
1546
1517
|
runs-on: ubuntu-latest
|
|
@@ -1589,6 +1560,10 @@ function requiredCheckSteps(nodeVersionYaml) {
|
|
|
1589
1560
|
}
|
|
1590
1561
|
];
|
|
1591
1562
|
}
|
|
1563
|
+
/** Resolve the CI workflow filename based on release strategy. */
|
|
1564
|
+
function ciWorkflowPath(ci, releaseStrategy) {
|
|
1565
|
+
return `${ci === "github" ? ".github/workflows" : ".forgejo/workflows"}/${releaseStrategy === "changesets" ? "ci.yml" : "check.yml"}`;
|
|
1566
|
+
}
|
|
1592
1567
|
async function generateCi(ctx) {
|
|
1593
1568
|
if (ctx.config.ci === "none") return {
|
|
1594
1569
|
filePath: "ci",
|
|
@@ -1596,16 +1571,23 @@ async function generateCi(ctx) {
|
|
|
1596
1571
|
description: "CI workflow not requested"
|
|
1597
1572
|
};
|
|
1598
1573
|
const isGitHub = ctx.config.ci === "github";
|
|
1574
|
+
const isChangesets = ctx.config.releaseStrategy === "changesets";
|
|
1599
1575
|
const nodeVersionYaml = hasEnginesNode$1(ctx) ? "node-version-file: package.json" : "node-version: \"24\"";
|
|
1600
|
-
const filePath =
|
|
1601
|
-
const content = ciWorkflow(nodeVersionYaml, !isGitHub);
|
|
1576
|
+
const filePath = ciWorkflowPath(ctx.config.ci, ctx.config.releaseStrategy);
|
|
1577
|
+
const content = ciWorkflow(nodeVersionYaml, !isGitHub, isChangesets);
|
|
1602
1578
|
if (ctx.exists(filePath)) {
|
|
1603
1579
|
const existing = ctx.read(filePath);
|
|
1604
1580
|
if (existing) {
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1581
|
+
let result = mergeWorkflowSteps(existing, "check", requiredCheckSteps(nodeVersionYaml));
|
|
1582
|
+
if (isChangesets) {
|
|
1583
|
+
const withConcurrency = ensureWorkflowConcurrency(result.content, CI_CONCURRENCY);
|
|
1584
|
+
result = {
|
|
1585
|
+
content: withConcurrency.content,
|
|
1586
|
+
changed: result.changed || withConcurrency.changed
|
|
1587
|
+
};
|
|
1588
|
+
}
|
|
1589
|
+
const withComment = ensureSchemaComment(result.content, isGitHub ? "github" : "forgejo");
|
|
1590
|
+
if (result.changed || withComment !== result.content) {
|
|
1609
1591
|
ctx.write(filePath, withComment);
|
|
1610
1592
|
return {
|
|
1611
1593
|
filePath,
|
|
@@ -2147,89 +2129,36 @@ jobs:
|
|
|
2147
2129
|
${commonSteps(nodeVersionYaml, publishesNpm)}${gitConfigStep}${releaseStep}
|
|
2148
2130
|
`;
|
|
2149
2131
|
}
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
};
|
|
2157
|
-
if (isGitHub) {
|
|
2158
|
-
const changesetsEnv = {
|
|
2159
|
-
GITHUB_TOKEN: actionsExpr("github.token"),
|
|
2160
|
-
...publishesNpm && { NPM_TOKEN: actionsExpr("secrets.NPM_TOKEN") }
|
|
2161
|
-
};
|
|
2162
|
-
return {
|
|
2163
|
-
needs: "check",
|
|
2132
|
+
/** Build the required release step for the check job (changesets). */
|
|
2133
|
+
function changesetsReleaseStep(ci, publishesNpm) {
|
|
2134
|
+
if (ci === "github") return {
|
|
2135
|
+
match: { uses: "changesets/action" },
|
|
2136
|
+
step: {
|
|
2137
|
+
uses: "changesets/action@v1",
|
|
2164
2138
|
if: "github.ref == 'refs/heads/main'",
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
"
|
|
2139
|
+
with: {
|
|
2140
|
+
publish: "pnpm changeset publish",
|
|
2141
|
+
version: "pnpm changeset version"
|
|
2168
2142
|
},
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
steps: [
|
|
2175
|
-
{
|
|
2176
|
-
uses: "actions/checkout@v4",
|
|
2177
|
-
with: { "fetch-depth": 0 }
|
|
2178
|
-
},
|
|
2179
|
-
{ uses: "pnpm/action-setup@v4" },
|
|
2180
|
-
{
|
|
2181
|
-
uses: "actions/setup-node@v4",
|
|
2182
|
-
with: nodeWith
|
|
2183
|
-
},
|
|
2184
|
-
{ run: "pnpm install --frozen-lockfile" },
|
|
2185
|
-
{ run: "pnpm build" },
|
|
2186
|
-
{
|
|
2187
|
-
uses: "changesets/action@v1",
|
|
2188
|
-
with: {
|
|
2189
|
-
publish: "pnpm changeset publish",
|
|
2190
|
-
version: "pnpm changeset version"
|
|
2191
|
-
},
|
|
2192
|
-
env: changesetsEnv
|
|
2193
|
-
}
|
|
2194
|
-
]
|
|
2195
|
-
};
|
|
2196
|
-
}
|
|
2197
|
-
const releaseEnv = {
|
|
2198
|
-
FORGEJO_SERVER_URL: actionsExpr("github.server_url"),
|
|
2199
|
-
FORGEJO_REPOSITORY: actionsExpr("github.repository"),
|
|
2200
|
-
FORGEJO_TOKEN: actionsExpr("secrets.FORGEJO_TOKEN"),
|
|
2201
|
-
...publishesNpm && { NODE_AUTH_TOKEN: actionsExpr("secrets.NPM_TOKEN") }
|
|
2143
|
+
env: {
|
|
2144
|
+
GITHUB_TOKEN: actionsExpr("github.token"),
|
|
2145
|
+
...publishesNpm && { NPM_TOKEN: actionsExpr("secrets.NPM_TOKEN") }
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2202
2148
|
};
|
|
2203
2149
|
return {
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
uses: "actions/checkout@v4",
|
|
2214
|
-
with: { "fetch-depth": 0 }
|
|
2215
|
-
},
|
|
2216
|
-
{ uses: "pnpm/action-setup@v4" },
|
|
2217
|
-
{
|
|
2218
|
-
uses: "actions/setup-node@v4",
|
|
2219
|
-
with: nodeWith
|
|
2220
|
-
},
|
|
2221
|
-
{ run: "pnpm install --frozen-lockfile" },
|
|
2222
|
-
{ run: "pnpm build" },
|
|
2223
|
-
{
|
|
2224
|
-
name: "Configure git",
|
|
2225
|
-
run: "git config user.name \"forgejo-actions[bot]\"\ngit config user.email \"forgejo-actions[bot]@noreply.localhost\"\n"
|
|
2150
|
+
match: { run: "release:changesets" },
|
|
2151
|
+
step: {
|
|
2152
|
+
name: "Release",
|
|
2153
|
+
if: "github.ref == 'refs/heads/main'",
|
|
2154
|
+
env: {
|
|
2155
|
+
FORGEJO_SERVER_URL: actionsExpr("github.server_url"),
|
|
2156
|
+
FORGEJO_REPOSITORY: actionsExpr("github.repository"),
|
|
2157
|
+
FORGEJO_TOKEN: actionsExpr("secrets.FORGEJO_TOKEN"),
|
|
2158
|
+
...publishesNpm && { NODE_AUTH_TOKEN: actionsExpr("secrets.NPM_TOKEN") }
|
|
2226
2159
|
},
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
env: releaseEnv,
|
|
2230
|
-
run: "pnpm exec tooling release:changesets"
|
|
2231
|
-
}
|
|
2232
|
-
]
|
|
2160
|
+
run: "pnpm exec tooling release:changesets"
|
|
2161
|
+
}
|
|
2233
2162
|
};
|
|
2234
2163
|
}
|
|
2235
2164
|
function requiredReleaseSteps(strategy, nodeVersionYaml, publishesNpm) {
|
|
@@ -2296,36 +2225,25 @@ function buildWorkflow(strategy, ci, nodeVersionYaml, publishesNpm) {
|
|
|
2296
2225
|
}
|
|
2297
2226
|
}
|
|
2298
2227
|
function generateChangesetsReleaseCi(ctx, publishesNpm) {
|
|
2299
|
-
const
|
|
2300
|
-
const
|
|
2301
|
-
const existing = ctx.read(checkPath);
|
|
2228
|
+
const ciPath = ciWorkflowPath(ctx.config.ci, ctx.config.releaseStrategy);
|
|
2229
|
+
const existing = ctx.read(ciPath);
|
|
2302
2230
|
if (!existing) return {
|
|
2303
|
-
filePath:
|
|
2231
|
+
filePath: ciPath,
|
|
2304
2232
|
action: "skipped",
|
|
2305
2233
|
description: "CI workflow not found — run check generator first"
|
|
2306
2234
|
};
|
|
2307
|
-
const
|
|
2308
|
-
if (addResult.changed) {
|
|
2309
|
-
const withComment = ensureSchemaComment(addResult.content, ctx.config.ci);
|
|
2310
|
-
ctx.write(checkPath, withComment);
|
|
2311
|
-
return {
|
|
2312
|
-
filePath: checkPath,
|
|
2313
|
-
action: "updated",
|
|
2314
|
-
description: "Added release job to CI workflow"
|
|
2315
|
-
};
|
|
2316
|
-
}
|
|
2317
|
-
const merged = mergeWorkflowSteps(existing, "release", requiredReleaseSteps("changesets", nodeVersionYaml, publishesNpm));
|
|
2235
|
+
const merged = mergeWorkflowSteps(existing, "check", [changesetsReleaseStep(ctx.config.ci, publishesNpm)]);
|
|
2318
2236
|
if (!merged.changed) return {
|
|
2319
|
-
filePath:
|
|
2237
|
+
filePath: ciPath,
|
|
2320
2238
|
action: "skipped",
|
|
2321
|
-
description: "Release
|
|
2239
|
+
description: "Release step in CI workflow already up to date"
|
|
2322
2240
|
};
|
|
2323
2241
|
const withComment = ensureSchemaComment(merged.content, ctx.config.ci);
|
|
2324
|
-
ctx.write(
|
|
2242
|
+
ctx.write(ciPath, withComment);
|
|
2325
2243
|
return {
|
|
2326
|
-
filePath:
|
|
2244
|
+
filePath: ciPath,
|
|
2327
2245
|
action: "updated",
|
|
2328
|
-
description: "Added
|
|
2246
|
+
description: "Added release step to CI workflow"
|
|
2329
2247
|
};
|
|
2330
2248
|
}
|
|
2331
2249
|
async function generateReleaseCi(ctx) {
|
|
@@ -3614,8 +3532,21 @@ function buildReleaseConfig(flags) {
|
|
|
3614
3532
|
verbose: flags.verbose ?? false
|
|
3615
3533
|
};
|
|
3616
3534
|
}
|
|
3535
|
+
/** Resolve the current branch from CI env vars or git. */
|
|
3536
|
+
function getCurrentBranch(executor, cwd) {
|
|
3537
|
+
const ref = process.env["GITHUB_REF"];
|
|
3538
|
+
if (ref?.startsWith("refs/heads/")) return ref.slice(11);
|
|
3539
|
+
return executor.exec("git rev-parse --abbrev-ref HEAD", { cwd }).stdout.trim();
|
|
3540
|
+
}
|
|
3617
3541
|
/** Core release logic — testable with a mock executor. */
|
|
3618
3542
|
async function runRelease(config, executor) {
|
|
3543
|
+
const branch = getCurrentBranch(executor, config.cwd);
|
|
3544
|
+
if (branch !== "main") {
|
|
3545
|
+
debug$1(config, `Skipping release on non-main branch: ${branch}`);
|
|
3546
|
+
return { mode: "none" };
|
|
3547
|
+
}
|
|
3548
|
+
executor.exec("git config user.name \"forgejo-actions[bot]\"", { cwd: config.cwd });
|
|
3549
|
+
executor.exec("git config user.email \"forgejo-actions[bot]@noreply.localhost\"", { cwd: config.cwd });
|
|
3619
3550
|
const changesetFiles = executor.listChangesetFiles(config.cwd);
|
|
3620
3551
|
debug$1(config, `Changeset files found: ${changesetFiles.length > 0 ? changesetFiles.join(", ") : "(none)"}`);
|
|
3621
3552
|
if (changesetFiles.length > 0) {
|
|
@@ -4656,7 +4587,7 @@ const dockerCheckCommand = defineCommand({
|
|
|
4656
4587
|
const main = defineCommand({
|
|
4657
4588
|
meta: {
|
|
4658
4589
|
name: "tooling",
|
|
4659
|
-
version: "0.
|
|
4590
|
+
version: "0.23.0",
|
|
4660
4591
|
description: "Bootstrap and maintain standardized TypeScript project tooling"
|
|
4661
4592
|
},
|
|
4662
4593
|
subCommands: {
|
|
@@ -4672,7 +4603,7 @@ const main = defineCommand({
|
|
|
4672
4603
|
"docker:check": dockerCheckCommand
|
|
4673
4604
|
}
|
|
4674
4605
|
});
|
|
4675
|
-
console.log(`@bensandee/tooling v0.
|
|
4606
|
+
console.log(`@bensandee/tooling v0.23.0`);
|
|
4676
4607
|
runMain(main);
|
|
4677
4608
|
//#endregion
|
|
4678
4609
|
export {};
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bensandee/tooling",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "CLI tool to bootstrap and maintain standardized TypeScript project tooling",
|
|
5
5
|
"bin": {
|
|
6
6
|
"tooling": "./dist/bin.mjs"
|
|
7
7
|
},
|
|
8
8
|
"files": [
|
|
9
|
-
"dist"
|
|
9
|
+
"dist",
|
|
10
|
+
"tooling.schema.json"
|
|
10
11
|
],
|
|
11
12
|
"type": "module",
|
|
12
13
|
"imports": {
|
|
@@ -22,7 +23,8 @@
|
|
|
22
23
|
"types": "./dist/docker-check/index.d.mts",
|
|
23
24
|
"default": "./dist/docker-check/index.mjs"
|
|
24
25
|
},
|
|
25
|
-
"./package.json": "./package.json"
|
|
26
|
+
"./package.json": "./package.json",
|
|
27
|
+
"./tooling.schema.json": "./tooling.schema.json"
|
|
26
28
|
},
|
|
27
29
|
"publishConfig": {
|
|
28
30
|
"access": "public"
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "@bensandee/tooling configuration",
|
|
4
|
+
"description": "Override convention-detected defaults for repo:sync. Only fields that differ from detected defaults need to be specified.",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"properties": {
|
|
8
|
+
"$schema": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"description": "JSON Schema reference (ignored by tooling)"
|
|
11
|
+
},
|
|
12
|
+
"structure": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"enum": ["single", "monorepo"],
|
|
15
|
+
"description": "Project structure"
|
|
16
|
+
},
|
|
17
|
+
"useEslintPlugin": {
|
|
18
|
+
"type": "boolean",
|
|
19
|
+
"description": "Include @bensandee/eslint-plugin oxlint plugin"
|
|
20
|
+
},
|
|
21
|
+
"formatter": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"enum": ["oxfmt", "prettier"],
|
|
24
|
+
"description": "Formatter choice"
|
|
25
|
+
},
|
|
26
|
+
"setupVitest": {
|
|
27
|
+
"type": "boolean",
|
|
28
|
+
"description": "Generate vitest config and example test"
|
|
29
|
+
},
|
|
30
|
+
"ci": {
|
|
31
|
+
"type": "string",
|
|
32
|
+
"enum": ["github", "forgejo", "none"],
|
|
33
|
+
"description": "CI platform"
|
|
34
|
+
},
|
|
35
|
+
"setupRenovate": {
|
|
36
|
+
"type": "boolean",
|
|
37
|
+
"description": "Generate Renovate config"
|
|
38
|
+
},
|
|
39
|
+
"releaseStrategy": {
|
|
40
|
+
"type": "string",
|
|
41
|
+
"enum": ["release-it", "simple", "changesets", "none"],
|
|
42
|
+
"description": "Release management strategy"
|
|
43
|
+
},
|
|
44
|
+
"projectType": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"enum": ["default", "node", "react", "library"],
|
|
47
|
+
"description": "Project type (determines tsconfig base)"
|
|
48
|
+
},
|
|
49
|
+
"detectPackageTypes": {
|
|
50
|
+
"type": "boolean",
|
|
51
|
+
"description": "Auto-detect project types for monorepo packages"
|
|
52
|
+
},
|
|
53
|
+
"setupDocker": {
|
|
54
|
+
"type": "boolean",
|
|
55
|
+
"description": "Generate Docker build/check scripts"
|
|
56
|
+
},
|
|
57
|
+
"docker": {
|
|
58
|
+
"type": "object",
|
|
59
|
+
"description": "Docker package overrides (package name → config)",
|
|
60
|
+
"additionalProperties": {
|
|
61
|
+
"type": "object",
|
|
62
|
+
"required": ["dockerfile"],
|
|
63
|
+
"properties": {
|
|
64
|
+
"dockerfile": {
|
|
65
|
+
"type": "string",
|
|
66
|
+
"description": "Path to Dockerfile relative to package"
|
|
67
|
+
},
|
|
68
|
+
"context": {
|
|
69
|
+
"type": "string",
|
|
70
|
+
"default": ".",
|
|
71
|
+
"description": "Docker build context relative to package"
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"additionalProperties": false
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"dockerCheck": {
|
|
78
|
+
"oneOf": [
|
|
79
|
+
{
|
|
80
|
+
"const": false,
|
|
81
|
+
"description": "Disable Docker health checks"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"type": "object",
|
|
85
|
+
"additionalProperties": false,
|
|
86
|
+
"properties": {
|
|
87
|
+
"composeFiles": {
|
|
88
|
+
"type": "array",
|
|
89
|
+
"items": { "type": "string" },
|
|
90
|
+
"description": "Compose files to use"
|
|
91
|
+
},
|
|
92
|
+
"envFile": {
|
|
93
|
+
"type": "string",
|
|
94
|
+
"description": "Environment file for compose"
|
|
95
|
+
},
|
|
96
|
+
"services": {
|
|
97
|
+
"type": "array",
|
|
98
|
+
"items": { "type": "string" },
|
|
99
|
+
"description": "Services to check (default: all)"
|
|
100
|
+
},
|
|
101
|
+
"healthChecks": {
|
|
102
|
+
"type": "array",
|
|
103
|
+
"items": {
|
|
104
|
+
"type": "object",
|
|
105
|
+
"required": ["name", "url"],
|
|
106
|
+
"additionalProperties": false,
|
|
107
|
+
"properties": {
|
|
108
|
+
"name": {
|
|
109
|
+
"type": "string",
|
|
110
|
+
"description": "Service name"
|
|
111
|
+
},
|
|
112
|
+
"url": {
|
|
113
|
+
"type": "string",
|
|
114
|
+
"description": "Health check URL"
|
|
115
|
+
},
|
|
116
|
+
"status": {
|
|
117
|
+
"type": "integer",
|
|
118
|
+
"description": "Expected HTTP status code"
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"description": "Health check definitions"
|
|
123
|
+
},
|
|
124
|
+
"buildCommand": {
|
|
125
|
+
"type": "string",
|
|
126
|
+
"description": "Command to build images before checking"
|
|
127
|
+
},
|
|
128
|
+
"buildCwd": {
|
|
129
|
+
"type": "string",
|
|
130
|
+
"description": "Working directory for build command"
|
|
131
|
+
},
|
|
132
|
+
"timeoutMs": {
|
|
133
|
+
"type": "integer",
|
|
134
|
+
"minimum": 1,
|
|
135
|
+
"description": "Overall timeout in milliseconds"
|
|
136
|
+
},
|
|
137
|
+
"pollIntervalMs": {
|
|
138
|
+
"type": "integer",
|
|
139
|
+
"minimum": 1,
|
|
140
|
+
"description": "Poll interval in milliseconds"
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
],
|
|
145
|
+
"description": "Docker health check configuration or false to disable"
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|