@infly/libs 2.0.26 → 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 -21
- package/build/build-dist/index.js +258 -61
- package/build/webpack5/remove-legacy-assets-plugin.js +84 -0
- package/build/webpack5/webpack.base.js +228 -20
- package/build/webpack5/webpack.base.test.js +59 -0
- package/index.js +10 -0
- package/module/Permission.js +121 -55
- package/module/REST.js +136 -26
- package/module/Router.js +15 -0
- package/module/Uts.js +380 -331
- 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 +11 -10
- 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 +378 -106
- package/script/index.js +8 -8
- 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 +75 -4
- package/store/modules/user.js +111 -9
- package/tools/auto-export.js +56 -0
- package/tools/file-export.js +32 -9
- package/tools/file-process.js +3 -0
- package/tools/project-preview.js +110 -97
- package/dataInit/commonTypeMap.js +0 -31
- package/dataInit/marketingActivitiesMap.js +0 -214
- package/dataInit/orderMap.js +0 -13
- package/dataInit/personalMap.js +0 -19
- package/dataInit/settlementMap.js +0 -17
- package/types/unused.index.d.ts +0 -71
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 深度合并对象
|
|
3
|
+
* @param {Object} target - 目标对象
|
|
4
|
+
* @param {Object} source - 源对象
|
|
5
|
+
* @param {boolean} overwrite - 是否覆盖已存在的属性,默认 false
|
|
6
|
+
* @returns {Object} 合并后的目标对象
|
|
7
|
+
*/
|
|
8
|
+
function deepMerge(target, source, overwrite = false) {
|
|
9
|
+
if (!source || typeof source !== "object") return target;
|
|
10
|
+
if (!target || typeof target !== "object") return source;
|
|
11
|
+
|
|
12
|
+
Object.keys(source).forEach((key) => {
|
|
13
|
+
const sourceValue = source[key];
|
|
14
|
+
const targetValue = target[key];
|
|
15
|
+
|
|
16
|
+
if (Array.isArray(sourceValue)) {
|
|
17
|
+
if (!overwrite && targetValue !== undefined) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
target[key] = [...sourceValue];
|
|
21
|
+
} else if (sourceValue && typeof sourceValue === "object") {
|
|
22
|
+
if (!target[key] || typeof target[key] !== "object") {
|
|
23
|
+
target[key] = {};
|
|
24
|
+
}
|
|
25
|
+
deepMerge(target[key], sourceValue, overwrite);
|
|
26
|
+
} else if (!overwrite && targetValue !== undefined) {
|
|
27
|
+
return;
|
|
28
|
+
} else {
|
|
29
|
+
target[key] = sourceValue;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
return target;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = {
|
|
37
|
+
deepMerge
|
|
38
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
const sameValue = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
2
|
+
|
|
3
|
+
const hasOwn = (target, key) => Object.prototype.hasOwnProperty.call(target, key);
|
|
4
|
+
|
|
5
|
+
function mergePageConfig(...sources) {
|
|
6
|
+
const pageConfig = {};
|
|
7
|
+
|
|
8
|
+
sources.forEach((source) => {
|
|
9
|
+
Object.keys(source || {}).forEach((key) => {
|
|
10
|
+
const value = source[key];
|
|
11
|
+
|
|
12
|
+
if (hasOwn(pageConfig, key) && !sameValue(pageConfig[key], value)) {
|
|
13
|
+
console.warn(
|
|
14
|
+
`[page-config] duplicate pageConfig key "${key}" has different values.`
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
pageConfig[key] = value;
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
return pageConfig;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function normalizePlatforms(platforms = [], platformGroups = {}) {
|
|
26
|
+
return platforms.reduce((result, platform) => {
|
|
27
|
+
if (platformGroups[platform]) {
|
|
28
|
+
result.push(...platformGroups[platform]);
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
result.push(platform);
|
|
32
|
+
return result;
|
|
33
|
+
}, []);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function normalizePlatformKey(key, platformGroups) {
|
|
37
|
+
return normalizePlatforms(
|
|
38
|
+
key.split(",").map((platform) => platform.trim()),
|
|
39
|
+
platformGroups
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function getPlatformChain(platform, platformExtends = {}) {
|
|
44
|
+
const chain = [];
|
|
45
|
+
let current = platform;
|
|
46
|
+
|
|
47
|
+
while (current && !chain.includes(current)) {
|
|
48
|
+
chain.push(current);
|
|
49
|
+
current = platformExtends[current];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return chain;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function resolvePageConfigValue(config, platform, options = {}) {
|
|
56
|
+
const { platformGroups = {}, platformExtends = {} } = options;
|
|
57
|
+
const platformChain = getPlatformChain(platform, platformExtends);
|
|
58
|
+
|
|
59
|
+
if (Array.isArray(config)) {
|
|
60
|
+
const platforms = normalizePlatforms(config, platformGroups);
|
|
61
|
+
return platformChain.some((item) => platforms.includes(item))
|
|
62
|
+
? true
|
|
63
|
+
: undefined;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!config || typeof config !== "object") {
|
|
67
|
+
return config;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const exactPlatform = platformChain.find((item) => hasOwn(config, item));
|
|
71
|
+
|
|
72
|
+
if (exactPlatform) {
|
|
73
|
+
return config[exactPlatform];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const matchedKey = Object.keys(config).find((key) => {
|
|
77
|
+
if (key === "DEFAULT") {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
const platforms = normalizePlatformKey(key, platformGroups);
|
|
81
|
+
return platformChain.some((item) => platforms.includes(item));
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
if (matchedKey) {
|
|
85
|
+
return config[matchedKey];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return config.DEFAULT;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function resolvePlatformPageConfig(pageConfig = {}, platform = "DEFAULT", options = {}) {
|
|
92
|
+
const resolvedConfig = {};
|
|
93
|
+
const keys = Object.keys(pageConfig);
|
|
94
|
+
const normalKeys = keys.filter((key) => !key.startsWith("!"));
|
|
95
|
+
const negatedKeys = keys.filter((key) => key.startsWith("!"));
|
|
96
|
+
|
|
97
|
+
normalKeys.forEach((key) => {
|
|
98
|
+
const value = resolvePageConfigValue(pageConfig[key], platform, options);
|
|
99
|
+
if (value !== undefined) {
|
|
100
|
+
resolvedConfig[key] = value;
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// "!showXxx": ["PARTNER"] → 命中平台时解析为 showXxx: false
|
|
105
|
+
negatedKeys.forEach((key) => {
|
|
106
|
+
const configKey = key.slice(1);
|
|
107
|
+
const value = resolvePageConfigValue(pageConfig[key], platform, options);
|
|
108
|
+
if (value === true) {
|
|
109
|
+
resolvedConfig[configKey] = false;
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
return resolvedConfig;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
module.exports = {
|
|
117
|
+
mergePageConfig,
|
|
118
|
+
resolvePlatformPageConfig
|
|
119
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
function normalizeRuleDomains(domains) {
|
|
2
|
+
if (!Array.isArray(domains)) {
|
|
3
|
+
return [];
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
return domains
|
|
7
|
+
.filter(Boolean)
|
|
8
|
+
.map((domain) => String(domain).trim().replace(/\/+$/, ""));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function normalizePathIncludes(pathIncludes) {
|
|
12
|
+
if (!Array.isArray(pathIncludes)) {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return pathIncludes.filter(Boolean).map((path) => String(path));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function resolveInternalServiceURL(url, rules = []) {
|
|
20
|
+
if (!url || !Array.isArray(rules) || rules.length === 0) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let parsed;
|
|
25
|
+
try {
|
|
26
|
+
parsed = new URL(url);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const requestOrigin = parsed.origin.replace(/\/+$/, "");
|
|
32
|
+
const requestPath = parsed.pathname || "/";
|
|
33
|
+
|
|
34
|
+
for (const rule of rules) {
|
|
35
|
+
const domains = normalizeRuleDomains(rule.domains);
|
|
36
|
+
const pathIncludes = normalizePathIncludes(rule.pathIncludes);
|
|
37
|
+
const domainMatched = domains.includes(requestOrigin);
|
|
38
|
+
const pathMatched =
|
|
39
|
+
pathIncludes.length === 0 ||
|
|
40
|
+
pathIncludes.some((path) => requestPath.includes(path));
|
|
41
|
+
|
|
42
|
+
if (domainMatched && pathMatched) {
|
|
43
|
+
return {
|
|
44
|
+
url: `${requestPath}${parsed.search || ""}`,
|
|
45
|
+
baseURL: rule.baseURL || "/"
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
module.exports = {
|
|
54
|
+
resolveInternalServiceURL
|
|
55
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@infly/libs",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.37",
|
|
4
4
|
"description": "工具组件库",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
"postinstall": "node index.js",
|
|
9
9
|
"publishPkg": "npm version patch && npm publish --access=public --registry=https://registry.npmjs.org/",
|
|
10
10
|
"preview": "infly-libs --preview",
|
|
11
|
-
"preview:no-build": "infly-libs --preview --no-build"
|
|
11
|
+
"preview:no-build": "infly-libs --preview --no-build",
|
|
12
|
+
"origin:preview": "infly-libs --preview",
|
|
13
|
+
"origin:preview:no-build": "infly-libs --preview --no-build"
|
|
12
14
|
},
|
|
13
15
|
"bin": {
|
|
14
16
|
"infly-libs": "bin/cli.js"
|
|
@@ -33,12 +35,12 @@
|
|
|
33
35
|
"author": "Kahal",
|
|
34
36
|
"license": "ISC",
|
|
35
37
|
"dependencies": {},
|
|
36
|
-
"devDependencies
|
|
37
|
-
"@babel/core": "^7.
|
|
38
|
-
"@babel/preset-env": "^7.
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@babel/core": "^7.23.3",
|
|
40
|
+
"@babel/preset-env": "^7.23.3",
|
|
39
41
|
"babel-loader": "^10.0.0",
|
|
40
|
-
"webpack": "^5.
|
|
41
|
-
"webpack-cli": "^
|
|
42
|
+
"webpack": "^5.88.2",
|
|
43
|
+
"webpack-cli": "^5.1.4",
|
|
42
44
|
"webpack-node-externals": "^3.0.0"
|
|
43
45
|
},
|
|
44
46
|
"peerDependencies": {
|
|
@@ -50,12 +52,11 @@
|
|
|
50
52
|
"html-webpack-plugin": "^5.5.3"
|
|
51
53
|
},
|
|
52
54
|
"infly": {
|
|
53
|
-
"
|
|
55
|
+
"buildConfigs": {
|
|
54
56
|
"buildFoldName": "[构建后目录名] 可选, 默认取值vue.config.js的outputDir, 配置化 eg: postal-benefits-level-pc",
|
|
55
57
|
"outputPath": "[输出文件目录链接] eg: ./ ",
|
|
56
58
|
"enabled": "[是否启用压缩] eg: true",
|
|
57
59
|
"gitAuto": "[是否自动提交git] eg: true",
|
|
58
|
-
"gitAutoPushRepos": "[自动提交推送git构建仓库] eg: frontend",
|
|
59
60
|
"gitAutoPushReposBranchMap": {
|
|
60
61
|
"release-eg": "develop-eg [自动提交推送项目构建分支和构建仓库推送分支对应配置,必须]"
|
|
61
62
|
},
|
|
@@ -73,7 +74,7 @@
|
|
|
73
74
|
"versionConfig": {
|
|
74
75
|
"mainVersion": "[主版本号] 可选, 默认取值项目package version, eg: 1",
|
|
75
76
|
"links": {
|
|
76
|
-
"master": "[master分支构建文件推送地址] eg: e.sutpay.com",
|
|
77
|
+
"master": "[master分支构建文件推送地址] eg: https://e.sutpay.com",
|
|
77
78
|
"release": "[release分支构建文件推送地址] eg: http://114.132.55.214:8081/"
|
|
78
79
|
},
|
|
79
80
|
"platformName": "[用以split的项目平台名称] eg: 邮惠权益平台-运营端",
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const { spawn } = require("child_process");
|
|
2
|
+
|
|
3
|
+
function run(command, args, options = {}) {
|
|
4
|
+
return new Promise((resolve, reject) => {
|
|
5
|
+
const child = spawn(command, args, {
|
|
6
|
+
cwd: options.cwd || process.cwd(),
|
|
7
|
+
env: {
|
|
8
|
+
...process.env,
|
|
9
|
+
...(options.env || {})
|
|
10
|
+
},
|
|
11
|
+
stdio: options.stdio || "inherit",
|
|
12
|
+
shell: process.platform === "win32"
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
child.on("close", (code) => {
|
|
16
|
+
if (code === 0) {
|
|
17
|
+
resolve();
|
|
18
|
+
} else {
|
|
19
|
+
reject(new Error(`${command} ${args.join(" ")} failed with exit code ${code}`));
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
child.on("error", reject);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function spawnBackground(command, args, options = {}) {
|
|
28
|
+
const child = spawn(command, args, {
|
|
29
|
+
cwd: options.cwd || process.cwd(),
|
|
30
|
+
env: {
|
|
31
|
+
...process.env,
|
|
32
|
+
...(options.env || {})
|
|
33
|
+
},
|
|
34
|
+
stdio: options.stdio || "inherit",
|
|
35
|
+
shell: process.platform === "win32"
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
child.on("error", (error) => {
|
|
39
|
+
console.error(error.message);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return child;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
module.exports = {
|
|
46
|
+
run,
|
|
47
|
+
spawnBackground
|
|
48
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const ENV = {
|
|
2
|
+
buildContext: "INFLY_BUILD_CONTEXT",
|
|
3
|
+
batchWebhookFile: "INFLY_BATCH_WEBHOOK_FILE",
|
|
4
|
+
batchPreview: "INFLY_BATCH_PREVIEW",
|
|
5
|
+
skipPreview: "INFLY_SKIP_PREVIEW",
|
|
6
|
+
skipPackagesUpdate: "INFLY_SKIP_PACKAGES_UPDATE",
|
|
7
|
+
skipBranchUpdate: "INFLY_SKIP_BRANCH_UPDATE"
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
function parseBuildContext() {
|
|
11
|
+
try {
|
|
12
|
+
return JSON.parse(process.env[ENV.buildContext] || "{}");
|
|
13
|
+
} catch {
|
|
14
|
+
return {};
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function createBuildContext(value) {
|
|
19
|
+
return {
|
|
20
|
+
[ENV.buildContext]: JSON.stringify(value || {})
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
module.exports = {
|
|
25
|
+
ENV,
|
|
26
|
+
parseBuildContext,
|
|
27
|
+
createBuildContext
|
|
28
|
+
};
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const { checkAndUpdatePackages } = require("../git-automation");
|
|
4
|
+
const { gitOutput, findGitRepo, getGitCommonDir } = require("../git-automation/git-utils");
|
|
5
|
+
const { run } = require("./command");
|
|
6
|
+
|
|
7
|
+
function getTargetBranch(rootPackageJson, mode) {
|
|
8
|
+
const branchMap = rootPackageJson.projectConfig?.buildBranchMap || {};
|
|
9
|
+
return branchMap[mode] || (mode === "prod" ? "master" : "develop");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function hasPackageGitRepos(rootDir) {
|
|
13
|
+
const packagesDir = path.join(rootDir, "packages");
|
|
14
|
+
|
|
15
|
+
if (!fs.existsSync(packagesDir)) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return ["infly-libs", "infly-ui"].some((name) => fs.existsSync(path.join(packagesDir, name, ".git")));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function updatePackageSources(rootDir) {
|
|
23
|
+
console.log("\x1b[32m%s\x1b[0m", "更新 admin-monorepo / packages 源码");
|
|
24
|
+
|
|
25
|
+
if (hasPackageGitRepos(rootDir)) {
|
|
26
|
+
console.log(" 使用 packages/* 独立 git 仓库模式,拉取 master");
|
|
27
|
+
} else {
|
|
28
|
+
console.log(" 使用 admin-monorepo 根仓库模式,拉取 master");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
global.logColor = global.logColor || {
|
|
32
|
+
success: "\n\x1b[32m%s\x1b[0m",
|
|
33
|
+
error: "\n\x1b[31m%s\x1b[0m",
|
|
34
|
+
warning: "\n\x1b[33m%s\x1b[0m",
|
|
35
|
+
link: "\x1b[34m%s\x1b[0m",
|
|
36
|
+
info: "\n\x1b[36m%s\x1b[0m"
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const packagesDir = path.join(rootDir, "packages");
|
|
40
|
+
await checkAndUpdatePackages(fs.existsSync(packagesDir) ? packagesDir : undefined, "master");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function getPackageSourcesKey(rootDir) {
|
|
44
|
+
if (!hasPackageGitRepos(rootDir)) {
|
|
45
|
+
return getGitCommonDir(rootDir);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return path.join(rootDir, "packages");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function findExistingAncestor(targetDir) {
|
|
52
|
+
let current = targetDir;
|
|
53
|
+
|
|
54
|
+
while (!fs.existsSync(current)) {
|
|
55
|
+
const parent = path.dirname(current);
|
|
56
|
+
|
|
57
|
+
if (parent === current) {
|
|
58
|
+
return "";
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
current = parent;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return current;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function getDistRepoInfo(rootDir, pkg, targetBranch, options = {}) {
|
|
68
|
+
const packageRoot = path.join(rootDir, pkg.dir);
|
|
69
|
+
const vueConfigPath = path.join(packageRoot, "vue.config.js");
|
|
70
|
+
const nextConfigJs = path.join(packageRoot, "next.config.js");
|
|
71
|
+
const nextConfigMjs = path.join(packageRoot, "next.config.mjs");
|
|
72
|
+
const nextConfigTs = path.join(packageRoot, "next.config.ts");
|
|
73
|
+
const hasVueConfig = fs.existsSync(vueConfigPath);
|
|
74
|
+
const hasNextConfig = !hasVueConfig && (
|
|
75
|
+
fs.existsSync(nextConfigJs) ||
|
|
76
|
+
fs.existsSync(nextConfigMjs) ||
|
|
77
|
+
fs.existsSync(nextConfigTs)
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
let outputDir;
|
|
81
|
+
|
|
82
|
+
if (hasVueConfig) {
|
|
83
|
+
outputDir = require(vueConfigPath).outputDir;
|
|
84
|
+
} else if (hasNextConfig) {
|
|
85
|
+
outputDir = pkg.packageJson.infly?.buildConfigs?.outputPath;
|
|
86
|
+
} else {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (outputDir && !path.isAbsolute(outputDir)) {
|
|
91
|
+
outputDir = path.resolve(packageRoot, outputDir);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (!outputDir) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const existingOutputDir = fs.existsSync(outputDir) ? outputDir : findExistingAncestor(outputDir);
|
|
99
|
+
|
|
100
|
+
if (!existingOutputDir) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const branchMap = pkg.packageJson.infly?.buildConfigs?.gitAutoPushReposBranchMap || {};
|
|
105
|
+
const distBranch = branchMap[targetBranch] || targetBranch;
|
|
106
|
+
let repoRoot = existingOutputDir;
|
|
107
|
+
let repoKey = existingOutputDir;
|
|
108
|
+
const repo = findGitRepo(existingOutputDir);
|
|
109
|
+
|
|
110
|
+
if (repo) {
|
|
111
|
+
repoRoot = repo.root;
|
|
112
|
+
repoKey = repo.commonDir;
|
|
113
|
+
} else {
|
|
114
|
+
try {
|
|
115
|
+
repoRoot = gitOutput(["-C", existingOutputDir, "rev-parse", "--show-toplevel"], rootDir);
|
|
116
|
+
repoKey = getGitCommonDir(existingOutputDir);
|
|
117
|
+
} catch (error) {
|
|
118
|
+
if (!options.allowPathFallback) {
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
cwd: repoRoot,
|
|
126
|
+
branch: distBranch,
|
|
127
|
+
key: repoKey,
|
|
128
|
+
label: `dist(${path.relative(rootDir, repoRoot)})`
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function getDistRepoTasks(rootDir, packages, targetBranch, options = {}) {
|
|
133
|
+
const repos = new Map();
|
|
134
|
+
|
|
135
|
+
packages.forEach((pkg) => {
|
|
136
|
+
const repo = getDistRepoInfo(rootDir, pkg, targetBranch, options);
|
|
137
|
+
|
|
138
|
+
if (repo && !repos.has(repo.key)) {
|
|
139
|
+
repos.set(repo.key, {
|
|
140
|
+
cwd: repo.cwd,
|
|
141
|
+
branch: repo.branch,
|
|
142
|
+
key: repo.key,
|
|
143
|
+
label: repo.label
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
return Array.from(repos.values());
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async function pullGitRepo(task) {
|
|
152
|
+
console.log("\x1b[32m%s\x1b[0m", `更新 ${task.label} -> ${task.branch}`);
|
|
153
|
+
const status = gitOutput(["status", "--porcelain"], task.cwd);
|
|
154
|
+
|
|
155
|
+
if (status) {
|
|
156
|
+
throw new Error(`${task.label} 存在未提交的更改,无法自动切换并拉取 ${task.branch}\n${status}`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
await run("git", ["checkout", task.branch], { cwd: task.cwd });
|
|
160
|
+
await run("git", ["pull", "origin", task.branch], { cwd: task.cwd });
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function getAppAndDistSourceTasks(rootDir, packages, targetBranch) {
|
|
164
|
+
const appTasks = packages.map((pkg) => {
|
|
165
|
+
const cwd = path.join(rootDir, pkg.dir);
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
cwd,
|
|
169
|
+
branch: targetBranch,
|
|
170
|
+
label: pkg.name,
|
|
171
|
+
key: getGitCommonDir(cwd),
|
|
172
|
+
run: pullGitRepo
|
|
173
|
+
};
|
|
174
|
+
});
|
|
175
|
+
const distTasks = getDistRepoTasks(rootDir, packages, targetBranch).map((task) => ({
|
|
176
|
+
...task,
|
|
177
|
+
run: pullGitRepo
|
|
178
|
+
}));
|
|
179
|
+
|
|
180
|
+
return [...appTasks, ...distTasks];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async function runSourceTasksWithOverlapCheck(tasks) {
|
|
184
|
+
const groups = new Map();
|
|
185
|
+
|
|
186
|
+
tasks.forEach((task) => {
|
|
187
|
+
const key = task.key || task.cwd || task.label;
|
|
188
|
+
|
|
189
|
+
if (!groups.has(key)) {
|
|
190
|
+
groups.set(key, []);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
groups.get(key).push(task);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
await Promise.all(
|
|
197
|
+
Array.from(groups.values()).map(async (group) => {
|
|
198
|
+
for (const task of group) {
|
|
199
|
+
await task.run(task);
|
|
200
|
+
}
|
|
201
|
+
})
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
async function updateAppAndDistSources(rootDir, packages, targetBranch) {
|
|
206
|
+
const tasks = getAppAndDistSourceTasks(rootDir, packages, targetBranch);
|
|
207
|
+
|
|
208
|
+
console.log("\x1b[32m%s\x1b[0m", "并行更新 app / dist 源码");
|
|
209
|
+
|
|
210
|
+
await runSourceTasksWithOverlapCheck(tasks);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async function updateAllSources(rootDir, packages, targetBranch) {
|
|
214
|
+
const tasks = [
|
|
215
|
+
{
|
|
216
|
+
label: "admin-monorepo/packages",
|
|
217
|
+
key: getPackageSourcesKey(rootDir),
|
|
218
|
+
run: () => updatePackageSources(rootDir)
|
|
219
|
+
},
|
|
220
|
+
...getAppAndDistSourceTasks(rootDir, packages, targetBranch)
|
|
221
|
+
];
|
|
222
|
+
|
|
223
|
+
await runSourceTasksWithOverlapCheck(tasks);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function printDryRunSourceUpdatePlan(rootDir, packages, targetBranch) {
|
|
227
|
+
console.log("并行拉取:");
|
|
228
|
+
console.log(" 1. admin-monorepo/packages -> master");
|
|
229
|
+
packages.forEach((pkg, index) => {
|
|
230
|
+
console.log(` ${index + 2}. ${pkg.name} -> ${targetBranch} (${pkg.dir})`);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
const distTasks = getDistRepoTasks(rootDir, packages, targetBranch, { allowPathFallback: true });
|
|
234
|
+
|
|
235
|
+
if (distTasks.length === 0) {
|
|
236
|
+
console.log(` ${packages.length + 2}. dist 仓库 -> 未解析到可拉取仓库`);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
distTasks.forEach((task, index) => {
|
|
241
|
+
console.log(` ${packages.length + 2 + index}. ${task.label} -> ${task.branch} (${path.relative(rootDir, task.cwd)})`);
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
module.exports = {
|
|
246
|
+
getTargetBranch,
|
|
247
|
+
updatePackageSources,
|
|
248
|
+
updateAppAndDistSources,
|
|
249
|
+
updateAllSources,
|
|
250
|
+
getDistRepoTasks,
|
|
251
|
+
printDryRunSourceUpdatePlan
|
|
252
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const { spawn } = require("child_process");
|
|
3
|
+
const { spawnBackground } = require("./command");
|
|
4
|
+
const { createBuildContext } = require("./env");
|
|
5
|
+
|
|
6
|
+
function killPreviewChild(child) {
|
|
7
|
+
if (!child || child.killed) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (process.platform === "win32") {
|
|
12
|
+
spawn("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
|
|
13
|
+
stdio: "ignore",
|
|
14
|
+
windowsHide: true
|
|
15
|
+
});
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
child.kill();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function startBatchPreviews(rootDir, packages) {
|
|
23
|
+
const previewPackages = packages.filter((pkg) => {
|
|
24
|
+
return pkg.packageJson.infly?.buildConfigs?.enablePreview !== false;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
if (previewPackages.length === 0) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
console.log("\n\x1b[32m%s\x1b[0m", "\x1b[42m\x1b[30m DONE \x1b[0m\x1b[32m 项目构建预览,CTRL + C 结束:");
|
|
32
|
+
|
|
33
|
+
const children = previewPackages.map((pkg) => {
|
|
34
|
+
const child = spawnBackground("infly-libs", ["preview", "--no-build"], {
|
|
35
|
+
cwd: path.join(rootDir, pkg.dir),
|
|
36
|
+
env: createBuildContext({
|
|
37
|
+
batchPreview: true
|
|
38
|
+
})
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// console.log(`preview ${pkg.name}: pid ${child.pid}`);
|
|
42
|
+
|
|
43
|
+
child.on("close", (code, signal) => {
|
|
44
|
+
if (code === 0 || signal) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
console.log(`preview ${pkg.name} 已退出,code=${code}`);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
child.on("error", (error) => {
|
|
52
|
+
console.error(`preview ${pkg.name} 启动失败:${error.message}`);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return child;
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const stop = () => {
|
|
59
|
+
children.forEach(killPreviewChild);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
process.on("SIGINT", () => {
|
|
63
|
+
stop();
|
|
64
|
+
process.exit(0);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
process.on("SIGTERM", () => {
|
|
68
|
+
stop();
|
|
69
|
+
process.exit(0);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
module.exports = {
|
|
74
|
+
startBatchPreviews
|
|
75
|
+
};
|