@varlet/release 1.2.0 → 2.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.
package/README.md CHANGED
@@ -46,9 +46,9 @@ When executing `vr release`, the following sequence of lifecycles occurs automat
46
46
  npx vr release
47
47
 
48
48
  # Specify remote name
49
- npx vr release -r https://github.com/varletjs/varlet-release
49
+ npx vr release -r origin
50
50
  # or
51
- npx vr release --remote https://github.com/varletjs/varlet-release
51
+ npx vr release --remote origin
52
52
 
53
53
  # Just generate changelogs
54
54
  npx vr changelog
@@ -59,10 +59,16 @@ npx vr changelog -f changelog.md
59
59
  npx vr changelog --file changelog.md
60
60
 
61
61
  # Lint commit message
62
- npx vr lint-commit -p .git/COMMIT_EDITMSG
62
+ npx vr commit-lint -p .git/COMMIT_EDITMSG
63
63
 
64
64
  # Publish to npm, which can be called in the ci environment
65
65
  npx vr publish
66
+
67
+ # Check if lockfile has been updated
68
+ npx vr lockfile-sync-check
69
+
70
+ # Auto install dependencies if lockfile changed
71
+ npx vr lockfile-sync-check -i
66
72
  ```
67
73
 
68
74
  ### Git Hooks Integration (Best Practice)
@@ -72,7 +78,7 @@ It is highly recommended to use `commit-lint` with `simple-git-hooks` or `husky`
72
78
  ```json
73
79
  {
74
80
  "simple-git-hooks": {
75
- "commit-msg": "npx vr lint-commit -p $1"
81
+ "commit-msg": "npx vr commit-lint -p $1"
76
82
  }
77
83
  }
78
84
  ```
@@ -81,38 +87,59 @@ It is highly recommended to use `commit-lint` with `simple-git-hooks` or `husky`
81
87
 
82
88
  #### release
83
89
 
84
- | Params | Instructions | Default |
85
- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------- | -------- |
86
- | -r --remote \<remote\> | Specify remote name | `origin` |
87
- | -s --skip-npm-publish | Skip npm publish | `false` |
88
- | -c --check-remote-version | Check if the remote version of the npm package is the same as the one you want to publish locally, if so, stop execution. | `false` |
89
- | -sc --skip-changelog | Skip generate changelog | `false` |
90
- | -sgt --skip-git-tag | Skip git tag | `false` |
91
- | -nt --npm-tag \<npmTag\> | npm tag | `-` |
90
+ ```
91
+ Usage: vr release [flags...]
92
+
93
+ Flags:
94
+ -r, --remote <string> Remote name
95
+ -s, --skip-npm-publish Skip npm publish
96
+ --skip-changelog Skip generate changelog
97
+ --skip-git-tag Skip git tag
98
+ -t, --npm-tag <string> Npm tag
99
+ -c, --check-remote-version Check remote version
100
+ ```
101
+
102
+ #### publish
103
+
104
+ ```
105
+ Usage: vr publish [flags...]
106
+
107
+ Flags:
108
+ -c, --check-remote-version Check remote version
109
+ -t, --npm-tag <string> Npm tag
110
+ ```
92
111
 
93
112
  #### changelog
94
113
 
95
- | Params | Instructions | Default |
96
- | ----------------------------------- | -------------------------- | -------------- |
97
- | -f --file \<filename\> | Specify changelog filename | `CHANGELOG.md` |
98
- | -rc --releaseCount \<releaseCount\> | Release count | `0` |
99
- | -p --preset \<preset\> | Specify changelog preset | `angular` |
114
+ ```
115
+ Usage: vr changelog [flags...]
100
116
 
101
- #### lint-commit
117
+ Flags:
118
+ -c, --release-count <number> Release count, default 0
119
+ -f, --file <string> Changelog filename
120
+ ```
102
121
 
103
- | Params | Instructions |
104
- | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
105
- | -p --commitMessagePath \<path\> | The path of the temporary file to which the git message is submitted. The git hook commit-msg will pass this parameter |
106
- | -r --commitMessageRe \<reg\> | Validate the regular of whether the commit message passes |
107
- | -e --errorMessage \<message\> | Validation failed to display error messages |
108
- | -w --warningMessage \<message\> | Validation failed to display warning messages |
122
+ #### commit-lint
109
123
 
110
- #### publish
124
+ ```
125
+ Usage: vr commit-lint [flags...]
126
+
127
+ Flags:
128
+ -p, --commit-message-path <string> Git commit message path
129
+ -r, --commit-message-re <string> Validate the regular of whether the commit message passes
130
+ -e, --error-message <string> Validation failed to display error messages
131
+ -w, --warning-message <string> Validation failed to display warning messages
132
+ ```
133
+
134
+ #### lockfile-sync-check
111
135
 
112
- | Params | Instructions | Default |
113
- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ------- |
114
- | -c --check-remote-version | Detects whether the remote version of the npm package is the same as the package version to be published locally, and if it is, skip the release | `false` |
115
- | -nt --npm-tag \<npmTag\> | npm tag | `-` |
136
+ ```
137
+ Usage: vr lockfile-sync-check [flags...]
138
+
139
+ Flags:
140
+ -m, --package-manager <string> Package manager (npm, yarn, pnpm), default pnpm
141
+ -i, --install Auto install dependencies if lockfile changed
142
+ ```
116
143
 
117
144
  ### Node API Custom Handle
118
145
 
package/README.zh-CN.md CHANGED
@@ -46,9 +46,9 @@ pnpm add @varlet/release -D
46
46
  npx vr release
47
47
 
48
48
  # 指定远程仓库名称
49
- npx vr release -r https://github.com/varletjs/varlet-release
49
+ npx vr release -r origin
50
50
  # 或
51
- npx vr release --remote https://github.com/varletjs/varlet-release
51
+ npx vr release --remote origin
52
52
 
53
53
  # 仅生成变更日志
54
54
  npx vr changelog
@@ -59,10 +59,16 @@ npx vr changelog -f changelog.md
59
59
  npx vr changelog --file changelog.md
60
60
 
61
61
  # 检测 commit message 是否符合规范
62
- npx vr lint-commit -p .git/COMMIT_EDITMSG
62
+ npx vr commit-lint -p .git/COMMIT_EDITMSG
63
63
 
64
64
  # 发布到 npm(通常在 CI/CD 中执行)
65
65
  npx vr publish
66
+
67
+ # 检查 lockfile 是否已更新
68
+ npx vr lockfile-sync-check
69
+
70
+ # 如果 lockfile 发生变化则自动安装依赖
71
+ npx vr lockfile-sync-check -i
66
72
  ```
