ai-project-manage-cli 6.0.65 → 6.0.66
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/dist/index.js +1148 -431
- package/package.json +3 -1
- package/template/apm.config.json +2 -6
- package/template/deploy/README.md +23 -4
- package/template/deploy/deploy.py +0 -564
package/dist/index.js
CHANGED
|
@@ -110,8 +110,8 @@ function toFsPath(inputPath) {
|
|
|
110
110
|
}
|
|
111
111
|
return `\\\\?\\${normalized}`;
|
|
112
112
|
}
|
|
113
|
-
function normalizeWorkdirPath(
|
|
114
|
-
let normalized =
|
|
113
|
+
function normalizeWorkdirPath(path12) {
|
|
114
|
+
let normalized = path12.trim().replace(/\\/g, "/").normalize("NFC");
|
|
115
115
|
if (normalized.startsWith("//?/")) {
|
|
116
116
|
normalized = normalized.slice(4);
|
|
117
117
|
}
|
|
@@ -326,9 +326,9 @@ function assertTemplateCopiedToApm(apmDir, workdir) {
|
|
|
326
326
|
"sessions"
|
|
327
327
|
];
|
|
328
328
|
for (const item of required) {
|
|
329
|
-
const
|
|
330
|
-
if (!existsSync(toFsPath(
|
|
331
|
-
throw new Error(`[apm] \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11: ${
|
|
329
|
+
const path12 = join2(apmDir, item);
|
|
330
|
+
if (!existsSync(toFsPath(path12))) {
|
|
331
|
+
throw new Error(`[apm] \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11: ${path12}`);
|
|
332
332
|
}
|
|
333
333
|
}
|
|
334
334
|
const leakedRules = join2(workdir, "rules");
|
|
@@ -613,14 +613,14 @@ function projectDocumentLocalPath(apmRoot, documentPath) {
|
|
|
613
613
|
const normalized = normalizeLocalDocumentPath(documentPath);
|
|
614
614
|
return join4(projectDocumentsDir(apmRoot), ...normalized.split("/"));
|
|
615
615
|
}
|
|
616
|
-
function normalizeLocalDocumentPath(
|
|
617
|
-
const trimmed =
|
|
616
|
+
function normalizeLocalDocumentPath(path12) {
|
|
617
|
+
const trimmed = path12.trim().replace(/\\/g, "/");
|
|
618
618
|
if (!trimmed || trimmed.startsWith("/") || /^[a-zA-Z]:/.test(trimmed)) {
|
|
619
|
-
throw new Error(`\u975E\u6CD5\u6587\u6863\u8DEF\u5F84: ${
|
|
619
|
+
throw new Error(`\u975E\u6CD5\u6587\u6863\u8DEF\u5F84: ${path12}`);
|
|
620
620
|
}
|
|
621
621
|
const segments = trimmed.split("/").filter(Boolean);
|
|
622
622
|
if (segments.some((segment) => segment === ".." || segment === ".")) {
|
|
623
|
-
throw new Error(`\u975E\u6CD5\u6587\u6863\u8DEF\u5F84: ${
|
|
623
|
+
throw new Error(`\u975E\u6CD5\u6587\u6863\u8DEF\u5F84: ${path12}`);
|
|
624
624
|
}
|
|
625
625
|
return segments.join("/");
|
|
626
626
|
}
|
|
@@ -671,15 +671,15 @@ function diffManifestPaths(remote, local) {
|
|
|
671
671
|
(local?.documents ?? []).map((doc) => [doc.path, doc.contentHash])
|
|
672
672
|
);
|
|
673
673
|
const download = [];
|
|
674
|
-
for (const [
|
|
675
|
-
if (localMap.get(
|
|
676
|
-
download.push(
|
|
674
|
+
for (const [path12, hash] of remoteMap) {
|
|
675
|
+
if (localMap.get(path12) !== hash) {
|
|
676
|
+
download.push(path12);
|
|
677
677
|
}
|
|
678
678
|
}
|
|
679
679
|
const deleteLocal = [];
|
|
680
|
-
for (const
|
|
681
|
-
if (!remoteMap.has(
|
|
682
|
-
deleteLocal.push(
|
|
680
|
+
for (const path12 of localMap.keys()) {
|
|
681
|
+
if (!remoteMap.has(path12)) {
|
|
682
|
+
deleteLocal.push(path12);
|
|
683
683
|
}
|
|
684
684
|
}
|
|
685
685
|
return { download, deleteLocal };
|
|
@@ -739,8 +739,8 @@ ${diagnostic ?? ""}`
|
|
|
739
739
|
}
|
|
740
740
|
}
|
|
741
741
|
let deleted = 0;
|
|
742
|
-
for (const
|
|
743
|
-
const absPath = toFsPath(projectDocumentLocalPath(targetApmDir,
|
|
742
|
+
for (const path12 of deleteLocal) {
|
|
743
|
+
const absPath = toFsPath(projectDocumentLocalPath(targetApmDir, path12));
|
|
744
744
|
if (existsSync2(absPath)) {
|
|
745
745
|
rmSync(absPath, { force: true });
|
|
746
746
|
deleted += 1;
|
|
@@ -785,21 +785,21 @@ async function syncRepositoryProjectDocumentsPush(cfg, workdirPath, apmRoot) {
|
|
|
785
785
|
])
|
|
786
786
|
);
|
|
787
787
|
let synced = 0;
|
|
788
|
-
for (const
|
|
789
|
-
const absPath = toFsPath(projectDocumentLocalPath(targetApmDir,
|
|
788
|
+
for (const path12 of localPaths) {
|
|
789
|
+
const absPath = toFsPath(projectDocumentLocalPath(targetApmDir, path12));
|
|
790
790
|
const content = readFileSync3(absPath, "utf8");
|
|
791
791
|
const contentHash = hashLocalFileContent(content);
|
|
792
|
-
if (remoteHashByPath.get(
|
|
792
|
+
if (remoteHashByPath.get(path12) === contentHash) {
|
|
793
793
|
continue;
|
|
794
794
|
}
|
|
795
795
|
await api.cli.upsertRepositoryProjectDocument({
|
|
796
796
|
repositoryId,
|
|
797
|
-
path:
|
|
797
|
+
path: path12,
|
|
798
798
|
content,
|
|
799
|
-
description: remoteDescriptionByPath.get(
|
|
799
|
+
description: remoteDescriptionByPath.get(path12) ?? void 0
|
|
800
800
|
});
|
|
801
801
|
synced += 1;
|
|
802
|
-
console.log(`[apm] \u5DF2\u540C\u6B65\u4ED3\u5E93\u9879\u76EE\u6587\u6863: ${
|
|
802
|
+
console.log(`[apm] \u5DF2\u540C\u6B65\u4ED3\u5E93\u9879\u76EE\u6587\u6863: ${path12}`);
|
|
803
803
|
}
|
|
804
804
|
if (synced === 0) {
|
|
805
805
|
console.log("[apm] \u4ED3\u5E93\u9879\u76EE\u6587\u6863\u65E0\u53D8\u5316\uFF0C\u8DF3\u8FC7\u63A8\u9001");
|
|
@@ -1395,13 +1395,13 @@ async function downloadAttachment(cfg, attachmentId) {
|
|
|
1395
1395
|
return Buffer.from(await res.arrayBuffer());
|
|
1396
1396
|
}
|
|
1397
1397
|
function loadManifest(dir) {
|
|
1398
|
-
const
|
|
1399
|
-
if (!existsSync4(
|
|
1398
|
+
const path12 = join6(dir, MANIFEST_FILE2);
|
|
1399
|
+
if (!existsSync4(path12)) {
|
|
1400
1400
|
return { version: 1, attachments: {} };
|
|
1401
1401
|
}
|
|
1402
1402
|
try {
|
|
1403
1403
|
const parsed = JSON.parse(
|
|
1404
|
-
readFileSync5(
|
|
1404
|
+
readFileSync5(path12, "utf8")
|
|
1405
1405
|
);
|
|
1406
1406
|
if (parsed?.version === 1 && parsed.attachments && typeof parsed.attachments === "object") {
|
|
1407
1407
|
return parsed;
|
|
@@ -1482,8 +1482,8 @@ function sanitizeSkillDirName(name) {
|
|
|
1482
1482
|
function listBaseSkillDirNames() {
|
|
1483
1483
|
if (!existsSync5(BASE_SKILLS_TEMPLATE_DIR)) return [];
|
|
1484
1484
|
return readdirSync3(BASE_SKILLS_TEMPLATE_DIR).filter((name) => {
|
|
1485
|
-
const
|
|
1486
|
-
return statSync2(
|
|
1485
|
+
const path12 = join7(BASE_SKILLS_TEMPLATE_DIR, name);
|
|
1486
|
+
return statSync2(path12).isDirectory();
|
|
1487
1487
|
});
|
|
1488
1488
|
}
|
|
1489
1489
|
function syncAgentsGuide(apmDir) {
|
|
@@ -1495,8 +1495,8 @@ function syncAgentsGuide(apmDir) {
|
|
|
1495
1495
|
function listBaseRuleFileNames() {
|
|
1496
1496
|
if (!existsSync5(BASE_RULES_TEMPLATE_DIR)) return [];
|
|
1497
1497
|
return readdirSync3(BASE_RULES_TEMPLATE_DIR).filter((name) => {
|
|
1498
|
-
const
|
|
1499
|
-
return statSync2(
|
|
1498
|
+
const path12 = join7(BASE_RULES_TEMPLATE_DIR, name);
|
|
1499
|
+
return statSync2(path12).isFile();
|
|
1500
1500
|
});
|
|
1501
1501
|
}
|
|
1502
1502
|
function syncBaseRules(rulesDir) {
|
|
@@ -1559,13 +1559,13 @@ function ruleLocalFileName(ruleName) {
|
|
|
1559
1559
|
return `${sanitized}.md`;
|
|
1560
1560
|
}
|
|
1561
1561
|
function loadManifest2(rulesDir) {
|
|
1562
|
-
const
|
|
1563
|
-
if (!existsSync6(toFsPath(
|
|
1562
|
+
const path12 = join8(rulesDir, MANIFEST_FILE3);
|
|
1563
|
+
if (!existsSync6(toFsPath(path12))) {
|
|
1564
1564
|
return { version: 1, rules: {} };
|
|
1565
1565
|
}
|
|
1566
1566
|
try {
|
|
1567
1567
|
const parsed = JSON.parse(
|
|
1568
|
-
readFileSync6(toFsPath(
|
|
1568
|
+
readFileSync6(toFsPath(path12), "utf8")
|
|
1569
1569
|
);
|
|
1570
1570
|
if (parsed?.version === 1 && parsed.rules && typeof parsed.rules === "object") {
|
|
1571
1571
|
return parsed;
|
|
@@ -2102,7 +2102,7 @@ async function runUpdateMessageStatus(options) {
|
|
|
2102
2102
|
}
|
|
2103
2103
|
|
|
2104
2104
|
// src/commands/connect.ts
|
|
2105
|
-
import { spawnSync as
|
|
2105
|
+
import { spawnSync as spawnSync4 } from "child_process";
|
|
2106
2106
|
import WebSocket from "ws";
|
|
2107
2107
|
|
|
2108
2108
|
// src/ws/protocol.ts
|
|
@@ -2226,19 +2226,915 @@ function validateAgentWsMessage(value, kind) {
|
|
|
2226
2226
|
|
|
2227
2227
|
// src/commands/connect/deploy-run.ts
|
|
2228
2228
|
import { spawn } from "node:child_process";
|
|
2229
|
-
import { readFileSync as
|
|
2229
|
+
import { existsSync as existsSync14, readFileSync as readFileSync12 } from "node:fs";
|
|
2230
2230
|
import { join as join13 } from "node:path";
|
|
2231
|
+
|
|
2232
|
+
// src/commands/deploy/internal/wisdom-auto-deploy.ts
|
|
2233
|
+
import { existsSync as existsSync13, readFileSync as readFileSync11 } from "node:fs";
|
|
2234
|
+
import path3 from "node:path";
|
|
2235
|
+
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
2236
|
+
|
|
2237
|
+
// src/commands/deploy/internal/apm-config.ts
|
|
2238
|
+
import { existsSync as existsSync11, readFileSync as readFileSync9 } from "node:fs";
|
|
2239
|
+
import { resolve as resolve3 } from "node:path";
|
|
2240
|
+
function loadApmConfig(options) {
|
|
2241
|
+
const p = resolve3(
|
|
2242
|
+
process.cwd(),
|
|
2243
|
+
options?.configPath ?? resolve3(workspaceApmDir(), "apm.config.json")
|
|
2244
|
+
);
|
|
2245
|
+
if (!existsSync11(p)) {
|
|
2246
|
+
console.error(`\u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6\uFF1A${p}`);
|
|
2247
|
+
process.exit(1);
|
|
2248
|
+
}
|
|
2249
|
+
try {
|
|
2250
|
+
const raw = readFileSync9(p, "utf8");
|
|
2251
|
+
return JSON.parse(raw);
|
|
2252
|
+
} catch (e) {
|
|
2253
|
+
console.error(`\u65E0\u6CD5\u89E3\u6790 apm.config.json\uFF1A${p}`, e);
|
|
2254
|
+
process.exit(1);
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2257
|
+
function req(v, field) {
|
|
2258
|
+
if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
|
|
2259
|
+
console.error(`apm.config.json \u4E2D backendDeploy.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
|
|
2260
|
+
process.exit(1);
|
|
2261
|
+
}
|
|
2262
|
+
return v;
|
|
2263
|
+
}
|
|
2264
|
+
function reqTopLevelName(cfg) {
|
|
2265
|
+
const n = (cfg.name ?? "").trim();
|
|
2266
|
+
if (!n) {
|
|
2267
|
+
console.error(
|
|
2268
|
+
"\u8BF7\u5728 apm.config.json \u9876\u5C42\u914D\u7F6E name\uFF08\u4E0E\u524D\u7AEF\u5236\u54C1\u524D\u7F00\u3001\u540E\u7AEF\u955C\u50CF\u540D\u5171\u7528\uFF09"
|
|
2269
|
+
);
|
|
2270
|
+
process.exit(1);
|
|
2271
|
+
}
|
|
2272
|
+
return n;
|
|
2273
|
+
}
|
|
2274
|
+
function reqBackendPositiveInt(v, field) {
|
|
2275
|
+
const n = Number(v);
|
|
2276
|
+
if (!Number.isFinite(n) || !Number.isInteger(n) || n < 1) {
|
|
2277
|
+
console.error(`apm.config.json \u4E2D backendDeploy.${field} \u987B\u4E3A\u6B63\u6574\u6570`);
|
|
2278
|
+
process.exit(1);
|
|
2279
|
+
}
|
|
2280
|
+
return n;
|
|
2281
|
+
}
|
|
2282
|
+
function resolveBackendDeployFromApmConfig(cfg) {
|
|
2283
|
+
const b = cfg.backendDeploy ?? {};
|
|
2284
|
+
const protoRaw = req(b.remoteProtocol, "remoteProtocol").trim().toLowerCase();
|
|
2285
|
+
if (protoRaw !== "http" && protoRaw !== "https") {
|
|
2286
|
+
console.error(
|
|
2287
|
+
"apm.config.json \u4E2D backendDeploy.remoteProtocol \u53EA\u80FD\u4E3A http \u6216 https"
|
|
2288
|
+
);
|
|
2289
|
+
process.exit(1);
|
|
2290
|
+
}
|
|
2291
|
+
const remoteProtocol = protoRaw;
|
|
2292
|
+
let mappings = [];
|
|
2293
|
+
const rawPorts = b.containerPortsMappings;
|
|
2294
|
+
if (rawPorts !== void 0 && rawPorts !== null) {
|
|
2295
|
+
if (!Array.isArray(rawPorts)) {
|
|
2296
|
+
console.error(
|
|
2297
|
+
"apm.config.json \u4E2D backendDeploy.containerPortsMappings \u987B\u4E3A\u5B57\u7B26\u4E32\u6570\u7EC4\uFF08\u53EF\u4E3A\u7A7A\uFF0C\u7701\u7565\u5219\u4E0D\u52A0\u7AEF\u53E3\u6620\u5C04\uFF09"
|
|
2298
|
+
);
|
|
2299
|
+
process.exit(1);
|
|
2300
|
+
}
|
|
2301
|
+
mappings = rawPorts.map((x) => String(x).trim()).filter(Boolean);
|
|
2302
|
+
}
|
|
2303
|
+
return {
|
|
2304
|
+
name: reqTopLevelName(cfg),
|
|
2305
|
+
registryHost: req(b.registryHost, "registryHost").trim(),
|
|
2306
|
+
registryNamespace: req(b.registryNamespace, "registryNamespace").trim(),
|
|
2307
|
+
registryUser: req(b.registryUser, "registryUser").trim(),
|
|
2308
|
+
registryPassword: req(b.registryPassword, "registryPassword").trim(),
|
|
2309
|
+
remoteHost: req(b.remoteHost, "remoteHost").trim(),
|
|
2310
|
+
remotePort: reqBackendPositiveInt(b.remotePort, "remotePort"),
|
|
2311
|
+
remoteProtocol,
|
|
2312
|
+
caPath: b.caPath?.trim(),
|
|
2313
|
+
certPath: b.certPath?.trim(),
|
|
2314
|
+
keyPath: b.keyPath?.trim(),
|
|
2315
|
+
envFilePath: typeof b.envFilePath === "string" ? b.envFilePath.trim() : "",
|
|
2316
|
+
containerPortsMappings: mappings,
|
|
2317
|
+
dockerNetwork: b.dockerNetwork?.trim() || void 0
|
|
2318
|
+
};
|
|
2319
|
+
}
|
|
2320
|
+
function reqFe(v, field) {
|
|
2321
|
+
if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
|
|
2322
|
+
console.error(`apm.config.json \u4E2D frontendDeploy.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
|
|
2323
|
+
process.exit(1);
|
|
2324
|
+
}
|
|
2325
|
+
return v;
|
|
2326
|
+
}
|
|
2327
|
+
function resolveFrontendDeployFromApmConfig(cfg) {
|
|
2328
|
+
const f = cfg.frontendDeploy ?? {};
|
|
2329
|
+
const port = Number(f.port);
|
|
2330
|
+
return {
|
|
2331
|
+
endpoint: reqFe(f.endpoint, "endpoint").trim(),
|
|
2332
|
+
port: Number.isFinite(port) && port > 0 ? port : 9e3,
|
|
2333
|
+
useSsl: Boolean(f.useSsl),
|
|
2334
|
+
accessKey: reqFe(f.accessKey, "accessKey").trim(),
|
|
2335
|
+
secretKey: reqFe(f.secretKey, "secretKey").trim(),
|
|
2336
|
+
bucket: reqFe(f.bucket, "bucket").trim()
|
|
2337
|
+
};
|
|
2338
|
+
}
|
|
2339
|
+
function reqWd(v, field) {
|
|
2340
|
+
if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
|
|
2341
|
+
console.error(`apm.config.json \u4E2D wisdomDeploy.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
|
|
2342
|
+
process.exit(1);
|
|
2343
|
+
}
|
|
2344
|
+
return v;
|
|
2345
|
+
}
|
|
2346
|
+
function reqWisdomPositiveInt(v, field) {
|
|
2347
|
+
const n = Number(v);
|
|
2348
|
+
if (!Number.isFinite(n) || !Number.isInteger(n) || n < 1) {
|
|
2349
|
+
console.error(`apm.config.json \u4E2D wisdomDeploy.${field} \u987B\u4E3A\u6B63\u6574\u6570`);
|
|
2350
|
+
process.exit(1);
|
|
2351
|
+
}
|
|
2352
|
+
return n;
|
|
2353
|
+
}
|
|
2354
|
+
function resolveWisdomDeployFromApmConfig(cfg) {
|
|
2355
|
+
const w = cfg.wisdomDeploy ?? {};
|
|
2356
|
+
return {
|
|
2357
|
+
host: reqWd(w.host, "host").trim(),
|
|
2358
|
+
port: reqWisdomPositiveInt(w.port, "port"),
|
|
2359
|
+
username: reqWd(w.username, "username").trim(),
|
|
2360
|
+
password: reqWd(w.password, "password").trim(),
|
|
2361
|
+
remotePath: reqWd(w.remotePath, "remotePath").trim()
|
|
2362
|
+
};
|
|
2363
|
+
}
|
|
2364
|
+
function reqHc(v, field) {
|
|
2365
|
+
if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
|
|
2366
|
+
console.error(`apm.config.json \u4E2D healthCheck.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
|
|
2367
|
+
process.exit(1);
|
|
2368
|
+
}
|
|
2369
|
+
return v;
|
|
2370
|
+
}
|
|
2371
|
+
function reqWb(v, field) {
|
|
2372
|
+
if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
|
|
2373
|
+
console.error(`apm.config.json \u4E2D wisdomDeploy.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
|
|
2374
|
+
process.exit(1);
|
|
2375
|
+
}
|
|
2376
|
+
return v;
|
|
2377
|
+
}
|
|
2378
|
+
function resolveWisdomBackendDeployFromApmConfig(cfg) {
|
|
2379
|
+
const projectName = reqTopLevelName(cfg);
|
|
2380
|
+
const w = cfg.wisdomDeploy ?? {};
|
|
2381
|
+
const h = cfg.healthCheck ?? {};
|
|
2382
|
+
const jarPath = reqWb(w.jarPath, "jarPath").trim();
|
|
2383
|
+
const remoteAppDir = posixDirname(jarPath);
|
|
2384
|
+
const healthPort = Number(reqHc(h.port, "port"));
|
|
2385
|
+
const healthTimeout = Number(reqHc(h.timeout, "timeout"));
|
|
2386
|
+
if (!Number.isFinite(healthPort) || !Number.isInteger(healthPort) || healthPort < 1) {
|
|
2387
|
+
console.error("apm.config.json \u4E2D healthCheck.port \u987B\u4E3A\u6B63\u6574\u6570");
|
|
2388
|
+
process.exit(1);
|
|
2389
|
+
}
|
|
2390
|
+
if (!Number.isFinite(healthTimeout) || !Number.isInteger(healthTimeout) || healthTimeout < 1) {
|
|
2391
|
+
console.error("apm.config.json \u4E2D healthCheck.timeout \u987B\u4E3A\u6B63\u6574\u6570");
|
|
2392
|
+
process.exit(1);
|
|
2393
|
+
}
|
|
2394
|
+
return {
|
|
2395
|
+
projectName,
|
|
2396
|
+
host: reqWd(w.host, "host").trim(),
|
|
2397
|
+
port: reqWisdomPositiveInt(w.port, "port"),
|
|
2398
|
+
username: reqWd(w.username, "username").trim(),
|
|
2399
|
+
password: reqWd(w.password, "password").trim(),
|
|
2400
|
+
remoteVueDistDir: reqWd(w.remotePath, "remotePath").trim(),
|
|
2401
|
+
remoteAppDir,
|
|
2402
|
+
remoteLibDir: `${remoteAppDir}/lib`,
|
|
2403
|
+
startupJar: posixBasename(jarPath),
|
|
2404
|
+
packageName: `${projectName}.jar.zip`,
|
|
2405
|
+
mavenLocalRepo: reqWb(w.mavenLocalRepo, "mavenLocalRepo").trim(),
|
|
2406
|
+
healthCheckPort: healthPort,
|
|
2407
|
+
healthCheckContext: reqHc(h.context, "context").trim(),
|
|
2408
|
+
healthCheckTimeout: healthTimeout
|
|
2409
|
+
};
|
|
2410
|
+
}
|
|
2411
|
+
function posixDirname(p) {
|
|
2412
|
+
const normalized = p.replace(/\\/g, "/");
|
|
2413
|
+
const idx = normalized.lastIndexOf("/");
|
|
2414
|
+
if (idx <= 0) {
|
|
2415
|
+
return normalized.startsWith("/") ? "/" : ".";
|
|
2416
|
+
}
|
|
2417
|
+
return normalized.slice(0, idx);
|
|
2418
|
+
}
|
|
2419
|
+
function posixBasename(p) {
|
|
2420
|
+
const normalized = p.replace(/\\/g, "/");
|
|
2421
|
+
const idx = normalized.lastIndexOf("/");
|
|
2422
|
+
return idx >= 0 ? normalized.slice(idx + 1) : normalized;
|
|
2423
|
+
}
|
|
2424
|
+
|
|
2425
|
+
// src/commands/deploy/internal/wisdom-backend-deploy.ts
|
|
2426
|
+
import {
|
|
2427
|
+
existsSync as existsSync12,
|
|
2428
|
+
mkdirSync as mkdirSync5,
|
|
2429
|
+
readdirSync as readdirSync5,
|
|
2430
|
+
readFileSync as readFileSync10,
|
|
2431
|
+
statSync as statSync5,
|
|
2432
|
+
writeFileSync as writeFileSync10
|
|
2433
|
+
} from "node:fs";
|
|
2434
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
2435
|
+
import path2 from "node:path";
|
|
2436
|
+
import { Client } from "ssh2";
|
|
2437
|
+
import JSZip2 from "jszip";
|
|
2438
|
+
import SftpClient2 from "ssh2-sftp-client";
|
|
2439
|
+
|
|
2440
|
+
// src/commands/deploy/internal/wisdom-sftp.ts
|
|
2441
|
+
import { readdir, readFile, unlink, writeFile } from "node:fs/promises";
|
|
2442
|
+
import path from "node:path";
|
|
2443
|
+
import JSZip from "jszip";
|
|
2444
|
+
import SftpClient from "ssh2-sftp-client";
|
|
2445
|
+
async function addDirToZip(dir, zipFolder) {
|
|
2446
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
2447
|
+
for (const entry of entries) {
|
|
2448
|
+
const fullPath = path.join(dir, entry.name);
|
|
2449
|
+
if (entry.isDirectory()) {
|
|
2450
|
+
const folder = zipFolder.folder(entry.name);
|
|
2451
|
+
if (folder) {
|
|
2452
|
+
await addDirToZip(fullPath, folder);
|
|
2453
|
+
}
|
|
2454
|
+
} else {
|
|
2455
|
+
const content = await readFile(fullPath);
|
|
2456
|
+
zipFolder.file(entry.name, content);
|
|
2457
|
+
}
|
|
2458
|
+
}
|
|
2459
|
+
}
|
|
2460
|
+
async function zipDirectory(distDir, zipPath) {
|
|
2461
|
+
console.error(`\u538B\u7F29\u76EE\u5F55: ${distDir}`);
|
|
2462
|
+
const zip = new JSZip();
|
|
2463
|
+
await addDirToZip(distDir, zip);
|
|
2464
|
+
const content = await zip.generateAsync({
|
|
2465
|
+
type: "nodebuffer",
|
|
2466
|
+
compression: "DEFLATE",
|
|
2467
|
+
compressionOptions: { level: 6 }
|
|
2468
|
+
});
|
|
2469
|
+
await writeFile(zipPath, content);
|
|
2470
|
+
const sizeMb = (content.length / 1024 / 1024).toFixed(2);
|
|
2471
|
+
console.error(`\u5DF2\u751F\u6210: ${zipPath} (${sizeMb} MB)`);
|
|
2472
|
+
return content.length;
|
|
2473
|
+
}
|
|
2474
|
+
async function ensureRemoteDir(sftp, dir) {
|
|
2475
|
+
const parts = dir.replace(/\\/g, "/").split("/").filter(Boolean);
|
|
2476
|
+
let current = dir.startsWith("/") ? "" : ".";
|
|
2477
|
+
for (const part of parts) {
|
|
2478
|
+
current = current ? `${current}/${part}` : `/${part}`;
|
|
2479
|
+
try {
|
|
2480
|
+
await sftp.mkdir(current, true);
|
|
2481
|
+
} catch {
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2484
|
+
}
|
|
2485
|
+
function execCommand(client, command) {
|
|
2486
|
+
return new Promise((resolve5, reject) => {
|
|
2487
|
+
client.exec(command, (err, stream) => {
|
|
2488
|
+
if (err) return reject(err);
|
|
2489
|
+
let stdout = "";
|
|
2490
|
+
let stderr = "";
|
|
2491
|
+
stream.on("close", (code) => {
|
|
2492
|
+
if (code !== 0) {
|
|
2493
|
+
reject(new Error(`\u8FDC\u7A0B\u547D\u4EE4\u5931\u8D25 (${code}): ${stderr || stdout}`));
|
|
2494
|
+
return;
|
|
2495
|
+
}
|
|
2496
|
+
resolve5(stdout);
|
|
2497
|
+
}).on("data", (data) => {
|
|
2498
|
+
stdout += data.toString();
|
|
2499
|
+
});
|
|
2500
|
+
stream.stderr.on("data", (data) => {
|
|
2501
|
+
stderr += data.toString();
|
|
2502
|
+
});
|
|
2503
|
+
});
|
|
2504
|
+
});
|
|
2505
|
+
}
|
|
2506
|
+
function shellSingleQuote(value) {
|
|
2507
|
+
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
2508
|
+
}
|
|
2509
|
+
function buildClearRemoteDirExceptZipCommand(target) {
|
|
2510
|
+
const normalized = target.replace(/\\/g, "/").replace(/\/$/, "");
|
|
2511
|
+
const quotedTarget = shellSingleQuote(normalized);
|
|
2512
|
+
const script = [
|
|
2513
|
+
`T=${quotedTarget}`,
|
|
2514
|
+
"S=$(mktemp -d)",
|
|
2515
|
+
'while IFS= read -r -d "" z; do r="${z#${T}/}"',
|
|
2516
|
+
'mkdir -p "${S}/$(dirname "$r")"',
|
|
2517
|
+
'mv "$z" "${S}/${r}"',
|
|
2518
|
+
'done < <(find "$T" -mindepth 1 -type f -iname "*.zip" -print0)',
|
|
2519
|
+
'rm -rf "${T}"/*',
|
|
2520
|
+
'while IFS= read -r -d "" r; do r="${r#./}"',
|
|
2521
|
+
'mkdir -p "${T}/$(dirname "$r")"',
|
|
2522
|
+
'mv "${S}/${r}" "${T}/${r}"',
|
|
2523
|
+
'done < <(cd "$S" 2>/dev/null && find . -type f -print0)',
|
|
2524
|
+
'rm -rf "$S"'
|
|
2525
|
+
].join("; ");
|
|
2526
|
+
return `bash -c ${shellSingleQuote(script)}`;
|
|
2527
|
+
}
|
|
2528
|
+
async function uploadAndMaybeExtract(settings, localZip, extract) {
|
|
2529
|
+
const remoteZipPath = `${settings.remotePath.replace(/\/$/, "")}/dist.zip`;
|
|
2530
|
+
console.error(
|
|
2531
|
+
`\u8FDE\u63A5 ${settings.username}@${settings.host}:${settings.port} ...`
|
|
2532
|
+
);
|
|
2533
|
+
const sftp = new SftpClient();
|
|
2534
|
+
try {
|
|
2535
|
+
await sftp.connect({
|
|
2536
|
+
host: settings.host,
|
|
2537
|
+
port: settings.port,
|
|
2538
|
+
username: settings.username,
|
|
2539
|
+
password: settings.password,
|
|
2540
|
+
readyTimeout: 2e4,
|
|
2541
|
+
tryKeyboard: true
|
|
2542
|
+
});
|
|
2543
|
+
await ensureRemoteDir(sftp, settings.remotePath);
|
|
2544
|
+
await sftp.put(localZip, remoteZipPath);
|
|
2545
|
+
console.error(` \u2713 ${localZip} -> ${remoteZipPath}`);
|
|
2546
|
+
if (extract) {
|
|
2547
|
+
const target = settings.remotePath.replace(/\/$/, "");
|
|
2548
|
+
const client = sftp.client;
|
|
2549
|
+
const clearCmd = buildClearRemoteDirExceptZipCommand(target);
|
|
2550
|
+
console.error(`\u8FDC\u7A0B\u6E05\u7406\u89E3\u538B\u76EE\u5F55: ${clearCmd}`);
|
|
2551
|
+
await execCommand(client, clearCmd);
|
|
2552
|
+
const unzipCmd = `unzip -o "${remoteZipPath}" -d "${target}"`;
|
|
2553
|
+
console.error(`\u8FDC\u7A0B\u89E3\u538B: ${unzipCmd}`);
|
|
2554
|
+
await execCommand(client, unzipCmd);
|
|
2555
|
+
console.error("\u8FDC\u7A0B\u89E3\u538B\u5B8C\u6210!");
|
|
2556
|
+
}
|
|
2557
|
+
console.error(extract ? "\u90E8\u7F72\u5B8C\u6210!" : "\u4E0A\u4F20\u5B8C\u6210!");
|
|
2558
|
+
} finally {
|
|
2559
|
+
await sftp.end();
|
|
2560
|
+
}
|
|
2561
|
+
}
|
|
2562
|
+
async function runWisdomSftpDeploy(params) {
|
|
2563
|
+
const zipPath = path.join(params.localDir, "..", ".deploy-sftp-dist.zip");
|
|
2564
|
+
const resolvedZipPath = path.resolve(zipPath);
|
|
2565
|
+
let zipSizeBytes = 0;
|
|
2566
|
+
try {
|
|
2567
|
+
zipSizeBytes = await zipDirectory(params.localDir, resolvedZipPath);
|
|
2568
|
+
await uploadAndMaybeExtract(
|
|
2569
|
+
params.settings,
|
|
2570
|
+
resolvedZipPath,
|
|
2571
|
+
params.extract
|
|
2572
|
+
);
|
|
2573
|
+
} finally {
|
|
2574
|
+
try {
|
|
2575
|
+
await unlink(resolvedZipPath);
|
|
2576
|
+
console.error(`\u5DF2\u6E05\u7406\u672C\u5730\u4E34\u65F6\u6587\u4EF6: ${resolvedZipPath}`);
|
|
2577
|
+
} catch {
|
|
2578
|
+
}
|
|
2579
|
+
}
|
|
2580
|
+
return {
|
|
2581
|
+
ok: true,
|
|
2582
|
+
localDir: params.localDir,
|
|
2583
|
+
host: params.settings.host,
|
|
2584
|
+
remotePath: params.settings.remotePath,
|
|
2585
|
+
zipSizeBytes,
|
|
2586
|
+
extracted: params.extract
|
|
2587
|
+
};
|
|
2588
|
+
}
|
|
2589
|
+
|
|
2590
|
+
// src/commands/deploy/internal/wisdom-backend-deploy.ts
|
|
2591
|
+
var SPRINGBOOT_SCRIPT = "springboot.sh";
|
|
2592
|
+
var MAVEN_MODULE = "jeecg-module-system/jeecg-system-start";
|
|
2593
|
+
var MAVEN_PROFILE = "dev";
|
|
2594
|
+
function log(message) {
|
|
2595
|
+
const now = /* @__PURE__ */ new Date();
|
|
2596
|
+
const hh = String(now.getHours()).padStart(2, "0");
|
|
2597
|
+
const mm = String(now.getMinutes()).padStart(2, "0");
|
|
2598
|
+
const ss = String(now.getSeconds()).padStart(2, "0");
|
|
2599
|
+
console.error(`[${hh}:${mm}:${ss}] ${message}`);
|
|
2600
|
+
}
|
|
2601
|
+
function fail(message) {
|
|
2602
|
+
log(`ERROR: ${message}`);
|
|
2603
|
+
process.exit(1);
|
|
2604
|
+
}
|
|
2605
|
+
function expandPath(pathStr) {
|
|
2606
|
+
return path2.resolve(pathStr.replace(/^~(?=\/|$)/, process.env.HOME ?? ""));
|
|
2607
|
+
}
|
|
2608
|
+
function deployCacheDir() {
|
|
2609
|
+
return path2.join(workspaceApmDir(), "deploy", ".deploy_cache");
|
|
2610
|
+
}
|
|
2611
|
+
function manifestFilePath() {
|
|
2612
|
+
return path2.join(deployCacheDir(), "manifest.json");
|
|
2613
|
+
}
|
|
2614
|
+
function getTargetDir(projectRoot) {
|
|
2615
|
+
return path2.join(projectRoot, MAVEN_MODULE, "target");
|
|
2616
|
+
}
|
|
2617
|
+
function relativeKey(projectRoot, filePath) {
|
|
2618
|
+
return path2.relative(projectRoot, filePath).split(path2.sep).join("/");
|
|
2619
|
+
}
|
|
2620
|
+
function fileSignature(filePath) {
|
|
2621
|
+
const stat2 = statSync5(filePath);
|
|
2622
|
+
return { size: stat2.size, mtime: stat2.mtimeMs / 1e3 };
|
|
2623
|
+
}
|
|
2624
|
+
function loadManifest3() {
|
|
2625
|
+
const manifestPath2 = manifestFilePath();
|
|
2626
|
+
if (!existsSync12(manifestPath2)) {
|
|
2627
|
+
return {};
|
|
2628
|
+
}
|
|
2629
|
+
return JSON.parse(readFileSync10(manifestPath2, "utf8"));
|
|
2630
|
+
}
|
|
2631
|
+
function saveManifest3(manifest) {
|
|
2632
|
+
const dir = deployCacheDir();
|
|
2633
|
+
mkdirSync5(dir, { recursive: true });
|
|
2634
|
+
writeFileSync10(manifestFilePath(), JSON.stringify(manifest, null, 2), "utf8");
|
|
2635
|
+
}
|
|
2636
|
+
function isProjectLibJar(jarName) {
|
|
2637
|
+
return jarName.startsWith("jeecg-");
|
|
2638
|
+
}
|
|
2639
|
+
function shouldUploadLibFile(localPath, remoteAttr, manifest, projectRoot) {
|
|
2640
|
+
if (!remoteAttr) {
|
|
2641
|
+
return [false, "\u8FDC\u7A0B\u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7"];
|
|
2642
|
+
}
|
|
2643
|
+
const localSize = statSync5(localPath).size;
|
|
2644
|
+
const remoteSize = remoteAttr.size;
|
|
2645
|
+
if (localSize !== remoteSize) {
|
|
2646
|
+
return [true, `\u5927\u5C0F\u53D8\u5316 ${remoteSize} -> ${localSize}`];
|
|
2647
|
+
}
|
|
2648
|
+
if (isProjectLibJar(path2.basename(localPath)) && manifest) {
|
|
2649
|
+
const key = relativeKey(projectRoot, localPath);
|
|
2650
|
+
const current = fileSignature(localPath);
|
|
2651
|
+
const previous = manifest[key];
|
|
2652
|
+
if (!previous) {
|
|
2653
|
+
return [true, "\u9879\u76EE\u6A21\u5757\u672A\u8BB0\u5F55"];
|
|
2654
|
+
}
|
|
2655
|
+
if (previous.size !== current.size) {
|
|
2656
|
+
return [true, "\u9879\u76EE\u6A21\u5757\u5927\u5C0F\u53D8\u5316"];
|
|
2657
|
+
}
|
|
2658
|
+
if (previous.mtime < current.mtime) {
|
|
2659
|
+
return [true, "\u9879\u76EE\u6A21\u5757\u91CD\u65B0\u6784\u5EFA"];
|
|
2660
|
+
}
|
|
2661
|
+
}
|
|
2662
|
+
return [false, "\u5927\u5C0F\u4E00\u81F4\uFF0C\u8DF3\u8FC7"];
|
|
2663
|
+
}
|
|
2664
|
+
function listLibFilesToUpload(localLibDir, remoteStats, projectRoot, manifest = null) {
|
|
2665
|
+
const entries = [];
|
|
2666
|
+
const jarFiles = readdirSync5(localLibDir).filter((name) => name.endsWith(".jar")).sort();
|
|
2667
|
+
for (const jarName of jarFiles) {
|
|
2668
|
+
const jarPath = path2.join(localLibDir, jarName);
|
|
2669
|
+
const remoteAttr = remoteStats.get(jarName);
|
|
2670
|
+
const [shouldUpload, reason] = shouldUploadLibFile(
|
|
2671
|
+
jarPath,
|
|
2672
|
+
remoteAttr,
|
|
2673
|
+
manifest,
|
|
2674
|
+
projectRoot
|
|
2675
|
+
);
|
|
2676
|
+
if (shouldUpload) {
|
|
2677
|
+
entries.push({ path: jarPath, arcname: jarName, reason });
|
|
2678
|
+
}
|
|
2679
|
+
}
|
|
2680
|
+
return entries;
|
|
2681
|
+
}
|
|
2682
|
+
function updateManifestEntries(manifest, entries, projectRoot) {
|
|
2683
|
+
for (const entry of entries) {
|
|
2684
|
+
manifest[relativeKey(projectRoot, entry.path)] = fileSignature(entry.path);
|
|
2685
|
+
}
|
|
2686
|
+
return manifest;
|
|
2687
|
+
}
|
|
2688
|
+
async function createUpdatePackage(entries, packageName) {
|
|
2689
|
+
const dir = deployCacheDir();
|
|
2690
|
+
mkdirSync5(dir, { recursive: true });
|
|
2691
|
+
const zipPath = path2.join(dir, packageName);
|
|
2692
|
+
log(`\u521B\u5EFA\u66F4\u65B0\u5305: ${path2.basename(zipPath)}\uFF08${entries.length} \u4E2A\u6587\u4EF6\uFF09`);
|
|
2693
|
+
const zip = new JSZip2();
|
|
2694
|
+
for (const entry of entries) {
|
|
2695
|
+
const content = readFileSync10(entry.path);
|
|
2696
|
+
zip.file(entry.arcname, content);
|
|
2697
|
+
log(` \u6253\u5305: ${entry.arcname} (${entry.reason})`);
|
|
2698
|
+
}
|
|
2699
|
+
const buffer = await zip.generateAsync({
|
|
2700
|
+
type: "nodebuffer",
|
|
2701
|
+
compression: "DEFLATE",
|
|
2702
|
+
compressionOptions: { level: 6 }
|
|
2703
|
+
});
|
|
2704
|
+
writeFileSync10(zipPath, buffer);
|
|
2705
|
+
return zipPath;
|
|
2706
|
+
}
|
|
2707
|
+
function getMvnExecutable() {
|
|
2708
|
+
const isWin = process.platform === "win32";
|
|
2709
|
+
const candidates = isWin ? ["mvn.cmd", "mvn.bat", "mvn"] : ["mvn"];
|
|
2710
|
+
for (const name of candidates) {
|
|
2711
|
+
const result = spawnSync2(isWin ? "where" : "which", [name], {
|
|
2712
|
+
encoding: "utf8"
|
|
2713
|
+
});
|
|
2714
|
+
if (result.status === 0 && result.stdout.trim()) {
|
|
2715
|
+
return result.stdout.trim().split(/\r?\n/)[0];
|
|
2716
|
+
}
|
|
2717
|
+
}
|
|
2718
|
+
fail("\u672A\u627E\u5230 mvn \u547D\u4EE4\uFF0C\u8BF7\u786E\u8BA4 Maven \u5DF2\u5B89\u88C5\u5E76\u52A0\u5165 PATH");
|
|
2719
|
+
}
|
|
2720
|
+
function runMavenBuild(projectRoot, mavenLocalRepo) {
|
|
2721
|
+
const mavenRepo = expandPath(mavenLocalRepo);
|
|
2722
|
+
const cmd = [
|
|
2723
|
+
getMvnExecutable(),
|
|
2724
|
+
"clean",
|
|
2725
|
+
"package",
|
|
2726
|
+
`-P${MAVEN_PROFILE}`,
|
|
2727
|
+
`-Dmaven.repo.local=${mavenRepo}`,
|
|
2728
|
+
"-DskipTests"
|
|
2729
|
+
];
|
|
2730
|
+
log(`\u5F00\u59CB Maven \u6784\u5EFA: ${cmd.join(" ")}`);
|
|
2731
|
+
log(`Maven \u672C\u5730\u4ED3\u5E93: ${mavenRepo}`);
|
|
2732
|
+
const result = spawnSync2(cmd[0], cmd.slice(1), {
|
|
2733
|
+
cwd: projectRoot,
|
|
2734
|
+
stdio: "inherit"
|
|
2735
|
+
});
|
|
2736
|
+
if (result.status !== 0) {
|
|
2737
|
+
fail(`Maven \u6784\u5EFA\u5931\u8D25\uFF0C\u9000\u51FA\u7801: ${result.status ?? 1}`);
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
function locateLibDir(projectRoot) {
|
|
2741
|
+
const targetDir = getTargetDir(projectRoot);
|
|
2742
|
+
if (!existsSync12(targetDir)) {
|
|
2743
|
+
fail(`\u6784\u5EFA\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728: ${targetDir}`);
|
|
2744
|
+
}
|
|
2745
|
+
const libDir = path2.join(targetDir, "lib");
|
|
2746
|
+
if (!existsSync12(libDir) || !statSync5(libDir).isDirectory()) {
|
|
2747
|
+
fail(`lib \u76EE\u5F55\u4E0D\u5B58\u5728: ${libDir}`);
|
|
2748
|
+
}
|
|
2749
|
+
const libJars = readdirSync5(libDir).filter((name) => name.endsWith(".jar"));
|
|
2750
|
+
if (libJars.length === 0) {
|
|
2751
|
+
fail(`lib \u76EE\u5F55\u4E0B\u6CA1\u6709\u4F9D\u8D56 JAR: ${libDir}`);
|
|
2752
|
+
}
|
|
2753
|
+
log(`\u5B9A\u4F4D lib \u4EA7\u7269: ${libJars.length} \u4E2A`);
|
|
2754
|
+
return libDir;
|
|
2755
|
+
}
|
|
2756
|
+
async function connectSsh(config) {
|
|
2757
|
+
const client = new Client();
|
|
2758
|
+
log(`\u8FDE\u63A5\u670D\u52A1\u5668 ${config.username}@${config.host}:${config.port}`);
|
|
2759
|
+
await new Promise((resolve5, reject) => {
|
|
2760
|
+
client.on("ready", () => resolve5()).on("error", (err) => reject(err)).connect({
|
|
2761
|
+
host: config.host,
|
|
2762
|
+
port: config.port,
|
|
2763
|
+
username: config.username,
|
|
2764
|
+
password: config.password,
|
|
2765
|
+
readyTimeout: 3e4,
|
|
2766
|
+
tryKeyboard: true
|
|
2767
|
+
});
|
|
2768
|
+
});
|
|
2769
|
+
const sftp = new SftpClient2();
|
|
2770
|
+
await sftp.connect({
|
|
2771
|
+
host: config.host,
|
|
2772
|
+
port: config.port,
|
|
2773
|
+
username: config.username,
|
|
2774
|
+
password: config.password,
|
|
2775
|
+
readyTimeout: 3e4,
|
|
2776
|
+
tryKeyboard: true
|
|
2777
|
+
});
|
|
2778
|
+
return { client, sftp };
|
|
2779
|
+
}
|
|
2780
|
+
async function closeSsh(conn) {
|
|
2781
|
+
try {
|
|
2782
|
+
await conn.sftp.end();
|
|
2783
|
+
} catch {
|
|
2784
|
+
}
|
|
2785
|
+
conn.client.end();
|
|
2786
|
+
}
|
|
2787
|
+
async function getRemoteFileStats(sftp, remoteDir) {
|
|
2788
|
+
const stats = /* @__PURE__ */ new Map();
|
|
2789
|
+
try {
|
|
2790
|
+
const listing = await sftp.list(remoteDir);
|
|
2791
|
+
for (const item of listing) {
|
|
2792
|
+
if (item.name.endsWith(".jar")) {
|
|
2793
|
+
stats.set(item.name, { filename: item.name, size: item.size });
|
|
2794
|
+
}
|
|
2795
|
+
}
|
|
2796
|
+
} catch {
|
|
2797
|
+
}
|
|
2798
|
+
return stats;
|
|
2799
|
+
}
|
|
2800
|
+
async function uploadUpdatePackage(sftp, zipPath, config) {
|
|
2801
|
+
const remoteDir = config.remoteVueDistDir.replace(/\/$/, "");
|
|
2802
|
+
const remotePath = `${remoteDir}/${path2.basename(zipPath)}`;
|
|
2803
|
+
log(`\u4E0A\u4F20\u66F4\u65B0\u5305 -> ${remotePath}`);
|
|
2804
|
+
try {
|
|
2805
|
+
await sftp.fastPut(zipPath, remotePath);
|
|
2806
|
+
log("\u66F4\u65B0\u5305\u4E0A\u4F20\u6210\u529F");
|
|
2807
|
+
} catch (err) {
|
|
2808
|
+
fail(`\u66F4\u65B0\u5305\u4E0A\u4F20\u5931\u8D25: ${err instanceof Error ? err.message : err}`);
|
|
2809
|
+
}
|
|
2810
|
+
return remotePath;
|
|
2811
|
+
}
|
|
2812
|
+
async function runRemoteCommand(client, command, options) {
|
|
2813
|
+
const check = options?.check ?? true;
|
|
2814
|
+
const stream = options?.stream ?? false;
|
|
2815
|
+
log(`\u8FDC\u7A0B\u6267\u884C: ${command}`);
|
|
2816
|
+
return new Promise((resolve5, reject) => {
|
|
2817
|
+
client.exec(command, (err, execStream) => {
|
|
2818
|
+
if (err) {
|
|
2819
|
+
reject(err);
|
|
2820
|
+
return;
|
|
2821
|
+
}
|
|
2822
|
+
let out = "";
|
|
2823
|
+
let errText = "";
|
|
2824
|
+
execStream.on("data", (data) => {
|
|
2825
|
+
const text = data.toString();
|
|
2826
|
+
out += text;
|
|
2827
|
+
if (stream) {
|
|
2828
|
+
process.stdout.write(text);
|
|
2829
|
+
}
|
|
2830
|
+
});
|
|
2831
|
+
execStream.stderr.on("data", (data) => {
|
|
2832
|
+
errText += data.toString();
|
|
2833
|
+
});
|
|
2834
|
+
execStream.on("close", (code) => {
|
|
2835
|
+
if (!stream) {
|
|
2836
|
+
if (out) {
|
|
2837
|
+
console.log(out.trimEnd());
|
|
2838
|
+
}
|
|
2839
|
+
if (errText) {
|
|
2840
|
+
console.error(errText.trimEnd());
|
|
2841
|
+
}
|
|
2842
|
+
} else if (out && !out.endsWith("\n")) {
|
|
2843
|
+
process.stdout.write("\n");
|
|
2844
|
+
}
|
|
2845
|
+
if (check && code !== 0) {
|
|
2846
|
+
fail(`\u8FDC\u7A0B\u547D\u4EE4\u5931\u8D25 (exit ${code}): ${command}`);
|
|
2847
|
+
}
|
|
2848
|
+
resolve5({ exitCode: code, out: out.trim(), err: errText.trim() });
|
|
2849
|
+
});
|
|
2850
|
+
});
|
|
2851
|
+
});
|
|
2852
|
+
}
|
|
2853
|
+
function buildExtractUpdatePackageScript(remoteZipPath, remoteLibDir) {
|
|
2854
|
+
const quotedZip = shellSingleQuote(remoteZipPath);
|
|
2855
|
+
const quotedLib = shellSingleQuote(remoteLibDir);
|
|
2856
|
+
return `
|
|
2857
|
+
set -e
|
|
2858
|
+
TMP=$(mktemp -d)
|
|
2859
|
+
trap 'rm -rf "$TMP"' EXIT
|
|
2860
|
+
unzip -oq ${quotedZip} -d "$TMP"
|
|
2861
|
+
updated=0
|
|
2862
|
+
while IFS= read -r -d '' src; do
|
|
2863
|
+
name=$(basename "$src")
|
|
2864
|
+
dest=${quotedLib}/"$name"
|
|
2865
|
+
if [ -f "$dest" ]; then
|
|
2866
|
+
cp -f "$src" "$dest"
|
|
2867
|
+
echo "\u8986\u76D6: $name"
|
|
2868
|
+
updated=$((updated + 1))
|
|
2869
|
+
else
|
|
2870
|
+
echo "\u8DF3\u8FC7(\u8FDC\u7A0B\u4E0D\u5B58\u5728): $name"
|
|
2871
|
+
fi
|
|
2872
|
+
done < <(find "$TMP" -name '*.jar' -type f -print0)
|
|
2873
|
+
echo "UPDATED_COUNT=$updated"
|
|
2874
|
+
`.trim();
|
|
2875
|
+
}
|
|
2876
|
+
async function extractUpdatePackageOnRemote(client, config, remoteZipPath) {
|
|
2877
|
+
const script = buildExtractUpdatePackageScript(
|
|
2878
|
+
remoteZipPath,
|
|
2879
|
+
config.remoteLibDir
|
|
2880
|
+
);
|
|
2881
|
+
const { out } = await runRemoteCommand(client, script);
|
|
2882
|
+
const match = out.match(/UPDATED_COUNT=(\d+)/);
|
|
2883
|
+
if (!match) {
|
|
2884
|
+
fail(`\u8FDC\u7A0B\u89E3\u538B\u5931\u8D25\uFF0C\u672A\u83B7\u53D6\u66F4\u65B0\u6570\u91CF
|
|
2885
|
+
\u8F93\u51FA: ${out || "(\u7A7A)"}`);
|
|
2886
|
+
}
|
|
2887
|
+
const updated = Number.parseInt(match[1], 10);
|
|
2888
|
+
log(`lib \u89E3\u538B\u5B8C\u6210: \u8986\u76D6 ${updated} \u4E2A`);
|
|
2889
|
+
return updated;
|
|
2890
|
+
}
|
|
2891
|
+
function springbootOutputIndicatesSuccess(action, combined) {
|
|
2892
|
+
const lower = combined.toLowerCase();
|
|
2893
|
+
if (action === "health") {
|
|
2894
|
+
return combined.includes("\u5065\u5EB7\u68C0\u67E5\u901A\u8FC7");
|
|
2895
|
+
}
|
|
2896
|
+
if (action === "start" || action === "restart") {
|
|
2897
|
+
return combined.includes("is starting") || lower.includes("is running");
|
|
2898
|
+
}
|
|
2899
|
+
if (action === "stop") {
|
|
2900
|
+
return combined.includes("is stopping") || lower.includes("not running") || lower.includes("please check it");
|
|
2901
|
+
}
|
|
2902
|
+
if (action === "status") {
|
|
2903
|
+
return lower.includes("running") || lower.includes("not running");
|
|
2904
|
+
}
|
|
2905
|
+
return true;
|
|
2906
|
+
}
|
|
2907
|
+
async function runSpringbootAction(client, config, action, ...args) {
|
|
2908
|
+
if (action === "start" || action === "restart") {
|
|
2909
|
+
if (args.length === 0) {
|
|
2910
|
+
fail(`\u8FDC\u7A0B ${action} \u7F3A\u5C11 jar \u53C2\u6570`);
|
|
2911
|
+
}
|
|
2912
|
+
const jar = args[0].trim().split(/\r?\n/)[0].trim();
|
|
2913
|
+
if (!jar) {
|
|
2914
|
+
fail(`\u65E0\u6548\u7684 jar \u540D\u79F0: ${JSON.stringify(args[0])}`);
|
|
2915
|
+
}
|
|
2916
|
+
}
|
|
2917
|
+
const quotedArgs = [action, ...args].map((arg) => shellSingleQuote(arg));
|
|
2918
|
+
const command = [
|
|
2919
|
+
`cd ${shellSingleQuote(config.remoteAppDir)}`,
|
|
2920
|
+
`./${SPRINGBOOT_SCRIPT} ${quotedArgs.join(" ")}`
|
|
2921
|
+
].join(" && ");
|
|
2922
|
+
const { exitCode, out, err } = await runRemoteCommand(client, command, {
|
|
2923
|
+
check: false
|
|
2924
|
+
});
|
|
2925
|
+
const combined = `${out}
|
|
2926
|
+
${err}`.trim();
|
|
2927
|
+
const outputOk = springbootOutputIndicatesSuccess(action, combined);
|
|
2928
|
+
if (action === "health") {
|
|
2929
|
+
if (exitCode !== 0 || !outputOk) {
|
|
2930
|
+
fail(`\u5065\u5EB7\u68C0\u67E5\u5931\u8D25
|
|
2931
|
+
\u547D\u4EE4: ${command}
|
|
2932
|
+
\u8F93\u51FA: ${combined || "(\u7A7A)"}`);
|
|
2933
|
+
}
|
|
2934
|
+
return combined;
|
|
2935
|
+
}
|
|
2936
|
+
if (exitCode !== 0 && !outputOk) {
|
|
2937
|
+
fail(`\u8FDC\u7A0B ${action} \u5931\u8D25: ${args.join(" ")}
|
|
2938
|
+
${combined}`);
|
|
2939
|
+
}
|
|
2940
|
+
if ((action === "start" || action === "restart") && !outputOk) {
|
|
2941
|
+
fail(
|
|
2942
|
+
`\u8FDC\u7A0B ${action} \u672A\u6210\u529F: ${args.join(" ")}
|
|
2943
|
+
\u547D\u4EE4: ${command}
|
|
2944
|
+
\u8F93\u51FA: ${combined || "(\u7A7A)"}`
|
|
2945
|
+
);
|
|
2946
|
+
}
|
|
2947
|
+
return combined;
|
|
2948
|
+
}
|
|
2949
|
+
function stripAnsi(text) {
|
|
2950
|
+
return text.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "");
|
|
2951
|
+
}
|
|
2952
|
+
async function getRunningJar(client, config) {
|
|
2953
|
+
const combined = await runSpringbootAction(
|
|
2954
|
+
client,
|
|
2955
|
+
config,
|
|
2956
|
+
"status",
|
|
2957
|
+
config.startupJar
|
|
2958
|
+
);
|
|
2959
|
+
const text = stripAnsi(combined).trim().toLowerCase();
|
|
2960
|
+
if (text.includes("not running")) {
|
|
2961
|
+
return null;
|
|
2962
|
+
}
|
|
2963
|
+
if (text.includes("running")) {
|
|
2964
|
+
return config.startupJar;
|
|
2965
|
+
}
|
|
2966
|
+
return null;
|
|
2967
|
+
}
|
|
2968
|
+
async function healthCheckService(client, config) {
|
|
2969
|
+
const port = String(config.healthCheckPort);
|
|
2970
|
+
const context = config.healthCheckContext;
|
|
2971
|
+
const timeout = String(config.healthCheckTimeout);
|
|
2972
|
+
log(`\u5065\u5EB7\u68C0\u67E5: springboot.sh health ${port} ${context} ${timeout}`);
|
|
2973
|
+
await runSpringbootAction(client, config, "health", port, context, timeout);
|
|
2974
|
+
}
|
|
2975
|
+
async function runWisdomBackendDeploy(options) {
|
|
2976
|
+
const projectRoot = path2.resolve(options.projectRoot ?? process.cwd());
|
|
2977
|
+
const config = options.config;
|
|
2978
|
+
log(`=== \u81EA\u52A8\u90E8\u7F72: ${config.projectName} ===`);
|
|
2979
|
+
log(`\u914D\u7F6E\u6587\u4EF6: ${path2.join(workspaceApmDir(), "apm.config.json")}`);
|
|
2980
|
+
log(`\u9879\u76EE\u6839\u76EE\u5F55: ${projectRoot}`);
|
|
2981
|
+
if (!options.skipMaven) {
|
|
2982
|
+
runMavenBuild(projectRoot, config.mavenLocalRepo);
|
|
2983
|
+
}
|
|
2984
|
+
const libDir = locateLibDir(projectRoot);
|
|
2985
|
+
let manifest = loadManifest3();
|
|
2986
|
+
const conn = await connectSsh(config);
|
|
2987
|
+
try {
|
|
2988
|
+
const remoteLibStats = await getRemoteFileStats(
|
|
2989
|
+
conn.sftp,
|
|
2990
|
+
config.remoteLibDir
|
|
2991
|
+
);
|
|
2992
|
+
log("\u6536\u96C6 JAR \u66F4\u65B0...");
|
|
2993
|
+
const libUploadEntries = listLibFilesToUpload(
|
|
2994
|
+
libDir,
|
|
2995
|
+
remoteLibStats,
|
|
2996
|
+
projectRoot,
|
|
2997
|
+
manifest
|
|
2998
|
+
);
|
|
2999
|
+
let updated = 0;
|
|
3000
|
+
if (libUploadEntries.length > 0) {
|
|
3001
|
+
const zipPath = await createUpdatePackage(
|
|
3002
|
+
libUploadEntries,
|
|
3003
|
+
config.packageName
|
|
3004
|
+
);
|
|
3005
|
+
const remoteZipPath = await uploadUpdatePackage(
|
|
3006
|
+
conn.sftp,
|
|
3007
|
+
zipPath,
|
|
3008
|
+
config
|
|
3009
|
+
);
|
|
3010
|
+
log("\u8FDC\u7A0B\u89E3\u538B lib \u76EE\u5F55\uFF08\u4EC5\u8986\u76D6\u5DF2\u6709 JAR\uFF09...");
|
|
3011
|
+
updated = await extractUpdatePackageOnRemote(
|
|
3012
|
+
conn.client,
|
|
3013
|
+
config,
|
|
3014
|
+
remoteZipPath
|
|
3015
|
+
);
|
|
3016
|
+
} else {
|
|
3017
|
+
log("\u65E0 JAR \u9700\u8981\u66F4\u65B0\uFF0C\u8DF3\u8FC7\u66F4\u65B0\u5305\u4E0A\u4F20");
|
|
3018
|
+
}
|
|
3019
|
+
const runningJar = await getRunningJar(conn.client, config);
|
|
3020
|
+
let needRestart = updated > 0;
|
|
3021
|
+
if (!needRestart && !runningJar) {
|
|
3022
|
+
log("\u670D\u52A1\u672A\u8FD0\u884C\uFF0C\u9700\u8981\u542F\u52A8");
|
|
3023
|
+
needRestart = true;
|
|
3024
|
+
} else if (!needRestart) {
|
|
3025
|
+
log("\u6CA1\u6709\u6587\u4EF6\u9700\u8981\u66F4\u65B0\uFF0C\u8DF3\u8FC7\u91CD\u542F");
|
|
3026
|
+
}
|
|
3027
|
+
if (needRestart) {
|
|
3028
|
+
log("\u91CD\u542F\u670D\u52A1...");
|
|
3029
|
+
await runSpringbootAction(
|
|
3030
|
+
conn.client,
|
|
3031
|
+
config,
|
|
3032
|
+
"restart",
|
|
3033
|
+
config.startupJar
|
|
3034
|
+
);
|
|
3035
|
+
}
|
|
3036
|
+
await healthCheckService(conn.client, config);
|
|
3037
|
+
if (libUploadEntries.length > 0) {
|
|
3038
|
+
manifest = updateManifestEntries(manifest, libUploadEntries, projectRoot);
|
|
3039
|
+
saveManifest3(manifest);
|
|
3040
|
+
}
|
|
3041
|
+
} finally {
|
|
3042
|
+
await closeSsh(conn);
|
|
3043
|
+
}
|
|
3044
|
+
log("\u90E8\u7F72\u5B8C\u6210");
|
|
3045
|
+
}
|
|
3046
|
+
|
|
3047
|
+
// src/commands/deploy/internal/wisdom-auto-deploy.ts
|
|
3048
|
+
function isWisdomLegacyDeploy(cfg) {
|
|
3049
|
+
const w = cfg.wisdomDeploy;
|
|
3050
|
+
if (!w?.host?.trim() || !w.remotePath?.trim()) {
|
|
3051
|
+
return false;
|
|
3052
|
+
}
|
|
3053
|
+
const hasNewFrontend = Boolean(cfg.frontendDeploy?.endpoint?.trim());
|
|
3054
|
+
const hasNewBackend = Boolean(cfg.backendDeploy?.registryHost?.trim());
|
|
3055
|
+
return !hasNewFrontend && !hasNewBackend;
|
|
3056
|
+
}
|
|
3057
|
+
function detectWisdomProjectType(cwd) {
|
|
3058
|
+
return existsSync13(path3.join(cwd, "package.json")) ? "frontend" : "backend";
|
|
3059
|
+
}
|
|
3060
|
+
function readPackageScripts(cwd) {
|
|
3061
|
+
const pkgPath = path3.join(cwd, "package.json");
|
|
3062
|
+
if (!existsSync13(pkgPath)) {
|
|
3063
|
+
return {};
|
|
3064
|
+
}
|
|
3065
|
+
try {
|
|
3066
|
+
const raw = readFileSync11(pkgPath, "utf8");
|
|
3067
|
+
const parsed = JSON.parse(raw);
|
|
3068
|
+
return parsed.scripts ?? {};
|
|
3069
|
+
} catch {
|
|
3070
|
+
return {};
|
|
3071
|
+
}
|
|
3072
|
+
}
|
|
3073
|
+
function resolveFrontendDeployCommand(env, cwd) {
|
|
3074
|
+
const scripts = readPackageScripts(cwd);
|
|
3075
|
+
const deployKey = `deploy:${env}`;
|
|
3076
|
+
if (scripts[deployKey]?.trim()) {
|
|
3077
|
+
return `npm run deploy:${env}`;
|
|
3078
|
+
}
|
|
3079
|
+
return null;
|
|
3080
|
+
}
|
|
3081
|
+
function runShellCommand(command, cwd) {
|
|
3082
|
+
console.error(`==> ${command}`);
|
|
3083
|
+
const result = spawnSync3(command, {
|
|
3084
|
+
cwd,
|
|
3085
|
+
stdio: "inherit",
|
|
3086
|
+
shell: true,
|
|
3087
|
+
env: process.env
|
|
3088
|
+
});
|
|
3089
|
+
if (result.status !== 0) {
|
|
3090
|
+
process.exit(result.status ?? 1);
|
|
3091
|
+
}
|
|
3092
|
+
}
|
|
3093
|
+
async function runWisdomAutoDeploy(options) {
|
|
3094
|
+
const cwd = path3.resolve(options.cwd ?? process.cwd());
|
|
3095
|
+
const projectType = detectWisdomProjectType(cwd);
|
|
3096
|
+
console.error(
|
|
3097
|
+
`[apm] \u533B\u52A1\u5B58\u91CF\u9879\u76EE\u81EA\u52A8\u8BC6\u522B: ${projectType === "frontend" ? "\u524D\u7AEF Vue" : "\u540E\u7AEF Java"}`
|
|
3098
|
+
);
|
|
3099
|
+
if (projectType === "frontend") {
|
|
3100
|
+
const deployCmd = resolveFrontendDeployCommand(options.env, cwd);
|
|
3101
|
+
if (!deployCmd) {
|
|
3102
|
+
console.error(
|
|
3103
|
+
`\u524D\u7AEF\u9879\u76EE ${path3.join(cwd, "package.json")} \u4E2D\u672A\u627E\u5230 deploy:${options.env} \u811A\u672C`
|
|
3104
|
+
);
|
|
3105
|
+
process.exit(1);
|
|
3106
|
+
}
|
|
3107
|
+
runShellCommand(deployCmd, cwd);
|
|
3108
|
+
return { projectType };
|
|
3109
|
+
}
|
|
3110
|
+
const configPath = options.configPath ?? path3.join(workspaceApmDir(cwd), "apm.config.json");
|
|
3111
|
+
const cfg = loadApmConfig({ configPath });
|
|
3112
|
+
const settings = resolveWisdomBackendDeployFromApmConfig(cfg);
|
|
3113
|
+
await runWisdomBackendDeploy({
|
|
3114
|
+
config: settings,
|
|
3115
|
+
projectRoot: cwd,
|
|
3116
|
+
skipMaven: Boolean(options.skipMaven)
|
|
3117
|
+
});
|
|
3118
|
+
return { projectType };
|
|
3119
|
+
}
|
|
3120
|
+
|
|
3121
|
+
// src/commands/connect/deploy-run.ts
|
|
2231
3122
|
var DEPLOY_LOG_SYNC_INTERVAL_MS = 3e4;
|
|
2232
|
-
function
|
|
3123
|
+
function readApmConfig(workdir) {
|
|
2233
3124
|
const configPath = join13(workspaceApmDir(workdir), "apm.config.json");
|
|
3125
|
+
if (!existsSync14(configPath)) {
|
|
3126
|
+
return void 0;
|
|
3127
|
+
}
|
|
2234
3128
|
try {
|
|
2235
|
-
const raw =
|
|
2236
|
-
|
|
2237
|
-
return parsed.deploy;
|
|
3129
|
+
const raw = readFileSync12(configPath, "utf8");
|
|
3130
|
+
return JSON.parse(raw);
|
|
2238
3131
|
} catch {
|
|
2239
3132
|
return void 0;
|
|
2240
3133
|
}
|
|
2241
3134
|
}
|
|
3135
|
+
function readDeployConfig(workdir) {
|
|
3136
|
+
return readApmConfig(workdir)?.deploy;
|
|
3137
|
+
}
|
|
2242
3138
|
function resolveDeployCommand(workdir, environment) {
|
|
2243
3139
|
const command = readDeployConfig(workdir)?.[environment];
|
|
2244
3140
|
if (typeof command === "string" && command.trim()) {
|
|
@@ -2252,7 +3148,7 @@ function missingDeployCommandMessage(environment) {
|
|
|
2252
3148
|
function buildDeployLog(stdout, stderr) {
|
|
2253
3149
|
return [stdout, stderr].filter(Boolean).join("\n");
|
|
2254
3150
|
}
|
|
2255
|
-
function
|
|
3151
|
+
function runShellCommand2(command, cwd, signal, onOutput) {
|
|
2256
3152
|
return new Promise((resolve5, reject) => {
|
|
2257
3153
|
const child = spawn(command, {
|
|
2258
3154
|
cwd,
|
|
@@ -2287,15 +3183,15 @@ function runShellCommand(command, cwd, signal, onOutput) {
|
|
|
2287
3183
|
});
|
|
2288
3184
|
child.on("close", (code) => {
|
|
2289
3185
|
signal.removeEventListener("abort", onAbort);
|
|
2290
|
-
const
|
|
3186
|
+
const log2 = buildDeployLog(stdout, stderr);
|
|
2291
3187
|
if (code === 0) {
|
|
2292
|
-
resolve5({ log });
|
|
3188
|
+
resolve5({ log: log2 });
|
|
2293
3189
|
return;
|
|
2294
3190
|
}
|
|
2295
3191
|
const error = new Error(
|
|
2296
3192
|
`\u90E8\u7F72\u547D\u4EE4\u9000\u51FA\u7801 ${code ?? "unknown"}: ${command}`
|
|
2297
3193
|
);
|
|
2298
|
-
error.log =
|
|
3194
|
+
error.log = log2;
|
|
2299
3195
|
reject(error);
|
|
2300
3196
|
});
|
|
2301
3197
|
});
|
|
@@ -2322,8 +3218,8 @@ function createDeployLogSyncer(api, deploymentRunId) {
|
|
|
2322
3218
|
});
|
|
2323
3219
|
}, DEPLOY_LOG_SYNC_INTERVAL_MS);
|
|
2324
3220
|
return {
|
|
2325
|
-
updateLog(
|
|
2326
|
-
latestLog =
|
|
3221
|
+
updateLog(log2) {
|
|
3222
|
+
latestLog = log2;
|
|
2327
3223
|
},
|
|
2328
3224
|
async flush() {
|
|
2329
3225
|
clearInterval(timer);
|
|
@@ -2343,6 +3239,39 @@ async function handleInboundDeploy(cfg, msg, signal) {
|
|
|
2343
3239
|
status: "DEPLOYING"
|
|
2344
3240
|
});
|
|
2345
3241
|
const workdir = requireRemoteWorkdir(msg.workdir);
|
|
3242
|
+
const apmConfig = readApmConfig(workdir);
|
|
3243
|
+
if (apmConfig && isWisdomLegacyDeploy(apmConfig)) {
|
|
3244
|
+
console.log(
|
|
3245
|
+
`[apm] deploy start id=${deploymentRunId} env=${msg.environment} cwd=${workdir} (wisdom auto)`
|
|
3246
|
+
);
|
|
3247
|
+
const logSyncer2 = createDeployLogSyncer(api, deploymentRunId);
|
|
3248
|
+
try {
|
|
3249
|
+
await runWisdomAutoDeploy({
|
|
3250
|
+
env: msg.environment,
|
|
3251
|
+
cwd: workdir
|
|
3252
|
+
});
|
|
3253
|
+
await logSyncer2.flush();
|
|
3254
|
+
await api.cli.completeTaskDeployment({
|
|
3255
|
+
id: deploymentRunId,
|
|
3256
|
+
status: "SUCCESS",
|
|
3257
|
+
log: "\u533B\u52A1\u5B58\u91CF\u9879\u76EE\u81EA\u52A8\u90E8\u7F72\u5B8C\u6210"
|
|
3258
|
+
});
|
|
3259
|
+
console.log(`[apm] deploy success id=${deploymentRunId}`);
|
|
3260
|
+
} catch (error) {
|
|
3261
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
3262
|
+
await logSyncer2.flush();
|
|
3263
|
+
await api.cli.completeTaskDeployment({
|
|
3264
|
+
id: deploymentRunId,
|
|
3265
|
+
status: "FAILED",
|
|
3266
|
+
log: detail,
|
|
3267
|
+
error: detail
|
|
3268
|
+
});
|
|
3269
|
+
console.error(`[apm] deploy failed id=${deploymentRunId}: ${detail}`);
|
|
3270
|
+
} finally {
|
|
3271
|
+
logSyncer2.dispose();
|
|
3272
|
+
}
|
|
3273
|
+
return;
|
|
3274
|
+
}
|
|
2346
3275
|
const command = resolveDeployCommand(workdir, msg.environment);
|
|
2347
3276
|
if (!command) {
|
|
2348
3277
|
const error = missingDeployCommandMessage(msg.environment);
|
|
@@ -2362,28 +3291,28 @@ async function handleInboundDeploy(cfg, msg, signal) {
|
|
|
2362
3291
|
const logSyncer = createDeployLogSyncer(api, deploymentRunId);
|
|
2363
3292
|
let latestLog = "";
|
|
2364
3293
|
try {
|
|
2365
|
-
const { log } = await
|
|
2366
|
-
latestLog =
|
|
2367
|
-
logSyncer.updateLog(
|
|
3294
|
+
const { log: log2 } = await runShellCommand2(command, workdir, signal, (log3) => {
|
|
3295
|
+
latestLog = log3;
|
|
3296
|
+
logSyncer.updateLog(log3);
|
|
2368
3297
|
});
|
|
2369
|
-
latestLog =
|
|
2370
|
-
logSyncer.updateLog(
|
|
3298
|
+
latestLog = log2;
|
|
3299
|
+
logSyncer.updateLog(log2);
|
|
2371
3300
|
await logSyncer.flush();
|
|
2372
3301
|
await api.cli.completeTaskDeployment({
|
|
2373
3302
|
id: deploymentRunId,
|
|
2374
3303
|
status: "SUCCESS",
|
|
2375
|
-
log
|
|
3304
|
+
log: log2
|
|
2376
3305
|
});
|
|
2377
3306
|
console.log(`[apm] deploy success id=${deploymentRunId}`);
|
|
2378
3307
|
} catch (error) {
|
|
2379
3308
|
const detail = error instanceof Error ? error.message : String(error);
|
|
2380
|
-
const
|
|
2381
|
-
logSyncer.updateLog(
|
|
3309
|
+
const log2 = error && typeof error === "object" && "log" in error ? String(error.log ?? latestLog) : latestLog;
|
|
3310
|
+
logSyncer.updateLog(log2);
|
|
2382
3311
|
await logSyncer.flush();
|
|
2383
3312
|
await api.cli.completeTaskDeployment({
|
|
2384
3313
|
id: deploymentRunId,
|
|
2385
3314
|
status: "FAILED",
|
|
2386
|
-
log,
|
|
3315
|
+
log: log2,
|
|
2387
3316
|
error: detail
|
|
2388
3317
|
});
|
|
2389
3318
|
console.error(`[apm] deploy failed id=${deploymentRunId}: ${detail}`);
|
|
@@ -2659,17 +3588,17 @@ ${JSON.stringify(event, null, 2)}
|
|
|
2659
3588
|
}
|
|
2660
3589
|
|
|
2661
3590
|
// src/commands/connect/agent-session-registry.ts
|
|
2662
|
-
import { existsSync as
|
|
2663
|
-
import { dirname as dirname4, resolve as
|
|
3591
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync6, readFileSync as readFileSync13, writeFileSync as writeFileSync11 } from "node:fs";
|
|
3592
|
+
import { dirname as dirname4, resolve as resolve4 } from "node:path";
|
|
2664
3593
|
function registryPath(workdir, sessionId) {
|
|
2665
|
-
return
|
|
3594
|
+
return resolve4(workdir, ".apm", "sessions", sessionId, "cursor-agents.json");
|
|
2666
3595
|
}
|
|
2667
|
-
function readRegistry(
|
|
2668
|
-
if (!
|
|
3596
|
+
function readRegistry(path12) {
|
|
3597
|
+
if (!existsSync15(path12)) {
|
|
2669
3598
|
return {};
|
|
2670
3599
|
}
|
|
2671
3600
|
try {
|
|
2672
|
-
const parsed = JSON.parse(
|
|
3601
|
+
const parsed = JSON.parse(readFileSync13(path12, "utf8"));
|
|
2673
3602
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
2674
3603
|
const result = {};
|
|
2675
3604
|
for (const [key, value] of Object.entries(
|
|
@@ -2685,9 +3614,9 @@ function readRegistry(path10) {
|
|
|
2685
3614
|
}
|
|
2686
3615
|
return {};
|
|
2687
3616
|
}
|
|
2688
|
-
function writeRegistry(
|
|
2689
|
-
|
|
2690
|
-
|
|
3617
|
+
function writeRegistry(path12, registry) {
|
|
3618
|
+
mkdirSync6(dirname4(path12), { recursive: true });
|
|
3619
|
+
writeFileSync11(path12, `${JSON.stringify(registry, null, 2)}
|
|
2691
3620
|
`, "utf8");
|
|
2692
3621
|
}
|
|
2693
3622
|
function loadSessionAgentId(workdir, sessionId, user) {
|
|
@@ -2695,19 +3624,19 @@ function loadSessionAgentId(workdir, sessionId, user) {
|
|
|
2695
3624
|
return registry[user];
|
|
2696
3625
|
}
|
|
2697
3626
|
function saveSessionAgentId(workdir, sessionId, user, agentId) {
|
|
2698
|
-
const
|
|
2699
|
-
const registry = readRegistry(
|
|
3627
|
+
const path12 = registryPath(workdir, sessionId);
|
|
3628
|
+
const registry = readRegistry(path12);
|
|
2700
3629
|
registry[user] = agentId;
|
|
2701
|
-
writeRegistry(
|
|
3630
|
+
writeRegistry(path12, registry);
|
|
2702
3631
|
}
|
|
2703
3632
|
function clearSessionAgentId(workdir, sessionId, user) {
|
|
2704
|
-
const
|
|
2705
|
-
const registry = readRegistry(
|
|
3633
|
+
const path12 = registryPath(workdir, sessionId);
|
|
3634
|
+
const registry = readRegistry(path12);
|
|
2706
3635
|
if (!(user in registry)) {
|
|
2707
3636
|
return;
|
|
2708
3637
|
}
|
|
2709
3638
|
delete registry[user];
|
|
2710
|
-
writeRegistry(
|
|
3639
|
+
writeRegistry(path12, registry);
|
|
2711
3640
|
}
|
|
2712
3641
|
|
|
2713
3642
|
// src/commands/connect/cursor-message-log.ts
|
|
@@ -3101,20 +4030,20 @@ async function runCursorAgent(cfg, ctx, options) {
|
|
|
3101
4030
|
}
|
|
3102
4031
|
|
|
3103
4032
|
// src/commands/connect/cli-version-sync.ts
|
|
3104
|
-
import { existsSync as
|
|
4033
|
+
import { existsSync as existsSync16, readFileSync as readFileSync14, writeFileSync as writeFileSync12 } from "fs";
|
|
3105
4034
|
import { join as join14 } from "path";
|
|
3106
4035
|
var CLI_VERSION_FILE = ".cli-version.json";
|
|
3107
4036
|
function manifestPath(apmDir) {
|
|
3108
4037
|
return join14(apmDir, CLI_VERSION_FILE);
|
|
3109
4038
|
}
|
|
3110
|
-
function
|
|
3111
|
-
const
|
|
3112
|
-
if (!
|
|
4039
|
+
function loadManifest4(apmDir) {
|
|
4040
|
+
const path12 = toFsPath(manifestPath(apmDir));
|
|
4041
|
+
if (!existsSync16(path12)) {
|
|
3113
4042
|
return null;
|
|
3114
4043
|
}
|
|
3115
4044
|
try {
|
|
3116
4045
|
const parsed = JSON.parse(
|
|
3117
|
-
|
|
4046
|
+
readFileSync14(path12, "utf8")
|
|
3118
4047
|
);
|
|
3119
4048
|
if (parsed?.version === 1 && typeof parsed.cliVersion === "string" && parsed.cliVersion.trim()) {
|
|
3120
4049
|
return parsed;
|
|
@@ -3123,9 +4052,9 @@ function loadManifest3(apmDir) {
|
|
|
3123
4052
|
}
|
|
3124
4053
|
return null;
|
|
3125
4054
|
}
|
|
3126
|
-
function
|
|
4055
|
+
function saveManifest4(apmDir, cliVersion) {
|
|
3127
4056
|
const manifest = { version: 1, cliVersion };
|
|
3128
|
-
|
|
4057
|
+
writeFileSync12(
|
|
3129
4058
|
toFsPath(manifestPath(apmDir)),
|
|
3130
4059
|
`${JSON.stringify(manifest, null, 2)}
|
|
3131
4060
|
`,
|
|
@@ -3138,7 +4067,7 @@ function shouldSyncSkillsForCliVersion(workdir, currentVersion) {
|
|
|
3138
4067
|
if (cached === currentVersion) {
|
|
3139
4068
|
return false;
|
|
3140
4069
|
}
|
|
3141
|
-
const stored =
|
|
4070
|
+
const stored = loadManifest4(workspaceApmDir(workdir));
|
|
3142
4071
|
if (stored?.cliVersion === currentVersion) {
|
|
3143
4072
|
syncedInSession.set(workdir, currentVersion);
|
|
3144
4073
|
return false;
|
|
@@ -3146,7 +4075,7 @@ function shouldSyncSkillsForCliVersion(workdir, currentVersion) {
|
|
|
3146
4075
|
return true;
|
|
3147
4076
|
}
|
|
3148
4077
|
function markSkillsSyncedForCliVersion(workdir, cliVersion) {
|
|
3149
|
-
|
|
4078
|
+
saveManifest4(workspaceApmDir(workdir), cliVersion);
|
|
3150
4079
|
syncedInSession.set(workdir, cliVersion);
|
|
3151
4080
|
}
|
|
3152
4081
|
|
|
@@ -3373,7 +4302,7 @@ function reexecConnect(options) {
|
|
|
3373
4302
|
if (server) {
|
|
3374
4303
|
args.push("--server", server);
|
|
3375
4304
|
}
|
|
3376
|
-
const result =
|
|
4305
|
+
const result = spawnSync4(process.execPath, args, { stdio: "inherit" });
|
|
3377
4306
|
if (result.error) {
|
|
3378
4307
|
console.error("[apm] \u91CD\u542F connect \u5931\u8D25:", result.error.message);
|
|
3379
4308
|
process.exit(1);
|
|
@@ -3509,202 +4438,123 @@ async function runConnect(options) {
|
|
|
3509
4438
|
activeTasks.delete(task);
|
|
3510
4439
|
});
|
|
3511
4440
|
});
|
|
3512
|
-
ws.on("close", (code, reason) => {
|
|
3513
|
-
console.log(
|
|
3514
|
-
`[apm] \u8FDE\u63A5\u5DF2\u65AD\u5F00 code=${code}${reason ? ` reason=${reason.toString()}` : ""}`
|
|
3515
|
-
);
|
|
3516
|
-
void shutdown();
|
|
3517
|
-
});
|
|
3518
|
-
ws.on("error", (err) => {
|
|
3519
|
-
console.error("[apm] WebSocket \u9519\u8BEF:", err.message);
|
|
3520
|
-
reject(err);
|
|
3521
|
-
});
|
|
3522
|
-
process.on("SIGINT", () => {
|
|
3523
|
-
console.log("[apm] \u6B63\u5728\u5173\u95ED\u2026");
|
|
3524
|
-
void shutdown();
|
|
3525
|
-
});
|
|
3526
|
-
process.on("SIGTERM", () => {
|
|
3527
|
-
void shutdown();
|
|
3528
|
-
});
|
|
3529
|
-
});
|
|
3530
|
-
}
|
|
3531
|
-
|
|
3532
|
-
// src/commands/create-pr.ts
|
|
3533
|
-
async function runCreatePr(options) {
|
|
3534
|
-
const sessionId = options.sessionId.trim();
|
|
3535
|
-
if (!sessionId) {
|
|
3536
|
-
console.error("[apm] sessionId \u4E0D\u80FD\u4E3A\u7A7A");
|
|
3537
|
-
process.exit(1);
|
|
3538
|
-
}
|
|
3539
|
-
const title = options.title.trim();
|
|
3540
|
-
if (!title) {
|
|
3541
|
-
console.error("[apm] \u8BF7\u901A\u8FC7 --title \u6307\u5B9A PR \u6807\u9898");
|
|
3542
|
-
process.exit(1);
|
|
3543
|
-
}
|
|
3544
|
-
const cfg = await ensureLoggedConfig();
|
|
3545
|
-
const api = createApmApiClient(cfg);
|
|
3546
|
-
const workdir = resolveWorkdirPath(options.cwd ?? process.cwd());
|
|
3547
|
-
const pr = await api.cli.createPullRequest({
|
|
3548
|
-
sessionId,
|
|
3549
|
-
workdir,
|
|
3550
|
-
title,
|
|
3551
|
-
content: options.content ?? ""
|
|
3552
|
-
});
|
|
3553
|
-
console.log(`[apm] PR \u5DF2\u5C31\u7EEA #${pr.number} (${pr.state}): ${pr.url}`);
|
|
3554
|
-
}
|
|
3555
|
-
|
|
3556
|
-
// src/commands/deploy/backend.ts
|
|
3557
|
-
import path5 from "node:path";
|
|
3558
|
-
|
|
3559
|
-
// src/commands/deploy/internal/apm-config.ts
|
|
3560
|
-
import { existsSync as existsSync13, readFileSync as readFileSync12 } from "node:fs";
|
|
3561
|
-
import { resolve as resolve4 } from "node:path";
|
|
3562
|
-
function loadApmConfig(options) {
|
|
3563
|
-
const p = resolve4(
|
|
3564
|
-
process.cwd(),
|
|
3565
|
-
options?.configPath ?? resolve4(workspaceApmDir(), "apm.config.json")
|
|
3566
|
-
);
|
|
3567
|
-
if (!existsSync13(p)) {
|
|
3568
|
-
console.error(`\u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6\uFF1A${p}`);
|
|
3569
|
-
process.exit(1);
|
|
3570
|
-
}
|
|
3571
|
-
try {
|
|
3572
|
-
const raw = readFileSync12(p, "utf8");
|
|
3573
|
-
return JSON.parse(raw);
|
|
3574
|
-
} catch (e) {
|
|
3575
|
-
console.error(`\u65E0\u6CD5\u89E3\u6790 apm.config.json\uFF1A${p}`, e);
|
|
3576
|
-
process.exit(1);
|
|
3577
|
-
}
|
|
3578
|
-
}
|
|
3579
|
-
function req(v, field) {
|
|
3580
|
-
if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
|
|
3581
|
-
console.error(`apm.config.json \u4E2D backendDeploy.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
|
|
3582
|
-
process.exit(1);
|
|
3583
|
-
}
|
|
3584
|
-
return v;
|
|
3585
|
-
}
|
|
3586
|
-
function reqTopLevelName(cfg) {
|
|
3587
|
-
const n = (cfg.name ?? "").trim();
|
|
3588
|
-
if (!n) {
|
|
3589
|
-
console.error(
|
|
3590
|
-
"\u8BF7\u5728 apm.config.json \u9876\u5C42\u914D\u7F6E name\uFF08\u4E0E\u524D\u7AEF\u5236\u54C1\u524D\u7F00\u3001\u540E\u7AEF\u955C\u50CF\u540D\u5171\u7528\uFF09"
|
|
3591
|
-
);
|
|
3592
|
-
process.exit(1);
|
|
3593
|
-
}
|
|
3594
|
-
return n;
|
|
3595
|
-
}
|
|
3596
|
-
function reqBackendPositiveInt(v, field) {
|
|
3597
|
-
const n = Number(v);
|
|
3598
|
-
if (!Number.isFinite(n) || !Number.isInteger(n) || n < 1) {
|
|
3599
|
-
console.error(`apm.config.json \u4E2D backendDeploy.${field} \u987B\u4E3A\u6B63\u6574\u6570`);
|
|
3600
|
-
process.exit(1);
|
|
3601
|
-
}
|
|
3602
|
-
return n;
|
|
3603
|
-
}
|
|
3604
|
-
function resolveBackendDeployFromApmConfig(cfg) {
|
|
3605
|
-
const b = cfg.backendDeploy ?? {};
|
|
3606
|
-
const protoRaw = req(b.remoteProtocol, "remoteProtocol").trim().toLowerCase();
|
|
3607
|
-
if (protoRaw !== "http" && protoRaw !== "https") {
|
|
3608
|
-
console.error(
|
|
3609
|
-
"apm.config.json \u4E2D backendDeploy.remoteProtocol \u53EA\u80FD\u4E3A http \u6216 https"
|
|
3610
|
-
);
|
|
3611
|
-
process.exit(1);
|
|
3612
|
-
}
|
|
3613
|
-
const remoteProtocol = protoRaw;
|
|
3614
|
-
let mappings = [];
|
|
3615
|
-
const rawPorts = b.containerPortsMappings;
|
|
3616
|
-
if (rawPorts !== void 0 && rawPorts !== null) {
|
|
3617
|
-
if (!Array.isArray(rawPorts)) {
|
|
3618
|
-
console.error(
|
|
3619
|
-
"apm.config.json \u4E2D backendDeploy.containerPortsMappings \u987B\u4E3A\u5B57\u7B26\u4E32\u6570\u7EC4\uFF08\u53EF\u4E3A\u7A7A\uFF0C\u7701\u7565\u5219\u4E0D\u52A0\u7AEF\u53E3\u6620\u5C04\uFF09"
|
|
3620
|
-
);
|
|
3621
|
-
process.exit(1);
|
|
3622
|
-
}
|
|
3623
|
-
mappings = rawPorts.map((x) => String(x).trim()).filter(Boolean);
|
|
3624
|
-
}
|
|
3625
|
-
return {
|
|
3626
|
-
name: reqTopLevelName(cfg),
|
|
3627
|
-
registryHost: req(b.registryHost, "registryHost").trim(),
|
|
3628
|
-
registryNamespace: req(b.registryNamespace, "registryNamespace").trim(),
|
|
3629
|
-
registryUser: req(b.registryUser, "registryUser").trim(),
|
|
3630
|
-
registryPassword: req(b.registryPassword, "registryPassword").trim(),
|
|
3631
|
-
remoteHost: req(b.remoteHost, "remoteHost").trim(),
|
|
3632
|
-
remotePort: reqBackendPositiveInt(b.remotePort, "remotePort"),
|
|
3633
|
-
remoteProtocol,
|
|
3634
|
-
caPath: b.caPath?.trim(),
|
|
3635
|
-
certPath: b.certPath?.trim(),
|
|
3636
|
-
keyPath: b.keyPath?.trim(),
|
|
3637
|
-
envFilePath: typeof b.envFilePath === "string" ? b.envFilePath.trim() : "",
|
|
3638
|
-
containerPortsMappings: mappings,
|
|
3639
|
-
dockerNetwork: b.dockerNetwork?.trim() || void 0
|
|
3640
|
-
};
|
|
4441
|
+
ws.on("close", (code, reason) => {
|
|
4442
|
+
console.log(
|
|
4443
|
+
`[apm] \u8FDE\u63A5\u5DF2\u65AD\u5F00 code=${code}${reason ? ` reason=${reason.toString()}` : ""}`
|
|
4444
|
+
);
|
|
4445
|
+
void shutdown();
|
|
4446
|
+
});
|
|
4447
|
+
ws.on("error", (err) => {
|
|
4448
|
+
console.error("[apm] WebSocket \u9519\u8BEF:", err.message);
|
|
4449
|
+
reject(err);
|
|
4450
|
+
});
|
|
4451
|
+
process.on("SIGINT", () => {
|
|
4452
|
+
console.log("[apm] \u6B63\u5728\u5173\u95ED\u2026");
|
|
4453
|
+
void shutdown();
|
|
4454
|
+
});
|
|
4455
|
+
process.on("SIGTERM", () => {
|
|
4456
|
+
void shutdown();
|
|
4457
|
+
});
|
|
4458
|
+
});
|
|
3641
4459
|
}
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
4460
|
+
|
|
4461
|
+
// src/commands/create-pr.ts
|
|
4462
|
+
async function runCreatePr(options) {
|
|
4463
|
+
const sessionId = options.sessionId.trim();
|
|
4464
|
+
if (!sessionId) {
|
|
4465
|
+
console.error("[apm] sessionId \u4E0D\u80FD\u4E3A\u7A7A");
|
|
3645
4466
|
process.exit(1);
|
|
3646
4467
|
}
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
const f = cfg.frontendDeploy ?? {};
|
|
3651
|
-
const port = Number(f.port);
|
|
3652
|
-
return {
|
|
3653
|
-
endpoint: reqFe(f.endpoint, "endpoint").trim(),
|
|
3654
|
-
port: Number.isFinite(port) && port > 0 ? port : 9e3,
|
|
3655
|
-
useSsl: Boolean(f.useSsl),
|
|
3656
|
-
accessKey: reqFe(f.accessKey, "accessKey").trim(),
|
|
3657
|
-
secretKey: reqFe(f.secretKey, "secretKey").trim(),
|
|
3658
|
-
bucket: reqFe(f.bucket, "bucket").trim()
|
|
3659
|
-
};
|
|
3660
|
-
}
|
|
3661
|
-
function reqWd(v, field) {
|
|
3662
|
-
if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
|
|
3663
|
-
console.error(`apm.config.json \u4E2D wisdomDeploy.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
|
|
4468
|
+
const title = options.title.trim();
|
|
4469
|
+
if (!title) {
|
|
4470
|
+
console.error("[apm] \u8BF7\u901A\u8FC7 --title \u6307\u5B9A PR \u6807\u9898");
|
|
3664
4471
|
process.exit(1);
|
|
3665
4472
|
}
|
|
3666
|
-
|
|
4473
|
+
const cfg = await ensureLoggedConfig();
|
|
4474
|
+
const api = createApmApiClient(cfg);
|
|
4475
|
+
const workdir = resolveWorkdirPath(options.cwd ?? process.cwd());
|
|
4476
|
+
const pr = await api.cli.createPullRequest({
|
|
4477
|
+
sessionId,
|
|
4478
|
+
workdir,
|
|
4479
|
+
title,
|
|
4480
|
+
content: options.content ?? ""
|
|
4481
|
+
});
|
|
4482
|
+
console.log(`[apm] PR \u5DF2\u5C31\u7EEA #${pr.number} (${pr.state}): ${pr.url}`);
|
|
3667
4483
|
}
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
4484
|
+
|
|
4485
|
+
// src/commands/deploy/deploy.ts
|
|
4486
|
+
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
4487
|
+
function runShellCommand3(command, cwd) {
|
|
4488
|
+
console.error(`==> ${command}`);
|
|
4489
|
+
const result = spawnSync5(command, {
|
|
4490
|
+
cwd,
|
|
4491
|
+
stdio: "inherit",
|
|
4492
|
+
shell: true,
|
|
4493
|
+
env: process.env
|
|
4494
|
+
});
|
|
4495
|
+
if (result.status !== 0) {
|
|
4496
|
+
process.exit(result.status ?? 1);
|
|
3673
4497
|
}
|
|
3674
|
-
return n;
|
|
3675
4498
|
}
|
|
3676
|
-
function
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
4499
|
+
function registerDeployMainCommand(program) {
|
|
4500
|
+
program.command("deploy").description(
|
|
4501
|
+
"\u7EDF\u4E00\u90E8\u7F72\uFF1A\u533B\u52A1\u5B58\u91CF\u9879\u76EE\u81EA\u52A8\u8BC6\u522B\u524D\u540E\u7AEF\uFF1B\u5176\u4ED6\u9879\u76EE\u6309 deploy.<\u73AF\u5883> \u6267\u884C shell \u547D\u4EE4"
|
|
4502
|
+
).argument("<env>", "\u90E8\u7F72\u73AF\u5883\u540D\uFF08\u5982 test\u3001online\uFF09").option(
|
|
4503
|
+
"--config <path>",
|
|
4504
|
+
"apm.config.json \u8DEF\u5F84\uFF08\u9ED8\u8BA4 .apm/apm.config.json\uFF09"
|
|
4505
|
+
).option("--skip-maven", "\u8DF3\u8FC7 Maven \u6784\u5EFA\uFF08\u4EC5\u533B\u52A1\u540E\u7AEF\uFF09").action(
|
|
4506
|
+
async (env, opts) => {
|
|
4507
|
+
const cwd = process.cwd();
|
|
4508
|
+
const cfg = loadApmConfig({ configPath: opts.config });
|
|
4509
|
+
if (isWisdomLegacyDeploy(cfg)) {
|
|
4510
|
+
await runWisdomAutoDeploy({
|
|
4511
|
+
env,
|
|
4512
|
+
cwd,
|
|
4513
|
+
configPath: opts.config,
|
|
4514
|
+
skipMaven: opts.skipMaven
|
|
4515
|
+
});
|
|
4516
|
+
return;
|
|
4517
|
+
}
|
|
4518
|
+
const deployCommands = cfg.deploy ?? {};
|
|
4519
|
+
const command = deployCommands[env]?.trim();
|
|
4520
|
+
if (!command) {
|
|
4521
|
+
const keys = Object.keys(deployCommands);
|
|
4522
|
+
console.error(
|
|
4523
|
+
keys.length > 0 ? `apm.config.json \u4E2D\u672A\u914D\u7F6E deploy.${env}\uFF0C\u53EF\u7528\u73AF\u5883: ${keys.join(
|
|
4524
|
+
", "
|
|
4525
|
+
)}` : `apm.config.json \u4E2D\u672A\u914D\u7F6E deploy \u6BB5`
|
|
4526
|
+
);
|
|
4527
|
+
process.exit(1);
|
|
4528
|
+
}
|
|
4529
|
+
runShellCommand3(command, cwd);
|
|
4530
|
+
}
|
|
4531
|
+
);
|
|
3685
4532
|
}
|
|
3686
4533
|
|
|
4534
|
+
// src/commands/deploy/backend.ts
|
|
4535
|
+
import path8 from "node:path";
|
|
4536
|
+
|
|
3687
4537
|
// src/commands/deploy/internal/backend-deploy/backend-deploy-workflow.ts
|
|
3688
|
-
import
|
|
4538
|
+
import path7 from "node:path";
|
|
3689
4539
|
|
|
3690
4540
|
// src/commands/deploy/internal/backend-deploy/dockerode-client/client.ts
|
|
3691
4541
|
import Docker from "dockerode";
|
|
3692
4542
|
|
|
3693
4543
|
// src/commands/deploy/internal/backend-deploy/dockerode-client/connection-options.ts
|
|
3694
|
-
import { existsSync as
|
|
3695
|
-
import
|
|
4544
|
+
import { existsSync as existsSync17, readFileSync as readFileSync15 } from "node:fs";
|
|
4545
|
+
import path4 from "node:path";
|
|
3696
4546
|
function asOptionalTlsBuffer(value) {
|
|
3697
4547
|
if (typeof value !== "string") {
|
|
3698
4548
|
console.log("tls filepath not exist");
|
|
3699
4549
|
return void 0;
|
|
3700
4550
|
}
|
|
3701
|
-
console.log("tls filepath",
|
|
4551
|
+
console.log("tls filepath", path4.join(process.cwd(), value));
|
|
3702
4552
|
const normalized = value.trim();
|
|
3703
4553
|
if (normalized === "") {
|
|
3704
4554
|
return void 0;
|
|
3705
4555
|
}
|
|
3706
|
-
if (
|
|
3707
|
-
return
|
|
4556
|
+
if (existsSync17(normalized)) {
|
|
4557
|
+
return readFileSync15(normalized);
|
|
3708
4558
|
}
|
|
3709
4559
|
const looksLikePath = /[\\/]/.test(normalized) || normalized.endsWith(".pem");
|
|
3710
4560
|
if (looksLikePath) {
|
|
@@ -3914,8 +4764,8 @@ var DockerodeClient = class {
|
|
|
3914
4764
|
var createDockerodeClient = (config) => new DockerodeClient(config);
|
|
3915
4765
|
|
|
3916
4766
|
// src/commands/deploy/internal/backend-deploy/dockerode-client/env.ts
|
|
3917
|
-
import { existsSync as
|
|
3918
|
-
import
|
|
4767
|
+
import { existsSync as existsSync18, readFileSync as readFileSync16, statSync as statSync6 } from "node:fs";
|
|
4768
|
+
import path5 from "node:path";
|
|
3919
4769
|
function stripSurroundingQuotes(value) {
|
|
3920
4770
|
const t = value.trim();
|
|
3921
4771
|
if (t.length >= 2) {
|
|
@@ -3930,11 +4780,11 @@ function loadEnvFromFile(envFilePath) {
|
|
|
3930
4780
|
if (!envFilePath) {
|
|
3931
4781
|
return {};
|
|
3932
4782
|
}
|
|
3933
|
-
const targetPath =
|
|
3934
|
-
if (!
|
|
4783
|
+
const targetPath = path5.resolve(envFilePath);
|
|
4784
|
+
if (!existsSync18(targetPath) || !statSync6(targetPath).isFile()) {
|
|
3935
4785
|
return {};
|
|
3936
4786
|
}
|
|
3937
|
-
const raw =
|
|
4787
|
+
const raw = readFileSync16(targetPath, "utf-8");
|
|
3938
4788
|
const result = {};
|
|
3939
4789
|
for (const line of raw.split(/\r?\n/)) {
|
|
3940
4790
|
const normalized = line.trim();
|
|
@@ -4105,12 +4955,12 @@ function dockerPushImage(params, cwd) {
|
|
|
4105
4955
|
}
|
|
4106
4956
|
|
|
4107
4957
|
// src/commands/deploy/internal/backend-deploy/resolve-dockerfile.ts
|
|
4108
|
-
import { existsSync as
|
|
4109
|
-
import
|
|
4958
|
+
import { existsSync as existsSync19 } from "node:fs";
|
|
4959
|
+
import path6 from "node:path";
|
|
4110
4960
|
function resolveDockerBuildPaths(cwd) {
|
|
4111
|
-
const dockerfilePath =
|
|
4961
|
+
const dockerfilePath = path6.join(cwd, "Dockerfile");
|
|
4112
4962
|
Logger.info(`\u67E5\u627EDockerfile\u6587\u4EF6\uFF0C\u8DEF\u5F84: ${dockerfilePath}`);
|
|
4113
|
-
if (!
|
|
4963
|
+
if (!existsSync19(dockerfilePath)) {
|
|
4114
4964
|
throw new Error(`Dockerfile \u4E0D\u5B58\u5728\uFF1A${dockerfilePath}`);
|
|
4115
4965
|
}
|
|
4116
4966
|
Logger.info("\u2713 Dockerfile \u5B58\u5728");
|
|
@@ -4165,7 +5015,7 @@ var BackendDeployWorkflow = class {
|
|
|
4165
5015
|
serveraddress
|
|
4166
5016
|
});
|
|
4167
5017
|
Logger.success("\u8FDC\u7A0B\u62C9\u53D6\u955C\u50CF\u5B8C\u6210");
|
|
4168
|
-
const envFilePath =
|
|
5018
|
+
const envFilePath = path7.resolve(cwd, this.params.envFilePath || ".env");
|
|
4169
5019
|
const envObj = loadEnvFromFile(envFilePath);
|
|
4170
5020
|
if (this.params.dockerNetwork?.trim()) {
|
|
4171
5021
|
Logger.info(`\u8FDC\u7A0B\u5BB9\u5668\u5C06\u52A0\u5165 Docker \u7F51\u7EDC\uFF1A${this.params.dockerNetwork.trim()}`);
|
|
@@ -4205,7 +5055,7 @@ function registerDeployBackendCommands(program) {
|
|
|
4205
5055
|
assertDeployImageTag(tag);
|
|
4206
5056
|
const cfg = loadApmConfig({ configPath: opts.config });
|
|
4207
5057
|
const fromApm = resolveBackendDeployFromApmConfig(cfg);
|
|
4208
|
-
const dirAbs =
|
|
5058
|
+
const dirAbs = path8.resolve(process.cwd(), opts.dir || "servers/api");
|
|
4209
5059
|
const params = {
|
|
4210
5060
|
image: fromApm.name,
|
|
4211
5061
|
tag,
|
|
@@ -4235,18 +5085,18 @@ function registerDeployBackendCommands(program) {
|
|
|
4235
5085
|
}
|
|
4236
5086
|
|
|
4237
5087
|
// src/commands/deploy/frontend.ts
|
|
4238
|
-
import { copyFile, readdir as
|
|
4239
|
-
import
|
|
5088
|
+
import { copyFile, readdir as readdir3, stat } from "node:fs/promises";
|
|
5089
|
+
import path10 from "node:path";
|
|
4240
5090
|
|
|
4241
5091
|
// src/commands/deploy/internal/minio.ts
|
|
4242
|
-
import { statSync as
|
|
4243
|
-
import { readdir, readFile } from "node:fs/promises";
|
|
4244
|
-
import
|
|
5092
|
+
import { statSync as statSync7 } from "node:fs";
|
|
5093
|
+
import { readdir as readdir2, readFile as readFile2 } from "node:fs/promises";
|
|
5094
|
+
import path9 from "node:path";
|
|
4245
5095
|
import * as Minio from "minio";
|
|
4246
5096
|
var DEFAULT_MAX_FILE_SIZE_MB = 50;
|
|
4247
5097
|
async function isDirectoryPath(dir) {
|
|
4248
5098
|
try {
|
|
4249
|
-
const st =
|
|
5099
|
+
const st = statSync7(dir);
|
|
4250
5100
|
return st.isDirectory();
|
|
4251
5101
|
} catch {
|
|
4252
5102
|
return false;
|
|
@@ -4265,18 +5115,18 @@ function sanitizeRelativePath(rel) {
|
|
|
4265
5115
|
async function collectFiles(root) {
|
|
4266
5116
|
const out = [];
|
|
4267
5117
|
async function walk(dir, prefix) {
|
|
4268
|
-
const entries = await
|
|
5118
|
+
const entries = await readdir2(dir, { withFileTypes: true });
|
|
4269
5119
|
for (const e of entries) {
|
|
4270
5120
|
const name = e.name;
|
|
4271
5121
|
if (name === "." || name === "..") {
|
|
4272
5122
|
continue;
|
|
4273
5123
|
}
|
|
4274
|
-
const abs =
|
|
5124
|
+
const abs = path9.join(dir, name);
|
|
4275
5125
|
const rel = prefix ? `${prefix}/${name}` : name;
|
|
4276
5126
|
if (e.isDirectory()) {
|
|
4277
5127
|
await walk(abs, rel);
|
|
4278
5128
|
} else if (e.isFile()) {
|
|
4279
|
-
const st =
|
|
5129
|
+
const st = statSync7(abs);
|
|
4280
5130
|
out.push({
|
|
4281
5131
|
absPath: abs,
|
|
4282
5132
|
relativePath: rel.replace(/\\/g, "/"),
|
|
@@ -4290,7 +5140,7 @@ async function collectFiles(root) {
|
|
|
4290
5140
|
return out;
|
|
4291
5141
|
}
|
|
4292
5142
|
async function readArtifactFile(absPath) {
|
|
4293
|
-
return
|
|
5143
|
+
return readFile2(absPath);
|
|
4294
5144
|
}
|
|
4295
5145
|
function toMB(bytes) {
|
|
4296
5146
|
return Math.round(bytes / (1024 * 1024) * 1e3) / 1e3;
|
|
@@ -4314,7 +5164,7 @@ var MIME = {
|
|
|
4314
5164
|
".map": "application/json"
|
|
4315
5165
|
};
|
|
4316
5166
|
function detectMimeType(filePath) {
|
|
4317
|
-
const ext =
|
|
5167
|
+
const ext = path9.extname(filePath).toLowerCase();
|
|
4318
5168
|
return MIME[ext] ?? "";
|
|
4319
5169
|
}
|
|
4320
5170
|
var MinioClient = class {
|
|
@@ -4402,7 +5252,7 @@ function artifactObjectKey(namePrefix, branchSegment, relativePath) {
|
|
|
4402
5252
|
return `${base}/${branchSegment}/dist/${rel}`;
|
|
4403
5253
|
}
|
|
4404
5254
|
async function ensureArtifactRootIndexHtml(root) {
|
|
4405
|
-
const indexHtmlPath =
|
|
5255
|
+
const indexHtmlPath = path10.join(root, "index.html");
|
|
4406
5256
|
try {
|
|
4407
5257
|
const st = await stat(indexHtmlPath);
|
|
4408
5258
|
if (st.isFile()) {
|
|
@@ -4412,14 +5262,14 @@ async function ensureArtifactRootIndexHtml(root) {
|
|
|
4412
5262
|
}
|
|
4413
5263
|
let entries;
|
|
4414
5264
|
try {
|
|
4415
|
-
entries = await
|
|
5265
|
+
entries = await readdir3(root, { withFileTypes: true });
|
|
4416
5266
|
} catch (e) {
|
|
4417
5267
|
console.error(`\u65E0\u6CD5\u8BFB\u53D6\u4EA7\u7269\u76EE\u5F55\uFF1A${root}`, e);
|
|
4418
5268
|
process.exit(1);
|
|
4419
5269
|
}
|
|
4420
5270
|
const dirNames = entries.filter((e) => e.isDirectory()).map((e) => String(e.name)).sort();
|
|
4421
5271
|
for (const name of dirNames) {
|
|
4422
|
-
const candidate =
|
|
5272
|
+
const candidate = path10.join(root, name, "index.html");
|
|
4423
5273
|
try {
|
|
4424
5274
|
const st = await stat(candidate);
|
|
4425
5275
|
if (!st.isFile()) {
|
|
@@ -4430,7 +5280,7 @@ async function ensureArtifactRootIndexHtml(root) {
|
|
|
4430
5280
|
}
|
|
4431
5281
|
await copyFile(candidate, indexHtmlPath);
|
|
4432
5282
|
console.error(
|
|
4433
|
-
`\u4EA7\u7269\u534F\u8BAE\uFF1A\u5DF2\u5C06 ${
|
|
5283
|
+
`\u4EA7\u7269\u534F\u8BAE\uFF1A\u5DF2\u5C06 ${path10.join(name, "index.html")} \u590D\u5236\u4E3A\u6839\u76EE\u5F55 index.html`
|
|
4434
5284
|
);
|
|
4435
5285
|
return;
|
|
4436
5286
|
}
|
|
@@ -4466,7 +5316,7 @@ function registerDeployFrontendCommands(program) {
|
|
|
4466
5316
|
secretKey: settings.secretKey
|
|
4467
5317
|
});
|
|
4468
5318
|
const bucket = settings.bucket;
|
|
4469
|
-
const root =
|
|
5319
|
+
const root = path10.resolve(process.cwd(), opts.dir || "apps/web/dist");
|
|
4470
5320
|
if (!await isDirectoryPath(root)) {
|
|
4471
5321
|
console.error(`\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${root}`);
|
|
4472
5322
|
process.exit(1);
|
|
@@ -4535,159 +5385,7 @@ function registerDeployFrontendCommands(program) {
|
|
|
4535
5385
|
}
|
|
4536
5386
|
|
|
4537
5387
|
// src/commands/deploy/sftp.ts
|
|
4538
|
-
import
|
|
4539
|
-
|
|
4540
|
-
// src/commands/deploy/internal/wisdom-sftp.ts
|
|
4541
|
-
import { readdir as readdir3, readFile as readFile2, unlink, writeFile } from "node:fs/promises";
|
|
4542
|
-
import path8 from "node:path";
|
|
4543
|
-
import JSZip from "jszip";
|
|
4544
|
-
import SftpClient from "ssh2-sftp-client";
|
|
4545
|
-
async function addDirToZip(dir, zipFolder) {
|
|
4546
|
-
const entries = await readdir3(dir, { withFileTypes: true });
|
|
4547
|
-
for (const entry of entries) {
|
|
4548
|
-
const fullPath = path8.join(dir, entry.name);
|
|
4549
|
-
if (entry.isDirectory()) {
|
|
4550
|
-
const folder = zipFolder.folder(entry.name);
|
|
4551
|
-
if (folder) {
|
|
4552
|
-
await addDirToZip(fullPath, folder);
|
|
4553
|
-
}
|
|
4554
|
-
} else {
|
|
4555
|
-
const content = await readFile2(fullPath);
|
|
4556
|
-
zipFolder.file(entry.name, content);
|
|
4557
|
-
}
|
|
4558
|
-
}
|
|
4559
|
-
}
|
|
4560
|
-
async function zipDirectory(distDir, zipPath) {
|
|
4561
|
-
console.error(`\u538B\u7F29\u76EE\u5F55: ${distDir}`);
|
|
4562
|
-
const zip = new JSZip();
|
|
4563
|
-
await addDirToZip(distDir, zip);
|
|
4564
|
-
const content = await zip.generateAsync({
|
|
4565
|
-
type: "nodebuffer",
|
|
4566
|
-
compression: "DEFLATE",
|
|
4567
|
-
compressionOptions: { level: 6 }
|
|
4568
|
-
});
|
|
4569
|
-
await writeFile(zipPath, content);
|
|
4570
|
-
const sizeMb = (content.length / 1024 / 1024).toFixed(2);
|
|
4571
|
-
console.error(`\u5DF2\u751F\u6210: ${zipPath} (${sizeMb} MB)`);
|
|
4572
|
-
return content.length;
|
|
4573
|
-
}
|
|
4574
|
-
async function ensureRemoteDir(sftp, dir) {
|
|
4575
|
-
const parts = dir.replace(/\\/g, "/").split("/").filter(Boolean);
|
|
4576
|
-
let current = dir.startsWith("/") ? "" : ".";
|
|
4577
|
-
for (const part of parts) {
|
|
4578
|
-
current = current ? `${current}/${part}` : `/${part}`;
|
|
4579
|
-
try {
|
|
4580
|
-
await sftp.mkdir(current, true);
|
|
4581
|
-
} catch {
|
|
4582
|
-
}
|
|
4583
|
-
}
|
|
4584
|
-
}
|
|
4585
|
-
function execCommand(client, command) {
|
|
4586
|
-
return new Promise((resolve5, reject) => {
|
|
4587
|
-
client.exec(command, (err, stream) => {
|
|
4588
|
-
if (err) return reject(err);
|
|
4589
|
-
let stdout = "";
|
|
4590
|
-
let stderr = "";
|
|
4591
|
-
stream.on("close", (code) => {
|
|
4592
|
-
if (code !== 0) {
|
|
4593
|
-
reject(new Error(`\u8FDC\u7A0B\u547D\u4EE4\u5931\u8D25 (${code}): ${stderr || stdout}`));
|
|
4594
|
-
return;
|
|
4595
|
-
}
|
|
4596
|
-
resolve5(stdout);
|
|
4597
|
-
}).on("data", (data) => {
|
|
4598
|
-
stdout += data.toString();
|
|
4599
|
-
});
|
|
4600
|
-
stream.stderr.on("data", (data) => {
|
|
4601
|
-
stderr += data.toString();
|
|
4602
|
-
});
|
|
4603
|
-
});
|
|
4604
|
-
});
|
|
4605
|
-
}
|
|
4606
|
-
function shellSingleQuote(value) {
|
|
4607
|
-
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
4608
|
-
}
|
|
4609
|
-
function buildClearRemoteDirExceptZipCommand(target) {
|
|
4610
|
-
const normalized = target.replace(/\\/g, "/").replace(/\/$/, "");
|
|
4611
|
-
const quotedTarget = shellSingleQuote(normalized);
|
|
4612
|
-
const script = [
|
|
4613
|
-
`T=${quotedTarget}`,
|
|
4614
|
-
"S=$(mktemp -d)",
|
|
4615
|
-
'while IFS= read -r -d "" z; do r="${z#${T}/}"',
|
|
4616
|
-
'mkdir -p "${S}/$(dirname "$r")"',
|
|
4617
|
-
'mv "$z" "${S}/${r}"',
|
|
4618
|
-
'done < <(find "$T" -mindepth 1 -type f -iname "*.zip" -print0)',
|
|
4619
|
-
'rm -rf "${T}"/*',
|
|
4620
|
-
'while IFS= read -r -d "" r; do r="${r#./}"',
|
|
4621
|
-
'mkdir -p "${T}/$(dirname "$r")"',
|
|
4622
|
-
'mv "${S}/${r}" "${T}/${r}"',
|
|
4623
|
-
'done < <(cd "$S" 2>/dev/null && find . -type f -print0)',
|
|
4624
|
-
'rm -rf "$S"'
|
|
4625
|
-
].join("; ");
|
|
4626
|
-
return `bash -c ${shellSingleQuote(script)}`;
|
|
4627
|
-
}
|
|
4628
|
-
async function uploadAndMaybeExtract(settings, localZip, extract) {
|
|
4629
|
-
const remoteZipPath = `${settings.remotePath.replace(/\/$/, "")}/dist.zip`;
|
|
4630
|
-
console.error(
|
|
4631
|
-
`\u8FDE\u63A5 ${settings.username}@${settings.host}:${settings.port} ...`
|
|
4632
|
-
);
|
|
4633
|
-
const sftp = new SftpClient();
|
|
4634
|
-
try {
|
|
4635
|
-
await sftp.connect({
|
|
4636
|
-
host: settings.host,
|
|
4637
|
-
port: settings.port,
|
|
4638
|
-
username: settings.username,
|
|
4639
|
-
password: settings.password,
|
|
4640
|
-
readyTimeout: 2e4,
|
|
4641
|
-
tryKeyboard: true
|
|
4642
|
-
});
|
|
4643
|
-
await ensureRemoteDir(sftp, settings.remotePath);
|
|
4644
|
-
await sftp.put(localZip, remoteZipPath);
|
|
4645
|
-
console.error(` \u2713 ${localZip} -> ${remoteZipPath}`);
|
|
4646
|
-
if (extract) {
|
|
4647
|
-
const target = settings.remotePath.replace(/\/$/, "");
|
|
4648
|
-
const client = sftp.client;
|
|
4649
|
-
const clearCmd = buildClearRemoteDirExceptZipCommand(target);
|
|
4650
|
-
console.error(`\u8FDC\u7A0B\u6E05\u7406\u89E3\u538B\u76EE\u5F55: ${clearCmd}`);
|
|
4651
|
-
await execCommand(client, clearCmd);
|
|
4652
|
-
const unzipCmd = `unzip -o "${remoteZipPath}" -d "${target}"`;
|
|
4653
|
-
console.error(`\u8FDC\u7A0B\u89E3\u538B: ${unzipCmd}`);
|
|
4654
|
-
await execCommand(client, unzipCmd);
|
|
4655
|
-
console.error("\u8FDC\u7A0B\u89E3\u538B\u5B8C\u6210!");
|
|
4656
|
-
}
|
|
4657
|
-
console.error(extract ? "\u90E8\u7F72\u5B8C\u6210!" : "\u4E0A\u4F20\u5B8C\u6210!");
|
|
4658
|
-
} finally {
|
|
4659
|
-
await sftp.end();
|
|
4660
|
-
}
|
|
4661
|
-
}
|
|
4662
|
-
async function runWisdomSftpDeploy(params) {
|
|
4663
|
-
const zipPath = path8.join(params.localDir, "..", ".deploy-sftp-dist.zip");
|
|
4664
|
-
const resolvedZipPath = path8.resolve(zipPath);
|
|
4665
|
-
let zipSizeBytes = 0;
|
|
4666
|
-
try {
|
|
4667
|
-
zipSizeBytes = await zipDirectory(params.localDir, resolvedZipPath);
|
|
4668
|
-
await uploadAndMaybeExtract(
|
|
4669
|
-
params.settings,
|
|
4670
|
-
resolvedZipPath,
|
|
4671
|
-
params.extract
|
|
4672
|
-
);
|
|
4673
|
-
} finally {
|
|
4674
|
-
try {
|
|
4675
|
-
await unlink(resolvedZipPath);
|
|
4676
|
-
console.error(`\u5DF2\u6E05\u7406\u672C\u5730\u4E34\u65F6\u6587\u4EF6: ${resolvedZipPath}`);
|
|
4677
|
-
} catch {
|
|
4678
|
-
}
|
|
4679
|
-
}
|
|
4680
|
-
return {
|
|
4681
|
-
ok: true,
|
|
4682
|
-
localDir: params.localDir,
|
|
4683
|
-
host: params.settings.host,
|
|
4684
|
-
remotePath: params.settings.remotePath,
|
|
4685
|
-
zipSizeBytes,
|
|
4686
|
-
extracted: params.extract
|
|
4687
|
-
};
|
|
4688
|
-
}
|
|
4689
|
-
|
|
4690
|
-
// src/commands/deploy/sftp.ts
|
|
5388
|
+
import path11 from "node:path";
|
|
4691
5389
|
function registerDeploySftpCommands(program) {
|
|
4692
5390
|
program.command("deploy-sftp").description(
|
|
4693
5391
|
"\u5C06\u6307\u5B9A\u76EE\u5F55\u538B\u7F29\u4E3A zip \u540E\u901A\u8FC7 SFTP \u4E0A\u4F20\u5230\u8FDC\u7A0B\u670D\u52A1\u5668\uFF08\u8FDE\u63A5\u4FE1\u606F\u89C1 apm.config.json wisdomDeploy\uFF09"
|
|
@@ -4702,7 +5400,7 @@ function registerDeploySftpCommands(program) {
|
|
|
4702
5400
|
async (opts) => {
|
|
4703
5401
|
const cfg = loadApmConfig({ configPath: opts.config });
|
|
4704
5402
|
const settings = resolveWisdomDeployFromApmConfig(cfg);
|
|
4705
|
-
const root =
|
|
5403
|
+
const root = path11.resolve(process.cwd(), opts.dir || "apps/web/dist");
|
|
4706
5404
|
if (!await isDirectoryPath(root)) {
|
|
4707
5405
|
console.error(`\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${root}`);
|
|
4708
5406
|
process.exit(1);
|
|
@@ -4723,11 +5421,30 @@ function registerDeploySftpCommands(program) {
|
|
|
4723
5421
|
);
|
|
4724
5422
|
}
|
|
4725
5423
|
|
|
5424
|
+
// src/commands/deploy/wisdom-backend.ts
|
|
5425
|
+
function registerDeployWisdomBackendCommands(program) {
|
|
5426
|
+
program.command("deploy-wisdom-backend").description(
|
|
5427
|
+
"Maven \u6784\u5EFA\u540E\u901A\u8FC7 SFTP \u589E\u91CF\u66F4\u65B0\u8FDC\u7A0B lib \u76EE\u5F55\u5E76\u91CD\u542F Spring Boot \u670D\u52A1\uFF08\u914D\u7F6E\u89C1 apm.config.json \u7684 wisdomDeploy \u4E0E healthCheck\uFF09"
|
|
5428
|
+
).option(
|
|
5429
|
+
"--config <path>",
|
|
5430
|
+
"apm.config.json \u8DEF\u5F84\uFF08\u9ED8\u8BA4 .apm/apm.config.json\uFF09"
|
|
5431
|
+
).option("--skip-maven", "\u8DF3\u8FC7 Maven \u6784\u5EFA\uFF0C\u4EC5\u4E0A\u4F20\u5E76\u91CD\u542F").action(async (opts) => {
|
|
5432
|
+
const cfg = loadApmConfig({ configPath: opts.config });
|
|
5433
|
+
const settings = resolveWisdomBackendDeployFromApmConfig(cfg);
|
|
5434
|
+
await runWisdomBackendDeploy({
|
|
5435
|
+
config: settings,
|
|
5436
|
+
skipMaven: Boolean(opts.skipMaven)
|
|
5437
|
+
});
|
|
5438
|
+
});
|
|
5439
|
+
}
|
|
5440
|
+
|
|
4726
5441
|
// src/commands/deploy/index.ts
|
|
4727
5442
|
function registerDeployCommands(program) {
|
|
5443
|
+
registerDeployMainCommand(program);
|
|
4728
5444
|
registerDeployBackendCommands(program);
|
|
4729
5445
|
registerDeployFrontendCommands(program);
|
|
4730
5446
|
registerDeploySftpCommands(program);
|
|
5447
|
+
registerDeployWisdomBackendCommands(program);
|
|
4731
5448
|
}
|
|
4732
5449
|
|
|
4733
5450
|
// src/index.ts
|