@mznjs/mbump 2.0.0 → 2.0.1
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/CHANGELOG.md +6 -0
- package/package.json +1 -1
- package/dist/VersionManager-DSOVXsFt.js +0 -1118
- package/dist/VersionManager-DSOVXsFt.js.map +0 -1
- package/dist/chunk-Cl8Af3a2.js +0 -11
- package/dist/cli.d.ts +0 -9
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -547
- package/dist/cli.js.map +0 -1
- package/dist/index.d.ts +0 -265
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -52
- package/dist/index.js.map +0 -1
|
@@ -1,1118 +0,0 @@
|
|
|
1
|
-
import { __export } from "./chunk-Cl8Af3a2.js";
|
|
2
|
-
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
-
import { createRequire } from "node:module";
|
|
4
|
-
import { dirname, join, resolve } from "node:path";
|
|
5
|
-
import { consola } from "consola";
|
|
6
|
-
import ora from "ora";
|
|
7
|
-
import { execSync } from "node:child_process";
|
|
8
|
-
import process from "node:process";
|
|
9
|
-
import semver from "semver";
|
|
10
|
-
|
|
11
|
-
//#region src/utils/logger.ts
|
|
12
|
-
const logger = consola.create({ formatOptions: { date: false } });
|
|
13
|
-
function setLevel(level) {
|
|
14
|
-
logger.level = level === "debug" ? 4 : 3;
|
|
15
|
-
}
|
|
16
|
-
function debug(message) {
|
|
17
|
-
logger.debug(message);
|
|
18
|
-
}
|
|
19
|
-
function info(message) {
|
|
20
|
-
logger.info(message);
|
|
21
|
-
}
|
|
22
|
-
function success(message) {
|
|
23
|
-
logger.success(message);
|
|
24
|
-
}
|
|
25
|
-
function warn(message) {
|
|
26
|
-
logger.warn(message);
|
|
27
|
-
}
|
|
28
|
-
function error(message) {
|
|
29
|
-
logger.error(message);
|
|
30
|
-
}
|
|
31
|
-
function dryRun(message) {
|
|
32
|
-
logger.info(`[dry-run] ${message}`);
|
|
33
|
-
}
|
|
34
|
-
async function withSpinner(text, fn, options = {}) {
|
|
35
|
-
const spinner = ora(text).start();
|
|
36
|
-
try {
|
|
37
|
-
const result = await fn();
|
|
38
|
-
spinner.succeed(options.succeedText || text);
|
|
39
|
-
console.log();
|
|
40
|
-
return result;
|
|
41
|
-
} catch (error$1) {
|
|
42
|
-
spinner.fail(options.failText || text);
|
|
43
|
-
console.log();
|
|
44
|
-
throw error$1;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
var logger_default = {
|
|
48
|
-
setLevel,
|
|
49
|
-
debug,
|
|
50
|
-
info,
|
|
51
|
-
success,
|
|
52
|
-
warn,
|
|
53
|
-
error,
|
|
54
|
-
dryRun,
|
|
55
|
-
withSpinner
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
//#endregion
|
|
59
|
-
//#region src/config/schema.ts
|
|
60
|
-
const BASE_CONFIG = {
|
|
61
|
-
packagePaths: { default: "package.json" },
|
|
62
|
-
defaults: {
|
|
63
|
-
releaseType: "patch",
|
|
64
|
-
dryRun: false,
|
|
65
|
-
verbose: false,
|
|
66
|
-
allowUncommitted: false,
|
|
67
|
-
npm: false
|
|
68
|
-
},
|
|
69
|
-
git: {
|
|
70
|
-
commitMessage: "chore: bump version to {{newVersion}}",
|
|
71
|
-
push: true,
|
|
72
|
-
autoCommit: true,
|
|
73
|
-
tag: true,
|
|
74
|
-
tagPrefix: "v",
|
|
75
|
-
changelog: true
|
|
76
|
-
},
|
|
77
|
-
publish: {
|
|
78
|
-
command: "pnpm publish --access public --no-git-checks",
|
|
79
|
-
skipChecks: true
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
function isValidConfig(config) {
|
|
83
|
-
return config && config.packagePaths && typeof config.packagePaths === "object" && Object.keys(config.packagePaths).length > 0;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
//#endregion
|
|
87
|
-
//#region src/config/loader.ts
|
|
88
|
-
/**
|
|
89
|
-
* 配置缓存 - 避免重复读取和解析配置文件
|
|
90
|
-
* Key: 项目根目录的绝对路径
|
|
91
|
-
* Value: 配置对象
|
|
92
|
-
*/
|
|
93
|
-
const configCache = new Map();
|
|
94
|
-
/**
|
|
95
|
-
* 清除配置缓存
|
|
96
|
-
* @param rootDir 可选,指定要清除的项目目录,不传则清除所有缓存
|
|
97
|
-
*/
|
|
98
|
-
function clearConfigCache(rootDir) {
|
|
99
|
-
if (rootDir) {
|
|
100
|
-
const cacheKey = resolve(rootDir);
|
|
101
|
-
configCache.delete(cacheKey);
|
|
102
|
-
logger_default.debug(`已清除配置缓存: ${cacheKey}`);
|
|
103
|
-
} else {
|
|
104
|
-
configCache.clear();
|
|
105
|
-
logger_default.debug("已清除所有配置缓存");
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* 获取缓存的配置
|
|
110
|
-
* @param rootDir 项目根目录
|
|
111
|
-
* @returns 缓存的配置,如果不存在则返回 null
|
|
112
|
-
*/
|
|
113
|
-
function getCachedConfig(rootDir) {
|
|
114
|
-
const cacheKey = resolve(rootDir);
|
|
115
|
-
return configCache.get(cacheKey) || null;
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* 设置配置缓存
|
|
119
|
-
* @param rootDir 项目根目录
|
|
120
|
-
* @param config 配置对象
|
|
121
|
-
*/
|
|
122
|
-
function setCachedConfig(rootDir, config) {
|
|
123
|
-
const cacheKey = resolve(rootDir);
|
|
124
|
-
configCache.set(cacheKey, config);
|
|
125
|
-
logger_default.debug(`已缓存配置: ${cacheKey}`);
|
|
126
|
-
}
|
|
127
|
-
function removeJsoncComments(jsoncString) {
|
|
128
|
-
let cleanString = jsoncString.replace(/\/\/.*$/gm, "");
|
|
129
|
-
cleanString = cleanString.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
130
|
-
return cleanString;
|
|
131
|
-
}
|
|
132
|
-
function tryParseYaml(yamlString) {
|
|
133
|
-
try {
|
|
134
|
-
const result = {};
|
|
135
|
-
const lines = yamlString.split("\n");
|
|
136
|
-
for (let line of lines) {
|
|
137
|
-
const commentIndex = line.indexOf("#");
|
|
138
|
-
if (commentIndex !== -1) line = line.substring(0, commentIndex).trim();
|
|
139
|
-
line = line.trim();
|
|
140
|
-
if (line) {
|
|
141
|
-
const colonIndex = line.indexOf(":");
|
|
142
|
-
if (colonIndex > 0) {
|
|
143
|
-
const keyPath = line.substring(0, colonIndex).trim();
|
|
144
|
-
const valueStr = line.substring(colonIndex + 1).trim();
|
|
145
|
-
let value = valueStr;
|
|
146
|
-
if (value === "true") value = true;
|
|
147
|
-
else if (value === "false") value = false;
|
|
148
|
-
else if (value === "null") value = null;
|
|
149
|
-
else if (!Number.isNaN(Number(value)) && value !== "") value = Number(value);
|
|
150
|
-
else if (value.startsWith("{") || value.startsWith("[")) try {
|
|
151
|
-
value = JSON.parse(value);
|
|
152
|
-
} catch {}
|
|
153
|
-
if (keyPath.includes(".")) {
|
|
154
|
-
const parts = keyPath.split(".");
|
|
155
|
-
let current = result;
|
|
156
|
-
for (let i = 0; i < parts.length - 1; i++) {
|
|
157
|
-
const part = parts[i];
|
|
158
|
-
if (!current[part]) current[part] = {};
|
|
159
|
-
current = current[part];
|
|
160
|
-
}
|
|
161
|
-
current[parts[parts.length - 1]] = value;
|
|
162
|
-
} else result[keyPath] = value;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
return result;
|
|
167
|
-
} catch {
|
|
168
|
-
return null;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
function tryParseToml(tomlString) {
|
|
172
|
-
try {
|
|
173
|
-
const result = {};
|
|
174
|
-
const lines = tomlString.split("\n");
|
|
175
|
-
for (let line of lines) {
|
|
176
|
-
const commentIndex = line.indexOf("#");
|
|
177
|
-
if (commentIndex !== -1) line = line.substring(0, commentIndex).trim();
|
|
178
|
-
line = line.trim();
|
|
179
|
-
if (line) {
|
|
180
|
-
const equalsIndex = line.indexOf("=");
|
|
181
|
-
if (equalsIndex > 0) {
|
|
182
|
-
const keyPath = line.substring(0, equalsIndex).trim();
|
|
183
|
-
const valueStr = line.substring(equalsIndex + 1).trim();
|
|
184
|
-
let value = valueStr;
|
|
185
|
-
if (value.startsWith("\"") && value.endsWith("\"") || value.startsWith("'") && value.endsWith("'")) value = value.slice(1, -1);
|
|
186
|
-
if (value === "true") value = true;
|
|
187
|
-
else if (value === "false") value = false;
|
|
188
|
-
else if (value === "null") value = null;
|
|
189
|
-
else if (!Number.isNaN(Number(value)) && value !== "") value = Number(value);
|
|
190
|
-
else if (value.startsWith("{") || value.startsWith("[")) try {
|
|
191
|
-
value = JSON.parse(value);
|
|
192
|
-
} catch {}
|
|
193
|
-
if (keyPath.includes(".")) {
|
|
194
|
-
const parts = keyPath.split(".");
|
|
195
|
-
let current = result;
|
|
196
|
-
for (let i = 0; i < parts.length - 1; i++) {
|
|
197
|
-
const part = parts[i];
|
|
198
|
-
if (!current[part]) current[part] = {};
|
|
199
|
-
current = current[part];
|
|
200
|
-
}
|
|
201
|
-
current[parts[parts.length - 1]] = value;
|
|
202
|
-
} else result[keyPath] = value;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
return result;
|
|
207
|
-
} catch {
|
|
208
|
-
return null;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
const parsers = {
|
|
212
|
-
json: { parse(content, configPath) {
|
|
213
|
-
let jsonContent = content;
|
|
214
|
-
if (configPath.endsWith(".jsonc")) jsonContent = removeJsoncComments(content);
|
|
215
|
-
try {
|
|
216
|
-
const parsedConfig = JSON.parse(jsonContent);
|
|
217
|
-
if (configPath.includes("package.json")) return parsedConfig.mbump || parsedConfig.mvbump || parsedConfig.bump || null;
|
|
218
|
-
return parsedConfig;
|
|
219
|
-
} catch {
|
|
220
|
-
return null;
|
|
221
|
-
}
|
|
222
|
-
} },
|
|
223
|
-
yaml: { parse(content) {
|
|
224
|
-
return tryParseYaml(content);
|
|
225
|
-
} },
|
|
226
|
-
toml: { parse(content) {
|
|
227
|
-
return tryParseToml(content);
|
|
228
|
-
} },
|
|
229
|
-
js: { parse(_, configPath) {
|
|
230
|
-
try {
|
|
231
|
-
const require = createRequire(import.meta.url);
|
|
232
|
-
const jsModule = require(configPath);
|
|
233
|
-
return jsModule.default || jsModule;
|
|
234
|
-
} catch {
|
|
235
|
-
return null;
|
|
236
|
-
}
|
|
237
|
-
} }
|
|
238
|
-
};
|
|
239
|
-
function getFileExtension(path) {
|
|
240
|
-
const ext = path.split(".").pop()?.toLowerCase();
|
|
241
|
-
if (ext === "yml") return "yaml";
|
|
242
|
-
if (ext === "cjs" || ext === "mjs" || ext === "ts" || ext === "js") return "js";
|
|
243
|
-
if (ext === "jsonc") return "json";
|
|
244
|
-
return ext || "";
|
|
245
|
-
}
|
|
246
|
-
async function loadConfigAsyncImpl(rootDir) {
|
|
247
|
-
const configPaths = [
|
|
248
|
-
join(rootDir, ".mbump.config.ts"),
|
|
249
|
-
join(rootDir, ".zbump.config.ts"),
|
|
250
|
-
join(rootDir, ".mbump.config.mjs"),
|
|
251
|
-
join(rootDir, ".zbump.config.mjs"),
|
|
252
|
-
join(rootDir, ".mbump.config.js"),
|
|
253
|
-
join(rootDir, ".zbump.config.js"),
|
|
254
|
-
join(rootDir, ".mbump.config.cjs"),
|
|
255
|
-
join(rootDir, ".zbump.config.cjs"),
|
|
256
|
-
join(rootDir, ".mbump.config.json"),
|
|
257
|
-
join(rootDir, ".zbump.config.json"),
|
|
258
|
-
join(rootDir, ".mbump.config.jsonc"),
|
|
259
|
-
join(rootDir, ".zbump.config.jsonc"),
|
|
260
|
-
join(rootDir, ".mbump.config.yaml"),
|
|
261
|
-
join(rootDir, ".zbump.config.yaml"),
|
|
262
|
-
join(rootDir, ".mbump.config.yml"),
|
|
263
|
-
join(rootDir, ".zbump.config.yml"),
|
|
264
|
-
join(rootDir, ".mbump.config.toml"),
|
|
265
|
-
join(rootDir, ".zbump.config.toml"),
|
|
266
|
-
join(rootDir, "package.json")
|
|
267
|
-
];
|
|
268
|
-
for (const configPath of configPaths) try {
|
|
269
|
-
const ext = getFileExtension(configPath);
|
|
270
|
-
if (ext === "js") {
|
|
271
|
-
const absPath = resolve(rootDir, configPath);
|
|
272
|
-
let config;
|
|
273
|
-
try {
|
|
274
|
-
if (configPath.endsWith(".ts")) {
|
|
275
|
-
const require = createRequire(import.meta.url);
|
|
276
|
-
require("tsx");
|
|
277
|
-
const tsModule = require(absPath);
|
|
278
|
-
config = tsModule.default || tsModule;
|
|
279
|
-
} else if (configPath.endsWith(".mjs")) {
|
|
280
|
-
const jsModule = await import(`file://${absPath}`);
|
|
281
|
-
config = jsModule.default || jsModule;
|
|
282
|
-
} else if (configPath.endsWith(".js")) try {
|
|
283
|
-
const jsModule = await import(`file://${absPath}`);
|
|
284
|
-
config = jsModule.default || jsModule;
|
|
285
|
-
} catch {
|
|
286
|
-
const require = createRequire(import.meta.url);
|
|
287
|
-
const cjsModule = require(absPath);
|
|
288
|
-
config = cjsModule.default || cjsModule;
|
|
289
|
-
}
|
|
290
|
-
else if (configPath.endsWith(".cjs")) {
|
|
291
|
-
const require = createRequire(import.meta.url);
|
|
292
|
-
const cjsModule = require(absPath);
|
|
293
|
-
config = cjsModule.default || cjsModule;
|
|
294
|
-
}
|
|
295
|
-
if (typeof config === "function") config = config();
|
|
296
|
-
if (config && typeof config === "object") return {
|
|
297
|
-
config,
|
|
298
|
-
path: configPath
|
|
299
|
-
};
|
|
300
|
-
} catch {
|
|
301
|
-
continue;
|
|
302
|
-
}
|
|
303
|
-
} else {
|
|
304
|
-
const content = readFileSync(configPath, "utf8");
|
|
305
|
-
const parser = parsers[ext];
|
|
306
|
-
if (parser) {
|
|
307
|
-
const config = parser.parse(content, configPath);
|
|
308
|
-
if (config && typeof config === "object") return {
|
|
309
|
-
config,
|
|
310
|
-
path: configPath
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
} catch {
|
|
315
|
-
continue;
|
|
316
|
-
}
|
|
317
|
-
return {
|
|
318
|
-
config: {},
|
|
319
|
-
path: null
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
function loadConfigSyncImpl(rootDir) {
|
|
323
|
-
const configPaths = [
|
|
324
|
-
join(rootDir, ".mbump.config.cjs"),
|
|
325
|
-
join(rootDir, ".zbump.config.cjs"),
|
|
326
|
-
join(rootDir, ".mbump.config.json"),
|
|
327
|
-
join(rootDir, ".zbump.config.json"),
|
|
328
|
-
join(rootDir, ".mbump.config.jsonc"),
|
|
329
|
-
join(rootDir, ".zbump.config.jsonc"),
|
|
330
|
-
join(rootDir, ".mbump.config.yaml"),
|
|
331
|
-
join(rootDir, ".zbump.config.yaml"),
|
|
332
|
-
join(rootDir, ".mbump.config.yml"),
|
|
333
|
-
join(rootDir, ".zbump.config.yml"),
|
|
334
|
-
join(rootDir, ".mbump.config.toml"),
|
|
335
|
-
join(rootDir, ".zbump.config.toml"),
|
|
336
|
-
join(rootDir, ".mbump.config.js"),
|
|
337
|
-
join(rootDir, ".zbump.config.js"),
|
|
338
|
-
join(rootDir, "package.json")
|
|
339
|
-
];
|
|
340
|
-
for (const configPath of configPaths) try {
|
|
341
|
-
const ext = getFileExtension(configPath);
|
|
342
|
-
if (ext === "js") try {
|
|
343
|
-
const require = createRequire(import.meta.url);
|
|
344
|
-
const jsModule = require(configPath);
|
|
345
|
-
let config = jsModule.default || jsModule;
|
|
346
|
-
if (typeof config === "function") config = config();
|
|
347
|
-
if (config && typeof config === "object") return {
|
|
348
|
-
config,
|
|
349
|
-
path: configPath
|
|
350
|
-
};
|
|
351
|
-
} catch {
|
|
352
|
-
continue;
|
|
353
|
-
}
|
|
354
|
-
else {
|
|
355
|
-
const content = readFileSync(configPath, "utf8");
|
|
356
|
-
const parser = parsers[ext];
|
|
357
|
-
if (parser) {
|
|
358
|
-
const config = parser.parse(content, configPath);
|
|
359
|
-
if (config && typeof config === "object") return {
|
|
360
|
-
config,
|
|
361
|
-
path: configPath
|
|
362
|
-
};
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
} catch {
|
|
366
|
-
continue;
|
|
367
|
-
}
|
|
368
|
-
return {
|
|
369
|
-
config: {},
|
|
370
|
-
path: null
|
|
371
|
-
};
|
|
372
|
-
}
|
|
373
|
-
function mergeConfig(userConfig, rootDir) {
|
|
374
|
-
const userPackagePaths = userConfig?.packagePaths;
|
|
375
|
-
const hasUserPackagePaths = userPackagePaths && Object.keys(userPackagePaths).length > 0;
|
|
376
|
-
const mergedConfig = {
|
|
377
|
-
...BASE_CONFIG,
|
|
378
|
-
...userConfig || {},
|
|
379
|
-
packagePaths: hasUserPackagePaths ? {
|
|
380
|
-
...BASE_CONFIG.packagePaths,
|
|
381
|
-
...userPackagePaths
|
|
382
|
-
} : BASE_CONFIG.packagePaths,
|
|
383
|
-
defaults: {
|
|
384
|
-
...BASE_CONFIG.defaults,
|
|
385
|
-
...userConfig?.defaults || {}
|
|
386
|
-
},
|
|
387
|
-
git: {
|
|
388
|
-
...BASE_CONFIG.git,
|
|
389
|
-
...userConfig?.git || {}
|
|
390
|
-
},
|
|
391
|
-
publish: {
|
|
392
|
-
...BASE_CONFIG.publish,
|
|
393
|
-
...userConfig?.publish || {}
|
|
394
|
-
}
|
|
395
|
-
};
|
|
396
|
-
if (!isValidConfig(mergedConfig)) throw new Error("配置无效:未找到有效的包路径配置\n请创建配置文件并添加至少一个包路径,例如:\n```\npackagePaths: {\n components: 'packages/components/package.json',\n plugins: 'packages/plugins/package.json'\n}\n```");
|
|
397
|
-
const resolvedPackagePaths = {};
|
|
398
|
-
for (const [name, path] of Object.entries(mergedConfig.packagePaths)) if (path && typeof path === "string" && !path.startsWith("/") && !/^[a-z]:\\/i.test(path)) resolvedPackagePaths[name] = join(rootDir, path);
|
|
399
|
-
else resolvedPackagePaths[name] = path;
|
|
400
|
-
mergedConfig.packagePaths = resolvedPackagePaths;
|
|
401
|
-
return mergedConfig;
|
|
402
|
-
}
|
|
403
|
-
async function loadConfigAsync(rootDir) {
|
|
404
|
-
const cached = getCachedConfig(rootDir);
|
|
405
|
-
if (cached) {
|
|
406
|
-
logger_default.debug("使用缓存的配置");
|
|
407
|
-
return cached;
|
|
408
|
-
}
|
|
409
|
-
const { config: userConfig, path: usedConfigPath } = await loadConfigAsyncImpl(rootDir);
|
|
410
|
-
if (usedConfigPath) logger_default.success(`配置加载完成 (配置文件: ${usedConfigPath})`);
|
|
411
|
-
else logger_default.warn("未找到配置文件,将使用默认配置");
|
|
412
|
-
const mergedConfig = mergeConfig(userConfig, rootDir);
|
|
413
|
-
mergedConfig.usedConfigPath = usedConfigPath;
|
|
414
|
-
setCachedConfig(rootDir, mergedConfig);
|
|
415
|
-
return mergedConfig;
|
|
416
|
-
}
|
|
417
|
-
function loadConfig(rootDir) {
|
|
418
|
-
const cached = getCachedConfig(rootDir);
|
|
419
|
-
if (cached) {
|
|
420
|
-
logger_default.debug("使用缓存的配置");
|
|
421
|
-
return cached;
|
|
422
|
-
}
|
|
423
|
-
const { config: userConfig, path: usedConfigPath } = loadConfigSyncImpl(rootDir);
|
|
424
|
-
if (usedConfigPath) logger_default.success(`配置加载完成 (配置文件: ${usedConfigPath})`);
|
|
425
|
-
else logger_default.warn("未找到配置文件,将使用默认配置");
|
|
426
|
-
const mergedConfig = mergeConfig(userConfig, rootDir);
|
|
427
|
-
mergedConfig.usedConfigPath = usedConfigPath;
|
|
428
|
-
setCachedConfig(rootDir, mergedConfig);
|
|
429
|
-
return mergedConfig;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
//#endregion
|
|
433
|
-
//#region src/core/ChangelogManager.ts
|
|
434
|
-
const TYPE_CONFIG = {
|
|
435
|
-
feat: {
|
|
436
|
-
title: "🚀 新增功能",
|
|
437
|
-
emoji: "🚀",
|
|
438
|
-
color: "green"
|
|
439
|
-
},
|
|
440
|
-
feature: {
|
|
441
|
-
title: "🚀 新增功能",
|
|
442
|
-
emoji: "🚀",
|
|
443
|
-
color: "green"
|
|
444
|
-
},
|
|
445
|
-
fix: {
|
|
446
|
-
title: "🩹 缺陷修复",
|
|
447
|
-
emoji: "🩹",
|
|
448
|
-
color: "red"
|
|
449
|
-
},
|
|
450
|
-
bugfix: {
|
|
451
|
-
title: "🩹 缺陷修复",
|
|
452
|
-
emoji: "🩹",
|
|
453
|
-
color: "red"
|
|
454
|
-
},
|
|
455
|
-
perf: {
|
|
456
|
-
title: "🔥 性能优化",
|
|
457
|
-
emoji: "🔥",
|
|
458
|
-
color: "yellow"
|
|
459
|
-
},
|
|
460
|
-
performance: {
|
|
461
|
-
title: "🔥 性能优化",
|
|
462
|
-
emoji: "🔥",
|
|
463
|
-
color: "yellow"
|
|
464
|
-
},
|
|
465
|
-
refactor: {
|
|
466
|
-
title: "♻️ 代码重构",
|
|
467
|
-
emoji: "♻️",
|
|
468
|
-
color: "cyan"
|
|
469
|
-
},
|
|
470
|
-
docs: {
|
|
471
|
-
title: "📝 文档更新",
|
|
472
|
-
emoji: "📝",
|
|
473
|
-
color: "blue"
|
|
474
|
-
},
|
|
475
|
-
style: {
|
|
476
|
-
title: "💄 代码格式",
|
|
477
|
-
emoji: "💄",
|
|
478
|
-
color: "white"
|
|
479
|
-
},
|
|
480
|
-
chore: {
|
|
481
|
-
title: "🔧 工具变更",
|
|
482
|
-
emoji: "🔧",
|
|
483
|
-
color: "gray"
|
|
484
|
-
},
|
|
485
|
-
build: {
|
|
486
|
-
title: "📦 构建变更",
|
|
487
|
-
emoji: "📦",
|
|
488
|
-
color: "magenta"
|
|
489
|
-
},
|
|
490
|
-
ci: {
|
|
491
|
-
title: "👷 CI 变更",
|
|
492
|
-
emoji: "👷",
|
|
493
|
-
color: "cyan"
|
|
494
|
-
},
|
|
495
|
-
test: {
|
|
496
|
-
title: "✅ 测试更新",
|
|
497
|
-
emoji: "✅",
|
|
498
|
-
color: "green"
|
|
499
|
-
},
|
|
500
|
-
revert: {
|
|
501
|
-
title: "⏪ 回滚提交",
|
|
502
|
-
emoji: "⏪",
|
|
503
|
-
color: "red"
|
|
504
|
-
},
|
|
505
|
-
breaking: {
|
|
506
|
-
title: "💥 破坏性变更",
|
|
507
|
-
emoji: "💥",
|
|
508
|
-
color: "red"
|
|
509
|
-
},
|
|
510
|
-
break: {
|
|
511
|
-
title: "💥 破坏性变更",
|
|
512
|
-
emoji: "💥",
|
|
513
|
-
color: "red"
|
|
514
|
-
}
|
|
515
|
-
};
|
|
516
|
-
var ChangelogManager = class {
|
|
517
|
-
changelogPath;
|
|
518
|
-
constructor(rootDir) {
|
|
519
|
-
this.changelogPath = `${rootDir}/CHANGELOG.md`;
|
|
520
|
-
}
|
|
521
|
-
getTypeConfig(message) {
|
|
522
|
-
const match = message.match(/^(\w+)(?:\(([^)]+)\))?:\s*(.+)$/);
|
|
523
|
-
if (match) {
|
|
524
|
-
const [, type] = match;
|
|
525
|
-
return TYPE_CONFIG[type.toLowerCase()] || {
|
|
526
|
-
title: "📦 其他变更",
|
|
527
|
-
emoji: "📦",
|
|
528
|
-
color: "gray"
|
|
529
|
-
};
|
|
530
|
-
}
|
|
531
|
-
return {
|
|
532
|
-
title: "📦 其他变更",
|
|
533
|
-
emoji: "📦",
|
|
534
|
-
color: "gray"
|
|
535
|
-
};
|
|
536
|
-
}
|
|
537
|
-
formatFileNames(files) {
|
|
538
|
-
return files.map((f) => {
|
|
539
|
-
const parts = f.split("/");
|
|
540
|
-
return parts[parts.length - 1];
|
|
541
|
-
});
|
|
542
|
-
}
|
|
543
|
-
detectChangelogFormat(content) {
|
|
544
|
-
const lines = content.split("\n");
|
|
545
|
-
for (const line of lines) if (line.startsWith("## [") || line.startsWith("## Version")) return {
|
|
546
|
-
hasHeader: true,
|
|
547
|
-
titlePrefix: line.startsWith("## [") ? "## [" : "## ",
|
|
548
|
-
usesBrackets: line.startsWith("## ["),
|
|
549
|
-
sectionLevel: "###"
|
|
550
|
-
};
|
|
551
|
-
return {
|
|
552
|
-
hasHeader: false,
|
|
553
|
-
titlePrefix: "## [",
|
|
554
|
-
usesBrackets: true,
|
|
555
|
-
sectionLevel: "###"
|
|
556
|
-
};
|
|
557
|
-
}
|
|
558
|
-
async updateChangelog(newVersion, commits, packageName) {
|
|
559
|
-
const today = new Date().toISOString().split("T")[0];
|
|
560
|
-
const versionTitle = packageName ? `${packageName}@${newVersion}` : newVersion;
|
|
561
|
-
const categorized = {};
|
|
562
|
-
for (const { message, files } of commits) {
|
|
563
|
-
const typeConfig = this.getTypeConfig(message);
|
|
564
|
-
const typeKey = typeConfig.title;
|
|
565
|
-
if (!categorized[typeKey]) categorized[typeKey] = {
|
|
566
|
-
config: typeConfig,
|
|
567
|
-
items: []
|
|
568
|
-
};
|
|
569
|
-
const fileNames = this.formatFileNames(files);
|
|
570
|
-
const fileTag = fileNames.length > 0 ? ` (${fileNames.join(", ")})` : "";
|
|
571
|
-
categorized[typeKey].items.push({
|
|
572
|
-
message: message + fileTag,
|
|
573
|
-
files
|
|
574
|
-
});
|
|
575
|
-
}
|
|
576
|
-
if (!existsSync(this.changelogPath)) {
|
|
577
|
-
let content = `# 更新日志 (Changelog)\n\n本项目的所有重要变更都将记录在此文件中。\n\n格式遵循 [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\n本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/)。\n\n`;
|
|
578
|
-
content += `## [${versionTitle}] - ${today}\n\n`;
|
|
579
|
-
const sortedCategories$1 = Object.values(categorized).sort((a, b) => {
|
|
580
|
-
const order = [
|
|
581
|
-
"🚀",
|
|
582
|
-
"🩹",
|
|
583
|
-
"🔥",
|
|
584
|
-
"♻️",
|
|
585
|
-
"📝",
|
|
586
|
-
"💄",
|
|
587
|
-
"🔧",
|
|
588
|
-
"📦",
|
|
589
|
-
"👷",
|
|
590
|
-
"✅",
|
|
591
|
-
"⏪",
|
|
592
|
-
"💥"
|
|
593
|
-
];
|
|
594
|
-
return order.indexOf(a.config.emoji) - order.indexOf(b.config.emoji);
|
|
595
|
-
});
|
|
596
|
-
for (const category of sortedCategories$1) {
|
|
597
|
-
content += `${category.config.title}\n\n`;
|
|
598
|
-
for (const item of category.items) content += `- ${item.message}\n`;
|
|
599
|
-
content += "\n";
|
|
600
|
-
}
|
|
601
|
-
await writeFileSync(this.changelogPath, content, "utf-8");
|
|
602
|
-
return;
|
|
603
|
-
}
|
|
604
|
-
const existingContent = await readFileSync(this.changelogPath, "utf-8");
|
|
605
|
-
const format = this.detectChangelogFormat(existingContent);
|
|
606
|
-
let header;
|
|
607
|
-
if (format.usesBrackets) header = `${format.titlePrefix}${versionTitle}] - ${today}\n\n`;
|
|
608
|
-
else header = `${format.titlePrefix}${versionTitle} - ${today}\n\n`;
|
|
609
|
-
const sortedCategories = Object.values(categorized).sort((a, b) => {
|
|
610
|
-
const order = [
|
|
611
|
-
"🚀",
|
|
612
|
-
"🩹",
|
|
613
|
-
"🔥",
|
|
614
|
-
"♻️",
|
|
615
|
-
"📝",
|
|
616
|
-
"💄",
|
|
617
|
-
"🔧",
|
|
618
|
-
"📦",
|
|
619
|
-
"👷",
|
|
620
|
-
"✅",
|
|
621
|
-
"⏪",
|
|
622
|
-
"💥"
|
|
623
|
-
];
|
|
624
|
-
return order.indexOf(a.config.emoji) - order.indexOf(b.config.emoji);
|
|
625
|
-
});
|
|
626
|
-
for (const category of sortedCategories) {
|
|
627
|
-
header += `${category.config.title}\n\n`;
|
|
628
|
-
for (const item of category.items) header += `- ${item.message}\n`;
|
|
629
|
-
header += "\n";
|
|
630
|
-
}
|
|
631
|
-
if (commits.length === 0) header += `### 待补充\n\n`;
|
|
632
|
-
let newContent;
|
|
633
|
-
if (format.hasHeader) {
|
|
634
|
-
const firstVersionIndex = existingContent.search(/^##\s*\[?/m);
|
|
635
|
-
if (firstVersionIndex !== -1) newContent = existingContent.slice(0, firstVersionIndex) + header + existingContent.slice(firstVersionIndex);
|
|
636
|
-
else newContent = header + existingContent;
|
|
637
|
-
} else newContent = header + existingContent;
|
|
638
|
-
await writeFileSync(this.changelogPath, newContent, "utf-8");
|
|
639
|
-
}
|
|
640
|
-
};
|
|
641
|
-
|
|
642
|
-
//#endregion
|
|
643
|
-
//#region src/core/GitManager.ts
|
|
644
|
-
var GitManager = class {
|
|
645
|
-
rootDir;
|
|
646
|
-
constructor(rootDir) {
|
|
647
|
-
this.rootDir = rootDir;
|
|
648
|
-
}
|
|
649
|
-
hasUncommittedChanges() {
|
|
650
|
-
try {
|
|
651
|
-
const output = execSync("git status --porcelain", {
|
|
652
|
-
cwd: this.rootDir,
|
|
653
|
-
encoding: "utf8",
|
|
654
|
-
stdio: "pipe"
|
|
655
|
-
});
|
|
656
|
-
return output.trim() !== "";
|
|
657
|
-
} catch {
|
|
658
|
-
return false;
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
getLastTag() {
|
|
662
|
-
try {
|
|
663
|
-
const output = execSync("git describe --tags --abbrev=0", {
|
|
664
|
-
cwd: this.rootDir,
|
|
665
|
-
encoding: "utf8",
|
|
666
|
-
stdio: "pipe"
|
|
667
|
-
});
|
|
668
|
-
return output.trim() || null;
|
|
669
|
-
} catch {
|
|
670
|
-
return null;
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
getCommitsSinceLastTag() {
|
|
674
|
-
try {
|
|
675
|
-
const lastTag = this.getLastTag();
|
|
676
|
-
const range = lastTag ? `${lastTag}..HEAD` : "--max-count=50";
|
|
677
|
-
const output = execSync(`git log ${range} --format="COMMIT_START%n%s" --name-only`, {
|
|
678
|
-
cwd: this.rootDir,
|
|
679
|
-
encoding: "utf8",
|
|
680
|
-
stdio: "pipe"
|
|
681
|
-
});
|
|
682
|
-
const commits = [];
|
|
683
|
-
const blocks = output.split("COMMIT_START").filter(Boolean);
|
|
684
|
-
for (const block of blocks) {
|
|
685
|
-
const lines = block.trim().split("\n");
|
|
686
|
-
if (lines.length === 0) continue;
|
|
687
|
-
const messageLines = lines.filter((line) => line.trim());
|
|
688
|
-
if (messageLines.length === 0) continue;
|
|
689
|
-
const message = messageLines[0].trim();
|
|
690
|
-
const files = lines.slice(1).map((f) => f.trim()).filter((f) => f && !f.startsWith("COMMIT_START"));
|
|
691
|
-
commits.push({
|
|
692
|
-
message,
|
|
693
|
-
files
|
|
694
|
-
});
|
|
695
|
-
}
|
|
696
|
-
return commits;
|
|
697
|
-
} catch {
|
|
698
|
-
return [];
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
checkVersionExists(version, tagPrefix = "v") {
|
|
702
|
-
try {
|
|
703
|
-
execSync(`git rev-parse --verify ${tagPrefix}${version}`, {
|
|
704
|
-
cwd: this.rootDir,
|
|
705
|
-
stdio: "pipe"
|
|
706
|
-
});
|
|
707
|
-
return true;
|
|
708
|
-
} catch {
|
|
709
|
-
return false;
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
addFiles(files) {
|
|
713
|
-
try {
|
|
714
|
-
execSync(`git add ${files.join(" ")}`, {
|
|
715
|
-
cwd: this.rootDir,
|
|
716
|
-
stdio: "pipe"
|
|
717
|
-
});
|
|
718
|
-
} catch (error$1) {
|
|
719
|
-
throw new Error(`Git add failed: ${error$1.message}`);
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
commit(message) {
|
|
723
|
-
try {
|
|
724
|
-
execSync(`git commit -m "${message}"`, {
|
|
725
|
-
cwd: this.rootDir,
|
|
726
|
-
stdio: "pipe"
|
|
727
|
-
});
|
|
728
|
-
logger_default.debug(`Git commit: ${message}`);
|
|
729
|
-
} catch (error$1) {
|
|
730
|
-
throw new Error(`Git commit failed: ${error$1.message}`);
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
createTag(version, tagPrefix = "v") {
|
|
734
|
-
try {
|
|
735
|
-
const tagName = `${tagPrefix}${version}`;
|
|
736
|
-
execSync(`git tag -a ${tagName} -m "Release ${tagName}"`, {
|
|
737
|
-
cwd: this.rootDir,
|
|
738
|
-
stdio: "pipe"
|
|
739
|
-
});
|
|
740
|
-
logger_default.success(`已创建 tag: ${tagName}`);
|
|
741
|
-
} catch (error$1) {
|
|
742
|
-
throw new Error(`创建 Tag 失败: ${error$1.message}`);
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
push(includeTags = true) {
|
|
746
|
-
try {
|
|
747
|
-
execSync("git push", {
|
|
748
|
-
cwd: this.rootDir,
|
|
749
|
-
stdio: "pipe"
|
|
750
|
-
});
|
|
751
|
-
logger_default.debug("Git push");
|
|
752
|
-
if (includeTags) {
|
|
753
|
-
execSync("git push --tags", {
|
|
754
|
-
cwd: this.rootDir,
|
|
755
|
-
stdio: "pipe"
|
|
756
|
-
});
|
|
757
|
-
logger_default.success("已推送 tags");
|
|
758
|
-
}
|
|
759
|
-
} catch (error$1) {
|
|
760
|
-
throw new Error(`Git push failed: ${error$1.message}`);
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
commitAndPush(message, push = true, createTag = false, tagVersion, tagPrefix = "v") {
|
|
764
|
-
try {
|
|
765
|
-
execSync("git config --local core.autocrlf false", {
|
|
766
|
-
cwd: this.rootDir,
|
|
767
|
-
stdio: "ignore"
|
|
768
|
-
});
|
|
769
|
-
} catch {
|
|
770
|
-
logger_default.warn("Failed to set git config");
|
|
771
|
-
}
|
|
772
|
-
this.addFiles(["-u"]);
|
|
773
|
-
this.commit(message);
|
|
774
|
-
if (createTag && tagVersion) this.createTag(tagVersion, tagPrefix);
|
|
775
|
-
if (push) try {
|
|
776
|
-
this.push(createTag);
|
|
777
|
-
} catch (error$1) {
|
|
778
|
-
logger_default.warn(`Git push failed: ${error$1.message}`);
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
};
|
|
782
|
-
|
|
783
|
-
//#endregion
|
|
784
|
-
//#region src/utils/security.ts
|
|
785
|
-
var security_exports = {};
|
|
786
|
-
__export(security_exports, {
|
|
787
|
-
sanitizeFileName: () => sanitizeFileName,
|
|
788
|
-
validateCommand: () => validateCommand,
|
|
789
|
-
validatePath: () => validatePath
|
|
790
|
-
});
|
|
791
|
-
function validatePath(path, rootDir) {
|
|
792
|
-
const resolvedPath = resolve(path);
|
|
793
|
-
return resolvedPath.startsWith(rootDir);
|
|
794
|
-
}
|
|
795
|
-
function validateCommand(command) {
|
|
796
|
-
const dangerousPatterns = [
|
|
797
|
-
/;\s*[a-z0-9]/i,
|
|
798
|
-
/\|\|\s*[a-z0-9]/i,
|
|
799
|
-
/&&\s*[a-z0-9]/i,
|
|
800
|
-
/\$\(.*\)/,
|
|
801
|
-
/`.*`/,
|
|
802
|
-
/\|\s*[a-z0-9]/i
|
|
803
|
-
];
|
|
804
|
-
return !dangerousPatterns.some((pattern) => pattern.test(command));
|
|
805
|
-
}
|
|
806
|
-
function sanitizeFileName(name) {
|
|
807
|
-
return name.replace(/[<>:"/\\|?*]/g, "_");
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
//#endregion
|
|
811
|
-
//#region src/core/VersionManager.ts
|
|
812
|
-
var VersionManager = class {
|
|
813
|
-
config;
|
|
814
|
-
rootDir;
|
|
815
|
-
packagePaths;
|
|
816
|
-
publishConfig;
|
|
817
|
-
gitConfig;
|
|
818
|
-
gitPush;
|
|
819
|
-
packageCache = new Map();
|
|
820
|
-
gitManager;
|
|
821
|
-
changelogManager;
|
|
822
|
-
constructor(options = {}) {
|
|
823
|
-
const { packagePaths, configPath, config, rootDir = process.cwd() } = options;
|
|
824
|
-
this.config = config || (configPath ? loadConfig(dirname(configPath)) : loadConfig(rootDir));
|
|
825
|
-
this.rootDir = rootDir;
|
|
826
|
-
this.packagePaths = packagePaths || this.config.packagePaths;
|
|
827
|
-
this.publishConfig = this.config.publish || {};
|
|
828
|
-
this.gitConfig = this.config.git || {};
|
|
829
|
-
this.gitPush = this.gitConfig.push !== false;
|
|
830
|
-
this.gitManager = new GitManager(rootDir);
|
|
831
|
-
this.changelogManager = new ChangelogManager(rootDir);
|
|
832
|
-
if (!this.packagePaths || typeof this.packagePaths !== "object" || Object.keys(this.packagePaths).length === 0) throw new Error("配置错误:未找到有效的包路径配置");
|
|
833
|
-
this._resolvePackagePaths(rootDir);
|
|
834
|
-
this._preloadPackageCache();
|
|
835
|
-
}
|
|
836
|
-
/**
|
|
837
|
-
* 预加载所有包信息到缓存,避免后续重复读取文件
|
|
838
|
-
*/
|
|
839
|
-
_preloadPackageCache() {
|
|
840
|
-
for (const pkgPath of Object.values(this.packagePaths)) try {
|
|
841
|
-
this.getPackageInfo(pkgPath);
|
|
842
|
-
} catch (error$1) {
|
|
843
|
-
logger_default.debug(`预加载包信息失败 ${pkgPath}: ${error$1.message}`);
|
|
844
|
-
}
|
|
845
|
-
logger_default.debug(`已预加载 ${this.packageCache.size} 个包的信息到缓存`);
|
|
846
|
-
}
|
|
847
|
-
/**
|
|
848
|
-
* 清除包信息缓存
|
|
849
|
-
* @param pkgPath 可选,指定要清除的包路径,不传则清除所有缓存
|
|
850
|
-
*/
|
|
851
|
-
clearPackageCache(pkgPath) {
|
|
852
|
-
if (pkgPath) {
|
|
853
|
-
this.packageCache.delete(pkgPath);
|
|
854
|
-
logger_default.debug(`已清除包缓存: ${pkgPath}`);
|
|
855
|
-
} else {
|
|
856
|
-
this.packageCache.clear();
|
|
857
|
-
logger_default.debug("已清除所有包缓存");
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
/**
|
|
861
|
-
* 刷新指定包的缓存(重新从文件读取)
|
|
862
|
-
* @param pkgPath 包的路径
|
|
863
|
-
*/
|
|
864
|
-
refreshPackageCache(pkgPath) {
|
|
865
|
-
this.packageCache.delete(pkgPath);
|
|
866
|
-
return this.getPackageInfo(pkgPath);
|
|
867
|
-
}
|
|
868
|
-
/**
|
|
869
|
-
* 获取缓存统计信息
|
|
870
|
-
*/
|
|
871
|
-
getCacheStats() {
|
|
872
|
-
return {
|
|
873
|
-
size: this.packageCache.size,
|
|
874
|
-
packages: Array.from(this.packageCache.keys())
|
|
875
|
-
};
|
|
876
|
-
}
|
|
877
|
-
_resolvePackagePaths(rootDir) {
|
|
878
|
-
for (const [name, path] of Object.entries(this.packagePaths)) if (path && typeof path === "string" && !path.startsWith("/") && !/^[a-z]:\\/i.test(path)) this.packagePaths[name] = `${rootDir}/${path}`;
|
|
879
|
-
}
|
|
880
|
-
async updateVersion(pkgName, releaseType = "patch", options = {}) {
|
|
881
|
-
const { dryRun: dryRun$1 = false, verbose = false, packagePaths = this.packagePaths, customVersion = null, autoCommit = this.gitConfig.autoCommit !== false, npm = false, changelog = this.gitConfig.changelog !== false, tag = this.gitConfig.tag !== false, tagPrefix = this.gitConfig.tagPrefix || "v", isBatchMode = false } = options;
|
|
882
|
-
const result = {
|
|
883
|
-
success: false,
|
|
884
|
-
updatedPackages: [],
|
|
885
|
-
publishedPackages: [],
|
|
886
|
-
error: null
|
|
887
|
-
};
|
|
888
|
-
return logger_default.withSpinner(`正在更新${pkgName === "all" ? "所有包" : `包${pkgName}`}的版本...`, async () => {
|
|
889
|
-
try {
|
|
890
|
-
const targets = pkgName === "all" ? Object.values(packagePaths) : [packagePaths[pkgName]];
|
|
891
|
-
if (!targets.length || targets.some((path) => !path)) throw new Error(`无效的包名: ${pkgName}`);
|
|
892
|
-
let finalVersion = null;
|
|
893
|
-
for (const pkgPath of targets) {
|
|
894
|
-
const pkg = this.getPackageInfo(pkgPath);
|
|
895
|
-
let newVersion = null;
|
|
896
|
-
if (customVersion) {
|
|
897
|
-
if (!semver.valid(customVersion)) throw new Error(`无效的自定义版本号: ${customVersion}`);
|
|
898
|
-
newVersion = customVersion;
|
|
899
|
-
} else try {
|
|
900
|
-
switch (releaseType) {
|
|
901
|
-
case "major":
|
|
902
|
-
case "minor":
|
|
903
|
-
case "patch":
|
|
904
|
-
newVersion = semver.inc(pkg.version, releaseType);
|
|
905
|
-
break;
|
|
906
|
-
case "next":
|
|
907
|
-
newVersion = semver.inc(pkg.version, "patch");
|
|
908
|
-
break;
|
|
909
|
-
case "pre-patch":
|
|
910
|
-
if (semver.prerelease(pkg.version)) newVersion = semver.inc(pkg.version, "prerelease");
|
|
911
|
-
else newVersion = semver.inc(pkg.version, "prepatch", "beta");
|
|
912
|
-
break;
|
|
913
|
-
case "pre-minor":
|
|
914
|
-
if (semver.prerelease(pkg.version)) {
|
|
915
|
-
const currentMinor = semver.minor(pkg.version);
|
|
916
|
-
const potentialVersion = semver.inc(pkg.version, "preminor", "beta");
|
|
917
|
-
if (potentialVersion && semver.minor(potentialVersion) > currentMinor) newVersion = potentialVersion;
|
|
918
|
-
else newVersion = semver.inc(pkg.version, "prerelease");
|
|
919
|
-
} else newVersion = semver.inc(pkg.version, "preminor", "beta");
|
|
920
|
-
break;
|
|
921
|
-
case "pre-major":
|
|
922
|
-
if (semver.prerelease(pkg.version)) {
|
|
923
|
-
const currentMajor = semver.major(pkg.version);
|
|
924
|
-
const potentialVersion = semver.inc(pkg.version, "premajor", "beta");
|
|
925
|
-
if (potentialVersion && semver.major(potentialVersion) > currentMajor) newVersion = potentialVersion;
|
|
926
|
-
else newVersion = semver.inc(pkg.version, "prerelease");
|
|
927
|
-
} else newVersion = semver.inc(pkg.version, "premajor", "beta");
|
|
928
|
-
break;
|
|
929
|
-
case "as-is":
|
|
930
|
-
newVersion = pkg.version;
|
|
931
|
-
break;
|
|
932
|
-
case "conventional":
|
|
933
|
-
newVersion = semver.inc(pkg.version, "patch");
|
|
934
|
-
break;
|
|
935
|
-
default: throw new Error(`不支持的版本类型: ${releaseType}`);
|
|
936
|
-
}
|
|
937
|
-
} catch (error$1) {
|
|
938
|
-
throw new Error(`版本计算失败: ${error$1.message}`);
|
|
939
|
-
}
|
|
940
|
-
if (!newVersion) throw new Error(`无法计算新版本号,当前版本: ${pkg.version},类型: ${releaseType}`);
|
|
941
|
-
if (!finalVersion) {
|
|
942
|
-
finalVersion = newVersion;
|
|
943
|
-
if (!dryRun$1 && this.gitManager.checkVersionExists(newVersion, tagPrefix)) throw new Error(`版本 ${tagPrefix}${newVersion} 已存在,请使用其他版本`);
|
|
944
|
-
}
|
|
945
|
-
if (dryRun$1) logger_default.dryRun(`将更新 ${pkg.name} 从 v${pkg.version} 到 v${newVersion}`);
|
|
946
|
-
else {
|
|
947
|
-
const updatedPkg = {
|
|
948
|
-
...pkg,
|
|
949
|
-
version: newVersion
|
|
950
|
-
};
|
|
951
|
-
this.savePackageInfo(pkgPath, updatedPkg);
|
|
952
|
-
logger_default.info(`已更新 ${pkg.name} 到 v${newVersion}`);
|
|
953
|
-
}
|
|
954
|
-
result.updatedPackages.push({
|
|
955
|
-
name: pkg.name,
|
|
956
|
-
oldVersion: pkg.version,
|
|
957
|
-
newVersion
|
|
958
|
-
});
|
|
959
|
-
}
|
|
960
|
-
const isDefaultPackage = pkgName === "default" || this.config.packagePaths[pkgName] === "package.json";
|
|
961
|
-
if (!dryRun$1 && changelog && finalVersion) if (isBatchMode && !isDefaultPackage) logger_default.info(`子包 ${pkgName} 跳过 CHANGELOG 生成`);
|
|
962
|
-
else try {
|
|
963
|
-
const commits = this.gitManager.getCommitsSinceLastTag();
|
|
964
|
-
let packageName;
|
|
965
|
-
if (!isDefaultPackage) {
|
|
966
|
-
const firstPkg = this.getPackageInfo(targets[0]);
|
|
967
|
-
packageName = firstPkg.name;
|
|
968
|
-
}
|
|
969
|
-
await this.changelogManager.updateChangelog(finalVersion, commits, packageName);
|
|
970
|
-
logger_default.success("已更新 CHANGELOG.md");
|
|
971
|
-
} catch (changelogError) {
|
|
972
|
-
logger_default.warn(`CHANGELOG生成失败: ${changelogError.message}`);
|
|
973
|
-
}
|
|
974
|
-
if (!dryRun$1 && npm) for (const pkgPath of targets) {
|
|
975
|
-
const pkg = this.getPackageInfo(pkgPath);
|
|
976
|
-
const pkgDir = dirname(pkgPath);
|
|
977
|
-
logger_default.info(`\n发布 ${pkg.name}...`);
|
|
978
|
-
try {
|
|
979
|
-
const publishCmd = this.publishConfig.command || "pnpm publish --access public --no-git-checks";
|
|
980
|
-
if (!validateCommand(publishCmd)) throw new Error(`不安全的发布命令: ${publishCmd}`);
|
|
981
|
-
if (verbose) logger_default.debug(`执行命令: ${publishCmd} (在目录: ${pkgDir})`);
|
|
982
|
-
const { execSync: execSync$1 } = await import("node:child_process");
|
|
983
|
-
execSync$1(publishCmd, {
|
|
984
|
-
cwd: pkgDir,
|
|
985
|
-
stdio: "inherit"
|
|
986
|
-
});
|
|
987
|
-
result.publishedPackages.push(pkg.name);
|
|
988
|
-
} catch (e) {
|
|
989
|
-
throw new Error(`发布失败 ${pkg.name}: ${e.message}`);
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
if (!dryRun$1 && autoCommit && result.updatedPackages.length > 0) try {
|
|
993
|
-
let commitMessage;
|
|
994
|
-
const updatedPackage = result.updatedPackages[0];
|
|
995
|
-
const newVersion = updatedPackage.newVersion;
|
|
996
|
-
const isDefaultPackage$1 = pkgName === "default" || this.config.packagePaths[pkgName] === "package.json";
|
|
997
|
-
if (this.gitConfig.commitMessage && this.gitConfig.commitMessage !== "chore: bump version to {{newVersion}}") commitMessage = this.gitConfig.commitMessage.replace(/\{\{newVersion\}\}/g, newVersion);
|
|
998
|
-
else if (pkgName === "all") {
|
|
999
|
-
const versionInfo = result.updatedPackages.map((pkg) => `${pkg.name}@${pkg.newVersion}`).join(", ");
|
|
1000
|
-
commitMessage = `chore: bump version for all packages\n\n${versionInfo}`;
|
|
1001
|
-
} else commitMessage = `chore: bump version for ${pkgName} to v${newVersion}`;
|
|
1002
|
-
if (isDefaultPackage$1) this.gitManager.commitAndPush(commitMessage, this.gitPush, tag, newVersion, tagPrefix);
|
|
1003
|
-
else {
|
|
1004
|
-
const { execSync: execSync$1 } = await import("node:child_process");
|
|
1005
|
-
this.gitManager.addFiles(["-u"]);
|
|
1006
|
-
this.gitManager.commit(commitMessage);
|
|
1007
|
-
const tagName = `${updatedPackage.name}@${newVersion}`;
|
|
1008
|
-
try {
|
|
1009
|
-
execSync$1(`git tag -a ${tagName} -m "Release ${tagName}"`, {
|
|
1010
|
-
cwd: this.rootDir,
|
|
1011
|
-
stdio: "pipe"
|
|
1012
|
-
});
|
|
1013
|
-
logger_default.success(`已创建 tag: ${tagName}`);
|
|
1014
|
-
} catch (tagError) {
|
|
1015
|
-
logger_default.warn(`创建 tag ${tagName} 失败: ${tagError.message}`);
|
|
1016
|
-
}
|
|
1017
|
-
if (this.gitPush) try {
|
|
1018
|
-
this.gitManager.push(true);
|
|
1019
|
-
} catch (pushError) {
|
|
1020
|
-
logger_default.warn(`Git push failed: ${pushError.message}`);
|
|
1021
|
-
}
|
|
1022
|
-
}
|
|
1023
|
-
} catch (gitError) {
|
|
1024
|
-
logger_default.warn(`Git操作失败: ${gitError.message}`);
|
|
1025
|
-
}
|
|
1026
|
-
result.success = true;
|
|
1027
|
-
return result;
|
|
1028
|
-
} catch (error$1) {
|
|
1029
|
-
result.error = error$1.message;
|
|
1030
|
-
return result;
|
|
1031
|
-
}
|
|
1032
|
-
}, {
|
|
1033
|
-
succeedText: pkgName === "all" ? "所有包版本更新完成" : `包 ${pkgName} 版本更新完成`,
|
|
1034
|
-
failText: "版本更新失败"
|
|
1035
|
-
});
|
|
1036
|
-
}
|
|
1037
|
-
async gitCommitAndPush(push = true, updatedPackages, tag = this.gitConfig.tag !== false, tagPrefix = this.gitConfig.tagPrefix || "v") {
|
|
1038
|
-
try {
|
|
1039
|
-
const commitMessage = "chore: bump versions for multiple packages";
|
|
1040
|
-
if (tag && updatedPackages && updatedPackages.length > 0) {
|
|
1041
|
-
this.gitManager.addFiles(["-u"]);
|
|
1042
|
-
this.gitManager.commit(commitMessage);
|
|
1043
|
-
const { execSync: execSync$1 } = await import("node:child_process");
|
|
1044
|
-
for (const pkg of updatedPackages) {
|
|
1045
|
-
let tagName;
|
|
1046
|
-
const isMainPackage = pkg.pkgKey === "default";
|
|
1047
|
-
if (isMainPackage) tagName = `${tagPrefix}${pkg.newVersion}`;
|
|
1048
|
-
else tagName = `${pkg.name}@${pkg.newVersion}`;
|
|
1049
|
-
try {
|
|
1050
|
-
execSync$1(`git tag -a ${tagName} -m "Release ${tagName}"`, {
|
|
1051
|
-
cwd: this.rootDir,
|
|
1052
|
-
stdio: "pipe"
|
|
1053
|
-
});
|
|
1054
|
-
logger_default.success(`已创建 tag: ${tagName}`);
|
|
1055
|
-
} catch (error$1) {
|
|
1056
|
-
logger_default.warn(`创建 tag ${tagName} 失败: ${error$1.message}`);
|
|
1057
|
-
}
|
|
1058
|
-
}
|
|
1059
|
-
if (push) try {
|
|
1060
|
-
this.gitManager.push(true);
|
|
1061
|
-
} catch (error$1) {
|
|
1062
|
-
logger_default.warn(`Git push failed: ${error$1.message}`);
|
|
1063
|
-
}
|
|
1064
|
-
} else this.gitManager.commitAndPush(commitMessage, push, false);
|
|
1065
|
-
} catch (error$1) {
|
|
1066
|
-
logger_default.warn(`Git操作失败: ${error$1.message}`);
|
|
1067
|
-
}
|
|
1068
|
-
}
|
|
1069
|
-
/**
|
|
1070
|
-
* 获取包信息(带缓存)
|
|
1071
|
-
* @param pkgPath 包的路径
|
|
1072
|
-
* @returns 包信息对象
|
|
1073
|
-
*/
|
|
1074
|
-
getPackageInfo(pkgPath) {
|
|
1075
|
-
const cached = this.packageCache.get(pkgPath);
|
|
1076
|
-
if (cached) return cached;
|
|
1077
|
-
try {
|
|
1078
|
-
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
1079
|
-
this.packageCache.set(pkgPath, pkg);
|
|
1080
|
-
return pkg;
|
|
1081
|
-
} catch (error$1) {
|
|
1082
|
-
throw new Error(`读取文件失败 ${pkgPath}: ${error$1.message}`);
|
|
1083
|
-
}
|
|
1084
|
-
}
|
|
1085
|
-
savePackageInfo(pkgPath, pkg) {
|
|
1086
|
-
if (!validatePath(pkgPath, this.rootDir)) throw new Error(`不安全的文件路径: ${pkgPath}`);
|
|
1087
|
-
try {
|
|
1088
|
-
writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
1089
|
-
this.packageCache.set(pkgPath, pkg);
|
|
1090
|
-
} catch (error$1) {
|
|
1091
|
-
throw new Error(`写入文件失败 ${pkgPath}: ${error$1.message}`);
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
getPackageVersion(pkgName) {
|
|
1095
|
-
const pkgPath = this.packagePaths[pkgName];
|
|
1096
|
-
if (!pkgPath) return null;
|
|
1097
|
-
try {
|
|
1098
|
-
const pkg = this.getPackageInfo(pkgPath);
|
|
1099
|
-
return pkg.version;
|
|
1100
|
-
} catch {
|
|
1101
|
-
return null;
|
|
1102
|
-
}
|
|
1103
|
-
}
|
|
1104
|
-
isValidVersion(version) {
|
|
1105
|
-
return semver.valid(version) !== null;
|
|
1106
|
-
}
|
|
1107
|
-
getVersionDiff(oldVersion, newVersion) {
|
|
1108
|
-
if (!semver.valid(oldVersion) || !semver.valid(newVersion)) return null;
|
|
1109
|
-
if (semver.major(newVersion) > semver.major(oldVersion)) return "major";
|
|
1110
|
-
if (semver.minor(newVersion) > semver.minor(oldVersion)) return "minor";
|
|
1111
|
-
if (semver.patch(newVersion) > semver.patch(oldVersion)) return "patch";
|
|
1112
|
-
return null;
|
|
1113
|
-
}
|
|
1114
|
-
};
|
|
1115
|
-
|
|
1116
|
-
//#endregion
|
|
1117
|
-
export { BASE_CONFIG, ChangelogManager, GitManager, VersionManager, clearConfigCache, loadConfig, loadConfigAsync, logger_default, security_exports };
|
|
1118
|
-
//# sourceMappingURL=VersionManager-DSOVXsFt.js.map
|