@nocobase/cli 2.1.0-alpha.26 → 2.1.0-alpha.27
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 +24 -0
- package/README.zh-CN.md +4 -0
- package/dist/commands/app/down.js +2 -3
- package/dist/commands/app/upgrade.js +112 -128
- package/dist/commands/config/delete.js +30 -0
- package/dist/commands/config/get.js +29 -0
- package/dist/commands/config/index.js +20 -0
- package/dist/commands/config/list.js +29 -0
- package/dist/commands/config/set.js +35 -0
- package/dist/commands/db/check.js +230 -0
- package/dist/commands/db/shared.js +1 -1
- package/dist/commands/env/shared.js +1 -1
- package/dist/commands/init.js +0 -1
- package/dist/commands/install.js +87 -35
- package/dist/commands/license/activate.js +357 -0
- package/dist/commands/license/env.js +94 -0
- package/dist/commands/license/generate-id.js +107 -0
- package/dist/commands/license/id.js +52 -0
- package/dist/commands/license/index.js +20 -0
- package/dist/commands/license/plugins/clean.js +98 -0
- package/dist/commands/license/plugins/index.js +20 -0
- package/dist/commands/license/plugins/list.js +50 -0
- package/dist/commands/license/plugins/shared.js +325 -0
- package/dist/commands/license/plugins/sync.js +267 -0
- package/dist/commands/license/shared.js +411 -0
- package/dist/commands/license/status.js +50 -0
- package/dist/lib/api-client.js +74 -3
- package/dist/lib/app-runtime.js +26 -10
- package/dist/lib/auth-store.js +29 -66
- package/dist/lib/build-config.js +8 -0
- package/dist/lib/cli-config.js +176 -0
- package/dist/lib/cli-home.js +6 -21
- package/dist/lib/db-connection-check.js +178 -0
- package/dist/lib/generated-command.js +23 -3
- package/dist/lib/plugin-storage.js +127 -0
- package/dist/lib/prompt-validators.js +4 -4
- package/dist/lib/runtime-generator.js +89 -10
- package/dist/lib/self-manager.js +57 -2
- package/dist/lib/startup-update.js +85 -7
- package/dist/locale/en-US.json +16 -13
- package/dist/locale/zh-CN.json +16 -13
- package/nocobase-ctl.config.json +82 -0
- package/package.json +16 -4
|
@@ -0,0 +1,230 @@
|
|
|
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, Flags } from '@oclif/core';
|
|
10
|
+
import { formatMissingManagedAppEnvMessage, resolveManagedAppRuntime } from '../../lib/app-runtime.js';
|
|
11
|
+
import { checkExternalDbConnection, formatDbCheckAddress, readExternalDbConnectionConfig, } from "../../lib/db-connection-check.js";
|
|
12
|
+
import { commandOutput } from '../../lib/run-npm.js';
|
|
13
|
+
import { validateTcpPort } from "../../lib/prompt-validators.js";
|
|
14
|
+
const DEFAULT_DOCKER_REGISTRY = 'nocobase/nocobase';
|
|
15
|
+
const DEFAULT_DOCKER_VERSION = 'alpha';
|
|
16
|
+
function trimValue(value) {
|
|
17
|
+
const text = String(value ?? '').trim();
|
|
18
|
+
return text || undefined;
|
|
19
|
+
}
|
|
20
|
+
function resolveRequiredDbField(flagValue, envValue) {
|
|
21
|
+
return trimValue(flagValue) ?? trimValue(envValue);
|
|
22
|
+
}
|
|
23
|
+
function normalizeDockerPlatform(value) {
|
|
24
|
+
const text = trimValue(value);
|
|
25
|
+
if (!text || text === 'auto') {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
if (text === 'linux/amd64' || text === 'linux/arm64') {
|
|
29
|
+
return text;
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
function formatMissingFieldsMessage(missing, hasEnv) {
|
|
34
|
+
return [
|
|
35
|
+
'Missing database settings for connectivity check.',
|
|
36
|
+
`Required: ${missing.join(', ')}.`,
|
|
37
|
+
hasEnv
|
|
38
|
+
? 'Pass `--env <name>` to reuse a saved env, or provide the missing `--db-*` flags explicitly.'
|
|
39
|
+
: 'Provide all required `--db-*` flags explicitly, or pass `--env <name>` to reuse a saved env.',
|
|
40
|
+
].join('\n');
|
|
41
|
+
}
|
|
42
|
+
function resolveDbConfigFromFlags(flags, envConfig) {
|
|
43
|
+
return {
|
|
44
|
+
builtinDb: false,
|
|
45
|
+
dbDialect: resolveRequiredDbField(flags['db-dialect'], envConfig?.dbDialect),
|
|
46
|
+
dbHost: resolveRequiredDbField(flags['db-host'], envConfig?.dbHost),
|
|
47
|
+
dbPort: resolveRequiredDbField(flags['db-port'], envConfig?.dbPort),
|
|
48
|
+
dbDatabase: resolveRequiredDbField(flags['db-database'], envConfig?.dbDatabase),
|
|
49
|
+
dbUser: resolveRequiredDbField(flags['db-user'], envConfig?.dbUser),
|
|
50
|
+
dbPassword: flags['db-password'] !== undefined
|
|
51
|
+
? String(flags['db-password'] ?? '')
|
|
52
|
+
: envConfig?.dbPassword !== undefined
|
|
53
|
+
? String(envConfig.dbPassword ?? '')
|
|
54
|
+
: undefined,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function validateDbConfigOrThrow(command, dbConfig, hasEnv) {
|
|
58
|
+
const missing = [];
|
|
59
|
+
if (!dbConfig.dbDialect) {
|
|
60
|
+
missing.push('--db-dialect');
|
|
61
|
+
}
|
|
62
|
+
if (!dbConfig.dbHost) {
|
|
63
|
+
missing.push('--db-host');
|
|
64
|
+
}
|
|
65
|
+
if (!dbConfig.dbPort) {
|
|
66
|
+
missing.push('--db-port');
|
|
67
|
+
}
|
|
68
|
+
if (!dbConfig.dbDatabase) {
|
|
69
|
+
missing.push('--db-database');
|
|
70
|
+
}
|
|
71
|
+
if (!dbConfig.dbUser) {
|
|
72
|
+
missing.push('--db-user');
|
|
73
|
+
}
|
|
74
|
+
if (!dbConfig.dbPassword) {
|
|
75
|
+
missing.push('--db-password');
|
|
76
|
+
}
|
|
77
|
+
if (missing.length > 0) {
|
|
78
|
+
command.error(formatMissingFieldsMessage(missing, hasEnv));
|
|
79
|
+
}
|
|
80
|
+
const portError = validateTcpPort(dbConfig.dbPort);
|
|
81
|
+
if (portError) {
|
|
82
|
+
command.error(portError);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async function resolveDbCheckInput(command, flags) {
|
|
86
|
+
const envName = flags.env?.trim() || undefined;
|
|
87
|
+
if (!envName) {
|
|
88
|
+
const dbConfig = resolveDbConfigFromFlags(flags);
|
|
89
|
+
validateDbConfigOrThrow(command, dbConfig, false);
|
|
90
|
+
return {
|
|
91
|
+
dbConfig,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
const runtime = await resolveManagedAppRuntime(envName);
|
|
95
|
+
if (!runtime) {
|
|
96
|
+
command.error(formatMissingManagedAppEnvMessage(envName));
|
|
97
|
+
}
|
|
98
|
+
const dbConfig = resolveDbConfigFromFlags(flags, runtime.env.config);
|
|
99
|
+
validateDbConfigOrThrow(command, dbConfig, true);
|
|
100
|
+
return {
|
|
101
|
+
envName: runtime.envName,
|
|
102
|
+
kind: runtime.kind,
|
|
103
|
+
runtime: runtime,
|
|
104
|
+
dbConfig,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function buildConnectionConfigOrThrow(command, dbConfig) {
|
|
108
|
+
const connectionConfig = readExternalDbConnectionConfig(dbConfig);
|
|
109
|
+
if (!connectionConfig) {
|
|
110
|
+
command.error('Unsupported or incomplete database settings for connectivity check.');
|
|
111
|
+
}
|
|
112
|
+
return connectionConfig;
|
|
113
|
+
}
|
|
114
|
+
async function runExplicitDbCheck(command, dbConfig) {
|
|
115
|
+
const connectionConfig = buildConnectionConfigOrThrow(command, dbConfig);
|
|
116
|
+
const address = formatDbCheckAddress(connectionConfig);
|
|
117
|
+
const validationError = await checkExternalDbConnection(connectionConfig);
|
|
118
|
+
return {
|
|
119
|
+
ok: !validationError,
|
|
120
|
+
dialect: connectionConfig.dialect,
|
|
121
|
+
address,
|
|
122
|
+
error: validationError ?? null,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
async function runDockerDbCheck(command, runtime, dbConfig) {
|
|
126
|
+
const connectionConfig = buildConnectionConfigOrThrow(command, dbConfig);
|
|
127
|
+
const config = runtime.env.config ?? {};
|
|
128
|
+
const imageRef = `${trimValue(config.dockerRegistry) || DEFAULT_DOCKER_REGISTRY}:${trimValue(config.downloadVersion) || DEFAULT_DOCKER_VERSION}`;
|
|
129
|
+
const args = [
|
|
130
|
+
'run',
|
|
131
|
+
'--rm',
|
|
132
|
+
'--network',
|
|
133
|
+
runtime.dockerNetworkName || runtime.workspaceName,
|
|
134
|
+
];
|
|
135
|
+
const dockerPlatform = normalizeDockerPlatform(config.dockerPlatform);
|
|
136
|
+
if (dockerPlatform) {
|
|
137
|
+
args.push('--platform', dockerPlatform);
|
|
138
|
+
}
|
|
139
|
+
args.push('--entrypoint', 'nb', imageRef, 'db', 'check', '--db-dialect', connectionConfig.dialect, '--db-host', connectionConfig.host, '--db-port', String(connectionConfig.port), '--db-database', connectionConfig.database, '--db-user', connectionConfig.user, '--db-password', connectionConfig.password, '--json');
|
|
140
|
+
const output = await commandOutput('docker', args, {
|
|
141
|
+
errorName: 'docker run',
|
|
142
|
+
});
|
|
143
|
+
let payload;
|
|
144
|
+
try {
|
|
145
|
+
payload = JSON.parse(output);
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
command.error(`Failed to parse database check response from Docker: ${output}`);
|
|
149
|
+
}
|
|
150
|
+
const ok = Boolean(payload.ok);
|
|
151
|
+
const dialect = trimValue(payload.dialect) || connectionConfig.dialect;
|
|
152
|
+
const address = trimValue(payload.address) || formatDbCheckAddress(connectionConfig);
|
|
153
|
+
const error = trimValue(payload.error) || null;
|
|
154
|
+
return {
|
|
155
|
+
ok,
|
|
156
|
+
dialect,
|
|
157
|
+
address,
|
|
158
|
+
error,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
async function runDbCheckForRuntime(command, runtime, dbConfig) {
|
|
162
|
+
if (runtime.kind === 'docker') {
|
|
163
|
+
return await runDockerDbCheck(command, runtime, dbConfig);
|
|
164
|
+
}
|
|
165
|
+
if (runtime.kind === 'local') {
|
|
166
|
+
return await runExplicitDbCheck(command, dbConfig);
|
|
167
|
+
}
|
|
168
|
+
command.error(`Env "${runtime.envName}" does not support automatic database connectivity checks.`);
|
|
169
|
+
}
|
|
170
|
+
export default class DbCheck extends Command {
|
|
171
|
+
static description = 'Check whether a database is reachable using the selected env settings or explicit `--db-*` flags.';
|
|
172
|
+
static examples = [
|
|
173
|
+
'<%= config.bin %> <%= command.id %> --env app1',
|
|
174
|
+
'<%= config.bin %> <%= command.id %> --env app1 --db-password new-secret --json',
|
|
175
|
+
'<%= config.bin %> <%= command.id %> --db-dialect postgres --db-host 127.0.0.1 --db-port 5432 --db-database nocobase --db-user nocobase --db-password secret',
|
|
176
|
+
];
|
|
177
|
+
static flags = {
|
|
178
|
+
env: Flags.string({
|
|
179
|
+
char: 'e',
|
|
180
|
+
description: 'CLI env name to read saved database settings from. Defaults to the current env when omitted.',
|
|
181
|
+
}),
|
|
182
|
+
'db-dialect': Flags.string({
|
|
183
|
+
description: 'Database dialect: postgres, kingbase, mysql, or mariadb.',
|
|
184
|
+
options: ['postgres', 'kingbase', 'mysql', 'mariadb'],
|
|
185
|
+
}),
|
|
186
|
+
'db-host': Flags.string({
|
|
187
|
+
description: 'Database host name or IP address.',
|
|
188
|
+
}),
|
|
189
|
+
'db-port': Flags.string({
|
|
190
|
+
description: 'Database TCP port.',
|
|
191
|
+
}),
|
|
192
|
+
'db-database': Flags.string({
|
|
193
|
+
description: 'Database name.',
|
|
194
|
+
}),
|
|
195
|
+
'db-user': Flags.string({
|
|
196
|
+
description: 'Database username.',
|
|
197
|
+
}),
|
|
198
|
+
'db-password': Flags.string({
|
|
199
|
+
description: 'Database password.',
|
|
200
|
+
}),
|
|
201
|
+
json: Flags.boolean({
|
|
202
|
+
description: 'Output the check result as JSON.',
|
|
203
|
+
default: false,
|
|
204
|
+
}),
|
|
205
|
+
};
|
|
206
|
+
async run() {
|
|
207
|
+
const { flags } = await this.parse(DbCheck);
|
|
208
|
+
const input = await resolveDbCheckInput(this, flags);
|
|
209
|
+
const result = input.runtime
|
|
210
|
+
? await runDbCheckForRuntime(this, input.runtime, input.dbConfig)
|
|
211
|
+
: await runExplicitDbCheck(this, input.dbConfig);
|
|
212
|
+
if (flags.json) {
|
|
213
|
+
this.log(JSON.stringify({
|
|
214
|
+
ok: result.ok,
|
|
215
|
+
env: input.envName,
|
|
216
|
+
kind: input.kind,
|
|
217
|
+
dialect: result.dialect,
|
|
218
|
+
address: result.address,
|
|
219
|
+
error: result.error,
|
|
220
|
+
}, null, 2));
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
if (!result.ok) {
|
|
224
|
+
this.error(result.error ?? 'Database check failed.');
|
|
225
|
+
}
|
|
226
|
+
this.log(input.envName
|
|
227
|
+
? `Database check passed for env "${input.envName}" (${result.dialect} ${result.address}).`
|
|
228
|
+
: `Database check passed (${result.dialect} ${result.address}).`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
@@ -23,7 +23,7 @@ export async function resolveDbRuntime(envName) {
|
|
|
23
23
|
const source = runtime.kind === 'http' || runtime.kind === 'ssh' ? runtime.kind : runtime.source;
|
|
24
24
|
const dbDialect = String(runtime.env.config.dbDialect ?? 'postgres').trim() || 'postgres';
|
|
25
25
|
if ((runtime.kind === 'local' || runtime.kind === 'docker') && runtime.env.config.builtinDb) {
|
|
26
|
-
const containerName = buildDockerDbContainerName(runtime.envName, dbDialect, runtime.workspaceName);
|
|
26
|
+
const containerName = buildDockerDbContainerName(runtime.envName, dbDialect, runtime.dockerContainerPrefix || runtime.workspaceName);
|
|
27
27
|
return {
|
|
28
28
|
kind: 'builtin',
|
|
29
29
|
envName: runtime.envName,
|
|
@@ -141,7 +141,7 @@ export async function dbStatus(runtime) {
|
|
|
141
141
|
return '-';
|
|
142
142
|
}
|
|
143
143
|
const dbDialect = String(runtime.env.config.dbDialect ?? 'postgres').trim() || 'postgres';
|
|
144
|
-
const containerName = buildDockerDbContainerName(runtime.envName, dbDialect, runtime.workspaceName);
|
|
144
|
+
const containerName = buildDockerDbContainerName(runtime.envName, dbDialect, runtime.dockerContainerPrefix || runtime.workspaceName);
|
|
145
145
|
return await dockerStatus(containerName);
|
|
146
146
|
}
|
|
147
147
|
export async function runtimeStatus(runtime) {
|
package/dist/commands/init.js
CHANGED
package/dist/commands/install.js
CHANGED
|
@@ -17,11 +17,14 @@ 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
19
|
import { resolveConfiguredEnvPath, resolveDefaultConfigScope, resolveEnvRoot, resolveEnvRelativePath, } from '../lib/cli-home.js';
|
|
20
|
+
import { defaultDockerContainerPrefix, defaultDockerNetworkName, } from '../lib/app-runtime.js';
|
|
21
|
+
import { resolveDockerContainerPrefix, resolveDockerNetworkName, } from '../lib/cli-config.js';
|
|
20
22
|
import { findAvailableTcpPort, validateAvailableTcpPort, validateTcpPort, validateEnvKey, } from "../lib/prompt-validators.js";
|
|
23
|
+
import { validateExternalDbConfig } from "../lib/db-connection-check.js";
|
|
21
24
|
import { formatMissingManagedAppEnvMessage } from '../lib/app-runtime.js';
|
|
22
25
|
import { run, runNocoBaseCommand } from '../lib/run-npm.js';
|
|
23
26
|
import { startTask, stopTask, updateTask } from '../lib/ui.js';
|
|
24
|
-
import {
|
|
27
|
+
import { getEnv, upsertEnv } from '../lib/auth-store.js';
|
|
25
28
|
import { buildStoredEnvConfig } from '../lib/env-config.js';
|
|
26
29
|
import Download, { defaultDockerRegistryForLang, } from './download.js';
|
|
27
30
|
import EnvAdd from "./env/add.js";
|
|
@@ -180,6 +183,16 @@ function validateBuiltinDbEnabled(value, values) {
|
|
|
180
183
|
}
|
|
181
184
|
return translateCli('commands.install.validation.builtinDbUnsupported', { dialect });
|
|
182
185
|
}
|
|
186
|
+
async function validateExternalDbPromptField(value, values) {
|
|
187
|
+
const builtinDb = values.builtinDb === undefined ? true : Boolean(values.builtinDb);
|
|
188
|
+
if (builtinDb) {
|
|
189
|
+
return undefined;
|
|
190
|
+
}
|
|
191
|
+
if (typeof value === 'string' && value.trim() === '') {
|
|
192
|
+
return undefined;
|
|
193
|
+
}
|
|
194
|
+
return await validateExternalDbConfig(values);
|
|
195
|
+
}
|
|
183
196
|
function defaultInstallAppRootPath(envName) {
|
|
184
197
|
const name = String(envName ?? DEFAULT_INSTALL_ENV_NAME).trim() || DEFAULT_INSTALL_ENV_NAME;
|
|
185
198
|
return `./${name}/source/`;
|
|
@@ -447,6 +460,7 @@ export default class Install extends Command {
|
|
|
447
460
|
initialValue: (values) => defaultDbHostForBuiltinDb(values),
|
|
448
461
|
yesInitialValue: DEFAULT_INSTALL_BUILTIN_DB_HOST,
|
|
449
462
|
required: true,
|
|
463
|
+
validate: validateExternalDbPromptField,
|
|
450
464
|
hidden: (values) => Boolean(values.builtinDb),
|
|
451
465
|
},
|
|
452
466
|
dbPort: {
|
|
@@ -464,6 +478,7 @@ export default class Install extends Command {
|
|
|
464
478
|
message: installText('prompts.dbDatabase.message'),
|
|
465
479
|
initialValue: (values) => defaultDbDatabaseForDialect(values.dbDialect),
|
|
466
480
|
required: true,
|
|
481
|
+
validate: validateExternalDbPromptField,
|
|
467
482
|
},
|
|
468
483
|
dbUser: {
|
|
469
484
|
type: 'text',
|
|
@@ -471,6 +486,7 @@ export default class Install extends Command {
|
|
|
471
486
|
initialValue: DEFAULT_INSTALL_DB_USER,
|
|
472
487
|
yesInitialValue: DEFAULT_INSTALL_DB_USER,
|
|
473
488
|
required: true,
|
|
489
|
+
validate: validateExternalDbPromptField,
|
|
474
490
|
},
|
|
475
491
|
dbPassword: {
|
|
476
492
|
type: 'password',
|
|
@@ -478,6 +494,7 @@ export default class Install extends Command {
|
|
|
478
494
|
initialValue: DEFAULT_INSTALL_DB_PASSWORD,
|
|
479
495
|
yesInitialValue: DEFAULT_INSTALL_DB_PASSWORD,
|
|
480
496
|
required: true,
|
|
497
|
+
validate: validateExternalDbPromptField,
|
|
481
498
|
},
|
|
482
499
|
};
|
|
483
500
|
static rootUserPrompts = {
|
|
@@ -741,6 +758,9 @@ export default class Install extends Command {
|
|
|
741
758
|
const builtinDb = values.builtinDb === undefined ? true : Boolean(values.builtinDb);
|
|
742
759
|
const source = String(values.source ?? '').trim();
|
|
743
760
|
if (!builtinDb || source === 'docker') {
|
|
761
|
+
if (!builtinDb) {
|
|
762
|
+
return await validateExternalDbConfig({ ...values, dbPort: value });
|
|
763
|
+
}
|
|
744
764
|
return undefined;
|
|
745
765
|
}
|
|
746
766
|
return await Install.validateResumeAwareTcpPort(value, values, 'db');
|
|
@@ -765,6 +785,23 @@ export default class Install extends Command {
|
|
|
765
785
|
});
|
|
766
786
|
return reusesManagedPort ? undefined : portError;
|
|
767
787
|
}
|
|
788
|
+
static async ensureExternalDbReadyForInstall(dbResults) {
|
|
789
|
+
const builtinDb = dbResults.builtinDb === undefined ? true : Boolean(dbResults.builtinDb);
|
|
790
|
+
if (builtinDb) {
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
const dialect = String(dbResults.dbDialect ?? 'postgres').trim() || 'postgres';
|
|
794
|
+
const host = String(dbResults.dbHost ?? '').trim();
|
|
795
|
+
const port = String(dbResults.dbPort ?? '').trim();
|
|
796
|
+
const database = String(dbResults.dbDatabase ?? '').trim();
|
|
797
|
+
const address = host && port ? `${host}:${port}` : host || port || '(unknown address)';
|
|
798
|
+
const target = database ? `${address}/${database}` : address;
|
|
799
|
+
p.log.step(`Checking external ${dialect} database: ${target}`);
|
|
800
|
+
const validationError = await validateExternalDbConfig(dbResults);
|
|
801
|
+
if (validationError) {
|
|
802
|
+
throw new Error(validationError);
|
|
803
|
+
}
|
|
804
|
+
}
|
|
768
805
|
static async readResumePortValidationContext(values) {
|
|
769
806
|
if (!Boolean(values.resume)) {
|
|
770
807
|
return undefined;
|
|
@@ -777,24 +814,23 @@ export default class Install extends Command {
|
|
|
777
814
|
const builtinDb = values.builtinDb === undefined ? undefined : Boolean(values.builtinDb);
|
|
778
815
|
const dbDialect = Install.toOptionalPromptString(values.dbDialect);
|
|
779
816
|
const appRootPath = Install.toOptionalPromptString(values.appRootPath);
|
|
780
|
-
const
|
|
781
|
-
|
|
817
|
+
const dockerNetworkName = await Install.resolveResumeDockerNetworkName();
|
|
818
|
+
const dockerContainerPrefix = await Install.resolveResumeDockerContainerPrefix();
|
|
782
819
|
return {
|
|
783
820
|
envName,
|
|
784
|
-
...(
|
|
821
|
+
...(dockerNetworkName ? { dockerNetworkName } : {}),
|
|
822
|
+
...(dockerContainerPrefix ? { dockerContainerPrefix } : {}),
|
|
785
823
|
...(source ? { source } : {}),
|
|
786
824
|
...(builtinDb !== undefined ? { builtinDb } : {}),
|
|
787
825
|
...(dbDialect ? { dbDialect } : {}),
|
|
788
826
|
...(appRootPath ? { appRootPath } : {}),
|
|
789
827
|
};
|
|
790
828
|
}
|
|
791
|
-
static async
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
const stored = String(config.name ?? '').trim();
|
|
797
|
-
return stored || Install.defaultWorkspaceName();
|
|
829
|
+
static async resolveResumeDockerNetworkName() {
|
|
830
|
+
return await resolveDockerNetworkName({ scope: resolveDefaultConfigScope() });
|
|
831
|
+
}
|
|
832
|
+
static async resolveResumeDockerContainerPrefix() {
|
|
833
|
+
return await resolveDockerContainerPrefix({ scope: resolveDefaultConfigScope() });
|
|
798
834
|
}
|
|
799
835
|
static async isResumeManagedPortReuse(params) {
|
|
800
836
|
if (params.target === 'app') {
|
|
@@ -802,13 +838,13 @@ export default class Install extends Command {
|
|
|
802
838
|
&& params.context.appRootPath) {
|
|
803
839
|
return await Install.isLocalPm2ProcessUsingPort(params.context.appRootPath, params.port);
|
|
804
840
|
}
|
|
805
|
-
const containerName = Install.buildDockerAppContainerName(params.context.envName, params.context.
|
|
841
|
+
const containerName = Install.buildDockerAppContainerName(params.context.envName, params.context.dockerContainerPrefix);
|
|
806
842
|
return await Install.isDockerContainerPublishingPort(containerName, params.port);
|
|
807
843
|
}
|
|
808
844
|
if (!params.context.builtinDb || params.context.source === 'docker') {
|
|
809
845
|
return false;
|
|
810
846
|
}
|
|
811
|
-
const containerName = Install.buildBuiltinDbContainerName(params.context.envName, params.context.dbDialect ?? 'postgres', params.context.
|
|
847
|
+
const containerName = Install.buildBuiltinDbContainerName(params.context.envName, params.context.dbDialect ?? 'postgres', params.context.dockerContainerPrefix);
|
|
812
848
|
return await Install.isDockerContainerPublishingPort(containerName, params.port);
|
|
813
849
|
}
|
|
814
850
|
static async isDockerContainerPublishingPort(containerName, port) {
|
|
@@ -1148,27 +1184,33 @@ export default class Install extends Command {
|
|
|
1148
1184
|
.replace(/^-+|-+$/g, '');
|
|
1149
1185
|
return normalized || 'nocobase';
|
|
1150
1186
|
}
|
|
1151
|
-
static
|
|
1152
|
-
return Install.sanitizeDockerResourceName(
|
|
1187
|
+
static defaultDockerNetworkName() {
|
|
1188
|
+
return Install.sanitizeDockerResourceName(defaultDockerNetworkName());
|
|
1153
1189
|
}
|
|
1154
|
-
static
|
|
1155
|
-
|
|
1156
|
-
|
|
1190
|
+
static defaultDockerContainerPrefix() {
|
|
1191
|
+
return Install.sanitizeDockerResourceName(defaultDockerContainerPrefix(resolveEnvRoot(resolveDefaultConfigScope())));
|
|
1192
|
+
}
|
|
1193
|
+
static buildBuiltinDbContainerPrefix(containerPrefix) {
|
|
1194
|
+
const storedName = String(containerPrefix ?? '').trim();
|
|
1157
1195
|
return storedName
|
|
1158
1196
|
? Install.sanitizeDockerResourceName(storedName)
|
|
1159
|
-
: Install.
|
|
1197
|
+
: Install.defaultDockerContainerPrefix();
|
|
1160
1198
|
}
|
|
1161
|
-
static
|
|
1162
|
-
|
|
1199
|
+
static buildManagedDockerNetworkName(networkName) {
|
|
1200
|
+
const storedName = String(networkName ?? '').trim();
|
|
1201
|
+
return storedName
|
|
1202
|
+
? Install.sanitizeDockerResourceName(storedName)
|
|
1203
|
+
: Install.defaultDockerNetworkName();
|
|
1163
1204
|
}
|
|
1164
|
-
static buildBuiltinDbNetworkName(envName,
|
|
1165
|
-
|
|
1205
|
+
static buildBuiltinDbNetworkName(envName, networkName) {
|
|
1206
|
+
void envName;
|
|
1207
|
+
return Install.buildManagedDockerNetworkName(networkName);
|
|
1166
1208
|
}
|
|
1167
|
-
static buildBuiltinDbContainerName(envName, dbDialect,
|
|
1168
|
-
return Install.sanitizeDockerResourceName(`${Install.
|
|
1209
|
+
static buildBuiltinDbContainerName(envName, dbDialect, containerPrefix) {
|
|
1210
|
+
return Install.sanitizeDockerResourceName(`${Install.buildBuiltinDbContainerPrefix(containerPrefix)}-${envName}-${dbDialect}`);
|
|
1169
1211
|
}
|
|
1170
|
-
static buildDockerAppContainerName(envName,
|
|
1171
|
-
return Install.sanitizeDockerResourceName(`${Install.
|
|
1212
|
+
static buildDockerAppContainerName(envName, containerPrefix) {
|
|
1213
|
+
return Install.sanitizeDockerResourceName(`${Install.buildBuiltinDbContainerPrefix(containerPrefix)}-${envName}-app`);
|
|
1172
1214
|
}
|
|
1173
1215
|
static buildInitAppEnvVars(params) {
|
|
1174
1216
|
const out = {};
|
|
@@ -1194,8 +1236,8 @@ export default class Install extends Command {
|
|
|
1194
1236
|
const dbPort = String(params.dbPort ?? defaultDbPortForDialect(dbDialect)).trim()
|
|
1195
1237
|
|| defaultDbPortForDialect(dbDialect);
|
|
1196
1238
|
const defaultDbDatabase = defaultDbDatabaseForDialect(dbDialect);
|
|
1197
|
-
const networkName = Install.buildBuiltinDbNetworkName(params.envName, params.workspaceName);
|
|
1198
|
-
const containerName = Install.buildBuiltinDbContainerName(params.envName, dbDialect, params.workspaceName);
|
|
1239
|
+
const networkName = Install.buildBuiltinDbNetworkName(params.envName, params.dockerNetworkName ?? params.workspaceName);
|
|
1240
|
+
const containerName = Install.buildBuiltinDbContainerName(params.envName, dbDialect, params.dockerContainerPrefix ?? params.workspaceName);
|
|
1199
1241
|
const dbHostInput = String(params.dbHost ?? '').trim();
|
|
1200
1242
|
const dbHost = Install.shouldPublishBuiltinDbPort(params.source)
|
|
1201
1243
|
? (dbHostInput
|
|
@@ -1485,6 +1527,8 @@ export default class Install extends Command {
|
|
|
1485
1527
|
const plan = Install.buildBuiltinDbPlan({
|
|
1486
1528
|
envName: params.envName,
|
|
1487
1529
|
workspaceName: params.workspaceName,
|
|
1530
|
+
dockerNetworkName: params.dockerNetworkName,
|
|
1531
|
+
dockerContainerPrefix: params.dockerContainerPrefix,
|
|
1488
1532
|
storagePath,
|
|
1489
1533
|
source: params.downloadResults.source,
|
|
1490
1534
|
dbDialect: params.dbResults.dbDialect,
|
|
@@ -1532,7 +1576,7 @@ export default class Install extends Command {
|
|
|
1532
1576
|
const dbPassword = String(params.dbResults.dbPassword ?? DEFAULT_INSTALL_DB_PASSWORD) || DEFAULT_INSTALL_DB_PASSWORD;
|
|
1533
1577
|
const appKey = crypto.randomBytes(32).toString('hex');
|
|
1534
1578
|
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC';
|
|
1535
|
-
const containerName = Install.buildDockerAppContainerName(params.envName, params.workspaceName);
|
|
1579
|
+
const containerName = Install.buildDockerAppContainerName(params.envName, params.dockerContainerPrefix ?? params.workspaceName);
|
|
1536
1580
|
const initEnvVars = Install.buildInitAppEnvVars({
|
|
1537
1581
|
appResults: params.appResults,
|
|
1538
1582
|
rootResults: params.rootResults,
|
|
@@ -1580,11 +1624,12 @@ export default class Install extends Command {
|
|
|
1580
1624
|
}
|
|
1581
1625
|
async installDockerApp(params) {
|
|
1582
1626
|
const networkName = params.builtinDbPlan?.networkName
|
|
1583
|
-
?? Install.buildBuiltinDbNetworkName(params.envName, params.workspaceName);
|
|
1627
|
+
?? Install.buildBuiltinDbNetworkName(params.envName, params.dockerNetworkName ?? params.workspaceName);
|
|
1584
1628
|
await this.ensureDockerNetwork(networkName);
|
|
1585
1629
|
const plan = Install.buildDockerAppPlan({
|
|
1586
1630
|
envName: params.envName,
|
|
1587
1631
|
workspaceName: params.workspaceName,
|
|
1632
|
+
dockerContainerPrefix: params.dockerContainerPrefix,
|
|
1588
1633
|
appResults: params.appResults,
|
|
1589
1634
|
downloadResults: params.downloadResults,
|
|
1590
1635
|
dbResults: params.dbResults,
|
|
@@ -2041,9 +2086,13 @@ export default class Install extends Command {
|
|
|
2041
2086
|
const source = String(downloadResultsValue(downloadResults, 'source') ?? '').trim();
|
|
2042
2087
|
const usesDockerResources = Boolean(dbResults.builtinDb)
|
|
2043
2088
|
|| (Boolean(appResults.fetchSource) && source === 'docker');
|
|
2044
|
-
const
|
|
2045
|
-
? await
|
|
2089
|
+
const dockerNetworkName = usesDockerResources
|
|
2090
|
+
? await resolveDockerNetworkName({ scope: resolveDefaultConfigScope() })
|
|
2091
|
+
: undefined;
|
|
2092
|
+
const dockerContainerPrefix = usesDockerResources
|
|
2093
|
+
? await resolveDockerContainerPrefix({ scope: resolveDefaultConfigScope() })
|
|
2046
2094
|
: undefined;
|
|
2095
|
+
await Install.ensureExternalDbReadyForInstall(dbResults);
|
|
2047
2096
|
if (!parsed.resume) {
|
|
2048
2097
|
await this.saveInstalledEnv({
|
|
2049
2098
|
envName,
|
|
@@ -2053,12 +2102,14 @@ export default class Install extends Command {
|
|
|
2053
2102
|
rootResults,
|
|
2054
2103
|
envAddResults,
|
|
2055
2104
|
});
|
|
2105
|
+
p.log.info(`Saved install config for env "${envName}"`);
|
|
2056
2106
|
}
|
|
2057
2107
|
let builtinDbPlan;
|
|
2058
2108
|
if (Boolean(dbResults.builtinDb)) {
|
|
2059
2109
|
builtinDbPlan = await this.startBuiltinDb({
|
|
2060
2110
|
envName,
|
|
2061
|
-
|
|
2111
|
+
dockerNetworkName,
|
|
2112
|
+
dockerContainerPrefix,
|
|
2062
2113
|
appResults,
|
|
2063
2114
|
downloadResults,
|
|
2064
2115
|
dbResults,
|
|
@@ -2082,7 +2133,8 @@ export default class Install extends Command {
|
|
|
2082
2133
|
});
|
|
2083
2134
|
dockerAppPlan = await this.installDockerApp({
|
|
2084
2135
|
envName,
|
|
2085
|
-
|
|
2136
|
+
dockerNetworkName,
|
|
2137
|
+
dockerContainerPrefix,
|
|
2086
2138
|
appResults,
|
|
2087
2139
|
downloadResults,
|
|
2088
2140
|
dbResults,
|