@nocobase/cli 2.1.0-beta.46 → 2.1.0-beta.48
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/bin/run.js +2 -1
- package/dist/commands/app/destroy.js +3 -3
- package/dist/commands/app/restart.js +1 -2
- package/dist/commands/app/start.js +28 -3
- package/dist/commands/app/upgrade.js +1 -1
- package/dist/commands/env/update.js +11 -1
- package/dist/commands/init.js +44 -76
- package/dist/commands/install.js +68 -50
- package/dist/commands/license/activate.js +1 -1
- package/dist/commands/proxy/caddy/current.js +17 -0
- package/dist/commands/proxy/caddy/generate.js +69 -0
- package/dist/commands/proxy/caddy/index.js +28 -0
- package/dist/commands/proxy/caddy/info.js +31 -0
- package/dist/commands/proxy/caddy/reload.js +30 -0
- package/dist/commands/proxy/caddy/restart.js +28 -0
- package/dist/commands/proxy/caddy/start.js +30 -0
- package/dist/commands/proxy/caddy/status.js +19 -0
- package/dist/commands/proxy/caddy/stop.js +30 -0
- package/dist/commands/proxy/caddy/use.js +26 -0
- package/dist/commands/proxy/index.js +28 -0
- package/dist/commands/proxy/nginx/current.js +18 -0
- package/dist/commands/proxy/nginx/generate.js +68 -0
- package/dist/commands/proxy/nginx/index.js +28 -0
- package/dist/commands/proxy/nginx/info.js +34 -0
- package/dist/commands/proxy/nginx/reload.js +30 -0
- package/dist/commands/proxy/nginx/restart.js +28 -0
- package/dist/commands/proxy/nginx/start.js +30 -0
- package/dist/commands/proxy/nginx/status.js +19 -0
- package/dist/commands/proxy/nginx/stop.js +30 -0
- package/dist/commands/proxy/nginx/use.js +31 -0
- package/dist/commands/revision/create.js +31 -2
- package/dist/lib/app-managed-resources.js +7 -2
- package/dist/lib/auth-store.js +8 -0
- package/dist/lib/cli-config.js +73 -1
- package/dist/lib/env-config.js +8 -0
- package/dist/lib/env-proxy.js +105 -75
- package/dist/lib/managed-env-file.js +7 -4
- package/dist/lib/managed-init-env.js +32 -0
- package/dist/lib/prompt-catalog-terminal.js +1 -2
- package/dist/lib/prompt-validators.js +6 -0
- package/dist/lib/proxy-caddy.js +274 -0
- package/dist/lib/proxy-nginx.js +330 -0
- package/dist/locale/en-US.json +4 -3
- package/dist/locale/zh-CN.json +4 -3
- package/package.json +2 -2
- package/dist/commands/env/proxy/caddy.js +0 -28
- package/dist/commands/env/proxy/index.js +0 -353
- package/dist/commands/env/proxy/nginx.js +0 -28
package/bin/run.js
CHANGED
|
@@ -79,6 +79,7 @@ const cliEntryErrorPath = isDev
|
|
|
79
79
|
: path.join(root, 'dist/lib/cli-entry-error.js');
|
|
80
80
|
const { appendDiagnosticLogPath, formatCliEntryError } = await import(pathToFileURL(cliEntryErrorPath).href);
|
|
81
81
|
const { flush, run, settings } = await import('@oclif/core');
|
|
82
|
+
const forcedColors = pc.createColors(true);
|
|
82
83
|
|
|
83
84
|
if (isDev) {
|
|
84
85
|
settings.debug = true;
|
|
@@ -138,7 +139,7 @@ try {
|
|
|
138
139
|
formatCliEntryError(error, process.argv.slice(2)),
|
|
139
140
|
commandLogSession?.logFile,
|
|
140
141
|
);
|
|
141
|
-
console.error(
|
|
142
|
+
console.error(forcedColors.red(message));
|
|
142
143
|
finalizeCommandLogOnce({ exitCode: 1, errorMessage: message });
|
|
143
144
|
process.exit(1);
|
|
144
145
|
}
|
|
@@ -53,7 +53,7 @@ function buildDestroyPrompt(runtime, options) {
|
|
|
53
53
|
if (options.removesManagedLocalAppFiles) {
|
|
54
54
|
lines.push('CLI-managed local app files will also be removed.');
|
|
55
55
|
}
|
|
56
|
-
lines.push('Env-specific proxy entry files generated by `nb
|
|
56
|
+
lines.push('Env-specific proxy entry files generated by `nb proxy` will also be removed when present.');
|
|
57
57
|
if (options.removesStorageData) {
|
|
58
58
|
lines.push('Storage data will be removed.');
|
|
59
59
|
}
|
|
@@ -204,11 +204,11 @@ export default class AppDestroy extends Command {
|
|
|
204
204
|
resolveEnvProxyEntryDir(runtime.envName, { provider: 'caddy' }),
|
|
205
205
|
path.dirname(resolveLegacyNginxEnvProxyAppOutputPath(runtime.envName)),
|
|
206
206
|
];
|
|
207
|
-
startTask(`Removing
|
|
207
|
+
startTask(`Removing proxy entry files for "${runtime.envName}"...`);
|
|
208
208
|
for (const proxyEntryDir of proxyEntryDirs) {
|
|
209
209
|
await removePathIfExists(proxyEntryDir, `proxy entry files for "${runtime.envName}"`);
|
|
210
210
|
}
|
|
211
|
-
succeedTask(`
|
|
211
|
+
succeedTask(`Proxy entry files removed for "${runtime.envName}".`);
|
|
212
212
|
const configuredStoragePath = resolveConfiguredStoragePath(runtime.env.config);
|
|
213
213
|
if (configuredStoragePath) {
|
|
214
214
|
startTask(`Removing storage data for "${runtime.envName}"...`);
|
|
@@ -68,8 +68,6 @@ export default class AppRestart extends Command {
|
|
|
68
68
|
static examples = [
|
|
69
69
|
'<%= config.bin %> <%= command.id %>',
|
|
70
70
|
'<%= config.bin %> <%= command.id %> --env local',
|
|
71
|
-
'<%= config.bin %> <%= command.id %> --env local --daemon',
|
|
72
|
-
'<%= config.bin %> <%= command.id %> --env local --no-daemon',
|
|
73
71
|
'<%= config.bin %> <%= command.id %> --env local --verbose',
|
|
74
72
|
'<%= config.bin %> <%= command.id %> --env local-docker',
|
|
75
73
|
];
|
|
@@ -98,6 +96,7 @@ export default class AppRestart extends Command {
|
|
|
98
96
|
allowNo: true,
|
|
99
97
|
}),
|
|
100
98
|
daemon: Flags.boolean({
|
|
99
|
+
hidden: true,
|
|
101
100
|
description: 'Run the application as a daemon after stopping it (default: true; use --no-daemon to stay in the foreground)',
|
|
102
101
|
char: 'd',
|
|
103
102
|
required: false,
|
|
@@ -12,6 +12,8 @@ import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../lib/env-
|
|
|
12
12
|
import { formatMissingManagedAppEnvMessage, managedAppLifecycleEnvVars, resolveManagedAppRuntime, runLocalNocoBaseCommand, } from '../../lib/app-runtime.js';
|
|
13
13
|
import { AppHealthCheckError, formatAppUrl, isAppReady, resolveManagedAppApiBaseUrl, waitForAppReady, } from '../../lib/app-health.js';
|
|
14
14
|
import { ensureBuiltinDbReady, ensureLocalPostinstall, ensureSavedLocalSource, recreateSavedDockerApp, } from '../../lib/app-managed-resources.js';
|
|
15
|
+
import { clearEnvRootSetup, getEnv, upsertEnv } from '../../lib/auth-store.js';
|
|
16
|
+
import { buildInitAppEnvVarsFromConfig, isPreparedSetupState } from '../../lib/managed-init-env.js';
|
|
15
17
|
import { resolveAppUrlFromApiBaseUrl } from '../env/shared.js';
|
|
16
18
|
import { readManagedRuntimeEnvValues } from '../../lib/managed-env-file.js';
|
|
17
19
|
import { run } from '../../lib/run-npm.js';
|
|
@@ -116,14 +118,20 @@ async function resolveDefaultLocalCdnBaseUrl(runtime) {
|
|
|
116
118
|
}
|
|
117
119
|
return buildDefaultCdnBaseUrl(runtime.env.config?.appPublicPath || envValues.APP_PUBLIC_PATH, activeVersion);
|
|
118
120
|
}
|
|
121
|
+
async function finalizePreparedEnv(envName) {
|
|
122
|
+
const existingEnv = await getEnv(envName);
|
|
123
|
+
await clearEnvRootSetup(envName);
|
|
124
|
+
await upsertEnv(envName, {
|
|
125
|
+
...(existingEnv?.config.apiBaseUrl ? { apiBaseUrl: existingEnv.config.apiBaseUrl } : {}),
|
|
126
|
+
setupState: 'installed',
|
|
127
|
+
});
|
|
128
|
+
}
|
|
119
129
|
export default class AppStart extends Command {
|
|
120
130
|
static hidden = false;
|
|
121
131
|
static description = 'Start NocoBase for the selected env. When applicable, the CLI synchronizes licensed commercial plugins first, then prepares and starts the app or recreates the saved Docker container.';
|
|
122
132
|
static examples = [
|
|
123
133
|
'<%= config.bin %> <%= command.id %>',
|
|
124
134
|
'<%= config.bin %> <%= command.id %> --env local',
|
|
125
|
-
'<%= config.bin %> <%= command.id %> --env local --daemon',
|
|
126
|
-
'<%= config.bin %> <%= command.id %> --env local --no-daemon',
|
|
127
135
|
'<%= config.bin %> <%= command.id %> --env local --verbose',
|
|
128
136
|
'<%= config.bin %> <%= command.id %> --env local-docker',
|
|
129
137
|
];
|
|
@@ -152,6 +160,7 @@ export default class AppStart extends Command {
|
|
|
152
160
|
allowNo: true,
|
|
153
161
|
}),
|
|
154
162
|
daemon: Flags.boolean({
|
|
163
|
+
hidden: true,
|
|
155
164
|
description: 'Run the application as a daemon (default: true; use --no-daemon to stay in the foreground)',
|
|
156
165
|
char: 'd',
|
|
157
166
|
required: false,
|
|
@@ -181,6 +190,8 @@ export default class AppStart extends Command {
|
|
|
181
190
|
}
|
|
182
191
|
const daemonFlagWasProvided = argvHasToken(this.argv, ['--daemon', '--no-daemon']);
|
|
183
192
|
const runtime = await resolveManagedAppRuntime(requestedEnv);
|
|
193
|
+
const preparedInitEnvVars = buildInitAppEnvVarsFromConfig(runtime?.env.config);
|
|
194
|
+
const isPreparedEnv = isPreparedSetupState(runtime?.env.config?.setupState);
|
|
184
195
|
const runCommand = this.config.runCommand.bind(this.config);
|
|
185
196
|
const commandStdio = flags.verbose ? 'inherit' : 'ignore';
|
|
186
197
|
if (!runtime) {
|
|
@@ -239,6 +250,7 @@ export default class AppStart extends Command {
|
|
|
239
250
|
stdio: commandStdio,
|
|
240
251
|
}).catch(() => undefined);
|
|
241
252
|
await recreateSavedDockerApp(runtime, {
|
|
253
|
+
initEnvVars: isPreparedEnv ? preparedInitEnvVars : undefined,
|
|
242
254
|
verbose: flags.verbose,
|
|
243
255
|
});
|
|
244
256
|
succeedTask(`Docker app container is ready for "${runtime.envName}".`);
|
|
@@ -255,6 +267,9 @@ export default class AppStart extends Command {
|
|
|
255
267
|
logHint: `You can inspect startup logs with \`nb app logs --env ${runtime.envName}\`.`,
|
|
256
268
|
...(flags.verbose ? { verbose: true } : {}),
|
|
257
269
|
});
|
|
270
|
+
if (isPreparedEnv) {
|
|
271
|
+
await finalizePreparedEnv(runtime.envName);
|
|
272
|
+
}
|
|
258
273
|
if (shouldPrintStartSuccess()) {
|
|
259
274
|
succeedTask(`NocoBase is running for "${runtime.envName}"${appUrl ? ` at ${appUrl}` : ''}.`);
|
|
260
275
|
}
|
|
@@ -275,6 +290,9 @@ export default class AppStart extends Command {
|
|
|
275
290
|
onFailTask: failTask,
|
|
276
291
|
});
|
|
277
292
|
}
|
|
293
|
+
if (isPreparedEnv && flags.daemon === false) {
|
|
294
|
+
this.error(`Can't start "${runtime.envName}" with --no-daemon yet. Run \`nb app start --env ${runtime.envName}\` to finish the first installation in daemon mode.`);
|
|
295
|
+
}
|
|
278
296
|
const npmArgs = ['start'];
|
|
279
297
|
if (quickstart) {
|
|
280
298
|
npmArgs.push('--quickstart');
|
|
@@ -357,8 +375,12 @@ export default class AppStart extends Command {
|
|
|
357
375
|
? {
|
|
358
376
|
...managedAppLifecycleEnvVars(),
|
|
359
377
|
CDN_BASE_URL: defaultCdnBaseUrl,
|
|
378
|
+
...(isPreparedEnv ? preparedInitEnvVars : {}),
|
|
360
379
|
}
|
|
361
|
-
:
|
|
380
|
+
: {
|
|
381
|
+
...managedAppLifecycleEnvVars(),
|
|
382
|
+
...(isPreparedEnv ? preparedInitEnvVars : {}),
|
|
383
|
+
};
|
|
362
384
|
await runLocalNocoBaseCommand(runtime, npmArgs, {
|
|
363
385
|
env: startEnv,
|
|
364
386
|
stdio: commandStdio,
|
|
@@ -369,6 +391,9 @@ export default class AppStart extends Command {
|
|
|
369
391
|
apiBaseUrl,
|
|
370
392
|
logHint: `You can inspect startup logs with \`nb app logs --env ${runtime.envName}\`.`,
|
|
371
393
|
});
|
|
394
|
+
if (isPreparedEnv) {
|
|
395
|
+
await finalizePreparedEnv(runtime.envName);
|
|
396
|
+
}
|
|
372
397
|
if (shouldPrintStartSuccess()) {
|
|
373
398
|
succeedTask(`NocoBase is running for "${runtime.envName}"${appUrl ? ` at ${appUrl}` : ''}.`);
|
|
374
399
|
}
|
|
@@ -288,7 +288,7 @@ export default class AppUpgrade extends Command {
|
|
|
288
288
|
}),
|
|
289
289
|
verbose: Flags.boolean({
|
|
290
290
|
description: 'Show raw output from the underlying local or Docker commands',
|
|
291
|
-
default:
|
|
291
|
+
default: true,
|
|
292
292
|
}),
|
|
293
293
|
};
|
|
294
294
|
static resolveUpgradeVersion(runtime, flags) {
|
|
@@ -12,10 +12,16 @@ import { Args, Command, Flags } from '@oclif/core';
|
|
|
12
12
|
import { getCurrentEnvName, getEnv, replaceEnvConfig } from '../../lib/auth-store.js';
|
|
13
13
|
import { updateEnvRuntime } from '../../lib/bootstrap.js';
|
|
14
14
|
import { resolveDefaultConfigScope } from '../../lib/cli-home.js';
|
|
15
|
+
import { appendDiagnosticLogPath } from '../../lib/cli-entry-error.js';
|
|
16
|
+
import { getActiveCommandLogFile } from '../../lib/command-log.js';
|
|
15
17
|
import { ENV_BOOLEAN_CONFIG_FLAG_MAP, ENV_STRING_CONFIG_FLAG_MAP } from '../../lib/env-command-config.js';
|
|
16
18
|
import { buildStoredEnvConfig } from '../../lib/env-config.js';
|
|
17
|
-
import {
|
|
19
|
+
import { validateApiBaseUrl } from '../../lib/prompt-validators.js';
|
|
20
|
+
import { failTask, printInfo, printVerbose, printWarningBlock, setVerboseMode, startTask, stopTask, succeedTask, } from '../../lib/ui.js';
|
|
18
21
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
22
|
+
function throwValidationError(message) {
|
|
23
|
+
throw new Error(appendDiagnosticLogPath(message, getActiveCommandLogFile()));
|
|
24
|
+
}
|
|
19
25
|
const UPDATE_STRING_FLAGS = [
|
|
20
26
|
'source',
|
|
21
27
|
'download-version',
|
|
@@ -384,6 +390,10 @@ export default class EnvUpdate extends Command {
|
|
|
384
390
|
nextInput.authType = currentEnv.authType;
|
|
385
391
|
nextInput.authUsername = currentEnv.config.authUsername;
|
|
386
392
|
if (parsedFlags['api-base-url'] !== undefined) {
|
|
393
|
+
const apiBaseUrlValidationError = await validateApiBaseUrl(parsedFlags['api-base-url']);
|
|
394
|
+
if (apiBaseUrlValidationError) {
|
|
395
|
+
throwValidationError(apiBaseUrlValidationError);
|
|
396
|
+
}
|
|
387
397
|
nextInput.apiBaseUrl = parsedFlags['api-base-url'];
|
|
388
398
|
}
|
|
389
399
|
if (parsedFlags['auth-type'] !== undefined) {
|
package/dist/commands/init.js
CHANGED
|
@@ -18,6 +18,7 @@ import { applyCliLocale, localeText, translateCli } from "../lib/cli-locale.js";
|
|
|
18
18
|
import { resolveDefaultConfigScope } from '../lib/cli-home.js';
|
|
19
19
|
import { resolveDefaultApiHost, resolveDefaultUiHost } from '../lib/cli-config.js';
|
|
20
20
|
import { areConfiguredPathsEquivalent, deriveConfiguredSourcePath, deriveConfiguredStoragePath, inferConfiguredAppPathFromLegacyConfig, } from '../lib/env-paths.js';
|
|
21
|
+
import { formatMissingManagedAppEnvMessage } from '../lib/app-runtime.js';
|
|
21
22
|
import { runPromptCatalogWebUI } from "../lib/prompt-web-ui.js";
|
|
22
23
|
import { validateApiBaseUrl, validateEnvKey } from "../lib/prompt-validators.js";
|
|
23
24
|
import { installNocoBaseSkills, isNpmRegistryUnavailable } from '../lib/skills-manager.js';
|
|
@@ -467,7 +468,7 @@ Prompt modes:
|
|
|
467
468
|
}),
|
|
468
469
|
verbose: Flags.boolean({
|
|
469
470
|
description: 'Show detailed command output',
|
|
470
|
-
default:
|
|
471
|
+
default: true,
|
|
471
472
|
}),
|
|
472
473
|
'skip-skills': Flags.boolean({
|
|
473
474
|
description: 'Skip installing NocoBase AI coding skills during init',
|
|
@@ -482,7 +483,7 @@ Prompt modes:
|
|
|
482
483
|
max: 65535,
|
|
483
484
|
}),
|
|
484
485
|
...pickKeys(EnvAdd.flags, INIT_ENV_ADD_FLAG_NAMES),
|
|
485
|
-
...omitKeys(Install.flags, ['yes', 'env']),
|
|
486
|
+
...omitKeys(Install.flags, ['yes', 'env', 'verbose']),
|
|
486
487
|
};
|
|
487
488
|
async run() {
|
|
488
489
|
const parsedResult = await this.parse(Init);
|
|
@@ -499,13 +500,13 @@ Prompt modes:
|
|
|
499
500
|
(normalizedFlags['access-token'] !== undefined || normalizedFlags.token !== undefined)) {
|
|
500
501
|
this.error('--skip-auth cannot be used with --access-token or --token.');
|
|
501
502
|
}
|
|
502
|
-
if (normalizedFlags
|
|
503
|
-
this.error('--
|
|
503
|
+
if (normalizedFlags['prepare-only'] && explicitSetupModeFlag(normalizedFlags) === 'connect-remote') {
|
|
504
|
+
this.error('--prepare-only is only available for local or install-new setup flows.');
|
|
504
505
|
}
|
|
505
506
|
if (!normalizedFlags.ui && (normalizedFlags['ui-host'] !== undefined || normalizedFlags['ui-port'] !== undefined)) {
|
|
506
507
|
this.error('--ui-host and --ui-port require --ui.');
|
|
507
508
|
}
|
|
508
|
-
if (normalizedFlags.resume) {
|
|
509
|
+
if (normalizedFlags.resume && !normalizedFlags.ui) {
|
|
509
510
|
const envName = String(normalizedFlags.env ?? '').trim();
|
|
510
511
|
if (!envName) {
|
|
511
512
|
this.error(formatResumeEnvRequiredMessage());
|
|
@@ -533,15 +534,26 @@ Prompt modes:
|
|
|
533
534
|
const resumeEnv = await getEnv(resumeEnvName, {
|
|
534
535
|
scope: resolveDefaultConfigScope(),
|
|
535
536
|
});
|
|
536
|
-
if (resumeEnv) {
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
537
|
+
if (!resumeEnv) {
|
|
538
|
+
this.error(formatMissingManagedAppEnvMessage(resumeEnvName));
|
|
539
|
+
}
|
|
540
|
+
const resumePresetValues = Install.buildResumePresetValues(resumeEnv);
|
|
541
|
+
presetValues = {
|
|
542
|
+
...resumePresetValues.envPreset,
|
|
543
|
+
...resumePresetValues.appPreset,
|
|
544
|
+
...resumePresetValues.downloadPreset,
|
|
545
|
+
...resumePresetValues.dbPreset,
|
|
546
|
+
...resumePresetValues.rootPreset,
|
|
547
|
+
...resumePresetValues.envAddPreset,
|
|
548
|
+
...presetValues,
|
|
549
|
+
};
|
|
550
|
+
const savedAppPort = String(resumeEnv.config.appPort ?? '').trim();
|
|
551
|
+
const savedDbPort = String(resumeEnv.config.dbPort ?? '').trim();
|
|
552
|
+
if (savedAppPort) {
|
|
553
|
+
presetValues.resumeSavedAppPort = savedAppPort;
|
|
554
|
+
}
|
|
555
|
+
if (savedDbPort) {
|
|
556
|
+
presetValues.resumeSavedDbPort = savedDbPort;
|
|
545
557
|
}
|
|
546
558
|
}
|
|
547
559
|
}
|
|
@@ -653,14 +665,14 @@ Prompt modes:
|
|
|
653
665
|
await this.persistManagedEnvConfig(normalizedResults, normalizedFlags);
|
|
654
666
|
managedInstallResults = normalizedResults;
|
|
655
667
|
printInfo(`Saved env config for "${String(normalizedResults.appName ?? DEFAULT_INIT_APP_NAME).trim() || DEFAULT_INIT_APP_NAME}".`);
|
|
656
|
-
printVerbose('Running nb
|
|
668
|
+
printVerbose('Running nb install');
|
|
657
669
|
await this.config.runCommand('install', this.buildInstallArgv(normalizedResults, normalizedFlags));
|
|
658
670
|
}
|
|
659
671
|
}
|
|
660
672
|
catch (error) {
|
|
661
673
|
const message = error instanceof Error ? error.message : String(error);
|
|
662
674
|
const formatted = managedInstallResults
|
|
663
|
-
? this.formatManagedInstallFailureMessage(message, managedInstallResults, normalizedFlags)
|
|
675
|
+
? await this.formatManagedInstallFailureMessage(message, managedInstallResults, normalizedFlags)
|
|
664
676
|
: message;
|
|
665
677
|
this.error(pc.red(formatted));
|
|
666
678
|
this.exit(1);
|
|
@@ -1068,6 +1080,8 @@ Prompt modes:
|
|
|
1068
1080
|
...(dbSchema ? { dbSchema } : {}),
|
|
1069
1081
|
...(dbTablePrefix ? { dbTablePrefix } : {}),
|
|
1070
1082
|
...(results.dbUnderscored !== undefined ? { dbUnderscored: Boolean(results.dbUnderscored) } : {}),
|
|
1083
|
+
setupState: 'prepared',
|
|
1084
|
+
...(String(results.lang ?? '').trim() ? { lang: String(results.lang ?? '').trim() } : {}),
|
|
1071
1085
|
}, { scope: resolveDefaultConfigScope() });
|
|
1072
1086
|
}
|
|
1073
1087
|
buildEnvAddArgv(results) {
|
|
@@ -1115,6 +1129,9 @@ Prompt modes:
|
|
|
1115
1129
|
if (options?.resume) {
|
|
1116
1130
|
argv.push('--resume');
|
|
1117
1131
|
}
|
|
1132
|
+
if (flags['prepare-only']) {
|
|
1133
|
+
argv.push('--prepare-only');
|
|
1134
|
+
}
|
|
1118
1135
|
if (flags.verbose) {
|
|
1119
1136
|
argv.push('--verbose');
|
|
1120
1137
|
}
|
|
@@ -1291,72 +1308,23 @@ Prompt modes:
|
|
|
1291
1308
|
}
|
|
1292
1309
|
buildManagedInstallResumeCommand(results, flags) {
|
|
1293
1310
|
const argv = ['nb', 'init'];
|
|
1294
|
-
if (flags.yes) {
|
|
1295
|
-
argv.push('--yes');
|
|
1296
|
-
}
|
|
1297
1311
|
const envName = String(results.appName ?? DEFAULT_INIT_APP_NAME).trim() || DEFAULT_INIT_APP_NAME;
|
|
1298
1312
|
argv.push('--env', envName);
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
argv.push('--setup-mode', 'manage-local');
|
|
1302
|
-
}
|
|
1303
|
-
const source = String(results.source ?? '').trim();
|
|
1304
|
-
const skipDownload = setupMode === 'manage-local' ? false : Boolean(flags['skip-download']) || results.skipDownload === true;
|
|
1305
|
-
if (source) {
|
|
1306
|
-
argv.push('--source', source);
|
|
1307
|
-
}
|
|
1308
|
-
const version = resolveInitDownloadVersion(results);
|
|
1309
|
-
if (version) {
|
|
1310
|
-
argv.push('--version', version);
|
|
1311
|
-
}
|
|
1312
|
-
const gitUrl = String(results.gitUrl ?? '').trim();
|
|
1313
|
-
if (gitUrl) {
|
|
1314
|
-
argv.push('--git-url', gitUrl);
|
|
1315
|
-
}
|
|
1316
|
-
const dockerRegistry = String(results.dockerRegistry ?? '').trim();
|
|
1317
|
-
if (dockerRegistry) {
|
|
1318
|
-
argv.push('--docker-registry', dockerRegistry);
|
|
1319
|
-
}
|
|
1320
|
-
const dockerPlatform = String(results.dockerPlatform ?? '').trim();
|
|
1321
|
-
if (dockerPlatform) {
|
|
1322
|
-
argv.push('--docker-platform', dockerPlatform);
|
|
1323
|
-
}
|
|
1324
|
-
const npmRegistry = String(results.npmRegistry ?? '').trim();
|
|
1325
|
-
if (npmRegistry) {
|
|
1326
|
-
argv.push('--npm-registry', npmRegistry);
|
|
1327
|
-
}
|
|
1328
|
-
if (skipDownload) {
|
|
1329
|
-
argv.push('--skip-download');
|
|
1313
|
+
if (flags.yes) {
|
|
1314
|
+
argv.push('--yes');
|
|
1330
1315
|
}
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
const appPath = String(results.appPath ?? '').trim() ||
|
|
1334
|
-
inferConfiguredAppPathFromLegacyConfig({
|
|
1335
|
-
appRootPath: results.appRootPath,
|
|
1336
|
-
storagePath: results.storagePath,
|
|
1337
|
-
}) ||
|
|
1338
|
-
'';
|
|
1339
|
-
const expectedOutputDir = String(results.appRootPath ?? '').trim() || (appPath ? deriveConfiguredSourcePath(appPath) : '');
|
|
1340
|
-
if (outputDir && outputDir !== expectedOutputDir) {
|
|
1341
|
-
argv.push('--output-dir', outputDir);
|
|
1342
|
-
}
|
|
1343
|
-
if (results.devDependencies) {
|
|
1344
|
-
argv.push('--dev-dependencies');
|
|
1345
|
-
}
|
|
1346
|
-
if (results.dockerSave) {
|
|
1347
|
-
argv.push('--docker-save');
|
|
1348
|
-
}
|
|
1349
|
-
if (results.build !== undefined && !results.build) {
|
|
1350
|
-
argv.push('--no-build');
|
|
1351
|
-
}
|
|
1352
|
-
if (results.buildDts) {
|
|
1353
|
-
argv.push('--build-dts');
|
|
1354
|
-
}
|
|
1316
|
+
if (flags.ui) {
|
|
1317
|
+
argv.push('--ui');
|
|
1355
1318
|
}
|
|
1356
|
-
argv.push('--resume'
|
|
1319
|
+
argv.push('--resume');
|
|
1357
1320
|
return argv.map(shellQuoteArg).join(' ');
|
|
1358
1321
|
}
|
|
1359
|
-
formatManagedInstallFailureMessage(message, results, flags) {
|
|
1322
|
+
async formatManagedInstallFailureMessage(message, results, flags) {
|
|
1323
|
+
const envName = String(results.appName ?? DEFAULT_INIT_APP_NAME).trim() || DEFAULT_INIT_APP_NAME;
|
|
1324
|
+
const savedEnv = await getEnv(envName, { scope: resolveDefaultConfigScope() });
|
|
1325
|
+
if (savedEnv?.config.setupState === 'installed') {
|
|
1326
|
+
return message;
|
|
1327
|
+
}
|
|
1360
1328
|
const command = this.buildManagedInstallResumeCommand(results, flags);
|
|
1361
1329
|
return [message, '', translateCli('commands.init.messages.resumeAfterInstallFailure', { command })].join('\n');
|
|
1362
1330
|
}
|
package/dist/commands/install.js
CHANGED
|
@@ -28,6 +28,7 @@ import { clearEnvRootSetup, getEnv, setCurrentEnv, upsertEnv } from '../lib/auth
|
|
|
28
28
|
import { buildStoredEnvConfig } from '../lib/env-config.js';
|
|
29
29
|
import { resolveDockerEnvFileArg } from "../lib/docker-env-file.js";
|
|
30
30
|
import { startDockerLogFollower } from '../lib/docker-log-stream.js';
|
|
31
|
+
import { buildInitAppEnvVarsFromConfig } from '../lib/managed-init-env.js';
|
|
31
32
|
import { areConfiguredPathsEquivalent, deriveConfiguredSourcePath, deriveConfiguredStoragePath, inferConfiguredAppPathFromLegacyConfig, } from '../lib/env-paths.js';
|
|
32
33
|
import Download, { defaultDockerRegistryForLang } from './download.js';
|
|
33
34
|
import EnvAdd from "./env/add.js";
|
|
@@ -351,6 +352,10 @@ export default class Install extends Command {
|
|
|
351
352
|
hidden: true,
|
|
352
353
|
default: false,
|
|
353
354
|
}),
|
|
355
|
+
'prepare-only': Flags.boolean({
|
|
356
|
+
description: 'Prepare the env and save config without installing or starting the application yet',
|
|
357
|
+
default: false,
|
|
358
|
+
}),
|
|
354
359
|
env: Flags.string({
|
|
355
360
|
char: 'e',
|
|
356
361
|
description: 'App/env name to create or update. Defaults the app path to ./<envName>/ and derives source/storage inside it.',
|
|
@@ -1110,9 +1115,11 @@ export default class Install extends Command {
|
|
|
1110
1115
|
const rootEmail = Install.toOptionalPromptString(config.rootEmail);
|
|
1111
1116
|
const rootPassword = Install.toOptionalPromptString(config.rootPassword);
|
|
1112
1117
|
const rootNickname = Install.toOptionalPromptString(config.rootNickname);
|
|
1118
|
+
const lang = Install.toOptionalPromptString(config.lang);
|
|
1113
1119
|
const auth = config.auth;
|
|
1114
1120
|
const savedAuthType = Install.toOptionalPromptString(config.authType) ?? Install.toOptionalPromptString(auth?.type);
|
|
1115
1121
|
const appPreset = {
|
|
1122
|
+
...(lang ? { lang } : {}),
|
|
1116
1123
|
...(appPath ? { appPath } : {}),
|
|
1117
1124
|
...(appRootPath ? { appRootPath } : {}),
|
|
1118
1125
|
...(appPort ? { appPort } : {}),
|
|
@@ -1185,21 +1192,25 @@ export default class Install extends Command {
|
|
|
1185
1192
|
envAddPreset,
|
|
1186
1193
|
};
|
|
1187
1194
|
}
|
|
1188
|
-
static buildResumeMissingYesFlags(flags) {
|
|
1195
|
+
static buildResumeMissingYesFlags(flags, resumePreset) {
|
|
1189
1196
|
const missing = [];
|
|
1190
|
-
if (!Install.toOptionalPromptString(flags.lang)) {
|
|
1197
|
+
if (!Install.toOptionalPromptString(flags.lang) && !Install.toOptionalPromptString(resumePreset.appPreset.lang)) {
|
|
1191
1198
|
missing.push('--lang');
|
|
1192
1199
|
}
|
|
1193
|
-
if (!Install.toOptionalPromptString(flags['root-username'])
|
|
1200
|
+
if (!Install.toOptionalPromptString(flags['root-username']) &&
|
|
1201
|
+
!Install.toOptionalPromptString(resumePreset.rootPreset.rootUsername)) {
|
|
1194
1202
|
missing.push('--root-username');
|
|
1195
1203
|
}
|
|
1196
|
-
if (!Install.toOptionalPromptString(flags['root-email'])
|
|
1204
|
+
if (!Install.toOptionalPromptString(flags['root-email']) &&
|
|
1205
|
+
!Install.toOptionalPromptString(resumePreset.rootPreset.rootEmail)) {
|
|
1197
1206
|
missing.push('--root-email');
|
|
1198
1207
|
}
|
|
1199
|
-
if (!Install.toOptionalPromptString(flags['root-password'])
|
|
1208
|
+
if (!Install.toOptionalPromptString(flags['root-password']) &&
|
|
1209
|
+
!Install.toOptionalPromptString(resumePreset.rootPreset.rootPassword)) {
|
|
1200
1210
|
missing.push('--root-password');
|
|
1201
1211
|
}
|
|
1202
|
-
if (!Install.toOptionalPromptString(flags['root-nickname'])
|
|
1212
|
+
if (!Install.toOptionalPromptString(flags['root-nickname']) &&
|
|
1213
|
+
!Install.toOptionalPromptString(resumePreset.rootPreset.rootNickname)) {
|
|
1203
1214
|
missing.push('--root-nickname');
|
|
1204
1215
|
}
|
|
1205
1216
|
return missing;
|
|
@@ -1212,8 +1223,9 @@ export default class Install extends Command {
|
|
|
1212
1223
|
if (!env) {
|
|
1213
1224
|
throw new Error(formatMissingManagedAppEnvMessage(parsed.env));
|
|
1214
1225
|
}
|
|
1226
|
+
const resumePreset = Install.buildResumePresetValues(env);
|
|
1215
1227
|
if (yes) {
|
|
1216
|
-
const missingFlags = Install.buildResumeMissingYesFlags(parsed);
|
|
1228
|
+
const missingFlags = Install.buildResumeMissingYesFlags(parsed, resumePreset);
|
|
1217
1229
|
if (missingFlags.length > 0) {
|
|
1218
1230
|
throw new Error([
|
|
1219
1231
|
`Cannot continue setup for "${env.name}" in non-interactive resume mode yet.`,
|
|
@@ -1222,7 +1234,7 @@ export default class Install extends Command {
|
|
|
1222
1234
|
].join('\n'));
|
|
1223
1235
|
}
|
|
1224
1236
|
}
|
|
1225
|
-
return
|
|
1237
|
+
return resumePreset;
|
|
1226
1238
|
}
|
|
1227
1239
|
static async resolveAvailableDefaultPort(defaultPort, options) {
|
|
1228
1240
|
const normalized = String(defaultPort).trim();
|
|
@@ -1374,7 +1386,7 @@ export default class Install extends Command {
|
|
|
1374
1386
|
if (argvHasToken(argv, ['--build-dts', '--no-build-dts'])) {
|
|
1375
1387
|
preset.buildDts = flags['build-dts'];
|
|
1376
1388
|
}
|
|
1377
|
-
if (yes) {
|
|
1389
|
+
if (yes && !flags.resume) {
|
|
1378
1390
|
preset.source ??= 'docker';
|
|
1379
1391
|
preset.version ??= 'alpha';
|
|
1380
1392
|
preset.outputDir ??= appRoot;
|
|
@@ -1415,20 +1427,13 @@ export default class Install extends Command {
|
|
|
1415
1427
|
return Install.sanitizeDockerResourceName(`${Install.buildBuiltinDbContainerPrefix(containerPrefix)}-${envName}-app`);
|
|
1416
1428
|
}
|
|
1417
1429
|
static buildInitAppEnvVars(params) {
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
};
|
|
1426
|
-
put('INIT_APP_LANG', params.appResults.lang);
|
|
1427
|
-
put('INIT_ROOT_USERNAME', params.rootResults.rootUsername);
|
|
1428
|
-
put('INIT_ROOT_EMAIL', params.rootResults.rootEmail);
|
|
1429
|
-
put('INIT_ROOT_PASSWORD', params.rootResults.rootPassword);
|
|
1430
|
-
put('INIT_ROOT_NICKNAME', params.rootResults.rootNickname);
|
|
1431
|
-
return out;
|
|
1430
|
+
return buildInitAppEnvVarsFromConfig({
|
|
1431
|
+
lang: String(params.appResults.lang ?? ''),
|
|
1432
|
+
rootUsername: String(params.rootResults.rootUsername ?? ''),
|
|
1433
|
+
rootEmail: String(params.rootResults.rootEmail ?? ''),
|
|
1434
|
+
rootPassword: String(params.rootResults.rootPassword ?? ''),
|
|
1435
|
+
rootNickname: String(params.rootResults.rootNickname ?? ''),
|
|
1436
|
+
});
|
|
1432
1437
|
}
|
|
1433
1438
|
static shouldPublishBuiltinDbPort(source) {
|
|
1434
1439
|
return String(source ?? '').trim() !== 'docker';
|
|
@@ -2232,6 +2237,7 @@ export default class Install extends Command {
|
|
|
2232
2237
|
authType,
|
|
2233
2238
|
...(authUsername ? { authUsername } : {}),
|
|
2234
2239
|
accessToken: params.envAddResults.accessToken,
|
|
2240
|
+
setupState: params.appResults.setupState,
|
|
2235
2241
|
source: downloadResultsValue(params.downloadResults, 'source'),
|
|
2236
2242
|
downloadVersion: downloadResultsValue(params.downloadResults, 'version'),
|
|
2237
2243
|
dockerRegistry: downloadResultsValue(params.downloadResults, 'dockerRegistry'),
|
|
@@ -2247,6 +2253,7 @@ export default class Install extends Command {
|
|
|
2247
2253
|
...(storagePath && !areConfiguredPathsEquivalent(storagePath, derivedStoragePath) ? { storagePath } : {}),
|
|
2248
2254
|
...(appPublicPath ? { appPublicPath } : {}),
|
|
2249
2255
|
...(envFile ? { envFile } : {}),
|
|
2256
|
+
lang: params.appResults.lang,
|
|
2250
2257
|
appKey: params.appResults.appKey,
|
|
2251
2258
|
timezone: params.appResults.timeZone,
|
|
2252
2259
|
builtinDb: params.dbResults.builtinDb,
|
|
@@ -2432,6 +2439,7 @@ export default class Install extends Command {
|
|
|
2432
2439
|
envName,
|
|
2433
2440
|
appResults,
|
|
2434
2441
|
});
|
|
2442
|
+
appResults.setupState = 'prepared';
|
|
2435
2443
|
const source = String(downloadResultsValue(downloadResults, 'source') ?? '').trim();
|
|
2436
2444
|
const usesDockerResources = Boolean(dbResults.builtinDb) || source === 'docker';
|
|
2437
2445
|
const dockerNetworkName = usesDockerResources
|
|
@@ -2496,20 +2504,22 @@ export default class Install extends Command {
|
|
|
2496
2504
|
});
|
|
2497
2505
|
printInfo('Application image ready.');
|
|
2498
2506
|
}
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2507
|
+
if (!parsed['prepare-only']) {
|
|
2508
|
+
dockerAppPlan = await this.installDockerApp({
|
|
2509
|
+
envName,
|
|
2510
|
+
dockerNetworkName,
|
|
2511
|
+
dockerContainerPrefix,
|
|
2512
|
+
appResults,
|
|
2513
|
+
downloadResults,
|
|
2514
|
+
dbResults,
|
|
2515
|
+
rootResults,
|
|
2516
|
+
builtinDbPlan,
|
|
2517
|
+
force: parsed.force,
|
|
2518
|
+
commandStdio,
|
|
2519
|
+
});
|
|
2520
|
+
appResults.appKey = dockerAppPlan.appKey;
|
|
2521
|
+
appResults.timeZone = dockerAppPlan.timeZone;
|
|
2522
|
+
}
|
|
2513
2523
|
}
|
|
2514
2524
|
else if (source === 'npm' || source === 'git') {
|
|
2515
2525
|
const localSource = source === 'npm' ? 'npm' : 'git';
|
|
@@ -2528,17 +2538,19 @@ export default class Install extends Command {
|
|
|
2528
2538
|
if (!parsed['skip-download']) {
|
|
2529
2539
|
printInfo('Application files ready.');
|
|
2530
2540
|
}
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2541
|
+
if (!parsed['prepare-only']) {
|
|
2542
|
+
localAppPlan = await this.startLocalApp({
|
|
2543
|
+
envName,
|
|
2544
|
+
source: localSource,
|
|
2545
|
+
projectRoot,
|
|
2546
|
+
appResults,
|
|
2547
|
+
dbResults,
|
|
2548
|
+
rootResults,
|
|
2549
|
+
commandStdio,
|
|
2550
|
+
});
|
|
2551
|
+
appResults.appKey = localAppPlan.appKey;
|
|
2552
|
+
appResults.timeZone = localAppPlan.timeZone;
|
|
2553
|
+
}
|
|
2542
2554
|
}
|
|
2543
2555
|
}
|
|
2544
2556
|
else {
|
|
@@ -2560,6 +2572,7 @@ export default class Install extends Command {
|
|
|
2560
2572
|
defaultApiHost,
|
|
2561
2573
|
});
|
|
2562
2574
|
printInfo(`NocoBase is ready at ${formatInstallDisplayUrl(displayApiBaseUrl)}`);
|
|
2575
|
+
appResults.setupState = 'installed';
|
|
2563
2576
|
}
|
|
2564
2577
|
if (dockerAppPlan || localAppPlan || builtinDbPlan) {
|
|
2565
2578
|
await this.saveInstalledEnv({
|
|
@@ -2577,8 +2590,13 @@ export default class Install extends Command {
|
|
|
2577
2590
|
appReady: Boolean(dockerAppPlan || localAppPlan),
|
|
2578
2591
|
skipAuth: Boolean(parsed['skip-auth']),
|
|
2579
2592
|
});
|
|
2580
|
-
|
|
2581
|
-
|
|
2593
|
+
if (!parsed['prepare-only']) {
|
|
2594
|
+
await clearEnvRootSetup(envName, { scope: resolveDefaultConfigScope() });
|
|
2595
|
+
}
|
|
2596
|
+
if (parsed['prepare-only']) {
|
|
2597
|
+
printInfo(`Preparation complete for "${envName}". Activate the license, then run \`nb app start --env ${envName}\`.`);
|
|
2598
|
+
}
|
|
2599
|
+
else if (!dockerAppPlan && !localAppPlan) {
|
|
2582
2600
|
printInfo(`Install config for "${envName}" has been saved.`);
|
|
2583
2601
|
}
|
|
2584
2602
|
}
|
|
@@ -174,6 +174,6 @@ export default class LicenseActivate extends Command {
|
|
|
174
174
|
this.error(licenseActivateText('errors.activationFailed', { envName: runtime.envName, reason }));
|
|
175
175
|
}
|
|
176
176
|
this.log(licenseActivateText('messages.activated', { envName: runtime.envName }));
|
|
177
|
-
this.log(licenseActivateText('messages.savedLicenseKey'
|
|
177
|
+
this.log(licenseActivateText('messages.savedLicenseKey'));
|
|
178
178
|
}
|
|
179
179
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { Command } from '@oclif/core';
|
|
10
|
+
import { getCaddyProxyDriver } from '../../../lib/proxy-caddy.js';
|
|
11
|
+
export default class ProxyCaddyCurrent extends Command {
|
|
12
|
+
static summary = 'Print the current caddy runtime driver';
|
|
13
|
+
async run() {
|
|
14
|
+
await this.parse(ProxyCaddyCurrent);
|
|
15
|
+
this.log(await getCaddyProxyDriver());
|
|
16
|
+
}
|
|
17
|
+
}
|