@nocobase/cli 2.1.0-beta.32 → 2.1.0-beta.34
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/dist/commands/app/down.js +10 -13
- package/dist/commands/app/logs.js +0 -1
- package/dist/commands/app/restart.js +63 -2
- package/dist/commands/app/start.js +41 -17
- package/dist/commands/app/stop.js +0 -1
- package/dist/commands/app/upgrade.js +9 -4
- package/dist/commands/env/add.js +3 -4
- package/dist/commands/env/auth.js +3 -2
- package/dist/commands/env/remove.js +38 -13
- package/dist/commands/env/update.js +9 -2
- package/dist/commands/examples/prompts-stages.js +4 -4
- package/dist/commands/examples/prompts-test.js +4 -4
- package/dist/commands/init.js +38 -31
- package/dist/commands/install.js +100 -63
- package/dist/commands/license/activate.js +66 -64
- package/dist/commands/license/id.js +0 -1
- package/dist/commands/license/plugins/clean.js +0 -1
- package/dist/commands/license/plugins/list.js +0 -1
- package/dist/commands/license/plugins/sync.js +0 -1
- package/dist/commands/license/shared.js +3 -3
- package/dist/commands/license/status.js +0 -1
- package/dist/commands/plugin/disable.js +0 -1
- package/dist/commands/plugin/enable.js +0 -1
- package/dist/commands/plugin/list.js +0 -1
- package/dist/commands/self/update.js +12 -3
- package/dist/commands/skills/install.js +12 -3
- package/dist/commands/skills/remove.js +12 -3
- package/dist/commands/skills/update.js +12 -3
- package/dist/commands/source/dev.js +0 -1
- package/dist/commands/source/download.js +29 -17
- package/dist/lib/app-managed-resources.js +8 -2
- package/dist/lib/bootstrap.js +11 -2
- package/dist/lib/db-connection-check.js +3 -23
- package/dist/lib/docker-env-file.js +52 -0
- package/dist/lib/env-auth.js +4 -3
- package/dist/lib/env-config.js +1 -0
- package/dist/lib/env-guard.js +8 -7
- package/dist/lib/generated-command.js +0 -1
- package/dist/lib/inquirer-theme.js +17 -0
- package/dist/lib/inquirer.js +244 -0
- package/dist/lib/object-utils.js +76 -0
- package/dist/lib/prompt-catalog-core.js +185 -0
- package/dist/lib/prompt-catalog-terminal.js +375 -0
- package/dist/lib/prompt-catalog.js +2 -573
- package/dist/lib/prompt-validators.js +56 -1
- package/dist/lib/resource-command.js +0 -1
- package/dist/lib/skills-manager.js +75 -11
- package/dist/lib/startup-update.js +12 -8
- package/dist/lib/ui.js +28 -51
- package/dist/locale/en-US.json +8 -3
- package/dist/locale/zh-CN.json +8 -3
- package/dist/post-processors/data-modeling.js +25 -7
- package/dist/post-processors/data-source-manager.js +24 -0
- package/nocobase-ctl.config.json +20 -1
- package/package.json +7 -5
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
|
-
import * as p from '@clack/prompts';
|
|
10
9
|
import { Command, Flags } from '@oclif/core';
|
|
11
10
|
import { readFile } from 'node:fs/promises';
|
|
12
11
|
import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../lib/env-guard.js';
|
|
12
|
+
import { input, password as promptPassword, select } from "../../lib/inquirer.js";
|
|
13
13
|
import { createLicenseEnvFlag, ensureInstanceId, licenseJsonFlag, licensePkgUrlFlag, licenseYesFlag, redactLicenseKey, requireLicenseRuntime, resolveLicenseKeyFile, resolveLicenseServiceUrl, saveLicenseKey, sanitizeLicenseOutput, validateLicenseKey, } from './shared.js';
|
|
14
14
|
import { announceTargetEnv, isInteractiveTerminal } from '../../lib/ui.js';
|
|
15
15
|
import { appUrl } from '../env/shared.js';
|
|
@@ -17,102 +17,107 @@ function resolveOnlineInputValue(value) {
|
|
|
17
17
|
return String(value ?? '').trim();
|
|
18
18
|
}
|
|
19
19
|
async function promptActivationMode() {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
20
|
+
try {
|
|
21
|
+
return await select({
|
|
22
|
+
message: 'How do you want to activate the license?',
|
|
23
|
+
choices: [
|
|
24
|
+
{ value: 'key', name: 'Use an existing license key' },
|
|
25
|
+
{ value: 'online', name: 'Request and activate a license online' },
|
|
26
|
+
{ value: 'cancel', name: 'Cancel' },
|
|
27
|
+
],
|
|
28
|
+
default: 'key',
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
31
32
|
return 'cancel';
|
|
32
33
|
}
|
|
33
|
-
return answer;
|
|
34
34
|
}
|
|
35
35
|
async function promptLicenseKeyInput() {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
36
|
+
let answer;
|
|
37
|
+
try {
|
|
38
|
+
answer = await select({
|
|
39
|
+
message: 'How do you want to provide the license key?',
|
|
40
|
+
choices: [
|
|
41
|
+
{ value: 'key', name: 'Paste the license key' },
|
|
42
|
+
{ value: 'file', name: 'Read the key from a file' },
|
|
43
|
+
],
|
|
44
|
+
default: 'key',
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
46
48
|
return {};
|
|
47
49
|
}
|
|
48
50
|
if (answer === 'key') {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
try {
|
|
52
|
+
const key = await input({
|
|
53
|
+
message: 'License key',
|
|
54
|
+
validate: (value) => String(value ?? '').trim() ? true : 'License key is required.',
|
|
55
|
+
});
|
|
56
|
+
return { key: String(key ?? '').trim() || undefined };
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
55
59
|
return {};
|
|
56
60
|
}
|
|
57
|
-
return { key: String(key ?? '').trim() || undefined };
|
|
58
61
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
try {
|
|
63
|
+
const keyFile = await input({
|
|
64
|
+
message: 'Path to the license key file',
|
|
65
|
+
validate: (value) => String(value ?? '').trim() ? true : 'License key file path is required.',
|
|
66
|
+
});
|
|
67
|
+
return { keyFile: String(keyFile ?? '').trim() || undefined };
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
65
70
|
return {};
|
|
66
71
|
}
|
|
67
|
-
return { keyFile: String(keyFile ?? '').trim() || undefined };
|
|
68
72
|
}
|
|
69
73
|
async function promptOnlineActivationInput(initial) {
|
|
70
74
|
let account = String(initial.account ?? '').trim();
|
|
71
75
|
if (!account) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
try {
|
|
77
|
+
const answer = await input({
|
|
78
|
+
message: 'Service account',
|
|
79
|
+
validate: (value) => String(value ?? '').trim() ? true : 'Service account is required.',
|
|
80
|
+
});
|
|
81
|
+
account = String(answer ?? '').trim();
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
78
84
|
return;
|
|
79
85
|
}
|
|
80
|
-
account = String(answer ?? '').trim();
|
|
81
86
|
}
|
|
82
87
|
if (!account) {
|
|
83
|
-
p.cancel('License activation cancelled.');
|
|
84
88
|
return;
|
|
85
89
|
}
|
|
86
90
|
let password = String(initial.password ?? '').trim();
|
|
87
91
|
if (!password) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
try {
|
|
93
|
+
const answer = await promptPassword({
|
|
94
|
+
message: 'Service password',
|
|
95
|
+
mask: '•',
|
|
96
|
+
validate: (value) => String(value ?? '').trim() ? true : 'Service password is required.',
|
|
97
|
+
});
|
|
98
|
+
password = String(answer ?? '').trim();
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
94
101
|
return;
|
|
95
102
|
}
|
|
96
|
-
password = String(answer ?? '').trim();
|
|
97
103
|
}
|
|
98
104
|
if (!password) {
|
|
99
|
-
p.cancel('License activation cancelled.');
|
|
100
105
|
return;
|
|
101
106
|
}
|
|
102
107
|
let appName = String(initial.appName ?? '').trim();
|
|
103
108
|
if (!appName) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
109
|
+
try {
|
|
110
|
+
const answer = await input({
|
|
111
|
+
message: 'Application name',
|
|
112
|
+
validate: (value) => String(value ?? '').trim() ? true : 'Application name is required.',
|
|
113
|
+
});
|
|
114
|
+
appName = String(answer ?? '').trim();
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
110
117
|
return;
|
|
111
118
|
}
|
|
112
|
-
appName = String(answer ?? '').trim();
|
|
113
119
|
}
|
|
114
120
|
if (!appName) {
|
|
115
|
-
p.cancel('License activation cancelled.');
|
|
116
121
|
return;
|
|
117
122
|
}
|
|
118
123
|
return {
|
|
@@ -206,7 +211,6 @@ export default class LicenseActivate extends Command {
|
|
|
206
211
|
yes: flags.yes,
|
|
207
212
|
});
|
|
208
213
|
if (!confirmed) {
|
|
209
|
-
this.log('Canceled.');
|
|
210
214
|
return;
|
|
211
215
|
}
|
|
212
216
|
}
|
|
@@ -223,7 +227,6 @@ export default class LicenseActivate extends Command {
|
|
|
223
227
|
}
|
|
224
228
|
const mode = await promptActivationMode();
|
|
225
229
|
if (mode === 'cancel') {
|
|
226
|
-
this.log('Cancelled license activation.');
|
|
227
230
|
return;
|
|
228
231
|
}
|
|
229
232
|
if (mode === 'online') {
|
|
@@ -258,7 +261,6 @@ export default class LicenseActivate extends Command {
|
|
|
258
261
|
}
|
|
259
262
|
const prompted = await promptOnlineActivationInput(initialOnline);
|
|
260
263
|
if (!prompted) {
|
|
261
|
-
this.log('Cancelled license activation.');
|
|
262
264
|
return;
|
|
263
265
|
}
|
|
264
266
|
onlineInput = prompted;
|
|
@@ -10,12 +10,12 @@ import { Flags } from '@oclif/core';
|
|
|
10
10
|
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
11
11
|
import path from 'node:path';
|
|
12
12
|
import { getEnvAsync, getInstanceIdAsync, keyDecrypt } from '@nocobase/license-kit';
|
|
13
|
-
import _ from 'lodash';
|
|
14
13
|
import { checkExternalDbConnection, readExternalDbConnectionConfig, } from "../../lib/db-connection-check.js";
|
|
15
14
|
import { DEFAULT_DOCKER_REGISTRY, DEFAULT_DOCKER_VERSION, resolveDockerImageRef, } from "../../lib/docker-image.js";
|
|
16
15
|
import { formatMissingManagedAppEnvMessage, resolveManagedAppRuntime } from '../../lib/app-runtime.js';
|
|
17
16
|
import { buildRuntimeEnvVars } from '../../lib/runtime-env-vars.js';
|
|
18
17
|
import { resolveLicensePkgUrlFromConfig } from '../../lib/cli-config.js';
|
|
18
|
+
import { deepEqual, omitKeys } from "../../lib/object-utils.js";
|
|
19
19
|
import { commandOutput } from '../../lib/run-npm.js';
|
|
20
20
|
import { appUrl } from '../env/shared.js';
|
|
21
21
|
export function createLicenseEnvFlag(description) {
|
|
@@ -296,7 +296,7 @@ export function isDbMatch(env, keyData) {
|
|
|
296
296
|
if (currentDb?.id && licenseDb?.id) {
|
|
297
297
|
return currentDb.id === licenseDb.id;
|
|
298
298
|
}
|
|
299
|
-
return
|
|
299
|
+
return deepEqual(omitKeys(currentDb, ['id']), omitKeys(licenseDb, ['id']));
|
|
300
300
|
}
|
|
301
301
|
export function isSysMatch(env, keyData) {
|
|
302
302
|
const instance = keyData?.instanceData;
|
|
@@ -307,7 +307,7 @@ export function isSysMatch(env, keyData) {
|
|
|
307
307
|
sys: item?.sys ?? null,
|
|
308
308
|
osVer: item?.osVer ?? null,
|
|
309
309
|
});
|
|
310
|
-
return
|
|
310
|
+
return deepEqual(normalize(env), normalize(instance));
|
|
311
311
|
}
|
|
312
312
|
export async function getLicenseStatus(keyData) {
|
|
313
313
|
if (!keyData) {
|
|
@@ -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 { confirm } from "../../lib/inquirer.js";
|
|
11
|
+
import { setVerboseMode } from '../../lib/ui.js';
|
|
11
12
|
import { formatSelfUpdateUnavailableMessage, formatUnsupportedSelfUpdateMessage, inspectSelfStatus, updateSelf, } from '../../lib/self-manager.js';
|
|
12
13
|
export default class SelfUpdate extends Command {
|
|
13
14
|
static summary = 'Update the globally installed NocoBase CLI';
|
|
@@ -50,9 +51,17 @@ export default class SelfUpdate extends Command {
|
|
|
50
51
|
this.error(formatSelfUpdateUnavailableMessage(status));
|
|
51
52
|
}
|
|
52
53
|
if (!flags.yes && status.updateAvailable) {
|
|
53
|
-
|
|
54
|
+
let confirmed = false;
|
|
55
|
+
try {
|
|
56
|
+
confirmed = await confirm({
|
|
57
|
+
message: `Update ${status.packageName} from ${status.currentVersion} to ${status.latestVersion}?`,
|
|
58
|
+
default: false,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
54
64
|
if (!confirmed) {
|
|
55
|
-
this.log('Skipped CLI update.');
|
|
56
65
|
return;
|
|
57
66
|
}
|
|
58
67
|
}
|
|
@@ -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 { confirm } from "../../lib/inquirer.js";
|
|
11
|
+
import { setVerboseMode } from '../../lib/ui.js';
|
|
11
12
|
import { installNocoBaseSkills } from '../../lib/skills-manager.js';
|
|
12
13
|
export default class SkillsInstall extends Command {
|
|
13
14
|
static summary = 'Install the NocoBase AI coding skills globally';
|
|
@@ -36,9 +37,17 @@ export default class SkillsInstall extends Command {
|
|
|
36
37
|
const { flags } = await this.parse(SkillsInstall);
|
|
37
38
|
setVerboseMode(flags.verbose);
|
|
38
39
|
if (!flags.yes) {
|
|
39
|
-
|
|
40
|
+
let confirmed = false;
|
|
41
|
+
try {
|
|
42
|
+
confirmed = await confirm({
|
|
43
|
+
message: 'Install the NocoBase AI coding skills globally?',
|
|
44
|
+
default: true,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
40
50
|
if (!confirmed) {
|
|
41
|
-
this.log('Skipped skills install.');
|
|
42
51
|
return;
|
|
43
52
|
}
|
|
44
53
|
}
|
|
@@ -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 { confirm } from "../../lib/inquirer.js";
|
|
11
|
+
import { setVerboseMode } from '../../lib/ui.js';
|
|
11
12
|
import { removeNocoBaseSkills } from '../../lib/skills-manager.js';
|
|
12
13
|
export default class SkillsRemove extends Command {
|
|
13
14
|
static summary = 'Remove the globally installed NocoBase AI coding skills';
|
|
@@ -36,9 +37,17 @@ export default class SkillsRemove extends Command {
|
|
|
36
37
|
const { flags } = await this.parse(SkillsRemove);
|
|
37
38
|
setVerboseMode(flags.verbose);
|
|
38
39
|
if (!flags.yes) {
|
|
39
|
-
|
|
40
|
+
let confirmed = false;
|
|
41
|
+
try {
|
|
42
|
+
confirmed = await confirm({
|
|
43
|
+
message: 'Remove the globally installed NocoBase AI coding skills?',
|
|
44
|
+
default: true,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
40
50
|
if (!confirmed) {
|
|
41
|
-
this.log('Skipped skills removal.');
|
|
42
51
|
return;
|
|
43
52
|
}
|
|
44
53
|
}
|
|
@@ -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 { confirm } from "../../lib/inquirer.js";
|
|
11
|
+
import { setVerboseMode } from '../../lib/ui.js';
|
|
11
12
|
import { updateNocoBaseSkills } from '../../lib/skills-manager.js';
|
|
12
13
|
export default class SkillsUpdate extends Command {
|
|
13
14
|
static summary = 'Update the globally installed NocoBase AI coding skills';
|
|
@@ -36,9 +37,17 @@ export default class SkillsUpdate extends Command {
|
|
|
36
37
|
const { flags } = await this.parse(SkillsUpdate);
|
|
37
38
|
setVerboseMode(flags.verbose);
|
|
38
39
|
if (!flags.yes) {
|
|
39
|
-
|
|
40
|
+
let confirmed = false;
|
|
41
|
+
try {
|
|
42
|
+
confirmed = await confirm({
|
|
43
|
+
message: 'Update the globally installed NocoBase AI coding skills?',
|
|
44
|
+
default: true,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
40
50
|
if (!confirmed) {
|
|
41
|
-
this.log('Skipped skills update.');
|
|
42
51
|
return;
|
|
43
52
|
}
|
|
44
53
|
}
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import fsp from 'node:fs/promises';
|
|
10
10
|
import { Command, Flags } from '@oclif/core';
|
|
11
|
-
import * as p from '@clack/prompts';
|
|
12
11
|
import path from 'node:path';
|
|
13
12
|
import { stdin as stdinStream, stdout as stdoutStream } from 'node:process';
|
|
14
13
|
import { runPromptCatalog, } from "../../lib/prompt-catalog.js";
|
|
@@ -181,6 +180,11 @@ export default class SourceDownload extends Command {
|
|
|
181
180
|
description: 'Skip command intro when invoked by another CLI command',
|
|
182
181
|
default: false,
|
|
183
182
|
}),
|
|
183
|
+
'compact-log': Flags.boolean({
|
|
184
|
+
hidden: true,
|
|
185
|
+
description: 'Reduce default logs when invoked inside another setup flow',
|
|
186
|
+
default: false,
|
|
187
|
+
}),
|
|
184
188
|
source: Flags.string({
|
|
185
189
|
char: 's',
|
|
186
190
|
description: 'How to get NocoBase: Docker image, npm package, or Git repository.',
|
|
@@ -601,7 +605,6 @@ export default class SourceDownload extends Command {
|
|
|
601
605
|
command: this,
|
|
602
606
|
hooks: {
|
|
603
607
|
onCancel: () => {
|
|
604
|
-
p.cancel('Download cancelled.');
|
|
605
608
|
this.exit(0);
|
|
606
609
|
},
|
|
607
610
|
onMissingNonInteractive: (message) => {
|
|
@@ -640,6 +643,15 @@ export default class SourceDownload extends Command {
|
|
|
640
643
|
commandStdio() {
|
|
641
644
|
return this.isVerbose() ? 'inherit' : 'ignore';
|
|
642
645
|
}
|
|
646
|
+
useCompactLog() {
|
|
647
|
+
const flags = this._flags;
|
|
648
|
+
return Boolean(flags?.['compact-log']);
|
|
649
|
+
}
|
|
650
|
+
logProgress(message) {
|
|
651
|
+
if (this.isVerbose() || !this.useCompactLog()) {
|
|
652
|
+
this.log(message);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
643
655
|
formatCommandForLog(name, args, cwd) {
|
|
644
656
|
const quotedArgs = args.map((arg) => (/\s/.test(arg) ? JSON.stringify(arg) : arg));
|
|
645
657
|
const commandLine = [name, ...quotedArgs].join(' ');
|
|
@@ -683,7 +695,7 @@ export default class SourceDownload extends Command {
|
|
|
683
695
|
}
|
|
684
696
|
startPreparationTask(message) {
|
|
685
697
|
if (this.isVerbose()) {
|
|
686
|
-
|
|
698
|
+
this.log(message);
|
|
687
699
|
return;
|
|
688
700
|
}
|
|
689
701
|
this.preparationTaskActive = true;
|
|
@@ -721,12 +733,12 @@ export default class SourceDownload extends Command {
|
|
|
721
733
|
}
|
|
722
734
|
pullArgs.push(imageRef);
|
|
723
735
|
this.finishPreparationTask();
|
|
724
|
-
|
|
736
|
+
this.logProgress(`Pulling Docker image ${imageRef}`);
|
|
725
737
|
await this.runExternalCommand('docker', pullArgs, {
|
|
726
738
|
errorName: 'docker pull',
|
|
727
739
|
loadingMessage: 'Pulling the Docker image',
|
|
728
740
|
});
|
|
729
|
-
|
|
741
|
+
this.logProgress(`Docker image is ready: ${imageRef}`);
|
|
730
742
|
if (!flags['docker-save']) {
|
|
731
743
|
return;
|
|
732
744
|
}
|
|
@@ -739,12 +751,12 @@ export default class SourceDownload extends Command {
|
|
|
739
751
|
}
|
|
740
752
|
await fsp.mkdir(outAbs, { recursive: true });
|
|
741
753
|
const tarPath = this.dockerTarPath(flags, outAbs);
|
|
742
|
-
|
|
754
|
+
this.log(`Saving Docker image tarball to ${tarPath}`);
|
|
743
755
|
await this.runExternalCommand('docker', ['save', '-o', tarPath, imageRef], {
|
|
744
756
|
errorName: 'docker save',
|
|
745
757
|
loadingMessage: 'Saving the Docker image tarball',
|
|
746
758
|
});
|
|
747
|
-
|
|
759
|
+
this.log(`Docker image tarball saved: ${tarPath}`);
|
|
748
760
|
}
|
|
749
761
|
async downloadFromNpm(flags) {
|
|
750
762
|
const versionSpec = flags.version || 'latest';
|
|
@@ -760,7 +772,7 @@ export default class SourceDownload extends Command {
|
|
|
760
772
|
await fsp.mkdir(parentDir, { recursive: true });
|
|
761
773
|
const registryEnv = this.npmRegistryEnv(flags);
|
|
762
774
|
this.finishPreparationTask();
|
|
763
|
-
|
|
775
|
+
this.log(`Creating NocoBase app "${appName}" from npm`);
|
|
764
776
|
await this.runExternalCommand('npx', npxArgs, {
|
|
765
777
|
...this.runOptionsWithCwd(parentDir, registryEnv),
|
|
766
778
|
errorName: 'npx create-nocobase-app',
|
|
@@ -770,20 +782,20 @@ export default class SourceDownload extends Command {
|
|
|
770
782
|
if (!flags['dev-dependencies']) {
|
|
771
783
|
installArgs.push('--production');
|
|
772
784
|
}
|
|
773
|
-
|
|
785
|
+
this.log(`Installing dependencies in ${projectRoot}`);
|
|
774
786
|
await this.runExternalCommand('yarn', installArgs, {
|
|
775
787
|
...this.runOptionsWithCwd(projectRoot, registryEnv),
|
|
776
788
|
errorName: 'yarn install',
|
|
777
789
|
loadingMessage: 'Installing dependencies',
|
|
778
790
|
});
|
|
779
791
|
if (flags.build && flags['dev-dependencies']) {
|
|
780
|
-
|
|
792
|
+
this.log(`Building app in ${projectRoot}`);
|
|
781
793
|
await this.config.runCommand('source:build', [
|
|
782
794
|
...this.buildCommandArgv(projectRoot, flags),
|
|
783
795
|
...(this.isVerbose() ? ['--verbose'] : []),
|
|
784
796
|
]);
|
|
785
797
|
}
|
|
786
|
-
|
|
798
|
+
this.log(`NocoBase app is ready at ${projectRoot}`);
|
|
787
799
|
return projectRoot;
|
|
788
800
|
}
|
|
789
801
|
async downloadFromGit(flags) {
|
|
@@ -796,7 +808,7 @@ export default class SourceDownload extends Command {
|
|
|
796
808
|
gitArgs.push('--branch', branch);
|
|
797
809
|
gitArgs.push('--depth', '1', repoUrl, outputDir);
|
|
798
810
|
this.finishPreparationTask();
|
|
799
|
-
|
|
811
|
+
this.log(branch === versionSpec
|
|
800
812
|
? `Cloning NocoBase from ${repoUrl} (${branch})`
|
|
801
813
|
: `Cloning NocoBase from ${repoUrl} (${branch}, resolved from ${versionSpec})`);
|
|
802
814
|
await this.runExternalCommand('git', gitArgs, {
|
|
@@ -805,20 +817,20 @@ export default class SourceDownload extends Command {
|
|
|
805
817
|
});
|
|
806
818
|
const projectRoot = path.resolve(process.cwd(), outputDir);
|
|
807
819
|
const registryEnv = this.npmRegistryEnv(flags);
|
|
808
|
-
|
|
820
|
+
this.log(`Installing dependencies in ${projectRoot}`);
|
|
809
821
|
await this.runExternalCommand('yarn', ['install'], {
|
|
810
822
|
...this.runOptionsWithCwd(projectRoot, registryEnv),
|
|
811
823
|
errorName: 'yarn install',
|
|
812
824
|
loadingMessage: 'Installing dependencies',
|
|
813
825
|
});
|
|
814
826
|
if (flags.build) {
|
|
815
|
-
|
|
827
|
+
this.log(`Building app in ${projectRoot}`);
|
|
816
828
|
await this.config.runCommand('source:build', [
|
|
817
829
|
...this.buildCommandArgv(projectRoot, flags),
|
|
818
830
|
...(this.isVerbose() ? ['--verbose'] : []),
|
|
819
831
|
]);
|
|
820
832
|
}
|
|
821
|
-
|
|
833
|
+
this.log(`NocoBase app is ready at ${projectRoot}`);
|
|
822
834
|
return projectRoot;
|
|
823
835
|
}
|
|
824
836
|
async download() {
|
|
@@ -827,7 +839,7 @@ export default class SourceDownload extends Command {
|
|
|
827
839
|
applyCliLocale(this._flags.locale);
|
|
828
840
|
setVerboseMode(Boolean(flags.verbose));
|
|
829
841
|
if (!flags['no-intro']) {
|
|
830
|
-
|
|
842
|
+
this.log('Get NocoBase');
|
|
831
843
|
}
|
|
832
844
|
const resolved = await this.resolveDownloadFlags(flags);
|
|
833
845
|
const source = resolved.source;
|
|
@@ -857,7 +869,7 @@ export default class SourceDownload extends Command {
|
|
|
857
869
|
async run() {
|
|
858
870
|
try {
|
|
859
871
|
const result = await this.download();
|
|
860
|
-
|
|
872
|
+
this.logProgress(`Download completed via ${downloadSourceLabel(result.resolved.source)}.`);
|
|
861
873
|
return result;
|
|
862
874
|
}
|
|
863
875
|
catch (error) {
|
|
@@ -10,6 +10,7 @@ import { mkdir, readdir } from 'node:fs/promises';
|
|
|
10
10
|
import { dockerContainerExists, startDockerContainer } from './app-runtime.js';
|
|
11
11
|
import { deriveBuiltinDbConnection, resolveBuiltinDbConnection } from './builtin-db.js';
|
|
12
12
|
import { resolveConfiguredEnvPath } from './cli-home.js';
|
|
13
|
+
import { resolveDockerEnvFileArg } from "./docker-env-file.js";
|
|
13
14
|
import { DEFAULT_DOCKER_REGISTRY, DEFAULT_DOCKER_VERSION, resolveDockerImageRef, } from "./docker-image.js";
|
|
14
15
|
import { commandSucceeds, run } from './run-npm.js';
|
|
15
16
|
import Install from '../commands/install.js';
|
|
@@ -81,12 +82,13 @@ async function localProjectHasFiles(projectRoot) {
|
|
|
81
82
|
return false;
|
|
82
83
|
}
|
|
83
84
|
}
|
|
84
|
-
export function buildSavedDockerRunArgs(runtime) {
|
|
85
|
+
export async function buildSavedDockerRunArgs(runtime) {
|
|
85
86
|
const config = runtime.env.config ?? {};
|
|
86
87
|
const configuredStoragePath = trimValue(config.storagePath);
|
|
87
88
|
const storagePath = configuredStoragePath
|
|
88
89
|
? trimValue(resolveConfiguredEnvPath(configuredStoragePath))
|
|
89
90
|
: '';
|
|
91
|
+
const envFile = await resolveDockerEnvFileArg(runtime.envName, config);
|
|
90
92
|
const appPort = runtime.env.appPort === undefined || runtime.env.appPort === null
|
|
91
93
|
? ''
|
|
92
94
|
: trimValue(runtime.env.appPort);
|
|
@@ -150,16 +152,20 @@ export function buildSavedDockerRunArgs(runtime) {
|
|
|
150
152
|
if (appPort) {
|
|
151
153
|
args.push('-p', `${appPort}:80`);
|
|
152
154
|
}
|
|
155
|
+
if (envFile) {
|
|
156
|
+
args.push('--env-file', envFile);
|
|
157
|
+
}
|
|
153
158
|
args.push('-e', `APP_KEY=${appKey}`, '-e', `DB_DIALECT=${dbDialect}`, '-e', `DB_HOST=${dbHost}`, '-e', `DB_PORT=${dbPort}`, '-e', `DB_DATABASE=${dbDatabase}`, '-e', `DB_USER=${dbUser}`, '-e', `DB_PASSWORD=${dbPassword}`, '-e', `TZ=${timeZone}`, '-v', `${storagePath}:${DOCKER_APP_STORAGE_DESTINATION}`, imageRef);
|
|
154
159
|
return {
|
|
155
160
|
appPort: appPort || undefined,
|
|
156
161
|
storagePath,
|
|
162
|
+
envFile,
|
|
157
163
|
imageRef,
|
|
158
164
|
args,
|
|
159
165
|
};
|
|
160
166
|
}
|
|
161
167
|
export async function recreateSavedDockerApp(runtime, options) {
|
|
162
|
-
const plan = buildSavedDockerRunArgs(runtime);
|
|
168
|
+
const plan = await buildSavedDockerRunArgs(runtime);
|
|
163
169
|
try {
|
|
164
170
|
await ensureDockerNetwork(runtime.workspaceName);
|
|
165
171
|
await mkdir(plan.storagePath, { recursive: true });
|