67
73
 
68
74
  ### Git Hooks 集成 (推荐最佳实践)
@@ -72,7 +78,7 @@ npx vr publish
72
78
  ```json
73
79
  {
74
80
  "simple-git-hooks": {
75
- "commit-msg": "npx vr lint-commit -p $1"
81
+ "commit-msg": "npx vr commit-lint -p $1"
76
82
  }
77
83
  }
78
84
  ```
@@ -81,38 +87,59 @@ npx vr publish
81
87
 
82
88
  #### release
83
89
 
84
- | 参数 | 说明 | 默认值 |
85
- | ------------------------- | ----------------------------------------------------------------------- | -------- |
86
- | -r --remote \<remote\> | 指定远程仓库名称 | `origin` |
87
- | -s --skip-npm-publish | 跳过 npm 发布 | `false` |
88
- | -c --check-remote-version | 检测 npm 包的远程版本是否与要在本地发布的包版本相同,如果是,则停止执行 | `false` |
89
- | -sc --skip-changelog | 跳过生成变更日志 | `false` |
90
- | -sgt --skip-git-tag | 跳过 git tag | `false` |
91
- | -nt --npm-tag \<npmTag\> | npm tag | `-` |
90
+ ```
91
+ 用法: vr release [标志...]
92
+
93
+ 标志:
94
+ -r, --remote <string> 远程仓库名称
95
+ -s, --skip-npm-publish 跳过 npm 发布
96
+ --skip-changelog 跳过生成变更日志
97
+ --skip-git-tag 跳过 git tag
98
+ -t, --npm-tag <string> npm tag
99
+ -c, --check-remote-version 检查远程版本
100
+ ```
101
+
102
+ #### publish
103
+
104
+ ```
105
+ 用法: vr publish [标志...]
106
+
107
+ 标志:
108
+ -c, --check-remote-version 检查远程版本
109
+ -t, --npm-tag <string> npm tag
110
+ ```
92
111
 
93
112
  #### changelog
94
113
 
95
- | 参数 | 说明 | 默认值 |
96
- | ----------------------------------- | ------------------ | -------------- |
97
- | -f --file \<filename\> | 指定变更日志文件名 | `CHANGELOG.md` |
98
- | -rc --releaseCount \<releaseCount\> | 发布数量 | `0` |
99
- | -p --preset \<preset\> | 指定变更预设 | `angular` |
114
+ ```
115
+ 用法: vr changelog [标志...]
100
116
 
101
- #### lint-commit
117
+ 标志:
118
+ -c, --release-count <number> 发布数量,默认 0
119
+ -f, --file <string> 变更日志文件名
120
+ ```
102
121
 
103
- | 参数 | 说明 |
104
- | ------------------------------- | --------------------------------------------------------------------------- |
105
- | -p --commitMessagePath \<path\> | 提交 `git message` 的临时文件路径。`git` 钩子 `commit-msg` 会传递这个参数。 |
106
- | -r --commitMessageRe \<reg\> | 验证 `commit message` 是否通过的正则 |
107
- | -e --errorMessage \<message\> | 验证失败展示的错误信息 |
108
- | -w --warningMessage \<message\> | 验证失败展示的提示信息 |
122
+ #### commit-lint
109
123
 
110
- #### publish
124
+ ```
125
+ 用法: vr commit-lint [标志...]
126
+
127
+ 标志:
128
+ -p, --commit-message-path <string> Git commit message 路径
129
+ -r, --commit-message-re <string> 验证 commit message 是否通过的正则表达式
130
+ -e, --error-message <string> 验证失败时显示的错误信息
131
+ -w, --warning-message <string> 验证失败时显示的警告信息
132
+ ```
133
+
134
+ #### lockfile-sync-check
111
135
 
112
- | 参数 | 说明 | 默认值 |
113
- | ------------------------- | --------------------------------------------------------------------- | ------- |
114
- | -c --check-remote-version | 检测npm包的远程版本是否与要在本地发布的包版本相同,如果是,则跳过发布 | `false` |
115
- | -nt --npm-tag \<npmTag\> | npm tag | `-` |
136
+ ```
137
+ 用法: vr lockfile-sync-check [标志...]
138
+
139
+ 标志:
140
+ -m, --package-manager <string> 包管理器 (npm, yarn, pnpm),默认 pnpm
141
+ -i, --install 如果 lockfile 发生变化则自动安装依赖
142
+ ```
116
143
 
117
144
  ### Node API 自定义处理
118
145
 
package/dist/cli.js CHANGED
@@ -1,16 +1,124 @@
1
1
  #!/usr/bin/env node
2
- import { i as release, l as commitLint, o as changelog, r as publish } from "./src-BWrnR5U-.js";
3
- import { Command } from "commander";
4
- //#region package.json
5
- var version = "1.2.0";
2
+ import { c as release, i as lockfileSyncCheck, p as commitLint, s as publish, u as changelog } from "./src-CkbCVkad.js";
3
+ import { cli, command } from "cleye";
6
4
  //#endregion
