@nocobase/cli 2.1.0-beta.15 → 2.1.0-beta.17

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.
Files changed (132) hide show
  1. package/LICENSE.txt +107 -0
  2. package/README.md +307 -63
  3. package/README.zh-CN.md +332 -0
  4. package/bin/run.cmd +3 -0
  5. package/bin/run.js +114 -0
  6. package/dist/commands/api/resource/create.js +15 -0
  7. package/dist/commands/api/resource/destroy.js +15 -0
  8. package/dist/commands/api/resource/get.js +15 -0
  9. package/dist/commands/api/resource/index.js +20 -0
  10. package/dist/commands/api/resource/list.js +16 -0
  11. package/dist/commands/api/resource/query.js +15 -0
  12. package/dist/commands/api/resource/update.js +15 -0
  13. package/dist/commands/build.js +57 -0
  14. package/dist/commands/db/logs.js +85 -0
  15. package/dist/commands/db/ps.js +60 -0
  16. package/dist/commands/db/shared.js +81 -0
  17. package/dist/commands/db/start.js +70 -0
  18. package/dist/commands/db/stop.js +70 -0
  19. package/dist/commands/dev.js +149 -0
  20. package/dist/commands/down.js +193 -0
  21. package/dist/commands/download.js +779 -0
  22. package/dist/commands/env/add.js +327 -0
  23. package/dist/commands/env/auth.js +62 -0
  24. package/dist/commands/env/list.js +41 -0
  25. package/dist/commands/env/remove.js +65 -0
  26. package/dist/commands/env/update.js +73 -0
  27. package/dist/commands/env/use.js +36 -0
  28. package/dist/commands/init.js +813 -0
  29. package/dist/commands/install.js +1850 -0
  30. package/dist/commands/logs.js +90 -0
  31. package/dist/commands/pm/disable.js +63 -0
  32. package/dist/commands/pm/enable.js +63 -0
  33. package/dist/commands/pm/list.js +54 -0
  34. package/dist/commands/prompts-stages.js +150 -0
  35. package/dist/commands/prompts-test.js +181 -0
  36. package/dist/commands/ps.js +116 -0
  37. package/dist/commands/scaffold/migration.js +38 -0
  38. package/dist/commands/scaffold/plugin.js +37 -0
  39. package/dist/commands/start.js +211 -0
  40. package/dist/commands/stop.js +90 -0
  41. package/dist/commands/upgrade.js +583 -0
  42. package/dist/generated/command-registry.js +133 -0
  43. package/dist/help/runtime-help.js +20 -0
  44. package/dist/lib/api-client.js +243 -0
  45. package/dist/lib/app-runtime.js +142 -0
  46. package/dist/lib/auth-store.js +241 -0
  47. package/dist/lib/bootstrap.js +387 -0
  48. package/dist/lib/build-config.js +10 -0
  49. package/dist/lib/cli-home.js +30 -0
  50. package/dist/lib/cli-locale.js +115 -0
  51. package/dist/lib/command-discovery.js +39 -0
  52. package/dist/lib/env-auth.js +872 -0
  53. package/dist/lib/generated-command.js +142 -0
  54. package/dist/lib/naming.js +70 -0
  55. package/dist/lib/openapi.js +62 -0
  56. package/dist/lib/post-processors.js +23 -0
  57. package/dist/lib/prompt-catalog.js +574 -0
  58. package/dist/lib/prompt-validators.js +185 -0
  59. package/dist/lib/prompt-web-ui.js +2061 -0
  60. package/dist/lib/resource-command.js +335 -0
  61. package/dist/lib/resource-request.js +104 -0
  62. package/dist/lib/run-npm.js +123 -0
  63. package/dist/lib/runtime-generator.js +419 -0
  64. package/dist/lib/runtime-store.js +56 -0
  65. package/dist/lib/ui.js +175 -0
  66. package/dist/locale/en-US.json +319 -0
  67. package/dist/locale/zh-CN.json +319 -0
  68. package/dist/post-processors/data-modeling.js +66 -0
  69. package/dist/post-processors/data-source-manager.js +114 -0
  70. package/dist/post-processors/index.js +19 -0
  71. package/nocobase-ctl.config.json +287 -0
  72. package/package.json +53 -25
  73. package/LICENSE +0 -201
  74. package/bin/index.js +0 -39
  75. package/nocobase.conf.tpl +0 -95
  76. package/src/cli.js +0 -19
  77. package/src/commands/benchmark.js +0 -73
  78. package/src/commands/build.js +0 -49
  79. package/src/commands/clean.js +0 -30
  80. package/src/commands/client.js +0 -166
  81. package/src/commands/create-nginx-conf.js +0 -37
  82. package/src/commands/create-plugin.js +0 -33
  83. package/src/commands/dev.js +0 -200
  84. package/src/commands/doc.js +0 -76
  85. package/src/commands/e2e.js +0 -265
  86. package/src/commands/global.js +0 -43
  87. package/src/commands/index.js +0 -45
  88. package/src/commands/instance-id.js +0 -47
  89. package/src/commands/locale/cronstrue.js +0 -122
  90. package/src/commands/locale/react-js-cron/en-US.json +0 -75
  91. package/src/commands/locale/react-js-cron/index.js +0 -17
  92. package/src/commands/locale/react-js-cron/zh-CN.json +0 -33
  93. package/src/commands/locale/react-js-cron/zh-TW.json +0 -33
  94. package/src/commands/locale.js +0 -81
  95. package/src/commands/p-test.js +0 -88
  96. package/src/commands/perf.js +0 -63
  97. package/src/commands/pkg.js +0 -321
  98. package/src/commands/pm2.js +0 -37
  99. package/src/commands/postinstall.js +0 -88
  100. package/src/commands/start.js +0 -148
  101. package/src/commands/tar.js +0 -36
  102. package/src/commands/test-coverage.js +0 -55
  103. package/src/commands/test.js +0 -107
  104. package/src/commands/umi.js +0 -33
  105. package/src/commands/update-deps.js +0 -72
  106. package/src/commands/upgrade.js +0 -47
  107. package/src/commands/view-license-key.js +0 -44
  108. package/src/index.js +0 -14
  109. package/src/license.js +0 -76
  110. package/src/logger.js +0 -75
  111. package/src/plugin-generator.js +0 -80
  112. package/src/util.js +0 -517
  113. package/templates/bundle-status.html +0 -338
  114. package/templates/create-app-package.json +0 -39
  115. package/templates/plugin/.npmignore.tpl +0 -2
  116. package/templates/plugin/README.md.tpl +0 -1
  117. package/templates/plugin/client.d.ts +0 -2
  118. package/templates/plugin/client.js +0 -1
  119. package/templates/plugin/package.json.tpl +0 -11
  120. package/templates/plugin/server.d.ts +0 -2
  121. package/templates/plugin/server.js +0 -1
  122. package/templates/plugin/src/client/client.d.ts +0 -249
  123. package/templates/plugin/src/client/index.tsx.tpl +0 -1
  124. package/templates/plugin/src/client/locale.ts +0 -21
  125. package/templates/plugin/src/client/models/index.ts +0 -12
  126. package/templates/plugin/src/client/plugin.tsx.tpl +0 -10
  127. package/templates/plugin/src/index.ts +0 -2
  128. package/templates/plugin/src/locale/en-US.json +0 -1
  129. package/templates/plugin/src/locale/zh-CN.json +0 -1
  130. package/templates/plugin/src/server/collections/.gitkeep +0 -0
  131. package/templates/plugin/src/server/index.ts.tpl +0 -1
  132. package/templates/plugin/src/server/plugin.ts.tpl +0 -19
