@peiyanlu/release 0.0.6 → 0.0.8

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
@@ -65,6 +65,18 @@ pnpm release minor --ci
65
65
  | `--show-changelog` | 打印生成的 Changelog 并退出 |
66
66
  | `--ci` | 启用 CI 模式:禁用交互提示,缺少必要参数时直接失败;GitHub Actions 等 CI/CD 环境中默认启用 |
67
67
 
68
+ ### Prepare 相关参数
69
+
70
+ | 参数 | 说明 |
71
+ |-------------|--------------------------|
72
+ | `--prepare` | 仅仅变更版本、提交代码、创建 Tag、推送到远程 |
73
+
74
+ ```bash
75
+ pnpm release minor --prepare --ci --package pkg-a
76
+ ```
77
+
78
+ > 后续可以通过 tag 进行 npm 发布和创建 GitHub release
79
+
68
80
  ### Monorepo / CI 相关参数
69
81
 
70
82
  | 参数 | 说明 |
@@ -72,7 +84,7 @@ pnpm release minor --ci
72
84
  | `-p, --package <pkg>` | 指定要发布的子包名称(仅用于 Monorepo 的 CI 场景) |
73
85
 
74
86
  ```bash
75
- pnpm release minor --ci --package test-a
87
+ pnpm release minor --ci --package pkg-a
76
88
  ```
77
89
 
78
90
  ### npm 发布相关参数
@@ -268,6 +280,36 @@ GitHub Release 可基于 Git Tag 自动创建,并支持附带:
268
280
 
269
281
  工具默认配置偏向于 **单仓库(Single Repo)** 项目,但是可以通过配置使其支持 **Monorepo**
270
282
 
283
+ ## 流程拆分
284
+
285
+ ### 本地准备 Release(仅创建 Tag)
286
+
287
+ 在本地完成版本确认与变更准备:
288
+
289
+ - 确定下一个版本
290
+ - 更新 `package.json` / `CHANGELOG`
291
+ - 创建发布提交
292
+ - 创建并推送 git 标签
293
+
294
+ ### CI/CD 自动发布(由 Tag 触发)
295
+
296
+ 当 Tag 推送到远端后,CI/CD 自动执行:
297
+
298
+ - 发布到 npm
299
+ - 创建 GItHub release
300
+
301
+ ```ts
302
+ // publishCI.ts
303
+ import { publishTagToNpm } from '@peiyanlu/release'
304
+
305
+
306
+ await publishTagToNpm({
307
+ gitTag: '1.0.16',
308
+ getPkgDir: () => '.',
309
+ defaultPackage: '.',
310
+ })
311
+ ```
312
+
271
313
  ## Dry Run
272
314
 
