@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 +78 -90
- package/dist/index.d.mts +14 -8
- package/dist/index.mjs +3 -5
- package/package.json +8 -7
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,
|
|
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.
|
|
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
|
-
|
|
47
|
+
configFile: "",
|
|
49
48
|
config: {}
|
|
50
49
|
};
|
|
51
50
|
return {
|
|
52
|
-
|
|
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
|
|
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,
|
|
160
|
-
if (
|
|
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 (
|
|
172
|
-
if (
|
|
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
|
|
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
|
|
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
|
|
204
|
+
const remotes = await getRemoteNames();
|
|
206
205
|
for (const remoteName of remotes) {
|
|
207
|
-
await
|
|
208
|
-
await
|
|
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
|
-
|
|
217
|
-
|
|
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 (!
|
|
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
|
-
|
|
454
|
-
|
|
455
|
-
|
|
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
|
-
|
|
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 } =
|
|
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 {
|
|
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(
|
|
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,
|
|
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 ||
|
|
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
|
|
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
|
|
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
|
|
1176
|
-
if (changeset) msg("GIT", `Changes:${eol(2)}` +
|
|
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
|
|
1252
|
-
if (existsSync(
|
|
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
|
-
|
|
1266
|
-
|
|
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
|
-
/**
|
|
31
|
+
/**
|
|
32
|
+
* 作为 CHANGELOG 标题的 Tag 前缀,多包场景下需要 `${pkg}@`
|
|
33
|
+
*/
|
|
34
|
+
tagPrefix: ((pkg: string) => string);
|
|
35
|
+
/**
|
|
36
|
+
* 生成多少个版本的变更日志,详见 {@link Options}
|
|
37
|
+
*/
|
|
32
38
|
releaseCount: number;
|
|
33
39
|
};
|
|
34
|
-
/**
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
34
|
-
"@peiyanlu/ts-utils": "^0.0.
|
|
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.
|
|
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.
|
|
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.
|
|
51
|
+
"tsdown": "^0.22.3",
|
|
51
52
|
"typescript": "^6.0.3",
|
|
52
|
-
"vitest": "^4.1.
|
|
53
|
+
"vitest": "^4.1.9"
|
|
53
54
|
},
|
|
54
55
|
"author": {
|
|
55
56
|
"name": "YanluPei",
|