@williamthorsen/release-kit 0.2.3 → 1.0.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,15 +1,20 @@
1
- const DEFAULT_WORK_TYPES = [
2
- { type: "fix", header: "Bug fixes", bump: "patch", aliases: ["bugfix"] },
3
- { type: "feat", header: "Features", bump: "minor", aliases: ["feature"] },
4
- { type: "internal", header: "Internal", bump: "patch" },
5
- { type: "refactor", header: "Refactoring", bump: "patch" },
6
- { type: "tests", header: "Tests", bump: "patch", aliases: ["test"] },
7
- { type: "tooling", header: "Tooling", bump: "patch" },
8
- { type: "ci", header: "CI", bump: "patch" },
9
- { type: "deps", header: "Dependencies", bump: "patch", aliases: ["dep"] },
10
- { type: "docs", header: "Documentation", bump: "patch", aliases: ["doc"] },
11
- { type: "fmt", header: "Formatting", bump: "patch" }
12
- ];
1
+ const DEFAULT_WORK_TYPES = {
2
+ fix: { header: "Bug fixes", aliases: ["bugfix"] },
3
+ feat: { header: "Features", aliases: ["feature"] },
4
+ internal: { header: "Internal" },
5
+ refactor: { header: "Refactoring" },
6
+ tests: { header: "Tests", aliases: ["test"] },
7
+ tooling: { header: "Tooling" },
8
+ ci: { header: "CI" },
9
+ deps: { header: "Dependencies", aliases: ["dep"] },
10
+ docs: { header: "Documentation", aliases: ["doc"] },
11
+ fmt: { header: "Formatting" }
12
+ };
13
+ const DEFAULT_VERSION_PATTERNS = {
14
+ major: ["!"],
15
+ minor: ["feat", "feature"]
16
+ };
13
17
  export {
18
+ DEFAULT_VERSION_PATTERNS,
14
19
  DEFAULT_WORK_TYPES
15
20
  };
@@ -1,2 +1,2 @@
1
- import type { ParsedCommit, ReleaseType, WorkTypeConfig } from './types.ts';
2
- export declare function determineBumpType(commits: readonly ParsedCommit[], workTypes: readonly WorkTypeConfig[]): ReleaseType | undefined;
1
+ import type { ParsedCommit, ReleaseType, VersionPatterns, WorkTypeConfig } from './types.ts';
2
+ export declare function determineBumpType(commits: readonly ParsedCommit[], workTypes: Record<string, WorkTypeConfig>, versionPatterns: VersionPatterns): ReleaseType | undefined;
@@ -3,24 +3,25 @@ const RELEASE_PRIORITY = {
3
3
  minor: 2,
4
4
  patch: 1
5
5
  };
