@nocobase/cli 2.1.0-beta.33 → 2.1.0-beta.35
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.js +2 -1
- package/bin/session-env.js +12 -0
- 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 +53 -18
- package/dist/commands/app/stop.js +0 -1
- package/dist/commands/app/upgrade.js +16 -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 +8 -2
- package/dist/commands/source/download.js +29 -17
- package/dist/commands/source/publish.js +92 -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/lib/app-managed-resources.js +30 -3
- package/dist/lib/bootstrap.js +12 -3
- 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/run-npm.js +8 -9
- package/dist/lib/skills-manager.js +75 -11
- package/dist/lib/source-publish.js +287 -0
- package/dist/lib/source-registry.js +188 -0
- 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/package.json +7 -5
|
@@ -0,0 +1,92 @@
|
|
|
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 { buildSuggestedInitCommand, publishSourceSnapshot } from '../../lib/source-publish.js';
|
|
11
|
+
import { failTask, printInfo, startTask, succeedTask } from '../../lib/ui.js';
|
|
12
|
+
function formatPublishFailure(message) {
|
|
13
|
+
return [
|
|
14
|
+
'Couldn\'t publish a source snapshot.',
|
|
15
|
+
'Check that Docker is running, the target npm registry is reachable, and the current directory is a NocoBase source repo.',
|
|
16
|
+
`Details: ${message}`,
|
|
17
|
+
].join('\n');
|
|
18
|
+
}
|
|
19
|
+
export default class SourcePublish extends Command {
|
|
20
|
+
static description = 'Publish the current NocoBase source repo as a snapshot version to an npm registry for install testing.';
|
|
21
|
+
static examples = [
|
|
22
|
+
'<%= config.bin %> <%= command.id %> --snapshot',
|
|
23
|
+
'<%= config.bin %> <%= command.id %> --snapshot --cwd /path/to/nocobase/source',
|
|
24
|
+
'<%= config.bin %> <%= command.id %> --snapshot --npm-registry=http://127.0.0.1:4873',
|
|
25
|
+
'<%= config.bin %> <%= command.id %> --snapshot --json',
|
|
26
|
+
];
|
|
27
|
+
static flags = {
|
|
28
|
+
snapshot: Flags.boolean({
|
|
29
|
+
description: 'Publish the current source repo as a unique snapshot version',
|
|
30
|
+
required: true,
|
|
31
|
+
default: false,
|
|
32
|
+
}),
|
|
33
|
+
'npm-registry': Flags.string({
|
|
34
|
+
description: 'npm registry URL to publish to. Defaults to the running local source registry when available',
|
|
35
|
+
required: false,
|
|
36
|
+
}),
|
|
37
|
+
cwd: Flags.string({
|
|
38
|
+
description: 'Source repository path. Defaults to the nearest detected NocoBase source root from the current working directory',
|
|
39
|
+
required: false,
|
|
40
|
+
}),
|
|
41
|
+
json: Flags.boolean({
|
|
42
|
+
description: 'Print the publish result as JSON',
|
|
43
|
+
default: false,
|
|
44
|
+
}),
|
|
45
|
+
verbose: Flags.boolean({
|
|
46
|
+
description: 'Show detailed command output while versioning and publishing the snapshot',
|
|
47
|
+
default: false,
|
|
48
|
+
}),
|
|
49
|
+
};
|
|
50
|
+
async run() {
|
|
51
|
+
const { flags } = await this.parse(SourcePublish);
|
|
52
|
+
if (!flags.snapshot) {
|
|
53
|
+
this.error('`nb source publish` currently requires `--snapshot`.');
|
|
54
|
+
}
|
|
55
|
+
if (!flags.json) {
|
|
56
|
+
startTask('Publishing a source snapshot...');
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
const result = await publishSourceSnapshot({
|
|
60
|
+
cwd: flags.cwd,
|
|
61
|
+
npmRegistry: flags['npm-registry'],
|
|
62
|
+
verbose: flags.verbose,
|
|
63
|
+
});
|
|
64
|
+
if (flags.json) {
|
|
65
|
+
this.log(JSON.stringify({
|
|
66
|
+
version: result.version,
|
|
67
|
+
npmRegistry: result.npmRegistry,
|
|
68
|
+
gitSha: result.gitSha,
|
|
69
|
+
projectRoot: result.projectRoot,
|
|
70
|
+
suggestedInitCommand: buildSuggestedInitCommand(result),
|
|
71
|
+
}, null, 2));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
succeedTask(`Published source snapshot ${result.version} to ${result.npmRegistry}.`);
|
|
75
|
+
printInfo(`Source root: ${result.projectRoot}`);
|
|
76
|
+
printInfo(`Snapshot version: ${result.version}`);
|
|
77
|
+
printInfo(`npm registry: ${result.npmRegistry}`);
|
|
78
|
+
printInfo(`Next: ${buildSuggestedInitCommand(result)}`);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
82
|
+
if (flags.json) {
|
|
83
|
+
this.logToStderr(JSON.stringify({
|
|
84
|
+
error: formatPublishFailure(message),
|
|
85
|
+
}, null, 2));
|
|
86
|
+
this.exit(1);
|
|
87
|
+
}
|
|
88
|
+
failTask('Failed to publish the source snapshot.');
|
|
89
|
+
this.error(formatPublishFailure(message));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
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 { run } from '../../../lib/run-npm.js';
|
|
11
|
+
import { printInfo } from '../../../lib/ui.js';
|
|
12
|
+
import { getSourceRegistryInfo } from '../../../lib/source-registry.js';
|
|
13
|
+
function formatLogsFailure(message) {
|
|
14
|
+
if (/does not exist/i.test(message)) {
|
|
15
|
+
return [
|
|
16
|
+
'Can\'t show source registry logs yet.',
|
|
17
|
+
'The saved source registry container could not be found on this machine.',
|
|
18
|
+
'Start the registry first with `nb source registry start`.',
|
|
19
|
+
`Details: ${message}`,
|
|
20
|
+
].join('\n');
|
|
21
|
+
}
|
|
22
|
+
return [
|
|
23
|
+
'Couldn\'t show source registry logs.',
|
|
24
|
+
'Check that Docker is installed and the source registry container still exists, then try again.',
|
|
25
|
+
`Details: ${message}`,
|
|
26
|
+
].join('\n');
|
|
27
|
+
}
|
|
28
|
+
export default class SourceRegistryLogs extends Command {
|
|
29
|
+
static description = 'Show logs for the local Docker-based npm registry used for source tests.';
|
|
30
|
+
static examples = [
|
|
31
|
+
'<%= config.bin %> <%= command.id %>',
|
|
32
|
+
'<%= config.bin %> <%= command.id %> --tail 200',
|
|
33
|
+
'<%= config.bin %> <%= command.id %> --follow',
|
|
34
|
+
];
|
|
35
|
+
static flags = {
|
|
36
|
+
tail: Flags.integer({
|
|
37
|
+
description: 'Number of recent log lines to show before following',
|
|
38
|
+
default: 100,
|
|
39
|
+
min: 0,
|
|
40
|
+
}),
|
|
41
|
+
follow: Flags.boolean({
|
|
42
|
+
char: 'f',
|
|
43
|
+
description: 'Keep streaming new log lines',
|
|
44
|
+
default: false,
|
|
45
|
+
allowNo: true,
|
|
46
|
+
}),
|
|
47
|
+
};
|
|
48
|
+
async run() {
|
|
49
|
+
const { flags } = await this.parse(SourceRegistryLogs);
|
|
50
|
+
const info = getSourceRegistryInfo();
|
|
51
|
+
printInfo(flags.follow
|
|
52
|
+
? `Showing source registry logs from "${info.containerName}" (press Ctrl+C to stop).`
|
|
53
|
+
: `Showing recent source registry logs from "${info.containerName}".`);
|
|
54
|
+
const dockerArgs = ['logs', '--tail', String(flags.tail ?? 100)];
|
|
55
|
+
if (flags.follow) {
|
|
56
|
+
dockerArgs.push('--follow');
|
|
57
|
+
}
|
|
58
|
+
dockerArgs.push(info.containerName);
|
|
59
|
+
try {
|
|
60
|
+
await run('docker', dockerArgs, {
|
|
61
|
+
errorName: 'docker logs',
|
|
62
|
+
stdio: 'inherit',
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
67
|
+
this.error(formatLogsFailure(message));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
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 { failTask, startTask, succeedTask } from '../../../lib/ui.js';
|
|
11
|
+
import { getSourceRegistryInfo, startSourceRegistry } from '../../../lib/source-registry.js';
|
|
12
|
+
function formatStartFailure(message) {
|
|
13
|
+
if (/port is already allocated|address already in use/i.test(message)) {
|
|
14
|
+
return [
|
|
15
|
+
'Can\'t start the source registry.',
|
|
16
|
+
'Port 4873 is already in use on this machine.',
|
|
17
|
+
'Stop the conflicting process, or free the port before trying again.',
|
|
18
|
+
`Details: ${message}`,
|
|
19
|
+
].join('\n');
|
|
20
|
+
}
|
|
21
|
+
return [
|
|
22
|
+
'Couldn\'t start the source registry.',
|
|
23
|
+
'Check that Docker is installed and running, then try again.',
|
|
24
|
+
`Details: ${message}`,
|
|
25
|
+
].join('\n');
|
|
26
|
+
}
|
|
27
|
+
export default class SourceRegistryStart extends Command {
|
|
28
|
+
static description = 'Start the local Docker-based npm registry used for source snapshot publish and install tests.';
|
|
29
|
+
static examples = [
|
|
30
|
+
'<%= config.bin %> <%= command.id %>',
|
|
31
|
+
'<%= config.bin %> <%= command.id %> --verbose',
|
|
32
|
+
];
|
|
33
|
+
static flags = {
|
|
34
|
+
verbose: Flags.boolean({
|
|
35
|
+
description: 'Show raw Docker output while starting the registry container',
|
|
36
|
+
default: false,
|
|
37
|
+
}),
|
|
38
|
+
};
|
|
39
|
+
async run() {
|
|
40
|
+
const { flags } = await this.parse(SourceRegistryStart);
|
|
41
|
+
const info = getSourceRegistryInfo();
|
|
42
|
+
startTask(`Starting the source registry at ${info.url}...`);
|
|
43
|
+
try {
|
|
44
|
+
const state = await startSourceRegistry({
|
|
45
|
+
stdio: flags.verbose ? 'inherit' : 'ignore',
|
|
46
|
+
});
|
|
47
|
+
succeedTask(state === 'already-running'
|
|
48
|
+
? `The source registry is already running at ${info.url}.`
|
|
49
|
+
: `The source registry is running at ${info.url}.`);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
53
|
+
failTask('Failed to start the source registry.');
|
|
54
|
+
this.error(formatStartFailure(message));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
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 { renderTable } from '../../../lib/ui.js';
|
|
11
|
+
import { resolveSourceRegistryInfo } from '../../../lib/source-registry.js';
|
|
12
|
+
export default class SourceRegistryStatus extends Command {
|
|
13
|
+
static description = 'Show the status of the local Docker-based npm registry used for source tests.';
|
|
14
|
+
static examples = [
|
|
15
|
+
'<%= config.bin %> <%= command.id %>',
|
|
16
|
+
'<%= config.bin %> <%= command.id %> --json',
|
|
17
|
+
];
|
|
18
|
+
static flags = {
|
|
19
|
+
json: Flags.boolean({
|
|
20
|
+
description: 'Print the source registry status as JSON',
|
|
21
|
+
default: false,
|
|
22
|
+
}),
|
|
23
|
+
};
|
|
24
|
+
async run() {
|
|
25
|
+
const { flags } = await this.parse(SourceRegistryStatus);
|
|
26
|
+
const info = await resolveSourceRegistryInfo();
|
|
27
|
+
if (flags.json) {
|
|
28
|
+
this.log(JSON.stringify(info, null, 2));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
this.log(renderTable(['Container', 'Status', 'URL', 'Storage'], [[info.containerName, info.status, info.url, info.storageDir]]));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
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 { failTask, startTask, succeedTask } from '../../../lib/ui.js';
|
|
11
|
+
import { stopSourceRegistry } from '../../../lib/source-registry.js';
|
|
12
|
+
function formatStopFailure(message) {
|
|
13
|
+
return [
|
|
14
|
+
'Couldn\'t stop the source registry.',
|
|
15
|
+
'Check that Docker is installed and the saved registry container still exists, then try again.',
|
|
16
|
+
`Details: ${message}`,
|
|
17
|
+
].join('\n');
|
|
18
|
+
}
|
|
19
|
+
export default class SourceRegistryStop extends Command {
|
|
20
|
+
static description = 'Stop the local Docker-based npm registry used for source snapshot tests.';
|
|
21
|
+
static examples = [
|
|
22
|
+
'<%= config.bin %> <%= command.id %>',
|
|
23
|
+
'<%= config.bin %> <%= command.id %> --verbose',
|
|
24
|
+
];
|
|
25
|
+
static flags = {
|
|
26
|
+
verbose: Flags.boolean({
|
|
27
|
+
description: 'Show raw Docker output while stopping the registry container',
|
|
28
|
+
default: false,
|
|
29
|
+
}),
|
|
30
|
+
};
|
|
31
|
+
async run() {
|
|
32
|
+
const { flags } = await this.parse(SourceRegistryStop);
|
|
33
|
+
startTask('Stopping the source registry...');
|
|
34
|
+
try {
|
|
35
|
+
const state = await stopSourceRegistry({
|
|
36
|
+
stdio: flags.verbose ? 'inherit' : 'ignore',
|
|
37
|
+
});
|
|
38
|
+
succeedTask(state === 'already-stopped'
|
|
39
|
+
? 'The source registry is already stopped.'
|
|
40
|
+
: 'The source registry has stopped.');
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
44
|
+
failTask('Failed to stop the source registry.');
|
|
45
|
+
this.error(formatStopFailure(message));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
import { mkdir, readdir } from 'node:fs/promises';
|
|
10
|
-
import { dockerContainerExists, startDockerContainer } from './app-runtime.js';
|
|
10
|
+
import { dockerContainerExists, runLocalNocoBaseCommand, 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';
|
|
@@ -57,6 +58,14 @@ function formatLocalSourceRestoreFailure(envName, source, message) {
|
|
|
57
58
|
`Details: ${message}`,
|
|
58
59
|
].join('\n');
|
|
59
60
|
}
|
|
61
|
+
function formatLocalPostinstallFailure(envName, message) {
|
|
62
|
+
return [
|
|
63
|
+
`Couldn't prepare NocoBase for "${envName}".`,
|
|
64
|
+
'The CLI was not able to run `nocobase-v1 postinstall` before starting the local app.',
|
|
65
|
+
'Check the local dependencies, storage path, and saved env settings, then try again.',
|
|
66
|
+
`Details: ${message}`,
|
|
67
|
+
].join('\n');
|
|
68
|
+
}
|
|
60
69
|
function formatSavedDockerSettingsIncomplete(envName, missing) {
|
|
61
70
|
return [
|
|
62
71
|
`Can't start NocoBase for "${envName}" yet.`,
|
|
@@ -81,12 +90,13 @@ async function localProjectHasFiles(projectRoot) {
|
|
|
81
90
|
return false;
|
|
82
91
|
}
|
|
83
92
|
}
|
|
84
|
-
export function buildSavedDockerRunArgs(runtime) {
|
|
93
|
+
export async function buildSavedDockerRunArgs(runtime) {
|
|
85
94
|
const config = runtime.env.config ?? {};
|
|
86
95
|
const configuredStoragePath = trimValue(config.storagePath);
|
|
87
96
|
const storagePath = configuredStoragePath
|
|
88
97
|
? trimValue(resolveConfiguredEnvPath(configuredStoragePath))
|
|
89
98
|
: '';
|
|
99
|
+
const envFile = await resolveDockerEnvFileArg(runtime.envName, config);
|
|
90
100
|
const appPort = runtime.env.appPort === undefined || runtime.env.appPort === null
|
|
91
101
|
? ''
|
|
92
102
|
: trimValue(runtime.env.appPort);
|
|
@@ -150,16 +160,20 @@ export function buildSavedDockerRunArgs(runtime) {
|
|
|
150
160
|
if (appPort) {
|
|
151
161
|
args.push('-p', `${appPort}:80`);
|
|
152
162
|
}
|
|
163
|
+
if (envFile) {
|
|
164
|
+
args.push('--env-file', envFile);
|
|
165
|
+
}
|
|
153
166
|
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
167
|
return {
|
|
155
168
|
appPort: appPort || undefined,
|
|
156
169
|
storagePath,
|
|
170
|
+
envFile,
|
|
157
171
|
imageRef,
|
|
158
172
|
args,
|
|
159
173
|
};
|
|
160
174
|
}
|
|
161
175
|
export async function recreateSavedDockerApp(runtime, options) {
|
|
162
|
-
const plan = buildSavedDockerRunArgs(runtime);
|
|
176
|
+
const plan = await buildSavedDockerRunArgs(runtime);
|
|
163
177
|
try {
|
|
164
178
|
await ensureDockerNetwork(runtime.workspaceName);
|
|
165
179
|
await mkdir(plan.storagePath, { recursive: true });
|
|
@@ -268,3 +282,16 @@ export async function ensureSavedLocalSource(runtime, runCommand, options) {
|
|
|
268
282
|
throw new Error(formatLocalSourceRestoreFailure(runtime.envName, runtime.source, error instanceof Error ? error.message : String(error)));
|
|
269
283
|
}
|
|
270
284
|
}
|
|
285
|
+
export async function ensureLocalPostinstall(runtime, options) {
|
|
286
|
+
options?.onStartTask?.(`Running local postinstall for "${runtime.envName}"...`);
|
|
287
|
+
try {
|
|
288
|
+
await runLocalNocoBaseCommand(runtime, ['postinstall'], {
|
|
289
|
+
stdio: commandStdio(options?.verbose),
|
|
290
|
+
});
|
|
291
|
+
options?.onSucceedTask?.(`Local postinstall finished for "${runtime.envName}".`);
|
|
292
|
+
}
|
|
293
|
+
catch (error) {
|
|
294
|
+
options?.onFailTask?.(`Failed to run local postinstall for "${runtime.envName}".`);
|
|
295
|
+
throw new Error(formatLocalPostinstallFailure(runtime.envName, error instanceof Error ? error.message : String(error)));
|
|
296
|
+
}
|
|
297
|
+
}
|
package/dist/lib/bootstrap.js
CHANGED
|
@@ -6,12 +6,13 @@
|
|
|
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 { confirm } from "./inquirer.js";
|
|
9
10
|
import { getCurrentEnvName, getEnv, setEnvRuntime, updateEnvConnection } from './auth-store.js';
|
|
10
11
|
import { resolveAccessToken } from './env-auth.js';
|
|
11
12
|
import { fetchWithPreservedAuthRedirect } from './http-request.js';
|
|
12
13
|
import { generateRuntime } from './runtime-generator.js';
|
|
13
14
|
import { hasRuntimeSync, saveRuntime } from './runtime-store.js';
|
|
14
|
-
import {
|
|
15
|
+
import { printInfo, printVerbose, printWarningBlock, setVerboseMode, stopTask, updateTask } from './ui.js';
|
|
15
16
|
const APP_RETRY_INTERVAL = 2000;
|
|
16
17
|
const APP_RETRY_TIMEOUT = 120000;
|
|
17
18
|
function readFlag(argv, name) {
|
|
@@ -186,7 +187,15 @@ async function waitForSwaggerSchema(baseUrl, token, role) {
|
|
|
186
187
|
return await requestJson(swaggerUrl, { token, role });
|
|
187
188
|
}
|
|
188
189
|
async function confirmEnableApiDoc() {
|
|
189
|
-
|
|
190
|
+
try {
|
|
191
|
+
return await confirm({
|
|
192
|
+
message: 'Enable the API documentation plugin now?',
|
|
193
|
+
default: false,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
190
199
|
}
|
|
191
200
|
async function fetchSwaggerSchema(baseUrl, token, role, context = {}, options = {}) {
|
|
192
201
|
let response = options.retryAppAvailability === false
|
|
@@ -335,7 +344,7 @@ export async function ensureRuntimeFromArgv(argv, options) {
|
|
|
335
344
|
}
|
|
336
345
|
stopTask();
|
|
337
346
|
const message = error instanceof Error ? error.message : String(error);
|
|
338
|
-
printWarningBlock(`Unable to load runtime commands. Showing built-in help instead.\
|
|
347
|
+
printWarningBlock(`Unable to load runtime commands. Showing built-in help instead.\n\n${message}`);
|
|
339
348
|
}
|
|
340
349
|
}
|
|
341
350
|
export async function updateEnvRuntime(options) {
|
|
@@ -100,7 +100,7 @@ async function checkPostgresFamilyConnection(config) {
|
|
|
100
100
|
await Promise.resolve(client.end()).catch(() => undefined);
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
|
-
async function
|
|
103
|
+
async function checkMysqlFamilyConnection(config) {
|
|
104
104
|
const { default: mysql } = await import('mysql2/promise');
|
|
105
105
|
const connection = await mysql.createConnection({
|
|
106
106
|
host: config.host,
|
|
@@ -117,23 +117,6 @@ async function checkMysqlConnection(config) {
|
|
|
117
117
|
await Promise.resolve(connection.end()).catch(() => undefined);
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
|
-
async function checkMariaDbConnection(config) {
|
|
121
|
-
const { default: mariadb } = await import('mariadb');
|
|
122
|
-
const connection = await mariadb.createConnection({
|
|
123
|
-
host: config.host,
|
|
124
|
-
port: config.port,
|
|
125
|
-
user: config.user,
|
|
126
|
-
password: config.password,
|
|
127
|
-
database: config.database,
|
|
128
|
-
connectTimeout: DB_CONNECTION_TIMEOUT_MS,
|
|
129
|
-
});
|
|
130
|
-
try {
|
|
131
|
-
await connection.query('SELECT 1');
|
|
132
|
-
}
|
|
133
|
-
finally {
|
|
134
|
-
await Promise.resolve(connection.end()).catch(() => undefined);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
120
|
async function performExternalDbConnectionCheck(config) {
|
|
138
121
|
try {
|
|
139
122
|
switch (config.dialect) {
|
|
@@ -142,12 +125,9 @@ async function performExternalDbConnectionCheck(config) {
|
|
|
142
125
|
await checkPostgresFamilyConnection(config);
|
|
143
126
|
return undefined;
|
|
144
127
|
}
|
|
145
|
-
case 'mysql':
|
|
146
|
-
await checkMysqlConnection(config);
|
|
147
|
-
return undefined;
|
|
148
|
-
}
|
|
128
|
+
case 'mysql':
|
|
149
129
|
case 'mariadb': {
|
|
150
|
-
await
|
|
130
|
+
await checkMysqlFamilyConnection(config);
|
|
151
131
|
return undefined;
|
|
152
132
|
}
|
|
153
133
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
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 { access } from 'node:fs/promises';
|
|
10
|
+
import { resolveConfiguredEnvPath } from './cli-home.js';
|
|
11
|
+
function trimValue(value) {
|
|
12
|
+
const text = String(value ?? '').trim();
|
|
13
|
+
return text || undefined;
|
|
14
|
+
}
|
|
15
|
+
export function defaultDockerEnvFilePath(envName) {
|
|
16
|
+
return `${envName}/.env`;
|
|
17
|
+
}
|
|
18
|
+
export function resolveConfiguredDockerEnvFilePath(envName, config) {
|
|
19
|
+
return trimValue(config?.envFile) || defaultDockerEnvFilePath(envName);
|
|
20
|
+
}
|
|
21
|
+
export function hasExplicitDockerEnvFile(config) {
|
|
22
|
+
return Boolean(trimValue(config?.envFile));
|
|
23
|
+
}
|
|
24
|
+
export function resolveDockerEnvFilePath(envName, config) {
|
|
25
|
+
return resolveConfiguredEnvPath(resolveConfiguredDockerEnvFilePath(envName, config));
|
|
26
|
+
}
|
|
27
|
+
export async function dockerEnvFileExists(envName, config) {
|
|
28
|
+
const filePath = resolveDockerEnvFilePath(envName, config);
|
|
29
|
+
if (!filePath) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
await access(filePath);
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
catch (_error) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export async function resolveDockerEnvFileArg(envName, config) {
|
|
41
|
+
const filePath = resolveDockerEnvFilePath(envName, config);
|
|
42
|
+
if (!filePath) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
if (await dockerEnvFileExists(envName, config)) {
|
|
46
|
+
return filePath;
|
|
47
|
+
}
|
|
48
|
+
if (hasExplicitDockerEnvFile(config)) {
|
|
49
|
+
throw new Error(`The configured envFile for "${envName}" does not exist: ${resolveConfiguredDockerEnvFilePath(envName, config)}`);
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
package/dist/lib/env-auth.js
CHANGED
|
@@ -14,7 +14,7 @@ import { mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
|
14
14
|
import os from 'node:os';
|
|
15
15
|
import path from 'node:path';
|
|
16
16
|
import { getCurrentEnvName, getEnv, setEnvOauthSession, } from './auth-store.js';
|
|
17
|
-
import { printInfo, printVerbose, printWarning, printWarningBlock, updateTask } from './ui.js';
|
|
17
|
+
import { printInfo, printVerbose, printWarning, printWarningBlock, stopTask, updateTask } from './ui.js';
|
|
18
18
|
const ACCESS_TOKEN_REFRESH_WINDOW_MS = 60_000;
|
|
19
19
|
const LOOPBACK_HOST = '127.0.0.1';
|
|
20
20
|
const OAUTH_LOGIN_TIMEOUT_MS = 5 * 60 * 1000;
|
|
@@ -823,10 +823,11 @@ export async function authenticateEnvWithOauth(options) {
|
|
|
823
823
|
const browser = await maybeOpenBrowser(authorizationUrl.toString());
|
|
824
824
|
cleanupBrowserOpenTarget = browser.cleanup;
|
|
825
825
|
if (!browser.opened) {
|
|
826
|
-
printWarningBlock('We could not open your browser automatically. Open
|
|
826
|
+
printWarningBlock('We could not open your browser automatically. Open the URL below to continue signing in:');
|
|
827
827
|
}
|
|
828
828
|
else {
|
|
829
|
-
|
|
829
|
+
stopTask();
|
|
830
|
+
printInfo('Open this URL to sign in.');
|
|
830
831
|
}
|
|
831
832
|
printInfo(authorizationUrl.toString());
|
|
832
833
|
const code = await new Promise((resolve, reject) => {
|
package/dist/lib/env-config.js
CHANGED
package/dist/lib/env-guard.js
CHANGED
|
@@ -6,9 +6,9 @@
|
|
|
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 { stdin as input, stdout as output } from 'node:process';
|
|
11
10
|
import { getCurrentEnvName } from './auth-store.js';
|
|
11
|
+
import { confirm } from "./inquirer.js";
|
|
12
12
|
function normalizeEnvName(value) {
|
|
13
13
|
const text = String(value ?? '').trim();
|
|
14
14
|
return text || undefined;
|
|
@@ -50,12 +50,13 @@ export async function ensureCrossEnvConfirmed(options) {
|
|
|
50
50
|
if (!interactiveTerminal) {
|
|
51
51
|
options.command.error(formatCrossEnvRefusalMessage(currentEnv, requestedEnv));
|
|
52
52
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
try {
|
|
54
|
+
return Boolean(await confirm({
|
|
55
|
+
message: formatCrossEnvPromptMessage(currentEnv, requestedEnv),
|
|
56
|
+
default: false,
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
58
60
|
return false;
|
|
59
61
|
}
|
|
60
|
-
return Boolean(answer);
|
|
61
62
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
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
|
+
export function buildPlainMessageTheme(extra) {
|
|
10
|
+
return {
|
|
11
|
+
...extra,
|
|
12
|
+
style: {
|
|
13
|
+
...extra?.style,
|
|
14
|
+
message: (text) => text,
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
}
|