@nocobase/cli 2.1.0-beta.36 → 2.1.0-beta.37
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 +1 -1
- package/README.zh-CN.md +1 -1
- package/bin/run.js +3 -2
- package/dist/commands/config/delete.js +4 -0
- package/dist/commands/config/get.js +4 -0
- package/dist/commands/config/set.js +5 -1
- 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 +2 -2
- package/dist/commands/env/shared.js +41 -3
- package/dist/commands/init.js +196 -136
- package/dist/commands/install.js +311 -265
- package/dist/lib/auth-store.js +47 -19
- package/dist/lib/cli-config.js +99 -4
- package/dist/lib/cli-locale.js +19 -7
- package/dist/lib/db-connection-check.js +61 -0
- package/dist/lib/env-auth.js +79 -0
- package/dist/lib/env-config.js +3 -2
- 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 +74 -4
- package/dist/locale/en-US.json +36 -5
- package/dist/locale/zh-CN.json +36 -5
- package/package.json +2 -2
package/dist/commands/install.js
CHANGED
|
@@ -7,27 +7,26 @@
|
|
|
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 Download, { defaultDockerRegistryForLang
|
|
28
|
+
import { resolveDockerEnvFileArg } from "../lib/docker-env-file.js";
|
|
29
|
+
import Download, { defaultDockerRegistryForLang } from './download.js';
|
|
31
30
|
import EnvAdd from "./env/add.js";
|
|
32
31
|
const DEFAULT_INSTALL_ENV_NAME = 'local';
|
|
33
32
|
const DEFAULT_INSTALL_LANG = 'en-US';
|
|
@@ -139,6 +138,9 @@ const installText = (key, values) => localeText(`commands.install.${key}`, value
|
|
|
139
138
|
function formatDeferredAuthMessage(envName, authType) {
|
|
140
139
|
const normalizedAuthType = String(authType ?? '').trim();
|
|
141
140
|
const nextStep = `Authentication was skipped for env "${envName}". Run \`nb env auth ${envName}\` to finish setup.`;
|
|
141
|
+
if (normalizedAuthType === 'basic') {
|
|
142
|
+
return `${nextStep} You will be prompted for a username and password.`;
|
|
143
|
+
}
|
|
142
144
|
if (normalizedAuthType === 'token') {
|
|
143
145
|
return `${nextStep} You will be prompted for an access token.`;
|
|
144
146
|
}
|
|
@@ -154,9 +156,7 @@ function isInstallDbDialect(value) {
|
|
|
154
156
|
return INSTALL_DB_DIALECTS.includes(value);
|
|
155
157
|
}
|
|
156
158
|
function downloadVersionPromptValue(version) {
|
|
157
|
-
return version === 'latest' || version === 'beta' || version === 'alpha'
|
|
158
|
-
? version
|
|
159
|
-
: 'other';
|
|
159
|
+
return version === 'latest' || version === 'beta' || version === 'alpha' ? version : 'other';
|
|
160
160
|
}
|
|
161
161
|
function supportsBuiltinDbDialect(value) {
|
|
162
162
|
const dialect = String(value ?? '').trim();
|
|
@@ -171,22 +171,16 @@ function defaultBuiltinDbImageForDialect(value) {
|
|
|
171
171
|
const defaults = resolveCliLocale(process.env.NB_LOCALE) === 'zh-CN'
|
|
172
172
|
? DEFAULT_INSTALL_BUILTIN_DB_IMAGES_ZH_CN
|
|
173
173
|
: DEFAULT_INSTALL_BUILTIN_DB_IMAGES;
|
|
174
|
-
return supportsBuiltinDbDialect(dialect)
|
|
175
|
-
? defaults[dialect]
|
|
176
|
-
: defaults.postgres;
|
|
174
|
+
return supportsBuiltinDbDialect(dialect) ? defaults[dialect] : defaults.postgres;
|
|
177
175
|
}
|
|
178
176
|
function defaultDbDatabaseForDialect(value) {
|
|
179
|
-
return String(value ?? '').trim() === 'kingbase'
|
|
180
|
-
? 'kingbase'
|
|
181
|
-
: DEFAULT_INSTALL_DB_DATABASE;
|
|
177
|
+
return String(value ?? '').trim() === 'kingbase' ? 'kingbase' : DEFAULT_INSTALL_DB_DATABASE;
|
|
182
178
|
}
|
|
183
179
|
function defaultDbHostForBuiltinDb(values) {
|
|
184
|
-
return
|
|
185
|
-
? DEFAULT_INSTALL_BUILTIN_DB_HOST
|
|
186
|
-
: DEFAULT_INSTALL_DB_HOST;
|
|
180
|
+
return values.builtinDb ? DEFAULT_INSTALL_BUILTIN_DB_HOST : DEFAULT_INSTALL_DB_HOST;
|
|
187
181
|
}
|
|
188
182
|
function validateBuiltinDbEnabled(value, values) {
|
|
189
|
-
if (!
|
|
183
|
+
if (!value) {
|
|
190
184
|
return undefined;
|
|
191
185
|
}
|
|
192
186
|
const dialect = String(values.dbDialect ?? 'postgres').trim() || 'postgres';
|
|
@@ -203,7 +197,14 @@ async function validateExternalDbPromptField(value, values) {
|
|
|
203
197
|
if (typeof value === 'string' && value.trim() === '') {
|
|
204
198
|
return undefined;
|
|
205
199
|
}
|
|
206
|
-
|
|
200
|
+
const connectionError = await validateExternalDbConfig(values);
|
|
201
|
+
if (connectionError) {
|
|
202
|
+
return connectionError;
|
|
203
|
+
}
|
|
204
|
+
if (!Object.prototype.hasOwnProperty.call(values, 'dbUnderscored')) {
|
|
205
|
+
return undefined;
|
|
206
|
+
}
|
|
207
|
+
return await validateMysqlLowerCaseTableNamesCompatibility(values);
|
|
207
208
|
}
|
|
208
209
|
function defaultInstallAppRootPath(envName) {
|
|
209
210
|
const name = String(envName ?? DEFAULT_INSTALL_ENV_NAME).trim() || DEFAULT_INSTALL_ENV_NAME;
|
|
@@ -222,54 +223,6 @@ function pickPresetKeys(source, keys) {
|
|
|
222
223
|
}
|
|
223
224
|
return out;
|
|
224
225
|
}
|
|
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
226
|
function optionalEnvString(value) {
|
|
274
227
|
const text = String(value ?? '').trim();
|
|
275
228
|
return text || undefined;
|
|
@@ -324,7 +277,7 @@ export default class Install extends Command {
|
|
|
324
277
|
'<%= config.bin %> <%= command.id %> --env app1 --root-nickname "Super Admin"',
|
|
325
278
|
'<%= config.bin %> <%= command.id %> --env myenv --app-root-path=./myenv/source/ --storage-path=./myenv/storage/',
|
|
326
279
|
'<%= config.bin %> <%= command.id %> --env dev -y --app-root-path=./dev/source/',
|
|
327
|
-
'<%= config.bin %> <%= command.id %> --env dev -y --
|
|
280
|
+
'<%= config.bin %> <%= command.id %> --env dev -y --skip-download --source git --app-root-path=./dev/source/',
|
|
328
281
|
];
|
|
329
282
|
static flags = {
|
|
330
283
|
yes: Flags.boolean({
|
|
@@ -359,14 +312,20 @@ export default class Install extends Command {
|
|
|
359
312
|
}),
|
|
360
313
|
'auth-type': Flags.string({
|
|
361
314
|
char: 'a',
|
|
362
|
-
description: 'Authentication: token (API key) or oauth (browser login via `nb env auth`)',
|
|
363
|
-
options: ['token', 'oauth'],
|
|
315
|
+
description: 'Authentication: basic (username/password login), token (API key), or oauth (browser login via `nb env auth`)',
|
|
316
|
+
options: ['basic', 'token', 'oauth'],
|
|
364
317
|
}),
|
|
365
318
|
'access-token': Flags.string({
|
|
366
319
|
char: 't',
|
|
367
320
|
aliases: ['token'],
|
|
368
321
|
description: 'API key or access token when using --auth-type token',
|
|
369
322
|
}),
|
|
323
|
+
username: Flags.string({
|
|
324
|
+
description: 'Username when using --auth-type basic',
|
|
325
|
+
}),
|
|
326
|
+
password: Flags.string({
|
|
327
|
+
description: 'Password when using --auth-type basic',
|
|
328
|
+
}),
|
|
370
329
|
'skip-auth': Flags.boolean({
|
|
371
330
|
description: 'Save the env auth mode now and finish authentication later with `nb env auth`',
|
|
372
331
|
default: false,
|
|
@@ -440,8 +399,8 @@ export default class Install extends Command {
|
|
|
440
399
|
description: 'Use underscored database naming for the app',
|
|
441
400
|
default: false,
|
|
442
401
|
}),
|
|
443
|
-
'
|
|
444
|
-
description: '
|
|
402
|
+
'skip-download': Flags.boolean({
|
|
403
|
+
description: 'Skip the download step and reuse an existing local app directory or Docker image',
|
|
445
404
|
default: false,
|
|
446
405
|
}),
|
|
447
406
|
...omitKeys(Download.flags, ['yes']),
|
|
@@ -488,12 +447,6 @@ export default class Install extends Command {
|
|
|
488
447
|
placeholder: installText('prompts.storagePath.placeholder'),
|
|
489
448
|
initialValue: (values) => defaultInstallStoragePath(values.env ?? values.appName),
|
|
490
449
|
},
|
|
491
|
-
fetchSource: {
|
|
492
|
-
type: 'boolean',
|
|
493
|
-
message: installText('prompts.fetchSource.message'),
|
|
494
|
-
initialValue: true,
|
|
495
|
-
yesInitialValue: true,
|
|
496
|
-
},
|
|
497
450
|
};
|
|
498
451
|
static dbPrompts = {
|
|
499
452
|
dbDialect: {
|
|
@@ -521,8 +474,7 @@ export default class Install extends Command {
|
|
|
521
474
|
message: installText('prompts.builtinDbImage.message'),
|
|
522
475
|
placeholder: installText('prompts.builtinDbImage.placeholder'),
|
|
523
476
|
initialValue: (values) => defaultBuiltinDbImageForDialect(values.dbDialect),
|
|
524
|
-
hidden: (values) => !
|
|
525
|
-
|| !supportsBuiltinDbDialect(values.dbDialect),
|
|
477
|
+
hidden: (values) => !values.builtinDb || !supportsBuiltinDbDialect(values.dbDialect),
|
|
526
478
|
required: true,
|
|
527
479
|
},
|
|
528
480
|
dbHost: {
|
|
@@ -542,8 +494,7 @@ export default class Install extends Command {
|
|
|
542
494
|
initialValue: (values) => defaultDbPortForDialect(values.dbDialect),
|
|
543
495
|
required: true,
|
|
544
496
|
validate: Install.validateDbPort,
|
|
545
|
-
hidden: (values) => Boolean(values.builtinDb)
|
|
546
|
-
&& String(values.source ?? '').trim() === 'docker',
|
|
497
|
+
hidden: (values) => Boolean(values.builtinDb) && String(values.source ?? '').trim() === 'docker',
|
|
547
498
|
},
|
|
548
499
|
dbDatabase: {
|
|
549
500
|
type: 'text',
|
|
@@ -568,6 +519,27 @@ export default class Install extends Command {
|
|
|
568
519
|
required: true,
|
|
569
520
|
validate: validateExternalDbPromptField,
|
|
570
521
|
},
|
|
522
|
+
dbSchema: {
|
|
523
|
+
type: 'text',
|
|
524
|
+
message: installText('prompts.dbSchema.message'),
|
|
525
|
+
placeholder: installText('prompts.dbSchema.placeholder'),
|
|
526
|
+
hidden: (values) => String(values.dbDialect ?? '').trim() !== 'postgres',
|
|
527
|
+
},
|
|
528
|
+
dbTablePrefix: {
|
|
529
|
+
type: 'text',
|
|
530
|
+
message: installText('prompts.dbTablePrefix.message'),
|
|
531
|
+
placeholder: installText('prompts.dbTablePrefix.placeholder'),
|
|
532
|
+
},
|
|
533
|
+
dbUnderscored: {
|
|
534
|
+
type: 'boolean',
|
|
535
|
+
message: installText('prompts.dbUnderscored.message'),
|
|
536
|
+
initialValue: false,
|
|
537
|
+
yesInitialValue: false,
|
|
538
|
+
validate: (value, values) => validateExternalDbPromptField(value, {
|
|
539
|
+
...values,
|
|
540
|
+
dbUnderscored: Boolean(value),
|
|
541
|
+
}),
|
|
542
|
+
},
|
|
571
543
|
};
|
|
572
544
|
static rootUserPrompts = {
|
|
573
545
|
rootUsername: {
|
|
@@ -662,9 +634,8 @@ export default class Install extends Command {
|
|
|
662
634
|
* Booleans with defaults are only preset when the user passed the flag on argv (see `download`).
|
|
663
635
|
* Does not include `env` — use {@link buildEnvPresetValuesFromFlags} for {@link Install.envPrompts}.
|
|
664
636
|
*/
|
|
665
|
-
static buildPresetValuesFromFlags(flags) {
|
|
637
|
+
static buildPresetValuesFromFlags(flags, argv = process.argv.slice(2)) {
|
|
666
638
|
const preset = {};
|
|
667
|
-
const argv = process.argv.slice(2);
|
|
668
639
|
const apiBaseUrl = Install.toOptionalPromptString(flags['api-base-url']);
|
|
669
640
|
if (apiBaseUrl) {
|
|
670
641
|
preset.apiBaseUrl = apiBaseUrl;
|
|
@@ -687,6 +658,12 @@ export default class Install extends Command {
|
|
|
687
658
|
if (flags['access-token'] !== undefined || flags.token !== undefined) {
|
|
688
659
|
preset.accessToken = String(flags['access-token'] ?? flags.token ?? '');
|
|
689
660
|
}
|
|
661
|
+
if (flags.username !== undefined) {
|
|
662
|
+
preset.username = String(flags.username ?? '').trim();
|
|
663
|
+
}
|
|
664
|
+
if (flags.password !== undefined) {
|
|
665
|
+
preset.password = String(flags.password ?? '');
|
|
666
|
+
}
|
|
690
667
|
if (flags.lang !== undefined) {
|
|
691
668
|
const v = String(flags.lang).trim();
|
|
692
669
|
if (v) {
|
|
@@ -726,8 +703,15 @@ export default class Install extends Command {
|
|
|
726
703
|
if (flags['root-nickname'] !== undefined) {
|
|
727
704
|
preset.rootNickname = String(flags['root-nickname'] ?? '').trim();
|
|
728
705
|
}
|
|
729
|
-
if (argvHasToken(argv, ['--
|
|
730
|
-
preset.
|
|
706
|
+
if (argvHasToken(argv, ['--skip-download'])) {
|
|
707
|
+
preset.skipDownload = flags['skip-download'];
|
|
708
|
+
if (flags['skip-download']) {
|
|
709
|
+
preset.dockerSave = false;
|
|
710
|
+
preset.replace = false;
|
|
711
|
+
preset.devDependencies = false;
|
|
712
|
+
preset.build = false;
|
|
713
|
+
preset.buildDts = false;
|
|
714
|
+
}
|
|
731
715
|
}
|
|
732
716
|
if (argvHasToken(argv, ['--builtin-db', '--no-builtin-db'])) {
|
|
733
717
|
preset.builtinDb = flags['builtin-db'];
|
|
@@ -789,18 +773,17 @@ export default class Install extends Command {
|
|
|
789
773
|
}
|
|
790
774
|
return preset;
|
|
791
775
|
}
|
|
792
|
-
static buildAppPresetValuesFromFlags(flags) {
|
|
793
|
-
return pickPresetKeys(Install.buildPresetValuesFromFlags(flags), [
|
|
776
|
+
static buildAppPresetValuesFromFlags(flags, argv = process.argv.slice(2)) {
|
|
777
|
+
return pickPresetKeys(Install.buildPresetValuesFromFlags(flags, argv), [
|
|
794
778
|
'lang',
|
|
795
779
|
'force',
|
|
796
780
|
'appRootPath',
|
|
797
781
|
'appPort',
|
|
798
782
|
'storagePath',
|
|
799
|
-
'fetchSource',
|
|
800
783
|
]);
|
|
801
784
|
}
|
|
802
|
-
static buildDbPresetValuesFromFlags(flags) {
|
|
803
|
-
return pickPresetKeys(Install.buildPresetValuesFromFlags(flags), [
|
|
785
|
+
static buildDbPresetValuesFromFlags(flags, argv = process.argv.slice(2)) {
|
|
786
|
+
return pickPresetKeys(Install.buildPresetValuesFromFlags(flags, argv), [
|
|
804
787
|
'builtinDb',
|
|
805
788
|
'dbDialect',
|
|
806
789
|
'builtinDbImage',
|
|
@@ -814,18 +797,20 @@ export default class Install extends Command {
|
|
|
814
797
|
'dbUnderscored',
|
|
815
798
|
]);
|
|
816
799
|
}
|
|
817
|
-
static buildRootPresetValuesFromFlags(flags) {
|
|
818
|
-
return pickPresetKeys(Install.buildPresetValuesFromFlags(flags), [
|
|
800
|
+
static buildRootPresetValuesFromFlags(flags, argv = process.argv.slice(2)) {
|
|
801
|
+
return pickPresetKeys(Install.buildPresetValuesFromFlags(flags, argv), [
|
|
819
802
|
'rootUsername',
|
|
820
803
|
'rootEmail',
|
|
821
804
|
'rootPassword',
|
|
822
805
|
'rootNickname',
|
|
823
806
|
]);
|
|
824
807
|
}
|
|
825
|
-
static buildEnvAddPresetValuesFromFlags(flags) {
|
|
826
|
-
return pickPresetKeys(Install.buildPresetValuesFromFlags(flags), [
|
|
808
|
+
static buildEnvAddPresetValuesFromFlags(flags, argv = process.argv.slice(2)) {
|
|
809
|
+
return pickPresetKeys(Install.buildPresetValuesFromFlags(flags, argv), [
|
|
827
810
|
'apiBaseUrl',
|
|
828
811
|
'authType',
|
|
812
|
+
'username',
|
|
813
|
+
'password',
|
|
829
814
|
'accessToken',
|
|
830
815
|
]);
|
|
831
816
|
}
|
|
@@ -915,9 +900,13 @@ export default class Install extends Command {
|
|
|
915
900
|
if (validationError) {
|
|
916
901
|
throw new Error(validationError);
|
|
917
902
|
}
|
|
903
|
+
const compatibilityError = await validateMysqlLowerCaseTableNamesCompatibility(dbResults);
|
|
904
|
+
if (compatibilityError) {
|
|
905
|
+
throw new Error(compatibilityError);
|
|
906
|
+
}
|
|
918
907
|
}
|
|
919
908
|
static async readResumePortValidationContext(values) {
|
|
920
|
-
if (!
|
|
909
|
+
if (!values.resume) {
|
|
921
910
|
return undefined;
|
|
922
911
|
}
|
|
923
912
|
const envName = Install.toOptionalPromptString(values.env);
|
|
@@ -948,8 +937,7 @@ export default class Install extends Command {
|
|
|
948
937
|
}
|
|
949
938
|
static async isResumeManagedPortReuse(params) {
|
|
950
939
|
if (params.target === 'app') {
|
|
951
|
-
if ((params.context.source === 'npm' || params.context.source === 'git')
|
|
952
|
-
&& params.context.appRootPath) {
|
|
940
|
+
if ((params.context.source === 'npm' || params.context.source === 'git') && params.context.appRootPath) {
|
|
953
941
|
return await Install.isLocalPm2ProcessUsingPort(params.context.appRootPath, params.port);
|
|
954
942
|
}
|
|
955
943
|
const containerName = Install.buildDockerAppContainerName(params.context.envName, params.context.dockerContainerPrefix);
|
|
@@ -965,19 +953,13 @@ export default class Install extends Command {
|
|
|
965
953
|
if (!containerName || !port) {
|
|
966
954
|
return false;
|
|
967
955
|
}
|
|
968
|
-
const exists = await commandSucceeds('docker', [
|
|
969
|
-
'container',
|
|
970
|
-
'inspect',
|
|
971
|
-
containerName,
|
|
972
|
-
]);
|
|
956
|
+
const exists = await commandSucceeds('docker', ['container', 'inspect', containerName]);
|
|
973
957
|
if (!exists) {
|
|
974
958
|
return false;
|
|
975
959
|
}
|
|
976
960
|
try {
|
|
977
961
|
const output = await commandOutput('docker', ['port', containerName]);
|
|
978
|
-
return output
|
|
979
|
-
.split(/\r?\n/)
|
|
980
|
-
.some((line) => line.includes(`:${port}`));
|
|
962
|
+
return output.split(/\r?\n/).some((line) => line.includes(`:${port}`));
|
|
981
963
|
}
|
|
982
964
|
catch {
|
|
983
965
|
return false;
|
|
@@ -1033,29 +1015,20 @@ export default class Install extends Command {
|
|
|
1033
1015
|
...(appRootPath ? { appRootPath } : {}),
|
|
1034
1016
|
...(appPort ? { appPort } : {}),
|
|
1035
1017
|
...(storagePath ? { storagePath } : {}),
|
|
1036
|
-
...(source
|
|
1037
|
-
? { fetchSource: true }
|
|
1038
|
-
: appRootPath
|
|
1039
|
-
? { fetchSource: false }
|
|
1040
|
-
: {}),
|
|
1041
1018
|
};
|
|
1042
1019
|
const downloadPreset = {
|
|
1043
1020
|
...(source ? { source } : {}),
|
|
1044
1021
|
...(downloadVersion
|
|
1045
1022
|
? {
|
|
1046
1023
|
version: downloadVersionPromptValue(downloadVersion),
|
|
1047
|
-
...(downloadVersionPromptValue(downloadVersion) === 'other'
|
|
1048
|
-
? { otherVersion: downloadVersion }
|
|
1049
|
-
: {}),
|
|
1024
|
+
...(downloadVersionPromptValue(downloadVersion) === 'other' ? { otherVersion: downloadVersion } : {}),
|
|
1050
1025
|
}
|
|
1051
1026
|
: {}),
|
|
1052
1027
|
...(dockerRegistry ? { dockerRegistry } : {}),
|
|
1053
1028
|
...(dockerPlatform ? { dockerPlatform } : {}),
|
|
1054
1029
|
...(gitUrl ? { gitUrl } : {}),
|
|
1055
1030
|
...(npmRegistry ? { npmRegistry } : {}),
|
|
1056
|
-
...(typeof config.devDependencies === 'boolean'
|
|
1057
|
-
? { devDependencies: config.devDependencies }
|
|
1058
|
-
: {}),
|
|
1031
|
+
...(typeof config.devDependencies === 'boolean' ? { devDependencies: config.devDependencies } : {}),
|
|
1059
1032
|
...(typeof config.build === 'boolean' ? { build: config.build } : {}),
|
|
1060
1033
|
...(typeof config.buildDts === 'boolean' ? { buildDts: config.buildDts } : {}),
|
|
1061
1034
|
};
|
|
@@ -1085,6 +1058,13 @@ export default class Install extends Command {
|
|
|
1085
1058
|
envAddPreset.accessToken = String(auth.accessToken);
|
|
1086
1059
|
}
|
|
1087
1060
|
}
|
|
1061
|
+
else if (savedAuthType === 'basic') {
|
|
1062
|
+
envAddPreset.authType = 'basic';
|
|
1063
|
+
const authUsername = Install.toOptionalPromptString(config.authUsername) ?? rootUsername;
|
|
1064
|
+
if (authUsername) {
|
|
1065
|
+
envAddPreset.username = authUsername;
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1088
1068
|
else if (savedAuthType === 'oauth') {
|
|
1089
1069
|
envAddPreset.authType = 'oauth';
|
|
1090
1070
|
}
|
|
@@ -1169,8 +1149,7 @@ export default class Install extends Command {
|
|
|
1169
1149
|
}
|
|
1170
1150
|
static shouldPublishBuiltinDbPortForValues(values) {
|
|
1171
1151
|
const builtinDb = values.builtinDb === undefined ? true : Boolean(values.builtinDb);
|
|
1172
|
-
return builtinDb
|
|
1173
|
-
&& Install.shouldPublishBuiltinDbPort(values.source);
|
|
1152
|
+
return builtinDb && Install.shouldPublishBuiltinDbPort(values.source);
|
|
1174
1153
|
}
|
|
1175
1154
|
static async buildDbPromptInitialValues(params) {
|
|
1176
1155
|
if (params.flags['db-port'] !== undefined) {
|
|
@@ -1226,9 +1205,8 @@ export default class Install extends Command {
|
|
|
1226
1205
|
* Resolve the effective preset `values` for the embedded download step.
|
|
1227
1206
|
* Explicit download flags win; otherwise `-y` falls back to the docker + alpha quickstart path.
|
|
1228
1207
|
*/
|
|
1229
|
-
static buildDownloadPresetValuesForInstall(flags, appResults, envName, yes) {
|
|
1208
|
+
static buildDownloadPresetValuesForInstall(flags, appResults, envName, yes, argv = process.argv.slice(2)) {
|
|
1230
1209
|
const preset = {};
|
|
1231
|
-
const argv = process.argv.slice(2);
|
|
1232
1210
|
const appRoot = String(appResults.appRootPath ?? '').trim() || defaultInstallAppRootPath(envName);
|
|
1233
1211
|
const lang = String(appResults.lang ?? DEFAULT_INSTALL_LANG).trim() || DEFAULT_INSTALL_LANG;
|
|
1234
1212
|
preset.lang = lang;
|
|
@@ -1267,8 +1245,7 @@ export default class Install extends Command {
|
|
|
1267
1245
|
}
|
|
1268
1246
|
}
|
|
1269
1247
|
if (flags['npm-registry'] !== undefined) {
|
|
1270
|
-
preset.npmRegistry =
|
|
1271
|
-
typeof flags['npm-registry'] === 'string' ? flags['npm-registry'] : '';
|
|
1248
|
+
preset.npmRegistry = typeof flags['npm-registry'] === 'string' ? flags['npm-registry'] : '';
|
|
1272
1249
|
}
|
|
1273
1250
|
if (flags.resume && !argvHasToken(argv, ['--replace', '-r'])) {
|
|
1274
1251
|
preset.replace = true;
|
|
@@ -1312,15 +1289,11 @@ export default class Install extends Command {
|
|
|
1312
1289
|
}
|
|
1313
1290
|
static buildBuiltinDbContainerPrefix(containerPrefix) {
|
|
1314
1291
|
const storedName = String(containerPrefix ?? '').trim();
|
|
1315
|
-
return storedName
|
|
1316
|
-
? Install.sanitizeDockerResourceName(storedName)
|
|
1317
|
-
: Install.defaultDockerContainerPrefix();
|
|
1292
|
+
return storedName ? Install.sanitizeDockerResourceName(storedName) : Install.defaultDockerContainerPrefix();
|
|
1318
1293
|
}
|
|
1319
1294
|
static buildManagedDockerNetworkName(networkName) {
|
|
1320
1295
|
const storedName = String(networkName ?? '').trim();
|
|
1321
|
-
return storedName
|
|
1322
|
-
? Install.sanitizeDockerResourceName(storedName)
|
|
1323
|
-
: Install.defaultDockerNetworkName();
|
|
1296
|
+
return storedName ? Install.sanitizeDockerResourceName(storedName) : Install.defaultDockerNetworkName();
|
|
1324
1297
|
}
|
|
1325
1298
|
static buildBuiltinDbNetworkName(envName, networkName) {
|
|
1326
1299
|
void envName;
|
|
@@ -1353,25 +1326,19 @@ export default class Install extends Command {
|
|
|
1353
1326
|
}
|
|
1354
1327
|
static buildBuiltinDbPlan(params) {
|
|
1355
1328
|
const dbDialect = String(params.dbDialect ?? 'postgres').trim() || 'postgres';
|
|
1356
|
-
const dbPort = String(params.dbPort ?? defaultDbPortForDialect(dbDialect)).trim()
|
|
1357
|
-
|| defaultDbPortForDialect(dbDialect);
|
|
1329
|
+
const dbPort = String(params.dbPort ?? defaultDbPortForDialect(dbDialect)).trim() || defaultDbPortForDialect(dbDialect);
|
|
1358
1330
|
const defaultDbDatabase = defaultDbDatabaseForDialect(dbDialect);
|
|
1359
1331
|
const networkName = Install.buildBuiltinDbNetworkName(params.envName, params.dockerNetworkName ?? params.workspaceName);
|
|
1360
1332
|
const containerName = Install.buildBuiltinDbContainerName(params.envName, dbDialect, params.dockerContainerPrefix ?? params.workspaceName);
|
|
1361
1333
|
const dbHostInput = String(params.dbHost ?? '').trim();
|
|
1362
1334
|
const dbHost = Install.shouldPublishBuiltinDbPort(params.source)
|
|
1363
|
-
?
|
|
1364
|
-
&& dbHostInput !== DEFAULT_INSTALL_BUILTIN_DB_HOST
|
|
1365
|
-
&& dbHostInput !== containerName
|
|
1335
|
+
? dbHostInput && dbHostInput !== DEFAULT_INSTALL_BUILTIN_DB_HOST && dbHostInput !== containerName
|
|
1366
1336
|
? dbHostInput
|
|
1367
|
-
: DEFAULT_INSTALL_DB_HOST
|
|
1368
|
-
:
|
|
1369
|
-
&& dbHostInput !== DEFAULT_INSTALL_DB_HOST
|
|
1370
|
-
&& dbHostInput !== 'localhost'
|
|
1337
|
+
: DEFAULT_INSTALL_DB_HOST
|
|
1338
|
+
: dbHostInput && dbHostInput !== DEFAULT_INSTALL_DB_HOST && dbHostInput !== 'localhost'
|
|
1371
1339
|
? dbHostInput
|
|
1372
|
-
: containerName
|
|
1373
|
-
const storagePath = resolveConfiguredEnvPath(params.storagePath)
|
|
1374
|
-
?? resolveEnvRelativePath(defaultInstallStoragePath(params.envName));
|
|
1340
|
+
: containerName;
|
|
1341
|
+
const storagePath = resolveConfiguredEnvPath(params.storagePath) ?? resolveEnvRelativePath(defaultInstallStoragePath(params.envName));
|
|
1375
1342
|
if (dbDialect === 'postgres') {
|
|
1376
1343
|
const image = String(params.builtinDbImage ?? '').trim() || defaultBuiltinDbImageForDialect(dbDialect);
|
|
1377
1344
|
const dataDir = path.resolve(storagePath, 'db', 'postgres');
|
|
@@ -1402,12 +1369,9 @@ export default class Install extends Command {
|
|
|
1402
1369
|
dbDialect,
|
|
1403
1370
|
dbHost,
|
|
1404
1371
|
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,
|
|
1372
|
+
dbDatabase: String(params.dbDatabase ?? defaultDbDatabase).trim() || defaultDbDatabase,
|
|
1373
|
+
dbUser: String(params.dbUser ?? DEFAULT_INSTALL_DB_USER).trim() || DEFAULT_INSTALL_DB_USER,
|
|
1374
|
+
dbPassword: String(params.dbPassword ?? DEFAULT_INSTALL_DB_PASSWORD) || DEFAULT_INSTALL_DB_PASSWORD,
|
|
1411
1375
|
networkName,
|
|
1412
1376
|
containerName,
|
|
1413
1377
|
dataDir,
|
|
@@ -1593,11 +1557,7 @@ export default class Install extends Command {
|
|
|
1593
1557
|
}
|
|
1594
1558
|
}
|
|
1595
1559
|
async dockerContainerExists(name) {
|
|
1596
|
-
return await commandSucceeds('docker', [
|
|
1597
|
-
'container',
|
|
1598
|
-
'inspect',
|
|
1599
|
-
name,
|
|
1600
|
-
]);
|
|
1560
|
+
return await commandSucceeds('docker', ['container', 'inspect', name]);
|
|
1601
1561
|
}
|
|
1602
1562
|
async removeDockerContainer(name) {
|
|
1603
1563
|
await run('docker', ['rm', '-f', name], {
|
|
@@ -1647,8 +1607,7 @@ export default class Install extends Command {
|
|
|
1647
1607
|
});
|
|
1648
1608
|
}
|
|
1649
1609
|
async startBuiltinDb(params) {
|
|
1650
|
-
const storagePath = String(params.appResults.storagePath ?? '').trim()
|
|
1651
|
-
|| defaultInstallStoragePath(params.envName);
|
|
1610
|
+
const storagePath = String(params.appResults.storagePath ?? '').trim() || defaultInstallStoragePath(params.envName);
|
|
1652
1611
|
const plan = Install.buildBuiltinDbPlan({
|
|
1653
1612
|
envName: params.envName,
|
|
1654
1613
|
workspaceName: params.workspaceName,
|
|
@@ -1686,23 +1645,20 @@ export default class Install extends Command {
|
|
|
1686
1645
|
return plan;
|
|
1687
1646
|
}
|
|
1688
1647
|
static async buildDockerAppPlan(params) {
|
|
1689
|
-
const dockerRegistry = String(downloadResultsValue(params.downloadResults, 'dockerRegistry') ?? '').trim()
|
|
1690
|
-
|
|
1648
|
+
const dockerRegistry = String(downloadResultsValue(params.downloadResults, 'dockerRegistry') ?? '').trim() ||
|
|
1649
|
+
defaultDockerRegistryForLang(process.env.NB_LOCALE);
|
|
1691
1650
|
const version = String(downloadResultsValue(params.downloadResults, 'version') ?? '').trim() || DEFAULT_DOCKER_VERSION;
|
|
1692
1651
|
const imageRef = resolveDockerImageRef(dockerRegistry, version, {
|
|
1693
1652
|
defaultRegistry: defaultDockerRegistryForLang(process.env.NB_LOCALE),
|
|
1694
1653
|
defaultVersion: DEFAULT_DOCKER_VERSION,
|
|
1695
1654
|
});
|
|
1696
1655
|
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));
|
|
1656
|
+
const storagePath = resolveConfiguredEnvPath(String(params.appResults.storagePath ?? '').trim() || defaultInstallStoragePath(params.envName)) ?? resolveEnvRelativePath(defaultInstallStoragePath(params.envName));
|
|
1700
1657
|
const dbDialect = String(params.dbResults.dbDialect ?? 'postgres').trim() || 'postgres';
|
|
1701
1658
|
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;
|
|
1659
|
+
const dbPort = String(params.dbResults.dbPort ?? defaultDbPortForDialect(dbDialect)).trim() ||
|
|
1660
|
+
defaultDbPortForDialect(dbDialect);
|
|
1661
|
+
const dbDatabase = String(params.dbResults.dbDatabase ?? DEFAULT_INSTALL_DB_DATABASE).trim() || DEFAULT_INSTALL_DB_DATABASE;
|
|
1706
1662
|
const dbUser = String(params.dbResults.dbUser ?? DEFAULT_INSTALL_DB_USER).trim() || DEFAULT_INSTALL_DB_USER;
|
|
1707
1663
|
const dbPassword = String(params.dbResults.dbPassword ?? DEFAULT_INSTALL_DB_PASSWORD) || DEFAULT_INSTALL_DB_PASSWORD;
|
|
1708
1664
|
const dbSchema = optionalEnvString(params.dbResults.dbSchema);
|
|
@@ -1767,8 +1723,8 @@ export default class Install extends Command {
|
|
|
1767
1723
|
return 'created';
|
|
1768
1724
|
}
|
|
1769
1725
|
async installDockerApp(params) {
|
|
1770
|
-
const networkName = params.builtinDbPlan?.networkName
|
|
1771
|
-
|
|
1726
|
+
const networkName = params.builtinDbPlan?.networkName ??
|
|
1727
|
+
Install.buildBuiltinDbNetworkName(params.envName, params.dockerNetworkName ?? params.workspaceName);
|
|
1772
1728
|
await this.ensureDockerNetwork(networkName);
|
|
1773
1729
|
const plan = await Install.buildDockerAppPlan({
|
|
1774
1730
|
envName: params.envName,
|
|
@@ -1815,26 +1771,26 @@ export default class Install extends Command {
|
|
|
1815
1771
|
Install.pushDownloadArgIfValue(argv, '--source', results.source);
|
|
1816
1772
|
Install.pushDownloadArgIfValue(argv, '--version', downloadResultsValue(results, 'version'));
|
|
1817
1773
|
Install.pushDownloadArgIfValue(argv, '--output-dir', source === 'npm' || source === 'git'
|
|
1818
|
-
?
|
|
1819
|
-
|
|
1774
|
+
? resolveConfiguredEnvPath(results.outputDir) ??
|
|
1775
|
+
resolveConfiguredEnvPath(String(results.outputDir ?? '').trim() || defaultInstallAppRootPath(results.env))
|
|
1820
1776
|
: results.outputDir);
|
|
1821
1777
|
Install.pushDownloadArgIfValue(argv, '--git-url', results.gitUrl);
|
|
1822
1778
|
Install.pushDownloadArgIfValue(argv, '--docker-registry', results.dockerRegistry);
|
|
1823
1779
|
Install.pushDownloadArgIfValue(argv, '--docker-platform', results.dockerPlatform);
|
|
1824
1780
|
Install.pushDownloadArgIfValue(argv, '--npm-registry', results.npmRegistry);
|
|
1825
|
-
if (
|
|
1781
|
+
if (results.replace) {
|
|
1826
1782
|
argv.push('--replace');
|
|
1827
1783
|
}
|
|
1828
|
-
if (
|
|
1784
|
+
if (results.devDependencies) {
|
|
1829
1785
|
argv.push('--dev-dependencies');
|
|
1830
1786
|
}
|
|
1831
|
-
if (
|
|
1787
|
+
if (results.dockerSave) {
|
|
1832
1788
|
argv.push('--docker-save');
|
|
1833
1789
|
}
|
|
1834
|
-
if (results.build !== undefined && !
|
|
1790
|
+
if (results.build !== undefined && !results.build) {
|
|
1835
1791
|
argv.push('--no-build');
|
|
1836
1792
|
}
|
|
1837
|
-
if (
|
|
1793
|
+
if (results.buildDts) {
|
|
1838
1794
|
argv.push('--build-dts');
|
|
1839
1795
|
}
|
|
1840
1796
|
return argv;
|
|
@@ -1844,15 +1800,26 @@ export default class Install extends Command {
|
|
|
1844
1800
|
if (projectRoot) {
|
|
1845
1801
|
return projectRoot;
|
|
1846
1802
|
}
|
|
1847
|
-
const outputDir = String(params.downloadResults.outputDir ?? '').trim()
|
|
1848
|
-
|
|
1849
|
-
|
|
1803
|
+
const outputDir = String(params.downloadResults.outputDir ?? '').trim() ||
|
|
1804
|
+
String(params.appResults.appRootPath ?? '').trim() ||
|
|
1805
|
+
defaultInstallAppRootPath(params.envName);
|
|
1850
1806
|
return resolveConfiguredEnvPath(outputDir) ?? resolveEnvRelativePath(defaultInstallAppRootPath(params.envName));
|
|
1851
1807
|
}
|
|
1852
1808
|
static resolveLocalProjectConfigPath(params) {
|
|
1853
|
-
return (String(params.downloadResults.outputDir ?? '').trim()
|
|
1854
|
-
|
|
1855
|
-
|
|
1809
|
+
return (String(params.downloadResults.outputDir ?? '').trim() ||
|
|
1810
|
+
String(params.appResults.appRootPath ?? '').trim() ||
|
|
1811
|
+
defaultInstallAppRootPath(params.envName));
|
|
1812
|
+
}
|
|
1813
|
+
static buildSkipDownloadValues(envName, appResults) {
|
|
1814
|
+
const appRoot = String(appResults.appRootPath ?? '').trim() || defaultInstallAppRootPath(envName);
|
|
1815
|
+
return {
|
|
1816
|
+
outputDir: appRoot,
|
|
1817
|
+
replace: false,
|
|
1818
|
+
dockerSave: false,
|
|
1819
|
+
devDependencies: false,
|
|
1820
|
+
build: false,
|
|
1821
|
+
buildDts: false,
|
|
1822
|
+
};
|
|
1856
1823
|
}
|
|
1857
1824
|
commandStdio(verbose) {
|
|
1858
1825
|
return verbose ? 'inherit' : 'ignore';
|
|
@@ -1862,7 +1829,41 @@ export default class Install extends Command {
|
|
|
1862
1829
|
verbose: params.verbose,
|
|
1863
1830
|
compactLog: true,
|
|
1864
1831
|
});
|
|
1865
|
-
return await this.config.runCommand('source:download', argv);
|
|
1832
|
+
return (await this.config.runCommand('source:download', argv));
|
|
1833
|
+
}
|
|
1834
|
+
async ensureSkippedDownloadInputsReady(params) {
|
|
1835
|
+
if (params.source === 'docker') {
|
|
1836
|
+
const dockerRegistry = String(downloadResultsValue(params.downloadResults, 'dockerRegistry') ?? '').trim() ||
|
|
1837
|
+
defaultDockerRegistryForLang(process.env.NB_LOCALE);
|
|
1838
|
+
const version = String(downloadResultsValue(params.downloadResults, 'version') ?? '').trim() || DEFAULT_DOCKER_VERSION;
|
|
1839
|
+
const imageRef = resolveDockerImageRef(dockerRegistry, version, {
|
|
1840
|
+
defaultRegistry: defaultDockerRegistryForLang(process.env.NB_LOCALE),
|
|
1841
|
+
defaultVersion: DEFAULT_DOCKER_VERSION,
|
|
1842
|
+
});
|
|
1843
|
+
const imageExists = await commandSucceeds('docker', ['image', 'inspect', imageRef]);
|
|
1844
|
+
if (!imageExists) {
|
|
1845
|
+
throw new Error(translateCli('commands.install.messages.skipDownloadDockerImageMissing', {
|
|
1846
|
+
imageRef,
|
|
1847
|
+
}));
|
|
1848
|
+
}
|
|
1849
|
+
return;
|
|
1850
|
+
}
|
|
1851
|
+
if (params.source === 'npm' || params.source === 'git') {
|
|
1852
|
+
const projectRoot = Install.resolveLocalProjectRoot({
|
|
1853
|
+
envName: params.envName,
|
|
1854
|
+
appResults: params.appResults,
|
|
1855
|
+
downloadResults: params.downloadResults,
|
|
1856
|
+
});
|
|
1857
|
+
try {
|
|
1858
|
+
await access(projectRoot);
|
|
1859
|
+
await access(path.join(projectRoot, 'package.json'));
|
|
1860
|
+
}
|
|
1861
|
+
catch {
|
|
1862
|
+
throw new Error(translateCli('commands.install.messages.skipDownloadLocalAppMissing', {
|
|
1863
|
+
projectRoot,
|
|
1864
|
+
}));
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1866
1867
|
}
|
|
1867
1868
|
async downloadLocalApp(params) {
|
|
1868
1869
|
const result = await this.downloadManagedSource({
|
|
@@ -1883,31 +1884,24 @@ export default class Install extends Command {
|
|
|
1883
1884
|
return downloadedProjectRoot;
|
|
1884
1885
|
}
|
|
1885
1886
|
static buildLocalAppEnvVars(params) {
|
|
1886
|
-
const configuredStoragePath = String(params.appResults.storagePath ?? '').trim()
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
const dbDialect = String(params.dbResults.dbDialect ?? 'postgres').trim()
|
|
1891
|
-
|| 'postgres';
|
|
1887
|
+
const configuredStoragePath = String(params.appResults.storagePath ?? '').trim() || defaultInstallStoragePath(params.envName);
|
|
1888
|
+
const storagePath = resolveConfiguredEnvPath(configuredStoragePath) ??
|
|
1889
|
+
resolveEnvRelativePath(defaultInstallStoragePath(params.envName));
|
|
1890
|
+
const dbDialect = String(params.dbResults.dbDialect ?? 'postgres').trim() || 'postgres';
|
|
1892
1891
|
const appKey = crypto.randomBytes(32).toString('hex');
|
|
1893
1892
|
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC';
|
|
1894
1893
|
const env = {
|
|
1895
1894
|
STORAGE_PATH: storagePath,
|
|
1896
|
-
APP_PORT: String(params.appResults.appPort ?? DEFAULT_INSTALL_APP_PORT).trim()
|
|
1897
|
-
|| DEFAULT_INSTALL_APP_PORT,
|
|
1895
|
+
APP_PORT: String(params.appResults.appPort ?? DEFAULT_INSTALL_APP_PORT).trim() || DEFAULT_INSTALL_APP_PORT,
|
|
1898
1896
|
APP_KEY: appKey,
|
|
1899
1897
|
TZ: timeZone,
|
|
1900
1898
|
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,
|
|
1899
|
+
DB_HOST: String(params.dbResults.dbHost ?? DEFAULT_INSTALL_DB_HOST).trim() || DEFAULT_INSTALL_DB_HOST,
|
|
1900
|
+
DB_PORT: String(params.dbResults.dbPort ?? defaultDbPortForDialect(dbDialect)).trim() ||
|
|
1901
|
+
defaultDbPortForDialect(dbDialect),
|
|
1902
|
+
DB_DATABASE: String(params.dbResults.dbDatabase ?? DEFAULT_INSTALL_DB_DATABASE).trim() || DEFAULT_INSTALL_DB_DATABASE,
|
|
1903
|
+
DB_USER: String(params.dbResults.dbUser ?? DEFAULT_INSTALL_DB_USER).trim() || DEFAULT_INSTALL_DB_USER,
|
|
1904
|
+
DB_PASSWORD: String(params.dbResults.dbPassword ?? DEFAULT_INSTALL_DB_PASSWORD) || DEFAULT_INSTALL_DB_PASSWORD,
|
|
1911
1905
|
...Install.buildInitAppEnvVars({
|
|
1912
1906
|
appResults: params.appResults,
|
|
1913
1907
|
rootResults: params.rootResults,
|
|
@@ -1957,10 +1951,8 @@ export default class Install extends Command {
|
|
|
1957
1951
|
};
|
|
1958
1952
|
}
|
|
1959
1953
|
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`);
|
|
1954
|
+
const appPort = String(params.appResults.appPort ?? DEFAULT_INSTALL_APP_PORT).trim() || DEFAULT_INSTALL_APP_PORT;
|
|
1955
|
+
return String(params.envAddResults.apiBaseUrl ?? '').trim() || `http://127.0.0.1:${appPort}/api`;
|
|
1964
1956
|
}
|
|
1965
1957
|
static buildHealthCheckUrl(apiBaseUrl) {
|
|
1966
1958
|
return `${apiBaseUrl.replace(/\/+$/, '')}/__health_check`;
|
|
@@ -1989,9 +1981,7 @@ export default class Install extends Command {
|
|
|
1989
1981
|
const body = Install.formatHealthCheckMessage(text);
|
|
1990
1982
|
return {
|
|
1991
1983
|
ok: response.ok && text.trim().toLowerCase() === 'ok',
|
|
1992
|
-
message: response.ok
|
|
1993
|
-
? `HTTP ${response.status}: ${body}`
|
|
1994
|
-
: `HTTP ${response.status}: ${body}`,
|
|
1984
|
+
message: response.ok ? `HTTP ${response.status}: ${body}` : `HTTP ${response.status}: ${body}`,
|
|
1995
1985
|
};
|
|
1996
1986
|
}
|
|
1997
1987
|
catch (error) {
|
|
@@ -2055,8 +2045,7 @@ export default class Install extends Command {
|
|
|
2055
2045
|
if (!params.appReady) {
|
|
2056
2046
|
return;
|
|
2057
2047
|
}
|
|
2058
|
-
const authType = String(params.envAddResults.authType ?? 'oauth').trim()
|
|
2059
|
-
|| 'oauth';
|
|
2048
|
+
const authType = String(params.envAddResults.authType ?? 'oauth').trim() || 'oauth';
|
|
2060
2049
|
if (params.skipAuth) {
|
|
2061
2050
|
printInfo(formatDeferredAuthMessage(params.envName, authType));
|
|
2062
2051
|
return;
|
|
@@ -2064,23 +2053,34 @@ export default class Install extends Command {
|
|
|
2064
2053
|
if (authType === 'oauth') {
|
|
2065
2054
|
await this.config.runCommand('env:auth', [params.envName]);
|
|
2066
2055
|
}
|
|
2056
|
+
else if (authType === 'basic') {
|
|
2057
|
+
const authArgv = [params.envName, '--auth-type', 'basic'];
|
|
2058
|
+
const username = String(params.envAddResults.username ?? '').trim();
|
|
2059
|
+
const password = String(params.envAddResults.password ?? '');
|
|
2060
|
+
if (username) {
|
|
2061
|
+
authArgv.push('--username', username);
|
|
2062
|
+
}
|
|
2063
|
+
if (password) {
|
|
2064
|
+
authArgv.push('--password', password);
|
|
2065
|
+
}
|
|
2066
|
+
await this.config.runCommand('env:auth', authArgv);
|
|
2067
|
+
}
|
|
2067
2068
|
await this.config.runCommand('env:update', [params.envName]);
|
|
2068
2069
|
}
|
|
2069
2070
|
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);
|
|
2071
|
+
const appPort = String(params.appResults.appPort ?? DEFAULT_INSTALL_APP_PORT).trim() || DEFAULT_INSTALL_APP_PORT;
|
|
2072
|
+
const storagePath = String(params.appResults.storagePath ?? '').trim() || defaultInstallStoragePath(params.envName);
|
|
2074
2073
|
const envFile = String(params.appResults.envFile ?? '').trim() || undefined;
|
|
2075
2074
|
const apiBaseUrl = Install.resolveApiBaseUrl({
|
|
2076
2075
|
appResults: params.appResults,
|
|
2077
2076
|
envAddResults: params.envAddResults,
|
|
2078
2077
|
});
|
|
2079
|
-
const authType = String(params.envAddResults.authType ?? 'oauth').trim()
|
|
2080
|
-
|
|
2078
|
+
const authType = String(params.envAddResults.authType ?? 'oauth').trim() || 'oauth';
|
|
2079
|
+
const authUsername = authType === 'basic' ? String(params.envAddResults.username ?? params.rootResults.rootUsername ?? '').trim() : '';
|
|
2081
2080
|
return buildStoredEnvConfig({
|
|
2082
2081
|
apiBaseUrl,
|
|
2083
2082
|
authType,
|
|
2083
|
+
...(authUsername ? { authUsername } : {}),
|
|
2084
2084
|
accessToken: params.envAddResults.accessToken,
|
|
2085
2085
|
source: downloadResultsValue(params.downloadResults, 'source'),
|
|
2086
2086
|
downloadVersion: downloadResultsValue(params.downloadResults, 'version'),
|
|
@@ -2115,6 +2115,7 @@ export default class Install extends Command {
|
|
|
2115
2115
|
});
|
|
2116
2116
|
}
|
|
2117
2117
|
async collectPromptResults(parsed, yes) {
|
|
2118
|
+
const commandArgv = this.argv ?? process.argv.slice(2);
|
|
2118
2119
|
const resumePreset = await this.resolveResumePresetValues(parsed, yes);
|
|
2119
2120
|
const envPreset = {
|
|
2120
2121
|
...(resumePreset?.envPreset ?? {}),
|
|
@@ -2130,7 +2131,7 @@ export default class Install extends Command {
|
|
|
2130
2131
|
const envName = String(envResults.env ?? '').trim() || DEFAULT_INSTALL_ENV_NAME;
|
|
2131
2132
|
const appPreset = {
|
|
2132
2133
|
...(resumePreset?.appPreset ?? {}),
|
|
2133
|
-
...Install.buildAppPresetValuesFromFlags(parsed),
|
|
2134
|
+
...Install.buildAppPresetValuesFromFlags(parsed, commandArgv),
|
|
2134
2135
|
};
|
|
2135
2136
|
const appCatalog = Install.buildAppPromptsCatalog(envName, {
|
|
2136
2137
|
resume: parsed.resume,
|
|
@@ -2140,56 +2141,58 @@ export default class Install extends Command {
|
|
|
2140
2141
|
envName,
|
|
2141
2142
|
flags: {
|
|
2142
2143
|
...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),
|
|
2144
|
+
'app-root-path': parsed['app-root-path'] ?? Install.toOptionalPromptString(appPreset.appRootPath),
|
|
2145
|
+
'app-port': parsed['app-port'] ?? Install.toOptionalPromptString(appPreset.appPort),
|
|
2146
|
+
'storage-path': parsed['storage-path'] ?? Install.toOptionalPromptString(appPreset.storagePath),
|
|
2149
2147
|
},
|
|
2150
2148
|
}),
|
|
2151
2149
|
values: appPreset,
|
|
2152
2150
|
yesInitialValues: { resume: parsed.resume },
|
|
2153
2151
|
yes,
|
|
2154
2152
|
});
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
downloadOpts.values
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2153
|
+
const downloadOpts = Install.buildDownloadPromptOptionsForInstall(appResults, envName);
|
|
2154
|
+
downloadOpts.values = {
|
|
2155
|
+
...(resumePreset?.downloadPreset ?? {}),
|
|
2156
|
+
...downloadOpts.values,
|
|
2157
|
+
...Install.buildDownloadPresetValuesForInstall(parsed, appResults, envName, yes, commandArgv),
|
|
2158
|
+
...(parsed['skip-download'] ? Install.buildSkipDownloadValues(envName, appResults) : {}),
|
|
2159
|
+
};
|
|
2160
|
+
downloadOpts.yes = yes;
|
|
2161
|
+
const downloadResults = await runPromptCatalog(Download.prompts, downloadOpts);
|
|
2162
|
+
if (parsed['skip-download']) {
|
|
2163
|
+
delete downloadResults.outputDir;
|
|
2164
|
+
delete downloadResults.replace;
|
|
2165
|
+
delete downloadResults.dockerSave;
|
|
2166
|
+
delete downloadResults.devDependencies;
|
|
2167
|
+
delete downloadResults.build;
|
|
2168
|
+
delete downloadResults.buildDts;
|
|
2165
2169
|
}
|
|
2166
2170
|
const dbPreset = {
|
|
2167
2171
|
...(resumePreset?.dbPreset ?? {}),
|
|
2168
|
-
...Install.buildDbPresetValuesFromFlags(parsed),
|
|
2172
|
+
...Install.buildDbPresetValuesFromFlags(parsed, commandArgv),
|
|
2169
2173
|
};
|
|
2170
2174
|
const promptedDbResults = await runPromptCatalog(Install.buildDbPromptsCatalog(envName, downloadResults, {
|
|
2171
2175
|
resume: parsed.resume,
|
|
2172
2176
|
}), {
|
|
2173
2177
|
initialValues: {
|
|
2174
2178
|
...downloadResults,
|
|
2175
|
-
...await Install.buildDbPromptInitialValues({
|
|
2179
|
+
...(await Install.buildDbPromptInitialValues({
|
|
2176
2180
|
flags: {
|
|
2177
2181
|
...parsed,
|
|
2178
|
-
'db-port': parsed['db-port']
|
|
2179
|
-
?? Install.toOptionalPromptString(dbPreset.dbPort),
|
|
2182
|
+
'db-port': parsed['db-port'] ?? Install.toOptionalPromptString(dbPreset.dbPort),
|
|
2180
2183
|
},
|
|
2181
2184
|
downloadResults,
|
|
2182
2185
|
dbPreset,
|
|
2183
|
-
}),
|
|
2186
|
+
})),
|
|
2184
2187
|
},
|
|
2185
2188
|
values: dbPreset,
|
|
2186
2189
|
yes,
|
|
2187
2190
|
});
|
|
2188
2191
|
const dbResults = {
|
|
2189
|
-
...promptedDbResults,
|
|
2190
2192
|
...pickPresetKeys(dbPreset, ['dbSchema', 'dbTablePrefix', 'dbUnderscored']),
|
|
2193
|
+
...promptedDbResults,
|
|
2191
2194
|
};
|
|
2192
|
-
const rootPreset = Install.buildRootPresetValuesFromFlags(parsed);
|
|
2195
|
+
const rootPreset = Install.buildRootPresetValuesFromFlags(parsed, commandArgv);
|
|
2193
2196
|
const rootResults = await runPromptCatalog(Install.rootUserPrompts, {
|
|
2194
2197
|
initialValues: {},
|
|
2195
2198
|
values: {
|
|
@@ -2199,18 +2202,44 @@ export default class Install extends Command {
|
|
|
2199
2202
|
yes,
|
|
2200
2203
|
});
|
|
2201
2204
|
const envAddPromptsForInstall = this.buildEnvAddPromptsForInstall(parsed);
|
|
2202
|
-
const
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2205
|
+
const envAddResumePreset = resumePreset?.envAddPreset ?? {};
|
|
2206
|
+
const envAddFlagValues = Install.buildEnvAddPresetValuesFromFlags(parsed, commandArgv);
|
|
2207
|
+
const envAddPreset = {
|
|
2208
|
+
...envAddResumePreset,
|
|
2209
|
+
...envAddFlagValues,
|
|
2210
|
+
};
|
|
2211
|
+
const resolvedEnvAddAuthType = String(envAddPreset.authType ?? '').trim();
|
|
2212
|
+
const envAddInitialValues = {
|
|
2213
|
+
apiBaseUrl: `http://127.0.0.1:${appResults.appPort ?? DEFAULT_INSTALL_APP_PORT}/api`,
|
|
2214
|
+
...envAddResumePreset,
|
|
2215
|
+
...(!parsed['skip-auth'] && resolvedEnvAddAuthType === 'basic'
|
|
2216
|
+
? {
|
|
2217
|
+
...(!Object.prototype.hasOwnProperty.call(envAddResumePreset, 'username') &&
|
|
2218
|
+
!Object.prototype.hasOwnProperty.call(envAddFlagValues, 'username') &&
|
|
2219
|
+
rootResults.rootUsername !== undefined
|
|
2220
|
+
? { username: String(rootResults.rootUsername).trim() }
|
|
2221
|
+
: {}),
|
|
2222
|
+
...(!Object.prototype.hasOwnProperty.call(envAddFlagValues, 'password') &&
|
|
2223
|
+
rootResults.rootPassword !== undefined
|
|
2224
|
+
? { password: String(rootResults.rootPassword ?? '') }
|
|
2225
|
+
: {}),
|
|
2226
|
+
}
|
|
2227
|
+
: {}),
|
|
2228
|
+
};
|
|
2229
|
+
const promptedEnvAddResults = await runPromptCatalog(envAddPromptsForInstall, {
|
|
2230
|
+
initialValues: envAddInitialValues,
|
|
2206
2231
|
values: {
|
|
2207
2232
|
name: envName,
|
|
2208
2233
|
...(parsed['skip-auth'] ? { skipAuth: true } : {}),
|
|
2209
|
-
...
|
|
2210
|
-
...Install.buildEnvAddPresetValuesFromFlags(parsed),
|
|
2234
|
+
...envAddFlagValues,
|
|
2211
2235
|
},
|
|
2212
2236
|
yes,
|
|
2213
2237
|
});
|
|
2238
|
+
const envAddResults = {
|
|
2239
|
+
...pickPresetKeys(envAddInitialValues, ['username', 'password']),
|
|
2240
|
+
...promptedEnvAddResults,
|
|
2241
|
+
...pickPresetKeys(envAddFlagValues, ['username', 'password']),
|
|
2242
|
+
};
|
|
2214
2243
|
return {
|
|
2215
2244
|
envName,
|
|
2216
2245
|
envResults,
|
|
@@ -2243,16 +2272,23 @@ export default class Install extends Command {
|
|
|
2243
2272
|
: 'Resuming setup from the saved workspace config');
|
|
2244
2273
|
}
|
|
2245
2274
|
const promptResults = await this.collectPromptResults(parsed, flags.yes);
|
|
2246
|
-
const { envName, appResults, downloadResults, dbResults, rootResults, envAddResults
|
|
2275
|
+
const { envName, appResults, downloadResults, dbResults, rootResults, envAddResults } = promptResults;
|
|
2247
2276
|
const source = String(downloadResultsValue(downloadResults, 'source') ?? '').trim();
|
|
2248
|
-
const usesDockerResources = Boolean(dbResults.builtinDb)
|
|
2249
|
-
|| (Boolean(appResults.fetchSource) && source === 'docker');
|
|
2277
|
+
const usesDockerResources = Boolean(dbResults.builtinDb) || source === 'docker';
|
|
2250
2278
|
const dockerNetworkName = usesDockerResources
|
|
2251
2279
|
? await resolveDockerNetworkName({ scope: resolveDefaultConfigScope() })
|
|
2252
2280
|
: undefined;
|
|
2253
2281
|
const dockerContainerPrefix = usesDockerResources
|
|
2254
2282
|
? await resolveDockerContainerPrefix({ scope: resolveDefaultConfigScope() })
|
|
2255
2283
|
: undefined;
|
|
2284
|
+
if (parsed['skip-download']) {
|
|
2285
|
+
await this.ensureSkippedDownloadInputsReady({
|
|
2286
|
+
source,
|
|
2287
|
+
envName,
|
|
2288
|
+
appResults,
|
|
2289
|
+
downloadResults,
|
|
2290
|
+
});
|
|
2291
|
+
}
|
|
2256
2292
|
await Install.ensureExternalDbReadyForInstall(dbResults);
|
|
2257
2293
|
if (!parsed.resume) {
|
|
2258
2294
|
if (!parsed['skip-save-env-log']) {
|
|
@@ -2271,7 +2307,7 @@ export default class Install extends Command {
|
|
|
2271
2307
|
}
|
|
2272
2308
|
}
|
|
2273
2309
|
let builtinDbPlan;
|
|
2274
|
-
if (
|
|
2310
|
+
if (dbResults.builtinDb) {
|
|
2275
2311
|
builtinDbPlan = await this.startBuiltinDb({
|
|
2276
2312
|
envName,
|
|
2277
2313
|
dockerNetworkName,
|
|
@@ -2291,14 +2327,16 @@ export default class Install extends Command {
|
|
|
2291
2327
|
}
|
|
2292
2328
|
let dockerAppPlan;
|
|
2293
2329
|
let localAppPlan;
|
|
2294
|
-
if (
|
|
2330
|
+
if (source === 'docker' || source === 'npm' || source === 'git') {
|
|
2295
2331
|
this.logStage('Preparing application');
|
|
2296
2332
|
if (source === 'docker') {
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2333
|
+
if (!parsed['skip-download']) {
|
|
2334
|
+
await this.downloadManagedSource({
|
|
2335
|
+
downloadResults,
|
|
2336
|
+
verbose: parsed.verbose,
|
|
2337
|
+
});
|
|
2338
|
+
printInfo('Application image ready.');
|
|
2339
|
+
}
|
|
2302
2340
|
dockerAppPlan = await this.installDockerApp({
|
|
2303
2341
|
envName,
|
|
2304
2342
|
dockerNetworkName,
|
|
@@ -2316,13 +2354,21 @@ export default class Install extends Command {
|
|
|
2316
2354
|
}
|
|
2317
2355
|
else if (source === 'npm' || source === 'git') {
|
|
2318
2356
|
const localSource = source === 'npm' ? 'npm' : 'git';
|
|
2319
|
-
const projectRoot =
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2357
|
+
const projectRoot = parsed['skip-download']
|
|
2358
|
+
? Install.resolveLocalProjectRoot({
|
|
2359
|
+
envName,
|
|
2360
|
+
appResults,
|
|
2361
|
+
downloadResults,
|
|
2362
|
+
})
|
|
2363
|
+
: await this.downloadLocalApp({
|
|
2364
|
+
envName,
|
|
2365
|
+
appResults,
|
|
2366
|
+
downloadResults,
|
|
2367
|
+
verbose: parsed.verbose,
|
|
2368
|
+
});
|
|
2369
|
+
if (!parsed['skip-download']) {
|
|
2370
|
+
printInfo('Application files ready.');
|
|
2371
|
+
}
|
|
2326
2372
|
localAppPlan = await this.startLocalApp({
|
|
2327
2373
|
envName,
|
|
2328
2374
|
source: localSource,
|