@bensandee/tooling 0.32.0 → 0.33.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 +36 -8
- package/dist/bin.mjs +75 -19
- package/dist/{check-DMDdHanG.mjs → check-B2AAPCBO.mjs} +18 -10
- package/dist/docker-check/index.mjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -63,11 +63,37 @@ The generated `ci:check` script defaults to `pnpm check --skip 'docker:*'` since
|
|
|
63
63
|
| Command | Description |
|
|
64
64
|
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
|
65
65
|
| `tooling release:changesets` | Changesets version/publish for Forgejo CI. Flag: `--dry-run`. Env: `FORGEJO_SERVER_URL`, `FORGEJO_REPOSITORY`, `RELEASE_TOKEN`. |
|
|
66
|
-
| `tooling release:simple` | Streamlined release using commit-and-tag-version.
|
|
66
|
+
| `tooling release:simple` | Streamlined release using commit-and-tag-version. Flags: `--release-as`, `--first-release`, `--prerelease`. |
|
|
67
67
|
| `tooling release:trigger` | Trigger a release workflow. |
|
|
68
68
|
| `tooling forgejo:create-release` | Create a Forgejo release from a tag. |
|
|
69
69
|
| `tooling changesets:merge` | Merge a changesets version PR. |
|
|
70
70
|
|
|
71
|
+
#### `release:simple`
|
|
72
|
+
|
|
73
|
+
Uses `commit-and-tag-version` under the hood. Version bumps are auto-detected from [Conventional Commits](https://www.conventionalcommits.org/):
|
|
74
|
+
|
|
75
|
+
| Commit prefix | Bump | Example |
|
|
76
|
+
| ----------------------- | ----- | ------------------------------------ |
|
|
77
|
+
| `fix:` | patch | `fix: handle null response` |
|
|
78
|
+
| `feat:` | minor | `feat: add retry logic` |
|
|
79
|
+
| `feat!:` / `fix!:` etc | major | `feat!: drop v1 API` |
|
|
80
|
+
| `BREAKING CHANGE:` body | major | Any type with breaking change footer |
|
|
81
|
+
|
|
82
|
+
Override auto-detection with CLI flags:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# Force a major bump
|
|
86
|
+
tooling release:simple --release-as major
|
|
87
|
+
|
|
88
|
+
# Force a specific version
|
|
89
|
+
tooling release:simple --release-as 2.0.0
|
|
90
|
+
|
|
91
|
+
# Create a prerelease
|
|
92
|
+
tooling release:simple --release-as major --prerelease beta # → 2.0.0-beta.0
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The generated release workflow exposes these as optional `workflow_dispatch` inputs (`bump` and `prerelease`), so bumps can also be controlled from the CI UI.
|
|
96
|
+
|
|
71
97
|
### Docker
|
|
72
98
|
|
|
73
99
|
| Command | Description |
|
|
@@ -133,14 +159,16 @@ Each package is tagged independently using its own version, so packages in a mon
|
|
|
133
159
|
|
|
134
160
|
**Flags:** `--dry-run` (build and tag only, skip login/push/logout)
|
|
135
161
|
|
|
136
|
-
**Required
|
|
162
|
+
**Required CI variables:**
|
|
163
|
+
|
|
164
|
+
| Variable | Type | Description |
|
|
165
|
+
| --------------------------- | -------- | --------------------------------------------------------------------- |
|
|
166
|
+
| `DOCKER_REGISTRY_HOST` | variable | Registry hostname (e.g. `code.orangebikelabs.com`) |
|
|
167
|
+
| `DOCKER_REGISTRY_NAMESPACE` | variable | Full namespace for tagging (e.g. `code.orangebikelabs.com/bensandee`) |
|
|
168
|
+
| `DOCKER_USERNAME` | secret | Registry username |
|
|
169
|
+
| `DOCKER_PASSWORD` | secret | Registry password |
|
|
137
170
|
|
|
138
|
-
|
|
139
|
-
| --------------------------- | --------------------------------------------------------------------- |
|
|
140
|
-
| `DOCKER_REGISTRY_HOST` | Registry hostname (e.g. `code.orangebikelabs.com`) |
|
|
141
|
-
| `DOCKER_REGISTRY_NAMESPACE` | Full namespace for tagging (e.g. `code.orangebikelabs.com/bensandee`) |
|
|
142
|
-
| `DOCKER_USERNAME` | Registry username |
|
|
143
|
-
| `DOCKER_PASSWORD` | Registry password |
|
|
171
|
+
**Forgejo setup:** On Forgejo, `DOCKER_USERNAME` is your Forgejo account username, and `DOCKER_PASSWORD` can reuse the same token as `RELEASE_TOKEN`. The token needs write permissions on the org, package, and repository scopes. These permissions should be set for the **user** if the package is under a user namespace (e.g. `bensandee`), or the **organization** if it's under an org namespace (e.g. `orangebikelabs`).
|
|
144
172
|
|
|
145
173
|
## Config file
|
|
146
174
|
|
package/dist/bin.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { l as createRealExecutor$1, t as runDockerCheck, u as isExecSyncError } from "./check-
|
|
2
|
+
import { l as createRealExecutor$1, t as runDockerCheck, u as isExecSyncError } from "./check-B2AAPCBO.mjs";
|
|
3
3
|
import { defineCommand, runMain } from "citty";
|
|
4
4
|
import * as clack from "@clack/prompts";
|
|
5
5
|
import { isCancel, select } from "@clack/prompts";
|
|
@@ -1590,7 +1590,7 @@ function getAddedDevDepNames(config) {
|
|
|
1590
1590
|
const deps = { ...ROOT_DEV_DEPS };
|
|
1591
1591
|
if (config.structure !== "monorepo") Object.assign(deps, PER_PACKAGE_DEV_DEPS);
|
|
1592
1592
|
deps["@bensandee/config"] = "0.9.1";
|
|
1593
|
-
deps["@bensandee/tooling"] = "0.
|
|
1593
|
+
deps["@bensandee/tooling"] = "0.33.0";
|
|
1594
1594
|
if (config.formatter === "oxfmt") deps["oxfmt"] = {
|
|
1595
1595
|
"@changesets/cli": "2.30.0",
|
|
1596
1596
|
"@release-it/bumper": "7.0.5",
|
|
@@ -1645,7 +1645,7 @@ async function generatePackageJson(ctx) {
|
|
|
1645
1645
|
const devDeps = { ...ROOT_DEV_DEPS };
|
|
1646
1646
|
if (!isMonorepo) Object.assign(devDeps, PER_PACKAGE_DEV_DEPS);
|
|
1647
1647
|
devDeps["@bensandee/config"] = isWorkspacePackage(ctx, "@bensandee/config") ? "workspace:*" : "0.9.1";
|
|
1648
|
-
devDeps["@bensandee/tooling"] = isWorkspacePackage(ctx, "@bensandee/tooling") ? "workspace:*" : "0.
|
|
1648
|
+
devDeps["@bensandee/tooling"] = isWorkspacePackage(ctx, "@bensandee/tooling") ? "workspace:*" : "0.33.0";
|
|
1649
1649
|
if (ctx.config.useEslintPlugin) devDeps["@bensandee/eslint-plugin"] = isWorkspacePackage(ctx, "@bensandee/eslint-plugin") ? "workspace:*" : "0.9.2";
|
|
1650
1650
|
if (ctx.config.formatter === "oxfmt") devDeps["oxfmt"] = {
|
|
1651
1651
|
"@changesets/cli": "2.30.0",
|
|
@@ -2804,6 +2804,41 @@ function releaseItSteps(ci, nodeVersionYaml, publishesNpm) {
|
|
|
2804
2804
|
}
|
|
2805
2805
|
}];
|
|
2806
2806
|
}
|
|
2807
|
+
/** Build the workflow_dispatch trigger with optional inputs for the simple strategy. */
|
|
2808
|
+
function simpleWorkflowDispatchTrigger() {
|
|
2809
|
+
return { workflow_dispatch: { inputs: {
|
|
2810
|
+
bump: {
|
|
2811
|
+
description: "Version bump type (default: conventional-commits auto-detect)",
|
|
2812
|
+
required: false,
|
|
2813
|
+
type: "choice",
|
|
2814
|
+
default: "auto",
|
|
2815
|
+
options: [
|
|
2816
|
+
"auto",
|
|
2817
|
+
"major",
|
|
2818
|
+
"minor",
|
|
2819
|
+
"patch",
|
|
2820
|
+
"first-release"
|
|
2821
|
+
]
|
|
2822
|
+
},
|
|
2823
|
+
prerelease: {
|
|
2824
|
+
description: "Create a prerelease with the given tag (e.g., beta, alpha)",
|
|
2825
|
+
required: false,
|
|
2826
|
+
type: "string"
|
|
2827
|
+
}
|
|
2828
|
+
} } };
|
|
2829
|
+
}
|
|
2830
|
+
/** Build the release:simple run command with conditional flags from workflow inputs. */
|
|
2831
|
+
function simpleReleaseCommand() {
|
|
2832
|
+
return [
|
|
2833
|
+
"FLAGS=",
|
|
2834
|
+
`case "${actionsExpr("inputs.bump")}" in`,
|
|
2835
|
+
" major|minor|patch) FLAGS=\"$FLAGS --release-as " + actionsExpr("inputs.bump") + "\" ;;",
|
|
2836
|
+
" first-release) FLAGS=\"$FLAGS --first-release\" ;;",
|
|
2837
|
+
"esac",
|
|
2838
|
+
`if [ -n "${actionsExpr("inputs.prerelease")}" ]; then FLAGS="$FLAGS --prerelease ${actionsExpr("inputs.prerelease")}"; fi`,
|
|
2839
|
+
"pnpm exec bst release:simple $FLAGS"
|
|
2840
|
+
].join("\n");
|
|
2841
|
+
}
|
|
2807
2842
|
function simpleReleaseSteps(ci, nodeVersionYaml, publishesNpm, hasDocker) {
|
|
2808
2843
|
const releaseStep = {
|
|
2809
2844
|
match: { run: "release:simple" },
|
|
@@ -2814,7 +2849,7 @@ function simpleReleaseSteps(ci, nodeVersionYaml, publishesNpm, hasDocker) {
|
|
|
2814
2849
|
FORGEJO_REPOSITORY: actionsExpr("github.repository"),
|
|
2815
2850
|
RELEASE_TOKEN: actionsExpr("secrets.RELEASE_TOKEN")
|
|
2816
2851
|
},
|
|
2817
|
-
run:
|
|
2852
|
+
run: simpleReleaseCommand()
|
|
2818
2853
|
}
|
|
2819
2854
|
};
|
|
2820
2855
|
const dockerStep = {
|
|
@@ -2929,10 +2964,11 @@ async function generateReleaseCi(ctx) {
|
|
|
2929
2964
|
action: "skipped",
|
|
2930
2965
|
description: "Release CI workflow not applicable"
|
|
2931
2966
|
};
|
|
2967
|
+
const on = ctx.config.releaseStrategy === "simple" ? simpleWorkflowDispatchTrigger() : { workflow_dispatch: null };
|
|
2932
2968
|
const content = buildWorkflowYaml({
|
|
2933
2969
|
ci: ctx.config.ci,
|
|
2934
2970
|
name: "Release",
|
|
2935
|
-
on
|
|
2971
|
+
on,
|
|
2936
2972
|
...isGitHub && { permissions: { contents: "write" } },
|
|
2937
2973
|
jobName: "release",
|
|
2938
2974
|
steps
|
|
@@ -3285,7 +3321,7 @@ function generateMigratePrompt(results, config, detected) {
|
|
|
3285
3321
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
3286
3322
|
sections.push("# Migration Prompt");
|
|
3287
3323
|
sections.push("");
|
|
3288
|
-
sections.push(`_Generated by \`@bensandee/tooling@0.
|
|
3324
|
+
sections.push(`_Generated by \`@bensandee/tooling@0.33.0 repo:sync\` on ${timestamp}_`);
|
|
3289
3325
|
sections.push("");
|
|
3290
3326
|
sections.push("The following prompt was generated by `@bensandee/tooling repo:sync`. Paste it into Claude Code or another AI assistant to finish migrating this repository.");
|
|
3291
3327
|
sections.push("");
|
|
@@ -4293,33 +4329,53 @@ const releaseTriggerCommand = defineCommand({
|
|
|
4293
4329
|
name: "release:trigger",
|
|
4294
4330
|
description: "Trigger the release CI workflow"
|
|
4295
4331
|
},
|
|
4296
|
-
args: {
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4332
|
+
args: {
|
|
4333
|
+
ref: {
|
|
4334
|
+
type: "string",
|
|
4335
|
+
description: "Git ref to trigger on (default: main)",
|
|
4336
|
+
required: false
|
|
4337
|
+
},
|
|
4338
|
+
bump: {
|
|
4339
|
+
type: "string",
|
|
4340
|
+
description: "Version bump type: auto, major, minor, patch, or first-release",
|
|
4341
|
+
required: false
|
|
4342
|
+
},
|
|
4343
|
+
prerelease: {
|
|
4344
|
+
type: "string",
|
|
4345
|
+
description: "Create a prerelease with the given tag (e.g., beta, alpha)",
|
|
4346
|
+
required: false
|
|
4347
|
+
}
|
|
4348
|
+
},
|
|
4301
4349
|
async run({ args }) {
|
|
4302
4350
|
const ref = args.ref ?? "main";
|
|
4351
|
+
const inputs = {};
|
|
4352
|
+
if (args.bump) inputs["bump"] = args.bump;
|
|
4353
|
+
if (args.prerelease) inputs["prerelease"] = args.prerelease;
|
|
4303
4354
|
const resolved = resolveConnection(process.cwd());
|
|
4304
|
-
if (resolved.type === "forgejo") await triggerForgejo(resolved.conn, ref);
|
|
4305
|
-
else triggerGitHub(ref);
|
|
4355
|
+
if (resolved.type === "forgejo") await triggerForgejo(resolved.conn, ref, inputs);
|
|
4356
|
+
else triggerGitHub(ref, inputs);
|
|
4306
4357
|
}
|
|
4307
4358
|
});
|
|
4308
|
-
async function triggerForgejo(conn, ref) {
|
|
4359
|
+
async function triggerForgejo(conn, ref, inputs) {
|
|
4309
4360
|
const url = `${conn.serverUrl}/api/v1/repos/${conn.repository}/actions/workflows/release.yml/dispatches`;
|
|
4361
|
+
const body = { ref };
|
|
4362
|
+
if (Object.keys(inputs).length > 0) body["inputs"] = inputs;
|
|
4310
4363
|
const res = await fetch(url, {
|
|
4311
4364
|
method: "POST",
|
|
4312
4365
|
headers: {
|
|
4313
4366
|
Authorization: `token ${conn.token}`,
|
|
4314
4367
|
"Content-Type": "application/json"
|
|
4315
4368
|
},
|
|
4316
|
-
body: JSON.stringify(
|
|
4369
|
+
body: JSON.stringify(body)
|
|
4317
4370
|
});
|
|
4318
4371
|
if (!res.ok) throw new FatalError(`Failed to trigger Forgejo workflow: ${res.status} ${res.statusText}`);
|
|
4319
4372
|
log$2.info(`Triggered release workflow on Forgejo (ref: ${ref})`);
|
|
4320
4373
|
}
|
|
4321
|
-
function triggerGitHub(ref) {
|
|
4322
|
-
const
|
|
4374
|
+
function triggerGitHub(ref, inputs) {
|
|
4375
|
+
const executor = createRealExecutor();
|
|
4376
|
+
const inputFlags = Object.entries(inputs).map(([k, v]) => `-f ${k}=${v}`).join(" ");
|
|
4377
|
+
const cmd = `gh workflow run release.yml --ref ${ref}${inputFlags ? ` ${inputFlags}` : ""}`;
|
|
4378
|
+
const result = executor.exec(cmd, { cwd: process.cwd() });
|
|
4323
4379
|
if (result.exitCode !== 0) throw new FatalError(`Failed to trigger GitHub workflow: ${result.stderr || result.stdout || "unknown error"}`);
|
|
4324
4380
|
log$2.info(`Triggered release workflow on GitHub (ref: ${ref})`);
|
|
4325
4381
|
}
|
|
@@ -5103,7 +5159,7 @@ const dockerCheckCommand = defineCommand({
|
|
|
5103
5159
|
const main = defineCommand({
|
|
5104
5160
|
meta: {
|
|
5105
5161
|
name: "bst",
|
|
5106
|
-
version: "0.
|
|
5162
|
+
version: "0.33.0",
|
|
5107
5163
|
description: "Bootstrap and maintain standardized TypeScript project tooling"
|
|
5108
5164
|
},
|
|
5109
5165
|
subCommands: {
|
|
@@ -5119,7 +5175,7 @@ const main = defineCommand({
|
|
|
5119
5175
|
"docker:check": dockerCheckCommand
|
|
5120
5176
|
}
|
|
5121
5177
|
});
|
|
5122
|
-
console.log(`@bensandee/tooling v0.
|
|
5178
|
+
console.log(`@bensandee/tooling v0.33.0`);
|
|
5123
5179
|
async function run() {
|
|
5124
5180
|
await runMain(main);
|
|
5125
5181
|
process.exit(process.exitCode ?? 0);
|
|
@@ -145,14 +145,19 @@ async function runDockerCheck(executor, config) {
|
|
|
145
145
|
const pollIntervalMs = config.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
146
146
|
const { compose } = config;
|
|
147
147
|
const cleanup = () => composeDown(executor, compose);
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
148
|
+
let cleaningUp = false;
|
|
149
|
+
const gracefulShutdown = () => {
|
|
150
|
+
if (cleaningUp) {
|
|
151
|
+
executor.log("Cleanup in progress, please wait...");
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
cleaningUp = true;
|
|
155
|
+
executor.log("Interrupted — shutting down compose stack...");
|
|
153
156
|
cleanup();
|
|
154
157
|
process.exit(1);
|
|
155
|
-
}
|
|
158
|
+
};
|
|
159
|
+
const disposeInt = executor.onSignal("SIGINT", gracefulShutdown);
|
|
160
|
+
const disposeTerm = executor.onSignal("SIGTERM", gracefulShutdown);
|
|
156
161
|
try {
|
|
157
162
|
if (config.buildCommand) {
|
|
158
163
|
executor.log("Building images...");
|
|
@@ -162,6 +167,7 @@ async function runDockerCheck(executor, config) {
|
|
|
162
167
|
composeUp(executor, compose);
|
|
163
168
|
executor.log(`Waiting for stack to be healthy (max ${timeoutMs / 1e3}s)...`);
|
|
164
169
|
const startTime = executor.now();
|
|
170
|
+
let lastStatusLogTime = startTime;
|
|
165
171
|
const healthStatus = new Map(config.healthChecks.map((c) => [c.name, false]));
|
|
166
172
|
while (executor.now() - startTime < timeoutMs) {
|
|
167
173
|
const containers = composePs(executor, compose);
|
|
@@ -195,10 +201,12 @@ async function runDockerCheck(executor, config) {
|
|
|
195
201
|
elapsedMs: executor.now() - startTime
|
|
196
202
|
};
|
|
197
203
|
}
|
|
198
|
-
const
|
|
199
|
-
if (
|
|
200
|
-
|
|
201
|
-
|
|
204
|
+
const now = executor.now();
|
|
205
|
+
if (now - lastStatusLogTime >= 5e3) {
|
|
206
|
+
lastStatusLogTime = now;
|
|
207
|
+
const elapsed = Math.floor((now - startTime) / 1e3);
|
|
208
|
+
const parts = [compose.services.map((s) => `${s}=${getContainerHealth(containers, s)}`).join(", "), [...healthStatus.entries()].map(([name, ok]) => `${name}=${ok ? "OK" : "Pending"}`).join(", ")].filter(Boolean).join(" | ");
|
|
209
|
+
executor.log(`Waiting... (${elapsed}s elapsed). ${parts}`);
|
|
202
210
|
}
|
|
203
211
|
await executor.sleep(pollIntervalMs);
|
|
204
212
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as composeDown, c as composeUp, i as composeCommand, l as createRealExecutor, n as checkHttpHealth, o as composeLogs, r as getContainerHealth, s as composePs, t as runDockerCheck } from "../check-
|
|
1
|
+
import { a as composeDown, c as composeUp, i as composeCommand, l as createRealExecutor, n as checkHttpHealth, o as composeLogs, r as getContainerHealth, s as composePs, t as runDockerCheck } from "../check-B2AAPCBO.mjs";
|
|
2
2
|
export { checkHttpHealth, composeCommand, composeDown, composeLogs, composePs, composeUp, createRealExecutor, getContainerHealth, runDockerCheck };
|