@peiyanlu/release 0.0.1 → 0.0.3
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 +94 -37
- package/dist/cli.mjs +697 -699
- package/dist/index.cjs +3 -4
- package/dist/index.d.cts +122 -7
- package/dist/index.d.mts +122 -7
- package/dist/index.mjs +3 -3
- package/package.json +5 -9
package/dist/cli.mjs
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { blue, dim, gray, green, red, rgb, yellow } from "ansis";
|
|
3
|
-
import { program } from "commander";
|
|
4
|
-
import path, { dirname, join, resolve } from "node:path";
|
|
1
|
+
import path, { join, resolve } from "node:path";
|
|
5
2
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
3
|
+
import { eol, execAsync, isGitRepo, parseGitHubRepo, readJsonFile, runGit, runNpm } from "@peiyanlu/cli-utils";
|
|
4
|
+
import { dim, gray, green, red, rgb, underline, yellow } from "ansis";
|
|
5
|
+
import { program } from "commander";
|
|
6
6
|
import { cancel, confirm, group, intro, isCancel, log, outro, select, tasks, text } from "@clack/prompts";
|
|
7
|
-
import { inspect, styleText } from "node:util";
|
|
8
7
|
import { clean, coerce, gt, gte, inc, parse, prerelease, valid } from "semver";
|
|
8
|
+
import { castArray, isPlainObject, isUndefined } from "@peiyanlu/ts-utils";
|
|
9
9
|
import { createReadStream, existsSync, statSync } from "node:fs";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
10
|
+
import { spawnSync } from "node:child_process";
|
|
11
|
+
import { inspect, styleText } from "node:util";
|
|
12
12
|
import { Octokit } from "@octokit/rest";
|
|
13
13
|
import { contentType } from "mime-types";
|
|
14
14
|
import open from "open";
|
|
15
15
|
import { glob } from "tinyglobby";
|
|
16
|
-
import {
|
|
16
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
17
17
|
|
|
18
|
-
//#region node_modules/.pnpm/tsdown@0.18.
|
|
18
|
+
//#region node_modules/.pnpm/tsdown@0.18.4_typescript@5.9.3/node_modules/tsdown/esm-shims.js
|
|
19
19
|
const getFilename = () => fileURLToPath(import.meta.url);
|
|
20
20
|
const getDirname = () => path.dirname(getFilename());
|
|
21
|
-
const __dirname
|
|
21
|
+
const __dirname = /* @__PURE__ */ getDirname();
|
|
22
22
|
|
|
23
23
|
//#endregion
|
|
24
24
|
//#region src/config.ts
|
|
@@ -47,9 +47,7 @@ const resolveConfig = async (cwd, log$1) => {
|
|
|
47
47
|
log$1?.(configFile);
|
|
48
48
|
return loadConfig(configFile);
|
|
49
49
|
};
|
|
50
|
-
const
|
|
51
|
-
const isPlainObject = (v) => toString(v) === "[object Object]";
|
|
52
|
-
const isFunction = (v) => toString(v) === "[object Function]";
|
|
50
|
+
const isFunction = (v) => typeof v === "function";
|
|
53
51
|
const mergeConfig = (defaults, overrides) => {
|
|
54
52
|
if (!overrides) return structuredClone(defaults);
|
|
55
53
|
if (Object.keys(defaults).length === 0) return structuredClone(overrides);
|
|
@@ -66,57 +64,13 @@ const mergeConfig = (defaults, overrides) => {
|
|
|
66
64
|
return result;
|
|
67
65
|
};
|
|
68
66
|
|
|
69
|
-
//#endregion
|
|
70
|
-
//#region src/utils.ts
|
|
71
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
72
|
-
const __dirname = dirname(__filename);
|
|
73
|
-
function joinUrl(input) {
|
|
74
|
-
const temps = Array.isArray(input) ? input : [...arguments];
|
|
75
|
-
if (temps.length === 0) return "";
|
|
76
|
-
const result = [];
|
|
77
|
-
const parts = [...temps];
|
|
78
|
-
/** 协议正则 */
|
|
79
|
-
const PROTOCOL_RE = /^[^/:]+:\/*$/;
|
|
80
|
-
const FILE_PROTOCOL_RE = /^file:\/\/\//;
|
|
81
|
-
if (PROTOCOL_RE.test(parts[0]) && parts.length > 1) {
|
|
82
|
-
parts[1] = parts[0] + parts[1];
|
|
83
|
-
parts.shift();
|
|
84
|
-
}
|
|
85
|
-
if (FILE_PROTOCOL_RE.test(parts[0])) parts[0] = parts[0].replace(/^([^/:]+):\/*/, "$1:///");
|
|
86
|
-
else parts[0] = parts[0].replace(/^([^/:]+):\/*/, "$1://");
|
|
87
|
-
parts.forEach((part, index) => {
|
|
88
|
-
if (!part) return;
|
|
89
|
-
let segment = part;
|
|
90
|
-
if (index > 0) segment = segment.replace(/^\/+/, "");
|
|
91
|
-
if (index < parts.length - 1) segment = segment.replace(/\/+$/, "");
|
|
92
|
-
else segment = segment.replace(/\/+$/, "/");
|
|
93
|
-
result.push(segment);
|
|
94
|
-
});
|
|
95
|
-
let url = result.join("/");
|
|
96
|
-
url = url.replace(/\/(\?|&|#[^!])/g, "$1");
|
|
97
|
-
const [base, ...queryParts] = url.split("?");
|
|
98
|
-
url = base + (queryParts.length ? "?" + queryParts.join("&") : "");
|
|
99
|
-
return url;
|
|
100
|
-
}
|
|
101
|
-
const isUndefined = (val) => {
|
|
102
|
-
return void 0 === val;
|
|
103
|
-
};
|
|
104
|
-
const eol = (n$1 = 1) => EOL.repeat(n$1);
|
|
105
|
-
const underline = (text$1) => {
|
|
106
|
-
return styleText(["dim", "underline"], text$1);
|
|
107
|
-
};
|
|
108
|
-
const castArray = (arr) => {
|
|
109
|
-
return Array.isArray(arr) ? arr : [arr];
|
|
110
|
-
};
|
|
111
|
-
|
|
112
67
|
//#endregion
|
|
113
68
|
//#region src/messages.ts
|
|
114
|
-
const n = (b) =>
|
|
115
|
-
|
|
116
|
-
};
|
|
69
|
+
const n = (b) => b ? "(dry run)" : "";
|
|
70
|
+
const t = () => green(`${Math.floor(process.uptime())}s`);
|
|
117
71
|
const MSG = {
|
|
118
|
-
INTRO: (pkgName, dryRun) => `🚀 Starting release ${yellow(pkgName)}${n(dryRun)}`,
|
|
119
|
-
OUTRO: (dryRun) => `🎉 Release finished successfully${n(dryRun)}
|
|
72
|
+
INTRO: (pkgName, dryRun) => `🚀 Starting release ${yellow(pkgName)} ${n(dryRun)}`,
|
|
73
|
+
OUTRO: (dryRun) => `🎉 Release finished successfully in ${t()} ${n(dryRun)}.`,
|
|
120
74
|
LOG: {
|
|
121
75
|
SHOW_VERSION: (version) => `🎉 Released ${green(version)}`,
|
|
122
76
|
SHOW_CHANGELOG: "🎉 Changelog collected",
|
|
@@ -126,21 +80,25 @@ const MSG = {
|
|
|
126
80
|
CHECK: {
|
|
127
81
|
GIT: {
|
|
128
82
|
CHECKING: "Checking Git repository",
|
|
129
|
-
CHECKED: (name, url) => `Git remote resolved: ${dim(name)} → ${underline(url)}`
|
|
83
|
+
CHECKED: (name, url) => `Git remote resolved: ${dim(name)} → ${underline(dim(url))}`
|
|
130
84
|
},
|
|
131
85
|
NPM: {
|
|
132
86
|
CHECKING: "Checking npm registry",
|
|
133
|
-
CHECKED: (registry, msg$1) => `NPM registry: ${underline(registry)}${msg$1 ? ` ${msg$1}` : ""}`
|
|
87
|
+
CHECKED: (registry, msg$1) => `NPM registry: ${underline(dim(registry))}${msg$1 ? ` ${msg$1}` : ""}`
|
|
134
88
|
}
|
|
135
89
|
},
|
|
136
90
|
TASK: {
|
|
137
91
|
VERSION: {
|
|
138
92
|
START: "Bumping version",
|
|
139
|
-
END: (
|
|
93
|
+
END: (to) => `Version bumped: ${underline(dim(to))}`
|
|
94
|
+
},
|
|
95
|
+
CHANGELOG: {
|
|
96
|
+
START: "Generating changelog",
|
|
97
|
+
END: `Changelog generated`
|
|
140
98
|
},
|
|
141
99
|
NPM: {
|
|
142
100
|
START: "Publishing npm package",
|
|
143
|
-
END:
|
|
101
|
+
END: (url) => `NPM package published: ${underline(dim(url))}`
|
|
144
102
|
},
|
|
145
103
|
GIT: {
|
|
146
104
|
START: "Creating git commit, tag & push",
|
|
@@ -148,333 +106,159 @@ const MSG = {
|
|
|
148
106
|
},
|
|
149
107
|
GITHUB: {
|
|
150
108
|
START: "Creating GitHub release",
|
|
151
|
-
END:
|
|
109
|
+
END: (url) => `GitHub release created: ${underline(dim(url))}`
|
|
152
110
|
}
|
|
153
111
|
},
|
|
154
112
|
PROMPT: {
|
|
155
113
|
SELECT_VERSION: "Select version bump:",
|
|
156
114
|
INPUT_VERSION: "Enter custom version:",
|
|
157
|
-
NPM_PUBLISH: (pkg$1) => `Publish to npm ${underline(`(${pkg$1})`)}?`,
|
|
115
|
+
NPM_PUBLISH: (pkg$1) => `Publish to npm ${underline(dim`(${pkg$1})`)}?`,
|
|
158
116
|
NPM_OTP: "Enter npm one-time password (OTP):",
|
|
159
|
-
GITHUB_RELEASE: (title) => `Create a new GitHub release ${underline(`(${title})`)}?`,
|
|
160
|
-
GIT_COMMIT: (msg$1) => `Create git commit ${underline(`(${msg$1})`)}?`,
|
|
161
|
-
GIT_TAG: (msg$1) => `Create git tag ${underline(`(${msg$1})`)}?`,
|
|
117
|
+
GITHUB_RELEASE: (title) => `Create a new GitHub release ${underline(dim`(${title})`)}?`,
|
|
118
|
+
GIT_COMMIT: (msg$1) => `Create git commit ${underline(dim`(${msg$1})`)}?`,
|
|
119
|
+
GIT_TAG: (msg$1) => `Create git tag ${underline(dim`(${msg$1})`)}?`,
|
|
162
120
|
GIT_PUSH: "Push commits and tags to remote?"
|
|
163
121
|
},
|
|
164
122
|
ERROR: {
|
|
123
|
+
GIT_WORKDIR: `[git] Working dir must be clean`,
|
|
165
124
|
GIT_REGISTRY: (name) => `[git] Repository not found for ${dim(name)}`,
|
|
166
125
|
GIT_REMOTE: (name) => `[git] Remote "${dim(name)}" not found`,
|
|
167
126
|
GITHUB_TAG_EXIT: (tag) => `[github] Release or tag "${tag}" already exists`,
|
|
168
127
|
GITHUB_TOKEN: (tokenRef) => `[github] Missing GitHub token. Please set ${yellow(tokenRef ?? "GITHUB_TOKEN")}`,
|
|
169
128
|
GITHUB_AUTH: "[github] Invalid GitHub token or insufficient permissions",
|
|
170
129
|
GITHUB_USER: "[github] User does not have permission to create releases",
|
|
171
|
-
NPM_REGISTRY: (registry) => `[npm] Unable to reach npm registry ${underline(registry)}`,
|
|
130
|
+
NPM_REGISTRY: (registry) => `[npm] Unable to reach npm registry ${underline(dim(registry))}`,
|
|
172
131
|
NPM_AUTH: `[npm] Not authenticated with npm. Please run ${yellow("npm login")} and try again.`,
|
|
173
132
|
NPM_USER: (user, name) => `[npm] User ${dim(user)} is not a collaborator of ${dim(name)}.`
|
|
174
133
|
}
|
|
175
134
|
};
|
|
176
135
|
|
|
177
136
|
//#endregion
|
|
178
|
-
//#region src/
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
process.exit(0);
|
|
182
|
-
};
|
|
183
|
-
const abortOnCancel = (value) => {
|
|
184
|
-
if (isCancel(value)) abortTask("Operation cancelled.");
|
|
185
|
-
};
|
|
186
|
-
const abortOnError = (err) => {
|
|
187
|
-
const msg$1 = err.message.replace(/^\[(github|npm|git)]/, (a) => red(a));
|
|
188
|
-
log.message(`\n${msg$1}\n`);
|
|
189
|
-
process.exit(1);
|
|
190
|
-
};
|
|
191
|
-
const taskEnd = (msg$1) => {
|
|
192
|
-
outro(msg$1);
|
|
193
|
-
process.exit(0);
|
|
194
|
-
};
|
|
195
|
-
const msg = (prefix, msg$1) => {
|
|
196
|
-
log.message(gray`${rgb(33, 91, 184)(`[${prefix}]`)} ${msg$1}`);
|
|
197
|
-
};
|
|
198
|
-
const prompt = (msg$1) => {
|
|
199
|
-
return `${blue`?`} ${msg$1}`;
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
//#endregion
|
|
203
|
-
//#region src/version/bump.ts
|
|
204
|
-
const isPreRelease = (version) => {
|
|
205
|
-
return Boolean(prerelease(version));
|
|
206
|
-
};
|
|
207
|
-
const isValid = (version) => {
|
|
208
|
-
return Boolean(valid(version));
|
|
137
|
+
//#region src/github/release.ts
|
|
138
|
+
const getGithubUrl = (owner, repo) => {
|
|
139
|
+
return `https://github.com/${owner}/${repo}`;
|
|
209
140
|
};
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
const { prerelease: prerelease$1 } = parse(next);
|
|
214
|
-
const toPreRelease = Boolean(prerelease$1.length);
|
|
215
|
-
const [preId, preBase] = prerelease$1.map(String);
|
|
216
|
-
return {
|
|
217
|
-
next,
|
|
218
|
-
toPreRelease,
|
|
219
|
-
preId,
|
|
220
|
-
preBase
|
|
221
|
-
};
|
|
141
|
+
const truncateBody = (body) => {
|
|
142
|
+
if (body && body.length >= 124e3) return body.substring(0, 124e3) + "...";
|
|
143
|
+
return body;
|
|
222
144
|
};
|
|
223
|
-
const
|
|
224
|
-
|
|
145
|
+
const uploadAssets = async (ctx, config) => {
|
|
146
|
+
const { github: { assets } } = config;
|
|
147
|
+
const { github: { isReleased, owner, repo, uploadUrl, releaseId, token }, pkg: { name } } = ctx;
|
|
148
|
+
if (!assets?.length || !isReleased) return;
|
|
149
|
+
const octokit = new Octokit({ auth: token });
|
|
150
|
+
const files = await glob(assets);
|
|
151
|
+
await Promise.all(files.map((file) => {
|
|
152
|
+
return octokit.repos.uploadReleaseAsset({
|
|
153
|
+
owner,
|
|
154
|
+
repo,
|
|
155
|
+
name,
|
|
156
|
+
url: uploadUrl,
|
|
157
|
+
release_id: releaseId,
|
|
158
|
+
data: createReadStream(file),
|
|
159
|
+
headers: {
|
|
160
|
+
"content-type": contentType(file) || "application/octet-stream",
|
|
161
|
+
"content-length": statSync(file).size
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}));
|
|
225
165
|
};
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
PreRelease$1["MINOR"] = "preminor";
|
|
238
|
-
PreRelease$1["PATCH"] = "prepatch";
|
|
239
|
-
PreRelease$1["RELEASE"] = "prerelease";
|
|
240
|
-
return PreRelease$1;
|
|
241
|
-
}({});
|
|
242
|
-
let PreId = /* @__PURE__ */ function(PreId$1) {
|
|
243
|
-
PreId$1["ALPHA"] = "alpha";
|
|
244
|
-
PreId$1["BETA"] = "beta";
|
|
245
|
-
PreId$1["RC"] = "rc";
|
|
246
|
-
PreId$1["NET"] = "next";
|
|
247
|
-
PreId$1["CANARY"] = "canary";
|
|
248
|
-
PreId$1["NIGHT"] = "nightly";
|
|
249
|
-
PreId$1["DEV"] = "dev";
|
|
250
|
-
return PreId$1;
|
|
251
|
-
}({});
|
|
252
|
-
const diff = (from, to) => {
|
|
253
|
-
const a = from.split(".");
|
|
254
|
-
return to.split(".").map((v, i) => v === a[i] ? dim(v) : green(v)).join(".");
|
|
166
|
+
const createWebRelease = async (ctx, config) => {
|
|
167
|
+
const { pkg: { next, toPreRelease }, github: { owner, repo, changelog, releaseName } } = ctx;
|
|
168
|
+
const { github: { prerelease: prerelease$1 } } = config;
|
|
169
|
+
const github = getGithubUrl(owner, repo);
|
|
170
|
+
const url = new URL(`${github}/releases/new`);
|
|
171
|
+
url.searchParams.set("tag", next);
|
|
172
|
+
url.searchParams.set("title", releaseName ?? `Release ${next}`);
|
|
173
|
+
url.searchParams.set("body", truncateBody(changelog));
|
|
174
|
+
url.searchParams.set("prelease", String(toPreRelease || prerelease$1));
|
|
175
|
+
const isWindows = process.platform === "win32";
|
|
176
|
+
await open(url.toString(), { wait: isWindows });
|
|
255
177
|
};
|
|
256
|
-
const
|
|
257
|
-
const { pkg: {
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
label: "Pre-Patch",
|
|
274
|
-
value: prepatch,
|
|
275
|
-
hint: prepatch
|
|
276
|
-
},
|
|
277
|
-
{
|
|
278
|
-
label: "Pre-Minor",
|
|
279
|
-
value: preminor,
|
|
280
|
-
hint: preminor
|
|
281
|
-
},
|
|
282
|
-
{
|
|
283
|
-
label: "Pre-Major",
|
|
284
|
-
value: premajor,
|
|
285
|
-
hint: premajor
|
|
286
|
-
}
|
|
287
|
-
];
|
|
288
|
-
const release = [
|
|
289
|
-
{
|
|
290
|
-
label: "Patch",
|
|
291
|
-
value: patch,
|
|
292
|
-
hint: patch
|
|
293
|
-
},
|
|
294
|
-
{
|
|
295
|
-
label: "Minor",
|
|
296
|
-
value: minor,
|
|
297
|
-
hint: minor
|
|
298
|
-
},
|
|
299
|
-
{
|
|
300
|
-
label: "Major",
|
|
301
|
-
value: major,
|
|
302
|
-
hint: major
|
|
303
|
-
}
|
|
304
|
-
];
|
|
305
|
-
const custom = [{
|
|
306
|
-
label: "As-Is",
|
|
307
|
-
value: "ignore",
|
|
308
|
-
hint: current
|
|
309
|
-
}, {
|
|
310
|
-
label: "Custom",
|
|
311
|
-
value: "custom",
|
|
312
|
-
hint: "custom specified"
|
|
313
|
-
}];
|
|
314
|
-
const version = await select({
|
|
315
|
-
message: prompt(MSG.PROMPT.SELECT_VERSION),
|
|
316
|
-
options: [
|
|
317
|
-
...fromPreRelease ? pr : [],
|
|
318
|
-
...release,
|
|
319
|
-
...fromPreRelease ? [] : pre,
|
|
320
|
-
...custom
|
|
321
|
-
],
|
|
322
|
-
initialValue: fromPreRelease ? prerelease$1 : patch
|
|
178
|
+
const createCiRelease = async (ctx, config) => {
|
|
179
|
+
const { pkg: { next, toPreRelease }, github: { owner, repo, token, changelog, releaseName } } = ctx;
|
|
180
|
+
const { github: { prerelease: prerelease$1, draft, autoGenerate } } = config;
|
|
181
|
+
const octokit = new Octokit({ auth: token });
|
|
182
|
+
try {
|
|
183
|
+
const { data } = await octokit.repos.createRelease({
|
|
184
|
+
owner,
|
|
185
|
+
repo,
|
|
186
|
+
tag_name: next,
|
|
187
|
+
target_commitish: void 0,
|
|
188
|
+
name: releaseName ?? `Release ${next}`,
|
|
189
|
+
body: autoGenerate ? "" : truncateBody(changelog),
|
|
190
|
+
draft: draft ?? false,
|
|
191
|
+
prerelease: (toPreRelease || prerelease$1) ?? false,
|
|
192
|
+
discussion_category_name: void 0,
|
|
193
|
+
generate_release_notes: autoGenerate,
|
|
194
|
+
make_latest: "true"
|
|
323
195
|
});
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
validate: (val) => {
|
|
332
|
-
if (!isValid(val)) return "Invalid version";
|
|
333
|
-
}
|
|
196
|
+
const { html_url, upload_url, id, discussion_url } = data;
|
|
197
|
+
Object.assign(ctx.github, {
|
|
198
|
+
isReleased: true,
|
|
199
|
+
releaseId: id,
|
|
200
|
+
releaseUrl: html_url,
|
|
201
|
+
uploadUrl: upload_url,
|
|
202
|
+
discussionUrl: discussion_url
|
|
334
203
|
});
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
const next = type === "custom" ? await inputVersion() : type === "ignore" ? current : type;
|
|
340
|
-
const parsed = parseVersion(next);
|
|
341
|
-
Object.assign(ctx.pkg, { ...parsed });
|
|
342
|
-
ctx.isIncrement = gte(next, current);
|
|
343
|
-
log.message(gray`
|
|
344
|
-
from ${dim(current)}
|
|
345
|
-
to ${diff(current, next)}
|
|
346
|
-
`);
|
|
347
|
-
return { next };
|
|
204
|
+
} catch (e) {
|
|
205
|
+
if (e?.status === 422) throw new Error(MSG.ERROR.GITHUB_TAG_EXIT(next));
|
|
206
|
+
throw e;
|
|
207
|
+
}
|
|
348
208
|
};
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
previousTag: "",
|
|
386
|
-
currentTag: "",
|
|
387
|
-
isCommitted: false,
|
|
388
|
-
isTagged: false
|
|
389
|
-
},
|
|
390
|
-
github: {
|
|
391
|
-
username: "",
|
|
392
|
-
repo: "",
|
|
393
|
-
changelog: "",
|
|
394
|
-
owner: "",
|
|
395
|
-
isWeb: false,
|
|
396
|
-
skipChecks: false,
|
|
397
|
-
isReleased: false,
|
|
398
|
-
releaseId: 0,
|
|
399
|
-
releaseUrl: "",
|
|
400
|
-
uploadUrl: "",
|
|
401
|
-
discussionUrl: "",
|
|
402
|
-
token: ""
|
|
209
|
+
const parseGithubUrl = (ctx) => {
|
|
210
|
+
const { git: { remoteUrl } } = ctx;
|
|
211
|
+
const [owner, repo] = parseGitHubRepo(remoteUrl);
|
|
212
|
+
Object.assign(ctx.github, {
|
|
213
|
+
owner,
|
|
214
|
+
repo
|
|
215
|
+
});
|
|
216
|
+
};
|
|
217
|
+
const createRelease = async (ctx, config) => {
|
|
218
|
+
const { github: { owner, repo }, isCI } = ctx;
|
|
219
|
+
const { github: { tokenRef, release, skipChecks } } = config;
|
|
220
|
+
if (!release) return;
|
|
221
|
+
const token = tokenRef ? process.env[tokenRef] : process.env.GITHUB_TOKEN;
|
|
222
|
+
if (!token) {
|
|
223
|
+
Object.assign(ctx.github, { isWeb: true });
|
|
224
|
+
if (isCI && process.env.GITHUB_ACTIONS) throw new Error(MSG.ERROR.GITHUB_TOKEN(tokenRef));
|
|
225
|
+
}
|
|
226
|
+
Object.assign(ctx.github, { token });
|
|
227
|
+
const octokit = new Octokit({ auth: token });
|
|
228
|
+
if (token && !skipChecks) if (process.env.GITHUB_ACTIONS) Object.assign(ctx.github, { username: process.env.GITHUB_ACTOR });
|
|
229
|
+
else {
|
|
230
|
+
try {
|
|
231
|
+
const { data: { login: username } } = await octokit.users.getAuthenticated();
|
|
232
|
+
Object.assign(ctx.github, { username });
|
|
233
|
+
} catch (e) {
|
|
234
|
+
throw new Error(MSG.ERROR.GITHUB_AUTH);
|
|
235
|
+
}
|
|
236
|
+
try {
|
|
237
|
+
const { github: { username } } = ctx;
|
|
238
|
+
await octokit.repos.checkCollaborator({
|
|
239
|
+
owner,
|
|
240
|
+
repo,
|
|
241
|
+
username
|
|
242
|
+
});
|
|
243
|
+
} catch (e) {
|
|
244
|
+
throw new Error(MSG.ERROR.GITHUB_USER);
|
|
403
245
|
}
|
|
404
|
-
}
|
|
246
|
+
}
|
|
247
|
+
const { github: { isWeb }, dryRun } = ctx;
|
|
248
|
+
if (dryRun) return true;
|
|
249
|
+
if (isWeb) await createWebRelease(ctx, config);
|
|
250
|
+
else if (isCI) {
|
|
251
|
+
await createCiRelease(ctx, config);
|
|
252
|
+
await uploadAssets(ctx, config);
|
|
253
|
+
}
|
|
405
254
|
};
|
|
406
|
-
const
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
"before:bump": "",
|
|
410
|
-
"after:bump": "",
|
|
411
|
-
"before:publish": "",
|
|
412
|
-
"after:publish": "",
|
|
413
|
-
"before:push": "",
|
|
414
|
-
"after:push": "",
|
|
415
|
-
"before:release": "",
|
|
416
|
-
"after:release": ""
|
|
417
|
-
},
|
|
418
|
-
git: {
|
|
419
|
-
commit: isCI,
|
|
420
|
-
tag: isCI,
|
|
421
|
-
push: isCI,
|
|
422
|
-
commitMessage: "chore(release): ${version}",
|
|
423
|
-
tagMessage: "Release ${version}",
|
|
424
|
-
tagName: "${version}"
|
|
425
|
-
},
|
|
426
|
-
npm: {
|
|
427
|
-
publish: isCI,
|
|
428
|
-
tag: "",
|
|
429
|
-
allowSameVersion: false
|
|
430
|
-
},
|
|
431
|
-
github: {
|
|
432
|
-
release: isCI,
|
|
433
|
-
releaseName: "Release ${version}",
|
|
434
|
-
prerelease: false,
|
|
435
|
-
draft: false,
|
|
436
|
-
tokenRef: "GITHUB_TOKEN",
|
|
437
|
-
assets: []
|
|
438
|
-
}
|
|
439
|
-
};
|
|
255
|
+
const getGithubReleaseUrl = (ctx) => {
|
|
256
|
+
const { github: { owner, repo }, git: { currentTag } } = ctx;
|
|
257
|
+
return `${getGithubUrl(owner, repo)}/releases/tag/${normalizeTag(currentTag)}`;
|
|
440
258
|
};
|
|
441
259
|
|
|
442
260
|
//#endregion
|
|
443
261
|
//#region src/git/commit.ts
|
|
444
|
-
const spawnAsync = (cmd, args, options) => {
|
|
445
|
-
return new Promise((resolve$1) => {
|
|
446
|
-
const { trim, error, dryRun, ...others } = options ?? {};
|
|
447
|
-
const fullCmd = [cmd, ...args].join(" ");
|
|
448
|
-
const dim$1 = (text$1) => styleText(["dim"], text$1);
|
|
449
|
-
const red$1 = (text$1) => styleText(["red"], text$1);
|
|
450
|
-
if (dryRun) {
|
|
451
|
-
console.log(`${dim$1("[dry-run]")} ${fullCmd}`);
|
|
452
|
-
return resolve$1(void 0);
|
|
453
|
-
}
|
|
454
|
-
const child = spawn(cmd, args, { ...others });
|
|
455
|
-
let stdout = "";
|
|
456
|
-
child.stdout?.setEncoding("utf-8");
|
|
457
|
-
child.stdout?.on("data", (data) => stdout += trim ? data.trim() : data);
|
|
458
|
-
let stderr = "";
|
|
459
|
-
child.stderr?.setEncoding("utf-8");
|
|
460
|
-
child.stderr?.on("data", (data) => stderr += trim ? data.trim() : data);
|
|
461
|
-
child.on("close", (code) => {
|
|
462
|
-
if (stderr) {
|
|
463
|
-
const err = `${red$1("spawnAsync")} ${dim$1(fullCmd)} ${stderr}`;
|
|
464
|
-
switch (error) {
|
|
465
|
-
case "log":
|
|
466
|
-
console.error(err);
|
|
467
|
-
break;
|
|
468
|
-
case "throw": throw new Error(err);
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
resolve$1(0 === code ? stdout : void 0);
|
|
472
|
-
});
|
|
473
|
-
});
|
|
474
|
-
};
|
|
475
|
-
const runGit = async (args, trim = true) => {
|
|
476
|
-
return spawnAsync("git", args, { trim });
|
|
477
|
-
};
|
|
478
262
|
const getBranchName = () => {
|
|
479
263
|
return runGit([
|
|
480
264
|
"rev-parse",
|
|
@@ -494,10 +278,7 @@ const getStatus = () => {
|
|
|
494
278
|
"status",
|
|
495
279
|
"--short",
|
|
496
280
|
"--untracked-files=no"
|
|
497
|
-
], false);
|
|
498
|
-
};
|
|
499
|
-
const gitRestore = () => {
|
|
500
|
-
return runGit(["restore", "."]);
|
|
281
|
+
], { trim: false });
|
|
501
282
|
};
|
|
502
283
|
const coloredChangeset = (log$1) => {
|
|
503
284
|
const colorStatusChar = (ch) => {
|
|
@@ -531,10 +312,6 @@ const getRemote = async () => {
|
|
|
531
312
|
]))
|
|
532
313
|
};
|
|
533
314
|
};
|
|
534
|
-
const parseGitHubRepo = (url) => {
|
|
535
|
-
const match = url.trim().match(/github(?:\.com)?[:/](.+?)\/(.+?)(\/.+?)?(\.git)?$/);
|
|
536
|
-
return match ? match.slice(1, 3) : [];
|
|
537
|
-
};
|
|
538
315
|
const getLatestTag = async (match = "*", exclude = "*-beta.*") => {
|
|
539
316
|
return runGit([
|
|
540
317
|
"describe",
|
|
@@ -577,29 +354,10 @@ const getLog = async (print, isIncrement) => {
|
|
|
577
354
|
const cmd = ["log", `--pretty=format:${print ? "* %s (%h)" : "%s %h %H"}`];
|
|
578
355
|
const { from, to } = await resolveChangelogRange(isIncrement);
|
|
579
356
|
if (from) cmd.push(`${from}...${to}`);
|
|
580
|
-
return runGit(cmd, false);
|
|
581
|
-
};
|
|
582
|
-
const normalizeTag = (tag) => clean(tag) ?? tag;
|
|
583
|
-
const resolveTag$1 = async (ctx, config) => {
|
|
584
|
-
const { git: { tagName: tagTemplate } } = config;
|
|
585
|
-
const latestTag = await getLatestTag() ?? "";
|
|
586
|
-
const currentTag = format(tagTemplate || ((latestTag || "").match(/^v/) ? "v${version}" : "${version}"), ctx);
|
|
587
|
-
Object.assign(ctx.git, {
|
|
588
|
-
latestTag,
|
|
589
|
-
currentTag
|
|
590
|
-
});
|
|
591
|
-
return true;
|
|
357
|
+
return runGit(cmd, { trim: false });
|
|
592
358
|
};
|
|
593
|
-
const
|
|
594
|
-
|
|
595
|
-
if (!await isGitRepo()) throw new Error(MSG.ERROR.GIT_REGISTRY(name));
|
|
596
|
-
const { remoteName, remoteUrl } = await getRemote();
|
|
597
|
-
if (!remoteUrl) throw new Error(MSG.ERROR.GIT_REMOTE(name));
|
|
598
|
-
Object.assign(ctx.git, {
|
|
599
|
-
remoteName,
|
|
600
|
-
remoteUrl
|
|
601
|
-
});
|
|
602
|
-
parseGithubUrl(ctx);
|
|
359
|
+
const isWorkingDirClean = async () => {
|
|
360
|
+
return (await runGit(["status", "-s"]))?.length === 0;
|
|
603
361
|
};
|
|
604
362
|
const hasUpstreamBranch = async () => {
|
|
605
363
|
const branch = await runGit([
|
|
@@ -612,37 +370,52 @@ const hasUpstreamBranch = async () => {
|
|
|
612
370
|
const getUpstreamArgs = async (remoteName) => {
|
|
613
371
|
const hasUpstream = await hasUpstreamBranch();
|
|
614
372
|
const branch = await getBranchName();
|
|
615
|
-
if (!hasUpstream) return
|
|
616
|
-
"--set-upstream",
|
|
617
|
-
remoteName,
|
|
618
|
-
branch
|
|
619
|
-
] : [
|
|
373
|
+
if (!hasUpstream) return [
|
|
620
374
|
"--set-upstream",
|
|
621
|
-
"origin",
|
|
375
|
+
remoteName || "origin",
|
|
622
376
|
branch
|
|
623
377
|
];
|
|
624
378
|
if (remoteName) return [remoteName];
|
|
625
379
|
return [];
|
|
626
380
|
};
|
|
627
|
-
const
|
|
628
|
-
|
|
629
|
-
|
|
381
|
+
const normalizeTag = (tag) => clean(tag) ?? tag;
|
|
382
|
+
const gitCheck = async (ctx, config) => {
|
|
383
|
+
const { pkg: { name } } = ctx;
|
|
384
|
+
const { git: { requireRepository, requireRemote, requireWorkDirClean } } = config;
|
|
385
|
+
if (!await isGitRepo()) if (requireRepository) throw new Error(MSG.ERROR.GIT_REGISTRY(name));
|
|
386
|
+
else {
|
|
387
|
+
ctx.noGit = true;
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
if (requireWorkDirClean && !await isWorkingDirClean()) throw new Error(MSG.ERROR.GIT_WORKDIR);
|
|
391
|
+
const { remoteName, remoteUrl } = await getRemote();
|
|
392
|
+
if (!remoteUrl) if (requireRemote) throw new Error(MSG.ERROR.GIT_REMOTE(name));
|
|
393
|
+
else {
|
|
394
|
+
ctx.noGitHub = true;
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
Object.assign(ctx.git, {
|
|
398
|
+
remoteName,
|
|
399
|
+
remoteUrl
|
|
400
|
+
});
|
|
401
|
+
parseGithubUrl(ctx);
|
|
630
402
|
};
|
|
631
403
|
const commitAndTag = async (ctx, config) => {
|
|
632
|
-
const { git: { currentTag,
|
|
633
|
-
const { git: { commit, tag, push,
|
|
404
|
+
const { git: { remoteName, currentTag, commitMessage, tagMessage }, dryRun } = ctx;
|
|
405
|
+
const { git: { commit, tag, push, addUntrackedFiles, commitArgs, tagArgs, pushArgs } } = config;
|
|
634
406
|
if (!commit) return;
|
|
635
407
|
const args = dryRun ? ["--dry-run"] : [];
|
|
636
408
|
await runGit([
|
|
637
409
|
"add",
|
|
638
410
|
".",
|
|
639
|
-
"--all",
|
|
411
|
+
addUntrackedFiles ? "--all" : "--update",
|
|
640
412
|
...args
|
|
641
413
|
]);
|
|
642
414
|
await runGit([
|
|
643
415
|
"commit",
|
|
644
416
|
"--message",
|
|
645
|
-
|
|
417
|
+
commitMessage,
|
|
418
|
+
...commitArgs,
|
|
646
419
|
...args
|
|
647
420
|
]);
|
|
648
421
|
if (!dryRun) Object.assign(ctx.git, { isCommitted: true });
|
|
@@ -651,8 +424,9 @@ const commitAndTag = async (ctx, config) => {
|
|
|
651
424
|
"tag",
|
|
652
425
|
"--annotate",
|
|
653
426
|
"--message",
|
|
654
|
-
|
|
427
|
+
tagMessage,
|
|
655
428
|
currentTag,
|
|
429
|
+
...tagArgs,
|
|
656
430
|
...args
|
|
657
431
|
]);
|
|
658
432
|
if (!dryRun) Object.assign(ctx.git, { isTagged: true });
|
|
@@ -661,18 +435,19 @@ const commitAndTag = async (ctx, config) => {
|
|
|
661
435
|
"push",
|
|
662
436
|
...await getUpstreamArgs(remoteName),
|
|
663
437
|
"--follow-tags",
|
|
438
|
+
...pushArgs,
|
|
664
439
|
...args
|
|
665
440
|
]);
|
|
666
441
|
};
|
|
667
|
-
const gitRollback =
|
|
442
|
+
const gitRollback$1 = (ctx) => {
|
|
668
443
|
const { git: { currentTag, isCommitted, isTagged } } = ctx;
|
|
669
|
-
|
|
670
|
-
if (isTagged)
|
|
444
|
+
spawnSync("git", ["restore", "."]);
|
|
445
|
+
if (isTagged) spawnSync("git", [
|
|
671
446
|
"tag",
|
|
672
447
|
"--delete",
|
|
673
448
|
currentTag
|
|
674
449
|
]);
|
|
675
|
-
|
|
450
|
+
spawnSync("git", [
|
|
676
451
|
"reset",
|
|
677
452
|
"--hard",
|
|
678
453
|
isCommitted ? "HEAD~1" : "HEAD"
|
|
@@ -680,123 +455,344 @@ const gitRollback = async (ctx) => {
|
|
|
680
455
|
};
|
|
681
456
|
|
|
682
457
|
//#endregion
|
|
683
|
-
//#region src/
|
|
684
|
-
const
|
|
685
|
-
|
|
458
|
+
//#region src/utils.ts
|
|
459
|
+
const info = (msg$1) => {
|
|
460
|
+
console.log(`${rgb(33, 91, 184)(`i`)} ${gray(msg$1)}`);
|
|
686
461
|
};
|
|
687
|
-
const
|
|
688
|
-
|
|
689
|
-
return body;
|
|
462
|
+
const msg = (prefix, msg$1) => {
|
|
463
|
+
log.message(gray`${rgb(33, 91, 184)(`[${prefix}]`)} ${msg$1}`);
|
|
690
464
|
};
|
|
691
|
-
const
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
465
|
+
const question = (msg$1, type) => {
|
|
466
|
+
return `${{
|
|
467
|
+
version: green,
|
|
468
|
+
git: rgb(220, 94, 62),
|
|
469
|
+
npm: rgb(186, 70, 61),
|
|
470
|
+
github: rgb(64, 110, 228)
|
|
471
|
+
}[type]`?`} ${msg$1}`;
|
|
472
|
+
};
|
|
473
|
+
const success = (msg$1, dryRun) => {
|
|
474
|
+
return `${(dryRun ? rgb(123, 115, 66) : green)("✔")} ${msg$1}`;
|
|
475
|
+
};
|
|
476
|
+
const runLifeCycleHook = async (hooks, key, dryRun) => {
|
|
477
|
+
const handler = hooks[key];
|
|
478
|
+
if (typeof handler === "function") {
|
|
479
|
+
if (!dryRun) await handler();
|
|
480
|
+
log.success(success(`${dim`run`} ${inspect(handler)}`, dryRun));
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
return Promise.allSettled(castArray(handler).filter(Boolean).map(async (hook) => {
|
|
484
|
+
if (!dryRun) await execAsync(hook).catch(log.error);
|
|
485
|
+
log.success(success(hook.replace(/^echo$/, dim("echo")), dryRun));
|
|
486
|
+
}));
|
|
487
|
+
};
|
|
488
|
+
const gitRollback = (ctx) => {
|
|
489
|
+
const { git: { currentTag, isCommitted, isTagged } } = ctx;
|
|
490
|
+
spawnSync("git", ["restore", "."]);
|
|
491
|
+
if (isTagged) spawnSync("git", [
|
|
492
|
+
"tag",
|
|
493
|
+
"--delete",
|
|
494
|
+
currentTag
|
|
495
|
+
]);
|
|
496
|
+
spawnSync("git", [
|
|
497
|
+
"reset",
|
|
498
|
+
"--hard",
|
|
499
|
+
isCommitted ? "HEAD~1" : "HEAD"
|
|
500
|
+
]);
|
|
501
|
+
};
|
|
502
|
+
const diff = (from, to, separator = ".") => {
|
|
503
|
+
const a = from.split(separator);
|
|
504
|
+
return to.split(separator).map((v, i) => v === a[i] ? dim(v) : green(v)).join(separator);
|
|
505
|
+
};
|
|
506
|
+
const formatTemplate = async (ctx, config) => {
|
|
507
|
+
const { pkg: { next } } = ctx;
|
|
508
|
+
const { git: { commitMessage: cm, tagMessage: tm, tagName }, github: { releaseName: rm } } = config;
|
|
509
|
+
const f = (s, v) => s.replace("${version}", v);
|
|
510
|
+
const latestTag = await getLatestTag() ?? "";
|
|
511
|
+
const currentTag = f(tagName || (latestTag.match(/^v/) ? "v${version}" : "${version}"), next);
|
|
512
|
+
const commitMessage = f(cm, next);
|
|
513
|
+
const tagMessage = f(tm, next);
|
|
514
|
+
const releaseName = f(rm, next);
|
|
515
|
+
Object.assign(ctx.git, {
|
|
516
|
+
latestTag,
|
|
517
|
+
currentTag,
|
|
518
|
+
commitMessage,
|
|
519
|
+
tagMessage
|
|
520
|
+
});
|
|
521
|
+
Object.assign(ctx.github, { releaseName });
|
|
522
|
+
};
|
|
523
|
+
|
|
524
|
+
//#endregion
|
|
525
|
+
//#region src/prompts.ts
|
|
526
|
+
const abortTask = (msg$1) => {
|
|
527
|
+
cancel(`${red("✕")} ${msg$1}`);
|
|
528
|
+
process.exit(0);
|
|
529
|
+
};
|
|
530
|
+
const abortSinglePrompt = (value) => {
|
|
531
|
+
if (isCancel(value)) abortTask("Operation cancelled.");
|
|
532
|
+
};
|
|
533
|
+
const abortGroupPrompt = (ctx) => {
|
|
534
|
+
ctx && gitRollback(ctx);
|
|
535
|
+
abortTask("Operation cancelled.");
|
|
536
|
+
};
|
|
537
|
+
const abortOnError = (err, ctx) => {
|
|
538
|
+
ctx && gitRollback(ctx);
|
|
539
|
+
const msg$1 = err.message.replace(/^\[(github|npm|git)]/, (a) => red(a));
|
|
540
|
+
log.message(`\n${msg$1}\n`);
|
|
541
|
+
process.exit(1);
|
|
542
|
+
};
|
|
543
|
+
const taskEnd = (msg$1) => {
|
|
544
|
+
outro(msg$1);
|
|
545
|
+
process.exit(0);
|
|
546
|
+
};
|
|
547
|
+
|
|
548
|
+
//#endregion
|
|
549
|
+
//#region src/version/bump.ts
|
|
550
|
+
const isPreRelease = (version) => {
|
|
551
|
+
return Boolean(prerelease(version));
|
|
552
|
+
};
|
|
553
|
+
const isValid = (version) => {
|
|
554
|
+
return Boolean(valid(version));
|
|
555
|
+
};
|
|
556
|
+
const parseVersion = (raw) => {
|
|
557
|
+
const next = isValid(raw) ? raw : coerce(raw)?.toString();
|
|
558
|
+
if (!next) return {};
|
|
559
|
+
const { prerelease: prerelease$1 } = parse(next);
|
|
560
|
+
const toPreRelease = Boolean(prerelease$1.length);
|
|
561
|
+
const [preId, preBase] = prerelease$1.map(String);
|
|
562
|
+
return {
|
|
563
|
+
next,
|
|
564
|
+
toPreRelease,
|
|
565
|
+
preId,
|
|
566
|
+
preBase
|
|
567
|
+
};
|
|
568
|
+
};
|
|
569
|
+
const getCIVersion = (current) => {
|
|
570
|
+
return inc(current, Release.PATCH) ?? "";
|
|
571
|
+
};
|
|
572
|
+
|
|
573
|
+
//#endregion
|
|
574
|
+
//#region src/version/prompts.ts
|
|
575
|
+
let Release = /* @__PURE__ */ function(Release$1) {
|
|
576
|
+
Release$1["MAJOR"] = "major";
|
|
577
|
+
Release$1["MINOR"] = "minor";
|
|
578
|
+
Release$1["PATCH"] = "patch";
|
|
579
|
+
return Release$1;
|
|
580
|
+
}({});
|
|
581
|
+
let PreRelease = /* @__PURE__ */ function(PreRelease$1) {
|
|
582
|
+
PreRelease$1["MAJOR"] = "premajor";
|
|
583
|
+
PreRelease$1["MINOR"] = "preminor";
|
|
584
|
+
PreRelease$1["PATCH"] = "prepatch";
|
|
585
|
+
PreRelease$1["RELEASE"] = "prerelease";
|
|
586
|
+
return PreRelease$1;
|
|
587
|
+
}({});
|
|
588
|
+
let PreId = /* @__PURE__ */ function(PreId$1) {
|
|
589
|
+
PreId$1["ALPHA"] = "alpha";
|
|
590
|
+
PreId$1["BETA"] = "beta";
|
|
591
|
+
PreId$1["RC"] = "rc";
|
|
592
|
+
PreId$1["NET"] = "next";
|
|
593
|
+
PreId$1["CANARY"] = "canary";
|
|
594
|
+
PreId$1["NIGHT"] = "nightly";
|
|
595
|
+
PreId$1["DEV"] = "dev";
|
|
596
|
+
return PreId$1;
|
|
597
|
+
}({});
|
|
598
|
+
const runVersionPrompts = async (ctx, config) => {
|
|
599
|
+
const { pkg: { current, fromPreRelease } } = ctx;
|
|
600
|
+
const selectVersion = async () => {
|
|
601
|
+
const patch = inc(current, Release.PATCH);
|
|
602
|
+
const minor = inc(current, Release.MINOR);
|
|
603
|
+
const major = inc(current, Release.MAJOR);
|
|
604
|
+
const prerelease$1 = inc(current, PreRelease.RELEASE);
|
|
605
|
+
const prepatch = inc(current, PreRelease.PATCH, PreId.BETA);
|
|
606
|
+
const preminor = inc(current, PreRelease.MINOR, PreId.BETA);
|
|
607
|
+
const premajor = inc(current, PreRelease.MAJOR, PreId.BETA);
|
|
608
|
+
const pr = [{
|
|
609
|
+
label: "Pre-Release",
|
|
610
|
+
value: prerelease$1,
|
|
611
|
+
hint: prerelease$1
|
|
612
|
+
}];
|
|
613
|
+
const pre = [
|
|
614
|
+
{
|
|
615
|
+
label: "Pre-Patch",
|
|
616
|
+
value: prepatch,
|
|
617
|
+
hint: prepatch
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
label: "Pre-Minor",
|
|
621
|
+
value: preminor,
|
|
622
|
+
hint: preminor
|
|
623
|
+
},
|
|
624
|
+
{
|
|
625
|
+
label: "Pre-Major",
|
|
626
|
+
value: premajor,
|
|
627
|
+
hint: premajor
|
|
628
|
+
}
|
|
629
|
+
];
|
|
630
|
+
const release = [
|
|
631
|
+
{
|
|
632
|
+
label: "Patch",
|
|
633
|
+
value: patch,
|
|
634
|
+
hint: patch
|
|
635
|
+
},
|
|
636
|
+
{
|
|
637
|
+
label: "Minor",
|
|
638
|
+
value: minor,
|
|
639
|
+
hint: minor
|
|
640
|
+
},
|
|
641
|
+
{
|
|
642
|
+
label: "Major",
|
|
643
|
+
value: major,
|
|
644
|
+
hint: major
|
|
708
645
|
}
|
|
646
|
+
];
|
|
647
|
+
const custom = [{
|
|
648
|
+
label: "As-Is",
|
|
649
|
+
value: "ignore",
|
|
650
|
+
hint: current
|
|
651
|
+
}, {
|
|
652
|
+
label: "Custom",
|
|
653
|
+
value: "custom",
|
|
654
|
+
hint: "custom specified"
|
|
655
|
+
}];
|
|
656
|
+
const version = await select({
|
|
657
|
+
message: question(MSG.PROMPT.SELECT_VERSION, "version"),
|
|
658
|
+
options: [
|
|
659
|
+
...fromPreRelease ? pr : [],
|
|
660
|
+
...release,
|
|
661
|
+
...fromPreRelease ? [] : pre,
|
|
662
|
+
...custom
|
|
663
|
+
],
|
|
664
|
+
initialValue: fromPreRelease ? prerelease$1 : patch
|
|
709
665
|
});
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
const
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
url.searchParams.set("prelease", String(toPreRelease || prerelease$1));
|
|
721
|
-
const isWindows = process.platform === "win32";
|
|
722
|
-
await open(url.toString(), { wait: isWindows });
|
|
723
|
-
};
|
|
724
|
-
const createCiRelease = async (ctx, config) => {
|
|
725
|
-
const { pkg: { next, toPreRelease }, github: { owner, repo, token, changelog } } = ctx;
|
|
726
|
-
const { github: { prerelease: prerelease$1, releaseName, draft } } = config;
|
|
727
|
-
const octokit = new Octokit({ auth: token });
|
|
728
|
-
try {
|
|
729
|
-
const { data } = await octokit.repos.createRelease({
|
|
730
|
-
owner,
|
|
731
|
-
repo,
|
|
732
|
-
tag_name: next,
|
|
733
|
-
name: format(releaseName, ctx) ?? `Release ${next}`,
|
|
734
|
-
body: truncateBody(changelog),
|
|
735
|
-
draft: draft ?? false,
|
|
736
|
-
prerelease: (toPreRelease || prerelease$1) ?? false
|
|
737
|
-
});
|
|
738
|
-
const { html_url, upload_url, id, discussion_url } = data;
|
|
739
|
-
Object.assign(ctx.github, {
|
|
740
|
-
isReleased: true,
|
|
741
|
-
releaseId: id,
|
|
742
|
-
releaseUrl: html_url,
|
|
743
|
-
uploadUrl: upload_url,
|
|
744
|
-
discussionUrl: discussion_url
|
|
666
|
+
abortSinglePrompt(version);
|
|
667
|
+
return version;
|
|
668
|
+
};
|
|
669
|
+
const inputVersion = async () => {
|
|
670
|
+
const version = await text({
|
|
671
|
+
message: question(MSG.PROMPT.INPUT_VERSION, "version"),
|
|
672
|
+
initialValue: current,
|
|
673
|
+
validate: (val) => {
|
|
674
|
+
if (!isValid(val)) return "Invalid version";
|
|
675
|
+
}
|
|
745
676
|
});
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
const [owner, repo] = parseGitHubRepo(remoteUrl);
|
|
754
|
-
Object.assign(ctx.github, {
|
|
755
|
-
owner,
|
|
756
|
-
repo
|
|
757
|
-
});
|
|
677
|
+
abortSinglePrompt(version);
|
|
678
|
+
return version;
|
|
679
|
+
};
|
|
680
|
+
const type = await selectVersion();
|
|
681
|
+
const next = type === "custom" ? await inputVersion() : type === "ignore" ? current : type;
|
|
682
|
+
ctx.isIncrement = gte(next, current);
|
|
683
|
+
return { next };
|
|
758
684
|
};
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
685
|
+
|
|
686
|
+
//#endregion
|
|
687
|
+
//#region src/defaults.ts
|
|
688
|
+
const createDefaultContext = () => {
|
|
689
|
+
return {
|
|
690
|
+
isCI: false,
|
|
691
|
+
release: false,
|
|
692
|
+
showRelease: false,
|
|
693
|
+
showChangelog: false,
|
|
694
|
+
dryRun: false,
|
|
695
|
+
noGit: false,
|
|
696
|
+
noNpm: false,
|
|
697
|
+
noGitHub: false,
|
|
698
|
+
increment: "",
|
|
699
|
+
isIncrement: false,
|
|
700
|
+
configFileExists: false,
|
|
701
|
+
pkg: {
|
|
702
|
+
current: "",
|
|
703
|
+
next: "",
|
|
704
|
+
name: "",
|
|
705
|
+
isPrivate: false,
|
|
706
|
+
fromPreRelease: false,
|
|
707
|
+
toPreRelease: false,
|
|
708
|
+
publishConfig: {
|
|
709
|
+
access: "public",
|
|
710
|
+
registry: "https://registry.npmjs.org"
|
|
711
|
+
},
|
|
712
|
+
preId: PreId.BETA,
|
|
713
|
+
preBase: "0"
|
|
714
|
+
},
|
|
715
|
+
npm: {
|
|
716
|
+
username: "",
|
|
717
|
+
otp: "",
|
|
718
|
+
tag: "latest"
|
|
719
|
+
},
|
|
720
|
+
git: {
|
|
721
|
+
remoteName: "origin",
|
|
722
|
+
remoteUrl: "",
|
|
723
|
+
latestTag: "",
|
|
724
|
+
previousTag: "",
|
|
725
|
+
currentTag: "",
|
|
726
|
+
isCommitted: false,
|
|
727
|
+
isTagged: false,
|
|
728
|
+
commitMessage: "",
|
|
729
|
+
tagMessage: "",
|
|
730
|
+
tagName: ""
|
|
731
|
+
},
|
|
732
|
+
github: {
|
|
733
|
+
username: "",
|
|
734
|
+
repo: "",
|
|
735
|
+
changelog: "",
|
|
736
|
+
owner: "",
|
|
737
|
+
isWeb: false,
|
|
738
|
+
isReleased: false,
|
|
739
|
+
releaseId: 0,
|
|
740
|
+
releaseUrl: "",
|
|
741
|
+
uploadUrl: "",
|
|
742
|
+
discussionUrl: "",
|
|
743
|
+
token: "",
|
|
744
|
+
releaseName: ""
|
|
787
745
|
}
|
|
788
|
-
}
|
|
789
|
-
const { github: { isWeb }, dryRun } = ctx;
|
|
790
|
-
if (dryRun) return true;
|
|
791
|
-
if (isWeb) await createWebRelease(ctx, config);
|
|
792
|
-
else if (ci) {
|
|
793
|
-
await createCiRelease(ctx, config);
|
|
794
|
-
await uploadAssets(ctx, config);
|
|
795
|
-
}
|
|
746
|
+
};
|
|
796
747
|
};
|
|
797
|
-
const
|
|
798
|
-
|
|
799
|
-
|
|
748
|
+
const createDefaultConfig = (isCI) => {
|
|
749
|
+
return {
|
|
750
|
+
hooks: {
|
|
751
|
+
"before:bump": "",
|
|
752
|
+
"after:bump": "",
|
|
753
|
+
"before:publish": "",
|
|
754
|
+
"after:publish": "",
|
|
755
|
+
"before:push": "",
|
|
756
|
+
"after:push": "",
|
|
757
|
+
"before:release": "",
|
|
758
|
+
"after:release": ""
|
|
759
|
+
},
|
|
760
|
+
git: {
|
|
761
|
+
commit: isCI,
|
|
762
|
+
tag: isCI,
|
|
763
|
+
push: isCI,
|
|
764
|
+
commitMessage: "chore(release): ${version}",
|
|
765
|
+
commitArgs: [],
|
|
766
|
+
tagMessage: "Release ${version}",
|
|
767
|
+
tagName: "${version}",
|
|
768
|
+
tagArgs: [],
|
|
769
|
+
pushArgs: [],
|
|
770
|
+
addUntrackedFiles: false,
|
|
771
|
+
requireRemote: true,
|
|
772
|
+
requireRepository: true,
|
|
773
|
+
requireWorkDirClean: true
|
|
774
|
+
},
|
|
775
|
+
npm: {
|
|
776
|
+
publish: isCI,
|
|
777
|
+
publishPath: ".",
|
|
778
|
+
pushArgs: [],
|
|
779
|
+
skipChecks: false
|
|
780
|
+
},
|
|
781
|
+
github: {
|
|
782
|
+
release: isCI,
|
|
783
|
+
releaseName: "Release ${version}",
|
|
784
|
+
autoGenerate: false,
|
|
785
|
+
prerelease: false,
|
|
786
|
+
draft: false,
|
|
787
|
+
tokenRef: "GITHUB_TOKEN",
|
|
788
|
+
assets: [],
|
|
789
|
+
skipChecks: false
|
|
790
|
+
},
|
|
791
|
+
changelog: {
|
|
792
|
+
infile: "CHANGELOG.md",
|
|
793
|
+
types: []
|
|
794
|
+
}
|
|
795
|
+
};
|
|
800
796
|
};
|
|
801
797
|
|
|
802
798
|
//#endregion
|
|
@@ -893,6 +889,13 @@ const defaultTypes = [
|
|
|
893
889
|
description: "破坏性变更"
|
|
894
890
|
}
|
|
895
891
|
];
|
|
892
|
+
const mergeTypes = (types) => {
|
|
893
|
+
types.forEach((item) => {
|
|
894
|
+
const index = defaultTypes.findIndex((it) => it.type === item.type);
|
|
895
|
+
if (index >= 0) defaultTypes.splice(index, 1, { ...item });
|
|
896
|
+
else defaultTypes.push({ ...item });
|
|
897
|
+
});
|
|
898
|
+
};
|
|
896
899
|
const findType = (type) => {
|
|
897
900
|
return defaultTypes.find((item) => item.type === type)?.section ?? type;
|
|
898
901
|
};
|
|
@@ -927,24 +930,20 @@ const classify = (commits) => {
|
|
|
927
930
|
return sections;
|
|
928
931
|
};
|
|
929
932
|
const renderChangelog = async (ctx, sections) => {
|
|
930
|
-
const {
|
|
933
|
+
const { github: { owner, repo }, git: { latestTag, currentTag } } = ctx;
|
|
931
934
|
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
932
935
|
const github = getGithubUrl(owner, repo);
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
md += `**Full Changelog**: ${github}/compare/${latestTag}...${to}`;
|
|
945
|
-
md += eol$1(3);
|
|
946
|
-
}
|
|
947
|
-
return md;
|
|
936
|
+
return [
|
|
937
|
+
latestTag ? `## [${currentTag}](${github}/compare/${latestTag}...${currentTag}) (${date})` : `## ${currentTag} (${date})`,
|
|
938
|
+
Object.entries(sections).map((entry) => {
|
|
939
|
+
const [type, items] = entry;
|
|
940
|
+
return [`### ${findType(type)}`, items.map((item) => {
|
|
941
|
+
const [desc, hash, fullHash] = item;
|
|
942
|
+
return `* **${type}** ${desc} [${hash}](${github}/commit/${fullHash})`;
|
|
943
|
+
}).join(eol(1))].join(eol(2));
|
|
944
|
+
}).join(eol(2)),
|
|
945
|
+
latestTag ? `**Full Changelog**: ${github}/compare/${latestTag}...${currentTag}` : ""
|
|
946
|
+
].join(eol(3));
|
|
948
947
|
};
|
|
949
948
|
const generateChangelog = async (ctx) => {
|
|
950
949
|
const { isIncrement } = ctx;
|
|
@@ -954,36 +953,46 @@ const generateChangelog = async (ctx) => {
|
|
|
954
953
|
Object.assign(ctx.github, { changelog });
|
|
955
954
|
return changelog;
|
|
956
955
|
};
|
|
957
|
-
const updateChangelog = async (newContent) => {
|
|
958
|
-
const
|
|
959
|
-
const
|
|
960
|
-
|
|
961
|
-
await
|
|
956
|
+
const updateChangelog = async (file, newContent) => {
|
|
957
|
+
const infile = file || "CHANGELOG.md";
|
|
958
|
+
const target = join(process.cwd(), infile);
|
|
959
|
+
const SHORT_TITLE = "# Changelog";
|
|
960
|
+
const exist = (existsSync(target) ? await readFile(target, "utf-8") : "").replace(/\r\n/g, "\n");
|
|
961
|
+
await writeFile(target, [
|
|
962
|
+
SHORT_TITLE,
|
|
963
|
+
newContent,
|
|
964
|
+
exist.startsWith(SHORT_TITLE) ? exist.slice(11) : exist
|
|
965
|
+
].map((k) => k.trim()).join(eol(4)) + eol());
|
|
966
|
+
await runGit(["add", infile]);
|
|
967
|
+
};
|
|
968
|
+
const writeChangelog = async (ctx, config) => {
|
|
969
|
+
const { changelog: { infile, types } } = config;
|
|
970
|
+
mergeTypes(types);
|
|
971
|
+
await updateChangelog(infile, await generateChangelog(ctx));
|
|
962
972
|
};
|
|
963
973
|
|
|
964
974
|
//#endregion
|
|
965
975
|
//#region src/git/prompts.ts
|
|
966
976
|
const runGitPrompts = async (ctx, config) => {
|
|
967
|
-
const { git: { currentTag }, configFileExists: cfe, dryRun } = ctx;
|
|
968
|
-
const { git: { commit, tag, push
|
|
977
|
+
const { git: { currentTag, commitMessage }, configFileExists: cfe, dryRun } = ctx;
|
|
978
|
+
const { git: { commit, tag, push } } = config;
|
|
969
979
|
const logs = [];
|
|
970
|
-
const cMsg = format(commitMessage, ctx);
|
|
971
980
|
const shouldPrompt = (val) => isUndefined(val) || dryRun;
|
|
972
981
|
const { log: _, ...reset } = await group({
|
|
973
982
|
commit: () => {
|
|
974
|
-
return shouldPrompt(commit) ? confirm({ message:
|
|
983
|
+
return shouldPrompt(commit) ? confirm({ message: question(MSG.PROMPT.GIT_COMMIT(commitMessage), "git") }) : (() => {
|
|
975
984
|
logs.push(yellow`git.commit`);
|
|
976
985
|
return Promise.resolve(commit);
|
|
977
986
|
})();
|
|
978
987
|
},
|
|
979
988
|
tag: () => {
|
|
980
|
-
return shouldPrompt(tag) ? confirm({ message:
|
|
989
|
+
return shouldPrompt(tag) ? confirm({ message: question(MSG.PROMPT.GIT_TAG(currentTag), "git") }) : (() => {
|
|
981
990
|
logs.push(yellow`git.tag`);
|
|
982
991
|
return Promise.resolve(tag);
|
|
983
992
|
})();
|
|
984
993
|
},
|
|
985
994
|
push: () => {
|
|
986
|
-
return shouldPrompt(push) ? confirm({ message:
|
|
995
|
+
return shouldPrompt(push) ? confirm({ message: question(MSG.PROMPT.GIT_PUSH, "git") }) : (() => {
|
|
987
996
|
logs.push(yellow`git.push`);
|
|
988
997
|
return Promise.resolve(push);
|
|
989
998
|
})();
|
|
@@ -992,9 +1001,8 @@ const runGitPrompts = async (ctx, config) => {
|
|
|
992
1001
|
if (logs.length) msg("GIT", `Using ${cfe ? "user" : "default"} config: ${logs.join(", ")}`);
|
|
993
1002
|
return Promise.resolve();
|
|
994
1003
|
}
|
|
995
|
-
}, { onCancel:
|
|
996
|
-
|
|
997
|
-
abortTask("Operation cancelled.");
|
|
1004
|
+
}, { onCancel: ({ results }) => {
|
|
1005
|
+
abortGroupPrompt(ctx);
|
|
998
1006
|
} });
|
|
999
1007
|
Object.assign(config.git, reset);
|
|
1000
1008
|
};
|
|
@@ -1002,13 +1010,12 @@ const runGitPrompts = async (ctx, config) => {
|
|
|
1002
1010
|
//#endregion
|
|
1003
1011
|
//#region src/github/prompts.ts
|
|
1004
1012
|
const runGithubPrompts = async (ctx, config) => {
|
|
1005
|
-
const { configFileExists: cfe, dryRun } = ctx;
|
|
1006
|
-
const { github: { release
|
|
1013
|
+
const { configFileExists: cfe, dryRun, github: { releaseName } } = ctx;
|
|
1014
|
+
const { github: { release } } = config;
|
|
1007
1015
|
const logs = [];
|
|
1008
|
-
const title = format(releaseName, ctx);
|
|
1009
1016
|
const shouldPrompt = (val) => isUndefined(val) || dryRun;
|
|
1010
1017
|
const res = await group({
|
|
1011
|
-
release: () => shouldPrompt(release) ? confirm({ message:
|
|
1018
|
+
release: () => shouldPrompt(release) ? confirm({ message: question(MSG.PROMPT.GITHUB_RELEASE(releaseName), "github") }) : (() => {
|
|
1012
1019
|
logs.push(yellow`github.release`);
|
|
1013
1020
|
return Promise.resolve(release);
|
|
1014
1021
|
})(),
|
|
@@ -1016,9 +1023,8 @@ const runGithubPrompts = async (ctx, config) => {
|
|
|
1016
1023
|
if (logs.length) msg("GITHUB", `Using ${cfe ? "user" : "default"} config: ${logs.join(", ")}`);
|
|
1017
1024
|
return Promise.resolve();
|
|
1018
1025
|
}
|
|
1019
|
-
}, { onCancel:
|
|
1020
|
-
|
|
1021
|
-
abortTask("Operation cancelled.");
|
|
1026
|
+
}, { onCancel: ({ results }) => {
|
|
1027
|
+
abortGroupPrompt(ctx);
|
|
1022
1028
|
} });
|
|
1023
1029
|
Object.assign(config.github, { release: res.release });
|
|
1024
1030
|
return res;
|
|
@@ -1033,7 +1039,7 @@ const runNpmPublishPrompts = async (ctx, config) => {
|
|
|
1033
1039
|
const target = `${name}@${next}`;
|
|
1034
1040
|
const shouldPrompt = (val) => isUndefined(val) || dryRun;
|
|
1035
1041
|
const res = await group({
|
|
1036
|
-
publish: () => shouldPrompt(publish) ? confirm({ message:
|
|
1042
|
+
publish: () => shouldPrompt(publish) ? confirm({ message: question(MSG.PROMPT.NPM_PUBLISH(target), "npm") }) : (() => {
|
|
1037
1043
|
logs.push(yellow`npm.publish`);
|
|
1038
1044
|
return Promise.resolve(publish);
|
|
1039
1045
|
})(),
|
|
@@ -1042,16 +1048,14 @@ const runNpmPublishPrompts = async (ctx, config) => {
|
|
|
1042
1048
|
return Promise.resolve();
|
|
1043
1049
|
}
|
|
1044
1050
|
}, { onCancel: async ({ results }) => {
|
|
1045
|
-
|
|
1046
|
-
abortTask("Operation cancelled.");
|
|
1051
|
+
abortGroupPrompt(ctx);
|
|
1047
1052
|
} });
|
|
1048
1053
|
Object.assign(config.npm, { publish: res.publish });
|
|
1049
1054
|
return res;
|
|
1050
1055
|
};
|
|
1051
1056
|
const runNpmOptPrompts = async (ctx, config) => {
|
|
1052
|
-
const res = await group({ otp: () => text({ message: MSG.PROMPT.NPM_OTP }) }, { onCancel:
|
|
1053
|
-
|
|
1054
|
-
abortTask("Operation cancelled.");
|
|
1057
|
+
const res = await group({ otp: () => text({ message: MSG.PROMPT.NPM_OTP }) }, { onCancel: ({ results }) => {
|
|
1058
|
+
abortGroupPrompt(ctx);
|
|
1055
1059
|
} });
|
|
1056
1060
|
Object.assign(ctx.npm, { otp: res.otp });
|
|
1057
1061
|
return res;
|
|
@@ -1059,22 +1063,17 @@ const runNpmOptPrompts = async (ctx, config) => {
|
|
|
1059
1063
|
|
|
1060
1064
|
//#endregion
|
|
1061
1065
|
//#region src/npm/publish.ts
|
|
1062
|
-
const DEFAULT_TAG = "latest";
|
|
1063
|
-
const DEFAULT_TAG_PRERELEASE = "next";
|
|
1064
|
-
const runNpm = (args) => {
|
|
1065
|
-
return execAsync(["npm", ...args].join(" "));
|
|
1066
|
-
};
|
|
1067
1066
|
const getRegistry = (publishConfig = {}) => {
|
|
1068
1067
|
return (publishConfig.registry ? [publishConfig.registry] : Object.keys(publishConfig).filter((key) => key.endsWith("registry")).map((key) => publishConfig[key]))[0];
|
|
1069
1068
|
};
|
|
1070
1069
|
const isRegistryUp = async (registry) => {
|
|
1071
|
-
return void 0 !== await runNpm(["ping", ...registry ? [
|
|
1070
|
+
return void 0 !== await runNpm(["ping", ...registry ? ["--registry", registry] : []]);
|
|
1072
1071
|
};
|
|
1073
1072
|
const isAuthenticated = (registry) => {
|
|
1074
|
-
return runNpm(["whoami", ...registry ? [
|
|
1073
|
+
return runNpm(["whoami", ...registry ? ["--registry", registry] : []]);
|
|
1075
1074
|
};
|
|
1076
1075
|
const getLatestRegistryVersion = (name, tag, registry) => {
|
|
1077
|
-
const registryArg = registry ? [
|
|
1076
|
+
const registryArg = registry ? ["--registry", registry] : [];
|
|
1078
1077
|
return runNpm([
|
|
1079
1078
|
"show",
|
|
1080
1079
|
`${name}@${tag}`,
|
|
@@ -1082,16 +1081,6 @@ const getLatestRegistryVersion = (name, tag, registry) => {
|
|
|
1082
1081
|
...registryArg
|
|
1083
1082
|
]);
|
|
1084
1083
|
};
|
|
1085
|
-
const getRegistryTags = async (name, registry) => {
|
|
1086
|
-
const res = await runNpm([
|
|
1087
|
-
"view",
|
|
1088
|
-
name,
|
|
1089
|
-
"dist-tags",
|
|
1090
|
-
"--json",
|
|
1091
|
-
...registry ? [`--registry ${registry}`] : []
|
|
1092
|
-
]);
|
|
1093
|
-
return Object.keys(JSON.parse(res || "{}"));
|
|
1094
|
-
};
|
|
1095
1084
|
const bump = (version, allowSameVersion, args = []) => {
|
|
1096
1085
|
allowSameVersion && args.push(`--allow-same-version`);
|
|
1097
1086
|
return runNpm([
|
|
@@ -1102,20 +1091,15 @@ const bump = (version, allowSameVersion, args = []) => {
|
|
|
1102
1091
|
...args
|
|
1103
1092
|
]);
|
|
1104
1093
|
};
|
|
1105
|
-
const
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
const { npm: { tag } } = config;
|
|
1110
|
-
const { pkg: { name, current } } = ctx;
|
|
1111
|
-
const { toPreRelease, preId } = parseVersion(current);
|
|
1112
|
-
if (!toPreRelease) return DEFAULT_TAG;
|
|
1113
|
-
else return tag || preId || await guessPreReleaseTag(name);
|
|
1094
|
+
const resolveTag = async (version) => {
|
|
1095
|
+
const { toPreRelease, preId } = parseVersion(version);
|
|
1096
|
+
if (!toPreRelease) return "latest";
|
|
1097
|
+
else return preId || "next";
|
|
1114
1098
|
};
|
|
1115
1099
|
const isCollaborator = async (ctx) => {
|
|
1116
|
-
const { name, publishConfig } = ctx
|
|
1100
|
+
const { pkg: { name, publishConfig }, npm: { username } } = ctx;
|
|
1117
1101
|
const registry = getRegistry(publishConfig);
|
|
1118
|
-
const registryArg = registry ? [
|
|
1102
|
+
const registryArg = registry ? ["--registry", registry] : [];
|
|
1119
1103
|
let npmVersion = await runNpm(["--version"]);
|
|
1120
1104
|
let accessCommand;
|
|
1121
1105
|
if (gt(npmVersion, "9.0.0")) accessCommand = [
|
|
@@ -1131,88 +1115,82 @@ const isCollaborator = async (ctx) => {
|
|
|
1131
1115
|
...registryArg
|
|
1132
1116
|
]);
|
|
1133
1117
|
if (res) {
|
|
1134
|
-
const permissions = JSON.parse(res ?? "{}")[
|
|
1118
|
+
const permissions = JSON.parse(res ?? "{}")[username];
|
|
1135
1119
|
return permissions && permissions.includes("write");
|
|
1136
1120
|
}
|
|
1137
|
-
log.error(`Unable to verify if user ${
|
|
1121
|
+
log.error(`Unable to verify if user ${username} is a collaborator for ${name}.`);
|
|
1138
1122
|
};
|
|
1139
1123
|
const getPackageUrl = (ctx) => {
|
|
1140
|
-
const { name } = ctx
|
|
1141
|
-
return
|
|
1142
|
-
"https://www.npmjs.com",
|
|
1143
|
-
"/package",
|
|
1144
|
-
name
|
|
1145
|
-
]);
|
|
1124
|
+
const { pkg: { name, next } } = ctx;
|
|
1125
|
+
return `https://www.npmjs.com/package/${name}/v/${next}`;
|
|
1146
1126
|
};
|
|
1147
1127
|
const npmCheck = async (ctx, config) => {
|
|
1148
|
-
const { pkg: { name, publishConfig }, npm: { username } } = ctx;
|
|
1128
|
+
const { pkg: { name, current, publishConfig }, npm: { username } } = ctx;
|
|
1129
|
+
const { npm: { skipChecks } } = config;
|
|
1149
1130
|
const registry = getRegistry(publishConfig);
|
|
1150
|
-
const tag = await resolveTag(
|
|
1131
|
+
const tag = await resolveTag(current);
|
|
1132
|
+
Object.assign(ctx.npm, { tag });
|
|
1133
|
+
if (skipChecks) return "";
|
|
1134
|
+
if (!await isRegistryUp()) throw new Error(MSG.ERROR.NPM_REGISTRY(registry));
|
|
1151
1135
|
const getUser = async () => {
|
|
1152
1136
|
const username$1 = await isAuthenticated(registry);
|
|
1153
1137
|
if (!username$1) return false;
|
|
1154
1138
|
Object.assign(ctx.npm, { username: username$1 });
|
|
1155
1139
|
return true;
|
|
1156
1140
|
};
|
|
1157
|
-
if (!await isRegistryUp()) throw new Error(MSG.ERROR.NPM_REGISTRY(registry));
|
|
1158
1141
|
if (!await getUser()) throw new Error(MSG.ERROR.NPM_AUTH);
|
|
1159
1142
|
const latestPublish = await getLatestRegistryVersion(name, tag, registry);
|
|
1160
1143
|
if (latestPublish) {
|
|
1161
1144
|
if (!await isCollaborator(ctx)) throw new Error(MSG.ERROR.NPM_USER(username, name));
|
|
1162
1145
|
}
|
|
1163
|
-
return dim(latestPublish ? `(latest is ${latestPublish})` : "(new publish)");
|
|
1146
|
+
return underline(dim(latestPublish ? `(latest is ${latestPublish})` : "(new publish)"));
|
|
1164
1147
|
};
|
|
1165
1148
|
const isOtpError = (err) => /one-time password|otp/i.test(err.message);
|
|
1166
1149
|
const publishNpm = async (ctx, config) => {
|
|
1167
|
-
const { dryRun, npm: { otp } } = ctx;
|
|
1168
|
-
const { npm: { publish,
|
|
1150
|
+
const { dryRun, npm: { otp, tag }, pkg: { publishConfig } } = ctx;
|
|
1151
|
+
const { npm: { publish, publishPath, pushArgs } } = config;
|
|
1152
|
+
const registry = getRegistry(publishConfig);
|
|
1169
1153
|
if (!publish) return;
|
|
1170
|
-
const
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1154
|
+
const otpArgs = otp ? ["--otp", otp] : [];
|
|
1155
|
+
const dryRunArg = dryRun ? ["--dry-run"] : [];
|
|
1156
|
+
const registryArg = registry ? ["--registry", registry] : [];
|
|
1157
|
+
return runNpm([
|
|
1158
|
+
"publish",
|
|
1159
|
+
publishPath,
|
|
1160
|
+
"--tag",
|
|
1161
|
+
tag,
|
|
1162
|
+
"--workspaces=false",
|
|
1163
|
+
...otpArgs,
|
|
1164
|
+
...pushArgs,
|
|
1165
|
+
...registryArg,
|
|
1166
|
+
...dryRunArg
|
|
1167
|
+
]);
|
|
1175
1168
|
};
|
|
1176
1169
|
|
|
1177
1170
|
//#endregion
|
|
1178
1171
|
//#region src/action.ts
|
|
1179
|
-
const info = (msg$1) => {
|
|
1180
|
-
console.log(`${rgb(33, 91, 184)(`ℹ`)} ${gray(msg$1)}`);
|
|
1181
|
-
};
|
|
1182
|
-
const success = (msg$1, dryRun) => {
|
|
1183
|
-
return `${(dryRun ? rgb(123, 115, 66) : green)("✔")} ${msg$1}`;
|
|
1184
|
-
};
|
|
1185
|
-
const runLifeCycleHook = async (hooks, key, dryRun) => {
|
|
1186
|
-
const handler = hooks[key];
|
|
1187
|
-
if (typeof handler === "function") {
|
|
1188
|
-
if (!dryRun) await handler();
|
|
1189
|
-
log.success(success(`${dim`run`} ${inspect(handler)}`, dryRun));
|
|
1190
|
-
return;
|
|
1191
|
-
}
|
|
1192
|
-
return Promise.allSettled(castArray(handler).map(async (hook) => {
|
|
1193
|
-
if (!dryRun) await execAsync(hook).catch(console.error);
|
|
1194
|
-
handler && log.success(success(hook.replace("echo", dim("echo")), dryRun));
|
|
1195
|
-
}));
|
|
1196
|
-
};
|
|
1197
1172
|
var Action = class {
|
|
1198
1173
|
async handle(cmdArgs, options) {
|
|
1199
|
-
const { version: cVersion, name: cName } = readJsonFile(join(__dirname
|
|
1174
|
+
const { version: cVersion, name: cName } = readJsonFile(join(__dirname, "../package.json"));
|
|
1200
1175
|
info(`${cName} ${dim(`v${cVersion}`)} `);
|
|
1201
1176
|
const { otp, ...others } = options;
|
|
1202
1177
|
const { showChangelog, showRelease, ci, dryRun } = Object.fromEntries(Object.entries(others).map(([k, v]) => [k, Boolean(v)]));
|
|
1178
|
+
process.env["dryRun"] = String(dryRun);
|
|
1203
1179
|
const { version: pkgVersion, private: pkgPrivate, name: pkgName, publishConfig = {} } = readJsonFile("package.json");
|
|
1204
1180
|
const nextVersion = inc(pkgVersion, cmdArgs) ?? "";
|
|
1205
1181
|
const local = await resolveConfig(process.cwd(), (path$1) => {
|
|
1206
|
-
info(`config file: ${underline(path$1)}`);
|
|
1182
|
+
info(`config file: ${underline(dim(path$1))}`);
|
|
1207
1183
|
});
|
|
1208
1184
|
const config = mergeConfig(createDefaultConfig(ci ? true : void 0), local);
|
|
1209
1185
|
const ctx = mergeConfig(createDefaultContext(), {
|
|
1210
1186
|
configFileExists: Object.keys(local).length > 0,
|
|
1211
1187
|
dryRun,
|
|
1188
|
+
showRelease,
|
|
1189
|
+
showChangelog,
|
|
1212
1190
|
npm: { otp: String(otp) },
|
|
1213
1191
|
increment: cmdArgs,
|
|
1214
1192
|
isIncrement: true,
|
|
1215
|
-
|
|
1193
|
+
isCI: [
|
|
1216
1194
|
ci,
|
|
1217
1195
|
showChangelog,
|
|
1218
1196
|
showRelease,
|
|
@@ -1224,14 +1202,25 @@ var Action = class {
|
|
|
1224
1202
|
isPrivate: pkgPrivate,
|
|
1225
1203
|
fromPreRelease: isPreRelease(pkgVersion),
|
|
1226
1204
|
current: pkgVersion,
|
|
1227
|
-
next:
|
|
1205
|
+
next: nextVersion,
|
|
1228
1206
|
toPreRelease: false,
|
|
1229
1207
|
publishConfig: { ...publishConfig }
|
|
1230
|
-
}
|
|
1208
|
+
},
|
|
1209
|
+
noNpm: pkgPrivate
|
|
1231
1210
|
});
|
|
1232
1211
|
console.log();
|
|
1233
1212
|
intro(MSG.INTRO(pkgName, dryRun));
|
|
1234
|
-
|
|
1213
|
+
await this.checkTask(ctx, config);
|
|
1214
|
+
await this.bumpTask(ctx, config);
|
|
1215
|
+
await this.changelogTask(ctx, config);
|
|
1216
|
+
await this.gitTask(ctx, config);
|
|
1217
|
+
await this.npmTask(ctx, config);
|
|
1218
|
+
await this.githubTask(ctx, config);
|
|
1219
|
+
if (dryRun) gitRollback$1(ctx);
|
|
1220
|
+
taskEnd(MSG.OUTRO(dryRun));
|
|
1221
|
+
}
|
|
1222
|
+
async checkTask(ctx, config) {
|
|
1223
|
+
const { noNpm, dryRun } = ctx;
|
|
1235
1224
|
await tasks([{
|
|
1236
1225
|
title: MSG.CHECK.GIT.CHECKING,
|
|
1237
1226
|
task: async () => {
|
|
@@ -1245,73 +1234,58 @@ var Action = class {
|
|
|
1245
1234
|
const msg$1 = await npmCheck(ctx, config);
|
|
1246
1235
|
const { pkg: { publishConfig: { registry } } } = ctx;
|
|
1247
1236
|
return success(MSG.CHECK.NPM.CHECKED(registry, msg$1), dryRun);
|
|
1248
|
-
}
|
|
1237
|
+
},
|
|
1238
|
+
enabled: !noNpm
|
|
1249
1239
|
}]).catch(abortOnError);
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
const { pkg: { next: next$1 } } = ctx;
|
|
1262
|
-
taskEnd(MSG.LOG.SHOW_VERSION(next$1));
|
|
1263
|
-
}
|
|
1264
|
-
}
|
|
1265
|
-
}
|
|
1266
|
-
{
|
|
1267
|
-
const logStr = await getLog(true, ctx.isIncrement);
|
|
1268
|
-
if (logStr) {
|
|
1269
|
-
msg("GIT", `Changelog:${eol(2)}` + dim(logStr));
|
|
1270
|
-
if (showChangelog) taskEnd(MSG.LOG.SHOW_CHANGELOG);
|
|
1271
|
-
} else msg("GIT", MSG.LOG.CHANGELOG_EMPTY);
|
|
1272
|
-
}
|
|
1273
|
-
{
|
|
1274
|
-
const { pkg: { next }, isIncrement } = ctx;
|
|
1275
|
-
if (!next && isIncrement) await runVersionPrompts(ctx, config);
|
|
1276
|
-
await runLifeCycleHook(hooks, "before:bump", dryRun);
|
|
1277
|
-
await tasks([{
|
|
1278
|
-
title: MSG.TASK.VERSION.START,
|
|
1279
|
-
task: async () => {
|
|
1280
|
-
const { pkg: { next: next$1 }, isIncrement: isIncrement$1 } = ctx;
|
|
1281
|
-
await bump(next$1, isIncrement$1);
|
|
1282
|
-
await resolveTag$1(ctx, config);
|
|
1283
|
-
await updateChangelog(await generateChangelog(ctx));
|
|
1284
|
-
return success(MSG.TASK.VERSION.END(next$1), dryRun);
|
|
1285
|
-
}
|
|
1286
|
-
}]).catch(abortOnError);
|
|
1287
|
-
await runLifeCycleHook(hooks, "after:bump", dryRun);
|
|
1288
|
-
}
|
|
1289
|
-
{
|
|
1290
|
-
const changeset = await getStatus();
|
|
1291
|
-
if (changeset) msg("GIT", `Changes:${eol(2)}` + coloredChangeset(changeset));
|
|
1292
|
-
else msg("GIT", MSG.LOG.CHANGES_EMPTY);
|
|
1240
|
+
}
|
|
1241
|
+
async bumpTask(ctx, config) {
|
|
1242
|
+
const { pkg: { current }, dryRun, isCI, showRelease, showChangelog } = ctx;
|
|
1243
|
+
const { hooks } = config;
|
|
1244
|
+
const need = (ctx$1) => {
|
|
1245
|
+
const { pkg: { next: next$1 }, isIncrement: isIncrement$1 } = ctx$1;
|
|
1246
|
+
return !next$1 && isIncrement$1;
|
|
1247
|
+
};
|
|
1248
|
+
if (need(ctx)) {
|
|
1249
|
+
const parsed = parseVersion(isCI && getCIVersion(current) || (await runVersionPrompts(ctx, config)).next);
|
|
1250
|
+
Object.assign(ctx.pkg, { ...parsed });
|
|
1293
1251
|
}
|
|
1294
|
-
{
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
await runNpmOptPrompts(ctx, config);
|
|
1305
|
-
await publishNpm(ctx, config);
|
|
1306
|
-
} else throw err;
|
|
1307
|
-
});
|
|
1308
|
-
const url = getPackageUrl(ctx);
|
|
1309
|
-
return success(MSG.TASK.NPM.END + `: ${url}`, dryRun);
|
|
1310
|
-
}
|
|
1311
|
-
}]).catch(abortOnError);
|
|
1312
|
-
await runLifeCycleHook(hooks, "after:publish", dryRun);
|
|
1252
|
+
const { pkg: { next }, isIncrement } = ctx;
|
|
1253
|
+
if (showRelease) taskEnd(MSG.LOG.SHOW_VERSION(next));
|
|
1254
|
+
await runLifeCycleHook(hooks, "before:bump", dryRun);
|
|
1255
|
+
await tasks([{
|
|
1256
|
+
title: MSG.TASK.VERSION.START,
|
|
1257
|
+
task: async () => {
|
|
1258
|
+
await bump(next, isIncrement);
|
|
1259
|
+
await formatTemplate(ctx, config);
|
|
1260
|
+
const to = `(${current}...${diff(current, next)})`;
|
|
1261
|
+
return success(MSG.TASK.VERSION.END(to), dryRun);
|
|
1313
1262
|
}
|
|
1314
|
-
}
|
|
1263
|
+
}]).catch((err) => abortOnError(err, ctx));
|
|
1264
|
+
await runLifeCycleHook(hooks, "after:bump", dryRun);
|
|
1265
|
+
const logStr = (await getLog(true, isIncrement))?.split("\n").filter((line) => /^(\*\s+)?(\w+):\s(.+)\s\((\w{7})\)$/.test(line)).join("\n");
|
|
1266
|
+
if (logStr) {
|
|
1267
|
+
msg("GIT", `Changelog:${eol(2)}` + dim(logStr));
|
|
1268
|
+
if (showChangelog) taskEnd(MSG.LOG.SHOW_CHANGELOG);
|
|
1269
|
+
} else msg("GIT", MSG.LOG.CHANGELOG_EMPTY);
|
|
1270
|
+
const changeset = await getStatus();
|
|
1271
|
+
if (changeset) msg("GIT", `Changes:${eol(2)}` + coloredChangeset(changeset));
|
|
1272
|
+
else msg("GIT", MSG.LOG.CHANGES_EMPTY);
|
|
1273
|
+
}
|
|
1274
|
+
async changelogTask(ctx, config) {
|
|
1275
|
+
const { isIncrement, dryRun } = ctx;
|
|
1276
|
+
await tasks([{
|
|
1277
|
+
title: MSG.TASK.CHANGELOG.START,
|
|
1278
|
+
task: async () => {
|
|
1279
|
+
await writeChangelog(ctx, config);
|
|
1280
|
+
return success(MSG.TASK.CHANGELOG.END, dryRun);
|
|
1281
|
+
},
|
|
1282
|
+
enabled: isIncrement
|
|
1283
|
+
}]).catch((err) => abortOnError(err, ctx));
|
|
1284
|
+
}
|
|
1285
|
+
async gitTask(ctx, config) {
|
|
1286
|
+
const { noGit, dryRun } = ctx;
|
|
1287
|
+
const { hooks } = config;
|
|
1288
|
+
if (noGit) return;
|
|
1315
1289
|
await runGitPrompts(ctx, config);
|
|
1316
1290
|
await runLifeCycleHook(hooks, "before:push", dryRun);
|
|
1317
1291
|
await tasks([{
|
|
@@ -1320,8 +1294,34 @@ var Action = class {
|
|
|
1320
1294
|
await commitAndTag(ctx, config);
|
|
1321
1295
|
return success(MSG.TASK.GIT.END, dryRun);
|
|
1322
1296
|
}
|
|
1323
|
-
}]).catch(abortOnError);
|
|
1297
|
+
}]).catch((err) => abortOnError(err, ctx));
|
|
1324
1298
|
await runLifeCycleHook(hooks, "after:push", dryRun);
|
|
1299
|
+
}
|
|
1300
|
+
async npmTask(ctx, config) {
|
|
1301
|
+
const { noNpm, dryRun, isCI } = ctx;
|
|
1302
|
+
const { hooks } = config;
|
|
1303
|
+
if (noNpm) return;
|
|
1304
|
+
await runNpmPublishPrompts(ctx, config);
|
|
1305
|
+
await runLifeCycleHook(hooks, "before:publish", dryRun);
|
|
1306
|
+
await tasks([{
|
|
1307
|
+
title: MSG.TASK.NPM.START,
|
|
1308
|
+
task: async () => {
|
|
1309
|
+
await publishNpm(ctx, config).catch(async (err) => {
|
|
1310
|
+
if (isOtpError(err) && !isCI) {
|
|
1311
|
+
await runNpmOptPrompts(ctx, config);
|
|
1312
|
+
await publishNpm(ctx, config);
|
|
1313
|
+
} else throw err;
|
|
1314
|
+
});
|
|
1315
|
+
const url = getPackageUrl(ctx);
|
|
1316
|
+
return success(MSG.TASK.NPM.END(url), dryRun);
|
|
1317
|
+
}
|
|
1318
|
+
}]).catch((err) => abortOnError(err, ctx));
|
|
1319
|
+
await runLifeCycleHook(hooks, "after:publish", dryRun);
|
|
1320
|
+
}
|
|
1321
|
+
async githubTask(ctx, config) {
|
|
1322
|
+
const { noGitHub, dryRun } = ctx;
|
|
1323
|
+
const { hooks } = config;
|
|
1324
|
+
if (noGitHub) return;
|
|
1325
1325
|
await runGithubPrompts(ctx, config);
|
|
1326
1326
|
await runLifeCycleHook(hooks, "before:release", dryRun);
|
|
1327
1327
|
await tasks([{
|
|
@@ -1329,12 +1329,10 @@ var Action = class {
|
|
|
1329
1329
|
task: async () => {
|
|
1330
1330
|
await createRelease(ctx, config);
|
|
1331
1331
|
const url = getGithubReleaseUrl(ctx);
|
|
1332
|
-
return success(MSG.TASK.GITHUB.END
|
|
1332
|
+
return success(MSG.TASK.GITHUB.END(url), dryRun);
|
|
1333
1333
|
}
|
|
1334
|
-
}]).catch(abortOnError);
|
|
1334
|
+
}]).catch((err) => abortOnError(err, ctx));
|
|
1335
1335
|
await runLifeCycleHook(hooks, "after:release", dryRun);
|
|
1336
|
-
if (dryRun) await gitRollback(ctx);
|
|
1337
|
-
taskEnd(MSG.OUTRO(dryRun));
|
|
1338
1336
|
}
|
|
1339
1337
|
};
|
|
1340
1338
|
|