@nocobase/cli 2.1.0-beta.29 → 2.1.0-beta.30
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 +14 -0
- package/README.zh-CN.md +14 -0
- package/bin/run.js +3 -0
- package/bin/session-env.js +27 -0
- package/dist/commands/app/down.js +47 -9
- package/dist/commands/app/logs.js +17 -0
- package/dist/commands/app/restart.js +23 -1
- package/dist/commands/app/start.js +17 -0
- package/dist/commands/app/stop.js +17 -0
- package/dist/commands/app/upgrade.js +22 -2
- package/dist/commands/db/check.js +6 -4
- package/dist/commands/db/ps.js +1 -1
- package/dist/commands/env/add.js +3 -2
- package/dist/commands/env/auth.js +1 -1
- package/dist/commands/env/current.js +21 -0
- package/dist/commands/env/info.js +4 -3
- package/dist/commands/env/list.js +8 -14
- package/dist/commands/env/remove.js +2 -2
- package/dist/commands/env/status.js +90 -0
- package/dist/commands/env/update.js +1 -1
- package/dist/commands/env/use.js +11 -1
- package/dist/commands/install.js +10 -4
- package/dist/commands/license/activate.js +20 -24
- package/dist/commands/license/id.js +17 -2
- package/dist/commands/license/plugins/clean.js +17 -2
- package/dist/commands/license/plugins/list.js +17 -2
- package/dist/commands/license/plugins/sync.js +22 -5
- package/dist/commands/license/shared.js +15 -6
- package/dist/commands/license/status.js +17 -2
- package/dist/commands/plugin/disable.js +25 -4
- package/dist/commands/plugin/enable.js +25 -4
- package/dist/commands/plugin/list.js +25 -4
- 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/source/dev.js +19 -1
- package/dist/commands/source/download.js +10 -8
- package/dist/lib/app-managed-resources.js +5 -3
- package/dist/lib/app-runtime.js +1 -1
- package/dist/lib/auth-store.js +28 -11
- package/dist/lib/docker-image.js +37 -0
- package/dist/lib/env-guard.js +61 -0
- package/dist/lib/generated-command.js +16 -0
- package/dist/lib/plugin-storage.js +1 -64
- package/dist/lib/resource-command.js +15 -0
- package/dist/lib/runtime-generator.js +1 -1
- 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/package.json +3 -3
|
@@ -0,0 +1,90 @@
|
|
|
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 { Args, Command, Flags } from '@oclif/core';
|
|
10
|
+
import { formatMissingManagedAppEnvMessage, resolveManagedAppRuntime } from '../../lib/app-runtime.js';
|
|
11
|
+
import { getCurrentEnvName, listEnvs } from '../../lib/auth-store.js';
|
|
12
|
+
import { resolveDefaultConfigScope } from '../../lib/cli-home.js';
|
|
13
|
+
import { renderTable } from '../../lib/ui.js';
|
|
14
|
+
import { apiStatus, runtimeStatus } from './shared.js';
|
|
15
|
+
export default class EnvStatus extends Command {
|
|
16
|
+
static summary = 'Show application runtime status for the current env, one env, or all envs';
|
|
17
|
+
static examples = [
|
|
18
|
+
'<%= config.bin %> <%= command.id %>',
|
|
19
|
+
'<%= config.bin %> <%= command.id %> app1',
|
|
20
|
+
'<%= config.bin %> <%= command.id %> --all',
|
|
21
|
+
'<%= config.bin %> <%= command.id %> --all --json-output',
|
|
22
|
+
];
|
|
23
|
+
static args = {
|
|
24
|
+
name: Args.string({
|
|
25
|
+
description: 'Configured environment name to inspect. Defaults to the current env when omitted; cannot be used with --all',
|
|
26
|
+
required: false,
|
|
27
|
+
}),
|
|
28
|
+
};
|
|
29
|
+
static flags = {
|
|
30
|
+
all: Flags.boolean({
|
|
31
|
+
description: 'Show status for all configured envs',
|
|
32
|
+
default: false,
|
|
33
|
+
}),
|
|
34
|
+
'json-output': Flags.boolean({
|
|
35
|
+
description: 'Output the result as JSON',
|
|
36
|
+
default: false,
|
|
37
|
+
}),
|
|
38
|
+
};
|
|
39
|
+
async run() {
|
|
40
|
+
const { args, flags } = await this.parse(EnvStatus);
|
|
41
|
+
const scope = resolveDefaultConfigScope();
|
|
42
|
+
const requestedEnv = args.name?.trim() || undefined;
|
|
43
|
+
if (requestedEnv && flags.all) {
|
|
44
|
+
this.error('`nb env status <name>` and `nb env status --all` cannot be used together.');
|
|
45
|
+
}
|
|
46
|
+
const { envs } = await listEnvs({ scope });
|
|
47
|
+
const configuredEnvNames = Object.keys(envs).sort();
|
|
48
|
+
if (!configuredEnvNames.length) {
|
|
49
|
+
this.log('No envs configured.');
|
|
50
|
+
this.log('Run `nb env add <name> --api-base-url <url>` to add one.');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const envNames = flags.all
|
|
54
|
+
? configuredEnvNames
|
|
55
|
+
: [requestedEnv || (await getCurrentEnvName({ scope }))];
|
|
56
|
+
const rows = [];
|
|
57
|
+
for (const envName of envNames) {
|
|
58
|
+
const runtime = await resolveManagedAppRuntime(envName);
|
|
59
|
+
if (!runtime) {
|
|
60
|
+
if (!flags.all) {
|
|
61
|
+
this.error(formatMissingManagedAppEnvMessage(envName));
|
|
62
|
+
}
|
|
63
|
+
rows.push({
|
|
64
|
+
env: envName,
|
|
65
|
+
status: 'missing',
|
|
66
|
+
apiBaseUrl: '',
|
|
67
|
+
});
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const status = runtime.kind === 'http' || runtime.kind === 'ssh'
|
|
71
|
+
? await apiStatus(envName, {
|
|
72
|
+
...envs[envName],
|
|
73
|
+
...(runtime.env.config ?? {}),
|
|
74
|
+
}, { scope })
|
|
75
|
+
: await runtimeStatus(runtime);
|
|
76
|
+
rows.push({
|
|
77
|
+
env: runtime.envName,
|
|
78
|
+
status,
|
|
79
|
+
apiBaseUrl: runtime.env.apiBaseUrl
|
|
80
|
+
|| String(runtime.env.config.apiBaseUrl ?? runtime.env.config.baseUrl ?? envs[envName]?.apiBaseUrl ?? envs[envName]?.baseUrl ?? '').trim(),
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
if (flags['json-output']) {
|
|
84
|
+
this.log(JSON.stringify(flags.all ? rows : rows[0], null, 2));
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const tableRows = rows.map((row) => [row.env, row.status, row.apiBaseUrl]);
|
|
88
|
+
this.log(renderTable(['Env', 'Status', 'API Base URL'], tableRows));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -22,7 +22,7 @@ export default class EnvUpdate extends Command {
|
|
|
22
22
|
];
|
|
23
23
|
static args = {
|
|
24
24
|
name: Args.string({
|
|
25
|
-
description: '
|
|
25
|
+
description: 'Configured environment name to refresh. Defaults to the current env when omitted',
|
|
26
26
|
required: false,
|
|
27
27
|
}),
|
|
28
28
|
};
|
package/dist/commands/env/use.js
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
import { Args, Command } from '@oclif/core';
|
|
10
10
|
import { setCurrentEnv } from '../../lib/auth-store.js';
|
|
11
11
|
import { resolveDefaultConfigScope } from '../../lib/cli-home.js';
|
|
12
|
+
import { resolveSessionIdentity } from '../../lib/session-id.js';
|
|
13
|
+
import { isInteractiveTerminal, printInfo } from '../../lib/ui.js';
|
|
12
14
|
export default class EnvUse extends Command {
|
|
13
15
|
static summary = 'Switch the current environment';
|
|
14
16
|
static examples = [
|
|
@@ -16,7 +18,7 @@ export default class EnvUse extends Command {
|
|
|
16
18
|
];
|
|
17
19
|
static args = {
|
|
18
20
|
name: Args.string({
|
|
19
|
-
description: 'Configured environment name',
|
|
21
|
+
description: 'Configured environment name to switch to',
|
|
20
22
|
required: true,
|
|
21
23
|
}),
|
|
22
24
|
};
|
|
@@ -24,5 +26,13 @@ export default class EnvUse extends Command {
|
|
|
24
26
|
const { args } = await this.parse(EnvUse);
|
|
25
27
|
await setCurrentEnv(args.name, { scope: resolveDefaultConfigScope() });
|
|
26
28
|
this.log(`Current env: ${args.name}`);
|
|
29
|
+
const identity = resolveSessionIdentity();
|
|
30
|
+
if (identity || !isInteractiveTerminal()) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
this.log('Session mode is not enabled for the current shell or runtime.');
|
|
34
|
+
this.log('Without session mode, switching the current env here can affect other sessions running in parallel.');
|
|
35
|
+
this.log('');
|
|
36
|
+
printInfo('Run `nb session setup` to enable session mode for this shell or runtime.');
|
|
27
37
|
}
|
|
28
38
|
}
|
package/dist/commands/install.js
CHANGED
|
@@ -19,12 +19,13 @@ import { applyCliLocale, localeText, resolveCliLocale, translateCli, } from "../
|
|
|
19
19
|
import { resolveConfiguredEnvPath, resolveDefaultConfigScope, resolveEnvRoot, resolveEnvRelativePath, } from '../lib/cli-home.js';
|
|
20
20
|
import { defaultDockerContainerPrefix, defaultDockerNetworkName, } from '../lib/app-runtime.js';
|
|
21
21
|
import { resolveDockerContainerPrefix, resolveDockerNetworkName, } from '../lib/cli-config.js';
|
|
22
|
+
import { DEFAULT_DOCKER_VERSION, resolveDockerImageRef, } from "../lib/docker-image.js";
|
|
22
23
|
import { findAvailableTcpPort, validateAvailableTcpPort, validateTcpPort, validateEnvKey, } from "../lib/prompt-validators.js";
|
|
23
24
|
import { validateExternalDbConfig } from "../lib/db-connection-check.js";
|
|
24
25
|
import { formatMissingManagedAppEnvMessage } from '../lib/app-runtime.js';
|
|
25
26
|
import { run, runNocoBaseCommand } from '../lib/run-npm.js';
|
|
26
27
|
import { startTask, stopTask, updateTask } from '../lib/ui.js';
|
|
27
|
-
import { getEnv, upsertEnv } from '../lib/auth-store.js';
|
|
28
|
+
import { getEnv, setCurrentEnv, upsertEnv } from '../lib/auth-store.js';
|
|
28
29
|
import { buildStoredEnvConfig } from '../lib/env-config.js';
|
|
29
30
|
import Download, { defaultDockerRegistryForLang, } from './download.js';
|
|
30
31
|
import EnvAdd from "./env/add.js";
|
|
@@ -1561,7 +1562,11 @@ export default class Install extends Command {
|
|
|
1561
1562
|
static buildDockerAppPlan(params) {
|
|
1562
1563
|
const dockerRegistry = String(downloadResultsValue(params.downloadResults, 'dockerRegistry') ?? '').trim()
|
|
1563
1564
|
|| defaultDockerRegistryForLang(process.env.NB_LOCALE);
|
|
1564
|
-
const version = String(downloadResultsValue(params.downloadResults, 'version') ?? '').trim() ||
|
|
1565
|
+
const version = String(downloadResultsValue(params.downloadResults, 'version') ?? '').trim() || DEFAULT_DOCKER_VERSION;
|
|
1566
|
+
const imageRef = resolveDockerImageRef(dockerRegistry, version, {
|
|
1567
|
+
defaultRegistry: defaultDockerRegistryForLang(process.env.NB_LOCALE),
|
|
1568
|
+
defaultVersion: DEFAULT_DOCKER_VERSION,
|
|
1569
|
+
});
|
|
1565
1570
|
const appPort = String(params.appResults.appPort ?? DEFAULT_INSTALL_APP_PORT).trim() || DEFAULT_INSTALL_APP_PORT;
|
|
1566
1571
|
const storagePath = resolveConfiguredEnvPath(String(params.appResults.storagePath ?? '').trim()
|
|
1567
1572
|
|| defaultInstallStoragePath(params.envName))
|
|
@@ -1596,12 +1601,12 @@ export default class Install extends Command {
|
|
|
1596
1601
|
for (const [key, value] of Object.entries(initEnvVars)) {
|
|
1597
1602
|
args.push('-e', `${key}=${value}`);
|
|
1598
1603
|
}
|
|
1599
|
-
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}:/app/nocobase/storage`,
|
|
1604
|
+
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}:/app/nocobase/storage`, imageRef);
|
|
1600
1605
|
return {
|
|
1601
1606
|
source: 'docker',
|
|
1602
1607
|
networkName: params.networkName,
|
|
1603
1608
|
containerName,
|
|
1604
|
-
imageRef
|
|
1609
|
+
imageRef,
|
|
1605
1610
|
appPort,
|
|
1606
1611
|
storagePath,
|
|
1607
1612
|
appKey,
|
|
@@ -1908,6 +1913,7 @@ export default class Install extends Command {
|
|
|
1908
1913
|
}
|
|
1909
1914
|
async saveInstalledEnv(params) {
|
|
1910
1915
|
await upsertEnv(params.envName, Install.buildSavedEnvConfig(params), { scope: resolveDefaultConfigScope() });
|
|
1916
|
+
await setCurrentEnv(params.envName, { scope: resolveDefaultConfigScope() });
|
|
1911
1917
|
}
|
|
1912
1918
|
async syncInstalledEnvConnection(params) {
|
|
1913
1919
|
if (!params.appReady) {
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
import * as p from '@clack/prompts';
|
|
10
10
|
import { Command, Flags } from '@oclif/core';
|
|
11
11
|
import { readFile } from 'node:fs/promises';
|
|
12
|
-
import {
|
|
12
|
+
import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../lib/env-guard.js';
|
|
13
|
+
import { createLicenseEnvFlag, ensureInstanceId, licenseJsonFlag, licensePkgUrlFlag, licenseYesFlag, redactLicenseKey, requireLicenseRuntime, resolveLicenseKeyFile, resolveLicenseServiceUrl, saveLicenseKey, sanitizeLicenseOutput, validateLicenseKey, } from './shared.js';
|
|
13
14
|
import { announceTargetEnv, isInteractiveTerminal } from '../../lib/ui.js';
|
|
14
15
|
import { appUrl } from '../env/shared.js';
|
|
15
16
|
function resolveOnlineInputValue(value) {
|
|
@@ -114,21 +115,10 @@ async function promptOnlineActivationInput(initial) {
|
|
|
114
115
|
p.cancel('License activation cancelled.');
|
|
115
116
|
return;
|
|
116
117
|
}
|
|
117
|
-
const confirmedAnswer = typeof initial.confirmed === 'boolean'
|
|
118
|
-
? initial.confirmed
|
|
119
|
-
: await p.confirm({
|
|
120
|
-
message: 'Confirm that the submitted license information is true and accurate?',
|
|
121
|
-
initialValue: false,
|
|
122
|
-
});
|
|
123
|
-
if (p.isCancel(confirmedAnswer)) {
|
|
124
|
-
p.cancel('License activation cancelled.');
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
118
|
return {
|
|
128
119
|
account,
|
|
129
120
|
password,
|
|
130
121
|
appName,
|
|
131
|
-
confirmed: Boolean(confirmedAnswer),
|
|
132
122
|
serviceUrl: await resolveLicenseServiceUrl(initial.serviceUrl),
|
|
133
123
|
};
|
|
134
124
|
}
|
|
@@ -176,11 +166,12 @@ export default class LicenseActivate extends Command {
|
|
|
176
166
|
'<%= config.bin %> <%= command.id %> --env app1 --key <licenseKey>',
|
|
177
167
|
'<%= config.bin %> <%= command.id %> --env app1 --key-file ./license.txt',
|
|
178
168
|
'<%= config.bin %> <%= command.id %> --env app1 --online',
|
|
169
|
+
'<%= config.bin %> <%= command.id %> --env app1 --online --account aa --password bb --desc test24',
|
|
179
170
|
'<%= config.bin %> <%= command.id %> --env app1 --online --account aa --password bb --desc test24 --yes',
|
|
180
171
|
'<%= config.bin %> <%= command.id %> --env app1 --json --key-file ./license.txt',
|
|
181
172
|
];
|
|
182
173
|
static flags = {
|
|
183
|
-
env:
|
|
174
|
+
env: createLicenseEnvFlag('CLI env name to activate a license for. Defaults to the current env when omitted'),
|
|
184
175
|
json: licenseJsonFlag,
|
|
185
176
|
key: Flags.string({
|
|
186
177
|
description: 'Existing license key to activate',
|
|
@@ -202,13 +193,23 @@ export default class LicenseActivate extends Command {
|
|
|
202
193
|
description: 'Application name for online activation',
|
|
203
194
|
}),
|
|
204
195
|
'pkg-url': licensePkgUrlFlag,
|
|
205
|
-
yes:
|
|
206
|
-
description: 'Confirm that the submitted application information is true and accurate',
|
|
207
|
-
default: false,
|
|
208
|
-
}),
|
|
196
|
+
yes: licenseYesFlag,
|
|
209
197
|
};
|
|
210
198
|
async run() {
|
|
211
199
|
const { flags } = await this.parse(LicenseActivate);
|
|
200
|
+
const requestedEnv = flags.env?.trim() || undefined;
|
|
201
|
+
const explicitEnvSelection = Boolean(requestedEnv && hasExplicitEnvSelection(this.argv ?? []));
|
|
202
|
+
if (explicitEnvSelection) {
|
|
203
|
+
const confirmed = await ensureCrossEnvConfirmed({
|
|
204
|
+
command: this,
|
|
205
|
+
requestedEnv,
|
|
206
|
+
yes: flags.yes,
|
|
207
|
+
});
|
|
208
|
+
if (!confirmed) {
|
|
209
|
+
this.log('Canceled.');
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
212
213
|
const runtime = await requireLicenseRuntime(flags.env);
|
|
213
214
|
if (!flags.json) {
|
|
214
215
|
announceTargetEnv(runtime.envName);
|
|
@@ -246,16 +247,14 @@ export default class LicenseActivate extends Command {
|
|
|
246
247
|
account: resolveOnlineInputValue(flags.account),
|
|
247
248
|
password: resolveOnlineInputValue(flags.password),
|
|
248
249
|
appName: resolveOnlineInputValue(flags.desc),
|
|
249
|
-
confirmed: flags.yes ? true : undefined,
|
|
250
250
|
serviceUrl: resolvedServiceUrl,
|
|
251
251
|
};
|
|
252
252
|
let onlineInput = initialOnline;
|
|
253
253
|
if (!onlineInput.account
|
|
254
254
|
|| !onlineInput.password
|
|
255
|
-
|| !onlineInput.appName
|
|
256
|
-
|| !onlineInput.confirmed) {
|
|
255
|
+
|| !onlineInput.appName) {
|
|
257
256
|
if (!isInteractiveTerminal()) {
|
|
258
|
-
this.error('Online activation requires --account, --password,
|
|
257
|
+
this.error('Online activation requires --account, --password, and --desc when not using a TTY.');
|
|
259
258
|
}
|
|
260
259
|
const prompted = await promptOnlineActivationInput(initialOnline);
|
|
261
260
|
if (!prompted) {
|
|
@@ -264,9 +263,6 @@ export default class LicenseActivate extends Command {
|
|
|
264
263
|
}
|
|
265
264
|
onlineInput = prompted;
|
|
266
265
|
}
|
|
267
|
-
if (!onlineInput.confirmed) {
|
|
268
|
-
this.error('Online activation requires confirmation that the submitted application information is true and accurate.');
|
|
269
|
-
}
|
|
270
266
|
const instanceId = await ensureInstanceId(runtime);
|
|
271
267
|
const resolvedAppUrl = resolveAppUrlOrThrow(runtime);
|
|
272
268
|
const resolvedKey = await requestOnlineLicenseKey(onlineInput.serviceUrl, onlineInput.account, onlineInput.password, {
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
import { Command, Flags } from '@oclif/core';
|
|
10
|
-
import {
|
|
10
|
+
import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../lib/env-guard.js';
|
|
11
|
+
import { createLicenseEnvFlag, generateAndSaveInstanceId, licenseJsonFlag, licenseYesFlag, readSavedInstanceId, requireLicenseRuntime, resolveInstanceIdFile, } from './shared.js';
|
|
11
12
|
import { announceTargetEnv } from '../../lib/ui.js';
|
|
12
13
|
export default class LicenseId extends Command {
|
|
13
14
|
static summary = 'Show the instance ID for the selected env';
|
|
@@ -19,8 +20,9 @@ export default class LicenseId extends Command {
|
|
|
19
20
|
'<%= config.bin %> <%= command.id %> --env app1 --json',
|
|
20
21
|
];
|
|
21
22
|
static flags = {
|
|
22
|
-
env:
|
|
23
|
+
env: createLicenseEnvFlag('CLI env name to inspect. Defaults to the current env when omitted'),
|
|
23
24
|
json: licenseJsonFlag,
|
|
25
|
+
yes: licenseYesFlag,
|
|
24
26
|
force: Flags.boolean({
|
|
25
27
|
description: 'Force regenerate the instance ID even if one is already saved',
|
|
26
28
|
default: false,
|
|
@@ -28,6 +30,19 @@ export default class LicenseId extends Command {
|
|
|
28
30
|
};
|
|
29
31
|
async run() {
|
|
30
32
|
const { flags } = await this.parse(LicenseId);
|
|
33
|
+
const requestedEnv = flags.env?.trim() || undefined;
|
|
34
|
+
const explicitEnvSelection = Boolean(requestedEnv && hasExplicitEnvSelection(this.argv ?? []));
|
|
35
|
+
if (explicitEnvSelection) {
|
|
36
|
+
const confirmed = await ensureCrossEnvConfirmed({
|
|
37
|
+
command: this,
|
|
38
|
+
requestedEnv,
|
|
39
|
+
yes: flags.yes,
|
|
40
|
+
});
|
|
41
|
+
if (!confirmed) {
|
|
42
|
+
this.log('Canceled.');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
31
46
|
const runtime = await requireLicenseRuntime(flags.env);
|
|
32
47
|
if (!flags.json) {
|
|
33
48
|
announceTargetEnv(runtime.envName);
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { Command, Flags } from '@oclif/core';
|
|
10
10
|
import pc from 'picocolors';
|
|
11
|
-
import {
|
|
11
|
+
import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../../lib/env-guard.js';
|
|
12
|
+
import { createLicenseEnvFlag, licenseJsonFlag, licensePkgUrlFlag, licenseYesFlag, requireLicenseRuntime, } from '../shared.js';
|
|
12
13
|
import { cleanLicensedPlugins } from './shared.js';
|
|
13
14
|
import { resolvePluginStoragePath } from '../../../lib/plugin-storage.js';
|
|
14
15
|
import { announceTargetEnv } from '../../../lib/ui.js';
|
|
@@ -31,7 +32,7 @@ export default class LicensePluginsClean extends Command {
|
|
|
31
32
|
'<%= config.bin %> <%= command.id %> --env app1 --json',
|
|
32
33
|
];
|
|
33
34
|
static flags = {
|
|
34
|
-
env:
|
|
35
|
+
env: createLicenseEnvFlag('CLI env name to clean licensed plugins for. Defaults to the current env when omitted'),
|
|
35
36
|
json: licenseJsonFlag,
|
|
36
37
|
'pkg-url': licensePkgUrlFlag,
|
|
37
38
|
'dry-run': Flags.boolean({
|
|
@@ -42,9 +43,23 @@ export default class LicensePluginsClean extends Command {
|
|
|
42
43
|
description: 'Show detailed per-plugin clean logs',
|
|
43
44
|
default: false,
|
|
44
45
|
}),
|
|
46
|
+
yes: licenseYesFlag,
|
|
45
47
|
};
|
|
46
48
|
async run() {
|
|
47
49
|
const { flags } = await this.parse(LicensePluginsClean);
|
|
50
|
+
const requestedEnv = flags.env?.trim() || undefined;
|
|
51
|
+
const explicitEnvSelection = Boolean(requestedEnv && hasExplicitEnvSelection(this.argv ?? []));
|
|
52
|
+
if (explicitEnvSelection) {
|
|
53
|
+
const confirmed = await ensureCrossEnvConfirmed({
|
|
54
|
+
command: this,
|
|
55
|
+
requestedEnv,
|
|
56
|
+
yes: flags.yes,
|
|
57
|
+
});
|
|
58
|
+
if (!confirmed) {
|
|
59
|
+
this.log('Canceled.');
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
48
63
|
const runtime = await requireLicenseRuntime(flags.env);
|
|
49
64
|
if (!flags.json) {
|
|
50
65
|
announceTargetEnv(runtime.envName);
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
import { Command } from '@oclif/core';
|
|
10
|
-
import {
|
|
10
|
+
import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../../lib/env-guard.js';
|
|
11
|
+
import { createLicenseEnvFlag, licenseJsonFlag, licensePkgUrlFlag, licenseYesFlag, requireLicenseRuntime, } from '../shared.js';
|
|
11
12
|
import { fetchLicensedPluginPackages } from './shared.js';
|
|
12
13
|
import { renderTable } from '../../../lib/ui.js';
|
|
13
14
|
export default class LicensePluginsList extends Command {
|
|
@@ -19,12 +20,26 @@ export default class LicensePluginsList extends Command {
|
|
|
19
20
|
'<%= config.bin %> <%= command.id %> --env app1 --json',
|
|
20
21
|
];
|
|
21
22
|
static flags = {
|
|
22
|
-
env:
|
|
23
|
+
env: createLicenseEnvFlag('CLI env name to inspect licensed plugins for. Defaults to the current env when omitted'),
|
|
23
24
|
json: licenseJsonFlag,
|
|
24
25
|
'pkg-url': licensePkgUrlFlag,
|
|
26
|
+
yes: licenseYesFlag,
|
|
25
27
|
};
|
|
26
28
|
async run() {
|
|
27
29
|
const { flags } = await this.parse(LicensePluginsList);
|
|
30
|
+
const requestedEnv = flags.env?.trim() || undefined;
|
|
31
|
+
const explicitEnvSelection = Boolean(requestedEnv && hasExplicitEnvSelection(this.argv ?? []));
|
|
32
|
+
if (explicitEnvSelection) {
|
|
33
|
+
const confirmed = await ensureCrossEnvConfirmed({
|
|
34
|
+
command: this,
|
|
35
|
+
requestedEnv,
|
|
36
|
+
yes: flags.yes,
|
|
37
|
+
});
|
|
38
|
+
if (!confirmed) {
|
|
39
|
+
this.log('Canceled.');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
28
43
|
const runtime = await requireLicenseRuntime(flags.env);
|
|
29
44
|
const { commercialPlugins, licensedPlugins } = await fetchLicensedPluginPackages(runtime, {
|
|
30
45
|
pkgUrl: flags['pkg-url'],
|
|
@@ -10,7 +10,9 @@ import { Command, Flags } from '@oclif/core';
|
|
|
10
10
|
import pc from 'picocolors';
|
|
11
11
|
import { readFile } from 'node:fs/promises';
|
|
12
12
|
import path from 'node:path';
|
|
13
|
-
import {
|
|
13
|
+
import { DEFAULT_DOCKER_REGISTRY, DEFAULT_DOCKER_VERSION, resolveDockerImageRef, } from "../../../lib/docker-image.js";
|
|
14
|
+
import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../../lib/env-guard.js';
|
|
15
|
+
import { createLicenseEnvFlag, licenseJsonFlag, licensePkgUrlFlag, licenseYesFlag, requireLicenseRuntime, } from '../shared.js';
|
|
14
16
|
import { syncLicensedPlugins } from './shared.js';
|
|
15
17
|
import { resolvePluginStoragePath } from '../../../lib/plugin-storage.js';
|
|
16
18
|
import { commandOutput } from '../../../lib/run-npm.js';
|
|
@@ -18,8 +20,6 @@ import { announceTargetEnv, startTask, stopTask, succeedTask, updateTask } from
|
|
|
18
20
|
const SYNC_LOADING_DELAY_MS = 1200;
|
|
19
21
|
const SYNC_LOADING_UPDATE_MS = 5000;
|
|
20
22
|
const LOCAL_APP_PACKAGE_JSON_PATH = 'node_modules/@nocobase/app/package.json';
|
|
21
|
-
const DEFAULT_DOCKER_REGISTRY = 'nocobase/nocobase';
|
|
22
|
-
const DEFAULT_DOCKER_VERSION = 'alpha';
|
|
23
23
|
function formatActionLabel(action) {
|
|
24
24
|
switch (action) {
|
|
25
25
|
case 'installed':
|
|
@@ -89,7 +89,10 @@ async function resolveLocalAppVersion(runtime) {
|
|
|
89
89
|
}
|
|
90
90
|
async function resolveDockerAppVersion(runtime) {
|
|
91
91
|
const config = runtime.env.config ?? {};
|
|
92
|
-
const imageRef =
|
|
92
|
+
const imageRef = resolveDockerImageRef(config.dockerRegistry, config.downloadVersion, {
|
|
93
|
+
defaultRegistry: DEFAULT_DOCKER_REGISTRY,
|
|
94
|
+
defaultVersion: DEFAULT_DOCKER_VERSION,
|
|
95
|
+
});
|
|
93
96
|
const args = [
|
|
94
97
|
'run',
|
|
95
98
|
'--rm',
|
|
@@ -137,7 +140,7 @@ export default class LicensePluginsSync extends Command {
|
|
|
137
140
|
'<%= config.bin %> <%= command.id %> --env app1 --json',
|
|
138
141
|
];
|
|
139
142
|
static flags = {
|
|
140
|
-
env:
|
|
143
|
+
env: createLicenseEnvFlag('CLI env name to sync licensed plugins for. Defaults to the current env when omitted'),
|
|
141
144
|
json: licenseJsonFlag,
|
|
142
145
|
'pkg-url': licensePkgUrlFlag,
|
|
143
146
|
'dry-run': Flags.boolean({
|
|
@@ -151,9 +154,23 @@ export default class LicensePluginsSync extends Command {
|
|
|
151
154
|
description: 'Show detailed per-plugin sync logs',
|
|
152
155
|
default: false,
|
|
153
156
|
}),
|
|
157
|
+
yes: licenseYesFlag,
|
|
154
158
|
};
|
|
155
159
|
async run() {
|
|
156
160
|
const { flags } = await this.parse(LicensePluginsSync);
|
|
161
|
+
const requestedEnv = flags.env?.trim() || undefined;
|
|
162
|
+
const explicitEnvSelection = Boolean(requestedEnv && hasExplicitEnvSelection(this.argv ?? []));
|
|
163
|
+
if (explicitEnvSelection) {
|
|
164
|
+
const confirmed = await ensureCrossEnvConfirmed({
|
|
165
|
+
command: this,
|
|
166
|
+
requestedEnv,
|
|
167
|
+
yes: flags.yes,
|
|
168
|
+
});
|
|
169
|
+
if (!confirmed) {
|
|
170
|
+
this.log('Canceled.');
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
157
174
|
const runtime = await requireLicenseRuntime(flags.env);
|
|
158
175
|
if (!flags.json) {
|
|
159
176
|
announceTargetEnv(runtime.envName);
|
|
@@ -12,22 +12,28 @@ import path from 'node:path';
|
|
|
12
12
|
import { getEnvAsync, getInstanceIdAsync, keyDecrypt } from '@nocobase/license-kit';
|
|
13
13
|
import _ from 'lodash';
|
|
14
14
|
import { checkExternalDbConnection, readExternalDbConnectionConfig, } from "../../lib/db-connection-check.js";
|
|
15
|
+
import { DEFAULT_DOCKER_REGISTRY, DEFAULT_DOCKER_VERSION, resolveDockerImageRef, } from "../../lib/docker-image.js";
|
|
15
16
|
import { formatMissingManagedAppEnvMessage, resolveManagedAppRuntime } from '../../lib/app-runtime.js';
|
|
16
17
|
import { buildRuntimeEnvVars } from '../../lib/runtime-env-vars.js';
|
|
17
18
|
import { resolveLicensePkgUrlFromConfig } from '../../lib/cli-config.js';
|
|
18
19
|
import { commandOutput } from '../../lib/run-npm.js';
|
|
19
20
|
import { appUrl } from '../env/shared.js';
|
|
20
|
-
export
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
export function createLicenseEnvFlag(description) {
|
|
22
|
+
return Flags.string({
|
|
23
|
+
char: 'e',
|
|
24
|
+
description,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
export const licenseYesFlag = Flags.boolean({
|
|
28
|
+
char: 'y',
|
|
29
|
+
description: 'Confirm using --env when it targets a different env than the current env',
|
|
30
|
+
default: false,
|
|
23
31
|
});
|
|
24
32
|
export const licenseJsonFlag = Flags.boolean({
|
|
25
33
|
description: 'Output the result as JSON',
|
|
26
34
|
default: false,
|
|
27
35
|
});
|
|
28
36
|
const DEFAULT_LICENSE_PKG_URL = 'https://pkg.nocobase.com/';
|
|
29
|
-
const DEFAULT_DOCKER_REGISTRY = 'nocobase/nocobase';
|
|
30
|
-
const DEFAULT_DOCKER_VERSION = 'alpha';
|
|
31
37
|
export const licensePkgUrlFlag = Flags.string({
|
|
32
38
|
description: 'Commercial package service base URL',
|
|
33
39
|
hidden: true,
|
|
@@ -74,7 +80,10 @@ function normalizeDockerPlatform(value) {
|
|
|
74
80
|
}
|
|
75
81
|
function resolveDockerLicenseImageRef(runtime) {
|
|
76
82
|
const config = runtime.env.config ?? {};
|
|
77
|
-
return
|
|
83
|
+
return resolveDockerImageRef(config.dockerRegistry, config.downloadVersion, {
|
|
84
|
+
defaultRegistry: DEFAULT_DOCKER_REGISTRY,
|
|
85
|
+
defaultVersion: DEFAULT_DOCKER_VERSION,
|
|
86
|
+
});
|
|
78
87
|
}
|
|
79
88
|
function buildDockerLicenseDbFlagArgs(envVars) {
|
|
80
89
|
return [
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
import { Command, Flags } from '@oclif/core';
|
|
10
|
-
import {
|
|
10
|
+
import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../lib/env-guard.js';
|
|
11
|
+
import { createLicenseEnvFlag, ensureInstanceId, licenseJsonFlag, licenseYesFlag, requireLicenseRuntime } from './shared.js';
|
|
11
12
|
export default class LicenseStatus extends Command {
|
|
12
13
|
static summary = 'Show commercial license status for the selected env';
|
|
13
14
|
static description = 'Inspect the selected env and show the current commercial licensing status. Use `--doctor` for extra diagnostic checks once the license backend wiring is implemented.';
|
|
@@ -18,8 +19,9 @@ export default class LicenseStatus extends Command {
|
|
|
18
19
|
'<%= config.bin %> <%= command.id %> --env app1 --json',
|
|
19
20
|
];
|
|
20
21
|
static flags = {
|
|
21
|
-
env:
|
|
22
|
+
env: createLicenseEnvFlag('CLI env name to inspect. Defaults to the current env when omitted'),
|
|
22
23
|
json: licenseJsonFlag,
|
|
24
|
+
yes: licenseYesFlag,
|
|
23
25
|
doctor: Flags.boolean({
|
|
24
26
|
description: 'Run extra diagnostic checks and suggestions',
|
|
25
27
|
default: false,
|
|
@@ -27,6 +29,19 @@ export default class LicenseStatus extends Command {
|
|
|
27
29
|
};
|
|
28
30
|
async run() {
|
|
29
31
|
const { flags } = await this.parse(LicenseStatus);
|
|
32
|
+
const requestedEnv = flags.env?.trim() || undefined;
|
|
33
|
+
const explicitEnvSelection = Boolean(requestedEnv && hasExplicitEnvSelection(this.argv ?? []));
|
|
34
|
+
if (explicitEnvSelection) {
|
|
35
|
+
const confirmed = await ensureCrossEnvConfirmed({
|
|
36
|
+
command: this,
|
|
37
|
+
requestedEnv,
|
|
38
|
+
yes: flags.yes,
|
|
39
|
+
});
|
|
40
|
+
if (!confirmed) {
|
|
41
|
+
this.log('Canceled.');
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
30
45
|
const runtime = await requireLicenseRuntime(flags.env);
|
|
31
46
|
const payload = {
|
|
32
47
|
ok: true,
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { Args, Command, Flags } from '@oclif/core';
|
|
10
10
|
import { formatMissingManagedAppEnvMessage, resolveManagedAppRuntime, runDockerNocoBaseCommand, runLocalNocoBaseCommand, } from '../../lib/app-runtime.js';
|
|
11
|
+
import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../lib/env-guard.js';
|
|
11
12
|
import { announceTargetEnv } from '../../lib/ui.js';
|
|
12
13
|
export default class PluginDisable extends Command {
|
|
13
14
|
static hidden = false;
|
|
@@ -27,18 +28,36 @@ export default class PluginDisable extends Command {
|
|
|
27
28
|
static flags = {
|
|
28
29
|
env: Flags.string({
|
|
29
30
|
char: 'e',
|
|
30
|
-
description: 'CLI env name
|
|
31
|
+
description: 'CLI env name to disable plugins for. Defaults to the current env when omitted',
|
|
32
|
+
}),
|
|
33
|
+
yes: Flags.boolean({
|
|
34
|
+
char: 'y',
|
|
35
|
+
description: 'Confirm using --env when it targets a different env than the current env',
|
|
36
|
+
default: false,
|
|
31
37
|
}),
|
|
32
38
|
};
|
|
33
39
|
async run() {
|
|
34
40
|
const { args, flags } = await this.parse(PluginDisable);
|
|
41
|
+
const requestedEnv = flags.env?.trim() || undefined;
|
|
42
|
+
const explicitEnvSelection = Boolean(requestedEnv && hasExplicitEnvSelection(this.argv));
|
|
43
|
+
if (explicitEnvSelection) {
|
|
44
|
+
const confirmed = await ensureCrossEnvConfirmed({
|
|
45
|
+
command: this,
|
|
46
|
+
requestedEnv,
|
|
47
|
+
yes: flags.yes,
|
|
48
|
+
});
|
|
49
|
+
if (!confirmed) {
|
|
50
|
+
this.log('Canceled.');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
35
54
|
const packages = args.packages;
|
|
36
55
|
if (!Array.isArray(packages) || packages.length === 0) {
|
|
37
56
|
this.error('Pass at least one plugin package name.');
|
|
38
57
|
}
|
|
39
|
-
const runtime = await resolveManagedAppRuntime(
|
|
58
|
+
const runtime = await resolveManagedAppRuntime(requestedEnv);
|
|
40
59
|
if (!runtime) {
|
|
41
|
-
this.error(formatMissingManagedAppEnvMessage(
|
|
60
|
+
this.error(formatMissingManagedAppEnvMessage(requestedEnv));
|
|
42
61
|
}
|
|
43
62
|
announceTargetEnv(runtime.envName);
|
|
44
63
|
if (runtime.kind === 'local') {
|
|
@@ -61,6 +80,8 @@ export default class PluginDisable extends Command {
|
|
|
61
80
|
}
|
|
62
81
|
return;
|
|
63
82
|
}
|
|
64
|
-
await this.config.runCommand('api:pm:disable',
|
|
83
|
+
await this.config.runCommand('api:pm:disable', explicitEnvSelection
|
|
84
|
+
? ['--await-response', '--filter-by-tk', packages.join(','), '--env', runtime.envName, '--yes']
|
|
85
|
+
: ['--await-response', '--filter-by-tk', packages.join(',')]);
|
|
65
86
|
}
|
|
66
87
|
}
|