@vc-shell/release-config 1.2.1 → 1.2.3-beta.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 CHANGED
@@ -96,6 +96,94 @@ This command:
96
96
 
97
97
  **Note:** This is typically a one-time operation during initial setup or migration.
98
98
 
99
+ ## Programmatic API for Changelog Generation
100
+
101
+ You can also use the changelog generation functionality programmatically in your own scripts:
102
+
103
+ ### Using the CLI
104
+
105
+ ```bash
106
+ # Install the package
107
+ yarn add -D @vc-shell/release-config
108
+
109
+ # Create a configuration file
110
+ npx vc-generate-changelogs --help
111
+
112
+ # Run with your config
113
+ npx vc-generate-changelogs changelog-config.js
114
+ ```
115
+
116
+ ### Using the JavaScript API
117
+
118
+ ```typescript
119
+ import { generateInitialChangelogs, PackageConfig } from "@vc-shell/release-config";
120
+
121
+ const packages: PackageConfig[] = [
122
+ {
123
+ name: "framework",
124
+ path: "framework",
125
+ displayName: "Framework (@vc-shell/framework)"
126
+ },
127
+ {
128
+ name: "cli/api-client",
129
+ path: "cli/api-client",
130
+ displayName: "API Client Generator (@vc-shell/api-client-generator)"
131
+ },
132
+ // ... more packages
133
+ ];
134
+
135
+ await generateInitialChangelogs({
136
+ packages,
137
+ rootDir: process.cwd(), // Optional: root directory
138
+ generateRoot: true, // Optional: generate root changelog
139
+ includeRootHeader: true // Optional: include header in root changelog
140
+ });
141
+ ```
142
+
143
+ ### Configuration File Format
144
+
145
+ Create a `changelog-config.js` file:
146
+
147
+ ```javascript
148
+ export default {
149
+ packages: [
150
+ {
151
+ name: "framework",
152
+ path: "framework",
153
+ displayName: "Framework (@vc-shell/framework)"
154
+ },
155
+ // ... more packages
156
+ ],
157
+ rootDir: process.cwd(),
158
+ generateRoot: true,
159
+ includeRootHeader: true,
160
+ };
161
+ ```
162
+
163
+ ### Generating Only Root Changelog
164
+
165
+ If you already have package changelogs and want to regenerate just the root one:
166
+
167
+ ```typescript
168
+ import { generateRootChangelog } from "@vc-shell/release-config";
169
+
170
+ await generateRootChangelog({
171
+ packages,
172
+ rootDir: process.cwd(),
173
+ includeRootHeader: true,
174
+ });
175
+ ```
176
+
177
+ ### Use Cases
178
+
179
+ This programmatic API is useful for:
180
+ - **Custom monorepo structures** - Different from standard VC-Shell layout
181
+ - **CI/CD pipelines** - Automated changelog generation
182
+ - **Migration scripts** - One-time setup for new repositories
183
+ - **Custom workflows** - Integration with other release tools
184
+
185
+ See [changelog-config.example.js](./changelog-config.example.js) for a complete configuration example.
186
+
99
187
  ### Root CHANGELOG Format
100
188
 
