@nocobase/cli 2.1.0-alpha.40 → 2.1.0-alpha.46
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 +20 -8
- package/README.zh-CN.md +20 -8
- package/bin/run.js +9 -37
- package/dist/commands/app/destroy.js +225 -0
- package/dist/commands/app/down.js +24 -254
- package/dist/commands/app/restart.js +12 -5
- package/dist/commands/app/shared.js +122 -0
- package/dist/commands/app/start.js +41 -59
- package/dist/commands/app/stop.js +72 -26
- package/dist/commands/app/upgrade.js +312 -429
- package/dist/commands/config/delete.js +8 -1
- package/dist/commands/config/get.js +5 -0
- package/dist/commands/config/set.js +10 -1
- package/dist/commands/db/ps.js +5 -18
- package/dist/commands/db/start.js +23 -8
- package/dist/commands/env/add.js +66 -6
- package/dist/commands/env/auth.js +86 -27
- package/dist/commands/env/info.js +52 -8
- package/dist/commands/env/list.js +6 -7
- package/dist/commands/env/shared.js +41 -3
- package/dist/commands/env/status.js +10 -7
- package/dist/commands/init.js +214 -136
- package/dist/commands/install.js +364 -294
- package/dist/commands/license/plugins/shared.js +9 -3
- package/dist/commands/license/plugins/sync.js +54 -25
- package/dist/commands/self/update.js +58 -1
- package/dist/commands/source/dev.js +5 -5
- package/dist/commands/source/download.js +29 -25
- package/dist/generated/command-registry.js +3 -2
- package/dist/lib/api-client.js +6 -0
- package/dist/lib/api-command-compat.js +641 -0
- package/dist/lib/app-health.js +31 -18
- package/dist/lib/app-managed-resources.js +1 -1
- package/dist/lib/app-runtime.js +2 -2
- package/dist/lib/auth-store.js +56 -19
- package/dist/lib/backup.js +3 -3
- package/dist/lib/bootstrap.js +14 -8
- package/dist/lib/cli-config.js +137 -4
- package/dist/lib/cli-entry-error.js +44 -0
- package/dist/lib/cli-locale.js +19 -7
- package/dist/lib/db-connection-check.js +61 -0
- package/dist/lib/docker-log-stream.js +45 -0
- package/dist/lib/env-auth.js +98 -11
- package/dist/lib/env-config.js +3 -2
- package/dist/lib/env-guard.js +1 -1
- package/dist/lib/generated-command.js +17 -0
- package/dist/lib/prompt-validators.js +23 -5
- package/dist/lib/prompt-web-ui.js +143 -19
- package/dist/lib/run-npm.js +133 -23
- package/dist/lib/skills-manager.js +80 -4
- package/dist/lib/source-publish.js +4 -1
- package/dist/lib/startup-update.js +74 -50
- package/dist/lib/ui.js +4 -1
- package/dist/locale/en-US.json +92 -5
- package/dist/locale/zh-CN.json +92 -5
- package/package.json +34 -2
package/dist/commands/install.js
CHANGED
|
@@ -7,27 +7,27 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
import { Command, Flags } from '@oclif/core';
|
|
10
|
-
import { spawn } from 'node:child_process';
|
|
11
10
|
import crypto from 'node:crypto';
|
|
12
|
-
import { mkdir } from 'node:fs/promises';
|
|
11
|
+
import { access, mkdir } from 'node:fs/promises';
|
|
13
12
|
import path from 'node:path';
|
|
14
13
|
import { exit } from 'node:process';
|
|
15
14
|
import { runPromptCatalog, } from "../lib/prompt-catalog.js";
|
|
16
|
-
import { applyCliLocale, localeText, resolveCliLocale, translateCli
|
|
15
|
+
import { applyCliLocale, localeText, resolveCliLocale, translateCli } from "../lib/cli-locale.js";
|
|
17
16
|
import { resolveConfiguredEnvPath, resolveDefaultConfigScope, resolveEnvRoot, resolveEnvRelativePath, } from '../lib/cli-home.js';
|
|
18
|
-
import { defaultDockerContainerPrefix, defaultDockerNetworkName
|
|
19
|
-
import { resolveDockerContainerPrefix, resolveDockerNetworkName
|
|
20
|
-
import { DEFAULT_DOCKER_VERSION, resolveDockerImageRef
|
|
17
|
+
import { defaultDockerContainerPrefix, defaultDockerNetworkName } from '../lib/app-runtime.js';
|
|
18
|
+
import { resolveDockerContainerPrefix, resolveDockerNetworkName } from '../lib/cli-config.js';
|
|
19
|
+
import { DEFAULT_DOCKER_VERSION, resolveDockerImageRef } from "../lib/docker-image.js";
|
|
21
20
|
import { findAvailableTcpPort, validateAvailableTcpPort, validateTcpPort, validateEnvKey, } from "../lib/prompt-validators.js";
|
|
22
|
-
import { validateExternalDbConfig } from "../lib/db-connection-check.js";
|
|
21
|
+
import { validateExternalDbConfig, validateMysqlLowerCaseTableNamesCompatibility } from "../lib/db-connection-check.js";
|
|
23
22
|
import { formatMissingManagedAppEnvMessage } from '../lib/app-runtime.js';
|
|
24
|
-
import { run, runNocoBaseCommand } from '../lib/run-npm.js';
|
|
25
|
-
import { printInfo, printStage, printVerbose, printWarning, setVerboseMode
|
|
23
|
+
import { commandOutput, commandSucceeds, run, runNocoBaseCommand } from '../lib/run-npm.js';
|
|
24
|
+
import { printInfo, printStage, printVerbose, printWarning, setVerboseMode } from '../lib/ui.js';
|
|
26
25
|
import { omitKeys, upperFirst } from "../lib/object-utils.js";
|
|
27
26
|
import { getEnv, setCurrentEnv, upsertEnv } from '../lib/auth-store.js';
|
|
28
27
|
import { buildStoredEnvConfig } from '../lib/env-config.js';
|
|
29
|
-
import { resolveDockerEnvFileArg
|
|
30
|
-
import
|
|
28
|
+
import { resolveDockerEnvFileArg } from "../lib/docker-env-file.js";
|
|
29
|
+
import { startDockerLogFollower } from '../lib/docker-log-stream.js';
|
|
30
|
+
import Download, { defaultDockerRegistryForLang } from './download.js';
|
|
31
31
|
import EnvAdd from "./env/add.js";
|
|
32
32
|
const DEFAULT_INSTALL_ENV_NAME = 'local';
|
|
33
33
|
const DEFAULT_INSTALL_LANG = 'en-US';
|
|
@@ -139,6 +139,9 @@ const installText = (key, values) => localeText(`commands.install.${key}`, value
|
|
|
139
139
|
function formatDeferredAuthMessage(envName, authType) {
|
|
140
140
|
const normalizedAuthType = String(authType ?? '').trim();
|
|
141
141
|
const nextStep = `Authentication was skipped for env "${envName}". Run \`nb env auth ${envName}\` to finish setup.`;
|
|
142
|
+
if (normalizedAuthType === 'basic') {
|
|
143
|
+
return `${nextStep} You will be prompted for a username and password.`;
|
|
144
|
+
}
|
|
142
145
|
if (normalizedAuthType === 'token') {
|
|
143
146
|
return `${nextStep} You will be prompted for an access token.`;
|
|
144
147
|
}
|
|
@@ -154,9 +157,7 @@ function isInstallDbDialect(value) {
|
|
|
154
157
|
return INSTALL_DB_DIALECTS.includes(value);
|
|
155
158
|
}
|
|
156
159
|
function downloadVersionPromptValue(version) {
|
|
157
|
-
return version === 'latest' || version === 'beta' || version === 'alpha'
|
|
158
|
-
? version
|
|
159
|
-
: 'other';
|
|
160
|
+
return version === 'latest' || version === 'beta' || version === 'alpha' ? version : 'other';
|
|
160
161
|
}
|
|
161
162
|
function supportsBuiltinDbDialect(value) {
|
|
162
163
|
const dialect = String(value ?? '').trim();
|
|
@@ -171,22 +172,16 @@ function defaultBuiltinDbImageForDialect(value) {
|
|
|
171
172
|
const defaults = resolveCliLocale(process.env.NB_LOCALE) === 'zh-CN'
|
|
172
173
|
? DEFAULT_INSTALL_BUILTIN_DB_IMAGES_ZH_CN
|
|
173
174
|
: DEFAULT_INSTALL_BUILTIN_DB_IMAGES;
|
|
174
|
-
return supportsBuiltinDbDialect(dialect)
|
|
175
|
-
? defaults[dialect]
|
|
176
|
-
: defaults.postgres;
|
|
175
|
+
return supportsBuiltinDbDialect(dialect) ? defaults[dialect] : defaults.postgres;
|
|
177
176
|
}
|
|
178
177
|
function defaultDbDatabaseForDialect(value) {
|
|
179
|
-
return String(value ?? '').trim() === 'kingbase'
|
|
180
|
-
? 'kingbase'
|
|
181
|
-
: DEFAULT_INSTALL_DB_DATABASE;
|
|
178
|
+
return String(value ?? '').trim() === 'kingbase' ? 'kingbase' : DEFAULT_INSTALL_DB_DATABASE;
|
|
182
179
|
}
|
|
183
180
|
function defaultDbHostForBuiltinDb(values) {
|
|
184
|
-
return
|
|
185
|
-
? DEFAULT_INSTALL_BUILTIN_DB_HOST
|
|
186
|
-
: DEFAULT_INSTALL_DB_HOST;
|
|
181
|
+
return values.builtinDb ? DEFAULT_INSTALL_BUILTIN_DB_HOST : DEFAULT_INSTALL_DB_HOST;
|
|
187
182
|
}
|
|
188
183
|
function validateBuiltinDbEnabled(value, values) {
|
|
189
|
-
if (!
|
|
184
|
+
if (!value) {
|
|
190
185
|
return undefined;
|
|
191
186
|
}
|
|
192
187
|
const dialect = String(values.dbDialect ?? 'postgres').trim() || 'postgres';
|
|
@@ -203,7 +198,14 @@ async function validateExternalDbPromptField(value, values) {
|
|
|
203
198
|
if (typeof value === 'string' && value.trim() === '') {
|
|
204
199
|
return undefined;
|
|
205
200
|
}
|
|
206
|
-
|
|
201
|
+
const connectionError = await validateExternalDbConfig(values);
|
|
202
|
+
if (connectionError) {
|
|
203
|
+
return connectionError;
|
|
204
|
+
}
|
|
205
|
+
if (!Object.prototype.hasOwnProperty.call(values, 'dbUnderscored')) {
|
|
206
|
+
return undefined;
|
|
207
|
+
}
|
|
208
|
+
return await validateMysqlLowerCaseTableNamesCompatibility(values);
|
|
207
209
|
}
|
|
208
210
|
function defaultInstallAppRootPath(envName) {
|
|
209
211
|
const name = String(envName ?? DEFAULT_INSTALL_ENV_NAME).trim() || DEFAULT_INSTALL_ENV_NAME;
|
|
@@ -222,54 +224,6 @@ function pickPresetKeys(source, keys) {
|
|
|
222
224
|
}
|
|
223
225
|
return out;
|
|
224
226
|
}
|
|
225
|
-
async function commandSucceeds(command, args, options) {
|
|
226
|
-
return await new Promise((resolve) => {
|
|
227
|
-
const child = spawn(command, args, {
|
|
228
|
-
cwd: options?.cwd,
|
|
229
|
-
env: {
|
|
230
|
-
...process.env,
|
|
231
|
-
...options?.env,
|
|
232
|
-
},
|
|
233
|
-
stdio: 'ignore',
|
|
234
|
-
});
|
|
235
|
-
child.once('error', () => resolve(false));
|
|
236
|
-
child.once('close', (code) => resolve(code === 0));
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
async function commandOutput(command, args, options) {
|
|
240
|
-
return await new Promise((resolve, reject) => {
|
|
241
|
-
const child = spawn(command, args, {
|
|
242
|
-
cwd: options?.cwd,
|
|
243
|
-
env: {
|
|
244
|
-
...process.env,
|
|
245
|
-
...options?.env,
|
|
246
|
-
},
|
|
247
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
248
|
-
});
|
|
249
|
-
let stdout = '';
|
|
250
|
-
let stderr = '';
|
|
251
|
-
child.stdout.setEncoding('utf8');
|
|
252
|
-
child.stderr.setEncoding('utf8');
|
|
253
|
-
child.stdout.on('data', (chunk) => {
|
|
254
|
-
stdout += chunk;
|
|
255
|
-
});
|
|
256
|
-
child.stderr.on('data', (chunk) => {
|
|
257
|
-
stderr += chunk;
|
|
258
|
-
});
|
|
259
|
-
child.once('error', reject);
|
|
260
|
-
child.once('close', (code, signal) => {
|
|
261
|
-
if (code === 0) {
|
|
262
|
-
resolve(stdout);
|
|
263
|
-
return;
|
|
264
|
-
}
|
|
265
|
-
if (signal) {
|
|
266
|
-
reject(new Error(`${command} exited due to signal ${signal}`));
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
reject(new Error(`${command} exited with code ${code}: ${stderr.trim()}`));
|
|
270
|
-
});
|
|
271
|
-
});
|
|
272
|
-
}
|
|
273
227
|
function optionalEnvString(value) {
|
|
274
228
|
const text = String(value ?? '').trim();
|
|
275
229
|
return text || undefined;
|
|
@@ -324,7 +278,7 @@ export default class Install extends Command {
|
|
|
324
278
|
'<%= config.bin %> <%= command.id %> --env app1 --root-nickname "Super Admin"',
|
|
325
279
|
'<%= config.bin %> <%= command.id %> --env myenv --app-root-path=./myenv/source/ --storage-path=./myenv/storage/',
|
|
326
280
|
'<%= config.bin %> <%= command.id %> --env dev -y --app-root-path=./dev/source/',
|
|
327
|
-
'<%= config.bin %> <%= command.id %> --env dev -y --
|
|
281
|
+
'<%= config.bin %> <%= command.id %> --env dev -y --skip-download --source git --app-root-path=./dev/source/',
|
|
328
282
|
];
|
|
329
283
|
static flags = {
|
|
330
284
|
yes: Flags.boolean({
|
|
@@ -359,14 +313,20 @@ export default class Install extends Command {
|
|
|
359
313
|
}),
|
|
360
314
|
'auth-type': Flags.string({
|
|
361
315
|
char: 'a',
|
|
362
|
-
description: 'Authentication: token (API key) or oauth (browser login via `nb env auth`)',
|
|
363
|
-
options: ['token', 'oauth'],
|
|
316
|
+
description: 'Authentication: basic (username/password login), token (API key), or oauth (browser login via `nb env auth`)',
|
|
317
|
+
options: ['basic', 'token', 'oauth'],
|
|
364
318
|
}),
|
|
365
319
|
'access-token': Flags.string({
|
|
366
320
|
char: 't',
|
|
367
321
|
aliases: ['token'],
|
|
368
322
|
description: 'API key or access token when using --auth-type token',
|
|
369
323
|
}),
|
|
324
|
+
username: Flags.string({
|
|
325
|
+
description: 'Username when using --auth-type basic',
|
|
326
|
+
}),
|
|
327
|
+
password: Flags.string({
|
|
328
|
+
description: 'Password when using --auth-type basic',
|
|
329
|
+
}),
|
|
370
330
|
'skip-auth': Flags.boolean({
|
|
371
331
|
description: 'Save the env auth mode now and finish authentication later with `nb env auth`',
|
|
372
332
|
default: false,
|
|
@@ -440,8 +400,8 @@ export default class Install extends Command {
|
|
|
440
400
|
description: 'Use underscored database naming for the app',
|
|
441
401
|
default: false,
|
|
442
402
|
}),
|
|
443
|
-
'
|
|
444
|
-
description: '
|
|
403
|
+
'skip-download': Flags.boolean({
|
|
404
|
+
description: 'Skip the download step and reuse an existing local app directory or Docker image',
|
|
445
405
|
default: false,
|
|
446
406
|
}),
|
|
447
407
|
...omitKeys(Download.flags, ['yes']),
|
|
@@ -488,12 +448,6 @@ export default class Install extends Command {
|
|
|
488
448
|
placeholder: installText('prompts.storagePath.placeholder'),
|
|
489
449
|
initialValue: (values) => defaultInstallStoragePath(values.env ?? values.appName),
|
|
490
450
|
},
|
|
491
|
-
fetchSource: {
|
|
492
|
-
type: 'boolean',
|
|
493
|
-
message: installText('prompts.fetchSource.message'),
|
|
494
|
-
initialValue: true,
|
|
495
|
-
yesInitialValue: true,
|
|
496
|
-
},
|
|
497
451
|
};
|
|
498
452
|
static dbPrompts = {
|
|
499
453
|
dbDialect: {
|
|
@@ -521,8 +475,7 @@ export default class Install extends Command {
|
|
|
521
475
|
message: installText('prompts.builtinDbImage.message'),
|
|
522
476
|
placeholder: installText('prompts.builtinDbImage.placeholder'),
|
|
523
477
|
initialValue: (values) => defaultBuiltinDbImageForDialect(values.dbDialect),
|
|
524
|
-
hidden: (values) => !
|
|
525
|
-
|| !supportsBuiltinDbDialect(values.dbDialect),
|
|
478
|
+
hidden: (values) => !values.builtinDb || !supportsBuiltinDbDialect(values.dbDialect),
|
|
526
479
|
required: true,
|
|
527
480
|
},
|
|
528
481
|
dbHost: {
|
|
@@ -542,8 +495,7 @@ export default class Install extends Command {
|
|
|
542
495
|
initialValue: (values) => defaultDbPortForDialect(values.dbDialect),
|
|
543
496
|
required: true,
|
|
544
497
|
validate: Install.validateDbPort,
|
|
545
|
-
hidden: (values) => Boolean(values.builtinDb)
|
|
546
|
-
&& String(values.source ?? '').trim() === 'docker',
|
|
498
|
+
hidden: (values) => Boolean(values.builtinDb) && String(values.source ?? '').trim() === 'docker',
|
|
547
499
|
},
|
|
548
500
|
dbDatabase: {
|
|
549
501
|
type: 'text',
|
|
@@ -568,6 +520,27 @@ export default class Install extends Command {
|
|
|
568
520
|
required: true,
|
|
569
521
|
validate: validateExternalDbPromptField,
|
|
570
522
|
},
|
|
523
|
+
dbSchema: {
|
|
524
|
+
type: 'text',
|
|
525
|
+
message: installText('prompts.dbSchema.message'),
|
|
526
|
+
placeholder: installText('prompts.dbSchema.placeholder'),
|
|
527
|
+
hidden: (values) => String(values.dbDialect ?? '').trim() !== 'postgres',
|
|
528
|
+
},
|
|
529
|
+
dbTablePrefix: {
|
|
530
|
+
type: 'text',
|
|
531
|
+
message: installText('prompts.dbTablePrefix.message'),
|
|
532
|
+
placeholder: installText('prompts.dbTablePrefix.placeholder'),
|
|
533
|
+
},
|
|
534
|
+
dbUnderscored: {
|
|
535
|
+
type: 'boolean',
|
|
536
|
+
message: installText('prompts.dbUnderscored.message'),
|
|
537
|
+
initialValue: false,
|
|
538
|
+
yesInitialValue: false,
|
|
539
|
+
validate: (value, values) => validateExternalDbPromptField(value, {
|
|
540
|
+
...values,
|
|
541
|
+
dbUnderscored: Boolean(value),
|
|
542
|
+
}),
|
|
543
|
+
},
|
|
571
544
|
};
|
|
572
545
|
static rootUserPrompts = {
|
|
573
546
|
rootUsername: {
|
|
@@ -662,9 +635,8 @@ export default class Install extends Command {
|
|
|
662
635
|
* Booleans with defaults are only preset when the user passed the flag on argv (see `download`).
|
|
663
636
|
* Does not include `env` — use {@link buildEnvPresetValuesFromFlags} for {@link Install.envPrompts}.
|
|
664
637
|
*/
|
|
665
|
-
static buildPresetValuesFromFlags(flags) {
|
|
638
|
+
static buildPresetValuesFromFlags(flags, argv = process.argv.slice(2)) {
|
|
666
639
|
const preset = {};
|
|
667
|
-
const argv = process.argv.slice(2);
|
|
668
640
|
const apiBaseUrl = Install.toOptionalPromptString(flags['api-base-url']);
|
|
669
641
|
if (apiBaseUrl) {
|
|
670
642
|
preset.apiBaseUrl = apiBaseUrl;
|
|
@@ -687,6 +659,12 @@ export default class Install extends Command {
|
|
|
687
659
|
if (flags['access-token'] !== undefined || flags.token !== undefined) {
|
|
688
660
|
preset.accessToken = String(flags['access-token'] ?? flags.token ?? '');
|
|
689
661
|
}
|
|
662
|
+
if (flags.username !== undefined) {
|
|
663
|
+
preset.username = String(flags.username ?? '').trim();
|
|
664
|
+
}
|
|
665
|
+
if (flags.password !== undefined) {
|
|
666
|
+
preset.password = String(flags.password ?? '');
|
|
667
|
+
}
|
|
690
668
|
if (flags.lang !== undefined) {
|
|
691
669
|
const v = String(flags.lang).trim();
|
|
692
670
|
if (v) {
|
|
@@ -726,8 +704,15 @@ export default class Install extends Command {
|
|
|
726
704
|
if (flags['root-nickname'] !== undefined) {
|
|
727
705
|
preset.rootNickname = String(flags['root-nickname'] ?? '').trim();
|
|
728
706
|
}
|
|
729
|
-
if (argvHasToken(argv, ['--
|
|
730
|
-
preset.
|
|
707
|
+
if (argvHasToken(argv, ['--skip-download'])) {
|
|
708
|
+
preset.skipDownload = flags['skip-download'];
|
|
709
|
+
if (flags['skip-download']) {
|
|
710
|
+
preset.dockerSave = false;
|
|
711
|
+
preset.replace = false;
|
|
712
|
+
preset.devDependencies = false;
|
|
713
|
+
preset.build = false;
|
|
714
|
+
preset.buildDts = false;
|
|
715
|
+
}
|
|
731
716
|
}
|
|
732
717
|
if (argvHasToken(argv, ['--builtin-db', '--no-builtin-db'])) {
|
|
733
718
|
preset.builtinDb = flags['builtin-db'];
|
|
@@ -789,18 +774,17 @@ export default class Install extends Command {
|
|
|
789
774
|
}
|
|
790
775
|
return preset;
|
|
791
776
|
}
|
|
792
|
-
static buildAppPresetValuesFromFlags(flags) {
|
|
793
|
-
return pickPresetKeys(Install.buildPresetValuesFromFlags(flags), [
|
|
777
|
+
static buildAppPresetValuesFromFlags(flags, argv = process.argv.slice(2)) {
|
|
778
|
+
return pickPresetKeys(Install.buildPresetValuesFromFlags(flags, argv), [
|
|
794
779
|
'lang',
|
|
795
780
|
'force',
|
|
796
781
|
'appRootPath',
|
|
797
782
|
'appPort',
|
|
798
783
|
'storagePath',
|
|
799
|
-
'fetchSource',
|
|
800
784
|
]);
|
|
801
785
|
}
|
|
802
|
-
static buildDbPresetValuesFromFlags(flags) {
|
|
803
|
-
return pickPresetKeys(Install.buildPresetValuesFromFlags(flags), [
|
|
786
|
+
static buildDbPresetValuesFromFlags(flags, argv = process.argv.slice(2)) {
|
|
787
|
+
return pickPresetKeys(Install.buildPresetValuesFromFlags(flags, argv), [
|
|
804
788
|
'builtinDb',
|
|
805
789
|
'dbDialect',
|
|
806
790
|
'builtinDbImage',
|
|
@@ -814,18 +798,20 @@ export default class Install extends Command {
|
|
|
814
798
|
'dbUnderscored',
|
|
815
799
|
]);
|
|
816
800
|
}
|
|
817
|
-
static buildRootPresetValuesFromFlags(flags) {
|
|
818
|
-
return pickPresetKeys(Install.buildPresetValuesFromFlags(flags), [
|
|
801
|
+
static buildRootPresetValuesFromFlags(flags, argv = process.argv.slice(2)) {
|
|
802
|
+
return pickPresetKeys(Install.buildPresetValuesFromFlags(flags, argv), [
|
|
819
803
|
'rootUsername',
|
|
820
804
|
'rootEmail',
|
|
821
805
|
'rootPassword',
|
|
822
806
|
'rootNickname',
|
|
823
807
|
]);
|
|
824
808
|
}
|
|
825
|
-
static buildEnvAddPresetValuesFromFlags(flags) {
|
|
826
|
-
return pickPresetKeys(Install.buildPresetValuesFromFlags(flags), [
|
|
809
|
+
static buildEnvAddPresetValuesFromFlags(flags, argv = process.argv.slice(2)) {
|
|
810
|
+
return pickPresetKeys(Install.buildPresetValuesFromFlags(flags, argv), [
|
|
827
811
|
'apiBaseUrl',
|
|
828
812
|
'authType',
|
|
813
|
+
'username',
|
|
814
|
+
'password',
|
|
829
815
|
'accessToken',
|
|
830
816
|
]);
|
|
831
817
|
}
|
|
@@ -857,6 +843,18 @@ export default class Install extends Command {
|
|
|
857
843
|
const text = String(value).trim();
|
|
858
844
|
return text || undefined;
|
|
859
845
|
}
|
|
846
|
+
static resolveManagedAppKey(value) {
|
|
847
|
+
return Install.toOptionalPromptString(value) ?? crypto.randomBytes(32).toString('hex');
|
|
848
|
+
}
|
|
849
|
+
static resolveManagedTimeZone(value) {
|
|
850
|
+
return Install.toOptionalPromptString(value) ?? (Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC');
|
|
851
|
+
}
|
|
852
|
+
async ensureManagedAppRuntimeConfig(params) {
|
|
853
|
+
const savedEnv = await getEnv(params.envName, { scope: resolveDefaultConfigScope() });
|
|
854
|
+
const savedConfig = savedEnv?.config;
|
|
855
|
+
params.appResults.appKey = Install.resolveManagedAppKey(params.appResults.appKey ?? savedConfig?.appKey);
|
|
856
|
+
params.appResults.timeZone = Install.resolveManagedTimeZone(params.appResults.timeZone ?? savedConfig?.timezone);
|
|
857
|
+
}
|
|
860
858
|
static async validateAppPort(value, values) {
|
|
861
859
|
const formatError = validateTcpPort(value);
|
|
862
860
|
if (formatError) {
|
|
@@ -915,9 +913,13 @@ export default class Install extends Command {
|
|
|
915
913
|
if (validationError) {
|
|
916
914
|
throw new Error(validationError);
|
|
917
915
|
}
|
|
916
|
+
const compatibilityError = await validateMysqlLowerCaseTableNamesCompatibility(dbResults);
|
|
917
|
+
if (compatibilityError) {
|
|
918
|
+
throw new Error(compatibilityError);
|
|
919
|
+
}
|
|
918
920
|
}
|
|
919
921
|
static async readResumePortValidationContext(values) {
|
|
920
|
-
if (!
|
|
922
|
+
if (!values.resume) {
|
|
921
923
|
return undefined;
|
|
922
924
|
}
|
|
923
925
|
const envName = Install.toOptionalPromptString(values.env);
|
|
@@ -948,8 +950,7 @@ export default class Install extends Command {
|
|
|
948
950
|
}
|
|
949
951
|
static async isResumeManagedPortReuse(params) {
|
|
950
952
|
if (params.target === 'app') {
|
|
951
|
-
if ((params.context.source === 'npm' || params.context.source === 'git')
|
|
952
|
-
&& params.context.appRootPath) {
|
|
953
|
+
if ((params.context.source === 'npm' || params.context.source === 'git') && params.context.appRootPath) {
|
|
953
954
|
return await Install.isLocalPm2ProcessUsingPort(params.context.appRootPath, params.port);
|
|
954
955
|
}
|
|
955
956
|
const containerName = Install.buildDockerAppContainerName(params.context.envName, params.context.dockerContainerPrefix);
|
|
@@ -965,19 +966,13 @@ export default class Install extends Command {
|
|
|
965
966
|
if (!containerName || !port) {
|
|
966
967
|
return false;
|
|
967
968
|
}
|
|
968
|
-
const exists = await commandSucceeds('docker', [
|
|
969
|
-
'container',
|
|
970
|
-
'inspect',
|
|
971
|
-
containerName,
|
|
972
|
-
]);
|
|
969
|
+
const exists = await commandSucceeds('docker', ['container', 'inspect', containerName]);
|
|
973
970
|
if (!exists) {
|
|
974
971
|
return false;
|
|
975
972
|
}
|
|
976
973
|
try {
|
|
977
974
|
const output = await commandOutput('docker', ['port', containerName]);
|
|
978
|
-
return output
|
|
979
|
-
.split(/\r?\n/)
|
|
980
|
-
.some((line) => line.includes(`:${port}`));
|
|
975
|
+
return output.split(/\r?\n/).some((line) => line.includes(`:${port}`));
|
|
981
976
|
}
|
|
982
977
|
catch {
|
|
983
978
|
return false;
|
|
@@ -1033,29 +1028,20 @@ export default class Install extends Command {
|
|
|
1033
1028
|
...(appRootPath ? { appRootPath } : {}),
|
|
1034
1029
|
...(appPort ? { appPort } : {}),
|
|
1035
1030
|
...(storagePath ? { storagePath } : {}),
|
|
1036
|
-
...(source
|
|
1037
|
-
? { fetchSource: true }
|
|
1038
|
-
: appRootPath
|
|
1039
|
-
? { fetchSource: false }
|
|
1040
|
-
: {}),
|
|
1041
1031
|
};
|
|
1042
1032
|
const downloadPreset = {
|
|
1043
1033
|
...(source ? { source } : {}),
|
|
1044
1034
|
...(downloadVersion
|
|
1045
1035
|
? {
|
|
1046
1036
|
version: downloadVersionPromptValue(downloadVersion),
|
|
1047
|
-
...(downloadVersionPromptValue(downloadVersion) === 'other'
|
|
1048
|
-
? { otherVersion: downloadVersion }
|
|
1049
|
-
: {}),
|
|
1037
|
+
...(downloadVersionPromptValue(downloadVersion) === 'other' ? { otherVersion: downloadVersion } : {}),
|
|
1050
1038
|
}
|
|
1051
1039
|
: {}),
|
|
1052
1040
|
...(dockerRegistry ? { dockerRegistry } : {}),
|
|
1053
1041
|
...(dockerPlatform ? { dockerPlatform } : {}),
|
|
1054
1042
|
...(gitUrl ? { gitUrl } : {}),
|
|
1055
1043
|
...(npmRegistry ? { npmRegistry } : {}),
|
|
1056
|
-
...(typeof config.devDependencies === 'boolean'
|
|
1057
|
-
? { devDependencies: config.devDependencies }
|
|
1058
|
-
: {}),
|
|
1044
|
+
...(typeof config.devDependencies === 'boolean' ? { devDependencies: config.devDependencies } : {}),
|
|
1059
1045
|
...(typeof config.build === 'boolean' ? { build: config.build } : {}),
|
|
1060
1046
|
...(typeof config.buildDts === 'boolean' ? { buildDts: config.buildDts } : {}),
|
|
1061
1047
|
};
|
|
@@ -1085,6 +1071,13 @@ export default class Install extends Command {
|
|
|
1085
1071
|
envAddPreset.accessToken = String(auth.accessToken);
|
|
1086
1072
|
}
|
|
1087
1073
|
}
|
|
1074
|
+
else if (savedAuthType === 'basic') {
|
|
1075
|
+
envAddPreset.authType = 'basic';
|
|
1076
|
+
const authUsername = Install.toOptionalPromptString(config.authUsername) ?? rootUsername;
|
|
1077
|
+
if (authUsername) {
|
|
1078
|
+
envAddPreset.username = authUsername;
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1088
1081
|
else if (savedAuthType === 'oauth') {
|
|
1089
1082
|
envAddPreset.authType = 'oauth';
|
|
1090
1083
|
}
|
|
@@ -1132,7 +1125,7 @@ export default class Install extends Command {
|
|
|
1132
1125
|
throw new Error([
|
|
1133
1126
|
`Cannot continue setup for "${env.name}" in non-interactive resume mode yet.`,
|
|
1134
1127
|
`These setup-only flags are not saved in the env config: ${missingFlags.join(', ')}`,
|
|
1135
|
-
`Run \`nb init --env ${env.name} --resume\` without \`--yes\`, or pass those flags again.`,
|
|
1128
|
+
`Run \`nb init --ui --env ${env.name} --resume\` without \`--yes\`, or pass those flags again.`,
|
|
1136
1129
|
].join('\n'));
|
|
1137
1130
|
}
|
|
1138
1131
|
}
|
|
@@ -1169,8 +1162,7 @@ export default class Install extends Command {
|
|
|
1169
1162
|
}
|
|
1170
1163
|
static shouldPublishBuiltinDbPortForValues(values) {
|
|
1171
1164
|
const builtinDb = values.builtinDb === undefined ? true : Boolean(values.builtinDb);
|
|
1172
|
-
return builtinDb
|
|
1173
|
-
&& Install.shouldPublishBuiltinDbPort(values.source);
|
|
1165
|
+
return builtinDb && Install.shouldPublishBuiltinDbPort(values.source);
|
|
1174
1166
|
}
|
|
1175
1167
|
static async buildDbPromptInitialValues(params) {
|
|
1176
1168
|
if (params.flags['db-port'] !== undefined) {
|
|
@@ -1226,9 +1218,8 @@ export default class Install extends Command {
|
|
|
1226
1218
|
* Resolve the effective preset `values` for the embedded download step.
|
|
1227
1219
|
* Explicit download flags win; otherwise `-y` falls back to the docker + alpha quickstart path.
|
|
1228
1220
|
*/
|
|
1229
|
-
static buildDownloadPresetValuesForInstall(flags, appResults, envName, yes) {
|
|
1221
|
+
static buildDownloadPresetValuesForInstall(flags, appResults, envName, yes, argv = process.argv.slice(2)) {
|
|
1230
1222
|
const preset = {};
|
|
1231
|
-
const argv = process.argv.slice(2);
|
|
1232
1223
|
const appRoot = String(appResults.appRootPath ?? '').trim() || defaultInstallAppRootPath(envName);
|
|
1233
1224
|
const lang = String(appResults.lang ?? DEFAULT_INSTALL_LANG).trim() || DEFAULT_INSTALL_LANG;
|
|
1234
1225
|
preset.lang = lang;
|
|
@@ -1267,8 +1258,7 @@ export default class Install extends Command {
|
|
|
1267
1258
|
}
|
|
1268
1259
|
}
|
|
1269
1260
|
if (flags['npm-registry'] !== undefined) {
|
|
1270
|
-
preset.npmRegistry =
|
|
1271
|
-
typeof flags['npm-registry'] === 'string' ? flags['npm-registry'] : '';
|
|
1261
|
+
preset.npmRegistry = typeof flags['npm-registry'] === 'string' ? flags['npm-registry'] : '';
|
|
1272
1262
|
}
|
|
1273
1263
|
if (flags.resume && !argvHasToken(argv, ['--replace', '-r'])) {
|
|
1274
1264
|
preset.replace = true;
|
|
@@ -1312,15 +1302,11 @@ export default class Install extends Command {
|
|
|
1312
1302
|
}
|
|
1313
1303
|
static buildBuiltinDbContainerPrefix(containerPrefix) {
|
|
1314
1304
|
const storedName = String(containerPrefix ?? '').trim();
|
|
1315
|
-
return storedName
|
|
1316
|
-
? Install.sanitizeDockerResourceName(storedName)
|
|
1317
|
-
: Install.defaultDockerContainerPrefix();
|
|
1305
|
+
return storedName ? Install.sanitizeDockerResourceName(storedName) : Install.defaultDockerContainerPrefix();
|
|
1318
1306
|
}
|
|
1319
1307
|
static buildManagedDockerNetworkName(networkName) {
|
|
1320
1308
|
const storedName = String(networkName ?? '').trim();
|
|
1321
|
-
return storedName
|
|
1322
|
-
? Install.sanitizeDockerResourceName(storedName)
|
|
1323
|
-
: Install.defaultDockerNetworkName();
|
|
1309
|
+
return storedName ? Install.sanitizeDockerResourceName(storedName) : Install.defaultDockerNetworkName();
|
|
1324
1310
|
}
|
|
1325
1311
|
static buildBuiltinDbNetworkName(envName, networkName) {
|
|
1326
1312
|
void envName;
|
|
@@ -1353,25 +1339,19 @@ export default class Install extends Command {
|
|
|
1353
1339
|
}
|
|
1354
1340
|
static buildBuiltinDbPlan(params) {
|
|
1355
1341
|
const dbDialect = String(params.dbDialect ?? 'postgres').trim() || 'postgres';
|
|
1356
|
-
const dbPort = String(params.dbPort ?? defaultDbPortForDialect(dbDialect)).trim()
|
|
1357
|
-
|| defaultDbPortForDialect(dbDialect);
|
|
1342
|
+
const dbPort = String(params.dbPort ?? defaultDbPortForDialect(dbDialect)).trim() || defaultDbPortForDialect(dbDialect);
|
|
1358
1343
|
const defaultDbDatabase = defaultDbDatabaseForDialect(dbDialect);
|
|
1359
1344
|
const networkName = Install.buildBuiltinDbNetworkName(params.envName, params.dockerNetworkName ?? params.workspaceName);
|
|
1360
1345
|
const containerName = Install.buildBuiltinDbContainerName(params.envName, dbDialect, params.dockerContainerPrefix ?? params.workspaceName);
|
|
1361
1346
|
const dbHostInput = String(params.dbHost ?? '').trim();
|
|
1362
1347
|
const dbHost = Install.shouldPublishBuiltinDbPort(params.source)
|
|
1363
|
-
?
|
|
1364
|
-
&& dbHostInput !== DEFAULT_INSTALL_BUILTIN_DB_HOST
|
|
1365
|
-
&& dbHostInput !== containerName
|
|
1348
|
+
? dbHostInput && dbHostInput !== DEFAULT_INSTALL_BUILTIN_DB_HOST && dbHostInput !== containerName
|
|
1366
1349
|
? dbHostInput
|
|
1367
|
-
: DEFAULT_INSTALL_DB_HOST
|
|
1368
|
-
:
|
|
1369
|
-
&& dbHostInput !== DEFAULT_INSTALL_DB_HOST
|
|
1370
|
-
&& dbHostInput !== 'localhost'
|
|
1350
|
+
: DEFAULT_INSTALL_DB_HOST
|
|
1351
|
+
: dbHostInput && dbHostInput !== DEFAULT_INSTALL_DB_HOST && dbHostInput !== 'localhost'
|
|
1371
1352
|
? dbHostInput
|
|
1372
|
-
: containerName
|
|
1373
|
-
const storagePath = resolveConfiguredEnvPath(params.storagePath)
|
|
1374
|
-
?? resolveEnvRelativePath(defaultInstallStoragePath(params.envName));
|
|
1353
|
+
: containerName;
|
|
1354
|
+
const storagePath = resolveConfiguredEnvPath(params.storagePath) ?? resolveEnvRelativePath(defaultInstallStoragePath(params.envName));
|
|
1375
1355
|
if (dbDialect === 'postgres') {
|
|
1376
1356
|
const image = String(params.builtinDbImage ?? '').trim() || defaultBuiltinDbImageForDialect(dbDialect);
|
|
1377
1357
|
const dataDir = path.resolve(storagePath, 'db', 'postgres');
|
|
@@ -1402,12 +1382,9 @@ export default class Install extends Command {
|
|
|
1402
1382
|
dbDialect,
|
|
1403
1383
|
dbHost,
|
|
1404
1384
|
dbPort,
|
|
1405
|
-
dbDatabase: String(params.dbDatabase ?? defaultDbDatabase).trim()
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|| DEFAULT_INSTALL_DB_USER,
|
|
1409
|
-
dbPassword: String(params.dbPassword ?? DEFAULT_INSTALL_DB_PASSWORD)
|
|
1410
|
-
|| DEFAULT_INSTALL_DB_PASSWORD,
|
|
1385
|
+
dbDatabase: String(params.dbDatabase ?? defaultDbDatabase).trim() || defaultDbDatabase,
|
|
1386
|
+
dbUser: String(params.dbUser ?? DEFAULT_INSTALL_DB_USER).trim() || DEFAULT_INSTALL_DB_USER,
|
|
1387
|
+
dbPassword: String(params.dbPassword ?? DEFAULT_INSTALL_DB_PASSWORD) || DEFAULT_INSTALL_DB_PASSWORD,
|
|
1411
1388
|
networkName,
|
|
1412
1389
|
containerName,
|
|
1413
1390
|
dataDir,
|
|
@@ -1593,11 +1570,7 @@ export default class Install extends Command {
|
|
|
1593
1570
|
}
|
|
1594
1571
|
}
|
|
1595
1572
|
async dockerContainerExists(name) {
|
|
1596
|
-
return await commandSucceeds('docker', [
|
|
1597
|
-
'container',
|
|
1598
|
-
'inspect',
|
|
1599
|
-
name,
|
|
1600
|
-
]);
|
|
1573
|
+
return await commandSucceeds('docker', ['container', 'inspect', name]);
|
|
1601
1574
|
}
|
|
1602
1575
|
async removeDockerContainer(name) {
|
|
1603
1576
|
await run('docker', ['rm', '-f', name], {
|
|
@@ -1647,8 +1620,7 @@ export default class Install extends Command {
|
|
|
1647
1620
|
});
|
|
1648
1621
|
}
|
|
1649
1622
|
async startBuiltinDb(params) {
|
|
1650
|
-
const storagePath = String(params.appResults.storagePath ?? '').trim()
|
|
1651
|
-
|| defaultInstallStoragePath(params.envName);
|
|
1623
|
+
const storagePath = String(params.appResults.storagePath ?? '').trim() || defaultInstallStoragePath(params.envName);
|
|
1652
1624
|
const plan = Install.buildBuiltinDbPlan({
|
|
1653
1625
|
envName: params.envName,
|
|
1654
1626
|
workspaceName: params.workspaceName,
|
|
@@ -1686,30 +1658,27 @@ export default class Install extends Command {
|
|
|
1686
1658
|
return plan;
|
|
1687
1659
|
}
|
|
1688
1660
|
static async buildDockerAppPlan(params) {
|
|
1689
|
-
const dockerRegistry = String(downloadResultsValue(params.downloadResults, 'dockerRegistry') ?? '').trim()
|
|
1690
|
-
|
|
1661
|
+
const dockerRegistry = String(downloadResultsValue(params.downloadResults, 'dockerRegistry') ?? '').trim() ||
|
|
1662
|
+
defaultDockerRegistryForLang(process.env.NB_LOCALE);
|
|
1691
1663
|
const version = String(downloadResultsValue(params.downloadResults, 'version') ?? '').trim() || DEFAULT_DOCKER_VERSION;
|
|
1692
1664
|
const imageRef = resolveDockerImageRef(dockerRegistry, version, {
|
|
1693
1665
|
defaultRegistry: defaultDockerRegistryForLang(process.env.NB_LOCALE),
|
|
1694
1666
|
defaultVersion: DEFAULT_DOCKER_VERSION,
|
|
1695
1667
|
});
|
|
1696
1668
|
const appPort = String(params.appResults.appPort ?? DEFAULT_INSTALL_APP_PORT).trim() || DEFAULT_INSTALL_APP_PORT;
|
|
1697
|
-
const storagePath = resolveConfiguredEnvPath(String(params.appResults.storagePath ?? '').trim()
|
|
1698
|
-
|| defaultInstallStoragePath(params.envName))
|
|
1699
|
-
?? resolveEnvRelativePath(defaultInstallStoragePath(params.envName));
|
|
1669
|
+
const storagePath = resolveConfiguredEnvPath(String(params.appResults.storagePath ?? '').trim() || defaultInstallStoragePath(params.envName)) ?? resolveEnvRelativePath(defaultInstallStoragePath(params.envName));
|
|
1700
1670
|
const dbDialect = String(params.dbResults.dbDialect ?? 'postgres').trim() || 'postgres';
|
|
1701
1671
|
const dbHost = String(params.dbResults.dbHost ?? DEFAULT_INSTALL_DB_HOST).trim() || DEFAULT_INSTALL_DB_HOST;
|
|
1702
|
-
const dbPort = String(params.dbResults.dbPort ?? defaultDbPortForDialect(dbDialect)).trim()
|
|
1703
|
-
|
|
1704
|
-
const dbDatabase = String(params.dbResults.dbDatabase ?? DEFAULT_INSTALL_DB_DATABASE).trim()
|
|
1705
|
-
|| DEFAULT_INSTALL_DB_DATABASE;
|
|
1672
|
+
const dbPort = String(params.dbResults.dbPort ?? defaultDbPortForDialect(dbDialect)).trim() ||
|
|
1673
|
+
defaultDbPortForDialect(dbDialect);
|
|
1674
|
+
const dbDatabase = String(params.dbResults.dbDatabase ?? DEFAULT_INSTALL_DB_DATABASE).trim() || DEFAULT_INSTALL_DB_DATABASE;
|
|
1706
1675
|
const dbUser = String(params.dbResults.dbUser ?? DEFAULT_INSTALL_DB_USER).trim() || DEFAULT_INSTALL_DB_USER;
|
|
1707
1676
|
const dbPassword = String(params.dbResults.dbPassword ?? DEFAULT_INSTALL_DB_PASSWORD) || DEFAULT_INSTALL_DB_PASSWORD;
|
|
1708
1677
|
const dbSchema = optionalEnvString(params.dbResults.dbSchema);
|
|
1709
1678
|
const dbTablePrefix = optionalEnvString(params.dbResults.dbTablePrefix);
|
|
1710
1679
|
const dbUnderscored = optionalEnvBoolean(params.dbResults.dbUnderscored);
|
|
1711
|
-
const appKey =
|
|
1712
|
-
const timeZone =
|
|
1680
|
+
const appKey = Install.resolveManagedAppKey(params.appResults.appKey);
|
|
1681
|
+
const timeZone = Install.resolveManagedTimeZone(params.appResults.timeZone);
|
|
1713
1682
|
const containerName = Install.buildDockerAppContainerName(params.envName, params.dockerContainerPrefix ?? params.workspaceName);
|
|
1714
1683
|
const configuredEnvFile = String(params.appResults.envFile ?? '').trim();
|
|
1715
1684
|
const envFile = await resolveDockerEnvFileArg(params.envName, configuredEnvFile ? { envFile: configuredEnvFile } : undefined);
|
|
@@ -1767,8 +1736,8 @@ export default class Install extends Command {
|
|
|
1767
1736
|
return 'created';
|
|
1768
1737
|
}
|
|
1769
1738
|
async installDockerApp(params) {
|
|
1770
|
-
const networkName = params.builtinDbPlan?.networkName
|
|
1771
|
-
|
|
1739
|
+
const networkName = params.builtinDbPlan?.networkName ??
|
|
1740
|
+
Install.buildBuiltinDbNetworkName(params.envName, params.dockerNetworkName ?? params.workspaceName);
|
|
1772
1741
|
await this.ensureDockerNetwork(networkName);
|
|
1773
1742
|
const plan = await Install.buildDockerAppPlan({
|
|
1774
1743
|
envName: params.envName,
|
|
@@ -1815,26 +1784,26 @@ export default class Install extends Command {
|
|
|
1815
1784
|
Install.pushDownloadArgIfValue(argv, '--source', results.source);
|
|
1816
1785
|
Install.pushDownloadArgIfValue(argv, '--version', downloadResultsValue(results, 'version'));
|
|
1817
1786
|
Install.pushDownloadArgIfValue(argv, '--output-dir', source === 'npm' || source === 'git'
|
|
1818
|
-
?
|
|
1819
|
-
|
|
1787
|
+
? resolveConfiguredEnvPath(results.outputDir) ??
|
|
1788
|
+
resolveConfiguredEnvPath(String(results.outputDir ?? '').trim() || defaultInstallAppRootPath(results.env))
|
|
1820
1789
|
: results.outputDir);
|
|
1821
1790
|
Install.pushDownloadArgIfValue(argv, '--git-url', results.gitUrl);
|
|
1822
1791
|
Install.pushDownloadArgIfValue(argv, '--docker-registry', results.dockerRegistry);
|
|
1823
1792
|
Install.pushDownloadArgIfValue(argv, '--docker-platform', results.dockerPlatform);
|
|
1824
1793
|
Install.pushDownloadArgIfValue(argv, '--npm-registry', results.npmRegistry);
|
|
1825
|
-
if (
|
|
1794
|
+
if (results.replace) {
|
|
1826
1795
|
argv.push('--replace');
|
|
1827
1796
|
}
|
|
1828
|
-
if (
|
|
1797
|
+
if (results.devDependencies) {
|
|
1829
1798
|
argv.push('--dev-dependencies');
|
|
1830
1799
|
}
|
|
1831
|
-
if (
|
|
1800
|
+
if (results.dockerSave) {
|
|
1832
1801
|
argv.push('--docker-save');
|
|
1833
1802
|
}
|
|
1834
|
-
if (results.build !== undefined && !
|
|
1803
|
+
if (results.build !== undefined && !results.build) {
|
|
1835
1804
|
argv.push('--no-build');
|
|
1836
1805
|
}
|
|
1837
|
-
if (
|
|
1806
|
+
if (results.buildDts) {
|
|
1838
1807
|
argv.push('--build-dts');
|
|
1839
1808
|
}
|
|
1840
1809
|
return argv;
|
|
@@ -1844,15 +1813,26 @@ export default class Install extends Command {
|
|
|
1844
1813
|
if (projectRoot) {
|
|
1845
1814
|
return projectRoot;
|
|
1846
1815
|
}
|
|
1847
|
-
const outputDir = String(params.downloadResults.outputDir ?? '').trim()
|
|
1848
|
-
|
|
1849
|
-
|
|
1816
|
+
const outputDir = String(params.downloadResults.outputDir ?? '').trim() ||
|
|
1817
|
+
String(params.appResults.appRootPath ?? '').trim() ||
|
|
1818
|
+
defaultInstallAppRootPath(params.envName);
|
|
1850
1819
|
return resolveConfiguredEnvPath(outputDir) ?? resolveEnvRelativePath(defaultInstallAppRootPath(params.envName));
|
|
1851
1820
|
}
|
|
1852
1821
|
static resolveLocalProjectConfigPath(params) {
|
|
1853
|
-
return (String(params.downloadResults.outputDir ?? '').trim()
|
|
1854
|
-
|
|
1855
|
-
|
|
1822
|
+
return (String(params.downloadResults.outputDir ?? '').trim() ||
|
|
1823
|
+
String(params.appResults.appRootPath ?? '').trim() ||
|
|
1824
|
+
defaultInstallAppRootPath(params.envName));
|
|
1825
|
+
}
|
|
1826
|
+
static buildSkipDownloadValues(envName, appResults) {
|
|
1827
|
+
const appRoot = String(appResults.appRootPath ?? '').trim() || defaultInstallAppRootPath(envName);
|
|
1828
|
+
return {
|
|
1829
|
+
outputDir: appRoot,
|
|
1830
|
+
replace: false,
|
|
1831
|
+
dockerSave: false,
|
|
1832
|
+
devDependencies: false,
|
|
1833
|
+
build: false,
|
|
1834
|
+
buildDts: false,
|
|
1835
|
+
};
|
|
1856
1836
|
}
|
|
1857
1837
|
commandStdio(verbose) {
|
|
1858
1838
|
return verbose ? 'inherit' : 'ignore';
|
|
@@ -1862,7 +1842,41 @@ export default class Install extends Command {
|
|
|
1862
1842
|
verbose: params.verbose,
|
|
1863
1843
|
compactLog: true,
|
|
1864
1844
|
});
|
|
1865
|
-
return await this.config.runCommand('source:download', argv);
|
|
1845
|
+
return (await this.config.runCommand('source:download', argv));
|
|
1846
|
+
}
|
|
1847
|
+
async ensureSkippedDownloadInputsReady(params) {
|
|
1848
|
+
if (params.source === 'docker') {
|
|
1849
|
+
const dockerRegistry = String(downloadResultsValue(params.downloadResults, 'dockerRegistry') ?? '').trim() ||
|
|
1850
|
+
defaultDockerRegistryForLang(process.env.NB_LOCALE);
|
|
1851
|
+
const version = String(downloadResultsValue(params.downloadResults, 'version') ?? '').trim() || DEFAULT_DOCKER_VERSION;
|
|
1852
|
+
const imageRef = resolveDockerImageRef(dockerRegistry, version, {
|
|
1853
|
+
defaultRegistry: defaultDockerRegistryForLang(process.env.NB_LOCALE),
|
|
1854
|
+
defaultVersion: DEFAULT_DOCKER_VERSION,
|
|
1855
|
+
});
|
|
1856
|
+
const imageExists = await commandSucceeds('docker', ['image', 'inspect', imageRef]);
|
|
1857
|
+
if (!imageExists) {
|
|
1858
|
+
throw new Error(translateCli('commands.install.messages.skipDownloadDockerImageMissing', {
|
|
1859
|
+
imageRef,
|
|
1860
|
+
}));
|
|
1861
|
+
}
|
|
1862
|
+
return;
|
|
1863
|
+
}
|
|
1864
|
+
if (params.source === 'npm' || params.source === 'git') {
|
|
1865
|
+
const projectRoot = Install.resolveLocalProjectRoot({
|
|
1866
|
+
envName: params.envName,
|
|
1867
|
+
appResults: params.appResults,
|
|
1868
|
+
downloadResults: params.downloadResults,
|
|
1869
|
+
});
|
|
1870
|
+
try {
|
|
1871
|
+
await access(projectRoot);
|
|
1872
|
+
await access(path.join(projectRoot, 'package.json'));
|
|
1873
|
+
}
|
|
1874
|
+
catch {
|
|
1875
|
+
throw new Error(translateCli('commands.install.messages.skipDownloadLocalAppMissing', {
|
|
1876
|
+
projectRoot,
|
|
1877
|
+
}));
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1866
1880
|
}
|
|
1867
1881
|
async downloadLocalApp(params) {
|
|
1868
1882
|
const result = await this.downloadManagedSource({
|
|
@@ -1883,31 +1897,24 @@ export default class Install extends Command {
|
|
|
1883
1897
|
return downloadedProjectRoot;
|
|
1884
1898
|
}
|
|
1885
1899
|
static buildLocalAppEnvVars(params) {
|
|
1886
|
-
const configuredStoragePath = String(params.appResults.storagePath ?? '').trim()
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
const
|
|
1891
|
-
|
|
1892
|
-
const appKey = crypto.randomBytes(32).toString('hex');
|
|
1893
|
-
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC';
|
|
1900
|
+
const configuredStoragePath = String(params.appResults.storagePath ?? '').trim() || defaultInstallStoragePath(params.envName);
|
|
1901
|
+
const storagePath = resolveConfiguredEnvPath(configuredStoragePath) ??
|
|
1902
|
+
resolveEnvRelativePath(defaultInstallStoragePath(params.envName));
|
|
1903
|
+
const dbDialect = String(params.dbResults.dbDialect ?? 'postgres').trim() || 'postgres';
|
|
1904
|
+
const appKey = Install.resolveManagedAppKey(params.appResults.appKey);
|
|
1905
|
+
const timeZone = Install.resolveManagedTimeZone(params.appResults.timeZone);
|
|
1894
1906
|
const env = {
|
|
1895
1907
|
STORAGE_PATH: storagePath,
|
|
1896
|
-
APP_PORT: String(params.appResults.appPort ?? DEFAULT_INSTALL_APP_PORT).trim()
|
|
1897
|
-
|| DEFAULT_INSTALL_APP_PORT,
|
|
1908
|
+
APP_PORT: String(params.appResults.appPort ?? DEFAULT_INSTALL_APP_PORT).trim() || DEFAULT_INSTALL_APP_PORT,
|
|
1898
1909
|
APP_KEY: appKey,
|
|
1899
1910
|
TZ: timeZone,
|
|
1900
1911
|
DB_DIALECT: dbDialect,
|
|
1901
|
-
DB_HOST: String(params.dbResults.dbHost ?? DEFAULT_INSTALL_DB_HOST).trim()
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
DB_USER: String(params.dbResults.dbUser ?? DEFAULT_INSTALL_DB_USER).trim()
|
|
1908
|
-
|| DEFAULT_INSTALL_DB_USER,
|
|
1909
|
-
DB_PASSWORD: String(params.dbResults.dbPassword ?? DEFAULT_INSTALL_DB_PASSWORD)
|
|
1910
|
-
|| DEFAULT_INSTALL_DB_PASSWORD,
|
|
1912
|
+
DB_HOST: String(params.dbResults.dbHost ?? DEFAULT_INSTALL_DB_HOST).trim() || DEFAULT_INSTALL_DB_HOST,
|
|
1913
|
+
DB_PORT: String(params.dbResults.dbPort ?? defaultDbPortForDialect(dbDialect)).trim() ||
|
|
1914
|
+
defaultDbPortForDialect(dbDialect),
|
|
1915
|
+
DB_DATABASE: String(params.dbResults.dbDatabase ?? DEFAULT_INSTALL_DB_DATABASE).trim() || DEFAULT_INSTALL_DB_DATABASE,
|
|
1916
|
+
DB_USER: String(params.dbResults.dbUser ?? DEFAULT_INSTALL_DB_USER).trim() || DEFAULT_INSTALL_DB_USER,
|
|
1917
|
+
DB_PASSWORD: String(params.dbResults.dbPassword ?? DEFAULT_INSTALL_DB_PASSWORD) || DEFAULT_INSTALL_DB_PASSWORD,
|
|
1911
1918
|
...Install.buildInitAppEnvVars({
|
|
1912
1919
|
appResults: params.appResults,
|
|
1913
1920
|
rootResults: params.rootResults,
|
|
@@ -1957,10 +1964,8 @@ export default class Install extends Command {
|
|
|
1957
1964
|
};
|
|
1958
1965
|
}
|
|
1959
1966
|
static resolveApiBaseUrl(params) {
|
|
1960
|
-
const appPort = String(params.appResults.appPort ?? DEFAULT_INSTALL_APP_PORT).trim()
|
|
1961
|
-
|
|
1962
|
-
return (String(params.envAddResults.apiBaseUrl ?? '').trim()
|
|
1963
|
-
|| `http://127.0.0.1:${appPort}/api`);
|
|
1967
|
+
const appPort = String(params.appResults.appPort ?? DEFAULT_INSTALL_APP_PORT).trim() || DEFAULT_INSTALL_APP_PORT;
|
|
1968
|
+
return String(params.envAddResults.apiBaseUrl ?? '').trim() || `http://127.0.0.1:${appPort}/api`;
|
|
1964
1969
|
}
|
|
1965
1970
|
static buildHealthCheckUrl(apiBaseUrl) {
|
|
1966
1971
|
return `${apiBaseUrl.replace(/\/+$/, '')}/__health_check`;
|
|
@@ -1989,9 +1994,7 @@ export default class Install extends Command {
|
|
|
1989
1994
|
const body = Install.formatHealthCheckMessage(text);
|
|
1990
1995
|
return {
|
|
1991
1996
|
ok: response.ok && text.trim().toLowerCase() === 'ok',
|
|
1992
|
-
message: response.ok
|
|
1993
|
-
? `HTTP ${response.status}: ${body}`
|
|
1994
|
-
: `HTTP ${response.status}: ${body}`,
|
|
1997
|
+
message: response.ok ? `HTTP ${response.status}: ${body}` : `HTTP ${response.status}: ${body}`,
|
|
1995
1998
|
};
|
|
1996
1999
|
}
|
|
1997
2000
|
catch (error) {
|
|
@@ -2020,32 +2023,38 @@ export default class Install extends Command {
|
|
|
2020
2023
|
let lastMessage = 'No response yet';
|
|
2021
2024
|
let lastLoggedStatus = '';
|
|
2022
2025
|
printInfo('Waiting for NocoBase to become ready...');
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
lastLoggedStatus
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2026
|
+
const dockerLogFollower = options?.verbose && options.containerName ? startDockerLogFollower(options.containerName) : undefined;
|
|
2027
|
+
try {
|
|
2028
|
+
while (Date.now() - startedAt < timeoutMs) {
|
|
2029
|
+
const result = await Install.requestAppHealthCheck({
|
|
2030
|
+
healthCheckUrl,
|
|
2031
|
+
fetchImpl,
|
|
2032
|
+
requestTimeoutMs,
|
|
2033
|
+
});
|
|
2034
|
+
if (result.ok) {
|
|
2035
|
+
return;
|
|
2036
|
+
}
|
|
2037
|
+
lastMessage = result.message;
|
|
2038
|
+
const elapsedSeconds = Math.max(1, Math.floor((Date.now() - startedAt) / 1000));
|
|
2039
|
+
const statusLine = `Waiting for NocoBase to become ready... (${elapsedSeconds}s elapsed, last status: ${Install.formatHealthCheckMessage(lastMessage)})`;
|
|
2040
|
+
if (statusLine !== lastLoggedStatus) {
|
|
2041
|
+
printInfo(statusLine);
|
|
2042
|
+
lastLoggedStatus = statusLine;
|
|
2043
|
+
}
|
|
2044
|
+
const remainingMs = timeoutMs - (Date.now() - startedAt);
|
|
2045
|
+
if (remainingMs <= 0) {
|
|
2046
|
+
break;
|
|
2047
|
+
}
|
|
2048
|
+
await Install.sleep(Math.min(intervalMs, remainingMs));
|
|
2042
2049
|
}
|
|
2043
|
-
|
|
2050
|
+
const logHint = options?.containerName
|
|
2051
|
+
? ` You can inspect startup logs with: docker logs ${options.containerName}`
|
|
2052
|
+
: '';
|
|
2053
|
+
throw new Error(`The application did not become ready in time. Expected \`${healthCheckUrl}\` to respond with \`ok\`, but the last status was: ${Install.formatHealthCheckMessage(lastMessage)}.${logHint}`);
|
|
2054
|
+
}
|
|
2055
|
+
finally {
|
|
2056
|
+
await dockerLogFollower?.stop();
|
|
2044
2057
|
}
|
|
2045
|
-
const logHint = options?.containerName
|
|
2046
|
-
? ` You can inspect startup logs with: docker logs ${options.containerName}`
|
|
2047
|
-
: '';
|
|
2048
|
-
throw new Error(`The application did not become ready in time. Expected \`${healthCheckUrl}\` to respond with \`ok\`, but the last status was: ${Install.formatHealthCheckMessage(lastMessage)}.${logHint}`);
|
|
2049
2058
|
}
|
|
2050
2059
|
async saveInstalledEnv(params) {
|
|
2051
2060
|
await upsertEnv(params.envName, Install.buildSavedEnvConfig(params), { scope: resolveDefaultConfigScope() });
|
|
@@ -2055,8 +2064,7 @@ export default class Install extends Command {
|
|
|
2055
2064
|
if (!params.appReady) {
|
|
2056
2065
|
return;
|
|
2057
2066
|
}
|
|
2058
|
-
const authType = String(params.envAddResults.authType ?? 'oauth').trim()
|
|
2059
|
-
|| 'oauth';
|
|
2067
|
+
const authType = String(params.envAddResults.authType ?? 'oauth').trim() || 'oauth';
|
|
2060
2068
|
if (params.skipAuth) {
|
|
2061
2069
|
printInfo(formatDeferredAuthMessage(params.envName, authType));
|
|
2062
2070
|
return;
|
|
@@ -2064,23 +2072,34 @@ export default class Install extends Command {
|
|
|
2064
2072
|
if (authType === 'oauth') {
|
|
2065
2073
|
await this.config.runCommand('env:auth', [params.envName]);
|
|
2066
2074
|
}
|
|
2075
|
+
else if (authType === 'basic') {
|
|
2076
|
+
const authArgv = [params.envName, '--auth-type', 'basic'];
|
|
2077
|
+
const username = String(params.envAddResults.username ?? '').trim();
|
|
2078
|
+
const password = String(params.envAddResults.password ?? '');
|
|
2079
|
+
if (username) {
|
|
2080
|
+
authArgv.push('--username', username);
|
|
2081
|
+
}
|
|
2082
|
+
if (password) {
|
|
2083
|
+
authArgv.push('--password', password);
|
|
2084
|
+
}
|
|
2085
|
+
await this.config.runCommand('env:auth', authArgv);
|
|
2086
|
+
}
|
|
2067
2087
|
await this.config.runCommand('env:update', [params.envName]);
|
|
2068
2088
|
}
|
|
2069
2089
|
static buildSavedEnvConfig(params) {
|
|
2070
|
-
const appPort = String(params.appResults.appPort ?? DEFAULT_INSTALL_APP_PORT).trim()
|
|
2071
|
-
|
|
2072
|
-
const storagePath = String(params.appResults.storagePath ?? '').trim()
|
|
2073
|
-
|| defaultInstallStoragePath(params.envName);
|
|
2090
|
+
const appPort = String(params.appResults.appPort ?? DEFAULT_INSTALL_APP_PORT).trim() || DEFAULT_INSTALL_APP_PORT;
|
|
2091
|
+
const storagePath = String(params.appResults.storagePath ?? '').trim() || defaultInstallStoragePath(params.envName);
|
|
2074
2092
|
const envFile = String(params.appResults.envFile ?? '').trim() || undefined;
|
|
2075
2093
|
const apiBaseUrl = Install.resolveApiBaseUrl({
|
|
2076
2094
|
appResults: params.appResults,
|
|
2077
2095
|
envAddResults: params.envAddResults,
|
|
2078
2096
|
});
|
|
2079
|
-
const authType = String(params.envAddResults.authType ?? 'oauth').trim()
|
|
2080
|
-
|
|
2097
|
+
const authType = String(params.envAddResults.authType ?? 'oauth').trim() || 'oauth';
|
|
2098
|
+
const authUsername = authType === 'basic' ? String(params.envAddResults.username ?? params.rootResults.rootUsername ?? '').trim() : '';
|
|
2081
2099
|
return buildStoredEnvConfig({
|
|
2082
2100
|
apiBaseUrl,
|
|
2083
2101
|
authType,
|
|
2102
|
+
...(authUsername ? { authUsername } : {}),
|
|
2084
2103
|
accessToken: params.envAddResults.accessToken,
|
|
2085
2104
|
source: downloadResultsValue(params.downloadResults, 'source'),
|
|
2086
2105
|
downloadVersion: downloadResultsValue(params.downloadResults, 'version'),
|
|
@@ -2115,6 +2134,7 @@ export default class Install extends Command {
|
|
|
2115
2134
|
});
|
|
2116
2135
|
}
|
|
2117
2136
|
async collectPromptResults(parsed, yes) {
|
|
2137
|
+
const commandArgv = this.argv ?? process.argv.slice(2);
|
|
2118
2138
|
const resumePreset = await this.resolveResumePresetValues(parsed, yes);
|
|
2119
2139
|
const envPreset = {
|
|
2120
2140
|
...(resumePreset?.envPreset ?? {}),
|
|
@@ -2130,7 +2150,7 @@ export default class Install extends Command {
|
|
|
2130
2150
|
const envName = String(envResults.env ?? '').trim() || DEFAULT_INSTALL_ENV_NAME;
|
|
2131
2151
|
const appPreset = {
|
|
2132
2152
|
...(resumePreset?.appPreset ?? {}),
|
|
2133
|
-
...Install.buildAppPresetValuesFromFlags(parsed),
|
|
2153
|
+
...Install.buildAppPresetValuesFromFlags(parsed, commandArgv),
|
|
2134
2154
|
};
|
|
2135
2155
|
const appCatalog = Install.buildAppPromptsCatalog(envName, {
|
|
2136
2156
|
resume: parsed.resume,
|
|
@@ -2140,56 +2160,58 @@ export default class Install extends Command {
|
|
|
2140
2160
|
envName,
|
|
2141
2161
|
flags: {
|
|
2142
2162
|
...parsed,
|
|
2143
|
-
'app-root-path': parsed['app-root-path']
|
|
2144
|
-
|
|
2145
|
-
'
|
|
2146
|
-
?? Install.toOptionalPromptString(appPreset.appPort),
|
|
2147
|
-
'storage-path': parsed['storage-path']
|
|
2148
|
-
?? Install.toOptionalPromptString(appPreset.storagePath),
|
|
2163
|
+
'app-root-path': parsed['app-root-path'] ?? Install.toOptionalPromptString(appPreset.appRootPath),
|
|
2164
|
+
'app-port': parsed['app-port'] ?? Install.toOptionalPromptString(appPreset.appPort),
|
|
2165
|
+
'storage-path': parsed['storage-path'] ?? Install.toOptionalPromptString(appPreset.storagePath),
|
|
2149
2166
|
},
|
|
2150
2167
|
}),
|
|
2151
2168
|
values: appPreset,
|
|
2152
2169
|
yesInitialValues: { resume: parsed.resume },
|
|
2153
2170
|
yes,
|
|
2154
2171
|
});
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
downloadOpts.values
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2172
|
+
const downloadOpts = Install.buildDownloadPromptOptionsForInstall(appResults, envName);
|
|
2173
|
+
downloadOpts.values = {
|
|
2174
|
+
...(resumePreset?.downloadPreset ?? {}),
|
|
2175
|
+
...downloadOpts.values,
|
|
2176
|
+
...Install.buildDownloadPresetValuesForInstall(parsed, appResults, envName, yes, commandArgv),
|
|
2177
|
+
...(parsed['skip-download'] ? Install.buildSkipDownloadValues(envName, appResults) : {}),
|
|
2178
|
+
};
|
|
2179
|
+
downloadOpts.yes = yes;
|
|
2180
|
+
const downloadResults = await runPromptCatalog(Download.prompts, downloadOpts);
|
|
2181
|
+
if (parsed['skip-download']) {
|
|
2182
|
+
delete downloadResults.outputDir;
|
|
2183
|
+
delete downloadResults.replace;
|
|
2184
|
+
delete downloadResults.dockerSave;
|
|
2185
|
+
delete downloadResults.devDependencies;
|
|
2186
|
+
delete downloadResults.build;
|
|
2187
|
+
delete downloadResults.buildDts;
|
|
2165
2188
|
}
|
|
2166
2189
|
const dbPreset = {
|
|
2167
2190
|
...(resumePreset?.dbPreset ?? {}),
|
|
2168
|
-
...Install.buildDbPresetValuesFromFlags(parsed),
|
|
2191
|
+
...Install.buildDbPresetValuesFromFlags(parsed, commandArgv),
|
|
2169
2192
|
};
|
|
2170
2193
|
const promptedDbResults = await runPromptCatalog(Install.buildDbPromptsCatalog(envName, downloadResults, {
|
|
2171
2194
|
resume: parsed.resume,
|
|
2172
2195
|
}), {
|
|
2173
2196
|
initialValues: {
|
|
2174
2197
|
...downloadResults,
|
|
2175
|
-
...await Install.buildDbPromptInitialValues({
|
|
2198
|
+
...(await Install.buildDbPromptInitialValues({
|
|
2176
2199
|
flags: {
|
|
2177
2200
|
...parsed,
|
|
2178
|
-
'db-port': parsed['db-port']
|
|
2179
|
-
?? Install.toOptionalPromptString(dbPreset.dbPort),
|
|
2201
|
+
'db-port': parsed['db-port'] ?? Install.toOptionalPromptString(dbPreset.dbPort),
|
|
2180
2202
|
},
|
|
2181
2203
|
downloadResults,
|
|
2182
2204
|
dbPreset,
|
|
2183
|
-
}),
|
|
2205
|
+
})),
|
|
2184
2206
|
},
|
|
2185
2207
|
values: dbPreset,
|
|
2186
2208
|
yes,
|
|
2187
2209
|
});
|
|
2188
2210
|
const dbResults = {
|
|
2189
|
-
...promptedDbResults,
|
|
2190
2211
|
...pickPresetKeys(dbPreset, ['dbSchema', 'dbTablePrefix', 'dbUnderscored']),
|
|
2212
|
+
...promptedDbResults,
|
|
2191
2213
|
};
|
|
2192
|
-
const rootPreset = Install.buildRootPresetValuesFromFlags(parsed);
|
|
2214
|
+
const rootPreset = Install.buildRootPresetValuesFromFlags(parsed, commandArgv);
|
|
2193
2215
|
const rootResults = await runPromptCatalog(Install.rootUserPrompts, {
|
|
2194
2216
|
initialValues: {},
|
|
2195
2217
|
values: {
|
|
@@ -2199,18 +2221,44 @@ export default class Install extends Command {
|
|
|
2199
2221
|
yes,
|
|
2200
2222
|
});
|
|
2201
2223
|
const envAddPromptsForInstall = this.buildEnvAddPromptsForInstall(parsed);
|
|
2202
|
-
const
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2224
|
+
const envAddResumePreset = resumePreset?.envAddPreset ?? {};
|
|
2225
|
+
const envAddFlagValues = Install.buildEnvAddPresetValuesFromFlags(parsed, commandArgv);
|
|
2226
|
+
const envAddPreset = {
|
|
2227
|
+
...envAddResumePreset,
|
|
2228
|
+
...envAddFlagValues,
|
|
2229
|
+
};
|
|
2230
|
+
const resolvedEnvAddAuthType = String(envAddPreset.authType ?? '').trim();
|
|
2231
|
+
const envAddInitialValues = {
|
|
2232
|
+
apiBaseUrl: `http://127.0.0.1:${appResults.appPort ?? DEFAULT_INSTALL_APP_PORT}/api`,
|
|
2233
|
+
...envAddResumePreset,
|
|
2234
|
+
...(!parsed['skip-auth'] && resolvedEnvAddAuthType === 'basic'
|
|
2235
|
+
? {
|
|
2236
|
+
...(!Object.prototype.hasOwnProperty.call(envAddResumePreset, 'username') &&
|
|
2237
|
+
!Object.prototype.hasOwnProperty.call(envAddFlagValues, 'username') &&
|
|
2238
|
+
rootResults.rootUsername !== undefined
|
|
2239
|
+
? { username: String(rootResults.rootUsername).trim() }
|
|
2240
|
+
: {}),
|
|
2241
|
+
...(!Object.prototype.hasOwnProperty.call(envAddFlagValues, 'password') &&
|
|
2242
|
+
rootResults.rootPassword !== undefined
|
|
2243
|
+
? { password: String(rootResults.rootPassword ?? '') }
|
|
2244
|
+
: {}),
|
|
2245
|
+
}
|
|
2246
|
+
: {}),
|
|
2247
|
+
};
|
|
2248
|
+
const promptedEnvAddResults = await runPromptCatalog(envAddPromptsForInstall, {
|
|
2249
|
+
initialValues: envAddInitialValues,
|
|
2206
2250
|
values: {
|
|
2207
2251
|
name: envName,
|
|
2208
2252
|
...(parsed['skip-auth'] ? { skipAuth: true } : {}),
|
|
2209
|
-
...
|
|
2210
|
-
...Install.buildEnvAddPresetValuesFromFlags(parsed),
|
|
2253
|
+
...envAddFlagValues,
|
|
2211
2254
|
},
|
|
2212
2255
|
yes,
|
|
2213
2256
|
});
|
|
2257
|
+
const envAddResults = {
|
|
2258
|
+
...pickPresetKeys(envAddInitialValues, ['username', 'password']),
|
|
2259
|
+
...promptedEnvAddResults,
|
|
2260
|
+
...pickPresetKeys(envAddFlagValues, ['username', 'password']),
|
|
2261
|
+
};
|
|
2214
2262
|
return {
|
|
2215
2263
|
envName,
|
|
2216
2264
|
envResults,
|
|
@@ -2243,16 +2291,27 @@ export default class Install extends Command {
|
|
|
2243
2291
|
: 'Resuming setup from the saved workspace config');
|
|
2244
2292
|
}
|
|
2245
2293
|
const promptResults = await this.collectPromptResults(parsed, flags.yes);
|
|
2246
|
-
const { envName, appResults, downloadResults, dbResults, rootResults, envAddResults
|
|
2294
|
+
const { envName, appResults, downloadResults, dbResults, rootResults, envAddResults } = promptResults;
|
|
2295
|
+
await this.ensureManagedAppRuntimeConfig({
|
|
2296
|
+
envName,
|
|
2297
|
+
appResults,
|
|
2298
|
+
});
|
|
2247
2299
|
const source = String(downloadResultsValue(downloadResults, 'source') ?? '').trim();
|
|
2248
|
-
const usesDockerResources = Boolean(dbResults.builtinDb)
|
|
2249
|
-
|| (Boolean(appResults.fetchSource) && source === 'docker');
|
|
2300
|
+
const usesDockerResources = Boolean(dbResults.builtinDb) || source === 'docker';
|
|
2250
2301
|
const dockerNetworkName = usesDockerResources
|
|
2251
2302
|
? await resolveDockerNetworkName({ scope: resolveDefaultConfigScope() })
|
|
2252
2303
|
: undefined;
|
|
2253
2304
|
const dockerContainerPrefix = usesDockerResources
|
|
2254
2305
|
? await resolveDockerContainerPrefix({ scope: resolveDefaultConfigScope() })
|
|
2255
2306
|
: undefined;
|
|
2307
|
+
if (parsed['skip-download']) {
|
|
2308
|
+
await this.ensureSkippedDownloadInputsReady({
|
|
2309
|
+
source,
|
|
2310
|
+
envName,
|
|
2311
|
+
appResults,
|
|
2312
|
+
downloadResults,
|
|
2313
|
+
});
|
|
2314
|
+
}
|
|
2256
2315
|
await Install.ensureExternalDbReadyForInstall(dbResults);
|
|
2257
2316
|
if (!parsed.resume) {
|
|
2258
2317
|
if (!parsed['skip-save-env-log']) {
|
|
@@ -2271,7 +2330,7 @@ export default class Install extends Command {
|
|
|
2271
2330
|
}
|
|
2272
2331
|
}
|
|
2273
2332
|
let builtinDbPlan;
|
|
2274
|
-
if (
|
|
2333
|
+
if (dbResults.builtinDb) {
|
|
2275
2334
|
builtinDbPlan = await this.startBuiltinDb({
|
|
2276
2335
|
envName,
|
|
2277
2336
|
dockerNetworkName,
|
|
@@ -2291,14 +2350,16 @@ export default class Install extends Command {
|
|
|
2291
2350
|
}
|
|
2292
2351
|
let dockerAppPlan;
|
|
2293
2352
|
let localAppPlan;
|
|
2294
|
-
if (
|
|
2353
|
+
if (source === 'docker' || source === 'npm' || source === 'git') {
|
|
2295
2354
|
this.logStage('Preparing application');
|
|
2296
2355
|
if (source === 'docker') {
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2356
|
+
if (!parsed['skip-download']) {
|
|
2357
|
+
await this.downloadManagedSource({
|
|
2358
|
+
downloadResults,
|
|
2359
|
+
verbose: parsed.verbose,
|
|
2360
|
+
});
|
|
2361
|
+
printInfo('Application image ready.');
|
|
2362
|
+
}
|
|
2302
2363
|
dockerAppPlan = await this.installDockerApp({
|
|
2303
2364
|
envName,
|
|
2304
2365
|
dockerNetworkName,
|
|
@@ -2316,13 +2377,21 @@ export default class Install extends Command {
|
|
|
2316
2377
|
}
|
|
2317
2378
|
else if (source === 'npm' || source === 'git') {
|
|
2318
2379
|
const localSource = source === 'npm' ? 'npm' : 'git';
|
|
2319
|
-
const projectRoot =
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2380
|
+
const projectRoot = parsed['skip-download']
|
|
2381
|
+
? Install.resolveLocalProjectRoot({
|
|
2382
|
+
envName,
|
|
2383
|
+
appResults,
|
|
2384
|
+
downloadResults,
|
|
2385
|
+
})
|
|
2386
|
+
: await this.downloadLocalApp({
|
|
2387
|
+
envName,
|
|
2388
|
+
appResults,
|
|
2389
|
+
downloadResults,
|
|
2390
|
+
verbose: parsed.verbose,
|
|
2391
|
+
});
|
|
2392
|
+
if (!parsed['skip-download']) {
|
|
2393
|
+
printInfo('Application files ready.');
|
|
2394
|
+
}
|
|
2326
2395
|
localAppPlan = await this.startLocalApp({
|
|
2327
2396
|
envName,
|
|
2328
2397
|
source: localSource,
|
|
@@ -2346,6 +2415,7 @@ export default class Install extends Command {
|
|
|
2346
2415
|
envAddResults,
|
|
2347
2416
|
}), {
|
|
2348
2417
|
containerName: dockerAppPlan?.containerName,
|
|
2418
|
+
verbose: parsed.verbose,
|
|
2349
2419
|
});
|
|
2350
2420
|
printInfo(`NocoBase is ready at http://127.0.0.1:${dockerAppPlan?.appPort ?? localAppPlan?.appPort}`);
|
|
2351
2421
|
}
|