@nocobase/cli 2.1.0-alpha.45 → 2.1.0-alpha.47
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/LICENSE +201 -0
- package/README.md +63 -380
- package/assets/env-proxy/nginx/app.conf.tpl +23 -0
- package/assets/env-proxy/nginx/nocobase.conf.tpl +5 -0
- package/assets/env-proxy/nginx/snippets/dist-location.conf +5 -0
- package/assets/env-proxy/nginx/snippets/gzip.conf +17 -0
- package/assets/env-proxy/nginx/snippets/log-format-http.conf +13 -0
- package/assets/env-proxy/nginx/snippets/maps-http.conf +14 -0
- package/assets/env-proxy/nginx/snippets/mime-types.conf +98 -0
- package/assets/env-proxy/nginx/snippets/proxy-location.conf +17 -0
- package/assets/env-proxy/nginx/snippets/spa-location.conf +6 -0
- package/assets/env-proxy/nginx/snippets/uploads-location.conf +21 -0
- package/bin/run.js +40 -32
- package/dist/commands/app/autostart/disable.js +55 -0
- package/dist/commands/app/autostart/enable.js +55 -0
- package/dist/commands/app/autostart/list.js +37 -0
- package/dist/commands/app/autostart/run.js +84 -0
- package/dist/commands/app/autostart/shared.js +49 -0
- package/dist/commands/app/destroy.js +21 -12
- package/dist/commands/app/down.js +2 -2
- package/dist/commands/app/logs.js +2 -1
- package/dist/commands/app/restart.js +92 -20
- package/dist/commands/app/shared.js +3 -2
- package/dist/commands/app/start.js +143 -38
- package/dist/commands/app/stop.js +31 -2
- package/dist/commands/app/upgrade.js +11 -7
- package/dist/commands/config/delete.js +10 -2
- package/dist/commands/config/get.js +7 -1
- package/dist/commands/config/set.js +12 -2
- package/dist/commands/db/ps.js +5 -18
- package/dist/commands/env/add.js +24 -44
- package/dist/commands/env/auth.js +1 -1
- package/dist/commands/env/info.js +3 -2
- package/dist/commands/env/list.js +4 -5
- package/dist/commands/env/proxy/caddy.js +28 -0
- package/dist/commands/env/proxy/index.js +353 -0
- package/dist/commands/env/proxy/nginx.js +28 -0
- package/dist/commands/env/remove.js +112 -22
- package/dist/commands/env/shared.js +17 -9
- package/dist/commands/env/status.js +10 -7
- package/dist/commands/env/update.js +385 -21
- package/dist/commands/init.js +368 -98
- package/dist/commands/install.js +271 -104
- package/dist/commands/license/activate.js +63 -244
- package/dist/commands/license/plugins/shared.js +64 -13
- package/dist/commands/plugin/import.js +108 -0
- package/dist/commands/revision/create.js +89 -0
- package/dist/commands/self/update.js +58 -1
- package/dist/commands/source/dev.js +5 -5
- package/dist/commands/source/test.js +13 -14
- package/dist/lib/app-health.js +39 -32
- package/dist/lib/app-managed-resources.js +25 -9
- package/dist/lib/app-public-path.js +80 -0
- package/dist/lib/app-runtime.js +12 -3
- package/dist/lib/auth-store.js +128 -4
- package/dist/lib/backup.js +3 -3
- package/dist/lib/bootstrap.js +14 -8
- package/dist/lib/cli-config.js +229 -3
- package/dist/lib/cli-entry-error.js +52 -0
- package/dist/lib/command-log.js +284 -0
- package/dist/lib/docker-env-file.js +10 -2
- package/dist/lib/docker-log-stream.js +45 -0
- package/dist/lib/env-auth.js +25 -14
- package/dist/lib/env-command-config.js +45 -0
- package/dist/lib/env-config.js +7 -2
- package/dist/lib/env-guard.js +9 -10
- package/dist/lib/env-paths.js +101 -0
- package/dist/lib/env-proxy.js +1295 -0
- package/dist/lib/inquirer.js +4 -5
- package/dist/lib/managed-env-file.js +98 -0
- package/dist/lib/plugin-import.js +279 -0
- package/dist/lib/prompt-catalog-core.js +3 -2
- package/dist/lib/prompt-validators.js +14 -0
- package/dist/lib/prompt-web-ui.js +8 -1
- package/dist/lib/run-npm.js +56 -12
- package/dist/lib/skills-manager.js +3 -1
- package/dist/lib/source-publish.js +22 -2
- package/dist/lib/startup-update.js +74 -50
- package/dist/lib/ui.js +2 -1
- package/dist/locale/en-US.json +122 -22
- package/dist/locale/zh-CN.json +119 -19
- package/package.json +5 -7
- package/scripts/build.mjs +34 -0
- package/scripts/clean.mjs +9 -0
- package/tsconfig.json +19 -0
- package/LICENSE.txt +0 -107
- package/README.zh-CN.md +0 -355
|
@@ -9,20 +9,168 @@
|
|
|
9
9
|
import path from 'node:path';
|
|
10
10
|
import { fileURLToPath } from 'node:url';
|
|
11
11
|
import { Args, Command, Flags } from '@oclif/core';
|
|
12
|
-
import { getCurrentEnvName } from '../../lib/auth-store.js';
|
|
12
|
+
import { getCurrentEnvName, getEnv, replaceEnvConfig } from '../../lib/auth-store.js';
|
|
13
13
|
import { updateEnvRuntime } from '../../lib/bootstrap.js';
|
|
14
14
|
import { resolveDefaultConfigScope } from '../../lib/cli-home.js';
|
|
15
|
-
import {
|
|
15
|
+
import { ENV_BOOLEAN_CONFIG_FLAG_MAP, ENV_STRING_CONFIG_FLAG_MAP } from '../../lib/env-command-config.js';
|
|
16
|
+
import { buildStoredEnvConfig } from '../../lib/env-config.js';
|
|
17
|
+
import { failTask, printInfo, printVerbose, printWarningBlock, setVerboseMode, startTask, stopTask, succeedTask } from '../../lib/ui.js';
|
|
16
18
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
const UPDATE_STRING_FLAGS = [
|
|
20
|
+
'source',
|
|
21
|
+
'download-version',
|
|
22
|
+
'docker-registry',
|
|
23
|
+
'docker-platform',
|
|
24
|
+
'git-url',
|
|
25
|
+
'npm-registry',
|
|
26
|
+
'app-path',
|
|
27
|
+
'app-root-path',
|
|
28
|
+
'storage-path',
|
|
29
|
+
'app-public-path',
|
|
30
|
+
'cdn-base-url',
|
|
31
|
+
'env-file',
|
|
32
|
+
'app-port',
|
|
33
|
+
'app-key',
|
|
34
|
+
'timezone',
|
|
35
|
+
'db-dialect',
|
|
36
|
+
'builtin-db-image',
|
|
37
|
+
'db-host',
|
|
38
|
+
'db-port',
|
|
39
|
+
'db-database',
|
|
40
|
+
'db-user',
|
|
41
|
+
'db-password',
|
|
42
|
+
'db-schema',
|
|
43
|
+
'db-table-prefix',
|
|
44
|
+
];
|
|
45
|
+
const UPDATE_BOOLEAN_FLAGS = ['builtin-db', 'dev-dependencies', 'build', 'build-dts', 'db-underscored'];
|
|
46
|
+
const UPDATE_SPECIAL_FIELDS = ['api-base-url', 'auth-type', 'access-token', 'username'];
|
|
47
|
+
const UNSETTABLE_FIELDS = new Set([...UPDATE_SPECIAL_FIELDS, ...UPDATE_STRING_FLAGS, ...UPDATE_BOOLEAN_FLAGS]);
|
|
48
|
+
const SOURCE_SETTING_FIELDS = new Set([
|
|
49
|
+
'source',
|
|
50
|
+
'download-version',
|
|
51
|
+
'docker-registry',
|
|
52
|
+
'docker-platform',
|
|
53
|
+
'git-url',
|
|
54
|
+
'npm-registry',
|
|
55
|
+
'dev-dependencies',
|
|
56
|
+
'build',
|
|
57
|
+
'build-dts',
|
|
58
|
+
]);
|
|
59
|
+
const APP_RESTART_FIELDS = new Set([
|
|
60
|
+
'app-path',
|
|
61
|
+
'app-root-path',
|
|
62
|
+
'storage-path',
|
|
63
|
+
'app-public-path',
|
|
64
|
+
'env-file',
|
|
65
|
+
'app-port',
|
|
66
|
+
'app-key',
|
|
67
|
+
'timezone',
|
|
68
|
+
'db-host',
|
|
69
|
+
'db-port',
|
|
70
|
+
'db-database',
|
|
71
|
+
'db-user',
|
|
72
|
+
'db-password',
|
|
73
|
+
'db-schema',
|
|
74
|
+
'db-table-prefix',
|
|
75
|
+
'db-underscored',
|
|
76
|
+
]);
|
|
77
|
+
const APP_RESTART_WITH_DB_FIELDS = new Set([
|
|
78
|
+
'builtin-db',
|
|
79
|
+
'db-dialect',
|
|
80
|
+
'builtin-db-image',
|
|
81
|
+
'db-port',
|
|
82
|
+
'db-database',
|
|
83
|
+
'db-user',
|
|
84
|
+
'db-password',
|
|
85
|
+
'storage-path',
|
|
86
|
+
]);
|
|
87
|
+
const __dirnameConfigFile = path.join(path.dirname(path.dirname(path.dirname(__dirname))), 'nocobase-ctl.config.json');
|
|
88
|
+
function hasTokenOverride(flags) {
|
|
89
|
+
return flags['access-token'] !== undefined || flags.token !== undefined;
|
|
90
|
+
}
|
|
91
|
+
function collectProvidedConfigFields(flags) {
|
|
92
|
+
const fields = new Set();
|
|
93
|
+
for (const field of UPDATE_SPECIAL_FIELDS) {
|
|
94
|
+
if (field === 'access-token') {
|
|
95
|
+
if (hasTokenOverride(flags)) {
|
|
96
|
+
fields.add(field);
|
|
97
|
+
}
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (flags[field] !== undefined) {
|
|
101
|
+
fields.add(field);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
for (const field of UPDATE_STRING_FLAGS) {
|
|
105
|
+
if (flags[field] !== undefined) {
|
|
106
|
+
fields.add(field);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
for (const field of UPDATE_BOOLEAN_FLAGS) {
|
|
110
|
+
if (flags[field] !== undefined) {
|
|
111
|
+
fields.add(field);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return fields;
|
|
115
|
+
}
|
|
116
|
+
function normalizeUnsetFields(unset) {
|
|
117
|
+
const normalized = (unset ?? [])
|
|
118
|
+
.flatMap((value) => value.split(','))
|
|
119
|
+
.map((value) => value.trim())
|
|
120
|
+
.filter(Boolean);
|
|
121
|
+
for (const field of normalized) {
|
|
122
|
+
if (!UNSETTABLE_FIELDS.has(field)) {
|
|
123
|
+
throw new Error(`Unsupported --unset field "${field}". Supported fields: ${Array.from(UNSETTABLE_FIELDS).sort().join(', ')}.`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return Array.from(new Set(normalized));
|
|
127
|
+
}
|
|
128
|
+
function buildCurrentConfigInput(env) {
|
|
129
|
+
return {
|
|
130
|
+
...env.config,
|
|
131
|
+
apiBaseUrl: env.apiBaseUrl,
|
|
132
|
+
authType: env.authType,
|
|
133
|
+
authUsername: env.config.authUsername,
|
|
134
|
+
accessToken: env.auth?.type === 'token' ? env.auth.accessToken : undefined,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function applyUnsetField(nextInput, field) {
|
|
138
|
+
switch (field) {
|
|
139
|
+
case 'api-base-url':
|
|
140
|
+
delete nextInput.apiBaseUrl;
|
|
141
|
+
return;
|
|
142
|
+
case 'auth-type':
|
|
143
|
+
delete nextInput.authType;
|
|
144
|
+
return;
|
|
145
|
+
case 'access-token':
|
|
146
|
+
delete nextInput.accessToken;
|
|
147
|
+
return;
|
|
148
|
+
case 'username':
|
|
149
|
+
delete nextInput.authUsername;
|
|
150
|
+
return;
|
|
151
|
+
default:
|
|
152
|
+
if (field in ENV_STRING_CONFIG_FLAG_MAP) {
|
|
153
|
+
delete nextInput[ENV_STRING_CONFIG_FLAG_MAP[field]];
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (field in ENV_BOOLEAN_CONFIG_FLAG_MAP) {
|
|
157
|
+
delete nextInput[ENV_BOOLEAN_CONFIG_FLAG_MAP[field]];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
17
161
|
export default class EnvUpdate extends Command {
|
|
18
|
-
static summary = 'Refresh an environment runtime from swagger:get
|
|
162
|
+
static summary = 'Refresh an environment runtime from swagger:get, or update the saved env config for one environment';
|
|
19
163
|
static examples = [
|
|
20
164
|
'<%= config.bin %> <%= command.id %>',
|
|
21
165
|
'<%= config.bin %> <%= command.id %> prod',
|
|
166
|
+
'<%= config.bin %> <%= command.id %> prod --api-base-url http://localhost:13000/api --access-token <token>',
|
|
167
|
+
'<%= config.bin %> <%= command.id %> local --app-port 13080 --timezone Asia/Shanghai',
|
|
168
|
+
'<%= config.bin %> <%= command.id %> local --cdn-base-url https://cdn.example.com/nocobase/',
|
|
169
|
+
'<%= config.bin %> <%= command.id %> local --unset git-url --unset npm-registry',
|
|
22
170
|
];
|
|
23
171
|
static args = {
|
|
24
172
|
name: Args.string({
|
|
25
|
-
description: 'Configured environment name to
|
|
173
|
+
description: 'Configured environment name to update. Defaults to the current env when omitted',
|
|
26
174
|
required: false,
|
|
27
175
|
}),
|
|
28
176
|
};
|
|
@@ -32,33 +180,138 @@ export default class EnvUpdate extends Command {
|
|
|
32
180
|
default: false,
|
|
33
181
|
}),
|
|
34
182
|
'api-base-url': Flags.string({
|
|
35
|
-
|
|
183
|
+
char: 'u',
|
|
184
|
+
description: 'Root URL for HTTP API calls, including the /api prefix (e.g. http://localhost:13000/api)',
|
|
36
185
|
}),
|
|
37
|
-
|
|
38
|
-
description: '
|
|
186
|
+
'auth-type': Flags.string({
|
|
187
|
+
description: 'Authentication: basic, token, or oauth',
|
|
188
|
+
options: ['basic', 'token', 'oauth'],
|
|
39
189
|
}),
|
|
40
|
-
token: Flags.string({
|
|
190
|
+
'access-token': Flags.string({
|
|
41
191
|
char: 't',
|
|
42
|
-
|
|
192
|
+
aliases: ['token'],
|
|
193
|
+
description: 'API key or access token for token-based authentication',
|
|
194
|
+
}),
|
|
195
|
+
username: Flags.string({
|
|
196
|
+
description: 'Username to save for basic authentication',
|
|
197
|
+
}),
|
|
198
|
+
source: Flags.string({
|
|
199
|
+
description: 'Saved application source type for this env',
|
|
200
|
+
options: ['docker', 'git', 'local', 'npm'],
|
|
201
|
+
}),
|
|
202
|
+
'download-version': Flags.string({
|
|
203
|
+
aliases: ['version'],
|
|
204
|
+
description: 'Saved downloaded app version for this env',
|
|
205
|
+
}),
|
|
206
|
+
'docker-registry': Flags.string({
|
|
207
|
+
description: 'Saved Docker registry for this env',
|
|
208
|
+
}),
|
|
209
|
+
'docker-platform': Flags.string({
|
|
210
|
+
description: 'Saved Docker image platform for this env',
|
|
211
|
+
options: ['auto', 'linux/amd64', 'linux/arm64'],
|
|
212
|
+
}),
|
|
213
|
+
'git-url': Flags.string({
|
|
214
|
+
description: 'Saved Git repository URL for this env',
|
|
215
|
+
}),
|
|
216
|
+
'npm-registry': Flags.string({
|
|
217
|
+
description: 'Saved npm registry for this env',
|
|
218
|
+
}),
|
|
219
|
+
'dev-dependencies': Flags.boolean({
|
|
220
|
+
allowNo: true,
|
|
221
|
+
description: 'Whether development dependencies are installed for this env',
|
|
222
|
+
}),
|
|
223
|
+
build: Flags.boolean({
|
|
224
|
+
allowNo: true,
|
|
225
|
+
description: 'Whether the app should be built after source download',
|
|
226
|
+
}),
|
|
227
|
+
'build-dts': Flags.boolean({
|
|
228
|
+
allowNo: true,
|
|
229
|
+
description: 'Whether declaration files should be emitted during build',
|
|
230
|
+
}),
|
|
231
|
+
'app-path': Flags.string({
|
|
232
|
+
description: 'Saved app path for this env',
|
|
233
|
+
}),
|
|
234
|
+
'app-root-path': Flags.string({
|
|
235
|
+
hidden: true,
|
|
236
|
+
description: 'Saved application root path for this env',
|
|
237
|
+
}),
|
|
238
|
+
'storage-path': Flags.string({
|
|
239
|
+
hidden: true,
|
|
240
|
+
description: 'Saved storage path for this env',
|
|
241
|
+
}),
|
|
242
|
+
'app-public-path': Flags.string({
|
|
243
|
+
description: 'Saved application public path for this env',
|
|
244
|
+
}),
|
|
245
|
+
'cdn-base-url': Flags.string({
|
|
246
|
+
description: 'Saved client asset CDN base URL (CDN_BASE_URL) for this env',
|
|
247
|
+
}),
|
|
248
|
+
'env-file': Flags.string({
|
|
249
|
+
hidden: true,
|
|
250
|
+
description: 'Saved Docker --env-file path for this env',
|
|
251
|
+
}),
|
|
252
|
+
'app-port': Flags.string({
|
|
253
|
+
description: 'Saved application HTTP port for this env',
|
|
254
|
+
}),
|
|
255
|
+
'app-key': Flags.string({
|
|
256
|
+
description: 'Saved application secret key for this env',
|
|
257
|
+
}),
|
|
258
|
+
timezone: Flags.string({
|
|
259
|
+
description: 'Saved application timezone for this env',
|
|
260
|
+
}),
|
|
261
|
+
'builtin-db': Flags.boolean({
|
|
262
|
+
allowNo: true,
|
|
263
|
+
description: 'Whether this env uses a CLI-managed built-in database',
|
|
264
|
+
}),
|
|
265
|
+
'db-dialect': Flags.string({
|
|
266
|
+
description: 'Saved database dialect for this env',
|
|
267
|
+
options: ['kingbase', 'mariadb', 'mysql', 'postgres'],
|
|
268
|
+
}),
|
|
269
|
+
'builtin-db-image': Flags.string({
|
|
270
|
+
description: 'Saved built-in database image for this env',
|
|
271
|
+
}),
|
|
272
|
+
'db-host': Flags.string({
|
|
273
|
+
description: 'Saved database host for this env',
|
|
274
|
+
}),
|
|
275
|
+
'db-port': Flags.string({
|
|
276
|
+
description: 'Saved database port for this env',
|
|
277
|
+
}),
|
|
278
|
+
'db-database': Flags.string({
|
|
279
|
+
description: 'Saved database name for this env',
|
|
280
|
+
}),
|
|
281
|
+
'db-user': Flags.string({
|
|
282
|
+
description: 'Saved database user for this env',
|
|
283
|
+
}),
|
|
284
|
+
'db-password': Flags.string({
|
|
285
|
+
description: 'Saved database password for this env',
|
|
286
|
+
}),
|
|
287
|
+
'db-schema': Flags.string({
|
|
288
|
+
description: 'Saved database schema for this env',
|
|
289
|
+
}),
|
|
290
|
+
'db-table-prefix': Flags.string({
|
|
291
|
+
description: 'Saved database table prefix for this env',
|
|
292
|
+
}),
|
|
293
|
+
'db-underscored': Flags.boolean({
|
|
294
|
+
allowNo: true,
|
|
295
|
+
description: 'Whether this env uses underscored database naming',
|
|
296
|
+
}),
|
|
297
|
+
unset: Flags.string({
|
|
298
|
+
multiple: true,
|
|
299
|
+
description: 'Unset one or more saved env config fields by canonical flag name',
|
|
43
300
|
}),
|
|
44
301
|
};
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
startTask(`Updating env runtime: ${envLabel}`);
|
|
302
|
+
buildRuntimeUpdateTaskMessage(envLabel) {
|
|
303
|
+
return `Updating env runtime: ${envLabel}`;
|
|
304
|
+
}
|
|
305
|
+
async refreshRuntime(envName, envLabel, verbose) {
|
|
306
|
+
startTask(this.buildRuntimeUpdateTaskMessage(envLabel));
|
|
51
307
|
try {
|
|
52
308
|
const runtime = await updateEnvRuntime({
|
|
53
309
|
envName,
|
|
54
310
|
scope: resolveDefaultConfigScope(),
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
token: flags.token,
|
|
58
|
-
configFile: path.join(path.dirname(path.dirname(path.dirname(__dirname))), 'nocobase-ctl.config.json'),
|
|
59
|
-
verbose: flags.verbose,
|
|
311
|
+
configFile: __dirnameConfigFile,
|
|
312
|
+
verbose,
|
|
60
313
|
});
|
|
61
|
-
if (
|
|
314
|
+
if (verbose) {
|
|
62
315
|
succeedTask(`Updated env "${envLabel}" to runtime "${runtime.version}".`);
|
|
63
316
|
}
|
|
64
317
|
else {
|
|
@@ -71,4 +324,115 @@ export default class EnvUpdate extends Command {
|
|
|
71
324
|
throw error;
|
|
72
325
|
}
|
|
73
326
|
}
|
|
327
|
+
printConfigUpdateHints(envName, changedFields, nextConfig) {
|
|
328
|
+
if (changedFields.size === 0) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
printInfo('Saved env config was updated. Runtime commands were not refreshed automatically.');
|
|
332
|
+
const shouldRestartWithDb = Array.from(changedFields).some((field) => APP_RESTART_WITH_DB_FIELDS.has(field)) &&
|
|
333
|
+
(nextConfig.builtinDb === true || changedFields.has('builtin-db'));
|
|
334
|
+
if (shouldRestartWithDb) {
|
|
335
|
+
printInfo(`Run \`nb app restart --env ${envName} --with-db\` when you're ready to apply these changes.`);
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
if (Array.from(changedFields).some((field) => APP_RESTART_FIELDS.has(field))) {
|
|
339
|
+
printInfo(`Run \`nb app restart --env ${envName}\` when you're ready to apply these changes.`);
|
|
340
|
+
}
|
|
341
|
+
if (Array.from(changedFields).some((field) => SOURCE_SETTING_FIELDS.has(field))) {
|
|
342
|
+
printInfo('Saved source settings were updated. Existing local source files are not replaced automatically.');
|
|
343
|
+
}
|
|
344
|
+
if (Array.from(changedFields).some((field) => field === 'auth-type' || field === 'access-token' || field === 'username') &&
|
|
345
|
+
(nextConfig.authType === 'basic' || nextConfig.authType === 'oauth' || !nextConfig.accessToken)) {
|
|
346
|
+
printInfo(`Run \`nb env auth ${envName}\` if you need to authenticate this env again before using runtime commands.`);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
async run() {
|
|
350
|
+
const { args, flags } = await this.parse(EnvUpdate);
|
|
351
|
+
const parsedFlags = flags;
|
|
352
|
+
setVerboseMode(Boolean(parsedFlags.verbose));
|
|
353
|
+
const unsetFields = normalizeUnsetFields(parsedFlags.unset);
|
|
354
|
+
const providedFields = collectProvidedConfigFields(parsedFlags);
|
|
355
|
+
const hasConfigChanges = providedFields.size > 0 || unsetFields.length > 0;
|
|
356
|
+
const tokenOverride = hasTokenOverride(parsedFlags);
|
|
357
|
+
for (const field of unsetFields) {
|
|
358
|
+
if (providedFields.has(field)) {
|
|
359
|
+
this.error(`Cannot combine --unset ${field} with an explicit update for the same field.`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
if (tokenOverride && parsedFlags['auth-type'] && parsedFlags['auth-type'] !== 'token') {
|
|
363
|
+
this.error('--access-token or --token can only be used with --auth-type token.');
|
|
364
|
+
}
|
|
365
|
+
if (!hasConfigChanges) {
|
|
366
|
+
const envName = args.name;
|
|
367
|
+
const envLabel = envName ?? (await getCurrentEnvName({ scope: resolveDefaultConfigScope() }));
|
|
368
|
+
await this.refreshRuntime(envName, envLabel, Boolean(parsedFlags.verbose));
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
const currentEnv = await getEnv(args.name, { scope: resolveDefaultConfigScope() });
|
|
372
|
+
if (!currentEnv) {
|
|
373
|
+
this.error(args.name?.trim()
|
|
374
|
+
? `Env "${args.name.trim()}" is not configured`
|
|
375
|
+
: 'No env is configured. Run `nb init --ui` or `nb env add <name> --api-base-url <url>` first.');
|
|
376
|
+
}
|
|
377
|
+
const envName = String(currentEnv.name ?? '').trim();
|
|
378
|
+
const effectiveAuthType = parsedFlags['auth-type'] ?? (tokenOverride ? 'token' : currentEnv.authType);
|
|
379
|
+
if (parsedFlags.username !== undefined && effectiveAuthType !== 'basic') {
|
|
380
|
+
this.error('--username can only be used when the env uses basic authentication.');
|
|
381
|
+
}
|
|
382
|
+
const nextInput = buildCurrentConfigInput(currentEnv);
|
|
383
|
+
nextInput.apiBaseUrl = currentEnv.apiBaseUrl;
|
|
384
|
+
nextInput.authType = currentEnv.authType;
|
|
385
|
+
nextInput.authUsername = currentEnv.config.authUsername;
|
|
386
|
+
if (parsedFlags['api-base-url'] !== undefined) {
|
|
387
|
+
nextInput.apiBaseUrl = parsedFlags['api-base-url'];
|
|
388
|
+
}
|
|
389
|
+
if (parsedFlags['auth-type'] !== undefined) {
|
|
390
|
+
nextInput.authType = parsedFlags['auth-type'];
|
|
391
|
+
}
|
|
392
|
+
if (parsedFlags.username !== undefined) {
|
|
393
|
+
nextInput.authUsername = String(parsedFlags.username ?? '').trim();
|
|
394
|
+
}
|
|
395
|
+
if (tokenOverride) {
|
|
396
|
+
nextInput.authType = 'token';
|
|
397
|
+
nextInput.accessToken = parsedFlags['access-token'] ?? parsedFlags.token;
|
|
398
|
+
}
|
|
399
|
+
for (const field of UPDATE_STRING_FLAGS) {
|
|
400
|
+
if (parsedFlags[field] !== undefined) {
|
|
401
|
+
nextInput[ENV_STRING_CONFIG_FLAG_MAP[field]] = parsedFlags[field];
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
for (const field of UPDATE_BOOLEAN_FLAGS) {
|
|
405
|
+
if (parsedFlags[field] !== undefined) {
|
|
406
|
+
nextInput[ENV_BOOLEAN_CONFIG_FLAG_MAP[field]] = parsedFlags[field];
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
for (const field of unsetFields) {
|
|
410
|
+
applyUnsetField(nextInput, field);
|
|
411
|
+
}
|
|
412
|
+
const nextConfig = buildStoredEnvConfig(nextInput);
|
|
413
|
+
startTask(`Saving env config: ${envName}`);
|
|
414
|
+
try {
|
|
415
|
+
await replaceEnvConfig(envName, nextConfig, { scope: resolveDefaultConfigScope() });
|
|
416
|
+
succeedTask(`Saved env config for "${envName}".`);
|
|
417
|
+
}
|
|
418
|
+
catch (error) {
|
|
419
|
+
failTask(`Failed to save env config for "${envName}".`);
|
|
420
|
+
throw error;
|
|
421
|
+
}
|
|
422
|
+
const shouldRefreshRuntime = providedFields.has('api-base-url') || providedFields.has('access-token');
|
|
423
|
+
if (!shouldRefreshRuntime) {
|
|
424
|
+
this.printConfigUpdateHints(envName, new Set([...providedFields, ...unsetFields]), nextConfig);
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
try {
|
|
428
|
+
await this.refreshRuntime(envName, envName, Boolean(parsedFlags.verbose));
|
|
429
|
+
}
|
|
430
|
+
catch (error) {
|
|
431
|
+
this.printConfigUpdateHints(envName, new Set([...providedFields, ...unsetFields]), nextConfig);
|
|
432
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
433
|
+
printWarningBlock(`Saved env config for "${envName}", but failed to refresh the runtime.\n${message}`);
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
printVerbose(`Updated env "${envName}" config and refreshed the runtime.`);
|
|
437
|
+
}
|
|
74
438
|
}
|