@nocobase/cli 2.1.0-beta.21 → 2.1.0-beta.23
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 +37 -49
- package/README.zh-CN.md +36 -47
- package/dist/commands/app/down.js +260 -0
- package/dist/commands/app/logs.js +98 -0
- package/dist/commands/app/restart.js +75 -0
- package/dist/commands/app/start.js +252 -0
- package/dist/commands/app/stop.js +98 -0
- package/dist/commands/app/upgrade.js +595 -0
- package/dist/commands/build.js +3 -48
- package/dist/commands/dev.js +3 -147
- package/dist/commands/down.js +3 -188
- package/dist/commands/download.js +4 -856
- package/dist/commands/env/add.js +28 -23
- package/dist/commands/env/info.js +152 -0
- package/dist/commands/env/list.js +23 -9
- package/dist/commands/env/shared.js +158 -0
- package/dist/commands/{prompts-stages.js → examples/prompts-stages.js} +3 -3
- package/dist/commands/{prompts-test.js → examples/prompts-test.js} +3 -3
- package/dist/commands/init.js +84 -6
- package/dist/commands/install.js +288 -61
- package/dist/commands/logs.js +3 -88
- package/dist/commands/plugin/disable.js +64 -0
- package/dist/commands/plugin/enable.js +64 -0
- package/dist/commands/plugin/list.js +62 -0
- package/dist/commands/pm/disable.js +3 -54
- package/dist/commands/pm/enable.js +3 -54
- package/dist/commands/pm/list.js +3 -52
- package/dist/commands/restart.js +3 -65
- package/dist/commands/scaffold/migration.js +1 -1
- package/dist/commands/scaffold/plugin.js +1 -1
- package/dist/commands/skills/remove.js +71 -0
- package/dist/commands/skills/update.js +7 -0
- package/dist/commands/source/build.js +58 -0
- package/dist/commands/source/dev.js +157 -0
- package/dist/commands/source/download.js +866 -0
- package/dist/commands/source/test.js +467 -0
- package/dist/commands/start.js +3 -209
- package/dist/commands/stop.js +3 -88
- package/dist/commands/test.js +3 -457
- package/dist/commands/upgrade.js +3 -585
- package/dist/help/runtime-help.js +3 -0
- package/dist/lib/api-client.js +20 -6
- package/dist/lib/app-health.js +126 -0
- package/dist/lib/app-managed-resources.js +264 -0
- package/dist/lib/auth-store.js +5 -2
- package/dist/lib/cli-home.js +7 -6
- package/dist/lib/cli-locale.js +15 -1
- package/dist/lib/env-config.js +80 -0
- package/dist/lib/prompt-web-ui.js +13 -6
- package/dist/lib/skills-manager.js +34 -7
- package/package.json +27 -4
- package/dist/commands/ps.js +0 -119
package/dist/commands/install.js
CHANGED
|
@@ -16,12 +16,13 @@ import path from 'node:path';
|
|
|
16
16
|
import { exit } from 'node:process';
|
|
17
17
|
import { runPromptCatalog, } from "../lib/prompt-catalog.js";
|
|
18
18
|
import { applyCliLocale, localeText, resolveCliLocale, translateCli, } from "../lib/cli-locale.js";
|
|
19
|
-
import { resolveConfiguredEnvPath, resolveDefaultConfigScope, resolveEnvRelativePath, } from '../lib/cli-home.js';
|
|
19
|
+
import { resolveConfiguredEnvPath, resolveDefaultConfigScope, resolveEnvRoot, resolveEnvRelativePath, } from '../lib/cli-home.js';
|
|
20
20
|
import { findAvailableTcpPort, validateAvailableTcpPort, validateTcpPort, validateEnvKey, } from "../lib/prompt-validators.js";
|
|
21
21
|
import { formatMissingManagedAppEnvMessage } from '../lib/app-runtime.js';
|
|
22
22
|
import { run, runNocoBaseCommand } from '../lib/run-npm.js';
|
|
23
23
|
import { startTask, stopTask, updateTask } from '../lib/ui.js';
|
|
24
|
-
import { ensureWorkspaceName, getEnv } from '../lib/auth-store.js';
|
|
24
|
+
import { ensureWorkspaceName, getEnv, loadAuthConfig, upsertEnv } from '../lib/auth-store.js';
|
|
25
|
+
import { buildStoredEnvConfig } from '../lib/env-config.js';
|
|
25
26
|
import Download, { defaultDockerRegistryForLang, } from './download.js';
|
|
26
27
|
import EnvAdd from "./env/add.js";
|
|
27
28
|
const DEFAULT_INSTALL_ENV_NAME = 'local';
|
|
@@ -245,7 +246,8 @@ async function commandOutput(command, args, options) {
|
|
|
245
246
|
});
|
|
246
247
|
}
|
|
247
248
|
export default class Install extends Command {
|
|
248
|
-
static
|
|
249
|
+
static hidden = true;
|
|
250
|
+
static description = 'Install NocoBase: database, storage, admin user, and `nocobase-v1 install`. Optionally run `nb source download` first; distribution and image details are configured on `nb source download`, not here. Use `--resume` to continue an interrupted setup from the saved workspace env config.';
|
|
249
251
|
static examples = [
|
|
250
252
|
'<%= config.bin %> <%= command.id %>',
|
|
251
253
|
'<%= config.bin %> <%= command.id %> --env app1',
|
|
@@ -276,6 +278,25 @@ export default class Install extends Command {
|
|
|
276
278
|
char: 'e',
|
|
277
279
|
description: 'App/env name to create or update. Defaults app paths to ./<envName>/source/ and ./<envName>/storage/.',
|
|
278
280
|
}),
|
|
281
|
+
'default-api-base-url': Flags.string({
|
|
282
|
+
char: 'd',
|
|
283
|
+
hidden: true,
|
|
284
|
+
description: 'Default API base URL for HTTP API calls, including the /api prefix (e.g. http://localhost:13000/api)',
|
|
285
|
+
}),
|
|
286
|
+
'api-base-url': Flags.string({
|
|
287
|
+
char: 'u',
|
|
288
|
+
description: 'Root URL for HTTP API calls, including the /api prefix (e.g. http://localhost:13000/api)',
|
|
289
|
+
}),
|
|
290
|
+
'auth-type': Flags.string({
|
|
291
|
+
char: 'a',
|
|
292
|
+
description: 'Authentication: token (API key) or oauth (browser login via `nb env auth`)',
|
|
293
|
+
options: ['token', 'oauth'],
|
|
294
|
+
}),
|
|
295
|
+
'access-token': Flags.string({
|
|
296
|
+
char: 't',
|
|
297
|
+
aliases: ['token'],
|
|
298
|
+
description: 'API key or access token when using --auth-type token',
|
|
299
|
+
}),
|
|
279
300
|
lang: Flags.string({ description: 'Language for the installed NocoBase app', char: 'l', required: false }),
|
|
280
301
|
force: Flags.boolean({
|
|
281
302
|
description: 'Reconfigure an existing env and replace conflicting runtime resources when needed',
|
|
@@ -374,7 +395,7 @@ export default class Install extends Command {
|
|
|
374
395
|
type: 'text',
|
|
375
396
|
message: installText('prompts.appPort.message'),
|
|
376
397
|
placeholder: installText('prompts.appPort.placeholder'),
|
|
377
|
-
validate:
|
|
398
|
+
validate: Install.validateAppPort,
|
|
378
399
|
},
|
|
379
400
|
storagePath: {
|
|
380
401
|
type: 'text',
|
|
@@ -434,7 +455,7 @@ export default class Install extends Command {
|
|
|
434
455
|
placeholder: installText('prompts.dbPort.placeholder'),
|
|
435
456
|
initialValue: (values) => defaultDbPortForDialect(values.dbDialect),
|
|
436
457
|
required: true,
|
|
437
|
-
validate:
|
|
458
|
+
validate: Install.validateDbPort,
|
|
438
459
|
hidden: (values) => Boolean(values.builtinDb)
|
|
439
460
|
&& String(values.source ?? '').trim() === 'docker',
|
|
440
461
|
},
|
|
@@ -492,7 +513,7 @@ export default class Install extends Command {
|
|
|
492
513
|
* App catalog with `env` seeded into `out` first so `storagePath`’s `initialValue(values)`
|
|
493
514
|
* sees `values.env` (same iteration order as {@link runPromptCatalog}).
|
|
494
515
|
*/
|
|
495
|
-
static buildAppPromptsCatalog(seedEnv) {
|
|
516
|
+
static buildAppPromptsCatalog(seedEnv, options) {
|
|
496
517
|
return {
|
|
497
518
|
seedEnv: {
|
|
498
519
|
type: 'run',
|
|
@@ -500,12 +521,27 @@ export default class Install extends Command {
|
|
|
500
521
|
values.env = seedEnv;
|
|
501
522
|
},
|
|
502
523
|
},
|
|
524
|
+
seedResume: {
|
|
525
|
+
type: 'run',
|
|
526
|
+
run: (values) => {
|
|
527
|
+
const record = values;
|
|
528
|
+
record.resume = Boolean(options?.resume);
|
|
529
|
+
},
|
|
530
|
+
},
|
|
503
531
|
...Install.appPrompts,
|
|
504
532
|
};
|
|
505
533
|
}
|
|
506
|
-
static buildDbPromptsCatalog(downloadResults) {
|
|
534
|
+
static buildDbPromptsCatalog(envName, downloadResults, options) {
|
|
507
535
|
const source = String(downloadResults.source ?? '').trim();
|
|
508
536
|
return {
|
|
537
|
+
seedEnv: {
|
|
538
|
+
type: 'run',
|
|
539
|
+
run: (values) => {
|
|
540
|
+
if (envName) {
|
|
541
|
+
values.env = envName;
|
|
542
|
+
}
|
|
543
|
+
},
|
|
544
|
+
},
|
|
509
545
|
seedDownloadSource: {
|
|
510
546
|
type: 'run',
|
|
511
547
|
run: (values) => {
|
|
@@ -514,6 +550,13 @@ export default class Install extends Command {
|
|
|
514
550
|
}
|
|
515
551
|
},
|
|
516
552
|
},
|
|
553
|
+
seedResume: {
|
|
554
|
+
type: 'run',
|
|
555
|
+
run: (values) => {
|
|
556
|
+
const record = values;
|
|
557
|
+
record.resume = Boolean(options?.resume);
|
|
558
|
+
},
|
|
559
|
+
},
|
|
517
560
|
...Install.dbPrompts,
|
|
518
561
|
};
|
|
519
562
|
}
|
|
@@ -533,6 +576,25 @@ export default class Install extends Command {
|
|
|
533
576
|
static buildPresetValuesFromFlags(flags) {
|
|
534
577
|
const preset = {};
|
|
535
578
|
const argv = process.argv.slice(2);
|
|
579
|
+
const apiBaseUrl = Install.toOptionalPromptString(flags['api-base-url']);
|
|
580
|
+
if (apiBaseUrl) {
|
|
581
|
+
preset.apiBaseUrl = apiBaseUrl;
|
|
582
|
+
}
|
|
583
|
+
else if (flags['default-api-base-url'] !== undefined) {
|
|
584
|
+
const defaultApiBaseUrl = Install.toOptionalPromptString(flags['default-api-base-url']);
|
|
585
|
+
if (defaultApiBaseUrl) {
|
|
586
|
+
preset.apiBaseUrl = defaultApiBaseUrl;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
if (flags['auth-type'] !== undefined) {
|
|
590
|
+
const authType = Install.toOptionalPromptString(flags['auth-type']);
|
|
591
|
+
if (authType) {
|
|
592
|
+
preset.authType = authType;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
if (flags['access-token'] !== undefined || flags.token !== undefined) {
|
|
596
|
+
preset.accessToken = String(flags['access-token'] ?? flags.token ?? '');
|
|
597
|
+
}
|
|
536
598
|
if (flags.lang !== undefined) {
|
|
537
599
|
const v = String(flags.lang).trim();
|
|
538
600
|
if (v) {
|
|
@@ -650,6 +712,13 @@ export default class Install extends Command {
|
|
|
650
712
|
'rootNickname',
|
|
651
713
|
]);
|
|
652
714
|
}
|
|
715
|
+
static buildEnvAddPresetValuesFromFlags(flags) {
|
|
716
|
+
return pickPresetKeys(Install.buildPresetValuesFromFlags(flags), [
|
|
717
|
+
'apiBaseUrl',
|
|
718
|
+
'authType',
|
|
719
|
+
'accessToken',
|
|
720
|
+
]);
|
|
721
|
+
}
|
|
653
722
|
static toOptionalPromptString(value) {
|
|
654
723
|
if (value === undefined || value === null) {
|
|
655
724
|
return undefined;
|
|
@@ -657,6 +726,131 @@ export default class Install extends Command {
|
|
|
657
726
|
const text = String(value).trim();
|
|
658
727
|
return text || undefined;
|
|
659
728
|
}
|
|
729
|
+
static async validateAppPort(value, values) {
|
|
730
|
+
const formatError = validateTcpPort(value);
|
|
731
|
+
if (formatError) {
|
|
732
|
+
return formatError;
|
|
733
|
+
}
|
|
734
|
+
return await Install.validateResumeAwareTcpPort(value, values, 'app');
|
|
735
|
+
}
|
|
736
|
+
static async validateDbPort(value, values) {
|
|
737
|
+
const formatError = validateTcpPort(value);
|
|
738
|
+
if (formatError) {
|
|
739
|
+
return formatError;
|
|
740
|
+
}
|
|
741
|
+
const builtinDb = values.builtinDb === undefined ? true : Boolean(values.builtinDb);
|
|
742
|
+
const source = String(values.source ?? '').trim();
|
|
743
|
+
if (!builtinDb || source === 'docker') {
|
|
744
|
+
return undefined;
|
|
745
|
+
}
|
|
746
|
+
return await Install.validateResumeAwareTcpPort(value, values, 'db');
|
|
747
|
+
}
|
|
748
|
+
static async validateResumeAwareTcpPort(value, values, target) {
|
|
749
|
+
const portError = await validateAvailableTcpPort(value);
|
|
750
|
+
if (!portError) {
|
|
751
|
+
return undefined;
|
|
752
|
+
}
|
|
753
|
+
const context = await Install.readResumePortValidationContext(values);
|
|
754
|
+
if (!context) {
|
|
755
|
+
return portError;
|
|
756
|
+
}
|
|
757
|
+
const port = Install.toOptionalPromptString(value);
|
|
758
|
+
if (!port) {
|
|
759
|
+
return portError;
|
|
760
|
+
}
|
|
761
|
+
const reusesManagedPort = await Install.isResumeManagedPortReuse({
|
|
762
|
+
target,
|
|
763
|
+
port,
|
|
764
|
+
context,
|
|
765
|
+
});
|
|
766
|
+
return reusesManagedPort ? undefined : portError;
|
|
767
|
+
}
|
|
768
|
+
static async readResumePortValidationContext(values) {
|
|
769
|
+
if (!Boolean(values.resume)) {
|
|
770
|
+
return undefined;
|
|
771
|
+
}
|
|
772
|
+
const envName = Install.toOptionalPromptString(values.env);
|
|
773
|
+
if (!envName) {
|
|
774
|
+
return undefined;
|
|
775
|
+
}
|
|
776
|
+
const source = Install.toOptionalPromptString(values.source);
|
|
777
|
+
const builtinDb = values.builtinDb === undefined ? undefined : Boolean(values.builtinDb);
|
|
778
|
+
const dbDialect = Install.toOptionalPromptString(values.dbDialect);
|
|
779
|
+
const appRootPath = Install.toOptionalPromptString(values.appRootPath);
|
|
780
|
+
const workspaceName = Install.toOptionalPromptString(values.workspaceName)
|
|
781
|
+
?? await Install.resolveResumeWorkspaceName(envName);
|
|
782
|
+
return {
|
|
783
|
+
envName,
|
|
784
|
+
...(workspaceName ? { workspaceName } : {}),
|
|
785
|
+
...(source ? { source } : {}),
|
|
786
|
+
...(builtinDb !== undefined ? { builtinDb } : {}),
|
|
787
|
+
...(dbDialect ? { dbDialect } : {}),
|
|
788
|
+
...(appRootPath ? { appRootPath } : {}),
|
|
789
|
+
};
|
|
790
|
+
}
|
|
791
|
+
static async resolveResumeWorkspaceName(envName) {
|
|
792
|
+
if (!envName) {
|
|
793
|
+
return undefined;
|
|
794
|
+
}
|
|
795
|
+
const config = await loadAuthConfig({ scope: resolveDefaultConfigScope() });
|
|
796
|
+
const stored = String(config.name ?? '').trim();
|
|
797
|
+
return stored || Install.defaultWorkspaceName();
|
|
798
|
+
}
|
|
799
|
+
static async isResumeManagedPortReuse(params) {
|
|
800
|
+
if (params.target === 'app') {
|
|
801
|
+
if ((params.context.source === 'npm' || params.context.source === 'git')
|
|
802
|
+
&& params.context.appRootPath) {
|
|
803
|
+
return await Install.isLocalPm2ProcessUsingPort(params.context.appRootPath, params.port);
|
|
804
|
+
}
|
|
805
|
+
const containerName = Install.buildDockerAppContainerName(params.context.envName, params.context.workspaceName);
|
|
806
|
+
return await Install.isDockerContainerPublishingPort(containerName, params.port);
|
|
807
|
+
}
|
|
808
|
+
if (!params.context.builtinDb || params.context.source === 'docker') {
|
|
809
|
+
return false;
|
|
810
|
+
}
|
|
811
|
+
const containerName = Install.buildBuiltinDbContainerName(params.context.envName, params.context.dbDialect ?? 'postgres', params.context.workspaceName);
|
|
812
|
+
return await Install.isDockerContainerPublishingPort(containerName, params.port);
|
|
813
|
+
}
|
|
814
|
+
static async isDockerContainerPublishingPort(containerName, port) {
|
|
815
|
+
if (!containerName || !port) {
|
|
816
|
+
return false;
|
|
817
|
+
}
|
|
818
|
+
const exists = await commandSucceeds('docker', [
|
|
819
|
+
'container',
|
|
820
|
+
'inspect',
|
|
821
|
+
containerName,
|
|
822
|
+
]);
|
|
823
|
+
if (!exists) {
|
|
824
|
+
return false;
|
|
825
|
+
}
|
|
826
|
+
try {
|
|
827
|
+
const output = await commandOutput('docker', ['port', containerName]);
|
|
828
|
+
return output
|
|
829
|
+
.split(/\r?\n/)
|
|
830
|
+
.some((line) => line.includes(`:${port}`));
|
|
831
|
+
}
|
|
832
|
+
catch {
|
|
833
|
+
return false;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
static async isLocalPm2ProcessUsingPort(appRootPath, port) {
|
|
837
|
+
const cwd = resolveConfiguredEnvPath(appRootPath);
|
|
838
|
+
if (!cwd) {
|
|
839
|
+
return false;
|
|
840
|
+
}
|
|
841
|
+
try {
|
|
842
|
+
const output = await commandOutput('pm2', ['jlist'], { cwd });
|
|
843
|
+
const rows = JSON.parse(output);
|
|
844
|
+
return rows.some((row) => {
|
|
845
|
+
const pmCwd = Install.toOptionalPromptString(row.pm2_env?.pm_cwd);
|
|
846
|
+
const appPort = Install.toOptionalPromptString(row.pm2_env?.env?.APP_PORT);
|
|
847
|
+
return Boolean(pmCwd && appPort && pmCwd === cwd && appPort === port);
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
catch {
|
|
851
|
+
return false;
|
|
852
|
+
}
|
|
853
|
+
}
|
|
660
854
|
static buildResumePresetValues(env) {
|
|
661
855
|
const envName = String(env.name ?? '').trim();
|
|
662
856
|
const config = env.config ?? {};
|
|
@@ -676,6 +870,10 @@ export default class Install extends Command {
|
|
|
676
870
|
const dbUser = Install.toOptionalPromptString(config.dbUser);
|
|
677
871
|
const dbPassword = Install.toOptionalPromptString(config.dbPassword);
|
|
678
872
|
const builtinDbImage = Install.toOptionalPromptString(config.builtinDbImage);
|
|
873
|
+
const rootUsername = Install.toOptionalPromptString(config.rootUsername);
|
|
874
|
+
const rootEmail = Install.toOptionalPromptString(config.rootEmail);
|
|
875
|
+
const rootPassword = Install.toOptionalPromptString(config.rootPassword);
|
|
876
|
+
const rootNickname = Install.toOptionalPromptString(config.rootNickname);
|
|
679
877
|
const auth = config.auth;
|
|
680
878
|
const appPreset = {
|
|
681
879
|
...(appRootPath ? { appRootPath } : {}),
|
|
@@ -717,6 +915,12 @@ export default class Install extends Command {
|
|
|
717
915
|
...(dbUser ? { dbUser } : {}),
|
|
718
916
|
...(dbPassword ? { dbPassword } : {}),
|
|
719
917
|
};
|
|
918
|
+
const rootPreset = {
|
|
919
|
+
...(rootUsername ? { rootUsername } : {}),
|
|
920
|
+
...(rootEmail ? { rootEmail } : {}),
|
|
921
|
+
...(rootPassword ? { rootPassword } : {}),
|
|
922
|
+
...(rootNickname ? { rootNickname } : {}),
|
|
923
|
+
};
|
|
720
924
|
const envAddPreset = {};
|
|
721
925
|
if (auth?.type === 'token') {
|
|
722
926
|
envAddPreset.authType = 'token';
|
|
@@ -734,6 +938,7 @@ export default class Install extends Command {
|
|
|
734
938
|
appPreset,
|
|
735
939
|
downloadPreset,
|
|
736
940
|
dbPreset,
|
|
941
|
+
rootPreset,
|
|
737
942
|
envAddPreset,
|
|
738
943
|
};
|
|
739
944
|
}
|
|
@@ -770,7 +975,7 @@ export default class Install extends Command {
|
|
|
770
975
|
throw new Error([
|
|
771
976
|
`Cannot continue setup for "${env.name}" in non-interactive resume mode yet.`,
|
|
772
977
|
`These setup-only flags are not saved in the env config: ${missingFlags.join(', ')}`,
|
|
773
|
-
`Run \`nb
|
|
978
|
+
`Run \`nb init --env ${env.name} --resume\` without \`--yes\`, or pass those flags again.`,
|
|
774
979
|
].join('\n'));
|
|
775
980
|
}
|
|
776
981
|
}
|
|
@@ -944,7 +1149,7 @@ export default class Install extends Command {
|
|
|
944
1149
|
return normalized || 'nocobase';
|
|
945
1150
|
}
|
|
946
1151
|
static defaultWorkspaceName() {
|
|
947
|
-
return Install.sanitizeDockerResourceName(`nb-${path.basename(
|
|
1152
|
+
return Install.sanitizeDockerResourceName(`nb-${path.basename(resolveEnvRoot(resolveDefaultConfigScope()))}`);
|
|
948
1153
|
}
|
|
949
1154
|
static buildBuiltinDbResourcePrefix(envName, workspaceName) {
|
|
950
1155
|
void envName;
|
|
@@ -1468,7 +1673,7 @@ export default class Install extends Command {
|
|
|
1468
1673
|
p.log.step(source === 'docker'
|
|
1469
1674
|
? 'Downloading Docker image'
|
|
1470
1675
|
: 'Downloading local NocoBase app files');
|
|
1471
|
-
return await this.config.runCommand('download', argv);
|
|
1676
|
+
return await this.config.runCommand('source:download', argv);
|
|
1472
1677
|
}
|
|
1473
1678
|
async downloadLocalApp(params) {
|
|
1474
1679
|
const result = await this.downloadManagedSource({
|
|
@@ -1657,21 +1862,20 @@ export default class Install extends Command {
|
|
|
1657
1862
|
throw new Error(`The application did not become ready in time. Expected \`${healthCheckUrl}\` to respond with \`ok\`, but the last status was: ${Install.formatHealthCheckMessage(lastMessage)}.${logHint}`);
|
|
1658
1863
|
}
|
|
1659
1864
|
async saveInstalledEnv(params) {
|
|
1660
|
-
await
|
|
1865
|
+
await upsertEnv(params.envName, Install.buildSavedEnvConfig(params), { scope: resolveDefaultConfigScope() });
|
|
1661
1866
|
}
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
if (text) {
|
|
1665
|
-
argv.push(flag, text);
|
|
1666
|
-
}
|
|
1667
|
-
}
|
|
1668
|
-
static pushBooleanArgIfSet(argv, flag, value) {
|
|
1669
|
-
if (value === undefined) {
|
|
1867
|
+
async syncInstalledEnvConnection(params) {
|
|
1868
|
+
if (!params.appReady) {
|
|
1670
1869
|
return;
|
|
1671
1870
|
}
|
|
1672
|
-
|
|
1871
|
+
const authType = String(params.envAddResults.authType ?? 'oauth').trim()
|
|
1872
|
+
|| 'oauth';
|
|
1873
|
+
if (authType === 'oauth') {
|
|
1874
|
+
await this.config.runCommand('env:auth', [params.envName]);
|
|
1875
|
+
}
|
|
1876
|
+
await this.config.runCommand('env:update', [params.envName]);
|
|
1673
1877
|
}
|
|
1674
|
-
static
|
|
1878
|
+
static buildSavedEnvConfig(params) {
|
|
1675
1879
|
const appPort = String(params.appResults.appPort ?? DEFAULT_INSTALL_APP_PORT).trim()
|
|
1676
1880
|
|| DEFAULT_INSTALL_APP_PORT;
|
|
1677
1881
|
const storagePath = String(params.appResults.storagePath ?? '').trim()
|
|
@@ -1682,42 +1886,37 @@ export default class Install extends Command {
|
|
|
1682
1886
|
});
|
|
1683
1887
|
const authType = String(params.envAddResults.authType ?? 'oauth').trim()
|
|
1684
1888
|
|| 'oauth';
|
|
1685
|
-
|
|
1686
|
-
params.envName,
|
|
1687
|
-
'--no-intro',
|
|
1688
|
-
'--api-base-url',
|
|
1889
|
+
return buildStoredEnvConfig({
|
|
1689
1890
|
apiBaseUrl,
|
|
1690
|
-
'--auth-type',
|
|
1691
1891
|
authType,
|
|
1692
|
-
|
|
1892
|
+
accessToken: params.envAddResults.accessToken,
|
|
1893
|
+
source: downloadResultsValue(params.downloadResults, 'source'),
|
|
1894
|
+
downloadVersion: downloadResultsValue(params.downloadResults, 'version'),
|
|
1895
|
+
dockerRegistry: downloadResultsValue(params.downloadResults, 'dockerRegistry'),
|
|
1896
|
+
dockerPlatform: downloadResultsValue(params.downloadResults, 'dockerPlatform'),
|
|
1897
|
+
gitUrl: downloadResultsValue(params.downloadResults, 'gitUrl'),
|
|
1898
|
+
npmRegistry: downloadResultsValue(params.downloadResults, 'npmRegistry'),
|
|
1899
|
+
devDependencies: downloadResultsValue(params.downloadResults, 'devDependencies'),
|
|
1900
|
+
build: downloadResultsValue(params.downloadResults, 'build'),
|
|
1901
|
+
buildDts: downloadResultsValue(params.downloadResults, 'buildDts'),
|
|
1902
|
+
appRootPath: params.appResults.appRootPath,
|
|
1693
1903
|
appPort,
|
|
1694
|
-
'--storage-path',
|
|
1695
1904
|
storagePath,
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
Install.pushArgIfValue(argv, '--builtin-db-image', params.dbResults.builtinDbImage);
|
|
1712
|
-
Install.pushArgIfValue(argv, '--db-host', params.dbResults.dbHost);
|
|
1713
|
-
Install.pushArgIfValue(argv, '--db-port', params.dbResults.dbPort);
|
|
1714
|
-
Install.pushArgIfValue(argv, '--db-database', params.dbResults.dbDatabase);
|
|
1715
|
-
Install.pushArgIfValue(argv, '--db-user', params.dbResults.dbUser);
|
|
1716
|
-
Install.pushArgIfValue(argv, '--db-password', params.dbResults.dbPassword);
|
|
1717
|
-
if (authType === 'token') {
|
|
1718
|
-
argv.push('--access-token', String(params.envAddResults.accessToken ?? ''));
|
|
1719
|
-
}
|
|
1720
|
-
return argv;
|
|
1905
|
+
appKey: params.appResults.appKey,
|
|
1906
|
+
timezone: params.appResults.timeZone,
|
|
1907
|
+
builtinDb: params.dbResults.builtinDb,
|
|
1908
|
+
dbDialect: params.dbResults.dbDialect,
|
|
1909
|
+
builtinDbImage: params.dbResults.builtinDbImage,
|
|
1910
|
+
dbHost: params.dbResults.dbHost,
|
|
1911
|
+
dbPort: params.dbResults.dbPort,
|
|
1912
|
+
dbDatabase: params.dbResults.dbDatabase,
|
|
1913
|
+
dbUser: params.dbResults.dbUser,
|
|
1914
|
+
dbPassword: params.dbResults.dbPassword,
|
|
1915
|
+
rootUsername: params.rootResults.rootUsername,
|
|
1916
|
+
rootEmail: params.rootResults.rootEmail,
|
|
1917
|
+
rootPassword: params.rootResults.rootPassword,
|
|
1918
|
+
rootNickname: params.rootResults.rootNickname,
|
|
1919
|
+
});
|
|
1721
1920
|
}
|
|
1722
1921
|
async collectPromptResults(parsed, yes) {
|
|
1723
1922
|
const resumePreset = await this.resolveResumePresetValues(parsed, yes);
|
|
@@ -1737,7 +1936,9 @@ export default class Install extends Command {
|
|
|
1737
1936
|
...(resumePreset?.appPreset ?? {}),
|
|
1738
1937
|
...Install.buildAppPresetValuesFromFlags(parsed),
|
|
1739
1938
|
};
|
|
1740
|
-
const appCatalog = Install.buildAppPromptsCatalog(envName
|
|
1939
|
+
const appCatalog = Install.buildAppPromptsCatalog(envName, {
|
|
1940
|
+
resume: parsed.resume,
|
|
1941
|
+
});
|
|
1741
1942
|
const appResults = await runPromptCatalog(appCatalog, {
|
|
1742
1943
|
initialValues: await Install.buildAppPromptInitialValues({
|
|
1743
1944
|
envName,
|
|
@@ -1752,6 +1953,7 @@ export default class Install extends Command {
|
|
|
1752
1953
|
},
|
|
1753
1954
|
}),
|
|
1754
1955
|
values: appPreset,
|
|
1956
|
+
yesInitialValues: { resume: parsed.resume },
|
|
1755
1957
|
yes,
|
|
1756
1958
|
});
|
|
1757
1959
|
let downloadResults = {};
|
|
@@ -1769,7 +1971,9 @@ export default class Install extends Command {
|
|
|
1769
1971
|
...(resumePreset?.dbPreset ?? {}),
|
|
1770
1972
|
...Install.buildDbPresetValuesFromFlags(parsed),
|
|
1771
1973
|
};
|
|
1772
|
-
const dbResults = await runPromptCatalog(Install.buildDbPromptsCatalog(downloadResults
|
|
1974
|
+
const dbResults = await runPromptCatalog(Install.buildDbPromptsCatalog(envName, downloadResults, {
|
|
1975
|
+
resume: parsed.resume,
|
|
1976
|
+
}), {
|
|
1773
1977
|
initialValues: {
|
|
1774
1978
|
...downloadResults,
|
|
1775
1979
|
...await Install.buildDbPromptInitialValues({
|
|
@@ -1788,7 +1992,10 @@ export default class Install extends Command {
|
|
|
1788
1992
|
const rootPreset = Install.buildRootPresetValuesFromFlags(parsed);
|
|
1789
1993
|
const rootResults = await runPromptCatalog(Install.rootUserPrompts, {
|
|
1790
1994
|
initialValues: {},
|
|
1791
|
-
values:
|
|
1995
|
+
values: {
|
|
1996
|
+
...(resumePreset?.rootPreset ?? {}),
|
|
1997
|
+
...rootPreset,
|
|
1998
|
+
},
|
|
1792
1999
|
yes,
|
|
1793
2000
|
});
|
|
1794
2001
|
const envAddResults = await runPromptCatalog(EnvAdd.prompts, {
|
|
@@ -1798,6 +2005,7 @@ export default class Install extends Command {
|
|
|
1798
2005
|
values: {
|
|
1799
2006
|
name: envName,
|
|
1800
2007
|
...(resumePreset?.envAddPreset ?? {}),
|
|
2008
|
+
...Install.buildEnvAddPresetValuesFromFlags(parsed),
|
|
1801
2009
|
},
|
|
1802
2010
|
yes,
|
|
1803
2011
|
});
|
|
@@ -1836,6 +2044,16 @@ export default class Install extends Command {
|
|
|
1836
2044
|
const workspaceName = usesDockerResources
|
|
1837
2045
|
? await Install.ensureWorkspaceName()
|
|
1838
2046
|
: undefined;
|
|
2047
|
+
if (!parsed.resume) {
|
|
2048
|
+
await this.saveInstalledEnv({
|
|
2049
|
+
envName,
|
|
2050
|
+
appResults,
|
|
2051
|
+
downloadResults,
|
|
2052
|
+
dbResults,
|
|
2053
|
+
rootResults,
|
|
2054
|
+
envAddResults,
|
|
2055
|
+
});
|
|
2056
|
+
}
|
|
1839
2057
|
let builtinDbPlan;
|
|
1840
2058
|
if (Boolean(dbResults.builtinDb)) {
|
|
1841
2059
|
builtinDbPlan = await this.startBuiltinDb({
|
|
@@ -1877,6 +2095,7 @@ export default class Install extends Command {
|
|
|
1877
2095
|
appResults.timeZone = dockerAppPlan.timeZone;
|
|
1878
2096
|
}
|
|
1879
2097
|
else if (source === 'npm' || source === 'git') {
|
|
2098
|
+
const localSource = source === 'npm' ? 'npm' : 'git';
|
|
1880
2099
|
const projectRoot = await this.downloadLocalApp({
|
|
1881
2100
|
envName,
|
|
1882
2101
|
appResults,
|
|
@@ -1885,7 +2104,7 @@ export default class Install extends Command {
|
|
|
1885
2104
|
});
|
|
1886
2105
|
localAppPlan = await this.startLocalApp({
|
|
1887
2106
|
envName,
|
|
1888
|
-
source,
|
|
2107
|
+
source: localSource,
|
|
1889
2108
|
projectRoot,
|
|
1890
2109
|
appResults,
|
|
1891
2110
|
dbResults,
|
|
@@ -1907,12 +2126,20 @@ export default class Install extends Command {
|
|
|
1907
2126
|
containerName: dockerAppPlan?.containerName,
|
|
1908
2127
|
});
|
|
1909
2128
|
}
|
|
1910
|
-
|
|
2129
|
+
if (dockerAppPlan || localAppPlan || builtinDbPlan) {
|
|
2130
|
+
await this.saveInstalledEnv({
|
|
2131
|
+
envName,
|
|
2132
|
+
appResults,
|
|
2133
|
+
downloadResults,
|
|
2134
|
+
dbResults,
|
|
2135
|
+
rootResults,
|
|
2136
|
+
envAddResults,
|
|
2137
|
+
});
|
|
2138
|
+
}
|
|
2139
|
+
await this.syncInstalledEnvConnection({
|
|
1911
2140
|
envName,
|
|
1912
|
-
appResults,
|
|
1913
|
-
downloadResults,
|
|
1914
|
-
dbResults,
|
|
1915
2141
|
envAddResults,
|
|
2142
|
+
appReady: Boolean(dockerAppPlan || localAppPlan),
|
|
1916
2143
|
});
|
|
1917
2144
|
p.outro(dockerAppPlan || localAppPlan
|
|
1918
2145
|
? `NocoBase is ready at http://127.0.0.1:${dockerAppPlan?.appPort ?? localAppPlan?.appPort}`
|
package/dist/commands/logs.js
CHANGED
|
@@ -6,92 +6,7 @@
|
|
|
6
6
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
|
-
import
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
import { printInfo } from '../lib/ui.js';
|
|
13
|
-
function formatLogsFailure(envName, message) {
|
|
14
|
-
return [
|
|
15
|
-
`Couldn't show logs for "${envName}".`,
|
|
16
|
-
'Check that the saved local app or Docker container still exists on this machine, then try again.',
|
|
17
|
-
`Details: ${message}`,
|
|
18
|
-
].join('\n');
|
|
19
|
-
}
|
|
20
|
-
export default class Logs extends Command {
|
|
21
|
-
static description = 'Show NocoBase logs for the selected env. Local npm/git installs use pm2 logs, and Docker installs use docker logs.';
|
|
22
|
-
static examples = [
|
|
23
|
-
'<%= config.bin %> <%= command.id %>',
|
|
24
|
-
'<%= config.bin %> <%= command.id %> --env app1',
|
|
25
|
-
'<%= config.bin %> <%= command.id %> --env app1 --tail 200',
|
|
26
|
-
'<%= config.bin %> <%= command.id %> --env app1 --no-follow',
|
|
27
|
-
];
|
|
28
|
-
static flags = {
|
|
29
|
-
env: Flags.string({
|
|
30
|
-
char: 'e',
|
|
31
|
-
description: 'CLI env name to inspect logs for. Defaults to the current env when omitted',
|
|
32
|
-
}),
|
|
33
|
-
tail: Flags.integer({
|
|
34
|
-
description: 'Number of recent log lines to show before following',
|
|
35
|
-
default: 100,
|
|
36
|
-
min: 0,
|
|
37
|
-
}),
|
|
38
|
-
follow: Flags.boolean({
|
|
39
|
-
char: 'f',
|
|
40
|
-
description: 'Keep streaming new log lines',
|
|
41
|
-
default: true,
|
|
42
|
-
allowNo: true,
|
|
43
|
-
}),
|
|
44
|
-
};
|
|
45
|
-
async run() {
|
|
46
|
-
const { flags } = await this.parse(Logs);
|
|
47
|
-
const requestedEnv = flags.env?.trim() || undefined;
|
|
48
|
-
const runtime = await resolveManagedAppRuntime(requestedEnv);
|
|
49
|
-
if (!runtime) {
|
|
50
|
-
this.error(formatMissingManagedAppEnvMessage(requestedEnv));
|
|
51
|
-
}
|
|
52
|
-
if (runtime.kind === 'http') {
|
|
53
|
-
this.error([
|
|
54
|
-
`Can't show runtime logs for "${runtime.envName}" from this machine.`,
|
|
55
|
-
'This env only has an API connection, so there is no saved local app or Docker container to read logs from.',
|
|
56
|
-
'Connect it to a local checkout or reinstall it with npm, git, or Docker if you want CLI-managed logs.',
|
|
57
|
-
].join('\n'));
|
|
58
|
-
}
|
|
59
|
-
if (runtime.kind === 'ssh') {
|
|
60
|
-
this.error([
|
|
61
|
-
`Can't show runtime logs for "${runtime.envName}" yet.`,
|
|
62
|
-
'SSH env support is reserved but not implemented yet.',
|
|
63
|
-
'Use a local or Docker env for CLI-managed logs for now.',
|
|
64
|
-
].join('\n'));
|
|
65
|
-
}
|
|
66
|
-
const tail = String(flags.tail ?? 100);
|
|
67
|
-
const follow = flags.follow !== false;
|
|
68
|
-
printInfo(follow
|
|
69
|
-
? `Showing logs for "${runtime.envName}" (press Ctrl+C to stop).`
|
|
70
|
-
: `Showing recent logs for "${runtime.envName}".`);
|
|
71
|
-
try {
|
|
72
|
-
if (runtime.kind === 'docker') {
|
|
73
|
-
const dockerArgs = ['logs', '--tail', tail];
|
|
74
|
-
if (follow) {
|
|
75
|
-
dockerArgs.push('--follow');
|
|
76
|
-
}
|
|
77
|
-
dockerArgs.push(runtime.containerName);
|
|
78
|
-
await run('docker', dockerArgs, {
|
|
79
|
-
errorName: 'docker logs',
|
|
80
|
-
stdio: 'inherit',
|
|
81
|
-
});
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
const localArgs = ['pm2', 'logs', '--lines', tail];
|
|
85
|
-
if (!follow) {
|
|
86
|
-
localArgs.push('--nostream');
|
|
87
|
-
}
|
|
88
|
-
await runLocalNocoBaseCommand(runtime, localArgs, {
|
|
89
|
-
stdio: 'inherit',
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
catch (error) {
|
|
93
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
94
|
-
this.error(formatLogsFailure(runtime.envName, message));
|
|
95
|
-
}
|
|
96
|
-
}
|
|
9
|
+
import AppLogs from './app/logs.js';
|
|
10
|
+
export default class Logs extends AppLogs {
|
|
11
|
+
static hidden = true;
|
|
97
12
|
}
|