ai-project-manage-cli 6.0.102 → 6.0.104
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 +2096 -1738
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2389,7 +2389,7 @@ async function runUpdateMessageStatus(options) {
|
|
|
2389
2389
|
|
|
2390
2390
|
// src/commands/connect.ts
|
|
2391
2391
|
import WebSocket from "ws";
|
|
2392
|
-
import { setTimeout as
|
|
2392
|
+
import { setTimeout as delay3 } from "node:timers/promises";
|
|
2393
2393
|
|
|
2394
2394
|
// src/ws/protocol.ts
|
|
2395
2395
|
function nonEmptyString(v) {
|
|
@@ -2511,8 +2511,67 @@ function validateAgentWsMessage(value, kind) {
|
|
|
2511
2511
|
return validateMessagePush(o);
|
|
2512
2512
|
}
|
|
2513
2513
|
|
|
2514
|
+
// src/commands/deploy/deploy-log-utils.ts
|
|
2515
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
2516
|
+
var DEPLOY_SPAWN_MAX_BUFFER_BYTES = 50 * 1024 * 1024;
|
|
2517
|
+
var DEPLOY_LOG_SYNC_MAX_CHUNK_BYTES = 4 * 1024 * 1024;
|
|
2518
|
+
var DEPLOY_COMPLETE_LOG_MAX_BYTES = 9 * 1024 * 1024;
|
|
2519
|
+
var DEPLOY_LOG_SYNC_MAX_ATTEMPTS = 3;
|
|
2520
|
+
async function retryDeployLogSync(fn, attempts = DEPLOY_LOG_SYNC_MAX_ATTEMPTS) {
|
|
2521
|
+
let lastError;
|
|
2522
|
+
for (let attempt = 1; attempt <= attempts; attempt += 1) {
|
|
2523
|
+
try {
|
|
2524
|
+
return await fn();
|
|
2525
|
+
} catch (error) {
|
|
2526
|
+
lastError = error;
|
|
2527
|
+
if (attempt < attempts) {
|
|
2528
|
+
await delay(1e3 * attempt);
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
2532
|
+
throw lastError;
|
|
2533
|
+
}
|
|
2534
|
+
function splitUtf8StringByMaxBytes(value, maxBytes) {
|
|
2535
|
+
if (maxBytes <= 0) {
|
|
2536
|
+
throw new Error("maxBytes must be positive");
|
|
2537
|
+
}
|
|
2538
|
+
const bytes = Buffer.from(value, "utf8");
|
|
2539
|
+
if (bytes.length <= maxBytes) {
|
|
2540
|
+
return [value];
|
|
2541
|
+
}
|
|
2542
|
+
const chunks = [];
|
|
2543
|
+
let offset = 0;
|
|
2544
|
+
while (offset < bytes.length) {
|
|
2545
|
+
let end = Math.min(offset + maxBytes, bytes.length);
|
|
2546
|
+
while (end > offset && (bytes[end] & 192) === 128) {
|
|
2547
|
+
end -= 1;
|
|
2548
|
+
}
|
|
2549
|
+
if (end <= offset) {
|
|
2550
|
+
end = Math.min(offset + maxBytes, bytes.length);
|
|
2551
|
+
}
|
|
2552
|
+
chunks.push(bytes.subarray(offset, end).toString("utf8"));
|
|
2553
|
+
offset = end;
|
|
2554
|
+
}
|
|
2555
|
+
return chunks;
|
|
2556
|
+
}
|
|
2557
|
+
function truncateDeployLogForComplete(log2) {
|
|
2558
|
+
const bytes = Buffer.from(log2, "utf8");
|
|
2559
|
+
if (bytes.length <= DEPLOY_COMPLETE_LOG_MAX_BYTES) {
|
|
2560
|
+
return { log: log2, truncated: false };
|
|
2561
|
+
}
|
|
2562
|
+
const tailBudget = Math.max(DEPLOY_COMPLETE_LOG_MAX_BYTES - 512, 1024);
|
|
2563
|
+
const prefix = `[apm] \u65E5\u5FD7\u8FC7\u957F\uFF08${Math.ceil(bytes.length / 1024)}KB\uFF09\uFF0C\u4EC5\u4FDD\u7559\u672B\u5C3E ${Math.floor(tailBudget / 1024)}KB
|
|
2564
|
+
`;
|
|
2565
|
+
let tail = bytes.subarray(bytes.length - tailBudget).toString("utf8");
|
|
2566
|
+
const brokenPrefix = tail.indexOf("\uFFFD");
|
|
2567
|
+
if (brokenPrefix >= 0) {
|
|
2568
|
+
const newline = tail.indexOf("\n", brokenPrefix);
|
|
2569
|
+
tail = newline >= 0 ? tail.slice(newline + 1) : tail.slice(brokenPrefix + 1);
|
|
2570
|
+
}
|
|
2571
|
+
return { log: prefix + tail, truncated: true };
|
|
2572
|
+
}
|
|
2573
|
+
|
|
2514
2574
|
// src/commands/deploy/deploy-execute.ts
|
|
2515
|
-
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
2516
2575
|
import path5 from "node:path";
|
|
2517
2576
|
|
|
2518
2577
|
// src/commands/deploy/internal/apm-config.ts
|
|
@@ -2819,33 +2878,17 @@ function posixBasename(p) {
|
|
|
2819
2878
|
}
|
|
2820
2879
|
|
|
2821
2880
|
// src/commands/deploy/internal/deploy-hints.ts
|
|
2822
|
-
function
|
|
2823
|
-
const configuredEnvs = Object.keys(deployCommands).filter(
|
|
2824
|
-
(key) => deployCommands[key]?.trim()
|
|
2825
|
-
);
|
|
2826
|
-
if (configuredEnvs.length > 0) {
|
|
2827
|
-
return [
|
|
2828
|
-
`[apm] \u65E0\u6CD5\u6267\u884C\u90E8\u7F72\uFF1Aapm.config.json \u4E2D\u672A\u914D\u7F6E deploy.${env}`,
|
|
2829
|
-
`[apm] \u5F53\u524D\u5DF2\u914D\u7F6E\u7684\u73AF\u5883: ${configuredEnvs.join(", ")}`
|
|
2830
|
-
];
|
|
2831
|
-
}
|
|
2881
|
+
function formatMissingWisdomDeployLines() {
|
|
2832
2882
|
return [
|
|
2833
|
-
"[apm] \u65E0\u6CD5\u6267\u884C\
|
|
2834
|
-
"[apm] \u90E8\u5206\u9879\u76EE\u4E0D\u652F\u6301\u6216\u672A\u542F\u7528\u81EA\u52A8\u5316\u90E8\u7F72\uFF0C\u5C5E\u6B63\u5E38\u60C5\u51B5\uFF0C\u53EF\u8DF3\u8FC7\u90E8\u7F72"
|
|
2883
|
+
"[apm] \u65E0\u6CD5\u6267\u884C apm deploy\uFF1A\u8BF7\u5728 apm.config.json \u4E2D\u914D\u7F6E wisdomDeploy\uFF08host\u3001remotePath\uFF09"
|
|
2835
2884
|
];
|
|
2836
2885
|
}
|
|
2837
2886
|
function formatWisdomFrontendBuildNotConfiguredLines(env, packageJsonPath) {
|
|
2838
2887
|
return [
|
|
2839
|
-
`[apm] \u65E0\u6CD5\u6267\u884C\
|
|
2888
|
+
`[apm] \u65E0\u6CD5\u6267\u884C\u524D\u7AEF\u90E8\u7F72\uFF1A${packageJsonPath} \u4E2D\u672A\u627E\u5230 build:${env} \u811A\u672C`,
|
|
2840
2889
|
"[apm] \u8BF7\u914D\u7F6E npm run build:test / build:online \u540E\u518D\u8BD5"
|
|
2841
2890
|
];
|
|
2842
2891
|
}
|
|
2843
|
-
function formatWisdomFrontendDeployNotConfiguredLines(env, packageJsonPath) {
|
|
2844
|
-
return [
|
|
2845
|
-
`[apm] \u65E0\u6CD5\u6267\u884C\u90E8\u7F72\uFF1A${packageJsonPath} \u4E2D\u672A\u627E\u5230 deploy:${env} \u811A\u672C`,
|
|
2846
|
-
"[apm] \u82E5\u672C\u9879\u76EE\u4E0D\u652F\u6301\u81EA\u52A8\u5316\u90E8\u7F72\uFF0C\u5C5E\u6B63\u5E38\u60C5\u51B5\uFF0C\u53EF\u8DF3\u8FC7\u90E8\u7F72"
|
|
2847
|
-
];
|
|
2848
|
-
}
|
|
2849
2892
|
|
|
2850
2893
|
// src/commands/deploy/deploy-errors.ts
|
|
2851
2894
|
var DeployExecutionError = class extends Error {
|
|
@@ -2859,31 +2902,10 @@ var DeployExecutionError = class extends Error {
|
|
|
2859
2902
|
}
|
|
2860
2903
|
};
|
|
2861
2904
|
|
|
2862
|
-
// src/commands/deploy/
|
|
2863
|
-
import {
|
|
2864
|
-
import
|
|
2865
|
-
import {
|
|
2866
|
-
|
|
2867
|
-
// src/commands/deploy/internal/wisdom-backend-deploy.ts
|
|
2868
|
-
import {
|
|
2869
|
-
existsSync as existsSync12,
|
|
2870
|
-
mkdirSync as mkdirSync5,
|
|
2871
|
-
readdirSync as readdirSync5,
|
|
2872
|
-
readFileSync as readFileSync11,
|
|
2873
|
-
statSync as statSync6,
|
|
2874
|
-
writeFileSync as writeFileSync10
|
|
2875
|
-
} from "node:fs";
|
|
2876
|
-
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
2877
|
-
import path3 from "node:path";
|
|
2878
|
-
import { Client as Client2 } from "ssh2";
|
|
2879
|
-
import JSZip2 from "jszip";
|
|
2880
|
-
import SftpClient2 from "ssh2-sftp-client";
|
|
2881
|
-
|
|
2882
|
-
// src/commands/deploy/internal/wisdom-sftp.ts
|
|
2883
|
-
import { readdir as readdir2, readFile as readFile3, unlink, writeFile } from "node:fs/promises";
|
|
2884
|
-
import path2 from "node:path";
|
|
2885
|
-
import JSZip from "jszip";
|
|
2886
|
-
import SftpClient from "ssh2-sftp-client";
|
|
2905
|
+
// src/commands/deploy/deploy-debug-log.ts
|
|
2906
|
+
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
2907
|
+
import { existsSync as existsSync14 } from "node:fs";
|
|
2908
|
+
import { dirname as dirname5, join as join16 } from "node:path";
|
|
2887
2909
|
|
|
2888
2910
|
// src/commands/deploy/internal/deploy-artifact-minio.ts
|
|
2889
2911
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
@@ -3135,1711 +3157,1974 @@ async function uploadDeployArtifactZip(options) {
|
|
|
3135
3157
|
};
|
|
3136
3158
|
}
|
|
3137
3159
|
|
|
3138
|
-
// src/commands/deploy/internal/
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3160
|
+
// src/commands/deploy/internal/deploy-shell-env.ts
|
|
3161
|
+
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
3162
|
+
import { dirname as dirname4 } from "node:path";
|
|
3163
|
+
|
|
3164
|
+
// src/commands/daemon.ts
|
|
3165
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
3166
|
+
import { setTimeout as delay2 } from "node:timers/promises";
|
|
3167
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync6, unlinkSync as unlinkSync2, writeFileSync as writeFileSync11 } from "fs";
|
|
3168
|
+
import { join as join15 } from "path";
|
|
3169
|
+
|
|
3170
|
+
// src/commands/connect-lock.ts
|
|
3171
|
+
import {
|
|
3172
|
+
existsSync as existsSync12,
|
|
3173
|
+
mkdirSync as mkdirSync5,
|
|
3174
|
+
readFileSync as readFileSync11,
|
|
3175
|
+
unlinkSync,
|
|
3176
|
+
writeFileSync as writeFileSync10
|
|
3177
|
+
} from "fs";
|
|
3178
|
+
import { join as join14 } from "path";
|
|
3179
|
+
var CONNECT_LOCK_PATH = join14(APM_CONFIG_DIR, "connect.lock");
|
|
3180
|
+
function isProcessAlive(pid) {
|
|
3181
|
+
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
3182
|
+
try {
|
|
3183
|
+
process.kill(pid, 0);
|
|
3184
|
+
return true;
|
|
3185
|
+
} catch {
|
|
3186
|
+
return false;
|
|
3152
3187
|
}
|
|
3153
3188
|
}
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
await addDirToZip(distDir, zip);
|
|
3158
|
-
const content = await zip.generateAsync({
|
|
3159
|
-
type: "nodebuffer",
|
|
3160
|
-
compression: "DEFLATE",
|
|
3161
|
-
compressionOptions: { level: 6 }
|
|
3162
|
-
});
|
|
3163
|
-
await writeFile(zipPath, content);
|
|
3164
|
-
const sizeMb = (content.length / 1024 / 1024).toFixed(2);
|
|
3165
|
-
console.error(`\u5DF2\u751F\u6210: ${zipPath} (${sizeMb} MB)`);
|
|
3166
|
-
return content.length;
|
|
3167
|
-
}
|
|
3168
|
-
var SFTP_UPLOAD_MAX_ATTEMPTS = 3;
|
|
3169
|
-
var SFTP_FAST_PUT_OPTIONS = {
|
|
3170
|
-
chunkSize: 64 * 1024,
|
|
3171
|
-
concurrency: 4
|
|
3172
|
-
};
|
|
3173
|
-
function buildSftpConnectOptions(settings) {
|
|
3174
|
-
return {
|
|
3175
|
-
host: settings.host,
|
|
3176
|
-
port: settings.port,
|
|
3177
|
-
username: settings.username,
|
|
3178
|
-
password: settings.password,
|
|
3179
|
-
readyTimeout: 3e4,
|
|
3180
|
-
tryKeyboard: true,
|
|
3181
|
-
keepaliveInterval: 1e4,
|
|
3182
|
-
keepaliveCountMax: 3
|
|
3183
|
-
};
|
|
3184
|
-
}
|
|
3185
|
-
async function sleep(ms) {
|
|
3186
|
-
await new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
3187
|
-
}
|
|
3188
|
-
async function uploadZipWithRetry(settings, localZip, remoteZipPath) {
|
|
3189
|
-
let lastError;
|
|
3190
|
-
for (let attempt = 1; attempt <= SFTP_UPLOAD_MAX_ATTEMPTS; attempt++) {
|
|
3191
|
-
const sftp = new SftpClient();
|
|
3192
|
-
try {
|
|
3193
|
-
if (attempt > 1) {
|
|
3194
|
-
console.error(
|
|
3195
|
-
`SFTP \u4E0A\u4F20\u91CD\u8BD5 (${attempt}/${SFTP_UPLOAD_MAX_ATTEMPTS})...`
|
|
3196
|
-
);
|
|
3197
|
-
}
|
|
3198
|
-
await sftp.connect(buildSftpConnectOptions(settings));
|
|
3199
|
-
await ensureRemoteDir(sftp, settings.remotePath);
|
|
3200
|
-
await sftp.fastPut(localZip, remoteZipPath, SFTP_FAST_PUT_OPTIONS);
|
|
3201
|
-
return sftp;
|
|
3202
|
-
} catch (err) {
|
|
3203
|
-
lastError = err;
|
|
3204
|
-
try {
|
|
3205
|
-
await sftp.end();
|
|
3206
|
-
} catch {
|
|
3207
|
-
}
|
|
3208
|
-
if (attempt < SFTP_UPLOAD_MAX_ATTEMPTS) {
|
|
3209
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
3210
|
-
const delaySec = attempt * 2;
|
|
3211
|
-
console.error(`SFTP \u4E0A\u4F20\u5931\u8D25 (${message})\uFF0C${delaySec}s \u540E\u91CD\u8BD5...`);
|
|
3212
|
-
await sleep(delaySec * 1e3);
|
|
3213
|
-
}
|
|
3214
|
-
}
|
|
3189
|
+
function sleepSync(ms) {
|
|
3190
|
+
const deadline = Date.now() + ms;
|
|
3191
|
+
while (Date.now() < deadline) {
|
|
3215
3192
|
}
|
|
3216
|
-
throw lastError;
|
|
3217
3193
|
}
|
|
3218
|
-
|
|
3219
|
-
const
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
} catch {
|
|
3194
|
+
function waitForPm2LockHandoff(timeoutMs = 5e3) {
|
|
3195
|
+
const deadline = Date.now() + timeoutMs;
|
|
3196
|
+
while (Date.now() < deadline) {
|
|
3197
|
+
pruneStaleConnectLock();
|
|
3198
|
+
const lock = readConnectLock();
|
|
3199
|
+
if (!lock || lock.mode !== "pm2" || lock.pid === process.pid || !isProcessAlive(lock.pid)) {
|
|
3200
|
+
return;
|
|
3226
3201
|
}
|
|
3202
|
+
sleepSync(100);
|
|
3227
3203
|
}
|
|
3228
3204
|
}
|
|
3229
|
-
function
|
|
3230
|
-
|
|
3231
|
-
client.exec(command, (err, stream) => {
|
|
3232
|
-
if (err) return reject(err);
|
|
3233
|
-
let stdout = "";
|
|
3234
|
-
let stderr = "";
|
|
3235
|
-
stream.on("close", (code) => {
|
|
3236
|
-
if (code !== 0) {
|
|
3237
|
-
reject(new Error(`\u8FDC\u7A0B\u547D\u4EE4\u5931\u8D25 (${code}): ${stderr || stdout}`));
|
|
3238
|
-
return;
|
|
3239
|
-
}
|
|
3240
|
-
resolve5(stdout);
|
|
3241
|
-
}).on("data", (data) => {
|
|
3242
|
-
stdout += data.toString();
|
|
3243
|
-
});
|
|
3244
|
-
stream.stderr.on("data", (data) => {
|
|
3245
|
-
stderr += data.toString();
|
|
3246
|
-
});
|
|
3247
|
-
});
|
|
3248
|
-
});
|
|
3249
|
-
}
|
|
3250
|
-
function shellSingleQuote(value) {
|
|
3251
|
-
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
3252
|
-
}
|
|
3253
|
-
function buildClearRemoteDirExceptZipCommand(target) {
|
|
3254
|
-
const normalized = target.replace(/\\/g, "/").replace(/\/$/, "");
|
|
3255
|
-
const quotedTarget = shellSingleQuote(normalized);
|
|
3256
|
-
const script = [
|
|
3257
|
-
`T=${quotedTarget}`,
|
|
3258
|
-
"S=$(mktemp -d)",
|
|
3259
|
-
'while IFS= read -r -d "" z; do r="${z#${T}/}"',
|
|
3260
|
-
'mkdir -p "${S}/$(dirname "$r")"',
|
|
3261
|
-
'mv "$z" "${S}/${r}"',
|
|
3262
|
-
'done < <(find "$T" -mindepth 1 -type f -iname "*.zip" -print0)',
|
|
3263
|
-
'rm -rf "${T}"/*',
|
|
3264
|
-
'while IFS= read -r -d "" r; do r="${r#./}"',
|
|
3265
|
-
'mkdir -p "${T}/$(dirname "$r")"',
|
|
3266
|
-
'mv "${S}/${r}" "${T}/${r}"',
|
|
3267
|
-
'done < <(cd "$S" 2>/dev/null && find . -type f -print0)',
|
|
3268
|
-
'rm -rf "$S"'
|
|
3269
|
-
].join("; ");
|
|
3270
|
-
return `bash -c ${shellSingleQuote(script)}`;
|
|
3271
|
-
}
|
|
3272
|
-
async function uploadAndMaybeExtract(settings, localZip, extract) {
|
|
3273
|
-
const remoteZipPath = `${settings.remotePath.replace(/\/$/, "")}/dist.zip`;
|
|
3274
|
-
console.error(
|
|
3275
|
-
`\u8FDE\u63A5 ${settings.username}@${settings.host}:${settings.port} ...`
|
|
3276
|
-
);
|
|
3277
|
-
const sftp = await uploadZipWithRetry(settings, localZip, remoteZipPath);
|
|
3205
|
+
function readConnectLock() {
|
|
3206
|
+
if (!existsSync12(CONNECT_LOCK_PATH)) return null;
|
|
3278
3207
|
try {
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
const clearCmd = buildClearRemoteDirExceptZipCommand(target);
|
|
3284
|
-
console.error(`\u8FDC\u7A0B\u6E05\u7406\u89E3\u538B\u76EE\u5F55: ${clearCmd}`);
|
|
3285
|
-
await execCommand(client, clearCmd);
|
|
3286
|
-
const unzipCmd = `unzip -o "${remoteZipPath}" -d "${target}"`;
|
|
3287
|
-
console.error(`\u8FDC\u7A0B\u89E3\u538B: ${unzipCmd}`);
|
|
3288
|
-
await execCommand(client, unzipCmd);
|
|
3289
|
-
console.error("\u8FDC\u7A0B\u89E3\u538B\u5B8C\u6210!");
|
|
3208
|
+
const raw = readFileSync11(CONNECT_LOCK_PATH, "utf8");
|
|
3209
|
+
const parsed = JSON.parse(raw);
|
|
3210
|
+
if (typeof parsed.pid !== "number" || parsed.mode !== "foreground" && parsed.mode !== "pm2" || typeof parsed.startedAt !== "string") {
|
|
3211
|
+
return null;
|
|
3290
3212
|
}
|
|
3291
|
-
|
|
3292
|
-
}
|
|
3293
|
-
|
|
3213
|
+
return parsed;
|
|
3214
|
+
} catch {
|
|
3215
|
+
return null;
|
|
3294
3216
|
}
|
|
3295
3217
|
}
|
|
3296
|
-
|
|
3297
|
-
const
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
let zipSizeBytes = 0;
|
|
3301
|
-
let artifactUploaded = false;
|
|
3218
|
+
function pruneStaleConnectLock() {
|
|
3219
|
+
const lock = readConnectLock();
|
|
3220
|
+
if (!lock) return;
|
|
3221
|
+
if (isProcessAlive(lock.pid)) return;
|
|
3302
3222
|
try {
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
const artifact = await uploadDeployArtifactZip({
|
|
3314
|
-
zipPath: resolvedZipPath,
|
|
3315
|
-
projectName: params.projectName,
|
|
3316
|
-
kind: "frontend",
|
|
3317
|
-
uploadWithoutRunId: packOnly && !resolveDeploymentRunIdFromEnv()
|
|
3318
|
-
});
|
|
3319
|
-
artifactUploaded = artifact !== null;
|
|
3320
|
-
if (packOnly && artifactUploaded) {
|
|
3321
|
-
console.error("\u6253\u5305\u5E76\u4E0A\u4F20 MinIO \u5B8C\u6210\uFF08\u672A\u4E0A\u4F20\u8FDC\u7A0B\u670D\u52A1\u5668\uFF09");
|
|
3223
|
+
unlinkSync(CONNECT_LOCK_PATH);
|
|
3224
|
+
} catch {
|
|
3225
|
+
}
|
|
3226
|
+
}
|
|
3227
|
+
function acquireConnectLock(mode) {
|
|
3228
|
+
pruneStaleConnectLock();
|
|
3229
|
+
const existing = readConnectLock();
|
|
3230
|
+
if (existing && isProcessAlive(existing.pid)) {
|
|
3231
|
+
if (existing.pid === process.pid) {
|
|
3232
|
+
return;
|
|
3322
3233
|
}
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
console.error(
|
|
3327
|
-
|
|
3234
|
+
if (mode === "pm2" && existing.mode === "pm2") {
|
|
3235
|
+
forceReleaseConnectLock();
|
|
3236
|
+
} else {
|
|
3237
|
+
console.error(
|
|
3238
|
+
`[apm] \u5DF2\u6709 apm connect \u5728\u8FD0\u884C (pid=${existing.pid}, mode=${existing.mode})`
|
|
3239
|
+
);
|
|
3240
|
+
process.exit(1);
|
|
3328
3241
|
}
|
|
3329
3242
|
}
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
zipSizeBytes,
|
|
3336
|
-
extracted: packOnly ? false : params.extract,
|
|
3337
|
-
packOnly,
|
|
3338
|
-
artifactUploaded
|
|
3243
|
+
mkdirSync5(APM_CONFIG_DIR, { recursive: true });
|
|
3244
|
+
const lock = {
|
|
3245
|
+
pid: process.pid,
|
|
3246
|
+
mode,
|
|
3247
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3339
3248
|
};
|
|
3249
|
+
writeFileSync10(
|
|
3250
|
+
CONNECT_LOCK_PATH,
|
|
3251
|
+
JSON.stringify(lock, null, 2) + "\n",
|
|
3252
|
+
"utf8"
|
|
3253
|
+
);
|
|
3254
|
+
}
|
|
3255
|
+
function releaseConnectLock() {
|
|
3256
|
+
const lock = readConnectLock();
|
|
3257
|
+
if (lock?.pid !== process.pid) return;
|
|
3258
|
+
try {
|
|
3259
|
+
unlinkSync(CONNECT_LOCK_PATH);
|
|
3260
|
+
} catch {
|
|
3261
|
+
}
|
|
3262
|
+
}
|
|
3263
|
+
function forceReleaseConnectLock() {
|
|
3264
|
+
try {
|
|
3265
|
+
if (existsSync12(CONNECT_LOCK_PATH)) {
|
|
3266
|
+
unlinkSync(CONNECT_LOCK_PATH);
|
|
3267
|
+
}
|
|
3268
|
+
} catch {
|
|
3269
|
+
}
|
|
3340
3270
|
}
|
|
3341
3271
|
|
|
3342
|
-
// src/commands/
|
|
3343
|
-
var
|
|
3344
|
-
var
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3272
|
+
// src/commands/daemon.ts
|
|
3273
|
+
var PM2_APP_NAME = "apm-connect";
|
|
3274
|
+
var PM2_ECOSYSTEM_PATH = join15(
|
|
3275
|
+
APM_CONFIG_DIR,
|
|
3276
|
+
"connect.ecosystem.config.cjs"
|
|
3277
|
+
);
|
|
3278
|
+
var PM2_CONNECT_ENTRY_PATH = join15(APM_CONFIG_DIR, "connect.entry.cjs");
|
|
3279
|
+
var PM2_CONNECT_LAUNCH_PATH = join15(
|
|
3280
|
+
APM_CONFIG_DIR,
|
|
3281
|
+
"connect.launch.json"
|
|
3282
|
+
);
|
|
3283
|
+
var LEGACY_PM2_ECOSYSTEM_PATH = join15(
|
|
3284
|
+
APM_CONFIG_DIR,
|
|
3285
|
+
"connect.ecosystem.cjs"
|
|
3286
|
+
);
|
|
3287
|
+
var LEGACY_PM2_APP_NAMES = ["connect.ecosystem"];
|
|
3288
|
+
var CONNECT_ENTRY_SCRIPT = `'use strict';
|
|
3289
|
+
const { spawnSync } = require('node:child_process');
|
|
3290
|
+
const { readFileSync } = require('node:fs');
|
|
3291
|
+
const { join } = require('node:path');
|
|
3292
|
+
|
|
3293
|
+
const launchConfigPath = join(__dirname, 'connect.launch.json');
|
|
3294
|
+
let config;
|
|
3295
|
+
try {
|
|
3296
|
+
config = JSON.parse(readFileSync(launchConfigPath, 'utf8'));
|
|
3297
|
+
} catch (err) {
|
|
3298
|
+
console.error('[apm] \u65E0\u6CD5\u8BFB\u53D6 connect.launch.json:', err instanceof Error ? err.message : err);
|
|
3299
|
+
process.exit(1);
|
|
3352
3300
|
}
|
|
3353
|
-
|
|
3354
|
-
|
|
3301
|
+
|
|
3302
|
+
const nodeArgs = [config.apmScript, ...(config.connectArgs || [])];
|
|
3303
|
+
const childEnv = {
|
|
3304
|
+
...process.env,
|
|
3305
|
+
...(config.env || {}),
|
|
3306
|
+
APM_CONNECT_UNDER_PM2: '1',
|
|
3307
|
+
};
|
|
3308
|
+
|
|
3309
|
+
const result = spawnSync(config.nodePath, nodeArgs, {
|
|
3310
|
+
cwd: config.cwd || undefined,
|
|
3311
|
+
env: childEnv,
|
|
3312
|
+
stdio: 'inherit',
|
|
3313
|
+
windowsHide: true,
|
|
3314
|
+
});
|
|
3315
|
+
|
|
3316
|
+
if (result.error) {
|
|
3317
|
+
console.error('[apm] connect \u542F\u52A8\u5931\u8D25:', result.error.message);
|
|
3355
3318
|
process.exit(1);
|
|
3356
3319
|
}
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3320
|
+
process.exit(result.status ?? 0);
|
|
3321
|
+
`;
|
|
3322
|
+
function resolveConnectArgs(server) {
|
|
3323
|
+
const args = ["connect"];
|
|
3324
|
+
const trimmed = server?.trim();
|
|
3325
|
+
if (trimmed) {
|
|
3326
|
+
args.push("--server", trimmed.replace(/\/+$/, ""));
|
|
3327
|
+
}
|
|
3328
|
+
return args;
|
|
3360
3329
|
}
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3330
|
+
var PM2_LAUNCH_ENV_KEYS = [
|
|
3331
|
+
"PATH",
|
|
3332
|
+
"HOME",
|
|
3333
|
+
"USER",
|
|
3334
|
+
"SHELL",
|
|
3335
|
+
"LANG",
|
|
3336
|
+
"LC_ALL",
|
|
3337
|
+
"LC_CTYPE",
|
|
3338
|
+
"NVM_DIR",
|
|
3339
|
+
"NVM_BIN",
|
|
3340
|
+
"NVM_INC",
|
|
3341
|
+
"FNM_DIR",
|
|
3342
|
+
"VOLTA_HOME",
|
|
3343
|
+
"PNPM_HOME",
|
|
3344
|
+
"npm_config_prefix",
|
|
3345
|
+
"NODE_HOME"
|
|
3346
|
+
];
|
|
3347
|
+
function collectPm2LaunchEnv() {
|
|
3348
|
+
const env = {};
|
|
3349
|
+
for (const key of PM2_LAUNCH_ENV_KEYS) {
|
|
3350
|
+
const value = process.env[key]?.trim();
|
|
3351
|
+
if (value) {
|
|
3352
|
+
env[key] = value;
|
|
3353
|
+
}
|
|
3364
3354
|
}
|
|
3365
|
-
return
|
|
3355
|
+
return env;
|
|
3366
3356
|
}
|
|
3367
|
-
function
|
|
3357
|
+
function buildConnectPm2Ecosystem(options) {
|
|
3358
|
+
const env = {};
|
|
3359
|
+
const baseUrl = options.baseUrl?.trim().replace(/\/+$/, "");
|
|
3360
|
+
if (baseUrl) {
|
|
3361
|
+
env.AI_PM_SERVER = baseUrl;
|
|
3362
|
+
}
|
|
3363
|
+
const app = {
|
|
3364
|
+
name: PM2_APP_NAME,
|
|
3365
|
+
script: options.entryScript,
|
|
3366
|
+
cwd: APM_CONFIG_DIR,
|
|
3367
|
+
autorestart: true,
|
|
3368
|
+
min_uptime: "10s",
|
|
3369
|
+
max_restarts: 10,
|
|
3370
|
+
restart_delay: 3e3,
|
|
3371
|
+
exp_backoff_restart_delay: 1e3,
|
|
3372
|
+
max_memory_restart: "2G",
|
|
3373
|
+
kill_timeout: 5e3,
|
|
3374
|
+
shutdown_with_message: true,
|
|
3375
|
+
instances: 1,
|
|
3376
|
+
exec_mode: "fork",
|
|
3377
|
+
env
|
|
3378
|
+
};
|
|
3368
3379
|
if (process.platform === "win32") {
|
|
3369
|
-
|
|
3380
|
+
app.windowsHide = true;
|
|
3370
3381
|
}
|
|
3371
|
-
return
|
|
3382
|
+
return {
|
|
3383
|
+
apps: [app]
|
|
3384
|
+
};
|
|
3372
3385
|
}
|
|
3373
|
-
function
|
|
3374
|
-
return
|
|
3386
|
+
function formatConnectPm2EcosystemFile(ecosystem) {
|
|
3387
|
+
return `module.exports = ${JSON.stringify(ecosystem, null, 2)};
|
|
3388
|
+
`;
|
|
3375
3389
|
}
|
|
3376
|
-
|
|
3377
|
-
|
|
3390
|
+
var useNpmShell2 = process.platform === "win32";
|
|
3391
|
+
function runNpm2(args, options = {}) {
|
|
3392
|
+
return spawnSync2(useNpmShell2 ? "npm.cmd" : "npm", args, {
|
|
3393
|
+
...options,
|
|
3394
|
+
shell: useNpmShell2
|
|
3395
|
+
});
|
|
3378
3396
|
}
|
|
3379
|
-
function
|
|
3380
|
-
|
|
3397
|
+
function resolveNpmGlobalBin() {
|
|
3398
|
+
const binResult = runNpm2(["bin", "-g"], {
|
|
3399
|
+
encoding: "utf8",
|
|
3400
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
3401
|
+
});
|
|
3402
|
+
if (binResult.status !== 0) return null;
|
|
3403
|
+
return binResult.stdout?.toString().trim() || null;
|
|
3381
3404
|
}
|
|
3382
|
-
function
|
|
3383
|
-
|
|
3405
|
+
function resolvePm2FromNpmRoot() {
|
|
3406
|
+
const rootResult = runNpm2(["root", "-g"], {
|
|
3407
|
+
encoding: "utf8",
|
|
3408
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
3409
|
+
});
|
|
3410
|
+
if (rootResult.status !== 0) return null;
|
|
3411
|
+
const root = rootResult.stdout?.toString().trim();
|
|
3412
|
+
if (!root) return null;
|
|
3413
|
+
for (const rel of ["pm2/bin/pm2", "pm2/bin/pm2.js"]) {
|
|
3414
|
+
const candidate = join15(root, ...rel.split("/"));
|
|
3415
|
+
if (existsSync13(candidate)) {
|
|
3416
|
+
return candidate;
|
|
3417
|
+
}
|
|
3418
|
+
}
|
|
3419
|
+
return null;
|
|
3384
3420
|
}
|
|
3385
|
-
function
|
|
3386
|
-
|
|
3387
|
-
return { size: stat2.size, mtime: stat2.mtimeMs / 1e3 };
|
|
3421
|
+
function isPm2NodeScript(path13) {
|
|
3422
|
+
return path13.endsWith(".js") || /[\\/]pm2[\\/]bin[\\/]pm2$/.test(path13);
|
|
3388
3423
|
}
|
|
3389
|
-
function
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3424
|
+
function buildPm2SpawnTarget(binPath) {
|
|
3425
|
+
if (isPm2NodeScript(binPath)) {
|
|
3426
|
+
return {
|
|
3427
|
+
command: process.execPath,
|
|
3428
|
+
prefixArgs: [binPath],
|
|
3429
|
+
displayPath: binPath
|
|
3430
|
+
};
|
|
3393
3431
|
}
|
|
3394
|
-
return
|
|
3432
|
+
return {
|
|
3433
|
+
command: binPath,
|
|
3434
|
+
prefixArgs: [],
|
|
3435
|
+
displayPath: binPath
|
|
3436
|
+
};
|
|
3395
3437
|
}
|
|
3396
|
-
function
|
|
3397
|
-
const
|
|
3398
|
-
|
|
3399
|
-
|
|
3438
|
+
function spawnPm2Target(target, args, options = {}) {
|
|
3439
|
+
const useShell = useNpmShell2 && target.prefixArgs.length === 0;
|
|
3440
|
+
return spawnSync2(target.command, [...target.prefixArgs, ...args], {
|
|
3441
|
+
encoding: "utf8",
|
|
3442
|
+
env: process.env,
|
|
3443
|
+
shell: useShell,
|
|
3444
|
+
windowsHide: useNpmShell2,
|
|
3445
|
+
...options
|
|
3446
|
+
});
|
|
3400
3447
|
}
|
|
3401
|
-
function
|
|
3402
|
-
return
|
|
3448
|
+
function spawnPm2At(binPath, args, options = {}) {
|
|
3449
|
+
return spawnPm2Target(buildPm2SpawnTarget(binPath), args, options);
|
|
3403
3450
|
}
|
|
3404
|
-
function
|
|
3405
|
-
if (!
|
|
3406
|
-
return
|
|
3407
|
-
}
|
|
3408
|
-
const localSize = statSync6(localPath).size;
|
|
3409
|
-
const remoteSize = remoteAttr.size;
|
|
3410
|
-
if (localSize !== remoteSize) {
|
|
3411
|
-
return [true, `\u5927\u5C0F\u53D8\u5316 ${remoteSize} -> ${localSize}`];
|
|
3451
|
+
function verifyPm2Bin(pm2Bin) {
|
|
3452
|
+
if (!pm2Bin.trim() || !existsSync13(pm2Bin)) {
|
|
3453
|
+
return false;
|
|
3412
3454
|
}
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3455
|
+
const result = spawnPm2At(pm2Bin, ["--version"], {
|
|
3456
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
3457
|
+
});
|
|
3458
|
+
return !result.error && result.status === 0;
|
|
3459
|
+
}
|
|
3460
|
+
function collectPm2Candidates() {
|
|
3461
|
+
const candidates = [];
|
|
3462
|
+
const globalBin = resolveNpmGlobalBin();
|
|
3463
|
+
if (globalBin) {
|
|
3464
|
+
if (useNpmShell2) {
|
|
3465
|
+
candidates.push(join15(globalBin, "pm2.cmd"));
|
|
3466
|
+
candidates.push(join15(globalBin, "pm2"));
|
|
3467
|
+
} else {
|
|
3468
|
+
candidates.push(join15(globalBin, "pm2"));
|
|
3422
3469
|
}
|
|
3423
|
-
|
|
3424
|
-
|
|
3470
|
+
}
|
|
3471
|
+
const fromRoot = resolvePm2FromNpmRoot();
|
|
3472
|
+
if (fromRoot) {
|
|
3473
|
+
candidates.push(fromRoot);
|
|
3474
|
+
}
|
|
3475
|
+
const whichResult = spawnSync2(useNpmShell2 ? "where" : "which", ["pm2"], {
|
|
3476
|
+
encoding: "utf8",
|
|
3477
|
+
shell: useNpmShell2,
|
|
3478
|
+
env: process.env,
|
|
3479
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
3480
|
+
});
|
|
3481
|
+
if (whichResult.status === 0) {
|
|
3482
|
+
const fromPath = whichResult.stdout?.toString().trim().split(/\r?\n/).map((line) => line.trim()).filter(Boolean) ?? [];
|
|
3483
|
+
if (useNpmShell2) {
|
|
3484
|
+
fromPath.sort((a, b) => {
|
|
3485
|
+
const aCmd = a.toLowerCase().endsWith(".cmd") ? 0 : 1;
|
|
3486
|
+
const bCmd = b.toLowerCase().endsWith(".cmd") ? 0 : 1;
|
|
3487
|
+
return aCmd - bCmd;
|
|
3488
|
+
});
|
|
3425
3489
|
}
|
|
3490
|
+
candidates.push(...fromPath);
|
|
3426
3491
|
}
|
|
3427
|
-
return
|
|
3492
|
+
return candidates;
|
|
3428
3493
|
}
|
|
3429
|
-
function
|
|
3430
|
-
const
|
|
3431
|
-
const
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
remoteAttr,
|
|
3438
|
-
manifest,
|
|
3439
|
-
projectRoot
|
|
3440
|
-
);
|
|
3441
|
-
if (shouldUpload) {
|
|
3442
|
-
entries.push({ path: jarPath, arcname: jarName, reason });
|
|
3494
|
+
function findGlobalPm2() {
|
|
3495
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3496
|
+
for (const candidate of collectPm2Candidates()) {
|
|
3497
|
+
const key = useNpmShell2 ? candidate.toLowerCase() : candidate;
|
|
3498
|
+
if (seen.has(key)) continue;
|
|
3499
|
+
seen.add(key);
|
|
3500
|
+
if (verifyPm2Bin(candidate)) {
|
|
3501
|
+
return candidate;
|
|
3443
3502
|
}
|
|
3444
3503
|
}
|
|
3445
|
-
return
|
|
3504
|
+
return null;
|
|
3446
3505
|
}
|
|
3447
|
-
function
|
|
3448
|
-
|
|
3449
|
-
|
|
3506
|
+
function installGlobalPm2() {
|
|
3507
|
+
console.log("[apm] \u672A\u68C0\u6D4B\u5230\u5168\u5C40 pm2\uFF0C\u6B63\u5728\u5B89\u88C5 npm install -g pm2 \u2026");
|
|
3508
|
+
const result = runNpm2(["install", "-g", "pm2"], {
|
|
3509
|
+
encoding: "utf8",
|
|
3510
|
+
stdio: "inherit"
|
|
3511
|
+
});
|
|
3512
|
+
if (result.status !== 0) {
|
|
3513
|
+
console.error("[apm] \u5B89\u88C5 pm2 \u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u6267\u884C: npm install -g pm2");
|
|
3514
|
+
process.exit(result.status ?? 1);
|
|
3450
3515
|
}
|
|
3451
|
-
return manifest;
|
|
3452
3516
|
}
|
|
3453
|
-
|
|
3454
|
-
const
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
for (const entry of entries) {
|
|
3460
|
-
const content = readFileSync11(entry.path);
|
|
3461
|
-
zip.file(entry.arcname, content);
|
|
3462
|
-
log(` \u6253\u5305: ${entry.arcname} (${entry.reason})`);
|
|
3517
|
+
function readPm2Version(pm2Bin) {
|
|
3518
|
+
const result = spawnPm2At(pm2Bin, ["--version"], {
|
|
3519
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
3520
|
+
});
|
|
3521
|
+
if (result.error || result.status !== 0) {
|
|
3522
|
+
return null;
|
|
3463
3523
|
}
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3524
|
+
return result.stdout?.toString().trim() || null;
|
|
3525
|
+
}
|
|
3526
|
+
function logPm2Ready(pm2Bin, installed2) {
|
|
3527
|
+
const version = readPm2Version(pm2Bin);
|
|
3528
|
+
const versionSuffix = version ? ` ${version}` : "";
|
|
3529
|
+
if (installed2) {
|
|
3530
|
+
console.log(`[apm] \u5168\u5C40 pm2 \u5DF2\u5B89\u88C5${versionSuffix}: ${pm2Bin}`);
|
|
3531
|
+
} else {
|
|
3532
|
+
console.log(`[apm] \u5DF2\u68C0\u6D4B\u5230\u5168\u5C40 pm2${versionSuffix}: ${pm2Bin}`);
|
|
3533
|
+
}
|
|
3534
|
+
}
|
|
3535
|
+
function isPm2DaemonOutOfDate(output) {
|
|
3536
|
+
return /In-memory PM2 is out-of-date/i.test(output);
|
|
3537
|
+
}
|
|
3538
|
+
function ensurePm2DaemonUpdated(pm2Bin) {
|
|
3539
|
+
const probe = spawnPm2At(pm2Bin, ["jlist"], {
|
|
3540
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
3468
3541
|
});
|
|
3469
|
-
|
|
3470
|
-
|
|
3542
|
+
const combined = `${probe.stdout ?? ""}
|
|
3543
|
+
${probe.stderr ?? ""}`;
|
|
3544
|
+
if (!isPm2DaemonOutOfDate(combined)) {
|
|
3545
|
+
return;
|
|
3546
|
+
}
|
|
3547
|
+
console.log("[apm] \u68C0\u6D4B\u5230 PM2 \u5185\u5B58\u7248\u672C\u4E0E\u672C\u5730\u4E0D\u4E00\u81F4\uFF0C\u6B63\u5728\u6267\u884C pm2 update \u2026");
|
|
3548
|
+
const update = spawnPm2At(pm2Bin, ["update"], {
|
|
3549
|
+
stdio: "inherit"
|
|
3550
|
+
});
|
|
3551
|
+
if (update.error || update.status !== 0) {
|
|
3552
|
+
console.error("[apm] pm2 update \u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u6267\u884C: pm2 update");
|
|
3553
|
+
}
|
|
3471
3554
|
}
|
|
3472
|
-
function
|
|
3473
|
-
const
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
shell: true
|
|
3479
|
-
});
|
|
3480
|
-
if (result.status === 0 && result.stdout.trim()) {
|
|
3481
|
-
return result.stdout.trim().split(/\r?\n/)[0].trim();
|
|
3555
|
+
function ensureGlobalPm2(options) {
|
|
3556
|
+
const existing = findGlobalPm2();
|
|
3557
|
+
if (existing) {
|
|
3558
|
+
ensurePm2DaemonUpdated(existing);
|
|
3559
|
+
if (!options?.quiet) {
|
|
3560
|
+
logPm2Ready(existing, false);
|
|
3482
3561
|
}
|
|
3562
|
+
return existing;
|
|
3483
3563
|
}
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
"clean",
|
|
3492
|
-
"package",
|
|
3493
|
-
`-P${MAVEN_PROFILE}`,
|
|
3494
|
-
formatMavenLocalRepoArg(mavenRepo),
|
|
3495
|
-
"-DskipTests"
|
|
3496
|
-
].join(" ");
|
|
3497
|
-
log("\u5F00\u59CB Maven \u6784\u5EFA...");
|
|
3498
|
-
if (repoSource) {
|
|
3499
|
-
log(
|
|
3500
|
-
`Maven \u672C\u5730\u4ED3\u5E93: ${mavenRepo} (\u6765\u6E90: ${repoSource.source}/${repoSource.sourceDetail})`
|
|
3564
|
+
installGlobalPm2();
|
|
3565
|
+
const installed2 = findGlobalPm2();
|
|
3566
|
+
if (!installed2) {
|
|
3567
|
+
const globalBin = resolveNpmGlobalBin();
|
|
3568
|
+
const moduleEntry = resolvePm2FromNpmRoot();
|
|
3569
|
+
console.error(
|
|
3570
|
+
"[apm] \u5B89\u88C5 pm2 \u540E\u4ECD\u65E0\u6CD5\u627E\u5230\u53EF\u6267\u884C\u6587\u4EF6\uFF0C\u8BF7\u624B\u52A8\u6267\u884C: npm install -g pm2"
|
|
3501
3571
|
);
|
|
3502
|
-
|
|
3503
|
-
|
|
3572
|
+
if (globalBin) {
|
|
3573
|
+
console.error(`[apm] npm \u5168\u5C40 bin: ${globalBin}`);
|
|
3574
|
+
}
|
|
3575
|
+
if (moduleEntry) {
|
|
3576
|
+
console.error(`[apm] \u5DF2\u68C0\u6D4B\u5230 pm2 \u6A21\u5757: ${moduleEntry}`);
|
|
3577
|
+
console.error(
|
|
3578
|
+
"[apm] \u82E5 pm2 --version \u53EF\u7528\uFF0C\u8BF7\u68C0\u67E5 Node/npm \u5168\u5C40\u5B89\u88C5\u6743\u9650\u6216 PATH"
|
|
3579
|
+
);
|
|
3580
|
+
}
|
|
3581
|
+
process.exit(1);
|
|
3504
3582
|
}
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
stdio: "inherit",
|
|
3509
|
-
shell: true,
|
|
3510
|
-
env: process.env
|
|
3511
|
-
});
|
|
3512
|
-
if (result.status !== 0) {
|
|
3513
|
-
fail(`Maven \u6784\u5EFA\u5931\u8D25\uFF0C\u9000\u51FA\u7801: ${result.status ?? 1}`);
|
|
3583
|
+
ensurePm2DaemonUpdated(installed2);
|
|
3584
|
+
if (!options?.quiet) {
|
|
3585
|
+
logPm2Ready(installed2, true);
|
|
3514
3586
|
}
|
|
3587
|
+
return installed2;
|
|
3515
3588
|
}
|
|
3516
|
-
function
|
|
3517
|
-
const
|
|
3518
|
-
if (
|
|
3519
|
-
|
|
3589
|
+
function resolveApmEntryPath(entryArg = process.argv[1]) {
|
|
3590
|
+
const fromArgv = entryArg?.trim();
|
|
3591
|
+
if (fromArgv && existsSync13(fromArgv)) {
|
|
3592
|
+
return fromArgv;
|
|
3520
3593
|
}
|
|
3521
|
-
const
|
|
3522
|
-
|
|
3523
|
-
|
|
3594
|
+
const npmResult = spawnSync2(useNpmShell2 ? "npm.cmd" : "npm", ["root", "-g"], {
|
|
3595
|
+
encoding: "utf8",
|
|
3596
|
+
shell: useNpmShell2,
|
|
3597
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
3598
|
+
});
|
|
3599
|
+
if (npmResult.status === 0) {
|
|
3600
|
+
const globalRoot = npmResult.stdout?.toString().trim();
|
|
3601
|
+
if (globalRoot) {
|
|
3602
|
+
const candidate = join15(globalRoot, CLI_PACKAGE_NAME, "dist", "index.js");
|
|
3603
|
+
if (existsSync13(candidate)) {
|
|
3604
|
+
return candidate;
|
|
3605
|
+
}
|
|
3606
|
+
}
|
|
3524
3607
|
}
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
fail(`lib \u76EE\u5F55\u4E0B\u6CA1\u6709\u4F9D\u8D56 JAR: ${libDir}`);
|
|
3608
|
+
if (fromArgv) {
|
|
3609
|
+
return fromArgv;
|
|
3528
3610
|
}
|
|
3529
|
-
|
|
3530
|
-
|
|
3611
|
+
console.error("[apm] \u65E0\u6CD5\u89E3\u6790 apm \u5165\u53E3\u8DEF\u5F84");
|
|
3612
|
+
process.exit(1);
|
|
3531
3613
|
}
|
|
3532
|
-
function
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
fail(`\u6784\u5EFA\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728: ${targetDir}`);
|
|
3614
|
+
function isRunningUnderPm2() {
|
|
3615
|
+
if (process.env.APM_CONNECT_UNDER_PM2 === "1") {
|
|
3616
|
+
return true;
|
|
3536
3617
|
}
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
fail(`target \u76EE\u5F55\u4E0B\u6CA1\u6709\u4E3B JAR: ${targetDir}`);
|
|
3618
|
+
if (process.env.pm_id === void 0) {
|
|
3619
|
+
return false;
|
|
3540
3620
|
}
|
|
3541
|
-
const
|
|
3542
|
-
|
|
3543
|
-
return mainJar;
|
|
3621
|
+
const name = process.env.name;
|
|
3622
|
+
return name === PM2_APP_NAME || name !== void 0 && LEGACY_PM2_APP_NAMES.includes(name);
|
|
3544
3623
|
}
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
host: config.host,
|
|
3551
|
-
port: config.port,
|
|
3552
|
-
username: config.username,
|
|
3553
|
-
password: config.password,
|
|
3554
|
-
readyTimeout: 3e4,
|
|
3555
|
-
tryKeyboard: true
|
|
3556
|
-
});
|
|
3557
|
-
});
|
|
3558
|
-
const sftp = new SftpClient2();
|
|
3559
|
-
await sftp.connect({
|
|
3560
|
-
host: config.host,
|
|
3561
|
-
port: config.port,
|
|
3562
|
-
username: config.username,
|
|
3563
|
-
password: config.password,
|
|
3564
|
-
readyTimeout: 3e4,
|
|
3565
|
-
tryKeyboard: true
|
|
3566
|
-
});
|
|
3567
|
-
return { client, sftp };
|
|
3624
|
+
function isConnectPm2Process(app) {
|
|
3625
|
+
if (app.name === PM2_APP_NAME) {
|
|
3626
|
+
return true;
|
|
3627
|
+
}
|
|
3628
|
+
return app.name !== void 0 && LEGACY_PM2_APP_NAMES.includes(app.name);
|
|
3568
3629
|
}
|
|
3569
|
-
|
|
3630
|
+
function listPm2Processes() {
|
|
3570
3631
|
try {
|
|
3571
|
-
|
|
3632
|
+
const raw = runPm2Json(["jlist"]);
|
|
3633
|
+
return JSON.parse(raw);
|
|
3572
3634
|
} catch {
|
|
3635
|
+
return [];
|
|
3573
3636
|
}
|
|
3574
|
-
conn.client.end();
|
|
3575
3637
|
}
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3638
|
+
function findPm2ConnectProcess() {
|
|
3639
|
+
return listPm2Processes().find(isConnectPm2Process) ?? null;
|
|
3640
|
+
}
|
|
3641
|
+
function resolvePm2ConnectName(app) {
|
|
3642
|
+
return app?.name ?? PM2_APP_NAME;
|
|
3643
|
+
}
|
|
3644
|
+
function deletePm2AppIfExists(name) {
|
|
3645
|
+
const pm2Bin = findGlobalPm2();
|
|
3646
|
+
if (!pm2Bin) {
|
|
3647
|
+
return;
|
|
3586
3648
|
}
|
|
3587
|
-
|
|
3649
|
+
ensurePm2DaemonUpdated(pm2Bin);
|
|
3650
|
+
spawnPm2At(pm2Bin, ["delete", name], {
|
|
3651
|
+
stdio: "ignore"
|
|
3652
|
+
});
|
|
3588
3653
|
}
|
|
3589
|
-
|
|
3590
|
-
const
|
|
3591
|
-
const
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
fail(`\u66F4\u65B0\u5305\u4E0A\u4F20\u5931\u8D25: ${err instanceof Error ? err.message : err}`);
|
|
3654
|
+
function removePm2ConnectProcesses() {
|
|
3655
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3656
|
+
for (const app of listPm2Processes()) {
|
|
3657
|
+
if (!isConnectPm2Process(app) || !app.name || seen.has(app.name)) {
|
|
3658
|
+
continue;
|
|
3659
|
+
}
|
|
3660
|
+
seen.add(app.name);
|
|
3661
|
+
deletePm2AppIfExists(app.name);
|
|
3598
3662
|
}
|
|
3599
|
-
|
|
3663
|
+
for (const legacyName of LEGACY_PM2_APP_NAMES) {
|
|
3664
|
+
deletePm2AppIfExists(legacyName);
|
|
3665
|
+
}
|
|
3666
|
+
deletePm2AppIfExists(PM2_APP_NAME);
|
|
3600
3667
|
}
|
|
3601
|
-
|
|
3602
|
-
const
|
|
3603
|
-
const
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
}
|
|
3610
|
-
|
|
3668
|
+
function runPm2(args, options) {
|
|
3669
|
+
const pm2Bin = ensureGlobalPm2({ quiet: true });
|
|
3670
|
+
const result = spawnPm2At(pm2Bin, args, {
|
|
3671
|
+
stdio: options?.inherit ? "inherit" : ["ignore", "pipe", "pipe"]
|
|
3672
|
+
});
|
|
3673
|
+
if (result.error) {
|
|
3674
|
+
console.error("[apm] \u6267\u884C pm2 \u5931\u8D25:", result.error.message);
|
|
3675
|
+
process.exit(1);
|
|
3676
|
+
}
|
|
3677
|
+
if (result.status !== 0) {
|
|
3678
|
+
const stderr = result.stderr?.toString().trim();
|
|
3679
|
+
const stdout = result.stdout?.toString().trim();
|
|
3680
|
+
const detail = stderr || stdout || `exit code ${result.status}`;
|
|
3681
|
+
console.error(`[apm] pm2 ${args.join(" ")} \u5931\u8D25: ${detail}`);
|
|
3682
|
+
process.exit(result.status ?? 1);
|
|
3611
3683
|
}
|
|
3612
3684
|
}
|
|
3613
|
-
|
|
3614
|
-
const
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
return;
|
|
3622
|
-
}
|
|
3623
|
-
let out = "";
|
|
3624
|
-
let errText = "";
|
|
3625
|
-
execStream.on("data", (data) => {
|
|
3626
|
-
const text = data.toString();
|
|
3627
|
-
out += text;
|
|
3628
|
-
if (stream) {
|
|
3629
|
-
process.stdout.write(text);
|
|
3630
|
-
}
|
|
3631
|
-
});
|
|
3632
|
-
execStream.stderr.on("data", (data) => {
|
|
3633
|
-
errText += data.toString();
|
|
3634
|
-
});
|
|
3635
|
-
execStream.on("close", (code) => {
|
|
3636
|
-
if (stream && out && !out.endsWith("\n")) {
|
|
3637
|
-
process.stdout.write("\n");
|
|
3638
|
-
}
|
|
3639
|
-
if (check && code !== 0) {
|
|
3640
|
-
const combined = `${out}
|
|
3641
|
-
${errText}`.trim();
|
|
3642
|
-
fail(
|
|
3643
|
-
`${label}\u5931\u8D25 (exit ${code})` + (combined ? `
|
|
3644
|
-
\u8F93\u51FA: ${combined}` : "")
|
|
3645
|
-
);
|
|
3646
|
-
}
|
|
3647
|
-
resolve5({ exitCode: code, out: out.trim(), err: errText.trim() });
|
|
3648
|
-
});
|
|
3649
|
-
});
|
|
3685
|
+
function runPm2Json(args) {
|
|
3686
|
+
const pm2Bin = findGlobalPm2();
|
|
3687
|
+
if (!pm2Bin) {
|
|
3688
|
+
return "[]";
|
|
3689
|
+
}
|
|
3690
|
+
ensurePm2DaemonUpdated(pm2Bin);
|
|
3691
|
+
const result = spawnPm2At(pm2Bin, args, {
|
|
3692
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
3650
3693
|
});
|
|
3694
|
+
if (result.status !== 0) return "[]";
|
|
3695
|
+
return result.stdout?.toString() ?? "[]";
|
|
3651
3696
|
}
|
|
3652
|
-
function
|
|
3653
|
-
const
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
TMP=$(mktemp -d)
|
|
3658
|
-
trap 'rm -rf "$TMP"' EXIT
|
|
3659
|
-
unzip -oq ${quotedZip} -d "$TMP"
|
|
3660
|
-
updated=0
|
|
3661
|
-
while IFS= read -r -d '' src; do
|
|
3662
|
-
name=$(basename "$src")
|
|
3663
|
-
dest=${quotedLib}/"$name"
|
|
3664
|
-
if [ -f "$dest" ]; then
|
|
3665
|
-
cp -f "$src" "$dest"
|
|
3666
|
-
echo "\u8986\u76D6: $name"
|
|
3667
|
-
updated=$((updated + 1))
|
|
3668
|
-
else
|
|
3669
|
-
echo "\u8DF3\u8FC7(\u8FDC\u7A0B\u4E0D\u5B58\u5728): $name"
|
|
3670
|
-
fi
|
|
3671
|
-
done < <(find "$TMP" -name '*.jar' -type f -print0)
|
|
3672
|
-
echo "UPDATED_COUNT=$updated"
|
|
3673
|
-
`.trim();
|
|
3697
|
+
function isPm2ConnectOnline() {
|
|
3698
|
+
const app = findPm2ConnectProcess();
|
|
3699
|
+
if (!app) return false;
|
|
3700
|
+
const status = app.pm2_env?.status;
|
|
3701
|
+
return status === "online" || status === "launching";
|
|
3674
3702
|
}
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3703
|
+
function printConnectNotRunningHint() {
|
|
3704
|
+
console.log(`[apm] ${PM2_APP_NAME} \u672A\u5728\u8FD0\u884C`);
|
|
3705
|
+
console.log("[apm] \u542F\u52A8\u5B88\u62A4: apm connect --daemon");
|
|
3706
|
+
}
|
|
3707
|
+
function assertConnectNotRunning() {
|
|
3708
|
+
pruneStaleConnectLock();
|
|
3709
|
+
const lock = readConnectLock();
|
|
3710
|
+
if (lock && isProcessAlive(lock.pid) && lock.pid !== process.pid) {
|
|
3711
|
+
console.error(
|
|
3712
|
+
`[apm] \u5DF2\u6709 apm connect \u5728\u8FD0\u884C (pid=${lock.pid}, mode=${lock.mode})\uFF0C\u8BF7\u5148\u505C\u6B62\u540E\u518D\u542F\u52A8`
|
|
3713
|
+
);
|
|
3714
|
+
process.exit(1);
|
|
3715
|
+
}
|
|
3716
|
+
if (!isRunningUnderPm2() && isPm2ConnectOnline()) {
|
|
3717
|
+
console.error(
|
|
3718
|
+
"[apm] \u5DF2\u6709 apm connect \u5B88\u62A4\u8FDB\u7A0B\u5728\u8FD0\u884C\uFF0C\u8BF7\u5148\u6267\u884C apm daemon stop"
|
|
3719
|
+
);
|
|
3720
|
+
process.exit(1);
|
|
3687
3721
|
}
|
|
3688
|
-
const updated = Number.parseInt(match[1], 10);
|
|
3689
|
-
log(`lib \u89E3\u538B\u5B8C\u6210: \u8986\u76D6 ${updated} \u4E2A`);
|
|
3690
|
-
return updated;
|
|
3691
3722
|
}
|
|
3692
|
-
function
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3723
|
+
function resolveRuntimePaths() {
|
|
3724
|
+
return {
|
|
3725
|
+
apmScript: resolveApmEntryPath(),
|
|
3726
|
+
nodePath: process.execPath
|
|
3727
|
+
};
|
|
3728
|
+
}
|
|
3729
|
+
function reexecConnectWithResolvedPath(options) {
|
|
3730
|
+
const apmScript = resolveApmEntryPath();
|
|
3731
|
+
const args = [apmScript, "connect"];
|
|
3732
|
+
const server = options.server?.trim();
|
|
3733
|
+
if (server) {
|
|
3734
|
+
args.push("--server", server);
|
|
3696
3735
|
}
|
|
3697
|
-
|
|
3698
|
-
|
|
3736
|
+
const result = spawnSync2(process.execPath, args, { stdio: "inherit" });
|
|
3737
|
+
if (result.error) {
|
|
3738
|
+
console.error("[apm] \u91CD\u542F connect \u5931\u8D25:", result.error.message);
|
|
3739
|
+
process.exit(1);
|
|
3699
3740
|
}
|
|
3700
|
-
|
|
3701
|
-
|
|
3741
|
+
process.exit(result.status ?? 0);
|
|
3742
|
+
}
|
|
3743
|
+
async function handleConnectAfterUpdate(options) {
|
|
3744
|
+
console.log("[apm] \u66F4\u65B0\u5B8C\u6210\uFF0C\u6B63\u5728\u4EE5\u65B0\u7248\u672C\u91CD\u65B0\u8FDE\u63A5\u2026");
|
|
3745
|
+
await prepareEcosystem(options.server);
|
|
3746
|
+
if (isRunningUnderPm2()) {
|
|
3747
|
+
runPm2(["reload", PM2_ECOSYSTEM_PATH, "--update-env"], { inherit: true });
|
|
3748
|
+
console.log("[apm] \u5DF2\u901A\u77E5 PM2 \u4F7F\u7528\u65B0\u7248\u672C\u91CD\u65B0\u52A0\u8F7D connect");
|
|
3749
|
+
process.exit(0);
|
|
3702
3750
|
}
|
|
3703
|
-
|
|
3704
|
-
|
|
3751
|
+
reexecConnectWithResolvedPath(options);
|
|
3752
|
+
}
|
|
3753
|
+
async function resolveBaseUrl(server) {
|
|
3754
|
+
if (server?.trim()) {
|
|
3755
|
+
return server.trim().replace(/\/+$/, "");
|
|
3705
3756
|
}
|
|
3706
|
-
|
|
3757
|
+
const cfg = await tryReadApmConfig();
|
|
3758
|
+
return cfg?.baseUrl;
|
|
3707
3759
|
}
|
|
3708
|
-
function
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
echo -e "\\033[31m Not running \\033[0m"
|
|
3718
|
-
else
|
|
3719
|
-
echo -e "\\033[32m Running [$appIds] \\033[0m"
|
|
3720
|
-
fi
|
|
3721
|
-
`.trim();
|
|
3722
|
-
}
|
|
3723
|
-
function buildRemoteRestartScript(remoteAppDir) {
|
|
3724
|
-
const dir = shellSingleQuote(remoteAppDir);
|
|
3725
|
-
const javaOpts = shellSingleQuote(SPRINGBOOT_JAVA_OPTS);
|
|
3726
|
-
return `
|
|
3727
|
-
set -e
|
|
3728
|
-
cd ${dir}
|
|
3729
|
-
releaseApp=$(ls -t | grep '.jar$' | head -n1)
|
|
3730
|
-
lastVersionApp=$(ls -t | grep '.jar$' | head -n2 | tail -n1)
|
|
3731
|
-
appName=$lastVersionApp
|
|
3732
|
-
appIds=$(ps -ef | grep java | grep "$appName" | awk '{print $2}')
|
|
3733
|
-
if [ -z "$appIds" ]; then
|
|
3734
|
-
echo "Maybe $appName not running, please check it..."
|
|
3735
|
-
else
|
|
3736
|
-
echo "The $appName is stopping..."
|
|
3737
|
-
echo "$appIds" | xargs kill
|
|
3738
|
-
fi
|
|
3739
|
-
for i in $(seq 15 -1 1); do
|
|
3740
|
-
echo -n "$i "
|
|
3741
|
-
sleep 1
|
|
3742
|
-
done
|
|
3743
|
-
echo 0
|
|
3744
|
-
if [ ! -d "backup" ]; then
|
|
3745
|
-
mkdir backup
|
|
3746
|
-
fi
|
|
3747
|
-
for i in $(ls | grep '.jar$' | grep -vFx "$releaseApp"); do
|
|
3748
|
-
echo "backup $i"
|
|
3749
|
-
mv "$i" backup/
|
|
3750
|
-
done
|
|
3751
|
-
appName=$releaseApp
|
|
3752
|
-
count=$(ps -ef | grep java | grep "$appName" | wc -l)
|
|
3753
|
-
if [ "$count" != "0" ]; then
|
|
3754
|
-
echo "Maybe $appName is running, please check it..."
|
|
3755
|
-
else
|
|
3756
|
-
echo "The $appName is starting..."
|
|
3757
|
-
nohup java -jar "./$appName" ${javaOpts} > nohup.out 2>&1 &
|
|
3758
|
-
fi
|
|
3759
|
-
`.trim();
|
|
3760
|
-
}
|
|
3761
|
-
function normalizeHealthContext(context) {
|
|
3762
|
-
let normalized = context.trim() || "/";
|
|
3763
|
-
if (!normalized.startsWith("/")) {
|
|
3764
|
-
normalized = `/${normalized}`;
|
|
3765
|
-
}
|
|
3766
|
-
if (!normalized.endsWith("/")) {
|
|
3767
|
-
normalized = `${normalized}/`;
|
|
3760
|
+
function writeConnectLaunchFiles(options) {
|
|
3761
|
+
mkdirSync6(APM_CONFIG_DIR, { recursive: true });
|
|
3762
|
+
writeFileSync11(PM2_CONNECT_ENTRY_PATH, CONNECT_ENTRY_SCRIPT, "utf8");
|
|
3763
|
+
const env = {
|
|
3764
|
+
...collectPm2LaunchEnv()
|
|
3765
|
+
};
|
|
3766
|
+
const baseUrl = options.baseUrl?.trim().replace(/\/+$/, "");
|
|
3767
|
+
if (baseUrl) {
|
|
3768
|
+
env.AI_PM_SERVER = baseUrl;
|
|
3768
3769
|
}
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
echo "\u5065\u5EB7\u68C0\u67E5: \${check_url} (\u8D85\u65F6 \${timeout}s)"
|
|
3782
|
-
deadline=$(($(date +%s) + timeout))
|
|
3783
|
-
attempt=0
|
|
3784
|
-
while [ $(date +%s) -lt $deadline ]; do
|
|
3785
|
-
attempt=$((attempt + 1))
|
|
3786
|
-
code=$(curl -s -o /dev/null -w "%{http_code}" "$check_url" 2>/dev/null || echo "000")
|
|
3787
|
-
code=$(echo "$code" | tail -n1 | tr -d '[:space:]')
|
|
3788
|
-
if [ \${#code} -ge 3 ]; then
|
|
3789
|
-
status=\${code:0:3}
|
|
3790
|
-
if echo "$status" | grep -qE '^[0-9]+$' && [ "$status" -ge 200 ] && [ "$status" -lt 500 ]; then
|
|
3791
|
-
echo -e "\\033[32m\u5065\u5EB7\u68C0\u67E5\u901A\u8FC7 (HTTP \${status})\\033[0m"
|
|
3792
|
-
exit 0
|
|
3793
|
-
fi
|
|
3794
|
-
fi
|
|
3795
|
-
remaining=$((deadline - $(date +%s)))
|
|
3796
|
-
if [ $remaining -lt 0 ]; then
|
|
3797
|
-
remaining=0
|
|
3798
|
-
fi
|
|
3799
|
-
echo "\u7B49\u5F85\u670D\u52A1\u542F\u52A8... \u7B2C \${attempt} \u6B21\uFF0C\u5269\u4F59 \${remaining}s"
|
|
3800
|
-
sleep 5
|
|
3801
|
-
done
|
|
3802
|
-
echo -e "\\033[31m\u5065\u5EB7\u68C0\u67E5\u8D85\u65F6 (\${timeout}s): \${check_url}\\033[0m"
|
|
3803
|
-
exit 1
|
|
3804
|
-
`.trim();
|
|
3770
|
+
const launch = {
|
|
3771
|
+
nodePath: options.nodePath,
|
|
3772
|
+
apmScript: options.apmScript,
|
|
3773
|
+
connectArgs: options.connectArgs,
|
|
3774
|
+
cwd: options.cwd,
|
|
3775
|
+
env
|
|
3776
|
+
};
|
|
3777
|
+
writeFileSync11(
|
|
3778
|
+
PM2_CONNECT_LAUNCH_PATH,
|
|
3779
|
+
JSON.stringify(launch, null, 2) + "\n",
|
|
3780
|
+
"utf8"
|
|
3781
|
+
);
|
|
3805
3782
|
}
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3783
|
+
function writeEcosystemFile(options) {
|
|
3784
|
+
writeConnectLaunchFiles(options);
|
|
3785
|
+
const ecosystem = buildConnectPm2Ecosystem({
|
|
3786
|
+
entryScript: PM2_CONNECT_ENTRY_PATH,
|
|
3787
|
+
baseUrl: options.baseUrl
|
|
3810
3788
|
});
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
if (exitCode !== 0 || !outputOk) {
|
|
3816
|
-
fail(`\u5065\u5EB7\u68C0\u67E5\u5931\u8D25
|
|
3817
|
-
\u8F93\u51FA: ${combined || "(\u7A7A)"}`);
|
|
3818
|
-
}
|
|
3819
|
-
return combined;
|
|
3820
|
-
}
|
|
3821
|
-
if (exitCode !== 0 && !outputOk) {
|
|
3822
|
-
fail(`\u8FDC\u7A0B ${action} \u5931\u8D25
|
|
3823
|
-
${combined}`);
|
|
3824
|
-
}
|
|
3825
|
-
if (action === "restart" && !outputOk) {
|
|
3826
|
-
fail(`\u8FDC\u7A0B restart \u672A\u6210\u529F
|
|
3827
|
-
\u8F93\u51FA: ${combined || "(\u7A7A)"}`);
|
|
3828
|
-
}
|
|
3829
|
-
return combined;
|
|
3830
|
-
}
|
|
3831
|
-
function stripAnsi(text) {
|
|
3832
|
-
return text.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "");
|
|
3833
|
-
}
|
|
3834
|
-
async function getRunningJar(client, config) {
|
|
3835
|
-
const script = buildRemoteStatusScript(
|
|
3836
|
-
config.remoteAppDir,
|
|
3837
|
-
config.startupJar
|
|
3789
|
+
writeFileSync11(
|
|
3790
|
+
PM2_ECOSYSTEM_PATH,
|
|
3791
|
+
formatConnectPm2EcosystemFile(ecosystem),
|
|
3792
|
+
"utf8"
|
|
3838
3793
|
);
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
|
|
3844
|
-
if (text.includes("running")) {
|
|
3845
|
-
return config.startupJar;
|
|
3794
|
+
if (existsSync13(LEGACY_PM2_ECOSYSTEM_PATH)) {
|
|
3795
|
+
try {
|
|
3796
|
+
unlinkSync2(LEGACY_PM2_ECOSYSTEM_PATH);
|
|
3797
|
+
} catch {
|
|
3798
|
+
}
|
|
3846
3799
|
}
|
|
3847
|
-
return null;
|
|
3848
|
-
}
|
|
3849
|
-
async function healthCheckService(client, config) {
|
|
3850
|
-
log("\u5065\u5EB7\u68C0\u67E5...");
|
|
3851
|
-
const script = buildRemoteHealthScript(
|
|
3852
|
-
config.healthCheckPort,
|
|
3853
|
-
config.healthCheckContext,
|
|
3854
|
-
config.healthCheckTimeout
|
|
3855
|
-
);
|
|
3856
|
-
await runRemoteServiceScript(client, script, "health");
|
|
3857
3800
|
}
|
|
3858
|
-
async function
|
|
3859
|
-
|
|
3860
|
-
await
|
|
3861
|
-
}
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
const projectRoot = path3.resolve(options.projectRoot ?? process.cwd());
|
|
3871
|
-
const config = options.config;
|
|
3872
|
-
const packOnly = Boolean(options.packOnly);
|
|
3873
|
-
log(`=== \u81EA\u52A8\u90E8\u7F72: ${config.projectName} ===`);
|
|
3874
|
-
log(`\u914D\u7F6E\u6587\u4EF6: ${path3.join(workspaceApmDir(), "apm.config.json")}`);
|
|
3875
|
-
log(`\u9879\u76EE\u6839\u76EE\u5F55: ${projectRoot}`);
|
|
3876
|
-
log(
|
|
3877
|
-
`\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"}${packOnly ? "\uFF1B\u4EC5\u6253\u5305\uFF08\u4E0D\u4E0A\u4F20\u8FDC\u7A0B\uFF09" : ""}`
|
|
3878
|
-
);
|
|
3879
|
-
runMavenBuild(projectRoot, config.mavenLocalRepo, {
|
|
3880
|
-
source: config.mavenLocalRepoSource,
|
|
3881
|
-
sourceDetail: config.mavenLocalRepoSourceDetail
|
|
3801
|
+
async function prepareEcosystem(server) {
|
|
3802
|
+
await ensureLoggedConfig();
|
|
3803
|
+
const cfg = await ensureApmConfig();
|
|
3804
|
+
const { apmScript, nodePath } = resolveRuntimePaths();
|
|
3805
|
+
const connectArgs = resolveConnectArgs(server);
|
|
3806
|
+
const baseUrl = await resolveBaseUrl(server);
|
|
3807
|
+
writeEcosystemFile({
|
|
3808
|
+
apmScript,
|
|
3809
|
+
nodePath,
|
|
3810
|
+
connectArgs,
|
|
3811
|
+
baseUrl,
|
|
3812
|
+
cwd: process.cwd()
|
|
3882
3813
|
});
|
|
3883
|
-
|
|
3884
|
-
const uploadWithoutRunId = !resolveDeploymentRunIdFromEnv();
|
|
3885
|
-
if (config.mode === "full") {
|
|
3886
|
-
const mainJar = locateMainJar(projectRoot);
|
|
3887
|
-
const archiveZipPath = await createUpdatePackage(
|
|
3888
|
-
[
|
|
3889
|
-
{
|
|
3890
|
-
path: mainJar,
|
|
3891
|
-
arcname: path3.basename(mainJar),
|
|
3892
|
-
reason: "\u5168\u91CF JAR \u5F52\u6863"
|
|
3893
|
-
}
|
|
3894
|
-
],
|
|
3895
|
-
`.deploy-archive-${config.projectName}.jar.zip`
|
|
3896
|
-
);
|
|
3897
|
-
await uploadDeployArtifactZip({
|
|
3898
|
-
zipPath: archiveZipPath,
|
|
3899
|
-
projectName: config.projectName,
|
|
3900
|
-
kind: "backend",
|
|
3901
|
-
uploadWithoutRunId
|
|
3902
|
-
});
|
|
3903
|
-
} else {
|
|
3904
|
-
const libDir = locateLibDir(projectRoot);
|
|
3905
|
-
const entries = listAllLibFilesForArchive(libDir);
|
|
3906
|
-
if (entries.length === 0) {
|
|
3907
|
-
fail("lib \u76EE\u5F55\u4E0B\u6CA1\u6709\u53EF\u5F52\u6863\u7684 JAR");
|
|
3908
|
-
}
|
|
3909
|
-
const zipPath = await createUpdatePackage(entries, config.packageName);
|
|
3910
|
-
await uploadDeployArtifactZip({
|
|
3911
|
-
zipPath,
|
|
3912
|
-
projectName: config.projectName,
|
|
3913
|
-
kind: "backend",
|
|
3914
|
-
uploadWithoutRunId
|
|
3915
|
-
});
|
|
3916
|
-
}
|
|
3917
|
-
log("\u4EC5\u6253\u5305\u5B8C\u6210\uFF08\u672A\u4E0A\u4F20\u8FDC\u7A0B\u670D\u52A1\u5668\uFF09");
|
|
3918
|
-
return;
|
|
3919
|
-
}
|
|
3920
|
-
const conn = await connectSsh(config);
|
|
3921
|
-
try {
|
|
3922
|
-
if (config.mode === "full") {
|
|
3923
|
-
const mainJar = locateMainJar(projectRoot);
|
|
3924
|
-
await uploadFullJar(conn.sftp, mainJar, config);
|
|
3925
|
-
const archiveZipPath = await createUpdatePackage(
|
|
3926
|
-
[
|
|
3927
|
-
{
|
|
3928
|
-
path: mainJar,
|
|
3929
|
-
arcname: path3.basename(mainJar),
|
|
3930
|
-
reason: "\u5168\u91CF JAR \u5F52\u6863"
|
|
3931
|
-
}
|
|
3932
|
-
],
|
|
3933
|
-
`.deploy-archive-${config.projectName}.jar.zip`
|
|
3934
|
-
);
|
|
3935
|
-
await uploadDeployArtifactZip({
|
|
3936
|
-
zipPath: archiveZipPath,
|
|
3937
|
-
projectName: config.projectName,
|
|
3938
|
-
kind: "backend"
|
|
3939
|
-
});
|
|
3940
|
-
log("\u91CD\u542F\u670D\u52A1...");
|
|
3941
|
-
await restartRemoteService(conn.client, config);
|
|
3942
|
-
await healthCheckService(conn.client, config);
|
|
3943
|
-
log("\u90E8\u7F72\u5B8C\u6210");
|
|
3944
|
-
return;
|
|
3945
|
-
}
|
|
3946
|
-
const libDir = locateLibDir(projectRoot);
|
|
3947
|
-
let manifest = loadManifest3();
|
|
3948
|
-
const remoteLibStats = await getRemoteFileStats(
|
|
3949
|
-
conn.sftp,
|
|
3950
|
-
config.remoteLibDir
|
|
3951
|
-
);
|
|
3952
|
-
log("\u6536\u96C6 JAR \u66F4\u65B0...");
|
|
3953
|
-
const libUploadEntries = listLibFilesToUpload(
|
|
3954
|
-
libDir,
|
|
3955
|
-
remoteLibStats,
|
|
3956
|
-
projectRoot,
|
|
3957
|
-
manifest
|
|
3958
|
-
);
|
|
3959
|
-
let updated = 0;
|
|
3960
|
-
if (libUploadEntries.length > 0) {
|
|
3961
|
-
const zipPath = await createUpdatePackage(
|
|
3962
|
-
libUploadEntries,
|
|
3963
|
-
config.packageName
|
|
3964
|
-
);
|
|
3965
|
-
const remoteZipPath = await uploadUpdatePackage(
|
|
3966
|
-
conn.sftp,
|
|
3967
|
-
zipPath,
|
|
3968
|
-
config
|
|
3969
|
-
);
|
|
3970
|
-
await uploadDeployArtifactZip({
|
|
3971
|
-
zipPath,
|
|
3972
|
-
projectName: config.projectName,
|
|
3973
|
-
kind: "backend"
|
|
3974
|
-
});
|
|
3975
|
-
log("\u8FDC\u7A0B\u89E3\u538B lib \u76EE\u5F55\uFF08\u4EC5\u8986\u76D6\u5DF2\u6709 JAR\uFF09...");
|
|
3976
|
-
updated = await extractUpdatePackageOnRemote(
|
|
3977
|
-
conn.client,
|
|
3978
|
-
config,
|
|
3979
|
-
remoteZipPath
|
|
3980
|
-
);
|
|
3981
|
-
} else {
|
|
3982
|
-
log("\u65E0 JAR \u9700\u8981\u66F4\u65B0\uFF0C\u8DF3\u8FC7\u66F4\u65B0\u5305\u4E0A\u4F20");
|
|
3983
|
-
}
|
|
3984
|
-
const runningJar = await getRunningJar(conn.client, config);
|
|
3985
|
-
let needRestart = updated > 0;
|
|
3986
|
-
if (!needRestart && !runningJar) {
|
|
3987
|
-
log("\u670D\u52A1\u672A\u8FD0\u884C\uFF0C\u9700\u8981\u542F\u52A8");
|
|
3988
|
-
needRestart = true;
|
|
3989
|
-
} else if (!needRestart) {
|
|
3990
|
-
log("\u6CA1\u6709\u6587\u4EF6\u9700\u8981\u66F4\u65B0\uFF0C\u8DF3\u8FC7\u91CD\u542F");
|
|
3991
|
-
}
|
|
3992
|
-
if (needRestart) {
|
|
3993
|
-
log("\u91CD\u542F\u670D\u52A1...");
|
|
3994
|
-
await restartRemoteService(conn.client, config);
|
|
3995
|
-
}
|
|
3996
|
-
await healthCheckService(conn.client, config);
|
|
3997
|
-
if (libUploadEntries.length > 0) {
|
|
3998
|
-
manifest = updateManifestEntries(manifest, libUploadEntries, projectRoot);
|
|
3999
|
-
saveManifest3(manifest);
|
|
4000
|
-
}
|
|
4001
|
-
} finally {
|
|
4002
|
-
await closeSsh(conn);
|
|
4003
|
-
}
|
|
4004
|
-
log("\u90E8\u7F72\u5B8C\u6210");
|
|
3814
|
+
return cfg;
|
|
4005
3815
|
}
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
import {
|
|
4019
|
-
existsSync as existsSync13,
|
|
4020
|
-
mkdirSync as mkdirSync6,
|
|
4021
|
-
readFileSync as readFileSync12,
|
|
4022
|
-
unlinkSync,
|
|
4023
|
-
writeFileSync as writeFileSync11
|
|
4024
|
-
} from "fs";
|
|
4025
|
-
import { join as join14 } from "path";
|
|
4026
|
-
var CONNECT_LOCK_PATH = join14(APM_CONFIG_DIR, "connect.lock");
|
|
4027
|
-
function isProcessAlive(pid) {
|
|
4028
|
-
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
4029
|
-
try {
|
|
4030
|
-
process.kill(pid, 0);
|
|
4031
|
-
return true;
|
|
4032
|
-
} catch {
|
|
4033
|
-
return false;
|
|
3816
|
+
async function runDaemonStart(options) {
|
|
3817
|
+
assertConnectNotRunning();
|
|
3818
|
+
await runUpdate();
|
|
3819
|
+
ensureGlobalPm2();
|
|
3820
|
+
const cfg = await prepareEcosystem(options.server);
|
|
3821
|
+
removePm2ConnectProcesses();
|
|
3822
|
+
runPm2(["start", PM2_ECOSYSTEM_PATH, "--update-env"], { inherit: true });
|
|
3823
|
+
await delay2(1e3);
|
|
3824
|
+
if (!isPm2ConnectOnline()) {
|
|
3825
|
+
console.error(
|
|
3826
|
+
`[apm] ${PM2_APP_NAME} \u542F\u52A8\u540E\u672A\u5904\u4E8E online \u72B6\u6001\uFF0C\u8BF7\u6267\u884C: apm daemon logs -n 200`
|
|
3827
|
+
);
|
|
4034
3828
|
}
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
3829
|
+
console.log(
|
|
3830
|
+
`[apm] ${PM2_APP_NAME} \u5DF2\u7531 PM2 \u542F\u52A8\uFF08server=${options.server?.trim() || cfg.baseUrl}\uFF09`
|
|
3831
|
+
);
|
|
3832
|
+
if (options.follow) {
|
|
3833
|
+
console.log(
|
|
3834
|
+
"[apm] \u6B63\u5728\u8DDF\u8E2A\u65E5\u5FD7\uFF08Ctrl+C \u4EC5\u9000\u51FA\u65E5\u5FD7\u67E5\u770B\uFF0C\u5B88\u62A4\u8FDB\u7A0B\u7EE7\u7EED\u8FD0\u884C\uFF09"
|
|
3835
|
+
);
|
|
3836
|
+
runDaemonLogs({ follow: true });
|
|
3837
|
+
return;
|
|
4039
3838
|
}
|
|
3839
|
+
console.log("[apm] \u67E5\u770B\u72B6\u6001: apm daemon status");
|
|
3840
|
+
console.log("[apm] \u67E5\u770B\u65E5\u5FD7: apm daemon logs -f");
|
|
3841
|
+
console.log("[apm] \u505C\u6B62: apm daemon stop");
|
|
4040
3842
|
}
|
|
4041
|
-
function
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
}
|
|
4049
|
-
sleepSync(100);
|
|
3843
|
+
async function runDaemonStop() {
|
|
3844
|
+
pruneStaleConnectLock();
|
|
3845
|
+
if (!isPm2ConnectOnline()) {
|
|
3846
|
+
killConnectLockProcessIfAlive();
|
|
3847
|
+
forceReleaseConnectLock();
|
|
3848
|
+
console.log(`[apm] ${PM2_APP_NAME} \u672A\u5728\u8FD0\u884C`);
|
|
3849
|
+
return;
|
|
4050
3850
|
}
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
}
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
3851
|
+
runPm2(["stop", resolvePm2ConnectName(findPm2ConnectProcess())], {
|
|
3852
|
+
inherit: true
|
|
3853
|
+
});
|
|
3854
|
+
for (let i = 0; i < 10; i += 1) {
|
|
3855
|
+
if (!isPm2ConnectOnline()) break;
|
|
3856
|
+
await delay2(500);
|
|
3857
|
+
}
|
|
3858
|
+
if (isPm2ConnectOnline()) {
|
|
3859
|
+
console.log(`[apm] \u4F18\u96C5\u505C\u6B62\u8D85\u65F6\uFF0C\u5F3A\u5236\u79FB\u9664 ${PM2_APP_NAME}\u2026`);
|
|
3860
|
+
runPm2(["delete", resolvePm2ConnectName(findPm2ConnectProcess())], {
|
|
3861
|
+
inherit: true
|
|
3862
|
+
});
|
|
4063
3863
|
}
|
|
3864
|
+
killConnectLockProcessIfAlive();
|
|
3865
|
+
forceReleaseConnectLock();
|
|
3866
|
+
console.log(`[apm] ${PM2_APP_NAME} \u5DF2\u505C\u6B62`);
|
|
4064
3867
|
}
|
|
4065
|
-
function
|
|
3868
|
+
function killConnectLockProcessIfAlive() {
|
|
3869
|
+
pruneStaleConnectLock();
|
|
4066
3870
|
const lock = readConnectLock();
|
|
4067
|
-
if (!lock) return;
|
|
4068
|
-
if (isProcessAlive(lock.pid)) return;
|
|
3871
|
+
if (!lock || !isProcessAlive(lock.pid)) return;
|
|
4069
3872
|
try {
|
|
4070
|
-
|
|
3873
|
+
process.kill(lock.pid, "SIGTERM");
|
|
4071
3874
|
} catch {
|
|
3875
|
+
forceReleaseConnectLock();
|
|
3876
|
+
return;
|
|
4072
3877
|
}
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
if (existing && isProcessAlive(existing.pid)) {
|
|
4078
|
-
if (existing.pid === process.pid) {
|
|
4079
|
-
return;
|
|
4080
|
-
}
|
|
4081
|
-
if (mode === "pm2" && existing.mode === "pm2") {
|
|
4082
|
-
forceReleaseConnectLock();
|
|
4083
|
-
} else {
|
|
4084
|
-
console.error(
|
|
4085
|
-
`[apm] \u5DF2\u6709 apm connect \u5728\u8FD0\u884C (pid=${existing.pid}, mode=${existing.mode})`
|
|
4086
|
-
);
|
|
4087
|
-
process.exit(1);
|
|
3878
|
+
if (isProcessAlive(lock.pid)) {
|
|
3879
|
+
try {
|
|
3880
|
+
process.kill(lock.pid, "SIGKILL");
|
|
3881
|
+
} catch {
|
|
4088
3882
|
}
|
|
4089
3883
|
}
|
|
4090
|
-
|
|
4091
|
-
const lock = {
|
|
4092
|
-
pid: process.pid,
|
|
4093
|
-
mode,
|
|
4094
|
-
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4095
|
-
};
|
|
4096
|
-
writeFileSync11(
|
|
4097
|
-
CONNECT_LOCK_PATH,
|
|
4098
|
-
JSON.stringify(lock, null, 2) + "\n",
|
|
4099
|
-
"utf8"
|
|
4100
|
-
);
|
|
3884
|
+
forceReleaseConnectLock();
|
|
4101
3885
|
}
|
|
4102
|
-
function
|
|
3886
|
+
async function runDaemonRestart(options) {
|
|
3887
|
+
pruneStaleConnectLock();
|
|
4103
3888
|
const lock = readConnectLock();
|
|
4104
|
-
if (lock
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
3889
|
+
if (lock && isProcessAlive(lock.pid) && !isPm2ConnectOnline()) {
|
|
3890
|
+
console.error(
|
|
3891
|
+
`[apm] \u5DF2\u6709\u524D\u53F0 apm connect \u5728\u8FD0\u884C (pid=${lock.pid})\uFF0C\u8BF7\u5148\u505C\u6B62\u540E\u518D\u542F\u52A8\u5B88\u62A4\u8FDB\u7A0B`
|
|
3892
|
+
);
|
|
3893
|
+
process.exit(1);
|
|
4108
3894
|
}
|
|
3895
|
+
await runUpdate();
|
|
3896
|
+
await prepareEcosystem(options.server);
|
|
3897
|
+
removePm2ConnectProcesses();
|
|
3898
|
+
runPm2(["start", PM2_ECOSYSTEM_PATH, "--update-env"], { inherit: true });
|
|
3899
|
+
console.log(`[apm] ${PM2_APP_NAME} \u5DF2\u91CD\u542F`);
|
|
4109
3900
|
}
|
|
4110
|
-
function
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
}
|
|
4115
|
-
|
|
3901
|
+
async function runDaemonDelete() {
|
|
3902
|
+
ensureGlobalPm2();
|
|
3903
|
+
const app = findPm2ConnectProcess();
|
|
3904
|
+
if (!app?.name) {
|
|
3905
|
+
console.log(`[apm] ${PM2_APP_NAME} \u672A\u5728 PM2 \u4E2D\u6CE8\u518C`);
|
|
3906
|
+
return;
|
|
4116
3907
|
}
|
|
3908
|
+
runPm2(["delete", app.name], { inherit: true });
|
|
3909
|
+
forceReleaseConnectLock();
|
|
3910
|
+
console.log(`[apm] ${app.name} \u5DF2\u4ECE PM2 \u79FB\u9664`);
|
|
4117
3911
|
}
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
var PM2_CONNECT_LAUNCH_PATH = join15(
|
|
4127
|
-
APM_CONFIG_DIR,
|
|
4128
|
-
"connect.launch.json"
|
|
4129
|
-
);
|
|
4130
|
-
var LEGACY_PM2_ECOSYSTEM_PATH = join15(
|
|
4131
|
-
APM_CONFIG_DIR,
|
|
4132
|
-
"connect.ecosystem.cjs"
|
|
4133
|
-
);
|
|
4134
|
-
var LEGACY_PM2_APP_NAMES = ["connect.ecosystem"];
|
|
4135
|
-
var CONNECT_ENTRY_SCRIPT = `'use strict';
|
|
4136
|
-
const { spawnSync } = require('node:child_process');
|
|
4137
|
-
const { readFileSync } = require('node:fs');
|
|
4138
|
-
const { join } = require('node:path');
|
|
4139
|
-
|
|
4140
|
-
const launchConfigPath = join(__dirname, 'connect.launch.json');
|
|
4141
|
-
let config;
|
|
4142
|
-
try {
|
|
4143
|
-
config = JSON.parse(readFileSync(launchConfigPath, 'utf8'));
|
|
4144
|
-
} catch (err) {
|
|
4145
|
-
console.error('[apm] \u65E0\u6CD5\u8BFB\u53D6 connect.launch.json:', err instanceof Error ? err.message : err);
|
|
4146
|
-
process.exit(1);
|
|
3912
|
+
async function runDaemonStatus() {
|
|
3913
|
+
ensureGlobalPm2();
|
|
3914
|
+
const app = findPm2ConnectProcess();
|
|
3915
|
+
if (!app?.name) {
|
|
3916
|
+
printConnectNotRunningHint();
|
|
3917
|
+
return;
|
|
3918
|
+
}
|
|
3919
|
+
runPm2(["describe", app.name], { inherit: true });
|
|
4147
3920
|
}
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
const
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
}
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
windowsHide: true,
|
|
4161
|
-
});
|
|
4162
|
-
|
|
4163
|
-
if (result.error) {
|
|
4164
|
-
console.error('[apm] connect \u542F\u52A8\u5931\u8D25:', result.error.message);
|
|
4165
|
-
process.exit(1);
|
|
3921
|
+
async function runDaemonLogs(options) {
|
|
3922
|
+
ensureGlobalPm2();
|
|
3923
|
+
const app = findPm2ConnectProcess();
|
|
3924
|
+
if (!app?.name) {
|
|
3925
|
+
printConnectNotRunningHint();
|
|
3926
|
+
return;
|
|
3927
|
+
}
|
|
3928
|
+
const args = ["logs", app.name, "--lines", String(options.lines ?? 100)];
|
|
3929
|
+
if (!options.follow) {
|
|
3930
|
+
args.push("--nostream");
|
|
3931
|
+
}
|
|
3932
|
+
runPm2(args, { inherit: true });
|
|
4166
3933
|
}
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
3934
|
+
|
|
3935
|
+
// src/commands/deploy/internal/deploy-shell-env.ts
|
|
3936
|
+
var PATH_SEP = process.platform === "win32" ? ";" : ":";
|
|
3937
|
+
var useNpmShell3 = process.platform === "win32";
|
|
3938
|
+
function resolveNpmGlobalBin2() {
|
|
3939
|
+
const result = spawnSync3(useNpmShell3 ? "npm.cmd" : "npm", ["bin", "-g"], {
|
|
3940
|
+
encoding: "utf8",
|
|
3941
|
+
shell: useNpmShell3,
|
|
3942
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
3943
|
+
});
|
|
3944
|
+
if (result.status !== 0) {
|
|
3945
|
+
return null;
|
|
4174
3946
|
}
|
|
4175
|
-
|
|
3947
|
+
const bin = result.stdout?.toString().trim();
|
|
3948
|
+
return bin || null;
|
|
4176
3949
|
}
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
"NVM_INC",
|
|
4188
|
-
"FNM_DIR",
|
|
4189
|
-
"VOLTA_HOME",
|
|
4190
|
-
"PNPM_HOME",
|
|
4191
|
-
"npm_config_prefix",
|
|
4192
|
-
"NODE_HOME"
|
|
4193
|
-
];
|
|
4194
|
-
function collectPm2LaunchEnv() {
|
|
4195
|
-
const env = {};
|
|
4196
|
-
for (const key of PM2_LAUNCH_ENV_KEYS) {
|
|
4197
|
-
const value = process.env[key]?.trim();
|
|
4198
|
-
if (value) {
|
|
4199
|
-
env[key] = value;
|
|
4200
|
-
}
|
|
3950
|
+
function prependPath(pathValue, segment) {
|
|
3951
|
+
if (!segment) {
|
|
3952
|
+
return pathValue ?? "";
|
|
3953
|
+
}
|
|
3954
|
+
if (!pathValue) {
|
|
3955
|
+
return segment;
|
|
3956
|
+
}
|
|
3957
|
+
const segments = pathValue.split(PATH_SEP);
|
|
3958
|
+
if (segments.includes(segment)) {
|
|
3959
|
+
return pathValue;
|
|
4201
3960
|
}
|
|
4202
|
-
return
|
|
3961
|
+
return `${segment}${PATH_SEP}${pathValue}`;
|
|
4203
3962
|
}
|
|
4204
|
-
function
|
|
4205
|
-
const env = {};
|
|
4206
|
-
const
|
|
4207
|
-
|
|
4208
|
-
|
|
3963
|
+
function buildDeployShellEnv(extra) {
|
|
3964
|
+
const env = { ...process.env, ...extra };
|
|
3965
|
+
const pathSegments = [dirname4(process.execPath)];
|
|
3966
|
+
const globalBin = resolveNpmGlobalBin2();
|
|
3967
|
+
if (globalBin) {
|
|
3968
|
+
pathSegments.push(globalBin);
|
|
4209
3969
|
}
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
cwd: APM_CONFIG_DIR,
|
|
4214
|
-
autorestart: true,
|
|
4215
|
-
min_uptime: "10s",
|
|
4216
|
-
max_restarts: 10,
|
|
4217
|
-
restart_delay: 3e3,
|
|
4218
|
-
exp_backoff_restart_delay: 1e3,
|
|
4219
|
-
max_memory_restart: "1G",
|
|
4220
|
-
kill_timeout: 5e3,
|
|
4221
|
-
shutdown_with_message: true,
|
|
4222
|
-
instances: 1,
|
|
4223
|
-
exec_mode: "fork",
|
|
4224
|
-
env
|
|
4225
|
-
};
|
|
4226
|
-
if (process.platform === "win32") {
|
|
4227
|
-
app.windowsHide = true;
|
|
3970
|
+
try {
|
|
3971
|
+
resolveApmEntryPath();
|
|
3972
|
+
} catch {
|
|
4228
3973
|
}
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
}
|
|
3974
|
+
for (const segment of pathSegments) {
|
|
3975
|
+
env.PATH = prependPath(env.PATH, segment);
|
|
3976
|
+
}
|
|
3977
|
+
return env;
|
|
4232
3978
|
}
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
3979
|
+
|
|
3980
|
+
// src/commands/deploy/deploy-debug-log.ts
|
|
3981
|
+
var LOG_PREFIX = "[apm:deploy-debug]";
|
|
3982
|
+
var SENSITIVE_ENV_KEY = /(password|secret|token|api[_-]?key|authorization|credential|private|passwd)/i;
|
|
3983
|
+
var PATH_SEP2 = process.platform === "win32" ? ";" : ":";
|
|
3984
|
+
function logLine(message) {
|
|
3985
|
+
console.error(`${LOG_PREFIX} ${message}`);
|
|
3986
|
+
}
|
|
3987
|
+
function pathEntries(value) {
|
|
3988
|
+
if (!value?.trim()) return [];
|
|
3989
|
+
return value.split(PATH_SEP2).filter(Boolean);
|
|
3990
|
+
}
|
|
3991
|
+
function summarizePath(value, maxEntries = 12) {
|
|
3992
|
+
const entries = pathEntries(value);
|
|
3993
|
+
if (entries.length === 0) return "(empty)";
|
|
3994
|
+
const head = entries.slice(0, maxEntries).join(PATH_SEP2);
|
|
3995
|
+
if (entries.length <= maxEntries) return head;
|
|
3996
|
+
return `${head}${PATH_SEP2}\u2026 (+${entries.length - maxEntries} more)`;
|
|
3997
|
+
}
|
|
3998
|
+
function pickEnvKeys(env, keys) {
|
|
3999
|
+
const out = {};
|
|
4000
|
+
for (const key of keys) {
|
|
4001
|
+
const value = env[key];
|
|
4002
|
+
if (value !== void 0 && value !== "") {
|
|
4003
|
+
out[key] = value;
|
|
4004
|
+
}
|
|
4005
|
+
}
|
|
4006
|
+
return out;
|
|
4236
4007
|
}
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4008
|
+
function collectInterestingEnv(env) {
|
|
4009
|
+
const keys = /* @__PURE__ */ new Set([
|
|
4010
|
+
"PATH",
|
|
4011
|
+
"HOME",
|
|
4012
|
+
"USER",
|
|
4013
|
+
"LOGNAME",
|
|
4014
|
+
"SHELL",
|
|
4015
|
+
"LANG",
|
|
4016
|
+
"LC_ALL",
|
|
4017
|
+
"NODE_ENV",
|
|
4018
|
+
"npm_config_registry",
|
|
4019
|
+
"NPM_CONFIG_REGISTRY",
|
|
4020
|
+
"npm_config_prefix",
|
|
4021
|
+
"NPM_CONFIG_PREFIX",
|
|
4022
|
+
APM_DEPLOYMENT_RUN_ID_ENV
|
|
4023
|
+
]);
|
|
4024
|
+
for (const key of Object.keys(env)) {
|
|
4025
|
+
if (/^npm_config_/i.test(key) || /^NPM_CONFIG_/i.test(key)) {
|
|
4026
|
+
keys.add(key);
|
|
4027
|
+
}
|
|
4028
|
+
if (/^APM_/i.test(key) && !SENSITIVE_ENV_KEY.test(key)) {
|
|
4029
|
+
keys.add(key);
|
|
4030
|
+
}
|
|
4031
|
+
}
|
|
4032
|
+
const picked = {};
|
|
4033
|
+
for (const key of [...keys].sort()) {
|
|
4034
|
+
const value = env[key];
|
|
4035
|
+
if (value === void 0 || value === "") continue;
|
|
4036
|
+
picked[key] = SENSITIVE_ENV_KEY.test(key) ? "***" : value;
|
|
4037
|
+
}
|
|
4038
|
+
return picked;
|
|
4243
4039
|
}
|
|
4244
|
-
function
|
|
4245
|
-
const
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
}
|
|
4249
|
-
if (binResult.status !== 0) return null;
|
|
4250
|
-
return binResult.stdout?.toString().trim() || null;
|
|
4040
|
+
function describePathDelta(before, after) {
|
|
4041
|
+
const beforeSet = new Set(pathEntries(before));
|
|
4042
|
+
const added = pathEntries(after).filter((entry) => !beforeSet.has(entry));
|
|
4043
|
+
if (added.length === 0) return "buildDeployShellEnv \u672A prepend \u65B0 PATH \u6BB5";
|
|
4044
|
+
return `prepend: ${added.join(PATH_SEP2)}`;
|
|
4251
4045
|
}
|
|
4252
|
-
function
|
|
4253
|
-
const
|
|
4046
|
+
function probeCommand(label, command, cwd, env) {
|
|
4047
|
+
const result = spawnSync4(command, {
|
|
4048
|
+
cwd,
|
|
4049
|
+
shell: true,
|
|
4050
|
+
env,
|
|
4254
4051
|
encoding: "utf8",
|
|
4255
4052
|
stdio: ["ignore", "pipe", "pipe"]
|
|
4256
4053
|
});
|
|
4257
|
-
|
|
4258
|
-
const
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
}
|
|
4265
|
-
|
|
4266
|
-
return null;
|
|
4054
|
+
const stdout = String(result.stdout ?? "").trim();
|
|
4055
|
+
const stderr = String(result.stderr ?? "").trim();
|
|
4056
|
+
const detail = stdout || stderr || "(no output)";
|
|
4057
|
+
logLine(
|
|
4058
|
+
`probe ${label}: exit=${result.status ?? "null"} output=${detail.slice(
|
|
4059
|
+
0,
|
|
4060
|
+
500
|
|
4061
|
+
)}`
|
|
4062
|
+
);
|
|
4267
4063
|
}
|
|
4268
|
-
function
|
|
4269
|
-
|
|
4064
|
+
function probeShellTooling(cwd, env) {
|
|
4065
|
+
logLine("--- shell \u5DE5\u5177\u63A2\u6D4B\uFF08\u4E0E runDeployShellCommand \u76F8\u540C env/cwd\uFF09---");
|
|
4066
|
+
probeCommand("node -v", "node -v", cwd, env);
|
|
4067
|
+
probeCommand("npm -v", "npm -v", cwd, env);
|
|
4068
|
+
if (process.platform === "win32") {
|
|
4069
|
+
probeCommand("where node", "where node", cwd, env);
|
|
4070
|
+
probeCommand("where npm", "where npm", cwd, env);
|
|
4071
|
+
} else {
|
|
4072
|
+
probeCommand("which node", "which node", cwd, env);
|
|
4073
|
+
probeCommand("which npm", "which npm", cwd, env);
|
|
4074
|
+
}
|
|
4075
|
+
}
|
|
4076
|
+
function logExecuteDeployContext(input) {
|
|
4077
|
+
const trigger = input.trigger ?? "cli";
|
|
4078
|
+
const deploymentRunId = process.env[APM_DEPLOYMENT_RUN_ID_ENV]?.trim() || null;
|
|
4079
|
+
const shellEnv = buildDeployShellEnv();
|
|
4080
|
+
const npmGlobalBin = resolveNpmGlobalBin2();
|
|
4081
|
+
const packageJsonPath = join16(input.cwd, "package.json");
|
|
4082
|
+
logLine("========== executeDeploy \u4E0A\u4E0B\u6587 ==========");
|
|
4083
|
+
logLine(`trigger=${trigger} deployEnv=${input.env}`);
|
|
4084
|
+
logLine(`cwd(input)=${input.cwdInput}`);
|
|
4085
|
+
logLine(`cwd(resolved)=${input.cwd}`);
|
|
4086
|
+
logLine(`process.cwd()=${input.processCwd}`);
|
|
4087
|
+
logLine(
|
|
4088
|
+
`cwdMatchProcess=${input.cwd === input.processCwd ? "yes" : "no"} (connect \u901A\u5E38\u4E3A no)`
|
|
4089
|
+
);
|
|
4090
|
+
logLine(
|
|
4091
|
+
`apm.config=${input.apmConfigPath} exists=${existsSync14(
|
|
4092
|
+
input.apmConfigPath
|
|
4093
|
+
)}`
|
|
4094
|
+
);
|
|
4095
|
+
logLine(
|
|
4096
|
+
`package.json=${packageJsonPath} exists=${existsSync14(packageJsonPath)}`
|
|
4097
|
+
);
|
|
4098
|
+
logLine(
|
|
4099
|
+
`flags captureOutput=${input.captureOutput} packOnly=${Boolean(
|
|
4100
|
+
input.packOnly
|
|
4101
|
+
)} archiveDeployArtifact=${Boolean(input.archiveDeployArtifact)}`
|
|
4102
|
+
);
|
|
4103
|
+
logLine(`configPathOption=${input.configPathOption ?? "(default)"}`);
|
|
4104
|
+
logLine(`${APM_DEPLOYMENT_RUN_ID_ENV}=${deploymentRunId ?? "(unset)"}`);
|
|
4105
|
+
logLine(
|
|
4106
|
+
`process execPath=${process.execPath} pid=${process.pid} platform=${process.platform} arch=${process.arch}`
|
|
4107
|
+
);
|
|
4108
|
+
logLine(`process argv=${process.argv.join(" ")}`);
|
|
4109
|
+
logLine(`npmGlobalBin=${npmGlobalBin ?? "(resolve failed)"}`);
|
|
4110
|
+
logLine(`nodeDir=${dirname5(process.execPath)}`);
|
|
4111
|
+
logLine("--- process.env\uFF08\u8282\u9009\uFF09---");
|
|
4112
|
+
for (const [key, value] of Object.entries(
|
|
4113
|
+
collectInterestingEnv(process.env)
|
|
4114
|
+
)) {
|
|
4115
|
+
logLine(` ${key}=${value}`);
|
|
4116
|
+
}
|
|
4117
|
+
logLine(`process.env.PATH=${summarizePath(process.env.PATH)}`);
|
|
4118
|
+
logLine("--- buildDeployShellEnv()\uFF08\u5B50\u8FDB\u7A0B\u5B9E\u9645 env\uFF09---");
|
|
4119
|
+
logLine(describePathDelta(process.env.PATH, shellEnv.PATH));
|
|
4120
|
+
logLine(`shellEnv.PATH=${summarizePath(shellEnv.PATH)}`);
|
|
4121
|
+
for (const [key, value] of Object.entries(
|
|
4122
|
+
pickEnvKeys(shellEnv, [APM_DEPLOYMENT_RUN_ID_ENV, "NODE_ENV"])
|
|
4123
|
+
)) {
|
|
4124
|
+
logLine(` shellEnv.${key}=${value}`);
|
|
4125
|
+
}
|
|
4126
|
+
probeShellTooling(input.cwd, shellEnv);
|
|
4127
|
+
logLine("==========================================");
|
|
4128
|
+
}
|
|
4129
|
+
function logRunDeployShellContext(input) {
|
|
4130
|
+
const shellEnv = buildDeployShellEnv();
|
|
4131
|
+
logLine("---------- runDeployShellCommand ----------");
|
|
4132
|
+
logLine(`command=${input.command}`);
|
|
4133
|
+
logLine(`cwd=${input.cwd}`);
|
|
4134
|
+
logLine(`captureOutput=${input.captureOutput}`);
|
|
4135
|
+
logLine(
|
|
4136
|
+
`stdio=${input.captureOutput ? "stdin=inherit stdout=pipe stderr=pipe" : "inherit"}`
|
|
4137
|
+
);
|
|
4138
|
+
logLine(`shell=true maxBuffer=${50 * 1024 * 1024}`);
|
|
4139
|
+
logLine(`shellEnv.PATH(head)=${summarizePath(shellEnv.PATH, 8)}`);
|
|
4140
|
+
logLine("--------------------------------------------");
|
|
4270
4141
|
}
|
|
4271
|
-
function
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
prefixArgs: [binPath],
|
|
4276
|
-
displayPath: binPath
|
|
4277
|
-
};
|
|
4278
|
-
}
|
|
4279
|
-
return {
|
|
4280
|
-
command: binPath,
|
|
4281
|
-
prefixArgs: [],
|
|
4282
|
-
displayPath: binPath
|
|
4283
|
-
};
|
|
4142
|
+
function logRunDeployShellResult(input) {
|
|
4143
|
+
logLine(
|
|
4144
|
+
`runDeployShellCommand done command=${input.command} exit=${input.exitCode ?? "null"} signal=${input.signal ?? "null"} capturedBytes=${input.outputBytes}${input.errorMessage ? ` error=${input.errorMessage}` : ""}`
|
|
4145
|
+
);
|
|
4284
4146
|
}
|
|
4285
|
-
function
|
|
4286
|
-
|
|
4287
|
-
|
|
4147
|
+
function logWisdomFrontendDeployContext(input) {
|
|
4148
|
+
logLine("--- wisdom Vue \u524D\u7AEF ---");
|
|
4149
|
+
logLine(
|
|
4150
|
+
`buildKey=build:${input.env} buildCmd=${input.buildCmd ?? "(missing)"}`
|
|
4151
|
+
);
|
|
4152
|
+
logLine(`distDir=${input.distDir} exists=${existsSync14(input.distDir)}`);
|
|
4153
|
+
logLine(
|
|
4154
|
+
`packOnly=${input.packOnly} archiveDeployArtifact=${input.archiveDeployArtifact}`
|
|
4155
|
+
);
|
|
4156
|
+
}
|
|
4157
|
+
|
|
4158
|
+
// src/commands/deploy/internal/wisdom-deploy.ts
|
|
4159
|
+
import { existsSync as existsSync16, readFileSync as readFileSync13, statSync as statSync7 } from "node:fs";
|
|
4160
|
+
import path4 from "node:path";
|
|
4161
|
+
|
|
4162
|
+
// src/commands/deploy/deploy-shell-run.ts
|
|
4163
|
+
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
4164
|
+
function runDeployShellCommand(command, cwd, captureOutput) {
|
|
4165
|
+
logRunDeployShellContext({ command, cwd, captureOutput });
|
|
4166
|
+
const shellEnv = buildDeployShellEnv();
|
|
4167
|
+
const result = spawnSync5(command, {
|
|
4168
|
+
cwd,
|
|
4169
|
+
shell: true,
|
|
4170
|
+
env: shellEnv,
|
|
4288
4171
|
encoding: "utf8",
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
windowsHide: useNpmShell2,
|
|
4292
|
-
...options
|
|
4172
|
+
maxBuffer: DEPLOY_SPAWN_MAX_BUFFER_BYTES,
|
|
4173
|
+
stdio: captureOutput ? ["inherit", "pipe", "pipe"] : "inherit"
|
|
4293
4174
|
});
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
4175
|
+
const stdout = captureOutput ? String(result.stdout ?? "") : "";
|
|
4176
|
+
const stderr = captureOutput ? String(result.stderr ?? "") : "";
|
|
4177
|
+
const output = [stdout, stderr].filter(Boolean).join("\n");
|
|
4178
|
+
logRunDeployShellResult({
|
|
4179
|
+
command,
|
|
4180
|
+
exitCode: result.status,
|
|
4181
|
+
signal: result.signal,
|
|
4182
|
+
errorMessage: result.error?.message,
|
|
4183
|
+
outputBytes: Buffer.byteLength(output, "utf8")
|
|
4304
4184
|
});
|
|
4305
|
-
|
|
4185
|
+
if (captureOutput) {
|
|
4186
|
+
if (stdout) process.stdout.write(stdout);
|
|
4187
|
+
if (stderr) process.stderr.write(stderr);
|
|
4188
|
+
}
|
|
4189
|
+
if (result.error) {
|
|
4190
|
+
throw new DeployExecutionError(
|
|
4191
|
+
`\u90E8\u7F72\u547D\u4EE4\u6267\u884C\u5931\u8D25: ${result.error.message}`,
|
|
4192
|
+
1,
|
|
4193
|
+
output
|
|
4194
|
+
);
|
|
4195
|
+
}
|
|
4196
|
+
if (result.status !== 0) {
|
|
4197
|
+
throw new DeployExecutionError(
|
|
4198
|
+
`\u90E8\u7F72\u547D\u4EE4\u9000\u51FA\u7801 ${result.status ?? "unknown"}: ${command}`,
|
|
4199
|
+
result.status ?? 1,
|
|
4200
|
+
output
|
|
4201
|
+
);
|
|
4202
|
+
}
|
|
4203
|
+
return output;
|
|
4306
4204
|
}
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4205
|
+
|
|
4206
|
+
// src/commands/deploy/internal/wisdom-backend-deploy.ts
|
|
4207
|
+
import {
|
|
4208
|
+
existsSync as existsSync15,
|
|
4209
|
+
mkdirSync as mkdirSync7,
|
|
4210
|
+
readdirSync as readdirSync5,
|
|
4211
|
+
readFileSync as readFileSync12,
|
|
4212
|
+
statSync as statSync6,
|
|
4213
|
+
writeFileSync as writeFileSync12
|
|
4214
|
+
} from "node:fs";
|
|
4215
|
+
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
4216
|
+
import path3 from "node:path";
|
|
4217
|
+
import { Client as Client2 } from "ssh2";
|
|
4218
|
+
import JSZip2 from "jszip";
|
|
4219
|
+
import SftpClient2 from "ssh2-sftp-client";
|
|
4220
|
+
|
|
4221
|
+
// src/commands/deploy/internal/wisdom-sftp.ts
|
|
4222
|
+
import { readdir as readdir2, readFile as readFile3, unlink, writeFile } from "node:fs/promises";
|
|
4223
|
+
import path2 from "node:path";
|
|
4224
|
+
import JSZip from "jszip";
|
|
4225
|
+
import SftpClient from "ssh2-sftp-client";
|
|
4226
|
+
async function addDirToZip(dir, zipFolder) {
|
|
4227
|
+
const entries = await readdir2(dir, { withFileTypes: true });
|
|
4228
|
+
for (const entry of entries) {
|
|
4229
|
+
const fullPath = path2.join(dir, entry.name);
|
|
4230
|
+
if (entry.isDirectory()) {
|
|
4231
|
+
const folder = zipFolder.folder(entry.name);
|
|
4232
|
+
if (folder) {
|
|
4233
|
+
await addDirToZip(fullPath, folder);
|
|
4234
|
+
}
|
|
4314
4235
|
} else {
|
|
4315
|
-
|
|
4236
|
+
const content = await readFile3(fullPath);
|
|
4237
|
+
zipFolder.file(entry.name, content);
|
|
4316
4238
|
}
|
|
4317
4239
|
}
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4240
|
+
}
|
|
4241
|
+
async function zipDirectory(distDir, zipPath) {
|
|
4242
|
+
console.error(`\u538B\u7F29\u76EE\u5F55: ${distDir}`);
|
|
4243
|
+
const zip = new JSZip();
|
|
4244
|
+
await addDirToZip(distDir, zip);
|
|
4245
|
+
const content = await zip.generateAsync({
|
|
4246
|
+
type: "nodebuffer",
|
|
4247
|
+
compression: "DEFLATE",
|
|
4248
|
+
compressionOptions: { level: 6 }
|
|
4327
4249
|
});
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4250
|
+
await writeFile(zipPath, content);
|
|
4251
|
+
const sizeMb = (content.length / 1024 / 1024).toFixed(2);
|
|
4252
|
+
console.error(`\u5DF2\u751F\u6210: ${zipPath} (${sizeMb} MB)`);
|
|
4253
|
+
return content.length;
|
|
4254
|
+
}
|
|
4255
|
+
var SFTP_UPLOAD_MAX_ATTEMPTS = 3;
|
|
4256
|
+
var SFTP_FAST_PUT_OPTIONS = {
|
|
4257
|
+
chunkSize: 64 * 1024,
|
|
4258
|
+
concurrency: 4
|
|
4259
|
+
};
|
|
4260
|
+
function buildSftpConnectOptions(settings) {
|
|
4261
|
+
return {
|
|
4262
|
+
host: settings.host,
|
|
4263
|
+
port: settings.port,
|
|
4264
|
+
username: settings.username,
|
|
4265
|
+
password: settings.password,
|
|
4266
|
+
readyTimeout: 3e4,
|
|
4267
|
+
tryKeyboard: true,
|
|
4268
|
+
keepaliveInterval: 1e4,
|
|
4269
|
+
keepaliveCountMax: 3
|
|
4270
|
+
};
|
|
4271
|
+
}
|
|
4272
|
+
async function sleep(ms) {
|
|
4273
|
+
await new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
4274
|
+
}
|
|
4275
|
+
async function uploadZipWithRetry(settings, localZip, remoteZipPath) {
|
|
4276
|
+
let lastError;
|
|
4277
|
+
for (let attempt = 1; attempt <= SFTP_UPLOAD_MAX_ATTEMPTS; attempt++) {
|
|
4278
|
+
const sftp = new SftpClient();
|
|
4279
|
+
try {
|
|
4280
|
+
if (attempt > 1) {
|
|
4281
|
+
console.error(
|
|
4282
|
+
`SFTP \u4E0A\u4F20\u91CD\u8BD5 (${attempt}/${SFTP_UPLOAD_MAX_ATTEMPTS})...`
|
|
4283
|
+
);
|
|
4284
|
+
}
|
|
4285
|
+
await sftp.connect(buildSftpConnectOptions(settings));
|
|
4286
|
+
await ensureRemoteDir(sftp, settings.remotePath);
|
|
4287
|
+
await sftp.fastPut(localZip, remoteZipPath, SFTP_FAST_PUT_OPTIONS);
|
|
4288
|
+
return sftp;
|
|
4289
|
+
} catch (err) {
|
|
4290
|
+
lastError = err;
|
|
4291
|
+
try {
|
|
4292
|
+
await sftp.end();
|
|
4293
|
+
} catch {
|
|
4294
|
+
}
|
|
4295
|
+
if (attempt < SFTP_UPLOAD_MAX_ATTEMPTS) {
|
|
4296
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
4297
|
+
const delaySec = attempt * 2;
|
|
4298
|
+
console.error(`SFTP \u4E0A\u4F20\u5931\u8D25 (${message})\uFF0C${delaySec}s \u540E\u91CD\u8BD5...`);
|
|
4299
|
+
await sleep(delaySec * 1e3);
|
|
4300
|
+
}
|
|
4336
4301
|
}
|
|
4337
|
-
candidates.push(...fromPath);
|
|
4338
4302
|
}
|
|
4339
|
-
|
|
4303
|
+
throw lastError;
|
|
4340
4304
|
}
|
|
4341
|
-
function
|
|
4342
|
-
const
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4305
|
+
async function ensureRemoteDir(sftp, dir) {
|
|
4306
|
+
const parts = dir.replace(/\\/g, "/").split("/").filter(Boolean);
|
|
4307
|
+
let current = dir.startsWith("/") ? "" : ".";
|
|
4308
|
+
for (const part of parts) {
|
|
4309
|
+
current = current ? `${current}/${part}` : `/${part}`;
|
|
4310
|
+
try {
|
|
4311
|
+
await sftp.mkdir(current, true);
|
|
4312
|
+
} catch {
|
|
4349
4313
|
}
|
|
4350
4314
|
}
|
|
4351
|
-
return null;
|
|
4352
4315
|
}
|
|
4353
|
-
function
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4316
|
+
function execCommand(client, command) {
|
|
4317
|
+
return new Promise((resolve5, reject) => {
|
|
4318
|
+
client.exec(command, (err, stream) => {
|
|
4319
|
+
if (err) return reject(err);
|
|
4320
|
+
let stdout = "";
|
|
4321
|
+
let stderr = "";
|
|
4322
|
+
stream.on("close", (code) => {
|
|
4323
|
+
if (code !== 0) {
|
|
4324
|
+
reject(new Error(`\u8FDC\u7A0B\u547D\u4EE4\u5931\u8D25 (${code}): ${stderr || stdout}`));
|
|
4325
|
+
return;
|
|
4326
|
+
}
|
|
4327
|
+
resolve5(stdout);
|
|
4328
|
+
}).on("data", (data) => {
|
|
4329
|
+
stdout += data.toString();
|
|
4330
|
+
});
|
|
4331
|
+
stream.stderr.on("data", (data) => {
|
|
4332
|
+
stderr += data.toString();
|
|
4333
|
+
});
|
|
4334
|
+
});
|
|
4358
4335
|
});
|
|
4359
|
-
if (result.status !== 0) {
|
|
4360
|
-
console.error("[apm] \u5B89\u88C5 pm2 \u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u6267\u884C: npm install -g pm2");
|
|
4361
|
-
process.exit(result.status ?? 1);
|
|
4362
|
-
}
|
|
4363
4336
|
}
|
|
4364
|
-
function
|
|
4365
|
-
|
|
4366
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
4367
|
-
});
|
|
4368
|
-
if (result.error || result.status !== 0) {
|
|
4369
|
-
return null;
|
|
4370
|
-
}
|
|
4371
|
-
return result.stdout?.toString().trim() || null;
|
|
4337
|
+
function shellSingleQuote(value) {
|
|
4338
|
+
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
4372
4339
|
}
|
|
4373
|
-
function
|
|
4374
|
-
const
|
|
4375
|
-
const
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4340
|
+
function buildClearRemoteDirExceptZipCommand(target) {
|
|
4341
|
+
const normalized = target.replace(/\\/g, "/").replace(/\/$/, "");
|
|
4342
|
+
const quotedTarget = shellSingleQuote(normalized);
|
|
4343
|
+
const script = [
|
|
4344
|
+
`T=${quotedTarget}`,
|
|
4345
|
+
"S=$(mktemp -d)",
|
|
4346
|
+
'while IFS= read -r -d "" z; do r="${z#${T}/}"',
|
|
4347
|
+
'mkdir -p "${S}/$(dirname "$r")"',
|
|
4348
|
+
'mv "$z" "${S}/${r}"',
|
|
4349
|
+
'done < <(find "$T" -mindepth 1 -type f -iname "*.zip" -print0)',
|
|
4350
|
+
'rm -rf "${T}"/*',
|
|
4351
|
+
'while IFS= read -r -d "" r; do r="${r#./}"',
|
|
4352
|
+
'mkdir -p "${T}/$(dirname "$r")"',
|
|
4353
|
+
'mv "${S}/${r}" "${T}/${r}"',
|
|
4354
|
+
'done < <(cd "$S" 2>/dev/null && find . -type f -print0)',
|
|
4355
|
+
'rm -rf "$S"'
|
|
4356
|
+
].join("; ");
|
|
4357
|
+
return `bash -c ${shellSingleQuote(script)}`;
|
|
4381
4358
|
}
|
|
4382
|
-
function
|
|
4383
|
-
|
|
4359
|
+
async function uploadAndMaybeExtract(settings, localZip, extract) {
|
|
4360
|
+
const remoteZipPath = `${settings.remotePath.replace(/\/$/, "")}/dist.zip`;
|
|
4361
|
+
console.error(
|
|
4362
|
+
`\u8FDE\u63A5 ${settings.username}@${settings.host}:${settings.port} ...`
|
|
4363
|
+
);
|
|
4364
|
+
const sftp = await uploadZipWithRetry(settings, localZip, remoteZipPath);
|
|
4365
|
+
try {
|
|
4366
|
+
console.error(` \u2713 ${localZip} -> ${remoteZipPath}`);
|
|
4367
|
+
if (extract) {
|
|
4368
|
+
const target = settings.remotePath.replace(/\/$/, "");
|
|
4369
|
+
const client = sftp.client;
|
|
4370
|
+
const clearCmd = buildClearRemoteDirExceptZipCommand(target);
|
|
4371
|
+
console.error(`\u8FDC\u7A0B\u6E05\u7406\u89E3\u538B\u76EE\u5F55: ${clearCmd}`);
|
|
4372
|
+
await execCommand(client, clearCmd);
|
|
4373
|
+
const unzipCmd = `unzip -o "${remoteZipPath}" -d "${target}"`;
|
|
4374
|
+
console.error(`\u8FDC\u7A0B\u89E3\u538B: ${unzipCmd}`);
|
|
4375
|
+
await execCommand(client, unzipCmd);
|
|
4376
|
+
console.error("\u8FDC\u7A0B\u89E3\u538B\u5B8C\u6210!");
|
|
4377
|
+
}
|
|
4378
|
+
console.error(extract ? "\u90E8\u7F72\u5B8C\u6210!" : "\u4E0A\u4F20\u5B8C\u6210!");
|
|
4379
|
+
} finally {
|
|
4380
|
+
await sftp.end();
|
|
4381
|
+
}
|
|
4384
4382
|
}
|
|
4385
|
-
function
|
|
4386
|
-
const
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
const combined = `${probe.stdout ?? ""}
|
|
4390
|
-
${probe.stderr ?? ""}`;
|
|
4391
|
-
if (!isPm2DaemonOutOfDate(combined)) {
|
|
4392
|
-
return;
|
|
4383
|
+
function resolveDeployArtifactUpload(input) {
|
|
4384
|
+
const { packOnly, archiveDeployArtifact, deploymentRunId } = input;
|
|
4385
|
+
if (deploymentRunId) {
|
|
4386
|
+
return { upload: true, uploadWithoutRunId: false };
|
|
4393
4387
|
}
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
stdio: "inherit"
|
|
4397
|
-
});
|
|
4398
|
-
if (update.error || update.status !== 0) {
|
|
4399
|
-
console.error("[apm] pm2 update \u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u6267\u884C: pm2 update");
|
|
4388
|
+
if (archiveDeployArtifact || packOnly) {
|
|
4389
|
+
return { upload: true, uploadWithoutRunId: true };
|
|
4400
4390
|
}
|
|
4391
|
+
return { upload: false, uploadWithoutRunId: false };
|
|
4401
4392
|
}
|
|
4402
|
-
function
|
|
4403
|
-
const
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4393
|
+
async function runWisdomSftpDeploy(params) {
|
|
4394
|
+
const zipPath = path2.join(params.localDir, "..", ".deploy-sftp-dist.zip");
|
|
4395
|
+
const resolvedZipPath = path2.resolve(zipPath);
|
|
4396
|
+
const packOnly = Boolean(params.packOnly);
|
|
4397
|
+
const archiveDeployArtifact = Boolean(params.archiveDeployArtifact);
|
|
4398
|
+
const deploymentRunId = resolveDeploymentRunIdFromEnv();
|
|
4399
|
+
const artifactUpload = resolveDeployArtifactUpload({
|
|
4400
|
+
packOnly,
|
|
4401
|
+
archiveDeployArtifact,
|
|
4402
|
+
deploymentRunId
|
|
4403
|
+
});
|
|
4404
|
+
let zipSizeBytes = 0;
|
|
4405
|
+
let artifactUploaded = false;
|
|
4406
|
+
try {
|
|
4407
|
+
zipSizeBytes = await zipDirectory(params.localDir, resolvedZipPath);
|
|
4408
|
+
if (!packOnly) {
|
|
4409
|
+
await uploadAndMaybeExtract(
|
|
4410
|
+
params.settings,
|
|
4411
|
+
resolvedZipPath,
|
|
4412
|
+
params.extract
|
|
4413
|
+
);
|
|
4414
|
+
} else {
|
|
4415
|
+
console.error("[apm] \u4EC5\u6253\u5305\u6A21\u5F0F\uFF1A\u8DF3\u8FC7 SFTP \u8FDC\u7A0B\u4E0A\u4F20");
|
|
4408
4416
|
}
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
"[apm] \u5B89\u88C5 pm2 \u540E\u4ECD\u65E0\u6CD5\u627E\u5230\u53EF\u6267\u884C\u6587\u4EF6\uFF0C\u8BF7\u624B\u52A8\u6267\u884C: npm install -g pm2"
|
|
4418
|
-
);
|
|
4419
|
-
if (globalBin) {
|
|
4420
|
-
console.error(`[apm] npm \u5168\u5C40 bin: ${globalBin}`);
|
|
4417
|
+
if (artifactUpload.upload) {
|
|
4418
|
+
const artifact = await uploadDeployArtifactZip({
|
|
4419
|
+
zipPath: resolvedZipPath,
|
|
4420
|
+
projectName: params.projectName,
|
|
4421
|
+
kind: "frontend",
|
|
4422
|
+
uploadWithoutRunId: artifactUpload.uploadWithoutRunId
|
|
4423
|
+
});
|
|
4424
|
+
artifactUploaded = artifact !== null;
|
|
4421
4425
|
}
|
|
4422
|
-
if (
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4426
|
+
if (artifactUploaded) {
|
|
4427
|
+
if (packOnly) {
|
|
4428
|
+
console.error("\u6253\u5305\u5E76\u4E0A\u4F20 MinIO \u5B8C\u6210\uFF08\u672A\u4E0A\u4F20\u8FDC\u7A0B\u670D\u52A1\u5668\uFF09");
|
|
4429
|
+
} else {
|
|
4430
|
+
console.error("[apm] SFTP \u90E8\u7F72\u5B8C\u6210\uFF0C\u90E8\u7F72\u4EA7\u7269\u5DF2\u5F52\u6863 MinIO");
|
|
4431
|
+
}
|
|
4432
|
+
}
|
|
4433
|
+
} finally {
|
|
4434
|
+
try {
|
|
4435
|
+
await unlink(resolvedZipPath);
|
|
4436
|
+
console.error(`\u5DF2\u6E05\u7406\u672C\u5730\u4E34\u65F6\u6587\u4EF6: ${resolvedZipPath}`);
|
|
4437
|
+
} catch {
|
|
4427
4438
|
}
|
|
4428
|
-
process.exit(1);
|
|
4429
|
-
}
|
|
4430
|
-
ensurePm2DaemonUpdated(installed2);
|
|
4431
|
-
if (!options?.quiet) {
|
|
4432
|
-
logPm2Ready(installed2, true);
|
|
4433
4439
|
}
|
|
4434
|
-
return
|
|
4440
|
+
return {
|
|
4441
|
+
ok: true,
|
|
4442
|
+
localDir: params.localDir,
|
|
4443
|
+
host: params.settings.host,
|
|
4444
|
+
remotePath: params.settings.remotePath,
|
|
4445
|
+
zipSizeBytes,
|
|
4446
|
+
extracted: packOnly ? false : params.extract,
|
|
4447
|
+
packOnly,
|
|
4448
|
+
artifactUploaded
|
|
4449
|
+
};
|
|
4435
4450
|
}
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4451
|
+
|
|
4452
|
+
// src/commands/deploy/internal/wisdom-backend-deploy.ts
|
|
4453
|
+
var SPRINGBOOT_JAVA_OPTS = "-XX:+UseG1GC -XX:+HeapDumpOnOutOfMemoryError -Xms512M -Xmx1G";
|
|
4454
|
+
var MAVEN_MODULE = "jeecg-module-system/jeecg-system-start";
|
|
4455
|
+
var MAVEN_PROFILE = "dev";
|
|
4456
|
+
function log(message) {
|
|
4457
|
+
const now = /* @__PURE__ */ new Date();
|
|
4458
|
+
const hh = String(now.getHours()).padStart(2, "0");
|
|
4459
|
+
const mm = String(now.getMinutes()).padStart(2, "0");
|
|
4460
|
+
const ss = String(now.getSeconds()).padStart(2, "0");
|
|
4461
|
+
console.error(`[${hh}:${mm}:${ss}] ${message}`);
|
|
4462
|
+
}
|
|
4463
|
+
function fail(message) {
|
|
4464
|
+
log(`ERROR: ${message}`);
|
|
4465
|
+
process.exit(1);
|
|
4466
|
+
}
|
|
4467
|
+
function expandPath(pathStr) {
|
|
4468
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
4469
|
+
return path3.resolve(pathStr.replace(/^~(?=\/|\\|$)/, home));
|
|
4470
|
+
}
|
|
4471
|
+
function quoteForShell(value) {
|
|
4472
|
+
if (process.platform === "win32") {
|
|
4473
|
+
return `"${value.replace(/"/g, '""')}"`;
|
|
4440
4474
|
}
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
if (npmResult.status === 0) {
|
|
4447
|
-
const globalRoot = npmResult.stdout?.toString().trim();
|
|
4448
|
-
if (globalRoot) {
|
|
4449
|
-
const candidate = join15(globalRoot, CLI_PACKAGE_NAME, "dist", "index.js");
|
|
4450
|
-
if (existsSync14(candidate)) {
|
|
4451
|
-
return candidate;
|
|
4452
|
-
}
|
|
4453
|
-
}
|
|
4475
|
+
return shellSingleQuote(value);
|
|
4476
|
+
}
|
|
4477
|
+
function formatMavenLocalRepoArg(repoPath) {
|
|
4478
|
+
if (process.platform === "win32") {
|
|
4479
|
+
return `-Dmaven.repo.local=${quoteForShell(repoPath)}`;
|
|
4454
4480
|
}
|
|
4455
|
-
|
|
4456
|
-
|
|
4481
|
+
return `-Dmaven.repo.local=${repoPath}`;
|
|
4482
|
+
}
|
|
4483
|
+
function deployCacheDir() {
|
|
4484
|
+
return path3.join(workspaceApmDir(), "deploy", ".deploy_cache");
|
|
4485
|
+
}
|
|
4486
|
+
function manifestFilePath() {
|
|
4487
|
+
return path3.join(deployCacheDir(), "manifest.json");
|
|
4488
|
+
}
|
|
4489
|
+
function getTargetDir(projectRoot) {
|
|
4490
|
+
return path3.join(projectRoot, MAVEN_MODULE, "target");
|
|
4491
|
+
}
|
|
4492
|
+
function relativeKey(projectRoot, filePath) {
|
|
4493
|
+
return path3.relative(projectRoot, filePath).split(path3.sep).join("/");
|
|
4494
|
+
}
|
|
4495
|
+
function fileSignature(filePath) {
|
|
4496
|
+
const stat2 = statSync6(filePath);
|
|
4497
|
+
return { size: stat2.size, mtime: stat2.mtimeMs / 1e3 };
|
|
4498
|
+
}
|
|
4499
|
+
function loadManifest3() {
|
|
4500
|
+
const manifestPath2 = manifestFilePath();
|
|
4501
|
+
if (!existsSync15(manifestPath2)) {
|
|
4502
|
+
return {};
|
|
4457
4503
|
}
|
|
4458
|
-
|
|
4459
|
-
process.exit(1);
|
|
4504
|
+
return JSON.parse(readFileSync12(manifestPath2, "utf8"));
|
|
4460
4505
|
}
|
|
4461
|
-
function
|
|
4462
|
-
|
|
4463
|
-
|
|
4506
|
+
function saveManifest3(manifest) {
|
|
4507
|
+
const dir = deployCacheDir();
|
|
4508
|
+
mkdirSync7(dir, { recursive: true });
|
|
4509
|
+
writeFileSync12(manifestFilePath(), JSON.stringify(manifest, null, 2), "utf8");
|
|
4510
|
+
}
|
|
4511
|
+
function isProjectLibJar(jarName) {
|
|
4512
|
+
return jarName.startsWith("jeecg-");
|
|
4513
|
+
}
|
|
4514
|
+
function shouldUploadLibFile(localPath, remoteAttr, manifest, projectRoot) {
|
|
4515
|
+
if (!remoteAttr) {
|
|
4516
|
+
return [false, "\u8FDC\u7A0B\u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7"];
|
|
4464
4517
|
}
|
|
4465
|
-
|
|
4466
|
-
|
|
4518
|
+
const localSize = statSync6(localPath).size;
|
|
4519
|
+
const remoteSize = remoteAttr.size;
|
|
4520
|
+
if (localSize !== remoteSize) {
|
|
4521
|
+
return [true, `\u5927\u5C0F\u53D8\u5316 ${remoteSize} -> ${localSize}`];
|
|
4467
4522
|
}
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4523
|
+
if (isProjectLibJar(path3.basename(localPath)) && manifest) {
|
|
4524
|
+
const key = relativeKey(projectRoot, localPath);
|
|
4525
|
+
const current = fileSignature(localPath);
|
|
4526
|
+
const previous = manifest[key];
|
|
4527
|
+
if (!previous) {
|
|
4528
|
+
return [true, "\u9879\u76EE\u6A21\u5757\u672A\u8BB0\u5F55"];
|
|
4529
|
+
}
|
|
4530
|
+
if (previous.size !== current.size) {
|
|
4531
|
+
return [true, "\u9879\u76EE\u6A21\u5757\u5927\u5C0F\u53D8\u5316"];
|
|
4532
|
+
}
|
|
4533
|
+
if (previous.mtime < current.mtime) {
|
|
4534
|
+
return [true, "\u9879\u76EE\u6A21\u5757\u91CD\u65B0\u6784\u5EFA"];
|
|
4535
|
+
}
|
|
4474
4536
|
}
|
|
4475
|
-
return
|
|
4537
|
+
return [false, "\u5927\u5C0F\u4E00\u81F4\uFF0C\u8DF3\u8FC7"];
|
|
4476
4538
|
}
|
|
4477
|
-
function
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4539
|
+
function listLibFilesToUpload(localLibDir, remoteStats, projectRoot, manifest = null) {
|
|
4540
|
+
const entries = [];
|
|
4541
|
+
const jarFiles = readdirSync5(localLibDir).filter((name) => name.endsWith(".jar")).sort();
|
|
4542
|
+
for (const jarName of jarFiles) {
|
|
4543
|
+
const jarPath = path3.join(localLibDir, jarName);
|
|
4544
|
+
const remoteAttr = remoteStats.get(jarName);
|
|
4545
|
+
const [shouldUpload, reason] = shouldUploadLibFile(
|
|
4546
|
+
jarPath,
|
|
4547
|
+
remoteAttr,
|
|
4548
|
+
manifest,
|
|
4549
|
+
projectRoot
|
|
4550
|
+
);
|
|
4551
|
+
if (shouldUpload) {
|
|
4552
|
+
entries.push({ path: jarPath, arcname: jarName, reason });
|
|
4553
|
+
}
|
|
4483
4554
|
}
|
|
4555
|
+
return entries;
|
|
4484
4556
|
}
|
|
4485
|
-
function
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
return
|
|
4557
|
+
function updateManifestEntries(manifest, entries, projectRoot) {
|
|
4558
|
+
for (const entry of entries) {
|
|
4559
|
+
manifest[relativeKey(projectRoot, entry.path)] = fileSignature(entry.path);
|
|
4560
|
+
}
|
|
4561
|
+
return manifest;
|
|
4490
4562
|
}
|
|
4491
|
-
function
|
|
4492
|
-
const
|
|
4493
|
-
|
|
4494
|
-
|
|
4563
|
+
async function createUpdatePackage(entries, packageName) {
|
|
4564
|
+
const dir = deployCacheDir();
|
|
4565
|
+
mkdirSync7(dir, { recursive: true });
|
|
4566
|
+
const zipPath = path3.join(dir, packageName);
|
|
4567
|
+
log(`\u521B\u5EFA\u66F4\u65B0\u5305: ${path3.basename(zipPath)}\uFF08${entries.length} \u4E2A\u6587\u4EF6\uFF09`);
|
|
4568
|
+
const zip = new JSZip2();
|
|
4569
|
+
for (const entry of entries) {
|
|
4570
|
+
const content = readFileSync12(entry.path);
|
|
4571
|
+
zip.file(entry.arcname, content);
|
|
4572
|
+
log(` \u6253\u5305: ${entry.arcname} (${entry.reason})`);
|
|
4495
4573
|
}
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4574
|
+
const buffer = await zip.generateAsync({
|
|
4575
|
+
type: "nodebuffer",
|
|
4576
|
+
compression: "DEFLATE",
|
|
4577
|
+
compressionOptions: { level: 6 }
|
|
4499
4578
|
});
|
|
4579
|
+
writeFileSync12(zipPath, buffer);
|
|
4580
|
+
return zipPath;
|
|
4500
4581
|
}
|
|
4501
|
-
function
|
|
4502
|
-
const
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4582
|
+
function getMvnExecutable() {
|
|
4583
|
+
const isWin = process.platform === "win32";
|
|
4584
|
+
const candidates = isWin ? ["mvn.cmd", "mvn.bat", "mvn"] : ["mvn"];
|
|
4585
|
+
for (const name of candidates) {
|
|
4586
|
+
const result = spawnSync6(isWin ? `where ${name}` : `which ${name}`, {
|
|
4587
|
+
encoding: "utf8",
|
|
4588
|
+
shell: true
|
|
4589
|
+
});
|
|
4590
|
+
if (result.status === 0 && result.stdout.trim()) {
|
|
4591
|
+
return result.stdout.trim().split(/\r?\n/)[0].trim();
|
|
4506
4592
|
}
|
|
4507
|
-
seen.add(app.name);
|
|
4508
|
-
deletePm2AppIfExists(app.name);
|
|
4509
|
-
}
|
|
4510
|
-
for (const legacyName of LEGACY_PM2_APP_NAMES) {
|
|
4511
|
-
deletePm2AppIfExists(legacyName);
|
|
4512
4593
|
}
|
|
4513
|
-
|
|
4594
|
+
fail("\u672A\u627E\u5230 mvn \u547D\u4EE4\uFF0C\u8BF7\u786E\u8BA4 Maven \u5DF2\u5B89\u88C5\u5E76\u52A0\u5165 PATH");
|
|
4514
4595
|
}
|
|
4515
|
-
function
|
|
4516
|
-
const
|
|
4517
|
-
const
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4596
|
+
function runMavenBuild(projectRoot, mavenLocalRepo, repoSource) {
|
|
4597
|
+
const mavenRepo = expandPath(mavenLocalRepo);
|
|
4598
|
+
const mvn = getMvnExecutable();
|
|
4599
|
+
const command = [
|
|
4600
|
+
quoteForShell(mvn),
|
|
4601
|
+
"clean",
|
|
4602
|
+
"package",
|
|
4603
|
+
`-P${MAVEN_PROFILE}`,
|
|
4604
|
+
formatMavenLocalRepoArg(mavenRepo),
|
|
4605
|
+
"-DskipTests"
|
|
4606
|
+
].join(" ");
|
|
4607
|
+
log("\u5F00\u59CB Maven \u6784\u5EFA...");
|
|
4608
|
+
if (repoSource) {
|
|
4609
|
+
log(
|
|
4610
|
+
`Maven \u672C\u5730\u4ED3\u5E93: ${mavenRepo} (\u6765\u6E90: ${repoSource.source}/${repoSource.sourceDetail})`
|
|
4611
|
+
);
|
|
4612
|
+
} else {
|
|
4613
|
+
log(`Maven \u672C\u5730\u4ED3\u5E93: ${mavenRepo}`);
|
|
4523
4614
|
}
|
|
4615
|
+
log(`\u6784\u5EFA\u76EE\u5F55: ${projectRoot}`);
|
|
4616
|
+
const result = spawnSync6(command, {
|
|
4617
|
+
cwd: projectRoot,
|
|
4618
|
+
stdio: "inherit",
|
|
4619
|
+
shell: true,
|
|
4620
|
+
env: process.env
|
|
4621
|
+
});
|
|
4524
4622
|
if (result.status !== 0) {
|
|
4525
|
-
|
|
4526
|
-
const stdout = result.stdout?.toString().trim();
|
|
4527
|
-
const detail = stderr || stdout || `exit code ${result.status}`;
|
|
4528
|
-
console.error(`[apm] pm2 ${args.join(" ")} \u5931\u8D25: ${detail}`);
|
|
4529
|
-
process.exit(result.status ?? 1);
|
|
4623
|
+
fail(`Maven \u6784\u5EFA\u5931\u8D25\uFF0C\u9000\u51FA\u7801: ${result.status ?? 1}`);
|
|
4530
4624
|
}
|
|
4531
4625
|
}
|
|
4532
|
-
function
|
|
4533
|
-
const
|
|
4534
|
-
if (!
|
|
4535
|
-
|
|
4626
|
+
function locateLibDir(projectRoot) {
|
|
4627
|
+
const targetDir = getTargetDir(projectRoot);
|
|
4628
|
+
if (!existsSync15(targetDir)) {
|
|
4629
|
+
fail(`\u6784\u5EFA\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728: ${targetDir}`);
|
|
4536
4630
|
}
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
}
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
}
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
const status = app.pm2_env?.status;
|
|
4548
|
-
return status === "online" || status === "launching";
|
|
4549
|
-
}
|
|
4550
|
-
function printConnectNotRunningHint() {
|
|
4551
|
-
console.log(`[apm] ${PM2_APP_NAME} \u672A\u5728\u8FD0\u884C`);
|
|
4552
|
-
console.log("[apm] \u542F\u52A8\u5B88\u62A4: apm connect --daemon");
|
|
4631
|
+
const libDir = path3.join(targetDir, "lib");
|
|
4632
|
+
if (!existsSync15(libDir) || !statSync6(libDir).isDirectory()) {
|
|
4633
|
+
fail(`lib \u76EE\u5F55\u4E0D\u5B58\u5728: ${libDir}`);
|
|
4634
|
+
}
|
|
4635
|
+
const libJars = readdirSync5(libDir).filter((name) => name.endsWith(".jar"));
|
|
4636
|
+
if (libJars.length === 0) {
|
|
4637
|
+
fail(`lib \u76EE\u5F55\u4E0B\u6CA1\u6709\u4F9D\u8D56 JAR: ${libDir}`);
|
|
4638
|
+
}
|
|
4639
|
+
log(`\u5B9A\u4F4D lib \u4EA7\u7269: ${libJars.length} \u4E2A`);
|
|
4640
|
+
return libDir;
|
|
4553
4641
|
}
|
|
4554
|
-
function
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
console.error(
|
|
4559
|
-
`[apm] \u5DF2\u6709 apm connect \u5728\u8FD0\u884C (pid=${lock.pid}, mode=${lock.mode})\uFF0C\u8BF7\u5148\u505C\u6B62\u540E\u518D\u542F\u52A8`
|
|
4560
|
-
);
|
|
4561
|
-
process.exit(1);
|
|
4642
|
+
function locateMainJar(projectRoot) {
|
|
4643
|
+
const targetDir = getTargetDir(projectRoot);
|
|
4644
|
+
if (!existsSync15(targetDir)) {
|
|
4645
|
+
fail(`\u6784\u5EFA\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728: ${targetDir}`);
|
|
4562
4646
|
}
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
);
|
|
4567
|
-
process.exit(1);
|
|
4647
|
+
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);
|
|
4648
|
+
if (jarFiles.length === 0) {
|
|
4649
|
+
fail(`target \u76EE\u5F55\u4E0B\u6CA1\u6709\u4E3B JAR: ${targetDir}`);
|
|
4568
4650
|
}
|
|
4651
|
+
const mainJar = jarFiles[0];
|
|
4652
|
+
log(`\u5B9A\u4F4D\u4E3B JAR \u4EA7\u7269: ${path3.basename(mainJar)}`);
|
|
4653
|
+
return mainJar;
|
|
4569
4654
|
}
|
|
4570
|
-
function
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4655
|
+
async function connectSsh(config) {
|
|
4656
|
+
const client = new Client2();
|
|
4657
|
+
log(`\u8FDE\u63A5\u670D\u52A1\u5668 ${config.username}@${config.host}:${config.port}`);
|
|
4658
|
+
await new Promise((resolve5, reject) => {
|
|
4659
|
+
client.on("ready", () => resolve5()).on("error", (err) => reject(err)).connect({
|
|
4660
|
+
host: config.host,
|
|
4661
|
+
port: config.port,
|
|
4662
|
+
username: config.username,
|
|
4663
|
+
password: config.password,
|
|
4664
|
+
readyTimeout: 3e4,
|
|
4665
|
+
tryKeyboard: true
|
|
4666
|
+
});
|
|
4667
|
+
});
|
|
4668
|
+
const sftp = new SftpClient2();
|
|
4669
|
+
await sftp.connect({
|
|
4670
|
+
host: config.host,
|
|
4671
|
+
port: config.port,
|
|
4672
|
+
username: config.username,
|
|
4673
|
+
password: config.password,
|
|
4674
|
+
readyTimeout: 3e4,
|
|
4675
|
+
tryKeyboard: true
|
|
4676
|
+
});
|
|
4677
|
+
return { client, sftp };
|
|
4575
4678
|
}
|
|
4576
|
-
function
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
if (server) {
|
|
4581
|
-
args.push("--server", server);
|
|
4582
|
-
}
|
|
4583
|
-
const result = spawnSync3(process.execPath, args, { stdio: "inherit" });
|
|
4584
|
-
if (result.error) {
|
|
4585
|
-
console.error("[apm] \u91CD\u542F connect \u5931\u8D25:", result.error.message);
|
|
4586
|
-
process.exit(1);
|
|
4679
|
+
async function closeSsh(conn) {
|
|
4680
|
+
try {
|
|
4681
|
+
await conn.sftp.end();
|
|
4682
|
+
} catch {
|
|
4587
4683
|
}
|
|
4588
|
-
|
|
4684
|
+
conn.client.end();
|
|
4589
4685
|
}
|
|
4590
|
-
async function
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4686
|
+
async function getRemoteFileStats(sftp, remoteDir) {
|
|
4687
|
+
const stats = /* @__PURE__ */ new Map();
|
|
4688
|
+
try {
|
|
4689
|
+
const listing = await sftp.list(remoteDir);
|
|
4690
|
+
for (const item of listing) {
|
|
4691
|
+
if (item.name.endsWith(".jar")) {
|
|
4692
|
+
stats.set(item.name, { filename: item.name, size: item.size });
|
|
4693
|
+
}
|
|
4694
|
+
}
|
|
4695
|
+
} catch {
|
|
4597
4696
|
}
|
|
4598
|
-
|
|
4697
|
+
return stats;
|
|
4599
4698
|
}
|
|
4600
|
-
async function
|
|
4601
|
-
|
|
4602
|
-
|
|
4699
|
+
async function uploadUpdatePackage(sftp, zipPath, config) {
|
|
4700
|
+
const remoteDir = config.remoteVueDistDir.replace(/\/$/, "");
|
|
4701
|
+
const remotePath = `${remoteDir}/${path3.basename(zipPath)}`;
|
|
4702
|
+
log(`\u4E0A\u4F20\u66F4\u65B0\u5305 -> ${remotePath}`);
|
|
4703
|
+
try {
|
|
4704
|
+
await sftp.fastPut(zipPath, remotePath);
|
|
4705
|
+
log("\u66F4\u65B0\u5305\u4E0A\u4F20\u6210\u529F");
|
|
4706
|
+
} catch (err) {
|
|
4707
|
+
fail(`\u66F4\u65B0\u5305\u4E0A\u4F20\u5931\u8D25: ${err instanceof Error ? err.message : err}`);
|
|
4603
4708
|
}
|
|
4604
|
-
|
|
4605
|
-
return cfg?.baseUrl;
|
|
4709
|
+
return remotePath;
|
|
4606
4710
|
}
|
|
4607
|
-
function
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4711
|
+
async function uploadFullJar(sftp, localJarPath, config) {
|
|
4712
|
+
const remoteDir = config.remoteAppDir.replace(/\/$/, "");
|
|
4713
|
+
const remotePath = `${remoteDir}/${config.startupJar}`;
|
|
4714
|
+
log(`\u4E0A\u4F20\u5168\u91CF JAR (${path3.basename(localJarPath)}) -> ${remotePath}`);
|
|
4715
|
+
try {
|
|
4716
|
+
await sftp.mkdir(remoteDir, true);
|
|
4717
|
+
await sftp.fastPut(localJarPath, remotePath);
|
|
4718
|
+
log("\u5168\u91CF JAR \u4E0A\u4F20\u6210\u529F");
|
|
4719
|
+
} catch (err) {
|
|
4720
|
+
fail(`\u5168\u91CF JAR \u4E0A\u4F20\u5931\u8D25: ${err instanceof Error ? err.message : err}`);
|
|
4616
4721
|
}
|
|
4617
|
-
const launch = {
|
|
4618
|
-
nodePath: options.nodePath,
|
|
4619
|
-
apmScript: options.apmScript,
|
|
4620
|
-
connectArgs: options.connectArgs,
|
|
4621
|
-
cwd: options.cwd,
|
|
4622
|
-
env
|
|
4623
|
-
};
|
|
4624
|
-
writeFileSync12(
|
|
4625
|
-
PM2_CONNECT_LAUNCH_PATH,
|
|
4626
|
-
JSON.stringify(launch, null, 2) + "\n",
|
|
4627
|
-
"utf8"
|
|
4628
|
-
);
|
|
4629
4722
|
}
|
|
4630
|
-
function
|
|
4631
|
-
|
|
4632
|
-
const
|
|
4633
|
-
|
|
4634
|
-
|
|
4723
|
+
async function runRemoteCommand(client, command, options) {
|
|
4724
|
+
const check = options?.check ?? true;
|
|
4725
|
+
const stream = options?.stream ?? false;
|
|
4726
|
+
const label = options?.label ?? "\u8FDC\u7A0B\u547D\u4EE4";
|
|
4727
|
+
return new Promise((resolve5, reject) => {
|
|
4728
|
+
client.exec(command, (err, execStream) => {
|
|
4729
|
+
if (err) {
|
|
4730
|
+
reject(err);
|
|
4731
|
+
return;
|
|
4732
|
+
}
|
|
4733
|
+
let out = "";
|
|
4734
|
+
let errText = "";
|
|
4735
|
+
execStream.on("data", (data) => {
|
|
4736
|
+
const text = data.toString();
|
|
4737
|
+
out += text;
|
|
4738
|
+
if (stream) {
|
|
4739
|
+
process.stdout.write(text);
|
|
4740
|
+
}
|
|
4741
|
+
});
|
|
4742
|
+
execStream.stderr.on("data", (data) => {
|
|
4743
|
+
errText += data.toString();
|
|
4744
|
+
});
|
|
4745
|
+
execStream.on("close", (code) => {
|
|
4746
|
+
if (stream && out && !out.endsWith("\n")) {
|
|
4747
|
+
process.stdout.write("\n");
|
|
4748
|
+
}
|
|
4749
|
+
if (check && code !== 0) {
|
|
4750
|
+
const combined = `${out}
|
|
4751
|
+
${errText}`.trim();
|
|
4752
|
+
fail(
|
|
4753
|
+
`${label}\u5931\u8D25 (exit ${code})` + (combined ? `
|
|
4754
|
+
\u8F93\u51FA: ${combined}` : "")
|
|
4755
|
+
);
|
|
4756
|
+
}
|
|
4757
|
+
resolve5({ exitCode: code, out: out.trim(), err: errText.trim() });
|
|
4758
|
+
});
|
|
4759
|
+
});
|
|
4635
4760
|
});
|
|
4636
|
-
writeFileSync12(
|
|
4637
|
-
PM2_ECOSYSTEM_PATH,
|
|
4638
|
-
formatConnectPm2EcosystemFile(ecosystem),
|
|
4639
|
-
"utf8"
|
|
4640
|
-
);
|
|
4641
|
-
if (existsSync14(LEGACY_PM2_ECOSYSTEM_PATH)) {
|
|
4642
|
-
try {
|
|
4643
|
-
unlinkSync2(LEGACY_PM2_ECOSYSTEM_PATH);
|
|
4644
|
-
} catch {
|
|
4645
|
-
}
|
|
4646
|
-
}
|
|
4647
4761
|
}
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
const
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4762
|
+
function buildExtractUpdatePackageScript(remoteZipPath, remoteLibDir) {
|
|
4763
|
+
const quotedZip = shellSingleQuote(remoteZipPath);
|
|
4764
|
+
const quotedLib = shellSingleQuote(remoteLibDir);
|
|
4765
|
+
return `
|
|
4766
|
+
set -e
|
|
4767
|
+
TMP=$(mktemp -d)
|
|
4768
|
+
trap 'rm -rf "$TMP"' EXIT
|
|
4769
|
+
unzip -oq ${quotedZip} -d "$TMP"
|
|
4770
|
+
updated=0
|
|
4771
|
+
while IFS= read -r -d '' src; do
|
|
4772
|
+
name=$(basename "$src")
|
|
4773
|
+
dest=${quotedLib}/"$name"
|
|
4774
|
+
if [ -f "$dest" ]; then
|
|
4775
|
+
cp -f "$src" "$dest"
|
|
4776
|
+
echo "\u8986\u76D6: $name"
|
|
4777
|
+
updated=$((updated + 1))
|
|
4778
|
+
else
|
|
4779
|
+
echo "\u8DF3\u8FC7(\u8FDC\u7A0B\u4E0D\u5B58\u5728): $name"
|
|
4780
|
+
fi
|
|
4781
|
+
done < <(find "$TMP" -name '*.jar' -type f -print0)
|
|
4782
|
+
echo "UPDATED_COUNT=$updated"
|
|
4783
|
+
`.trim();
|
|
4784
|
+
}
|
|
4785
|
+
async function extractUpdatePackageOnRemote(client, config, remoteZipPath) {
|
|
4786
|
+
const script = buildExtractUpdatePackageScript(
|
|
4787
|
+
remoteZipPath,
|
|
4788
|
+
config.remoteLibDir
|
|
4789
|
+
);
|
|
4790
|
+
const { out } = await runRemoteCommand(client, script, {
|
|
4791
|
+
label: "\u8FDC\u7A0B\u89E3\u538B"
|
|
4660
4792
|
});
|
|
4661
|
-
|
|
4793
|
+
const match = out.match(/UPDATED_COUNT=(\d+)/);
|
|
4794
|
+
if (!match) {
|
|
4795
|
+
fail(`\u8FDC\u7A0B\u89E3\u538B\u5931\u8D25\uFF0C\u672A\u83B7\u53D6\u66F4\u65B0\u6570\u91CF
|
|
4796
|
+
\u8F93\u51FA: ${out || "(\u7A7A)"}`);
|
|
4797
|
+
}
|
|
4798
|
+
const updated = Number.parseInt(match[1], 10);
|
|
4799
|
+
log(`lib \u89E3\u538B\u5B8C\u6210: \u8986\u76D6 ${updated} \u4E2A`);
|
|
4800
|
+
return updated;
|
|
4662
4801
|
}
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
const cfg = await prepareEcosystem(options.server);
|
|
4668
|
-
removePm2ConnectProcesses();
|
|
4669
|
-
runPm2(["start", PM2_ECOSYSTEM_PATH, "--update-env"], { inherit: true });
|
|
4670
|
-
await delay(1e3);
|
|
4671
|
-
if (!isPm2ConnectOnline()) {
|
|
4672
|
-
console.error(
|
|
4673
|
-
`[apm] ${PM2_APP_NAME} \u542F\u52A8\u540E\u672A\u5904\u4E8E online \u72B6\u6001\uFF0C\u8BF7\u6267\u884C: apm daemon logs -n 200`
|
|
4674
|
-
);
|
|
4802
|
+
function springbootOutputIndicatesSuccess(action, combined) {
|
|
4803
|
+
const lower = combined.toLowerCase();
|
|
4804
|
+
if (action === "health") {
|
|
4805
|
+
return combined.includes("\u5065\u5EB7\u68C0\u67E5\u901A\u8FC7");
|
|
4675
4806
|
}
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
);
|
|
4679
|
-
if (options.follow) {
|
|
4680
|
-
console.log(
|
|
4681
|
-
"[apm] \u6B63\u5728\u8DDF\u8E2A\u65E5\u5FD7\uFF08Ctrl+C \u4EC5\u9000\u51FA\u65E5\u5FD7\u67E5\u770B\uFF0C\u5B88\u62A4\u8FDB\u7A0B\u7EE7\u7EED\u8FD0\u884C\uFF09"
|
|
4682
|
-
);
|
|
4683
|
-
runDaemonLogs({ follow: true });
|
|
4684
|
-
return;
|
|
4807
|
+
if (action === "start" || action === "restart") {
|
|
4808
|
+
return combined.includes("is starting") || lower.includes("is running");
|
|
4685
4809
|
}
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4810
|
+
if (action === "stop") {
|
|
4811
|
+
return combined.includes("is stopping") || lower.includes("not running") || lower.includes("please check it");
|
|
4812
|
+
}
|
|
4813
|
+
if (action === "status") {
|
|
4814
|
+
return lower.includes("running") || lower.includes("not running");
|
|
4815
|
+
}
|
|
4816
|
+
return true;
|
|
4817
|
+
}
|
|
4818
|
+
function buildRemoteStatusScript(remoteAppDir, appName) {
|
|
4819
|
+
const dir = shellSingleQuote(remoteAppDir);
|
|
4820
|
+
const jar = shellSingleQuote(appName);
|
|
4821
|
+
return `
|
|
4822
|
+
set -e
|
|
4823
|
+
cd ${dir}
|
|
4824
|
+
appName=${jar}
|
|
4825
|
+
appIds=$(ps -ef | grep java | grep "$appName" | awk '{print $2}')
|
|
4826
|
+
if [ -z "$appIds" ]; then
|
|
4827
|
+
echo -e "\\033[31m Not running \\033[0m"
|
|
4828
|
+
else
|
|
4829
|
+
echo -e "\\033[32m Running [$appIds] \\033[0m"
|
|
4830
|
+
fi
|
|
4831
|
+
`.trim();
|
|
4832
|
+
}
|
|
4833
|
+
function buildRemoteRestartScript(remoteAppDir) {
|
|
4834
|
+
const dir = shellSingleQuote(remoteAppDir);
|
|
4835
|
+
const javaOpts = shellSingleQuote(SPRINGBOOT_JAVA_OPTS);
|
|
4836
|
+
return `
|
|
4837
|
+
set -e
|
|
4838
|
+
cd ${dir}
|
|
4839
|
+
releaseApp=$(ls -t | grep '.jar$' | head -n1)
|
|
4840
|
+
lastVersionApp=$(ls -t | grep '.jar$' | head -n2 | tail -n1)
|
|
4841
|
+
appName=$lastVersionApp
|
|
4842
|
+
appIds=$(ps -ef | grep java | grep "$appName" | awk '{print $2}')
|
|
4843
|
+
if [ -z "$appIds" ]; then
|
|
4844
|
+
echo "Maybe $appName not running, please check it..."
|
|
4845
|
+
else
|
|
4846
|
+
echo "The $appName is stopping..."
|
|
4847
|
+
echo "$appIds" | xargs kill
|
|
4848
|
+
fi
|
|
4849
|
+
for i in $(seq 15 -1 1); do
|
|
4850
|
+
echo -n "$i "
|
|
4851
|
+
sleep 1
|
|
4852
|
+
done
|
|
4853
|
+
echo 0
|
|
4854
|
+
if [ ! -d "backup" ]; then
|
|
4855
|
+
mkdir backup
|
|
4856
|
+
fi
|
|
4857
|
+
for i in $(ls | grep '.jar$' | grep -vFx "$releaseApp"); do
|
|
4858
|
+
echo "backup $i"
|
|
4859
|
+
mv "$i" backup/
|
|
4860
|
+
done
|
|
4861
|
+
appName=$releaseApp
|
|
4862
|
+
count=$(ps -ef | grep java | grep "$appName" | wc -l)
|
|
4863
|
+
if [ "$count" != "0" ]; then
|
|
4864
|
+
echo "Maybe $appName is running, please check it..."
|
|
4865
|
+
else
|
|
4866
|
+
echo "The $appName is starting..."
|
|
4867
|
+
nohup java -jar "./$appName" ${javaOpts} > nohup.out 2>&1 &
|
|
4868
|
+
fi
|
|
4869
|
+
`.trim();
|
|
4689
4870
|
}
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
if (!
|
|
4693
|
-
|
|
4694
|
-
forceReleaseConnectLock();
|
|
4695
|
-
console.log(`[apm] ${PM2_APP_NAME} \u672A\u5728\u8FD0\u884C`);
|
|
4696
|
-
return;
|
|
4697
|
-
}
|
|
4698
|
-
runPm2(["stop", resolvePm2ConnectName(findPm2ConnectProcess())], {
|
|
4699
|
-
inherit: true
|
|
4700
|
-
});
|
|
4701
|
-
for (let i = 0; i < 10; i += 1) {
|
|
4702
|
-
if (!isPm2ConnectOnline()) break;
|
|
4703
|
-
await delay(500);
|
|
4871
|
+
function normalizeHealthContext(context) {
|
|
4872
|
+
let normalized = context.trim() || "/";
|
|
4873
|
+
if (!normalized.startsWith("/")) {
|
|
4874
|
+
normalized = `/${normalized}`;
|
|
4704
4875
|
}
|
|
4705
|
-
if (
|
|
4706
|
-
|
|
4707
|
-
runPm2(["delete", resolvePm2ConnectName(findPm2ConnectProcess())], {
|
|
4708
|
-
inherit: true
|
|
4709
|
-
});
|
|
4876
|
+
if (!normalized.endsWith("/")) {
|
|
4877
|
+
normalized = `${normalized}/`;
|
|
4710
4878
|
}
|
|
4711
|
-
|
|
4712
|
-
forceReleaseConnectLock();
|
|
4713
|
-
console.log(`[apm] ${PM2_APP_NAME} \u5DF2\u505C\u6B62`);
|
|
4879
|
+
return normalized;
|
|
4714
4880
|
}
|
|
4715
|
-
function
|
|
4716
|
-
|
|
4717
|
-
const
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4881
|
+
function buildRemoteHealthScript(port, context, timeoutSecs) {
|
|
4882
|
+
const normalizedContext = normalizeHealthContext(context);
|
|
4883
|
+
const portStr = String(port);
|
|
4884
|
+
const timeoutStr = String(timeoutSecs);
|
|
4885
|
+
return `
|
|
4886
|
+
set -e
|
|
4887
|
+
port=${shellSingleQuote(portStr)}
|
|
4888
|
+
context=${shellSingleQuote(normalizedContext)}
|
|
4889
|
+
timeout=${shellSingleQuote(timeoutStr)}
|
|
4890
|
+
check_url="http://127.0.0.1:${portStr}${normalizedContext}"
|
|
4891
|
+
echo "\u5065\u5EB7\u68C0\u67E5: \${check_url} (\u8D85\u65F6 \${timeout}s)"
|
|
4892
|
+
deadline=$(($(date +%s) + timeout))
|
|
4893
|
+
attempt=0
|
|
4894
|
+
while [ $(date +%s) -lt $deadline ]; do
|
|
4895
|
+
attempt=$((attempt + 1))
|
|
4896
|
+
code=$(curl -s -o /dev/null -w "%{http_code}" "$check_url" 2>/dev/null || echo "000")
|
|
4897
|
+
code=$(echo "$code" | tail -n1 | tr -d '[:space:]')
|
|
4898
|
+
if [ \${#code} -ge 3 ]; then
|
|
4899
|
+
status=\${code:0:3}
|
|
4900
|
+
if echo "$status" | grep -qE '^[0-9]+$' && [ "$status" -ge 200 ] && [ "$status" -lt 500 ]; then
|
|
4901
|
+
echo -e "\\033[32m\u5065\u5EB7\u68C0\u67E5\u901A\u8FC7 (HTTP \${status})\\033[0m"
|
|
4902
|
+
exit 0
|
|
4903
|
+
fi
|
|
4904
|
+
fi
|
|
4905
|
+
remaining=$((deadline - $(date +%s)))
|
|
4906
|
+
if [ $remaining -lt 0 ]; then
|
|
4907
|
+
remaining=0
|
|
4908
|
+
fi
|
|
4909
|
+
echo "\u7B49\u5F85\u670D\u52A1\u542F\u52A8... \u7B2C \${attempt} \u6B21\uFF0C\u5269\u4F59 \${remaining}s"
|
|
4910
|
+
sleep 5
|
|
4911
|
+
done
|
|
4912
|
+
echo -e "\\033[31m\u5065\u5EB7\u68C0\u67E5\u8D85\u65F6 (\${timeout}s): \${check_url}\\033[0m"
|
|
4913
|
+
exit 1
|
|
4914
|
+
`.trim();
|
|
4915
|
+
}
|
|
4916
|
+
async function runRemoteServiceScript(client, script, action) {
|
|
4917
|
+
const { exitCode, out, err } = await runRemoteCommand(client, script, {
|
|
4918
|
+
check: false,
|
|
4919
|
+
label: action === "status" ? "\u8FDC\u7A0B status" : action === "restart" ? "\u8FDC\u7A0B restart" : "\u5065\u5EB7\u68C0\u67E5"
|
|
4920
|
+
});
|
|
4921
|
+
const combined = `${out}
|
|
4922
|
+
${err}`.trim();
|
|
4923
|
+
const outputOk = springbootOutputIndicatesSuccess(action, combined);
|
|
4924
|
+
if (action === "health") {
|
|
4925
|
+
if (exitCode !== 0 || !outputOk) {
|
|
4926
|
+
fail(`\u5065\u5EB7\u68C0\u67E5\u5931\u8D25
|
|
4927
|
+
\u8F93\u51FA: ${combined || "(\u7A7A)"}`);
|
|
4729
4928
|
}
|
|
4929
|
+
return combined;
|
|
4730
4930
|
}
|
|
4731
|
-
|
|
4732
|
-
}
|
|
4733
|
-
|
|
4734
|
-
pruneStaleConnectLock();
|
|
4735
|
-
const lock = readConnectLock();
|
|
4736
|
-
if (lock && isProcessAlive(lock.pid) && !isPm2ConnectOnline()) {
|
|
4737
|
-
console.error(
|
|
4738
|
-
`[apm] \u5DF2\u6709\u524D\u53F0 apm connect \u5728\u8FD0\u884C (pid=${lock.pid})\uFF0C\u8BF7\u5148\u505C\u6B62\u540E\u518D\u542F\u52A8\u5B88\u62A4\u8FDB\u7A0B`
|
|
4739
|
-
);
|
|
4740
|
-
process.exit(1);
|
|
4931
|
+
if (exitCode !== 0 && !outputOk) {
|
|
4932
|
+
fail(`\u8FDC\u7A0B ${action} \u5931\u8D25
|
|
4933
|
+
${combined}`);
|
|
4741
4934
|
}
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
runPm2(["start", PM2_ECOSYSTEM_PATH, "--update-env"], { inherit: true });
|
|
4746
|
-
console.log(`[apm] ${PM2_APP_NAME} \u5DF2\u91CD\u542F`);
|
|
4747
|
-
}
|
|
4748
|
-
async function runDaemonDelete() {
|
|
4749
|
-
ensureGlobalPm2();
|
|
4750
|
-
const app = findPm2ConnectProcess();
|
|
4751
|
-
if (!app?.name) {
|
|
4752
|
-
console.log(`[apm] ${PM2_APP_NAME} \u672A\u5728 PM2 \u4E2D\u6CE8\u518C`);
|
|
4753
|
-
return;
|
|
4935
|
+
if (action === "restart" && !outputOk) {
|
|
4936
|
+
fail(`\u8FDC\u7A0B restart \u672A\u6210\u529F
|
|
4937
|
+
\u8F93\u51FA: ${combined || "(\u7A7A)"}`);
|
|
4754
4938
|
}
|
|
4755
|
-
|
|
4756
|
-
forceReleaseConnectLock();
|
|
4757
|
-
console.log(`[apm] ${app.name} \u5DF2\u4ECE PM2 \u79FB\u9664`);
|
|
4939
|
+
return combined;
|
|
4758
4940
|
}
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
const app = findPm2ConnectProcess();
|
|
4762
|
-
if (!app?.name) {
|
|
4763
|
-
printConnectNotRunningHint();
|
|
4764
|
-
return;
|
|
4765
|
-
}
|
|
4766
|
-
runPm2(["describe", app.name], { inherit: true });
|
|
4941
|
+
function stripAnsi(text) {
|
|
4942
|
+
return text.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "");
|
|
4767
4943
|
}
|
|
4768
|
-
async function
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4944
|
+
async function getRunningJar(client, config) {
|
|
4945
|
+
const script = buildRemoteStatusScript(
|
|
4946
|
+
config.remoteAppDir,
|
|
4947
|
+
config.startupJar
|
|
4948
|
+
);
|
|
4949
|
+
const combined = await runRemoteServiceScript(client, script, "status");
|
|
4950
|
+
const text = stripAnsi(combined).trim().toLowerCase();
|
|
4951
|
+
if (text.includes("not running")) {
|
|
4952
|
+
return null;
|
|
4774
4953
|
}
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
args.push("--nostream");
|
|
4954
|
+
if (text.includes("running")) {
|
|
4955
|
+
return config.startupJar;
|
|
4778
4956
|
}
|
|
4779
|
-
|
|
4957
|
+
return null;
|
|
4780
4958
|
}
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
4790
|
-
});
|
|
4791
|
-
if (result.status !== 0) {
|
|
4792
|
-
return null;
|
|
4793
|
-
}
|
|
4794
|
-
const bin = result.stdout?.toString().trim();
|
|
4795
|
-
return bin || null;
|
|
4959
|
+
async function healthCheckService(client, config) {
|
|
4960
|
+
log("\u5065\u5EB7\u68C0\u67E5...");
|
|
4961
|
+
const script = buildRemoteHealthScript(
|
|
4962
|
+
config.healthCheckPort,
|
|
4963
|
+
config.healthCheckContext,
|
|
4964
|
+
config.healthCheckTimeout
|
|
4965
|
+
);
|
|
4966
|
+
await runRemoteServiceScript(client, script, "health");
|
|
4796
4967
|
}
|
|
4797
|
-
function
|
|
4798
|
-
|
|
4799
|
-
|
|
4800
|
-
}
|
|
4801
|
-
if (!pathValue) {
|
|
4802
|
-
return segment;
|
|
4803
|
-
}
|
|
4804
|
-
const segments = pathValue.split(PATH_SEP);
|
|
4805
|
-
if (segments.includes(segment)) {
|
|
4806
|
-
return pathValue;
|
|
4807
|
-
}
|
|
4808
|
-
return `${segment}${PATH_SEP}${pathValue}`;
|
|
4968
|
+
async function restartRemoteService(client, config) {
|
|
4969
|
+
const script = buildRemoteRestartScript(config.remoteAppDir);
|
|
4970
|
+
await runRemoteServiceScript(client, script, "restart");
|
|
4809
4971
|
}
|
|
4810
|
-
function
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4972
|
+
function listAllLibFilesForArchive(libDir) {
|
|
4973
|
+
return readdirSync5(libDir).filter((name) => name.endsWith(".jar")).sort().map((jarName) => ({
|
|
4974
|
+
path: path3.join(libDir, jarName),
|
|
4975
|
+
arcname: jarName,
|
|
4976
|
+
reason: "\u4EC5\u6253\u5305\u5F52\u6863"
|
|
4977
|
+
}));
|
|
4978
|
+
}
|
|
4979
|
+
async function runWisdomBackendDeploy(options) {
|
|
4980
|
+
const projectRoot = path3.resolve(options.projectRoot ?? process.cwd());
|
|
4981
|
+
const config = options.config;
|
|
4982
|
+
const packOnly = Boolean(options.packOnly);
|
|
4983
|
+
log(`=== \u81EA\u52A8\u90E8\u7F72: ${config.projectName} ===`);
|
|
4984
|
+
log(`\u914D\u7F6E\u6587\u4EF6: ${path3.join(workspaceApmDir(), "apm.config.json")}`);
|
|
4985
|
+
log(`\u9879\u76EE\u6839\u76EE\u5F55: ${projectRoot}`);
|
|
4986
|
+
log(
|
|
4987
|
+
`\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"}${packOnly ? "\uFF1B\u4EC5\u6253\u5305\uFF08\u4E0D\u4E0A\u4F20\u8FDC\u7A0B\uFF09" : ""}`
|
|
4988
|
+
);
|
|
4989
|
+
runMavenBuild(projectRoot, config.mavenLocalRepo, {
|
|
4990
|
+
source: config.mavenLocalRepoSource,
|
|
4991
|
+
sourceDetail: config.mavenLocalRepoSourceDetail
|
|
4992
|
+
});
|
|
4993
|
+
if (packOnly) {
|
|
4994
|
+
const uploadWithoutRunId = !resolveDeploymentRunIdFromEnv();
|
|
4995
|
+
if (config.mode === "full") {
|
|
4996
|
+
const mainJar = locateMainJar(projectRoot);
|
|
4997
|
+
const archiveZipPath = await createUpdatePackage(
|
|
4998
|
+
[
|
|
4999
|
+
{
|
|
5000
|
+
path: mainJar,
|
|
5001
|
+
arcname: path3.basename(mainJar),
|
|
5002
|
+
reason: "\u5168\u91CF JAR \u5F52\u6863"
|
|
5003
|
+
}
|
|
5004
|
+
],
|
|
5005
|
+
`.deploy-archive-${config.projectName}.jar.zip`
|
|
5006
|
+
);
|
|
5007
|
+
await uploadDeployArtifactZip({
|
|
5008
|
+
zipPath: archiveZipPath,
|
|
5009
|
+
projectName: config.projectName,
|
|
5010
|
+
kind: "backend",
|
|
5011
|
+
uploadWithoutRunId
|
|
5012
|
+
});
|
|
5013
|
+
} else {
|
|
5014
|
+
const libDir = locateLibDir(projectRoot);
|
|
5015
|
+
const entries = listAllLibFilesForArchive(libDir);
|
|
5016
|
+
if (entries.length === 0) {
|
|
5017
|
+
fail("lib \u76EE\u5F55\u4E0B\u6CA1\u6709\u53EF\u5F52\u6863\u7684 JAR");
|
|
5018
|
+
}
|
|
5019
|
+
const zipPath = await createUpdatePackage(entries, config.packageName);
|
|
5020
|
+
await uploadDeployArtifactZip({
|
|
5021
|
+
zipPath,
|
|
5022
|
+
projectName: config.projectName,
|
|
5023
|
+
kind: "backend",
|
|
5024
|
+
uploadWithoutRunId
|
|
5025
|
+
});
|
|
5026
|
+
}
|
|
5027
|
+
log("\u4EC5\u6253\u5305\u5B8C\u6210\uFF08\u672A\u4E0A\u4F20\u8FDC\u7A0B\u670D\u52A1\u5668\uFF09");
|
|
5028
|
+
return;
|
|
4816
5029
|
}
|
|
5030
|
+
const conn = await connectSsh(config);
|
|
4817
5031
|
try {
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4821
|
-
|
|
4822
|
-
|
|
5032
|
+
if (config.mode === "full") {
|
|
5033
|
+
const mainJar = locateMainJar(projectRoot);
|
|
5034
|
+
await uploadFullJar(conn.sftp, mainJar, config);
|
|
5035
|
+
const archiveZipPath = await createUpdatePackage(
|
|
5036
|
+
[
|
|
5037
|
+
{
|
|
5038
|
+
path: mainJar,
|
|
5039
|
+
arcname: path3.basename(mainJar),
|
|
5040
|
+
reason: "\u5168\u91CF JAR \u5F52\u6863"
|
|
5041
|
+
}
|
|
5042
|
+
],
|
|
5043
|
+
`.deploy-archive-${config.projectName}.jar.zip`
|
|
5044
|
+
);
|
|
5045
|
+
await uploadDeployArtifactZip({
|
|
5046
|
+
zipPath: archiveZipPath,
|
|
5047
|
+
projectName: config.projectName,
|
|
5048
|
+
kind: "backend"
|
|
5049
|
+
});
|
|
5050
|
+
log("\u91CD\u542F\u670D\u52A1...");
|
|
5051
|
+
await restartRemoteService(conn.client, config);
|
|
5052
|
+
await healthCheckService(conn.client, config);
|
|
5053
|
+
log("\u90E8\u7F72\u5B8C\u6210");
|
|
5054
|
+
return;
|
|
5055
|
+
}
|
|
5056
|
+
const libDir = locateLibDir(projectRoot);
|
|
5057
|
+
let manifest = loadManifest3();
|
|
5058
|
+
const remoteLibStats = await getRemoteFileStats(
|
|
5059
|
+
conn.sftp,
|
|
5060
|
+
config.remoteLibDir
|
|
5061
|
+
);
|
|
5062
|
+
log("\u6536\u96C6 JAR \u66F4\u65B0...");
|
|
5063
|
+
const libUploadEntries = listLibFilesToUpload(
|
|
5064
|
+
libDir,
|
|
5065
|
+
remoteLibStats,
|
|
5066
|
+
projectRoot,
|
|
5067
|
+
manifest
|
|
5068
|
+
);
|
|
5069
|
+
let updated = 0;
|
|
5070
|
+
if (libUploadEntries.length > 0) {
|
|
5071
|
+
const zipPath = await createUpdatePackage(
|
|
5072
|
+
libUploadEntries,
|
|
5073
|
+
config.packageName
|
|
5074
|
+
);
|
|
5075
|
+
const remoteZipPath = await uploadUpdatePackage(
|
|
5076
|
+
conn.sftp,
|
|
5077
|
+
zipPath,
|
|
5078
|
+
config
|
|
5079
|
+
);
|
|
5080
|
+
await uploadDeployArtifactZip({
|
|
5081
|
+
zipPath,
|
|
5082
|
+
projectName: config.projectName,
|
|
5083
|
+
kind: "backend"
|
|
5084
|
+
});
|
|
5085
|
+
log("\u8FDC\u7A0B\u89E3\u538B lib \u76EE\u5F55\uFF08\u4EC5\u8986\u76D6\u5DF2\u6709 JAR\uFF09...");
|
|
5086
|
+
updated = await extractUpdatePackageOnRemote(
|
|
5087
|
+
conn.client,
|
|
5088
|
+
config,
|
|
5089
|
+
remoteZipPath
|
|
5090
|
+
);
|
|
5091
|
+
} else {
|
|
5092
|
+
log("\u65E0 JAR \u9700\u8981\u66F4\u65B0\uFF0C\u8DF3\u8FC7\u66F4\u65B0\u5305\u4E0A\u4F20");
|
|
5093
|
+
}
|
|
5094
|
+
const runningJar = await getRunningJar(conn.client, config);
|
|
5095
|
+
let needRestart = updated > 0;
|
|
5096
|
+
if (!needRestart && !runningJar) {
|
|
5097
|
+
log("\u670D\u52A1\u672A\u8FD0\u884C\uFF0C\u9700\u8981\u542F\u52A8");
|
|
5098
|
+
needRestart = true;
|
|
5099
|
+
} else if (!needRestart) {
|
|
5100
|
+
log("\u6CA1\u6709\u6587\u4EF6\u9700\u8981\u66F4\u65B0\uFF0C\u8DF3\u8FC7\u91CD\u542F");
|
|
5101
|
+
}
|
|
5102
|
+
if (needRestart) {
|
|
5103
|
+
log("\u91CD\u542F\u670D\u52A1...");
|
|
5104
|
+
await restartRemoteService(conn.client, config);
|
|
5105
|
+
}
|
|
5106
|
+
await healthCheckService(conn.client, config);
|
|
5107
|
+
if (libUploadEntries.length > 0) {
|
|
5108
|
+
manifest = updateManifestEntries(manifest, libUploadEntries, projectRoot);
|
|
5109
|
+
saveManifest3(manifest);
|
|
5110
|
+
}
|
|
5111
|
+
} finally {
|
|
5112
|
+
await closeSsh(conn);
|
|
4823
5113
|
}
|
|
4824
|
-
|
|
5114
|
+
log("\u90E8\u7F72\u5B8C\u6210");
|
|
4825
5115
|
}
|
|
4826
5116
|
|
|
4827
|
-
// src/commands/deploy/internal/wisdom-
|
|
4828
|
-
function
|
|
5117
|
+
// src/commands/deploy/internal/wisdom-deploy.ts
|
|
5118
|
+
function isWisdomDeployConfigured(cfg) {
|
|
4829
5119
|
const w = cfg.wisdomDeploy;
|
|
4830
|
-
|
|
4831
|
-
return false;
|
|
4832
|
-
}
|
|
4833
|
-
const hasNewFrontend = Boolean(cfg.frontendDeploy?.endpoint?.trim());
|
|
4834
|
-
const hasNewBackend = Boolean(cfg.backendDeploy?.registryHost?.trim());
|
|
4835
|
-
return !hasNewFrontend && !hasNewBackend;
|
|
5120
|
+
return Boolean(w?.host?.trim() && w?.remotePath?.trim());
|
|
4836
5121
|
}
|
|
4837
5122
|
function detectWisdomProjectType(cwd) {
|
|
4838
|
-
return
|
|
5123
|
+
return existsSync16(path4.join(cwd, "package.json")) ? "frontend" : "backend";
|
|
4839
5124
|
}
|
|
4840
5125
|
function readPackageScripts(cwd) {
|
|
4841
5126
|
const pkgPath = path4.join(cwd, "package.json");
|
|
4842
|
-
if (!
|
|
5127
|
+
if (!existsSync16(pkgPath)) {
|
|
4843
5128
|
return {};
|
|
4844
5129
|
}
|
|
4845
5130
|
try {
|
|
@@ -4850,14 +5135,6 @@ function readPackageScripts(cwd) {
|
|
|
4850
5135
|
return {};
|
|
4851
5136
|
}
|
|
4852
5137
|
}
|
|
4853
|
-
function resolveFrontendDeployCommand(env, cwd) {
|
|
4854
|
-
const scripts = readPackageScripts(cwd);
|
|
4855
|
-
const deployKey = `deploy:${env}`;
|
|
4856
|
-
if (scripts[deployKey]?.trim()) {
|
|
4857
|
-
return `npm run deploy:${env}`;
|
|
4858
|
-
}
|
|
4859
|
-
return null;
|
|
4860
|
-
}
|
|
4861
5138
|
function resolveFrontendBuildCommand(env, cwd) {
|
|
4862
5139
|
const scripts = readPackageScripts(cwd);
|
|
4863
5140
|
const buildKey = `build:${env}`;
|
|
@@ -4866,36 +5143,12 @@ function resolveFrontendBuildCommand(env, cwd) {
|
|
|
4866
5143
|
}
|
|
4867
5144
|
return null;
|
|
4868
5145
|
}
|
|
4869
|
-
function runShellCommand(command, cwd, captureOutput) {
|
|
4870
|
-
const result = spawnSync5(command, {
|
|
4871
|
-
cwd,
|
|
4872
|
-
shell: true,
|
|
4873
|
-
env: buildDeployShellEnv(),
|
|
4874
|
-
encoding: "utf8",
|
|
4875
|
-
stdio: captureOutput ? ["inherit", "pipe", "pipe"] : "inherit"
|
|
4876
|
-
});
|
|
4877
|
-
const stdout = captureOutput ? String(result.stdout ?? "") : "";
|
|
4878
|
-
const stderr = captureOutput ? String(result.stderr ?? "") : "";
|
|
4879
|
-
const output = [stdout, stderr].filter(Boolean).join("\n");
|
|
4880
|
-
if (captureOutput) {
|
|
4881
|
-
if (stdout) process.stdout.write(stdout);
|
|
4882
|
-
if (stderr) process.stderr.write(stderr);
|
|
4883
|
-
}
|
|
4884
|
-
if (result.status !== 0) {
|
|
4885
|
-
throw new DeployExecutionError(
|
|
4886
|
-
`\u90E8\u7F72\u547D\u4EE4\u9000\u51FA\u7801 ${result.status ?? "unknown"}: ${command}`,
|
|
4887
|
-
result.status ?? 1,
|
|
4888
|
-
output
|
|
4889
|
-
);
|
|
4890
|
-
}
|
|
4891
|
-
return output;
|
|
4892
|
-
}
|
|
4893
5146
|
function resolveFrontendDistDir(cwd) {
|
|
4894
5147
|
const candidates = ["dist", "apps/web/dist"];
|
|
4895
5148
|
for (const rel of candidates) {
|
|
4896
5149
|
const full = path4.join(cwd, rel);
|
|
4897
5150
|
try {
|
|
4898
|
-
if (
|
|
5151
|
+
if (existsSync16(full) && statSync7(full).isDirectory()) {
|
|
4899
5152
|
return full;
|
|
4900
5153
|
}
|
|
4901
5154
|
} catch {
|
|
@@ -4903,62 +5156,57 @@ function resolveFrontendDistDir(cwd) {
|
|
|
4903
5156
|
}
|
|
4904
5157
|
return path4.join(cwd, "dist");
|
|
4905
5158
|
}
|
|
4906
|
-
async function
|
|
4907
|
-
const cwd =
|
|
4908
|
-
const
|
|
4909
|
-
const
|
|
4910
|
-
|
|
4911
|
-
|
|
4912
|
-
|
|
5159
|
+
async function executeWisdomFrontendDeploy(options) {
|
|
5160
|
+
const { cwd, cfg, captureOutput, packOnly, archiveDeployArtifact } = options;
|
|
5161
|
+
const buildCmd = resolveFrontendBuildCommand(options.env, cwd);
|
|
5162
|
+
const distDir = resolveFrontendDistDir(cwd);
|
|
5163
|
+
logWisdomFrontendDeployContext({
|
|
5164
|
+
env: options.env,
|
|
5165
|
+
cwd,
|
|
5166
|
+
buildCmd,
|
|
5167
|
+
distDir,
|
|
5168
|
+
packOnly,
|
|
5169
|
+
archiveDeployArtifact
|
|
5170
|
+
});
|
|
5171
|
+
if (!buildCmd) {
|
|
5172
|
+
const lines = formatWisdomFrontendBuildNotConfiguredLines(
|
|
5173
|
+
options.env,
|
|
5174
|
+
path4.join(cwd, "package.json")
|
|
5175
|
+
);
|
|
5176
|
+
throw new DeployExecutionError(lines.join("\n"), 1, lines.join("\n"));
|
|
5177
|
+
}
|
|
4913
5178
|
console.error(
|
|
4914
|
-
`[apm] \
|
|
5179
|
+
`[apm] Vue\uFF1A${buildCmd}` + (packOnly ? "\uFF08\u4EC5\u6253\u5305\uFF0C\u8DF3\u8FC7 SFTP\uFF09" : " \u2192 SFTP \u4E0A\u4F20\u5E76\u8FDC\u7A0B\u89E3\u538B" + (archiveDeployArtifact ? " \u2192 \u5E73\u53F0\u90E8\u7F72\u4EA7\u7269\u5F52\u6863" : ""))
|
|
4915
5180
|
);
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
console.error(`[apm] \u524D\u7AEF\u4EC5\u6253\u5305\u6A21\u5F0F\uFF1A\u6267\u884C ${buildCmd}`);
|
|
4927
|
-
runShellCommand(buildCmd, cwd, captureOutput);
|
|
4928
|
-
const projectName = (cfg.name ?? "").trim();
|
|
4929
|
-
if (!projectName) {
|
|
4930
|
-
throw new DeployExecutionError(
|
|
4931
|
-
"\u8BF7\u5728 .apm/apm.config.json \u9876\u5C42\u914D\u7F6E name\uFF08\u4F5C\u4E3A\u90E8\u7F72\u4EA7\u7269\u9879\u76EE\u540D\uFF09",
|
|
4932
|
-
1
|
|
4933
|
-
);
|
|
4934
|
-
}
|
|
4935
|
-
const settings2 = resolveWisdomDeployFromApmConfig(cfg);
|
|
4936
|
-
await runWisdomSftpDeploy({
|
|
4937
|
-
localDir: resolveFrontendDistDir(cwd),
|
|
4938
|
-
settings: settings2,
|
|
4939
|
-
extract: false,
|
|
4940
|
-
projectName,
|
|
4941
|
-
packOnly: true
|
|
4942
|
-
});
|
|
4943
|
-
return { projectType };
|
|
4944
|
-
}
|
|
4945
|
-
const deployCmd = resolveFrontendDeployCommand(options.env, cwd);
|
|
4946
|
-
if (!deployCmd) {
|
|
4947
|
-
const lines = formatWisdomFrontendDeployNotConfiguredLines(
|
|
4948
|
-
options.env,
|
|
4949
|
-
path4.join(cwd, "package.json")
|
|
4950
|
-
);
|
|
4951
|
-
throw new DeployExecutionError(lines.join("\n"), 1, lines.join("\n"));
|
|
4952
|
-
}
|
|
4953
|
-
runShellCommand(deployCmd, cwd, captureOutput);
|
|
4954
|
-
return { projectType };
|
|
5181
|
+
runDeployShellCommand(buildCmd, cwd, captureOutput);
|
|
5182
|
+
let projectName = (cfg.name ?? "").trim();
|
|
5183
|
+
if ((packOnly || archiveDeployArtifact) && !projectName) {
|
|
5184
|
+
throw new DeployExecutionError(
|
|
5185
|
+
"\u8BF7\u5728 .apm/apm.config.json \u9876\u5C42\u914D\u7F6E name\uFF08\u4F5C\u4E3A\u90E8\u7F72\u4EA7\u7269\u9879\u76EE\u540D\uFF09",
|
|
5186
|
+
1
|
|
5187
|
+
);
|
|
5188
|
+
}
|
|
5189
|
+
if (!projectName) {
|
|
5190
|
+
projectName = path4.basename(cwd);
|
|
4955
5191
|
}
|
|
5192
|
+
const settings = resolveWisdomDeployFromApmConfig(cfg);
|
|
5193
|
+
await runWisdomSftpDeploy({
|
|
5194
|
+
localDir: distDir,
|
|
5195
|
+
settings,
|
|
5196
|
+
extract: !packOnly,
|
|
5197
|
+
projectName,
|
|
5198
|
+
packOnly,
|
|
5199
|
+
archiveDeployArtifact
|
|
5200
|
+
});
|
|
5201
|
+
}
|
|
5202
|
+
async function executeWisdomBackendDeployFlow(options) {
|
|
5203
|
+
const { cwd, cfg, packOnly } = options;
|
|
4956
5204
|
const settings = resolveWisdomBackendDeployFromApmConfig(cfg);
|
|
4957
5205
|
if (packOnly) {
|
|
4958
|
-
console.error(`[apm] \
|
|
5206
|
+
console.error(`[apm] Java\uFF1AMaven \u6784\u5EFA\uFF08\u4EC5\u6253\u5305\uFF0C\u5FFD\u7565\u73AF\u5883 ${options.env}\uFF09`);
|
|
4959
5207
|
} else {
|
|
4960
5208
|
console.error(
|
|
4961
|
-
`[apm] \
|
|
5209
|
+
`[apm] Java\uFF1AMaven \u6784\u5EFA\u5E76\u90E8\u7F72\uFF08\u4E0D\u533A\u5206 test/online\uFF0C\u5FFD\u7565\u73AF\u5883 ${options.env}\uFF09`
|
|
4962
5210
|
);
|
|
4963
5211
|
}
|
|
4964
5212
|
await runWisdomBackendDeploy({
|
|
@@ -4966,11 +5214,40 @@ async function runWisdomAutoDeploy(options) {
|
|
|
4966
5214
|
projectRoot: cwd,
|
|
4967
5215
|
packOnly
|
|
4968
5216
|
});
|
|
5217
|
+
}
|
|
5218
|
+
async function executeWisdomDeploy(options) {
|
|
5219
|
+
const cwd = path4.resolve(options.cwd);
|
|
5220
|
+
const captureOutput = options.captureOutput ?? false;
|
|
5221
|
+
const packOnly = Boolean(options.packOnly);
|
|
5222
|
+
const archiveDeployArtifact = Boolean(options.archiveDeployArtifact);
|
|
5223
|
+
const projectType = detectWisdomProjectType(cwd);
|
|
5224
|
+
const configPath = options.configPath ?? path4.join(workspaceApmDir(cwd), "apm.config.json");
|
|
5225
|
+
const cfg = loadApmConfig({ configPath });
|
|
5226
|
+
console.error(
|
|
5227
|
+
`[apm] ${projectType === "frontend" ? "Vue \u524D\u7AEF" : "Java \u540E\u7AEF"}${packOnly ? "\uFF08\u4EC5\u6253\u5305\uFF09" : ""}`
|
|
5228
|
+
);
|
|
5229
|
+
if (projectType === "frontend") {
|
|
5230
|
+
await executeWisdomFrontendDeploy({
|
|
5231
|
+
...options,
|
|
5232
|
+
cwd,
|
|
5233
|
+
cfg,
|
|
5234
|
+
captureOutput,
|
|
5235
|
+
packOnly,
|
|
5236
|
+
archiveDeployArtifact
|
|
5237
|
+
});
|
|
5238
|
+
return { projectType };
|
|
5239
|
+
}
|
|
5240
|
+
await executeWisdomBackendDeployFlow({
|
|
5241
|
+
...options,
|
|
5242
|
+
cwd,
|
|
5243
|
+
cfg,
|
|
5244
|
+
packOnly
|
|
5245
|
+
});
|
|
4969
5246
|
return { projectType };
|
|
4970
5247
|
}
|
|
4971
5248
|
|
|
4972
5249
|
// src/commands/deploy/internal/deploy-baseline-sync.ts
|
|
4973
|
-
var
|
|
5250
|
+
var LOG_PREFIX2 = "[apm] \u90E8\u7F72\u524D\u57FA\u7EBF\u540C\u6B65:";
|
|
4974
5251
|
function formatGitError(error) {
|
|
4975
5252
|
return error instanceof Error ? error.message : String(error);
|
|
4976
5253
|
}
|
|
@@ -5006,20 +5283,20 @@ async function restoreWorkingTree(cwd) {
|
|
|
5006
5283
|
}
|
|
5007
5284
|
async function mergeBaselineBranch(cwd, baselineBranch, currentBranch, note) {
|
|
5008
5285
|
const mergeTarget = `origin/${baselineBranch}`;
|
|
5009
|
-
note(`${
|
|
5286
|
+
note(`${LOG_PREFIX2} \u5F00\u59CB\u5408\u5E76 ${mergeTarget} \u5230\u5F53\u524D\u5206\u652F ${currentBranch}`);
|
|
5010
5287
|
try {
|
|
5011
5288
|
if (currentBranch === baselineBranch) {
|
|
5012
5289
|
await execGit(cwd, ["merge", "--ff-only", mergeTarget]);
|
|
5013
5290
|
} else {
|
|
5014
5291
|
await execGit(cwd, ["merge", mergeTarget, "--no-edit"]);
|
|
5015
5292
|
}
|
|
5016
|
-
note(`${
|
|
5293
|
+
note(`${LOG_PREFIX2} \u5DF2\u5408\u5E76 ${mergeTarget} \u6700\u65B0\u4EE3\u7801`);
|
|
5017
5294
|
return { merged: true, conflictRollback: false };
|
|
5018
5295
|
} catch (error) {
|
|
5019
5296
|
await abortMergeIfNeeded(cwd);
|
|
5020
|
-
note(`${
|
|
5021
|
-
note(`${
|
|
5022
|
-
note(`${
|
|
5297
|
+
note(`${LOG_PREFIX2} \u5408\u5E76 ${mergeTarget} \u5931\u8D25: ${formatGitError(error)}`);
|
|
5298
|
+
note(`${LOG_PREFIX2} \u5DF2\u6267\u884C git merge --abort \u56DE\u9000\u5230\u5408\u5E76\u524D\u72B6\u6001`);
|
|
5299
|
+
note(`${LOG_PREFIX2} \u5C06\u4F7F\u7528\u56DE\u9000\u540E\u7684\u4EE3\u7801\u7EE7\u7EED\u90E8\u7F72`);
|
|
5023
5300
|
return { merged: false, conflictRollback: true };
|
|
5024
5301
|
}
|
|
5025
5302
|
}
|
|
@@ -5027,17 +5304,17 @@ async function restoreStashIfNeeded(cwd, stashed, note) {
|
|
|
5027
5304
|
if (!stashed) {
|
|
5028
5305
|
return false;
|
|
5029
5306
|
}
|
|
5030
|
-
note(`${
|
|
5307
|
+
note(`${LOG_PREFIX2} \u6B63\u5728\u6062\u590D stash \u4E2D\u7684\u672A\u63D0\u4EA4\u6539\u52A8`);
|
|
5031
5308
|
try {
|
|
5032
5309
|
await execGit(cwd, ["stash", "pop"], true);
|
|
5033
|
-
note(`${
|
|
5310
|
+
note(`${LOG_PREFIX2} \u5DF2\u6062\u590D stash \u4E2D\u7684\u672A\u63D0\u4EA4\u6539\u52A8`);
|
|
5034
5311
|
return false;
|
|
5035
5312
|
} catch (error) {
|
|
5036
5313
|
await abortMergeIfNeeded(cwd);
|
|
5037
5314
|
await restoreWorkingTree(cwd);
|
|
5038
|
-
note(`${
|
|
5039
|
-
note(`${
|
|
5040
|
-
note(`${
|
|
5315
|
+
note(`${LOG_PREFIX2} \u6062\u590D stash \u5931\u8D25: ${formatGitError(error)}`);
|
|
5316
|
+
note(`${LOG_PREFIX2} \u5DF2\u56DE\u9000\u5DE5\u4F5C\u533A\uFF08git reset --hard HEAD\uFF09\uFF0Cstash \u4ECD\u4FDD\u7559`);
|
|
5317
|
+
note(`${LOG_PREFIX2} \u5C06\u4F7F\u7528\u56DE\u9000\u540E\u7684\u4EE3\u7801\u7EE7\u7EED\u90E8\u7F72`);
|
|
5041
5318
|
return true;
|
|
5042
5319
|
}
|
|
5043
5320
|
}
|
|
@@ -5056,30 +5333,30 @@ async function syncDeployBaselineBeforeDeploy(cwd) {
|
|
|
5056
5333
|
...partial
|
|
5057
5334
|
});
|
|
5058
5335
|
if (!await isGitRepo(cwd)) {
|
|
5059
|
-
note(`${
|
|
5336
|
+
note(`${LOG_PREFIX2} \u5F53\u524D\u76EE\u5F55\u4E0D\u662F git \u4ED3\u5E93\uFF0C\u8DF3\u8FC7`);
|
|
5060
5337
|
return emptyResult();
|
|
5061
5338
|
}
|
|
5062
5339
|
const cfg = await tryReadApmConfig();
|
|
5063
5340
|
if (!cfg || !resolveApiKey(cfg)) {
|
|
5064
|
-
note(`${
|
|
5341
|
+
note(`${LOG_PREFIX2} \u672A\u767B\u5F55\uFF0C\u8DF3\u8FC7`);
|
|
5065
5342
|
return emptyResult();
|
|
5066
5343
|
}
|
|
5067
5344
|
await ensureGitRepo(cwd);
|
|
5068
5345
|
const api = createApmApiClient(cfg);
|
|
5069
5346
|
const baselineBranch = await resolveBaselineBranch2(cwd, api);
|
|
5070
|
-
note(`${
|
|
5071
|
-
note(`${
|
|
5347
|
+
note(`${LOG_PREFIX2} \u57FA\u7EBF\u5206\u652F ${baselineBranch}`);
|
|
5348
|
+
note(`${LOG_PREFIX2} \u6B63\u5728 fetch origin ${baselineBranch}`);
|
|
5072
5349
|
await execGit(cwd, ["fetch", "origin", baselineBranch], true);
|
|
5073
5350
|
if (!await remoteBranchExists(cwd, baselineBranch)) {
|
|
5074
5351
|
throw new Error(
|
|
5075
5352
|
`\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`
|
|
5076
5353
|
);
|
|
5077
5354
|
}
|
|
5078
|
-
note(`${
|
|
5355
|
+
note(`${LOG_PREFIX2} fetch \u5B8C\u6210`);
|
|
5079
5356
|
const currentBranch = await getCurrentBranch(cwd);
|
|
5080
5357
|
let stashed = false;
|
|
5081
5358
|
if (await isWorkingTreeDirty(cwd)) {
|
|
5082
|
-
note(`${
|
|
5359
|
+
note(`${LOG_PREFIX2} \u68C0\u6D4B\u5230\u672A\u63D0\u4EA4\u6539\u52A8\uFF0C\u5148 stash`);
|
|
5083
5360
|
await execGit(cwd, [
|
|
5084
5361
|
"stash",
|
|
5085
5362
|
"push",
|
|
@@ -5088,7 +5365,7 @@ async function syncDeployBaselineBeforeDeploy(cwd) {
|
|
|
5088
5365
|
"apm: deploy baseline sync"
|
|
5089
5366
|
]);
|
|
5090
5367
|
stashed = true;
|
|
5091
|
-
note(`${
|
|
5368
|
+
note(`${LOG_PREFIX2} \u5DF2 stash \u672A\u63D0\u4EA4\u6539\u52A8`);
|
|
5092
5369
|
}
|
|
5093
5370
|
const { merged, conflictRollback } = await mergeBaselineBranch(
|
|
5094
5371
|
cwd,
|
|
@@ -5098,10 +5375,10 @@ async function syncDeployBaselineBeforeDeploy(cwd) {
|
|
|
5098
5375
|
);
|
|
5099
5376
|
const stashConflict = await restoreStashIfNeeded(cwd, stashed, note);
|
|
5100
5377
|
if (conflictRollback || stashConflict) {
|
|
5101
|
-
note(`${
|
|
5378
|
+
note(`${LOG_PREFIX2} \u57FA\u7EBF\u540C\u6B65\u672A\u5B8C\u6210\uFF08\u5B58\u5728\u51B2\u7A81\u5E76\u5DF2\u56DE\u9000\uFF09\uFF0C\u7EE7\u7EED\u6267\u884C\u90E8\u7F72`);
|
|
5102
5379
|
} else if (merged) {
|
|
5103
5380
|
note(
|
|
5104
|
-
`${
|
|
5381
|
+
`${LOG_PREFIX2} \u5B8C\u6210\uFF08\u5F53\u524D\u5206\u652F ${currentBranch} \u5DF2\u5305\u542B ${baselineBranch} \u6700\u65B0\u4EE3\u7801\uFF09`
|
|
5105
5382
|
);
|
|
5106
5383
|
}
|
|
5107
5384
|
return {
|
|
@@ -5114,35 +5391,27 @@ async function syncDeployBaselineBeforeDeploy(cwd) {
|
|
|
5114
5391
|
}
|
|
5115
5392
|
|
|
5116
5393
|
// src/commands/deploy/deploy-execute.ts
|
|
5117
|
-
function runShellCommand2(command, cwd, captureOutput) {
|
|
5118
|
-
const result = spawnSync6(command, {
|
|
5119
|
-
cwd,
|
|
5120
|
-
shell: true,
|
|
5121
|
-
env: buildDeployShellEnv(),
|
|
5122
|
-
encoding: "utf8",
|
|
5123
|
-
stdio: captureOutput ? ["inherit", "pipe", "pipe"] : "inherit"
|
|
5124
|
-
});
|
|
5125
|
-
const stdout = captureOutput ? String(result.stdout ?? "") : "";
|
|
5126
|
-
const stderr = captureOutput ? String(result.stderr ?? "") : "";
|
|
5127
|
-
const output = [stdout, stderr].filter(Boolean).join("\n");
|
|
5128
|
-
if (captureOutput) {
|
|
5129
|
-
if (stdout) process.stdout.write(stdout);
|
|
5130
|
-
if (stderr) process.stderr.write(stderr);
|
|
5131
|
-
}
|
|
5132
|
-
if (result.status !== 0) {
|
|
5133
|
-
throw new DeployExecutionError(
|
|
5134
|
-
`\u90E8\u7F72\u547D\u4EE4\u9000\u51FA\u7801 ${result.status ?? "unknown"}: ${command}`,
|
|
5135
|
-
result.status ?? 1,
|
|
5136
|
-
output
|
|
5137
|
-
);
|
|
5138
|
-
}
|
|
5139
|
-
return output;
|
|
5140
|
-
}
|
|
5141
5394
|
async function executeDeploy(options) {
|
|
5142
|
-
const
|
|
5395
|
+
const cwdInput = options.cwd.trim();
|
|
5396
|
+
if (!cwdInput) {
|
|
5397
|
+
throw new DeployExecutionError("[apm] executeDeploy \u7F3A\u5C11\u5DE5\u4F5C\u76EE\u5F55 cwd", 1);
|
|
5398
|
+
}
|
|
5399
|
+
const cwd = resolveWorkdirPath(cwdInput);
|
|
5143
5400
|
const apmConfigPath = options.configPath ?? path5.join(workspaceApmDir(cwd), "apm.config.json");
|
|
5144
5401
|
const captureOutput = options.captureOutput ?? false;
|
|
5145
5402
|
const outputParts = [];
|
|
5403
|
+
logExecuteDeployContext({
|
|
5404
|
+
trigger: options.deployTrigger,
|
|
5405
|
+
env: options.env,
|
|
5406
|
+
cwd,
|
|
5407
|
+
cwdInput,
|
|
5408
|
+
processCwd: process.cwd(),
|
|
5409
|
+
apmConfigPath,
|
|
5410
|
+
captureOutput,
|
|
5411
|
+
packOnly: options.packOnly,
|
|
5412
|
+
archiveDeployArtifact: options.archiveDeployArtifact,
|
|
5413
|
+
configPathOption: options.configPath
|
|
5414
|
+
});
|
|
5146
5415
|
try {
|
|
5147
5416
|
const configSyncResult = await syncRemoteDeploymentConfig(
|
|
5148
5417
|
cwd,
|
|
@@ -5165,36 +5434,29 @@ async function executeDeploy(options) {
|
|
|
5165
5434
|
detail
|
|
5166
5435
|
);
|
|
5167
5436
|
}
|
|
5437
|
+
const preDeployLog = outputParts.join("\n");
|
|
5168
5438
|
const cfg = loadApmConfig({ configPath: apmConfigPath });
|
|
5169
|
-
if (
|
|
5170
|
-
|
|
5171
|
-
await runWisdomAutoDeploy({
|
|
5172
|
-
env: options.env,
|
|
5173
|
-
cwd,
|
|
5174
|
-
configPath: apmConfigPath,
|
|
5175
|
-
captureOutput,
|
|
5176
|
-
packOnly: options.packOnly
|
|
5177
|
-
});
|
|
5178
|
-
return outputParts.join("\n");
|
|
5179
|
-
} catch (error) {
|
|
5180
|
-
if (error instanceof DeployExecutionError) {
|
|
5181
|
-
throw error;
|
|
5182
|
-
}
|
|
5183
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
5184
|
-
throw new DeployExecutionError(detail, 1);
|
|
5185
|
-
}
|
|
5186
|
-
}
|
|
5187
|
-
const deployCommands = cfg.deploy ?? {};
|
|
5188
|
-
const command = deployCommands[options.env]?.trim();
|
|
5189
|
-
if (!command) {
|
|
5190
|
-
const lines = formatDeployNotConfiguredLines(options.env, deployCommands);
|
|
5439
|
+
if (!isWisdomDeployConfigured(cfg)) {
|
|
5440
|
+
const lines = formatMissingWisdomDeployLines();
|
|
5191
5441
|
throw new DeployExecutionError(lines.join("\n"), 1, lines.join("\n"));
|
|
5192
5442
|
}
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5443
|
+
try {
|
|
5444
|
+
await executeWisdomDeploy({
|
|
5445
|
+
env: options.env,
|
|
5446
|
+
cwd,
|
|
5447
|
+
configPath: apmConfigPath,
|
|
5448
|
+
captureOutput,
|
|
5449
|
+
packOnly: options.packOnly,
|
|
5450
|
+
archiveDeployArtifact: options.archiveDeployArtifact
|
|
5451
|
+
});
|
|
5452
|
+
return preDeployLog;
|
|
5453
|
+
} catch (error) {
|
|
5454
|
+
if (error instanceof DeployExecutionError) {
|
|
5455
|
+
throw error;
|
|
5456
|
+
}
|
|
5457
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
5458
|
+
throw new DeployExecutionError(detail, 1);
|
|
5196
5459
|
}
|
|
5197
|
-
return outputParts.join("\n");
|
|
5198
5460
|
}
|
|
5199
5461
|
function printDeployExecutionError(error) {
|
|
5200
5462
|
if (error.output.trim()) {
|
|
@@ -5209,9 +5471,32 @@ var DEPLOY_LOG_SYNC_INTERVAL_MS = 3e4;
|
|
|
5209
5471
|
function resolveDeployCommand(environment, packOnly) {
|
|
5210
5472
|
return packOnly ? `apm deploy ${environment} --pack-only` : `apm deploy ${environment}`;
|
|
5211
5473
|
}
|
|
5474
|
+
function logDeploySyncFailure(error) {
|
|
5475
|
+
console.error(
|
|
5476
|
+
"[apm] deploy log sync failed:",
|
|
5477
|
+
error instanceof Error ? error.message : String(error)
|
|
5478
|
+
);
|
|
5479
|
+
}
|
|
5212
5480
|
function createDeployLogSyncer(api, deploymentRunId) {
|
|
5213
5481
|
let lastSyncedLog = "";
|
|
5214
5482
|
let latestLog = "";
|
|
5483
|
+
let timer = null;
|
|
5484
|
+
const syncDelta = async (delta, append) => {
|
|
5485
|
+
const chunks = splitUtf8StringByMaxBytes(
|
|
5486
|
+
delta,
|
|
5487
|
+
DEPLOY_LOG_SYNC_MAX_CHUNK_BYTES
|
|
5488
|
+
);
|
|
5489
|
+
for (let index = 0; index < chunks.length; index += 1) {
|
|
5490
|
+
const chunk = chunks[index];
|
|
5491
|
+
await retryDeployLogSync(
|
|
5492
|
+
() => api.cli.syncTaskDeploymentLog({
|
|
5493
|
+
id: deploymentRunId,
|
|
5494
|
+
log: chunk,
|
|
5495
|
+
append: append || index > 0
|
|
5496
|
+
})
|
|
5497
|
+
);
|
|
5498
|
+
}
|
|
5499
|
+
};
|
|
5215
5500
|
const syncIfChanged = async () => {
|
|
5216
5501
|
if (!latestLog || latestLog === lastSyncedLog) {
|
|
5217
5502
|
return;
|
|
@@ -5220,34 +5505,58 @@ function createDeployLogSyncer(api, deploymentRunId) {
|
|
|
5220
5505
|
if (!delta) {
|
|
5221
5506
|
return;
|
|
5222
5507
|
}
|
|
5223
|
-
await
|
|
5224
|
-
id: deploymentRunId,
|
|
5225
|
-
log: delta,
|
|
5226
|
-
append: lastSyncedLog.length > 0
|
|
5227
|
-
});
|
|
5508
|
+
await syncDelta(delta, lastSyncedLog.length > 0);
|
|
5228
5509
|
lastSyncedLog = latestLog;
|
|
5229
5510
|
};
|
|
5230
|
-
|
|
5231
|
-
void syncIfChanged().catch(
|
|
5232
|
-
console.error(
|
|
5233
|
-
"[apm] deploy log sync failed:",
|
|
5234
|
-
error instanceof Error ? error.message : String(error)
|
|
5235
|
-
);
|
|
5236
|
-
});
|
|
5511
|
+
timer = setInterval(() => {
|
|
5512
|
+
void syncIfChanged().catch(logDeploySyncFailure);
|
|
5237
5513
|
}, DEPLOY_LOG_SYNC_INTERVAL_MS);
|
|
5238
5514
|
return {
|
|
5239
5515
|
updateLog(log2) {
|
|
5240
5516
|
latestLog = log2;
|
|
5241
5517
|
},
|
|
5242
5518
|
async flush() {
|
|
5243
|
-
|
|
5519
|
+
if (timer) {
|
|
5520
|
+
clearInterval(timer);
|
|
5521
|
+
timer = null;
|
|
5522
|
+
}
|
|
5244
5523
|
await syncIfChanged();
|
|
5245
5524
|
},
|
|
5525
|
+
async flushSafe() {
|
|
5526
|
+
if (timer) {
|
|
5527
|
+
clearInterval(timer);
|
|
5528
|
+
timer = null;
|
|
5529
|
+
}
|
|
5530
|
+
try {
|
|
5531
|
+
await syncIfChanged();
|
|
5532
|
+
return true;
|
|
5533
|
+
} catch (error) {
|
|
5534
|
+
logDeploySyncFailure(error);
|
|
5535
|
+
return false;
|
|
5536
|
+
}
|
|
5537
|
+
},
|
|
5246
5538
|
dispose() {
|
|
5247
|
-
|
|
5539
|
+
if (timer) {
|
|
5540
|
+
clearInterval(timer);
|
|
5541
|
+
timer = null;
|
|
5542
|
+
}
|
|
5248
5543
|
}
|
|
5249
5544
|
};
|
|
5250
5545
|
}
|
|
5546
|
+
async function finalizeTaskDeployment(api, deploymentRunId, logSyncer, input) {
|
|
5547
|
+
const synced = await logSyncer.flushSafe();
|
|
5548
|
+
const payload = {
|
|
5549
|
+
id: deploymentRunId,
|
|
5550
|
+
status: input.status
|
|
5551
|
+
};
|
|
5552
|
+
if (input.error) {
|
|
5553
|
+
payload.error = input.error;
|
|
5554
|
+
}
|
|
5555
|
+
if (!synced) {
|
|
5556
|
+
payload.log = truncateDeployLogForComplete(input.fullLog).log;
|
|
5557
|
+
}
|
|
5558
|
+
await retryDeployLogSync(() => api.cli.completeTaskDeployment(payload));
|
|
5559
|
+
}
|
|
5251
5560
|
function captureDeployConsole(logSyncer) {
|
|
5252
5561
|
const chunks = [];
|
|
5253
5562
|
const appendLog = (line) => {
|
|
@@ -5296,7 +5605,9 @@ async function handleInboundDeploy(cfg, msg, signal) {
|
|
|
5296
5605
|
env: msg.environment,
|
|
5297
5606
|
cwd: workdir,
|
|
5298
5607
|
packOnly: msg.packOnly,
|
|
5299
|
-
captureOutput: true
|
|
5608
|
+
captureOutput: true,
|
|
5609
|
+
archiveDeployArtifact: true,
|
|
5610
|
+
deployTrigger: "connect"
|
|
5300
5611
|
};
|
|
5301
5612
|
try {
|
|
5302
5613
|
if (signal.aborted) return;
|
|
@@ -5304,11 +5615,9 @@ async function handleInboundDeploy(cfg, msg, signal) {
|
|
|
5304
5615
|
if (output.trim()) {
|
|
5305
5616
|
capture.appendLog(output);
|
|
5306
5617
|
}
|
|
5307
|
-
await logSyncer
|
|
5308
|
-
await api.cli.completeTaskDeployment({
|
|
5309
|
-
id: deploymentRunId,
|
|
5618
|
+
await finalizeTaskDeployment(api, deploymentRunId, logSyncer, {
|
|
5310
5619
|
status: "SUCCESS",
|
|
5311
|
-
|
|
5620
|
+
fullLog: capture.getLog()
|
|
5312
5621
|
});
|
|
5313
5622
|
console.log(`[apm] deploy success id=${deploymentRunId}`);
|
|
5314
5623
|
} catch (error) {
|
|
@@ -5321,13 +5630,18 @@ async function handleInboundDeploy(cfg, msg, signal) {
|
|
|
5321
5630
|
} else {
|
|
5322
5631
|
capture.appendLog(deployError.message);
|
|
5323
5632
|
}
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
})
|
|
5633
|
+
try {
|
|
5634
|
+
await finalizeTaskDeployment(api, deploymentRunId, logSyncer, {
|
|
5635
|
+
status: "FAILED",
|
|
5636
|
+
fullLog: capture.getLog(),
|
|
5637
|
+
error: deployError.message
|
|
5638
|
+
});
|
|
5639
|
+
} catch (finalizeError) {
|
|
5640
|
+
console.error(
|
|
5641
|
+
`[apm] deploy finalize failed id=${deploymentRunId}:`,
|
|
5642
|
+
finalizeError instanceof Error ? finalizeError.message : String(finalizeError)
|
|
5643
|
+
);
|
|
5644
|
+
}
|
|
5331
5645
|
console.error(
|
|
5332
5646
|
`[apm] deploy failed id=${deploymentRunId}: ${deployError.message}`
|
|
5333
5647
|
);
|
|
@@ -5609,13 +5923,13 @@ ${JSON.stringify(event, null, 2)}
|
|
|
5609
5923
|
}
|
|
5610
5924
|
|
|
5611
5925
|
// src/commands/connect/agent-session-registry.ts
|
|
5612
|
-
import { existsSync as
|
|
5613
|
-
import { dirname as
|
|
5926
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync8, readFileSync as readFileSync14, writeFileSync as writeFileSync13 } from "node:fs";
|
|
5927
|
+
import { dirname as dirname6, resolve as resolve4 } from "node:path";
|
|
5614
5928
|
function registryPath(workdir, sessionId) {
|
|
5615
5929
|
return resolve4(workdir, ".apm", "sessions", sessionId, "cursor-agents.json");
|
|
5616
5930
|
}
|
|
5617
5931
|
function readRegistry(path13) {
|
|
5618
|
-
if (!
|
|
5932
|
+
if (!existsSync17(path13)) {
|
|
5619
5933
|
return {};
|
|
5620
5934
|
}
|
|
5621
5935
|
try {
|
|
@@ -5636,7 +5950,7 @@ function readRegistry(path13) {
|
|
|
5636
5950
|
return {};
|
|
5637
5951
|
}
|
|
5638
5952
|
function writeRegistry(path13, registry) {
|
|
5639
|
-
mkdirSync8(
|
|
5953
|
+
mkdirSync8(dirname6(path13), { recursive: true });
|
|
5640
5954
|
writeFileSync13(path13, `${JSON.stringify(registry, null, 2)}
|
|
5641
5955
|
`, "utf8");
|
|
5642
5956
|
}
|
|
@@ -6087,15 +6401,15 @@ async function ensureMessageHasReply(cfg, sessionId, messageId, fallback) {
|
|
|
6087
6401
|
}
|
|
6088
6402
|
|
|
6089
6403
|
// src/commands/connect/cli-version-sync.ts
|
|
6090
|
-
import { existsSync as
|
|
6091
|
-
import { join as
|
|
6404
|
+
import { existsSync as existsSync18, readFileSync as readFileSync15, writeFileSync as writeFileSync14 } from "fs";
|
|
6405
|
+
import { join as join17 } from "path";
|
|
6092
6406
|
var CLI_VERSION_FILE = ".cli-version.json";
|
|
6093
6407
|
function manifestPath(apmDir) {
|
|
6094
|
-
return
|
|
6408
|
+
return join17(apmDir, CLI_VERSION_FILE);
|
|
6095
6409
|
}
|
|
6096
6410
|
function loadManifest4(apmDir) {
|
|
6097
6411
|
const path13 = toFsPath(manifestPath(apmDir));
|
|
6098
|
-
if (!
|
|
6412
|
+
if (!existsSync18(path13)) {
|
|
6099
6413
|
return null;
|
|
6100
6414
|
}
|
|
6101
6415
|
try {
|
|
@@ -6163,23 +6477,53 @@ function markPullDone(sessionId, workdir) {
|
|
|
6163
6477
|
|
|
6164
6478
|
// src/commands/connect/run-slot-pool.ts
|
|
6165
6479
|
var DEFAULT_MAX_CONCURRENT = 5;
|
|
6166
|
-
function createRunSlotPool(maxConcurrent = DEFAULT_MAX_CONCURRENT) {
|
|
6480
|
+
function createRunSlotPool(maxConcurrent = DEFAULT_MAX_CONCURRENT, options = {}) {
|
|
6481
|
+
const label = options.label ?? "task";
|
|
6482
|
+
const isDeployPool = label === "deploy";
|
|
6167
6483
|
let active = 0;
|
|
6168
6484
|
const waiters = [];
|
|
6169
|
-
const
|
|
6485
|
+
const logDeploy = (message) => {
|
|
6486
|
+
if (isDeployPool) {
|
|
6487
|
+
console.error(`[apm] deploy \u4E32\u884C\u9650\u6D41\uFF1A${message}`);
|
|
6488
|
+
}
|
|
6489
|
+
};
|
|
6490
|
+
const acquire = (meta) => {
|
|
6170
6491
|
if (active < maxConcurrent) {
|
|
6171
6492
|
active += 1;
|
|
6493
|
+
if (isDeployPool) {
|
|
6494
|
+
logDeploy(
|
|
6495
|
+
`\u5F00\u59CB\u6267\u884C${meta ? `\uFF08${meta}\uFF09` : ""}\uFF0C\u5F53\u524D\u5360\u7528 ${active}/${maxConcurrent}`
|
|
6496
|
+
);
|
|
6497
|
+
}
|
|
6172
6498
|
return Promise.resolve();
|
|
6173
6499
|
}
|
|
6500
|
+
const queueIndex = waiters.length + 1;
|
|
6501
|
+
if (isDeployPool) {
|
|
6502
|
+
logDeploy(
|
|
6503
|
+
`\u5E76\u53D1\u5DF2\u6EE1\uFF08${maxConcurrent}/${maxConcurrent}\uFF09\uFF0C${meta ? `${meta} ` : ""}\u8FDB\u5165\u6392\u961F\uFF0C\u524D\u65B9 ${queueIndex} \u4E2A`
|
|
6504
|
+
);
|
|
6505
|
+
}
|
|
6506
|
+
const queuedAt = Date.now();
|
|
6174
6507
|
return new Promise((resolve5) => {
|
|
6175
6508
|
waiters.push(() => {
|
|
6176
6509
|
active += 1;
|
|
6510
|
+
const waitedMs = Date.now() - queuedAt;
|
|
6511
|
+
if (isDeployPool) {
|
|
6512
|
+
logDeploy(
|
|
6513
|
+
`\u6392\u961F\u7ED3\u675F\uFF0C\u5F00\u59CB\u6267\u884C${meta ? `\uFF08${meta}\uFF09` : ""}\uFF0C\u7B49\u5F85 ${Math.ceil(
|
|
6514
|
+
waitedMs / 1e3
|
|
6515
|
+
)}s\uFF0C\u5F53\u524D\u5360\u7528 ${active}/${maxConcurrent}`
|
|
6516
|
+
);
|
|
6517
|
+
}
|
|
6177
6518
|
resolve5();
|
|
6178
6519
|
});
|
|
6179
6520
|
});
|
|
6180
6521
|
};
|
|
6181
6522
|
const release = () => {
|
|
6182
6523
|
active = Math.max(0, active - 1);
|
|
6524
|
+
if (isDeployPool) {
|
|
6525
|
+
logDeploy(`\u6267\u884C\u69FD\u91CA\u653E\uFF0C\u5F53\u524D\u5360\u7528 ${active}/${maxConcurrent}`);
|
|
6526
|
+
}
|
|
6183
6527
|
const next = waiters.shift();
|
|
6184
6528
|
if (next) {
|
|
6185
6529
|
next();
|
|
@@ -6376,6 +6720,7 @@ function attachWsHandlers(ws, ctx, onOpen) {
|
|
|
6376
6720
|
clientMachineId,
|
|
6377
6721
|
shutdownAbort,
|
|
6378
6722
|
runSlots,
|
|
6723
|
+
deployRunSlots,
|
|
6379
6724
|
activeTasks,
|
|
6380
6725
|
activeRuns,
|
|
6381
6726
|
pendingCancels,
|
|
@@ -6414,12 +6759,13 @@ function attachWsHandlers(ws, ctx, onOpen) {
|
|
|
6414
6759
|
shutdownAbort.signal,
|
|
6415
6760
|
perDeployController.signal
|
|
6416
6761
|
]);
|
|
6762
|
+
const deploySlotMeta = `deploymentRunId=${msg2.deploymentRunId} env=${msg2.environment} workdir=${msg2.workdir}`;
|
|
6417
6763
|
const task2 = (async () => {
|
|
6418
|
-
await
|
|
6764
|
+
await deployRunSlots.acquire(deploySlotMeta);
|
|
6419
6765
|
try {
|
|
6420
6766
|
await handleInboundDeploy(cfg, msg2, signal2);
|
|
6421
6767
|
} finally {
|
|
6422
|
-
|
|
6768
|
+
deployRunSlots.release();
|
|
6423
6769
|
}
|
|
6424
6770
|
})();
|
|
6425
6771
|
activeTasks.add(task2);
|
|
@@ -6577,6 +6923,7 @@ async function runConnect(options) {
|
|
|
6577
6923
|
const lifecycleAbort = new AbortController();
|
|
6578
6924
|
const shutdownAbort = new AbortController();
|
|
6579
6925
|
const runSlots = createRunSlotPool();
|
|
6926
|
+
const deployRunSlots = createRunSlotPool(1, { label: "deploy" });
|
|
6580
6927
|
const activeTasks = /* @__PURE__ */ new Set();
|
|
6581
6928
|
const activeRuns = /* @__PURE__ */ new Map();
|
|
6582
6929
|
const pendingCancels = /* @__PURE__ */ new Set();
|
|
@@ -6586,6 +6933,7 @@ async function runConnect(options) {
|
|
|
6586
6933
|
clientMachineId,
|
|
6587
6934
|
shutdownAbort,
|
|
6588
6935
|
runSlots,
|
|
6936
|
+
deployRunSlots,
|
|
6589
6937
|
activeTasks,
|
|
6590
6938
|
activeRuns,
|
|
6591
6939
|
pendingCancels,
|
|
@@ -6599,7 +6947,7 @@ async function runConnect(options) {
|
|
|
6599
6947
|
shutdownAbort.abort();
|
|
6600
6948
|
logAbortSignalStats(shutdownAbort.signal, "connect:shutdown-after-abort");
|
|
6601
6949
|
try {
|
|
6602
|
-
await Promise.race([Promise.all(activeTasks),
|
|
6950
|
+
await Promise.race([Promise.all(activeTasks), delay3(drainMs)]);
|
|
6603
6951
|
} catch {
|
|
6604
6952
|
}
|
|
6605
6953
|
releaseConnectLock();
|
|
@@ -6797,10 +7145,9 @@ function normalizeDeployEnvironment(env) {
|
|
|
6797
7145
|
}
|
|
6798
7146
|
async function completeTrackedDeploy(api, deploymentRunId, logSyncer, input) {
|
|
6799
7147
|
logSyncer.updateLog(input.log);
|
|
6800
|
-
await logSyncer
|
|
6801
|
-
await api.cli.completeTaskDeployment({
|
|
6802
|
-
id: deploymentRunId,
|
|
7148
|
+
await finalizeTaskDeployment(api, deploymentRunId, logSyncer, {
|
|
6803
7149
|
status: input.status,
|
|
7150
|
+
fullLog: input.log,
|
|
6804
7151
|
error: input.error
|
|
6805
7152
|
});
|
|
6806
7153
|
}
|
|
@@ -6825,7 +7172,7 @@ async function runDeployWithBackendTracking(options) {
|
|
|
6825
7172
|
const run = await api.cli.createTaskDeployment({
|
|
6826
7173
|
sessionId: options.sessionId,
|
|
6827
7174
|
environment,
|
|
6828
|
-
workdirPath: options.cwd
|
|
7175
|
+
workdirPath: options.cwd
|
|
6829
7176
|
});
|
|
6830
7177
|
deploymentRunId = run.id;
|
|
6831
7178
|
console.log(
|
|
@@ -6861,7 +7208,11 @@ async function runDeployWithBackendTracking(options) {
|
|
|
6861
7208
|
originalError.apply(console, args);
|
|
6862
7209
|
};
|
|
6863
7210
|
try {
|
|
6864
|
-
const output = await executeDeploy({
|
|
7211
|
+
const output = await executeDeploy({
|
|
7212
|
+
...options,
|
|
7213
|
+
captureOutput: true,
|
|
7214
|
+
archiveDeployArtifact: true
|
|
7215
|
+
});
|
|
6865
7216
|
if (output.trim()) {
|
|
6866
7217
|
appendLog(output);
|
|
6867
7218
|
}
|
|
@@ -6904,8 +7255,8 @@ async function runDeployWithBackendTracking(options) {
|
|
|
6904
7255
|
// src/commands/deploy/deploy.ts
|
|
6905
7256
|
function registerDeployMainCommand(program) {
|
|
6906
7257
|
program.command("deploy").description(
|
|
6907
|
-
"\
|
|
6908
|
-
).argument("<env>", "\u90E8\u7F72\u73AF\u5883\u540D\uFF08\u5982 test\u3001online\uFF09").option(
|
|
7258
|
+
"\u533B\u52A1\u90E8\u7F72\uFF1AVue build + SFTP / Java Maven + SSH\uFF08\u9700 apm.config.json wisdomDeploy\uFF09"
|
|
7259
|
+
).argument("<env>", "\u90E8\u7F72\u73AF\u5883\u540D\uFF08\u5982 test\u3001online\uFF1BVue \u5BF9\u5E94 build:<env>\uFF09").option(
|
|
6909
7260
|
"--config <path>",
|
|
6910
7261
|
"apm.config.json \u8DEF\u5F84\uFF08\u9ED8\u8BA4 .apm/apm.config.json\uFF09"
|
|
6911
7262
|
).option(
|
|
@@ -6913,7 +7264,7 @@ function registerDeployMainCommand(program) {
|
|
|
6913
7264
|
"\u6C9F\u901A\u7FA4 ID\uFF1B\u4F20\u5165\u65F6\u5728\u5E73\u53F0\u521B\u5EFA\u90E8\u7F72\u8BB0\u5F55\u5E76\u540C\u6B65\u65E5\u5FD7"
|
|
6914
7265
|
).option(
|
|
6915
7266
|
"--pack-only",
|
|
6916
|
-
"\u4EC5\u6784\u5EFA/\u6253\u5305\
|
|
7267
|
+
"\u4EC5\u6784\u5EFA/\u6253\u5305\uFF0C\u4E0D\u4E0A\u4F20\u8FDC\u7A0B SFTP/SSH\uFF1B\u53EF\u5F52\u6863\u5E73\u53F0\u90E8\u7F72\u4EA7\u7269"
|
|
6917
7268
|
).action(
|
|
6918
7269
|
async (env, opts) => {
|
|
6919
7270
|
const cwd = process.cwd();
|
|
@@ -6926,11 +7277,18 @@ function registerDeployMainCommand(program) {
|
|
|
6926
7277
|
cwd,
|
|
6927
7278
|
configPath: opts.config,
|
|
6928
7279
|
sessionId,
|
|
6929
|
-
packOnly
|
|
7280
|
+
packOnly,
|
|
7281
|
+
deployTrigger: "session"
|
|
6930
7282
|
});
|
|
6931
7283
|
return;
|
|
6932
7284
|
}
|
|
6933
|
-
await executeDeploy({
|
|
7285
|
+
await executeDeploy({
|
|
7286
|
+
env,
|
|
7287
|
+
cwd,
|
|
7288
|
+
configPath: opts.config,
|
|
7289
|
+
packOnly,
|
|
7290
|
+
deployTrigger: "cli"
|
|
7291
|
+
});
|
|
6934
7292
|
} catch (error) {
|
|
6935
7293
|
if (error instanceof DeployExecutionError) {
|
|
6936
7294
|
printDeployExecutionError(error);
|
|
@@ -6952,7 +7310,7 @@ import path9 from "node:path";
|
|
|
6952
7310
|
import Docker from "dockerode";
|
|
6953
7311
|
|
|
6954
7312
|
// src/commands/deploy/internal/backend-deploy/dockerode-client/connection-options.ts
|
|
6955
|
-
import { existsSync as
|
|
7313
|
+
import { existsSync as existsSync19, readFileSync as readFileSync16 } from "node:fs";
|
|
6956
7314
|
import path6 from "node:path";
|
|
6957
7315
|
function asOptionalTlsBuffer(value) {
|
|
6958
7316
|
if (typeof value !== "string") {
|
|
@@ -6964,7 +7322,7 @@ function asOptionalTlsBuffer(value) {
|
|
|
6964
7322
|
if (normalized === "") {
|
|
6965
7323
|
return void 0;
|
|
6966
7324
|
}
|
|
6967
|
-
if (
|
|
7325
|
+
if (existsSync19(normalized)) {
|
|
6968
7326
|
return readFileSync16(normalized);
|
|
6969
7327
|
}
|
|
6970
7328
|
const looksLikePath = /[\\/]/.test(normalized) || normalized.endsWith(".pem");
|
|
@@ -7175,7 +7533,7 @@ var DockerodeClient = class {
|
|
|
7175
7533
|
var createDockerodeClient = (config) => new DockerodeClient(config);
|
|
7176
7534
|
|
|
7177
7535
|
// src/commands/deploy/internal/backend-deploy/dockerode-client/env.ts
|
|
7178
|
-
import { existsSync as
|
|
7536
|
+
import { existsSync as existsSync20, readFileSync as readFileSync17, statSync as statSync8 } from "node:fs";
|
|
7179
7537
|
import path7 from "node:path";
|
|
7180
7538
|
function stripSurroundingQuotes(value) {
|
|
7181
7539
|
const t = value.trim();
|
|
@@ -7192,7 +7550,7 @@ function loadEnvFromFile(envFilePath) {
|
|
|
7192
7550
|
return {};
|
|
7193
7551
|
}
|
|
7194
7552
|
const targetPath = path7.resolve(envFilePath);
|
|
7195
|
-
if (!
|
|
7553
|
+
if (!existsSync20(targetPath) || !statSync8(targetPath).isFile()) {
|
|
7196
7554
|
return {};
|
|
7197
7555
|
}
|
|
7198
7556
|
const raw = readFileSync17(targetPath, "utf-8");
|
|
@@ -7366,12 +7724,12 @@ function dockerPushImage(params, cwd) {
|
|
|
7366
7724
|
}
|
|
7367
7725
|
|
|
7368
7726
|
// src/commands/deploy/internal/backend-deploy/resolve-dockerfile.ts
|
|
7369
|
-
import { existsSync as
|
|
7727
|
+
import { existsSync as existsSync21 } from "node:fs";
|
|
7370
7728
|
import path8 from "node:path";
|
|
7371
7729
|
function resolveDockerBuildPaths(cwd) {
|
|
7372
7730
|
const dockerfilePath = path8.join(cwd, "Dockerfile");
|
|
7373
7731
|
Logger.info(`\u67E5\u627EDockerfile\u6587\u4EF6\uFF0C\u8DEF\u5F84: ${dockerfilePath}`);
|
|
7374
|
-
if (!
|
|
7732
|
+
if (!existsSync21(dockerfilePath)) {
|
|
7375
7733
|
throw new Error(`Dockerfile \u4E0D\u5B58\u5728\uFF1A${dockerfilePath}`);
|
|
7376
7734
|
}
|
|
7377
7735
|
Logger.info("\u2713 Dockerfile \u5B58\u5728");
|