273
315
  ```bash
package/dist/cli.mjs CHANGED
@@ -1,14 +1,14 @@
1
1
  import path, { join, resolve } from "node:path";
2
2
  import { fileURLToPath, pathToFileURL } from "node:url";
3
- import { bumpPackageVersion, coloredChangeset, eol, execAsync, getAllRemotes, getAuthenticatedUser, getCurrentBranch, getGithubReleaseUrl, getGithubUrl, getLatestTag, getLog, getPackageInfo, getPackageUrl, getPublishedVersion, getRemote, getStatus, gitAddAll, gitAddTracked, gitCommit, gitTagAnnotated, hasWriteAccess, isGitRepo, isWorkingDirClean, parseGitHubRepo, pingRegistry, publishPackage, pushBranch, pushTag, readJsonFile, resolveChangelogRange } from "@peiyanlu/cli-utils";
3
+ import { bumpPackageVersion, coloredChangeset, eol, execAsync, getAllRemotes, getAuthenticatedUser, getCurrentBranch, getGithubReleaseUrl, getGithubUrl, getLatestTag, getLog, getPackageInfo, getPackageUrl, getPublishedVersion, getRemote, getStatus, gitAddAll, gitAddTracked, gitCommit, gitTagAnnotated, hasWriteAccess, isGitRepo, isOtpError, isPrerelease, isValid, isWorkingDirClean, parseGitHubRepo, parseVersion, pingRegistry, publishPackage, pushBranch, pushTag, readJsonFile, resolveChangelogRange, resolvePublishTag } from "@peiyanlu/cli-utils";
4
4
  import { dim, green, red, rgb, underline, yellow } from "ansis";
5
5
  import { program } from "commander";
6
6
  import { createReadStream, createWriteStream, existsSync, readFileSync, statSync, writeFileSync } from "node:fs";
7
7
  import { cancel, confirm, group, intro, isCancel, log, outro, select, tasks, text } from "@clack/prompts";
8
8
  import { publint } from "publint";
9
9
  import { formatMessage } from "publint/utils";
10
- import { coerce, inc, lt, neq, parse, prerelease, valid } from "semver";
11
- import { castArray, isPlainObject, isUndefined } from "@peiyanlu/ts-utils";
10
+ import { inc, neq } from "semver";
11
+ import { castArray, isFunction, isPlainObject, isUndefined } from "@peiyanlu/ts-utils";
12
12
  import { spawnSync } from "node:child_process";
13
13
  import { inspect } from "node:util";
14
14
  import { ConventionalChangelog } from "conventional-changelog";
@@ -19,12 +19,10 @@ import { Octokit } from "@octokit/rest";
19
19
  import { contentType } from "mime-types";
20
20
  import open from "open";
21
21
  import { glob } from "tinyglobby";
22
-
23
- //#region node_modules/.pnpm/tsdown@0.18.4_publint@0.3.17_typescript@5.9.3/node_modules/tsdown/esm-shims.js
22
+ //#region node_modules/.pnpm/tsdown@0.21.7_publint@0.3.18_typescript@6.0.2/node_modules/tsdown/esm-shims.js
24
23
  const getFilename = () => fileURLToPath(import.meta.url);
25
24
  const getDirname = () => path.dirname(getFilename());
26
25
  const __dirname = /* @__PURE__ */ getDirname();
27
-
28
26
  //#endregion
29
27
  //#region src/config.ts
30
28
  const findConfigFile = (cwd = process.cwd()) => {
@@ -34,8 +32,8 @@ const findConfigFile = (cwd = process.cwd()) => {
34
32
  "js",
35
33
  "mjs"
36
34
  ]) {
37
- const path$1 = resolve(cwd, `release.config.${ext}`);
38
- if (existsSync(path$1)) return path$1;
35
+ const path = resolve(cwd, `release.config.${ext}`);
36
+ if (existsSync(path)) return path;
39
37
  }
40
38
  };
41
39
  const loadConfig = async (file) => {
@@ -55,7 +53,6 @@ const resolveConfig = async (cwd) => {
55
53
  config: await loadConfig(configFile)
56
54
  };
57
55
  };
58
- const isFunction = (v) => typeof v === "function";
59
56
  const mergeConfig = (defaults, overrides) => {
60
57
  if (!overrides) return structuredClone(defaults);
61
58
  if (Object.keys(defaults).length === 0) return structuredClone(overrides);
@@ -71,15 +68,15 @@ const mergeConfig = (defaults, overrides) => {
71
68
  }
72
69
  return result;
73
70
  };
74
-
75
71
  //#endregion
76
72
  //#region src/messages.ts
77
73
  const n = (b) => b ? "(dry run)" : "";
78
74
  const t = () => green(`${Math.floor(process.uptime())}s`);
79
75
  const MSG = {
80
76
  INTRO: (dryRun) => `🚀 Starting release ${n(dryRun)}`,
77
+ INTRO_PREPARE: (dryRun) => `🚀 Starting prepare release ${n(dryRun)}`,
81
78
  OUTRO: (dryRun) => `🎉 Release finished successfully in ${t()} ${n(dryRun)}`,
82
- OUTRO_PREPARE: (dryRun) => `🎉 PrepareRelease finished successfully in ${t()} ${n(dryRun)}`,
79
+ OUTRO_PREPARE: (dryRun) => `🎉 Prepare release finished successfully in ${t()} ${n(dryRun)}`,
83
80
  LOG: {
84
81
  SHOW_VERSION: (version) => `🎉 Released ${green(version)}`,
85
82
  SHOW_CHANGELOG: "🎉 Changelog collected",
@@ -93,11 +90,11 @@ const MSG = {
93
90
  },
94
91
  NPM: {
95
92
  CHECKING: "Checking npm registry",
96
- CHECKED: (registry, msg$1) => `NPM registry: ${underline(dim(registry))} ${underline(dim(msg$1))}`
93
+ CHECKED: (registry, msg) => `NPM registry: ${underline(dim(registry))} ${underline(dim(msg))}`
97
94
  },
98
95
  GITHUB: {
99
96
  CHECKING: "Checking github repository",
100
- CHECKED: (repository, msg$1) => `GitHub repository: ${underline(dim(repository))} ${underline(dim(msg$1))}`
97
+ CHECKED: (repository, msg) => `GitHub repository: ${underline(dim(repository))} ${underline(dim(msg))}`
101
98
  }
102
99
  },
103
100
  TASK: {
@@ -126,11 +123,11 @@ const MSG = {
126
123
  SELECT_PACKAGE: "Select package release:",
127
124
  SELECT_VERSION: "Select version bump:",
128
125
  INPUT_VERSION: "Enter custom version:",
129
- NPM_PUBLISH: (pkg$1) => `Publish to npm ${underline(dim`(${pkg$1})`)}?`,
126
+ NPM_PUBLISH: (pkg) => `Publish to npm ${underline(dim`(${pkg})`)}?`,
130
127
  NPM_OTP: "Enter npm one-time password (OTP):",
131
128
  GITHUB_RELEASE: (title) => `Create a new GitHub release ${underline(dim`(${title})`)}?`,
132
- GIT_COMMIT: (msg$1) => `Create git commit ${underline(dim`(${msg$1})`)}?`,
133
- GIT_TAG: (msg$1) => `Create git tag ${underline(dim`(${msg$1})`)}?`,
129
+ GIT_COMMIT: (msg) => `Create git commit ${underline(dim`(${msg})`)}?`,
130
+ GIT_TAG: (msg) => `Create git tag ${underline(dim`(${msg})`)}?`,
134
131
  GIT_PUSH: "Push commits and tags to remote?"
135
132
  },
136
133
  ERROR: {
@@ -152,10 +149,9 @@ const MSG = {
152
149
  },
153
150
  INFO: {
154
151
  TOOL: (name, version) => `${name} ${dim(`v${version}`)}`,
155
- CONFIG: (path$1) => `config file: ${underline(dim(path$1 || "not found"))}`
152
+ CONFIG: (path) => `config file: ${underline(dim(path || "not found"))}`
156
153
  }
157
154
  };
158
-
159
155
  //#endregion
160
156
  //#region src/git/commit.ts
161
157
  const gitCheck = async (ctx, config) => {
@@ -197,9 +193,9 @@ const commitAndTag = async (ctx, config) => {
197
193
  }
198
194
  if (push) {
199
195
  const remotes = await getAllRemotes();
200
- for (const remoteName$1 of remotes) {
201
- await pushTag(remoteName$1, currentTag, args);
202
- await pushBranch(remoteName$1, await getCurrentBranch(), [...pushArgs, ...args]);
196
+ for (const remoteName of remotes) {
197
+ await pushTag(remoteName, currentTag, args);
198
+ await pushBranch(remoteName, await getCurrentBranch(), [...pushArgs, ...args]);
203
199
  }
204
200
  if (!dryRun) Object.assign(ctx.git, { isPushed: true });
205
201
  }
@@ -219,11 +215,10 @@ const gitRollback = (ctx) => {
219
215
  isCommitted ? "HEAD~1" : "HEAD"
220
216
  ]);
221
217
  };
222
-
223
218
  //#endregion
224
219
  //#region src/prompts.ts
225
- const abortTask = (msg$1) => {
226
- cancel(`${red("✕")} ${msg$1}`);
220
+ const abortTask = (msg) => {
221
+ cancel(`${red("✕")} ${msg}`);
227
222
  process.exit(0);
228
223
  };
229
224
  const abortSinglePrompt = (value) => {
@@ -235,34 +230,33 @@ const abortGroupPrompt = (ctx) => {
235
230
  };
236
231
  const abortOnError = (err, ctx) => {
237
232
  ctx && gitRollback(ctx);
238
- const msg$1 = err.message.replace(/^\[(github|npm|git)]/, (a) => red(a));
239
- log.message(`\n${msg$1}\n`);
233
+ const msg = err.message.replace(/^\[(github|npm|git)]/, (a) => red(a));
234
+ log.message(`\n${msg}\n`);
240
235
  process.exit(1);
241
236
  };
242
- const taskEnd = (msg$1) => {
243
- outro(msg$1);
237
+ const taskEnd = (msg) => {
238
+ outro(msg);
244
239
  process.exit(0);
245
240
  };
246
-
247
241
  //#endregion
248
242
  //#region src/utils.ts
249
- const info = (msg$1) => {
250
- console.log(`${rgb(33, 91, 184)(`i`)} ${msg$1}`);
243
+ const info = (msg) => {
244
+ console.log(`${rgb(33, 91, 184)(`i`)} ${msg}`);
251
245
  };
252
- const msg = (prefix, msg$1) => {
253
- log.message(`${rgb(33, 91, 184)(`[${prefix}]`)} ${dim(msg$1)}`);
246
+ const msg = (prefix, msg) => {
247
+ log.message(`${rgb(33, 91, 184)(`[${prefix}]`)} ${dim(msg)}`);
254
248
  };
255
- const question = (msg$1, type) => {
249
+ const question = (msg, type) => {
256
250
  return `${{
257
251
  package: yellow,
258
252
  version: green,
259
253
  git: rgb(220, 94, 62),
260
254
  npm: rgb(186, 70, 61),
261
255
  github: rgb(64, 110, 228)
262
- }[type]`?`} ${msg$1}`;
256
+ }[type]`?`} ${msg}`;
263
257
  };
