@peiyanlu/release 0.0.2 → 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 -621
- package/dist/index.cjs +3 -4
- package/dist/index.d.cts +120 -3
- package/dist/index.d.mts +120 -3
- package/dist/index.mjs +3 -3
- package/package.json +4 -6
package/dist/cli.mjs
CHANGED
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
import path, {
|
|
1
|
+
import path, { join, resolve } from "node:path";
|
|
2
2
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
3
3
|
import { eol, execAsync, isGitRepo, parseGitHubRepo, readJsonFile, runGit, runNpm } from "@peiyanlu/cli-utils";
|
|
4
|
-
import {
|
|
4
|
+
import { dim, gray, green, red, rgb, underline, yellow } from "ansis";
|
|
5
5
|
import { program } from "commander";
|
|
6
6
|
import { cancel, confirm, group, intro, isCancel, log, outro, select, tasks, text } from "@clack/prompts";
|
|
7
7
|
import { clean, coerce, gt, gte, inc, parse, prerelease, valid } from "semver";
|
|
8
|
+
import { castArray, isPlainObject, isUndefined } from "@peiyanlu/ts-utils";
|
|
8
9
|
import { createReadStream, existsSync, statSync } from "node:fs";
|
|
9
|
-
import {
|
|
10
|
+
import { spawnSync } from "node:child_process";
|
|
11
|
+
import { inspect, styleText } from "node:util";
|
|
10
12
|
import { Octokit } from "@octokit/rest";
|
|
11
13
|
import { contentType } from "mime-types";
|
|
12
14
|
import open from "open";
|
|
13
15
|
import { glob } from "tinyglobby";
|
|
14
|
-
import {
|
|
15
|
-
import { castArray, isUndefined } from "@peiyanlu/ts-utils";
|
|
16
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
16
17
|
|
|
17
18
|
//#region node_modules/.pnpm/tsdown@0.18.4_typescript@5.9.3/node_modules/tsdown/esm-shims.js
|
|
18
19
|
const getFilename = () => fileURLToPath(import.meta.url);
|
|
19
20
|
const getDirname = () => path.dirname(getFilename());
|
|
20
|
-
const __dirname
|
|
21
|
+
const __dirname = /* @__PURE__ */ getDirname();
|
|
21
22
|
|
|
22
23
|
//#endregion
|
|
23
24
|
//#region src/config.ts
|
|
@@ -46,9 +47,7 @@ const resolveConfig = async (cwd, log$1) => {
|
|
|
46
47
|
log$1?.(configFile);
|
|
47
48
|
return loadConfig(configFile);
|
|
48
49
|
};
|
|
49
|
-
const
|
|
50
|
-
const isPlainObject = (v) => toString(v) === "[object Object]";
|
|
51
|
-
const isFunction = (v) => toString(v) === "[object Function]";
|
|
50
|
+
const isFunction = (v) => typeof v === "function";
|
|
52
51
|
const mergeConfig = (defaults, overrides) => {
|
|
53
52
|
if (!overrides) return structuredClone(defaults);
|
|
54
53
|
if (Object.keys(defaults).length === 0) return structuredClone(overrides);
|
|
@@ -67,15 +66,11 @@ const mergeConfig = (defaults, overrides) => {
|
|
|
67
66
|
|
|
68
67
|
//#endregion
|
|
69
68
|
//#region src/messages.ts
|
|
70
|
-
const n = (b) =>
|
|
71
|
-
|
|
72
|
-
};
|
|
73
|
-
const t = () => {
|
|
74
|
-
return green(Math.floor(process.uptime()));
|
|
75
|
-
};
|
|
69
|
+
const n = (b) => b ? "(dry run)" : "";
|
|
70
|
+
const t = () => green(`${Math.floor(process.uptime())}s`);
|
|
76
71
|
const MSG = {
|
|
77
72
|
INTRO: (pkgName, dryRun) => `🚀 Starting release ${yellow(pkgName)} ${n(dryRun)}`,
|
|
78
|
-
OUTRO: (dryRun) => `🎉 Release finished successfully in ${t()}
|
|
73
|
+
OUTRO: (dryRun) => `🎉 Release finished successfully in ${t()} ${n(dryRun)}.`,
|
|
79
74
|
LOG: {
|
|
80
75
|
SHOW_VERSION: (version) => `🎉 Released ${green(version)}`,
|
|
81
76
|
SHOW_CHANGELOG: "🎉 Changelog collected",
|
|
@@ -95,11 +90,15 @@ const MSG = {
|
|
|
95
90
|
TASK: {
|
|
96
91
|
VERSION: {
|
|
97
92
|
START: "Bumping version",
|
|
98
|
-
END: (
|
|
93
|
+
END: (to) => `Version bumped: ${underline(dim(to))}`
|
|
94
|
+
},
|
|
95
|
+
CHANGELOG: {
|
|
96
|
+
START: "Generating changelog",
|
|
97
|
+
END: `Changelog generated`
|
|
99
98
|
},
|
|
100
99
|
NPM: {
|
|
101
100
|
START: "Publishing npm package",
|
|
102
|
-
END:
|
|
101
|
+
END: (url) => `NPM package published: ${underline(dim(url))}`
|
|
103
102
|
},
|
|
104
103
|
GIT: {
|
|
105
104
|
START: "Creating git commit, tag & push",
|
|
@@ -107,7 +106,7 @@ const MSG = {
|
|
|
107
106
|
},
|
|
108
107
|
GITHUB: {
|
|
109
108
|
START: "Creating GitHub release",
|
|
110
|
-
END:
|
|
109
|
+
END: (url) => `GitHub release created: ${underline(dim(url))}`
|
|
111
110
|
}
|
|
112
111
|
},
|
|
113
112
|
PROMPT: {
|
|
@@ -121,6 +120,7 @@ const MSG = {
|
|
|
121
120
|
GIT_PUSH: "Push commits and tags to remote?"
|
|
122
121
|
},
|
|
123
122
|
ERROR: {
|
|
123
|
+
GIT_WORKDIR: `[git] Working dir must be clean`,
|
|
124
124
|
GIT_REGISTRY: (name) => `[git] Repository not found for ${dim(name)}`,
|
|
125
125
|
GIT_REMOTE: (name) => `[git] Remote "${dim(name)}" not found`,
|
|
126
126
|
GITHUB_TAG_EXIT: (tag) => `[github] Release or tag "${tag}" already exists`,
|
|
@@ -134,322 +134,152 @@ const MSG = {
|
|
|
134
134
|
};
|
|
135
135
|
|
|
136
136
|
//#endregion
|
|
137
|
-
//#region src/
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
process.exit(0);
|
|
141
|
-
};
|
|
142
|
-
const abortOnCancel = (value) => {
|
|
143
|
-
if (isCancel(value)) abortTask("Operation cancelled.");
|
|
144
|
-
};
|
|
145
|
-
const abortOnError = (err) => {
|
|
146
|
-
const msg$1 = err.message.replace(/^\[(github|npm|git)]/, (a) => red(a));
|
|
147
|
-
log.message(`\n${msg$1}\n`);
|
|
148
|
-
process.exit(1);
|
|
149
|
-
};
|
|
150
|
-
const taskEnd = (msg$1) => {
|
|
151
|
-
outro(msg$1);
|
|
152
|
-
process.exit(0);
|
|
153
|
-
};
|
|
154
|
-
const msg = (prefix, msg$1) => {
|
|
155
|
-
log.message(gray`${rgb(33, 91, 184)(`[${prefix}]`)} ${msg$1}`);
|
|
156
|
-
};
|
|
157
|
-
const prompt = (msg$1) => {
|
|
158
|
-
return `${blue`?`} ${msg$1}`;
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
//#endregion
|
|
162
|
-
//#region src/version/bump.ts
|
|
163
|
-
const isPreRelease = (version) => {
|
|
164
|
-
return Boolean(prerelease(version));
|
|
165
|
-
};
|
|
166
|
-
const isValid = (version) => {
|
|
167
|
-
return Boolean(valid(version));
|
|
168
|
-
};
|
|
169
|
-
const parseVersion = (raw) => {
|
|
170
|
-
const next = isValid(raw) ? raw : coerce(raw)?.toString();
|
|
171
|
-
if (!next) return {};
|
|
172
|
-
const { prerelease: prerelease$1 } = parse(next);
|
|
173
|
-
const toPreRelease = Boolean(prerelease$1.length);
|
|
174
|
-
const [preId, preBase] = prerelease$1.map(String);
|
|
175
|
-
return {
|
|
176
|
-
next,
|
|
177
|
-
toPreRelease,
|
|
178
|
-
preId,
|
|
179
|
-
preBase
|
|
180
|
-
};
|
|
181
|
-
};
|
|
182
|
-
const getCIVersion = (current) => {
|
|
183
|
-
return inc(current, Release.PATCH);
|
|
137
|
+
//#region src/github/release.ts
|
|
138
|
+
const getGithubUrl = (owner, repo) => {
|
|
139
|
+
return `https://github.com/${owner}/${repo}`;
|
|
184
140
|
};
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
let Release = /* @__PURE__ */ function(Release$1) {
|
|
189
|
-
Release$1["MAJOR"] = "major";
|
|
190
|
-
Release$1["MINOR"] = "minor";
|
|
191
|
-
Release$1["PATCH"] = "patch";
|
|
192
|
-
return Release$1;
|
|
193
|
-
}({});
|
|
194
|
-
let PreRelease = /* @__PURE__ */ function(PreRelease$1) {
|
|
195
|
-
PreRelease$1["MAJOR"] = "premajor";
|
|
196
|
-
PreRelease$1["MINOR"] = "preminor";
|
|
197
|
-
PreRelease$1["PATCH"] = "prepatch";
|
|
198
|
-
PreRelease$1["RELEASE"] = "prerelease";
|
|
199
|
-
return PreRelease$1;
|
|
200
|
-
}({});
|
|
201
|
-
let PreId = /* @__PURE__ */ function(PreId$1) {
|
|
202
|
-
PreId$1["ALPHA"] = "alpha";
|
|
203
|
-
PreId$1["BETA"] = "beta";
|
|
204
|
-
PreId$1["RC"] = "rc";
|
|
205
|
-
PreId$1["NET"] = "next";
|
|
206
|
-
PreId$1["CANARY"] = "canary";
|
|
207
|
-
PreId$1["NIGHT"] = "nightly";
|
|
208
|
-
PreId$1["DEV"] = "dev";
|
|
209
|
-
return PreId$1;
|
|
210
|
-
}({});
|
|
211
|
-
const diff = (from, to) => {
|
|
212
|
-
const a = from.split(".");
|
|
213
|
-
return to.split(".").map((v, i) => v === a[i] ? dim(v) : green(v)).join(".");
|
|
141
|
+
const truncateBody = (body) => {
|
|
142
|
+
if (body && body.length >= 124e3) return body.substring(0, 124e3) + "...";
|
|
143
|
+
return body;
|
|
214
144
|
};
|
|
215
|
-
const
|
|
216
|
-
const {
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
label: "Pre-Patch",
|
|
233
|
-
value: prepatch,
|
|
234
|
-
hint: prepatch
|
|
235
|
-
},
|
|
236
|
-
{
|
|
237
|
-
label: "Pre-Minor",
|
|
238
|
-
value: preminor,
|
|
239
|
-
hint: preminor
|
|
240
|
-
},
|
|
241
|
-
{
|
|
242
|
-
label: "Pre-Major",
|
|
243
|
-
value: premajor,
|
|
244
|
-
hint: premajor
|
|
245
|
-
}
|
|
246
|
-
];
|
|
247
|
-
const release = [
|
|
248
|
-
{
|
|
249
|
-
label: "Patch",
|
|
250
|
-
value: patch,
|
|
251
|
-
hint: patch
|
|
252
|
-
},
|
|
253
|
-
{
|
|
254
|
-
label: "Minor",
|
|
255
|
-
value: minor,
|
|
256
|
-
hint: minor
|
|
257
|
-
},
|
|
258
|
-
{
|
|
259
|
-
label: "Major",
|
|
260
|
-
value: major,
|
|
261
|
-
hint: major
|
|
262
|
-
}
|
|
263
|
-
];
|
|
264
|
-
const custom = [{
|
|
265
|
-
label: "As-Is",
|
|
266
|
-
value: "ignore",
|
|
267
|
-
hint: current
|
|
268
|
-
}, {
|
|
269
|
-
label: "Custom",
|
|
270
|
-
value: "custom",
|
|
271
|
-
hint: "custom specified"
|
|
272
|
-
}];
|
|
273
|
-
const version = await select({
|
|
274
|
-
message: prompt(MSG.PROMPT.SELECT_VERSION),
|
|
275
|
-
options: [
|
|
276
|
-
...fromPreRelease ? pr : [],
|
|
277
|
-
...release,
|
|
278
|
-
...fromPreRelease ? [] : pre,
|
|
279
|
-
...custom
|
|
280
|
-
],
|
|
281
|
-
initialValue: fromPreRelease ? prerelease$1 : patch
|
|
282
|
-
});
|
|
283
|
-
abortOnCancel(version);
|
|
284
|
-
return version;
|
|
285
|
-
};
|
|
286
|
-
const inputVersion = async () => {
|
|
287
|
-
const version = await text({
|
|
288
|
-
message: prompt(MSG.PROMPT.INPUT_VERSION),
|
|
289
|
-
initialValue: current,
|
|
290
|
-
validate: (val) => {
|
|
291
|
-
if (!isValid(val)) return "Invalid version";
|
|
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
|
|
292
162
|
}
|
|
293
163
|
});
|
|
294
|
-
|
|
295
|
-
return version;
|
|
296
|
-
};
|
|
297
|
-
const type = await selectVersion();
|
|
298
|
-
const next = type === "custom" ? await inputVersion() : type === "ignore" ? current : type;
|
|
299
|
-
const parsed = parseVersion(next);
|
|
300
|
-
Object.assign(ctx.pkg, { ...parsed });
|
|
301
|
-
ctx.isIncrement = gte(next, current);
|
|
302
|
-
log.message(gray`from ${dim(current)}${eol()} to ${diff(current, next)}`);
|
|
303
|
-
return { next };
|
|
304
|
-
};
|
|
305
|
-
|
|
306
|
-
//#endregion
|
|
307
|
-
//#region src/defaults.ts
|
|
308
|
-
const createDefaultContext = () => {
|
|
309
|
-
return {
|
|
310
|
-
ci: false,
|
|
311
|
-
release: false,
|
|
312
|
-
dryRun: false,
|
|
313
|
-
changelog: false,
|
|
314
|
-
increment: "",
|
|
315
|
-
isIncrement: false,
|
|
316
|
-
configFileExists: false,
|
|
317
|
-
pkg: {
|
|
318
|
-
current: "",
|
|
319
|
-
next: "",
|
|
320
|
-
name: "",
|
|
321
|
-
isPrivate: false,
|
|
322
|
-
fromPreRelease: false,
|
|
323
|
-
toPreRelease: false,
|
|
324
|
-
publishConfig: {
|
|
325
|
-
access: "public",
|
|
326
|
-
registry: "https://registry.npmjs.org"
|
|
327
|
-
},
|
|
328
|
-
preId: PreId.BETA,
|
|
329
|
-
preBase: "0"
|
|
330
|
-
},
|
|
331
|
-
npm: {
|
|
332
|
-
username: "",
|
|
333
|
-
otp: ""
|
|
334
|
-
},
|
|
335
|
-
git: {
|
|
336
|
-
remoteName: "origin",
|
|
337
|
-
remoteUrl: "",
|
|
338
|
-
latestTag: "",
|
|
339
|
-
previousTag: "",
|
|
340
|
-
currentTag: "",
|
|
341
|
-
isCommitted: false,
|
|
342
|
-
isTagged: false
|
|
343
|
-
},
|
|
344
|
-
github: {
|
|
345
|
-
username: "",
|
|
346
|
-
repo: "",
|
|
347
|
-
changelog: "",
|
|
348
|
-
owner: "",
|
|
349
|
-
isWeb: false,
|
|
350
|
-
skipChecks: false,
|
|
351
|
-
isReleased: false,
|
|
352
|
-
releaseId: 0,
|
|
353
|
-
releaseUrl: "",
|
|
354
|
-
uploadUrl: "",
|
|
355
|
-
discussionUrl: "",
|
|
356
|
-
token: ""
|
|
357
|
-
}
|
|
358
|
-
};
|
|
164
|
+
}));
|
|
359
165
|
};
|
|
360
|
-
const
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
},
|
|
372
|
-
git: {
|
|
373
|
-
commit: isCI,
|
|
374
|
-
tag: isCI,
|
|
375
|
-
push: isCI,
|
|
376
|
-
commitMessage: "chore(release): ${version}",
|
|
377
|
-
tagMessage: "Release ${version}",
|
|
378
|
-
tagName: "${version}"
|
|
379
|
-
},
|
|
380
|
-
npm: {
|
|
381
|
-
publish: isCI,
|
|
382
|
-
tag: "",
|
|
383
|
-
allowSameVersion: false
|
|
384
|
-
},
|
|
385
|
-
github: {
|
|
386
|
-
release: isCI,
|
|
387
|
-
releaseName: "Release ${version}",
|
|
388
|
-
prerelease: false,
|
|
389
|
-
draft: false,
|
|
390
|
-
tokenRef: "GITHUB_TOKEN",
|
|
391
|
-
assets: []
|
|
392
|
-
}
|
|
393
|
-
};
|
|
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 });
|
|
394
177
|
};
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
const
|
|
399
|
-
|
|
400
|
-
const
|
|
401
|
-
|
|
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"
|
|
195
|
+
});
|
|
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
|
|
203
|
+
});
|
|
204
|
+
} catch (e) {
|
|
205
|
+
if (e?.status === 422) throw new Error(MSG.ERROR.GITHUB_TAG_EXIT(next));
|
|
206
|
+
throw e;
|
|
207
|
+
}
|
|
402
208
|
};
|
|
403
|
-
const
|
|
404
|
-
|
|
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
|
+
});
|
|
405
216
|
};
|
|
406
|
-
const
|
|
407
|
-
const
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
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);
|
|
245
|
+
}
|
|
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);
|
|
412
253
|
}
|
|
413
|
-
return Promise.allSettled(castArray(handler).filter(Boolean).map(async (hook) => {
|
|
414
|
-
if (!dryRun) await execAsync(hook, { shell: true }).catch(console.error);
|
|
415
|
-
log.success(success(hook.replace("echo", dim("echo")), dryRun));
|
|
416
|
-
}));
|
|
417
254
|
};
|
|
418
|
-
const
|
|
419
|
-
const {
|
|
420
|
-
return
|
|
255
|
+
const getGithubReleaseUrl = (ctx) => {
|
|
256
|
+
const { github: { owner, repo }, git: { currentTag } } = ctx;
|
|
257
|
+
return `${getGithubUrl(owner, repo)}/releases/tag/${normalizeTag(currentTag)}`;
|
|
421
258
|
};
|
|
422
259
|
|
|
423
260
|
//#endregion
|
|
424
261
|
//#region src/git/commit.ts
|
|
425
|
-
const runGitProxy = (...args) => {
|
|
426
|
-
if (process.env["dryRun"]) log.message(`${dim("$")} ${gray(["git", ...args[0]].join(" "))}`);
|
|
427
|
-
return runGit(...args);
|
|
428
|
-
};
|
|
429
262
|
const getBranchName = () => {
|
|
430
|
-
return
|
|
263
|
+
return runGit([
|
|
431
264
|
"rev-parse",
|
|
432
265
|
"--abbrev-ref",
|
|
433
266
|
"HEAD"
|
|
434
267
|
]);
|
|
435
268
|
};
|
|
436
269
|
const getRemoteForBranch = (branch) => {
|
|
437
|
-
return
|
|
270
|
+
return runGit([
|
|
438
271
|
"config",
|
|
439
272
|
"--get",
|
|
440
273
|
`branch.${branch}.remote`
|
|
441
274
|
]);
|
|
442
275
|
};
|
|
443
276
|
const getStatus = () => {
|
|
444
|
-
return
|
|
277
|
+
return runGit([
|
|
445
278
|
"status",
|
|
446
279
|
"--short",
|
|
447
280
|
"--untracked-files=no"
|
|
448
281
|
], { trim: false });
|
|
449
282
|
};
|
|
450
|
-
const gitRestore = () => {
|
|
451
|
-
return runGitProxy(["restore", "."]);
|
|
452
|
-
};
|
|
453
283
|
const coloredChangeset = (log$1) => {
|
|
454
284
|
const colorStatusChar = (ch) => {
|
|
455
285
|
switch (ch) {
|
|
@@ -471,11 +301,11 @@ const getRemote = async () => {
|
|
|
471
301
|
const remoteName = branch && await getRemoteForBranch(branch) || "origin";
|
|
472
302
|
return {
|
|
473
303
|
remoteName,
|
|
474
|
-
remoteUrl: await
|
|
304
|
+
remoteUrl: await runGit([
|
|
475
305
|
"remote",
|
|
476
306
|
"get-url",
|
|
477
307
|
remoteName
|
|
478
|
-
]).catch((_) =>
|
|
308
|
+
]).catch((_) => runGit([
|
|
479
309
|
"config",
|
|
480
310
|
"--get",
|
|
481
311
|
`remote.${remoteName}.url`
|
|
@@ -483,7 +313,7 @@ const getRemote = async () => {
|
|
|
483
313
|
};
|
|
484
314
|
};
|
|
485
315
|
const getLatestTag = async (match = "*", exclude = "*-beta.*") => {
|
|
486
|
-
return
|
|
316
|
+
return runGit([
|
|
487
317
|
"describe",
|
|
488
318
|
"--tags",
|
|
489
319
|
"--abbrev=0",
|
|
@@ -492,11 +322,11 @@ const getLatestTag = async (match = "*", exclude = "*-beta.*") => {
|
|
|
492
322
|
]);
|
|
493
323
|
};
|
|
494
324
|
const getPreviousTag = async (current) => {
|
|
495
|
-
return
|
|
325
|
+
return runGit([
|
|
496
326
|
"describe",
|
|
497
327
|
"--tags",
|
|
498
328
|
"--abbrev=0",
|
|
499
|
-
`${await
|
|
329
|
+
`${await runGit([
|
|
500
330
|
"rev-list",
|
|
501
331
|
"--tags",
|
|
502
332
|
current || "--skip=1",
|
|
@@ -524,98 +354,100 @@ const getLog = async (print, isIncrement) => {
|
|
|
524
354
|
const cmd = ["log", `--pretty=format:${print ? "* %s (%h)" : "%s %h %H"}`];
|
|
525
355
|
const { from, to } = await resolveChangelogRange(isIncrement);
|
|
526
356
|
if (from) cmd.push(`${from}...${to}`);
|
|
527
|
-
return
|
|
357
|
+
return runGit(cmd, { trim: false });
|
|
528
358
|
};
|
|
529
|
-
const
|
|
530
|
-
|
|
531
|
-
const { git: { tagName: tagTemplate } } = config;
|
|
532
|
-
const latestTag = await getLatestTag() ?? "";
|
|
533
|
-
const currentTag = format(tagTemplate || ((latestTag || "").match(/^v/) ? "v${version}" : "${version}"), ctx);
|
|
534
|
-
Object.assign(ctx.git, {
|
|
535
|
-
latestTag,
|
|
536
|
-
currentTag
|
|
537
|
-
});
|
|
538
|
-
return true;
|
|
539
|
-
};
|
|
540
|
-
const gitCheck = async (ctx, config) => {
|
|
541
|
-
const { pkg: { name } } = ctx;
|
|
542
|
-
if (!await isGitRepo()) throw new Error(MSG.ERROR.GIT_REGISTRY(name));
|
|
543
|
-
const { remoteName, remoteUrl } = await getRemote();
|
|
544
|
-
if (!remoteUrl) throw new Error(MSG.ERROR.GIT_REMOTE(name));
|
|
545
|
-
Object.assign(ctx.git, {
|
|
546
|
-
remoteName,
|
|
547
|
-
remoteUrl
|
|
548
|
-
});
|
|
549
|
-
parseGithubUrl(ctx);
|
|
359
|
+
const isWorkingDirClean = async () => {
|
|
360
|
+
return (await runGit(["status", "-s"]))?.length === 0;
|
|
550
361
|
};
|
|
551
362
|
const hasUpstreamBranch = async () => {
|
|
552
|
-
const branch = await
|
|
363
|
+
const branch = await runGit([
|
|
553
364
|
"for-each-ref",
|
|
554
365
|
"--format=%(upstream:short)",
|
|
555
|
-
await
|
|
366
|
+
await runGit(["symbolic-ref", "HEAD"])
|
|
556
367
|
]);
|
|
557
368
|
return Boolean(branch);
|
|
558
369
|
};
|
|
559
370
|
const getUpstreamArgs = async (remoteName) => {
|
|
560
371
|
const hasUpstream = await hasUpstreamBranch();
|
|
561
372
|
const branch = await getBranchName();
|
|
562
|
-
if (!hasUpstream) return
|
|
563
|
-
"--set-upstream",
|
|
564
|
-
remoteName,
|
|
565
|
-
branch
|
|
566
|
-
] : [
|
|
373
|
+
if (!hasUpstream) return [
|
|
567
374
|
"--set-upstream",
|
|
568
|
-
"origin",
|
|
375
|
+
remoteName || "origin",
|
|
569
376
|
branch
|
|
570
377
|
];
|
|
571
378
|
if (remoteName) return [remoteName];
|
|
572
379
|
return [];
|
|
573
380
|
};
|
|
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);
|
|
402
|
+
};
|
|
574
403
|
const commitAndTag = async (ctx, config) => {
|
|
575
|
-
const { git: { currentTag,
|
|
576
|
-
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;
|
|
577
406
|
if (!commit) return;
|
|
578
407
|
const args = dryRun ? ["--dry-run"] : [];
|
|
579
|
-
await
|
|
408
|
+
await runGit([
|
|
580
409
|
"add",
|
|
581
410
|
".",
|
|
582
|
-
"--all",
|
|
411
|
+
addUntrackedFiles ? "--all" : "--update",
|
|
583
412
|
...args
|
|
584
413
|
]);
|
|
585
|
-
await
|
|
414
|
+
await runGit([
|
|
586
415
|
"commit",
|
|
587
416
|
"--message",
|
|
588
|
-
|
|
417
|
+
commitMessage,
|
|
418
|
+
...commitArgs,
|
|
589
419
|
...args
|
|
590
420
|
]);
|
|
591
421
|
if (!dryRun) Object.assign(ctx.git, { isCommitted: true });
|
|
592
422
|
if (tag) {
|
|
593
|
-
await
|
|
423
|
+
await runGit([
|
|
594
424
|
"tag",
|
|
595
425
|
"--annotate",
|
|
596
426
|
"--message",
|
|
597
|
-
|
|
427
|
+
tagMessage,
|
|
598
428
|
currentTag,
|
|
429
|
+
...tagArgs,
|
|
599
430
|
...args
|
|
600
431
|
]);
|
|
601
432
|
if (!dryRun) Object.assign(ctx.git, { isTagged: true });
|
|
602
433
|
}
|
|
603
|
-
if (push) await
|
|
434
|
+
if (push) await runGit([
|
|
604
435
|
"push",
|
|
605
436
|
...await getUpstreamArgs(remoteName),
|
|
606
437
|
"--follow-tags",
|
|
438
|
+
...pushArgs,
|
|
607
439
|
...args
|
|
608
440
|
]);
|
|
609
441
|
};
|
|
610
|
-
const gitRollback =
|
|
442
|
+
const gitRollback$1 = (ctx) => {
|
|
611
443
|
const { git: { currentTag, isCommitted, isTagged } } = ctx;
|
|
612
|
-
|
|
613
|
-
if (isTagged)
|
|
444
|
+
spawnSync("git", ["restore", "."]);
|
|
445
|
+
if (isTagged) spawnSync("git", [
|
|
614
446
|
"tag",
|
|
615
447
|
"--delete",
|
|
616
448
|
currentTag
|
|
617
449
|
]);
|
|
618
|
-
|
|
450
|
+
spawnSync("git", [
|
|
619
451
|
"reset",
|
|
620
452
|
"--hard",
|
|
621
453
|
isCommitted ? "HEAD~1" : "HEAD"
|
|
@@ -623,123 +455,344 @@ const gitRollback = async (ctx) => {
|
|
|
623
455
|
};
|
|
624
456
|
|
|
625
457
|
//#endregion
|
|
626
|
-
//#region src/
|
|
627
|
-
const
|
|
628
|
-
|
|
458
|
+
//#region src/utils.ts
|
|
459
|
+
const info = (msg$1) => {
|
|
460
|
+
console.log(`${rgb(33, 91, 184)(`i`)} ${gray(msg$1)}`);
|
|
629
461
|
};
|
|
630
|
-
const
|
|
631
|
-
|
|
632
|
-
return body;
|
|
462
|
+
const msg = (prefix, msg$1) => {
|
|
463
|
+
log.message(gray`${rgb(33, 91, 184)(`[${prefix}]`)} ${msg$1}`);
|
|
633
464
|
};
|
|
634
|
-
const
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
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
|
|
651
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
|
|
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
|
|
652
665
|
});
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
const
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
url.searchParams.set("prelease", String(toPreRelease || prerelease$1));
|
|
664
|
-
const isWindows = process.platform === "win32";
|
|
665
|
-
await open(url.toString(), { wait: isWindows });
|
|
666
|
-
};
|
|
667
|
-
const createCiRelease = async (ctx, config) => {
|
|
668
|
-
const { pkg: { next, toPreRelease }, github: { owner, repo, token, changelog } } = ctx;
|
|
669
|
-
const { github: { prerelease: prerelease$1, releaseName, draft } } = config;
|
|
670
|
-
const octokit = new Octokit({ auth: token });
|
|
671
|
-
try {
|
|
672
|
-
const { data } = await octokit.repos.createRelease({
|
|
673
|
-
owner,
|
|
674
|
-
repo,
|
|
675
|
-
tag_name: next,
|
|
676
|
-
name: format(releaseName, ctx) ?? `Release ${next}`,
|
|
677
|
-
body: truncateBody(changelog),
|
|
678
|
-
draft: draft ?? false,
|
|
679
|
-
prerelease: (toPreRelease || prerelease$1) ?? false
|
|
680
|
-
});
|
|
681
|
-
const { html_url, upload_url, id, discussion_url } = data;
|
|
682
|
-
Object.assign(ctx.github, {
|
|
683
|
-
isReleased: true,
|
|
684
|
-
releaseId: id,
|
|
685
|
-
releaseUrl: html_url,
|
|
686
|
-
uploadUrl: upload_url,
|
|
687
|
-
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
|
+
}
|
|
688
676
|
});
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
const [owner, repo] = parseGitHubRepo(remoteUrl);
|
|
697
|
-
Object.assign(ctx.github, {
|
|
698
|
-
owner,
|
|
699
|
-
repo
|
|
700
|
-
});
|
|
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 };
|
|
701
684
|
};
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
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: ""
|
|
730
745
|
}
|
|
731
|
-
}
|
|
732
|
-
const { github: { isWeb }, dryRun } = ctx;
|
|
733
|
-
if (dryRun) return true;
|
|
734
|
-
if (isWeb) await createWebRelease(ctx, config);
|
|
735
|
-
else if (ci) {
|
|
736
|
-
await createCiRelease(ctx, config);
|
|
737
|
-
await uploadAssets(ctx, config);
|
|
738
|
-
}
|
|
746
|
+
};
|
|
739
747
|
};
|
|
740
|
-
const
|
|
741
|
-
|
|
742
|
-
|
|
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
|
+
};
|
|
743
796
|
};
|
|
744
797
|
|
|
745
798
|
//#endregion
|
|
@@ -836,6 +889,13 @@ const defaultTypes = [
|
|
|
836
889
|
description: "破坏性变更"
|
|
837
890
|
}
|
|
838
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
|
+
};
|
|
839
899
|
const findType = (type) => {
|
|
840
900
|
return defaultTypes.find((item) => item.type === type)?.section ?? type;
|
|
841
901
|
};
|
|
@@ -870,23 +930,20 @@ const classify = (commits) => {
|
|
|
870
930
|
return sections;
|
|
871
931
|
};
|
|
872
932
|
const renderChangelog = async (ctx, sections) => {
|
|
873
|
-
const {
|
|
933
|
+
const { github: { owner, repo }, git: { latestTag, currentTag } } = ctx;
|
|
874
934
|
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
875
935
|
const github = getGithubUrl(owner, repo);
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
md += eol(3);
|
|
888
|
-
}
|
|
889
|
-
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));
|
|
890
947
|
};
|
|
891
948
|
const generateChangelog = async (ctx) => {
|
|
892
949
|
const { isIncrement } = ctx;
|
|
@@ -896,36 +953,46 @@ const generateChangelog = async (ctx) => {
|
|
|
896
953
|
Object.assign(ctx.github, { changelog });
|
|
897
954
|
return changelog;
|
|
898
955
|
};
|
|
899
|
-
const updateChangelog = async (newContent) => {
|
|
900
|
-
const
|
|
901
|
-
const
|
|
902
|
-
|
|
903
|
-
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));
|
|
904
972
|
};
|
|
905
973
|
|
|
906
974
|
//#endregion
|
|
907
975
|
//#region src/git/prompts.ts
|
|
908
976
|
const runGitPrompts = async (ctx, config) => {
|
|
909
|
-
const { git: { currentTag }, configFileExists: cfe, dryRun } = ctx;
|
|
910
|
-
const { git: { commit, tag, push
|
|
977
|
+
const { git: { currentTag, commitMessage }, configFileExists: cfe, dryRun } = ctx;
|
|
978
|
+
const { git: { commit, tag, push } } = config;
|
|
911
979
|
const logs = [];
|
|
912
|
-
const cMsg = format(commitMessage, ctx);
|
|
913
980
|
const shouldPrompt = (val) => isUndefined(val) || dryRun;
|
|
914
981
|
const { log: _, ...reset } = await group({
|
|
915
982
|
commit: () => {
|
|
916
|
-
return shouldPrompt(commit) ? confirm({ message:
|
|
983
|
+
return shouldPrompt(commit) ? confirm({ message: question(MSG.PROMPT.GIT_COMMIT(commitMessage), "git") }) : (() => {
|
|
917
984
|
logs.push(yellow`git.commit`);
|
|
918
985
|
return Promise.resolve(commit);
|
|
919
986
|
})();
|
|
920
987
|
},
|
|
921
988
|
tag: () => {
|
|
922
|
-
return shouldPrompt(tag) ? confirm({ message:
|
|
989
|
+
return shouldPrompt(tag) ? confirm({ message: question(MSG.PROMPT.GIT_TAG(currentTag), "git") }) : (() => {
|
|
923
990
|
logs.push(yellow`git.tag`);
|
|
924
991
|
return Promise.resolve(tag);
|
|
925
992
|
})();
|
|
926
993
|
},
|
|
927
994
|
push: () => {
|
|
928
|
-
return shouldPrompt(push) ? confirm({ message:
|
|
995
|
+
return shouldPrompt(push) ? confirm({ message: question(MSG.PROMPT.GIT_PUSH, "git") }) : (() => {
|
|
929
996
|
logs.push(yellow`git.push`);
|
|
930
997
|
return Promise.resolve(push);
|
|
931
998
|
})();
|
|
@@ -934,9 +1001,8 @@ const runGitPrompts = async (ctx, config) => {
|
|
|
934
1001
|
if (logs.length) msg("GIT", `Using ${cfe ? "user" : "default"} config: ${logs.join(", ")}`);
|
|
935
1002
|
return Promise.resolve();
|
|
936
1003
|
}
|
|
937
|
-
}, { onCancel:
|
|
938
|
-
|
|
939
|
-
abortTask("Operation cancelled.");
|
|
1004
|
+
}, { onCancel: ({ results }) => {
|
|
1005
|
+
abortGroupPrompt(ctx);
|
|
940
1006
|
} });
|
|
941
1007
|
Object.assign(config.git, reset);
|
|
942
1008
|
};
|
|
@@ -944,13 +1010,12 @@ const runGitPrompts = async (ctx, config) => {
|
|
|
944
1010
|
//#endregion
|
|
945
1011
|
//#region src/github/prompts.ts
|
|
946
1012
|
const runGithubPrompts = async (ctx, config) => {
|
|
947
|
-
const { configFileExists: cfe, dryRun } = ctx;
|
|
948
|
-
const { github: { release
|
|
1013
|
+
const { configFileExists: cfe, dryRun, github: { releaseName } } = ctx;
|
|
1014
|
+
const { github: { release } } = config;
|
|
949
1015
|
const logs = [];
|
|
950
|
-
const title = format(releaseName, ctx);
|
|
951
1016
|
const shouldPrompt = (val) => isUndefined(val) || dryRun;
|
|
952
1017
|
const res = await group({
|
|
953
|
-
release: () => shouldPrompt(release) ? confirm({ message:
|
|
1018
|
+
release: () => shouldPrompt(release) ? confirm({ message: question(MSG.PROMPT.GITHUB_RELEASE(releaseName), "github") }) : (() => {
|
|
954
1019
|
logs.push(yellow`github.release`);
|
|
955
1020
|
return Promise.resolve(release);
|
|
956
1021
|
})(),
|
|
@@ -958,9 +1023,8 @@ const runGithubPrompts = async (ctx, config) => {
|
|
|
958
1023
|
if (logs.length) msg("GITHUB", `Using ${cfe ? "user" : "default"} config: ${logs.join(", ")}`);
|
|
959
1024
|
return Promise.resolve();
|
|
960
1025
|
}
|
|
961
|
-
}, { onCancel:
|
|
962
|
-
|
|
963
|
-
abortTask("Operation cancelled.");
|
|
1026
|
+
}, { onCancel: ({ results }) => {
|
|
1027
|
+
abortGroupPrompt(ctx);
|
|
964
1028
|
} });
|
|
965
1029
|
Object.assign(config.github, { release: res.release });
|
|
966
1030
|
return res;
|
|
@@ -975,7 +1039,7 @@ const runNpmPublishPrompts = async (ctx, config) => {
|
|
|
975
1039
|
const target = `${name}@${next}`;
|
|
976
1040
|
const shouldPrompt = (val) => isUndefined(val) || dryRun;
|
|
977
1041
|
const res = await group({
|
|
978
|
-
publish: () => shouldPrompt(publish) ? confirm({ message:
|
|
1042
|
+
publish: () => shouldPrompt(publish) ? confirm({ message: question(MSG.PROMPT.NPM_PUBLISH(target), "npm") }) : (() => {
|
|
979
1043
|
logs.push(yellow`npm.publish`);
|
|
980
1044
|
return Promise.resolve(publish);
|
|
981
1045
|
})(),
|
|
@@ -984,16 +1048,14 @@ const runNpmPublishPrompts = async (ctx, config) => {
|
|
|
984
1048
|
return Promise.resolve();
|
|
985
1049
|
}
|
|
986
1050
|
}, { onCancel: async ({ results }) => {
|
|
987
|
-
|
|
988
|
-
abortTask("Operation cancelled.");
|
|
1051
|
+
abortGroupPrompt(ctx);
|
|
989
1052
|
} });
|
|
990
1053
|
Object.assign(config.npm, { publish: res.publish });
|
|
991
1054
|
return res;
|
|
992
1055
|
};
|
|
993
1056
|
const runNpmOptPrompts = async (ctx, config) => {
|
|
994
|
-
const res = await group({ otp: () => text({ message: MSG.PROMPT.NPM_OTP }) }, { onCancel:
|
|
995
|
-
|
|
996
|
-
abortTask("Operation cancelled.");
|
|
1057
|
+
const res = await group({ otp: () => text({ message: MSG.PROMPT.NPM_OTP }) }, { onCancel: ({ results }) => {
|
|
1058
|
+
abortGroupPrompt(ctx);
|
|
997
1059
|
} });
|
|
998
1060
|
Object.assign(ctx.npm, { otp: res.otp });
|
|
999
1061
|
return res;
|
|
@@ -1001,43 +1063,27 @@ const runNpmOptPrompts = async (ctx, config) => {
|
|
|
1001
1063
|
|
|
1002
1064
|
//#endregion
|
|
1003
1065
|
//#region src/npm/publish.ts
|
|
1004
|
-
const runNpmProxy = (...args) => {
|
|
1005
|
-
if (process.env["dryRun"]) log.message(`${dim("$")} ${gray(["npm", ...args[0]].join(" "))}`);
|
|
1006
|
-
return runNpm(...args);
|
|
1007
|
-
};
|
|
1008
|
-
const DEFAULT_TAG = "latest";
|
|
1009
|
-
const DEFAULT_TAG_PRERELEASE = "next";
|
|
1010
1066
|
const getRegistry = (publishConfig = {}) => {
|
|
1011
1067
|
return (publishConfig.registry ? [publishConfig.registry] : Object.keys(publishConfig).filter((key) => key.endsWith("registry")).map((key) => publishConfig[key]))[0];
|
|
1012
1068
|
};
|
|
1013
1069
|
const isRegistryUp = async (registry) => {
|
|
1014
|
-
return void 0 !== await
|
|
1070
|
+
return void 0 !== await runNpm(["ping", ...registry ? ["--registry", registry] : []]);
|
|
1015
1071
|
};
|
|
1016
1072
|
const isAuthenticated = (registry) => {
|
|
1017
|
-
return
|
|
1073
|
+
return runNpm(["whoami", ...registry ? ["--registry", registry] : []]);
|
|
1018
1074
|
};
|
|
1019
1075
|
const getLatestRegistryVersion = (name, tag, registry) => {
|
|
1020
|
-
const registryArg = registry ? [
|
|
1021
|
-
return
|
|
1076
|
+
const registryArg = registry ? ["--registry", registry] : [];
|
|
1077
|
+
return runNpm([
|
|
1022
1078
|
"show",
|
|
1023
1079
|
`${name}@${tag}`,
|
|
1024
1080
|
"version",
|
|
1025
1081
|
...registryArg
|
|
1026
1082
|
]);
|
|
1027
1083
|
};
|
|
1028
|
-
const getRegistryTags = async (name, registry) => {
|
|
1029
|
-
const res = await runNpmProxy([
|
|
1030
|
-
"view",
|
|
1031
|
-
name,
|
|
1032
|
-
"dist-tags",
|
|
1033
|
-
"--json",
|
|
1034
|
-
...registry ? [`--registry ${registry}`] : []
|
|
1035
|
-
]);
|
|
1036
|
-
return Object.keys(JSON.parse(res || "{}"));
|
|
1037
|
-
};
|
|
1038
1084
|
const bump = (version, allowSameVersion, args = []) => {
|
|
1039
1085
|
allowSameVersion && args.push(`--allow-same-version`);
|
|
1040
|
-
return
|
|
1086
|
+
return runNpm([
|
|
1041
1087
|
"version",
|
|
1042
1088
|
version,
|
|
1043
1089
|
"--no-git-tag-version",
|
|
@@ -1045,21 +1091,16 @@ const bump = (version, allowSameVersion, args = []) => {
|
|
|
1045
1091
|
...args
|
|
1046
1092
|
]);
|
|
1047
1093
|
};
|
|
1048
|
-
const
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
const { npm: { tag } } = config;
|
|
1053
|
-
const { pkg: { name, current } } = ctx;
|
|
1054
|
-
const { toPreRelease, preId } = parseVersion(current);
|
|
1055
|
-
if (!toPreRelease) return DEFAULT_TAG;
|
|
1056
|
-
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";
|
|
1057
1098
|
};
|
|
1058
1099
|
const isCollaborator = async (ctx) => {
|
|
1059
1100
|
const { pkg: { name, publishConfig }, npm: { username } } = ctx;
|
|
1060
1101
|
const registry = getRegistry(publishConfig);
|
|
1061
|
-
const registryArg = registry ? [
|
|
1062
|
-
let npmVersion = await
|
|
1102
|
+
const registryArg = registry ? ["--registry", registry] : [];
|
|
1103
|
+
let npmVersion = await runNpm(["--version"]);
|
|
1063
1104
|
let accessCommand;
|
|
1064
1105
|
if (gt(npmVersion, "9.0.0")) accessCommand = [
|
|
1065
1106
|
"access",
|
|
@@ -1068,7 +1109,7 @@ const isCollaborator = async (ctx) => {
|
|
|
1068
1109
|
"--json"
|
|
1069
1110
|
];
|
|
1070
1111
|
else accessCommand = ["access", "ls-collaborators"];
|
|
1071
|
-
const res = await
|
|
1112
|
+
const res = await runNpm([
|
|
1072
1113
|
...accessCommand,
|
|
1073
1114
|
name,
|
|
1074
1115
|
...registryArg
|
|
@@ -1084,40 +1125,53 @@ const getPackageUrl = (ctx) => {
|
|
|
1084
1125
|
return `https://www.npmjs.com/package/${name}/v/${next}`;
|
|
1085
1126
|
};
|
|
1086
1127
|
const npmCheck = async (ctx, config) => {
|
|
1087
|
-
const { pkg: { name, publishConfig }, npm: { username } } = ctx;
|
|
1128
|
+
const { pkg: { name, current, publishConfig }, npm: { username } } = ctx;
|
|
1129
|
+
const { npm: { skipChecks } } = config;
|
|
1088
1130
|
const registry = getRegistry(publishConfig);
|
|
1089
|
-
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));
|
|
1090
1135
|
const getUser = async () => {
|
|
1091
1136
|
const username$1 = await isAuthenticated(registry);
|
|
1092
1137
|
if (!username$1) return false;
|
|
1093
1138
|
Object.assign(ctx.npm, { username: username$1 });
|
|
1094
1139
|
return true;
|
|
1095
1140
|
};
|
|
1096
|
-
if (!await isRegistryUp()) throw new Error(MSG.ERROR.NPM_REGISTRY(registry));
|
|
1097
1141
|
if (!await getUser()) throw new Error(MSG.ERROR.NPM_AUTH);
|
|
1098
1142
|
const latestPublish = await getLatestRegistryVersion(name, tag, registry);
|
|
1099
1143
|
if (latestPublish) {
|
|
1100
1144
|
if (!await isCollaborator(ctx)) throw new Error(MSG.ERROR.NPM_USER(username, name));
|
|
1101
1145
|
}
|
|
1102
|
-
return dim(latestPublish ? `(latest is ${latestPublish})` : "(new publish)");
|
|
1146
|
+
return underline(dim(latestPublish ? `(latest is ${latestPublish})` : "(new publish)"));
|
|
1103
1147
|
};
|
|
1104
1148
|
const isOtpError = (err) => /one-time password|otp/i.test(err.message);
|
|
1105
1149
|
const publishNpm = async (ctx, config) => {
|
|
1106
|
-
const { dryRun, npm: { otp } } = ctx;
|
|
1107
|
-
const { npm: { publish,
|
|
1150
|
+
const { dryRun, npm: { otp, tag }, pkg: { publishConfig } } = ctx;
|
|
1151
|
+
const { npm: { publish, publishPath, pushArgs } } = config;
|
|
1152
|
+
const registry = getRegistry(publishConfig);
|
|
1108
1153
|
if (!publish) return;
|
|
1109
|
-
const
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
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
|
+
]);
|
|
1114
1168
|
};
|
|
1115
1169
|
|
|
1116
1170
|
//#endregion
|
|
1117
1171
|
//#region src/action.ts
|
|
1118
1172
|
var Action = class {
|
|
1119
1173
|
async handle(cmdArgs, options) {
|
|
1120
|
-
const { version: cVersion, name: cName } = readJsonFile(join(__dirname
|
|
1174
|
+
const { version: cVersion, name: cName } = readJsonFile(join(__dirname, "../package.json"));
|
|
1121
1175
|
info(`${cName} ${dim(`v${cVersion}`)} `);
|
|
1122
1176
|
const { otp, ...others } = options;
|
|
1123
1177
|
const { showChangelog, showRelease, ci, dryRun } = Object.fromEntries(Object.entries(others).map(([k, v]) => [k, Boolean(v)]));
|
|
@@ -1131,10 +1185,12 @@ var Action = class {
|
|
|
1131
1185
|
const ctx = mergeConfig(createDefaultContext(), {
|
|
1132
1186
|
configFileExists: Object.keys(local).length > 0,
|
|
1133
1187
|
dryRun,
|
|
1188
|
+
showRelease,
|
|
1189
|
+
showChangelog,
|
|
1134
1190
|
npm: { otp: String(otp) },
|
|
1135
1191
|
increment: cmdArgs,
|
|
1136
1192
|
isIncrement: true,
|
|
1137
|
-
|
|
1193
|
+
isCI: [
|
|
1138
1194
|
ci,
|
|
1139
1195
|
showChangelog,
|
|
1140
1196
|
showRelease,
|
|
@@ -1146,14 +1202,25 @@ var Action = class {
|
|
|
1146
1202
|
isPrivate: pkgPrivate,
|
|
1147
1203
|
fromPreRelease: isPreRelease(pkgVersion),
|
|
1148
1204
|
current: pkgVersion,
|
|
1149
|
-
next:
|
|
1205
|
+
next: nextVersion,
|
|
1150
1206
|
toPreRelease: false,
|
|
1151
1207
|
publishConfig: { ...publishConfig }
|
|
1152
|
-
}
|
|
1208
|
+
},
|
|
1209
|
+
noNpm: pkgPrivate
|
|
1153
1210
|
});
|
|
1154
1211
|
console.log();
|
|
1155
1212
|
intro(MSG.INTRO(pkgName, dryRun));
|
|
1156
|
-
|
|
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;
|
|
1157
1224
|
await tasks([{
|
|
1158
1225
|
title: MSG.CHECK.GIT.CHECKING,
|
|
1159
1226
|
task: async () => {
|
|
@@ -1167,73 +1234,58 @@ var Action = class {
|
|
|
1167
1234
|
const msg$1 = await npmCheck(ctx, config);
|
|
1168
1235
|
const { pkg: { publishConfig: { registry } } } = ctx;
|
|
1169
1236
|
return success(MSG.CHECK.NPM.CHECKED(registry, msg$1), dryRun);
|
|
1170
|
-
}
|
|
1237
|
+
},
|
|
1238
|
+
enabled: !noNpm
|
|
1171
1239
|
}]).catch(abortOnError);
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
const { pkg: { next: next$1 } } = ctx;
|
|
1184
|
-
taskEnd(MSG.LOG.SHOW_VERSION(next$1));
|
|
1185
|
-
}
|
|
1186
|
-
}
|
|
1187
|
-
}
|
|
1188
|
-
{
|
|
1189
|
-
const logStr = await getLog(true, ctx.isIncrement);
|
|
1190
|
-
if (logStr) {
|
|
1191
|
-
msg("GIT", `Changelog:${eol(2)}` + dim(logStr));
|
|
1192
|
-
if (showChangelog) taskEnd(MSG.LOG.SHOW_CHANGELOG);
|
|
1193
|
-
} else msg("GIT", MSG.LOG.CHANGELOG_EMPTY);
|
|
1194
|
-
}
|
|
1195
|
-
{
|
|
1196
|
-
const { pkg: { next }, isIncrement } = ctx;
|
|
1197
|
-
if (!next && isIncrement) await runVersionPrompts(ctx, config);
|
|
1198
|
-
await runLifeCycleHook(hooks, "before:bump", dryRun);
|
|
1199
|
-
await tasks([{
|
|
1200
|
-
title: MSG.TASK.VERSION.START,
|
|
1201
|
-
task: async () => {
|
|
1202
|
-
const { pkg: { next: next$1 }, isIncrement: isIncrement$1 } = ctx;
|
|
1203
|
-
await bump(next$1, isIncrement$1);
|
|
1204
|
-
await resolveTag$1(ctx, config);
|
|
1205
|
-
await updateChangelog(await generateChangelog(ctx));
|
|
1206
|
-
return success(MSG.TASK.VERSION.END(next$1), dryRun);
|
|
1207
|
-
}
|
|
1208
|
-
}]).catch(abortOnError);
|
|
1209
|
-
await runLifeCycleHook(hooks, "after:bump", dryRun);
|
|
1210
|
-
}
|
|
1211
|
-
{
|
|
1212
|
-
const changeset = await getStatus();
|
|
1213
|
-
if (changeset) msg("GIT", `Changes:${eol(2)}` + coloredChangeset(changeset));
|
|
1214
|
-
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 });
|
|
1215
1251
|
}
|
|
1216
|
-
{
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
await runNpmOptPrompts(ctx, config);
|
|
1227
|
-
await publishNpm(ctx, config);
|
|
1228
|
-
} else throw err;
|
|
1229
|
-
});
|
|
1230
|
-
const url = getPackageUrl(ctx);
|
|
1231
|
-
return success(MSG.TASK.NPM.END + `: ${url}`, dryRun);
|
|
1232
|
-
}
|
|
1233
|
-
}]).catch(abortOnError);
|
|
1234
|
-
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);
|
|
1235
1262
|
}
|
|
1236
|
-
}
|
|
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;
|
|
1237
1289
|
await runGitPrompts(ctx, config);
|
|
1238
1290
|
await runLifeCycleHook(hooks, "before:push", dryRun);
|
|
1239
1291
|
await tasks([{
|
|
@@ -1242,8 +1294,34 @@ var Action = class {
|
|
|
1242
1294
|
await commitAndTag(ctx, config);
|
|
1243
1295
|
return success(MSG.TASK.GIT.END, dryRun);
|
|
1244
1296
|
}
|
|
1245
|
-
}]).catch(abortOnError);
|
|
1297
|
+
}]).catch((err) => abortOnError(err, ctx));
|
|
1246
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;
|
|
1247
1325
|
await runGithubPrompts(ctx, config);
|
|
1248
1326
|
await runLifeCycleHook(hooks, "before:release", dryRun);
|
|
1249
1327
|
await tasks([{
|
|
@@ -1251,18 +1329,16 @@ var Action = class {
|
|
|
1251
1329
|
task: async () => {
|
|
1252
1330
|
await createRelease(ctx, config);
|
|
1253
1331
|
const url = getGithubReleaseUrl(ctx);
|
|
1254
|
-
return success(MSG.TASK.GITHUB.END
|
|
1332
|
+
return success(MSG.TASK.GITHUB.END(url), dryRun);
|
|
1255
1333
|
}
|
|
1256
|
-
}]).catch(abortOnError);
|
|
1334
|
+
}]).catch((err) => abortOnError(err, ctx));
|
|
1257
1335
|
await runLifeCycleHook(hooks, "after:release", dryRun);
|
|
1258
|
-
if (dryRun) await gitRollback(ctx);
|
|
1259
|
-
taskEnd(MSG.OUTRO(dryRun));
|
|
1260
1336
|
}
|
|
1261
1337
|
};
|
|
1262
1338
|
|
|
1263
1339
|
//#endregion
|
|
1264
1340
|
//#region src/cli.ts
|
|
1265
|
-
const pkg = readJsonFile(join(__dirname
|
|
1341
|
+
const pkg = readJsonFile(join(__dirname, "..", "package.json"));
|
|
1266
1342
|
program.name(pkg.name).description(pkg.description).version(pkg.version, "-v, --version", "Output the current version.").usage("[ARGUMENT] [OPTION]...").argument("[argument]", "patch|minor|major").option("-n, --dry-run", "Report actions that would be performed without writing out results.", false).option("--ci", "CI mode", false).option("--otp", "npm publish otp", "").option("--show-changelog", "Skip npm publish", false).option("--show-release", "Skip github release", false).action(async (argName, options) => {
|
|
1267
1343
|
await new Action().handle(argName, options);
|
|
1268
1344
|
}).helpOption("-h, --help", "Output usage information.").parse(process.argv);
|