@nocobase/cli 2.1.0-alpha.3 → 2.1.0-alpha.31
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/LICENSE.txt +107 -0
- package/README.md +379 -19
- package/README.zh-CN.md +329 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +131 -0
- package/dist/commands/api/resource/create.js +15 -0
- package/dist/commands/api/resource/destroy.js +15 -0
- package/dist/commands/api/resource/get.js +15 -0
- package/dist/commands/api/resource/index.js +20 -0
- package/dist/commands/api/resource/list.js +16 -0
- package/dist/commands/api/resource/query.js +15 -0
- package/dist/commands/api/resource/update.js +15 -0
- package/dist/commands/app/down.js +266 -0
- package/dist/commands/app/logs.js +98 -0
- package/dist/commands/app/restart.js +75 -0
- package/dist/commands/app/start.js +253 -0
- package/dist/commands/app/stop.js +99 -0
- package/dist/commands/app/upgrade.js +582 -0
- package/{src/cli.js → dist/commands/build.js} +4 -11
- 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 +238 -0
- package/dist/commands/db/logs.js +85 -0
- package/dist/commands/db/ps.js +60 -0
- package/dist/commands/db/shared.js +96 -0
- package/dist/commands/db/start.js +71 -0
- package/dist/commands/db/stop.js +71 -0
- package/{templates/plugin/src/client/models/index.ts → dist/commands/dev.js} +4 -4
- package/{src/index.js → dist/commands/down.js} +4 -6
- package/{src/commands/locale/react-js-cron/index.js → dist/commands/download.js} +4 -8
- package/dist/commands/env/add.js +312 -0
- package/dist/commands/env/auth.js +55 -0
- package/dist/commands/env/info.js +156 -0
- package/dist/commands/env/list.js +50 -0
- package/dist/commands/env/remove.js +59 -0
- package/dist/commands/env/shared.js +158 -0
- package/dist/commands/env/update.js +67 -0
- package/dist/commands/env/use.js +28 -0
- package/dist/commands/examples/prompts-stages.js +150 -0
- package/dist/commands/examples/prompts-test.js +181 -0
- package/dist/commands/init.js +1027 -0
- package/dist/commands/install.js +2206 -0
- package/dist/commands/license/activate.js +360 -0
- package/dist/commands/license/env.js +94 -0
- package/dist/commands/license/generate-id.js +108 -0
- package/dist/commands/license/id.js +56 -0
- package/dist/commands/license/index.js +20 -0
- package/dist/commands/license/plugins/clean.js +101 -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 +269 -0
- package/dist/commands/license/shared.js +414 -0
- package/dist/commands/license/status.js +50 -0
- package/dist/commands/logs.js +12 -0
- package/dist/commands/plugin/disable.js +66 -0
- package/dist/commands/plugin/enable.js +66 -0
- package/dist/commands/plugin/list.js +62 -0
- package/dist/commands/pm/disable.js +12 -0
- package/dist/commands/pm/enable.js +12 -0
- package/dist/commands/pm/list.js +12 -0
- package/dist/commands/restart.js +12 -0
- package/dist/commands/scaffold/migration.js +38 -0
- package/dist/commands/scaffold/plugin.js +37 -0
- package/dist/commands/self/check.js +71 -0
- package/dist/commands/self/index.js +20 -0
- package/dist/commands/self/update.js +86 -0
- package/dist/commands/skills/check.js +69 -0
- package/dist/commands/skills/index.js +20 -0
- package/dist/commands/skills/install.js +71 -0
- package/dist/commands/skills/remove.js +71 -0
- package/dist/commands/skills/update.js +78 -0
- package/dist/commands/source/build.js +58 -0
- package/dist/commands/source/dev.js +158 -0
- package/dist/commands/source/download.js +866 -0
- package/dist/commands/source/test.js +477 -0
- package/dist/commands/start.js +12 -0
- package/dist/commands/stop.js +12 -0
- package/dist/commands/test.js +12 -0
- package/dist/commands/upgrade.js +12 -0
- package/dist/generated/command-registry.js +133 -0
- package/dist/help/runtime-help.js +23 -0
- package/dist/lib/api-client.js +329 -0
- package/dist/lib/app-health.js +126 -0
- package/dist/lib/app-managed-resources.js +268 -0
- package/dist/lib/app-runtime.js +171 -0
- package/dist/lib/auth-store.js +328 -0
- package/dist/lib/bootstrap.js +384 -0
- package/dist/lib/build-config.js +18 -0
- package/dist/lib/builtin-db.js +86 -0
- package/dist/lib/cli-config.js +176 -0
- package/dist/lib/cli-home.js +47 -0
- package/dist/lib/cli-locale.js +129 -0
- package/dist/lib/command-discovery.js +39 -0
- package/dist/lib/db-connection-check.js +178 -0
- package/dist/lib/env-auth.js +872 -0
- package/dist/lib/env-config.js +87 -0
- package/dist/lib/generated-command.js +171 -0
- package/dist/lib/http-request.js +49 -0
- package/dist/lib/naming.js +70 -0
- package/dist/lib/openapi.js +62 -0
- package/dist/lib/plugin-storage.js +127 -0
- package/dist/lib/post-processors.js +23 -0
- package/dist/lib/prompt-catalog.js +581 -0
- package/dist/lib/prompt-validators.js +185 -0
- package/dist/lib/prompt-web-ui.js +2103 -0
- package/dist/lib/resource-command.js +343 -0
- package/dist/lib/resource-request.js +104 -0
- package/dist/lib/run-npm.js +250 -0
- package/dist/lib/runtime-env-vars.js +32 -0
- package/dist/lib/runtime-generator.js +498 -0
- package/dist/lib/runtime-store.js +56 -0
- package/dist/lib/self-manager.js +301 -0
- package/dist/lib/skills-manager.js +296 -0
- package/dist/lib/startup-update.js +281 -0
- package/dist/lib/ui.js +178 -0
- package/dist/locale/en-US.json +339 -0
- package/dist/locale/zh-CN.json +339 -0
- package/dist/post-processors/data-modeling.js +66 -0
- package/dist/post-processors/data-source-manager.js +114 -0
- package/dist/post-processors/index.js +19 -0
- package/nocobase-ctl.config.json +369 -0
- package/package.json +95 -26
- package/LICENSE +0 -661
- package/bin/index.js +0 -39
- package/nocobase.conf.tpl +0 -95
- package/src/commands/benchmark.js +0 -73
- package/src/commands/build.js +0 -49
- package/src/commands/clean.js +0 -30
- package/src/commands/client.js +0 -166
- package/src/commands/create-nginx-conf.js +0 -37
- package/src/commands/create-plugin.js +0 -33
- package/src/commands/dev.js +0 -200
- package/src/commands/doc.js +0 -76
- package/src/commands/e2e.js +0 -265
- package/src/commands/global.js +0 -43
- package/src/commands/index.js +0 -45
- package/src/commands/instance-id.js +0 -47
- package/src/commands/locale/cronstrue.js +0 -122
- package/src/commands/locale/react-js-cron/en-US.json +0 -75
- package/src/commands/locale/react-js-cron/zh-CN.json +0 -33
- package/src/commands/locale/react-js-cron/zh-TW.json +0 -33
- package/src/commands/locale.js +0 -81
- package/src/commands/p-test.js +0 -88
- package/src/commands/perf.js +0 -63
- package/src/commands/pkg.js +0 -321
- package/src/commands/pm2.js +0 -37
- package/src/commands/postinstall.js +0 -88
- package/src/commands/start.js +0 -148
- package/src/commands/tar.js +0 -36
- package/src/commands/test-coverage.js +0 -55
- package/src/commands/test.js +0 -107
- package/src/commands/umi.js +0 -33
- package/src/commands/update-deps.js +0 -72
- package/src/commands/upgrade.js +0 -47
- package/src/commands/view-license-key.js +0 -44
- package/src/license.js +0 -76
- package/src/logger.js +0 -75
- package/src/plugin-generator.js +0 -80
- package/src/util.js +0 -517
- package/templates/bundle-status.html +0 -338
- package/templates/create-app-package.json +0 -39
- package/templates/plugin/.npmignore.tpl +0 -2
- package/templates/plugin/README.md.tpl +0 -1
- package/templates/plugin/client.d.ts +0 -2
- package/templates/plugin/client.js +0 -1
- package/templates/plugin/package.json.tpl +0 -11
- package/templates/plugin/server.d.ts +0 -2
- package/templates/plugin/server.js +0 -1
- package/templates/plugin/src/client/client.d.ts +0 -249
- package/templates/plugin/src/client/index.tsx.tpl +0 -1
- package/templates/plugin/src/client/locale.ts +0 -21
- package/templates/plugin/src/client/plugin.tsx.tpl +0 -10
- package/templates/plugin/src/index.ts +0 -2
- package/templates/plugin/src/locale/en-US.json +0 -1
- package/templates/plugin/src/locale/zh-CN.json +0 -1
- package/templates/plugin/src/server/collections/.gitkeep +0 -0
- package/templates/plugin/src/server/index.ts.tpl +0 -1
- package/templates/plugin/src/server/plugin.ts.tpl +0 -19
|
@@ -0,0 +1,268 @@
|
|
|
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 { mkdir, readdir } from 'node:fs/promises';
|
|
10
|
+
import { dockerContainerExists, startDockerContainer } from './app-runtime.js';
|
|
11
|
+
import { deriveBuiltinDbConnection, resolveBuiltinDbConnection } from './builtin-db.js';
|
|
12
|
+
import { resolveConfiguredEnvPath } from './cli-home.js';
|
|
13
|
+
import { commandSucceeds, run } from './run-npm.js';
|
|
14
|
+
import Install from '../commands/install.js';
|
|
15
|
+
const DEFAULT_DOCKER_REGISTRY = 'nocobase/nocobase';
|
|
16
|
+
const DEFAULT_DOCKER_VERSION = 'alpha';
|
|
17
|
+
const DOCKER_APP_STORAGE_DESTINATION = '/app/nocobase/storage';
|
|
18
|
+
function commandStdio(verbose) {
|
|
19
|
+
return verbose ? 'inherit' : 'ignore';
|
|
20
|
+
}
|
|
21
|
+
async function ensureDockerNetwork(networkName) {
|
|
22
|
+
if (await commandSucceeds('docker', ['network', 'inspect', networkName])) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
await run('docker', ['network', 'create', networkName], {
|
|
26
|
+
errorName: 'docker network create',
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
function localSourceLabel(source) {
|
|
30
|
+
return source === 'git' ? 'Git checkout' : 'npm app';
|
|
31
|
+
}
|
|
32
|
+
function trimValue(value) {
|
|
33
|
+
return String(value ?? '').trim();
|
|
34
|
+
}
|
|
35
|
+
function normalizeDockerPlatform(value) {
|
|
36
|
+
const text = trimValue(value);
|
|
37
|
+
if (!text || text === 'auto') {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
if (text === 'linux/amd64' || text === 'linux/arm64') {
|
|
41
|
+
return text;
|
|
42
|
+
}
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
function formatBuiltinDbFailure(envName, message) {
|
|
46
|
+
return [
|
|
47
|
+
`Couldn't restore the built-in database for "${envName}".`,
|
|
48
|
+
'Check the saved database settings, local storage path, and Docker runtime, then try again.',
|
|
49
|
+
`Details: ${message}`,
|
|
50
|
+
].join('\n');
|
|
51
|
+
}
|
|
52
|
+
function formatLocalSourceRestoreFailure(envName, source, message) {
|
|
53
|
+
const sourceLabel = source === 'git' ? 'the saved Git checkout' : 'the saved npm app';
|
|
54
|
+
return [
|
|
55
|
+
`Couldn't restore NocoBase files for "${envName}".`,
|
|
56
|
+
`The CLI was not able to download ${sourceLabel} before starting the app again.`,
|
|
57
|
+
'Check the saved source settings for this env, then try again.',
|
|
58
|
+
`Details: ${message}`,
|
|
59
|
+
].join('\n');
|
|
60
|
+
}
|
|
61
|
+
function formatSavedDockerSettingsIncomplete(envName, missing) {
|
|
62
|
+
return [
|
|
63
|
+
`Can't start NocoBase for "${envName}" yet.`,
|
|
64
|
+
`The saved Docker settings for this env are incomplete. Missing: ${missing.join(', ')}.`,
|
|
65
|
+
'Re-run `nb init` or `nb env add` to refresh this env config, then try again.',
|
|
66
|
+
].join('\n');
|
|
67
|
+
}
|
|
68
|
+
function formatDockerAppRecreateFailure(envName, message) {
|
|
69
|
+
return [
|
|
70
|
+
`Couldn't start NocoBase for "${envName}".`,
|
|
71
|
+
'The CLI was not able to recreate the saved Docker app container successfully.',
|
|
72
|
+
'Check the saved Docker image, container settings, and database connection, then try again.',
|
|
73
|
+
`Details: ${message}`,
|
|
74
|
+
].join('\n');
|
|
75
|
+
}
|
|
76
|
+
async function localProjectHasFiles(projectRoot) {
|
|
77
|
+
try {
|
|
78
|
+
const entries = await readdir(projectRoot);
|
|
79
|
+
return entries.length > 0;
|
|
80
|
+
}
|
|
81
|
+
catch (_error) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
export function buildSavedDockerRunArgs(runtime) {
|
|
86
|
+
const config = runtime.env.config ?? {};
|
|
87
|
+
const configuredStoragePath = trimValue(config.storagePath);
|
|
88
|
+
const storagePath = configuredStoragePath
|
|
89
|
+
? trimValue(resolveConfiguredEnvPath(configuredStoragePath))
|
|
90
|
+
: '';
|
|
91
|
+
const appPort = runtime.env.appPort === undefined || runtime.env.appPort === null
|
|
92
|
+
? ''
|
|
93
|
+
: trimValue(runtime.env.appPort);
|
|
94
|
+
const appKey = trimValue(config.appKey);
|
|
95
|
+
const timeZone = trimValue(config.timezone) || Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC';
|
|
96
|
+
const builtinDbConnection = config.builtinDb ? deriveBuiltinDbConnection(runtime) : undefined;
|
|
97
|
+
const dbDialect = builtinDbConnection?.dbDialect || trimValue(config.dbDialect);
|
|
98
|
+
const dbHost = builtinDbConnection?.dbHost || trimValue(config.dbHost);
|
|
99
|
+
const dbPort = builtinDbConnection?.dbPort || trimValue(config.dbPort);
|
|
100
|
+
const dbDatabase = trimValue(config.dbDatabase);
|
|
101
|
+
const dbUser = trimValue(config.dbUser);
|
|
102
|
+
const dbPassword = trimValue(config.dbPassword);
|
|
103
|
+
const dockerRegistry = trimValue(config.dockerRegistry) || DEFAULT_DOCKER_REGISTRY;
|
|
104
|
+
const version = trimValue(config.downloadVersion) || DEFAULT_DOCKER_VERSION;
|
|
105
|
+
const imageRef = `${dockerRegistry}:${version}`;
|
|
106
|
+
const missing = [];
|
|
107
|
+
if (!storagePath) {
|
|
108
|
+
missing.push('storagePath');
|
|
109
|
+
}
|
|
110
|
+
if (!appKey) {
|
|
111
|
+
missing.push('appKey');
|
|
112
|
+
}
|
|
113
|
+
if (!dbDialect) {
|
|
114
|
+
missing.push('dbDialect');
|
|
115
|
+
}
|
|
116
|
+
if (!dbHost) {
|
|
117
|
+
missing.push('dbHost');
|
|
118
|
+
}
|
|
119
|
+
if (!dbPort) {
|
|
120
|
+
missing.push('dbPort');
|
|
121
|
+
}
|
|
122
|
+
if (!dbDatabase) {
|
|
123
|
+
missing.push('dbDatabase');
|
|
124
|
+
}
|
|
125
|
+
if (!dbUser) {
|
|
126
|
+
missing.push('dbUser');
|
|
127
|
+
}
|
|
128
|
+
if (!dbPassword) {
|
|
129
|
+
missing.push('dbPassword');
|
|
130
|
+
}
|
|
131
|
+
if (missing.length > 0) {
|
|
132
|
+
throw new Error(formatSavedDockerSettingsIncomplete(runtime.envName, missing));
|
|
133
|
+
}
|
|
134
|
+
const args = [
|
|
135
|
+
'run',
|
|
136
|
+
'-d',
|
|
137
|
+
'--name',
|
|
138
|
+
runtime.containerName,
|
|
139
|
+
'--restart',
|
|
140
|
+
'always',
|
|
141
|
+
'--network',
|
|
142
|
+
runtime.workspaceName,
|
|
143
|
+
];
|
|
144
|
+
const dockerPlatform = normalizeDockerPlatform(config.dockerPlatform);
|
|
145
|
+
if (dockerPlatform) {
|
|
146
|
+
args.push('--platform', dockerPlatform);
|
|
147
|
+
}
|
|
148
|
+
if (appPort) {
|
|
149
|
+
args.push('-p', `${appPort}:80`);
|
|
150
|
+
}
|
|
151
|
+
args.push('-e', `APP_KEY=${appKey}`, '-e', `DB_DIALECT=${dbDialect}`, '-e', `DB_HOST=${dbHost}`, '-e', `DB_PORT=${dbPort}`, '-e', `DB_DATABASE=${dbDatabase}`, '-e', `DB_USER=${dbUser}`, '-e', `DB_PASSWORD=${dbPassword}`, '-e', `TZ=${timeZone}`, '-v', `${storagePath}:${DOCKER_APP_STORAGE_DESTINATION}`, imageRef);
|
|
152
|
+
return {
|
|
153
|
+
appPort: appPort || undefined,
|
|
154
|
+
storagePath,
|
|
155
|
+
imageRef,
|
|
156
|
+
args,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
export async function recreateSavedDockerApp(runtime, options) {
|
|
160
|
+
const plan = buildSavedDockerRunArgs(runtime);
|
|
161
|
+
try {
|
|
162
|
+
await ensureDockerNetwork(runtime.workspaceName);
|
|
163
|
+
await mkdir(plan.storagePath, { recursive: true });
|
|
164
|
+
await run('docker', plan.args, {
|
|
165
|
+
errorName: 'docker run',
|
|
166
|
+
stdio: commandStdio(options?.verbose),
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
171
|
+
if (message.includes(`Can't start NocoBase for "${runtime.envName}" yet.`)
|
|
172
|
+
|| message.includes(`Couldn't start NocoBase for "${runtime.envName}".`)) {
|
|
173
|
+
throw error instanceof Error ? error : new Error(message);
|
|
174
|
+
}
|
|
175
|
+
throw new Error(formatDockerAppRecreateFailure(runtime.envName, message));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
export async function ensureBuiltinDbReady(runtime, options) {
|
|
179
|
+
const config = runtime.env.config ?? {};
|
|
180
|
+
if (!config.builtinDb) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const builtinDbConnection = await resolveBuiltinDbConnection(runtime);
|
|
184
|
+
const plan = Install.buildBuiltinDbPlan({
|
|
185
|
+
envName: runtime.envName,
|
|
186
|
+
workspaceName: runtime.workspaceName,
|
|
187
|
+
dockerContainerPrefix: runtime.dockerContainerPrefix,
|
|
188
|
+
storagePath: config.storagePath,
|
|
189
|
+
source: runtime.source,
|
|
190
|
+
dbDialect: builtinDbConnection.dbDialect,
|
|
191
|
+
dbHost: builtinDbConnection.dbHost,
|
|
192
|
+
dbPort: builtinDbConnection.dbPort,
|
|
193
|
+
dbDatabase: config.dbDatabase,
|
|
194
|
+
dbUser: config.dbUser,
|
|
195
|
+
dbPassword: config.dbPassword,
|
|
196
|
+
builtinDbImage: config.builtinDbImage,
|
|
197
|
+
});
|
|
198
|
+
options?.onStartTask?.(`Restoring the built-in ${plan.dbDialect} database for "${runtime.envName}"...`);
|
|
199
|
+
try {
|
|
200
|
+
await ensureDockerNetwork(plan.networkName);
|
|
201
|
+
if (await dockerContainerExists(plan.containerName)) {
|
|
202
|
+
const state = await startDockerContainer(plan.containerName, {
|
|
203
|
+
stdio: commandStdio(options?.verbose),
|
|
204
|
+
});
|
|
205
|
+
options?.onSucceedTask?.(state === 'already-running'
|
|
206
|
+
? `The built-in ${plan.dbDialect} database is already running for "${runtime.envName}" at ${plan.dbHost}:${plan.dbPort}.`
|
|
207
|
+
: `The built-in ${plan.dbDialect} database is running for "${runtime.envName}" at ${plan.dbHost}:${plan.dbPort}.`);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
await mkdir(plan.dataDir, { recursive: true });
|
|
211
|
+
await run('docker', plan.args, {
|
|
212
|
+
errorName: 'docker run',
|
|
213
|
+
stdio: commandStdio(options?.verbose),
|
|
214
|
+
});
|
|
215
|
+
options?.onSucceedTask?.(`The built-in ${plan.dbDialect} database is running for "${runtime.envName}" at ${plan.dbHost}:${plan.dbPort}.`);
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
options?.onFailTask?.(`Failed to restore the built-in database for "${runtime.envName}".`);
|
|
219
|
+
throw new Error(formatBuiltinDbFailure(runtime.envName, error instanceof Error ? error.message : String(error)));
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
export function buildSavedLocalDownloadArgv(runtime, options) {
|
|
223
|
+
const config = runtime.env.config ?? {};
|
|
224
|
+
const argv = ['-y', '--no-intro'];
|
|
225
|
+
if (options?.verbose) {
|
|
226
|
+
argv.push('--verbose');
|
|
227
|
+
}
|
|
228
|
+
argv.push('--source', runtime.source, '--replace', '--output-dir', runtime.projectRoot);
|
|
229
|
+
const version = String(config.downloadVersion ?? '').trim();
|
|
230
|
+
const gitUrl = String(config.gitUrl ?? '').trim();
|
|
231
|
+
const npmRegistry = String(config.npmRegistry ?? '').trim();
|
|
232
|
+
if (version) {
|
|
233
|
+
argv.push('--version', version);
|
|
234
|
+
}
|
|
235
|
+
if (gitUrl) {
|
|
236
|
+
argv.push('--git-url', gitUrl);
|
|
237
|
+
}
|
|
238
|
+
if (npmRegistry) {
|
|
239
|
+
argv.push('--npm-registry', npmRegistry);
|
|
240
|
+
}
|
|
241
|
+
if (config.devDependencies === true) {
|
|
242
|
+
argv.push('--dev-dependencies');
|
|
243
|
+
}
|
|
244
|
+
if (config.build === false) {
|
|
245
|
+
argv.push('--no-build');
|
|
246
|
+
}
|
|
247
|
+
if (config.buildDts === true) {
|
|
248
|
+
argv.push('--build-dts');
|
|
249
|
+
}
|
|
250
|
+
return argv;
|
|
251
|
+
}
|
|
252
|
+
export async function ensureSavedLocalSource(runtime, runCommand, options) {
|
|
253
|
+
if (await localProjectHasFiles(runtime.projectRoot)) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
const sourceLabel = localSourceLabel(runtime.source);
|
|
257
|
+
options?.onStartTask?.(`Restoring the saved ${sourceLabel} for "${runtime.envName}"...`);
|
|
258
|
+
try {
|
|
259
|
+
await runCommand('source:download', buildSavedLocalDownloadArgv(runtime, {
|
|
260
|
+
verbose: options?.verbose,
|
|
261
|
+
}));
|
|
262
|
+
options?.onSucceedTask?.(`NocoBase files are ready for "${runtime.envName}".`);
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
options?.onFailTask?.(`Failed to restore NocoBase files for "${runtime.envName}".`);
|
|
266
|
+
throw new Error(formatLocalSourceRestoreFailure(runtime.envName, runtime.source, error instanceof Error ? error.message : String(error)));
|
|
267
|
+
}
|
|
268
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
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 path from 'node:path';
|
|
10
|
+
import { resolveEnvKind } from './auth-store.js';
|
|
11
|
+
import { getEnv, loadAuthConfig } from './auth-store.js';
|
|
12
|
+
import { DEFAULT_DOCKER_CONTAINER_PREFIX, DEFAULT_DOCKER_NETWORK, getEffectiveCliConfigValue, } from './cli-config.js';
|
|
13
|
+
import { commandOutput, commandSucceeds, run, runNocoBaseCommand } from './run-npm.js';
|
|
14
|
+
import { buildRuntimeEnvVars } from './runtime-env-vars.js';
|
|
15
|
+
const DOCKER_APP_WORKDIR = '/app/nocobase';
|
|
16
|
+
function sanitizeDockerResourceName(value) {
|
|
17
|
+
const normalized = value
|
|
18
|
+
.trim()
|
|
19
|
+
.toLowerCase()
|
|
20
|
+
.replace(/[^a-z0-9_.-]+/g, '-')
|
|
21
|
+
.replace(/-+/g, '-')
|
|
22
|
+
.replace(/^-+|-+$/g, '');
|
|
23
|
+
return normalized || 'nocobase';
|
|
24
|
+
}
|
|
25
|
+
export function defaultWorkspaceName(cwd = process.cwd()) {
|
|
26
|
+
return sanitizeDockerResourceName(`nb-${path.basename(cwd)}`);
|
|
27
|
+
}
|
|
28
|
+
export function defaultDockerContainerPrefix(cwd = process.cwd()) {
|
|
29
|
+
const configured = String(DEFAULT_DOCKER_CONTAINER_PREFIX ?? '').trim();
|
|
30
|
+
if (configured) {
|
|
31
|
+
return sanitizeDockerResourceName(configured);
|
|
32
|
+
}
|
|
33
|
+
return defaultWorkspaceName(cwd);
|
|
34
|
+
}
|
|
35
|
+
export function defaultDockerNetworkName() {
|
|
36
|
+
return sanitizeDockerResourceName(DEFAULT_DOCKER_NETWORK);
|
|
37
|
+
}
|
|
38
|
+
export function buildDockerAppContainerName(envName, containerPrefix) {
|
|
39
|
+
const prefix = containerPrefix?.trim() || defaultDockerContainerPrefix();
|
|
40
|
+
return sanitizeDockerResourceName(`${prefix}-${envName}-app`);
|
|
41
|
+
}
|
|
42
|
+
export function buildDockerDbContainerName(envName, dbDialect, containerPrefix) {
|
|
43
|
+
const prefix = containerPrefix?.trim() || defaultDockerContainerPrefix();
|
|
44
|
+
const dialect = dbDialect.trim() || 'postgres';
|
|
45
|
+
return sanitizeDockerResourceName(`${prefix}-${envName}-${dialect}`);
|
|
46
|
+
}
|
|
47
|
+
function normalizeEnvSource(env) {
|
|
48
|
+
const source = String(env.config.source ?? '').trim();
|
|
49
|
+
if (source === 'docker' || source === 'npm' || source === 'git') {
|
|
50
|
+
return source;
|
|
51
|
+
}
|
|
52
|
+
const kind = resolveEnvKind(env.config);
|
|
53
|
+
if (kind === 'local') {
|
|
54
|
+
return 'local';
|
|
55
|
+
}
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
export async function resolveManagedAppRuntime(envName) {
|
|
59
|
+
const config = await loadAuthConfig();
|
|
60
|
+
const env = await getEnv(envName, { config });
|
|
61
|
+
if (!env) {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
const resolvedName = env.name || envName?.trim() || config.currentEnv || 'default';
|
|
65
|
+
const source = normalizeEnvSource(env);
|
|
66
|
+
const dockerNetworkName = sanitizeDockerResourceName(getEffectiveCliConfigValue(config, 'docker.network') || defaultDockerNetworkName());
|
|
67
|
+
const dockerContainerPrefix = sanitizeDockerResourceName(getEffectiveCliConfigValue(config, 'docker.container-prefix') || defaultDockerContainerPrefix());
|
|
68
|
+
const kind = env.kind ?? resolveEnvKind(env.config);
|
|
69
|
+
if (kind === 'docker') {
|
|
70
|
+
return {
|
|
71
|
+
kind: 'docker',
|
|
72
|
+
env,
|
|
73
|
+
envName: resolvedName,
|
|
74
|
+
source: 'docker',
|
|
75
|
+
dockerNetworkName,
|
|
76
|
+
dockerContainerPrefix,
|
|
77
|
+
workspaceName: dockerNetworkName,
|
|
78
|
+
containerName: buildDockerAppContainerName(resolvedName, dockerContainerPrefix),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
if (kind === 'local') {
|
|
82
|
+
return {
|
|
83
|
+
kind: 'local',
|
|
84
|
+
env,
|
|
85
|
+
envName: resolvedName,
|
|
86
|
+
source: source === 'git' ? 'git' : source === 'npm' ? 'npm' : 'local',
|
|
87
|
+
projectRoot: env.appRootPath,
|
|
88
|
+
dockerNetworkName,
|
|
89
|
+
dockerContainerPrefix,
|
|
90
|
+
workspaceName: dockerNetworkName,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
if (kind === 'ssh') {
|
|
94
|
+
return {
|
|
95
|
+
kind: 'ssh',
|
|
96
|
+
env,
|
|
97
|
+
envName: resolvedName,
|
|
98
|
+
source,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
kind: 'http',
|
|
103
|
+
env,
|
|
104
|
+
envName: resolvedName,
|
|
105
|
+
source,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
export function formatMissingManagedAppEnvMessage(envName) {
|
|
109
|
+
const requested = String(envName ?? '').trim();
|
|
110
|
+
if (requested) {
|
|
111
|
+
return [
|
|
112
|
+
`Env "${requested}" is not configured in this workspace.`,
|
|
113
|
+
`If you want to create a new NocoBase AI environment, run \`nb init --env ${requested}\` first.`,
|
|
114
|
+
].join('\n');
|
|
115
|
+
}
|
|
116
|
+
return 'No NocoBase env is configured yet. Run `nb init` to create one first.';
|
|
117
|
+
}
|
|
118
|
+
export async function runLocalNocoBaseCommand(runtime, args, options) {
|
|
119
|
+
const envVars = await buildRuntimeEnvVars(runtime);
|
|
120
|
+
await runNocoBaseCommand(args, {
|
|
121
|
+
cwd: runtime.projectRoot,
|
|
122
|
+
env: envVars,
|
|
123
|
+
stdio: options?.stdio,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
export async function dockerContainerExists(containerName) {
|
|
127
|
+
return await commandSucceeds('docker', ['container', 'inspect', containerName]);
|
|
128
|
+
}
|
|
129
|
+
export async function dockerContainerIsRunning(containerName) {
|
|
130
|
+
try {
|
|
131
|
+
const output = await commandOutput('docker', ['inspect', '--format', '{{.State.Running}}', containerName], { errorName: 'docker inspect' });
|
|
132
|
+
return output.trim() === 'true';
|
|
133
|
+
}
|
|
134
|
+
catch (_error) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
export async function startDockerContainer(containerName, options) {
|
|
139
|
+
const exists = await dockerContainerExists(containerName);
|
|
140
|
+
if (!exists) {
|
|
141
|
+
throw new Error(`Docker app container "${containerName}" does not exist.`);
|
|
142
|
+
}
|
|
143
|
+
if (await dockerContainerIsRunning(containerName)) {
|
|
144
|
+
return 'already-running';
|
|
145
|
+
}
|
|
146
|
+
await run('docker', ['start', containerName], {
|
|
147
|
+
errorName: 'docker start',
|
|
148
|
+
stdio: options?.stdio,
|
|
149
|
+
});
|
|
150
|
+
return 'started';
|
|
151
|
+
}
|
|
152
|
+
export async function stopDockerContainer(containerName, options) {
|
|
153
|
+
const exists = await dockerContainerExists(containerName);
|
|
154
|
+
if (!exists) {
|
|
155
|
+
throw new Error(`Docker app container "${containerName}" does not exist.`);
|
|
156
|
+
}
|
|
157
|
+
if (!(await dockerContainerIsRunning(containerName))) {
|
|
158
|
+
return 'already-stopped';
|
|
159
|
+
}
|
|
160
|
+
await run('docker', ['stop', containerName], {
|
|
161
|
+
errorName: 'docker stop',
|
|
162
|
+
stdio: options?.stdio,
|
|
163
|
+
});
|
|
164
|
+
return 'stopped';
|
|
165
|
+
}
|
|
166
|
+
export async function runDockerNocoBaseCommand(containerName, args) {
|
|
167
|
+
await startDockerContainer(containerName);
|
|
168
|
+
await run('docker', ['exec', '-w', DOCKER_APP_WORKDIR, containerName, 'yarn', 'nocobase', ...args], {
|
|
169
|
+
errorName: 'docker exec',
|
|
170
|
+
});
|
|
171
|
+
}
|