7
5
  //#region src/cli.ts
8
- const program = new Command();
9
- program.version(version);
10
- program.command("release").option("-r --remote <remote>", "Remote name").option("-s --skip-npm-publish", "Skip npm publish").option("-sc --skip-changelog", "Skip generate changelog").option("-sgt --skip-git-tag", "Skip git tag").option("-nt --npm-tag <npmTag>", "Npm tag").option("-c --check-remote-version", "Check remote version").description("Release all packages and generate changelogs").action((options) => release(options));
11
- program.command("publish").option("-c --check-remote-version", "Check remote version").option("-nt --npm-tag <npmTag>", "Npm tag").description("Publish to npm").action((options) => publish(options));
12
- program.command("changelog").option("-rc --releaseCount <releaseCount>", "Release count").option("-f --file <file>", "Changelog filename").option("-p --preset <preset>", "Changelog preset").description("Generate changelog").action((options) => changelog(options));
13
- program.command("commit-lint").option("-p --commitMessagePath <path>", "Git commit message path").option("-r --commitMessageRe <reg>", "Validate the regular of whether the commit message passes").option("-e --errorMessage <message>", "Validation failed to display error messages").option("-w --warningMessage <message>", "Validation failed to display warning messages").description("Lint commit message").action((option) => commitLint(option));
14
- program.parse();
6
+ cli({
7
+ name: "vr",
8
+ version: "2.0.0",
9
+ commands: [
10
+ command({
11
+ name: "release",
12
+ flags: {
13
+ remote: {
14
+ type: String,
15
+ alias: "r",
16
+ description: "Remote name"
17
+ },
18
+ skipNpmPublish: {
19
+ type: Boolean,
20
+ alias: "s",
21
+ description: "Skip npm publish"
22
+ },
23
+ skipChangelog: {
24
+ type: Boolean,
25
+ description: "Skip generate changelog"
26
+ },
27
+ skipGitTag: {
28
+ type: Boolean,
29
+ description: "Skip git tag"
30
+ },
31
+ npmTag: {
32
+ type: String,
33
+ alias: "t",
34
+ description: "Npm tag"
35
+ },
36
+ checkRemoteVersion: {
37
+ type: Boolean,
38
+ alias: "c",
39
+ description: "Check remote version"
40
+ }
41
+ },
42
+ help: { description: "Release all packages and generate changelogs" }
43
+ }, (argv) => release(argv.flags)),
44
+ command({
45
+ name: "publish",
46
+ flags: {
47
+ checkRemoteVersion: {
48
+ type: Boolean,
49
+ alias: "c",
50
+ description: "Check remote version"
51
+ },
52
+ npmTag: {
53
+ type: String,
54
+ alias: "t",
55
+ description: "Npm tag"
56
+ }
57
+ },
58
+ help: { description: "Publish to npm" }
59
+ }, (argv) => publish(argv.flags)),
60
+ command({
61
+ name: "changelog",
62
+ flags: {
63
+ releaseCount: {
64
+ type: Number,
65
+ alias: "c",
66
+ default: 0,
67
+ description: "Release count, default 0"
68
+ },
69
+ file: {
70
+ type: String,
71
+ alias: "f",
72
+ description: "Changelog filename"
73
+ }
74
+ },
75
+ help: { description: "Generate changelog" }
76
+ }, (argv) => changelog(argv.flags)),
77
+ command({
78
+ name: "commit-lint",
79
+ flags: {
80
+ commitMessagePath: {
81
+ type: String,
82
+ alias: "p",
83
+ default: "",
84
+ description: "Git commit message path"
85
+ },
86
+ commitMessageRe: {
87
+ type: String,
88
+ alias: "r",
89
+ description: "Validate the regular of whether the commit message passes"
90
+ },
91
+ errorMessage: {
92
+ type: String,
93
+ alias: "e",
94
+ description: "Validation failed to display error messages"
95
+ },
96
+ warningMessage: {
97
+ type: String,
98
+ alias: "w",
99
+ description: "Validation failed to display warning messages"
100
+ }
101
+ },
102
+ help: { description: "Lint commit message" }
103
+ }, (argv) => commitLint(argv.flags)),
104
+ command({
105
+ name: "lockfile-sync-check",
106
+ flags: {
107
+ packageManager: {
108
+ type: String,
109
+ alias: "m",
110
+ default: "pnpm",
111
+ description: "Package manager (npm, yarn, pnpm), default pnpm"
112
+ },
113
+ install: {
114
+ type: Boolean,
115
+ alias: "i",
116
+ description: "Auto install dependencies if lockfile changed"
117
+ }
118
+ },
119
+ help: { description: "Check if lockfile has been updated and optionally install dependencies" }
120
+ }, (argv) => lockfileSyncCheck(argv.flags))
121
+ ]
122
+ });
15
123
  //#endregion
16
124
  export {};
package/dist/index.d.ts CHANGED
@@ -1,29 +1,34 @@
1
- import conventionalChangelog from "conventional-changelog";
1
+ import { Commit, Params } from "conventional-changelog";
2
2
 
3
3
  //#region src/release.d.ts
4
- declare function isSameVersion(version?: string): Promise<boolean | undefined>;
4
+ interface PackageJsonConfig {
5
+ name: string;
6
+ version: string;
7
+ private: boolean;
8
+ }
9
+ interface PackageJsonEntry {
10
+ filePath: string;
11
+ config: PackageJsonConfig;
12
+ }
13
+ declare function isSameVersion(version?: string, cwd?: string): Promise<boolean | undefined>;
5
14
  interface PublishCommandOptions {
6
15
  preRelease?: boolean;
7
16
  checkRemoteVersion?: boolean;
8
17
  npmTag?: string;
18
+ cwd?: string;
9
19
  }
