@peiyanlu/release 0.0.15 → 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.
package/dist/cli.mjs CHANGED
@@ -1,15 +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, isOtpError, isPrerelease, isValid, isWorkingDirClean, parseGitHubRepo, parseVersion, pingRegistry, publishPackage, pushBranch, pushTag, readJsonFile, registryArg, resolveChangelogRange, resolvePublishTag, runNpm } from "@peiyanlu/cli-utils";
3
+ import { bumpPackageVersion, canPublish, coloredStatus, eol, execAsync, getAuthenticatedUser, getGithubReleaseUrl, getGithubUrl, getLatestTag, getLogSince, getPackageInfo, getPackageUrl, getPublishedVersion, getRemoteList, getRemoteNames, getShortStatus, gitAddAll, gitAddSync, gitAddTracked, gitBranchCurrent, gitCommitMessage, gitPushBranch, gitPushTag, gitResetHardSync, gitTagAnnotated, gitTagDeleteSync, hasWriteAccess, isGitRepo, isOtpError, isPrerelease, isValidVersion, isWorkingTreeClean, parseGitHubRepo, parseVersion, pingRegistry, publishPackage, 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
- import { castArray, isFunction, isPlainObject, isUndefined, isZero } from "@peiyanlu/ts-utils";
8
+ import { castArray, isFunction, isPlainObject, isUndefined, isZero, mapObjectValues } from "@peiyanlu/ts-utils";
9
9
  import { publint } from "publint";
10
10
  import { formatMessage } from "publint/utils";
11
11
  import { inc, neq } from "semver";
12
- import { spawnSync } from "node:child_process";
13
12
  import { inspect } from "node:util";
14
13
  import { ConventionalChangelog } from "conventional-changelog";
15
14
  import createPreset from "conventional-changelog-conventionalcommits";
@@ -19,7 +18,7 @@ import { Octokit } from "@octokit/rest";
19
18
  import { contentType } from "mime-types";
20
19
  import open from "open";
21
20
  import { glob } from "tinyglobby";
22
- //#region node_modules/.pnpm/tsdown@0.22.1_publint@0.3.21_typescript@6.0.3/node_modules/tsdown/esm-shims.js
21
+ //#region node_modules/.pnpm/tsdown@0.22.3_publint@0.3.21_typescript@6.0.3/node_modules/tsdown/esm-shims.js
23
22
  const getFilename = () => fileURLToPath(import.meta.url);
24
23
  const getDirname = () => path.dirname(getFilename());
25
24
  const __dirname = /* @__PURE__ */ getDirname();
@@ -45,11 +44,11 @@ const loadConfig = async (file) => {
45
44
  const resolveConfig = async (cwd) => {
46
45
  const configFile = findConfigFile(cwd);
47
46
  if (!configFile) return {
48
- configPath: "",
47
+ configFile: "",
49
48
  config: {}
50
49
  };
51
50
  return {
52
- configPath: configFile,
51
+ configFile,
53
52
  config: await loadConfig(configFile)
54
53
  };
55
54
  };
@@ -130,7 +129,7 @@ const MSG = {
130
129
  GIT_PUSH: "Push commits and tags to remote?"
131
130
  },
132
131
  ERROR: {
133
- GIT_WORKDIR: `[git] Working dir must be clean`,
132
+ GIT_WORKDIR: `[git] Working tree must be clean`,
134
133
  GIT_REGISTRY: (name) => `[git] Repository not found for ${dim(name)}`,
135
134
  GIT_REMOTE: (name) => `[git] Remote "${dim(name)}" not found`,
136
135
  GITHUB_TAG_EXIT: (tag) => `[github] Release for tag "${tag}" already exists and is not a draft`,
@@ -156,8 +155,8 @@ const MSG = {
156
155
  //#region src/git/commit.ts
157
156
  const gitCheck = async (ctx, config) => {
158
157
  const { pkg: { name } } = ctx;
159
- const { git: { requireRepository, requireRemote, requireWorkDirClean }, ignoreGit, ignoreGithub } = config;
160
- if (ignoreGit) {
158
+ const { git: { requireRepository, requireRemote, requireCleanWorkingTree }, skipGit, skipGithub } = config;
159
+ if (skipGit) {
161
160
  ctx.noGit = true;
162
161
  ctx.noGitHub = true;
163
162
  return;
@@ -168,12 +167,12 @@ const gitCheck = async (ctx, config) => {
168
167
  ctx.noGitHub = true;
169
168
  return;
170
169
  }
171
- if (requireWorkDirClean && !await isWorkingDirClean()) throw new Error(MSG.ERROR.GIT_WORKDIR);
172
- if (ignoreGithub) {
170
+ if (requireCleanWorkingTree && !await isWorkingTreeClean()) throw new Error(MSG.ERROR.GIT_WORKDIR);
171
+ if (skipGithub) {
173
172
  ctx.noGitHub = true;
174
173
  return;
175
174
  }
176
- const { remoteName, remoteUrl } = await getRemote();
175
+ const { name: remoteName, url: remoteUrl } = (await getRemoteList())[0];
177
176
  if (!remoteUrl) if (requireRemote) throw new Error(MSG.ERROR.GIT_REMOTE(name));
178
177
  else {
179
178
  ctx.noGitHub = true;
@@ -194,18 +193,18 @@ const commitAndTag = async (ctx, config) => {
194
193
  const { git: { commit, tag, push, addUntrackedFiles, commitArgs, tagArgs, pushArgs } } = config;
195
194
  if (!commit) return;
196
195
  const args = dryRun ? ["--dry-run"] : [];
197
- addUntrackedFiles ? await gitAddAll() : await gitAddTracked(args);
198
- await gitCommit(commitMessage, [...commitArgs, ...args]);
196
+ addUntrackedFiles ? await gitAddAll(args) : await gitAddTracked(args);
197
+ await gitCommitMessage(commitMessage, [...commitArgs, ...args]);
199
198
  if (!dryRun) Object.assign(ctx.git, { isCommitted: true });
200
199
  if (tag) {
201
200
  await gitTagAnnotated(currentTag, tagMessage, [...tagArgs, ...args]);
202
201
  if (!dryRun) Object.assign(ctx.git, { isTagged: true });
203
202
  }
204
203
  if (push) {
205
- const remotes = await getAllRemotes();
204
+ const remotes = await getRemoteNames();
206
205
  for (const remoteName of remotes) {
207
- await pushTag(remoteName, currentTag, args);
208
- await pushBranch(remoteName, await getCurrentBranch(), [...pushArgs, ...args]);
206
+ await gitPushTag(remoteName, currentTag, args);
207
+ await gitPushBranch(remoteName, await gitBranchCurrent(), [...pushArgs, ...args]);
209
208
  }
210
209
  if (!dryRun) Object.assign(ctx.git, { isPushed: true });
211
210
  }
@@ -213,40 +212,8 @@ const commitAndTag = async (ctx, config) => {
213
212
  const gitRollback = (ctx) => {
214
213
  const { git: { currentTag, isCommitted, isTagged, isPushed } } = ctx;
215
214
  if (isPushed) return;
216
- spawnSync("git", ["restore", "."]);
217
- if (isTagged) spawnSync("git", [
218
- "tag",
219
- "--delete",
220
- currentTag
221
- ]);
222
- spawnSync("git", [
223
- "reset",
224
- "--hard",
225
- isCommitted ? "HEAD~1" : "HEAD"
226
- ]);
227
- };
228
- //#endregion
229
- //#region src/prompts.ts
230
- const abortTask = (msg) => {
231
- cancel(`${red("✕")} ${msg}`);
232
- process.exit(0);
233
- };
234
- const abortSinglePrompt = (value) => {
235
- if (isCancel(value)) abortTask(MSG.ABORT.CANCEL);
236
- };
237
- const abortGroupPrompt = (ctx) => {
238
- ctx && gitRollback(ctx);
239
- abortTask(MSG.ABORT.CANCEL);
240
- };
241
- const abortOnError = (err, ctx, exit = true) => {
242
- ctx && gitRollback(ctx);
243
- const msg = err.message.replace(/^\[(github|npm|git)]/, (a) => red(a));
244
- log.message(`\n${msg}\n`);
245
- exit && process.exit(1);
246
- };
247
- const taskEnd = (msg) => {
248
- outro(msg);
249
- process.exit(0);
215
+ if (isTagged) gitTagDeleteSync(currentTag);
216
+ gitResetHardSync(isCommitted ? 1 : 0);
250
217
  };
251
218
  //#endregion
252
219
  //#region src/utils.ts
@@ -301,6 +268,27 @@ const formatTemplate = async (ctx, config) => {
301
268
  });
302
269
  Object.assign(ctx.github, { releaseName });
303
270
  };
271
+ const abortTask = (msg) => {
272
+ cancel(`${red("✕")} ${msg}`);
273
+ process.exit(0);
274
+ };
275
+ const abortSinglePrompt = (value) => {
276
+ if (isCancel(value)) abortTask(MSG.ABORT.CANCEL);
277
+ };
278
+ const abortGroupPrompt = (ctx) => {
279
+ ctx && gitRollback(ctx);
280
+ abortTask(MSG.ABORT.CANCEL);
281
+ };
282
+ const abortOnError = (err, ctx, exit = true) => {
283
+ ctx && gitRollback(ctx);
284
+ const msg = err.message.replace(/^\[(github|npm|git)]/, (a) => red(a));
285
+ log.message(`\n${msg}\n`);
286
+ exit && process.exit(1);
287
+ };
288
+ const taskEnd = (msg) => {
289
+ outro(msg);
290
+ process.exit(0);
291
+ };
304
292
  //#endregion
305
293
  //#region src/version/prompts.ts
306
294
  const createVersionMap = (current) => ({
@@ -348,7 +336,7 @@ const runVersionPrompts = async (ctx, config) => {
348
336
  message: question(MSG.PROMPT.INPUT_VERSION, "version"),
349
337
  initialValue: current,
350
338
  validate: (val) => {
351
- if (!isValid(val)) return "Invalid version";
339
+ if (isUndefined(val) || !isValidVersion(val)) return "Invalid version";
352
340
  }
353
341
  });
354
342
  abortSinglePrompt(version);
@@ -450,9 +438,9 @@ const createDefaultConfig = (isCI) => {
450
438
  },
451
439
  releaseCount: 1
452
440
  },
453
- ignoreGit: false,
454
- ignoreNpm: false,
455
- ignoreGithub: false,
441
+ skipGit: false,
442
+ skipNpm: false,
443
+ skipGithub: false,
456
444
  git: {
457
445
  commit: isCI,
458
446
  tag: isCI,
@@ -465,7 +453,7 @@ const createDefaultConfig = (isCI) => {
465
453
  addUntrackedFiles: false,
466
454
  requireRemote: true,
467
455
  requireRepository: true,
468
- requireWorkDirClean: true
456
+ requireCleanWorkingTree: true
469
457
  },
470
458
  npm: {
471
459
  publish: isCI,
@@ -591,8 +579,7 @@ const parsePreset = async () => {
591
579
  hidden: false
592
580
  })) });
593
581
  preset.writer ??= {};
594
- preset.writer.headerPartial = `
595
- ## {{#if isPatch~}} <small> {{~/if~}}
582
+ preset.writer.headerPartial = `## {{#if isPatch~}} <small> {{~/if~}}
596
583
  {{#if @root.linkCompare~}}
597
584
  [{{version}}](
598
585
  {{~#if @root.repository~}}
@@ -616,8 +603,7 @@ const parsePreset = async () => {
616
603
  {{~/if}}
617
604
  {{~#if isPatch~}} </small> {{~/if}}
618
605
  `.trim() + eol();
619
- preset.writer.mainTemplate = `
620
- {{> header}}
606
+ preset.writer.mainTemplate = `{{> header}}
621
607
  {{#if noteGroups}}
622
608
  {{#each noteGroups}}
623
609
 
@@ -653,7 +639,7 @@ const getChangelog = async ({ getPkgDir, tagPrefix, releaseCount = 1 }) => {
653
639
  });
654
640
  let changelog = "";
655
641
  for await (const chunk of generator.write()) changelog += chunk;
656
- return changelog;
642
+ return changelog.trimEnd();
657
643
  };
658
644
  const generateChangelog = async ({ getPkgDir, tagPrefix, releaseCount = 1 }) => {
659
645
  const infile = join(getPkgDir(), "CHANGELOG.md");
@@ -932,18 +918,6 @@ const runNpmOptPrompts = async (ctx, config) => {
932
918
  };
933
919
  //#endregion
934
920
  //#region src/npm/publish.ts
935
- const canPublish = async (registry) => {
936
- const res = await runNpm([
937
- "publish",
938
- "--dry-run",
939
- "--no-git-checks",
940
- "--access",
941
- "public",
942
- ...registryArg(registry)
943
- ], { error: "throw" }).catch((err) => err);
944
- if (!(res instanceof Error)) return true;
945
- return [/previously published versions/i, /cannot publish over/i].some((reg) => reg.test(res.message));
946
- };
947
921
  const npmCheck = async (ctx, config) => {
948
922
  const { pkg: { name, current, publishConfig: { registry } } } = ctx;
949
923
  const { npm: { skipChecks } } = config;
@@ -1006,16 +980,26 @@ var Action = class {
1006
980
  }
1007
981
  async createContext(cmdArgs, options, prepare = false) {
1008
982
  const { version: cVersion, name: cName } = readJsonFile(join(__dirname, "../package.json"));
1009
- const { otp, package: defPkg, ...others } = options;
1010
- const { showChangelog, showRelease, ci, dryRun } = Object.fromEntries(Object.entries(others).map(([k, v]) => [k, Boolean(v)]));
983
+ const { otp, package: defPkg, releaseCount, ...others } = options;
984
+ const { showChangelog, showRelease, ci, dryRun } = mapObjectValues(others, (v) => Boolean(v));
1011
985
  process.env["dryRun"] = String(dryRun);
1012
- const { configPath, config: local } = await resolveConfig(process.cwd());
986
+ const { configFile, config: local } = await resolveConfig(process.cwd());
1013
987
  const config = mergeConfig(createDefaultConfig(ci ? true : void 0), local);
1014
988
  info(MSG.INFO.TOOL(cName, cVersion));
1015
- info(MSG.INFO.CONFIG(configPath));
989
+ info(MSG.INFO.CONFIG(configFile));
990
+ {
991
+ const { requireCleanWorkingTree, skipGit, skipNpm, skipGithub, isMonorepo } = mapObjectValues(others, (v) => Boolean(v));
992
+ const count = Number(releaseCount);
993
+ config.changelog.releaseCount = isNaN(count) ? 0 : count;
994
+ config.git.requireCleanWorkingTree = requireCleanWorkingTree;
995
+ config.skipGit = skipGit;
996
+ config.skipNpm = skipNpm;
997
+ config.skipGithub = skipGithub;
998
+ config.isMonorepo = isMonorepo;
999
+ }
1016
1000
  console.log();
1017
1001
  intro(prepare ? MSG.INTRO_PREPARE(dryRun) : MSG.INTRO(dryRun));
1018
- const { isMonorepo, packages, getPkgDir, ignoreNpm } = config;
1002
+ const { isMonorepo, packages, getPkgDir, skipNpm } = config;
1019
1003
  if (isMonorepo) {
1020
1004
  if (ci) {
1021
1005
  if (!defPkg) abortTask(MSG.ABORT.MONOREPO_CI_NO_PACKAGE);
@@ -1061,7 +1045,7 @@ var Action = class {
1061
1045
  toPreRelease: false,
1062
1046
  publishConfig: { ...publishConfig }
1063
1047
  },
1064
- noNpm: pkgPrivate || ignoreNpm
1048
+ noNpm: pkgPrivate || skipNpm
1065
1049
  });
1066
1050
  const { messages } = await publint({ pkgDir });
1067
1051
  for (const message of messages) {
@@ -1142,7 +1126,7 @@ var Action = class {
1142
1126
  from: "",
1143
1127
  to: "HEAD"
1144
1128
  } : await resolveChangelogRange(isIncrement, match);
1145
- const commits = await getLog(from, to, getPkgDir(selectedPkg));
1129
+ const commits = await getLogSince(from, to, getPkgDir(selectedPkg));
1146
1130
  const changelog = await getChangelog({
1147
1131
  getPkgDir: () => getPkgDir(selectedPkg),
1148
1132
  tagPrefix: tagPrefix?.(selectedPkg),
@@ -1150,7 +1134,7 @@ var Action = class {
1150
1134
  });
1151
1135
  Object.assign(ctx.github, { changelog });
1152
1136
  if (commits) {
1153
- msg("GIT", `Changelog(${from}...${to}):${eol(2)}` + changelog.trimEnd());
1137
+ msg("GIT", `Changelog(${from}...${to}):${eol(2)}` + changelog);
1154
1138
  msg("GIT", `Commits(${from}...${to}):${eol(2)}` + commits);
1155
1139
  if (showChangelog) taskEnd(MSG.LOG.SHOW_CHANGELOG);
1156
1140
  } else msg("GIT", MSG.LOG.CHANGELOG_EMPTY);
@@ -1172,8 +1156,8 @@ var Action = class {
1172
1156
  },
1173
1157
  enabled: isIncrement
1174
1158
  }]).catch((err) => abortOnError(err, ctx));
1175
- const changeset = await getStatus();
1176
- if (changeset) msg("GIT", `Changes:${eol(2)}` + coloredChangeset(changeset));
1159
+ const changeset = await getShortStatus();
1160
+ if (changeset) msg("GIT", `Changes:${eol(2)}` + coloredStatus(changeset));
1177
1161
  else msg("GIT", MSG.LOG.CHANGES_EMPTY);
1178
1162
  }
1179
1163
  async gitTask(ctx, config) {
@@ -1236,20 +1220,20 @@ var Action = class {
1236
1220
  //#endregion
1237
1221
  //#region src/cli.ts
1238
1222
  const pkg = readJsonFile(join(__dirname, "..", "package.json"));
1239
- 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) => {
1223
+ 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 (Mono-repo 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).option("-r, --release-count <count>", "Release count for release.", (value) => Number(value), 1).option("-C, --no-require-clean-working-tree", "Allow releasing with uncommitted changes.", true).option("-m, --is-monorepo", "Mono-repo project", false).option("--skip-git", "Skip all Git-related checks and operations.", false).option("--skip-npm", "Skip all npm-related checks and operations.", false).option("--skip-github", "Skip all GitHub-related checks and operations.", false).helpOption("-h, --help", "Display help information.").action(async (releaseType, options) => {
1240
1224
  const { prepare } = options;
1241
1225
  const action = new Action();
1242
1226
  prepare ? await action.handlePrepareRelease(releaseType, options) : await action.handleRelease(releaseType, options);
1243
1227
  });
1244
- 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) => {
1245
- const { force = false, monorepo = false } = options;
1228
+ program.command("init").description("Create a release configuration file").option("-f, --force", "Overwrite existing config file", false).option("-m, --monorepo", "Mono-repo project", false).option("-a, --add", "Automatically stage the config file.", false).action((options) => {
1229
+ const { force = false, monorepo = false, add = false } = options;
1246
1230
  const cwd = process.cwd();
1247
1231
  const { type } = readJsonFile(join(cwd, "package.json"));
1248
1232
  const isESM = type === "module";
1249
1233
  const isTS = existsSync(join(cwd, "tsconfig.json"));
1250
1234
  const infile = `release.config.${isESM ? "" : "m"}${isTS ? "ts" : "js"}`;
1251
- const configPath = join(cwd, infile);
1252
- if (existsSync(configPath) && !force) {
1235
+ const configFile = join(cwd, infile);
1236
+ if (existsSync(configFile) && !force) {
1253
1237
  console.error(`${red`Error:`} ${yellow(infile)} already exists.\nUse ${green`--force`} to overwrite.`);
1254
1238
  process.exit(1);
1255
1239
  }
@@ -1262,9 +1246,13 @@ program.command("init").description("Create a release configuration file").optio
1262
1246
  tagPrefix: (pkg) => \`\${ pkg }@\`,
1263
1247
  },
1264
1248
  }`;
1265
- writeFileSync(configPath, [`import { defineConfig } from '@peiyanlu/release'`, `export default defineConfig(${monorepo ? monoConfigToString() : "{}"})`].join(eol(2)), "utf-8");
1266
- console.log(`${green`✔`} ${infile} created successfully`);
1249
+ const content = [`import { defineConfig } from '@peiyanlu/release'`, `export default defineConfig(${monorepo ? monoConfigToString() : "{}"})`].join(eol(2));
1250
+ writeFileSync(configFile, content, "utf-8");
1251
+ console.log(`Wrote to ${underline(dim(configFile))}`);
1252
+ if (add) gitAddSync([infile]);
1253
+ console.log(`\n${content}`);
1267
1254
  });
1255
+ program.addHelpText("afterAll", "\nThanks for using!");
1268
1256
  program.parse(process.argv);
1269
1257
  program.on("command:*", () => {
1270
1258
  console.error(`\n${red`Error`} Invalid command: ${red`%s`}`, program.args.join(" "));
package/dist/index.d.mts CHANGED
@@ -28,15 +28,21 @@ interface ReleaseConfig {
28
28
  * 影响生成的日志数量、日志标题(monorepo)。
29
29
  */
30
30
  changelog: {
31
- /** 作为 CHANGELOG 标题的 Tag 前缀,多包场景下需要 `${pkg}@` */tagPrefix: ((pkg: string) => string); /** 生成多少个版本的变更日志,详见 {@link Options} */
31
+ /**
32
+ * 作为 CHANGELOG 标题的 Tag 前缀,多包场景下需要 `${pkg}@`
33
+ */
34
+ tagPrefix: ((pkg: string) => string);
35
+ /**
36
+ * 生成多少个版本的变更日志,详见 {@link Options}
37
+ */
32
38
  releaseCount: number;
33
39
  };
34
- /** 忽略 git、github 环境检查以及后续操作 */
35
- ignoreGit: boolean;
36
- /** 忽略 npm 环境检查以及后续操作 */
37
- ignoreNpm: boolean;
38
- /** 忽略 github 环境检查以及后续操作 */
39
- ignoreGithub: boolean;
40
+ /** 跳过 git、github 环境检查以及后续操作 */
41
+ skipGit: boolean;
42
+ /** 跳过 npm 环境检查以及后续操作 */
43
+ skipNpm: boolean;
44
+ /** 跳过 github 环境检查以及后续操作 */
45
+ skipGithub: boolean;
40
46
  /**
41
47
  * Git 相关配置
42
48
  * 影响提交、打 tag、推送等本地/远程 Git 行为。
@@ -90,7 +96,7 @@ interface ReleaseConfig {
90
96
  /**
91
97
  * 是否要求工作目录保持干净(无未提交的更改)
92
98
  */
93
- requireWorkDirClean: boolean;
99
+ requireCleanWorkingTree: boolean;
94
100
  };
95
101
  /**
96
102
  * NPM 发布相关配置
package/dist/index.mjs CHANGED
@@ -132,8 +132,7 @@ const parsePreset = async () => {
132
132
  hidden: false
133
133
  })) });
134
134
  preset.writer ??= {};
135
- preset.writer.headerPartial = `
136
- ## {{#if isPatch~}} <small> {{~/if~}}
135
+ preset.writer.headerPartial = `## {{#if isPatch~}} <small> {{~/if~}}
137
136
  {{#if @root.linkCompare~}}
138
137
  [{{version}}](
139
138
  {{~#if @root.repository~}}
@@ -157,8 +156,7 @@ const parsePreset = async () => {
157
156
  {{~/if}}
158
157
  {{~#if isPatch~}} </small> {{~/if}}
159
158
  `.trim() + eol();
160
- preset.writer.mainTemplate = `
161
- {{> header}}
159
+ preset.writer.mainTemplate = `{{> header}}
162
160
  {{#if noteGroups}}
163
161
  {{#each noteGroups}}
164
162
 
@@ -194,7 +192,7 @@ const getChangelog = async ({ getPkgDir, tagPrefix, releaseCount = 1 }) => {
194
192
  });
195
193
  let changelog = "";
196
194
  for await (const chunk of generator.write()) changelog += chunk;
197
- return changelog;
195
+ return changelog.trimEnd();
198
196
  };
199
197
  const generateChangelog = async ({ getPkgDir, tagPrefix, releaseCount = 1 }) => {
200
198
  const infile = join(getPkgDir(), "CHANGELOG.md");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peiyanlu/release",
3
- "version": "0.0.15",
3
+ "version": "1.0.0",
4
4
  "description": "Release project tool.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -30,16 +30,17 @@
30
30
  "@actions/github": "^9.1.1",
31
31
  "@clack/prompts": "^1.5.0",
32
32
  "@octokit/rest": "^22.0.1",
33
- "@peiyanlu/cli-utils": "^0.0.9",
34
- "@peiyanlu/ts-utils": "^0.0.7",
33
+ "@peiyanlu/cli-utils": "^0.0.12",
34
+ "@peiyanlu/ts-utils": "^0.0.8",
35
35
  "ansis": "^4.3.1",
36
36
  "commander": "^15.0.0",
37
- "conventional-changelog": "^7.2.0",
37
+ "conventional-changelog": "^7.2.1",
38
38
  "conventional-changelog-conventionalcommits": "^9.3.1",
39
+ "conventional-changelog-writer": "^8.3.0",
39
40
  "mime-types": "^3.0.2",
40
41
  "open": "^11.0.0",
41
42
  "publint": "^0.3.21",
42
- "semver": "^7.8.1",
43
+ "semver": "^7.8.5",
43
44
  "tinyglobby": "^0.2.17"
44
45
  },
45
46
  "devDependencies": {
@@ -47,9 +48,9 @@
47
48
  "@types/node": "^24.12.4",
48
49
  "@types/semver": "^7.7.1",
49
50
  "@vitest/coverage-v8": "^4.1.8",
50
- "tsdown": "^0.22.1",
51
+ "tsdown": "^0.22.3",
51
52
  "typescript": "^6.0.3",
52
- "vitest": "^4.1.8"
53
+ "vitest": "^4.1.9"
53
54
  },
54
55
  "author": {
55
56
  "name": "YanluPei",