@nocobase/cli 2.1.0-beta.9 → 2.1.0-rc.2
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.cmd +3 -0
- package/bin/run.js +145 -0
- package/bin/session-env.js +39 -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/autostart/disable.js +55 -0
- package/dist/commands/app/autostart/enable.js +55 -0
- package/dist/commands/app/autostart/list.js +37 -0
- package/dist/commands/app/autostart/run.js +84 -0
- package/dist/commands/app/autostart/shared.js +49 -0
- package/dist/commands/app/destroy.js +234 -0
- package/dist/commands/app/down.js +71 -0
- package/dist/commands/app/logs.js +115 -0
- package/dist/commands/app/restart.js +229 -0
- package/dist/commands/app/shared.js +123 -0
- package/dist/commands/app/start.js +416 -0
- package/dist/commands/app/stop.js +183 -0
- package/dist/commands/app/upgrade.js +523 -0
- package/dist/commands/backup/create.js +147 -0
- package/dist/commands/backup/index.js +20 -0
- package/dist/commands/backup/restore.js +105 -0
- package/{src/cli.js → dist/commands/build.js} +4 -11
- package/dist/commands/config/delete.js +42 -0
- package/dist/commands/config/get.js +39 -0
- package/dist/commands/config/index.js +20 -0
- package/dist/commands/config/list.js +29 -0
- package/dist/commands/config/set.js +49 -0
- package/dist/commands/db/check.js +240 -0
- package/dist/commands/db/logs.js +85 -0
- package/dist/commands/db/ps.js +47 -0
- package/dist/commands/db/shared.js +96 -0
- package/dist/commands/db/start.js +86 -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/commands/locale/react-js-cron/index.js → dist/commands/down.js} +3 -8
- package/dist/commands/download.js +13 -0
- package/dist/commands/env/add.js +406 -0
- package/dist/commands/env/auth.js +189 -0
- package/dist/commands/env/current.js +21 -0
- package/dist/commands/env/info.js +202 -0
- package/dist/commands/env/list.js +43 -0
- package/dist/commands/env/remove.js +174 -0
- package/dist/commands/env/shared.js +204 -0
- package/dist/commands/env/status.js +93 -0
- package/dist/commands/env/update.js +448 -0
- package/dist/commands/env/use.js +38 -0
- package/dist/commands/examples/prompts-stages.js +150 -0
- package/dist/commands/examples/prompts-test.js +181 -0
- package/dist/commands/init.js +1390 -0
- package/dist/commands/install.js +2609 -0
- package/dist/commands/license/activate.js +179 -0
- package/dist/commands/license/env.js +94 -0
- package/dist/commands/license/generate-id.js +108 -0
- package/dist/commands/license/id.js +70 -0
- package/dist/commands/license/index.js +20 -0
- package/dist/commands/license/plugins/clean.js +115 -0
- package/dist/commands/license/plugins/index.js +20 -0
- package/dist/commands/license/plugins/list.js +64 -0
- package/dist/commands/license/plugins/shared.js +382 -0
- package/dist/commands/license/plugins/sync.js +314 -0
- package/dist/commands/license/shared.js +423 -0
- package/dist/commands/license/status.js +64 -0
- package/dist/commands/logs.js +12 -0
- package/dist/commands/plugin/disable.js +86 -0
- package/dist/commands/plugin/enable.js +86 -0
- package/dist/commands/plugin/import.js +108 -0
- package/dist/commands/plugin/list.js +82 -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/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/restart.js +12 -0
- package/dist/commands/revision/create.js +118 -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 +152 -0
- package/dist/commands/session/id.js +24 -0
- package/dist/commands/session/remove.js +57 -0
- package/dist/commands/session/setup.js +62 -0
- package/dist/commands/skills/check.js +69 -0
- package/dist/commands/skills/index.js +20 -0
- package/dist/commands/skills/install.js +80 -0
- package/dist/commands/skills/remove.js +80 -0
- package/dist/commands/skills/update.js +87 -0
- package/dist/commands/source/build.js +58 -0
- package/dist/commands/source/dev.js +182 -0
- package/dist/commands/source/download.js +883 -0
- package/dist/commands/source/publish.js +109 -0
- package/dist/commands/source/registry/logs.js +70 -0
- package/dist/commands/source/registry/start.js +57 -0
- package/dist/commands/source/registry/status.js +33 -0
- package/dist/commands/source/registry/stop.js +48 -0
- package/dist/commands/source/test.js +476 -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/commands/v1.js +210 -0
- package/dist/generated/command-registry.js +134 -0
- package/dist/help/runtime-help.js +23 -0
- package/dist/lib/api-client.js +335 -0
- package/dist/lib/api-command-compat.js +641 -0
- package/dist/lib/app-health.js +139 -0
- package/dist/lib/app-managed-resources.js +337 -0
- package/dist/lib/app-public-path.js +80 -0
- package/dist/lib/app-runtime.js +189 -0
- package/dist/lib/auth-store.js +528 -0
- package/dist/lib/backup.js +171 -0
- package/dist/lib/bootstrap.js +409 -0
- package/dist/lib/build-config.js +18 -0
- package/dist/lib/builtin-db.js +86 -0
- package/dist/lib/cli-config.js +569 -0
- package/dist/lib/cli-entry-error.js +52 -0
- package/dist/lib/cli-home.js +47 -0
- package/dist/lib/cli-locale.js +141 -0
- package/dist/lib/command-discovery.js +39 -0
- package/dist/lib/command-log.js +284 -0
- package/dist/lib/db-connection-check.js +219 -0
- package/dist/lib/docker-env-file.js +60 -0
- package/dist/lib/docker-image.js +37 -0
- package/dist/lib/docker-log-stream.js +45 -0
- package/dist/lib/env-auth.js +963 -0
- package/dist/lib/env-command-config.js +45 -0
- package/dist/lib/env-config.js +108 -0
- package/dist/lib/env-guard.js +61 -0
- package/dist/lib/env-paths.js +101 -0
- package/dist/lib/env-proxy.js +1325 -0
- package/dist/lib/generated-command.js +203 -0
- package/dist/lib/http-request.js +49 -0
- package/dist/lib/inquirer-theme.js +17 -0
- package/dist/lib/inquirer.js +243 -0
- package/dist/lib/managed-env-file.js +101 -0
- package/dist/lib/managed-init-env.js +32 -0
- package/dist/lib/naming.js +70 -0
- package/dist/lib/object-utils.js +76 -0
- package/dist/lib/openapi.js +62 -0
- package/dist/lib/plugin-import.js +279 -0
- package/dist/lib/plugin-storage.js +64 -0
- package/dist/lib/post-processors.js +23 -0
- package/dist/lib/prompt-catalog-core.js +186 -0
- package/dist/lib/prompt-catalog-terminal.js +374 -0
- package/{src/index.js → dist/lib/prompt-catalog.js} +2 -6
- package/dist/lib/prompt-validators.js +278 -0
- package/dist/lib/prompt-web-ui.js +2234 -0
- package/dist/lib/proxy-caddy.js +274 -0
- package/dist/lib/proxy-nginx.js +330 -0
- package/dist/lib/resource-command.js +357 -0
- package/dist/lib/resource-request.js +104 -0
- package/dist/lib/run-npm.js +429 -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/session-id.js +17 -0
- package/dist/lib/session-integration.js +703 -0
- package/dist/lib/session-store.js +118 -0
- package/dist/lib/skills-manager.js +438 -0
- package/dist/lib/source-publish.js +326 -0
- package/dist/lib/source-registry.js +188 -0
- package/dist/lib/startup-update.js +309 -0
- package/dist/lib/ui.js +159 -0
- package/dist/locale/en-US.json +526 -0
- package/dist/locale/zh-CN.json +526 -0
- package/dist/post-processors/data-modeling.js +84 -0
- package/dist/post-processors/data-source-manager.js +138 -0
- package/dist/post-processors/index.js +19 -0
- package/nocobase-ctl.config.json +388 -0
- package/package.json +133 -25
- 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,234 @@
|
|
|
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 { removeEnv } from '../../lib/auth-store.js';
|
|
11
|
+
import { formatMissingManagedAppEnvMessage, managedAppLifecycleEnvVars, resolveManagedAppRuntime, runLocalNocoBaseCommand, } from '../../lib/app-runtime.js';
|
|
12
|
+
import { hasExplicitEnvSelection } from '../../lib/env-guard.js';
|
|
13
|
+
import { resolveEnvProxyEntryDir, resolveLegacyNginxEnvProxyAppOutputPath } from "../../lib/env-proxy.js";
|
|
14
|
+
import { resolveConfiguredStoragePath } from '../../lib/env-paths.js';
|
|
15
|
+
import { input } from "../../lib/inquirer.js";
|
|
16
|
+
import { announceTargetEnv, failTask, isInteractiveTerminal, printInfo, startTask, succeedTask } from '../../lib/ui.js';
|
|
17
|
+
import path from 'node:path';
|
|
18
|
+
import { builtinDbContainerName, managedDockerNetworkName, removeDockerContainerIfExists, removeDockerNetworkIfUnused, removePathIfExists, resolveManagedLocalAppPath, shouldRemoveManagedLocalAppFiles, } from './shared.js';
|
|
19
|
+
function formatDestroyFailure(envName, message) {
|
|
20
|
+
return [
|
|
21
|
+
`Couldn't destroy env "${envName}".`,
|
|
22
|
+
'Some managed local resources may still exist. Check Docker, local app files, and storage data, then try again.',
|
|
23
|
+
`Details: ${message}`,
|
|
24
|
+
].join('\n');
|
|
25
|
+
}
|
|
26
|
+
function formatDestroyForceRequiredMessage(envName, explicitEnv) {
|
|
27
|
+
if (!explicitEnv) {
|
|
28
|
+
return [
|
|
29
|
+
`Refusing to destroy current env "${envName}" without explicit selection in non-interactive mode.`,
|
|
30
|
+
`Re-run with \`--env ${envName} --force\` to destroy this env.`,
|
|
31
|
+
].join('\n');
|
|
32
|
+
}
|
|
33
|
+
return [
|
|
34
|
+
`Refusing to destroy env "${envName}" without confirmation in non-interactive mode.`,
|
|
35
|
+
`Re-run with \`--env ${envName} --force\` to destroy this env.`,
|
|
36
|
+
].join('\n');
|
|
37
|
+
}
|
|
38
|
+
function buildDestroyPrompt(runtime, options) {
|
|
39
|
+
const subject = options.explicitEnv ? `env "${runtime.envName}"` : `current env "${runtime.envName}"`;
|
|
40
|
+
const lines = [`Destroy ${subject}?`];
|
|
41
|
+
if (runtime.kind === 'http' || runtime.kind === 'ssh') {
|
|
42
|
+
lines.push('This env has no CLI-managed local app or database runtime on this machine.');
|
|
43
|
+
lines.push('Only the saved CLI env config will be removed. External services are not touched.');
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
lines.push('This removes managed app runtime resources.');
|
|
47
|
+
if (runtime.env.config.builtinDb) {
|
|
48
|
+
lines.push('CLI-managed built-in database runtime will also be removed.');
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
lines.push('External database resources are not managed by the CLI and will be left untouched.');
|
|
52
|
+
}
|
|
53
|
+
if (options.removesManagedLocalAppFiles) {
|
|
54
|
+
lines.push('CLI-managed local app files will also be removed.');
|
|
55
|
+
}
|
|
56
|
+
lines.push('Env-specific proxy entry files generated by `nb proxy` will also be removed when present.');
|
|
57
|
+
if (options.removesStorageData) {
|
|
58
|
+
lines.push('Storage data will be removed.');
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
lines.push('No saved storage path was found for this env.');
|
|
62
|
+
}
|
|
63
|
+
lines.push('The saved CLI env config will be removed.');
|
|
64
|
+
}
|
|
65
|
+
lines.push(`Type "${runtime.envName}" to confirm:`);
|
|
66
|
+
return lines.join('\n');
|
|
67
|
+
}
|
|
68
|
+
async function confirmDestroy(runtime, options) {
|
|
69
|
+
if (!isInteractiveTerminal()) {
|
|
70
|
+
if (!options.explicitEnv) {
|
|
71
|
+
throw new Error(formatDestroyForceRequiredMessage(runtime.envName, false));
|
|
72
|
+
}
|
|
73
|
+
if (options.force) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
throw new Error(formatDestroyForceRequiredMessage(runtime.envName, options.explicitEnv));
|
|
77
|
+
}
|
|
78
|
+
if (options.force) {
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
await input({
|
|
83
|
+
message: buildDestroyPrompt(runtime, options),
|
|
84
|
+
required: true,
|
|
85
|
+
validate: (value) => (value.trim() === runtime.envName ? true : `Type "${runtime.envName}" to confirm.`),
|
|
86
|
+
placeholder: runtime.envName,
|
|
87
|
+
});
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export default class AppDestroy extends Command {
|
|
95
|
+
static hidden = true;
|
|
96
|
+
static description = 'Deprecated compatibility alias for `nb env remove <name> --purge`.';
|
|
97
|
+
static examples = [
|
|
98
|
+
'<%= config.bin %> <%= command.id %> --env app1',
|
|
99
|
+
'<%= config.bin %> <%= command.id %> --env app1 --force',
|
|
100
|
+
];
|
|
101
|
+
static flags = {
|
|
102
|
+
env: Flags.string({
|
|
103
|
+
char: 'e',
|
|
104
|
+
description: 'CLI env name to destroy. Defaults to the current env when omitted in interactive mode',
|
|
105
|
+
}),
|
|
106
|
+
force: Flags.boolean({
|
|
107
|
+
char: 'f',
|
|
108
|
+
description: 'Skip confirmation and destroy the selected env immediately',
|
|
109
|
+
default: false,
|
|
110
|
+
}),
|
|
111
|
+
verbose: Flags.boolean({
|
|
112
|
+
description: 'Show raw output from destruction commands',
|
|
113
|
+
default: false,
|
|
114
|
+
}),
|
|
115
|
+
};
|
|
116
|
+
async run() {
|
|
117
|
+
const { flags } = await this.parse(AppDestroy);
|
|
118
|
+
const requestedEnv = flags.env?.trim() || undefined;
|
|
119
|
+
const explicitEnv = Boolean(requestedEnv && hasExplicitEnvSelection(this.argv));
|
|
120
|
+
const runtime = await resolveManagedAppRuntime(requestedEnv);
|
|
121
|
+
if (!runtime) {
|
|
122
|
+
this.error(formatMissingManagedAppEnvMessage(requestedEnv));
|
|
123
|
+
}
|
|
124
|
+
const removesManagedLocalAppFiles = runtime.kind === 'local' &&
|
|
125
|
+
Boolean(resolveManagedLocalAppPath(runtime)) &&
|
|
126
|
+
shouldRemoveManagedLocalAppFiles(runtime);
|
|
127
|
+
const removesStorageData = (runtime.kind === 'local' || runtime.kind === 'docker') &&
|
|
128
|
+
Boolean(resolveConfiguredStoragePath(runtime.env.config));
|
|
129
|
+
let confirmed = false;
|
|
130
|
+
try {
|
|
131
|
+
confirmed = await confirmDestroy(runtime, {
|
|
132
|
+
explicitEnv,
|
|
133
|
+
force: flags.force,
|
|
134
|
+
removesManagedLocalAppFiles,
|
|
135
|
+
removesStorageData,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
this.error(error instanceof Error ? error.message : String(error));
|
|
140
|
+
}
|
|
141
|
+
if (!confirmed) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
announceTargetEnv(runtime.envName);
|
|
145
|
+
try {
|
|
146
|
+
if (runtime.kind === 'docker') {
|
|
147
|
+
startTask(`Removing Docker app container for "${runtime.envName}"...`);
|
|
148
|
+
const state = await removeDockerContainerIfExists(runtime.containerName, {
|
|
149
|
+
stdio: flags.verbose ? 'inherit' : 'ignore',
|
|
150
|
+
});
|
|
151
|
+
succeedTask(state === 'removed'
|
|
152
|
+
? `Docker app container removed for "${runtime.envName}".`
|
|
153
|
+
: `No Docker app container found for "${runtime.envName}".`);
|
|
154
|
+
}
|
|
155
|
+
else if (runtime.kind === 'local') {
|
|
156
|
+
startTask(`Stopping local NocoBase app for "${runtime.envName}"...`);
|
|
157
|
+
await runLocalNocoBaseCommand(runtime, ['pm2', 'kill'], {
|
|
158
|
+
env: managedAppLifecycleEnvVars(),
|
|
159
|
+
stdio: flags.verbose ? 'inherit' : 'ignore',
|
|
160
|
+
});
|
|
161
|
+
succeedTask(`Local NocoBase app stopped for "${runtime.envName}".`);
|
|
162
|
+
}
|
|
163
|
+
if (runtime.kind === 'local' || runtime.kind === 'docker') {
|
|
164
|
+
const dbContainer = builtinDbContainerName(runtime);
|
|
165
|
+
if (dbContainer) {
|
|
166
|
+
startTask(`Removing built-in database container for "${runtime.envName}"...`);
|
|
167
|
+
const state = await removeDockerContainerIfExists(dbContainer, {
|
|
168
|
+
stdio: flags.verbose ? 'inherit' : 'ignore',
|
|
169
|
+
});
|
|
170
|
+
succeedTask(state === 'removed'
|
|
171
|
+
? `Built-in database container removed for "${runtime.envName}".`
|
|
172
|
+
: `No built-in database container found for "${runtime.envName}".`);
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
printInfo(`External database resources for "${runtime.envName}" were left untouched.`);
|
|
176
|
+
}
|
|
177
|
+
const networkName = managedDockerNetworkName(runtime);
|
|
178
|
+
if (networkName) {
|
|
179
|
+
startTask(`Removing Docker network for "${runtime.envName}" if unused...`);
|
|
180
|
+
const state = await removeDockerNetworkIfUnused(networkName);
|
|
181
|
+
if (state === 'removed') {
|
|
182
|
+
succeedTask(`Docker network removed for "${runtime.envName}".`);
|
|
183
|
+
}
|
|
184
|
+
else if (state === 'missing') {
|
|
185
|
+
succeedTask(`No Docker network found for "${runtime.envName}".`);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
succeedTask(`Docker network is still in use for "${runtime.envName}". Keeping it.`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
if (runtime.kind === 'local') {
|
|
192
|
+
const localAppPath = resolveManagedLocalAppPath(runtime);
|
|
193
|
+
if (localAppPath && removesManagedLocalAppFiles) {
|
|
194
|
+
startTask(`Removing managed local app files for "${runtime.envName}"...`);
|
|
195
|
+
await removePathIfExists(localAppPath, `managed app files for "${runtime.envName}"`);
|
|
196
|
+
succeedTask(`Managed local app files removed for "${runtime.envName}".`);
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
printInfo(`No saved local app path found for "${runtime.envName}".`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
const proxyEntryDirs = [
|
|
203
|
+
resolveEnvProxyEntryDir(runtime.envName, { provider: 'nginx' }),
|
|
204
|
+
resolveEnvProxyEntryDir(runtime.envName, { provider: 'caddy' }),
|
|
205
|
+
path.dirname(resolveLegacyNginxEnvProxyAppOutputPath(runtime.envName)),
|
|
206
|
+
];
|
|
207
|
+
startTask(`Removing proxy entry files for "${runtime.envName}"...`);
|
|
208
|
+
for (const proxyEntryDir of proxyEntryDirs) {
|
|
209
|
+
await removePathIfExists(proxyEntryDir, `proxy entry files for "${runtime.envName}"`);
|
|
210
|
+
}
|
|
211
|
+
succeedTask(`Proxy entry files removed for "${runtime.envName}".`);
|
|
212
|
+
const configuredStoragePath = resolveConfiguredStoragePath(runtime.env.config);
|
|
213
|
+
if (configuredStoragePath) {
|
|
214
|
+
startTask(`Removing storage data for "${runtime.envName}"...`);
|
|
215
|
+
await removePathIfExists(configuredStoragePath, `storage data for "${runtime.envName}"`);
|
|
216
|
+
succeedTask(`Storage data removed for "${runtime.envName}".`);
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
printInfo(`No saved storage path found for "${runtime.envName}".`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
printInfo(`No CLI-managed local app or database runtime exists for "${runtime.envName}" on this machine.`);
|
|
224
|
+
}
|
|
225
|
+
startTask(`Removing saved CLI env config for "${runtime.envName}"...`);
|
|
226
|
+
const result = await removeEnv(runtime.envName);
|
|
227
|
+
succeedTask(`Saved CLI env config removed for "${runtime.envName}"${result.lastEnv ? ` (last env: ${result.lastEnv})` : ''}.`);
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
failTask(`Failed to destroy env "${runtime.envName}".`);
|
|
231
|
+
this.error(formatDestroyFailure(runtime.envName, error instanceof Error ? error.message : String(error)));
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
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 { printWarning } from '../../lib/ui.js';
|
|
11
|
+
export default class AppDown extends Command {
|
|
12
|
+
static hidden = true;
|
|
13
|
+
static description = 'Deprecated compatibility alias for `nb app stop --with-db` and `nb env remove <name> --purge`.';
|
|
14
|
+
static examples = [
|
|
15
|
+
'<%= config.bin %> <%= command.id %> --env app1',
|
|
16
|
+
'<%= config.bin %> <%= command.id %> --env app1 --all --force',
|
|
17
|
+
];
|
|
18
|
+
static flags = {
|
|
19
|
+
env: Flags.string({
|
|
20
|
+
char: 'e',
|
|
21
|
+
description: 'CLI env name to bring down. Defaults to the current env when omitted',
|
|
22
|
+
}),
|
|
23
|
+
all: Flags.boolean({
|
|
24
|
+
description: 'Delete everything for this env, including storage data and the saved env config',
|
|
25
|
+
default: false,
|
|
26
|
+
}),
|
|
27
|
+
yes: Flags.boolean({
|
|
28
|
+
char: 'y',
|
|
29
|
+
description: 'Compatibility alias for confirmation flags on the replacement command',
|
|
30
|
+
default: false,
|
|
31
|
+
}),
|
|
32
|
+
force: Flags.boolean({
|
|
33
|
+
char: 'f',
|
|
34
|
+
description: 'Compatibility alias for confirmation flags on the replacement command',
|
|
35
|
+
default: false,
|
|
36
|
+
}),
|
|
37
|
+
verbose: Flags.boolean({
|
|
38
|
+
description: 'Show raw output from shutdown commands',
|
|
39
|
+
default: false,
|
|
40
|
+
}),
|
|
41
|
+
};
|
|
42
|
+
async run() {
|
|
43
|
+
const { flags } = await this.parse(AppDown);
|
|
44
|
+
const runCommand = this.config.runCommand.bind(this.config);
|
|
45
|
+
const envName = flags.env?.trim();
|
|
46
|
+
const argv = [];
|
|
47
|
+
if (envName) {
|
|
48
|
+
argv.push('--env', envName);
|
|
49
|
+
}
|
|
50
|
+
if (flags.verbose) {
|
|
51
|
+
argv.push('--verbose');
|
|
52
|
+
}
|
|
53
|
+
if (flags.all) {
|
|
54
|
+
printWarning('`nb app down --all` is deprecated. Use `nb env remove <name> --purge` instead.');
|
|
55
|
+
if (flags.force || flags.yes) {
|
|
56
|
+
argv.push('--force');
|
|
57
|
+
}
|
|
58
|
+
await runCommand('app:destroy', argv);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
printWarning('`nb app down` is deprecated. Use `nb app stop --with-db` instead.');
|
|
62
|
+
argv.push('--with-db');
|
|
63
|
+
if (flags.yes) {
|
|
64
|
+
argv.push('--yes');
|
|
65
|
+
}
|
|
66
|
+
if (flags.force) {
|
|
67
|
+
argv.push('--force');
|
|
68
|
+
}
|
|
69
|
+
await runCommand('app:stop', argv);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
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 { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../lib/env-guard.js';
|
|
11
|
+
import { formatMissingManagedAppEnvMessage, managedAppLifecycleEnvVars, resolveManagedAppRuntime, runLocalNocoBaseCommand, } from '../../lib/app-runtime.js';
|
|
12
|
+
import { run } from '../../lib/run-npm.js';
|
|
13
|
+
import { printInfo } from '../../lib/ui.js';
|
|
14
|
+
function formatLogsFailure(envName, message) {
|
|
15
|
+
return [
|
|
16
|
+
`Couldn't show logs for "${envName}".`,
|
|
17
|
+
'Check that the saved local app or Docker container still exists on this machine, then try again.',
|
|
18
|
+
`Details: ${message}`,
|
|
19
|
+
].join('\n');
|
|
20
|
+
}
|
|
21
|
+
export default class AppLogs extends Command {
|
|
22
|
+
static hidden = false;
|
|
23
|
+
static description = 'Show NocoBase logs for the selected env. Local npm/git installs use pm2 logs, and Docker installs use docker logs.';
|
|
24
|
+
static examples = [
|
|
25
|
+
'<%= config.bin %> <%= command.id %>',
|
|
26
|
+
'<%= config.bin %> <%= command.id %> --env app1',
|
|
27
|
+
'<%= config.bin %> <%= command.id %> --env app1 --tail 200',
|
|
28
|
+
'<%= config.bin %> <%= command.id %> --env app1 --no-follow',
|
|
29
|
+
];
|
|
30
|
+
static flags = {
|
|
31
|
+
env: Flags.string({
|
|
32
|
+
char: 'e',
|
|
33
|
+
description: 'CLI env name to inspect logs for. Defaults to the current env when omitted',
|
|
34
|
+
}),
|
|
35
|
+
yes: Flags.boolean({
|
|
36
|
+
char: 'y',
|
|
37
|
+
description: 'Confirm using --env when it targets a different env than the current env',
|
|
38
|
+
default: false,
|
|
39
|
+
}),
|
|
40
|
+
tail: Flags.integer({
|
|
41
|
+
description: 'Number of recent log lines to show before following',
|
|
42
|
+
default: 100,
|
|
43
|
+
min: 0,
|
|
44
|
+
}),
|
|
45
|
+
follow: Flags.boolean({
|
|
46
|
+
char: 'f',
|
|
47
|
+
description: 'Keep streaming new log lines',
|
|
48
|
+
default: false,
|
|
49
|
+
allowNo: true,
|
|
50
|
+
}),
|
|
51
|
+
};
|
|
52
|
+
async run() {
|
|
53
|
+
const { flags } = await this.parse(AppLogs);
|
|
54
|
+
const requestedEnv = flags.env?.trim() || undefined;
|
|
55
|
+
if (requestedEnv && hasExplicitEnvSelection(this.argv)) {
|
|
56
|
+
const confirmed = await ensureCrossEnvConfirmed({
|
|
57
|
+
command: this,
|
|
58
|
+
requestedEnv,
|
|
59
|
+
yes: flags.yes,
|
|
60
|
+
});
|
|
61
|
+
if (!confirmed) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const runtime = await resolveManagedAppRuntime(requestedEnv);
|
|
66
|
+
if (!runtime) {
|
|
67
|
+
this.error(formatMissingManagedAppEnvMessage(requestedEnv));
|
|
68
|
+
}
|
|
69
|
+
if (runtime.kind === 'http') {
|
|
70
|
+
this.error([
|
|
71
|
+
`Can't show runtime logs for "${runtime.envName}" from this machine.`,
|
|
72
|
+
'This env only has an API connection, so there is no saved local app or Docker container to read logs from.',
|
|
73
|
+
'Connect it to a local checkout or reinstall it with npm, git, or Docker if you want CLI-managed logs.',
|
|
74
|
+
].join('\n'));
|
|
75
|
+
}
|
|
76
|
+
if (runtime.kind === 'ssh') {
|
|
77
|
+
this.error([
|
|
78
|
+
`Can't show runtime logs for "${runtime.envName}" yet.`,
|
|
79
|
+
'SSH env support is reserved but not implemented yet.',
|
|
80
|
+
'Use a local or Docker env for CLI-managed logs for now.',
|
|
81
|
+
].join('\n'));
|
|
82
|
+
}
|
|
83
|
+
const tail = String(flags.tail ?? 100);
|
|
84
|
+
const follow = flags.follow === true;
|
|
85
|
+
printInfo(follow
|
|
86
|
+
? `Showing logs for "${runtime.envName}" (press Ctrl+C to stop).`
|
|
87
|
+
: `Showing recent logs for "${runtime.envName}".`);
|
|
88
|
+
try {
|
|
89
|
+
if (runtime.kind === 'docker') {
|
|
90
|
+
const dockerArgs = ['logs', '--tail', tail];
|
|
91
|
+
if (follow) {
|
|
92
|
+
dockerArgs.push('--follow');
|
|
93
|
+
}
|
|
94
|
+
dockerArgs.push(runtime.containerName);
|
|
95
|
+
await run('docker', dockerArgs, {
|
|
96
|
+
errorName: 'docker logs',
|
|
97
|
+
stdio: 'inherit',
|
|
98
|
+
});
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const localArgs = ['pm2', 'logs', '--lines', tail];
|
|
102
|
+
if (!follow) {
|
|
103
|
+
localArgs.push('--nostream');
|
|
104
|
+
}
|
|
105
|
+
await runLocalNocoBaseCommand(runtime, localArgs, {
|
|
106
|
+
env: managedAppLifecycleEnvVars(),
|
|
107
|
+
stdio: 'inherit',
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
112
|
+
this.error(formatLogsFailure(runtime.envName, message));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,229 @@
|
|
|
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 { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../lib/env-guard.js';
|
|
11
|
+
import { formatMissingManagedAppEnvMessage, resolveManagedAppRuntime, stopDockerContainer, } from '../../lib/app-runtime.js';
|
|
12
|
+
import { formatAppUrl, resolveManagedAppApiBaseUrl, waitForAppReady } from '../../lib/app-health.js';
|
|
13
|
+
import { recreateSavedDockerApp } from '../../lib/app-managed-resources.js';
|
|
14
|
+
import { resolveAppUrlFromApiBaseUrl } from '../env/shared.js';
|
|
15
|
+
import { run } from '../../lib/run-npm.js';
|
|
16
|
+
import { announceTargetEnv, failTask, startTask, succeedTask } from '../../lib/ui.js';
|
|
17
|
+
function argvHasToken(argv, tokens) {
|
|
18
|
+
return tokens.some((token) => argv.includes(token));
|
|
19
|
+
}
|
|
20
|
+
function pushFlag(argv, flag, value) {
|
|
21
|
+
if (value !== undefined) {
|
|
22
|
+
argv.push(flag, String(value));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function buildLicenseSyncArgv(envName, options) {
|
|
26
|
+
const argv = ['--env', envName, '--skip-if-no-license'];
|
|
27
|
+
if (options.yes || options.explicitEnvSelection) {
|
|
28
|
+
argv.push('--yes');
|
|
29
|
+
}
|
|
30
|
+
if (options.verbose) {
|
|
31
|
+
argv.push('--verbose');
|
|
32
|
+
}
|
|
33
|
+
return argv;
|
|
34
|
+
}
|
|
35
|
+
async function runWithSuppressedTargetEnvLog(task) {
|
|
36
|
+
const previousTargetEnv = process.env.NB_SKIP_TARGET_ENV_LOG;
|
|
37
|
+
process.env.NB_SKIP_TARGET_ENV_LOG = '1';
|
|
38
|
+
try {
|
|
39
|
+
return await task();
|
|
40
|
+
}
|
|
41
|
+
finally {
|
|
42
|
+
if (previousTargetEnv === undefined) {
|
|
43
|
+
delete process.env.NB_SKIP_TARGET_ENV_LOG;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
process.env.NB_SKIP_TARGET_ENV_LOG = previousTargetEnv;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function formatDockerRestartFailure(envName, message) {
|
|
51
|
+
return [
|
|
52
|
+
`Couldn't restart NocoBase for "${envName}".`,
|
|
53
|
+
'The CLI was not able to recreate the saved Docker app container successfully.',
|
|
54
|
+
'Check the saved Docker image, envFile, container settings, and database connection, then try again.',
|
|
55
|
+
`Details: ${message}`,
|
|
56
|
+
].join('\n');
|
|
57
|
+
}
|
|
58
|
+
function resolveDisplayAppUrl(apiBaseUrl, port, appPublicPath) {
|
|
59
|
+
const resolvedFromApiBaseUrl = resolveAppUrlFromApiBaseUrl(apiBaseUrl);
|
|
60
|
+
if (resolvedFromApiBaseUrl) {
|
|
61
|
+
return resolvedFromApiBaseUrl;
|
|
62
|
+
}
|
|
63
|
+
return formatAppUrl(port, appPublicPath);
|
|
64
|
+
}
|
|
65
|
+
export default class AppRestart extends Command {
|
|
66
|
+
static hidden = false;
|
|
67
|
+
static description = 'Restart NocoBase for the selected env. When applicable, the CLI synchronizes licensed commercial plugins first, then restarts the local app or recreates the saved Docker container.';
|
|
68
|
+
static examples = [
|
|
69
|
+
'<%= config.bin %> <%= command.id %>',
|
|
70
|
+
'<%= config.bin %> <%= command.id %> --env local',
|
|
71
|
+
'<%= config.bin %> <%= command.id %> --env local --verbose',
|
|
72
|
+
'<%= config.bin %> <%= command.id %> --env local-docker',
|
|
73
|
+
];
|
|
74
|
+
static flags = {
|
|
75
|
+
env: Flags.string({
|
|
76
|
+
char: 'e',
|
|
77
|
+
description: 'CLI env name to restart. Defaults to the current env when omitted',
|
|
78
|
+
}),
|
|
79
|
+
yes: Flags.boolean({
|
|
80
|
+
char: 'y',
|
|
81
|
+
description: 'Confirm using --env when it targets a different env than the current env',
|
|
82
|
+
default: false,
|
|
83
|
+
}),
|
|
84
|
+
quickstart: Flags.boolean({
|
|
85
|
+
hidden: true,
|
|
86
|
+
description: 'Quickstart the application after stopping it',
|
|
87
|
+
required: false,
|
|
88
|
+
default: true,
|
|
89
|
+
allowNo: true,
|
|
90
|
+
}),
|
|
91
|
+
'sync-licensed-plugins': Flags.boolean({
|
|
92
|
+
hidden: true,
|
|
93
|
+
description: 'Synchronize licensed commercial plugins before restarting the application',
|
|
94
|
+
required: false,
|
|
95
|
+
default: true,
|
|
96
|
+
allowNo: true,
|
|
97
|
+
}),
|
|
98
|
+
daemon: Flags.boolean({
|
|
99
|
+
hidden: true,
|
|
100
|
+
description: 'Run the application as a daemon after stopping it (default: true; use --no-daemon to stay in the foreground)',
|
|
101
|
+
char: 'd',
|
|
102
|
+
required: false,
|
|
103
|
+
default: true,
|
|
104
|
+
allowNo: true,
|
|
105
|
+
}),
|
|
106
|
+
verbose: Flags.boolean({
|
|
107
|
+
description: 'Show raw shutdown/startup output from the underlying local or Docker command',
|
|
108
|
+
default: false,
|
|
109
|
+
}),
|
|
110
|
+
};
|
|
111
|
+
async run() {
|
|
112
|
+
const { flags } = await this.parse(AppRestart);
|
|
113
|
+
const quickstart = flags.quickstart ?? true;
|
|
114
|
+
const requestedEnv = flags.env?.trim() || undefined;
|
|
115
|
+
const explicitEnvSelection = Boolean(requestedEnv && hasExplicitEnvSelection(this.argv));
|
|
116
|
+
const shouldSyncLicensedPlugins = flags['sync-licensed-plugins'] ?? true;
|
|
117
|
+
if (explicitEnvSelection) {
|
|
118
|
+
const confirmed = await ensureCrossEnvConfirmed({
|
|
119
|
+
command: this,
|
|
120
|
+
requestedEnv,
|
|
121
|
+
yes: flags.yes,
|
|
122
|
+
});
|
|
123
|
+
if (!confirmed) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const runtime = await resolveManagedAppRuntime(requestedEnv);
|
|
128
|
+
const runCommand = this.config.runCommand.bind(this.config);
|
|
129
|
+
const commandStdio = flags.verbose ? 'inherit' : 'ignore';
|
|
130
|
+
if (!runtime) {
|
|
131
|
+
this.error(formatMissingManagedAppEnvMessage(requestedEnv));
|
|
132
|
+
}
|
|
133
|
+
if (runtime.kind === 'http') {
|
|
134
|
+
this.error([
|
|
135
|
+
`Can't restart "${runtime.envName}" from this machine.`,
|
|
136
|
+
'This env only has an API connection, so there is no saved local app or Docker runtime to restart here.',
|
|
137
|
+
'Connect it to a local checkout or reinstall it with npm, git, or Docker if you want CLI-managed restart.',
|
|
138
|
+
].join('\n'));
|
|
139
|
+
}
|
|
140
|
+
if (runtime.kind === 'ssh') {
|
|
141
|
+
this.error([
|
|
142
|
+
`Can't restart "${runtime.envName}" yet.`,
|
|
143
|
+
'SSH env support is reserved but not implemented yet.',
|
|
144
|
+
'Use a local or Docker env if you need CLI-managed restart right now.',
|
|
145
|
+
].join('\n'));
|
|
146
|
+
}
|
|
147
|
+
announceTargetEnv(runtime.envName);
|
|
148
|
+
if (shouldSyncLicensedPlugins) {
|
|
149
|
+
try {
|
|
150
|
+
await runWithSuppressedTargetEnvLog(async () => {
|
|
151
|
+
await runCommand('license:plugins:sync', buildLicenseSyncArgv(runtime.envName, {
|
|
152
|
+
explicitEnvSelection,
|
|
153
|
+
yes: flags.yes,
|
|
154
|
+
verbose: flags.verbose,
|
|
155
|
+
}));
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
this.error(error instanceof Error ? error.message : String(error));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (runtime.kind === 'docker') {
|
|
163
|
+
startTask(`Stopping NocoBase for "${runtime.envName}" before restart...`);
|
|
164
|
+
try {
|
|
165
|
+
const state = await stopDockerContainer(runtime.containerName, {
|
|
166
|
+
stdio: commandStdio,
|
|
167
|
+
});
|
|
168
|
+
succeedTask(state === 'already-stopped'
|
|
169
|
+
? `NocoBase was already stopped for "${runtime.envName}".`
|
|
170
|
+
: `Stopped NocoBase for "${runtime.envName}".`);
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
174
|
+
failTask(`Failed to stop NocoBase for "${runtime.envName}".`);
|
|
175
|
+
this.error(formatDockerRestartFailure(runtime.envName, message));
|
|
176
|
+
}
|
|
177
|
+
startTask(`Recreating the Docker app container for "${runtime.envName}"...`);
|
|
178
|
+
try {
|
|
179
|
+
await run('docker', ['rm', '-f', runtime.containerName], {
|
|
180
|
+
errorName: 'docker rm',
|
|
181
|
+
stdio: commandStdio,
|
|
182
|
+
}).catch(() => undefined);
|
|
183
|
+
await recreateSavedDockerApp(runtime, {
|
|
184
|
+
verbose: flags.verbose,
|
|
185
|
+
});
|
|
186
|
+
succeedTask(`Docker app container is ready for "${runtime.envName}".`);
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
190
|
+
failTask(`Failed to recreate NocoBase for "${runtime.envName}".`);
|
|
191
|
+
this.error(formatDockerRestartFailure(runtime.envName, message));
|
|
192
|
+
}
|
|
193
|
+
const apiBaseUrl = resolveManagedAppApiBaseUrl(runtime);
|
|
194
|
+
const appUrl = resolveDisplayAppUrl(apiBaseUrl, runtime.env.appPort === undefined || runtime.env.appPort === null ? undefined : String(runtime.env.appPort), runtime.env.config?.appPublicPath);
|
|
195
|
+
await waitForAppReady({
|
|
196
|
+
envName: runtime.envName,
|
|
197
|
+
apiBaseUrl,
|
|
198
|
+
containerName: runtime.containerName,
|
|
199
|
+
logHint: `You can inspect startup logs with \`nb app logs --env ${runtime.envName}\`.`,
|
|
200
|
+
...(flags.verbose ? { verbose: true } : {}),
|
|
201
|
+
});
|
|
202
|
+
succeedTask(`NocoBase is running for "${runtime.envName}"${appUrl ? ` at ${appUrl}` : ''}.`);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
const stopArgv = [];
|
|
206
|
+
const daemonFlagWasProvided = argvHasToken(this.argv, ['--daemon', '--no-daemon']);
|
|
207
|
+
pushFlag(stopArgv, '--env', requestedEnv);
|
|
208
|
+
if (flags.yes || explicitEnvSelection) {
|
|
209
|
+
stopArgv.push('--yes');
|
|
210
|
+
}
|
|
211
|
+
if (flags.verbose) {
|
|
212
|
+
stopArgv.push('--verbose');
|
|
213
|
+
}
|
|
214
|
+
await runWithSuppressedTargetEnvLog(async () => {
|
|
215
|
+
await runCommand('app:stop', stopArgv);
|
|
216
|
+
});
|
|
217
|
+
const startArgv = [...stopArgv];
|
|
218
|
+
if (quickstart) {
|
|
219
|
+
startArgv.push('--quickstart');
|
|
220
|
+
}
|
|
221
|
+
startArgv.push('--no-sync-licensed-plugins');
|
|
222
|
+
if (daemonFlagWasProvided) {
|
|
223
|
+
startArgv.push(flags.daemon === false ? '--no-daemon' : '--daemon');
|
|
224
|
+
}
|
|
225
|
+
await runWithSuppressedTargetEnvLog(async () => {
|
|
226
|
+
await runCommand('app:start', startArgv);
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|