@infly/libs 2.0.37 → 2.0.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -37,3 +37,23 @@
37
37
  # 项目安装
38
38
  npm/pnpm install @infly/libs
39
39
  ```
40
+
41
+ ## Docker 镜像构建
42
+
43
+ 在应用目录中执行:
44
+
45
+ ```bash
46
+ infly-libs build:docker --local --env prod
47
+ ```
48
+
49
+ 可通过可选参数 `--cicd-url` 在构建和镜像推送全部成功后输出蓝色发布系统链接。支持等号和空格两种传参形式:
50
+
51
+ ```bash
52
+ infly-libs build:docker --local --cicd-url="https://cicd.sutpay.com/view/积分商城/"
53
+ ```
54
+
55
+ ```bash
56
+ infly-libs build:docker --local --cicd-url "https://cicd.sutpay.com/view/积分商城/"
57
+ ```
58
+
59
+ 未传 `--cicd-url` 时保持原有输出。参数值必须是合法的 HTTP/HTTPS URL,且不能包含用户名、密码或控制字符。
package/bin/cli.js CHANGED
@@ -8,31 +8,74 @@ function loadPreview() {
8
8
  return require("../tools/project-preview");
9
9
  }
10
10
 
11
- const command = process.argv[2];
12
- const commandMap = {
13
- afterBuild: () => loadBuildDist().init(),
14
- initZip: () => loadBuildDist().init(),
15
- preview: () => loadPreview().init(),
16
- "--preview": () => loadPreview().init(),
17
- beforeBuild: () => loadBuildDist().beforeBuild(),
18
- scriptOverride: () => {
19
- const preview = loadPreview();
20
- const buildDist = loadBuildDist();
21
-
22
- preview.scriptInit();
23
- buildDist.scriptInit();
11
+ function parseArgs(argv) {
12
+ const options = { env: "prod", local: false, dryRun: false };
13
+ let i = 0;
14
+ while (i < argv.length) {
15
+ const arg = argv[i];
16
+ if (arg.startsWith("--cicd-url=")) {
17
+ const value = arg.slice("--cicd-url=".length);
18
+ if (!value) {
19
+ throw new Error("--cicd-url 缺少参数值");
20
+ }
21
+ options.cicdUrl = value;
22
+ i++;
23
+ continue;
24
+ }
25
+
26
+ switch (arg) {
27
+ case "--local": options.local = true; i++; break;
28
+ case "--env": options.env = argv[i + 1]; i += 2; break;
29
+ case "--dry-run": options.dryRun = true; i++; break;
30
+ case "--cicd-url": {
31
+ const value = argv[i + 1];
32
+ if (!value || value.startsWith("--")) {
33
+ throw new Error("--cicd-url 缺少参数值");
34
+ }
35
+ options.cicdUrl = value;
36
+ i += 2;
37
+ break;
38
+ }
39
+ default: i++;
40
+ }
24
41
  }
25
- };
42
+ return options;
43
+ }
44
+
45
+ async function main(argv = process.argv.slice(2)) {
46
+ const command = argv[0];
47
+ const commandMap = {
48
+ afterBuild: () => loadBuildDist().init(),
49
+ initZip: () => loadBuildDist().init(),
50
+ preview: () => loadPreview().init(),
51
+ "--preview": () => loadPreview().init(),
52
+ beforeBuild: () => loadBuildDist().beforeBuild(),
53
+ scriptOverride: () => {
54
+ const preview = loadPreview();
55
+ const buildDist = loadBuildDist();
56
+ preview.scriptInit();
57
+ buildDist.scriptInit();
58
+ },
59
+ "build:docker": () => {
60
+ const opts = parseArgs(argv.slice(1));
61
+ return require("../build/docker/docker-build-push").dockerBuildPush(opts);
62
+ },
63
+ };
26
64
 
27
- (async () => {
28
65
  if (command && commandMap[command]) {
29
66
  await commandMap[command]();
30
67
  } else {
31
68
  console.error(`未知命令: ${command || "未提供命令"}`);
32
69
  console.log(`可用命令: ${Object.keys(commandMap).join(", ")}`);
33
- process.exit(1);
70
+ process.exitCode = 1;
34
71
  }
35
- })().catch((error) => {
36
- console.error("执行失败:", error);
37
- process.exit(1);
38
- });
72
+ }
73
+
74
+ if (require.main === module) {
75
+ main().catch((error) => {
76
+ console.error("执行失败:", error.message || error);
77
+ process.exitCode = 1;
78
+ });
79
+ }
80
+
81
+ module.exports = { main, parseArgs };
@@ -33,6 +33,7 @@ const {
33
33
  checkSingleDirGitStatus,
34
34
  pullSingleDirFromBranch
35
35
  } = require("../../script/git-automation");
36
+ const { resolveSiblingAppDeps } = require("../../script/build/deps");
36
37
 
37
38
  const scriptEvent = process.env.npm_lifecycle_event;
38
39
  const isBuilZipScript = process.env.npm_lifecycle_event;
@@ -62,11 +63,11 @@ const { title: projectTitle } = fs.existsSync(targetProjectSettingsJS) ? require
62
63
 
63
64
  const isExistTargetProjectVersionConfig = fs.existsSync(targetProjectVersionConfigPath); // 安装依赖项目下是否存在旧版本控制文件
64
65
  const isExistVueConfigFile = fs.existsSync(targetProjectVueConfigPath); // 安装依赖项目下是否存在vue.config.js文件
65
- const hasNextConfig = !isExistVueConfigFile && ( // Next.js 项目检测
66
- fs.existsSync(targetProjectFileResolve("next.config.js")) ||
67
- fs.existsSync(targetProjectFileResolve("next.config.mjs")) ||
68
- fs.existsSync(targetProjectFileResolve("next.config.ts"))
69
- );
66
+ const hasNextConfig =
67
+ !isExistVueConfigFile && // Next.js 项目检测
68
+ (fs.existsSync(targetProjectFileResolve("next.config.js")) ||
69
+ fs.existsSync(targetProjectFileResolve("next.config.mjs")) ||
70
+ fs.existsSync(targetProjectFileResolve("next.config.ts")));
70
71
  const isMaster = currentBranch === "master"; // 是否在master分支
71
72
  const isPkg = versionFileName === "package.json";
72
73
 
@@ -832,6 +833,27 @@ async function beforeBuild() {
832
833
  if (process.env.INFLY_SKIP_PACKAGES_UPDATE !== "1") {
833
834
  await checkAndUpdatePackages(undefined, "master");
834
835
  }
836
+
837
+ // 5. 检查并更新兄弟 app 依赖(通过 build config 中的 alias 推断,无需硬编码 app 名称)
838
+ if (process.env.INFLY_SKIP_SIBLING_UPDATE !== "1") {
839
+ const siblingDirs = resolveSiblingAppDeps(projectRoot);
840
+
841
+ for (const siblingDir of siblingDirs) {
842
+ const siblingName = path.basename(siblingDir);
843
+ const siblingStatus = checkSingleDirGitStatus(siblingDir, siblingName);
844
+
845
+ if (siblingStatus.hasUncommitted) {
846
+ console.log(global.logColor.error, `\n❌ 兄弟项目 ${siblingName} 存在未提交的更改,请先提交或暂存后再继续构建`);
847
+ process.exit(1);
848
+ }
849
+
850
+ const siblingUpdateResult = pullSingleDirFromBranch(siblingDir, siblingName, targetBranch);
851
+
852
+ if (!siblingUpdateResult.success) {
853
+ console.log(global.logColor.warning, `\n⚠️ 兄弟项目 ${siblingName} 更新失败,但可以继续执行`);
854
+ }
855
+ }
856
+ }
835
857
  }
836
858
  module.exports = {
837
859
  init,
@@ -0,0 +1,240 @@
1
+ /**
2
+ * Docker 镜像构建与推送(infly-libs 公共模块)
3
+ *
4
+ * 支持两种运行模式(自动检测):
5
+ *
6
+ * 1. Monorepo 模式 — 检测到 git submodule (--show-superproject-working-tree 有值)
7
+ * 构建上下文 = superproject 根,Dockerfile 使用 Dockerfile.monorepo
8
+ * @infly/* 包从 workspace 源码解析
9
+ *
10
+ * 2. 独立模式 — 非 submodule 且 cwd = git 根
11
+ * 构建上下文 = 当前目录,Dockerfile 使用 Dockerfile
12
+ * @infly/* 包从 npm registry 安装
13
+ *
14
+ * 用法:
15
+ * infly-libs build:docker [--local] [--env prod|dev] [--dry-run] [--cicd-url URL]
16
+ */
17
+
18
+ const { execSync } = require("child_process");
19
+ const fs = require("fs");
20
+ const path = require("path");
21
+
22
+ // ---------- 默认配置 ----------
23
+ const DEFAULT_REGISTRY = "ccr.ccs.tencentyun.com";
24
+ const DEFAULT_NAMESPACE = "points";
25
+
26
+ function formatCicdLink(value) {
27
+ if (value === undefined) {
28
+ return "";
29
+ }
30
+ if (typeof value !== "string" || !value.trim()) {
31
+ throw new Error("--cicd-url 缺少参数值");
32
+ }
33
+
34
+ const rawUrl = value.trim();
35
+ if (/[\u0000-\u001f\u007f]/.test(rawUrl)) {
36
+ throw new Error("--cicd-url 不能包含控制字符");
37
+ }
38
+
39
+ let parsedUrl;
40
+ try {
41
+ parsedUrl = new URL(rawUrl);
42
+ } catch {
43
+ throw new Error("--cicd-url 必须是合法的 HTTP/HTTPS URL");
44
+ }
45
+
46
+ if (!['http:', 'https:'].includes(parsedUrl.protocol)) {
47
+ throw new Error("--cicd-url 只支持 HTTP/HTTPS URL");
48
+ }
49
+ if (parsedUrl.username || parsedUrl.password) {
50
+ throw new Error("--cicd-url 不能包含用户名或密码凭据");
51
+ }
52
+
53
+ return `发布系统:\x1b[34m${decodeURI(parsedUrl.href)}\x1b[0m`;
54
+ }
55
+
56
+ function detectMode() {
57
+ const cwd = path.resolve(process.cwd());
58
+
59
+ // git submodule → monorepo 模式,contextRoot = superproject 根
60
+ try {
61
+ const superproject = execSync("git rev-parse --show-superproject-working-tree", {
62
+ encoding: "utf-8", stdio: "pipe",
63
+ }).trim();
64
+ if (superproject) {
65
+ return { isStandalone: false, contextRoot: superproject };
66
+ }
67
+ } catch {}
68
+
69
+ // 非 submodule:cwd = git 根 → 独立模式,否则 monorepo 模式
70
+ const gitRoot = execSync("git rev-parse --show-toplevel", { encoding: "utf-8" }).trim();
71
+ const isStandalone = path.resolve(cwd) === path.resolve(gitRoot);
72
+
73
+ return {
74
+ isStandalone,
75
+ contextRoot: isStandalone ? cwd : gitRoot,
76
+ };
77
+ }
78
+
79
+ function run(cmd, { silent = false, dryRun = false, cwd } = {}) {
80
+ if (dryRun) {
81
+ console.log(` [DRY RUN] ${cmd}`);
82
+ return "";
83
+ }
84
+ return execSync(cmd, {
85
+ stdio: silent ? "pipe" : "inherit",
86
+ cwd: cwd || process.cwd(),
87
+ encoding: "utf-8",
88
+ });
89
+ }
90
+
91
+ function startDockerDesktop() {
92
+ console.log("\x1b[1;33mDocker Desktop 未运行,正在启动...\x1b[0m");
93
+ try {
94
+ try {
95
+ execSync(
96
+ `powershell.exe -Command "Start-Process 'C:\\Program Files\\Docker\\Docker\\Docker Desktop.exe'"`,
97
+ { stdio: "ignore" }
98
+ );
99
+ } catch {
100
+ execSync(
101
+ `cmd.exe /c start "" "C:\\Program Files\\Docker\\Docker\\Docker Desktop.exe"`,
102
+ { stdio: "ignore" }
103
+ );
104
+ }
105
+
106
+ process.stdout.write("等待 Docker 引擎就绪");
107
+ for (let i = 0; i < 30; i++) {
108
+ try {
109
+ execSync("docker info", { stdio: "ignore" });
110
+ console.log("\n\x1b[0;32m✓ Docker 已就绪\x1b[0m");
111
+ return true;
112
+ } catch {}
113
+ process.stdout.write(".");
114
+ execSync("sleep 2", { stdio: "ignore" });
115
+ }
116
+ console.log("");
117
+ return false;
118
+ } catch {
119
+ return false;
120
+ }
121
+ }
122
+
123
+ async function dockerBuildPush(options = {}) {
124
+ const {
125
+ env = "prod",
126
+ registry = DEFAULT_REGISTRY,
127
+ namespace = DEFAULT_NAMESPACE,
128
+ local = false,
129
+ dryRun = false,
130
+ cicdUrl,
131
+ } = options;
132
+ const cicdLink = formatCicdLink(cicdUrl);
133
+
134
+ // 1. 检测运行模式并定位关键路径
135
+ const cwd = path.resolve(process.cwd());
136
+ const { isStandalone, contextRoot } = detectMode();
137
+
138
+ const appPkgPath = path.join(cwd, "package.json");
139
+ if (!fs.existsSync(appPkgPath)) {
140
+ console.error("错误: 当前目录下缺少 package.json,请在 app 目录内执行");
141
+ process.exit(1);
142
+ }
143
+
144
+ let buildContext, dockerfileArg, modeLabel;
145
+ if (isStandalone) {
146
+ if (!fs.existsSync(path.join(cwd, "Dockerfile"))) {
147
+ console.error("错误: 当前目录下缺少 Dockerfile");
148
+ process.exit(1);
149
+ }
150
+ buildContext = cwd;
151
+ dockerfileArg = "Dockerfile";
152
+ modeLabel = "独立模式";
153
+ } else {
154
+ const appDir = path.relative(contextRoot, cwd).replace(/\\/g, "/");
155
+ if (!fs.existsSync(path.join(contextRoot, appDir, "Dockerfile.monorepo"))) {
156
+ console.error("错误: 缺少 Dockerfile.monorepo");
157
+ process.exit(1);
158
+ }
159
+ buildContext = contextRoot;
160
+ dockerfileArg = `${appDir}/Dockerfile.monorepo`;
161
+ modeLabel = `monorepo 模式 (${appDir})`;
162
+ }
163
+
164
+ // 2. 从 package.json 推导镜像名
165
+ const pkg = JSON.parse(fs.readFileSync(appPkgPath, "utf-8"));
166
+ const imageName = pkg.name.replace(/^@[^/]+\//, "");
167
+
168
+ // 3. 获取版本号(monorepo 模式取 superproject 的 commit)
169
+ const commitHash = execSync("git rev-parse --short HEAD", {
170
+ cwd: contextRoot, encoding: "utf-8",
171
+ }).trim();
172
+ const fullCommit = execSync("git rev-parse HEAD", {
173
+ cwd: contextRoot, encoding: "utf-8",
174
+ }).trim();
175
+
176
+ // 4. 镜像标签
177
+ const imageBase = `${registry}/${namespace}/${imageName}`;
178
+ const tags = [`${imageBase}:${commitHash}`, `${imageBase}:${env}`];
179
+ if (env === "prod") tags.push(`${imageBase}:latest`);
180
+
181
+ // 5. Docker Desktop 自动启动(仅本地模式)
182
+ if (local) {
183
+ console.log("\x1b[0;32m>>> 检查 Docker 运行状态\x1b[0m");
184
+ try {
185
+ execSync("docker info", { stdio: "ignore" });
186
+ console.log("\x1b[0;32m✓ Docker 已运行\x1b[0m");
187
+ } catch {
188
+ const ok = startDockerDesktop();
189
+ if (!ok) {
190
+ console.error("\x1b[0;31m错误: Docker Desktop 启动超时,请手动启动后重试\x1b[0m");
191
+ process.exit(1);
192
+ }
193
+ }
194
+ }
195
+
196
+ // 6. 打印信息
197
+ console.log("\x1b[0;34m==========================================");
198
+ console.log("构建并推送 Docker 镜像");
199
+ console.log("==========================================\x1b[0m");
200
+ console.log(`运行模式: ${modeLabel}`);
201
+ console.log(`镜像名称: ${imageName}`);
202
+ console.log(`环境: ${env}`);
203
+ console.log(`版本号: ${commitHash}`);
204
+ console.log("标签:");
205
+ tags.forEach((t) => console.log(` ${t}`));
206
+ console.log("");
207
+
208
+ // 7. 构建
209
+ console.log("\x1b[0;32m>>> 开始构建 Docker 镜像\x1b[0m");
210
+ const tagArgs = tags.map((t) => `-t ${t}`).join(" ");
211
+ const buildCmd = `docker build -f ${dockerfileArg} ${tagArgs} --build-arg GIT_COMMIT=${fullCommit} .`;
212
+ run(buildCmd, { cwd: buildContext, dryRun });
213
+ console.log("\x1b[0;32m✓ 镜像构建完成\x1b[0m");
214
+
215
+ // 8. 推送
216
+ console.log("");
217
+ console.log(`\x1b[0;32m>>> 推送镜像到 ${registry}\x1b[0m`);
218
+ for (const tag of tags) {
219
+ run(`docker push ${tag}`, { dryRun });
220
+ }
221
+
222
+ // 9. 结果摘要
223
+ console.log("");
224
+ console.log("\x1b[0;34m==========================================");
225
+ console.log("✅ 完成");
226
+ console.log("==========================================\x1b[0m");
227
+ console.log("可用标签:");
228
+ console.log(` ${tags[0]} (commit 精确版本)`);
229
+ console.log(` ${tags[1]} (${env} 环境)`);
230
+ if (env === "prod") console.log(` ${tags[2]} (最新)`);
231
+ if (cicdLink) {
232
+ console.log("");
233
+ console.log(cicdLink);
234
+ }
235
+ console.log("");
236
+
237
+ return { mode: isStandalone ? "standalone" : "monorepo", buildContext, imageName, commitHash, tags };
238
+ }
239
+
240
+ module.exports = { dockerBuildPush, detectMode, formatCicdLink };
@@ -0,0 +1,81 @@
1
+ const assert = require("node:assert/strict");
2
+ const path = require("node:path");
3
+ const { spawnSync } = require("node:child_process");
4
+ const test = require("node:test");
5
+
6
+ const cliPath = path.resolve(__dirname, "../../bin/cli.js");
7
+
8
+ function parseArgsInChildProcess(argv) {
9
+ const source = `
10
+ const { parseArgs } = require(${JSON.stringify(cliPath)});
11
+ process.stdout.write(JSON.stringify(parseArgs(${JSON.stringify(argv)})));
12
+ `;
13
+ return spawnSync(process.execPath, ["-e", source], {
14
+ encoding: "utf-8",
15
+ });
16
+ }
17
+
18
+ test("parseArgs keeps existing defaults and options", () => {
19
+ const result = parseArgsInChildProcess(["--local", "--env", "dev", "--dry-run"]);
20
+
21
+ assert.equal(result.status, 0, result.stderr);
22
+ assert.deepEqual(JSON.parse(result.stdout), {
23
+ env: "dev",
24
+ local: true,
25
+ dryRun: true,
26
+ });
27
+ });
28
+
29
+ test("parseArgs accepts spaced and equals cicd URL forms", () => {
30
+ const url = "https://cicd.sutpay.com/view/积分商城/";
31
+ const spaced = parseArgsInChildProcess(["--cicd-url", url]);
32
+ const equals = parseArgsInChildProcess([`--cicd-url=${url}`]);
33
+
34
+ assert.equal(spaced.status, 0, spaced.stderr);
35
+ assert.equal(equals.status, 0, equals.stderr);
36
+ assert.equal(JSON.parse(spaced.stdout).cicdUrl, url);
37
+ assert.equal(JSON.parse(equals.stdout).cicdUrl, url);
38
+ });
39
+
40
+ test("parseArgs rejects cicd URL without a value", () => {
41
+ const result = parseArgsInChildProcess(["--cicd-url"]);
42
+
43
+ assert.notEqual(result.status, 0);
44
+ assert.match(result.stderr, /--cicd-url/);
45
+ });
46
+
47
+ test("CLI keeps the existing unknown command output", () => {
48
+ const result = spawnSync(process.execPath, [cliPath, "unknown-command"], {
49
+ encoding: "utf-8",
50
+ });
51
+
52
+ assert.equal(result.status, 1);
53
+ assert.match(result.stderr, /未知命令: unknown-command/);
54
+ assert.match(result.stdout, /可用命令:/);
55
+ });
56
+
57
+ test("formatCicdLink returns no output when option is absent", () => {
58
+ const { formatCicdLink } = require("./docker-build-push");
59
+
60
+ assert.equal(formatCicdLink(), "");
61
+ });
62
+
63
+ test("formatCicdLink normalizes encoded Chinese URL and colors it blue", () => {
64
+ const { formatCicdLink } = require("./docker-build-push");
65
+ const result = formatCicdLink(
66
+ "https://cicd.sutpay.com/view/%E7%A7%AF%E5%88%86%E5%95%86%E5%9F%8E/"
67
+ );
68
+
69
+ assert.equal(
70
+ result,
71
+ "发布系统:\x1b[34mhttps://cicd.sutpay.com/view/积分商城/\x1b[0m"
72
+ );
73
+ });
74
+
75
+ test("formatCicdLink rejects unsafe URL values", () => {
76
+ const { formatCicdLink } = require("./docker-build-push");
77
+
78
+ assert.throws(() => formatCicdLink("ftp://cicd.sutpay.com/build"), /HTTP\/HTTPS/);
79
+ assert.throws(() => formatCicdLink("https://user:secret@cicd.sutpay.com/"), /凭据/);
80
+ assert.throws(() => formatCicdLink("https://cicd.sutpay.com/\nnext"), /控制字符/);
81
+ });
package/module/Uts.js CHANGED
@@ -5285,7 +5285,7 @@ true
5285
5285
  isDevMode() {
5286
5286
  if (
5287
5287
  window.location.href.indexOf("http://localhost") != 0 &&
5288
- window.location.href.indexOf("http://192.168.4") != 0 &&
5288
+ window.location.href.indexOf("http://192.168") != 0 &&
5289
5289
  window.location.href.indexOf("dev=open") == -1
5290
5290
  ) {
5291
5291
  return false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@infly/libs",
3
- "version": "2.0.37",
3
+ "version": "2.0.40",
4
4
  "description": "工具组件库",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -31,10 +31,11 @@
31
31
  "infly-libs",
32
32
  "libs"
33
33
  ],
34
- "types-为了直接点击进入引用文件所以去掉": "types/index.d.ts",
35
34
  "author": "Kahal",
36
35
  "license": "ISC",
37
- "dependencies": {},
36
+ "dependencies": {
37
+ "path-browserify": "^1.0.1"
38
+ },
38
39
  "devDependencies": {
39
40
  "@babel/core": "^7.23.3",
40
41
  "@babel/preset-env": "^7.23.3",
@@ -0,0 +1,63 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ /**
5
+ * 从项目的 webpack/vite 等构建配置中解析对兄弟 app 的依赖。
6
+ *
7
+ * 规则:如果 vue.config.js / next.config.* 的 alias 中存在指向 ../ 的路径,
8
+ * 则认为当前项目依赖该兄弟 app,构建前需要确保兄弟 app 源码是最新的。
9
+ *
10
+ * 示例(vue.config.js):
11
+ * alias: {
12
+ * "@postal-benefits-platform": projectResolve("../postal-benefits-platform/src")
13
+ * }
14
+ *
15
+ * @param {string} appDir - 当前 app 目录的绝对路径
16
+ * @returns {string[]} 兄弟 app 根目录(含 package.json)的绝对路径列表
17
+ */
18
+ function resolveSiblingAppDeps(appDir) {
19
+ const siblings = [];
20
+ const configFiles = [
21
+ "vue.config.js",
22
+ "next.config.js",
23
+ "next.config.mjs",
24
+ "next.config.ts"
25
+ ];
26
+
27
+ for (const configFile of configFiles) {
28
+ const configPath = path.join(appDir, configFile);
29
+ if (!fs.existsSync(configPath)) continue;
30
+
31
+ const content = fs.readFileSync(configPath, "utf8");
32
+
33
+ // 匹配 alias 中指向 ../ 兄弟目录的值,兼容以下写法:
34
+ // "@foo": projectResolve("../foo/src")
35
+ // "@foo": resolve("../foo/src")
36
+ // "@foo": path.resolve(__dirname, "../foo/src")
37
+ const aliasPattern = /["'](@[^"']+)["']\s*:\s*(?:projectResolve|resolve|path\.resolve\s*\(\s*__dirname\s*,)\s*\(\s*["'](\.\.\/[^"']+)["']/g;
38
+
39
+ let match;
40
+ while ((match = aliasPattern.exec(content)) !== null) {
41
+ const [, , relativePath] = match;
42
+ const resolved = path.resolve(appDir, relativePath);
43
+
44
+ // 向上查找含 package.json 的目录,即 app 根目录
45
+ let current = resolved;
46
+ for (let i = 0; i < 5; i++) {
47
+ if (fs.existsSync(path.join(current, "package.json"))) {
48
+ if (current !== appDir && !siblings.includes(current)) {
49
+ siblings.push(current);
50
+ }
51
+ break;
52
+ }
53
+ const parent = path.dirname(current);
54
+ if (parent === current) break;
55
+ current = parent;
56
+ }
57
+ }
58
+ }
59
+
60
+ return siblings;
61
+ }
62
+
63
+ module.exports = { resolveSiblingAppDeps };
@@ -521,8 +521,8 @@ function checkAndUpdateRootPackages(packagesDir, targetBranch = "master") {
521
521
  stdio: "inherit"
522
522
  });
523
523
 
524
- // 使用 merge-from-master.sh 脚本进行安全合并
525
- const mergeScriptPath = path.join(rootDir, "script", "merge-from-master.sh");
524
+ // 只同步共享内容,保留当前分支配置和子模块集合
525
+ const mergeScriptPath = path.join(rootDir, "script", "sync-from-branch.sh");
526
526
  if (fs.existsSync(mergeScriptPath)) {
527
527
  execSync(`bash "${mergeScriptPath}" ${targetBranch}`, {
528
528
  cwd: rootDir,
@@ -699,42 +699,6 @@ async function checkAndUpdatePackages(outPackagesDir, targetBranch = "master") {
699
699
  console.log(global.logColor.warning, `\n⚠️ 有 ${failedUpdates.length} 个模块更新失败,但可以继续执行`);
700
700
  }
701
701
 
702
- // 4. 检查和更新 postal-benefits-platform(如果当前是 postal-benefits-platform-level)
703
- const currentProjectName = require(path.resolve(process.cwd(), "package.json")).name;
704
- if (currentProjectName === "postal-benefits-platform-level") {
705
- // console.log(global.logColor.info, `\n🚀 开始检查和更新 postal-benefits-platform...`);
706
-
707
- // 获取 postal-benefits-platform 的路径
708
- const appsDir = path.resolve(packagesDir, "..", "apps");
709
- const postalPlatformDir = path.join(appsDir, "postal-benefits-platform");
710
-
711
- // 获取 postal-benefits-platform-level 当前分支
712
- const currentLevelBranch = execSync("git rev-parse --abbrev-ref HEAD", {
713
- cwd: process.cwd(),
714
- encoding: "utf8"
715
- }).trim();
716
-
717
- // 检查 postal-benefits-platform 是否有未提交的更改
718
- const platformCheckResult = checkSingleDirGitStatus(postalPlatformDir, "postal-benefits-platform");
719
-
720
- if (platformCheckResult.hasUncommitted) {
721
- console.log(global.logColor.error, `\n❌ postal-benefits-platform 存在未提交的更改`);
722
- console.log(global.logColor.error, `\n请先提交或储藏这些更改后再继续执行!`);
723
- process.exit(1);
724
- }
725
-
726
- // 切换到与 postal-benefits-platform-level 相同的分支并拉取最新代码
727
- const platformUpdateResult = pullSingleDirFromBranch(
728
- postalPlatformDir,
729
- "postal-benefits-platform",
730
- currentLevelBranch
731
- );
732
-
733
- if (!platformUpdateResult.success) {
734
- console.log(global.logColor.warning, `\n⚠️ postal-benefits-platform 更新失败,但可以继续执行`);
735
- }
736
- }
737
-
738
702
  // console.log(global.logColor.success, `\n🎉 packages 检查和更新流程完成!`);
739
703
  return updateResults;
740
704
  } catch (error) {