@infly/libs 2.0.25

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.
@@ -0,0 +1,488 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const { execSync } = require("child_process");
4
+
5
+ /**
6
+ * 获取当前 Git 分支名称
7
+ * @returns
8
+ */
9
+ function getCurrentBranch() {
10
+ return execSync("git rev-parse --abbrev-ref HEAD").toString().trim();
11
+ }
12
+
13
+ /**
14
+ * 获取 Git 提交信息
15
+ * @returns {Object} 包含提交信息的对象,如果获取失败则返回空对象
16
+ */
17
+ function getLatestCommitInfo() {
18
+ // 定义 Git 命令
19
+ const commands = {
20
+ commitMsg: "git log -1 --no-merges --pretty=%B",
21
+ branch: "git rev-parse --abbrev-ref HEAD",
22
+ fullHash: "git rev-parse HEAD",
23
+ author: "git log -1 --no-merges --pretty=%an",
24
+ email: "git log -1 --no-merges --pretty=%ae",
25
+ date: "git log -1 --no-merges --pretty=%cd --date=iso"
26
+ };
27
+
28
+ // 结果对象
29
+ const commitInfo = {};
30
+
31
+ try {
32
+ // 检查当前目录是否是 Git 仓库
33
+ execSync("git rev-parse --is-inside-work-tree", { stdio: "ignore" });
34
+
35
+ // 遍历命令并执行
36
+ for (const [key, command] of Object.entries(commands)) {
37
+ try {
38
+ commitInfo[key] = execSync(`${command}`, { encoding: "utf-8" }).trim();
39
+ } catch (cmdError) {
40
+ console.warn(global.logColor.warning, `⚠️️ 获取 Git 信息失败(${key}):${cmdError.message}`);
41
+ commitInfo[key] = ""; // 失败时设置为空字符串
42
+ }
43
+ }
44
+ } catch (error) {
45
+ console.error(
46
+ global.logColor.error,
47
+ `❌ 获取 Git 信息失败:当前目录不是 Git 仓库或 Git 未安装。错误信息:${error.message}`
48
+ );
49
+ return {}; // 返回空对象
50
+ }
51
+
52
+ return commitInfo;
53
+ }
54
+
55
+ /**
56
+ * 获取指定文件的最后一次提交信息
57
+ * @param {String} filePath - 文件路径
58
+ * @returns {Object|null} 包含提交信息的对象,如果获取失败则返回 null
59
+ */
60
+ function getLastCommitByFile(filePath) {
61
+ try {
62
+ // 执行 Git 命令获取最后一次提交信息‌:ml-citation{ref="3,5" data="citationList"}
63
+ const cmd = `git log -1 --format="%H|%an|%ae|%at|%s" -- ${filePath}`;
64
+ const output = execSync(cmd, { encoding: "utf8" }).trim();
65
+ if (!output) return null;
66
+
67
+ // 解析提交信息‌:ml-citation{ref="1,5" data="citationList"}
68
+ const [hash, author, email, timestamp, message] = output.split("|");
69
+ return {
70
+ commitMsg: message.trim(),
71
+ hash,
72
+ author,
73
+ email,
74
+ date: new Date(parseInt(timestamp) * 1000).toISOString()
75
+ };
76
+ } catch {
77
+ return null;
78
+ }
79
+ }
80
+
81
+ /**
82
+ * 检查是否构建文件
83
+ * @param {String} targetProjectOutputDir 构建文件输出绝对路径
84
+ * @param {String} gitStatusLine 带文件状态的
85
+ * @returns
86
+ */
87
+ function isBuildFile(targetProjectOutputDir = "", gitLine = "", sliceLen = -2) {
88
+ // 统一路径分隔符
89
+ targetProjectOutputDir = targetProjectOutputDir.replace(/\\/g, "/");
90
+
91
+ // 取目录的最后 N 级,比如 frontend/ea
92
+ const dirFragment = targetProjectOutputDir.split("/").slice(sliceLen).join("/");
93
+
94
+ // 去掉状态前缀 (M, A, D, ?? 等)
95
+ const gitPath = gitLine.trim().slice(2).trim();
96
+
97
+ // 判断是否以 dirFragment 开头
98
+ return gitPath.startsWith(dirFragment + "/");
99
+ }
100
+
101
+ /**
102
+ * 检查 Git 状态
103
+ * @param {String} excludeDir - 排除的目录
104
+ * @param {String} extraFilter - 额外过滤条件
105
+ * @param {Object} extraParams - 额外的配置
106
+ */
107
+ function checkGitStatus(excludeDir, extraFilter, extraParams) {
108
+ const {
109
+ deleteOldFile = [],
110
+ versionFileName = "version-config.json",
111
+ gitAutoPushRepos,
112
+ targetProjectOutputDir,
113
+ targetProjectOutputDirCmd = gitAutoPushRepos ? ` -C ${targetProjectOutputDir}` : "",
114
+ onlyCheckStatus,
115
+ startLogText = "Git自动提交开始执行, 正在检查非构建文件"
116
+ } = extraParams || {};
117
+ try {
118
+ // 获取所有未跟踪和已修改的文件列表
119
+ const files = execSync(`git${targetProjectOutputDirCmd} status --porcelain -z`, { encoding: "utf8" })
120
+ .toString()
121
+ .split("\u0000")
122
+ .filter((line) => line.trim());
123
+ // .map((line) => line.substring(3).trim()); // 提取文件路径
124
+ const excludeFiles = []; // 非指定构建相关文件
125
+ const includeFiles = []; // 指定的构建相关文件
126
+
127
+ if (onlyCheckStatus) {
128
+ return files || [];
129
+ }
130
+
131
+ console.log(global.logColor.success, `🚀 ${startLogText}`);
132
+
133
+ files.forEach((file) => {
134
+ const existsDelFile = deleteOldFile.find((item) => file.includes(item));
135
+ if (
136
+ file.includes(`${excludeDir}/`) ||
137
+ file.includes(versionFileName) ||
138
+ file.includes(extraFilter) ||
139
+ isBuildFile(targetProjectOutputDir, file) ||
140
+ file.includes(`${gitAutoPushRepos}/`) || // 放宽文件判断条件,因为可能存在同时构建frontend/ea、frontend/e的情况
141
+ existsDelFile
142
+ ) {
143
+ includeFiles.push(file);
144
+ } else {
145
+ excludeFiles.push(file);
146
+ }
147
+ });
148
+
149
+ if (excludeFiles.length > 0) {
150
+ throw new Error(`存在非构建文件未提交,请手动确定提交信息,本次自动提交终止\n${excludeFiles.join("\n")}`);
151
+ }
152
+ } catch (err) {
153
+ console.error(global.logColor.error, `❌ 自动化构建Git状态检查存在问题:${err.message}`);
154
+ process.exit(1);
155
+ }
156
+ }
157
+
158
+ function runGitCommand(command, options = {}) {
159
+ try {
160
+ const result = execSync(command, {
161
+ ...options,
162
+ encoding: "utf8"
163
+ });
164
+ if (result) {
165
+ return result.trim();
166
+ }
167
+ } catch (error) {
168
+ console.error(global.logColor.error, `❌ 执行 Git 命令失败:${error.message}`);
169
+ process.exit(1);
170
+ }
171
+ }
172
+
173
+ /**
174
+ * git自动推送
175
+ * @param {String} buildFoldName 构建文件名称
176
+ * @param {String} newFileName 新压缩文件名
177
+ * @param {Object} extraParams 额外的参数
178
+ * @returns
179
+ */
180
+ function autoGitProcess(buildFoldName, newFileName, extraParams = {}) {
181
+ const {
182
+ newVersion,
183
+ gitInfo = {},
184
+ gitAutoCommitText = gitInfo.commitMsg,
185
+ gitAutoPushRepos,
186
+ targetProjectOutputDir,
187
+ gitAutoPushReposBranchMap = {},
188
+ targetProjectOutputDirCmd = gitAutoPushRepos ? ` -C ${targetProjectOutputDir}` : "",
189
+ projectName,
190
+ } = extraParams || {};
191
+ const { commitMsg, branch } = gitInfo || {};
192
+ const gitRepos = gitAutoPushRepos ? `构建仓库: ${targetProjectOutputDir}` : `当前项目: ${projectName}`;
193
+ let tempGitAutoCommitText = gitAutoCommitText ? gitAutoCommitText.replace("{version}", newVersion) : "";
194
+
195
+ if (gitAutoPushRepos) {
196
+ tempGitAutoCommitText = commitMsg;
197
+ }
198
+
199
+ const tempBranch = gitAutoPushRepos ? gitAutoPushReposBranchMap[branch] : branch;
200
+ const addCmd = `git${targetProjectOutputDirCmd} add -A`;
201
+ const commitCmd = `git${targetProjectOutputDirCmd} commit -m "${tempGitAutoCommitText}"`;
202
+ const pushCommand = `git${targetProjectOutputDirCmd} push origin ${tempBranch}`;
203
+
204
+ // 无分支则不执行,自动推送到单独仓库必须得配置分支枚举对应
205
+ /* "gitAutoPushReposBranchMap": {
206
+ "release-zkhTest": "develop-zkhTest"
207
+ }, */
208
+ if (!tempBranch) {
209
+ console.log(global.logColor.error, `❌ 缺少分支配置`);
210
+ return;
211
+ }
212
+
213
+ // 先执行构建仓库的推送,防止git提交信息被覆盖
214
+ runGitCommand(addCmd);
215
+ runGitCommand(commitCmd);
216
+ runGitCommand(pushCommand);
217
+
218
+ // 后执行当前项目的分支自动推送
219
+ if (gitAutoPushRepos) {
220
+ const overrideParams = { ...extraParams, gitAutoPushRepos: false };
221
+ const fileList = checkGitStatus(buildFoldName, newFileName, { ...overrideParams, onlyCheckStatus: true });
222
+ if (fileList.length > 0) {
223
+ autoGitProcess(buildFoldName, newFileName, overrideParams); // 执行自动推送当前项目的git信息
224
+ }
225
+ }
226
+
227
+ console.log(global.logColor.success, `✅ Git \x1b[34m${gitRepos}\x1b[32m 自动提交和推送成功!`);
228
+ }
229
+
230
+ /**
231
+ * 自动分支处理
232
+ * @param {Object} config - 分支配置
233
+ */
234
+ async function autoBranchProcess(config) {
235
+ const { gitAutoPushRepos, gitAutoPushReposBranchMap, currentBranch, targetProjectOutputDir, validateConfig } =
236
+ config || {};
237
+ const tempBranch = gitAutoPushRepos ? gitAutoPushReposBranchMap[currentBranch] : currentBranch;
238
+ const targetProjectOutputDirCmd = gitAutoPushRepos ? ` -C ${targetProjectOutputDir}` : "";
239
+ const checkoutCmd = `git${targetProjectOutputDirCmd} checkout ${tempBranch}`;
240
+ const pullCmd = `git${targetProjectOutputDirCmd} pull origin ${tempBranch}`;
241
+ const fileList = checkGitStatus(undefined, undefined, {
242
+ onlyCheckStatus: true,
243
+ targetProjectOutputDirCmd,
244
+ startLogText: "Git自动化开始执行..."
245
+ });
246
+
247
+ if (validateConfig && typeof validateConfig === "function") {
248
+ validateConfig();
249
+ }
250
+
251
+ if (!tempBranch) {
252
+ console.error(global.logColor.error, `❌ 缺少项目分支对应构建仓库分支配置,当前分支:${currentBranch},请检查`);
253
+ process.exit(1);
254
+ }
255
+
256
+ if (fileList.length > 0) {
257
+ console.error(global.logColor.error, `❌ 构建仓库存在未提交文件,请检查`);
258
+ process.exit(1);
259
+ }
260
+
261
+ runGitCommand(checkoutCmd);
262
+ runGitCommand(pullCmd);
263
+ }
264
+
265
+ /**
266
+ * 检查 packages 下的所有模块是否有未提交的代码
267
+ * @param {string} packagesDir - packages 目录的绝对路径
268
+ * @returns {Object} 检查结果
269
+ */
270
+ function checkPackagesGitStatus(packagesDir) {
271
+ const fs = require("fs");
272
+
273
+ if (!fs.existsSync(packagesDir)) {
274
+ console.error(global.logColor.error, `❌ packages 目录不存在: ${packagesDir}`);
275
+ return { hasUncommitted: false, modules: [] };
276
+ }
277
+
278
+ const modules = fs.readdirSync(packagesDir).filter((item) => {
279
+ const modulePath = path.join(packagesDir, item);
280
+ return fs.statSync(modulePath).isDirectory();
281
+ });
282
+
283
+ // console.log(global.logColor.info, `📦 检查 packages 下的 ${modules.length} 个模块...`);
284
+
285
+ const uncommittedModules = [];
286
+
287
+ for (const module of modules) {
288
+ const modulePath = path.join(packagesDir, module);
289
+ const gitPath = path.join(modulePath, ".git");
290
+
291
+ // 检查是否是 git 仓库
292
+ if (!fs.existsSync(gitPath)) {
293
+ console.log(global.logColor.warning, `⚠️ ${module}: 不是 git 仓库,跳过检查`);
294
+ continue;
295
+ }
296
+
297
+ try {
298
+ // 切换到模块目录并检查 git status
299
+ const statusOutput = execSync("git status --porcelain", {
300
+ cwd: modulePath,
301
+ encoding: "utf8"
302
+ }).trim();
303
+
304
+ if (statusOutput) {
305
+ console.log(global.logColor.error, `❌ ${module}: 存在未提交的更改`);
306
+ console.log(global.logColor.error, ` ${statusOutput.split("\n").join("\n ")}`);
307
+ uncommittedModules.push({
308
+ name: module,
309
+ path: modulePath,
310
+ changes: statusOutput.split("\n")
311
+ });
312
+ } else {
313
+ // console.log(global.logColor.success, `✅ ${module}: 工作区干净`);
314
+ }
315
+ } catch (error) {
316
+ console.error(global.logColor.error, `❌ ${module}: 检查失败 - ${error.message}`);
317
+ uncommittedModules.push({
318
+ name: module,
319
+ path: modulePath,
320
+ error: error.message
321
+ });
322
+ }
323
+ }
324
+
325
+ return {
326
+ hasUncommitted: uncommittedModules.length > 0,
327
+ modules: uncommittedModules,
328
+ totalModules: modules.length,
329
+ checkedModules: modules
330
+ };
331
+ }
332
+
333
+ /**
334
+ * 切换所有 packages 模块到 master 分支并拉取最新代码
335
+ * @param {string} packagesDir - packages 目录的绝对路径
336
+ * @param {string} targetBranch - 目标分支名,默认为 'master'
337
+ */
338
+ function pullPackagesFromMaster(packagesDir, targetBranch = "master") {
339
+ const fs = require("fs");
340
+
341
+ if (!fs.existsSync(packagesDir)) {
342
+ console.error(global.logColor.error, `❌ packages 目录不存在: ${packagesDir}`);
343
+ return;
344
+ }
345
+
346
+ const modules = fs.readdirSync(packagesDir).filter((item) => {
347
+ const modulePath = path.join(packagesDir, item);
348
+ return fs.statSync(modulePath).isDirectory();
349
+ });
350
+
351
+ // console.log(global.logColor.info, `🔄 切换 packages 下的模块到 ${targetBranch} 分支并拉取最新代码...`);
352
+
353
+ const results = [];
354
+
355
+ for (const module of modules) {
356
+ const modulePath = path.join(packagesDir, module);
357
+ const gitPath = path.join(modulePath, ".git");
358
+
359
+ // 检查是否是 git 仓库
360
+ if (!fs.existsSync(gitPath)) {
361
+ console.log(global.logColor.warning, `⚠️ ${module}: 不是 git 仓库,跳过操作`);
362
+ results.push({ module, success: false, reason: "不是 git 仓库" });
363
+ continue;
364
+ }
365
+
366
+ try {
367
+ // console.log(global.logColor.info, `🔄 处理模块: ${module}`);
368
+
369
+ // 获取当前分支
370
+ const currentBranch = execSync("git rev-parse --abbrev-ref HEAD", {
371
+ cwd: modulePath,
372
+ encoding: "utf8"
373
+ }).trim();
374
+
375
+ // console.log(global.logColor.info, ` 当前分支: ${currentBranch}`);
376
+
377
+ // 如果不在目标分支,则切换
378
+ if (currentBranch !== targetBranch) {
379
+ // console.log(global.logColor.info, ` 切换到 ${targetBranch} 分支...`);
380
+ execSync(`git checkout ${targetBranch}`, {
381
+ cwd: modulePath,
382
+ stdio: "pipe"
383
+ });
384
+ }
385
+
386
+ // 拉取最新代码
387
+ // console.log(global.logColor.info, ` 拉取 ${targetBranch} 最新代码...`);
388
+ execSync(`git pull origin ${targetBranch}`, {
389
+ cwd: modulePath,
390
+ stdio: "pipe"
391
+ });
392
+
393
+ console.log(global.logColor.success, `✅ ${module}: 成功更新到最新代码`);
394
+ results.push({ module, success: true });
395
+ } catch (error) {
396
+ console.error(global.logColor.error, `❌ ${module}: 操作失败 - ${error.message}`);
397
+ results.push({ module, success: false, reason: error.message });
398
+ }
399
+ }
400
+
401
+ // 输出结果摘要
402
+ const successful = results.filter((r) => r.success).length;
403
+ const failed = results.filter((r) => !r.success).length;
404
+
405
+ // console.log(global.logColor.info, `\n📊 操作完成: 成功 ${successful} 个,失败 ${failed} 个`);
406
+
407
+ return results;
408
+ }
409
+
410
+ // 获取 packages 目录路径(相对于当前项目根目录)
411
+ function findPackagesDir(currentDir) {
412
+ let searchDir = currentDir || process.cwd();
413
+
414
+ // 向上查找 packages 目录,最多查找 3 层
415
+ for (let i = 0; i < 3; i++) {
416
+ const packagesPath = path.resolve(searchDir, "packages");
417
+ if (fs.existsSync(packagesPath)) {
418
+ return packagesPath;
419
+ }
420
+ const parentDir = path.dirname(searchDir);
421
+ if (parentDir === searchDir) break; // 已到根目录
422
+ searchDir = parentDir;
423
+ }
424
+
425
+ return null;
426
+ }
427
+
428
+ /**
429
+ * 完整的 packages 检查和更新流程
430
+ * @param {string} packagesDir - packages 目录的绝对路径
431
+ * @param {string} targetBranch - 目标分支名,默认为 'master'
432
+ */
433
+ async function checkAndUpdatePackages(outPackagesDir, targetBranch = "master") {
434
+ try {
435
+ const packagesDir = outPackagesDir || findPackagesDir();
436
+
437
+ // 检查 packages 目录是否存在
438
+ if (!packagesDir) {
439
+ console.log(global.logColor.warning, `⚠️ packages 目录不存在,跳过检查`);
440
+ return;
441
+ }
442
+
443
+ console.log(global.logColor.info, `\n🚀 开始检查和更新 packages 模块...`);
444
+
445
+ // 1. 检查未提交的更改
446
+ const checkResult = checkPackagesGitStatus(packagesDir);
447
+
448
+ if (checkResult.hasUncommitted) {
449
+ // console.log(global.logColor.error, `\n❌ 发现 ${checkResult.modules.length} 个模块存在未提交的更改:`);
450
+ checkResult.modules.forEach((module) => {
451
+ // console.log(global.logColor.error, ` - ${module.name}`);
452
+ });
453
+ console.log(global.logColor.error, `\n请先提交或储藏这些更改后再继续执行!`);
454
+ process.exit(1);
455
+ }
456
+
457
+ // console.log(global.logColor.success, `\n✅ 所有模块工作区都是干净的,继续执行...`);
458
+
459
+ // 2. 切换到 master 并拉取最新代码
460
+ const updateResults = pullPackagesFromMaster(packagesDir, targetBranch);
461
+
462
+ // 3. 检查是否有失败的操作
463
+ const failedUpdates = updateResults.filter((r) => !r.success);
464
+ if (failedUpdates.length > 0) {
465
+ console.log(global.logColor.warning, `\n⚠️ 有 ${failedUpdates.length} 个模块更新失败,但可以继续执行`);
466
+ }
467
+
468
+ // console.log(global.logColor.success, `\n🎉 packages 检查和更新流程完成!`);
469
+ return updateResults;
470
+ } catch (error) {
471
+ console.error(global.logColor.error, `❌ packages 检查失败: ${error.message}`);
472
+ console.error(global.logColor.error, "请检查 packages 下的模块是否有未提交的更改");
473
+ process.exit(1);
474
+ }
475
+ }
476
+
477
+ module.exports = {
478
+ getCurrentBranch,
479
+ getLatestCommitInfo,
480
+ getLastCommitByFile,
481
+ checkGitStatus,
482
+ autoGitProcess,
483
+ runGitCommand,
484
+ autoBranchProcess,
485
+ checkPackagesGitStatus,
486
+ pullPackagesFromMaster,
487
+ checkAndUpdatePackages
488
+ };
@@ -0,0 +1,26 @@
1
+ module.exports = {
2
+ previewList: [
3
+ {
4
+ key: "preview",
5
+ value: "infly-libs --preview"
6
+ },
7
+ {
8
+ key: "preview:no-build",
9
+ value: "infly-libs --preview --no-build"
10
+ }
11
+ ],
12
+ buildList: [
13
+ {
14
+ key: "infly:build:prod",
15
+ value: "infly-libs beforeBuild && vue-cli-service build && infly-libs afterBuild"
16
+ },
17
+ {
18
+ key: "infly:build:stage",
19
+ value: "infly-libs beforeBuild && vue-cli-service build --mode staging && infly-libs afterBuild"
20
+ },
21
+ {
22
+ key: "infly:build:test",
23
+ value: "infly-libs beforeBuild && infly-libs afterBuild"
24
+ }
25
+ ]
26
+ };
@@ -0,0 +1,60 @@
1
+ function postVersionFileAndMsg(publishText, extraParams = {}) {
2
+ const {
3
+ projectName,
4
+ newFileName,
5
+ gitInfo,
6
+ webhookUrl = "", // 启用企业微信推送
7
+ webhookAtUser = [],
8
+ webhookExtraText = "",
9
+ gitAutoPushRepos,
10
+ gitAutoPushReposBranchMap
11
+ } = extraParams || {};
12
+ const { branch, commitMsg } = gitInfo || {};
13
+ const GITPATH = `https://gitee.com/gdinfly_1/${projectName}/blob/${branch}/${newFileName}`;
14
+ const UPLOADURL = `https://qyapi.weixin.qq.com/cgi-bin/webhook/upload_media?key=08ea37af-c6f5-47dc-8fab-0833707c70b8&type=file`;
15
+ /* const data = {
16
+ msgtype: "markdown",
17
+ markdown: {
18
+ content: `${publishText}\n构建文件:[点击下载](${GITPATH})`,
19
+ },
20
+ };
21
+ if (Array.isArray(webhookAtUser) && webhookAtUser.length > 0) {
22
+ webhookAtUser.forEach((item, index) => {
23
+ data.markdown.content = `${data.markdown.content}\n<@${item}>`;
24
+ });
25
+ } */
26
+ let content = publishText;
27
+ if (gitAutoPushRepos) {
28
+ content = `${publishText}\n构建文件:已推送对应仓库【${gitAutoPushRepos}】分支【${gitAutoPushReposBranchMap[branch]}】`;
29
+ } else {
30
+ content = `${publishText}\n构建文件下载地址:${GITPATH}\n${webhookExtraText}\n`;
31
+ }
32
+ const data = {
33
+ msgtype: "text",
34
+ text: {
35
+ content,
36
+ mentioned_mobile_list: Array.isArray(webhookAtUser) ? webhookAtUser : webhookAtUser[branch] // 支持按分支配置不同的提醒人
37
+ }
38
+ };
39
+ try {
40
+ const axios = require("axios");
41
+
42
+ if (axios) {
43
+ axios
44
+ .post(webhookUrl, data, {
45
+ headers: {
46
+ "Content-Type": "application/json"
47
+ }
48
+ })
49
+ .catch((e) => {
50
+ console.error("请求出错:", e);
51
+ });
52
+ }
53
+ } catch (error) {
54
+ console.error("axios is not available, please install it.");
55
+ }
56
+ }
57
+
58
+ module.exports = {
59
+ postVersionFileAndMsg
60
+ };
package/store/index.js ADDED
File without changes