@infly/libs 2.0.36 → 2.0.37
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/bin/cli.js +29 -22
- package/build/build-dist/index.js +211 -46
- package/build/webpack5/webpack.base.js +10 -1
- package/build/webpack5/webpack.base.test.js +59 -0
- package/module/Permission.js +43 -36
- package/module/REST.js +109 -46
- package/module/Uts.js +90 -52
- package/module/cjs/deep-merge.cjs +38 -0
- package/module/cjs/page-config.cjs +119 -0
- package/module/cjs/request-url-rules.cjs +55 -0
- package/package.json +6 -6
- package/script/build/command.js +48 -0
- package/script/build/env.js +28 -0
- package/script/build/git.js +252 -0
- package/script/build/preview.js +75 -0
- package/script/build/webhook.js +118 -0
- package/script/git-automation/check-packages.js +11 -8
- package/script/git-automation/git-utils.js +67 -0
- package/script/git-automation/index.js +229 -104
- package/script/pts/cloud-scenes.mjs +65 -0
- package/script/pts/cloud.js +151 -0
- package/script/pts/generate-cloud-params.mjs +210 -0
- package/script/pts/generate-cloud-params.test.mjs +67 -0
- package/script/webhook/webhook.js +72 -2
- package/store/modules/user.js +63 -46
- package/tools/auto-export.js +56 -0
- package/tools/file-export.js +16 -12
- package/tools/project-preview.js +110 -97
- package/types/unused.index.d.ts +0 -71
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
|
|
3
|
+
function shouldSkipWebhook(args) {
|
|
4
|
+
return args.some((arg) => ["--nowebhook", "--noWebhook", "--no-webhook"].includes(arg));
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function getVersionFromRecord(record) {
|
|
8
|
+
const fileName = record.extraParams?.newFileName || "";
|
|
9
|
+
const match = fileName.match(/-v([^-.]+(?:\.[^-.]+)*)-/);
|
|
10
|
+
return match ? match[1] : "";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function getProjectLine(record) {
|
|
14
|
+
const { projectName, gitInfo = {}, repos } = record.extraParams || {};
|
|
15
|
+
const version = getVersionFromRecord(record);
|
|
16
|
+
const branch = gitInfo.branch || "";
|
|
17
|
+
const repoText = repos ? `,构建仓库:${repos}` : "";
|
|
18
|
+
return `- ${projectName || "unknown"}${version ? ` v${version}` : ""}${branch ? ` ${branch}` : ""}${repoText}`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function getRecordContent(record, deployUrl) {
|
|
22
|
+
const { publishText = "", extraParams = {} } = record || {};
|
|
23
|
+
const {
|
|
24
|
+
gitInfo = {},
|
|
25
|
+
gitAutoPushReposBranchMap,
|
|
26
|
+
repos,
|
|
27
|
+
newFileName,
|
|
28
|
+
projectName,
|
|
29
|
+
webhookExtraText = ""
|
|
30
|
+
} = extraParams;
|
|
31
|
+
const { branch, author } = gitInfo || {};
|
|
32
|
+
|
|
33
|
+
if (gitAutoPushReposBranchMap) {
|
|
34
|
+
const targetBranch = gitAutoPushReposBranchMap[branch] || branch || "";
|
|
35
|
+
return [
|
|
36
|
+
publishText,
|
|
37
|
+
`构建文件:已推送对应仓库【${repos || ""}】- 分支【${targetBranch}】`,
|
|
38
|
+
`构建人:${author || ""}`,
|
|
39
|
+
`部署系统:${deployUrl}`
|
|
40
|
+
]
|
|
41
|
+
.filter(Boolean)
|
|
42
|
+
.join("\n");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const gitPath =
|
|
46
|
+
projectName && branch && newFileName
|
|
47
|
+
? `https://gitee.com/gdinfly_1/${projectName}/blob/${branch}/${newFileName}`
|
|
48
|
+
: "";
|
|
49
|
+
|
|
50
|
+
return [
|
|
51
|
+
publishText,
|
|
52
|
+
gitPath ? `构建文件下载地址:${gitPath}` : "",
|
|
53
|
+
webhookExtraText
|
|
54
|
+
]
|
|
55
|
+
.filter(Boolean)
|
|
56
|
+
.join("\n");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function postBatchWebhook(batchWebhookFile, extraArgs, mode) {
|
|
60
|
+
if (shouldSkipWebhook(extraArgs)) {
|
|
61
|
+
console.log("\n已跳过企业微信机器人汇总推送(nowebhook)");
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (!fs.existsSync(batchWebhookFile)) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const records = fs
|
|
70
|
+
.readFileSync(batchWebhookFile, "utf8")
|
|
71
|
+
.split(/\r?\n/)
|
|
72
|
+
.filter(Boolean)
|
|
73
|
+
.map((line) => JSON.parse(line));
|
|
74
|
+
|
|
75
|
+
if (records.length === 0) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const [firstRecord] = records;
|
|
80
|
+
const { webhookUrl, webhookAtUser = [], gitInfo = {}, deployUrl = "https://cicd.sutpay.com/" } =
|
|
81
|
+
firstRecord.extraParams || {};
|
|
82
|
+
|
|
83
|
+
if (!webhookUrl) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
let content = [
|
|
88
|
+
records.map((record) => getRecordContent(record, deployUrl)).join("\n\n")
|
|
89
|
+
].join("\n");
|
|
90
|
+
// 防御性过滤:防止运行时数据中的 %s 等格式化占位符泄露到推送内容
|
|
91
|
+
content = (content || "").replace(/%s/g, "");
|
|
92
|
+
const mentionedMobileList = Array.isArray(webhookAtUser) ? webhookAtUser : webhookAtUser[gitInfo.branch];
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
await require("axios").post(
|
|
96
|
+
webhookUrl,
|
|
97
|
+
{
|
|
98
|
+
msgtype: "text",
|
|
99
|
+
text: {
|
|
100
|
+
content,
|
|
101
|
+
mentioned_mobile_list: mentionedMobileList
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
headers: {
|
|
106
|
+
"Content-Type": "application/json"
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
console.log("\n已发送批量构建企业微信汇总推送");
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.error("企业微信汇总推送失败", error.message);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
module.exports = {
|
|
117
|
+
postBatchWebhook
|
|
118
|
+
};
|
|
@@ -13,23 +13,23 @@ global.logColor = {
|
|
|
13
13
|
/**
|
|
14
14
|
* 主函数:检查 packages 并处理
|
|
15
15
|
*/
|
|
16
|
-
function main() {
|
|
16
|
+
async function main() {
|
|
17
17
|
// packages 目录路径(相对于当前脚本的位置)
|
|
18
18
|
const packagesDir = path.resolve(__dirname, '../../../../packages');
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
console.log(global.logColor.info, `\n🔍 开始检查 packages 目录: ${packagesDir}\n`);
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
try {
|
|
23
23
|
// 执行完整的检查和更新流程
|
|
24
24
|
// 如果有未提交代码会自动中止并退出进程
|
|
25
25
|
// 如果没有问题会自动切换到 master 分支并拉取最新代码
|
|
26
|
-
checkAndUpdatePackages(packagesDir, 'master');
|
|
27
|
-
|
|
26
|
+
await checkAndUpdatePackages(packagesDir, 'master');
|
|
27
|
+
|
|
28
28
|
console.log(global.logColor.success, `\n✨ packages 检查和更新完成,可以继续执行后续操作!\n`);
|
|
29
|
-
|
|
29
|
+
|
|
30
30
|
// 在这里可以继续执行你的其他逻辑
|
|
31
31
|
// 比如构建、发布等操作
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
} catch (error) {
|
|
34
34
|
console.error(global.logColor.error, `\n💥 执行失败: ${error.message}\n`);
|
|
35
35
|
process.exit(1);
|
|
@@ -38,7 +38,10 @@ function main() {
|
|
|
38
38
|
|
|
39
39
|
// 如果直接运行此文件,则执行主函数
|
|
40
40
|
if (require.main === module) {
|
|
41
|
-
main()
|
|
41
|
+
main().catch(error => {
|
|
42
|
+
console.error(global.logColor.error, `\n💥 执行失败: ${error.message}\n`);
|
|
43
|
+
process.exit(1);
|
|
44
|
+
});
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
module.exports = { main };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const { execFileSync } = require("child_process");
|
|
4
|
+
|
|
5
|
+
function gitOutput(args, cwd = process.cwd()) {
|
|
6
|
+
return execFileSync("git", args, {
|
|
7
|
+
cwd,
|
|
8
|
+
encoding: "utf8",
|
|
9
|
+
shell: process.platform === "win32"
|
|
10
|
+
}).trim();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function findGitRepo(cwd) {
|
|
14
|
+
let currentDir = path.resolve(cwd || process.cwd());
|
|
15
|
+
|
|
16
|
+
while (true) {
|
|
17
|
+
const gitPath = path.join(currentDir, ".git");
|
|
18
|
+
|
|
19
|
+
if (fs.existsSync(gitPath)) {
|
|
20
|
+
const stat = fs.statSync(gitPath);
|
|
21
|
+
const repo = {
|
|
22
|
+
root: currentDir,
|
|
23
|
+
commonDir: gitPath
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
if (stat.isFile()) {
|
|
27
|
+
const content = fs.readFileSync(gitPath, "utf8");
|
|
28
|
+
const match = content.match(/gitdir:\s*(.+)/i);
|
|
29
|
+
|
|
30
|
+
if (match) {
|
|
31
|
+
repo.commonDir = path.resolve(currentDir, match[1].trim());
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return repo;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const parentDir = path.dirname(currentDir);
|
|
39
|
+
|
|
40
|
+
if (parentDir === currentDir) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
currentDir = parentDir;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function getGitCommonDir(cwd) {
|
|
49
|
+
const repo = findGitRepo(cwd);
|
|
50
|
+
|
|
51
|
+
if (repo) {
|
|
52
|
+
return repo.commonDir;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
const commonDir = gitOutput(["-C", cwd, "rev-parse", "--git-common-dir"]);
|
|
57
|
+
return path.resolve(cwd, commonDir);
|
|
58
|
+
} catch {
|
|
59
|
+
return path.resolve(cwd || process.cwd());
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
module.exports = {
|
|
64
|
+
gitOutput,
|
|
65
|
+
findGitRepo,
|
|
66
|
+
getGitCommonDir
|
|
67
|
+
};
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
const fs = require("fs");
|
|
2
2
|
const path = require("path");
|
|
3
|
-
const
|
|
3
|
+
const crypto = require("crypto");
|
|
4
|
+
const { execSync, exec } = require("child_process");
|
|
5
|
+
const { promisify } = require("util");
|
|
6
|
+
const { getGitCommonDir } = require("./git-utils");
|
|
7
|
+
const execAsync = promisify(exec);
|
|
4
8
|
|
|
5
9
|
/**
|
|
6
10
|
* 获取当前 Git 分支名称
|
|
@@ -117,6 +121,14 @@ function checkGitStatus(excludeDir, extraFilter, extraParams) {
|
|
|
117
121
|
onlyCheckStatus,
|
|
118
122
|
startLogText = "Git自动提交开始执行, 正在检查非构建文件"
|
|
119
123
|
} = extraParams || {};
|
|
124
|
+
|
|
125
|
+
// 如果指定了构建输出目录但目录不存在,则自动创建并初始化 Git 仓库
|
|
126
|
+
if (targetProjectOutputDir && !fs.existsSync(targetProjectOutputDir)) {
|
|
127
|
+
console.log(global.logColor.warning, `⚠️ 构建目录不存在,正在自动创建:${targetProjectOutputDir}`);
|
|
128
|
+
fs.mkdirSync(targetProjectOutputDir, { recursive: true });
|
|
129
|
+
console.log(global.logColor.success, `✅ 构建目录已创建并初始化 Git 仓库:${targetProjectOutputDir}`);
|
|
130
|
+
}
|
|
131
|
+
|
|
120
132
|
try {
|
|
121
133
|
// 获取所有未跟踪和已修改的文件列表
|
|
122
134
|
const files = execSync(`git${targetProjectOutputDirCmd} status --porcelain -z`, { encoding: "utf8" })
|
|
@@ -173,6 +185,56 @@ function runGitCommand(command, options = {}) {
|
|
|
173
185
|
}
|
|
174
186
|
}
|
|
175
187
|
|
|
188
|
+
function hasStagedChanges(targetProjectOutputDirCmd = "") {
|
|
189
|
+
try {
|
|
190
|
+
execSync(`git${targetProjectOutputDirCmd} diff --cached --quiet`, {
|
|
191
|
+
stdio: "ignore"
|
|
192
|
+
});
|
|
193
|
+
return false;
|
|
194
|
+
} catch (error) {
|
|
195
|
+
return error.status === 1;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function sleepSync(ms) {
|
|
200
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function withGitRepoLock(lockDir, lockKey, task) {
|
|
204
|
+
if (!lockDir || !lockKey) {
|
|
205
|
+
return task();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
fs.mkdirSync(lockDir, { recursive: true });
|
|
209
|
+
const lockName = crypto.createHash("md5").update(lockKey).digest("hex");
|
|
210
|
+
const lockPath = path.join(lockDir, `${lockName}.lock`);
|
|
211
|
+
const startTime = Date.now();
|
|
212
|
+
const timeout = 10 * 60 * 1000;
|
|
213
|
+
|
|
214
|
+
while (true) {
|
|
215
|
+
try {
|
|
216
|
+
fs.mkdirSync(lockPath);
|
|
217
|
+
break;
|
|
218
|
+
} catch (error) {
|
|
219
|
+
if (error.code !== "EEXIST") {
|
|
220
|
+
throw error;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (Date.now() - startTime > timeout) {
|
|
224
|
+
throw new Error(`等待 Git 仓库锁超时: ${lockKey}`);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
sleepSync(500);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
try {
|
|
232
|
+
return task();
|
|
233
|
+
} finally {
|
|
234
|
+
fs.rmSync(lockPath, { recursive: true, force: true });
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
176
238
|
/**
|
|
177
239
|
* git自动推送
|
|
178
240
|
* @param {String} buildFoldName 构建文件名称
|
|
@@ -189,10 +251,24 @@ function autoGitProcess(buildFoldName, newFileName, extraParams = {}) {
|
|
|
189
251
|
targetProjectOutputDir,
|
|
190
252
|
gitAutoPushReposBranchMap = {},
|
|
191
253
|
targetProjectOutputDirCmd = gitAutoPushRepos ? ` -C ${targetProjectOutputDir}` : "",
|
|
192
|
-
projectName
|
|
254
|
+
projectName,
|
|
255
|
+
gitLockDir,
|
|
256
|
+
gitProcessOrder
|
|
193
257
|
} = extraParams || {};
|
|
194
|
-
|
|
195
|
-
const
|
|
258
|
+
const appFirst = gitAutoPushRepos && gitProcessOrder === "app-first";
|
|
259
|
+
const runAppGitProcess = () => {
|
|
260
|
+
const overrideParams = {
|
|
261
|
+
...extraParams,
|
|
262
|
+
targetProjectOutputDir: "",
|
|
263
|
+
targetProjectOutputDirCmd: "",
|
|
264
|
+
gitAutoPushRepos: false
|
|
265
|
+
};
|
|
266
|
+
autoGitProcess(buildFoldName, newFileName, overrideParams);
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
if (appFirst) {
|
|
270
|
+
runAppGitProcess();
|
|
271
|
+
}
|
|
196
272
|
|
|
197
273
|
const { commitMsg, branch } = gitInfo || {};
|
|
198
274
|
const gitRepos = gitAutoPushRepos ? `构建仓库: ${targetProjectOutputDir}` : `当前项目: ${projectName}`;
|
|
@@ -207,36 +283,39 @@ function autoGitProcess(buildFoldName, newFileName, extraParams = {}) {
|
|
|
207
283
|
const commitCmd = `git${targetProjectOutputDirCmd} commit -m "${tempGitAutoCommitText}"`;
|
|
208
284
|
const pushCommand = `git${targetProjectOutputDirCmd} push origin ${tempBranch}`;
|
|
209
285
|
|
|
210
|
-
// 无分支则不执行,自动推送到单独仓库必须得配置分支枚举对应
|
|
211
|
-
/* "gitAutoPushReposBranchMap": {
|
|
212
|
-
"release-zkhTest": "develop-zkhTest"
|
|
213
|
-
}, */
|
|
214
286
|
if (!tempBranch) {
|
|
215
287
|
console.log(global.logColor.error, `❌ 缺少分支配置`);
|
|
216
288
|
return;
|
|
217
289
|
}
|
|
218
290
|
|
|
219
|
-
|
|
220
|
-
|
|
291
|
+
const checkCommitAndPush = () => {
|
|
292
|
+
const fileList = checkGitStatus(buildFoldName, newFileName, extraParams) || [];
|
|
293
|
+
|
|
294
|
+
if (fileList.length === 0) {
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
221
298
|
runGitCommand(addCmd);
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
299
|
+
if (!hasStagedChanges(targetProjectOutputDirCmd)) {
|
|
300
|
+
console.log(global.logColor.warning, `⚠️ Git ${gitRepos} 没有可提交的变更,跳过自动提交`);
|
|
301
|
+
} else {
|
|
302
|
+
runGitCommand(commitCmd);
|
|
303
|
+
runGitCommand(pushCommand);
|
|
304
|
+
}
|
|
305
|
+
};
|
|
225
306
|
|
|
226
|
-
// 后执行当前项目的分支自动推送
|
|
227
307
|
if (gitAutoPushRepos) {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
308
|
+
withGitRepoLock(gitLockDir, getGitCommonDir(targetProjectOutputDir), checkCommitAndPush);
|
|
309
|
+
} else {
|
|
310
|
+
checkCommitAndPush();
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (gitAutoPushRepos && !appFirst) {
|
|
314
|
+
runAppGitProcess();
|
|
235
315
|
}
|
|
236
316
|
|
|
237
317
|
console.log(global.logColor.success, `✅ Git \x1b[34m${gitRepos}\x1b[32m 自动提交和推送成功!`);
|
|
238
318
|
}
|
|
239
|
-
|
|
240
319
|
/**
|
|
241
320
|
* 自动分支处理
|
|
242
321
|
* @param {Object} config - 分支配置
|
|
@@ -278,7 +357,7 @@ async function autoBranchProcess(config) {
|
|
|
278
357
|
* @param {string} packagesDir - packages 目录的绝对路径
|
|
279
358
|
* @returns {Object} 检查结果
|
|
280
359
|
*/
|
|
281
|
-
function checkPackagesGitStatus(packagesDir) {
|
|
360
|
+
async function checkPackagesGitStatus(packagesDir) {
|
|
282
361
|
const fs = require("fs");
|
|
283
362
|
|
|
284
363
|
if (!fs.existsSync(packagesDir)) {
|
|
@@ -293,45 +372,42 @@ function checkPackagesGitStatus(packagesDir) {
|
|
|
293
372
|
|
|
294
373
|
// console.log(global.logColor.info, `📦 检查 packages 下的 ${modules.length} 个模块...`);
|
|
295
374
|
|
|
296
|
-
const uncommittedModules =
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
const gitPath = path.join(modulePath, ".git");
|
|
375
|
+
const uncommittedModules = await Promise.all(
|
|
376
|
+
modules.map(async (module) => {
|
|
377
|
+
const modulePath = path.join(packagesDir, module);
|
|
378
|
+
const gitPath = path.join(modulePath, ".git");
|
|
301
379
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
try {
|
|
309
|
-
// 切换到模块目录并检查 git status
|
|
310
|
-
const statusOutput = execSync("git status --porcelain", {
|
|
311
|
-
cwd: modulePath,
|
|
312
|
-
encoding: "utf8"
|
|
313
|
-
}).trim();
|
|
380
|
+
// 检查是否是 git 仓库
|
|
381
|
+
if (!fs.existsSync(gitPath)) {
|
|
382
|
+
console.log(global.logColor.warning, `⚠️ ${module}: 不是 git 仓库,跳过检查`);
|
|
383
|
+
return null;
|
|
384
|
+
}
|
|
314
385
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
386
|
+
try {
|
|
387
|
+
// 切换到模块目录并检查 git status
|
|
388
|
+
const { stdout } = await execAsync("git status --porcelain", { cwd: modulePath });
|
|
389
|
+
const statusOutput = stdout.trim();
|
|
390
|
+
|
|
391
|
+
if (statusOutput) {
|
|
392
|
+
console.log(global.logColor.error, `❌ ${module}: 存在未提交的更改`);
|
|
393
|
+
console.log(global.logColor.error, ` ${statusOutput.split("\n").join("\n ")}`);
|
|
394
|
+
return {
|
|
395
|
+
name: module,
|
|
396
|
+
path: modulePath,
|
|
397
|
+
changes: statusOutput.split("\n")
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
return null;
|
|
401
|
+
} catch (error) {
|
|
402
|
+
console.error(global.logColor.error, `❌ ${module}: 检查失败 - ${error.message}`);
|
|
403
|
+
return {
|
|
319
404
|
name: module,
|
|
320
405
|
path: modulePath,
|
|
321
|
-
|
|
322
|
-
}
|
|
323
|
-
} else {
|
|
324
|
-
// console.log(global.logColor.success, `✅ ${module}: 工作区干净`);
|
|
406
|
+
error: error.message
|
|
407
|
+
};
|
|
325
408
|
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
uncommittedModules.push({
|
|
329
|
-
name: module,
|
|
330
|
-
path: modulePath,
|
|
331
|
-
error: error.message
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
}
|
|
409
|
+
})
|
|
410
|
+
).then(results => results.filter(r => r !== null));
|
|
335
411
|
|
|
336
412
|
return {
|
|
337
413
|
hasUncommitted: uncommittedModules.length > 0,
|
|
@@ -346,7 +422,7 @@ function checkPackagesGitStatus(packagesDir) {
|
|
|
346
422
|
* @param {string} packagesDir - packages 目录的绝对路径
|
|
347
423
|
* @param {string} targetBranch - 目标分支名,默认为 'master'
|
|
348
424
|
*/
|
|
349
|
-
function pullPackagesFromMaster(packagesDir, targetBranch = "master") {
|
|
425
|
+
async function pullPackagesFromMaster(packagesDir, targetBranch = "master") {
|
|
350
426
|
const fs = require("fs");
|
|
351
427
|
|
|
352
428
|
if (!fs.existsSync(packagesDir)) {
|
|
@@ -361,53 +437,38 @@ function pullPackagesFromMaster(packagesDir, targetBranch = "master") {
|
|
|
361
437
|
|
|
362
438
|
// console.log(global.logColor.info, `🔄 切换 packages 下的模块到 ${targetBranch} 分支并拉取最新代码...`);
|
|
363
439
|
|
|
364
|
-
const results =
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
const gitPath = path.join(modulePath, ".git");
|
|
440
|
+
const results = await Promise.all(
|
|
441
|
+
modules.map(async (module) => {
|
|
442
|
+
const modulePath = path.join(packagesDir, module);
|
|
443
|
+
const gitPath = path.join(modulePath, ".git");
|
|
369
444
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
continue;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
try {
|
|
378
|
-
// console.log(global.logColor.info, `🔄 处理模块: ${module}`);
|
|
379
|
-
|
|
380
|
-
// 获取当前分支
|
|
381
|
-
const currentBranch = execSync("git rev-parse --abbrev-ref HEAD", {
|
|
382
|
-
cwd: modulePath,
|
|
383
|
-
encoding: "utf8"
|
|
384
|
-
}).trim();
|
|
385
|
-
|
|
386
|
-
// console.log(global.logColor.info, ` 当前分支: ${currentBranch}`);
|
|
387
|
-
|
|
388
|
-
// 如果不在目标分支,则切换
|
|
389
|
-
if (currentBranch !== targetBranch) {
|
|
390
|
-
// console.log(global.logColor.info, ` 切换到 ${targetBranch} 分支...`);
|
|
391
|
-
execSync(`git checkout ${targetBranch}`, {
|
|
392
|
-
cwd: modulePath,
|
|
393
|
-
stdio: "pipe"
|
|
394
|
-
});
|
|
445
|
+
// 检查是否是 git 仓库
|
|
446
|
+
if (!fs.existsSync(gitPath)) {
|
|
447
|
+
console.log(global.logColor.warning, `⚠️ ${module}: 不是 git 仓库,跳过操作`);
|
|
448
|
+
return { module, success: false, reason: "不是 git 仓库" };
|
|
395
449
|
}
|
|
396
450
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
451
|
+
try {
|
|
452
|
+
// 获取当前分支
|
|
453
|
+
const { stdout: branchOut } = await execAsync("git rev-parse --abbrev-ref HEAD", { cwd: modulePath });
|
|
454
|
+
const currentBranch = branchOut.trim();
|
|
455
|
+
|
|
456
|
+
// 如果不在目标分支,则切换
|
|
457
|
+
if (currentBranch !== targetBranch) {
|
|
458
|
+
await execAsync(`git checkout ${targetBranch}`, { cwd: modulePath });
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// 拉取最新代码
|
|
462
|
+
await execAsync(`git pull origin ${targetBranch}`, { cwd: modulePath });
|
|
463
|
+
|
|
464
|
+
console.log(global.logColor.success, `✅ \x1b[34m${module}\x1b[32m[${targetBranch}]: 更新到最新代码`);
|
|
465
|
+
return { module, success: true };
|
|
466
|
+
} catch (error) {
|
|
467
|
+
console.error(global.logColor.error, `❌ ${module}: 操作失败 - ${error.message}`);
|
|
468
|
+
return { module, success: false, reason: error.message };
|
|
469
|
+
}
|
|
470
|
+
})
|
|
471
|
+
);
|
|
411
472
|
|
|
412
473
|
// 输出结果摘要
|
|
413
474
|
const successful = results.filter((r) => r.success).length;
|
|
@@ -419,6 +480,66 @@ function pullPackagesFromMaster(packagesDir, targetBranch = "master") {
|
|
|
419
480
|
}
|
|
420
481
|
|
|
421
482
|
// 获取 packages 目录路径(相对于当前项目根目录)
|
|
483
|
+
function hasGitModules(packagesDir) {
|
|
484
|
+
if (!fs.existsSync(packagesDir)) {
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
return ["infly-libs", "infly-ui"].some((item) => fs.existsSync(path.join(packagesDir, item, ".git")));
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function checkAndUpdateRootPackages(packagesDir, targetBranch = "master") {
|
|
492
|
+
const rootDir = path.resolve(packagesDir, "..");
|
|
493
|
+
const gitPath = path.join(rootDir, ".git");
|
|
494
|
+
|
|
495
|
+
if (!fs.existsSync(gitPath)) {
|
|
496
|
+
console.log(global.logColor.warning, `⚠️ packages 不属于独立 git 仓库,也未找到根仓库,跳过 packages 更新`);
|
|
497
|
+
return [];
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const statusOutput = execSync("git status --porcelain", {
|
|
501
|
+
cwd: rootDir,
|
|
502
|
+
encoding: "utf8"
|
|
503
|
+
}).trim();
|
|
504
|
+
|
|
505
|
+
if (statusOutput) {
|
|
506
|
+
console.log(global.logColor.error, `\n❌ admin-monorepo 存在未提交的更改,无法合并 ${targetBranch}`);
|
|
507
|
+
console.log(global.logColor.error, ` ${statusOutput.split("\n").join("\n ")}`);
|
|
508
|
+
process.exit(1);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
const currentBranch = execSync("git rev-parse --abbrev-ref HEAD", {
|
|
512
|
+
cwd: rootDir,
|
|
513
|
+
encoding: "utf8"
|
|
514
|
+
}).trim();
|
|
515
|
+
|
|
516
|
+
console.log(global.logColor.info, `🔄 保持当前分支 ${currentBranch},合并 ${targetBranch} 的最新更改...`);
|
|
517
|
+
|
|
518
|
+
// 拉取远程最新的 targetBranch
|
|
519
|
+
execSync(`git fetch origin ${targetBranch}`, {
|
|
520
|
+
cwd: rootDir,
|
|
521
|
+
stdio: "inherit"
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
// 使用 merge-from-master.sh 脚本进行安全合并
|
|
525
|
+
const mergeScriptPath = path.join(rootDir, "script", "merge-from-master.sh");
|
|
526
|
+
if (fs.existsSync(mergeScriptPath)) {
|
|
527
|
+
execSync(`bash "${mergeScriptPath}" ${targetBranch}`, {
|
|
528
|
+
cwd: rootDir,
|
|
529
|
+
stdio: "inherit"
|
|
530
|
+
});
|
|
531
|
+
} else {
|
|
532
|
+
// 如果脚本不存在,使用基本的 merge 命令
|
|
533
|
+
execSync(`git merge origin/${targetBranch} --no-edit`, {
|
|
534
|
+
cwd: rootDir,
|
|
535
|
+
stdio: "inherit"
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
console.log(global.logColor.success, `✅ admin-monorepo[${currentBranch}]: 已合并 ${targetBranch} 的最新更改到 packages、docs 等目录`);
|
|
540
|
+
return [{ module: "admin-monorepo", success: true }];
|
|
541
|
+
}
|
|
542
|
+
|
|
422
543
|
function findPackagesDir(currentDir) {
|
|
423
544
|
let searchDir = currentDir || process.cwd();
|
|
424
545
|
|
|
@@ -552,7 +673,11 @@ async function checkAndUpdatePackages(outPackagesDir, targetBranch = "master") {
|
|
|
552
673
|
console.log(global.logColor.info, `\n🚀 开始检查和更新 packages 模块...`);
|
|
553
674
|
|
|
554
675
|
// 1. 检查未提交的更改
|
|
555
|
-
|
|
676
|
+
if (!hasGitModules(packagesDir)) {
|
|
677
|
+
return checkAndUpdateRootPackages(packagesDir, targetBranch);
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
const checkResult = await checkPackagesGitStatus(packagesDir);
|
|
556
681
|
|
|
557
682
|
if (checkResult.hasUncommitted) {
|
|
558
683
|
// console.log(global.logColor.error, `\n❌ 发现 ${checkResult.modules.length} 个模块存在未提交的更改:`);
|
|
@@ -566,7 +691,7 @@ async function checkAndUpdatePackages(outPackagesDir, targetBranch = "master") {
|
|
|
566
691
|
// console.log(global.logColor.success, `\n✅ 所有模块工作区都是干净的,继续执行...`);
|
|
567
692
|
|
|
568
693
|
// 2. 切换到 master 并拉取最新代码
|
|
569
|
-
const updateResults = pullPackagesFromMaster(packagesDir, targetBranch);
|
|
694
|
+
const updateResults = await pullPackagesFromMaster(packagesDir, targetBranch);
|
|
570
695
|
|
|
571
696
|
// 3. 检查是否有失败的操作
|
|
572
697
|
const failedUpdates = updateResults.filter((r) => !r.success);
|