@@ -0,0 +1,327 @@
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 { upsertEnv } from '../../lib/auth-store.js';
11
+ import { runPromptCatalog, } from '../../lib/prompt-catalog.js';
12
+ import { applyCliLocale, CLI_LOCALE_FLAG_DESCRIPTION, CLI_LOCALE_FLAG_OPTIONS, localeText, } from '../../lib/cli-locale.js';
13
+ import { validateApiBaseUrl } from '../../lib/prompt-validators.js';
14
+ import { printVerbose, setVerboseMode } from '../../lib/ui.js';
15
+ import * as p from '@clack/prompts';
16
+ const ENV_RUNTIME_FLAG_MAP = {
17
+ source: 'source',
18
+ 'download-version': 'downloadVersion',
19
+ 'docker-registry': 'dockerRegistry',
20
+ 'docker-platform': 'dockerPlatform',
21
+ 'git-url': 'gitUrl',
22
+ 'npm-registry': 'npmRegistry',
23
+ 'app-root-path': 'appRootPath',
24
+ 'storage-path': 'storagePath',
25
+ 'app-port': 'appPort',
26
+ 'app-key': 'appKey',
27
+ timezone: 'timezone',
28
+ 'db-dialect': 'dbDialect',
29
+ 'builtin-db-image': 'builtinDbImage',
30
+ 'db-host': 'dbHost',
31
+ 'db-port': 'dbPort',
32
+ 'db-database': 'dbDatabase',
33
+ 'db-user': 'dbUser',
34
+ 'db-password': 'dbPassword',
35
+ };
36
+ const ENV_BOOLEAN_RUNTIME_FLAG_MAP = {
37
+ 'builtin-db': 'builtinDb',
38
+ 'dev-dependencies': 'devDependencies',
39
+ build: 'build',
40
+ 'build-dts': 'buildDts',
41
+ };
42
+ const envAddText = (key, values) => localeText(`commands.envAdd.${key}`, values);
43
+ export default class EnvAdd extends Command {
44
+ static summary = 'Save a named NocoBase API endpoint (token or OAuth), then switch the CLI to use it';
45
+ static examples = [
46
+ '<%= config.bin %> <%= command.id %>',
47
+ '<%= config.bin %> <%= command.id %> local',
48
+ '<%= config.bin %> <%= command.id %> local --scope project --api-base-url http://localhost:13000/api --auth-type oauth',
49
+ ];
50
+ static args = {
51
+ name: Args.string({
52
+ description: 'Label for this environment (optional first argument; in a TTY, prompted when omitted; required when not using a TTY)',
53
+ required: false,
54
+ }),
55
+ };
56
+ static flags = {
57
+ env: Flags.string({
58
+ char: 'e',
59
+ hidden: true,
60
+ deprecated: true,
61
+ description: 'Environment name (same as the optional positional argument; for compatibility with -e/--env on other commands)',
62
+ }),
63
+ verbose: Flags.boolean({
64
+ description: 'Print detailed progress while writing config',
65
+ default: false,
66
+ }),
67
+ locale: Flags.string({
68
+ description: CLI_LOCALE_FLAG_DESCRIPTION,
69
+ options: CLI_LOCALE_FLAG_OPTIONS,
70
+ }),
71
+ 'no-intro': Flags.boolean({
72
+ hidden: true,
73
+ description: 'Skip command intro when invoked by another CLI command',
74
+ default: false,
75
+ }),
76
+ scope: Flags.string({
77
+ char: 's',
78
+ description: 'Where to store env config: project (.nocobase in the repo) or global (user-level); prompted in a TTY when omitted',
79
+ options: ['project', 'global'],
80
+ default: 'project',
81
+ }),
82
+ 'default-api-base-url': Flags.string({
83
+ char: 'd',
84
+ hidden: true,
85
+ description: 'Default API base URL for HTTP API calls, including the /api prefix (e.g. http://localhost:13000/api); prompted in a TTY when omitted',
86
+ }),
87
+ 'api-base-url': Flags.string({
88
+ char: 'u',
89
+ aliases: ['base-url'],
90
+ description: 'Root URL for HTTP API calls, including the /api prefix (e.g. http://localhost:13000/api); prompted in a TTY when omitted',
91
+ }),
92
+ 'auth-type': Flags.string({
93
+ char: 'a',
94
+ description: 'Authentication: token (API key) or oauth (browser login via `nb env auth`); prompted in a TTY when omitted',
95
+ options: ['token', 'oauth'],
96
+ }),
97
+ 'access-token': Flags.string({
98
+ char: 't',
99
+ aliases: ['token'],
100
+ description: 'API key or access token when using --auth-type token (prompted in a TTY when omitted)',
101
+ }),
102
+ source: Flags.string({
103
+ hidden: true,
104
+ description: 'Application source saved with this env',
105
+ }),
106
+ 'download-version': Flags.string({
107
+ hidden: true,
108
+ description: 'Downloaded app version saved with this env',
109
+ }),
110
+ 'docker-registry': Flags.string({
111
+ hidden: true,
112
+ description: 'Docker registry saved with this env',
113
+ }),
114
+ 'docker-platform': Flags.string({
115
+ hidden: true,
116
+ description: 'Docker image platform saved with this env',
117
+ }),
118
+ 'git-url': Flags.string({
119
+ hidden: true,
120
+ description: 'Git repository URL saved with this env',
121
+ }),
122
+ 'npm-registry': Flags.string({
123
+ hidden: true,
124
+ description: 'npm registry saved with this env',
125
+ }),
126
+ 'dev-dependencies': Flags.boolean({
127
+ allowNo: true,
128
+ hidden: true,
129
+ description: 'Whether development dependencies were installed for this env',
130
+ }),
131
+ build: Flags.boolean({
132
+ allowNo: true,
133
+ hidden: true,
134
+ description: 'Whether the app was built after download for this env',
135
+ }),
136
+ 'build-dts': Flags.boolean({
137
+ allowNo: true,
138
+ hidden: true,
139
+ description: 'Whether declaration files were emitted during build for this env',
140
+ }),
141
+ 'app-root-path': Flags.string({
142
+ hidden: true,
143
+ description: 'Application root path saved with this env',
144
+ }),
145
+ 'storage-path': Flags.string({
146
+ hidden: true,
147
+ description: 'Storage path saved with this env',
148
+ }),
149
+ 'app-port': Flags.string({
150
+ hidden: true,
151
+ description: 'Application HTTP port saved with this env',
152
+ }),
153
+ 'app-key': Flags.string({
154
+ hidden: true,
155
+ description: 'Application secret key saved with this env',
156
+ }),
157
+ timezone: Flags.string({
158
+ hidden: true,
159
+ description: 'Application timezone saved with this env',
160
+ }),
161
+ 'builtin-db': Flags.boolean({
162
+ allowNo: true,
163
+ hidden: true,
164
+ description: 'Whether this env uses a CLI-managed built-in database',
165
+ }),
166
+ 'db-dialect': Flags.string({
167
+ hidden: true,
168
+ description: 'Database dialect saved with this env',
169
+ }),
170
+ 'builtin-db-image': Flags.string({
171
+ hidden: true,
172
+ description: 'Built-in database image saved with this env',
173
+ }),
174
+ 'db-host': Flags.string({
175
+ hidden: true,
176
+ description: 'Database host saved with this env',
177
+ }),
178
+ 'db-port': Flags.string({
179
+ hidden: true,
180
+ description: 'Database port saved with this env',
181
+ }),
182
+ 'db-database': Flags.string({
183
+ hidden: true,
184
+ description: 'Database name saved with this env',
185
+ }),
186
+ 'db-user': Flags.string({
187
+ hidden: true,
188
+ description: 'Database user saved with this env',
189
+ }),
190
+ 'db-password': Flags.string({
191
+ hidden: true,
192
+ description: 'Database password saved with this env',
193
+ }),
194
+ };
195
+ static prompts = {
196
+ name: {
197
+ type: 'text',
198
+ message: envAddText('prompts.name.message'),
199
+ placeholder: envAddText('prompts.name.placeholder'),
200
+ required: true,
201
+ },
202
+ scope: {
203
+ type: 'select',
204
+ message: envAddText('prompts.scope.message'),
205
+ options: [
206
+ {
207
+ value: 'project',
208
+ label: envAddText('prompts.scope.projectLabel'),
209
+ hint: envAddText('prompts.scope.projectHint'),
210
+ },
211
+ {
212
+ value: 'global',
213
+ label: envAddText('prompts.scope.globalLabel'),
214
+ hint: envAddText('prompts.scope.globalHint'),
215
+ },
216
+ ],
217
+ initialValue: 'project',
218
+ required: true,
219
+ },
220
+ apiBaseUrl: {
221
+ type: 'text',
222
+ message: envAddText('prompts.apiBaseUrl.message'),
223
+ placeholder: envAddText('prompts.apiBaseUrl.placeholder'),
224
+ required: true,
225
+ validate: validateApiBaseUrl,
226
+ },
227
+ authType: {
228
+ type: 'select',
229
+ message: envAddText('prompts.authType.message'),
230
+ options: [
231
+ {
232
+ value: 'oauth',
233
+ label: envAddText('prompts.authType.oauthLabel'),
234
+ hint: envAddText('prompts.authType.oauthHint'),
235
+ },
236
+ { value: 'token', label: envAddText('prompts.authType.tokenLabel') },
237
+ ],
238
+ initialValue: 'oauth',
239
+ required: true,
240
+ },
241
+ accessToken: {
242
+ type: 'text',
243
+ message: envAddText('prompts.accessToken.message'),
244
+ placeholder: envAddText('prompts.accessToken.placeholder'),
245
+ required: true,
246
+ hidden: (values) => values.authType !== 'token',
247
+ },
248
+ };
249
+ buildPromptValues(nameArg, flags) {
250
+ const values = {};
251
+ const name = nameArg?.trim() || flags.env?.trim();
252
+ if (name) {
253
+ values.name = name;
254
+ }
255
+ if (flags.scope) {
256
+ values.scope = flags.scope;
257
+ }
258
+ const apiFromFlag = flags['api-base-url'] ?? flags['base-url'];
259
+ if (typeof apiFromFlag === 'string' && apiFromFlag.trim() !== '') {
260
+ values.apiBaseUrl = apiFromFlag.trim();
261
+ }
262
+ if (flags['auth-type']) {
263
+ values.authType = flags['auth-type'];
264
+ }
265
+ const token = flags['access-token'] ?? flags.token;
266
+ if (typeof token === 'string' && token !== '') {
267
+ values.accessToken = token;
268
+ }
269
+ return values;
270
+ }
271
+ buildPromptInitialValues(flags) {
272
+ const initialValues = {};
273
+ const defaultApiBaseUrl = flags['default-api-base-url']?.trim();
274
+ if (defaultApiBaseUrl) {
275
+ initialValues.apiBaseUrl = defaultApiBaseUrl;
276
+ }
277
+ return initialValues;
278
+ }
279
+ buildEnvConfig(results, flags) {
280
+ const envConfig = {
281
+ baseUrl: String(results.apiBaseUrl ?? ''),
282
+ };
283
+ for (const [flagName, configKey] of Object.entries(ENV_RUNTIME_FLAG_MAP)) {
284
+ const value = flags[flagName];
285
+ if (typeof value === 'string' && value.trim() !== '') {
286
+ envConfig[configKey] = value.trim();
287
+ }
288
+ }
289
+ for (const [flagName, configKey] of Object.entries(ENV_BOOLEAN_RUNTIME_FLAG_MAP)) {
290
+ const value = flags[flagName];
291
+ if (typeof value === 'boolean') {
292
+ envConfig[configKey] = value;
293
+ }
294
+ }
295
+ if (flags['builtin-db'] === false) {
296
+ envConfig.builtinDbImage = undefined;
297
+ }
298
+ if (results.authType === 'token' && results.accessToken != null) {
299
+ envConfig.accessToken = String(results.accessToken);
300
+ }
301
+ return envConfig;
302
+ }
303
+ async run() {
304
+ const { args, flags } = await this.parse(EnvAdd);
305
+ const parsedFlags = flags;
306
+ applyCliLocale(parsedFlags.locale);
307
+ setVerboseMode(parsedFlags.verbose);
308
+ if (!parsedFlags['no-intro']) {
309
+ p.intro('Connect a NocoBase Environment');
310
+ }
311
+ const results = await runPromptCatalog(EnvAdd.prompts, {
312
+ values: this.buildPromptValues(args.name, parsedFlags),
313
+ initialValues: this.buildPromptInitialValues(parsedFlags),
314
+ command: this,
315
+ });
316
+ const envName = String(results.name);
317
+ const scope = results.scope;
318
+ const envConfig = this.buildEnvConfig(results, parsedFlags);
319
+ printVerbose(`Saving env "${envName}" with scope "${scope}".`);
320
+ await upsertEnv(envName, envConfig, { scope });
321
+ if (results.authType === 'oauth') {
322
+ await this.config.runCommand('env:auth', [envName]);
323
+ }
324
+ await this.config.runCommand('env:update', [envName]);
325
+ p.outro(`Env "${envName}" added successfully.`);
326
+ }
327
+ }
@@ -0,0 +1,62 @@
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 { getCurrentEnvName } from '../../lib/auth-store.js';
11
+ import { formatCliHomeScope } from '../../lib/cli-home.js';
12
+ import { authenticateEnvWithOauth } from '../../lib/env-auth.js';
13
+ import { failTask, startTask, succeedTask } from '../../lib/ui.js';
14
+ export default class EnvAuth extends Command {
15
+ static summary = 'Sign in to a saved NocoBase environment with OAuth';
16
+ static examples = [
17
+ '<%= config.bin %> <%= command.id %>',
18
+ '<%= config.bin %> <%= command.id %> prod',
19
+ '<%= config.bin %> <%= command.id %> --scope global',
20
+ ];
21
+ static args = {
22
+ name: Args.string({
23
+ description: 'Environment name (omit to use the current env)',
24
+ required: false,
25
+ }),
26
+ };
27
+ static flags = {
28
+ env: Flags.string({
29
+ char: 'e',
30
+ hidden: true,
31
+ deprecated: true,
32
+ description: 'Environment name (same as the optional positional argument; for compatibility with -e/--env on other commands)',
33
+ }),
34
+ scope: Flags.string({
35
+ char: 's',
36
+ description: 'Config scope',
37
+ options: ['project', 'global'],
38
+ }),
39
+ };
40
+ async run() {
41
+ const { args, flags } = await this.parse(EnvAuth);
42
+ const scope = flags.scope;
43
+ const nameArg = args.name?.trim();
44
+ const nameFlag = flags.env?.trim() || undefined;
45
+ if (nameArg && nameFlag && nameArg !== nameFlag) {
46
+ this.error(`Environment name was provided both as the argument ("${nameArg}") and as --env ("${nameFlag}"). Please use only one.`);
47
+ }
48
+ const envName = nameArg || nameFlag || (await getCurrentEnvName({ scope }));
49
+ startTask(`Starting browser sign-in for "${envName}"${scope ? ` (${formatCliHomeScope(scope)} scope)` : ''}...`);
50
+ try {
51
+ await authenticateEnvWithOauth({
52
+ envName,
53
+ scope,
54
+ });
55
+ succeedTask(`Signed in to "${envName}"${scope ? ` in ${formatCliHomeScope(scope)} scope` : ''}.`);
56
+ }
57
+ catch (error) {
58
+ failTask(`Sign-in failed for "${envName}"${scope ? ` in ${formatCliHomeScope(scope)} scope` : ''}.`);
59
+ throw error;
60
+ }
61
+ }
62
+ }
@@ -0,0 +1,41 @@
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 { listEnvs } from '../../lib/auth-store.js';
11
+ import { formatCliHomeScope } from '../../lib/cli-home.js';
12
+ import { renderTable } from '../../lib/ui.js';
13
+ export default class EnvList extends Command {
14
+ static summary = 'List configured environments';
15
+ static examples = [
16
+ '<%= config.bin %> <%= command.id %>',
17
+ ];
18
+ static flags = {
19
+ scope: Flags.string({
20
+ char: 's',
21
+ description: 'Config scope',
22
+ options: ['project', 'global'],
23
+ }),
24
+ };
25
+ async run() {
26
+ const { flags } = await this.parse(EnvList);
27
+ const scope = flags.scope;
28
+ const { currentEnv, envs } = await listEnvs({ scope });
29
+ const names = Object.keys(envs).sort();
30
+ if (!names.length) {
31
+ this.log(`No envs configured${scope ? ` in ${formatCliHomeScope(scope)} scope` : ''}.`);
32
+ this.log('Run `nb env add <name> --base-url <url>` to add one.');
33
+ return;
34
+ }
35
+ const rows = names.map((name) => {
36
+ const env = envs[name];
37
+ return [name === currentEnv ? '*' : '', name, env.baseUrl ?? '', env.auth?.type ?? '', env.runtime?.version ?? ''];
38
+ });
39
+ this.log(renderTable(['Current', 'Name', 'Base URL', 'Auth', 'Runtime'], rows));
40
+ }
41
+ }
@@ -0,0 +1,65 @@
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 { getCurrentEnvName, removeEnv } from '../../lib/auth-store.js';
11
+ import { formatCliHomeScope } from '../../lib/cli-home.js';
12
+ import { confirmAction, isInteractiveTerminal, printVerbose, setVerboseMode } from '../../lib/ui.js';
13
+ export default class EnvRemove extends Command {
14
+ static summary = 'Remove a configured environment';
15
+ static examples = [
16
+ '<%= config.bin %> <%= command.id %> staging',
17
+ '<%= config.bin %> <%= command.id %> staging -f',
18
+ ];
19
+ static flags = {
20
+ force: Flags.boolean({
21
+ char: 'f',
22
+ description: 'Remove without confirmation',
23
+ default: false,
24
+ }),
25
+ verbose: Flags.boolean({
26
+ description: 'Show detailed progress output',
27
+ default: false,
28
+ }),
29
+ scope: Flags.string({
30
+ char: 's',
31
+ description: 'Config scope',
32
+ options: ['project', 'global'],
33
+ }),
34
+ };
35
+ static args = {
36
+ name: Args.string({
37
+ description: 'Configured environment name',
38
+ required: true,
39
+ }),
40
+ };
41
+ async run() {
42
+ const { args, flags } = await this.parse(EnvRemove);
43
+ setVerboseMode(flags.verbose);
44
+ const scope = flags.scope;
45
+ const currentEnv = await getCurrentEnvName({ scope });
46
+ if (args.name === currentEnv && !flags.force) {
47
+ if (!isInteractiveTerminal()) {
48
+ this.error('Refusing to remove the current env without confirmation. Re-run with `--force`.');
49
+ }
50
+ const confirmed = await confirmAction(`Remove current env "${args.name}"?`, { defaultValue: false });
51
+ if (!confirmed) {
52
+ this.log('Canceled.');
53
+ return;
54
+ }
55
+ }
56
+ printVerbose(`Removing env "${args.name}"`);
57
+ const result = await removeEnv(args.name, { scope });
58
+ this.log(`Removed env "${result.removed}"${scope ? ` from ${formatCliHomeScope(scope)} scope` : ''}.`);
59
+ if (result.hasEnvs) {
60
+ this.log(`Current env: ${result.currentEnv}`);
61
+ return;
62
+ }
63
+ this.log('No envs configured.');
64
+ }
65
+ }
@@ -0,0 +1,73 @@
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 { fileURLToPath } from 'node:url';
11
+ import { Args, Command, Flags } from '@oclif/core';
12
+ import { getCurrentEnvName } from '../../lib/auth-store.js';
13
+ import { updateEnvRuntime } from '../../lib/bootstrap.js';
14
+ import { formatCliHomeScope } from '../../lib/cli-home.js';
15
+ import { failTask, startTask, succeedTask } from '../../lib/ui.js';
16
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
17
+ export default class EnvUpdate extends Command {
18
+ static summary = 'Refresh an environment runtime from swagger:get and persist connection overrides';
19
+ static examples = [
20
+ '<%= config.bin %> <%= command.id %>',
21
+ '<%= config.bin %> <%= command.id %> prod',
22
+ ];
23
+ static args = {
24
+ name: Args.string({
25
+ description: 'Environment name (omit to use the current env)',
26
+ required: false,
27
+ }),
28
+ };
29
+ static flags = {
30
+ verbose: Flags.boolean({
31
+ description: 'Show detailed progress output',
32
+ default: false,
33
+ }),
34
+ scope: Flags.string({
35
+ char: 's',
36
+ description: 'Config scope',
37
+ options: ['project', 'global'],
38
+ }),
39
+ 'base-url': Flags.string({
40
+ description: 'NocoBase API base URL override. When provided, persist it to the target env before saving the refreshed runtime.',
41
+ }),
42
+ role: Flags.string({
43
+ description: 'Role override, sent as X-Role',
44
+ }),
45
+ token: Flags.string({
46
+ char: 't',
47
+ description: 'API key override. When provided, persist it to the target env before saving the refreshed runtime.',
48
+ }),
49
+ };
50
+ async run() {
51
+ const { args, flags } = await this.parse(EnvUpdate);
52
+ const scope = flags.scope;
53
+ const envName = args.name;
54
+ const envLabel = envName ?? (await getCurrentEnvName({ scope }));
55
+ startTask(`Updating env runtime: ${envLabel}${scope ? ` (${formatCliHomeScope(scope)})` : ''}`);
56
+ try {
57
+ const runtime = await updateEnvRuntime({
58
+ envName,
59
+ scope,
60
+ baseUrl: flags['base-url'],
61
+ role: flags.role,
62
+ token: flags.token,
63
+ configFile: path.join(path.dirname(path.dirname(path.dirname(__dirname))), 'nocobase-ctl.config.json'),
64
+ verbose: flags.verbose,
65
+ });
66
+ succeedTask(`Updated env "${envLabel}" to runtime "${runtime.version}"${scope ? ` in ${formatCliHomeScope(scope)} scope` : ''}.`);
67
+ }
68
+ catch (error) {
69
+ failTask(`Failed to update env "${envLabel}".`);
70
+ throw error;
71
+ }
72
+ }
73
+ }
@@ -0,0 +1,36 @@
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 { setCurrentEnv } from '../../lib/auth-store.js';
11
+ import { formatCliHomeScope } from '../../lib/cli-home.js';
12
+ export default class EnvUse extends Command {
13
+ static summary = 'Switch the current environment';
14
+ static examples = [
15
+ '<%= config.bin %> <%= command.id %> local',
16
+ ];
17
+ static flags = {
18
+ scope: Flags.string({
19
+ char: 's',
20
+ description: 'Config scope',
21
+ options: ['project', 'global'],
22
+ }),
23
+ };
24
+ static args = {
25
+ name: Args.string({
26
+ description: 'Configured environment name',
27
+ required: true,
28
+ }),
29
+ };
30
+ async run() {
31
+ const { args, flags } = await this.parse(EnvUse);
32
+ const scope = flags.scope;
33
+ await setCurrentEnv(args.name, { scope });
34
+ this.log(`Current env: ${args.name}${scope ? ` (${formatCliHomeScope(scope)} scope)` : ''}`);
35
+ }
36
+ }