@peiyanlu/release 0.0.4 → 0.0.5
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 +10 -10
- package/dist/cli.mjs +59 -314
- package/dist/index.d.mts +1 -1
- package/package.json +8 -5
package/README.md
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
# Release Project
|
|
2
2
|
|
|
3
3
|
<p>
|
|
4
|
-
<a href="https://www.npmjs.com/package/@peiyanlu/
|
|
5
|
-
<img src="https://img.shields.io/badge/npm-@peiyanlu/
|
|
4
|
+
<a href="https://www.npmjs.com/package/@peiyanlu/release" target="_blank">
|
|
5
|
+
<img src="https://img.shields.io/badge/npm-@peiyanlu/release-blue.svg?logo=npm" alt="NPM Package" />
|
|
6
6
|
</a>
|
|
7
|
-
<a href="https://www.npmjs.com/package/@peiyanlu/
|
|
8
|
-
<img src="https://img.shields.io/npm/v/@peiyanlu/
|
|
7
|
+
<a href="https://www.npmjs.com/package/@peiyanlu/release" target="_blank">
|
|
8
|
+
<img src="https://img.shields.io/npm/v/@peiyanlu/release.svg" alt="NPM Version" />
|
|
9
9
|
</a>
|
|
10
|
-
<a href="https://www.npmjs.com/package/@peiyanlu/
|
|
11
|
-
<img src="https://img.shields.io/npm/l/@peiyanlu/
|
|
10
|
+
<a href="https://www.npmjs.com/package/@peiyanlu/release" target="_blank">
|
|
11
|
+
<img src="https://img.shields.io/npm/l/@peiyanlu/release.svg" alt="Package License" />
|
|
12
12
|
</a>
|
|
13
|
-
<a href="https://www.npmjs.com/package/@peiyanlu/
|
|
14
|
-
<img src="https://img.shields.io/npm/dm/@peiyanlu/
|
|
13
|
+
<a href="https://www.npmjs.com/package/@peiyanlu/release" target="_blank">
|
|
14
|
+
<img src="https://img.shields.io/npm/dm/@peiyanlu/release.svg" alt="NPM Downloads" />
|
|
15
15
|
</a>
|
|
16
16
|
</p>
|
|
17
17
|
|
|
@@ -110,7 +110,7 @@ export default defineConfig({
|
|
|
110
110
|
packages: [],
|
|
111
111
|
getPkgDir: (pkg) => `.`,
|
|
112
112
|
toTag: (pkg: string, version: string) => `v${ version }`,
|
|
113
|
-
|
|
113
|
+
tagPrefix: undefined,
|
|
114
114
|
|
|
115
115
|
git: {
|
|
116
116
|
commit: true,
|
|
@@ -145,7 +145,7 @@ export default defineConfig({
|
|
|
145
145
|
packages: [ 'demo-a', 'demo-b' ],
|
|
146
146
|
getPkgDir: (pkg) => `packages/${ pkg }`,
|
|
147
147
|
toTag: (pkg: string, version: string) => `${ pkg }@${ version }`,
|
|
148
|
-
|
|
148
|
+
tagPrefix: (pkg: string) => `${ pkg }@`,
|
|
149
149
|
|
|
150
150
|
git: {
|
|
151
151
|
commit: true,
|
package/dist/cli.mjs
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import path, { join, resolve } from "node:path";
|
|
2
2
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
3
|
-
import { eol, execAsync, isGitRepo, parseGitHubRepo, readJsonFile,
|
|
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, runGit } 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 {
|
|
10
|
+
import { coerce, eq, inc, lt, parse, prerelease, valid } from "semver";
|
|
11
11
|
import { castArray, isPlainObject, isUndefined } from "@peiyanlu/ts-utils";
|
|
12
12
|
import { spawnSync } from "node:child_process";
|
|
13
|
-
import { inspect } from "node:util";
|
|
14
13
|
import { Octokit } from "@octokit/rest";
|
|
15
14
|
import { contentType } from "mime-types";
|
|
16
15
|
import open from "open";
|
|
17
16
|
import { glob } from "tinyglobby";
|
|
17
|
+
import { inspect } from "node:util";
|
|
18
18
|
import { ConventionalChangelog } from "conventional-changelog";
|
|
19
19
|
import createPreset from "conventional-changelog-conventionalcommits";
|
|
20
20
|
import { writeFile } from "node:fs/promises";
|
|
@@ -153,9 +153,6 @@ const MSG = {
|
|
|
153
153
|
|
|
154
154
|
//#endregion
|
|
155
155
|
//#region src/github/release.ts
|
|
156
|
-
const getGithubUrl = (owner, repo) => {
|
|
157
|
-
return `https://github.com/${owner}/${repo}`;
|
|
158
|
-
};
|
|
159
156
|
const truncateBody = (body) => {
|
|
160
157
|
if (body && body.length >= 124e3) return body.substring(0, 124e3) + "...";
|
|
161
158
|
return body;
|
|
@@ -270,140 +267,9 @@ const createRelease = async (ctx, config) => {
|
|
|
270
267
|
await uploadAssets(ctx, config);
|
|
271
268
|
}
|
|
272
269
|
};
|
|
273
|
-
const getGithubReleaseUrl = (ctx) => {
|
|
274
|
-
const { github: { owner, repo }, git: { currentTag } } = ctx;
|
|
275
|
-
return `${getGithubUrl(owner, repo)}/releases/tag/${normalizeTag(currentTag)}`;
|
|
276
|
-
};
|
|
277
270
|
|
|
278
271
|
//#endregion
|
|
279
272
|
//#region src/git/commit.ts
|
|
280
|
-
const getBranchName = async () => {
|
|
281
|
-
let branch = await runGit(["branch", "--show-current"]);
|
|
282
|
-
if (!branch) {
|
|
283
|
-
branch = await runGit([
|
|
284
|
-
"rev-parse",
|
|
285
|
-
"--abbrev-ref",
|
|
286
|
-
"HEAD"
|
|
287
|
-
]);
|
|
288
|
-
if (branch === "HEAD") return void 0;
|
|
289
|
-
}
|
|
290
|
-
return branch;
|
|
291
|
-
};
|
|
292
|
-
const getRemoteForBranch = (branch) => {
|
|
293
|
-
return runGit([
|
|
294
|
-
"config",
|
|
295
|
-
"--get",
|
|
296
|
-
`branch.${branch}.remote`
|
|
297
|
-
]);
|
|
298
|
-
};
|
|
299
|
-
const getAllRemotes = async () => {
|
|
300
|
-
return (await runGit(["remote"]))?.split("\n").filter(Boolean) ?? [];
|
|
301
|
-
};
|
|
302
|
-
const getStatus = () => {
|
|
303
|
-
return runGit([
|
|
304
|
-
"status",
|
|
305
|
-
"--short",
|
|
306
|
-
"--untracked-files=no"
|
|
307
|
-
], { trim: false });
|
|
308
|
-
};
|
|
309
|
-
const coloredChangeset = (log$1) => {
|
|
310
|
-
const colorStatusChar = (ch) => {
|
|
311
|
-
switch (ch) {
|
|
312
|
-
case "M": return `\x1b[33m${ch}\x1b[0m`;
|
|
313
|
-
case "A": return `\x1b[32m${ch}\x1b[0m`;
|
|
314
|
-
case "D": return `\x1b[31m${ch}\x1b[0m`;
|
|
315
|
-
default: return ch;
|
|
316
|
-
}
|
|
317
|
-
};
|
|
318
|
-
const colorStatus = (status) => status.split("").map(colorStatusChar).join("");
|
|
319
|
-
return log$1.split("\n").filter(Boolean).map((line) => {
|
|
320
|
-
const status = line.slice(0, 2);
|
|
321
|
-
const file = line.slice(3);
|
|
322
|
-
return `${colorStatus(status)} ${dim(file)}`;
|
|
323
|
-
}).join("\n");
|
|
324
|
-
};
|
|
325
|
-
const getRemote = async () => {
|
|
326
|
-
const branch = await getBranchName();
|
|
327
|
-
const remoteName = branch && await getRemoteForBranch(branch) || "origin";
|
|
328
|
-
return {
|
|
329
|
-
remoteName,
|
|
330
|
-
remoteUrl: await runGit([
|
|
331
|
-
"remote",
|
|
332
|
-
"get-url",
|
|
333
|
-
remoteName
|
|
334
|
-
]).catch((_) => runGit([
|
|
335
|
-
"config",
|
|
336
|
-
"--get",
|
|
337
|
-
`remote.${remoteName}.url`
|
|
338
|
-
]))
|
|
339
|
-
};
|
|
340
|
-
};
|
|
341
|
-
const getLatestTag = async (match = "*", exclude = "*-beta.*") => {
|
|
342
|
-
return runGit([
|
|
343
|
-
"describe",
|
|
344
|
-
"--tags",
|
|
345
|
-
"--abbrev=0",
|
|
346
|
-
`--match=${match}`,
|
|
347
|
-
`--exclude=${exclude}`
|
|
348
|
-
]);
|
|
349
|
-
};
|
|
350
|
-
const getPreviousTag = async (current) => {
|
|
351
|
-
return runGit([
|
|
352
|
-
"describe",
|
|
353
|
-
"--tags",
|
|
354
|
-
"--abbrev=0",
|
|
355
|
-
`${await runGit([
|
|
356
|
-
"rev-list",
|
|
357
|
-
"--tags",
|
|
358
|
-
current || "--skip=1",
|
|
359
|
-
"--max-count=1"
|
|
360
|
-
])}^`
|
|
361
|
-
]);
|
|
362
|
-
};
|
|
363
|
-
const resolveChangelogRange = async (isIncrement = true) => {
|
|
364
|
-
const latestTag = await getLatestTag();
|
|
365
|
-
const previousTag = await getPreviousTag(latestTag);
|
|
366
|
-
if (!latestTag) return {
|
|
367
|
-
from: "",
|
|
368
|
-
to: "HEAD"
|
|
369
|
-
};
|
|
370
|
-
if (!isIncrement && previousTag) return {
|
|
371
|
-
from: previousTag,
|
|
372
|
-
to: `${latestTag}^1`
|
|
373
|
-
};
|
|
374
|
-
return {
|
|
375
|
-
from: latestTag,
|
|
376
|
-
to: "HEAD"
|
|
377
|
-
};
|
|
378
|
-
};
|
|
379
|
-
const getLog = async (from = "", to = "HEAD", scope) => {
|
|
380
|
-
const cmd = ["log", `--pretty=format:* %s (%h)`];
|
|
381
|
-
if (from) cmd.push(`${from}...${to}`);
|
|
382
|
-
if (scope) cmd.push(...["--", scope]);
|
|
383
|
-
return runGit(cmd, { trim: false });
|
|
384
|
-
};
|
|
385
|
-
const isWorkingDirClean = async () => {
|
|
386
|
-
return (await runGit(["status", "-s"]))?.length === 0;
|
|
387
|
-
};
|
|
388
|
-
const hasUpstreamBranch = async () => {
|
|
389
|
-
const branch = await runGit([
|
|
390
|
-
"for-each-ref",
|
|
391
|
-
"--format=%(upstream:short)",
|
|
392
|
-
await runGit(["symbolic-ref", "HEAD"])
|
|
393
|
-
]);
|
|
394
|
-
return Boolean(branch);
|
|
395
|
-
};
|
|
396
|
-
const getUpstreamArgs = async (remoteName) => {
|
|
397
|
-
const hasUpstream = await hasUpstreamBranch();
|
|
398
|
-
const branch = await getBranchName();
|
|
399
|
-
if (!hasUpstream) return [
|
|
400
|
-
"--set-upstream",
|
|
401
|
-
remoteName,
|
|
402
|
-
branch
|
|
403
|
-
];
|
|
404
|
-
return [remoteName, branch];
|
|
405
|
-
};
|
|
406
|
-
const normalizeTag = (tag) => clean(tag) ?? tag;
|
|
407
273
|
const gitCheck = async (ctx, config) => {
|
|
408
274
|
const { pkg: { name } } = ctx;
|
|
409
275
|
const { git: { requireRepository, requireRemote, requireWorkDirClean } } = config;
|
|
@@ -430,53 +296,23 @@ const commitAndTag = async (ctx, config) => {
|
|
|
430
296
|
const { git: { commit, tag, push, addUntrackedFiles, commitArgs, tagArgs, pushArgs } } = config;
|
|
431
297
|
if (!commit) return;
|
|
432
298
|
const args = dryRun ? ["--dry-run"] : [];
|
|
433
|
-
await
|
|
434
|
-
|
|
435
|
-
".",
|
|
436
|
-
addUntrackedFiles ? "--all" : "--update",
|
|
437
|
-
...args
|
|
438
|
-
]);
|
|
439
|
-
await runGit([
|
|
440
|
-
"commit",
|
|
441
|
-
"--message",
|
|
442
|
-
commitMessage,
|
|
443
|
-
...commitArgs,
|
|
444
|
-
...args
|
|
445
|
-
]);
|
|
299
|
+
addUntrackedFiles ? await gitAddAll() : await gitAddTracked(args);
|
|
300
|
+
await gitCommit(commitMessage, [...commitArgs, ...args]);
|
|
446
301
|
if (!dryRun) Object.assign(ctx.git, { isCommitted: true });
|
|
447
302
|
if (tag) {
|
|
448
|
-
await
|
|
449
|
-
"tag",
|
|
450
|
-
"--annotate",
|
|
451
|
-
"--message",
|
|
452
|
-
tagMessage,
|
|
453
|
-
currentTag,
|
|
454
|
-
...tagArgs,
|
|
455
|
-
...args
|
|
456
|
-
]);
|
|
303
|
+
await gitTagAnnotated(currentTag, tagMessage, [...tagArgs, ...args]);
|
|
457
304
|
if (!dryRun) Object.assign(ctx.git, { isTagged: true });
|
|
458
305
|
}
|
|
459
306
|
if (push) {
|
|
460
307
|
const remotes = await getAllRemotes();
|
|
461
308
|
for (const remoteName$1 of remotes) {
|
|
462
|
-
|
|
463
|
-
await
|
|
464
|
-
"push",
|
|
465
|
-
remoteName$1,
|
|
466
|
-
`refs/tags/${currentTag}`,
|
|
467
|
-
...args
|
|
468
|
-
]);
|
|
469
|
-
await runGit([
|
|
470
|
-
"push",
|
|
471
|
-
...upstreamArgs,
|
|
472
|
-
...pushArgs,
|
|
473
|
-
...args
|
|
474
|
-
]);
|
|
309
|
+
await pushTag(remoteName$1, currentTag, args);
|
|
310
|
+
await pushBranch(remoteName$1, await getCurrentBranch(), [...pushArgs, ...args]);
|
|
475
311
|
}
|
|
476
312
|
if (!dryRun) Object.assign(ctx.git, { isPushed: true });
|
|
477
313
|
}
|
|
478
314
|
};
|
|
479
|
-
const gitRollback
|
|
315
|
+
const gitRollback = (ctx) => {
|
|
480
316
|
const { git: { currentTag, isCommitted, isTagged, isPushed } } = ctx;
|
|
481
317
|
if (isPushed) return;
|
|
482
318
|
spawnSync("git", ["restore", "."]);
|
|
@@ -492,6 +328,30 @@ const gitRollback$1 = (ctx) => {
|
|
|
492
328
|
]);
|
|
493
329
|
};
|
|
494
330
|
|
|
331
|
+
//#endregion
|
|
332
|
+
//#region src/prompts.ts
|
|
333
|
+
const abortTask = (msg$1) => {
|
|
334
|
+
cancel(`${red("✕")} ${msg$1}`);
|
|
335
|
+
process.exit(0);
|
|
336
|
+
};
|
|
337
|
+
const abortSinglePrompt = (value) => {
|
|
338
|
+
if (isCancel(value)) abortTask(MSG.ABORT.CANCEL);
|
|
339
|
+
};
|
|
340
|
+
const abortGroupPrompt = (ctx) => {
|
|
341
|
+
ctx && gitRollback(ctx);
|
|
342
|
+
abortTask(MSG.ABORT.CANCEL);
|
|
343
|
+
};
|
|
344
|
+
const abortOnError = (err, ctx) => {
|
|
345
|
+
ctx && gitRollback(ctx);
|
|
346
|
+
const msg$1 = err.message.replace(/^\[(github|npm|git)]/, (a) => red(a));
|
|
347
|
+
log.message(`\n${msg$1}\n`);
|
|
348
|
+
process.exit(1);
|
|
349
|
+
};
|
|
350
|
+
const taskEnd = (msg$1) => {
|
|
351
|
+
outro(msg$1);
|
|
352
|
+
process.exit(0);
|
|
353
|
+
};
|
|
354
|
+
|
|
495
355
|
//#endregion
|
|
496
356
|
//#region src/utils.ts
|
|
497
357
|
const info = (msg$1) => {
|
|
@@ -524,20 +384,6 @@ const runLifeCycleHook = async (hooks, key, dryRun) => {
|
|
|
524
384
|
log.success(success(hook.replace(/^echo$/, dim("echo")), dryRun));
|
|
525
385
|
}));
|
|
526
386
|
};
|
|
527
|
-
const gitRollback = (ctx) => {
|
|
528
|
-
const { git: { currentTag, isCommitted, isTagged } } = ctx;
|
|
529
|
-
spawnSync("git", ["restore", "."]);
|
|
530
|
-
if (isTagged) spawnSync("git", [
|
|
531
|
-
"tag",
|
|
532
|
-
"--delete",
|
|
533
|
-
currentTag
|
|
534
|
-
]);
|
|
535
|
-
spawnSync("git", [
|
|
536
|
-
"reset",
|
|
537
|
-
"--hard",
|
|
538
|
-
isCommitted ? "HEAD~1" : "HEAD"
|
|
539
|
-
]);
|
|
540
|
-
};
|
|
541
387
|
const diff = (from, to, separator = ".") => {
|
|
542
388
|
const a = from.split(separator);
|
|
543
389
|
return to.split(separator).map((v, i) => v === a[i] ? dim(v) : green(v)).join(separator);
|
|
@@ -559,39 +405,6 @@ const formatTemplate = async (ctx, config) => {
|
|
|
559
405
|
});
|
|
560
406
|
Object.assign(ctx.github, { releaseName });
|
|
561
407
|
};
|
|
562
|
-
const getPackageInfo = (pkgName, getPkgDir = (pkg$1) => `packages/${pkg$1}`) => {
|
|
563
|
-
const pkgDir = resolve(getPkgDir(pkgName));
|
|
564
|
-
const pkgPath = resolve(pkgDir, "package.json");
|
|
565
|
-
return {
|
|
566
|
-
pkg: readJsonFile(pkgPath),
|
|
567
|
-
pkgDir,
|
|
568
|
-
pkgPath
|
|
569
|
-
};
|
|
570
|
-
};
|
|
571
|
-
|
|
572
|
-
//#endregion
|
|
573
|
-
//#region src/prompts.ts
|
|
574
|
-
const abortTask = (msg$1) => {
|
|
575
|
-
cancel(`${red("✕")} ${msg$1}`);
|
|
576
|
-
process.exit(0);
|
|
577
|
-
};
|
|
578
|
-
const abortSinglePrompt = (value) => {
|
|
579
|
-
if (isCancel(value)) abortTask(MSG.ABORT.CANCEL);
|
|
580
|
-
};
|
|
581
|
-
const abortGroupPrompt = (ctx) => {
|
|
582
|
-
ctx && gitRollback(ctx);
|
|
583
|
-
abortTask(MSG.ABORT.CANCEL);
|
|
584
|
-
};
|
|
585
|
-
const abortOnError = (err, ctx) => {
|
|
586
|
-
ctx && gitRollback(ctx);
|
|
587
|
-
const msg$1 = err.message.replace(/^\[(github|npm|git)]/, (a) => red(a));
|
|
588
|
-
log.message(`\n${msg$1}\n`);
|
|
589
|
-
process.exit(1);
|
|
590
|
-
};
|
|
591
|
-
const taskEnd = (msg$1) => {
|
|
592
|
-
outro(msg$1);
|
|
593
|
-
process.exit(0);
|
|
594
|
-
};
|
|
595
408
|
|
|
596
409
|
//#endregion
|
|
597
410
|
//#region src/version/bump.ts
|
|
@@ -814,7 +627,7 @@ const createDefaultConfig = (isCI) => {
|
|
|
814
627
|
toTag(pkg$1, version) {
|
|
815
628
|
return `v${version}`;
|
|
816
629
|
},
|
|
817
|
-
|
|
630
|
+
tagPrefix: void 0,
|
|
818
631
|
git: {
|
|
819
632
|
commit: isCI,
|
|
820
633
|
tag: isCI,
|
|
@@ -1107,30 +920,6 @@ const runNpmOptPrompts = async (ctx, config) => {
|
|
|
1107
920
|
|
|
1108
921
|
//#endregion
|
|
1109
922
|
//#region src/npm/publish.ts
|
|
1110
|
-
const resolvePublishRegistry = (publishConfig = {}) => {
|
|
1111
|
-
if (publishConfig.registry) return publishConfig.registry;
|
|
1112
|
-
return Object.keys(publishConfig).filter((k) => k.endsWith("registry")).map((k) => publishConfig[k])[0];
|
|
1113
|
-
};
|
|
1114
|
-
const pingRegistry = async () => {
|
|
1115
|
-
return void 0 !== await runNpm(["ping"]);
|
|
1116
|
-
};
|
|
1117
|
-
const getAuthenticatedUser = () => {
|
|
1118
|
-
return runNpm(["whoami"]);
|
|
1119
|
-
};
|
|
1120
|
-
const getVersionByTag = (name, tag) => {
|
|
1121
|
-
return runNpm([
|
|
1122
|
-
"show",
|
|
1123
|
-
`${name}@${tag}`,
|
|
1124
|
-
"version"
|
|
1125
|
-
]);
|
|
1126
|
-
};
|
|
1127
|
-
const getPublishedVersion = (name) => {
|
|
1128
|
-
return runNpm([
|
|
1129
|
-
"info",
|
|
1130
|
-
name,
|
|
1131
|
-
"version"
|
|
1132
|
-
]);
|
|
1133
|
-
};
|
|
1134
923
|
const resolvePublishTag = async (pkgName, version) => {
|
|
1135
924
|
const { toPreRelease, preId } = parseVersion(version);
|
|
1136
925
|
if (!toPreRelease) {
|
|
@@ -1138,69 +927,20 @@ const resolvePublishTag = async (pkgName, version) => {
|
|
|
1138
927
|
return active && lt(version, active) ? "previous" : "latest";
|
|
1139
928
|
} else return preId || "prerelease";
|
|
1140
929
|
};
|
|
1141
|
-
const bumpPackageVersion = (version, args = [], cwd = ".") => {
|
|
1142
|
-
return runNpm([
|
|
1143
|
-
"version",
|
|
1144
|
-
version,
|
|
1145
|
-
"--no-git-tag-version",
|
|
1146
|
-
"--workspaces=false",
|
|
1147
|
-
"--allow-same-version",
|
|
1148
|
-
...args
|
|
1149
|
-
], { cwd });
|
|
1150
|
-
};
|
|
1151
930
|
const isOtpError = (err) => err instanceof Error && /one-time password|otp/i.test(err.message);
|
|
1152
|
-
const publishPackage = (pkg$1 = ".", tag = "latest", args = []) => {
|
|
1153
|
-
return runNpm([
|
|
1154
|
-
"publish",
|
|
1155
|
-
"--access",
|
|
1156
|
-
"public",
|
|
1157
|
-
"--tag",
|
|
1158
|
-
tag,
|
|
1159
|
-
"--workspaces=false",
|
|
1160
|
-
...args
|
|
1161
|
-
], { cwd: pkg$1 });
|
|
1162
|
-
};
|
|
1163
|
-
const getPackageUrl = (name, next) => {
|
|
1164
|
-
return `https://www.npmjs.com/package/${name}/v/${next}`;
|
|
1165
|
-
};
|
|
1166
|
-
const isCollaborator = async (ctx) => {
|
|
1167
|
-
const { pkg: { name, publishConfig }, npm: { username } } = ctx;
|
|
1168
|
-
const registry = resolvePublishRegistry(publishConfig);
|
|
1169
|
-
const registryArg = registry ? ["--registry", registry] : [];
|
|
1170
|
-
let npmVersion = await runNpm(["--version"]);
|
|
1171
|
-
let accessCommand;
|
|
1172
|
-
if (gt(npmVersion, "9.0.0")) accessCommand = [
|
|
1173
|
-
"access",
|
|
1174
|
-
"list",
|
|
1175
|
-
"collaborators",
|
|
1176
|
-
"--json"
|
|
1177
|
-
];
|
|
1178
|
-
else accessCommand = ["access", "ls-collaborators"];
|
|
1179
|
-
const res = await runNpm([
|
|
1180
|
-
...accessCommand,
|
|
1181
|
-
name,
|
|
1182
|
-
...registryArg
|
|
1183
|
-
]);
|
|
1184
|
-
if (res) return JSON.parse(res ?? "{}")[username]?.includes("write");
|
|
1185
|
-
return false;
|
|
1186
|
-
};
|
|
1187
931
|
const npmCheck = async (ctx, config) => {
|
|
1188
|
-
const { pkg: { name, current, publishConfig: { registry } }
|
|
932
|
+
const { pkg: { name, current, publishConfig: { registry } } } = ctx;
|
|
1189
933
|
const { npm: { skipChecks } } = config;
|
|
1190
934
|
const tag = await resolvePublishTag(name, current);
|
|
1191
935
|
Object.assign(ctx.npm, { tag });
|
|
1192
936
|
if (skipChecks) return "";
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
return true;
|
|
1199
|
-
};
|
|
1200
|
-
if (!await getUser()) throw new Error(MSG.ERROR.NPM_AUTH);
|
|
1201
|
-
const latest = await getVersionByTag(name, tag);
|
|
937
|
+
const [pinged, username] = await Promise.all([pingRegistry(registry), getAuthenticatedUser(registry)]);
|
|
938
|
+
if (!pinged) throw new Error(MSG.ERROR.NPM_REGISTRY(registry));
|
|
939
|
+
if (!username) throw new Error(MSG.ERROR.NPM_AUTH);
|
|
940
|
+
Object.assign(ctx.npm, { username });
|
|
941
|
+
const latest = await getPublishedVersion(`${name}@${tag}`);
|
|
1202
942
|
if (latest) {
|
|
1203
|
-
if (!await
|
|
943
|
+
if (!await hasWriteAccess(name, username, registry)) throw new Error(MSG.ERROR.NPM_USER(username, name));
|
|
1204
944
|
}
|
|
1205
945
|
return latest ? `(${tag} → ${latest})` : `(${tag} → no published version)`;
|
|
1206
946
|
};
|
|
@@ -1210,11 +950,15 @@ const publishNpm = async (ctx, config) => {
|
|
|
1210
950
|
if (!publish) return;
|
|
1211
951
|
const otpArgs = otp ? ["--otp", otp] : [];
|
|
1212
952
|
const dryRunArg = dryRun ? ["--dry-run"] : [];
|
|
1213
|
-
return publishPackage(
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
953
|
+
return publishPackage({
|
|
954
|
+
tag,
|
|
955
|
+
args: [
|
|
956
|
+
...otpArgs,
|
|
957
|
+
...pushArgs,
|
|
958
|
+
...dryRunArg
|
|
959
|
+
],
|
|
960
|
+
cwd: getPkgDir(selectedPkg)
|
|
961
|
+
});
|
|
1218
962
|
};
|
|
1219
963
|
|
|
1220
964
|
//#endregion
|
|
@@ -1290,7 +1034,7 @@ var Action = class {
|
|
|
1290
1034
|
await this.gitTask(ctx, config);
|
|
1291
1035
|
await this.npmTask(ctx, config);
|
|
1292
1036
|
await this.githubTask(ctx, config);
|
|
1293
|
-
if (dryRun) gitRollback
|
|
1037
|
+
if (dryRun) gitRollback(ctx);
|
|
1294
1038
|
taskEnd(MSG.OUTRO(dryRun));
|
|
1295
1039
|
}
|
|
1296
1040
|
async checkTask(ctx, config) {
|
|
@@ -1314,7 +1058,7 @@ var Action = class {
|
|
|
1314
1058
|
}
|
|
1315
1059
|
async bumpTask(ctx, config) {
|
|
1316
1060
|
const { pkg: { current }, dryRun, isCI, showRelease, showChangelog, selectedPkg } = ctx;
|
|
1317
|
-
const { hooks, getPkgDir } = config;
|
|
1061
|
+
const { isMonorepo, hooks, getPkgDir, tagPrefix } = config;
|
|
1318
1062
|
const need = (ctx$1) => {
|
|
1319
1063
|
const { pkg: { next: next$1 }, isIncrement: isIncrement$1 } = ctx$1;
|
|
1320
1064
|
return !next$1 && isIncrement$1;
|
|
@@ -1336,22 +1080,22 @@ var Action = class {
|
|
|
1336
1080
|
}
|
|
1337
1081
|
}]).catch((err) => abortOnError(err, ctx));
|
|
1338
1082
|
await runLifeCycleHook(hooks, "after:bump", dryRun);
|
|
1339
|
-
const { from, to } = await resolveChangelogRange(isIncrement);
|
|
1083
|
+
const { from, to } = await resolveChangelogRange(isIncrement, isMonorepo ? `${tagPrefix?.(selectedPkg)}*` : "*");
|
|
1340
1084
|
const logStr = await getLog(from, to, getPkgDir(selectedPkg));
|
|
1341
1085
|
if (logStr) {
|
|
1342
|
-
msg("GIT", `Changelog:${eol(2)}` + logStr);
|
|
1086
|
+
msg("GIT", `Changelog(${from}...${to}):${eol(2)}` + logStr);
|
|
1343
1087
|
if (showChangelog) taskEnd(MSG.LOG.SHOW_CHANGELOG);
|
|
1344
1088
|
} else msg("GIT", MSG.LOG.CHANGELOG_EMPTY);
|
|
1345
1089
|
}
|
|
1346
1090
|
async changelogTask(ctx, config) {
|
|
1347
1091
|
const { isIncrement, dryRun, selectedPkg } = ctx;
|
|
1348
|
-
const { getPkgDir,
|
|
1092
|
+
const { getPkgDir, tagPrefix } = config;
|
|
1349
1093
|
await tasks([{
|
|
1350
1094
|
title: MSG.TASK.CHANGELOG.START,
|
|
1351
1095
|
task: async () => {
|
|
1352
1096
|
const changelog = await generateChangelog({
|
|
1353
1097
|
getPkgDir: () => getPkgDir(selectedPkg),
|
|
1354
|
-
tagPrefix:
|
|
1098
|
+
tagPrefix: tagPrefix?.(selectedPkg)
|
|
1355
1099
|
});
|
|
1356
1100
|
await runGit(["add", `${getPkgDir(selectedPkg)}/CHANGELOG.md`]);
|
|
1357
1101
|
Object.assign(ctx.github, { changelog });
|
|
@@ -1408,8 +1152,9 @@ var Action = class {
|
|
|
1408
1152
|
await tasks([{
|
|
1409
1153
|
title: MSG.TASK.GITHUB.START,
|
|
1410
1154
|
task: async () => {
|
|
1155
|
+
const { github: { owner, repo }, git: { currentTag } } = ctx;
|
|
1411
1156
|
await createRelease(ctx, config);
|
|
1412
|
-
const url = getGithubReleaseUrl(
|
|
1157
|
+
const url = getGithubReleaseUrl(owner, repo, currentTag);
|
|
1413
1158
|
return success(MSG.TASK.GITHUB.END(url), dryRun);
|
|
1414
1159
|
}
|
|
1415
1160
|
}]).catch((err) => abortOnError(err, ctx));
|
|
@@ -1439,7 +1184,7 @@ program.command("init").description("Create a release configuration file").optio
|
|
|
1439
1184
|
packages: [ 'demo-a', 'demo-b' ],
|
|
1440
1185
|
getPkgDir: (pkg) => \`packages/\${ pkg }\`,
|
|
1441
1186
|
toTag: (pkg, version) => \`\${ pkg }@\${ version }\`,
|
|
1442
|
-
|
|
1187
|
+
tagPrefix: (pkg) => \`\${ pkg }@\`,
|
|
1443
1188
|
}`;
|
|
1444
1189
|
writeFileSync(configPath, `import { defineConfig } from '@peiyanlu/release'
|
|
1445
1190
|
|
package/dist/index.d.mts
CHANGED
|
@@ -24,7 +24,7 @@ interface ReleaseConfig {
|
|
|
24
24
|
/** 使用 monorepo 时使用 toTag,例如 `${pkg}@${version}`,默认为 `v${version}` 作为单仓库 */
|
|
25
25
|
toTag: (pkg: string, version: string) => string;
|
|
26
26
|
/** 作为 CHANGELOG 标题的 Tag 前缀,多包场景下需要 `${pkg}@` */
|
|
27
|
-
|
|
27
|
+
tagPrefix: ((pkg: string) => string | undefined) | undefined;
|
|
28
28
|
/**
|
|
29
29
|
* Git 相关配置
|
|
30
30
|
* 影响提交、打 tag、推送等本地/远程 Git 行为。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peiyanlu/release",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Release project tool.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -14,19 +14,21 @@
|
|
|
14
14
|
"types": "./dist/index.d.mts",
|
|
15
15
|
"default": "./dist/index.mjs"
|
|
16
16
|
}
|
|
17
|
-
}
|
|
17
|
+
},
|
|
18
|
+
"./package.json": "./package.json"
|
|
18
19
|
},
|
|
19
20
|
"scripts": {
|
|
20
21
|
"dev": "tsdown -w",
|
|
21
22
|
"build": "tsdown",
|
|
22
23
|
"prepublish": "tsdown",
|
|
24
|
+
"release": "tsdown && node index.js",
|
|
23
25
|
"test": "vitest run",
|
|
24
|
-
"
|
|
26
|
+
"test:cov": "vitest run --coverage"
|
|
25
27
|
},
|
|
26
28
|
"dependencies": {
|
|
27
29
|
"@clack/prompts": "^0.11.0",
|
|
28
30
|
"@octokit/rest": "^22.0.1",
|
|
29
|
-
"@peiyanlu/cli-utils": "^0.0.
|
|
31
|
+
"@peiyanlu/cli-utils": "^0.0.6",
|
|
30
32
|
"@peiyanlu/ts-utils": "^0.0.4",
|
|
31
33
|
"ansis": "^4.2.0",
|
|
32
34
|
"commander": "^14.0.2",
|
|
@@ -42,9 +44,10 @@
|
|
|
42
44
|
"@types/mime-types": "^3.0.1",
|
|
43
45
|
"@types/node": "^24.10.3",
|
|
44
46
|
"@types/semver": "^7.7.1",
|
|
47
|
+
"@vitest/coverage-v8": "^4.0.15",
|
|
45
48
|
"tsdown": "^0.18.4",
|
|
46
49
|
"typescript": "^5.9.3",
|
|
47
|
-
"vitest": "^4.0.
|
|
50
|
+
"vitest": "^4.0.18"
|
|
48
51
|
},
|
|
49
52
|
"author": {
|
|
50
53
|
"name": "YanluPei",
|