6
- function determineBumpType(commits, workTypes) {
7
- const typeToBump = {};
8
- for (const config of workTypes) {
9
- typeToBump[config.type] = config.bump;
10
- }
6
+ function determineBumpType(commits, workTypes, versionPatterns) {
7
+ const knownTypes = new Set(Object.keys(workTypes));
11
8
  let highestPriority = 0;
12
9
  let result;
13
10
  for (const commit of commits) {
14
- if (commit.breaking) {
11
+ if (commit.breaking && versionPatterns.major.includes("!")) {
15
12
  return "major";
16
13
  }
17
14
  const commitType = commit.type;
18
- if (!isKeyOf(commitType, typeToBump)) {
15
+ if (!knownTypes.has(commitType)) {
19
16
  continue;
20
17
  }
21
- const bump = typeToBump[commitType];
22
- if (bump === void 0) {
23
- continue;
18
+ let bump;
19
+ if (versionPatterns.major.includes(commitType)) {
20
+ bump = "major";
21
+ } else if (versionPatterns.minor.includes(commitType)) {
22
+ bump = "minor";
23
+ } else {
24
+ bump = "patch";
24
25
  }
25
26
  const priority = RELEASE_PRIORITY[bump];
26
27
  if (priority > highestPriority) {
@@ -30,9 +31,6 @@ function determineBumpType(commits, workTypes) {
30
31
  }
31
32
  return result;
32
33
  }
33
- function isKeyOf(key, obj) {
34
- return Object.hasOwn(obj, key);
35
- }
36
34
  export {
37
35
  determineBumpType
38
36
  };
@@ -0,0 +1 @@
1
+ export declare function discoverWorkspaces(): Promise<string[] | undefined>;
@@ -0,0 +1,45 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { glob } from "glob";
4
+ import { load } from "js-yaml";
5
+ async function discoverWorkspaces() {
6
+ const workspaceFile = "pnpm-workspace.yaml";
7
+ if (!existsSync(workspaceFile)) {
8
+ return void 0;
9
+ }
10
+ let content;
11
+ try {
12
+ content = readFileSync(workspaceFile, "utf8");
13
+ } catch (error) {
14
+ console.warn(`Warning: Failed to read ${workspaceFile}: ${error instanceof Error ? error.message : String(error)}`);
15
+ return void 0;
16
+ }
17
+ const parsed = load(content);
18
+ if (!isRecord(parsed)) {
19
+ return void 0;
20
+ }
21
+ const packagesField = parsed.packages;
22
+ if (!Array.isArray(packagesField)) {
23
+ return void 0;
24
+ }
25
+ const patterns = packagesField.filter((p) => typeof p === "string");
26
+ if (patterns.length === 0) {
27
+ return void 0;
28
+ }
29
+ const directories = [];
30
+ for (const pattern of patterns) {
31
+ const matches = await glob(pattern, { posix: true });
32
+ for (const match of matches) {
33
+ if (existsSync(join(match, "package.json"))) {
34
+ directories.push(match);
35
+ }
36
+ }
37
+ }
38
+ return directories.length > 0 ? [...directories].sort() : void 0;
39
+ }
40
+ function isRecord(value) {
41
+ return typeof value === "object" && value !== null && !Array.isArray(value);
42
+ }
43
+ export {
44
+ discoverWorkspaces
45
+ };
@@ -20,6 +20,7 @@ function findLatestTag(tagPrefix) {
20
20
  throw new Error(`Failed to run 'git describe': ${errorMessage(error)}`);
21
21
  }
22
22
  }
23
+ const RELEASE_COMMIT_PREFIX = "release:";
23
24
  function parseLogOutput(logOutput) {
24
25
  const commits = [];
25
26
  for (const line of logOutput.split("\n")) {
@@ -28,7 +29,7 @@ function parseLogOutput(logOutput) {
28
29
  continue;
29
30
  }
30
31
  const [message, hash] = trimmedLine.split(FIELD_SEPARATOR);
31
- if (message !== void 0 && hash !== void 0) {
32
+ if (message !== void 0 && hash !== void 0 && !message.startsWith(RELEASE_COMMIT_PREFIX)) {
32
33
  commits.push({ message, hash });
33
34
  }
34
35
  }
@@ -1,13 +1,15 @@
1
1
  export type { GenerateChangelogOptions } from './generateChangelogs.ts';
2
2
  export type { ReleasePrepareOptions } from './releasePrepare.ts';
3
- export type { Commit, ComponentConfig, MonorepoReleaseConfig, ParsedCommit, ReleaseConfig, ReleaseType, WorkTypeConfig, } from './types.ts';
4
- export { DEFAULT_WORK_TYPES } from './defaults.ts';
3
+ export type { Commit, ComponentConfig, ComponentOverride, MonorepoReleaseConfig, ParsedCommit, ReleaseConfig, ReleaseKitConfig, ReleaseType, VersionPatterns, WorkTypeConfig, } from './types.ts';
4
+ export { DEFAULT_VERSION_PATTERNS, DEFAULT_WORK_TYPES } from './defaults.ts';
5
5
  export { bumpAllVersions } from './bumpAllVersions.ts';
6
6
  export { bumpVersion } from './bumpVersion.ts';
7
+ export { component } from './component.ts';
7
8
  export { determineBumpType } from './determineBumpType.ts';
9
+ export { discoverWorkspaces } from './discoverWorkspaces.ts';
8
10
  export { generateChangelog, generateChangelogs } from './generateChangelogs.ts';
9
11
  export { getCommitsSinceTarget } from './getCommitsSinceTarget.ts';
10
12
  export { parseCommitMessage } from './parseCommitMessage.ts';
11
13
  export { releasePrepare } from './releasePrepare.ts';
12
14
  export { releasePrepareMono } from './releasePrepareMono.ts';
13
- export { runReleasePrepare } from './runReleasePrepare.ts';
15
+ export { RELEASE_TAGS_FILE, runReleasePrepare, writeReleaseTags } from './runReleasePrepare.ts';
package/dist/esm/index.js CHANGED
@@ -1,23 +1,30 @@
1
- import { DEFAULT_WORK_TYPES } from "./defaults.js";
1
+ import { DEFAULT_VERSION_PATTERNS, DEFAULT_WORK_TYPES } from "./defaults.js";
2
2
  import { bumpAllVersions } from "./bumpAllVersions.js";
3
3
  import { bumpVersion } from "./bumpVersion.js";
4
+ import { component } from "./component.js";
4
5
  import { determineBumpType } from "./determineBumpType.js";
6
+ import { discoverWorkspaces } from "./discoverWorkspaces.js";
5
7
  import { generateChangelog, generateChangelogs } from "./generateChangelogs.js";
6
8
  import { getCommitsSinceTarget } from "./getCommitsSinceTarget.js";
7
9
  import { parseCommitMessage } from "./parseCommitMessage.js";
8
10
  import { releasePrepare } from "./releasePrepare.js";
9
11
  import { releasePrepareMono } from "./releasePrepareMono.js";
10
- import { runReleasePrepare } from "./runReleasePrepare.js";
12
+ import { RELEASE_TAGS_FILE, runReleasePrepare, writeReleaseTags } from "./runReleasePrepare.js";
11
13
  export {
14
+ DEFAULT_VERSION_PATTERNS,
12
15
  DEFAULT_WORK_TYPES,
16
+ RELEASE_TAGS_FILE,
13
17
  bumpAllVersions,
14
18
  bumpVersion,
19
+ component,
15
20
  determineBumpType,
21
+ discoverWorkspaces,
16
22
  generateChangelog,
17
23
  generateChangelogs,
18
24
  getCommitsSinceTarget,
19
25
  parseCommitMessage,
20
26
  releasePrepare,
21
27
  releasePrepareMono,
22
- runReleasePrepare
28
+ runReleasePrepare,
29
+ writeReleaseTags
23
30
  };
@@ -39,12 +39,12 @@ function hasCliffToml() {
39
39
  return { ok: false, message: "No cliff.toml found. This file is required for changelog generation." };
40
40
  }
41
41
  function notAlreadyInitialized() {
42
- if (!existsSync(".github/scripts/release.config.ts")) {
42
+ if (!existsSync(".config/release-kit.config.ts") && !existsSync(".github/scripts/release.config.ts")) {
43
43
  return { ok: true };
44
44
  }
45
45
  return {
46
46
  ok: false,
47
- message: "release-kit appears to be already initialized (.github/scripts/release.config.ts exists)."
47
+ message: "release-kit appears to be already initialized."
48
48
  };
49
49
  }
50
50
  export {
@@ -54,12 +54,9 @@ async function initCommand({ dryRun }) {
54
54
  scaffoldFiles({ repoType, dryRun, overwrite: eligibility.overwrite });
55
55
  printStep("Next steps");
56
56
  console.info(`
57
- 1. Customize .github/scripts/release.config.ts for your project
58
- 2. Set the correct node-version and pnpm-version in .github/workflows/release.yaml
59
- 3. Install required dev dependencies: pnpm add --save-dev tsx @williamthorsen/release-kit
60
- 4. Install git-cliff if not already installed: https://git-cliff.org/docs/installation
61
- 5. Create an initial version tag (e.g., git tag v0.0.0)
62
- 6. Test with a dry run: pnpm run release:prepare:dry
57
+ 1. (Optional) Customize .config/release-kit.config.ts to exclude components, override version patterns, add custom work types, etc.
58
+ 2. Test by running: npx @williamthorsen/release-kit prepare --dry-run
59
+ 3. Commit the generated workflow file (and config file if created).
63
60
  `);
64
61
  return 0;
65
62
  }
@@ -1,9 +1,8 @@
1
1
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { dirname, resolve } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
- import { parseJsonRecord } from "./parseJsonRecord.js";
5
4
  import { printError, printSkip, printSuccess } from "./prompt.js";
6
- import { releaseConfigScript, releasePrepareScript, releaseWorkflow } from "./templates.js";
5
+ import { releaseConfigScript, releaseWorkflow } from "./templates.js";
7
6
  function tryWriteFile(filePath, content) {
8
7
  try {
9
8
  writeFileSync(filePath, content, "utf8");
@@ -53,60 +52,12 @@ function copyCliffTemplate(dryRun) {
53
52
  }
54
53
  function scaffoldFiles({ repoType, dryRun, overwrite }) {
55
54
  const files = [
56
- { path: ".github/scripts/release-prepare.ts", content: releasePrepareScript() },
57
- { path: ".github/scripts/release.config.ts", content: releaseConfigScript(repoType) },
55
+ { path: ".config/release-kit.config.ts", content: releaseConfigScript(repoType) },
58
56
  { path: ".github/workflows/release.yaml", content: releaseWorkflow(repoType) }
59
57
  ];
60
58
  for (const file of files) {
61
59
  writeIfAbsent(file.path, file.content, dryRun, overwrite);
62
60
  }
63
- updatePackageJsonScripts(dryRun);
64
- }
65
- function readPackageJson(pkgPath) {
66
- let raw;
67
- try {
68
- raw = readFileSync(pkgPath, "utf8");
69
- } catch (error) {
70
- const message = error instanceof Error ? error.message : String(error);
71
- printError(`Failed to read ${pkgPath}: ${message}`);
72
- return void 0;
73
- }
74
- const pkg = parseJsonRecord(raw);
75
- if (pkg === void 0) {
76
- printError("Failed to parse package.json");
77
- }
78
- return pkg;
79
- }
80
- function updatePackageJsonScripts(dryRun) {
81
- const pkgPath = "package.json";
82
- const pkg = readPackageJson(pkgPath);
83
- if (pkg === void 0) {
84
- return;
85
- }
86
- const existingScripts = pkg.scripts;
87
- const scripts = typeof existingScripts === "object" && existingScripts !== null && !Array.isArray(existingScripts) ? { ...existingScripts } : {};
88
- let changed = false;
89
- if (!("release:prepare" in scripts)) {
90
- scripts["release:prepare"] = "tsx .github/scripts/release-prepare.ts";
91
- changed = true;
92
- }
93
- if (!("release:prepare:dry" in scripts)) {
94
- scripts["release:prepare:dry"] = "tsx .github/scripts/release-prepare.ts --dry-run";
95
- changed = true;
96
- }
97
- if (!changed) {
98
- printSuccess("package.json scripts already configured");
99
- return;
100
- }
101
- if (dryRun) {
102
- printSuccess("[dry-run] Would add release:prepare scripts to package.json");
103
- return;
104
- }
105
- pkg.scripts = scripts;
106
- if (tryWriteFile(pkgPath, `${JSON.stringify(pkg, null, 2)}
107
- `)) {
108
- printSuccess("Added release:prepare scripts to package.json");
109
- }
110
61
  }
111
62
  export {
112
63
  copyCliffTemplate,
@@ -1,4 +1,3 @@
1
1
  import type { RepoType } from './detectRepoType.ts';
2
- export declare function releasePrepareScript(): string;
3
2
  export declare function releaseConfigScript(repoType: RepoType): string;
4
3
  export declare function releaseWorkflow(repoType: RepoType): string;
@@ -1,49 +1,35 @@
1
- function releasePrepareScript() {
2
- return `import { runReleasePrepare } from '@williamthorsen/release-kit';
3
-
4
- import { config } from './release.config.js';
5
-
6
- runReleasePrepare(config);
7
- `;
8
- }
9
1
  function releaseConfigScript(repoType) {
10
2
  if (repoType === "monorepo") {
11
- return `import type { MonorepoReleaseConfig } from '@williamthorsen/release-kit';
12
- import { DEFAULT_WORK_TYPES } from '@williamthorsen/release-kit';
3
+ return `import type { ReleaseKitConfig } from '@williamthorsen/release-kit';
13
4
 
14
- // TODO: Replace with your actual component directories
15
- function component(dir: string) {
16
- return {
17
- tagPrefix: \`\${dir}-v\`,
18
- packageFiles: [\`packages/\${dir}/package.json\`],
19
- changelogPaths: [\`packages/\${dir}\`],
20
- paths: [\`packages/\${dir}/**\`],
21
- };
22
- }
23
-
24
- export const config: MonorepoReleaseConfig = {
25
- components: [
26
- // TODO: Add your components here
27
- // component('my-package'),
28
- ],
29
- workTypes: [...DEFAULT_WORK_TYPES],
5
+ const config: ReleaseKitConfig = {
6
+ // Uncomment to exclude components from release processing:
7
+ // components: [
8
+ // { dir: 'my-package', shouldExclude: true },
9
+ // ],
10
+ // Uncomment to override the default version patterns:
11
+ // versionPatterns: { major: ['!'], minor: ['feat', 'feature'] },
12
+ // Uncomment to add custom work types (merged with defaults):
13
+ // workTypes: { perf: { header: 'Performance' } },
30
14
  // TODO: Uncomment and adjust if you have a format command
31
15
  // formatCommand: 'pnpm run fmt',
32
16
  };
17
+
18
+ export default config;
33
19
  `;
34
20
  }
35
- return `import type { ReleaseConfig } from '@williamthorsen/release-kit';
36
- import { DEFAULT_WORK_TYPES } from '@williamthorsen/release-kit';
21
+ return `import type { ReleaseKitConfig } from '@williamthorsen/release-kit';
37
22
 
38
- export const config: ReleaseConfig = {
39
- // TODO: Adjust the tag prefix if needed (e.g., 'v' for tags like v1.2.3)
40
- tagPrefix: 'v',
41
- packageFiles: ['package.json'],
42
- changelogPaths: ['.'],
43
- workTypes: [...DEFAULT_WORK_TYPES],
23
+ const config: ReleaseKitConfig = {
24
+ // Uncomment to override the default version patterns:
25
+ // versionPatterns: { major: ['!'], minor: ['feat', 'feature'] },
26
+ // Uncomment to add custom work types (merged with defaults):
27
+ // workTypes: { perf: { header: 'Performance' } },
44
28
  // TODO: Uncomment and adjust if you have a format command
45
29
  // formatCommand: 'pnpm run fmt',
46
30
  };
31
+
32
+ export default config;
47
33
  `;
48
34
  }
49
35
  function releaseWorkflow(repoType) {
@@ -74,12 +60,11 @@ permissions:
74
60
 
75
61
  jobs:
76
62
  release:
77
- uses: williamthorsen/.github/.github/workflows/release-pnpm.yaml@v1
63
+ uses: williamthorsen/.github/.github/workflows/release-pnpm.yaml@v2
78
64
  with:
79
65
  # TODO: Set the Node.js and pnpm versions for your project
80
- node-version: '22.0.0'
81
- pnpm-version: '10.0.0'
82
- monorepo: true
66
+ node-version: '24'
67
+ pnpm-version: '10.32.1'
83
68
  only: \${{ inputs.only }}
84
69
  bump: \${{ inputs.bump }}
85
70
  `;
@@ -106,16 +91,15 @@ permissions:
106
91
 
107
92
  jobs:
108
93
  release:
109
- uses: williamthorsen/.github/.github/workflows/release-pnpm.yaml@v1
94
+ uses: williamthorsen/.github/.github/workflows/release-pnpm.yaml@v2
110
95
  with:
111
96
  # TODO: Set the Node.js and pnpm versions for your project
112
- node-version: '22.0.0'
113
- pnpm-version: '10.0.0'
97
+ node-version: '24'
98
+ pnpm-version: '10.32.1'
114
99
  bump: \${{ inputs.bump }}
115
100
  `;
116
101
  }
117
102
  export {
118
103
  releaseConfigScript,
119
- releasePrepareScript,
120
104
  releaseWorkflow
121
105
  };
@@ -0,0 +1,5 @@
1
+ import type { MonorepoReleaseConfig, ReleaseConfig, ReleaseKitConfig } from './types.ts';
2
+ export declare const CONFIG_FILE_PATH = ".config/release-kit.config.ts";
3
+ export declare function loadConfig(): Promise<unknown>;
4
+ export declare function mergeMonorepoConfig(discoveredPaths: string[], userConfig: ReleaseKitConfig | undefined): MonorepoReleaseConfig;
5
+ export declare function mergeSinglePackageConfig(userConfig: ReleaseKitConfig | undefined): ReleaseConfig;
@@ -0,0 +1,91 @@
1
+ import { existsSync } from "node:fs";
2
+ import { component } from "./component.js";
3
+ import { DEFAULT_VERSION_PATTERNS, DEFAULT_WORK_TYPES } from "./defaults.js";
4
+ const CONFIG_FILE_PATH = ".config/release-kit.config.ts";
5
+ async function loadConfig() {
6
+ if (!existsSync(CONFIG_FILE_PATH)) {
7
+ return void 0;
8
+ }
9
+ const { createJiti } = await import("jiti");
10
+ const jiti = createJiti(import.meta.url);
11
+ const imported = await jiti.import(CONFIG_FILE_PATH);
12
+ if (!isRecord(imported)) {
13
+ throw new Error(`Config file must export an object, got ${Array.isArray(imported) ? "array" : typeof imported}`);
14
+ }
15
+ const resolved = imported.default ?? imported.config;
16
+ if (resolved === void 0) {
17
+ throw new Error(
18
+ "Config file must have a default export or a named `config` export (e.g., `export default { ... }` or `export const config = { ... }`)"
19
+ );
20
+ }
21
+ return resolved;
22
+ }
23
+ function isRecord(value) {
24
+ return typeof value === "object" && value !== null && !Array.isArray(value);
25
+ }
26
+ function mergeMonorepoConfig(discoveredPaths, userConfig) {
27
+ let components = discoveredPaths.map((workspacePath) => component(workspacePath));
28
+ if (userConfig?.components !== void 0) {
29
+ const overrides = new Map(userConfig.components.map((c) => [c.dir, c]));
30
+ components = components.filter((c) => {
31
+ const override = overrides.get(c.dir);
32
+ return override?.shouldExclude !== true;
33
+ }).map((c) => {
34
+ const override = overrides.get(c.dir);
35
+ if (override?.tagPrefix !== void 0) {
36
+ return { ...c, tagPrefix: override.tagPrefix };
37
+ }
38
+ return c;
39
+ });
40
+ }
41
+ const workTypes = userConfig?.workTypes === void 0 ? { ...DEFAULT_WORK_TYPES } : { ...DEFAULT_WORK_TYPES, ...userConfig.workTypes };
42
+ const versionPatterns = userConfig?.versionPatterns === void 0 ? { ...DEFAULT_VERSION_PATTERNS } : { ...userConfig.versionPatterns };
43
+ const result = {
44
+ components,
45
+ workTypes,
46
+ versionPatterns
47
+ };
48
+ const formatCommand = userConfig?.formatCommand;
49
+ if (formatCommand !== void 0) {
50
+ result.formatCommand = formatCommand;
51
+ }
52
+ const cliffConfigPath = userConfig?.cliffConfigPath;
53
+ if (cliffConfigPath !== void 0) {
54
+ result.cliffConfigPath = cliffConfigPath;
55
+ }
56
+ const workspaceAliases = userConfig?.workspaceAliases;
57
+ if (workspaceAliases !== void 0) {
58
+ result.workspaceAliases = workspaceAliases;
59
+ }
60
+ return result;
61
+ }
62
+ function mergeSinglePackageConfig(userConfig) {
63
+ const workTypes = userConfig?.workTypes === void 0 ? { ...DEFAULT_WORK_TYPES } : { ...DEFAULT_WORK_TYPES, ...userConfig.workTypes };
64
+ const versionPatterns = userConfig?.versionPatterns === void 0 ? { ...DEFAULT_VERSION_PATTERNS } : { ...userConfig.versionPatterns };
65
+ const result = {
66
+ tagPrefix: "v",
67
+ packageFiles: ["package.json"],
68
+ changelogPaths: ["."],
69
+ workTypes,
70
+ versionPatterns
71
+ };
72
+ const formatCommand = userConfig?.formatCommand;
73
+ if (formatCommand !== void 0) {
74
+ result.formatCommand = formatCommand;
75
+ }
76
+ const cliffConfigPath = userConfig?.cliffConfigPath;
77
+ if (cliffConfigPath !== void 0) {
78
+ result.cliffConfigPath = cliffConfigPath;
79
+ }
80
+ const workspaceAliases = userConfig?.workspaceAliases;
81
+ if (workspaceAliases !== void 0) {
82
+ result.workspaceAliases = workspaceAliases;
83
+ }
84
+ return result;
85
+ }
86
+ export {
87
+ CONFIG_FILE_PATH,
88
+ loadConfig,
89
+ mergeMonorepoConfig,
90
+ mergeSinglePackageConfig
91
+ };
@@ -1,2 +1,2 @@
1
1
  import type { ParsedCommit, WorkTypeConfig } from './types.ts';
2
- export declare function parseCommitMessage(message: string, hash: string, workTypes: readonly WorkTypeConfig[], workspaceAliases?: Record<string, string>): ParsedCommit | undefined;
2
+ export declare function parseCommitMessage(message: string, hash: string, workTypes: Record<string, WorkTypeConfig>, workspaceAliases?: Record<string, string>): ParsedCommit | undefined;
@@ -27,14 +27,14 @@ function parseCommitMessage(message, hash, workTypes, workspaceAliases) {
27
27
  }
28
28
  function resolveType(rawType, workTypes) {
29
29
  const lowered = rawType.toLowerCase();
30
- for (const config of workTypes) {
31
- if (config.type === lowered) {
32
- return config.type;
30
+ for (const [key, config] of Object.entries(workTypes)) {
31
+ if (key === lowered) {
32
+ return key;
33
33
  }
34
34
  if (config.aliases !== void 0) {
35
35
  for (const alias of config.aliases) {
36
36
  if (alias === lowered) {
37
- return config.type;
37
+ return key;
38
38
  }
39
39
  }
40
40
  }
@@ -0,0 +1 @@
1
+ export declare function prepareCommand(argv: string[]): Promise<void>;
@@ -0,0 +1,77 @@
1
+ import { discoverWorkspaces } from "./discoverWorkspaces.js";
2
+ import { loadConfig, mergeMonorepoConfig, mergeSinglePackageConfig } from "./loadConfig.js";
3
+ import { releasePrepare } from "./releasePrepare.js";
4
+ import { releasePrepareMono } from "./releasePrepareMono.js";
5
+ import { parseArgs, RELEASE_TAGS_FILE, writeReleaseTags } from "./runReleasePrepare.js";
6
+ import { validateConfig } from "./validateConfig.js";
7
+ async function prepareCommand(argv) {
8
+ const { dryRun, bumpOverride, only } = parseArgs(argv);
9
+ const options = { dryRun, ...bumpOverride === void 0 ? {} : { bumpOverride } };
10
+ let rawConfig;
11
+ try {
12
+ rawConfig = await loadConfig();
13
+ } catch (error) {
14
+ console.error(`Error loading config: ${error instanceof Error ? error.message : String(error)}`);
15
+ process.exit(1);
16
+ }
17
+ let userConfig;
18
+ if (rawConfig !== void 0) {
19
+ const { config, errors } = validateConfig(rawConfig);
20
+ if (errors.length > 0) {
21
+ console.error("Invalid config:");
22
+ for (const err of errors) {
23
+ console.error(` - ${err}`);
24
+ }
25
+ process.exit(1);
26
+ }
27
+ userConfig = config;
28
+ }
29
+ let discoveredPaths;
30
+ try {
31
+ discoveredPaths = await discoverWorkspaces();
32
+ } catch (error) {
33
+ console.error(`Error discovering workspaces: ${error instanceof Error ? error.message : String(error)}`);
34
+ process.exit(1);
35
+ }
36
+ let tags = [];
37
+ if (discoveredPaths === void 0) {
38
+ if (only !== void 0) {
39
+ console.error("Error: --only is only supported for monorepo configurations");
40
+ process.exit(1);
41
+ }
42
+ const config = mergeSinglePackageConfig(userConfig);
43
+ try {
44
+ tags = releasePrepare(config, options);
45
+ writeReleaseTags(tags, dryRun);
46
+ } catch (error) {
47
+ console.error("Error preparing release:", error instanceof Error ? error.message : String(error));
48
+ process.exit(1);
49
+ }
50
+ } else {
51
+ const config = mergeMonorepoConfig(discoveredPaths, userConfig);
52
+ if (only !== void 0) {
53
+ const knownNames = config.components.map((c) => c.dir);
54
+ for (const name of only) {
55
+ if (!knownNames.includes(name)) {
56
+ console.error(`Error: Unknown component "${name}". Known components: ${knownNames.join(", ")}`);
57
+ process.exit(1);
58
+ }
59
+ }
60
+ config.components = config.components.filter((c) => only.includes(c.dir));
61
+ }
62
+ try {
63
+ tags = releasePrepareMono(config, options);
64
+ writeReleaseTags(tags, dryRun);
65
+ } catch (error) {
66
+ console.error("Error preparing release:", error instanceof Error ? error.message : String(error));
67
+ process.exit(1);
68
+ }
69
+ }
70
+ if (tags.length > 0) {
71
+ console.info(`
72
+ Release tags file: ${RELEASE_TAGS_FILE}`);
73
+ }
74
+ }
75
+ export {
76
+ prepareCommand
77
+ };
@@ -1,19 +1,22 @@
1
1
  import { execSync } from "node:child_process";
2
2
  import { bumpAllVersions } from "./bumpAllVersions.js";
3
+ import { DEFAULT_VERSION_PATTERNS, DEFAULT_WORK_TYPES } from "./defaults.js";
3
4
  import { determineBumpType } from "./determineBumpType.js";
4
5
  import { generateChangelogs } from "./generateChangelogs.js";
5
6
  import { getCommitsSinceTarget } from "./getCommitsSinceTarget.js";
6
7
  import { parseCommitMessage } from "./parseCommitMessage.js";
7
8
  function releasePrepare(config, options) {
8
9
  const { dryRun, bumpOverride } = options;
10
+ const workTypes = config.workTypes ?? { ...DEFAULT_WORK_TYPES };
11
+ const versionPatterns = config.versionPatterns ?? { ...DEFAULT_VERSION_PATTERNS };
9
12
  console.info("Finding commits since last release...");
10
13
  const { tag, commits } = getCommitsSinceTarget(config.tagPrefix);
11
14
  console.info(` Found ${commits.length} commits since ${tag ?? "the beginning"}`);
12
15
  let releaseType;
13
16
  if (bumpOverride === void 0) {
14
- const parsedCommits = commits.map((c) => parseCommitMessage(c.message, c.hash, config.workTypes, config.workspaceAliases)).filter((c) => c !== void 0);
17
+ const parsedCommits = commits.map((c) => parseCommitMessage(c.message, c.hash, workTypes, config.workspaceAliases)).filter((c) => c !== void 0);
15
18
  console.info(` Parsed ${parsedCommits.length} typed commits`);
16
- releaseType = determineBumpType(parsedCommits, config.workTypes);
19
+ releaseType = determineBumpType(parsedCommits, workTypes, versionPatterns);
17
20
  } else {
18
21
  releaseType = bumpOverride;
19
22
  console.info(` Using bump override: ${releaseType}`);