264
- const success = (msg$1, dryRun) => {
265
- return `${(dryRun ? rgb(123, 115, 66) : green)("✔")} ${msg$1}`;
258
+ const success = (msg, dryRun) => {
259
+ return `${(dryRun ? rgb(123, 115, 66) : green)("✔")} ${msg}`;
266
260
  };
267
261
  const runLifeCycleHook = async (hooks, key, dryRun) => {
268
262
  const handler = hooks[key];
@@ -297,60 +291,31 @@ const formatTemplate = async (ctx, config) => {
297
291
  });
298
292
  Object.assign(ctx.github, { releaseName });
299
293
  };
300
-
301
- //#endregion
302
- //#region src/version/bump.ts
303
- const isPreRelease = (version) => {
304
- return Boolean(prerelease(version));
305
- };
306
- const isValid = (version) => {
307
- return Boolean(valid(version));
308
- };
309
- const parseVersion = (raw) => {
310
- const next = isValid(raw) ? raw : coerce(raw)?.toString();
311
- if (!next) return {};
312
- const { prerelease: prerelease$1 } = parse(next);
313
- const toPreRelease = Boolean(prerelease$1.length);
314
- const [preId, preBase] = prerelease$1.map(String);
315
- return {
316
- next,
317
- toPreRelease,
318
- preId,
319
- preBase
320
- };
321
- };
322
- const getCIVersion = (current) => {
323
- return inc(current, Release.PATCH);
324
- };
325
- const isNeq = (current, next) => {
326
- return neq(current, next);
327
- };
328
-
329
294
  //#endregion
330
295
  //#region src/version/prompts.ts
