@ranger1/dx 0.1.83 → 0.1.84
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.
|
@@ -16,6 +16,32 @@ function requirePositiveInteger(value, fieldPath) {
|
|
|
16
16
|
return parsed
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
function resolveVerifyConfig(verifyConfig = {}) {
|
|
20
|
+
const healthCheckConfig = verifyConfig?.healthCheck
|
|
21
|
+
if (healthCheckConfig == null) {
|
|
22
|
+
return {
|
|
23
|
+
healthCheck: null,
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const url = requireString(healthCheckConfig.url, 'verify.healthCheck.url')
|
|
28
|
+
try {
|
|
29
|
+
new URL(url)
|
|
30
|
+
} catch {
|
|
31
|
+
throw new Error(`缺少必填配置: verify.healthCheck.url`)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
healthCheck: {
|
|
36
|
+
url,
|
|
37
|
+
timeoutSeconds:
|
|
38
|
+
healthCheckConfig.timeoutSeconds == null
|
|
39
|
+
? 10
|
|
40
|
+
: requirePositiveInteger(healthCheckConfig.timeoutSeconds, 'verify.healthCheck.timeoutSeconds'),
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
19
45
|
function resolveBuildCommand(buildConfig, environment) {
|
|
20
46
|
if (buildConfig?.commands && typeof buildConfig.commands === 'object') {
|
|
21
47
|
const selected = buildConfig.commands[environment]
|
|
@@ -55,6 +81,7 @@ export function resolveBackendDeployConfig({ cli, targetConfig, environment, fla
|
|
|
55
81
|
const remoteConfig = deployConfig.remote || null
|
|
56
82
|
const startupConfig = deployConfig.startup || {}
|
|
57
83
|
const runConfig = deployConfig.deploy || {}
|
|
84
|
+
const verifyConfig = deployConfig.verify || {}
|
|
58
85
|
const buildOnly = Boolean(flags.buildOnly)
|
|
59
86
|
const startupMode = String(startupConfig.mode || 'pm2').trim()
|
|
60
87
|
const prismaGenerate = runConfig.prismaGenerate !== false
|
|
@@ -117,6 +144,7 @@ export function resolveBackendDeployConfig({ cli, targetConfig, environment, fla
|
|
|
117
144
|
prismaMigrateDeploy,
|
|
118
145
|
skipMigration: Boolean(flags.skipMigration),
|
|
119
146
|
},
|
|
147
|
+
verify: resolveVerifyConfig(verifyConfig),
|
|
120
148
|
}
|
|
121
149
|
|
|
122
150
|
if (!['pm2', 'direct'].includes(normalized.startup.mode)) {
|
|
@@ -8,7 +8,11 @@ export function buildRemoteDeployScript(phaseModel = []) {
|
|
|
8
8
|
const runtime = payload.runtime || {}
|
|
9
9
|
const startup = payload.startup || {}
|
|
10
10
|
const deploy = payload.deploy || {}
|
|
11
|
+
const verify = payload.verify || {}
|
|
12
|
+
const healthCheck = verify.healthCheck || null
|
|
11
13
|
const environment = String(payload.environment || 'production')
|
|
14
|
+
const expectedAppEnv = environment
|
|
15
|
+
const expectedNodeEnv = environment === 'development' ? 'development' : 'production'
|
|
12
16
|
const baseDir = String(remote.baseDir || '.')
|
|
13
17
|
const releaseDir = `${baseDir}/releases/${payload.versionName || 'unknown'}`
|
|
14
18
|
const currentLink = `${baseDir}/current`
|
|
@@ -26,6 +30,8 @@ export function buildRemoteDeployScript(phaseModel = []) {
|
|
|
26
30
|
const keepReleases = Number(deploy.keepReleases || 5)
|
|
27
31
|
const shouldGenerate = deploy.prismaGenerate !== false
|
|
28
32
|
const shouldMigrate = deploy.prismaMigrateDeploy !== false && deploy.skipMigration !== true
|
|
33
|
+
const healthCheckUrl = healthCheck?.url ? String(healthCheck.url) : ''
|
|
34
|
+
const healthCheckTimeoutSeconds = Number(healthCheck?.timeoutSeconds || 10)
|
|
29
35
|
|
|
30
36
|
return `#!/usr/bin/env bash
|
|
31
37
|
set -euo pipefail
|
|
@@ -36,6 +42,8 @@ ARCHIVE=${escapeShell(uploadedBundlePath)}
|
|
|
36
42
|
RELEASE_DIR=${escapeShell(releaseDir)}
|
|
37
43
|
CURRENT_LINK=${escapeShell(currentLink)}
|
|
38
44
|
ENV_NAME=${escapeShell(environment)}
|
|
45
|
+
EXPECTED_APP_ENV=${escapeShell(expectedAppEnv)}
|
|
46
|
+
EXPECTED_NODE_ENV=${escapeShell(expectedNodeEnv)}
|
|
39
47
|
ENV_FILE_NAME=${escapeShell(envFileName)}
|
|
40
48
|
ENV_LOCAL_FILE_NAME=${escapeShell(envLocalFileName)}
|
|
41
49
|
PRISMA_SCHEMA=${escapeShell(prismaSchema)}
|
|
@@ -45,6 +53,8 @@ INSTALL_COMMAND=${escapeShell(installCommand)}
|
|
|
45
53
|
START_MODE=${escapeShell(startupMode)}
|
|
46
54
|
SERVICE_NAME=${escapeShell(serviceName)}
|
|
47
55
|
START_ENTRY=${escapeShell(startupEntry)}
|
|
56
|
+
HEALTHCHECK_URL=${escapeShell(healthCheckUrl)}
|
|
57
|
+
HEALTHCHECK_TIMEOUT_SECONDS=${healthCheckTimeoutSeconds}
|
|
48
58
|
KEEP_RELEASES=${keepReleases}
|
|
49
59
|
SHOULD_GENERATE=${shouldGenerate ? '1' : '0'}
|
|
50
60
|
SHOULD_MIGRATE=${shouldMigrate ? '1' : '0'}
|
|
@@ -174,10 +184,22 @@ run_with_env() {
|
|
|
174
184
|
shift
|
|
175
185
|
(
|
|
176
186
|
cd "$cwd"
|
|
177
|
-
APP_ENV="$
|
|
187
|
+
APP_ENV="$EXPECTED_APP_ENV" NODE_ENV="$EXPECTED_NODE_ENV" \\
|
|
188
|
+
"$DOTENV_BIN" -o -e "$ENV_FILE_NAME" -e "$ENV_LOCAL_FILE_NAME" -- "$@"
|
|
178
189
|
)
|
|
179
190
|
}
|
|
180
191
|
|
|
192
|
+
read_pm2_env_var() {
|
|
193
|
+
local key="$1"
|
|
194
|
+
pm2 jlist | node -e '
|
|
195
|
+
const fs = require("node:fs")
|
|
196
|
+
const key = process.argv[1]
|
|
197
|
+
const list = JSON.parse(fs.readFileSync(0, "utf8"))
|
|
198
|
+
const app = list.find(item => item?.name === process.argv[2])
|
|
199
|
+
process.stdout.write(String(app?.pm2_env?.[key] || ""))
|
|
200
|
+
' "$key" "$SERVICE_NAME"
|
|
201
|
+
}
|
|
202
|
+
|
|
181
203
|
attempt_pm2_restore() {
|
|
182
204
|
if [[ -z "$PREVIOUS_CURRENT_TARGET" || ! -e "$PREVIOUS_CURRENT_TARGET/$ECOSYSTEM_CONFIG" ]]; then
|
|
183
205
|
ROLLBACK_SUCCEEDED=false
|
|
@@ -185,7 +207,8 @@ attempt_pm2_restore() {
|
|
|
185
207
|
fi
|
|
186
208
|
if (
|
|
187
209
|
cd "$PREVIOUS_CURRENT_TARGET"
|
|
188
|
-
APP_ENV="$
|
|
210
|
+
APP_ENV="$EXPECTED_APP_ENV" NODE_ENV="$EXPECTED_NODE_ENV" \\
|
|
211
|
+
"$DOTENV_BIN" -o -e "$ENV_FILE_NAME" -e "$ENV_LOCAL_FILE_NAME" -- \\
|
|
189
212
|
pm2 start "$ECOSYSTEM_CONFIG" --only "$SERVICE_NAME" --update-env
|
|
190
213
|
pm2 save
|
|
191
214
|
); then
|
|
@@ -291,7 +314,8 @@ if [[ "$START_MODE" == "pm2" ]]; then
|
|
|
291
314
|
if ! (
|
|
292
315
|
cd "$CURRENT_LINK"
|
|
293
316
|
pm2 delete "$SERVICE_NAME" || true
|
|
294
|
-
APP_ENV="$
|
|
317
|
+
APP_ENV="$EXPECTED_APP_ENV" NODE_ENV="$EXPECTED_NODE_ENV" \\
|
|
318
|
+
"$DOTENV_BIN" -o -e "$ENV_FILE_NAME" -e "$ENV_LOCAL_FILE_NAME" -- \\
|
|
295
319
|
pm2 start "$ECOSYSTEM_CONFIG" --only "$SERVICE_NAME" --update-env
|
|
296
320
|
pm2 save
|
|
297
321
|
); then
|
|
@@ -306,7 +330,8 @@ if [[ "$START_MODE" == "pm2" ]]; then
|
|
|
306
330
|
else
|
|
307
331
|
if ! (
|
|
308
332
|
cd "$CURRENT_LINK"
|
|
309
|
-
APP_ENV="$
|
|
333
|
+
APP_ENV="$EXPECTED_APP_ENV" NODE_ENV="$EXPECTED_NODE_ENV" \\
|
|
334
|
+
"$DOTENV_BIN" -o -e "$ENV_FILE_NAME" -e "$ENV_LOCAL_FILE_NAME" -- \\
|
|
310
335
|
node "$START_ENTRY"
|
|
311
336
|
); then
|
|
312
337
|
emit_result false "startup" "direct startup failed" false null
|
|
@@ -316,6 +341,50 @@ else
|
|
|
316
341
|
exit 0
|
|
317
342
|
fi
|
|
318
343
|
|
|
344
|
+
CURRENT_PHASE="verify"
|
|
345
|
+
echo "DX_REMOTE_PHASE=verify"
|
|
346
|
+
if [[ ! -L "$CURRENT_LINK" ]]; then
|
|
347
|
+
echo "current 软链接不存在: $CURRENT_LINK" >&2
|
|
348
|
+
exit 1
|
|
349
|
+
fi
|
|
350
|
+
|
|
351
|
+
current_release="$(readlink -f "$CURRENT_LINK")"
|
|
352
|
+
expected_release="$(readlink -f "$RELEASE_DIR")"
|
|
353
|
+
if [[ -z "$current_release" || ! -d "$current_release" ]]; then
|
|
354
|
+
echo "current 软链接未指向有效目录: \${current_release:-<empty>}" >&2
|
|
355
|
+
exit 1
|
|
356
|
+
fi
|
|
357
|
+
if [[ "$current_release" != "$expected_release" ]]; then
|
|
358
|
+
echo "current 软链接未指向本次 release: expected=$expected_release actual=$current_release" >&2
|
|
359
|
+
exit 1
|
|
360
|
+
fi
|
|
361
|
+
|
|
362
|
+
if [[ "$START_MODE" == "pm2" ]]; then
|
|
363
|
+
if ! pm2 describe "$SERVICE_NAME" >/dev/null 2>&1; then
|
|
364
|
+
echo "PM2 进程不存在: $SERVICE_NAME" >&2
|
|
365
|
+
pm2 list || true
|
|
366
|
+
exit 1
|
|
367
|
+
fi
|
|
368
|
+
|
|
369
|
+
pm2_app_env="$(read_pm2_env_var APP_ENV)"
|
|
370
|
+
if [[ "$pm2_app_env" != "$EXPECTED_APP_ENV" ]]; then
|
|
371
|
+
echo "APP_ENV 不匹配,期望=$EXPECTED_APP_ENV,实际=\${pm2_app_env:-<empty>}" >&2
|
|
372
|
+
pm2 describe "$SERVICE_NAME" || true
|
|
373
|
+
exit 1
|
|
374
|
+
fi
|
|
375
|
+
|
|
376
|
+
pm2_node_env="$(read_pm2_env_var NODE_ENV)"
|
|
377
|
+
if [[ "$pm2_node_env" != "$EXPECTED_NODE_ENV" ]]; then
|
|
378
|
+
echo "NODE_ENV 不匹配,期望=$EXPECTED_NODE_ENV,实际=\${pm2_node_env:-<empty>}" >&2
|
|
379
|
+
pm2 describe "$SERVICE_NAME" || true
|
|
380
|
+
exit 1
|
|
381
|
+
fi
|
|
382
|
+
fi
|
|
383
|
+
|
|
384
|
+
if [[ -n "$HEALTHCHECK_URL" ]]; then
|
|
385
|
+
curl -fsS --max-time "$HEALTHCHECK_TIMEOUT_SECONDS" "$HEALTHCHECK_URL" >/dev/null
|
|
386
|
+
fi
|
|
387
|
+
|
|
319
388
|
CURRENT_PHASE="cleanup"
|
|
320
389
|
echo "DX_REMOTE_PHASE=cleanup"
|
|
321
390
|
release_count=0
|