@ranger1/dx 0.1.86 → 0.1.88
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -199,11 +199,13 @@ dx deploy front --staging
|
|
|
199
199
|
dx deploy backend --prod
|
|
200
200
|
dx lint
|
|
201
201
|
dx test e2e backend apps/backend/e2e/auth
|
|
202
|
+
dx test e2e quantify apps/quantify/e2e/health/health.e2e-spec.ts
|
|
202
203
|
```
|
|
203
204
|
|
|
204
205
|
命令约束摘要:
|
|
205
206
|
|
|
206
|
-
- `dx test e2e
|
|
207
|
+
- 对声明了 `requiresPath: true` 的 E2E target,`dx test e2e <target>` 必须提供文件或目录路径,禁止无路径或 `all` 全量执行
|
|
208
|
+
- `dx test e2e all` 不受支持,必须显式指定 target 和路径
|
|
207
209
|
- `dx db migrate` 仅允许在 `--dev` 环境创建迁移;非开发环境请使用 `dx db deploy`
|
|
208
210
|
- `dx start` 未指定服务时默认是开发套件,仅允许 `--dev`
|
|
209
211
|
- `dx start` 下的单层目标(如 `stagewise-front`)默认仅支持 `--dev`
|
|
@@ -97,6 +97,7 @@ export function resolveBackendDeployConfig({ cli, targetConfig, environment, fla
|
|
|
97
97
|
const startupMode = String(startupConfig.mode || 'pm2').trim()
|
|
98
98
|
const prismaGenerate = runConfig.prismaGenerate !== false
|
|
99
99
|
const prismaMigrateDeploy = runConfig.prismaMigrateDeploy !== false
|
|
100
|
+
const prismaSeed = runConfig.prismaSeed === true
|
|
100
101
|
|
|
101
102
|
const normalized = {
|
|
102
103
|
projectRoot: cli.projectRoot,
|
|
@@ -153,6 +154,7 @@ export function resolveBackendDeployConfig({ cli, targetConfig, environment, fla
|
|
|
153
154
|
),
|
|
154
155
|
prismaGenerate,
|
|
155
156
|
prismaMigrateDeploy,
|
|
157
|
+
prismaSeed,
|
|
156
158
|
skipMigration: Boolean(flags.skipMigration),
|
|
157
159
|
},
|
|
158
160
|
verify: resolveVerifyConfig(verifyConfig),
|
|
@@ -168,7 +170,7 @@ export function resolveBackendDeployConfig({ cli, targetConfig, environment, fla
|
|
|
168
170
|
requireString(normalized.startup.entry, 'startup.entry')
|
|
169
171
|
}
|
|
170
172
|
|
|
171
|
-
if (normalized.deploy.prismaGenerate || normalized.deploy.prismaMigrateDeploy) {
|
|
173
|
+
if (normalized.deploy.prismaGenerate || normalized.deploy.prismaMigrateDeploy || normalized.deploy.prismaSeed) {
|
|
172
174
|
requireString(normalized.runtime.prismaSchemaDir, 'runtime.prismaSchemaDir')
|
|
173
175
|
requireString(normalized.runtime.prismaConfig, 'runtime.prismaConfig')
|
|
174
176
|
}
|
|
@@ -30,6 +30,7 @@ export function buildRemoteDeployScript(phaseModel = []) {
|
|
|
30
30
|
const keepReleases = Number(deploy.keepReleases || 5)
|
|
31
31
|
const shouldGenerate = deploy.prismaGenerate !== false
|
|
32
32
|
const shouldMigrate = deploy.prismaMigrateDeploy !== false && deploy.skipMigration !== true
|
|
33
|
+
const shouldSeed = deploy.prismaSeed === true
|
|
33
34
|
const healthCheckUrl = healthCheck?.url ? String(healthCheck.url) : ''
|
|
34
35
|
const healthCheckTimeoutSeconds = Number(healthCheck?.timeoutSeconds || 10)
|
|
35
36
|
const healthCheckMaxWaitSeconds = Number(healthCheck?.maxWaitSeconds || 24)
|
|
@@ -62,6 +63,7 @@ HEALTHCHECK_RETRY_DELAY_SECONDS=${healthCheckRetryIntervalSeconds}
|
|
|
62
63
|
KEEP_RELEASES=${keepReleases}
|
|
63
64
|
SHOULD_GENERATE=${shouldGenerate ? '1' : '0'}
|
|
64
65
|
SHOULD_MIGRATE=${shouldMigrate ? '1' : '0'}
|
|
66
|
+
SHOULD_SEED=${shouldSeed ? '1' : '0'}
|
|
65
67
|
|
|
66
68
|
LOCK_FILE="$APP_ROOT/.deploy.lock"
|
|
67
69
|
LOCK_DIR="$APP_ROOT/.deploy.lock.d"
|
|
@@ -345,6 +347,17 @@ if [[ "$SHOULD_MIGRATE" == "1" ]]; then
|
|
|
345
347
|
MIGRATION_EXECUTED=1
|
|
346
348
|
fi
|
|
347
349
|
|
|
350
|
+
if [[ "$SHOULD_SEED" == "1" ]]; then
|
|
351
|
+
CURRENT_PHASE="prisma-seed"
|
|
352
|
+
echo "DX_REMOTE_PHASE=prisma-seed"
|
|
353
|
+
PRISMA_BIN="$RELEASE_DIR/node_modules/.bin/prisma"
|
|
354
|
+
if [[ ! -x "$PRISMA_BIN" ]]; then
|
|
355
|
+
echo "缺少可执行文件: $PRISMA_BIN" >&2
|
|
356
|
+
exit 1
|
|
357
|
+
fi
|
|
358
|
+
run_with_env "$RELEASE_DIR" "$PRISMA_BIN" db seed --schema="$PRISMA_SCHEMA" --config="$PRISMA_CONFIG"
|
|
359
|
+
fi
|
|
360
|
+
|
|
348
361
|
CURRENT_PHASE="switch-current"
|
|
349
362
|
echo "DX_REMOTE_PHASE=switch-current"
|
|
350
363
|
ln -sfn "$RELEASE_DIR" "$CURRENT_LINK"
|
package/lib/cli/commands/core.js
CHANGED
|
@@ -94,22 +94,34 @@ export async function handleTest(cli, args) {
|
|
|
94
94
|
cli.flags.test = true
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
const typeConfig = cli.commands.test[type]
|
|
98
|
+
let testConfig = typeConfig?.[target]
|
|
99
|
+
if (!testConfig && typeConfig?.command) {
|
|
100
|
+
testConfig = typeConfig
|
|
101
|
+
}
|
|
98
102
|
|
|
99
103
|
if (!testConfig) {
|
|
100
104
|
logger.error(`未找到测试配置: ${type}.${target}`)
|
|
101
|
-
process.
|
|
105
|
+
process.exit(1)
|
|
102
106
|
return
|
|
103
107
|
}
|
|
104
108
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
109
|
+
if (type === 'e2e' && testConfig.requiresPath && testPath) {
|
|
110
|
+
if (!testConfig.fileCommand) {
|
|
111
|
+
logger.error(`测试配置错误: test.${type}.${target} 已启用 requiresPath,必须配置 fileCommand`)
|
|
112
|
+
process.exit(1)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const fileCommand = String(testConfig.fileCommand)
|
|
116
|
+
if (!fileCommand.includes('{TEST_PATH}')) {
|
|
117
|
+
logger.error(`测试配置错误: test.${type}.${target} 的 fileCommand 必须包含 {TEST_PATH}`)
|
|
118
|
+
process.exit(1)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
let command = fileCommand.replace('{TEST_PATH}', shellEscape(testPath))
|
|
108
122
|
|
|
109
|
-
// 如果指定了测试用例名称,添加 -t 参数
|
|
110
123
|
if (testNamePattern) {
|
|
111
|
-
|
|
112
|
-
command += ` -t "${escapedPattern}"`
|
|
124
|
+
command += ` -t ${shellEscape(testNamePattern)}`
|
|
113
125
|
}
|
|
114
126
|
|
|
115
127
|
testConfig = {
|
|
@@ -132,6 +144,10 @@ export async function handleTest(cli, args) {
|
|
|
132
144
|
await cli.executeCommand(testConfig)
|
|
133
145
|
}
|
|
134
146
|
|
|
147
|
+
function shellEscape(value) {
|
|
148
|
+
return `'${String(value).replace(/'/g, `'\\''`)}'`
|
|
149
|
+
}
|
|
150
|
+
|
|
135
151
|
export async function handleLint(cli, args) {
|
|
136
152
|
void args
|
|
137
153
|
const baseConfig = cli.commands.lint
|
package/lib/cli/dx-cli.js
CHANGED
|
@@ -608,17 +608,27 @@ class DxCli {
|
|
|
608
608
|
}
|
|
609
609
|
|
|
610
610
|
validateTestPositionals(positionalArgs) {
|
|
611
|
-
if (positionalArgs.length === 0) return
|
|
612
|
-
|
|
613
611
|
const [type = 'e2e', target = 'all', testPath] = positionalArgs
|
|
614
612
|
|
|
615
|
-
if (type
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
logger.
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
613
|
+
if (type !== 'e2e') return
|
|
614
|
+
|
|
615
|
+
if (target === 'all') {
|
|
616
|
+
logger.error('dx test e2e all 不受支持,请指定 target 和测试文件或目录路径')
|
|
617
|
+
process.exit(1)
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
const testConfig = this.commands?.test?.[type]?.[target]
|
|
621
|
+
if (!testConfig) return
|
|
622
|
+
if (!testConfig.requiresPath) return
|
|
623
|
+
|
|
624
|
+
if (!testPath) {
|
|
625
|
+
logger.error(`dx test e2e ${target} 必须提供测试文件或目录路径`)
|
|
626
|
+
logger.info(`示例: ${this.invocation} test e2e ${target} apps/${target}/e2e/health`)
|
|
627
|
+
process.exit(1)
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
if (testPath === 'all') {
|
|
631
|
+
logger.error(`dx test e2e ${target} 不支持 all,必须提供测试文件或目录路径`)
|
|
622
632
|
process.exit(1)
|
|
623
633
|
}
|
|
624
634
|
}
|
package/lib/cli/help.js
CHANGED
|
@@ -43,10 +43,10 @@ export function showHelp() {
|
|
|
43
43
|
'',
|
|
44
44
|
' test [type] [target] [path] [-t pattern] 运行测试',
|
|
45
45
|
' type: e2e, unit (默认: e2e)',
|
|
46
|
-
' target:
|
|
47
|
-
' path: 测试文件或目录路径 (
|
|
46
|
+
' target: 由 commands.json 的 test.<type>.<target> 决定(e2e 默认会拒绝隐式 all)',
|
|
47
|
+
' path: 测试文件或目录路径 (guarded e2e target 必填,例如 backend/quantify)',
|
|
48
48
|
' -t pattern: 指定测试用例名称模式 (可选,需要和 path 一起使用)',
|
|
49
|
-
' 说明:
|
|
49
|
+
' 说明: guarded E2E target 禁止无路径或 all 全量执行,dx test e2e all 也不受支持',
|
|
50
50
|
'',
|
|
51
51
|
' worktree [action] [num...] Git Worktree管理',
|
|
52
52
|
' action: make, del, list, clean',
|
|
@@ -94,6 +94,8 @@ export function showHelp() {
|
|
|
94
94
|
' dx test e2e backend apps/backend/e2e/auth # 按目录运行后端 E2E',
|
|
95
95
|
' dx test e2e backend apps/backend/e2e/activity/activity.admin.e2e-spec.ts # 运行单个E2E测试文件',
|
|
96
96
|
' dx test e2e backend apps/backend/e2e/activity/activity.admin.e2e-spec.ts -t "should list all activity definitions" # 运行特定测试用例',
|
|
97
|
+
' dx test e2e quantify apps/quantify/e2e/health/health.e2e-spec.ts # 运行 Quantify E2E 文件',
|
|
98
|
+
' dx test e2e all # 不受支持,必须指定 target 和 path',
|
|
97
99
|
' dx deploy front --staging # 部署前端到 Vercel(staging)',
|
|
98
100
|
' dx deploy backend --prod # 构建 backend 制品并上传/部署到远端主机',
|
|
99
101
|
' dx deploy backend --build-only # 仅构建 backend 制品,不执行远端部署',
|
|
@@ -255,17 +257,20 @@ test 命令用法:
|
|
|
255
257
|
|
|
256
258
|
参数说明:
|
|
257
259
|
type: e2e, unit (默认: e2e)
|
|
258
|
-
target:
|
|
259
|
-
path:
|
|
260
|
+
target: 由 commands.json 的 test.<type>.<target> 决定
|
|
261
|
+
path: guarded e2e target 必须提供文件或目录路径
|
|
260
262
|
-t pattern: 指定测试用例名称模式,需要和 path 一起使用
|
|
261
263
|
|
|
262
264
|
限制说明:
|
|
263
|
-
|
|
265
|
+
guarded E2E target 禁止无路径全量执行。
|
|
266
|
+
guarded E2E target 也不支持把 path 写成 all。
|
|
267
|
+
dx test e2e all 不受支持,必须显式指定 target 和 path。
|
|
264
268
|
|
|
265
269
|
常见示例:
|
|
266
270
|
dx test e2e backend apps/backend/e2e/auth
|
|
267
271
|
dx test e2e backend apps/backend/e2e/auth/auth.login.e2e-spec.ts
|
|
268
272
|
dx test e2e backend apps/backend/e2e/auth/auth.login.e2e-spec.ts -t "should login"
|
|
273
|
+
dx test e2e quantify apps/quantify/e2e/health/health.e2e-spec.ts
|
|
269
274
|
dx test unit front
|
|
270
275
|
dx test unit admin
|
|
271
276
|
`)
|