101
189
  The root `CHANGELOG.md` groups changes by package for each version:
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env node
2
+ import { g as i } from "./generate-changelogs-_wYT4v6U.js";
3
+ import { resolve as s } from "node:path";
4
+ import e from "chalk";
5
+ async function l() {
6
+ const n = process.argv.slice(2);
7
+ (n.includes("--help") || n.includes("-h")) && (console.log(`
8
+ ${e.cyan("vc-generate-changelogs")} - Generate CHANGELOG.md files from git history
9
+
10
+ ${e.bold("USAGE:")}
11
+ vc-generate-changelogs [config-file]
12
+
13
+ ${e.bold("ARGUMENTS:")}
14
+ config-file Path to configuration file (default: changelog-config.js)
15
+
16
+ ${e.bold("CONFIG FILE FORMAT:")}
17
+ The config file should export an object with the following structure:
18
+
19
+ export default {
20
+ packages: [
21
+ {
22
+ name: "framework",
23
+ path: "framework",
24
+ displayName: "Framework (@vc-shell/framework)"
25
+ },
26
+ // ... more packages
27
+ ],
28
+ rootDir: process.cwd(), // Optional: root directory
29
+ generateRoot: true, // Optional: generate root changelog
30
+ includeRootHeader: true // Optional: include header in root changelog
31
+ };
32
+
33
+ ${e.bold("EXAMPLE:")}
34
+ vc-generate-changelogs changelog-config.js
35
+ `), process.exit(0));
36
+ const t = n[0] || "changelog-config.js", c = s(process.cwd(), t);
37
+ try {
38
+ console.log(e.blue(`📖 Loading config from ${c}...`));
39
+ const o = await import(c), r = o.default || o;
40
+ (!r.packages || !Array.isArray(r.packages)) && (console.error(e.red(`
41
+ ❌ Error: Config must export an object with 'packages' array`)), console.error(e.yellow(`
42
+ Expected format:`)), console.error(e.gray(" export default { packages: [...] }")), process.exit(1));
43
+ for (const a of r.packages)
44
+ (!a.name || !a.path || !a.displayName) && (console.error(e.red(`
45
+ ❌ Error: Invalid package config: ${JSON.stringify(a)}`)), console.error(e.yellow(`
46
+ Each package must have: name, path, displayName`)), process.exit(1));
47
+ await i(r);
48
+ } catch (o) {
49
+ o.code === "MODULE_NOT_FOUND" || o.code === "ERR_MODULE_NOT_FOUND" ? (console.error(e.red(`
50
+ ❌ Error: Config file not found: ${c}`)), console.error(e.yellow(`
51
+ Create a config file or specify a different path.`)), console.error(e.gray(`
52
+ Run 'vc-generate-changelogs --help' for more information.`))) : console.error(e.red(`
53
+ ❌ Error generating changelogs:`), o), process.exit(1);
54
+ }
55
+ }
56
+ l();
@@ -0,0 +1,139 @@
1
+ import { sync as $ } from "cross-spawn";
2
+ import { existsSync as u, readFileSync as d, writeFileSync as y } from "node:fs";
3
+ import C from "node:path";
4
+ import i from "chalk";
5
+ async function L(N) {
6
+ const { packages: f, rootDir: m = process.cwd(), generateRoot: b = !0, includeRootHeader: g = !0 } = N;
7
+ console.log(i.cyan(`
8
+ 🚀 Generating initial CHANGELOG.md files...
9
+ `));
10
+ for (const l of f) {
11
+ const a = C.join(m, l.path, "CHANGELOG.md");
12
+ if (u(a)) {
13
+ const t = `${a}.backup`, s = d(a, "utf-8");
14
+ y(t, s, "utf-8"), console.log(i.gray(` 📦 Backed up ${a} to ${t}`));
15
+ }
16
+ if (console.log(i.blue(`
17
+ 📝 Generating changelog for ${l.name}...`)), $(
18
+ "npx",
19
+ [
20
+ "conventional-changelog",
21
+ "-p",
22
+ "conventionalcommits",
23
+ "-i",
24
+ a,
25
+ "-s",
26
+ "-r",
27
+ "0",
28
+ // 0 = all commits
29
+ "--commit-path",
30
+ C.join(m, l.path)
31
+ ],
32
+ { stdio: "inherit", cwd: m }
33
+ ).status === 0) {
34
+ if (u(a)) {
35
+ let t = d(a, "utf-8");
36
+ t = t.replace(/^# CHANGELOG\s*\n/gm, ""), t = t.replace(/^# Change Log\s*\n/gm, ""), t = t.replace(/^All notable changes to this (project|package) will be documented in this file\.\s*\n/gm, ""), t = t.replace(
37
+ /^See \[Conventional Commits\]\(https:\/\/conventionalcommits\.org\) for commit guidelines\.\s*\n/gm,
38
+ ""
39
+ ), t = t.replace(/\n{3,}/g, `
40
+
41
+ `), t = t.replace(
42
+ /^(##\s+\[[^\]]+\][^\n]*\n)\n(##\s+\[|$)/gm,
43
+ `$1
44
+ **Note:** Version bump only
45
+
46
+ $2`
47
+ ), t = t.trim() + `
48
+ `, y(a, t, "utf-8");
49
+ }
50
+ console.log(i.green(` ✓ Generated ${a}`));
51
+ } else
52
+ console.log(i.red(` ✗ Failed to generate ${a}`));
53
+ }
54
+ b && await w({ packages: f, rootDir: m, includeRootHeader: g }), console.log(i.green(`
55
+ ✅ Initial changelogs generated successfully!`)), console.log(i.cyan(`
56
+ 📋 Next steps:`)), console.log(i.cyan(" 1. Review the generated CHANGELOG.md files")), console.log(i.cyan(" 2. Make any manual adjustments if needed")), console.log(i.cyan(` 3. Commit the changes
57
+ `));
58
+ }
59
+ async function w(N) {
60
+ const { packages: f, rootDir: m = process.cwd(), includeRootHeader: b = !0 } = N;
61
+ console.log(i.blue(`
62
+ 📝 Generating consolidated root changelog...`));
63
+ const g = C.join(m, "CHANGELOG.md");
64
+ if (u(g)) {
65
+ const s = `${g}.backup`, r = d(g, "utf-8");
66
+ y(s, r, "utf-8"), console.log(i.gray(` 📦 Backed up ${g} to ${s}`));
67
+ }
68
+ const l = {}, a = {};
69
+ for (const s of f) {
70
+ const r = C.join(m, s.path, "CHANGELOG.md");
71
+ if (console.log(i.gray(` 📖 Collecting changes from ${s.name}...`)), u(r)) {
72
+ const p = d(r, "utf-8").split(`
73
+ `);
74
+ let e = null, o = [];
75
+ for (const n of p) {
76
+ const G = n.match(/^##\s+(?:\[)?([\d.a-z-]+)(?:\])?(?:\s+\([^)]+\))?/i);
77
+ if (G) {
78
+ if (e && o.length > 0) {
79
+ const k = o.join(`
80
+ `).trim();
81
+ l[e] || (l[e] = {}), l[e][s.displayName] = k;
82
+ }
83
+ e = G[1], o = [], a[e] || (a[e] = n.replace(/^##\s+/, ""));
84
+ } else e && n.trim() !== "" && !n.startsWith("# CHANGELOG") && !n.startsWith("# Change Log") && !n.startsWith("All notable changes") && !n.startsWith("See [Conventional Commits]") && o.push(n);
85
+ }
86
+ if (e && o.length > 0) {
87
+ const n = o.join(`
88
+ `).trim();
89
+ l[e] || (l[e] = {}), l[e][s.displayName] = n;
90
+ }
91
+ }
92
+ }
93
+ let c = "";
94
+ b && (c = `# CHANGELOG
95
+
96
+ All notable changes to this monorepo will be documented in this file.
97
+
98
+ `);
99
+ const t = Object.keys(l).sort((s, r) => {
100
+ const h = s.split(/[.-]/).map((e) => isNaN(parseInt(e)) ? e : parseInt(e)), p = r.split(/[.-]/).map((e) => isNaN(parseInt(e)) ? e : parseInt(e));
101
+ for (let e = 0; e < Math.max(h.length, p.length); e++) {
102
+ const o = h[e] ?? 0, n = p[e] ?? 0;
103
+ if (o !== n)
104
+ return typeof o == "number" && typeof n == "number" ? n - o : String(n).localeCompare(String(o));
105
+ }
106
+ return 0;
107
+ });
108
+ for (const s of t) {
109
+ const r = l[s], h = Object.values(r).some((o) => !o || !o.trim() ? !1 : o.replace(/\*\*Note:\*\*\s+Version bump only[^\n]*/gi, "").trim().length > 0), p = a[s] || s;
110
+ if (c += `## ${p}
111
+
112
+ `, !h) {
113
+ c += `**Note:** Version bump only
114
+
115
+ `;
116
+ continue;
117
+ }
118
+ let e = !1;
119
+ for (const o of f) {
120
+ const n = r[o.displayName];
121
+ n && n.trim() && n.replace(/\*\*Note:\*\*\s+Version bump only[^\n]*/gi, "").trim().length > 0 && (e = !0, c += `### ${o.displayName}
122
+
123
+ `, c += `${n}
124
+
125
+ `);
126
+ }
127
+ e || (c += `**Note:** Version bump only
128
+
129
+ `);
130
+ }
131
+ c = c.replace(/\n{3,}/g, `
132
+
133
+ `), c = c.trim() + `
134
+ `, y(g, c, "utf-8"), console.log(i.green(` ✓ Generated ${g} with package grouping`));
135
+ }
136
+ export {
137
+ w as a,
138
+ L as g
139
+ };
@@ -1,31 +1,40 @@
1
- import w from "prompts";
2
- import { parse as G, valid as S } from "semver";
3
- import { readFileSync as N, writeFileSync as b, existsSync as R } from "node:fs";
4
- import k from "node:path";
1
+ import G from "prompts";
2
+ import { parse as A, valid as E } from "semver";
3
+ import { readFileSync as P, writeFileSync as V, existsSync as j } from "node:fs";
4
+ import S from "node:path";
5
5
  import n from "chalk";
6
- import A from "mri";
7
- import { argv as V } from "node:process";
6
+ import O from "mri";
7
+ import { argv as H } from "node:process";
8
8
  import { sync as m } from "cross-spawn";
9
- const v = A(V.slice(2)), E = !!v.dry;
10
- E && (console.log(n.inverse(n.yellow(" DRY RUN "))), console.log());
11
- function C(r) {
12
- const g = k.resolve(r), c = k.resolve(g, "package.json");
13
- return { pkg: JSON.parse(N(c, "utf-8")), pkgDir: g, pkgPath: c };
9
+ import { g as K, a as Q } from "./generate-changelogs-_wYT4v6U.js";
10
+ const C = O(H.slice(2)), I = !!C.dry;
11
+ I && (console.log(n.inverse(n.yellow(" DRY RUN "))), console.log());
12
+ function N(s) {
13
+ const g = S.resolve(s), l = S.resolve(g, "package.json");
14
+ return { pkg: JSON.parse(P(l, "utf-8")), pkgDir: g, pkgPath: l };
14
15
  }
15
- const W = async ({
16
- packages: r,
16
+ const z = async ({
17
+ packages: s,
17
18
  bumpVersion: g,
18
- generateChangelog: c,
19
- toTag: t,
20
- customHooks: f
19
+ generateChangelog: l,
20
+ toTag: o,
21
+ customHooks: d
21
22
  }) => {
22
- if (r.length === 0)
23
+ if (s.length === 0)
23
24
  throw new Error("No packages to release");
24
- const l = !!v.dry;
25
- l && console.log(n.yellow(`
25
+ const r = !!C.dry;
26
+ r && console.log(n.yellow(`
26
27
  ⚠️ DRY RUN MODE - No git operations will be performed
27
28
  `));
28
- const { releaseType: h } = await w({
29
+ const { pkg: k } = N(s.find((h) => h !== ".") || s[0]), f = k.version.split(".").slice(0, 2).join("."), u = m("git", ["describe", "--tags", "--abbrev=0", "--match", `v${f}.*`], {
30
+ stdio: "pipe",
31
+ encoding: "utf-8"
32
+ });
33
+ let v = null;
34
+ u.status === 0 && u.stdout ? (v = u.stdout.toString().trim(), console.log(n.gray(`ℹ️ Using ${v} as reference point for changes
35
+ `))) : console.log(n.yellow(`⚠️ No matching tag found for v${f}.*, Lerna will use default behavior
36
+ `));
37
+ const { releaseType: t } = await G({
29
38
  type: "select",
30
39
  name: "releaseType",
31
40
  message: "Select release type",
@@ -36,99 +45,103 @@ const W = async ({
36
45
  { title: "Custom version", value: "custom" }
37
46
  ]
38
47
  });
39
- if (!h) {
48
+ if (!t) {
40
49
  console.log(n.yellow(`
41
50
  Release cancelled
42
51
  `));
43
52
  return;
44
53
  }
45
- const a = ["lerna", "version", "--conventional-commits"];
46
- if (h === "prerelease") {
47
- const { pkg: i } = C(r[0]), e = G(i.version), o = e && e.prerelease.length > 0, s = o ? e.prerelease[0] : null, { preid: y } = await w({
54
+ const e = ["lerna", "version"];
55
+ if (t === "auto")
56
+ e.push("--conventional-commits");
57
+ else if (t === "prerelease") {
58
+ const { pkg: h } = N(s[0]), w = A(h.version), c = w && w.prerelease.length > 0, y = c ? w.prerelease[0] : null, { preid: R } = await G({
48
59
  type: "select",
49
60
  name: "preid",
50
61
  message: "Select prerelease identifier",
51
62
  choices: [
52
63
  {
53
- title: o && s === "alpha" ? "alpha (continue)" : "alpha",
64
+ title: c && y === "alpha" ? "alpha (continue)" : "alpha",
54
65
  value: "alpha"
55
66
  },
56
67
  {
57
- title: o && s === "beta" ? "beta (continue)" : "beta",
68
+ title: c && y === "beta" ? "beta (continue)" : "beta",
58
69
  value: "beta"
59
70
  },
60
- { title: o && s === "rc" ? "rc (continue)" : "rc", value: "rc" }
71
+ { title: c && y === "rc" ? "rc (continue)" : "rc", value: "rc" }
61
72
  ]
62
73
  });
63
- if (!y) {
74
+ if (!R) {
64
75
  console.log(n.yellow(`
65
76
  Release cancelled
66
77
  `));
67
78
  return;
68
79
  }
69
- o && s === y ? a.push("prerelease") : a.push("prerelease", "--preid", y), v.tag || (v.tag = y);
70
- } else if (h === "graduate")
71
- a.push("--conventional-graduate");
72
- else if (h === "custom") {
73
- const { pkg: i } = C(r[0]), { customVersion: e } = await w({
80
+ c && y === R ? e.push("prerelease") : e.push("prerelease", "--preid", R), C.tag || (C.tag = R);
81
+ } else if (t === "graduate")
82
+ e.push("--conventional-graduate");
83
+ else if (t === "custom") {
84
+ const { pkg: h } = N(s[0]), { customVersion: w } = await G({
74
85
  type: "text",
75
86
  name: "customVersion",
76
87
  message: "Enter custom version",
77
- initial: i.version,
78
- validate: (s) => S(s) ? !0 : "Invalid semver version"
88
+ initial: h.version,
89
+ validate: (y) => E(y) ? !0 : "Invalid semver version"
79
90
  });
80
- if (!e) {
91
+ if (!w) {
81
92
  console.log(n.yellow(`
82
93
  Release cancelled
83
94
  `));
84
95
  return;
85
96
  }
86
- a.push(e);
87
- const o = G(e);
88
- if (o && o.prerelease.length > 0 && !v.tag) {
89
- const s = o.prerelease[0];
90
- typeof s == "string" && (v.tag = s);
97
+ e.push(w);
98
+ const c = A(w);
99
+ if (c && c.prerelease.length > 0 && !C.tag) {
100
+ const y = c.prerelease[0];
101
+ typeof y == "string" && (C.tag = y);
91
102
  }
92
103
  }
93
- const { yes: u } = await w({
104
+ const { yes: a } = await G({
94
105
  type: "confirm",
95
106
  name: "yes",
96
107
  message: "Ready to release. Continue?"
97
108
  });
98
- if (!u) {
109
+ if (!a) {
99
110
  console.log(n.yellow(`
100
111
  Release cancelled
101
112
  `));
102
113
  return;
103
114
  }
104
- l ? a.push("--no-git-tag-version", "--no-push") : a.push("--no-push"), console.log(n.cyan(`
105
- Running: npx ${a.join(" ")}
115
+ r ? e.push("--no-git-tag-version", "--no-push") : e.push("--no-push"), C.force && (e.push("--force-publish"), console.log(n.yellow(`
116
+ ⚠️ Force publish mode - all packages will be versioned
117
+ `))), console.log(n.cyan(`
118
+ Running: npx ${e.join(" ")}
106
119
  `));
107
- const p = m("npx", a, { stdio: "inherit" });
108
- if (p.status !== 0 && (console.error(n.red(`
120
+ const i = m("npx", e, { stdio: "inherit" });
121
+ if (i.status !== 0 && (console.error(n.red(`
109
122
  ❌ Release process failed
110
- `)), process.exit(p.status || 1)), await j(r), f) {
123
+ `)), process.exit(i.status || 1)), await $(s), d) {
111
124
  console.log(n.cyan(`
112
125
  Running post-version hooks...
113
126
  `));
114
- const { pkg: i } = C(r[0] === "." ? r[1] : r[0]);
115
- await f(i.version);
127
+ const { pkg: h } = N(s[0] === "." ? s[1] : s[0]);
128
+ await d(h.version);
116
129
  }
117
130
  console.log(n.cyan(`
118
131
  Updating yarn.lock with new package versions...
119
132
  `));
120
- const d = m("yarn", ["install"], { stdio: "inherit" });
121
- if (d.status !== 0 && (console.error(n.red(`
133
+ const b = m("yarn", ["install"], { stdio: "inherit" });
134
+ if (b.status !== 0 && (console.error(n.red(`
122
135
  ❌ Failed to update yarn.lock
123
- `)), process.exit(d.status || 1)), await O(r), await H(r), !l && m("git", ["status", "--porcelain"], { stdio: "pipe" }).stdout?.toString().trim()) {
124
- const o = m("git", ["describe", "--tags", "--abbrev=0"], { stdio: "pipe" }).stdout?.toString().trim() || "HEAD";
125
- m("git", ["add", "-A"], { stdio: "inherit" }), m("git", ["commit", "--amend", "--no-edit", "--no-verify"], { stdio: "inherit" }), m("git", ["tag", "-f", o], { stdio: "inherit" }), console.log(n.cyan(`
136
+ `)), process.exit(b.status || 1)), await L(s), await D(s), !r && m("git", ["status", "--porcelain"], { stdio: "pipe" }).stdout?.toString().trim()) {
137
+ const c = m("git", ["describe", "--tags", "--abbrev=0"], { stdio: "pipe" }).stdout?.toString().trim() || "HEAD";
138
+ m("git", ["add", "-A"], { stdio: "inherit" }), m("git", ["commit", "--amend", "--no-edit", "--no-verify"], { stdio: "inherit" }), m("git", ["tag", "-f", c], { stdio: "inherit" }), console.log(n.cyan(`
126
139
  Pushing changes to remote...
127
- `)), m("git", ["push", "origin", "HEAD", "--force-with-lease"], { stdio: "inherit" }), m("git", ["push", "origin", o, "--force"], { stdio: "inherit" }), console.log(n.green(`
140
+ `)), m("git", ["push", "origin", "HEAD", "--force-with-lease"], { stdio: "inherit" }), m("git", ["push", "origin", c, "--force"], { stdio: "inherit" }), console.log(n.green(`
128
141
  ✅ Updated changelogs, package.json, and pushed to remote
129
142
  `));
130
143
  }
131
- l ? (console.log(n.yellow(`
144
+ r ? (console.log(n.yellow(`
132
145
  ✅ Dry run completed successfully!
133
146
  `)), console.log(n.cyan("Changes made:")), console.log(n.cyan(" - Updated package versions")), console.log(n.cyan(" - Generated/updated CHANGELOG.md files")), console.log(n.cyan(" - npmTag will be determined from git tag in CI")), console.log(n.cyan(` - Updated yarn.lock with new package versions
134
147
  `)), console.log(n.yellow("No git operations performed. Review changes with:")), console.log(n.cyan(` git diff
@@ -139,111 +152,113 @@ Pushing changes to remote...
139
152
  ℹ️ npmTag will be automatically determined from git tag in CI`)), console.log(n.cyan(` GitHub Actions will publish with the correct tag based on the git tag
140
153
  `)));
141
154
  };
142
- async function O(r) {
155
+ async function L(s) {
143
156
  console.log(n.cyan(`
144
157
  Enhancing changelogs...
145
158
  `));
146
- for (const g of r) {
159
+ for (const g of s) {
147
160
  if (g === ".") continue;
148
- const c = k.join(g, "CHANGELOG.md");
149
- if (!R(c)) continue;
150
- let t = N(c, "utf-8");
151
- t = t.replace(/^# CHANGELOG\s*\n/gm, ""), t = t.replace(/^# Change Log\s*\n/gm, ""), t = t.replace(/^All notable changes to this (project|package) will be documented in this file\.\s*\n/gm, ""), t = t.replace(
161
+ const l = S.join(g, "CHANGELOG.md");
162
+ if (!j(l)) continue;
163
+ let o = P(l, "utf-8");
164
+ o = o.replace(/^# CHANGELOG\s*\n/gm, ""), o = o.replace(/^# Change Log\s*\n/gm, ""), o = o.replace(/^All notable changes to this (project|package) will be documented in this file\.\s*\n/gm, ""), o = o.replace(
152
165
  /^See \[Conventional Commits\]\(https:\/\/conventionalcommits\.org\) for commit guidelines\.\s*\n/gm,
153
166
  ""
154
- ), t = t.replace(/\n{3,}/g, `
167
+ ), o = o.replace(/\n{3,}/g, `
155
168
 
156
- `), t = t.replace(
169
+ `), o = o.replace(
157
170
  /^(##\s+\[[^\]]+\][^\n]*\n)\n(##\s+\[|$)/gm,
158
171
  `$1
159
172
  **Note:** Version bump only for package
160
173
 
161
174
  $2`
162
- ), t = t.trim() + `
163
- `, b(c, t, "utf-8");
175
+ ), o = o.trim() + `
176
+ `, V(l, o, "utf-8");
164
177
  }
165
178
  }
166
- async function j(r) {
167
- const g = r.find((h) => h !== ".");
179
+ async function $(s) {
180
+ const g = s.find((k) => k !== ".");
168
181
  if (!g) return;
169
- const { pkg: c } = C(g), t = c.version, f = "package.json", l = JSON.parse(N(f, "utf-8"));
170
- l.version !== t && (l.version = t, b(f, JSON.stringify(l, null, 2) + `
171
- `, "utf-8"), console.log(n.gray(` Updated root package.json version: ${t}`)));
182
+ const { pkg: l } = N(g), o = l.version, d = "package.json", r = JSON.parse(P(d, "utf-8"));
183
+ r.version !== o && (r.version = o, V(d, JSON.stringify(r, null, 2) + `
184
+ `, "utf-8"), console.log(n.gray(` Updated root package.json version: ${o}`)));
172
185
  }
173
- async function H(r) {
186
+ async function D(s) {
174
187
  console.log(n.cyan(`
175
188
  Generating root CHANGELOG with package grouping...
176
189
  `));
177
- const g = "CHANGELOG.md", c = {
190
+ const g = "CHANGELOG.md", l = {
178
191
  framework: "VC-Shell Framework (@vc-shell/framework)",
179
192
  "cli/api-client": "API Client Generator (@vc-shell/api-client-generator)",
180
193
  "cli/create-vc-app": "Create VC App (@vc-shell/create-vc-app)",
181
194
  "configs/release-config": "Release Config (@vc-shell/release-config)",
182
195
  "configs/vite-config": "Vite Config (@vc-shell/config-generator)",
183
196
  "configs/ts-config": "TypeScript Config (@vc-shell/ts-config)"
184
- }, t = {}, f = {};
185
- for (const a of r) {
186
- if (a === ".") continue;
187
- const u = k.join(a, "CHANGELOG.md"), p = c[a] || a;
188
- if (!R(u)) continue;
189
- const i = N(u, "utf-8").split(`
197
+ }, o = {}, d = {};
198
+ for (const p of s) {
199
+ if (p === ".") continue;
200
+ const f = S.join(p, "CHANGELOG.md"), u = l[p] || p;
201
+ if (!j(f)) continue;
202
+ const t = P(f, "utf-8").split(`
190
203
  `);
191
- let e = null, o = [];
192
- for (const s of i) {
193
- const y = s.match(/^##\s+(?:\[)?([\d.a-z-]+)(?:\])?(?:\s+\([^)]+\))?/i);
194
- if (y) {
195
- if (e && o.length > 0) {
196
- const P = o.join(`
204
+ let e = null, a = [];
205
+ for (const i of t) {
206
+ const b = i.match(/^##\s+(?:\[)?([\d.a-z-]+)(?:\])?(?:\s+\([^)]+\))?/i);
207
+ if (b) {
208
+ if (e && a.length > 0) {
209
+ const h = a.join(`
197
210
  `).trim();
198
- t[e] || (t[e] = {}), t[e][p] = P;
211
+ o[e] || (o[e] = {}), o[e][u] = h;
199
212
  }
200
- e = y[1], o = [], f[e] || (f[e] = s.replace(/^##\s+/, ""));
201
- } else e && s.trim() !== "" && !s.startsWith("# CHANGELOG") && !s.startsWith("# Change Log") && !s.startsWith("All notable changes") && !s.startsWith("See [Conventional Commits]") && o.push(s);
213
+ e = b[1], a = [], d[e] || (d[e] = i.replace(/^##\s+/, ""));
214
+ } else e && i.trim() !== "" && !i.startsWith("# CHANGELOG") && !i.startsWith("# Change Log") && !i.startsWith("All notable changes") && !i.startsWith("See [Conventional Commits]") && a.push(i);
202
215
  }
203
- if (e && o.length > 0) {
204
- const s = o.join(`
216
+ if (e && a.length > 0) {
217
+ const i = a.join(`
205
218
  `).trim();
206
- t[e] || (t[e] = {}), t[e][p] = s;
219
+ o[e] || (o[e] = {}), o[e][u] = i;
207
220
  }
208
221
  }
209
- let l = "";
210
- const h = Object.keys(t).sort((a, u) => {
211
- const p = a.split(/[.-]/).map((i) => isNaN(parseInt(i)) ? i : parseInt(i)), d = u.split(/[.-]/).map((i) => isNaN(parseInt(i)) ? i : parseInt(i));
212
- for (let i = 0; i < Math.max(p.length, d.length); i++) {
213
- const e = p[i] ?? 0, o = d[i] ?? 0;
214
- if (e !== o)
215
- return typeof e == "number" && typeof o == "number" ? o - e : String(o).localeCompare(String(e));
222
+ let r = "";
223
+ const k = Object.keys(o).sort((p, f) => {
224
+ const u = p.split(/[.-]/).map((t) => isNaN(parseInt(t)) ? t : parseInt(t)), v = f.split(/[.-]/).map((t) => isNaN(parseInt(t)) ? t : parseInt(t));
225
+ for (let t = 0; t < Math.max(u.length, v.length); t++) {
226
+ const e = u[t] ?? 0, a = v[t] ?? 0;
227
+ if (e !== a)
228
+ return typeof e == "number" && typeof a == "number" ? a - e : String(a).localeCompare(String(e));
216
229
  }
217
230
  return 0;
218
231
  });
219
- for (const a of h) {
220
- const u = t[a], p = Object.values(u).some((e) => !e || !e.trim() ? !1 : e.replace(/\*\*Note:\*\*\s+Version bump only[^\n]*/gi, "").trim().length > 0), d = f[a] || a;
221
- if (l += `## ${d}
232
+ for (const p of k) {
233
+ const f = o[p], u = Object.values(f).some((e) => !e || !e.trim() ? !1 : e.replace(/\*\*Note:\*\*\s+Version bump only[^\n]*/gi, "").trim().length > 0), v = d[p] || p;
234
+ if (r += `## ${v}
222
235
 
223
- `, !p) {
224
- l += `**Note:** Version bump only for package
236
+ `, !u) {
237
+ r += `**Note:** Version bump only for package
225
238
 
226
239
  `;
227
240
  continue;
228
241
  }
229
- let i = !1;
230
- for (const e of r) {
242
+ let t = !1;
243
+ for (const e of s) {
231
244
  if (e === ".") continue;
232
- const o = c[e] || e, s = u[o];
233
- s && s.trim() && s.replace(/\*\*Note:\*\*\s+Version bump only[^\n]*/gi, "").trim().length > 0 && (i = !0, l += `### ${o}
245
+ const a = l[e] || e, i = f[a];
246
+ i && i.trim() && i.replace(/\*\*Note:\*\*\s+Version bump only[^\n]*/gi, "").trim().length > 0 && (t = !0, r += `### ${a}
234
247
 
235
- `, l += `${s}
248
+ `, r += `${i}
236
249
 
237
250
  `);
238
251
  }
239
- i || (l += `**Note:** Version bump only for package
252
+ t || (r += `**Note:** Version bump only for package
240
253
 
241
254
  `);
242
255
  }
243
- l = l.replace(/\n{3,}/g, `
256
+ r = r.replace(/\n{3,}/g, `
244
257
 
245
- `), b(g, l, "utf-8"), console.log(n.green(" ✓ Generated root CHANGELOG.md with package grouping"));
258
+ `), V(g, r, "utf-8"), console.log(n.green(" ✓ Generated root CHANGELOG.md with package grouping"));
246
259
  }
247
260
  export {
248
- W as release
261
+ K as generateInitialChangelogs,
262
+ Q as generateRootChangelog,
263
+ z as release
249
264
  };
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli-generate-changelogs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-generate-changelogs.d.ts","sourceRoot":"","sources":["../../src/cli-generate-changelogs.ts"],"names":[],"mappings":""}
@@ -0,0 +1,27 @@
1
+ export interface PackageConfig {
2
+ name: string;
3
+ path: string;
4
+ displayName: string;
5
+ }
6
+ export interface ChangelogGeneratorOptions {
7
+ packages: PackageConfig[];
8
+ rootDir?: string;
9
+ generateRoot?: boolean;
10
+ includeRootHeader?: boolean;
11
+ }
12
+ /**
13
+ * Generates CHANGELOG.md files from all commits for specified packages
14
+ * @param options - Configuration options for changelog generation
15
+ */
16
+ export declare function generateInitialChangelogs(options: ChangelogGeneratorOptions): Promise<void>;
17
+ interface RootChangelogOptions {
18
+ packages: PackageConfig[];
19
+ rootDir?: string;
20
+ includeRootHeader?: boolean;
21
+ }
22
+ /**
23
+ * Generates consolidated root CHANGELOG.md from package changelogs
24
+ */
25
+ export declare function generateRootChangelog(options: RootChangelogOptions): Promise<void>;
26
+ export {};
27
+ //# sourceMappingURL=generate-changelogs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-changelogs.d.ts","sourceRoot":"","sources":["../../src/generate-changelogs.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgFjG;AAED,UAAU,oBAAoB;IAC5B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0JxF"}
@@ -1,2 +1,4 @@
1
1
  export { release } from './release';
2
+ export { generateInitialChangelogs, generateRootChangelog } from './generate-changelogs';
3
+ export type { PackageConfig, ChangelogGeneratorOptions } from './generate-changelogs';
2
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACzF,YAAY,EAAE,aAAa,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC"}
@@ -17,7 +17,7 @@ export declare const release: ({ packages, bumpVersion, generateChangelog, toTag
17
17
  * @param workspaceName
18
18
  * @returns
19
19
  */
20
- customHooks: (version: string) => void | Promise<void>;
20
+ customHooks?: (version: string) => void | Promise<void>;
21
21
  /** @deprecated Lerna handles version bumping automatically */
22
22
  bumpVersion?: (pkgName: string, version: string) => void | Promise<void>;
23
23
  /** @deprecated Lerna generates changelogs automatically */
@@ -1 +1 @@
1
- {"version":3,"file":"release.d.ts","sourceRoot":"","sources":["../../src/release.ts"],"names":[],"mappings":"AASA;;;;;;;;;GASG;AACH,eAAO,MAAM,OAAO,GAAU,mEAM3B;IACD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB;;;;;;OAMG;IACH,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,8DAA8D;IAC9D,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE,2DAA2D;IAC3D,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvG,8DAA8D;IAC9D,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;CACrC,kBAqMA,CAAC"}
1
+ {"version":3,"file":"release.d.ts","sourceRoot":"","sources":["../../src/release.ts"],"names":[],"mappings":"AASA;;;;;;;;;GASG;AACH,eAAO,MAAM,OAAO,GAAU,mEAM3B;IACD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,8DAA8D;IAC9D,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE,2DAA2D;IAC3D,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvG,8DAA8D;IAC9D,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;CACrC,kBAiOA,CAAC"}
package/package.json CHANGED
@@ -1,17 +1,21 @@
1
1
  {
2
2
  "name": "@vc-shell/release-config",
3
- "version": "1.2.1",
3
+ "version": "1.2.3-beta.0",
4
4
  "type": "module",
5
5
  "main": "dist/release-config.js",
6
6
  "types": "./dist/src/index.d.ts",
7
7
  "files": [
8
8
  "dist"
9
9
  ],
10
+ "bin": {
11
+ "vc-generate-changelogs": "./dist/cli-generate-changelogs.js"
12
+ },
10
13
  "scripts": {
11
14
  "build": "vite build"
12
15
  },
13
16
  "dependencies": {
14
17
  "chalk": "^2.4.2",
18
+ "conventional-changelog-cli": "^5.0.0",
15
19
  "cross-spawn": "^7.0.3",
16
20
  "lerna": "^9.0.0",
17
21
  "mri": "^1.2.0",
@@ -30,5 +34,5 @@
30
34
  "access": "public",
31
35
  "registry": "https://registry.npmjs.org/"
32
36
  },
33
- "gitHead": "75afdc6afb8a3563385e526f9384a34557fe3561"
37
+ "gitHead": "1394fe061df6f536cd2f0dac0e2a6082eb0c2b64"
34
38
  }