bdy 1.25.3-dev → 1.25.5-dev
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/distTs/package.json +2 -1
- package/distTs/src/agent/socket/tunnel.js +2 -0
- package/distTs/src/api/client.js +22 -55
- package/distTs/src/cliCommand.js +52 -0
- package/distTs/src/cliError.js +34 -0
- package/distTs/src/cliIndex.js +3 -1
- package/distTs/src/command/agent/proxy/status.js +9 -2
- package/distTs/src/command/agent/status.js +22 -6
- package/distTs/src/command/agent/tags/get.js +9 -2
- package/distTs/src/command/agent/target/status.js +9 -2
- package/distTs/src/command/agent/tunnel/list.js +6 -1
- package/distTs/src/command/agent/tunnel/status.js +13 -1
- package/distTs/src/command/agent/version.js +7 -2
- package/distTs/src/command/api/info.js +50 -2
- package/distTs/src/command/api/list.js +18 -2
- package/distTs/src/command/artifact/create.js +5 -0
- package/distTs/src/command/artifact/publish.js +20 -22
- package/distTs/src/command/artifact/version/create.js +5 -0
- package/distTs/src/command/config/get/tunnel.js +8 -3
- package/distTs/src/command/config/get/tunnels.js +8 -3
- package/distTs/src/command/discover.js +9 -11
- package/distTs/src/command/distro/create.js +5 -0
- package/distTs/src/command/distro/route/create.js +5 -0
- package/distTs/src/command/distro/route/update.js +5 -0
- package/distTs/src/command/distro/update.js +5 -0
- package/distTs/src/command/domain/search.js +31 -10
- package/distTs/src/command/environment/create.js +5 -0
- package/distTs/src/command/environment/update.js +5 -0
- package/distTs/src/command/sandbox/app/add.js +7 -1
- package/distTs/src/command/sandbox/app/logs.js +9 -4
- package/distTs/src/command/sandbox/create.js +13 -5
- package/distTs/src/command/sandbox/endpoint/add.js +5 -0
- package/distTs/src/command/sandbox/exec/command.js +15 -30
- package/distTs/src/command/sandbox/exec/logs.js +4 -29
- package/distTs/src/command/sandbox/finishExec.js +34 -0
- package/distTs/src/command/sandbox/logs.js +14 -1
- package/distTs/src/command/sandbox/snapshot/create.js +9 -1
- package/distTs/src/command/target/create.js +5 -0
- package/distTs/src/command/target/exec/logs.js +15 -2
- package/distTs/src/command/target/update.js +5 -0
- package/distTs/src/command/yaml/validate.js +111 -52
- package/distTs/src/index.js +6 -1
- package/distTs/src/input.js +12 -11
- package/distTs/src/openapi.js +8 -1
- package/distTs/src/output.js +55 -13
- package/distTs/src/texts.js +272 -59
- package/package.json +2 -1
|
@@ -7,43 +7,18 @@ const utils_1 = require("../../../utils");
|
|
|
7
7
|
const texts_1 = require("../../../texts");
|
|
8
8
|
const output_1 = __importDefault(require("../../../output"));
|
|
9
9
|
const input_1 = __importDefault(require("../../../input"));
|
|
10
|
-
const
|
|
10
|
+
const finishExec_1 = require("../finishExec");
|
|
11
|
+
const commandSandboxExecLogs = (0, utils_1.newCommand)('logs', texts_1.DESC_COMMAND_SANDBOX_EXEC_LOGS, { helpText: texts_1.HELP_SANDBOX_EXEC_JSONL, examples: texts_1.EXAMPLE_SANDBOX_EXEC_LOGS });
|
|
11
12
|
(0, utils_1.sandboxScopeOptions)(commandSandboxExecLogs);
|
|
12
13
|
commandSandboxExecLogs.option('--wait', texts_1.OPTION_SANDBOX_WAIT);
|
|
13
14
|
commandSandboxExecLogs.argument('<identifier>', texts_1.OPTION_SANDBOX_IDENTIFIER);
|
|
14
15
|
commandSandboxExecLogs.argument('<command-id>', texts_1.OPTION_SANDBOX_COMMAND_ID);
|
|
16
|
+
commandSandboxExecLogs.option('--format <text|jsonl>', texts_1.OPTION_FORMAT_JSONL);
|
|
15
17
|
commandSandboxExecLogs.action(async (identifier, commandId, options) => {
|
|
16
18
|
output_1.default.handleSignals();
|
|
17
19
|
const workspace = input_1.default.restApiWorkspace(options.workspace);
|
|
18
20
|
const client = input_1.default.restApiTokenClient();
|
|
19
21
|
const sandboxId = await input_1.default.sandboxId(client, workspace, options, identifier);
|
|
20
|
-
|
|
21
|
-
body.on('data', (data) => {
|
|
22
|
-
if (data) {
|
|
23
|
-
try {
|
|
24
|
-
const str = data.toString('utf8').split('\n');
|
|
25
|
-
str.forEach((s) => {
|
|
26
|
-
const json = JSON.parse(s);
|
|
27
|
-
if (json.data)
|
|
28
|
-
output_1.default.data(json.data);
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
catch {
|
|
32
|
-
// do nothing
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
body.on('close', async () => {
|
|
37
|
-
const cmdExit = await client.getSandboxCommand(workspace, sandboxId, commandId);
|
|
38
|
-
if (cmdExit.status === utils_1.SANDBOX_EXEC_STATUS.SUCCESSFUL) {
|
|
39
|
-
output_1.default.exitSuccess((0, texts_1.TXT_SANDBOX_EXEC_SUCCESS)(identifier, commandId));
|
|
40
|
-
}
|
|
41
|
-
else if (cmdExit.status === utils_1.SANDBOX_EXEC_STATUS.INPROGRESS) {
|
|
42
|
-
output_1.default.exitNormal((0, texts_1.TXT_SANDBOX_EXEC_INPROGRESS)(identifier, commandId));
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
output_1.default.exitError((0, texts_1.TXT_SANDBOX_EXEC_FAILED)(identifier, commandId));
|
|
46
|
-
}
|
|
47
|
-
});
|
|
22
|
+
await (0, finishExec_1.finishExec)(client, workspace, sandboxId, identifier, commandId, !!options.wait, options.format === 'jsonl');
|
|
48
23
|
});
|
|
49
24
|
exports.default = commandSandboxExecLogs;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.finishExec = finishExec;
|
|
7
|
+
const output_1 = __importDefault(require("../../output"));
|
|
8
|
+
const utils_1 = require("../../utils");
|
|
9
|
+
const texts_1 = require("../../texts");
|
|
10
|
+
async function finishExec(client, workspace, sandboxId, identifier, commandId, follow, jsonl) {
|
|
11
|
+
const body = await client.streamSandboxCommandLogs(workspace, sandboxId, commandId, follow);
|
|
12
|
+
await output_1.default.streamCommandLogs(body, jsonl);
|
|
13
|
+
const cmdExit = await client.getSandboxCommand(workspace, sandboxId, commandId);
|
|
14
|
+
if (jsonl) {
|
|
15
|
+
output_1.default.json({
|
|
16
|
+
type: 'exit',
|
|
17
|
+
status: cmdExit.status,
|
|
18
|
+
exit_code: cmdExit.exit_code ?? null,
|
|
19
|
+
});
|
|
20
|
+
if ([utils_1.SANDBOX_EXEC_STATUS.SUCCESSFUL, utils_1.SANDBOX_EXEC_STATUS.INPROGRESS].includes(cmdExit.status)) {
|
|
21
|
+
output_1.default.exitNormal();
|
|
22
|
+
}
|
|
23
|
+
output_1.default.exitCode(1);
|
|
24
|
+
}
|
|
25
|
+
if (cmdExit.status === utils_1.SANDBOX_EXEC_STATUS.SUCCESSFUL) {
|
|
26
|
+
output_1.default.exitSuccess((0, texts_1.TXT_SANDBOX_EXEC_SUCCESS)(identifier, commandId));
|
|
27
|
+
}
|
|
28
|
+
else if (cmdExit.status === utils_1.SANDBOX_EXEC_STATUS.INPROGRESS) {
|
|
29
|
+
output_1.default.exitNormal((0, texts_1.TXT_SANDBOX_EXEC_INPROGRESS)(identifier, commandId));
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
output_1.default.exitError((0, texts_1.TXT_SANDBOX_EXEC_FAILED)(identifier, commandId));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -7,15 +7,28 @@ const utils_1 = require("../../utils");
|
|
|
7
7
|
const texts_1 = require("../../texts");
|
|
8
8
|
const input_1 = __importDefault(require("../../input"));
|
|
9
9
|
const output_1 = __importDefault(require("../../output"));
|
|
10
|
-
const commandSandboxLogs = (0, utils_1.newCommand)('logs', texts_1.DESC_COMMAND_SANDBOX_LOGS);
|
|
10
|
+
const commandSandboxLogs = (0, utils_1.newCommand)('logs', texts_1.DESC_COMMAND_SANDBOX_LOGS, { examples: texts_1.EXAMPLE_SANDBOX_LOGS });
|
|
11
11
|
commandSandboxLogs.hideVersionUpdate = true;
|
|
12
12
|
(0, utils_1.sandboxScopeOptions)(commandSandboxLogs);
|
|
13
13
|
commandSandboxLogs.argument('<identifier>', texts_1.OPTION_SANDBOX_IDENTIFIER);
|
|
14
|
+
commandSandboxLogs.option('--format <text|jsonl>', texts_1.OPTION_FORMAT_JSONL);
|
|
14
15
|
commandSandboxLogs.action(async (identifier, options) => {
|
|
15
16
|
const workspace = input_1.default.restApiWorkspace(options.workspace);
|
|
16
17
|
const client = input_1.default.restApiTokenClient();
|
|
17
18
|
const sandboxId = await input_1.default.sandboxId(client, workspace, options, identifier);
|
|
18
19
|
const { boot_logs } = await client.getSandbox(workspace, sandboxId);
|
|
20
|
+
if (options.format === 'jsonl') {
|
|
21
|
+
for (const log of boot_logs || []) {
|
|
22
|
+
output_1.default.json(typeof log === 'string'
|
|
23
|
+
? { type: 'log', data: log }
|
|
24
|
+
: {
|
|
25
|
+
type: 'log',
|
|
26
|
+
data: log.data ?? JSON.stringify(log),
|
|
27
|
+
...(log.source ? { source: log.source } : {}),
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
output_1.default.exitNormal();
|
|
31
|
+
}
|
|
19
32
|
output_1.default.exitNormal((boot_logs || []).join('\n'));
|
|
20
33
|
});
|
|
21
34
|
exports.default = commandSandboxLogs;
|
|
@@ -13,6 +13,7 @@ commandSandboxSnapshotCreate.alias('add');
|
|
|
13
13
|
commandSandboxSnapshotCreate.option('-n, --name <name>', texts_1.OPTION_SANDBOX_SNAPSHOT_NAME);
|
|
14
14
|
commandSandboxSnapshotCreate.argument('<identifier>', texts_1.OPTION_SANDBOX_IDENTIFIER);
|
|
15
15
|
commandSandboxSnapshotCreate.option('--wait [seconds]', texts_1.OPTION_SANDBOX_WAIT);
|
|
16
|
+
commandSandboxSnapshotCreate.option('--format <text|json>', texts_1.OPTION_FORMAT);
|
|
16
17
|
commandSandboxSnapshotCreate.action(async (identifier, options) => {
|
|
17
18
|
const humanId = require('human-id').default;
|
|
18
19
|
const workspace = input_1.default.restApiWorkspace(options.workspace);
|
|
@@ -26,7 +27,8 @@ commandSandboxSnapshotCreate.action(async (identifier, options) => {
|
|
|
26
27
|
const snapshot = await client.createSandboxSnapshot(workspace, sandboxId, body);
|
|
27
28
|
const snapshotId = snapshot.id;
|
|
28
29
|
if (options.wait) {
|
|
29
|
-
|
|
30
|
+
if (options.format !== 'json')
|
|
31
|
+
output_1.default.normal(texts_1.TXT_SANDBOX_SNAPSHOT_WAITING);
|
|
30
32
|
const timeout = parseInt(options.wait, 10) || 300;
|
|
31
33
|
try {
|
|
32
34
|
const status = await client.sandboxWaitForSnapshot(workspace, sandboxId, snapshotId, timeout);
|
|
@@ -38,6 +40,12 @@ commandSandboxSnapshotCreate.action(async (identifier, options) => {
|
|
|
38
40
|
output_1.default.exitError(texts_1.ERR_SANDBOX_SNAPSHOT_TIMEOUT);
|
|
39
41
|
}
|
|
40
42
|
}
|
|
43
|
+
if (options.format === 'json') {
|
|
44
|
+
output_1.default.json(options.wait
|
|
45
|
+
? await client.getSandboxSnapshot(workspace, sandboxId, snapshotId)
|
|
46
|
+
: snapshot);
|
|
47
|
+
output_1.default.exitNormal();
|
|
48
|
+
}
|
|
41
49
|
output_1.default.exitSuccess((0, texts_1.TXT_SANDBOX_SNAPSHOT_CREATED)(snapshotName));
|
|
42
50
|
});
|
|
43
51
|
exports.default = commandSandboxSnapshotCreate;
|
|
@@ -18,6 +18,7 @@ commandTargetCreate.option('--pipeline <identifier>', texts_1.OPTION_TARGET_PIPE
|
|
|
18
18
|
commandTargetCreate.option('--environment <identifier>', texts_1.OPTION_TARGET_ENVIRONMENT);
|
|
19
19
|
commandTargetCreate.option('--scope <scope>', texts_1.OPT_COMMAND_TARGET_SCOPE);
|
|
20
20
|
commandTargetCreate.option('--yaml <content|@path>', texts_1.OPTION_TARGET_YAML);
|
|
21
|
+
commandTargetCreate.option('--format <text|json>', texts_1.OPTION_FORMAT);
|
|
21
22
|
commandTargetCreate.action(async (options) => {
|
|
22
23
|
const yaml = input_1.default.restApiYaml(options.yaml);
|
|
23
24
|
const workspace = input_1.default.restApiWorkspace(options.workspace);
|
|
@@ -29,6 +30,10 @@ commandTargetCreate.action(async (options) => {
|
|
|
29
30
|
yaml: Buffer.from(yaml, 'utf8').toString('base64'),
|
|
30
31
|
};
|
|
31
32
|
const result = await client.createTargetByYaml(workspace, scopeParams, body);
|
|
33
|
+
if (options.format === 'json') {
|
|
34
|
+
output_1.default.json(result);
|
|
35
|
+
output_1.default.exitNormal();
|
|
36
|
+
}
|
|
32
37
|
output_1.default.exitSuccess((0, texts_1.TXT_TARGET_CREATED)(result.identifier, result.html_url));
|
|
33
38
|
});
|
|
34
39
|
exports.default = commandTargetCreate;
|
|
@@ -8,19 +8,32 @@ const texts_1 = require("../../../texts");
|
|
|
8
8
|
const input_1 = __importDefault(require("../../../input"));
|
|
9
9
|
const output_1 = __importDefault(require("../../../output"));
|
|
10
10
|
const scope_1 = require("../scope");
|
|
11
|
-
const commandTargetExecLogs = (0, utils_1.newCommand)('logs', texts_1.DESC_COMMAND_TARGET_EXEC_LOGS, { examples: texts_1.EXAMPLE_TARGET_EXEC_LOGS });
|
|
11
|
+
const commandTargetExecLogs = (0, utils_1.newCommand)('logs', texts_1.DESC_COMMAND_TARGET_EXEC_LOGS, { helpText: texts_1.HELP_TARGET_EXEC_LOGS_JSONL, examples: texts_1.EXAMPLE_TARGET_EXEC_LOGS });
|
|
12
12
|
commandTargetExecLogs.option('-w, --workspace <domain>', texts_1.OPTION_REST_API_WORKSPACE);
|
|
13
13
|
commandTargetExecLogs.option('--offset <n>', texts_1.OPTION_TARGET_EXEC_LOG_OFFSET);
|
|
14
14
|
commandTargetExecLogs.option('--limit <n>', texts_1.OPTION_TARGET_EXEC_LOG_LIMIT);
|
|
15
15
|
commandTargetExecLogs.argument('<exec-id>', texts_1.OPTION_TARGET_EXEC_ID);
|
|
16
|
+
commandTargetExecLogs.option('--format <text|jsonl>', texts_1.OPTION_FORMAT_JSONL);
|
|
16
17
|
commandTargetExecLogs.action(async (execId, options) => {
|
|
17
18
|
const workspace = input_1.default.restApiWorkspace(options.workspace);
|
|
18
19
|
const client = input_1.default.restApiTokenClient();
|
|
19
20
|
const offset = options.offset ? parseInt(options.offset, 10) : 0;
|
|
20
21
|
const limit = options.limit ? parseInt(options.limit, 10) : undefined;
|
|
21
|
-
const { truncated } = await (0, scope_1.forwardExecLog)(client, workspace, execId, offset,
|
|
22
|
+
const { truncated } = await (0, scope_1.forwardExecLog)(client, workspace, execId, offset, options.format === 'jsonl'
|
|
23
|
+
? (lines) => lines.forEach((data) => output_1.default.json({ type: 'log', data }))
|
|
24
|
+
: undefined, limit);
|
|
22
25
|
if (truncated)
|
|
23
26
|
output_1.default.noteWarning(texts_1.WARN_TARGET_EXEC_TRUNCATED);
|
|
27
|
+
if (options.format === 'jsonl') {
|
|
28
|
+
const exec = await client.getTargetExec(workspace, execId);
|
|
29
|
+
output_1.default.json({
|
|
30
|
+
type: 'exit',
|
|
31
|
+
status: exec.status,
|
|
32
|
+
exit_code: exec.exit_code ?? null,
|
|
33
|
+
truncated,
|
|
34
|
+
});
|
|
35
|
+
output_1.default.exitNormal();
|
|
36
|
+
}
|
|
24
37
|
output_1.default.exitNormal();
|
|
25
38
|
});
|
|
26
39
|
exports.default = commandTargetExecLogs;
|
|
@@ -18,6 +18,7 @@ commandTargetUpdate.option('--pipeline <identifier>', texts_1.OPTION_TARGET_PIPE
|
|
|
18
18
|
commandTargetUpdate.option('--environment <identifier>', texts_1.OPTION_TARGET_ENVIRONMENT);
|
|
19
19
|
commandTargetUpdate.option('--yaml <content|@path>', texts_1.OPTION_TARGET_YAML);
|
|
20
20
|
commandTargetUpdate.argument('<identifier>', texts_1.OPTION_TARGET_IDENTIFIER);
|
|
21
|
+
commandTargetUpdate.option('--format <text|json>', texts_1.OPTION_FORMAT);
|
|
21
22
|
commandTargetUpdate.action(async (identifier, options) => {
|
|
22
23
|
const yaml = input_1.default.restApiYaml(options.yaml);
|
|
23
24
|
const workspace = input_1.default.restApiWorkspace(options.workspace);
|
|
@@ -28,6 +29,10 @@ commandTargetUpdate.action(async (identifier, options) => {
|
|
|
28
29
|
yaml: Buffer.from(yaml, 'utf8').toString('base64'),
|
|
29
30
|
};
|
|
30
31
|
const result = await client.updateTargetByYaml(workspace, target_id, body);
|
|
32
|
+
if (options.format === 'json') {
|
|
33
|
+
output_1.default.json(result);
|
|
34
|
+
output_1.default.exitNormal();
|
|
35
|
+
}
|
|
31
36
|
output_1.default.exitSuccess((0, texts_1.TXT_TARGET_UPDATED)(result.identifier, result.html_url));
|
|
32
37
|
});
|
|
33
38
|
exports.default = commandTargetUpdate;
|
|
@@ -22,9 +22,17 @@ function prettifyKey(key) {
|
|
|
22
22
|
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
23
23
|
.join(' ');
|
|
24
24
|
}
|
|
25
|
-
function
|
|
25
|
+
function recordError(context, path, message) {
|
|
26
|
+
context.errors.push({
|
|
27
|
+
pipeline: context.pipeline,
|
|
28
|
+
path: path.replace(/\.(\d+)(?=\.|$)/g, '[$1]'),
|
|
29
|
+
message,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
function outputErrors(result, indent, context, prefix = '') {
|
|
26
33
|
for (const err of result.errors) {
|
|
27
|
-
|
|
34
|
+
recordError(context, [prefix, err.path].filter(Boolean).join('.'), err.message);
|
|
35
|
+
context.output.muted(`${indent}${err.path}: ${err.message}`);
|
|
28
36
|
}
|
|
29
37
|
}
|
|
30
38
|
function valueType(value) {
|
|
@@ -34,9 +42,10 @@ function valueType(value) {
|
|
|
34
42
|
return 'array';
|
|
35
43
|
return typeof value;
|
|
36
44
|
}
|
|
37
|
-
function reportWrongContainer(header, expected, value) {
|
|
38
|
-
|
|
39
|
-
|
|
45
|
+
function reportWrongContainer(header, expected, value, context, path) {
|
|
46
|
+
recordError(context, path, (0, texts_1.ERR_YAML_MUST_BE)(expected, valueType(value)));
|
|
47
|
+
context.output.error(header);
|
|
48
|
+
context.output.muted(` ${(0, texts_1.ERR_YAML_MUST_BE)(expected, valueType(value))}`);
|
|
40
49
|
return 1;
|
|
41
50
|
}
|
|
42
51
|
// Array whose items reference a def — directly, or via a single $ref branch in
|
|
@@ -117,85 +126,101 @@ function itemLabel(value, index, discProp) {
|
|
|
117
126
|
name = `#${index + 1}`;
|
|
118
127
|
return discProp && value && value[discProp] ? `${name} (${value[discProp]})` : name;
|
|
119
128
|
}
|
|
120
|
-
function validateScalarItem(item, section) {
|
|
129
|
+
function validateScalarItem(item, section, context, path) {
|
|
121
130
|
// Null errors even where the section takes a string: coerceTypes cannot fix a root scalar.
|
|
122
131
|
if (item === null || !section.scalar) {
|
|
123
|
-
|
|
132
|
+
recordError(context, path, (0, texts_1.ERR_YAML_MUST_BE)('object', valueType(item)));
|
|
133
|
+
context.output.error(` ${String(item)}: ${(0, texts_1.ERR_YAML_MUST_BE)('object', valueType(item))}`);
|
|
124
134
|
return 1;
|
|
125
135
|
}
|
|
126
136
|
const result = (0, schemaUtils_1.validateAgainstSchema)({ ...section.scalar, $defs: (0, schemaUtils_1.loadRawSchema)().$defs }, item);
|
|
127
137
|
if (result.valid) {
|
|
128
|
-
|
|
138
|
+
context.output.green(` ${String(item)}`);
|
|
129
139
|
return 0;
|
|
130
140
|
}
|
|
131
|
-
|
|
132
|
-
outputErrors(result, ' ');
|
|
141
|
+
context.output.error(` ${String(item)}`);
|
|
142
|
+
outputErrors(result, ' ', context, path);
|
|
133
143
|
return result.errors.length;
|
|
134
144
|
}
|
|
135
|
-
function validateItemSection(unions, items, section) {
|
|
145
|
+
function validateItemSection(unions, items, section, context) {
|
|
136
146
|
const refName = section.defName;
|
|
137
147
|
const discProp = unions.get(refName)?.property ?? null;
|
|
138
148
|
let errors = 0;
|
|
139
149
|
for (let i = 0; i < items.length; i++) {
|
|
140
150
|
const item = items[i];
|
|
151
|
+
const path = `${section.key}[${i}]`;
|
|
141
152
|
if (item === null || typeof item !== 'object' || Array.isArray(item)) {
|
|
142
|
-
errors += validateScalarItem(item, section);
|
|
153
|
+
errors += validateScalarItem(item, section, context, path);
|
|
143
154
|
continue;
|
|
144
155
|
}
|
|
145
156
|
const label = itemLabel(item, i, discProp);
|
|
146
157
|
const resolved = resolveDef(unions, refName, item);
|
|
147
158
|
if ('missingType' in resolved) {
|
|
148
|
-
|
|
159
|
+
recordError(context, `${path}.${resolved.missingType}`, (0, texts_1.ERR_YAML_ITEM_MISSING)(resolved.missingType));
|
|
160
|
+
context.output.error(` ${label}: ${(0, texts_1.ERR_YAML_ITEM_MISSING)(resolved.missingType)}`);
|
|
149
161
|
errors++;
|
|
150
162
|
continue;
|
|
151
163
|
}
|
|
152
164
|
if ('unknownType' in resolved) {
|
|
153
|
-
|
|
165
|
+
recordError(context, `${path}.${resolved.prop}`, (0, texts_1.ERR_YAML_ITEM_UNKNOWN)(resolved.prop, resolved.unknownType));
|
|
166
|
+
context.output.error(` ${label}: ${(0, texts_1.ERR_YAML_ITEM_UNKNOWN)(resolved.prop, resolved.unknownType)}`);
|
|
154
167
|
errors++;
|
|
155
168
|
continue;
|
|
156
169
|
}
|
|
157
170
|
const result = (0, schemaUtils_1.validateAgainstDef)(resolved.defName, item);
|
|
158
171
|
if (result.valid) {
|
|
159
|
-
|
|
172
|
+
context.output.green(` ${label}`);
|
|
160
173
|
}
|
|
161
174
|
else {
|
|
162
175
|
errors += result.errors.length;
|
|
163
|
-
|
|
164
|
-
outputErrors(result, ' ');
|
|
176
|
+
context.output.error(` ${label}`);
|
|
177
|
+
outputErrors(result, ' ', context, path);
|
|
165
178
|
}
|
|
166
179
|
}
|
|
167
180
|
return errors;
|
|
168
181
|
}
|
|
169
|
-
function validateObjectSection(unions, label, value, refName) {
|
|
182
|
+
function validateObjectSection(unions, label, value, refName, context, path) {
|
|
170
183
|
const resolved = resolveDef(unions, refName, value);
|
|
171
184
|
if ('missingType' in resolved) {
|
|
172
|
-
|
|
173
|
-
|
|
185
|
+
context.output.error(label);
|
|
186
|
+
recordError(context, `${path}.${resolved.missingType}`, (0, texts_1.ERR_YAML_ITEM_MISSING)(resolved.missingType));
|
|
187
|
+
context.output.muted(` ${(0, texts_1.ERR_YAML_ITEM_MISSING)(resolved.missingType)}`);
|
|
174
188
|
return 1;
|
|
175
189
|
}
|
|
176
190
|
if ('unknownType' in resolved) {
|
|
177
|
-
|
|
178
|
-
|
|
191
|
+
context.output.error(label);
|
|
192
|
+
recordError(context, `${path}.${resolved.prop}`, (0, texts_1.ERR_YAML_ITEM_UNKNOWN)(resolved.prop, resolved.unknownType));
|
|
193
|
+
context.output.muted(` ${(0, texts_1.ERR_YAML_ITEM_UNKNOWN)(resolved.prop, resolved.unknownType)}`);
|
|
179
194
|
return 1;
|
|
180
195
|
}
|
|
181
196
|
const result = (0, schemaUtils_1.validateAgainstDef)(resolved.defName, value);
|
|
182
197
|
if (result.valid) {
|
|
183
|
-
|
|
198
|
+
context.output.green(label);
|
|
184
199
|
return 0;
|
|
185
200
|
}
|
|
186
|
-
|
|
187
|
-
outputErrors(result, ' ');
|
|
201
|
+
context.output.error(label);
|
|
202
|
+
outputErrors(result, ' ', context, path);
|
|
188
203
|
return result.errors.length;
|
|
189
204
|
}
|
|
190
|
-
function validateSinglePipeline(parsed, label, unions) {
|
|
205
|
+
function validateSinglePipeline(parsed, label, unions, context) {
|
|
191
206
|
let errors = 0;
|
|
192
207
|
const defs = (0, schemaUtils_1.getAllDefs)();
|
|
193
208
|
const pipelineDef = defs['PipelineYaml'];
|
|
194
209
|
const props = pipelineDef?.properties || {};
|
|
195
|
-
const allKnownKeys = new Set([
|
|
210
|
+
const allKnownKeys = new Set([
|
|
211
|
+
...Object.keys(props),
|
|
212
|
+
...SCHEMA_OMITTED_TOP_LEVEL_KEYS,
|
|
213
|
+
]);
|
|
196
214
|
const unknownKeys = Object.keys(parsed).filter((k) => !allKnownKeys.has(k));
|
|
197
215
|
if (unknownKeys.length > 0) {
|
|
198
|
-
|
|
216
|
+
for (const key of unknownKeys) {
|
|
217
|
+
context.warnings.push({
|
|
218
|
+
pipeline: context.pipeline,
|
|
219
|
+
path: key,
|
|
220
|
+
message: (0, texts_1.TXT_YAML_UNKNOWN_TOP_LEVEL_KEYS)(key),
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
context.output.yellow(`${label}${(0, texts_1.TXT_YAML_UNKNOWN_TOP_LEVEL_KEYS)(unknownKeys.join(', '))}`);
|
|
199
224
|
}
|
|
200
225
|
const { itemSections, objectSections, settingsProps } = classifySections(props);
|
|
201
226
|
if (Object.keys(settingsProps).length > 0) {
|
|
@@ -212,12 +237,12 @@ function validateSinglePipeline(parsed, label, unions) {
|
|
|
212
237
|
$defs: rawSchema.$defs,
|
|
213
238
|
}, settingsData);
|
|
214
239
|
if (result.valid) {
|
|
215
|
-
|
|
240
|
+
context.output.green(`${label}Pipeline settings`);
|
|
216
241
|
}
|
|
217
242
|
else {
|
|
218
243
|
errors += result.errors.length;
|
|
219
|
-
|
|
220
|
-
outputErrors(result, ' ');
|
|
244
|
+
context.output.error(`${label}Pipeline settings`);
|
|
245
|
+
outputErrors(result, ' ', context);
|
|
221
246
|
}
|
|
222
247
|
}
|
|
223
248
|
const itemByKey = new Map(itemSections.map((s) => [s.key, s]));
|
|
@@ -232,27 +257,52 @@ function validateSinglePipeline(parsed, label, unions) {
|
|
|
232
257
|
const header = `${label}${prettifyKey(key)}`;
|
|
233
258
|
if (itemByKey.has(key)) {
|
|
234
259
|
if (!Array.isArray(value)) {
|
|
235
|
-
errors += reportWrongContainer(header, 'array', value);
|
|
260
|
+
errors += reportWrongContainer(header, 'array', value, context, key);
|
|
236
261
|
continue;
|
|
237
262
|
}
|
|
238
|
-
|
|
239
|
-
errors += validateItemSection(unions, value, itemByKey.get(key));
|
|
263
|
+
context.output.blue(header);
|
|
264
|
+
errors += validateItemSection(unions, value, itemByKey.get(key), context);
|
|
240
265
|
}
|
|
241
266
|
else if (objByKey.has(key)) {
|
|
242
267
|
if (typeof value !== 'object' || Array.isArray(value)) {
|
|
243
|
-
errors += reportWrongContainer(header, 'object', value);
|
|
268
|
+
errors += reportWrongContainer(header, 'object', value, context, key);
|
|
244
269
|
continue;
|
|
245
270
|
}
|
|
246
|
-
errors += validateObjectSection(unions, header, value, objByKey.get(key));
|
|
271
|
+
errors += validateObjectSection(unions, header, value, objByKey.get(key), context, key);
|
|
247
272
|
}
|
|
248
273
|
}
|
|
249
274
|
return errors;
|
|
250
275
|
}
|
|
251
|
-
function validatePipelineFile(file, unions) {
|
|
276
|
+
function validatePipelineFile(file, unions, json) {
|
|
277
|
+
const context = {
|
|
278
|
+
output: {
|
|
279
|
+
normal: output_1.default.progress(json),
|
|
280
|
+
error: output_1.default.progress(json, output_1.default.error.bind(output_1.default)),
|
|
281
|
+
muted: output_1.default.progress(json, output_1.default.muted.bind(output_1.default)),
|
|
282
|
+
green: output_1.default.progress(json, output_1.default.green.bind(output_1.default)),
|
|
283
|
+
yellow: output_1.default.progress(json, output_1.default.yellow.bind(output_1.default)),
|
|
284
|
+
blue: output_1.default.progress(json, output_1.default.blue.bind(output_1.default)),
|
|
285
|
+
},
|
|
286
|
+
pipeline: 0,
|
|
287
|
+
errors: [],
|
|
288
|
+
warnings: [],
|
|
289
|
+
};
|
|
290
|
+
const invalidDocument = (message) => {
|
|
291
|
+
if (json) {
|
|
292
|
+
recordError(context, '', message);
|
|
293
|
+
output_1.default.json({
|
|
294
|
+
valid: false,
|
|
295
|
+
pipelines: 0,
|
|
296
|
+
errors: context.errors,
|
|
297
|
+
warnings: context.warnings,
|
|
298
|
+
});
|
|
299
|
+
output_1.default.exitCode(1);
|
|
300
|
+
}
|
|
301
|
+
output_1.default.exitError(message);
|
|
302
|
+
};
|
|
252
303
|
const filePath = (0, path_1.resolve)(file);
|
|
253
304
|
if (!(0, fs_1.existsSync)(filePath)) {
|
|
254
|
-
|
|
255
|
-
return;
|
|
305
|
+
invalidDocument((0, texts_1.ERR_YAML_VALIDATE_FILE_NOT_FOUND)(file));
|
|
256
306
|
}
|
|
257
307
|
const YAML = require('yaml');
|
|
258
308
|
const content = (0, fs_1.readFileSync)(filePath, 'utf8');
|
|
@@ -261,33 +311,40 @@ function validatePipelineFile(file, unions) {
|
|
|
261
311
|
parsed = YAML.parse(content);
|
|
262
312
|
}
|
|
263
313
|
catch (e) {
|
|
264
|
-
|
|
265
|
-
return;
|
|
314
|
+
invalidDocument((0, texts_1.ERR_YAML_PARSE)(e.message));
|
|
266
315
|
}
|
|
267
316
|
if (!parsed || typeof parsed !== 'object') {
|
|
268
|
-
|
|
269
|
-
return;
|
|
317
|
+
invalidDocument(texts_1.ERR_YAML_NOT_ARRAY);
|
|
270
318
|
}
|
|
271
319
|
if (!Array.isArray(parsed)) {
|
|
272
|
-
|
|
273
|
-
return;
|
|
320
|
+
invalidDocument(texts_1.ERR_YAML_PLAIN_OBJECT);
|
|
274
321
|
}
|
|
275
322
|
if (parsed.length === 0) {
|
|
276
|
-
|
|
277
|
-
return;
|
|
323
|
+
invalidDocument(texts_1.ERR_YAML_EMPTY_ARRAY);
|
|
278
324
|
}
|
|
279
325
|
let errors = 0;
|
|
280
326
|
for (let i = 0; i < parsed.length; i++) {
|
|
281
327
|
const pipeline = parsed[i];
|
|
328
|
+
context.pipeline = i + 1;
|
|
282
329
|
if (!pipeline || typeof pipeline !== 'object' || Array.isArray(pipeline)) {
|
|
283
|
-
|
|
330
|
+
recordError(context, '', (0, texts_1.ERR_YAML_PIPELINE_NOT_OBJECT)(i + 1));
|
|
331
|
+
context.output.error(` ${(0, texts_1.ERR_YAML_PIPELINE_NOT_OBJECT)(i + 1)}`);
|
|
284
332
|
errors++;
|
|
285
333
|
continue;
|
|
286
334
|
}
|
|
287
335
|
const pipelineLabel = parsed.length > 1 ? `[${pipeline.pipeline || i + 1}] ` : '';
|
|
288
|
-
errors += validateSinglePipeline(pipeline, pipelineLabel, unions);
|
|
336
|
+
errors += validateSinglePipeline(pipeline, pipelineLabel, unions, context);
|
|
337
|
+
}
|
|
338
|
+
if (json) {
|
|
339
|
+
output_1.default.json({
|
|
340
|
+
valid: errors === 0,
|
|
341
|
+
pipelines: parsed.length,
|
|
342
|
+
errors: context.errors,
|
|
343
|
+
warnings: context.warnings,
|
|
344
|
+
});
|
|
345
|
+
output_1.default.exitCode(errors > 0 ? 1 : 0);
|
|
289
346
|
}
|
|
290
|
-
|
|
347
|
+
context.output.normal('');
|
|
291
348
|
if (errors > 0) {
|
|
292
349
|
output_1.default.exitError((0, texts_1.ERR_YAML_VALIDATE_FAILED_COUNT)(errors));
|
|
293
350
|
}
|
|
@@ -296,11 +353,13 @@ function validatePipelineFile(file, unions) {
|
|
|
296
353
|
}
|
|
297
354
|
}
|
|
298
355
|
const commandYamlValidate = (0, utils_1.newCommand)('validate', texts_1.DESC_COMMAND_YAML_VALIDATE, {
|
|
356
|
+
helpText: texts_1.HELP_YAML_VALIDATE_JSON,
|
|
299
357
|
examples: texts_1.EXAMPLE_YAML_VALIDATE,
|
|
300
358
|
});
|
|
301
359
|
commandYamlValidate.argument('<file>', texts_1.OPTION_YAML_VALIDATE_FILE);
|
|
302
|
-
commandYamlValidate.
|
|
360
|
+
commandYamlValidate.option('--format <text|json>', texts_1.OPTION_FORMAT);
|
|
361
|
+
commandYamlValidate.action(async (file, options) => {
|
|
303
362
|
await (0, schemaUtils_1.ensureYamlSchema)();
|
|
304
|
-
validatePipelineFile(file, await unionMappings((0, schemaUtils_1.getAllDefs)()));
|
|
363
|
+
validatePipelineFile(file, await unionMappings((0, schemaUtils_1.getAllDefs)()), options.format === 'json');
|
|
305
364
|
});
|
|
306
365
|
exports.default = commandYamlValidate;
|
package/distTs/src/index.js
CHANGED
|
@@ -43,4 +43,9 @@ const isAgentRun = process.argv[2] === 'agent' && process.argv[3] === 'run';
|
|
|
43
43
|
const program = isAgentRun
|
|
44
44
|
? require('./agentIndex').default()
|
|
45
45
|
: require('./cliIndex').default();
|
|
46
|
-
program.
|
|
46
|
+
program.parseAsync().catch((err) => {
|
|
47
|
+
if (isEpipe(err))
|
|
48
|
+
process.exit(0);
|
|
49
|
+
logger_1.default.fatal(err);
|
|
50
|
+
output_1.default.exitError(err);
|
|
51
|
+
});
|
package/distTs/src/input.js
CHANGED
|
@@ -36,6 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
const cliError_1 = __importDefault(require("./cliError"));
|
|
39
40
|
const output_1 = __importDefault(require("./output"));
|
|
40
41
|
const netmask_1 = require("netmask");
|
|
41
42
|
const punycode_1 = __importDefault(require("punycode/"));
|
|
@@ -360,7 +361,7 @@ class Input {
|
|
|
360
361
|
if (!t && inSandbox && tokenEnv)
|
|
361
362
|
t = tokenEnv;
|
|
362
363
|
if (!t && !allowNoToken) {
|
|
363
|
-
output_1.default.exitError(texts_1.
|
|
364
|
+
output_1.default.exitError(new cliError_1.default('unauthorized', texts_1.ERR_REST_API_NOT_LOGGED_IN, texts_1.TXT_CLI_LOGIN_HINT));
|
|
364
365
|
}
|
|
365
366
|
return {
|
|
366
367
|
token: t || '',
|
|
@@ -488,7 +489,7 @@ class Input {
|
|
|
488
489
|
static runVariablesFromFile(p, encrypted) {
|
|
489
490
|
const s = (0, node_path_1.resolve)(p);
|
|
490
491
|
if (!node_fs_1.default.existsSync(s)) {
|
|
491
|
-
output_1.default.exitError(texts_1.ERR_RUN_VAR_FILE_NOT_FOUND);
|
|
492
|
+
output_1.default.exitError(new cliError_1.default('file_not_found', texts_1.ERR_RUN_VAR_FILE_NOT_FOUND));
|
|
492
493
|
}
|
|
493
494
|
let parsed;
|
|
494
495
|
try {
|
|
@@ -524,7 +525,7 @@ class Input {
|
|
|
524
525
|
}
|
|
525
526
|
catch (err) {
|
|
526
527
|
if (err.code === 'ENOENT')
|
|
527
|
-
output_1.default.exitError(texts_1.ERR_RUN_VAR_FILE_NOT_FOUND);
|
|
528
|
+
output_1.default.exitError(new cliError_1.default('file_not_found', texts_1.ERR_RUN_VAR_FILE_NOT_FOUND));
|
|
528
529
|
output_1.default.exitError(texts_1.ERR_RUN_VAR_FILE_INVALID);
|
|
529
530
|
}
|
|
530
531
|
list.push({
|
|
@@ -835,7 +836,7 @@ class Input {
|
|
|
835
836
|
return r;
|
|
836
837
|
}
|
|
837
838
|
else {
|
|
838
|
-
output_1.default.exitError(texts_1.ERR_REST_API_REGION);
|
|
839
|
+
output_1.default.exitError(new cliError_1.default('usage_error', texts_1.ERR_REST_API_REGION));
|
|
839
840
|
}
|
|
840
841
|
}
|
|
841
842
|
static restApiBaseUrlFromToken(token) {
|
|
@@ -894,14 +895,14 @@ class Input {
|
|
|
894
895
|
return new URL(`https://${u}`);
|
|
895
896
|
}
|
|
896
897
|
catch {
|
|
897
|
-
output_1.default.exitError(texts_1.ERR_REST_API_URL);
|
|
898
|
+
output_1.default.exitError(new cliError_1.default('usage_error', texts_1.ERR_REST_API_URL));
|
|
898
899
|
}
|
|
899
900
|
}
|
|
900
901
|
static resolvePath(path) {
|
|
901
902
|
const p = (0, node_path_1.resolve)(path);
|
|
902
903
|
const exists = node_fs_1.default.existsSync(p);
|
|
903
904
|
if (!exists) {
|
|
904
|
-
output_1.default.exitError(texts_1.ERR_PATH_NOT_EXISTS);
|
|
905
|
+
output_1.default.exitError(new cliError_1.default('file_not_found', texts_1.ERR_PATH_NOT_EXISTS));
|
|
905
906
|
}
|
|
906
907
|
return p;
|
|
907
908
|
}
|
|
@@ -923,7 +924,7 @@ class Input {
|
|
|
923
924
|
if (!w) {
|
|
924
925
|
if (allowNull)
|
|
925
926
|
return null;
|
|
926
|
-
output_1.default.exitError(texts_1.ERR_REST_API_WORKSPACE);
|
|
927
|
+
output_1.default.exitError(new cliError_1.default('usage_error', texts_1.ERR_REST_API_WORKSPACE, texts_1.TXT_CLI_WORKSPACE_HINT));
|
|
927
928
|
}
|
|
928
929
|
return w;
|
|
929
930
|
}
|
|
@@ -1255,14 +1256,14 @@ class Input {
|
|
|
1255
1256
|
if (!p) {
|
|
1256
1257
|
if (allowNull)
|
|
1257
1258
|
return null;
|
|
1258
|
-
output_1.default.exitError(texts_1.ERR_REST_API_PROJECT);
|
|
1259
|
+
output_1.default.exitError(new cliError_1.default('usage_error', texts_1.ERR_REST_API_PROJECT, texts_1.TXT_CLI_PROJECT_HINT));
|
|
1259
1260
|
}
|
|
1260
1261
|
return p;
|
|
1261
1262
|
}
|
|
1262
1263
|
static sandboxBootScript(s) {
|
|
1263
1264
|
const p = (0, node_path_1.resolve)(s);
|
|
1264
1265
|
if (!node_fs_1.default.existsSync(p))
|
|
1265
|
-
output_1.default.exitError(texts_1.ERR_SANDBOX_BOOT_SCRIPT_NOT_EXISTS);
|
|
1266
|
+
output_1.default.exitError(new cliError_1.default('file_not_found', texts_1.ERR_SANDBOX_BOOT_SCRIPT_NOT_EXISTS));
|
|
1266
1267
|
return node_fs_1.default.readFileSync(p, 'utf8');
|
|
1267
1268
|
}
|
|
1268
1269
|
static tags(tags) {
|
|
@@ -1273,11 +1274,11 @@ class Input {
|
|
|
1273
1274
|
}
|
|
1274
1275
|
static restApiYaml(yaml) {
|
|
1275
1276
|
if (!yaml)
|
|
1276
|
-
output_1.default.exitError(texts_1.ERR_REST_API_YAML);
|
|
1277
|
+
output_1.default.exitError(new cliError_1.default('usage_error', texts_1.ERR_REST_API_YAML));
|
|
1277
1278
|
if (yaml.startsWith('@')) {
|
|
1278
1279
|
const p = (0, node_path_1.resolve)(yaml.replace(/^@/, ''));
|
|
1279
1280
|
if (!node_fs_1.default.existsSync(p))
|
|
1280
|
-
output_1.default.exitError(texts_1.ERR_REST_API_YAML_NOT_FOUND);
|
|
1281
|
+
output_1.default.exitError(new cliError_1.default('file_not_found', texts_1.ERR_REST_API_YAML_NOT_FOUND));
|
|
1281
1282
|
return node_fs_1.default.readFileSync(p, 'utf8');
|
|
1282
1283
|
}
|
|
1283
1284
|
return yaml;
|