10
20
  declare function publish({
11
21
  preRelease,
12
22
  checkRemoteVersion,
13
- npmTag
23
+ npmTag,
24
+ cwd
14
25
  }: PublishCommandOptions): Promise<void>;
15
- declare function getPackageJsons(): {
16
- filePath: string;
17
- config: {
18
- name: string;
19
- version: string;
20
- private: boolean;
21
- };
22
- }[];
23
- declare function updateVersion(version: string): void;
26
+ declare function getPackageJsons(cwd?: string): PackageJsonEntry[];
27
+ declare function updateVersion(version: string, cwd?: string): void;
24
28
  interface ReleaseCommandOptions {
25
29
  remote?: string;
26
30
  npmTag?: string;
31
+ cwd?: string;
27
32
  skipNpmPublish?: boolean;
28
33
  skipChangelog?: boolean;
29
34
  skipGitTag?: boolean;
@@ -34,16 +39,18 @@ declare function release(options: ReleaseCommandOptions): Promise<void>;
34
39
  //#endregion
35
40
  //#region src/changelog.d.ts
36
41
  interface ChangelogCommandOptions {
42
+ cwd?: string;
37
43
  file?: string;
38
44
  releaseCount?: number;
39
- preset?: "angular" | "atom" | "codemirror" | "conventionalcommits" | "ember" | "eslint" | "express" | "jquery" | "jshint";
40
- writerOpts?: Parameters<typeof conventionalChangelog>["4"];
45
+ mainTemplate?: string;
46
+ transformCommit?: (commit: Commit, params: Params) => Partial<Commit> | Promise<Partial<Commit> | null> | null;
41
47
  }
42
48
  declare function changelog({
49
+ cwd,
43
50
  releaseCount,
44
51
  file,
45
- preset,
46
- writerOpts
52
+ mainTemplate,
53
+ transformCommit
47
54
  }?: ChangelogCommandOptions): Promise<void>;
48
55
  //#endregion
49
56
  //#region src/commitLint.d.ts
@@ -59,4 +66,15 @@ interface CommitLintCommandOptions {
59
66
  }
60
67
  declare function commitLint(options: CommitLintCommandOptions): void;
61
68
  //#endregion
62
- export { COMMIT_HEADER_RE, COMMIT_MESSAGE_RE, ChangelogCommandOptions, CommitLintCommandOptions, PublishCommandOptions, ReleaseCommandOptions, changelog, commitLint, getCommitMessage, getPackageJsons, isSameVersion, isVersionCommitMessage, publish, release, updateVersion };
69
+ //#region src/lockfileSyncCheck.d.ts
70
+ type PackageManager = "npm" | "yarn" | "pnpm";
71
+ interface LockfileSyncCheckOptions {
72
+ packageManager?: PackageManager;
73
+ install?: boolean;
74
+ }
75
+ declare function getLockfilePath(packageManager: PackageManager): string;
76
+ declare function checkLockfileSync(packageManager: PackageManager): Promise<boolean>;
77
+ declare function installDependencies(packageManager: PackageManager): Promise<void>;
78
+ declare function lockfileSyncCheck(options?: LockfileSyncCheckOptions): Promise<void>;
79
+ //#endregion
80
+ export { COMMIT_HEADER_RE, COMMIT_MESSAGE_RE, ChangelogCommandOptions, CommitLintCommandOptions, LockfileSyncCheckOptions, PackageManager, PublishCommandOptions, ReleaseCommandOptions, changelog, checkLockfileSync, commitLint, getCommitMessage, getLockfilePath, getPackageJsons, installDependencies, isSameVersion, isVersionCommitMessage, lockfileSyncCheck, publish, release, updateVersion };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as updateVersion, c as COMMIT_MESSAGE_RE, d as isVersionCommitMessage, i as release, l as commitLint, n as isSameVersion, o as changelog, r as publish, s as COMMIT_HEADER_RE, t as getPackageJsons, u as getCommitMessage } from "./src-BWrnR5U-.js";
2
- export { COMMIT_HEADER_RE, COMMIT_MESSAGE_RE, changelog, commitLint, getCommitMessage, getPackageJsons, isSameVersion, isVersionCommitMessage, publish, release, updateVersion };
1
+ import { a as getPackageJsons, c as release, d as COMMIT_HEADER_RE, f as COMMIT_MESSAGE_RE, h as isVersionCommitMessage, i as lockfileSyncCheck, l as updateVersion, m as getCommitMessage, n as getLockfilePath, o as isSameVersion, p as commitLint, r as installDependencies, s as publish, t as checkLockfileSync, u as changelog } from "./src-CkbCVkad.js";
2
+ export { COMMIT_HEADER_RE, COMMIT_MESSAGE_RE, changelog, checkLockfileSync, commitLint, getCommitMessage, getLockfilePath, getPackageJsons, installDependencies, isSameVersion, isVersionCommitMessage, lockfileSyncCheck, publish, release, updateVersion };
@@ -5,7 +5,7 @@ import { cancel, confirm, isCancel, select, spinner } from "@clack/prompts";
5
5
  import { logger } from "rslog";
6
6
  import semver from "semver";
7
7
  import { x } from "tinyexec";
8
- import conventionalChangelog from "conventional-changelog";
8
+ import { ConventionalChangelog } from "conventional-changelog";
9
9
  //#region src/commitLint.ts
10
10
  const COMMIT_HEADER_RE = /^(revert|fix|feat|docs|perf|test|types|style|build|chore|release|refactor|merge|wip)(?:\(([^)]+)\))?(!)?:\s(.+)$/;
11
11
  const COMMIT_MESSAGE_RE = new RegExp(COMMIT_HEADER_RE.source.replace(/\$$/, "") + "(?:\\n[\\s\\S]+)?$");
