ai-project-manage-cli 6.0.84 → 6.0.85
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 +557 -212
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -490,6 +490,16 @@ var requestConfig = {
|
|
|
490
490
|
completeTaskDeployment: defineEndpoint({
|
|
491
491
|
method: "PUT",
|
|
492
492
|
path: "/cli/task-deployments/complete"
|
|
493
|
+
}),
|
|
494
|
+
getDeployArtifactStorage: defineEndpoint(
|
|
495
|
+
{
|
|
496
|
+
method: "GET",
|
|
497
|
+
path: "/cli/deploy-artifact-storage"
|
|
498
|
+
}
|
|
499
|
+
),
|
|
500
|
+
attachTaskDeploymentArtifact: defineEndpoint({
|
|
501
|
+
method: "PUT",
|
|
502
|
+
path: "/cli/task-deployments/artifact"
|
|
493
503
|
})
|
|
494
504
|
}
|
|
495
505
|
};
|
|
@@ -835,6 +845,24 @@ async function isGitRepo(cwd) {
|
|
|
835
845
|
return false;
|
|
836
846
|
}
|
|
837
847
|
}
|
|
848
|
+
async function ensureGitRepo(cwd) {
|
|
849
|
+
await execGit(cwd, ["rev-parse", "--git-dir"], true);
|
|
850
|
+
}
|
|
851
|
+
async function getCurrentBranch(cwd) {
|
|
852
|
+
return (await execGit(cwd, ["rev-parse", "--abbrev-ref", "HEAD"], true)).trim();
|
|
853
|
+
}
|
|
854
|
+
async function isWorkingTreeDirty(cwd) {
|
|
855
|
+
const out = await execGit(cwd, ["status", "--porcelain"], true);
|
|
856
|
+
return out.trim().length > 0;
|
|
857
|
+
}
|
|
858
|
+
async function remoteBranchExists(cwd, branch) {
|
|
859
|
+
const out = await execGit(
|
|
860
|
+
cwd,
|
|
861
|
+
["ls-remote", "--heads", "origin", branch],
|
|
862
|
+
true
|
|
863
|
+
);
|
|
864
|
+
return out.trim().length > 0;
|
|
865
|
+
}
|
|
838
866
|
async function hasUpstream(cwd) {
|
|
839
867
|
try {
|
|
840
868
|
await execGit(cwd, ["rev-parse", "--abbrev-ref", "@{upstream}"], true);
|
|
@@ -1023,14 +1051,14 @@ async function execGit2(cwd, args, quiet) {
|
|
|
1023
1051
|
);
|
|
1024
1052
|
}
|
|
1025
1053
|
}
|
|
1026
|
-
async function
|
|
1054
|
+
async function ensureGitRepo2(cwd) {
|
|
1027
1055
|
await execGit2(cwd, ["rev-parse", "--git-dir"], true);
|
|
1028
1056
|
}
|
|
1029
|
-
async function
|
|
1057
|
+
async function getCurrentBranch2(cwd) {
|
|
1030
1058
|
const name = (await execGit2(cwd, ["rev-parse", "--abbrev-ref", "HEAD"], true)).trim();
|
|
1031
1059
|
return name;
|
|
1032
1060
|
}
|
|
1033
|
-
async function
|
|
1061
|
+
async function isWorkingTreeDirty2(cwd) {
|
|
1034
1062
|
const out = await execGit2(cwd, ["status", "--porcelain"], true);
|
|
1035
1063
|
return out.trim().length > 0;
|
|
1036
1064
|
}
|
|
@@ -1055,11 +1083,11 @@ async function localBranchExists(cwd, branch) {
|
|
|
1055
1083
|
}
|
|
1056
1084
|
}
|
|
1057
1085
|
async function commitWorkingTreeIfDirty(cwd, message) {
|
|
1058
|
-
await
|
|
1059
|
-
if (!await
|
|
1086
|
+
await ensureGitRepo2(cwd);
|
|
1087
|
+
if (!await isWorkingTreeDirty2(cwd)) {
|
|
1060
1088
|
return false;
|
|
1061
1089
|
}
|
|
1062
|
-
const commitMessage = message?.trim() || `chore(apm): \u540C\u6B65\u5DE5\u4F5C\u533A (${await
|
|
1090
|
+
const commitMessage = message?.trim() || `chore(apm): \u540C\u6B65\u5DE5\u4F5C\u533A (${await getCurrentBranch2(cwd)})`;
|
|
1063
1091
|
await execGit2(cwd, ["add", "-A"]);
|
|
1064
1092
|
await execGit2(cwd, ["commit", "-m", commitMessage]);
|
|
1065
1093
|
console.log(`[apm] \u5DF2\u63D0\u4EA4\u5DE5\u4F5C\u533A\u53D8\u66F4: ${commitMessage}`);
|
|
@@ -1068,14 +1096,14 @@ async function commitWorkingTreeIfDirty(cwd, message) {
|
|
|
1068
1096
|
async function ensureFeatureBranch(branch, baselineBranch, options) {
|
|
1069
1097
|
const cwd = options.cwd ?? process.cwd();
|
|
1070
1098
|
const commitMessage = options.message?.trim() || `chore(apm): \u540C\u6B65\u5DE5\u4F5C\u533A (${branch})`;
|
|
1071
|
-
await
|
|
1099
|
+
await ensureGitRepo2(cwd);
|
|
1072
1100
|
if (!await remoteHeadBranchExists(cwd, baselineBranch)) {
|
|
1073
1101
|
throw new Error(
|
|
1074
1102
|
`[apm] \u8FDC\u7A0B\u4E0D\u5B58\u5728\u57FA\u7EBF\u5206\u652F ${baselineBranch}\uFF0C\u8BF7\u786E\u8BA4\u4ED3\u5E93\u9ED8\u8BA4\u5206\u652F\u5DF2\u63A8\u9001\u5230 origin`
|
|
1075
1103
|
);
|
|
1076
1104
|
}
|
|
1077
|
-
const current = await
|
|
1078
|
-
const dirty = await
|
|
1105
|
+
const current = await getCurrentBranch2(cwd);
|
|
1106
|
+
const dirty = await isWorkingTreeDirty2(cwd);
|
|
1079
1107
|
if (dirty) {
|
|
1080
1108
|
if (current === branch) {
|
|
1081
1109
|
await commitWorkingTreeIfDirty(cwd, commitMessage);
|
|
@@ -1089,7 +1117,7 @@ async function ensureFeatureBranch(branch, baselineBranch, options) {
|
|
|
1089
1117
|
]);
|
|
1090
1118
|
}
|
|
1091
1119
|
}
|
|
1092
|
-
const onTargetBranch = await
|
|
1120
|
+
const onTargetBranch = await getCurrentBranch2(cwd) === branch;
|
|
1093
1121
|
if (onTargetBranch) {
|
|
1094
1122
|
await execGit2(cwd, ["fetch", "origin", baselineBranch]);
|
|
1095
1123
|
await execGit2(cwd, ["merge", `origin/${baselineBranch}`, "--no-edit"]);
|
|
@@ -1099,7 +1127,7 @@ async function ensureFeatureBranch(branch, baselineBranch, options) {
|
|
|
1099
1127
|
await execGit2(cwd, ["fetch", "origin", branch]);
|
|
1100
1128
|
await execGit2(cwd, ["checkout", "-B", branch, `origin/${branch}`]);
|
|
1101
1129
|
} else if (await localBranchExists(cwd, branch)) {
|
|
1102
|
-
if (await
|
|
1130
|
+
if (await getCurrentBranch2(cwd) !== branch) {
|
|
1103
1131
|
await execGit2(cwd, ["checkout", branch]);
|
|
1104
1132
|
}
|
|
1105
1133
|
console.log(`[apm] \u5206\u652F ${branch} \u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u521B\u5EFA`);
|
|
@@ -1115,7 +1143,7 @@ async function ensureFeatureBranch(branch, baselineBranch, options) {
|
|
|
1115
1143
|
await execGit2(cwd, ["push", "-u", "origin", branch]);
|
|
1116
1144
|
} catch (err) {
|
|
1117
1145
|
if (await localBranchExists(cwd, branch)) {
|
|
1118
|
-
if (await
|
|
1146
|
+
if (await getCurrentBranch2(cwd) !== branch) {
|
|
1119
1147
|
await execGit2(cwd, ["checkout", branch]);
|
|
1120
1148
|
}
|
|
1121
1149
|
console.log(`[apm] \u5206\u652F ${branch} \u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u521B\u5EFA`);
|
|
@@ -1178,10 +1206,10 @@ async function execGit3(cwd, args, quiet) {
|
|
|
1178
1206
|
);
|
|
1179
1207
|
}
|
|
1180
1208
|
}
|
|
1181
|
-
async function
|
|
1209
|
+
async function ensureGitRepo3(cwd) {
|
|
1182
1210
|
await execGit3(cwd, ["rev-parse", "--git-dir"], true);
|
|
1183
1211
|
}
|
|
1184
|
-
async function
|
|
1212
|
+
async function getCurrentBranch3(cwd) {
|
|
1185
1213
|
return (await execGit3(cwd, ["rev-parse", "--abbrev-ref", "HEAD"], true)).trim();
|
|
1186
1214
|
}
|
|
1187
1215
|
async function resolveBaselineBranch(cwd, api) {
|
|
@@ -1197,7 +1225,7 @@ async function resolveBaselineBranch(cwd, api) {
|
|
|
1197
1225
|
throw new Error("[apm] \u5E73\u53F0\u8FD4\u56DE\u7684\u57FA\u7EBF\u5206\u652F\u540D\u4E3A\u7A7A");
|
|
1198
1226
|
}
|
|
1199
1227
|
await execGit3(cwd, ["fetch", "origin", baselineBranch], true);
|
|
1200
|
-
if (!await
|
|
1228
|
+
if (!await remoteBranchExists2(cwd, baselineBranch)) {
|
|
1201
1229
|
throw new Error(
|
|
1202
1230
|
`[apm] \u8FDC\u7A0B\u4E0D\u5B58\u5728\u57FA\u7EBF\u5206\u652F origin/${baselineBranch}\uFF0C\u8BF7\u786E\u8BA4\u4ED3\u5E93\u9ED8\u8BA4\u5206\u652F\u5DF2\u63A8\u9001\u5230 origin`
|
|
1203
1231
|
);
|
|
@@ -1264,7 +1292,7 @@ async function localBranchExists2(cwd, branch) {
|
|
|
1264
1292
|
return false;
|
|
1265
1293
|
}
|
|
1266
1294
|
}
|
|
1267
|
-
async function
|
|
1295
|
+
async function remoteBranchExists2(cwd, branch) {
|
|
1268
1296
|
const out = await execGit3(
|
|
1269
1297
|
cwd,
|
|
1270
1298
|
["ls-remote", "--heads", "origin", branch],
|
|
@@ -1298,7 +1326,7 @@ async function runCleanBranches(options = {}) {
|
|
|
1298
1326
|
const cwd = options.cwd ?? process.cwd();
|
|
1299
1327
|
const dryRun = options.dryRun ?? false;
|
|
1300
1328
|
const includeRemote = options.includeRemote ?? false;
|
|
1301
|
-
await
|
|
1329
|
+
await ensureGitRepo3(cwd);
|
|
1302
1330
|
await execGit3(cwd, ["fetch", "--prune", "origin"], true);
|
|
1303
1331
|
const cfg = await ensureLoggedConfig();
|
|
1304
1332
|
const api = createApmApiClient(cfg);
|
|
@@ -1335,7 +1363,7 @@ async function runCleanBranches(options = {}) {
|
|
|
1335
1363
|
console.log("[apm] \u6CA1\u6709\u9700\u8981\u6E05\u7406\u7684 feat/session-* \u5206\u652F");
|
|
1336
1364
|
return;
|
|
1337
1365
|
}
|
|
1338
|
-
let currentBranch = await
|
|
1366
|
+
let currentBranch = await getCurrentBranch3(cwd);
|
|
1339
1367
|
for (const item of toDelete) {
|
|
1340
1368
|
const { branch, sessionId, reason } = item;
|
|
1341
1369
|
const label = `${branch} (${sessionId}: ${reason})`;
|
|
@@ -1357,7 +1385,7 @@ async function runCleanBranches(options = {}) {
|
|
|
1357
1385
|
await execGit3(cwd, ["branch", "-D", branch], true);
|
|
1358
1386
|
console.log(`[apm] \u5DF2\u5220\u9664\u672C\u5730\u5206\u652F ${branch}`);
|
|
1359
1387
|
}
|
|
1360
|
-
if (await
|
|
1388
|
+
if (await remoteBranchExists2(cwd, branch)) {
|
|
1361
1389
|
await execGit3(cwd, ["push", "origin", "--delete", branch], true);
|
|
1362
1390
|
console.log(`[apm] \u5DF2\u5220\u9664\u8FDC\u7A0B\u5206\u652F origin/${branch}`);
|
|
1363
1391
|
}
|
|
@@ -2280,6 +2308,254 @@ function validateAgentWsMessage(value, kind) {
|
|
|
2280
2308
|
|
|
2281
2309
|
// src/commands/connect/deploy-run.ts
|
|
2282
2310
|
import { spawn } from "node:child_process";
|
|
2311
|
+
|
|
2312
|
+
// src/commands/deploy/internal/deploy-artifact-minio.ts
|
|
2313
|
+
import { readFile as readFile2 } from "node:fs/promises";
|
|
2314
|
+
|
|
2315
|
+
// src/commands/deploy/internal/minio.ts
|
|
2316
|
+
import { statSync as statSync5 } from "node:fs";
|
|
2317
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
2318
|
+
import path from "node:path";
|
|
2319
|
+
import * as Minio from "minio";
|
|
2320
|
+
var DEFAULT_MAX_FILE_SIZE_MB = 50;
|
|
2321
|
+
async function isDirectoryPath(dir) {
|
|
2322
|
+
try {
|
|
2323
|
+
const st = statSync5(dir);
|
|
2324
|
+
return st.isDirectory();
|
|
2325
|
+
} catch {
|
|
2326
|
+
return false;
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2329
|
+
function sanitizeRelativePath(rel) {
|
|
2330
|
+
const norm = rel.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
2331
|
+
const segments = norm.split("/").filter(Boolean);
|
|
2332
|
+
for (const s of segments) {
|
|
2333
|
+
if (s === "." || s === "..") {
|
|
2334
|
+
throw new Error(`\u975E\u6CD5\u76F8\u5BF9\u8DEF\u5F84\u7247\u6BB5\uFF1A${s}`);
|
|
2335
|
+
}
|
|
2336
|
+
}
|
|
2337
|
+
return segments.join("/");
|
|
2338
|
+
}
|
|
2339
|
+
async function collectFiles(root) {
|
|
2340
|
+
const out = [];
|
|
2341
|
+
async function walk(dir, prefix) {
|
|
2342
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
2343
|
+
for (const e of entries) {
|
|
2344
|
+
const name = e.name;
|
|
2345
|
+
if (name === "." || name === "..") {
|
|
2346
|
+
continue;
|
|
2347
|
+
}
|
|
2348
|
+
const abs = path.join(dir, name);
|
|
2349
|
+
const rel = prefix ? `${prefix}/${name}` : name;
|
|
2350
|
+
if (e.isDirectory()) {
|
|
2351
|
+
await walk(abs, rel);
|
|
2352
|
+
} else if (e.isFile()) {
|
|
2353
|
+
const st = statSync5(abs);
|
|
2354
|
+
out.push({
|
|
2355
|
+
absPath: abs,
|
|
2356
|
+
relativePath: rel.replace(/\\/g, "/"),
|
|
2357
|
+
size: st.size
|
|
2358
|
+
});
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2361
|
+
}
|
|
2362
|
+
await walk(root, "");
|
|
2363
|
+
out.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
|
|
2364
|
+
return out;
|
|
2365
|
+
}
|
|
2366
|
+
async function readArtifactFile(absPath) {
|
|
2367
|
+
return readFile(absPath);
|
|
2368
|
+
}
|
|
2369
|
+
function toMB(bytes) {
|
|
2370
|
+
return Math.round(bytes / (1024 * 1024) * 1e3) / 1e3;
|
|
2371
|
+
}
|
|
2372
|
+
var MIME = {
|
|
2373
|
+
".html": "text/html; charset=utf-8",
|
|
2374
|
+
".css": "text/css; charset=utf-8",
|
|
2375
|
+
".js": "application/javascript; charset=utf-8",
|
|
2376
|
+
".json": "application/json; charset=utf-8",
|
|
2377
|
+
".svg": "image/svg+xml",
|
|
2378
|
+
".png": "image/png",
|
|
2379
|
+
".jpg": "image/jpeg",
|
|
2380
|
+
".jpeg": "image/jpeg",
|
|
2381
|
+
".gif": "image/gif",
|
|
2382
|
+
".webp": "image/webp",
|
|
2383
|
+
".woff": "font/woff",
|
|
2384
|
+
".woff2": "font/woff2",
|
|
2385
|
+
".ttf": "font/ttf",
|
|
2386
|
+
".ico": "image/x-icon",
|
|
2387
|
+
".txt": "text/plain; charset=utf-8",
|
|
2388
|
+
".map": "application/json"
|
|
2389
|
+
};
|
|
2390
|
+
function detectMimeType(filePath) {
|
|
2391
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
2392
|
+
return MIME[ext] ?? "";
|
|
2393
|
+
}
|
|
2394
|
+
var MinioClient = class {
|
|
2395
|
+
inner;
|
|
2396
|
+
constructor(opts) {
|
|
2397
|
+
const endPoint = opts.endPoint.replace(/^https?:\/\//i, "").split("/")[0] ?? opts.endPoint;
|
|
2398
|
+
this.inner = new Minio.Client({
|
|
2399
|
+
endPoint,
|
|
2400
|
+
port: opts.port,
|
|
2401
|
+
useSSL: opts.useSSL,
|
|
2402
|
+
accessKey: opts.accessKey,
|
|
2403
|
+
secretKey: opts.secretKey
|
|
2404
|
+
});
|
|
2405
|
+
}
|
|
2406
|
+
async ensureBucket(bucket) {
|
|
2407
|
+
const exists = await this.inner.bucketExists(bucket);
|
|
2408
|
+
if (!exists) {
|
|
2409
|
+
await this.inner.makeBucket(bucket);
|
|
2410
|
+
}
|
|
2411
|
+
}
|
|
2412
|
+
async deleteObjectsByPrefix(bucket, prefix) {
|
|
2413
|
+
const objectsStream = this.inner.listObjectsV2(bucket, prefix, true);
|
|
2414
|
+
const keys = [];
|
|
2415
|
+
await new Promise((resolve5, reject) => {
|
|
2416
|
+
objectsStream.on("data", (obj) => {
|
|
2417
|
+
if (obj.name) {
|
|
2418
|
+
keys.push(obj.name);
|
|
2419
|
+
}
|
|
2420
|
+
});
|
|
2421
|
+
objectsStream.on("error", reject);
|
|
2422
|
+
objectsStream.on("end", resolve5);
|
|
2423
|
+
});
|
|
2424
|
+
const chunkSize = 500;
|
|
2425
|
+
for (let i = 0; i < keys.length; i += chunkSize) {
|
|
2426
|
+
const chunk = keys.slice(i, i + chunkSize);
|
|
2427
|
+
await this.inner.removeObjects(
|
|
2428
|
+
bucket,
|
|
2429
|
+
chunk.map((name) => name)
|
|
2430
|
+
);
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
async putObject(bucket, objectKey, body, meta) {
|
|
2434
|
+
await this.inner.putObject(bucket, objectKey, body, body.length, meta);
|
|
2435
|
+
}
|
|
2436
|
+
/** 匿名可读当前桶全部对象(便于静态站点直链) */
|
|
2437
|
+
async setBucketPublicRead(bucket) {
|
|
2438
|
+
const policy = {
|
|
2439
|
+
Version: "2012-10-17",
|
|
2440
|
+
Statement: [
|
|
2441
|
+
{
|
|
2442
|
+
Effect: "Allow",
|
|
2443
|
+
Principal: { AWS: ["*"] },
|
|
2444
|
+
Action: ["s3:GetObject"],
|
|
2445
|
+
Resource: [`arn:aws:s3:::${bucket}/*`]
|
|
2446
|
+
}
|
|
2447
|
+
]
|
|
2448
|
+
};
|
|
2449
|
+
await this.inner.setBucketPolicy(bucket, JSON.stringify(policy));
|
|
2450
|
+
}
|
|
2451
|
+
};
|
|
2452
|
+
|
|
2453
|
+
// src/commands/deploy/internal/deploy-artifact-minio.ts
|
|
2454
|
+
var APM_DEPLOYMENT_RUN_ID_ENV = "APM_DEPLOYMENT_RUN_ID";
|
|
2455
|
+
function formatDeployArtifactTimestamp(date = /* @__PURE__ */ new Date()) {
|
|
2456
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
2457
|
+
return `${date.getFullYear()}${pad(date.getMonth() + 1)}${pad(date.getDate())}${pad(date.getHours())}${pad(date.getMinutes())}${pad(date.getSeconds())}`;
|
|
2458
|
+
}
|
|
2459
|
+
function sanitizeDeployProjectName(name) {
|
|
2460
|
+
const trimmed = name.trim().replace(/\\/g, "/");
|
|
2461
|
+
const base = trimmed.split("/").filter(Boolean).pop() ?? trimmed;
|
|
2462
|
+
try {
|
|
2463
|
+
return sanitizeRelativePath(base.replace(/[/\\:*?"<>|]/g, "_"));
|
|
2464
|
+
} catch {
|
|
2465
|
+
return "project";
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2468
|
+
function buildDeployArtifactFileName(kind, projectName, timestamp = formatDeployArtifactTimestamp()) {
|
|
2469
|
+
const safeName = sanitizeDeployProjectName(projectName);
|
|
2470
|
+
const suffix = kind === "frontend" ? "dist.zip" : "jar.zip";
|
|
2471
|
+
return `${timestamp}-${safeName}.${suffix}`;
|
|
2472
|
+
}
|
|
2473
|
+
function buildDeployArtifactObjectKey(projectName, fileName) {
|
|
2474
|
+
const safeProject = sanitizeDeployProjectName(projectName);
|
|
2475
|
+
return `deploy/${safeProject}/${fileName}`;
|
|
2476
|
+
}
|
|
2477
|
+
function resolveDeploymentRunIdFromEnv() {
|
|
2478
|
+
const raw = process.env[APM_DEPLOYMENT_RUN_ID_ENV]?.trim();
|
|
2479
|
+
return raw || null;
|
|
2480
|
+
}
|
|
2481
|
+
async function fetchDeployArtifactStorage(api) {
|
|
2482
|
+
return api.cli.getDeployArtifactStorage(void 0);
|
|
2483
|
+
}
|
|
2484
|
+
async function uploadDeployArtifactZip(options) {
|
|
2485
|
+
const deploymentRunId = options.deploymentRunId ?? resolveDeploymentRunIdFromEnv();
|
|
2486
|
+
if (!deploymentRunId) {
|
|
2487
|
+
return null;
|
|
2488
|
+
}
|
|
2489
|
+
const cfg = await tryReadApmConfig();
|
|
2490
|
+
if (!cfg || !resolveApiKey(cfg)) {
|
|
2491
|
+
console.warn("[apm] \u672A\u767B\u5F55\uFF0C\u8DF3\u8FC7 MinIO \u90E8\u7F72\u4EA7\u7269\u5F52\u6863");
|
|
2492
|
+
return null;
|
|
2493
|
+
}
|
|
2494
|
+
const api = options.api ?? createApmApiClient(cfg);
|
|
2495
|
+
let storage;
|
|
2496
|
+
try {
|
|
2497
|
+
storage = await fetchDeployArtifactStorage(api);
|
|
2498
|
+
} catch (error) {
|
|
2499
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
2500
|
+
console.warn(`[apm] \u83B7\u53D6 MinIO \u914D\u7F6E\u5931\u8D25\uFF0C\u8DF3\u8FC7\u90E8\u7F72\u4EA7\u7269\u5F52\u6863: ${detail}`);
|
|
2501
|
+
return null;
|
|
2502
|
+
}
|
|
2503
|
+
const fileName = buildDeployArtifactFileName(
|
|
2504
|
+
options.kind,
|
|
2505
|
+
options.projectName,
|
|
2506
|
+
options.timestamp
|
|
2507
|
+
);
|
|
2508
|
+
const objectKey = buildDeployArtifactObjectKey(options.projectName, fileName);
|
|
2509
|
+
let body;
|
|
2510
|
+
try {
|
|
2511
|
+
body = await readFile2(options.zipPath);
|
|
2512
|
+
} catch (error) {
|
|
2513
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
2514
|
+
console.warn(`[apm] \u8BFB\u53D6\u90E8\u7F72\u4EA7\u7269 zip \u5931\u8D25\uFF0C\u8DF3\u8FC7 MinIO \u5F52\u6863: ${detail}`);
|
|
2515
|
+
return null;
|
|
2516
|
+
}
|
|
2517
|
+
try {
|
|
2518
|
+
const client = new MinioClient({
|
|
2519
|
+
endPoint: storage.endpoint,
|
|
2520
|
+
port: storage.port,
|
|
2521
|
+
useSSL: storage.useSsl,
|
|
2522
|
+
accessKey: storage.accessKey,
|
|
2523
|
+
secretKey: storage.secretKey
|
|
2524
|
+
});
|
|
2525
|
+
await client.ensureBucket(storage.bucket);
|
|
2526
|
+
await client.putObject(storage.bucket, objectKey, body, {
|
|
2527
|
+
"Content-Type": "application/zip"
|
|
2528
|
+
});
|
|
2529
|
+
console.error(
|
|
2530
|
+
`[apm] \u5DF2\u5F52\u6863\u90E8\u7F72\u4EA7\u7269: ${storage.bucket}/${objectKey} (${(body.length / 1024 / 1024).toFixed(2)} MB)`
|
|
2531
|
+
);
|
|
2532
|
+
} catch (error) {
|
|
2533
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
2534
|
+
console.warn(`[apm] MinIO \u90E8\u7F72\u4EA7\u7269\u5F52\u6863\u5931\u8D25: ${detail}`);
|
|
2535
|
+
return null;
|
|
2536
|
+
}
|
|
2537
|
+
try {
|
|
2538
|
+
await api.cli.attachTaskDeploymentArtifact({
|
|
2539
|
+
id: deploymentRunId,
|
|
2540
|
+
artifactObjectKey: objectKey,
|
|
2541
|
+
artifactFileName: fileName
|
|
2542
|
+
});
|
|
2543
|
+
console.error(
|
|
2544
|
+
`[apm] \u5DF2\u7ED1\u5B9A\u90E8\u7F72\u4EA7\u7269\u5230\u8BB0\u5F55 id=${deploymentRunId} file=${fileName}`
|
|
2545
|
+
);
|
|
2546
|
+
} catch (error) {
|
|
2547
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
2548
|
+
console.warn(`[apm] \u7ED1\u5B9A\u90E8\u7F72\u4EA7\u7269\u5230\u8BB0\u5F55\u5931\u8D25: ${detail}`);
|
|
2549
|
+
return null;
|
|
2550
|
+
}
|
|
2551
|
+
return {
|
|
2552
|
+
objectKey,
|
|
2553
|
+
fileName,
|
|
2554
|
+
bucket: storage.bucket
|
|
2555
|
+
};
|
|
2556
|
+
}
|
|
2557
|
+
|
|
2558
|
+
// src/commands/connect/deploy-run.ts
|
|
2283
2559
|
var DEPLOY_LOG_SYNC_INTERVAL_MS = 3e4;
|
|
2284
2560
|
function resolveDeployCommand(environment) {
|
|
2285
2561
|
return `apm deploy ${environment}`;
|
|
@@ -2385,6 +2661,8 @@ async function handleInboundDeploy(cfg, msg, signal) {
|
|
|
2385
2661
|
console.log(`[apm] deploy command: ${command}`);
|
|
2386
2662
|
const logSyncer = createDeployLogSyncer(api, deploymentRunId);
|
|
2387
2663
|
let latestLog = "";
|
|
2664
|
+
const previousDeploymentRunId = process.env[APM_DEPLOYMENT_RUN_ID_ENV];
|
|
2665
|
+
process.env[APM_DEPLOYMENT_RUN_ID_ENV] = deploymentRunId;
|
|
2388
2666
|
try {
|
|
2389
2667
|
const { log: log2 } = await runShellCommand(command, workdir, signal, (log3) => {
|
|
2390
2668
|
latestLog = log3;
|
|
@@ -2412,6 +2690,11 @@ async function handleInboundDeploy(cfg, msg, signal) {
|
|
|
2412
2690
|
});
|
|
2413
2691
|
console.error(`[apm] deploy failed id=${deploymentRunId}: ${detail}`);
|
|
2414
2692
|
} finally {
|
|
2693
|
+
if (previousDeploymentRunId === void 0) {
|
|
2694
|
+
delete process.env[APM_DEPLOYMENT_RUN_ID_ENV];
|
|
2695
|
+
} else {
|
|
2696
|
+
process.env[APM_DEPLOYMENT_RUN_ID_ENV] = previousDeploymentRunId;
|
|
2697
|
+
}
|
|
2415
2698
|
logSyncer.dispose();
|
|
2416
2699
|
}
|
|
2417
2700
|
}
|
|
@@ -4067,7 +4350,7 @@ async function runCreatePr(options) {
|
|
|
4067
4350
|
|
|
4068
4351
|
// src/commands/deploy/deploy-execute.ts
|
|
4069
4352
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
4070
|
-
import
|
|
4353
|
+
import path5 from "node:path";
|
|
4071
4354
|
|
|
4072
4355
|
// src/commands/deploy/internal/apm-config.ts
|
|
4073
4356
|
import { existsSync as existsSync15, readFileSync as readFileSync12 } from "node:fs";
|
|
@@ -4409,7 +4692,7 @@ var DeployExecutionError = class extends Error {
|
|
|
4409
4692
|
|
|
4410
4693
|
// src/commands/deploy/internal/wisdom-auto-deploy.ts
|
|
4411
4694
|
import { existsSync as existsSync17, readFileSync as readFileSync14 } from "node:fs";
|
|
4412
|
-
import
|
|
4695
|
+
import path4 from "node:path";
|
|
4413
4696
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
4414
4697
|
|
|
4415
4698
|
// src/commands/deploy/internal/wisdom-backend-deploy.ts
|
|
@@ -4418,31 +4701,31 @@ import {
|
|
|
4418
4701
|
mkdirSync as mkdirSync8,
|
|
4419
4702
|
readdirSync as readdirSync5,
|
|
4420
4703
|
readFileSync as readFileSync13,
|
|
4421
|
-
statSync as
|
|
4704
|
+
statSync as statSync6,
|
|
4422
4705
|
writeFileSync as writeFileSync14
|
|
4423
4706
|
} from "node:fs";
|
|
4424
4707
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
4425
|
-
import
|
|
4426
|
-
import { Client } from "ssh2";
|
|
4708
|
+
import path3 from "node:path";
|
|
4709
|
+
import { Client as Client2 } from "ssh2";
|
|
4427
4710
|
import JSZip2 from "jszip";
|
|
4428
4711
|
import SftpClient2 from "ssh2-sftp-client";
|
|
4429
4712
|
|
|
4430
4713
|
// src/commands/deploy/internal/wisdom-sftp.ts
|
|
4431
|
-
import { readdir, readFile, unlink, writeFile } from "node:fs/promises";
|
|
4432
|
-
import
|
|
4714
|
+
import { readdir as readdir2, readFile as readFile3, unlink, writeFile } from "node:fs/promises";
|
|
4715
|
+
import path2 from "node:path";
|
|
4433
4716
|
import JSZip from "jszip";
|
|
4434
4717
|
import SftpClient from "ssh2-sftp-client";
|
|
4435
4718
|
async function addDirToZip(dir, zipFolder) {
|
|
4436
|
-
const entries = await
|
|
4719
|
+
const entries = await readdir2(dir, { withFileTypes: true });
|
|
4437
4720
|
for (const entry of entries) {
|
|
4438
|
-
const fullPath =
|
|
4721
|
+
const fullPath = path2.join(dir, entry.name);
|
|
4439
4722
|
if (entry.isDirectory()) {
|
|
4440
4723
|
const folder = zipFolder.folder(entry.name);
|
|
4441
4724
|
if (folder) {
|
|
4442
4725
|
await addDirToZip(fullPath, folder);
|
|
4443
4726
|
}
|
|
4444
4727
|
} else {
|
|
4445
|
-
const content = await
|
|
4728
|
+
const content = await readFile3(fullPath);
|
|
4446
4729
|
zipFolder.file(entry.name, content);
|
|
4447
4730
|
}
|
|
4448
4731
|
}
|
|
@@ -4550,8 +4833,8 @@ async function uploadAndMaybeExtract(settings, localZip, extract) {
|
|
|
4550
4833
|
}
|
|
4551
4834
|
}
|
|
4552
4835
|
async function runWisdomSftpDeploy(params) {
|
|
4553
|
-
const zipPath =
|
|
4554
|
-
const resolvedZipPath =
|
|
4836
|
+
const zipPath = path2.join(params.localDir, "..", ".deploy-sftp-dist.zip");
|
|
4837
|
+
const resolvedZipPath = path2.resolve(zipPath);
|
|
4555
4838
|
let zipSizeBytes = 0;
|
|
4556
4839
|
try {
|
|
4557
4840
|
zipSizeBytes = await zipDirectory(params.localDir, resolvedZipPath);
|
|
@@ -4560,6 +4843,11 @@ async function runWisdomSftpDeploy(params) {
|
|
|
4560
4843
|
resolvedZipPath,
|
|
4561
4844
|
params.extract
|
|
4562
4845
|
);
|
|
4846
|
+
await uploadDeployArtifactZip({
|
|
4847
|
+
zipPath: resolvedZipPath,
|
|
4848
|
+
projectName: params.projectName,
|
|
4849
|
+
kind: "frontend"
|
|
4850
|
+
});
|
|
4563
4851
|
} finally {
|
|
4564
4852
|
try {
|
|
4565
4853
|
await unlink(resolvedZipPath);
|
|
@@ -4594,7 +4882,7 @@ function fail(message) {
|
|
|
4594
4882
|
}
|
|
4595
4883
|
function expandPath(pathStr) {
|
|
4596
4884
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
4597
|
-
return
|
|
4885
|
+
return path3.resolve(pathStr.replace(/^~(?=\/|\\|$)/, home));
|
|
4598
4886
|
}
|
|
4599
4887
|
function quoteForShell(value) {
|
|
4600
4888
|
if (process.platform === "win32") {
|
|
@@ -4609,19 +4897,19 @@ function formatMavenLocalRepoArg(repoPath) {
|
|
|
4609
4897
|
return `-Dmaven.repo.local=${repoPath}`;
|
|
4610
4898
|
}
|
|
4611
4899
|
function deployCacheDir() {
|
|
4612
|
-
return
|
|
4900
|
+
return path3.join(workspaceApmDir(), "deploy", ".deploy_cache");
|
|
4613
4901
|
}
|
|
4614
4902
|
function manifestFilePath() {
|
|
4615
|
-
return
|
|
4903
|
+
return path3.join(deployCacheDir(), "manifest.json");
|
|
4616
4904
|
}
|
|
4617
4905
|
function getTargetDir(projectRoot) {
|
|
4618
|
-
return
|
|
4906
|
+
return path3.join(projectRoot, MAVEN_MODULE, "target");
|
|
4619
4907
|
}
|
|
4620
4908
|
function relativeKey(projectRoot, filePath) {
|
|
4621
|
-
return
|
|
4909
|
+
return path3.relative(projectRoot, filePath).split(path3.sep).join("/");
|
|
4622
4910
|
}
|
|
4623
4911
|
function fileSignature(filePath) {
|
|
4624
|
-
const stat2 =
|
|
4912
|
+
const stat2 = statSync6(filePath);
|
|
4625
4913
|
return { size: stat2.size, mtime: stat2.mtimeMs / 1e3 };
|
|
4626
4914
|
}
|
|
4627
4915
|
function loadManifest4() {
|
|
@@ -4643,12 +4931,12 @@ function shouldUploadLibFile(localPath, remoteAttr, manifest, projectRoot) {
|
|
|
4643
4931
|
if (!remoteAttr) {
|
|
4644
4932
|
return [false, "\u8FDC\u7A0B\u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7"];
|
|
4645
4933
|
}
|
|
4646
|
-
const localSize =
|
|
4934
|
+
const localSize = statSync6(localPath).size;
|
|
4647
4935
|
const remoteSize = remoteAttr.size;
|
|
4648
4936
|
if (localSize !== remoteSize) {
|
|
4649
4937
|
return [true, `\u5927\u5C0F\u53D8\u5316 ${remoteSize} -> ${localSize}`];
|
|
4650
4938
|
}
|
|
4651
|
-
if (isProjectLibJar(
|
|
4939
|
+
if (isProjectLibJar(path3.basename(localPath)) && manifest) {
|
|
4652
4940
|
const key = relativeKey(projectRoot, localPath);
|
|
4653
4941
|
const current = fileSignature(localPath);
|
|
4654
4942
|
const previous = manifest[key];
|
|
@@ -4668,7 +4956,7 @@ function listLibFilesToUpload(localLibDir, remoteStats, projectRoot, manifest =
|
|
|
4668
4956
|
const entries = [];
|
|
4669
4957
|
const jarFiles = readdirSync5(localLibDir).filter((name) => name.endsWith(".jar")).sort();
|
|
4670
4958
|
for (const jarName of jarFiles) {
|
|
4671
|
-
const jarPath =
|
|
4959
|
+
const jarPath = path3.join(localLibDir, jarName);
|
|
4672
4960
|
const remoteAttr = remoteStats.get(jarName);
|
|
4673
4961
|
const [shouldUpload, reason] = shouldUploadLibFile(
|
|
4674
4962
|
jarPath,
|
|
@@ -4691,8 +4979,8 @@ function updateManifestEntries(manifest, entries, projectRoot) {
|
|
|
4691
4979
|
async function createUpdatePackage(entries, packageName) {
|
|
4692
4980
|
const dir = deployCacheDir();
|
|
4693
4981
|
mkdirSync8(dir, { recursive: true });
|
|
4694
|
-
const zipPath =
|
|
4695
|
-
log(`\u521B\u5EFA\u66F4\u65B0\u5305: ${
|
|
4982
|
+
const zipPath = path3.join(dir, packageName);
|
|
4983
|
+
log(`\u521B\u5EFA\u66F4\u65B0\u5305: ${path3.basename(zipPath)}\uFF08${entries.length} \u4E2A\u6587\u4EF6\uFF09`);
|
|
4696
4984
|
const zip = new JSZip2();
|
|
4697
4985
|
for (const entry of entries) {
|
|
4698
4986
|
const content = readFileSync13(entry.path);
|
|
@@ -4756,8 +5044,8 @@ function locateLibDir(projectRoot) {
|
|
|
4756
5044
|
if (!existsSync16(targetDir)) {
|
|
4757
5045
|
fail(`\u6784\u5EFA\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728: ${targetDir}`);
|
|
4758
5046
|
}
|
|
4759
|
-
const libDir =
|
|
4760
|
-
if (!existsSync16(libDir) || !
|
|
5047
|
+
const libDir = path3.join(targetDir, "lib");
|
|
5048
|
+
if (!existsSync16(libDir) || !statSync6(libDir).isDirectory()) {
|
|
4761
5049
|
fail(`lib \u76EE\u5F55\u4E0D\u5B58\u5728: ${libDir}`);
|
|
4762
5050
|
}
|
|
4763
5051
|
const libJars = readdirSync5(libDir).filter((name) => name.endsWith(".jar"));
|
|
@@ -4772,16 +5060,16 @@ function locateMainJar(projectRoot) {
|
|
|
4772
5060
|
if (!existsSync16(targetDir)) {
|
|
4773
5061
|
fail(`\u6784\u5EFA\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728: ${targetDir}`);
|
|
4774
5062
|
}
|
|
4775
|
-
const jarFiles = readdirSync5(targetDir).filter((name) => name.endsWith(".jar") && !name.endsWith(".jar.original")).map((name) =>
|
|
5063
|
+
const jarFiles = readdirSync5(targetDir).filter((name) => name.endsWith(".jar") && !name.endsWith(".jar.original")).map((name) => path3.join(targetDir, name)).sort((a, b) => statSync6(b).mtimeMs - statSync6(a).mtimeMs);
|
|
4776
5064
|
if (jarFiles.length === 0) {
|
|
4777
5065
|
fail(`target \u76EE\u5F55\u4E0B\u6CA1\u6709\u4E3B JAR: ${targetDir}`);
|
|
4778
5066
|
}
|
|
4779
5067
|
const mainJar = jarFiles[0];
|
|
4780
|
-
log(`\u5B9A\u4F4D\u4E3B JAR \u4EA7\u7269: ${
|
|
5068
|
+
log(`\u5B9A\u4F4D\u4E3B JAR \u4EA7\u7269: ${path3.basename(mainJar)}`);
|
|
4781
5069
|
return mainJar;
|
|
4782
5070
|
}
|
|
4783
5071
|
async function connectSsh(config) {
|
|
4784
|
-
const client = new
|
|
5072
|
+
const client = new Client2();
|
|
4785
5073
|
log(`\u8FDE\u63A5\u670D\u52A1\u5668 ${config.username}@${config.host}:${config.port}`);
|
|
4786
5074
|
await new Promise((resolve5, reject) => {
|
|
4787
5075
|
client.on("ready", () => resolve5()).on("error", (err) => reject(err)).connect({
|
|
@@ -4826,7 +5114,7 @@ async function getRemoteFileStats(sftp, remoteDir) {
|
|
|
4826
5114
|
}
|
|
4827
5115
|
async function uploadUpdatePackage(sftp, zipPath, config) {
|
|
4828
5116
|
const remoteDir = config.remoteVueDistDir.replace(/\/$/, "");
|
|
4829
|
-
const remotePath = `${remoteDir}/${
|
|
5117
|
+
const remotePath = `${remoteDir}/${path3.basename(zipPath)}`;
|
|
4830
5118
|
log(`\u4E0A\u4F20\u66F4\u65B0\u5305 -> ${remotePath}`);
|
|
4831
5119
|
try {
|
|
4832
5120
|
await sftp.fastPut(zipPath, remotePath);
|
|
@@ -4839,7 +5127,7 @@ async function uploadUpdatePackage(sftp, zipPath, config) {
|
|
|
4839
5127
|
async function uploadFullJar(sftp, localJarPath, config) {
|
|
4840
5128
|
const remoteDir = config.remoteAppDir.replace(/\/$/, "");
|
|
4841
5129
|
const remotePath = `${remoteDir}/${config.startupJar}`;
|
|
4842
|
-
log(`\u4E0A\u4F20\u5168\u91CF JAR (${
|
|
5130
|
+
log(`\u4E0A\u4F20\u5168\u91CF JAR (${path3.basename(localJarPath)}) -> ${remotePath}`);
|
|
4843
5131
|
try {
|
|
4844
5132
|
await sftp.mkdir(remoteDir, true);
|
|
4845
5133
|
await sftp.fastPut(localJarPath, remotePath);
|
|
@@ -5098,10 +5386,10 @@ async function restartRemoteService(client, config) {
|
|
|
5098
5386
|
await runRemoteServiceScript(client, script, "restart");
|
|
5099
5387
|
}
|
|
5100
5388
|
async function runWisdomBackendDeploy(options) {
|
|
5101
|
-
const projectRoot =
|
|
5389
|
+
const projectRoot = path3.resolve(options.projectRoot ?? process.cwd());
|
|
5102
5390
|
const config = options.config;
|
|
5103
5391
|
log(`=== \u81EA\u52A8\u90E8\u7F72: ${config.projectName} ===`);
|
|
5104
|
-
log(`\u914D\u7F6E\u6587\u4EF6: ${
|
|
5392
|
+
log(`\u914D\u7F6E\u6587\u4EF6: ${path3.join(workspaceApmDir(), "apm.config.json")}`);
|
|
5105
5393
|
log(`\u9879\u76EE\u6839\u76EE\u5F55: ${projectRoot}`);
|
|
5106
5394
|
log(
|
|
5107
5395
|
`\u90E8\u7F72\u6A21\u5F0F: ${config.mode}${config.mode === "full" ? "\uFF08\u5168\u91CF JAR\uFF0C\u8DF3\u8FC7 lib \u68C0\u67E5\uFF09" : "\uFF08\u589E\u91CF lib \u66F4\u65B0\uFF09"}`
|
|
@@ -5115,6 +5403,21 @@ async function runWisdomBackendDeploy(options) {
|
|
|
5115
5403
|
if (config.mode === "full") {
|
|
5116
5404
|
const mainJar = locateMainJar(projectRoot);
|
|
5117
5405
|
await uploadFullJar(conn.sftp, mainJar, config);
|
|
5406
|
+
const archiveZipPath = await createUpdatePackage(
|
|
5407
|
+
[
|
|
5408
|
+
{
|
|
5409
|
+
path: mainJar,
|
|
5410
|
+
arcname: path3.basename(mainJar),
|
|
5411
|
+
reason: "\u5168\u91CF JAR \u5F52\u6863"
|
|
5412
|
+
}
|
|
5413
|
+
],
|
|
5414
|
+
`.deploy-archive-${config.projectName}.jar.zip`
|
|
5415
|
+
);
|
|
5416
|
+
await uploadDeployArtifactZip({
|
|
5417
|
+
zipPath: archiveZipPath,
|
|
5418
|
+
projectName: config.projectName,
|
|
5419
|
+
kind: "backend"
|
|
5420
|
+
});
|
|
5118
5421
|
log("\u91CD\u542F\u670D\u52A1...");
|
|
5119
5422
|
await restartRemoteService(conn.client, config);
|
|
5120
5423
|
await healthCheckService(conn.client, config);
|
|
@@ -5145,6 +5448,11 @@ async function runWisdomBackendDeploy(options) {
|
|
|
5145
5448
|
zipPath,
|
|
5146
5449
|
config
|
|
5147
5450
|
);
|
|
5451
|
+
await uploadDeployArtifactZip({
|
|
5452
|
+
zipPath,
|
|
5453
|
+
projectName: config.projectName,
|
|
5454
|
+
kind: "backend"
|
|
5455
|
+
});
|
|
5148
5456
|
log("\u8FDC\u7A0B\u89E3\u538B lib \u76EE\u5F55\uFF08\u4EC5\u8986\u76D6\u5DF2\u6709 JAR\uFF09...");
|
|
5149
5457
|
updated = await extractUpdatePackageOnRemote(
|
|
5150
5458
|
conn.client,
|
|
@@ -5188,10 +5496,10 @@ function isWisdomLegacyDeploy(cfg) {
|
|
|
5188
5496
|
return !hasNewFrontend && !hasNewBackend;
|
|
5189
5497
|
}
|
|
5190
5498
|
function detectWisdomProjectType(cwd) {
|
|
5191
|
-
return existsSync17(
|
|
5499
|
+
return existsSync17(path4.join(cwd, "package.json")) ? "frontend" : "backend";
|
|
5192
5500
|
}
|
|
5193
5501
|
function readPackageScripts(cwd) {
|
|
5194
|
-
const pkgPath =
|
|
5502
|
+
const pkgPath = path4.join(cwd, "package.json");
|
|
5195
5503
|
if (!existsSync17(pkgPath)) {
|
|
5196
5504
|
return {};
|
|
5197
5505
|
}
|
|
@@ -5236,7 +5544,7 @@ function runShellCommand2(command, cwd, captureOutput) {
|
|
|
5236
5544
|
return output;
|
|
5237
5545
|
}
|
|
5238
5546
|
async function runWisdomAutoDeploy(options) {
|
|
5239
|
-
const cwd =
|
|
5547
|
+
const cwd = path4.resolve(options.cwd ?? process.cwd());
|
|
5240
5548
|
const captureOutput = options.captureOutput ?? false;
|
|
5241
5549
|
const projectType = detectWisdomProjectType(cwd);
|
|
5242
5550
|
console.error(
|
|
@@ -5247,14 +5555,14 @@ async function runWisdomAutoDeploy(options) {
|
|
|
5247
5555
|
if (!deployCmd) {
|
|
5248
5556
|
const lines = formatWisdomFrontendDeployNotConfiguredLines(
|
|
5249
5557
|
options.env,
|
|
5250
|
-
|
|
5558
|
+
path4.join(cwd, "package.json")
|
|
5251
5559
|
);
|
|
5252
5560
|
throw new DeployExecutionError(lines.join("\n"), 1, lines.join("\n"));
|
|
5253
5561
|
}
|
|
5254
5562
|
runShellCommand2(deployCmd, cwd, captureOutput);
|
|
5255
5563
|
return { projectType };
|
|
5256
5564
|
}
|
|
5257
|
-
const configPath = options.configPath ??
|
|
5565
|
+
const configPath = options.configPath ?? path4.join(workspaceApmDir(cwd), "apm.config.json");
|
|
5258
5566
|
const cfg = loadApmConfig({ configPath });
|
|
5259
5567
|
const settings = resolveWisdomBackendDeployFromApmConfig(cfg);
|
|
5260
5568
|
console.error(
|
|
@@ -5267,6 +5575,150 @@ async function runWisdomAutoDeploy(options) {
|
|
|
5267
5575
|
return { projectType };
|
|
5268
5576
|
}
|
|
5269
5577
|
|
|
5578
|
+
// src/commands/deploy/internal/deploy-baseline-sync.ts
|
|
5579
|
+
var LOG_PREFIX = "[apm] \u90E8\u7F72\u524D\u57FA\u7EBF\u540C\u6B65:";
|
|
5580
|
+
function formatGitError(error) {
|
|
5581
|
+
return error instanceof Error ? error.message : String(error);
|
|
5582
|
+
}
|
|
5583
|
+
async function resolveBaselineBranch2(cwd, api) {
|
|
5584
|
+
const workdirPath = resolveWorkdirPath(cwd);
|
|
5585
|
+
const baseline = await api.cli.workspaceBaseline({ workdirPath });
|
|
5586
|
+
if (!baseline.repositoryId) {
|
|
5587
|
+
const detail = baseline.diagnostic?.message ?? `\u672A\u5728\u5E73\u53F0\u627E\u5230\u4E0E\u5F53\u524D\u76EE\u5F55\u5339\u914D\u7684\u5DE5\u4F5C\u76EE\u5F55\u767B\u8BB0\uFF1A${workdirPath}\uFF08\u89C4\u8303\u5316\uFF1A${baseline.workdirPath}\uFF09
|
|
5588
|
+
\u8BF7\u5148\u5728\u5E73\u53F0\u767B\u8BB0\u8BE5\u8DEF\u5F84\u5BF9\u5E94\u7684\u5DE5\u4F5C\u76EE\u5F55\u4E0E\u4ED3\u5E93\u3002`;
|
|
5589
|
+
throw new Error(detail);
|
|
5590
|
+
}
|
|
5591
|
+
const baselineBranch = (baseline.defaultBranch ?? "").trim();
|
|
5592
|
+
if (!baselineBranch) {
|
|
5593
|
+
throw new Error("\u5E73\u53F0\u8FD4\u56DE\u7684\u57FA\u7EBF\u5206\u652F\u540D\u4E3A\u7A7A");
|
|
5594
|
+
}
|
|
5595
|
+
return baselineBranch;
|
|
5596
|
+
}
|
|
5597
|
+
async function isMergeInProgress(cwd) {
|
|
5598
|
+
try {
|
|
5599
|
+
await execGit(cwd, ["rev-parse", "-q", "--verify", "MERGE_HEAD"], true);
|
|
5600
|
+
return true;
|
|
5601
|
+
} catch {
|
|
5602
|
+
return false;
|
|
5603
|
+
}
|
|
5604
|
+
}
|
|
5605
|
+
async function abortMergeIfNeeded(cwd) {
|
|
5606
|
+
if (await isMergeInProgress(cwd)) {
|
|
5607
|
+
await execGit(cwd, ["merge", "--abort"], true);
|
|
5608
|
+
}
|
|
5609
|
+
}
|
|
5610
|
+
async function restoreWorkingTree(cwd) {
|
|
5611
|
+
await execGit(cwd, ["reset", "--hard", "HEAD"], true);
|
|
5612
|
+
}
|
|
5613
|
+
async function mergeBaselineBranch(cwd, baselineBranch, currentBranch, note) {
|
|
5614
|
+
const mergeTarget = `origin/${baselineBranch}`;
|
|
5615
|
+
note(`${LOG_PREFIX} \u5F00\u59CB\u5408\u5E76 ${mergeTarget} \u5230\u5F53\u524D\u5206\u652F ${currentBranch}`);
|
|
5616
|
+
try {
|
|
5617
|
+
if (currentBranch === baselineBranch) {
|
|
5618
|
+
await execGit(cwd, ["merge", "--ff-only", mergeTarget]);
|
|
5619
|
+
} else {
|
|
5620
|
+
await execGit(cwd, ["merge", mergeTarget, "--no-edit"]);
|
|
5621
|
+
}
|
|
5622
|
+
note(`${LOG_PREFIX} \u5DF2\u5408\u5E76 ${mergeTarget} \u6700\u65B0\u4EE3\u7801`);
|
|
5623
|
+
return { merged: true, conflictRollback: false };
|
|
5624
|
+
} catch (error) {
|
|
5625
|
+
await abortMergeIfNeeded(cwd);
|
|
5626
|
+
note(`${LOG_PREFIX} \u5408\u5E76 ${mergeTarget} \u5931\u8D25: ${formatGitError(error)}`);
|
|
5627
|
+
note(`${LOG_PREFIX} \u5DF2\u6267\u884C git merge --abort \u56DE\u9000\u5230\u5408\u5E76\u524D\u72B6\u6001`);
|
|
5628
|
+
note(`${LOG_PREFIX} \u5C06\u4F7F\u7528\u56DE\u9000\u540E\u7684\u4EE3\u7801\u7EE7\u7EED\u90E8\u7F72`);
|
|
5629
|
+
return { merged: false, conflictRollback: true };
|
|
5630
|
+
}
|
|
5631
|
+
}
|
|
5632
|
+
async function restoreStashIfNeeded(cwd, stashed, note) {
|
|
5633
|
+
if (!stashed) {
|
|
5634
|
+
return false;
|
|
5635
|
+
}
|
|
5636
|
+
note(`${LOG_PREFIX} \u6B63\u5728\u6062\u590D stash \u4E2D\u7684\u672A\u63D0\u4EA4\u6539\u52A8`);
|
|
5637
|
+
try {
|
|
5638
|
+
await execGit(cwd, ["stash", "pop"], true);
|
|
5639
|
+
note(`${LOG_PREFIX} \u5DF2\u6062\u590D stash \u4E2D\u7684\u672A\u63D0\u4EA4\u6539\u52A8`);
|
|
5640
|
+
return false;
|
|
5641
|
+
} catch (error) {
|
|
5642
|
+
await abortMergeIfNeeded(cwd);
|
|
5643
|
+
await restoreWorkingTree(cwd);
|
|
5644
|
+
note(`${LOG_PREFIX} \u6062\u590D stash \u5931\u8D25: ${formatGitError(error)}`);
|
|
5645
|
+
note(`${LOG_PREFIX} \u5DF2\u56DE\u9000\u5DE5\u4F5C\u533A\uFF08git reset --hard HEAD\uFF09\uFF0Cstash \u4ECD\u4FDD\u7559`);
|
|
5646
|
+
note(`${LOG_PREFIX} \u5C06\u4F7F\u7528\u56DE\u9000\u540E\u7684\u4EE3\u7801\u7EE7\u7EED\u90E8\u7F72`);
|
|
5647
|
+
return true;
|
|
5648
|
+
}
|
|
5649
|
+
}
|
|
5650
|
+
async function syncDeployBaselineBeforeDeploy(cwd) {
|
|
5651
|
+
const lines = [];
|
|
5652
|
+
const note = (message) => {
|
|
5653
|
+
lines.push(message);
|
|
5654
|
+
console.error(message);
|
|
5655
|
+
};
|
|
5656
|
+
const emptyResult = (partial = {}) => ({
|
|
5657
|
+
log: lines.join("\n"),
|
|
5658
|
+
skipped: true,
|
|
5659
|
+
merged: false,
|
|
5660
|
+
conflictRollback: false,
|
|
5661
|
+
stashConflict: false,
|
|
5662
|
+
...partial
|
|
5663
|
+
});
|
|
5664
|
+
if (!await isGitRepo(cwd)) {
|
|
5665
|
+
note(`${LOG_PREFIX} \u5F53\u524D\u76EE\u5F55\u4E0D\u662F git \u4ED3\u5E93\uFF0C\u8DF3\u8FC7`);
|
|
5666
|
+
return emptyResult();
|
|
5667
|
+
}
|
|
5668
|
+
const cfg = await tryReadApmConfig();
|
|
5669
|
+
if (!cfg || !resolveApiKey(cfg)) {
|
|
5670
|
+
note(`${LOG_PREFIX} \u672A\u767B\u5F55\uFF0C\u8DF3\u8FC7`);
|
|
5671
|
+
return emptyResult();
|
|
5672
|
+
}
|
|
5673
|
+
await ensureGitRepo(cwd);
|
|
5674
|
+
const api = createApmApiClient(cfg);
|
|
5675
|
+
const baselineBranch = await resolveBaselineBranch2(cwd, api);
|
|
5676
|
+
note(`${LOG_PREFIX} \u57FA\u7EBF\u5206\u652F ${baselineBranch}`);
|
|
5677
|
+
note(`${LOG_PREFIX} \u6B63\u5728 fetch origin ${baselineBranch}`);
|
|
5678
|
+
await execGit(cwd, ["fetch", "origin", baselineBranch], true);
|
|
5679
|
+
if (!await remoteBranchExists(cwd, baselineBranch)) {
|
|
5680
|
+
throw new Error(
|
|
5681
|
+
`\u8FDC\u7A0B\u4E0D\u5B58\u5728\u57FA\u7EBF\u5206\u652F origin/${baselineBranch}\uFF0C\u8BF7\u786E\u8BA4\u4ED3\u5E93\u9ED8\u8BA4\u5206\u652F\u5DF2\u63A8\u9001\u5230 origin`
|
|
5682
|
+
);
|
|
5683
|
+
}
|
|
5684
|
+
note(`${LOG_PREFIX} fetch \u5B8C\u6210`);
|
|
5685
|
+
const currentBranch = await getCurrentBranch(cwd);
|
|
5686
|
+
let stashed = false;
|
|
5687
|
+
if (await isWorkingTreeDirty(cwd)) {
|
|
5688
|
+
note(`${LOG_PREFIX} \u68C0\u6D4B\u5230\u672A\u63D0\u4EA4\u6539\u52A8\uFF0C\u5148 stash`);
|
|
5689
|
+
await execGit(cwd, [
|
|
5690
|
+
"stash",
|
|
5691
|
+
"push",
|
|
5692
|
+
"-u",
|
|
5693
|
+
"-m",
|
|
5694
|
+
"apm: deploy baseline sync"
|
|
5695
|
+
]);
|
|
5696
|
+
stashed = true;
|
|
5697
|
+
note(`${LOG_PREFIX} \u5DF2 stash \u672A\u63D0\u4EA4\u6539\u52A8`);
|
|
5698
|
+
}
|
|
5699
|
+
const { merged, conflictRollback } = await mergeBaselineBranch(
|
|
5700
|
+
cwd,
|
|
5701
|
+
baselineBranch,
|
|
5702
|
+
currentBranch,
|
|
5703
|
+
note
|
|
5704
|
+
);
|
|
5705
|
+
const stashConflict = await restoreStashIfNeeded(cwd, stashed, note);
|
|
5706
|
+
if (conflictRollback || stashConflict) {
|
|
5707
|
+
note(`${LOG_PREFIX} \u57FA\u7EBF\u540C\u6B65\u672A\u5B8C\u6210\uFF08\u5B58\u5728\u51B2\u7A81\u5E76\u5DF2\u56DE\u9000\uFF09\uFF0C\u7EE7\u7EED\u6267\u884C\u90E8\u7F72`);
|
|
5708
|
+
} else if (merged) {
|
|
5709
|
+
note(
|
|
5710
|
+
`${LOG_PREFIX} \u5B8C\u6210\uFF08\u5F53\u524D\u5206\u652F ${currentBranch} \u5DF2\u5305\u542B ${baselineBranch} \u6700\u65B0\u4EE3\u7801\uFF09`
|
|
5711
|
+
);
|
|
5712
|
+
}
|
|
5713
|
+
return {
|
|
5714
|
+
log: lines.join("\n"),
|
|
5715
|
+
skipped: false,
|
|
5716
|
+
merged,
|
|
5717
|
+
conflictRollback,
|
|
5718
|
+
stashConflict
|
|
5719
|
+
};
|
|
5720
|
+
}
|
|
5721
|
+
|
|
5270
5722
|
// src/commands/deploy/deploy-execute.ts
|
|
5271
5723
|
function runShellCommand3(command, cwd, captureOutput) {
|
|
5272
5724
|
const result = spawnSync5(command, {
|
|
@@ -5293,8 +5745,22 @@ function runShellCommand3(command, cwd, captureOutput) {
|
|
|
5293
5745
|
return output;
|
|
5294
5746
|
}
|
|
5295
5747
|
async function executeDeploy(options) {
|
|
5296
|
-
const cwd =
|
|
5748
|
+
const cwd = path5.resolve(options.cwd ?? process.cwd());
|
|
5297
5749
|
const captureOutput = options.captureOutput ?? false;
|
|
5750
|
+
const outputParts = [];
|
|
5751
|
+
try {
|
|
5752
|
+
const syncResult = await syncDeployBaselineBeforeDeploy(cwd);
|
|
5753
|
+
if (syncResult.log.trim()) {
|
|
5754
|
+
outputParts.push(syncResult.log);
|
|
5755
|
+
}
|
|
5756
|
+
} catch (error) {
|
|
5757
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
5758
|
+
throw new DeployExecutionError(
|
|
5759
|
+
`\u90E8\u7F72\u524D\u540C\u6B65\u57FA\u7EBF\u5206\u652F\u5931\u8D25: ${detail}`,
|
|
5760
|
+
1,
|
|
5761
|
+
detail
|
|
5762
|
+
);
|
|
5763
|
+
}
|
|
5298
5764
|
const cfg = loadApmConfig({ configPath: options.configPath });
|
|
5299
5765
|
if (isWisdomLegacyDeploy(cfg)) {
|
|
5300
5766
|
try {
|
|
@@ -5304,7 +5770,7 @@ async function executeDeploy(options) {
|
|
|
5304
5770
|
configPath: options.configPath,
|
|
5305
5771
|
captureOutput
|
|
5306
5772
|
});
|
|
5307
|
-
return "";
|
|
5773
|
+
return outputParts.join("\n");
|
|
5308
5774
|
} catch (error) {
|
|
5309
5775
|
if (error instanceof DeployExecutionError) {
|
|
5310
5776
|
throw error;
|
|
@@ -5319,7 +5785,11 @@ async function executeDeploy(options) {
|
|
|
5319
5785
|
const lines = formatDeployNotConfiguredLines(options.env, deployCommands);
|
|
5320
5786
|
throw new DeployExecutionError(lines.join("\n"), 1, lines.join("\n"));
|
|
5321
5787
|
}
|
|
5322
|
-
|
|
5788
|
+
const commandOutput = runShellCommand3(command, cwd, captureOutput);
|
|
5789
|
+
if (commandOutput.trim()) {
|
|
5790
|
+
outputParts.push(commandOutput);
|
|
5791
|
+
}
|
|
5792
|
+
return outputParts.join("\n");
|
|
5323
5793
|
}
|
|
5324
5794
|
function printDeployExecutionError(error) {
|
|
5325
5795
|
if (error.output.trim()) {
|
|
@@ -5384,6 +5854,8 @@ async function runDeployWithBackendTracking(options) {
|
|
|
5384
5854
|
status: "DEPLOYING"
|
|
5385
5855
|
});
|
|
5386
5856
|
const logSyncer = createDeployLogSyncer(api, deploymentRunId);
|
|
5857
|
+
const previousDeploymentRunId = process.env[APM_DEPLOYMENT_RUN_ID_ENV];
|
|
5858
|
+
process.env[APM_DEPLOYMENT_RUN_ID_ENV] = deploymentRunId;
|
|
5387
5859
|
const chunks = [];
|
|
5388
5860
|
const appendLog = (line) => {
|
|
5389
5861
|
if (!line) return;
|
|
@@ -5430,6 +5902,11 @@ async function runDeployWithBackendTracking(options) {
|
|
|
5430
5902
|
printDeployExecutionError(deployError);
|
|
5431
5903
|
process.exit(deployError.exitCode);
|
|
5432
5904
|
} finally {
|
|
5905
|
+
if (previousDeploymentRunId === void 0) {
|
|
5906
|
+
delete process.env[APM_DEPLOYMENT_RUN_ID_ENV];
|
|
5907
|
+
} else {
|
|
5908
|
+
process.env[APM_DEPLOYMENT_RUN_ID_ENV] = previousDeploymentRunId;
|
|
5909
|
+
}
|
|
5433
5910
|
console.log = originalLog;
|
|
5434
5911
|
console.error = originalError;
|
|
5435
5912
|
logSyncer.dispose();
|
|
@@ -5473,23 +5950,23 @@ function registerDeployMainCommand(program) {
|
|
|
5473
5950
|
}
|
|
5474
5951
|
|
|
5475
5952
|
// src/commands/deploy/backend.ts
|
|
5476
|
-
import
|
|
5953
|
+
import path10 from "node:path";
|
|
5477
5954
|
|
|
5478
5955
|
// src/commands/deploy/internal/backend-deploy/backend-deploy-workflow.ts
|
|
5479
|
-
import
|
|
5956
|
+
import path9 from "node:path";
|
|
5480
5957
|
|
|
5481
5958
|
// src/commands/deploy/internal/backend-deploy/dockerode-client/client.ts
|
|
5482
5959
|
import Docker from "dockerode";
|
|
5483
5960
|
|
|
5484
5961
|
// src/commands/deploy/internal/backend-deploy/dockerode-client/connection-options.ts
|
|
5485
5962
|
import { existsSync as existsSync18, readFileSync as readFileSync15 } from "node:fs";
|
|
5486
|
-
import
|
|
5963
|
+
import path6 from "node:path";
|
|
5487
5964
|
function asOptionalTlsBuffer(value) {
|
|
5488
5965
|
if (typeof value !== "string") {
|
|
5489
5966
|
console.log("tls filepath not exist");
|
|
5490
5967
|
return void 0;
|
|
5491
5968
|
}
|
|
5492
|
-
console.log("tls filepath",
|
|
5969
|
+
console.log("tls filepath", path6.join(process.cwd(), value));
|
|
5493
5970
|
const normalized = value.trim();
|
|
5494
5971
|
if (normalized === "") {
|
|
5495
5972
|
return void 0;
|
|
@@ -5705,8 +6182,8 @@ var DockerodeClient = class {
|
|
|
5705
6182
|
var createDockerodeClient = (config) => new DockerodeClient(config);
|
|
5706
6183
|
|
|
5707
6184
|
// src/commands/deploy/internal/backend-deploy/dockerode-client/env.ts
|
|
5708
|
-
import { existsSync as existsSync19, readFileSync as readFileSync16, statSync as
|
|
5709
|
-
import
|
|
6185
|
+
import { existsSync as existsSync19, readFileSync as readFileSync16, statSync as statSync7 } from "node:fs";
|
|
6186
|
+
import path7 from "node:path";
|
|
5710
6187
|
function stripSurroundingQuotes(value) {
|
|
5711
6188
|
const t = value.trim();
|
|
5712
6189
|
if (t.length >= 2) {
|
|
@@ -5721,8 +6198,8 @@ function loadEnvFromFile(envFilePath) {
|
|
|
5721
6198
|
if (!envFilePath) {
|
|
5722
6199
|
return {};
|
|
5723
6200
|
}
|
|
5724
|
-
const targetPath =
|
|
5725
|
-
if (!existsSync19(targetPath) || !
|
|
6201
|
+
const targetPath = path7.resolve(envFilePath);
|
|
6202
|
+
if (!existsSync19(targetPath) || !statSync7(targetPath).isFile()) {
|
|
5726
6203
|
return {};
|
|
5727
6204
|
}
|
|
5728
6205
|
const raw = readFileSync16(targetPath, "utf-8");
|
|
@@ -5897,9 +6374,9 @@ function dockerPushImage(params, cwd) {
|
|
|
5897
6374
|
|
|
5898
6375
|
// src/commands/deploy/internal/backend-deploy/resolve-dockerfile.ts
|
|
5899
6376
|
import { existsSync as existsSync20 } from "node:fs";
|
|
5900
|
-
import
|
|
6377
|
+
import path8 from "node:path";
|
|
5901
6378
|
function resolveDockerBuildPaths(cwd) {
|
|
5902
|
-
const dockerfilePath =
|
|
6379
|
+
const dockerfilePath = path8.join(cwd, "Dockerfile");
|
|
5903
6380
|
Logger.info(`\u67E5\u627EDockerfile\u6587\u4EF6\uFF0C\u8DEF\u5F84: ${dockerfilePath}`);
|
|
5904
6381
|
if (!existsSync20(dockerfilePath)) {
|
|
5905
6382
|
throw new Error(`Dockerfile \u4E0D\u5B58\u5728\uFF1A${dockerfilePath}`);
|
|
@@ -5956,7 +6433,7 @@ var BackendDeployWorkflow = class {
|
|
|
5956
6433
|
serveraddress
|
|
5957
6434
|
});
|
|
5958
6435
|
Logger.success("\u8FDC\u7A0B\u62C9\u53D6\u955C\u50CF\u5B8C\u6210");
|
|
5959
|
-
const envFilePath =
|
|
6436
|
+
const envFilePath = path9.resolve(cwd, this.params.envFilePath || ".env");
|
|
5960
6437
|
const envObj = loadEnvFromFile(envFilePath);
|
|
5961
6438
|
if (this.params.dockerNetwork?.trim()) {
|
|
5962
6439
|
Logger.info(`\u8FDC\u7A0B\u5BB9\u5668\u5C06\u52A0\u5165 Docker \u7F51\u7EDC\uFF1A${this.params.dockerNetwork.trim()}`);
|
|
@@ -5996,7 +6473,7 @@ function registerDeployBackendCommands(program) {
|
|
|
5996
6473
|
assertDeployImageTag(tag);
|
|
5997
6474
|
const cfg = loadApmConfig({ configPath: opts.config });
|
|
5998
6475
|
const fromApm = resolveBackendDeployFromApmConfig(cfg);
|
|
5999
|
-
const dirAbs =
|
|
6476
|
+
const dirAbs = path10.resolve(process.cwd(), opts.dir || "servers/api");
|
|
6000
6477
|
const params = {
|
|
6001
6478
|
image: fromApm.name,
|
|
6002
6479
|
tag,
|
|
@@ -6028,146 +6505,6 @@ function registerDeployBackendCommands(program) {
|
|
|
6028
6505
|
// src/commands/deploy/frontend.ts
|
|
6029
6506
|
import { copyFile, readdir as readdir3, stat } from "node:fs/promises";
|
|
6030
6507
|
import path11 from "node:path";
|
|
6031
|
-
|
|
6032
|
-
// src/commands/deploy/internal/minio.ts
|
|
6033
|
-
import { statSync as statSync7 } from "node:fs";
|
|
6034
|
-
import { readdir as readdir2, readFile as readFile2 } from "node:fs/promises";
|
|
6035
|
-
import path10 from "node:path";
|
|
6036
|
-
import * as Minio from "minio";
|
|
6037
|
-
var DEFAULT_MAX_FILE_SIZE_MB = 50;
|
|
6038
|
-
async function isDirectoryPath(dir) {
|
|
6039
|
-
try {
|
|
6040
|
-
const st = statSync7(dir);
|
|
6041
|
-
return st.isDirectory();
|
|
6042
|
-
} catch {
|
|
6043
|
-
return false;
|
|
6044
|
-
}
|
|
6045
|
-
}
|
|
6046
|
-
function sanitizeRelativePath(rel) {
|
|
6047
|
-
const norm = rel.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
6048
|
-
const segments = norm.split("/").filter(Boolean);
|
|
6049
|
-
for (const s of segments) {
|
|
6050
|
-
if (s === "." || s === "..") {
|
|
6051
|
-
throw new Error(`\u975E\u6CD5\u76F8\u5BF9\u8DEF\u5F84\u7247\u6BB5\uFF1A${s}`);
|
|
6052
|
-
}
|
|
6053
|
-
}
|
|
6054
|
-
return segments.join("/");
|
|
6055
|
-
}
|
|
6056
|
-
async function collectFiles(root) {
|
|
6057
|
-
const out = [];
|
|
6058
|
-
async function walk(dir, prefix) {
|
|
6059
|
-
const entries = await readdir2(dir, { withFileTypes: true });
|
|
6060
|
-
for (const e of entries) {
|
|
6061
|
-
const name = e.name;
|
|
6062
|
-
if (name === "." || name === "..") {
|
|
6063
|
-
continue;
|
|
6064
|
-
}
|
|
6065
|
-
const abs = path10.join(dir, name);
|
|
6066
|
-
const rel = prefix ? `${prefix}/${name}` : name;
|
|
6067
|
-
if (e.isDirectory()) {
|
|
6068
|
-
await walk(abs, rel);
|
|
6069
|
-
} else if (e.isFile()) {
|
|
6070
|
-
const st = statSync7(abs);
|
|
6071
|
-
out.push({
|
|
6072
|
-
absPath: abs,
|
|
6073
|
-
relativePath: rel.replace(/\\/g, "/"),
|
|
6074
|
-
size: st.size
|
|
6075
|
-
});
|
|
6076
|
-
}
|
|
6077
|
-
}
|
|
6078
|
-
}
|
|
6079
|
-
await walk(root, "");
|
|
6080
|
-
out.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
|
|
6081
|
-
return out;
|
|
6082
|
-
}
|
|
6083
|
-
async function readArtifactFile(absPath) {
|
|
6084
|
-
return readFile2(absPath);
|
|
6085
|
-
}
|
|
6086
|
-
function toMB(bytes) {
|
|
6087
|
-
return Math.round(bytes / (1024 * 1024) * 1e3) / 1e3;
|
|
6088
|
-
}
|
|
6089
|
-
var MIME = {
|
|
6090
|
-
".html": "text/html; charset=utf-8",
|
|
6091
|
-
".css": "text/css; charset=utf-8",
|
|
6092
|
-
".js": "application/javascript; charset=utf-8",
|
|
6093
|
-
".json": "application/json; charset=utf-8",
|
|
6094
|
-
".svg": "image/svg+xml",
|
|
6095
|
-
".png": "image/png",
|
|
6096
|
-
".jpg": "image/jpeg",
|
|
6097
|
-
".jpeg": "image/jpeg",
|
|
6098
|
-
".gif": "image/gif",
|
|
6099
|
-
".webp": "image/webp",
|
|
6100
|
-
".woff": "font/woff",
|
|
6101
|
-
".woff2": "font/woff2",
|
|
6102
|
-
".ttf": "font/ttf",
|
|
6103
|
-
".ico": "image/x-icon",
|
|
6104
|
-
".txt": "text/plain; charset=utf-8",
|
|
6105
|
-
".map": "application/json"
|
|
6106
|
-
};
|
|
6107
|
-
function detectMimeType(filePath) {
|
|
6108
|
-
const ext = path10.extname(filePath).toLowerCase();
|
|
6109
|
-
return MIME[ext] ?? "";
|
|
6110
|
-
}
|
|
6111
|
-
var MinioClient = class {
|
|
6112
|
-
inner;
|
|
6113
|
-
constructor(opts) {
|
|
6114
|
-
const endPoint = opts.endPoint.replace(/^https?:\/\//i, "").split("/")[0] ?? opts.endPoint;
|
|
6115
|
-
this.inner = new Minio.Client({
|
|
6116
|
-
endPoint,
|
|
6117
|
-
port: opts.port,
|
|
6118
|
-
useSSL: opts.useSSL,
|
|
6119
|
-
accessKey: opts.accessKey,
|
|
6120
|
-
secretKey: opts.secretKey
|
|
6121
|
-
});
|
|
6122
|
-
}
|
|
6123
|
-
async ensureBucket(bucket) {
|
|
6124
|
-
const exists = await this.inner.bucketExists(bucket);
|
|
6125
|
-
if (!exists) {
|
|
6126
|
-
await this.inner.makeBucket(bucket);
|
|
6127
|
-
}
|
|
6128
|
-
}
|
|
6129
|
-
async deleteObjectsByPrefix(bucket, prefix) {
|
|
6130
|
-
const objectsStream = this.inner.listObjectsV2(bucket, prefix, true);
|
|
6131
|
-
const keys = [];
|
|
6132
|
-
await new Promise((resolve5, reject) => {
|
|
6133
|
-
objectsStream.on("data", (obj) => {
|
|
6134
|
-
if (obj.name) {
|
|
6135
|
-
keys.push(obj.name);
|
|
6136
|
-
}
|
|
6137
|
-
});
|
|
6138
|
-
objectsStream.on("error", reject);
|
|
6139
|
-
objectsStream.on("end", resolve5);
|
|
6140
|
-
});
|
|
6141
|
-
const chunkSize = 500;
|
|
6142
|
-
for (let i = 0; i < keys.length; i += chunkSize) {
|
|
6143
|
-
const chunk = keys.slice(i, i + chunkSize);
|
|
6144
|
-
await this.inner.removeObjects(
|
|
6145
|
-
bucket,
|
|
6146
|
-
chunk.map((name) => name)
|
|
6147
|
-
);
|
|
6148
|
-
}
|
|
6149
|
-
}
|
|
6150
|
-
async putObject(bucket, objectKey, body, meta) {
|
|
6151
|
-
await this.inner.putObject(bucket, objectKey, body, body.length, meta);
|
|
6152
|
-
}
|
|
6153
|
-
/** 匿名可读当前桶全部对象(便于静态站点直链) */
|
|
6154
|
-
async setBucketPublicRead(bucket) {
|
|
6155
|
-
const policy = {
|
|
6156
|
-
Version: "2012-10-17",
|
|
6157
|
-
Statement: [
|
|
6158
|
-
{
|
|
6159
|
-
Effect: "Allow",
|
|
6160
|
-
Principal: { AWS: ["*"] },
|
|
6161
|
-
Action: ["s3:GetObject"],
|
|
6162
|
-
Resource: [`arn:aws:s3:::${bucket}/*`]
|
|
6163
|
-
}
|
|
6164
|
-
]
|
|
6165
|
-
};
|
|
6166
|
-
await this.inner.setBucketPolicy(bucket, JSON.stringify(policy));
|
|
6167
|
-
}
|
|
6168
|
-
};
|
|
6169
|
-
|
|
6170
|
-
// src/commands/deploy/frontend.ts
|
|
6171
6508
|
function resolveArtifactNamePrefix(cfg) {
|
|
6172
6509
|
const nameRaw = (cfg.name ?? "").trim();
|
|
6173
6510
|
if (!nameRaw) {
|
|
@@ -6341,6 +6678,13 @@ function registerDeploySftpCommands(program) {
|
|
|
6341
6678
|
async (opts) => {
|
|
6342
6679
|
const cfg = loadApmConfig({ configPath: opts.config });
|
|
6343
6680
|
const settings = resolveWisdomDeployFromApmConfig(cfg);
|
|
6681
|
+
const projectName = (cfg.name ?? "").trim();
|
|
6682
|
+
if (!projectName) {
|
|
6683
|
+
console.error(
|
|
6684
|
+
"\u8BF7\u5728 .apm/apm.config.json \u9876\u5C42\u914D\u7F6E name\uFF08\u4F5C\u4E3A\u90E8\u7F72\u4EA7\u7269\u9879\u76EE\u540D\uFF09"
|
|
6685
|
+
);
|
|
6686
|
+
process.exit(1);
|
|
6687
|
+
}
|
|
6344
6688
|
const root = path12.resolve(process.cwd(), opts.dir || "apps/web/dist");
|
|
6345
6689
|
if (!await isDirectoryPath(root)) {
|
|
6346
6690
|
console.error(`\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${root}`);
|
|
@@ -6350,7 +6694,8 @@ function registerDeploySftpCommands(program) {
|
|
|
6350
6694
|
const result = await runWisdomSftpDeploy({
|
|
6351
6695
|
localDir: root,
|
|
6352
6696
|
settings,
|
|
6353
|
-
extract: Boolean(opts.extract)
|
|
6697
|
+
extract: Boolean(opts.extract),
|
|
6698
|
+
projectName
|
|
6354
6699
|
});
|
|
6355
6700
|
console.log(JSON.stringify(result, null, 2));
|
|
6356
6701
|
} catch (err) {
|