openxiangda 1.0.230 → 1.0.232

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.
@@ -0,0 +1,216 @@
1
+ const crypto = require('crypto');
2
+ const { createDeliveryV2Executor } = require('./delivery-v2-executor');
3
+ const { parseArgs, print, warn, writeJson } = require('./utils');
4
+
5
+ function createDeliveryV2Cli(dependencies) {
6
+ const deps = assertDependencies(dependencies);
7
+ const executor = createDeliveryV2Executor(deps);
8
+
9
+ async function run(command, argv = []) {
10
+ const { flags, positional } = parseArgs(argv);
11
+ if (flags.help || flags.h) {
12
+ printHelp(command);
13
+ return;
14
+ }
15
+ const config = deps.loadConfig();
16
+ if (command === 'check') {
17
+ const target = resolveTarget(config, flags, positional, false);
18
+ const inspected = await executor.inspect({
19
+ config,
20
+ target,
21
+ workspaceRoot: process.cwd(),
22
+ skipBuild: flags.build !== true,
23
+ buildCommand: stringFlag(flags, 'build-command'),
24
+ distDir: stringFlag(flags, 'dist'),
25
+ onBuildOutput: buildOutput(flags),
26
+ });
27
+ return output(
28
+ flags,
29
+ {
30
+ ok: true,
31
+ appType: target.appType,
32
+ environment: target.targetName || target.environmentKind || null,
33
+ packageDigest: inspected.compiled.packageDigest,
34
+ summary: inspected.compiled.summary,
35
+ targets: inspected.targets,
36
+ previousPackageDigest: inspected.previous?.packageDigest || null,
37
+ },
38
+ `Delivery V2 检查通过: ${inspected.compiled.packageDigest}`
39
+ );
40
+ }
41
+ if (command === 'deploy') {
42
+ const target = resolveTarget(config, flags, positional, true);
43
+ const packageDigest = stringFlag(flags, 'package');
44
+ const result = await executor.deploy({
45
+ config,
46
+ target,
47
+ workspaceRoot: process.cwd(),
48
+ packageDigest,
49
+ buildCommand: stringFlag(flags, 'build-command'),
50
+ distDir: stringFlag(flags, 'dist'),
51
+ clientSessionId: createClientSessionId(),
52
+ onBuildOutput: buildOutput(flags),
53
+ });
54
+ return output(
55
+ flags,
56
+ result,
57
+ `Delivery V2 发布成功: run=${result.run.id} package=${result.packageDigest}`
58
+ );
59
+ }
60
+ if (command === 'status') {
61
+ const runId = positional[0] || stringFlag(flags, 'run');
62
+ if (!runId) {
63
+ throw usageError('用法: openxiangda status <runId> [--json]');
64
+ }
65
+ const target = resolveTarget(config, flags, [], false);
66
+ const result = await executor.status({ config, target, runId });
67
+ return output(
68
+ flags,
69
+ result,
70
+ `Delivery V2: run=${result.id} status=${result.status} stage=${result.stage}`
71
+ );
72
+ }
73
+ if (command === 'retry') {
74
+ const runId = positional[0] || stringFlag(flags, 'run');
75
+ if (!runId) {
76
+ throw usageError('用法: openxiangda retry <runId> [--json]');
77
+ }
78
+ const target = resolveTarget(config, flags, [], false);
79
+ const result = await executor.retry({
80
+ config,
81
+ target,
82
+ runId,
83
+ workspaceRoot: process.cwd(),
84
+ });
85
+ return output(
86
+ flags,
87
+ result,
88
+ `Delivery V2 重试成功: run=${result.run.id} status=${result.run.status}`
89
+ );
90
+ }
91
+ if (command === 'rollback') {
92
+ const target = resolveTarget(config, flags, positional, true);
93
+ const releaseId = stringFlag(flags, 'to');
94
+ if (!releaseId) {
95
+ throw usageError(
96
+ '用法: openxiangda rollback <environment> --to <appReleaseId>'
97
+ );
98
+ }
99
+ const result = await executor.rollback({
100
+ config,
101
+ target,
102
+ releaseId,
103
+ workspaceRoot: process.cwd(),
104
+ clientSessionId: createClientSessionId(),
105
+ });
106
+ return output(
107
+ flags,
108
+ result,
109
+ `Delivery V2 回滚成功: run=${result.run.id} package=${result.packageDigest}`
110
+ );
111
+ }
112
+ throw usageError(`未知 Delivery V2 命令: ${command}`);
113
+ }
114
+
115
+ function resolveTarget(config, flags, positional, environmentRequired) {
116
+ const environment =
117
+ positional[0] ||
118
+ stringFlag(flags, 'environment') ||
119
+ stringFlag(flags, 'target');
120
+ if (environmentRequired && !environment) {
121
+ throw usageError(
122
+ '必须指定环境,例如 openxiangda deploy preproduction'
123
+ );
124
+ }
125
+ return deps.getWorkspaceTarget(
126
+ config,
127
+ stringFlag(flags, 'profile') || config.currentProfile,
128
+ {
129
+ ...flags,
130
+ ...(environment ? { environment } : {}),
131
+ }
132
+ );
133
+ }
134
+
135
+ return { run };
136
+ }
137
+
138
+ function output(flags, value, message) {
139
+ if (flags.json) return writeJson(value);
140
+ print(message);
141
+ if (value?.run?.failure?.code) {
142
+ warn(
143
+ `${value.run.failure.code}: ${value.run.failure.message || '发布失败'}`
144
+ );
145
+ }
146
+ return value;
147
+ }
148
+
149
+ function buildOutput(flags) {
150
+ if (flags.json || flags.quiet) return undefined;
151
+ return (stream, text) => {
152
+ if (stream === 'stderr') warn(text.trimEnd());
153
+ else print(text.trimEnd());
154
+ };
155
+ }
156
+
157
+ function stringFlag(flags, name) {
158
+ const value = flags?.[name];
159
+ if (value === undefined || value === null || value === false) return '';
160
+ return String(value).trim();
161
+ }
162
+
163
+ function createClientSessionId() {
164
+ return `delivery-v2-${process.pid}-${crypto
165
+ .randomBytes(10)
166
+ .toString('hex')}`;
167
+ }
168
+
169
+ function usageError(message) {
170
+ const error = new Error(message);
171
+ error.code = 'DELIVERY_USAGE_ERROR';
172
+ error.retryable = false;
173
+ return error;
174
+ }
175
+
176
+ function printHelp(command) {
177
+ const lines = {
178
+ check: [
179
+ '用法: openxiangda check [--environment <name>] [--build] [--json]',
180
+ '编译并校验 App Package V2;默认复用现有 dist,不执行 Runtime 构建。',
181
+ ],
182
+ deploy: [
183
+ '用法: openxiangda deploy <environment> [--package <sha256>] [--json]',
184
+ '不带 --package 时从当前工作区构建;带 --package 时直接部署已封存制品。',
185
+ ],
186
+ status: ['用法: openxiangda status <runId> [--json]'],
187
+ retry: ['用法: openxiangda retry <runId> [--json]'],
188
+ rollback: [
189
+ '用法: openxiangda rollback <environment> --to <appReleaseId> [--json]',
190
+ ],
191
+ };
192
+ print((lines[command] || ['Delivery V2']).join('\n'));
193
+ }
194
+
195
+ function assertDependencies(value) {
196
+ const required = [
197
+ 'clearDeliveryContext',
198
+ 'downloadWithAuth',
199
+ 'getWorkspaceTarget',
200
+ 'installDeliveryContext',
201
+ 'loadConfig',
202
+ 'requestFormWithAuth',
203
+ 'requestWithAuth',
204
+ 'runOpenXiangdaInProcess',
205
+ ];
206
+ for (const key of required) {
207
+ if (typeof value?.[key] !== 'function') {
208
+ throw new Error(`Delivery V2 CLI dependency 缺失: ${key}`);
209
+ }
210
+ }
211
+ return value;
212
+ }
213
+
214
+ module.exports = {
215
+ createDeliveryV2Cli,
216
+ };