331
- let Release = /* @__PURE__ */ function(Release$1) {
332
- Release$1["MAJOR"] = "major";
333
- Release$1["MINOR"] = "minor";
334
- Release$1["PATCH"] = "patch";
335
- Release$1["RELEASE"] = "release";
336
- return Release$1;
296
+ let Release = /* @__PURE__ */ function(Release) {
297
+ Release["MAJOR"] = "major";
298
+ Release["MINOR"] = "minor";
299
+ Release["PATCH"] = "patch";
300
+ Release["RELEASE"] = "release";
301
+ return Release;
337
302
  }({});
338
- let PreRelease = /* @__PURE__ */ function(PreRelease$1) {
339
- PreRelease$1["MAJOR"] = "premajor";
340
- PreRelease$1["MINOR"] = "preminor";
341
- PreRelease$1["PATCH"] = "prepatch";
342
- PreRelease$1["RELEASE"] = "prerelease";
343
- return PreRelease$1;
303
+ let PreRelease = /* @__PURE__ */ function(PreRelease) {
304
+ PreRelease["MAJOR"] = "premajor";
305
+ PreRelease["MINOR"] = "preminor";
306
+ PreRelease["PATCH"] = "prepatch";
307
+ PreRelease["RELEASE"] = "prerelease";
308
+ return PreRelease;
344
309
  }({});
345
- let PreId = /* @__PURE__ */ function(PreId$1) {
346
- PreId$1["ALPHA"] = "alpha";
347
- PreId$1["BETA"] = "beta";
348
- PreId$1["RC"] = "rc";
349
- PreId$1["NET"] = "next";
350
- PreId$1["CANARY"] = "canary";
351
- PreId$1["NIGHT"] = "nightly";
352
- PreId$1["DEV"] = "dev";
353
- return PreId$1;
310
+ let PreId = /* @__PURE__ */ function(PreId) {
311
+ PreId["ALPHA"] = "alpha";
312
+ PreId["BETA"] = "beta";
313
+ PreId["RC"] = "rc";
314
+ PreId["NET"] = "next";
315
+ PreId["CANARY"] = "canary";
316
+ PreId["NIGHT"] = "nightly";
317
+ PreId["DEV"] = "dev";
318
+ return PreId;
354
319
  }({});
355
320
  const createVersionMap = (current) => ({
356
321
  patch: inc(current, Release.PATCH),
@@ -403,14 +368,13 @@ const runVersionPrompts = async (ctx, config) => {
403
368
  abortSinglePrompt(version);
404
369
  return version;
405
370
  };
406
- const resolveNextVersion = async (type, current$1) => {
407
- if (type === "ignore") return current$1;
371
+ const resolveNextVersion = async (type, current) => {
372
+ if (type === "ignore") return current;
408
373
  if (type === "custom") return inputVersion();
409
- return createVersionMap(current$1)[type];
374
+ return createVersionMap(current)[type];
410
375
  };
411
376
  return await resolveNextVersion(await selectVersion(), current);
412
377
  };
413
-
414
378
  //#endregion
415
379
  //#region src/defaults.ts
416
380
  const createDefaultContext = () => {
@@ -488,10 +452,10 @@ const createDefaultConfig = (isCI) => {
488
452
  },
489
453
  isMonorepo: false,
490
454
  packages: [],
491
- getPkgDir(pkg$1) {
455
+ getPkgDir(pkg) {
492
456
  return ".";
493
457
  },
494
- toTag(pkg$1, version) {
458
+ toTag(pkg, version) {
495
459
  return `v${version}`;
496
460
  },
497
461
  tagPrefix: void 0,
@@ -526,7 +490,6 @@ const createDefaultConfig = (isCI) => {
526
490
  }
527
491
  };
528
492
  };
529
-
530
493
  //#endregion
531
494
  //#region src/git/changetype.ts
532
495
  const defaultTypes = [
@@ -621,13 +584,11 @@ const defaultTypes = [
621
584
  description: "紧急修复"
622
585
  }
623
586
  ];
624
-
625
587
  //#endregion
626
588
  //#region src/git/changelog.ts
627
- const createGenerator = async ({ getPkgDir, tagPrefix }) => {
628
- const pkgDir = getPkgDir();
629
- const preset = await createPreset({ types: defaultTypes.map((t$1) => ({
630
- ...t$1,
589
+ const parsePreset = async () => {
590
+ const preset = await createPreset({ types: defaultTypes.map((t) => ({
591
+ ...t,
631
592
  hidden: false
632
593
  })) });
633
594
  preset.writer ??= {};
@@ -678,6 +639,11 @@ const createGenerator = async ({ getPkgDir, tagPrefix }) => {
678
639
  {{> commit root=@root}}
679
640
  {{/each}}
680
641
  {{/each}}`.trim() + eol(2);
642
+ return preset;
643
+ };
644
+ const createGenerator = async ({ getPkgDir, tagPrefix }) => {
645
+ const pkgDir = getPkgDir();
646
+ const preset = await parsePreset();
681
647
  return new ConventionalChangelog().readPackage(`${pkgDir}/package.json`).config(preset).options({ releaseCount: 1 }).commits({ path: pkgDir }).tags({ prefix: tagPrefix });
682
648
  };
683
649
  const getChangelog = async ({ getPkgDir, tagPrefix }) => {
@@ -703,7 +669,6 @@ const generateChangelog = async ({ getPkgDir, tagPrefix }) => {
703
669
  writeStream.end();
704
670
  await finished(writeStream);
705
671
  };
706
-
707
672
  //#endregion
708
673
  //#region src/git/prompts.ts
709
674
  const runGitPrompts = async (ctx, config) => {
@@ -739,7 +704,6 @@ const runGitPrompts = async (ctx, config) => {
739
704
  } });
740
705
  Object.assign(config.git, reset);
741
706
  };
742
-
743
707
  //#endregion
744
708
  //#region src/github/prompts.ts
745
709
  const runGithubPrompts = async (ctx, config) => {
@@ -762,7 +726,6 @@ const runGithubPrompts = async (ctx, config) => {
762
726
  Object.assign(config.github, { release: res.release });
763
727
  return res;
764
728
  };
765
-
766
729
  //#endregion
767
730
  //#region src/github/release.ts
768
731
  const truncateBody = (body) => {
@@ -779,7 +742,7 @@ const getReleaseByTagSafe = async (octokit, options) => {
779
742
  }
780
743
  };
781
744
  const createCRelease = async (octokit, options) => {
782
- const { owner, repo, tag, name, body, draft, prerelease: prerelease$1, generateReleaseNotes, makeLatest, targetCommitish, discussionCategoryName } = options;
745
+ const { owner, repo, tag, name, body, draft, prerelease, generateReleaseNotes, makeLatest, targetCommitish, discussionCategoryName } = options;
783
746
  const { data } = await octokit.repos.createRelease({
784
747
  owner,
785
748
  repo,
@@ -787,7 +750,7 @@ const createCRelease = async (octokit, options) => {
787
750
  name,
788
751
  body,
789
752
  draft,
790
- prerelease: prerelease$1,
753
+ prerelease,
791
754
  generate_release_notes: generateReleaseNotes,
792
755
  make_latest: makeLatest,
793
756
  target_commitish: targetCommitish,
@@ -796,7 +759,7 @@ const createCRelease = async (octokit, options) => {
796
759
  return data;
797
760
  };
798
761
  const updateCRelease = async (octokit, options) => {
799
- const { owner, repo, tag, name, body, draft, prerelease: prerelease$1, generateReleaseNotes, makeLatest, targetCommitish, discussionCategoryName, releaseId } = options;
762
+ const { owner, repo, tag, name, body, draft, prerelease, generateReleaseNotes, makeLatest, targetCommitish, discussionCategoryName, releaseId } = options;
800
763
  const { data } = await octokit.repos.updateRelease({
801
764
  owner,
802
765
  repo,
@@ -805,7 +768,7 @@ const updateCRelease = async (octokit, options) => {
805
768
  name,
806
769
  body,
807
770
  draft,
808
- prerelease: prerelease$1,
771
+ prerelease,
809
772
  generate_release_notes: generateReleaseNotes,
810
773
  make_latest: makeLatest,
811
774
  target_commitish: targetCommitish,
@@ -842,13 +805,13 @@ const uploadAssets = async (octokit, options) => {
842
805
  }));
843
806
  };
844
807
  const createWebRelease = async (options) => {
845
- const { owner, repo, tag, title, body, prerelease: prerelease$1 } = options;
808
+ const { owner, repo, tag, title, body, prerelease } = options;
846
809
  const url = new URL(`${getGithubUrl(owner, repo)}/releases/new`);
847
810
  Object.entries({
848
811
  tag,
849
812
  title,
850
813
  body,
851
- prerelease: prerelease$1
814
+ prerelease
852
815
  }).forEach(([key, value]) => {
853
816
  url.searchParams.set(key, value);
854
817
  });
@@ -891,7 +854,7 @@ const githubCheck = async (ctx, config) => {
891
854
  const createRelease = async (ctx, config) => {
892
855
  const { pkg: { name, toPreRelease }, git: { currentTag }, isCI, dryRun } = ctx;
893
856
  const { github: { isWeb, token, owner, repo, changelog, releaseName } } = ctx;
894
- const { github: { release, assets, prerelease: prerelease$1, autoGenerate, draft } } = config;
857
+ const { github: { release, assets, prerelease, autoGenerate, draft } } = config;
895
858
  if (!release || dryRun) return;
896
859
  const octokit = new Octokit({ auth: token });
897
860
  if (isWeb) await createWebRelease({
@@ -900,7 +863,7 @@ const createRelease = async (ctx, config) => {
900
863
  tag: currentTag,
901
864
  title: releaseName,
902
865
  body: truncateBody(changelog),
903
- prerelease: String(toPreRelease || prerelease$1)
866
+ prerelease: String(toPreRelease || prerelease)
904
867
  });
905
868
  else if (isCI) {
906
869
  const res = await createCReleaseByTag(octokit, {
@@ -910,7 +873,7 @@ const createRelease = async (ctx, config) => {
910
873
  name: releaseName,
911
874
  body: autoGenerate ? "" : truncateBody(changelog),
912
875
  draft,
913
- prerelease: toPreRelease || prerelease$1,
876
+ prerelease: toPreRelease || prerelease,
914
877
  generateReleaseNotes: autoGenerate,
915
878
  makeLatest: "true"
916
879
  });
@@ -928,7 +891,6 @@ const createRelease = async (ctx, config) => {
928
891
  }
929
892
  }
930
893
  };
931
-
932
894
  //#endregion
933
895
  //#region src/npm/prompts.ts
934
896
  const runNpmPublishPrompts = async (ctx, config) => {
@@ -959,17 +921,8 @@ const runNpmOptPrompts = async (ctx, config) => {
959
921
  Object.assign(ctx.npm, { otp: res.otp });
960
922
  return res;
961
923
  };
962
-
963
924
  //#endregion
964
925
  //#region src/npm/publish.ts
965
- const resolvePublishTag = async (pkgName, version) => {
966
- const { toPreRelease, preId } = parseVersion(version);
967
- if (toPreRelease) return preId || "next";
968
- const active = await getPublishedVersion(pkgName);
969
- if (!active) return "latest";
970
- return lt(version, active) ? "previous" : "latest";
971
- };
972
- const isOtpError = (err) => err instanceof Error && /one-time password|otp/i.test(err.message);
973
926
  const npmCheck = async (ctx, config) => {
974
927
  const { pkg: { name, current, publishConfig: { registry } } } = ctx;
975
928
  const { npm: { skipChecks } } = config;
@@ -1002,7 +955,6 @@ const publishNpm = async (ctx, config) => {
1002
955
  cwd: getPkgDir(selectedPkg)
1003
956
  });
1004
957
  };
1005
-
1006
958
  //#endregion
1007
959
  //#region src/action.ts
1008
960
  var Action = class {
@@ -1018,7 +970,7 @@ var Action = class {
1018
970
  taskEnd(MSG.OUTRO(ctx.dryRun));
1019
971
  }
1020
972
  async handlePrepareRelease(cmdArgs, options) {
1021
- const { ctx, config } = await this.createContext(cmdArgs, options);
973
+ const { ctx, config } = await this.createContext(cmdArgs, options, true);
1022
974
  await this.checkTask(ctx, config);
1023
975
  await this.bumpTask(ctx, config);
1024
976
  await this.changelogTask(ctx, config);
@@ -1026,7 +978,7 @@ var Action = class {
1026
978
  if (ctx.dryRun) gitRollback(ctx);
1027
979
  taskEnd(MSG.OUTRO_PREPARE(ctx.dryRun));
1028
980
  }
1029
- async createContext(cmdArgs, options) {
981
+ async createContext(cmdArgs, options, prepare = false) {
1030
982
  const { version: cVersion, name: cName } = readJsonFile(join(__dirname, "../package.json"));
1031
983
  const { otp, package: defPkg, ...others } = options;
1032
984
  const { showChangelog, showRelease, ci, dryRun } = Object.fromEntries(Object.entries(others).map(([k, v]) => [k, Boolean(v)]));
@@ -1036,7 +988,7 @@ var Action = class {
1036
988
  info(MSG.INFO.TOOL(cName, cVersion));
1037
989
  info(MSG.INFO.CONFIG(configPath));
1038
990
  console.log();
1039
- intro(MSG.INTRO(dryRun));
991
+ intro(prepare ? MSG.INTRO_PREPARE(dryRun) : MSG.INTRO(dryRun));
1040
992
  const { isMonorepo, packages, getPkgDir } = config;
1041
993
  if (isMonorepo) {
1042
994
  if (ci) {
@@ -1044,19 +996,19 @@ var Action = class {
1044
996
  } else if (packages.length < 1) abortTask(MSG.ABORT.MONOREPO_NO_PACKAGES);
1045
997
  }
1046
998
  const selectPackage = async () => {
1047
- const pkg$2 = await select({
999
+ const pkg = await select({
1048
1000
  message: question(MSG.PROMPT.SELECT_PACKAGE, "package"),
1049
- options: packages.map((pkg$3) => ({
1050
- label: pkg$3,
1051
- value: pkg$3
1001
+ options: packages.map((pkg) => ({
1002
+ label: pkg,
1003
+ value: pkg
1052
1004
  }))
1053
1005
  });
1054
- abortSinglePrompt(pkg$2);
1055
- return pkg$2;
1006
+ abortSinglePrompt(pkg);
1007
+ return pkg;
1056
1008
  };
1057
1009
  const selectedPkg = !isMonorepo ? "" : ci ? defPkg : packages.length === 1 ? packages[0] : await selectPackage();
1058
- const { pkg: pkg$1, pkgDir } = getPackageInfo(selectedPkg, getPkgDir);
1059
- const { version: pkgVersion, private: pkgPrivate = false, name: pkgName, publishConfig = {} } = pkg$1;
1010
+ const { pkg, pkgDir } = getPackageInfo(selectedPkg, getPkgDir);
1011
+ const { version: pkgVersion, private: pkgPrivate = false, name: pkgName, publishConfig = {} } = pkg;
1060
1012
  const nextVersion = inc(pkgVersion, cmdArgs) ?? "";
1061
1013
  const ctx = mergeConfig(createDefaultContext(), {
1062
1014
  selectedPkg,
@@ -1077,7 +1029,7 @@ var Action = class {
1077
1029
  pkg: {
1078
1030
  name: pkgName,
1079
1031
  isPrivate: pkgPrivate,
1080
- fromPreRelease: isPreRelease(pkgVersion),
1032
+ fromPreRelease: isPrerelease(pkgVersion),
1081
1033
  current: pkgVersion,
1082
1034
  next: nextVersion,
1083
1035
  toPreRelease: false,
@@ -1087,7 +1039,7 @@ var Action = class {
1087
1039
  });
1088
1040
  const { messages } = await publint({ pkgDir });
1089
1041
  for (const message of messages) {
1090
- const formated = formatMessage(message, pkg$1);
1042
+ const formated = formatMessage(message, pkg);
1091
1043
  formated && msg("PKG", formated);
1092
1044
  }
1093
1045
  return {
@@ -1109,19 +1061,19 @@ var Action = class {
1109
1061
  {
1110
1062
  title: MSG.CHECK.NPM.CHECKING,
1111
1063
  task: async () => {
1112
- const msg$1 = await npmCheck(ctx, config);
1064
+ const msg = await npmCheck(ctx, config);
1113
1065
  const { pkg: { publishConfig: { registry } } } = ctx;
1114
- return success(MSG.CHECK.NPM.CHECKED(registry, msg$1), dryRun);
1066
+ return success(MSG.CHECK.NPM.CHECKED(registry, msg), dryRun);
1115
1067
  },
1116
1068
  enabled: !ctx.noNpm
1117
1069
  },
1118
1070
  {
1119
1071
  title: MSG.CHECK.GITHUB.CHECKING,
1120
1072
  task: async () => {
1121
- const msg$1 = await githubCheck(ctx, config);
1073
+ const msg = await githubCheck(ctx, config);
1122
1074
  const { github: { owner, repo } } = ctx;
1123
1075
  const repository = getGithubUrl(owner, repo);
1124
- return success(MSG.CHECK.GITHUB.CHECKED(repository, msg$1), dryRun);
1076
+ return success(MSG.CHECK.GITHUB.CHECKED(repository, msg), dryRun);
1125
1077
  },
1126
1078
  enabled: !ctx.noGitHub
1127
1079
  }
@@ -1130,15 +1082,20 @@ var Action = class {
1130
1082
  async bumpTask(ctx, config) {
1131
1083
  const { pkg: { current }, dryRun, isCI, showRelease, showChangelog, selectedPkg } = ctx;
1132
1084
  const { isMonorepo, hooks, getPkgDir, tagPrefix } = config;
1133
- const need = (ctx$1) => {
1134
- const { pkg: { next: next$1 }, isIncrement: isIncrement$1 } = ctx$1;
1135
- return !next$1 && isIncrement$1;
1085
+ const need = (ctx) => {
1086
+ const { pkg: { next }, isIncrement } = ctx;
1087
+ return !next && isIncrement;
1136
1088
  };
1137
1089
  if (need(ctx)) {
1138
- const next$1 = (isCI ? getCIVersion(current) : void 0) || await runVersionPrompts(ctx, config);
1139
- ctx.isIncrement = isNeq(current, next$1);
1140
- const parsed = parseVersion(next$1);
1141
- Object.assign(ctx.pkg, { ...parsed });
1090
+ const nextVersion = (isCI ? inc(current, "patch") : void 0) || await runVersionPrompts(ctx, config);
1091
+ ctx.isIncrement = neq(current, nextVersion);
1092
+ const { version: next, isPrerelease: toPreRelease, preId, preBase } = parseVersion(nextVersion);
1093
+ Object.assign(ctx.pkg, {
1094
+ next,
1095
+ toPreRelease,
1096
+ preId,
1097
+ preBase
1098
+ });
1142
1099
  }
1143
1100
  const { pkg: { next }, isIncrement } = ctx;
1144
1101
  if (showRelease) taskEnd(MSG.LOG.SHOW_VERSION(next));
@@ -1148,8 +1105,8 @@ var Action = class {
1148
1105
  task: async () => {
1149
1106
  await bumpPackageVersion(next, [], getPkgDir(selectedPkg));
1150
1107
  await formatTemplate(ctx, config);
1151
- const to$1 = `(${current}...${diff(current, next)})`;
1152
- return success(MSG.TASK.VERSION.END(to$1), dryRun);
1108
+ const to = `(${current}...${diff(current, next)})`;
1109
+ return success(MSG.TASK.VERSION.END(to), dryRun);
1153
1110
  }
1154
1111
  }]).catch((err) => abortOnError(err, ctx));
1155
1112
  await runLifeCycleHook(hooks, "after:bump", dryRun);
@@ -1239,18 +1196,13 @@ var Action = class {
1239
1196
  await runLifeCycleHook(hooks, "after:release", dryRun);
1240
1197
  }
1241
1198
  };
1242
-
1243
1199
  //#endregion
1244
1200
  //#region src/cli.ts
1245
1201
  const pkg = readJsonFile(join(__dirname, "..", "package.json"));
1246
- function withCommonOptions(cmd) {
1247
- return cmd.version(pkg.version, "-v, --version", "Print the tool version and exit.").usage("[release-type] [options]").argument("[release-type]", "Version bump type: patch | minor | major").option("-n, --dry-run", "Run in dry mode", false).option("-p, --package <pkg>", "Specify package name (CI only).", "").option("--otp <code>", "One-time password for npm publish.", "").option("--ci", "Enable CI mode.", false).option("--show-changelog", "Print changelog and exit.", false).option("--show-release", "Print release version and exit.", false).helpOption("-h, --help", "Display help information.");
1248
- }
1249
- withCommonOptions(program.name("release").description(pkg.description)).action(async (releaseType, options) => {
1250
- await new Action().handleRelease(releaseType, options);
1251
- });
1252
- withCommonOptions(program.command("prepare").description("Prepare a release (bump version, commit, tag)")).action(async (releaseType, options) => {
1253
- await new Action().handlePrepareRelease(releaseType, options);
1202
+ program.name("release").description(pkg.description).version(pkg.version, "-v, --version", "Print the tool version and exit.").usage("[release-type] [options]").argument("[release-type]", "Version bump type: patch | minor | major").option("-n, --dry-run", "Run in dry mode", false).option("-p, --package <pkg>", "Specify package name (CI only).", "").option("--otp <code>", "One-time password for npm publish.", "").option("--prepare", "Prepare a release.", false).option("--ci", "Enable CI mode.", false).option("--show-changelog", "Print changelog and exit.", false).option("--show-release", "Print release version and exit.", false).helpOption("-h, --help", "Display help information.").action(async (releaseType, options) => {
1203
+ const { prepare } = options;
1204
+ const action = new Action();
1205
+ prepare ? await action.handlePrepareRelease(releaseType, options) : await action.handleRelease(releaseType, options);
1254
1206
  });
1255
1207
  program.command("init").description("Create a release configuration file").option("-f, --force", "Overwrite existing config file", false).option("-m, --monorepo", "Mono-repo project", false).action((options) => {
1256
1208
  const { force = false, monorepo = false } = options;
@@ -1258,9 +1210,10 @@ program.command("init").description("Create a release configuration file").optio
1258
1210
  const { type } = readJsonFile(join(cwd, "package.json"));
1259
1211
  const isESM = type === "module";
1260
1212
  const isTS = existsSync(join(cwd, "tsconfig.json"));
1261
- const configPath = join(cwd, `release.config.${isESM ? "" : "m"}${isTS ? "ts" : "js"}`);
1213
+ const infile = `release.config.${isESM ? "" : "m"}${isTS ? "ts" : "js"}`;
1214
+ const configPath = join(cwd, infile);
1262
1215
  if (existsSync(configPath) && !force) {
1263
- console.error(`${red`Error:`} ${yellow`release.config.ts`} already exists.\nUse ${green`--force`} to overwrite.`);
1216
+ console.error(`${red`Error:`} ${yellow(infile)} already exists.\nUse ${green`--force`} to overwrite.`);
1264
1217
  process.exit(1);
1265
1218
  }
1266
1219
  const monoConfigToString = () => `{
@@ -1270,10 +1223,8 @@ program.command("init").description("Create a release configuration file").optio
1270
1223
  toTag: (pkg, version) => \`\${ pkg }@\${ version }\`,
1271
1224
  tagPrefix: (pkg) => \`\${ pkg }@\`,
1272
1225
  }`;
1273
- writeFileSync(configPath, `import { defineConfig } from '@peiyanlu/release'
1274
-
1275
- export default defineConfig(${monorepo ? monoConfigToString() : "{}"})`, "utf-8");
1276
- console.log(`${green`✔ release.config.ts`} created successfully`);
1226
+ writeFileSync(configPath, [`import { defineConfig } from '@peiyanlu/release'`, `export default defineConfig(${monorepo ? monoConfigToString() : "{}"})`].join(eol(2)), "utf-8");
1227
+ console.log(`${green`✔`} ${infile} created successfully`);
1277
1228
  });
1278
1229
  program.parse(process.argv);
1279
1230
  program.on("command:*", () => {
@@ -1281,6 +1232,5 @@ program.on("command:*", () => {
1281
1232
  console.log(`See ${red`--help`} for a list of available commands.\n`);
1282
1233
  process.exit(1);
1283
1234
  });
1284
-
1285
1235
  //#endregion
1286
- export { };
1236
+ export {};
package/dist/index.d.mts CHANGED
@@ -1,9 +1,8 @@
1
- import { log } from "@clack/prompts";
2
1
  import { DeepPartial, DeepRequired } from "@peiyanlu/ts-utils";
3
2
  import { ConventionalChangelog } from "conventional-changelog";
3
+ import { log } from "@clack/prompts";
4
4
 
5
5
  //#region src/types.d.ts
6
-
7
6
  type Logger = typeof log;
8
7
  type HookTiming = 'before' | 'after';
9
8
  type HookAction = 'bump' | 'publish' | 'push' | 'release';
@@ -172,7 +171,7 @@ declare const generateChangelog: ({
172
171
  tagPrefix
173
172
  }: Options) => Promise<void>;
174
173
  //#endregion
175
- //#region src/index.d.ts
174
+ //#region src/npm/publish.d.ts
176
175
  interface PublishTagOptions {
177
176
  /**
178
177
  * 支持通过命令行参数提供
package/dist/index.mjs CHANGED
@@ -1,133 +1,16 @@
1
- import { eol, getPackageInfo, getPublishedVersion, publishPackage } from "@peiyanlu/cli-utils";
2
- import { coerce, lt, parse, valid } from "semver";
3
- import { dim, green, underline, yellow } from "ansis";
4
- import { log } from "@clack/prompts";
5
- import { isPlainObject } from "@peiyanlu/ts-utils";
1
+ import { isFunction, isPlainObject } from "@peiyanlu/ts-utils";
6
2
  import { createWriteStream, existsSync, readFileSync } from "node:fs";
7
3
  import { join } from "node:path";
4
+ import { eol, getPackageInfo, publishPackage, resolvePublishTag } from "@peiyanlu/cli-utils";
8
5
  import { ConventionalChangelog } from "conventional-changelog";
9
6
  import createPreset from "conventional-changelog-conventionalcommits";
10
7
  import { writeFile } from "node:fs/promises";
11
8
  import { finished } from "node:stream/promises";
12
-
13
- //#region src/messages.ts
14
- const n = (b) => b ? "(dry run)" : "";
15
- const t = () => green(`${Math.floor(process.uptime())}s`);
16
- const MSG = {
17
- INTRO: (dryRun) => `🚀 Starting release ${n(dryRun)}`,
18
- OUTRO: (dryRun) => `🎉 Release finished successfully in ${t()} ${n(dryRun)}`,
19
- OUTRO_PREPARE: (dryRun) => `🎉 PrepareRelease finished successfully in ${t()} ${n(dryRun)}`,
20
- LOG: {
21
- SHOW_VERSION: (version) => `🎉 Released ${green(version)}`,
22
- SHOW_CHANGELOG: "🎉 Changelog collected",
23
- CHANGELOG_EMPTY: "No commits found since last release",
24
- CHANGES_EMPTY: "Working tree clean. No files changed"
25
- },
26
- CHECK: {
27
- GIT: {
28
- CHECKING: "Checking Git repository",
29
- CHECKED: (name, url) => `Git remote resolved: ${url ? `${dim(name)} → ${underline(dim(url))}` : "not found"}`
30
- },
31
- NPM: {
32
- CHECKING: "Checking npm registry",
33
- CHECKED: (registry, msg) => `NPM registry: ${underline(dim(registry))} ${underline(dim(msg))}`
34
- },
35
- GITHUB: {
36
- CHECKING: "Checking github repository",
37
- CHECKED: (repository, msg) => `GitHub repository: ${underline(dim(repository))} ${underline(dim(msg))}`
38
- }
39
- },
40
- TASK: {
41
- VERSION: {
42
- START: "Bumping version",
43
- END: (to) => `Version bumped: ${underline(dim(to))}`
44
- },
45
- CHANGELOG: {
46
- START: "Generating changelog",
47
- END: `Changelog generated`
48
- },
49
- NPM: {
50
- START: "Publishing npm package",
51
- END: (url) => `NPM package published: ${underline(dim(url))}`
52
- },
53
- GIT: {
54
- START: "Creating git commit, tag & push",
55
- END: "Git commit, tag & push completed"
56
- },
57
- GITHUB: {
58
- START: "Creating GitHub release",
59
- END: (url) => `GitHub release created: ${underline(dim(url))}`
60
- }
61
- },
62
- PROMPT: {
63
- SELECT_PACKAGE: "Select package release:",
64
- SELECT_VERSION: "Select version bump:",
65
- INPUT_VERSION: "Enter custom version:",
66
- NPM_PUBLISH: (pkg) => `Publish to npm ${underline(dim`(${pkg})`)}?`,
67
- NPM_OTP: "Enter npm one-time password (OTP):",
68
- GITHUB_RELEASE: (title) => `Create a new GitHub release ${underline(dim`(${title})`)}?`,
69
- GIT_COMMIT: (msg) => `Create git commit ${underline(dim`(${msg})`)}?`,
70
- GIT_TAG: (msg) => `Create git tag ${underline(dim`(${msg})`)}?`,
71
- GIT_PUSH: "Push commits and tags to remote?"
72
- },
73
- ERROR: {
74
- GIT_WORKDIR: `[git] Working dir must be clean`,
75
- GIT_REGISTRY: (name) => `[git] Repository not found for ${dim(name)}`,
76
- GIT_REMOTE: (name) => `[git] Remote "${dim(name)}" not found`,
77
- GITHUB_TAG_EXIT: (tag) => `[github] Release or tag "${tag}" already exists`,
78
- GITHUB_TOKEN: (tokenRef) => `[github] Missing GitHub token. Please set ${yellow(tokenRef ?? "GITHUB_TOKEN")}`,
79
- GITHUB_AUTH: "[github] Invalid GitHub token or insufficient permissions",
80
- GITHUB_USER: "[github] User does not have permission to create releases",
81
- NPM_REGISTRY: (registry) => `[npm] Unable to reach npm registry ${underline(dim(registry))}`,
82
- NPM_AUTH: `[npm] Not authenticated with npm. Please run ${yellow("npm login")} and try again.`,
83
- NPM_USER: (user, name) => `[npm] User ${dim(user)} is not a collaborator of ${dim(name)}.`
84
- },
85
- ABORT: {
86
- CANCEL: "Operation cancelled",
87
- MONOREPO_CI_NO_PACKAGE: "CI mode requires a target package in monorepo. Please specify it via \"--package <pkg>\"",
88
- MONOREPO_NO_PACKAGES: "Monorepo detected, but no packages found. Please configure \"config.packages\""
89
- },
90
- INFO: {
91
- TOOL: (name, version) => `${name} ${dim(`v${version}`)}`,
92
- CONFIG: (path) => `config file: ${underline(dim(path || "not found"))}`
93
- }
94
- };
95
-
96
- //#endregion
97
- //#region src/version/bump.ts
98
- const isValid = (version) => {
99
- return Boolean(valid(version));
100
- };
101
- const parseVersion = (raw) => {
102
- const next = isValid(raw) ? raw : coerce(raw)?.toString();
103
- if (!next) return {};
104
- const { prerelease } = parse(next);
105
- const toPreRelease = Boolean(prerelease.length);
106
- const [preId, preBase] = prerelease.map(String);
107
- return {
108
- next,
109
- toPreRelease,
110
- preId,
111
- preBase
112
- };
113
- };
114
-
115
- //#endregion
116
- //#region src/npm/publish.ts
117
- const resolvePublishTag = async (pkgName, version) => {
118
- const { toPreRelease, preId } = parseVersion(version);
119
- if (toPreRelease) return preId || "next";
120
- const active = await getPublishedVersion(pkgName);
121
- if (!active) return "latest";
122
- return lt(version, active) ? "previous" : "latest";
123
- };
124
-
125
- //#endregion
9
+ import { blue, cyan, green, magenta, red, underline, yellow } from "ansis";
126
10
  //#region src/config.ts
127
11
  function defineConfig(config) {
128
12
  return config;
129
13
  }
130
- const isFunction = (v) => typeof v === "function";
131
14
  const mergeConfig = (defaults, overrides) => {
132
15
  if (!overrides) return structuredClone(defaults);
133
16
  if (Object.keys(defaults).length === 0) return structuredClone(overrides);
@@ -143,7 +26,6 @@ const mergeConfig = (defaults, overrides) => {
143
26
  }
144
27
  return result;
145
28
  };
146
-
147
29
  //#endregion
148
30
  //#region src/git/changetype.ts
149
31
  const defaultTypes = [
@@ -238,13 +120,11 @@ const defaultTypes = [
238
120
  description: "紧急修复"
239
121
  }
240
122
  ];
241
-
242
123
  //#endregion
243
124
  //#region src/git/changelog.ts
244
- const createGenerator = async ({ getPkgDir, tagPrefix }) => {
245
- const pkgDir = getPkgDir();
246
- const preset = await createPreset({ types: defaultTypes.map((t$1) => ({
247
- ...t$1,
125
+ const parsePreset = async () => {
126
+ const preset = await createPreset({ types: defaultTypes.map((t) => ({
127
+ ...t,
248
128
  hidden: false
249
129
  })) });
250
130
  preset.writer ??= {};
@@ -295,6 +175,11 @@ const createGenerator = async ({ getPkgDir, tagPrefix }) => {
295
175
  {{> commit root=@root}}
296
176
  {{/each}}
297
177
  {{/each}}`.trim() + eol(2);
178
+ return preset;
179
+ };
180
+ const createGenerator = async ({ getPkgDir, tagPrefix }) => {
181
+ const pkgDir = getPkgDir();
182
+ const preset = await parsePreset();
298
183
  return new ConventionalChangelog().readPackage(`${pkgDir}/package.json`).config(preset).options({ releaseCount: 1 }).commits({ path: pkgDir }).tags({ prefix: tagPrefix });
299
184
  };
300
185
  const getChangelog = async ({ getPkgDir, tagPrefix }) => {
@@ -320,43 +205,42 @@ const generateChangelog = async ({ getPkgDir, tagPrefix }) => {
320
205
  writeStream.end();
321
206
  await finished(writeStream);
322
207
  };
323
-
208
+ `${yellow("npm login")}`;
324
209
  //#endregion
325
- //#region src/index.ts
210
+ //#region src/npm/publish.ts
326
211
  const publishTagToNpm = async (options) => {
327
212
  const { gitTag, defaultPackage, tagSeparator = "@", getPkgDir = () => ".", provenance } = options;
328
213
  const tag = process.argv.slice(2)[0] || gitTag;
329
214
  if (!tag) throw new Error(`❌ No git tag specified.`);
330
- console.log(`\n📦 Start publishing from git tag: ${tag}`);
215
+ console.log(`\n📦 Start publishing from git tag: ${cyan(tag)}`);
331
216
  let pkgName = defaultPackage;
332
217
  let version;
333
218
  if (tag.includes(tagSeparator)) {
334
219
  [pkgName, version] = tag.split(tagSeparator);
335
- console.log(`🔍 Parsed tag → package: "${pkgName}", version: "${version}"`);
220
+ console.log(`🔍 Parsed tag → package: "${yellow(pkgName)}", version: "${green(version)}"`);
336
221
  } else {
337
222
  version = tag;
338
- console.log(`🔍 Parsed tag → version only: "${version}"`);
223
+ console.log(`🔍 Parsed tag → version only: "${green(version)}"`);
339
224
  }
340
225
  if (version.startsWith("v")) {
341
226
  version = version.slice(1);
342
227
  console.log(`✂️ Normalized version (strip v): ${version}`);
343
228
  }
344
229
  if (!pkgName) throw new Error(`❌ Package name should be specified in tag "${tag}" when defaultPackage is not set`);
345
- console.log(`📁 Resolving package info for "${pkgName}"...`);
230
+ console.log(`📁 Resolving package info for "${magenta(pkgName)}"...`);
346
231
  const { pkg, pkgDir } = getPackageInfo(pkgName, getPkgDir);
347
- console.log(`📄 package.json → name: ${pkg.name}, version: ${pkg.version}`);
348
- console.log(`📂 Package directory: ${pkgDir}`);
232
+ console.log(`📄 package.json → name: ${yellow(pkg.name)}, version: ${green(pkg.version)}`);
233
+ console.log(`📂 Package directory: ${underline(pkgDir)}`);
349
234
  if (pkg.version !== version) throw new Error(`❌ Package version from tag "${version}" mismatches with current version "${pkg.version}"`);
350
235
  const publishTag = await resolvePublishTag(pkg.name, version);
351
- console.log(`🏷 Resolved npm dist-tag: "${publishTag}" (version ${version})`);
352
- console.log(`🚀 Publishing "${pkg.name}@${version}" to npm...`);
236
+ console.log(`🏷 Resolved npm dist-tag: "${blue(publishTag)}" (version ${green(version)})`);
237
+ console.log(`🚀 Publishing "${red`${pkg.name}@${version}`}" to npm...`);
353
238
  await publishPackage({
354
239
  tag: publishTag,
355
240
  args: provenance ? ["--provenance"] : [],
356
241
  cwd: pkgDir
357
242
  });
358
- console.log(`✅ Successfully published ${pkg.name}@${version} with dist-tag "${publishTag}"\n`);
243
+ console.log(`🎉 Successfully published ${red`${pkg.name}@${version}`} with dist-tag "${blue(publishTag)}"\n`);
359
244
  };
360
-
361
245
  //#endregion
362
- export { createGenerator, defineConfig, generateChangelog, getChangelog, mergeConfig, publishTagToNpm };
246
+ export { createGenerator, defineConfig, generateChangelog, getChangelog, mergeConfig, publishTagToNpm };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peiyanlu/release",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "description": "Release project tool.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -17,29 +17,37 @@
17
17
  },
18
18
  "./package.json": "./package.json"
19
19
  },
20
+ "scripts": {
21
+ "dev": "tsdown -w",
22
+ "build": "tsdown",
23
+ "prepublish": "tsdown",
24
+ "release": "node index.js",
25
+ "test": "vitest run",
26
+ "test:cov": "vitest run --coverage"
27
+ },
20
28
  "dependencies": {
21
- "@clack/prompts": "^0.11.0",
29
+ "@clack/prompts": "^1.2.0",
22
30
  "@octokit/rest": "^22.0.1",
23
- "@peiyanlu/cli-utils": "^0.0.6",
24
- "@peiyanlu/ts-utils": "^0.0.4",
31
+ "@peiyanlu/cli-utils": "^0.0.8",
32
+ "@peiyanlu/ts-utils": "^0.0.5",
25
33
  "ansis": "^4.2.0",
26
- "commander": "^14.0.2",
27
- "conventional-changelog": "^7.1.1",
28
- "conventional-changelog-conventionalcommits": "^9.1.0",
34
+ "commander": "^14.0.3",
35
+ "conventional-changelog": "^7.2.0",
36
+ "conventional-changelog-conventionalcommits": "^9.3.1",
29
37
  "mime-types": "^3.0.2",
30
38
  "open": "^11.0.0",
31
- "publint": "^0.3.17",
32
- "semver": "^7.7.3",
39
+ "publint": "^0.3.18",
40
+ "semver": "^7.7.4",
33
41
  "tinyglobby": "^0.2.15"
34
42
  },
35
43
  "devDependencies": {
36
44
  "@types/mime-types": "^3.0.1",
37
- "@types/node": "^24.10.3",
45
+ "@types/node": "^25.5.2",
38
46
  "@types/semver": "^7.7.1",
39
- "@vitest/coverage-v8": "^4.0.15",
40
- "tsdown": "^0.18.4",
41
- "typescript": "^5.9.3",
42
- "vitest": "^4.0.18"
47
+ "@vitest/coverage-v8": "^4.1.3",
48
+ "tsdown": "^0.21.7",
49
+ "typescript": "^6.0.2",
50
+ "vitest": "^4.1.3"
43
51
  },
44
52
  "author": {
45
53
  "name": "YanluPei",
@@ -66,13 +74,5 @@
66
74
  "bugs": {
67
75
  "url": "https://github.com/peiyanlu/release/issues"
68
76
  },
69
- "homepage": "https://github.com/peiyanlu/release#readme",
70
- "scripts": {
71
- "dev": "tsdown -w",
72
- "build": "tsdown",
73
- "prepublish": "tsdown",
74
- "release": "node index.js",
75
- "test": "vitest run",
76
- "test:cov": "vitest run --coverage"
77
- }
78
- }
77
+ "homepage": "https://github.com/peiyanlu/release#readme"
78
+ }