@@ -69,7 +69,7 @@ const COMMIT_TYPE_MAP = {
69
69
  fix: "Bug Fixes",
70
70
  perf: "Performance Improvements",
71
71
  revert: "Reverts",
72
- refactor: "Code Refactoring",
72
+ refactor: "Refactoring",
73
73
  docs: "Documentation",
74
74
  style: "Styles",
75
75
  test: "Tests",
@@ -83,7 +83,6 @@ const ALWAYS_SHOW_TYPES = new Set([
83
83
  "revert",
84
84
  "refactor"
85
85
  ]);
86
- const BREAKING_CHANGE_RE = /BREAKING CHANGES?:\s*([\s\S]+)/;
87
86
  const MAIN_TEMPLATE = `{{> header}}
88
87
 
89
88
  {{> footer}}
@@ -112,15 +111,6 @@ function linkify(text, context, issues) {
112
111
  if (context.host) result = result.replace(/\B@([a-z0-9](?:-?[a-z0-9/]){0,38})/g, (_, username) => username.includes("/") ? `@${username}` : `[@${username}](${context.host}/${username})`);
113
112
  return result;
114
113
  }
115
- function extractBreakingText(commit) {
116
- const body = typeof commit.body === "string" ? commit.body : "";
117
- const footer = typeof commit.footer === "string" ? commit.footer : "";
118
- const match = BREAKING_CHANGE_RE.exec(`${footer}\n${body}`);
119
- if (match?.[1]) return match[1].trim();
120
- if (typeof commit.subject === "string" && commit.subject) return commit.subject;
121
- if (typeof commit.header === "string" && commit.header) return commit.header;
122
- return "";
123
- }
124
114
  function tryParseHeader(commit) {
125
115
  if (typeof commit.header !== "string") return null;
126
116
  const match = COMMIT_HEADER_RE.exec(commit.header.trim());
@@ -134,19 +124,24 @@ function tryParseHeader(commit) {
134
124
  }
135
125
  function processBreakingChanges(commit, context, issues) {
136
126
  let discard = true;
137
- commit.notes.forEach((note) => {
138
- note.title = "BREAKING CHANGES";
139
- discard = false;
140
- });
141
- const hadBreakingNotes = commit.notes.length > 0;
127
+ commit.notes = [];
128
+ const getCommitHashLink = () => {
129
+ if (!commit.hash) return "";
130
+ const shortHash = commit.hash.substring(0, 7);
131
+ const repoUrl = context.repository ? `${context.host}/${context.owner}/${context.repository}` : context.repoUrl;
132
+ return repoUrl ? ` ([${shortHash}](${repoUrl}/commit/${commit.hash}))` : ` (${shortHash})`;
133
+ };
134
+ const hashLink = getCommitHashLink();
142
135
  const addBreakingNote = () => {
143
- if (!hadBreakingNotes) {
144
- const text = linkify(extractBreakingText(commit), context, issues);
145
- commit.notes.push({
146
- title: "BREAKING CHANGES",
147
- text
148
- });
136
+ let text = linkify(typeof commit.subject === "string" && commit.subject ? commit.subject : typeof commit.header === "string" && commit.header ? commit.header : "", context, issues) + hashLink;
137
+ if (commit.body) {
138
+ const indentedBody = linkify(commit.body, context, issues).split("\n").map((line) => line.trim() ? ` ${line}` : "").join("\n");
139
+ text += `\n\n${indentedBody}`;
149
140
  }
141
+ commit.notes.push({
142
+ title: "BREAKING CHANGES",
143
+ text
144
+ });
150
145
  discard = false;
151
146
  };
152
147
  const parsed = tryParseHeader(commit);
@@ -176,28 +171,37 @@ function mapCommitType(commit, discard) {
176
171
  }
177
172
  return !discard;
178
173
  }
179
- function createDefaultWriterOpts() {
180
- return {
181
- mainTemplate: MAIN_TEMPLATE,
182
- transform(commit, context) {
183
- const issues = [];
184
- if (!mapCommitType(commit, processBreakingChanges(commit, context, issues))) return false;
185
- if (commit.scope === "*") commit.scope = "";
186
- if (typeof commit.hash === "string") commit.shortHash = commit.hash.substring(0, 7);
187
- if (typeof commit.subject === "string") commit.subject = linkify(commit.subject, context, issues);
188
- commit.references = commit.references.filter((ref) => !issues.includes(ref.issue));
189
- return commit;
190
- }
174
+ function createDefaultTransformCommit() {
175
+ return (commit, params) => {
176
+ const context = {
177
+ host: params.context?.host,
178
+ owner: params.context?.owner,
179
+ repository: typeof params.repository === "object" && params.repository !== null ? params.repository.project : void 0,
180
+ repoUrl: params.context?.repoUrl
181
+ };
182
+ const issues = [];
183
+ const mutableCommit = { ...commit };
184
+ if (mutableCommit.notes) mutableCommit.notes = [...mutableCommit.notes];
185
+ if (!mapCommitType(mutableCommit, processBreakingChanges(mutableCommit, context, issues))) return null;
186
+ if (mutableCommit.scope === "*") mutableCommit.scope = "";
187
+ if (typeof mutableCommit.hash === "string") mutableCommit.shortHash = mutableCommit.hash.substring(0, 7);
188
+ if (typeof mutableCommit.subject === "string") mutableCommit.subject = linkify(mutableCommit.subject, context, issues);
189
+ if (mutableCommit.references) mutableCommit.references = mutableCommit.references.filter((ref) => !issues.includes(ref.issue));
190
+ return mutableCommit;
191
191
  };
192
192
  }
193
- function changelog({ releaseCount = 0, file = "CHANGELOG.md", preset = "angular", writerOpts = createDefaultWriterOpts() } = {}) {
193
+ function changelog({ cwd = process.cwd(), releaseCount = 0, file = "CHANGELOG.md", mainTemplate = MAIN_TEMPLATE, transformCommit = createDefaultTransformCommit() } = {}) {
194
194
  const s = spinner();
195
195
  s.start("Generating changelog");
196
196
  return new Promise((resolve$1) => {
197
- conventionalChangelog({
198
- preset,
199
- releaseCount
200
- }, void 0, void 0, void 0, writerOpts).pipe(createWriteStream(resolve(process.cwd(), file))).on("close", () => {
197
+ new ConventionalChangelog(cwd).readPackage().loadPreset("angular").options({
198
+ releaseCount,
199
+ transformCommit,
200
+ outputUnreleased: true
201
+ }).writer({
202
+ mainTemplate,
203
+ transform: (commit) => commit
204
+ }).writeStream().pipe(createWriteStream(resolve(cwd, file))).on("close", () => {
201
205
  s.stop("Changelog generated successfully!");
202
206
  resolve$1();
203
207
  });
@@ -216,8 +220,7 @@ function readJSONSync(path) {
216
220
  }
217
221
  //#endregion
218
222
  //#region src/release.ts
219
- const cwd = () => process.cwd();
220
- const releaseTypes = [
223
+ const RELEASE_TYPES = [
221
224
  "patch",
222
225
  "minor",
223
226
  "major",
@@ -225,15 +228,28 @@ const releaseTypes = [
225
228
  "preminor",
226
229
  "premajor"
227
230
  ];
228
- const BACK_HINT = "Back to previous step";
231
+ const BACK_VALUE = "back";
232
+ function unwrapPromptResult(result) {
233
+ if (isCancel(result)) {
234
+ cancel("Operation cancelled.");
235
+ process.exit(0);
236
+ }
237
+ return result;
238
+ }
239
+ function execGit(...args) {
240
+ return x("git", args, { throwOnError: true });
241
+ }
242
+ function logStdout(ret) {
243
+ if (ret.stdout) logger.log(ret.stdout);
244
+ }
229
245
  async function isWorktreeEmpty() {
230
246
  return !(await x("git", ["status", "--porcelain"])).stdout;
231
247
  }
232
- async function isSameVersion(version) {
248
+ async function isSameVersion(version, cwd = process.cwd()) {
233
249
  const s = spinner();
234
250
  s.start("Check remote version...");
235
- const packageJsones = getPackageJsons();
236
- const packageJson = packageJsones.find((packageJson) => !packageJson.config.private) || packageJsones[0];
251
+ const packageJsonEntries = getPackageJsons(cwd);
252
+ const packageJson = packageJsonEntries.find((entry) => !entry.config.private) || packageJsonEntries[0];
237
253
  if (packageJson) {
238
254
  const { config } = packageJson;
239
255
  try {
@@ -251,7 +267,7 @@ async function isSameVersion(version) {
251
267
  }
252
268
  }
253
269
  }
254
- async function publish({ preRelease, checkRemoteVersion, npmTag }) {
270
+ async function publish({ preRelease, checkRemoteVersion, npmTag, cwd = process.cwd() }) {
255
271
  const s = spinner();
256
272
  s.start("Publishing all packages");
257
273
  const args = [
@@ -261,7 +277,7 @@ async function publish({ preRelease, checkRemoteVersion, npmTag }) {
261
277
  "--access",
262
278
  "public"
263
279
  ];
264
- if (checkRemoteVersion && await isSameVersion()) {
280
+ if (checkRemoteVersion && await isSameVersion(void 0, cwd)) {
265
281
  logger.error("publishing automatically skipped.");
266
282
  return;
267
283
  }
@@ -270,7 +286,7 @@ async function publish({ preRelease, checkRemoteVersion, npmTag }) {
270
286
  try {
271
287
  const ret = await x("pnpm", args, { throwOnError: true });
272
288
  s.stop("Publish all packages successfully");
273
- ret.stdout && logger.log(ret.stdout);
289
+ logStdout(ret);
274
290
  } catch (error) {
275
291
  s.cancel("Publish all packages failed");
276
292
  throw error?.output?.stderr ?? error;
@@ -279,43 +295,33 @@ async function publish({ preRelease, checkRemoteVersion, npmTag }) {
279
295
  async function pushGit(version, remote = "origin", skipGitTag = false) {
280
296
  const s = spinner();
281
297
  s.start("Pushing to remote git repository");
282
- await x("git", ["add", "."], { throwOnError: true });
283
- await x("git", [
284
- "commit",
285
- "-m",
286
- `v${version}`
287
- ], { throwOnError: true });
298
+ await execGit("add", ".");
299
+ await execGit("commit", "-m", `v${version}`);
288
300
  if (!skipGitTag) {
289
- await x("git", ["tag", `v${version}`], { throwOnError: true });
290
- await x("git", [
291
- "push",
292
- remote,
293
- `v${version}`
294
- ], { throwOnError: true });
301
+ await execGit("tag", `v${version}`);
302
+ await execGit("push", remote, `v${version}`);
295
303
  }
296
- const ret = await x("git", ["push"], { throwOnError: true });
304
+ const ret = await execGit("push");
297
305
  s.stop("Push remote repository successfully");
298
- ret.stdout && logger.log(ret.stdout);
306
+ logStdout(ret);
299
307
  }
300
- function getPackageJsons() {
301
- const packageJsons = [resolve(cwd(), "package.json")];
302
- const packagesDir = resolve(cwd(), "packages");
308
+ function getPackageJsons(cwd = process.cwd()) {
309
+ const packageJsonPaths = [resolve(cwd, "package.json")];
310
+ const packagesDir = resolve(cwd, "packages");
303
311
  if (existsSync(packagesDir)) for (const name of readdirSync(packagesDir)) {
304
312
  const pkgPath = resolve(packagesDir, name, "package.json");
305
- if (existsSync(pkgPath)) packageJsons.push(pkgPath);
313
+ if (existsSync(pkgPath)) packageJsonPaths.push(pkgPath);
306
314
  }
307
- return packageJsons.map((path) => {
308
- return {
309
- filePath: path,
310
- config: readJSONSync(path)
311
- };
312
- });
315
+ return packageJsonPaths.map((path) => ({
316
+ filePath: path,
317
+ config: readJSONSync(path)
318
+ }));
313
319
  }
314
- function updateVersion(version) {
315
- getPackageJsons().forEach(({ config, filePath }) => {
320
+ function updateVersion(version, cwd = process.cwd()) {
321
+ for (const { config, filePath } of getPackageJsons(cwd)) {
316
322
  config.version = version;
317
323
  writeFileSync(filePath, JSON.stringify(config, null, 2));
318
- });
324
+ }
319
325
  }
320
326
  async function confirmRegistry() {
321
327
  const registry = (await x("npm", [
@@ -323,72 +329,63 @@ async function confirmRegistry() {
323
329
  "get",
324
330
  "registry"
325
331
  ])).stdout;
326
- const ret = await confirm({ message: `Current registry is: ${registry}` });
327
- if (isCancel(ret)) {
328
- cancel("Operation cancelled.");
329
- process.exit(0);
330
- }
331
- return ret;
332
+ return unwrapPromptResult(await confirm({ message: `Current registry is: ${registry}` }));
332
333
  }
333
334
  async function confirmVersion(currentVersion, expectVersion) {
334
- const ret = await select({
335
+ return unwrapPromptResult(await select({
335
336
  message: "Version confirm",
336
- options: [`All packages version ${currentVersion} -> ${expectVersion}`, BACK_HINT].map((value) => ({
337
- label: value,
338
- value
339
- }))
340
- });
341
- if (isCancel(ret)) {
342
- cancel("Operation cancelled.");
343
- process.exit(0);
344
- }
345
- return ret;
337
+ options: [{
338
+ label: `All packages version ${currentVersion} -> ${expectVersion}`,
339
+ value: "confirm"
340
+ }, {
341
+ label: "Back to previous step",
342
+ value: BACK_VALUE
343
+ }]
344
+ }));
346
345
  }
347
346
  async function confirmRefs(remote = "origin") {
348
347
  const { stdout } = await x("git", ["remote", "-v"]);
349
- const reg = new RegExp(`${remote}\t(.*) \\(push`);
348
+ const reg = new RegExp(`${remote}\\t(.*) \\(push\\)`);
350
349
  const repo = stdout.match(reg)?.[1];
351
350
  const { stdout: branch } = await x("git", ["branch", "--show-current"]);
352
- const ret = await confirm({ message: `Current refs ${repo}:refs/for/${styleText("blue", branch)}` });
353
- if (isCancel(ret)) {
354
- cancel("Operation cancelled.");
355
- process.exit(0);
356
- }
357
- return ret;
351
+ return unwrapPromptResult(await confirm({ message: `Current refs ${repo}:refs/for/${styleText("blue", branch)}` }));
352
+ }
353
+ function computeExpectVersion(currentVersion, type) {
354
+ const incremented = semver.inc(currentVersion, type, `alpha.${Date.now()}`);
355
+ if (!incremented) throw new Error(`Failed to increment version ${currentVersion} with type ${type}`);
356
+ return type.startsWith("pre") ? incremented.slice(0, -2) : incremented;
358
357
  }
359
- async function getReleaseType() {
360
- const releaseType = await select({
358
+ async function getReleaseType(currentVersion) {
359
+ return unwrapPromptResult(await select({
361
360
  message: "Please select release type",
362
- options: releaseTypes.map((type) => ({
363
- label: type,
364
- value: type
365
- }))
366
- });
367
- if (isCancel(releaseType)) {
368
- cancel("Operation cancelled.");
369
- process.exit(0);
370
- }
371
- return releaseType;
361
+ options: RELEASE_TYPES.map((type) => {
362
+ return {
363
+ label: `${type} (${currentVersion} → ${computeExpectVersion(currentVersion, type)})`,
364
+ value: type
365
+ };
366
+ })
367
+ }));
372
368
  }
373
369
  async function getReleaseVersion(currentVersion) {
374
- let isPreRelease = false;
375
- let expectVersion = "";
376
- let confirmVersionRet = "";
377
- do {
378
- const type = await getReleaseType();
379
- isPreRelease = type.startsWith("pre");
380
- expectVersion = semver.inc(currentVersion, type, `alpha.${Date.now()}`);
381
- expectVersion = isPreRelease ? expectVersion.slice(0, -2) : expectVersion;
382
- confirmVersionRet = await confirmVersion(currentVersion, expectVersion);
383
- } while (confirmVersionRet === BACK_HINT);
384
- return {
385
- isPreRelease,
386
- expectVersion
387
- };
370
+ while (true) {
371
+ const type = await getReleaseType(currentVersion);
372
+ const isPreRelease = type.startsWith("pre");
373
+ const expectVersion = computeExpectVersion(currentVersion, type);
374
+ if (await confirmVersion(currentVersion, expectVersion) !== BACK_VALUE) return {
375
+ isPreRelease,
376
+ expectVersion
377
+ };
378
+ }
379
+ }
380
+ async function restorePackageJsons() {
381
+ try {
382
+ await execGit("restore", "**/package.json", "package.json");
383
+ } catch {}
388
384
  }
389
385
  async function release(options) {
386
+ const cwd = options.cwd ?? process.cwd();
390
387
  try {
391
- const currentVersion = readJSONSync(resolve(cwd(), "package.json")).version;
388
+ const currentVersion = readJSONSync(resolve(cwd, "package.json")).version;
392
389
  if (!currentVersion) {
393
390
  logger.error("Your package is missing the version field");
394
391
  return;
@@ -400,33 +397,81 @@ async function release(options) {
400
397
  if (!await confirmRefs(options.remote)) return;
401
398
  if (!options.skipNpmPublish && !await confirmRegistry()) return;
402
399
  const { isPreRelease, expectVersion } = await getReleaseVersion(currentVersion);
403
- if (options.checkRemoteVersion && await isSameVersion(expectVersion)) {
400
+ if (options.checkRemoteVersion && await isSameVersion(expectVersion, cwd)) {
404
401
  logger.error("Please check remote version.");
405
402
  return;
406
403
  }
407
- updateVersion(expectVersion);
404
+ updateVersion(expectVersion, cwd);
408
405
  if (options.task) await options.task(expectVersion, currentVersion);
409
406
  if (!options.skipNpmPublish) await publish({
410
407
  preRelease: isPreRelease,
411
- npmTag: options.npmTag
408
+ npmTag: options.npmTag,
409
+ cwd
412
410
  });
413
411
  if (!isPreRelease) {
414
- if (!options.skipChangelog) await changelog();
412
+ if (!options.skipChangelog) await changelog({ cwd });
415
413
  await pushGit(expectVersion, options.remote, options.skipGitTag);
416
414
  }
417
415
  logger.success(`Release version ${expectVersion} successfully!`);
418
- if (isPreRelease) {
419
- try {
420
- await x("git", ["restore", "**/package.json"], { throwOnError: true });
421
- } catch {}
422
- try {
423
- await x("git", ["restore", "package.json"], { throwOnError: true });
424
- } catch {}
425
- }
416
+ if (isPreRelease) await restorePackageJsons();
426
417
  } catch (error) {
427
418
  logger.error(error);
428
419
  process.exit(1);
429
420
  }
430
421
  }
431
422
  //#endregion
432
- export { updateVersion as a, COMMIT_MESSAGE_RE as c, isVersionCommitMessage as d, release as i, commitLint as l, isSameVersion as n, changelog as o, publish as r, COMMIT_HEADER_RE as s, getPackageJsons as t, getCommitMessage as u };
423
+ //#region src/lockfileSyncCheck.ts
424
+ function getLockfilePath(packageManager) {
425
+ switch (packageManager) {
426
+ case "pnpm": return "pnpm-lock.yaml";
427
+ case "yarn": return "yarn.lock";
428
+ case "npm": return "package-lock.json";
429
+ }
430
+ }
431
+ async function checkLockfileSync(packageManager) {
432
+ const lockfile = getLockfilePath(packageManager);
433
+ try {
434
+ const { stdout } = await x("git", [
435
+ "diff",
436
+ "--name-only",
437
+ "ORIG_HEAD",
438
+ "HEAD"
439
+ ], { throwOnError: true });
440
+ return stdout.includes(lockfile);
441
+ } catch {
442
+ logger.warn("Error checking lockfile, please check manually.");
443
+ return false;
444
+ }
445
+ }
446
+ async function installDependencies(packageManager) {
447
+ const s = spinner();
448
+ s.start("Installing dependencies...");
449
+ const installArgs = {
450
+ npm: ["install"],
451
+ yarn: ["install"],
452
+ pnpm: ["install"]
453
+ };
454
+ try {
455
+ await x(packageManager, installArgs[packageManager], { throwOnError: true });
456
+ s.stop("Dependencies installed successfully");
457
+ logger.success("✨ All dependencies are up to date");
458
+ } catch (error) {
459
+ s.cancel("Failed to install dependencies");
460
+ logger.error(error);
461
+ throw error;
462
+ }
463
+ }
464
+ async function lockfileSyncCheck(options = {}) {
465
+ try {
466
+ const pkgManager = options.packageManager || "pnpm";
467
+ const installFlag = options.install || false;
468
+ if (await checkLockfileSync(pkgManager)) {
469
+ logger.warn("Lockfile has been updated!");
470
+ if (installFlag) await installDependencies(pkgManager);
471
+ }
472
+ } catch (error) {
473
+ logger.error("Error checking lockfile sync:", error);
474
+ }
475
+ }
476
+ //#endregion
477
+ export { getPackageJsons as a, release as c, COMMIT_HEADER_RE as d, COMMIT_MESSAGE_RE as f, isVersionCommitMessage as h, lockfileSyncCheck as i, updateVersion as l, getCommitMessage as m, getLockfilePath as n, isSameVersion as o, commitLint as p, installDependencies as r, publish as s, checkLockfileSync as t, changelog as u };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@varlet/release",
3
- "version": "1.2.0",
3
+ "version": "2.0.0",
4
4
  "description": "publish all packages, generate changelogs and check commit messages",
5
5
  "keywords": [
6
6
  "changelog",
@@ -31,19 +31,19 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@clack/prompts": "^1.2.0",
34
- "commander": "^11.1.0",
35
- "conventional-changelog": "^5.1.0",
34
+ "cleye": "^2.3.0",
35
+ "conventional-changelog": "^7.2.0",
36
36
  "rslog": "^2.1.1",
37
37
  "semver": "^7.7.4",
38
38
  "tinyexec": "^1.1.1"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@configurajs/vite-plus": "^0.2.2",
42
- "@types/conventional-changelog": "^3.1.5",
43
42
  "@types/node": "^22.14.0",
44
43
  "@types/semver": "^7.7.1",
45
44
  "@typescript/native-preview": "7.0.0-dev.20260410.1",
46
45
  "@vitest/coverage-v8": "^4.1.4",
46
+ "conventional-changelog-angular": "^8.3.1",
47
47
  "vite-plus": "latest"
48
48
  },
49
49
  "engines": {