@regardio/dev 2.2.0 → 2.4.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.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as git, c as runScript, i as getWorkspacePackages, n as choose, o as gitRead, s as runQualityChecks, t as branchExists } from "./utils-CGXmpKxp.mjs";
2
+ import { a as git, c as runScript, i as getWorkspacePackages, n as chooseForEach, o as gitRead, s as runQualityChecks, t as branchExists } from "./utils-rnvdLrkF.mjs";
3
3
  //#region src/bin/ship/hotfix.ts
4
4
  /**
5
5
  * ship-hotfix: Manage hotfix branches based on production code.
@@ -65,30 +65,23 @@ function runShipHotfix(subcommand, subArgs, cwd = process.cwd()) {
65
65
  console.error("No publishable workspace packages found.");
66
66
  process.exit(1);
67
67
  }
68
- const packageName = packages.length === 1 ? packages[0]?.name ?? "" : choose("Which package to ship?", packages.map((p) => ({
69
- label: p.name,
70
- value: p.name
71
- })));
72
- if (!packageName) {
73
- console.error("Could not determine package to ship.");
74
- process.exit(1);
68
+ console.log("\nSelect a version bump for each package (or skip):");
69
+ const bumps = chooseForEach(packages);
70
+ if (bumps.length === 0) {
71
+ console.log("\nNo packages selected for release. Aborted.");
72
+ process.exit(0);
75
73
  }
76
- const bumpType = choose("Select version bump:", [
77
- {
78
- label: "patch bug fixes",
79
- value: "patch"
80
- },
81
- {
82
- label: "minor — new features",
83
- value: "minor"
84
- },
85
- {
86
- label: "major — breaking changes",
87
- value: "major"
74
+ console.log("\nBumping versions and updating CHANGELOGs...");
75
+ for (const { package: pkg, bump } of bumps) {
76
+ const originalCwd = process.cwd();
77
+ process.chdir(pkg.path);
78
+ try {
79
+ runScript(`--filter-root release:${bump}`);
80
+ } catch {
81
+ runScript(`commit-and-tag-version ${bump === "patch" ? "" : `--release-as ${bump}`}`);
88
82
  }
89
- ]);
90
- console.log("\nBumping version and updating CHANGELOG...");
91
- runScript(`--filter ${packageName} release:${bumpType}`);
83
+ process.chdir(originalCwd);
84
+ }
92
85
  console.log("\nFetching latest state from origin...");
93
86
  git("fetch", "origin");
94
87
  console.log("\nMerging hotfix into production...");
@@ -110,7 +103,8 @@ function runShipHotfix(subcommand, subArgs, cwd = process.cwd()) {
110
103
  try {
111
104
  git("push", "origin", "--delete", currentBranch);
112
105
  } catch {}
113
- console.log(`\n✅ Hotfix ${packageName} shipped to production staging → main`);
106
+ const shipped = bumps.map((b) => b.package.name).join(", ");
107
+ console.log(`\n✅ Hotfix ${shipped} shipped to production → staging → main`);
114
108
  console.log("CI will publish changed packages to npm.");
115
109
  console.log("You are on main and ready to keep working.");
116
110
  process.exit(0);
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as git, c as runScript, i as getWorkspacePackages, n as choose, o as gitRead, r as confirm, s as runQualityChecks, t as branchExists } from "./utils-CGXmpKxp.mjs";
2
+ import { a as git, c as runScript, i as getWorkspacePackages, n as chooseForEach, o as gitRead, r as confirm, s as runQualityChecks, t as branchExists } from "./utils-rnvdLrkF.mjs";
3
3
  //#region src/bin/ship/production.ts
4
4
  /**
5
5
  * ship-production: Promote main to production following the GitLab workflow.
@@ -47,15 +47,13 @@ function runShipProduction(cwd = process.cwd()) {
47
47
  console.error("No publishable workspace packages found.");
48
48
  process.exit(1);
49
49
  }
50
- const packageName = packages.length === 1 ? packages[0]?.name ?? "" : choose("Which package to ship?", packages.map((p) => ({
51
- label: p.name,
52
- value: p.name
53
- })));
54
- if (!packageName) {
55
- console.error("Could not determine package to ship.");
56
- process.exit(1);
50
+ console.log("\nSelect a version bump for each package (or skip):");
51
+ const bumps = chooseForEach(packages);
52
+ if (bumps.length === 0) {
53
+ console.log("\nNo packages selected for release. Aborted.");
54
+ process.exit(0);
57
55
  }
58
- if (!confirm(`Ship ${packageName} to production?`)) {
56
+ if (!confirm(`\nShip to production?\n${bumps.map((b) => ` ${b.package.name} → ${b.bump}`).join("\n")}\n`)) {
59
57
  console.log("Aborted.");
60
58
  process.exit(0);
61
59
  }
@@ -67,22 +65,17 @@ function runShipProduction(cwd = process.cwd()) {
67
65
  process.exit(1);
68
66
  }
69
67
  console.log("✅ Quality checks passed");
70
- const bumpType = choose("Select version bump:", [
71
- {
72
- label: "patch bug fixes",
73
- value: "patch"
74
- },
75
- {
76
- label: "minor — new features",
77
- value: "minor"
78
- },
79
- {
80
- label: "major — breaking changes",
81
- value: "major"
68
+ console.log("\nBumping versions and updating CHANGELOGs...");
69
+ for (const { package: pkg, bump } of bumps) {
70
+ const originalCwd = process.cwd();
71
+ process.chdir(pkg.path);
72
+ try {
73
+ runScript(`--filter-root release:${bump}`);
74
+ } catch {
75
+ runScript(`commit-and-tag-version ${bump === "patch" ? "" : `--release-as ${bump}`}`);
82
76
  }
83
- ]);
84
- console.log("\nBumping version and updating CHANGELOG...");
85
- runScript(`--filter ${packageName} release:${bumpType}`);
77
+ process.chdir(originalCwd);
78
+ }
86
79
  console.log("\nMerging main into production...");
87
80
  git("checkout", "production");
88
81
  git("pull", "--ff-only", "origin", "production");
@@ -95,7 +88,8 @@ function runShipProduction(cwd = process.cwd()) {
95
88
  git("push", "origin", "staging");
96
89
  git("checkout", "main");
97
90
  git("push", "--follow-tags", "origin", "main");
98
- console.log(`\n✅ Shipped ${packageName} to production. CI will publish changed packages to npm.`);
91
+ const shipped = bumps.map((b) => b.package.name).join(", ");
92
+ console.log(`\n✅ Shipped ${shipped} to production. CI will publish changed packages to npm.`);
99
93
  console.log("You are on main and ready to keep working.");
100
94
  }
101
95
  //#endregion
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as git, o as gitRead, s as runQualityChecks, t as branchExists } from "./utils-CGXmpKxp.mjs";
2
+ import { a as git, o as gitRead, s as runQualityChecks, t as branchExists } from "./utils-rnvdLrkF.mjs";
3
3
  import { existsSync, readFileSync } from "node:fs";
4
4
  import { join } from "node:path";
5
5
  //#region src/bin/ship/staging.ts
@@ -20,7 +20,7 @@ const runScript = (script) => {
20
20
  execSync(`pnpm ${script}`, { stdio: "inherit" });
21
21
  };
22
22
  const runQualityChecks = () => {
23
- runScript("build");
23
+ runScript("lint");
24
24
  runScript("typecheck");
25
25
  runScript("test");
26
26
  };
@@ -40,6 +40,43 @@ const getWorkspacePackages = (cwd = process.cwd()) => {
40
40
  path
41
41
  }));
42
42
  };
43
+ const chooseForEach = (packages, ttyPath = "/dev/tty") => {
44
+ const bumps = [];
45
+ const options = [
46
+ {
47
+ label: "0) skip",
48
+ value: "0"
49
+ },
50
+ {
51
+ label: "1) patch — bug fixes",
52
+ value: "1"
53
+ },
54
+ {
55
+ label: "2) minor — new features",
56
+ value: "2"
57
+ },
58
+ {
59
+ label: "3) major — breaking changes",
60
+ value: "3"
61
+ }
62
+ ];
63
+ for (const pkg of packages) {
64
+ const answer = choose(`\n${pkg.name}:`, [...options], ttyPath);
65
+ if (answer === "1") bumps.push({
66
+ bump: "patch",
67
+ package: pkg
68
+ });
69
+ else if (answer === "2") bumps.push({
70
+ bump: "minor",
71
+ package: pkg
72
+ });
73
+ else if (answer === "3") bumps.push({
74
+ bump: "major",
75
+ package: pkg
76
+ });
77
+ }
78
+ return bumps;
79
+ };
43
80
  const branchExists = (name) => gitRead("branch", "--list", name) !== "" || gitRead("branch", "--list", "--remotes", `origin/${name}`) !== "";
44
81
  const confirm = (prompt, ttyPath = "/dev/tty") => {
45
82
  process.stdout.write(`${prompt} (y/N) `);
@@ -58,8 +95,8 @@ const confirm = (prompt, ttyPath = "/dev/tty") => {
58
95
  return answer === "y" || answer === "Y";
59
96
  };
60
97
  const choose = (prompt, options, ttyPath = "/dev/tty") => {
61
- const keys = options.map((_, i) => String(i + 1));
62
- const optionList = options.map((o, i) => ` ${i + 1}) ${o.label}`).join("\n");
98
+ const keys = options.map((o) => o.value);
99
+ const optionList = options.map((o) => ` ${o.label}`).join("\n");
63
100
  process.stdout.write(`${prompt}\n${optionList}\nChoice [${keys.join("/")}]: `);
64
101
  const buf = Buffer.alloc(1024);
65
102
  let fd;
@@ -83,4 +120,4 @@ const choose = (prompt, options, ttyPath = "/dev/tty") => {
83
120
  return chosen.value;
84
121
  };
85
122
  //#endregion
86
- export { git as a, runScript as c, getWorkspacePackages as i, choose as n, gitRead as o, confirm as r, runQualityChecks as s, branchExists as t };
123
+ export { git as a, runScript as c, getWorkspacePackages as i, chooseForEach as n, gitRead as o, confirm as r, runQualityChecks as s, branchExists as t };
@@ -10,9 +10,9 @@ interface BuildPlaywrightBaseConfigParams {
10
10
  webServerCommand: string;
11
11
  }
12
12
  /**
13
- * Build a base Playwright config object with Regardio defaults.
14
- * Consumers should wrap with defineConfig() in their local playwright.config.ts
15
- */
13
+ * Build a base Playwright config object with Regardio defaults.
14
+ * Consumers should wrap with defineConfig() in their local playwright.config.ts
15
+ */
16
16
  declare function buildPlaywrightBaseConfig({
17
17
  appUrl,
18
18
  appPort,
@@ -1,8 +1,8 @@
1
1
  //#region src/vitest/node.d.ts
2
2
  /**
3
- * Base Vitest configuration for Node.js packages.
4
- * Use with defineConfig() in your vitest.config.ts
5
- */
3
+ * Base Vitest configuration for Node.js packages.
4
+ * Use with defineConfig() in your vitest.config.ts
5
+ */
6
6
  declare const vitestNodeConfig: {
7
7
  coverage: {
8
8
  provider: "v8";
@@ -1,8 +1,8 @@
1
1
  //#region src/vitest/react.d.ts
2
2
  /**
3
- * Vitest configuration for React packages with jsdom environment.
4
- * Use with defineConfig() in your vitest.config.ts
5
- */
3
+ * Vitest configuration for React packages with jsdom environment.
4
+ * Use with defineConfig() in your vitest.config.ts
5
+ */
6
6
  declare const vitestReactConfig: {
7
7
  coverage: {
8
8
  provider: "v8";
@@ -25,17 +25,17 @@ main → staging (optional) → production
25
25
  - **`staging`** — optional validation environment. No versioning happens here.
26
26
  - **`production`** — versioned, published code only.
27
27
 
28
- When `ship-production` runs, it discovers publishable workspace packages. In a monorepo with multiple packages, you choose which package to ship; in a single-package repo the choice is automatic. Then you choose the bump type (`patch`, `minor`, `major`) and it calls `pnpm --filter <package> release:<type>`, which bumps that package's version, rewrites its `CHANGELOG.md` using commits since its last scoped tag, and commits on `main` before merging to `production`. CI on `production` publishes changed packages to npm.
28
+ When `ship-production` runs, it discovers all publishable workspace packages and asks you to assign a bump type `0` (skip), `1` (patch), `2` (minor), or `3` (major) — to each one individually. Packages you skip are left untouched. For each package with a bump, it first tries to run the release script from the root package.json (using `--filter-root release:<type>`), and if that fails, falls back to running `commit-and-tag-version` directly with the appropriate bump flag. This bumps that package's version, rewrites its `CHANGELOG.md` using commits since its last scoped tag, and commits on `main`. The branches merge once after all bumps are applied. CI on `production` publishes only the packages whose version changed.
29
29
 
30
30
  ## How It Works
31
31
 
32
32
  ### Design principles
33
33
 
34
34
  1. **Branches mirror environments.** `staging` reflects what is deployed to the staging server (when used); `production` always reflects what is published to npm. There is never ambiguity about what is running where.
35
- 2. **You choose the bump at ship time.** When running `ship-production` or `ship-hotfix finish`, you are prompted to select `patch`, `minor`, or `major`. The conventional commits in the log inform that choice; the decision is always explicit.
35
+ 2. **You choose the bump per package at ship time.** When running `ship-production` or `ship-hotfix finish`, every publishable package is listed and you assign it `0` (skip), `1` (patch), `2` (minor), or `3` (major). Packages you skip are untouched. The conventional commits in the log inform each choice; the decisions are always explicit.
36
36
  3. **Version numbers are a production guarantee.** Bumps are applied only at `ship-production` time. Every version tag in git and every release on npm corresponds to code that has been validated and shipped.
37
37
  4. **Staging is optional.** You can ship directly from `main` to `production`. Use `ship-staging` when you want to test changes in a staging environment first.
38
- 5. **Tests are a local gate, not a CI gate.** Quality checks (`build`, `typecheck`, `test`) run on your machine before any commit is made. Broken code cannot enter the repository.
38
+ 5. **Tests are a local gate, not a CI gate.** Quality checks (`lint`, `typecheck`, `test`) run on your machine before any commit is made. Broken code cannot enter the repository.
39
39
  6. **You always land back on `main`.** Every command returns you to `main` when it finishes.
40
40
 
41
41
  ### Full flow diagram
@@ -136,14 +136,14 @@ This will:
136
136
 
137
137
  1. Guard: must be on `main`, working tree clean
138
138
  2. Fetch and verify `staging` + `production` branches exist
139
- 3. Show commits to be shipped, ask for confirmation
140
- 4. Run full quality suite on `main` aborts on failure
141
- 5. If multiple publishable packages exist: prompt for which package to ship
142
- 6. Prompt for bump type: `patch`, `minor`, or `major`
143
- 7. Run `pnpm --filter <package> release:<type>` — bumps version, rewrites `CHANGELOG.md`, commits
139
+ 3. Show commits to be shipped
140
+ 4. For each publishable package: choose `0 (skip) / 1 (patch) / 2 (minor) / 3 (major)`
141
+ 5. Confirm the planned bumps abort if declined or all skipped
142
+ 6. Run full quality suite on `main` aborts on failure
143
+ 7. For each non-skipped package: run release script from root (if defined) or `commit-and-tag-version` directly — bumps version, rewrites `CHANGELOG.md`, commits
144
144
  8. Fast-forward merge `main` into `production` and push
145
145
  9. Sync `staging` with `production`
146
- 10. Push `main` with `--follow-tags` to push the version tag
146
+ 10. Push `main` with `--follow-tags` to push all new version tags
147
147
  11. Return to `main`
148
148
 
149
149
  CI on `production` runs `pnpm -r publish` to push changed packages to npm.
@@ -167,13 +167,15 @@ git add . && git commit -m "fix: ..."
167
167
  pnpm ship:hotfix finish
168
168
  ```
169
169
 
170
- `finish` prompts for a bump type (`patch`, `minor`, or `major`), runs `pnpm release:<type>` to bump the version and update `CHANGELOG.md`, then merges `hotfix → production → staging → main` and deletes the hotfix branch. CI publishes from `production`.
170
+ `finish` asks you to assign a bump type (`0` (skip), `1` (patch), `2` (minor), or `3` (major)) to each publishable package, runs the release script from root (if defined) or `commit-and-tag-version` directly for each non-skipped one to bump versions and update `CHANGELOG.md`, then merges `hotfix → production → staging → main` and deletes the hotfix branch. CI publishes from `production`.
171
171
 
172
172
  ## Adoption
173
173
 
174
174
  Install `@regardio/dev` and:
175
175
 
176
- 1. **Add the scripts to `package.json`**:
176
+ 1. **Add the scripts to `package.json`** (optional, for monorepos):
177
+
178
+ In a monorepo, you can define release scripts in the root `package.json` to centralize version management. The ship scripts will use these if available, and fall back to running `commit-and-tag-version` directly if not.
177
179
 
178
180
  ```json
179
181
  {
@@ -189,6 +191,8 @@ Install `@regardio/dev` and:
189
191
  }
190
192
  ```
191
193
 
194
+ For single-package repos or when you prefer direct `commit-and-tag-version` usage, you can omit the release scripts — the ship commands will call `commit-and-tag-version` directly.
195
+
192
196
  2. **Add a `.versionrc.json` to each publishable package** with a scoped `tagPrefix` so tags and changelogs stay isolated per package:
193
197
 
194
198
  ```bash
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://www.schemastore.org/package.json",
3
3
  "name": "@regardio/dev",
4
- "version": "2.2.0",
4
+ "version": "2.4.0",
5
5
  "private": false,
6
6
  "description": "Regardio development presets: biome, typescript, commitlint, markdownlint, vitest, playwright, sqlfluff, husky, and GitLab-flow ship tooling",
7
7
  "keywords": [
@@ -98,10 +98,6 @@
98
98
  "clean": "rimraf .turbo dist",
99
99
  "dev": "tsdown --watch",
100
100
  "fix": "run-s fix:pkg fix:md fix:biome",
101
- "release": "commit-and-tag-version",
102
- "release:major": "commit-and-tag-version --release-as major",
103
- "release:minor": "commit-and-tag-version --release-as minor",
104
- "release:patch": "commit-and-tag-version --release-as patch",
105
101
  "fix:biome": "biome check --write --unsafe .",
106
102
  "fix:md": "markdownlint-cli2 --config ../../.markdownlint-cli2.jsonc --fix",
107
103
  "fix:pkg": "sort-package-json",
@@ -7,12 +7,13 @@
7
7
  "allowUnusedLabels": false,
8
8
  "alwaysStrict": true,
9
9
  "checkJs": false,
10
+ "declaration": true,
10
11
  "esModuleInterop": true,
11
12
  "exactOptionalPropertyTypes": false,
12
13
  "forceConsistentCasingInFileNames": true,
13
14
  "incremental": false,
14
15
  "inlineSources": false,
15
- "isolatedDeclarations": false,
16
+ "isolatedDeclarations": true,
16
17
  "isolatedModules": true,
17
18
  "module": "ESNext",
18
19
  "moduleDetection": "force",