dataiku-sdk 0.10.0 → 0.11.0
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/packages/types/src/index.d.ts +15 -2
- package/dist/packages/types/src/index.js +9 -1
- package/dist/src/cli/coerce.d.ts +36 -0
- package/dist/src/cli/coerce.js +239 -0
- package/dist/src/cli/commands/api-deployer.d.ts +2 -0
- package/dist/src/cli/commands/api-deployer.js +170 -0
- package/dist/src/cli/commands/api-service.d.ts +2 -0
- package/dist/src/cli/commands/api-service.js +102 -0
- package/dist/src/cli/commands/app.d.ts +2 -0
- package/dist/src/cli/commands/app.js +78 -0
- package/dist/src/cli/commands/bundle.d.ts +2 -0
- package/dist/src/cli/commands/bundle.js +107 -0
- package/dist/src/cli/commands/business-app.d.ts +2 -0
- package/dist/src/cli/commands/business-app.js +76 -0
- package/dist/src/cli/commands/code-env.d.ts +2 -0
- package/dist/src/cli/commands/code-env.js +255 -0
- package/dist/src/cli/commands/code.d.ts +2 -0
- package/dist/src/cli/commands/code.js +63 -0
- package/dist/src/cli/commands/connection.d.ts +2 -0
- package/dist/src/cli/commands/connection.js +54 -0
- package/dist/src/cli/commands/continuous-activity.d.ts +2 -0
- package/dist/src/cli/commands/continuous-activity.js +38 -0
- package/dist/src/cli/commands/dashboard.d.ts +2 -0
- package/dist/src/cli/commands/dashboard.js +99 -0
- package/dist/src/cli/commands/data-quality.d.ts +2 -0
- package/dist/src/cli/commands/data-quality.js +235 -0
- package/dist/src/cli/commands/dataset.d.ts +2 -0
- package/dist/src/cli/commands/dataset.js +288 -0
- package/dist/src/cli/commands/discussion.d.ts +2 -0
- package/dist/src/cli/commands/discussion.js +47 -0
- package/dist/src/cli/commands/doctor.d.ts +2 -0
- package/dist/src/cli/commands/doctor.js +9 -0
- package/dist/src/cli/commands/flow-zone.d.ts +2 -0
- package/dist/src/cli/commands/flow-zone.js +282 -0
- package/dist/src/cli/commands/folder.d.ts +2 -0
- package/dist/src/cli/commands/folder.js +202 -0
- package/dist/src/cli/commands/future.d.ts +2 -0
- package/dist/src/cli/commands/future.js +57 -0
- package/dist/src/cli/commands/index.d.ts +2 -0
- package/dist/src/cli/commands/index.js +70 -0
- package/dist/src/cli/commands/insight.d.ts +2 -0
- package/dist/src/cli/commands/insight.js +156 -0
- package/dist/src/cli/commands/job.d.ts +2 -0
- package/dist/src/cli/commands/job.js +406 -0
- package/dist/src/cli/commands/meaning.d.ts +2 -0
- package/dist/src/cli/commands/meaning.js +115 -0
- package/dist/src/cli/commands/metrics.d.ts +2 -0
- package/dist/src/cli/commands/metrics.js +39 -0
- package/dist/src/cli/commands/notebook.d.ts +2 -0
- package/dist/src/cli/commands/notebook.js +242 -0
- package/dist/src/cli/commands/project-deployer.d.ts +2 -0
- package/dist/src/cli/commands/project-deployer.js +118 -0
- package/dist/src/cli/commands/project-library.d.ts +2 -0
- package/dist/src/cli/commands/project-library.js +197 -0
- package/dist/src/cli/commands/project.d.ts +2 -0
- package/dist/src/cli/commands/project.js +132 -0
- package/dist/src/cli/commands/recipe.d.ts +2 -0
- package/dist/src/cli/commands/recipe.js +632 -0
- package/dist/src/cli/commands/scenario.d.ts +2 -0
- package/dist/src/cli/commands/scenario.js +190 -0
- package/dist/src/cli/commands/sql.d.ts +2 -0
- package/dist/src/cli/commands/sql.js +109 -0
- package/dist/src/cli/commands/statistics.d.ts +2 -0
- package/dist/src/cli/commands/statistics.js +165 -0
- package/dist/src/cli/commands/streaming-endpoint.d.ts +2 -0
- package/dist/src/cli/commands/streaming-endpoint.js +50 -0
- package/dist/src/cli/commands/variable.d.ts +2 -0
- package/dist/src/cli/commands/variable.js +49 -0
- package/dist/src/cli/commands/webapp.d.ts +2 -0
- package/dist/src/cli/commands/webapp.js +67 -0
- package/dist/src/cli/commands/wiki.d.ts +2 -0
- package/dist/src/cli/commands/wiki.js +123 -0
- package/dist/src/cli/commands/workspace.d.ts +2 -0
- package/dist/src/cli/commands/workspace.js +68 -0
- package/dist/src/cli/contract.d.ts +104 -0
- package/dist/src/cli/contract.js +2031 -0
- package/dist/src/cli/doctor.d.ts +104 -0
- package/dist/src/cli/doctor.js +356 -0
- package/dist/src/cli/env.d.ts +2 -0
- package/dist/src/cli/env.js +37 -0
- package/dist/src/cli/flags.d.ts +16 -0
- package/dist/src/cli/flags.js +255 -0
- package/dist/src/cli/helpers/cleanup.d.ts +3 -0
- package/dist/src/cli/helpers/cleanup.js +158 -0
- package/dist/src/cli/helpers/dataset.d.ts +2 -0
- package/dist/src/cli/helpers/dataset.js +17 -0
- package/dist/src/cli/helpers/flow-zone.d.ts +69 -0
- package/dist/src/cli/helpers/flow-zone.js +420 -0
- package/dist/src/cli/helpers/recipe.d.ts +11 -0
- package/dist/src/cli/helpers/recipe.js +83 -0
- package/dist/src/cli/output.d.ts +38 -0
- package/dist/src/cli/output.js +159 -0
- package/dist/src/cli/runtime.d.ts +15 -0
- package/dist/src/cli/runtime.js +59 -0
- package/dist/src/cli/types.d.ts +25 -0
- package/dist/src/cli/types.js +1 -0
- package/dist/src/cli/usage.d.ts +16 -0
- package/dist/src/cli/usage.js +80 -0
- package/dist/src/cli/version.d.ts +14 -0
- package/dist/src/cli/version.js +63 -0
- package/dist/src/cli.js +671 -8254
- package/dist/src/client.d.ts +1 -1
- package/dist/src/client.js +14 -13
- package/dist/src/errors.d.ts +6 -0
- package/dist/src/errors.js +127 -4
- package/dist/src/index.d.ts +3 -3
- package/dist/src/index.js +2 -2
- package/dist/src/resources/applications.d.ts +1 -1
- package/dist/src/resources/applications.js +27 -1
- package/dist/src/resources/bundles.js +2 -2
- package/dist/src/resources/continuous-activities.js +1 -0
- package/dist/src/resources/data-quality.js +5 -3
- package/dist/src/resources/datasets.d.ts +3 -0
- package/dist/src/resources/datasets.js +3 -0
- package/dist/src/resources/flow-zones.d.ts +2 -2
- package/dist/src/resources/flow-zones.js +4 -1
- package/dist/src/resources/meanings.d.ts +2 -0
- package/dist/src/resources/meanings.js +4 -0
- package/dist/src/resources/notebooks.d.ts +5 -7
- package/dist/src/resources/notebooks.js +10 -7
- package/dist/src/resources/projects.d.ts +1 -1
- package/dist/src/resources/projects.js +2 -2
- package/dist/src/resources/recipes.d.ts +3 -3
- package/dist/src/resources/recipes.js +50 -7
- package/dist/src/resources/scenarios.js +67 -26
- package/dist/src/resources/statistics.js +9 -0
- package/dist/src/schemas.d.ts +2 -2
- package/dist/src/schemas.js +1 -1
- package/dist/src/skill.js +2 -2
- package/dist/src/utils/sanitize.js +2 -1
- package/package.json +1 -1
- package/packages/types/dist/index.d.ts +15 -2
- package/packages/types/dist/index.js +9 -1
|
@@ -0,0 +1,2031 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { validateCredentials, } from "../auth.js";
|
|
4
|
+
import { getCredentialsPath, saveCredentials, } from "../config.js";
|
|
5
|
+
import { DataikuError, } from "../errors.js";
|
|
6
|
+
import { jobBuildTargetTypeFromFlags, json, jsonInput, num, parseBooleanOption, parseJsonObject, requiredJsonInput, schemaColumnsInput, textInput, } from "./coerce.js";
|
|
7
|
+
import { commands, } from "./commands/index.js";
|
|
8
|
+
import { dataikuEnvironmentEnabled, } from "./env.js";
|
|
9
|
+
import { BOOLEAN_FLAGS, FLAG_ALIASES, KNOWN_LONG_FLAGS, } from "./flags.js";
|
|
10
|
+
import { flowZoneColor, flowZoneMoveItems, flowZoneName, } from "./helpers/flow-zone.js";
|
|
11
|
+
import { recipeBackupPath, recipeRunShouldWait, } from "./helpers/recipe.js";
|
|
12
|
+
import { encodedProjectEndpointForPlan, planResult, } from "./output.js";
|
|
13
|
+
import { resolveCredentials, resolveTlsSettings, } from "./runtime.js";
|
|
14
|
+
import { requireArgs, UsageError, } from "./usage.js";
|
|
15
|
+
import { AGENT_CONTRACT_SCHEMA_ID, AGENT_CONTRACT_VERSION, cliVersionResult, JSON_SCHEMA_DRAFT, } from "./version.js";
|
|
16
|
+
function codeEnvWait(flags) {
|
|
17
|
+
return flags["no-wait"] !== true;
|
|
18
|
+
}
|
|
19
|
+
function codeEnvParams(flags) {
|
|
20
|
+
const params = json(flags["params"]) ?? jsonInput(flags) ?? {};
|
|
21
|
+
if (typeof flags["python-interpreter"] === "string") {
|
|
22
|
+
params.pythonInterpreter = flags["python-interpreter"];
|
|
23
|
+
}
|
|
24
|
+
return params;
|
|
25
|
+
}
|
|
26
|
+
function splitPackageSpec(raw) {
|
|
27
|
+
return raw.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
28
|
+
}
|
|
29
|
+
function codeEnvPackageList(flags) {
|
|
30
|
+
const packages = [];
|
|
31
|
+
if (typeof flags["file"] === "string") {
|
|
32
|
+
packages.push(...splitPackageSpec(fs.readFileSync(flags["file"], "utf-8")));
|
|
33
|
+
}
|
|
34
|
+
if (typeof flags["packages"] === "string") {
|
|
35
|
+
packages.push(...splitPackageSpec(flags["packages"]));
|
|
36
|
+
}
|
|
37
|
+
if (typeof flags["package"] === "string") {
|
|
38
|
+
packages.push(...splitPackageSpec(flags["package"]));
|
|
39
|
+
}
|
|
40
|
+
if (packages.length === 0) {
|
|
41
|
+
throw new UsageError("--packages, --package, or --file is required. Use newline-separated package specs for version constraints.");
|
|
42
|
+
}
|
|
43
|
+
return packages;
|
|
44
|
+
}
|
|
45
|
+
export const AUTH_ACTIONS = {
|
|
46
|
+
login: {
|
|
47
|
+
handler: async (flags) => {
|
|
48
|
+
const tlsSettings = resolveTlsSettings(flags);
|
|
49
|
+
const useEnv = dataikuEnvironmentEnabled();
|
|
50
|
+
const url = typeof flags["url"] === "string"
|
|
51
|
+
? flags["url"]
|
|
52
|
+
: useEnv
|
|
53
|
+
? process.env.DATAIKU_URL ?? ""
|
|
54
|
+
: "";
|
|
55
|
+
const apiKey = typeof flags["api-key"] === "string"
|
|
56
|
+
? flags["api-key"]
|
|
57
|
+
: useEnv
|
|
58
|
+
? process.env.DATAIKU_API_KEY ?? ""
|
|
59
|
+
: "";
|
|
60
|
+
const projectKey = typeof flags["project-key"] === "string"
|
|
61
|
+
? flags["project-key"]
|
|
62
|
+
: useEnv
|
|
63
|
+
? process.env.DATAIKU_PROJECT_KEY
|
|
64
|
+
: undefined;
|
|
65
|
+
if (!url || !apiKey) {
|
|
66
|
+
throw new UsageError("Missing --url and/or --api-key for auth login.", "missing_required_flag", "Pass --url and --api-key, or set DATAIKU_URL and DATAIKU_API_KEY.", { requiredFlags: ["url", "api-key",], env: ["DATAIKU_URL", "DATAIKU_API_KEY",], });
|
|
67
|
+
}
|
|
68
|
+
const result = await validateCredentials(url, apiKey, tlsSettings);
|
|
69
|
+
if (!result.valid) {
|
|
70
|
+
if (result.dataikuError)
|
|
71
|
+
throw result.dataikuError;
|
|
72
|
+
throw new DataikuError(0, "Authentication Failed", result.error ?? "Credential validation failed");
|
|
73
|
+
}
|
|
74
|
+
const credentialsPath = getCredentialsPath();
|
|
75
|
+
saveCredentials({ url, apiKey, projectKey, ...tlsSettings, });
|
|
76
|
+
return { saved: true, path: credentialsPath, };
|
|
77
|
+
},
|
|
78
|
+
usage: "dss auth login --url URL --api-key KEY [--project-key KEY] [--insecure] [--ca-cert PATH]",
|
|
79
|
+
description: "Validate and save DSS credentials from flags or environment variables.",
|
|
80
|
+
examples: [
|
|
81
|
+
"dss auth login --url https://dss.example.com --api-key YOUR_KEY",
|
|
82
|
+
"dss auth login --url https://dss.example.com --api-key YOUR_KEY --project-key MYPROJ",
|
|
83
|
+
],
|
|
84
|
+
requiredFlags: ["url", "api-key",],
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
const READ_ACTIONS = new Set([
|
|
88
|
+
"cat",
|
|
89
|
+
"contents",
|
|
90
|
+
"deployment-settings",
|
|
91
|
+
"deployment-status",
|
|
92
|
+
"diff",
|
|
93
|
+
"download",
|
|
94
|
+
"download-code",
|
|
95
|
+
"flow",
|
|
96
|
+
"get",
|
|
97
|
+
"get-rule",
|
|
98
|
+
"get-definition",
|
|
99
|
+
"get-jupyter",
|
|
100
|
+
"get-payload",
|
|
101
|
+
"get-sql",
|
|
102
|
+
"graph",
|
|
103
|
+
"history-sql",
|
|
104
|
+
"history",
|
|
105
|
+
"infer",
|
|
106
|
+
"list",
|
|
107
|
+
"last-results",
|
|
108
|
+
"list-jupyter",
|
|
109
|
+
"list-sql",
|
|
110
|
+
"log",
|
|
111
|
+
"log-url",
|
|
112
|
+
"map",
|
|
113
|
+
"metadata",
|
|
114
|
+
"peek",
|
|
115
|
+
"source",
|
|
116
|
+
"summary",
|
|
117
|
+
"wait",
|
|
118
|
+
"watch",
|
|
119
|
+
"preview",
|
|
120
|
+
"query",
|
|
121
|
+
"schema",
|
|
122
|
+
"schemas",
|
|
123
|
+
"sessions-jupyter",
|
|
124
|
+
"status",
|
|
125
|
+
"rules",
|
|
126
|
+
"settings",
|
|
127
|
+
"settings-get",
|
|
128
|
+
"status-by-partition",
|
|
129
|
+
"usages",
|
|
130
|
+
]);
|
|
131
|
+
const PROJECT_SCOPED_RESOURCES = new Set([
|
|
132
|
+
"data-quality",
|
|
133
|
+
"dashboard",
|
|
134
|
+
"dataset",
|
|
135
|
+
"flow-zone",
|
|
136
|
+
"insight",
|
|
137
|
+
"folder",
|
|
138
|
+
"fixtures",
|
|
139
|
+
"job",
|
|
140
|
+
"notebook",
|
|
141
|
+
"recipe",
|
|
142
|
+
"scenario",
|
|
143
|
+
"sql",
|
|
144
|
+
"variable",
|
|
145
|
+
"wiki",
|
|
146
|
+
]);
|
|
147
|
+
const GLOBAL_AGENT_FLAGS = ["json", "verbose", "fields",];
|
|
148
|
+
const AUTHENTICATED_AGENT_FLAGS = [
|
|
149
|
+
"url",
|
|
150
|
+
"api-key",
|
|
151
|
+
"request-timeout",
|
|
152
|
+
"retries",
|
|
153
|
+
"insecure",
|
|
154
|
+
"ca-cert",
|
|
155
|
+
];
|
|
156
|
+
export const COMMANDS_USAGE = "dss commands run [--json]";
|
|
157
|
+
const COMMANDS_DESCRIPTION = "Print the machine-readable command registry for agent planning.";
|
|
158
|
+
const COMMANDS_EXAMPLES = ["dss commands run", "dss commands run --json",];
|
|
159
|
+
export const AGENT_CONTRACT_USAGE = "dss agent contract";
|
|
160
|
+
const AGENT_CONTRACT_DESCRIPTION = "Print the versioned JSON contract agents should use to drive dss.";
|
|
161
|
+
const AGENT_CONTRACT_EXAMPLES = ["dss agent contract",];
|
|
162
|
+
const VERSION_USAGE = "dss version";
|
|
163
|
+
const VERSION_DESCRIPTION = "Print the CLI version and git revision as JSON.";
|
|
164
|
+
const VERSION_EXAMPLES = ["dss version", "dss --version",];
|
|
165
|
+
const INSTALL_SKILL_USAGE = "dss install-skill [--global] [--agent NAME] [--target PATH] [--list-agents] [--dry-run] [--plan]";
|
|
166
|
+
const INSTALL_SKILL_DESCRIPTION = "Install the dataiku-dss agent skill for detected coding agents.";
|
|
167
|
+
const INSTALL_SKILL_EXAMPLES = [
|
|
168
|
+
"dss install-skill --list-agents",
|
|
169
|
+
"dss install-skill --agent omp --dry-run",
|
|
170
|
+
];
|
|
171
|
+
export const CLEANUP_USAGE = "dss cleanup --file PATH [--dry-run|--apply] [--continue-on-error]";
|
|
172
|
+
const CLEANUP_DESCRIPTION = "Replay cleanup ledger entries in reverse order.";
|
|
173
|
+
const CLEANUP_EXAMPLES = [
|
|
174
|
+
"dss cleanup --file cleanup.jsonl",
|
|
175
|
+
"dss cleanup --file cleanup.jsonl --apply",
|
|
176
|
+
];
|
|
177
|
+
const FIXTURES_USAGE = "dss fixtures [--json] [--project-key KEY] [--allow-types CSV]";
|
|
178
|
+
const FIXTURES_DESCRIPTION = "Discover safe live-test fixtures for agent workflows.";
|
|
179
|
+
const FIXTURES_EXAMPLES = [
|
|
180
|
+
"dss fixtures --json",
|
|
181
|
+
"dss fixtures --json --allow-types Filesystem,Inline",
|
|
182
|
+
];
|
|
183
|
+
const ALLOWED_CLEANUP_ACTIONS = new Set([
|
|
184
|
+
// Must mirror every cleanup.argv shape emitted by cleanupLedgerEntry().
|
|
185
|
+
"dataset delete",
|
|
186
|
+
"recipe delete",
|
|
187
|
+
"scenario delete",
|
|
188
|
+
"flow-zone delete",
|
|
189
|
+
"wiki delete",
|
|
190
|
+
"dashboard delete",
|
|
191
|
+
"insight delete",
|
|
192
|
+
"data-quality delete-rule",
|
|
193
|
+
"code-env delete",
|
|
194
|
+
"folder delete-file",
|
|
195
|
+
]);
|
|
196
|
+
export function isAllowedCleanupAction(resource, action) {
|
|
197
|
+
return ALLOWED_CLEANUP_ACTIONS.has(`${resource} ${action}`);
|
|
198
|
+
}
|
|
199
|
+
function uniqueStrings(values) {
|
|
200
|
+
return [...new Set(values),];
|
|
201
|
+
}
|
|
202
|
+
function flagKind(name) {
|
|
203
|
+
return BOOLEAN_FLAGS.has(name) ? "boolean" : "value";
|
|
204
|
+
}
|
|
205
|
+
function registryKey(resource, action) {
|
|
206
|
+
return `${resource}.${action}`;
|
|
207
|
+
}
|
|
208
|
+
function splitShellLike(input) {
|
|
209
|
+
const tokens = [];
|
|
210
|
+
let current = "";
|
|
211
|
+
let quote;
|
|
212
|
+
for (let index = 0; index < input.length; index++) {
|
|
213
|
+
const char = input[index];
|
|
214
|
+
if (quote) {
|
|
215
|
+
if (char === quote) {
|
|
216
|
+
quote = undefined;
|
|
217
|
+
}
|
|
218
|
+
else if (char === "\\" && quote === '"' && index + 1 < input.length) {
|
|
219
|
+
current += input[++index];
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
current += char;
|
|
223
|
+
}
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
if (char === "'" || char === '"') {
|
|
227
|
+
quote = char;
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
if (/\s/.test(char)) {
|
|
231
|
+
if (current.length > 0) {
|
|
232
|
+
tokens.push(current);
|
|
233
|
+
current = "";
|
|
234
|
+
}
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
if (char === "|" || char === "<" || char === ">" || char === ";" || char === "&") {
|
|
238
|
+
return undefined;
|
|
239
|
+
}
|
|
240
|
+
current += char;
|
|
241
|
+
}
|
|
242
|
+
if (quote)
|
|
243
|
+
return undefined;
|
|
244
|
+
if (current.length > 0)
|
|
245
|
+
tokens.push(current);
|
|
246
|
+
return tokens;
|
|
247
|
+
}
|
|
248
|
+
function exampleArgv(example) {
|
|
249
|
+
const tokens = splitShellLike(example);
|
|
250
|
+
if (!tokens || tokens[0] !== "dss")
|
|
251
|
+
return undefined;
|
|
252
|
+
return tokens.slice(1);
|
|
253
|
+
}
|
|
254
|
+
function structuredExamples(examples, examplePayload) {
|
|
255
|
+
return (examples ?? []).map((shell) => {
|
|
256
|
+
const argv = exampleArgv(shell);
|
|
257
|
+
return {
|
|
258
|
+
shell,
|
|
259
|
+
...(argv ? { argv, } : {}),
|
|
260
|
+
...(examplePayload !== undefined && shell.includes("--data")
|
|
261
|
+
? { payload: examplePayload, }
|
|
262
|
+
: {}),
|
|
263
|
+
};
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
function outputJsonSchema(shape) {
|
|
267
|
+
if (shape === "array")
|
|
268
|
+
return { type: "array", items: true, };
|
|
269
|
+
if (shape === "string")
|
|
270
|
+
return { type: "string", };
|
|
271
|
+
return { type: "object", additionalProperties: true, };
|
|
272
|
+
}
|
|
273
|
+
function payloadJsonSchema(payloadSchema) {
|
|
274
|
+
if (!payloadSchema)
|
|
275
|
+
return undefined;
|
|
276
|
+
return payloadSchema.jsonShape === "array"
|
|
277
|
+
? { type: "array", items: true, }
|
|
278
|
+
: { type: "object", additionalProperties: true, };
|
|
279
|
+
}
|
|
280
|
+
function argvJsonSchema(resource, action, _flags, _positionals, _requiredFlags, _requiredOneOf) {
|
|
281
|
+
return {
|
|
282
|
+
type: "object",
|
|
283
|
+
additionalProperties: true,
|
|
284
|
+
required: ["argv",],
|
|
285
|
+
properties: {
|
|
286
|
+
argv: { type: "array", items: { type: "string", }, minItems: 1, },
|
|
287
|
+
resource: { const: resource, },
|
|
288
|
+
action: { const: action, },
|
|
289
|
+
},
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
function unsafeOutputs(resource, action, flags, producesLocalFile) {
|
|
293
|
+
const outputs = [];
|
|
294
|
+
if (flags.some((flag) => flag.name === "raw")) {
|
|
295
|
+
outputs.push({
|
|
296
|
+
condition: "--raw without --output",
|
|
297
|
+
kind: "raw-stdout",
|
|
298
|
+
detail: `${resource} ${action} can intentionally write raw payload bytes/text instead of JSON.`,
|
|
299
|
+
safeAlternative: flags.some((flag) => flag.name === "output")
|
|
300
|
+
? "Pass --output PATH so stdout remains a JSON string containing the path."
|
|
301
|
+
: "Omit --raw when a JSON stdout value is required.",
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
if (producesLocalFile) {
|
|
305
|
+
outputs.push({
|
|
306
|
+
condition: "--output or --output-file",
|
|
307
|
+
kind: "local-file",
|
|
308
|
+
detail: "Command writes bytes to a local path and returns JSON metadata on stdout.",
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
return outputs.length > 0 ? outputs : undefined;
|
|
312
|
+
}
|
|
313
|
+
export function buildCommandSchemas(resource, action, flags, positionals, requiredFlags, requiredOneOf, payloadSchema, outputShape) {
|
|
314
|
+
return {
|
|
315
|
+
argv: argvJsonSchema(resource, action, flags, positionals, requiredFlags, requiredOneOf),
|
|
316
|
+
...(payloadSchema ? { input: payloadJsonSchema(payloadSchema), } : {}),
|
|
317
|
+
output: outputJsonSchema(outputShape),
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
const EXPLICIT_REGISTRY_OVERRIDES = {
|
|
321
|
+
"dashboard.create": {
|
|
322
|
+
examplePayload: { pages: [], },
|
|
323
|
+
},
|
|
324
|
+
"dashboard.update": {
|
|
325
|
+
examplePayload: { name: "Updated dashboard", },
|
|
326
|
+
},
|
|
327
|
+
"data-quality.create-rule": {
|
|
328
|
+
examplePayload: {
|
|
329
|
+
type: "RecordCountInRangeRule",
|
|
330
|
+
softMinimum: 1,
|
|
331
|
+
softMinimumEnabled: true,
|
|
332
|
+
displayName: "Has rows",
|
|
333
|
+
},
|
|
334
|
+
},
|
|
335
|
+
"data-quality.update-rule": {
|
|
336
|
+
examplePayload: { enabled: false, },
|
|
337
|
+
},
|
|
338
|
+
"dataset.update": {
|
|
339
|
+
examplePayload: { tags: ["production",], },
|
|
340
|
+
},
|
|
341
|
+
"insight.create": {
|
|
342
|
+
examplePayload: {
|
|
343
|
+
name: "Agent insight",
|
|
344
|
+
type: "chart",
|
|
345
|
+
listed: false,
|
|
346
|
+
params: {},
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
"insight.update": {
|
|
350
|
+
examplePayload: { listed: false, },
|
|
351
|
+
},
|
|
352
|
+
"recipe.update": {
|
|
353
|
+
examplePayload: { recipe: { params: {}, }, },
|
|
354
|
+
},
|
|
355
|
+
"scenario.update": {
|
|
356
|
+
examplePayload: { active: false, },
|
|
357
|
+
},
|
|
358
|
+
"wiki.update": {
|
|
359
|
+
examplePayload: { article: { name: "Updated article", }, },
|
|
360
|
+
},
|
|
361
|
+
};
|
|
362
|
+
function extractUsageFlags(usage) {
|
|
363
|
+
const flags = [];
|
|
364
|
+
for (const match of usage.matchAll(/--([a-z0-9-]+)/g)) {
|
|
365
|
+
flags.push(FLAG_ALIASES[match[1]] ?? match[1]);
|
|
366
|
+
}
|
|
367
|
+
return uniqueStrings(flags).filter((flag) => KNOWN_LONG_FLAGS.has(flag));
|
|
368
|
+
}
|
|
369
|
+
function extractPositionals(usage) {
|
|
370
|
+
return uniqueStrings([...usage.matchAll(/<([^>]+)>/g),].map((match) => match[1]));
|
|
371
|
+
}
|
|
372
|
+
function inferSideEffect(resource, action) {
|
|
373
|
+
if (resource === "auth")
|
|
374
|
+
return "auth";
|
|
375
|
+
if (resource === "agent" || resource === "doctor" || resource === "commands"
|
|
376
|
+
|| resource === "fixtures"
|
|
377
|
+
|| resource === "version") {
|
|
378
|
+
return "read";
|
|
379
|
+
}
|
|
380
|
+
if (resource === "install-skill")
|
|
381
|
+
return "write";
|
|
382
|
+
if (resource === "data-quality" && action === "compute")
|
|
383
|
+
return "write";
|
|
384
|
+
if (READ_ACTIONS.has(action))
|
|
385
|
+
return "read";
|
|
386
|
+
if (/^(create|clone|restore|update|delete|set|save|upload|run|build|abort|move|refresh|clear|unload|install|login|logout|add|remove|publish|activate|deploy|import|export|preload|upgrade|start|stop|restart|duplicate|put|rename|reply|compute|organize)/
|
|
387
|
+
.test(action)
|
|
388
|
+
// Compound actions whose mutating verb is a suffix (e.g. permissions-set, dataset-compute).
|
|
389
|
+
|| /-(set|compute)$/.test(action)) {
|
|
390
|
+
return "write";
|
|
391
|
+
}
|
|
392
|
+
return "read";
|
|
393
|
+
}
|
|
394
|
+
function inferRequiresAuth(resource) {
|
|
395
|
+
return resource !== "agent"
|
|
396
|
+
&& resource !== "auth"
|
|
397
|
+
&& resource !== "commands"
|
|
398
|
+
&& resource !== "install-skill"
|
|
399
|
+
&& resource !== "version";
|
|
400
|
+
}
|
|
401
|
+
export function inferRequiresProject(resource, _action, usage) {
|
|
402
|
+
if (resource === "agent" || resource === "auth" || resource === "doctor" || resource === "commands"
|
|
403
|
+
|| resource === "install-skill" || resource === "version") {
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
406
|
+
if (PROJECT_SCOPED_RESOURCES.has(resource))
|
|
407
|
+
return true;
|
|
408
|
+
return usage.includes("--project-key");
|
|
409
|
+
}
|
|
410
|
+
const ARRAY_OUTPUT_ACTIONS = new Set([
|
|
411
|
+
"history",
|
|
412
|
+
"find",
|
|
413
|
+
"infer",
|
|
414
|
+
"last-results",
|
|
415
|
+
"list",
|
|
416
|
+
"list-jupyter",
|
|
417
|
+
"list-sql",
|
|
418
|
+
"project-timeline",
|
|
419
|
+
"rules",
|
|
420
|
+
"schemas",
|
|
421
|
+
"sessions-jupyter",
|
|
422
|
+
"usages",
|
|
423
|
+
]);
|
|
424
|
+
const STRING_OUTPUT_ACTIONS = new Set([
|
|
425
|
+
"diff",
|
|
426
|
+
"download",
|
|
427
|
+
"download-code",
|
|
428
|
+
"get-payload",
|
|
429
|
+
"cat",
|
|
430
|
+
"log",
|
|
431
|
+
"log-url",
|
|
432
|
+
]);
|
|
433
|
+
function inferOutputShape(resource, action) {
|
|
434
|
+
if (resource === "agent" || resource === "auth" || resource === "commands"
|
|
435
|
+
|| resource === "install-skill"
|
|
436
|
+
|| resource === "version") {
|
|
437
|
+
return "object";
|
|
438
|
+
}
|
|
439
|
+
if (/^list(-|$)/.test(action))
|
|
440
|
+
return "array";
|
|
441
|
+
if (ARRAY_OUTPUT_ACTIONS.has(action))
|
|
442
|
+
return "array";
|
|
443
|
+
if (resource === "dataset" && action === "download")
|
|
444
|
+
return "object";
|
|
445
|
+
if (resource === "project-library" && action === "get")
|
|
446
|
+
return "string";
|
|
447
|
+
if (STRING_OUTPUT_ACTIONS.has(action))
|
|
448
|
+
return "string";
|
|
449
|
+
return "object";
|
|
450
|
+
}
|
|
451
|
+
export function inferInputContract(usage) {
|
|
452
|
+
return {
|
|
453
|
+
...(usage.includes("--stdin") ? { stdin: true, } : {}),
|
|
454
|
+
...(usage.includes("--data ") || usage.includes("--data JSON") ? { dataFlag: true, } : {}),
|
|
455
|
+
...(usage.includes("--data-file") ? { dataFileFlag: true, } : {}),
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
function stripOptionalUsageGroups(usage) {
|
|
459
|
+
return usage.replace(/\[[^\]]*\]/g, " ");
|
|
460
|
+
}
|
|
461
|
+
function stripAllUsageGroups(usage) {
|
|
462
|
+
return usage.replace(/\[[^\]]*\]/g, " ").replace(/\([^)]*\)/g, " ");
|
|
463
|
+
}
|
|
464
|
+
function topLevelParenGroups(usage) {
|
|
465
|
+
const groups = [];
|
|
466
|
+
let depth = 0;
|
|
467
|
+
let current = "";
|
|
468
|
+
for (const char of usage) {
|
|
469
|
+
if (char === "(") {
|
|
470
|
+
if (depth > 0)
|
|
471
|
+
current += char;
|
|
472
|
+
else
|
|
473
|
+
current = "";
|
|
474
|
+
depth++;
|
|
475
|
+
}
|
|
476
|
+
else if (char === ")") {
|
|
477
|
+
depth--;
|
|
478
|
+
if (depth === 0)
|
|
479
|
+
groups.push(current);
|
|
480
|
+
else
|
|
481
|
+
current += char;
|
|
482
|
+
}
|
|
483
|
+
else if (depth > 0) {
|
|
484
|
+
current += char;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
return groups;
|
|
488
|
+
}
|
|
489
|
+
function splitTopLevelChoices(group) {
|
|
490
|
+
const parts = [];
|
|
491
|
+
let depth = 0;
|
|
492
|
+
let current = "";
|
|
493
|
+
for (const char of group) {
|
|
494
|
+
if (char === "[" || char === "(")
|
|
495
|
+
depth++;
|
|
496
|
+
else if (char === "]" || char === ")")
|
|
497
|
+
depth--;
|
|
498
|
+
if (char === "|" && depth === 0) {
|
|
499
|
+
parts.push(current);
|
|
500
|
+
current = "";
|
|
501
|
+
}
|
|
502
|
+
else {
|
|
503
|
+
current += char;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
parts.push(current);
|
|
507
|
+
return parts;
|
|
508
|
+
}
|
|
509
|
+
function flagsInUsageFragment(fragment) {
|
|
510
|
+
return extractUsageFlags(fragment.replace(/\[[^\]]*\]/g, " "));
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Split required usage flags into unconditional flags and mutually-exclusive
|
|
514
|
+
* choice groups. A required `(--a X | --b Y)` group becomes a requiredOneOf entry
|
|
515
|
+
* (pick exactly one alternative; an alternative listing several flags must be
|
|
516
|
+
* supplied together) instead of marking every flag as unconditionally required.
|
|
517
|
+
*/
|
|
518
|
+
function deriveRequiredUsage(usage) {
|
|
519
|
+
const requiredFlags = extractUsageFlags(stripAllUsageGroups(usage));
|
|
520
|
+
const requiredOneOf = [];
|
|
521
|
+
for (const group of topLevelParenGroups(usage)) {
|
|
522
|
+
const alternatives = splitTopLevelChoices(group);
|
|
523
|
+
if (alternatives.length <= 1) {
|
|
524
|
+
requiredFlags.push(...flagsInUsageFragment(group));
|
|
525
|
+
continue;
|
|
526
|
+
}
|
|
527
|
+
const oneOf = alternatives
|
|
528
|
+
.map((alternative) => flagsInUsageFragment(alternative))
|
|
529
|
+
.filter((alternativeFlags) => alternativeFlags.length > 0);
|
|
530
|
+
if (oneOf.length > 1)
|
|
531
|
+
requiredOneOf.push({ oneOf, });
|
|
532
|
+
else if (oneOf.length === 1)
|
|
533
|
+
requiredFlags.push(...oneOf[0]);
|
|
534
|
+
}
|
|
535
|
+
return { requiredFlags: uniqueStrings(requiredFlags), requiredOneOf, };
|
|
536
|
+
}
|
|
537
|
+
const GLOBAL_FLAG_VALUE_HINTS = {
|
|
538
|
+
url: { valueType: "URL", },
|
|
539
|
+
fields: { valueType: "CSV", },
|
|
540
|
+
"api-key": { valueType: "KEY", },
|
|
541
|
+
"request-timeout": { valueType: "MS", },
|
|
542
|
+
retries: { valueType: "N", },
|
|
543
|
+
"ca-cert": { valueType: "PATH", },
|
|
544
|
+
"project-key": { valueType: "KEY", },
|
|
545
|
+
"record-cleanup": { valueType: "PATH", },
|
|
546
|
+
};
|
|
547
|
+
/** Derive a value placeholder (and enum members) for each value flag from its usage token. */
|
|
548
|
+
function extractFlagValueHints(usage) {
|
|
549
|
+
const hints = new Map();
|
|
550
|
+
for (const match of usage.matchAll(/--([a-z0-9-]+)\s+([a-z]+(?:\|[a-z]+)+)/g)) {
|
|
551
|
+
const flag = FLAG_ALIASES[match[1]] ?? match[1];
|
|
552
|
+
if (!hints.has(flag)) {
|
|
553
|
+
hints.set(flag, { valueType: "enum", enumValues: match[2].split("|"), });
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
for (const match of usage.matchAll(/--([a-z0-9-]+)\s+(<[^>]+>|[A-Z][A-Za-z0-9_]*)/g)) {
|
|
557
|
+
const flag = FLAG_ALIASES[match[1]] ?? match[1];
|
|
558
|
+
if (!hints.has(flag))
|
|
559
|
+
hints.set(flag, { valueType: match[2], });
|
|
560
|
+
}
|
|
561
|
+
return hints;
|
|
562
|
+
}
|
|
563
|
+
function inferPayloadSchema(inputContract) {
|
|
564
|
+
if (!inputContract.stdin && !inputContract.dataFlag && !inputContract.dataFileFlag) {
|
|
565
|
+
return undefined;
|
|
566
|
+
}
|
|
567
|
+
return { ...inputContract, jsonShape: "object", };
|
|
568
|
+
}
|
|
569
|
+
function inferExitCodes(asyncKind) {
|
|
570
|
+
return {
|
|
571
|
+
ok: 0,
|
|
572
|
+
usage: 1,
|
|
573
|
+
error: 2,
|
|
574
|
+
transient: 3,
|
|
575
|
+
...(asyncKind !== "none" ? { longRunningFailure: 4, } : {}),
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
function cleanupCommandFromDeleteUsage(resource, action) {
|
|
579
|
+
if (!(action.startsWith("create") || action === "clone"))
|
|
580
|
+
return undefined;
|
|
581
|
+
const deleteAction = action === "create-rule" ? "delete-rule" : "delete";
|
|
582
|
+
const deleteUsage = commands[resource]?.[deleteAction]?.usage;
|
|
583
|
+
if (!deleteUsage)
|
|
584
|
+
return undefined;
|
|
585
|
+
const base = stripOptionalUsageGroups(deleteUsage).replace(/\s+/g, " ").trim();
|
|
586
|
+
if (deleteUsage.includes("--if-exists"))
|
|
587
|
+
return `${base} --if-exists`;
|
|
588
|
+
return base;
|
|
589
|
+
}
|
|
590
|
+
export function supportsCleanupLedger(resource, action) {
|
|
591
|
+
return cleanupCommandFromDeleteUsage(resource, action) !== undefined
|
|
592
|
+
|| `${resource}.${action}` === "folder.upload";
|
|
593
|
+
}
|
|
594
|
+
function inferDestructiveLevel(sideEffect, action) {
|
|
595
|
+
if (sideEffect !== "write")
|
|
596
|
+
return "none";
|
|
597
|
+
if (/^(delete|abort|clear|unload|logout)/.test(action))
|
|
598
|
+
return "destructive";
|
|
599
|
+
return "reversible";
|
|
600
|
+
}
|
|
601
|
+
function inferAsyncKind(resource, action) {
|
|
602
|
+
if (resource === "job" && ["build", "build-and-wait", "wait", "monitor", "watch",].includes(action)) {
|
|
603
|
+
return "job";
|
|
604
|
+
}
|
|
605
|
+
if (resource === "recipe" && action === "run")
|
|
606
|
+
return "job";
|
|
607
|
+
if (resource === "future" && ["get", "peek", "wait", "abort",].includes(action))
|
|
608
|
+
return "future";
|
|
609
|
+
if (resource === "scenario" && ["run", "run-and-wait", "status",].includes(action)) {
|
|
610
|
+
return "future";
|
|
611
|
+
}
|
|
612
|
+
if (resource === "data-quality" && action === "compute")
|
|
613
|
+
return "future";
|
|
614
|
+
if (resource === "code" && action === "run")
|
|
615
|
+
return "future";
|
|
616
|
+
return "none";
|
|
617
|
+
}
|
|
618
|
+
function inferIdempotency(sideEffect, action, usage) {
|
|
619
|
+
if (sideEffect === "read")
|
|
620
|
+
return "safe";
|
|
621
|
+
if (action.startsWith("create") && usage.includes("--if-not-exists"))
|
|
622
|
+
return "if-not-exists";
|
|
623
|
+
if (action.startsWith("delete") && usage.includes("--if-exists"))
|
|
624
|
+
return "if-exists";
|
|
625
|
+
if (/^(clear|refresh|set|save)/.test(action))
|
|
626
|
+
return "convergent";
|
|
627
|
+
return "none";
|
|
628
|
+
}
|
|
629
|
+
export function inferCleanupHint(resource, action) {
|
|
630
|
+
if (!(action.startsWith("create") || action === "clone"))
|
|
631
|
+
return undefined;
|
|
632
|
+
const deleteAction = action === "create-rule" ? "delete-rule" : "delete";
|
|
633
|
+
const deleteUsage = commands[resource]?.[deleteAction]?.usage;
|
|
634
|
+
const ifExists = deleteUsage?.includes("--if-exists") ? " --if-exists" : "";
|
|
635
|
+
if (resource === "code-env") {
|
|
636
|
+
return `Delete with \`dss code-env delete <lang> <name>${ifExists}\`.`;
|
|
637
|
+
}
|
|
638
|
+
if (resource === "data-quality") {
|
|
639
|
+
return `Delete with \`dss data-quality delete-rule <dataset> <rule-id>${ifExists}\`.`;
|
|
640
|
+
}
|
|
641
|
+
return `Delete with \`dss ${resource} delete <id>${ifExists}\` when the created object is disposable.`;
|
|
642
|
+
}
|
|
643
|
+
function buildRegistryEntry(resource, action, meta) {
|
|
644
|
+
const requiresAuth = inferRequiresAuth(resource);
|
|
645
|
+
const requiresProject = inferRequiresProject(resource, action, meta.usage);
|
|
646
|
+
const sideEffect = inferSideEffect(resource, action);
|
|
647
|
+
const destructive = inferDestructiveLevel(sideEffect, action);
|
|
648
|
+
const asyncKind = inferAsyncKind(resource, action);
|
|
649
|
+
const mutatesDss = sideEffect === "write" && resource !== "auth" && resource !== "install-skill";
|
|
650
|
+
const supportsPlan = mutatesDss || sideEffect === "write";
|
|
651
|
+
const supportsCleanup = supportsCleanupLedger(resource, action);
|
|
652
|
+
const usageFlags = extractUsageFlags(meta.usage);
|
|
653
|
+
const flags = uniqueStrings([
|
|
654
|
+
...usageFlags,
|
|
655
|
+
...(supportsPlan ? ["plan",] : []),
|
|
656
|
+
...(supportsCleanup ? ["record-cleanup",] : []),
|
|
657
|
+
...GLOBAL_AGENT_FLAGS,
|
|
658
|
+
...(requiresAuth ? AUTHENTICATED_AGENT_FLAGS : []),
|
|
659
|
+
...(requiresProject ? ["project-key",] : []),
|
|
660
|
+
]);
|
|
661
|
+
const derivedRequired = deriveRequiredUsage(meta.usage);
|
|
662
|
+
const requiredFlags = meta.requiredFlags
|
|
663
|
+
?? EXPLICIT_REGISTRY_OVERRIDES[registryKey(resource, action)]?.requiredFlags
|
|
664
|
+
?? derivedRequired.requiredFlags;
|
|
665
|
+
const requiredOneOf = meta.requiredOneOf
|
|
666
|
+
?? EXPLICIT_REGISTRY_OVERRIDES[registryKey(resource, action)]?.requiredOneOf
|
|
667
|
+
?? derivedRequired.requiredOneOf;
|
|
668
|
+
const oneOfFlags = new Set(requiredOneOf.flatMap((choice) => choice.oneOf.flat()));
|
|
669
|
+
const optionalFlags = meta.optionalFlags
|
|
670
|
+
?? EXPLICIT_REGISTRY_OVERRIDES[registryKey(resource, action)]?.optionalFlags
|
|
671
|
+
?? flags.filter((flag) => !requiredFlags.includes(flag) && !oneOfFlags.has(flag));
|
|
672
|
+
const valueHints = extractFlagValueHints(meta.usage);
|
|
673
|
+
const inputContract = inferInputContract(meta.usage);
|
|
674
|
+
const cleanupHint = inferCleanupHint(resource, action);
|
|
675
|
+
const payloadSchema = meta.payloadSchema
|
|
676
|
+
?? EXPLICIT_REGISTRY_OVERRIDES[registryKey(resource, action)]?.payloadSchema
|
|
677
|
+
?? inferPayloadSchema(inputContract);
|
|
678
|
+
const examplePayload = meta.examplePayload
|
|
679
|
+
?? EXPLICIT_REGISTRY_OVERRIDES[registryKey(resource, action)]?.examplePayload;
|
|
680
|
+
const cleanupCommand = meta.cleanupCommand
|
|
681
|
+
?? EXPLICIT_REGISTRY_OVERRIDES[registryKey(resource, action)]?.cleanupCommand
|
|
682
|
+
?? cleanupCommandFromDeleteUsage(resource, action);
|
|
683
|
+
const flagMetadata = flags.map((name) => {
|
|
684
|
+
const aliases = Object.entries(FLAG_ALIASES)
|
|
685
|
+
.filter(([raw, canonical,]) => canonical === name && new RegExp(`--${raw}(?![a-z0-9-])`).test(meta.usage))
|
|
686
|
+
.map(([raw,]) => raw);
|
|
687
|
+
const aliasPart = aliases.length > 0 ? { aliases, } : {};
|
|
688
|
+
const kind = flagKind(name);
|
|
689
|
+
if (kind === "boolean")
|
|
690
|
+
return { name, kind, ...aliasPart, };
|
|
691
|
+
const hint = valueHints.get(name) ?? GLOBAL_FLAG_VALUE_HINTS[name];
|
|
692
|
+
if (!hint)
|
|
693
|
+
return { name, kind, ...aliasPart, };
|
|
694
|
+
return {
|
|
695
|
+
name,
|
|
696
|
+
kind,
|
|
697
|
+
valueType: hint.valueType,
|
|
698
|
+
...(hint.enumValues ? { enumValues: hint.enumValues, } : {}),
|
|
699
|
+
...aliasPart,
|
|
700
|
+
};
|
|
701
|
+
});
|
|
702
|
+
const positionals = extractPositionals(meta.usage);
|
|
703
|
+
const outputShape = inferOutputShape(resource, action);
|
|
704
|
+
const producesLocalFile = meta.usage.includes("--output PATH")
|
|
705
|
+
|| meta.usage.includes("--output-file PATH");
|
|
706
|
+
const uniqueRequiredFlags = uniqueStrings(requiredFlags);
|
|
707
|
+
const uniqueOptionalFlags = uniqueStrings(optionalFlags);
|
|
708
|
+
const unsafe = unsafeOutputs(resource, action, flagMetadata, producesLocalFile);
|
|
709
|
+
return {
|
|
710
|
+
resource,
|
|
711
|
+
action,
|
|
712
|
+
usage: meta.usage,
|
|
713
|
+
description: meta.description,
|
|
714
|
+
examples: meta.examples,
|
|
715
|
+
structuredExamples: structuredExamples(meta.examples, examplePayload),
|
|
716
|
+
flags: flagMetadata,
|
|
717
|
+
positionals,
|
|
718
|
+
sideEffect,
|
|
719
|
+
requiresAuth,
|
|
720
|
+
requiresProject,
|
|
721
|
+
outputShape,
|
|
722
|
+
inputContract,
|
|
723
|
+
destructive,
|
|
724
|
+
producesLocalFile,
|
|
725
|
+
mutatesDss,
|
|
726
|
+
async: asyncKind,
|
|
727
|
+
idempotency: inferIdempotency(sideEffect, action, meta.usage),
|
|
728
|
+
dryRun: meta.usage.includes("--dry-run"),
|
|
729
|
+
requiredFlags: uniqueRequiredFlags,
|
|
730
|
+
optionalFlags: uniqueOptionalFlags,
|
|
731
|
+
...(requiredOneOf.length > 0 ? { requiredOneOf, } : {}),
|
|
732
|
+
...(payloadSchema ? { payloadSchema, } : {}),
|
|
733
|
+
schemas: buildCommandSchemas(resource, action, flagMetadata, positionals, uniqueRequiredFlags, requiredOneOf, payloadSchema, outputShape),
|
|
734
|
+
...(unsafe ? { unsafeOutputs: unsafe, } : {}),
|
|
735
|
+
...(examplePayload !== undefined ? { examplePayload, } : {}),
|
|
736
|
+
...(cleanupCommand ? { cleanupCommand, } : {}),
|
|
737
|
+
exitCodes: inferExitCodes(asyncKind),
|
|
738
|
+
...(cleanupHint ? { cleanupHint, } : {}),
|
|
739
|
+
agentContractVersion: AGENT_CONTRACT_VERSION,
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
export function buildCommandRegistry() {
|
|
743
|
+
const registry = {};
|
|
744
|
+
for (const [resource, actions,] of Object.entries(commands)) {
|
|
745
|
+
registry[resource] = {};
|
|
746
|
+
for (const [action, meta,] of Object.entries(actions)) {
|
|
747
|
+
registry[resource][action] = buildRegistryEntry(resource, action, meta);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
registry.commands = {
|
|
751
|
+
run: buildRegistryEntry("commands", "run", {
|
|
752
|
+
handler: async () => undefined,
|
|
753
|
+
usage: COMMANDS_USAGE,
|
|
754
|
+
description: COMMANDS_DESCRIPTION,
|
|
755
|
+
examples: COMMANDS_EXAMPLES,
|
|
756
|
+
}),
|
|
757
|
+
};
|
|
758
|
+
registry.agent = {
|
|
759
|
+
contract: buildRegistryEntry("agent", "contract", {
|
|
760
|
+
handler: async () => undefined,
|
|
761
|
+
usage: AGENT_CONTRACT_USAGE,
|
|
762
|
+
description: AGENT_CONTRACT_DESCRIPTION,
|
|
763
|
+
examples: AGENT_CONTRACT_EXAMPLES,
|
|
764
|
+
}),
|
|
765
|
+
};
|
|
766
|
+
registry.version = {
|
|
767
|
+
run: buildRegistryEntry("version", "run", {
|
|
768
|
+
handler: async () => undefined,
|
|
769
|
+
usage: VERSION_USAGE,
|
|
770
|
+
description: VERSION_DESCRIPTION,
|
|
771
|
+
examples: VERSION_EXAMPLES,
|
|
772
|
+
}),
|
|
773
|
+
};
|
|
774
|
+
registry["install-skill"] = {
|
|
775
|
+
run: buildRegistryEntry("install-skill", "run", {
|
|
776
|
+
handler: async () => undefined,
|
|
777
|
+
usage: INSTALL_SKILL_USAGE,
|
|
778
|
+
description: INSTALL_SKILL_DESCRIPTION,
|
|
779
|
+
examples: INSTALL_SKILL_EXAMPLES,
|
|
780
|
+
}),
|
|
781
|
+
};
|
|
782
|
+
registry.cleanup = {
|
|
783
|
+
run: buildRegistryEntry("cleanup", "run", {
|
|
784
|
+
handler: async () => undefined,
|
|
785
|
+
usage: CLEANUP_USAGE,
|
|
786
|
+
description: CLEANUP_DESCRIPTION,
|
|
787
|
+
examples: CLEANUP_EXAMPLES,
|
|
788
|
+
}),
|
|
789
|
+
};
|
|
790
|
+
registry.fixtures = {
|
|
791
|
+
run: buildRegistryEntry("fixtures", "run", {
|
|
792
|
+
handler: async () => undefined,
|
|
793
|
+
usage: FIXTURES_USAGE,
|
|
794
|
+
description: FIXTURES_DESCRIPTION,
|
|
795
|
+
examples: FIXTURES_EXAMPLES,
|
|
796
|
+
}),
|
|
797
|
+
};
|
|
798
|
+
registry.batch = {
|
|
799
|
+
run: buildRegistryEntry("batch", "run", {
|
|
800
|
+
handler: async () => undefined,
|
|
801
|
+
usage: BATCH_USAGE,
|
|
802
|
+
description: BATCH_DESCRIPTION,
|
|
803
|
+
examples: BATCH_EXAMPLES,
|
|
804
|
+
examplePayload: BATCH_EXAMPLE_PAYLOAD,
|
|
805
|
+
payloadSchema: { stdin: true, dataFlag: true, dataFileFlag: true, jsonShape: "array", },
|
|
806
|
+
}),
|
|
807
|
+
};
|
|
808
|
+
registry.auth = {};
|
|
809
|
+
for (const [action, meta,] of Object.entries(AUTH_ACTIONS)) {
|
|
810
|
+
registry.auth[action] = buildRegistryEntry("auth", action, {
|
|
811
|
+
handler: async () => undefined,
|
|
812
|
+
usage: meta.usage,
|
|
813
|
+
description: meta.description,
|
|
814
|
+
examples: meta.examples,
|
|
815
|
+
requiredFlags: meta.requiredFlags,
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
return registry;
|
|
819
|
+
}
|
|
820
|
+
function commandFlagJsonSchema() {
|
|
821
|
+
return {
|
|
822
|
+
type: "object",
|
|
823
|
+
required: ["name", "kind",],
|
|
824
|
+
additionalProperties: false,
|
|
825
|
+
properties: {
|
|
826
|
+
name: { type: "string", },
|
|
827
|
+
kind: { enum: ["boolean", "value",], },
|
|
828
|
+
valueType: { type: "string", },
|
|
829
|
+
enumValues: { type: "array", items: { type: "string", }, },
|
|
830
|
+
aliases: { type: "array", items: { type: "string", }, },
|
|
831
|
+
},
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
function commandRegistryEntryJsonSchema() {
|
|
835
|
+
return {
|
|
836
|
+
type: "object",
|
|
837
|
+
required: [
|
|
838
|
+
"resource",
|
|
839
|
+
"action",
|
|
840
|
+
"usage",
|
|
841
|
+
"flags",
|
|
842
|
+
"positionals",
|
|
843
|
+
"sideEffect",
|
|
844
|
+
"requiresAuth",
|
|
845
|
+
"requiresProject",
|
|
846
|
+
"outputShape",
|
|
847
|
+
"inputContract",
|
|
848
|
+
"schemas",
|
|
849
|
+
"exitCodes",
|
|
850
|
+
"agentContractVersion",
|
|
851
|
+
],
|
|
852
|
+
additionalProperties: true,
|
|
853
|
+
properties: {
|
|
854
|
+
resource: { type: "string", },
|
|
855
|
+
action: { type: "string", },
|
|
856
|
+
usage: { type: "string", },
|
|
857
|
+
description: { type: "string", },
|
|
858
|
+
examples: { type: "array", items: { type: "string", }, },
|
|
859
|
+
structuredExamples: { type: "array", items: { type: "object", additionalProperties: true, }, },
|
|
860
|
+
flags: { type: "array", items: commandFlagJsonSchema(), },
|
|
861
|
+
positionals: { type: "array", items: { type: "string", }, },
|
|
862
|
+
sideEffect: { enum: ["read", "write", "auth",], },
|
|
863
|
+
requiresAuth: { type: "boolean", },
|
|
864
|
+
requiresProject: { type: "boolean", },
|
|
865
|
+
outputShape: { enum: ["object", "array", "string", "void",], },
|
|
866
|
+
inputContract: { type: "object", additionalProperties: { type: "boolean", }, },
|
|
867
|
+
destructive: { enum: ["none", "reversible", "destructive",], },
|
|
868
|
+
producesLocalFile: { type: "boolean", },
|
|
869
|
+
mutatesDss: { type: "boolean", },
|
|
870
|
+
async: { enum: ["none", "job", "future",], },
|
|
871
|
+
idempotency: { enum: ["safe", "convergent", "if-not-exists", "if-exists", "none",], },
|
|
872
|
+
dryRun: { type: "boolean", },
|
|
873
|
+
requiredFlags: { type: "array", items: { type: "string", }, },
|
|
874
|
+
optionalFlags: { type: "array", items: { type: "string", }, },
|
|
875
|
+
schemas: { type: "object", additionalProperties: true, },
|
|
876
|
+
unsafeOutputs: { type: "array", items: { type: "object", additionalProperties: true, }, },
|
|
877
|
+
exitCodes: { type: "object", additionalProperties: { type: "number", }, },
|
|
878
|
+
agentContractVersion: { const: AGENT_CONTRACT_VERSION, },
|
|
879
|
+
},
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
function commandRegistryJsonSchema() {
|
|
883
|
+
return {
|
|
884
|
+
$schema: JSON_SCHEMA_DRAFT,
|
|
885
|
+
type: "object",
|
|
886
|
+
additionalProperties: {
|
|
887
|
+
type: "object",
|
|
888
|
+
additionalProperties: commandRegistryEntryJsonSchema(),
|
|
889
|
+
},
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
function errorEnvelopeJsonSchema() {
|
|
893
|
+
return {
|
|
894
|
+
type: "object",
|
|
895
|
+
required: ["type", "ok", "error", "code", "category", "exitCode",],
|
|
896
|
+
additionalProperties: true,
|
|
897
|
+
properties: {
|
|
898
|
+
type: { const: "error", },
|
|
899
|
+
ok: { const: false, },
|
|
900
|
+
error: { type: "string", },
|
|
901
|
+
code: { type: "string", },
|
|
902
|
+
category: { enum: ["usage", "dss", "internal",], },
|
|
903
|
+
exitCode: { type: "number", },
|
|
904
|
+
resource: { type: "string", },
|
|
905
|
+
action: { type: "string", },
|
|
906
|
+
projectKey: { type: "string", },
|
|
907
|
+
},
|
|
908
|
+
};
|
|
909
|
+
}
|
|
910
|
+
function warningEventJsonSchema() {
|
|
911
|
+
return {
|
|
912
|
+
type: "object",
|
|
913
|
+
required: ["type", "warnings",],
|
|
914
|
+
additionalProperties: false,
|
|
915
|
+
properties: {
|
|
916
|
+
type: { const: "warning", },
|
|
917
|
+
warnings: { type: "array", items: { type: "object", additionalProperties: true, }, },
|
|
918
|
+
},
|
|
919
|
+
};
|
|
920
|
+
}
|
|
921
|
+
function traceEventJsonSchema() {
|
|
922
|
+
return {
|
|
923
|
+
type: "object",
|
|
924
|
+
required: ["type", "phase", "method", "url", "attempt", "maxAttempts",],
|
|
925
|
+
additionalProperties: false,
|
|
926
|
+
properties: {
|
|
927
|
+
type: { const: "trace", },
|
|
928
|
+
phase: { enum: ["request", "response", "error",], },
|
|
929
|
+
method: { type: "string", },
|
|
930
|
+
url: { type: "string", },
|
|
931
|
+
attempt: { type: "number", },
|
|
932
|
+
maxAttempts: { type: "number", },
|
|
933
|
+
status: { type: "number", },
|
|
934
|
+
elapsedMs: { type: "number", },
|
|
935
|
+
detail: { type: "string", },
|
|
936
|
+
},
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
export function agentContractJsonSchema() {
|
|
940
|
+
return {
|
|
941
|
+
$schema: JSON_SCHEMA_DRAFT,
|
|
942
|
+
$id: AGENT_CONTRACT_SCHEMA_ID,
|
|
943
|
+
type: "object",
|
|
944
|
+
required: ["protocol", "agentContractVersion", "cli", "commands", "schemas", "stdio",],
|
|
945
|
+
additionalProperties: true,
|
|
946
|
+
properties: {
|
|
947
|
+
protocol: { const: "dataiku-sdk-agent", },
|
|
948
|
+
agentContractVersion: { const: AGENT_CONTRACT_VERSION, },
|
|
949
|
+
cli: { type: "object", additionalProperties: true, },
|
|
950
|
+
commands: { type: "object", additionalProperties: true, },
|
|
951
|
+
schemas: { type: "object", additionalProperties: true, },
|
|
952
|
+
stdio: { type: "object", additionalProperties: true, },
|
|
953
|
+
},
|
|
954
|
+
};
|
|
955
|
+
}
|
|
956
|
+
function commandActionSummary(registry) {
|
|
957
|
+
const summary = {};
|
|
958
|
+
for (const [resource, actions,] of Object.entries(registry)) {
|
|
959
|
+
summary[resource] = Object.keys(actions).sort();
|
|
960
|
+
}
|
|
961
|
+
return summary;
|
|
962
|
+
}
|
|
963
|
+
export function buildAgentContract() {
|
|
964
|
+
const registry = buildCommandRegistry();
|
|
965
|
+
return {
|
|
966
|
+
protocol: "dataiku-sdk-agent",
|
|
967
|
+
agentContractVersion: AGENT_CONTRACT_VERSION,
|
|
968
|
+
cli: cliVersionResult(),
|
|
969
|
+
commands: {
|
|
970
|
+
discoveryCommand: "dss commands run",
|
|
971
|
+
actions: commandActionSummary(registry),
|
|
972
|
+
},
|
|
973
|
+
schemas: {
|
|
974
|
+
agentContract: agentContractJsonSchema(),
|
|
975
|
+
commandRegistry: commandRegistryJsonSchema(),
|
|
976
|
+
commandRegistryEntry: commandRegistryEntryJsonSchema(),
|
|
977
|
+
errorEnvelope: errorEnvelopeJsonSchema(),
|
|
978
|
+
warningEvent: warningEventJsonSchema(),
|
|
979
|
+
traceEvent: traceEventJsonSchema(),
|
|
980
|
+
},
|
|
981
|
+
stdio: {
|
|
982
|
+
stdout: {
|
|
983
|
+
success: "single-json-value",
|
|
984
|
+
rawEscapeHatches: [
|
|
985
|
+
"recipe get-payload --raw without --output",
|
|
986
|
+
"recipe cat --raw without --output",
|
|
987
|
+
],
|
|
988
|
+
},
|
|
989
|
+
stderr: {
|
|
990
|
+
format: "jsonl",
|
|
991
|
+
events: ["warning", "trace", "error",],
|
|
992
|
+
error: "single-final-error-event-on-nonzero-exit",
|
|
993
|
+
},
|
|
994
|
+
},
|
|
995
|
+
planning: {
|
|
996
|
+
discoveryCommand: "dss commands run",
|
|
997
|
+
contractCommand: AGENT_CONTRACT_USAGE,
|
|
998
|
+
mutatingCommandsAdvertisePlan: true,
|
|
999
|
+
},
|
|
1000
|
+
compatibility: {
|
|
1001
|
+
fieldsAreAdditiveWithinMajor: true,
|
|
1002
|
+
failFastWhenUnsupported: "Check agentContractVersion before planning commands.",
|
|
1003
|
+
},
|
|
1004
|
+
};
|
|
1005
|
+
}
|
|
1006
|
+
function exitCodesOnFailure(entry) {
|
|
1007
|
+
return {
|
|
1008
|
+
usage: entry.exitCodes.usage,
|
|
1009
|
+
error: entry.exitCodes.error,
|
|
1010
|
+
transient: entry.exitCodes.transient,
|
|
1011
|
+
...(entry.exitCodes.longRunningFailure !== undefined
|
|
1012
|
+
? { longRunningFailure: entry.exitCodes.longRunningFailure, }
|
|
1013
|
+
: {}),
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
function projectKeyForPlan(entry, flags) {
|
|
1017
|
+
if (!entry.requiresProject)
|
|
1018
|
+
return undefined;
|
|
1019
|
+
const projectKey = resolveCredentials(flags).projectKey;
|
|
1020
|
+
if (projectKey)
|
|
1021
|
+
return projectKey;
|
|
1022
|
+
throw new UsageError(`Missing project key. Pass --project-key or set DATAIKU_PROJECT_KEY before planning ${entry.resource} ${entry.action}.`);
|
|
1023
|
+
}
|
|
1024
|
+
function requiredPlanFlag(flags, name, usage) {
|
|
1025
|
+
const value = flags[name];
|
|
1026
|
+
if (typeof value === "string" && value.trim().length > 0)
|
|
1027
|
+
return value;
|
|
1028
|
+
throw new UsageError(`--${name} is required. Usage: ${usage}`);
|
|
1029
|
+
}
|
|
1030
|
+
function optionalJsonFlag(flags, name) {
|
|
1031
|
+
const value = flags[name];
|
|
1032
|
+
return typeof value === "string" ? parseJsonObject(value, `--${name}`) : undefined;
|
|
1033
|
+
}
|
|
1034
|
+
function requiredPlanJsonInput(flags, usage) {
|
|
1035
|
+
return requiredJsonInput(flags, `--data, --data-file, or --stdin is required. Usage: ${usage}`);
|
|
1036
|
+
}
|
|
1037
|
+
function requiredPlanPositionals(usage) {
|
|
1038
|
+
return [...stripOptionalUsageGroups(usage).matchAll(/<([^>]+)>/g),].map((match) => match[1]);
|
|
1039
|
+
}
|
|
1040
|
+
function dataQualityEndpoint(projectKey, datasetName, suffix) {
|
|
1041
|
+
return encodedProjectEndpointForPlan(projectKey, `/datasets/${encodeURIComponent(datasetName)}/data-quality${suffix}`);
|
|
1042
|
+
}
|
|
1043
|
+
function querySuffix(params) {
|
|
1044
|
+
const search = new URLSearchParams();
|
|
1045
|
+
for (const [key, value,] of Object.entries(params)) {
|
|
1046
|
+
if (value !== undefined)
|
|
1047
|
+
search.set(key, String(value));
|
|
1048
|
+
}
|
|
1049
|
+
const raw = search.toString();
|
|
1050
|
+
return raw ? `?${raw}` : "";
|
|
1051
|
+
}
|
|
1052
|
+
function jobBuildPayload(target, projectKey, flags) {
|
|
1053
|
+
const targetType = jobBuildTargetTypeFromFlags(flags);
|
|
1054
|
+
const partition = flags["partition"];
|
|
1055
|
+
const output = { projectKey, id: target, type: targetType, };
|
|
1056
|
+
if (targetType === "DATASET") {
|
|
1057
|
+
if (partition !== undefined)
|
|
1058
|
+
output.partition = partition;
|
|
1059
|
+
}
|
|
1060
|
+
else {
|
|
1061
|
+
output.targetManagedFolderProjectKey = projectKey;
|
|
1062
|
+
output.targetManagedFolder = target;
|
|
1063
|
+
output.targetPartition = partition ?? "NP";
|
|
1064
|
+
}
|
|
1065
|
+
const payload = {
|
|
1066
|
+
outputs: [output,],
|
|
1067
|
+
type: flags["build-mode"] ?? "NON_RECURSIVE_FORCED_BUILD",
|
|
1068
|
+
};
|
|
1069
|
+
if (flags["force-rebuild"] === true && targetType === "DATASET") {
|
|
1070
|
+
payload.autoUpdateSchemaBeforeEachRecipeRun = true;
|
|
1071
|
+
}
|
|
1072
|
+
return payload;
|
|
1073
|
+
}
|
|
1074
|
+
function uploadPayload(filePath) {
|
|
1075
|
+
return {
|
|
1076
|
+
contentType: "multipart/form-data",
|
|
1077
|
+
fileField: "file",
|
|
1078
|
+
filePath,
|
|
1079
|
+
fileName: path.basename(filePath),
|
|
1080
|
+
};
|
|
1081
|
+
}
|
|
1082
|
+
export function commandPlanShape(resource, action, args, flags, entry, projectKey) {
|
|
1083
|
+
const projectEndpoint = (suffix) => {
|
|
1084
|
+
if (!projectKey)
|
|
1085
|
+
throw new UsageError(`Missing project key for ${resource} ${action}.`);
|
|
1086
|
+
return encodedProjectEndpointForPlan(projectKey, suffix);
|
|
1087
|
+
};
|
|
1088
|
+
const id = args[0];
|
|
1089
|
+
const codeEnvEndpoint = (suffix = "") => `/public/api/admin/code-envs/${encodeURIComponent(args[0])}/${encodeURIComponent(args[1])}${suffix}`;
|
|
1090
|
+
const statisticsWorksheetsEndpoint = (datasetName) => projectEndpoint(`/datasets/${encodeURIComponent(datasetName)}/statistics/worksheets/`);
|
|
1091
|
+
const statisticsWorksheetEndpoint = (datasetName, worksheetId) => `${statisticsWorksheetsEndpoint(datasetName)}${encodeURIComponent(worksheetId)}`;
|
|
1092
|
+
switch (`${resource}.${action}`) {
|
|
1093
|
+
case "wiki.create": {
|
|
1094
|
+
const name = requiredPlanFlag(flags, "name", entry.usage);
|
|
1095
|
+
return {
|
|
1096
|
+
method: "POST",
|
|
1097
|
+
endpoint: projectEndpoint("/wiki/"),
|
|
1098
|
+
identifiers: { name, },
|
|
1099
|
+
payload: {
|
|
1100
|
+
projectKey,
|
|
1101
|
+
name,
|
|
1102
|
+
parent: flags["parent"] ?? null,
|
|
1103
|
+
content: textInput(flags),
|
|
1104
|
+
},
|
|
1105
|
+
};
|
|
1106
|
+
}
|
|
1107
|
+
case "wiki.update":
|
|
1108
|
+
return {
|
|
1109
|
+
method: "PUT",
|
|
1110
|
+
endpoint: projectEndpoint(`/wiki/${encodeURIComponent(id)}`),
|
|
1111
|
+
identifiers: { article: id, },
|
|
1112
|
+
payload: {
|
|
1113
|
+
...jsonInput(flags),
|
|
1114
|
+
name: flags["name"],
|
|
1115
|
+
content: textInput(flags),
|
|
1116
|
+
},
|
|
1117
|
+
};
|
|
1118
|
+
case "wiki.delete":
|
|
1119
|
+
return {
|
|
1120
|
+
method: "DELETE",
|
|
1121
|
+
endpoint: projectEndpoint(`/wiki/${encodeURIComponent(id)}`),
|
|
1122
|
+
identifiers: { article: id, },
|
|
1123
|
+
};
|
|
1124
|
+
case "dashboard.create": {
|
|
1125
|
+
const name = requiredPlanFlag(flags, "name", entry.usage);
|
|
1126
|
+
return {
|
|
1127
|
+
method: "POST",
|
|
1128
|
+
endpoint: projectEndpoint("/dashboards/"),
|
|
1129
|
+
identifiers: { name, },
|
|
1130
|
+
payload: { ...(jsonInput(flags) ?? { pages: [], }), name, },
|
|
1131
|
+
};
|
|
1132
|
+
}
|
|
1133
|
+
case "dashboard.update": {
|
|
1134
|
+
const payload = { ...jsonInput(flags), };
|
|
1135
|
+
if (typeof flags["name"] === "string")
|
|
1136
|
+
payload.name = flags["name"];
|
|
1137
|
+
return {
|
|
1138
|
+
method: "PUT",
|
|
1139
|
+
endpoint: projectEndpoint(`/dashboards/${encodeURIComponent(id)}/`),
|
|
1140
|
+
identifiers: { id, },
|
|
1141
|
+
payload,
|
|
1142
|
+
};
|
|
1143
|
+
}
|
|
1144
|
+
case "dashboard.delete":
|
|
1145
|
+
return {
|
|
1146
|
+
method: "DELETE",
|
|
1147
|
+
endpoint: projectEndpoint(`/dashboards/${encodeURIComponent(id)}/`),
|
|
1148
|
+
identifiers: { id, },
|
|
1149
|
+
};
|
|
1150
|
+
case "insight.create": {
|
|
1151
|
+
const data = jsonInput(flags);
|
|
1152
|
+
const name = flags["name"];
|
|
1153
|
+
const type = flags["type"];
|
|
1154
|
+
if (!data && (!name || !type)) {
|
|
1155
|
+
throw new UsageError("--data or both --name and --type are required. Usage: dss insight create --name NAME --type TYPE");
|
|
1156
|
+
}
|
|
1157
|
+
const prototype = { ...data, };
|
|
1158
|
+
if (name !== undefined)
|
|
1159
|
+
prototype.name = name;
|
|
1160
|
+
if (type !== undefined)
|
|
1161
|
+
prototype.type = type;
|
|
1162
|
+
const listed = parseBooleanOption(flags["listed"], "--listed");
|
|
1163
|
+
if (listed !== undefined)
|
|
1164
|
+
prototype.listed = listed;
|
|
1165
|
+
const params = optionalJsonFlag(flags, "params");
|
|
1166
|
+
if (params !== undefined)
|
|
1167
|
+
prototype.params = params;
|
|
1168
|
+
return {
|
|
1169
|
+
method: "POST",
|
|
1170
|
+
endpoint: projectEndpoint("/insights/"),
|
|
1171
|
+
identifiers: { name, type, },
|
|
1172
|
+
payload: {
|
|
1173
|
+
insightPrototype: prototype,
|
|
1174
|
+
contentType: flags["content-type"],
|
|
1175
|
+
payload: textInput(flags),
|
|
1176
|
+
},
|
|
1177
|
+
};
|
|
1178
|
+
}
|
|
1179
|
+
case "insight.update":
|
|
1180
|
+
return {
|
|
1181
|
+
method: "POST",
|
|
1182
|
+
endpoint: projectEndpoint(`/insights/${encodeURIComponent(id)}/`),
|
|
1183
|
+
identifiers: { id, },
|
|
1184
|
+
payload: {
|
|
1185
|
+
insight: {
|
|
1186
|
+
...jsonInput(flags),
|
|
1187
|
+
name: flags["name"],
|
|
1188
|
+
listed: parseBooleanOption(flags["listed"], "--listed"),
|
|
1189
|
+
params: optionalJsonFlag(flags, "params"),
|
|
1190
|
+
},
|
|
1191
|
+
contentType: flags["content-type"],
|
|
1192
|
+
payload: textInput(flags),
|
|
1193
|
+
},
|
|
1194
|
+
};
|
|
1195
|
+
case "insight.delete":
|
|
1196
|
+
return {
|
|
1197
|
+
method: "DELETE",
|
|
1198
|
+
endpoint: projectEndpoint(`/insights/${encodeURIComponent(id)}/`),
|
|
1199
|
+
identifiers: { id, },
|
|
1200
|
+
};
|
|
1201
|
+
case "data-quality.create-rule":
|
|
1202
|
+
return {
|
|
1203
|
+
method: "POST",
|
|
1204
|
+
endpoint: dataQualityEndpoint(projectKey, args[0], "/rules"),
|
|
1205
|
+
identifiers: { dataset: args[0], },
|
|
1206
|
+
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
1207
|
+
};
|
|
1208
|
+
case "data-quality.update-rule":
|
|
1209
|
+
return {
|
|
1210
|
+
method: "PUT",
|
|
1211
|
+
endpoint: dataQualityEndpoint(projectKey, args[0], `/rules/${encodeURIComponent(args[1])}`),
|
|
1212
|
+
identifiers: { dataset: args[0], ruleId: args[1], },
|
|
1213
|
+
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
1214
|
+
};
|
|
1215
|
+
case "data-quality.delete-rule":
|
|
1216
|
+
return {
|
|
1217
|
+
method: "DELETE",
|
|
1218
|
+
endpoint: dataQualityEndpoint(projectKey, args[0], `/rules/${encodeURIComponent(args[1])}${querySuffix({ ruleId: args[1], })}`),
|
|
1219
|
+
identifiers: { dataset: args[0], ruleId: args[1], },
|
|
1220
|
+
};
|
|
1221
|
+
case "data-quality.compute":
|
|
1222
|
+
return {
|
|
1223
|
+
method: "POST",
|
|
1224
|
+
endpoint: dataQualityEndpoint(projectKey, args[0], `/actions/compute-rules${querySuffix({
|
|
1225
|
+
partition: flags["partition"] ?? "NP",
|
|
1226
|
+
ruleId: flags["rule-id"],
|
|
1227
|
+
})}`),
|
|
1228
|
+
identifiers: { dataset: args[0], ruleId: flags["rule-id"], },
|
|
1229
|
+
wait: flags["wait"] === true,
|
|
1230
|
+
};
|
|
1231
|
+
case "future.abort":
|
|
1232
|
+
return {
|
|
1233
|
+
method: "POST",
|
|
1234
|
+
endpoint: `/public/api/futures/${encodeURIComponent(id)}/abort`,
|
|
1235
|
+
identifiers: { id, },
|
|
1236
|
+
};
|
|
1237
|
+
case "flow-zone.create": {
|
|
1238
|
+
const name = flowZoneName(flags["name"]);
|
|
1239
|
+
const payload = { name, color: flowZoneColor(flags["color"]), projectKey, };
|
|
1240
|
+
return {
|
|
1241
|
+
method: "POST",
|
|
1242
|
+
endpoint: projectEndpoint("/flow/zones"),
|
|
1243
|
+
identifiers: { name, },
|
|
1244
|
+
payload,
|
|
1245
|
+
};
|
|
1246
|
+
}
|
|
1247
|
+
case "flow-zone.update":
|
|
1248
|
+
return {
|
|
1249
|
+
method: "PUT",
|
|
1250
|
+
endpoint: projectEndpoint(`/flow/zones/${encodeURIComponent(id)}`),
|
|
1251
|
+
identifiers: { id, },
|
|
1252
|
+
payload: {
|
|
1253
|
+
name: typeof flags["name"] === "string" ? flowZoneName(flags["name"]) : undefined,
|
|
1254
|
+
color: flowZoneColor(flags["color"]),
|
|
1255
|
+
projectKey,
|
|
1256
|
+
},
|
|
1257
|
+
};
|
|
1258
|
+
case "flow-zone.delete":
|
|
1259
|
+
return {
|
|
1260
|
+
method: "DELETE",
|
|
1261
|
+
endpoint: projectEndpoint(`/flow/zones/${encodeURIComponent(id)}`),
|
|
1262
|
+
identifiers: { id, },
|
|
1263
|
+
};
|
|
1264
|
+
case "flow-zone.move":
|
|
1265
|
+
return {
|
|
1266
|
+
method: "POST",
|
|
1267
|
+
endpoint: projectEndpoint(`/flow/zones/${encodeURIComponent(id)}/add-items`),
|
|
1268
|
+
identifiers: { id, },
|
|
1269
|
+
payload: flowZoneMoveItems(flags),
|
|
1270
|
+
};
|
|
1271
|
+
case "dataset.create": {
|
|
1272
|
+
const name = requiredPlanFlag(flags, "name", entry.usage);
|
|
1273
|
+
const connection = requiredPlanFlag(flags, "connection", entry.usage);
|
|
1274
|
+
const dsType = requiredPlanFlag(flags, "type", entry.usage);
|
|
1275
|
+
return {
|
|
1276
|
+
method: "POST",
|
|
1277
|
+
endpoint: projectEndpoint("/datasets/"),
|
|
1278
|
+
identifiers: { name, },
|
|
1279
|
+
payload: { datasetName: name, connection, dsType, projectKey, },
|
|
1280
|
+
};
|
|
1281
|
+
}
|
|
1282
|
+
case "dataset.delete":
|
|
1283
|
+
return {
|
|
1284
|
+
method: "DELETE",
|
|
1285
|
+
endpoint: projectEndpoint(`/datasets/${encodeURIComponent(id)}`),
|
|
1286
|
+
identifiers: { name: id, },
|
|
1287
|
+
};
|
|
1288
|
+
case "dataset.refresh-schema": {
|
|
1289
|
+
const columns = schemaColumnsInput(flags, entry.usage);
|
|
1290
|
+
return {
|
|
1291
|
+
method: "PUT",
|
|
1292
|
+
endpoint: projectEndpoint(`/datasets/${encodeURIComponent(id)}/schema`),
|
|
1293
|
+
identifiers: { name: id, },
|
|
1294
|
+
payload: { columns, },
|
|
1295
|
+
};
|
|
1296
|
+
}
|
|
1297
|
+
case "dataset.update":
|
|
1298
|
+
return {
|
|
1299
|
+
method: "PUT",
|
|
1300
|
+
endpoint: projectEndpoint(`/datasets/${encodeURIComponent(id)}`),
|
|
1301
|
+
identifiers: { name: id, },
|
|
1302
|
+
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
1303
|
+
};
|
|
1304
|
+
case "recipe.delete":
|
|
1305
|
+
return {
|
|
1306
|
+
method: "DELETE",
|
|
1307
|
+
endpoint: projectEndpoint(`/recipes/${encodeURIComponent(id)}`),
|
|
1308
|
+
identifiers: { name: id, },
|
|
1309
|
+
};
|
|
1310
|
+
case "recipe.create": {
|
|
1311
|
+
const type = requiredPlanFlag(flags, "type", entry.usage);
|
|
1312
|
+
const outputDataset = flags["output"];
|
|
1313
|
+
const outputFolder = flags["output-folder"];
|
|
1314
|
+
if (outputDataset && outputFolder) {
|
|
1315
|
+
throw new UsageError("--output and --output-folder are mutually exclusive.");
|
|
1316
|
+
}
|
|
1317
|
+
if (!outputDataset && !outputFolder) {
|
|
1318
|
+
throw new UsageError("--output or --output-folder is required.");
|
|
1319
|
+
}
|
|
1320
|
+
if (outputFolder && !flags["output-connection"]) {
|
|
1321
|
+
throw new UsageError("--output-connection is required when using --output-folder.");
|
|
1322
|
+
}
|
|
1323
|
+
return {
|
|
1324
|
+
method: "POST",
|
|
1325
|
+
endpoint: projectEndpoint("/recipes/"),
|
|
1326
|
+
identifiers: { name: flags["name"], },
|
|
1327
|
+
payload: {
|
|
1328
|
+
type,
|
|
1329
|
+
name: flags["name"],
|
|
1330
|
+
inputDatasets: flags["input"] ? [flags["input"],] : undefined,
|
|
1331
|
+
outputDataset,
|
|
1332
|
+
outputFolder,
|
|
1333
|
+
outputConnection: flags["output-connection"],
|
|
1334
|
+
projectKey,
|
|
1335
|
+
},
|
|
1336
|
+
};
|
|
1337
|
+
}
|
|
1338
|
+
case "recipe.run":
|
|
1339
|
+
return {
|
|
1340
|
+
method: "POST",
|
|
1341
|
+
endpoint: projectEndpoint("/jobs/"),
|
|
1342
|
+
identifiers: { recipe: id, },
|
|
1343
|
+
payload: {
|
|
1344
|
+
recipe: id,
|
|
1345
|
+
outputResolution: "dynamic",
|
|
1346
|
+
projectKey,
|
|
1347
|
+
partition: flags["partition"],
|
|
1348
|
+
},
|
|
1349
|
+
wait: recipeRunShouldWait(flags),
|
|
1350
|
+
};
|
|
1351
|
+
case "recipe.update":
|
|
1352
|
+
return {
|
|
1353
|
+
method: "PUT",
|
|
1354
|
+
endpoint: projectEndpoint(`/recipes/${encodeURIComponent(id)}`),
|
|
1355
|
+
identifiers: { name: id, },
|
|
1356
|
+
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
1357
|
+
};
|
|
1358
|
+
case "recipe.set-payload": {
|
|
1359
|
+
const file = requiredPlanFlag(flags, "file", entry.usage);
|
|
1360
|
+
const backupDir = flags["no-backup"] === true
|
|
1361
|
+
? undefined
|
|
1362
|
+
: flags["backup-dir"]
|
|
1363
|
+
?? path.join(process.cwd(), ".dss-backups", "recipes");
|
|
1364
|
+
const backupPath = backupDir ? recipeBackupPath(id, backupDir) : undefined;
|
|
1365
|
+
return {
|
|
1366
|
+
method: "PUT",
|
|
1367
|
+
endpoint: projectEndpoint(`/recipes/${encodeURIComponent(id)}`),
|
|
1368
|
+
identifiers: { name: id, },
|
|
1369
|
+
payload: {
|
|
1370
|
+
file,
|
|
1371
|
+
content: textInput(flags),
|
|
1372
|
+
...(backupPath ? { backupPath, } : {}),
|
|
1373
|
+
},
|
|
1374
|
+
...(backupPath
|
|
1375
|
+
? { localWrites: [{ path: backupPath, source: "remote recipe backup", before: "PUT", },], }
|
|
1376
|
+
: {}),
|
|
1377
|
+
};
|
|
1378
|
+
}
|
|
1379
|
+
case "job.build":
|
|
1380
|
+
case "job.build-and-wait":
|
|
1381
|
+
return {
|
|
1382
|
+
method: "POST",
|
|
1383
|
+
endpoint: projectEndpoint("/jobs/"),
|
|
1384
|
+
identifiers: { target: id, },
|
|
1385
|
+
payload: jobBuildPayload(id, projectKey, flags),
|
|
1386
|
+
wait: action === "build-and-wait" || flags["wait"] === true,
|
|
1387
|
+
};
|
|
1388
|
+
case "job.abort":
|
|
1389
|
+
return {
|
|
1390
|
+
method: "POST",
|
|
1391
|
+
endpoint: projectEndpoint(`/jobs/${encodeURIComponent(id)}/abort/`),
|
|
1392
|
+
identifiers: { id, },
|
|
1393
|
+
};
|
|
1394
|
+
case "scenario.run":
|
|
1395
|
+
case "scenario.run-and-wait":
|
|
1396
|
+
return {
|
|
1397
|
+
method: "POST",
|
|
1398
|
+
endpoint: projectEndpoint(`/scenarios/${encodeURIComponent(id)}/run/`),
|
|
1399
|
+
identifiers: { id, },
|
|
1400
|
+
payload: {},
|
|
1401
|
+
wait: action === "run-and-wait" || flags["wait"] === true,
|
|
1402
|
+
};
|
|
1403
|
+
case "scenario.delete":
|
|
1404
|
+
return {
|
|
1405
|
+
method: "DELETE",
|
|
1406
|
+
endpoint: projectEndpoint(`/scenarios/${encodeURIComponent(id)}/`),
|
|
1407
|
+
identifiers: { id, },
|
|
1408
|
+
};
|
|
1409
|
+
case "scenario.create":
|
|
1410
|
+
return {
|
|
1411
|
+
method: "POST",
|
|
1412
|
+
endpoint: projectEndpoint("/scenarios/"),
|
|
1413
|
+
identifiers: { id: args[0], name: args[1], },
|
|
1414
|
+
payload: {
|
|
1415
|
+
id: args[0],
|
|
1416
|
+
name: args[1],
|
|
1417
|
+
projectKey,
|
|
1418
|
+
type: flags["type"] ?? "step_based",
|
|
1419
|
+
},
|
|
1420
|
+
};
|
|
1421
|
+
case "scenario.update":
|
|
1422
|
+
return {
|
|
1423
|
+
method: "PUT",
|
|
1424
|
+
endpoint: projectEndpoint(`/scenarios/${encodeURIComponent(id)}/`),
|
|
1425
|
+
identifiers: { id, },
|
|
1426
|
+
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
1427
|
+
};
|
|
1428
|
+
case "folder.create": {
|
|
1429
|
+
const name = requiredPlanFlag(flags, "name", entry.usage);
|
|
1430
|
+
const type = requiredPlanFlag(flags, "type", entry.usage);
|
|
1431
|
+
const connection = requiredPlanFlag(flags, "connection", entry.usage);
|
|
1432
|
+
return {
|
|
1433
|
+
method: "POST",
|
|
1434
|
+
endpoint: projectEndpoint("/managedfolders/"),
|
|
1435
|
+
identifiers: { name, },
|
|
1436
|
+
payload: { name, type, connection, path: flags["path"], projectKey, },
|
|
1437
|
+
};
|
|
1438
|
+
}
|
|
1439
|
+
case "folder.update":
|
|
1440
|
+
return {
|
|
1441
|
+
method: "PUT",
|
|
1442
|
+
endpoint: projectEndpoint(`/managedfolders/${encodeURIComponent(id)}`),
|
|
1443
|
+
identifiers: { folder: id, },
|
|
1444
|
+
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
1445
|
+
};
|
|
1446
|
+
case "folder.delete":
|
|
1447
|
+
return {
|
|
1448
|
+
method: "DELETE",
|
|
1449
|
+
endpoint: projectEndpoint(`/managedfolders/${encodeURIComponent(id)}`),
|
|
1450
|
+
identifiers: { folder: id, },
|
|
1451
|
+
};
|
|
1452
|
+
case "folder.upload":
|
|
1453
|
+
return {
|
|
1454
|
+
method: "POST",
|
|
1455
|
+
endpoint: projectEndpoint(`/managedfolders/${encodeURIComponent(args[0])}/contents/${encodeURIComponent(args[1])}`),
|
|
1456
|
+
identifiers: { folder: args[0], path: args[1], localPath: args[2], },
|
|
1457
|
+
};
|
|
1458
|
+
case "folder.delete-file":
|
|
1459
|
+
return {
|
|
1460
|
+
method: "DELETE",
|
|
1461
|
+
endpoint: projectEndpoint(`/managedfolders/${encodeURIComponent(args[0])}/contents/${encodeURIComponent(args[1])}`),
|
|
1462
|
+
identifiers: { folder: args[0], path: args[1], },
|
|
1463
|
+
};
|
|
1464
|
+
case "variable.set":
|
|
1465
|
+
return {
|
|
1466
|
+
method: "PUT",
|
|
1467
|
+
endpoint: projectEndpoint("/variables/"),
|
|
1468
|
+
payload: {
|
|
1469
|
+
standard: optionalJsonFlag(flags, "standard"),
|
|
1470
|
+
local: optionalJsonFlag(flags, "local"),
|
|
1471
|
+
replace: flags["replace"] === true,
|
|
1472
|
+
},
|
|
1473
|
+
};
|
|
1474
|
+
case "project-deployer.create-project": {
|
|
1475
|
+
const payload = requiredPlanJsonInput(flags, entry.usage);
|
|
1476
|
+
return {
|
|
1477
|
+
method: "POST",
|
|
1478
|
+
endpoint: "/public/api/project-deployer/projects",
|
|
1479
|
+
identifiers: { projectKey: payload.projectKey, id: payload.id, },
|
|
1480
|
+
payload,
|
|
1481
|
+
};
|
|
1482
|
+
}
|
|
1483
|
+
case "project-deployer.upload-bundle":
|
|
1484
|
+
return {
|
|
1485
|
+
method: "POST",
|
|
1486
|
+
endpoint: "/public/api/project-deployer/projects/bundles",
|
|
1487
|
+
identifiers: { filePath: id, },
|
|
1488
|
+
payload: uploadPayload(id),
|
|
1489
|
+
};
|
|
1490
|
+
case "project-deployer.create-deployment": {
|
|
1491
|
+
const payload = requiredPlanJsonInput(flags, entry.usage);
|
|
1492
|
+
return {
|
|
1493
|
+
method: "POST",
|
|
1494
|
+
endpoint: "/public/api/project-deployer/deployments",
|
|
1495
|
+
identifiers: { deploymentId: payload.deploymentId ?? payload.id, },
|
|
1496
|
+
payload,
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1499
|
+
case "project-deployer.save-deployment-settings":
|
|
1500
|
+
return {
|
|
1501
|
+
method: "PUT",
|
|
1502
|
+
endpoint: `/public/api/project-deployer/deployments/${encodeURIComponent(id)}/settings`,
|
|
1503
|
+
identifiers: { deploymentId: id, },
|
|
1504
|
+
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
1505
|
+
};
|
|
1506
|
+
case "project-deployer.deploy":
|
|
1507
|
+
return {
|
|
1508
|
+
method: "POST",
|
|
1509
|
+
endpoint: `/public/api/project-deployer/deployments/${encodeURIComponent(id)}/actions/update`,
|
|
1510
|
+
identifiers: { deploymentId: id, },
|
|
1511
|
+
payload: {},
|
|
1512
|
+
};
|
|
1513
|
+
case "project-deployer.delete-deployment":
|
|
1514
|
+
return {
|
|
1515
|
+
method: "DELETE",
|
|
1516
|
+
endpoint: `/public/api/project-deployer/deployments/${encodeURIComponent(id)}`,
|
|
1517
|
+
identifiers: { deploymentId: id, },
|
|
1518
|
+
};
|
|
1519
|
+
case "project-deployer.create-infra": {
|
|
1520
|
+
const payload = requiredPlanJsonInput(flags, entry.usage);
|
|
1521
|
+
return {
|
|
1522
|
+
method: "POST",
|
|
1523
|
+
endpoint: "/public/api/project-deployer/infras",
|
|
1524
|
+
identifiers: { infraId: payload.id, },
|
|
1525
|
+
payload,
|
|
1526
|
+
};
|
|
1527
|
+
}
|
|
1528
|
+
case "api-deployer.create-infra": {
|
|
1529
|
+
const payload = requiredPlanJsonInput(flags, entry.usage);
|
|
1530
|
+
return {
|
|
1531
|
+
method: "POST",
|
|
1532
|
+
endpoint: "/public/api/api-deployer/infras",
|
|
1533
|
+
identifiers: { infraId: payload.id, },
|
|
1534
|
+
payload,
|
|
1535
|
+
};
|
|
1536
|
+
}
|
|
1537
|
+
case "api-deployer.delete-infra":
|
|
1538
|
+
return {
|
|
1539
|
+
method: "DELETE",
|
|
1540
|
+
endpoint: `/public/api/api-deployer/infras/${encodeURIComponent(id)}`,
|
|
1541
|
+
identifiers: { infraId: id, },
|
|
1542
|
+
};
|
|
1543
|
+
case "api-deployer.create-service": {
|
|
1544
|
+
const payload = requiredPlanJsonInput(flags, entry.usage);
|
|
1545
|
+
return {
|
|
1546
|
+
method: "POST",
|
|
1547
|
+
endpoint: "/public/api/api-deployer/services",
|
|
1548
|
+
identifiers: { serviceId: payload.id ?? payload.publishedServiceId, },
|
|
1549
|
+
payload,
|
|
1550
|
+
};
|
|
1551
|
+
}
|
|
1552
|
+
case "api-deployer.delete-service":
|
|
1553
|
+
return {
|
|
1554
|
+
method: "DELETE",
|
|
1555
|
+
endpoint: `/public/api/api-deployer/services/${encodeURIComponent(id)}`,
|
|
1556
|
+
identifiers: { serviceId: id, },
|
|
1557
|
+
};
|
|
1558
|
+
case "api-deployer.publish-version":
|
|
1559
|
+
return {
|
|
1560
|
+
method: "POST",
|
|
1561
|
+
endpoint: `/public/api/api-deployer/services/${encodeURIComponent(args[0])}/versions`,
|
|
1562
|
+
identifiers: { serviceId: args[0], filePath: args[1], },
|
|
1563
|
+
payload: uploadPayload(args[1]),
|
|
1564
|
+
};
|
|
1565
|
+
case "api-deployer.delete-version":
|
|
1566
|
+
return {
|
|
1567
|
+
method: "DELETE",
|
|
1568
|
+
endpoint: `/public/api/api-deployer/services/${encodeURIComponent(args[0])}/versions/${encodeURIComponent(args[1])}`,
|
|
1569
|
+
identifiers: { serviceId: args[0], version: args[1], },
|
|
1570
|
+
};
|
|
1571
|
+
case "api-deployer.create-deployment": {
|
|
1572
|
+
const payload = requiredPlanJsonInput(flags, entry.usage);
|
|
1573
|
+
return {
|
|
1574
|
+
method: "POST",
|
|
1575
|
+
endpoint: "/public/api/api-deployer/deployments",
|
|
1576
|
+
identifiers: { deploymentId: payload.deploymentId ?? payload.id, },
|
|
1577
|
+
payload,
|
|
1578
|
+
};
|
|
1579
|
+
}
|
|
1580
|
+
case "api-deployer.save-deployment-settings":
|
|
1581
|
+
return {
|
|
1582
|
+
method: "PUT",
|
|
1583
|
+
endpoint: `/public/api/api-deployer/deployments/${encodeURIComponent(id)}/settings`,
|
|
1584
|
+
identifiers: { deploymentId: id, },
|
|
1585
|
+
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
1586
|
+
};
|
|
1587
|
+
case "api-deployer.deploy":
|
|
1588
|
+
return {
|
|
1589
|
+
method: "POST",
|
|
1590
|
+
endpoint: `/public/api/api-deployer/deployments/${encodeURIComponent(id)}/actions/update`,
|
|
1591
|
+
identifiers: { deploymentId: id, },
|
|
1592
|
+
payload: {},
|
|
1593
|
+
};
|
|
1594
|
+
case "api-deployer.delete-deployment":
|
|
1595
|
+
return {
|
|
1596
|
+
method: "DELETE",
|
|
1597
|
+
endpoint: `/public/api/api-deployer/deployments/${encodeURIComponent(id)}`,
|
|
1598
|
+
identifiers: { deploymentId: id, },
|
|
1599
|
+
};
|
|
1600
|
+
case "workspace.create": {
|
|
1601
|
+
const payload = requiredPlanJsonInput(flags, entry.usage);
|
|
1602
|
+
return {
|
|
1603
|
+
method: "POST",
|
|
1604
|
+
endpoint: "/public/api/workspaces/",
|
|
1605
|
+
identifiers: { workspaceKey: payload.workspaceKey, },
|
|
1606
|
+
payload,
|
|
1607
|
+
};
|
|
1608
|
+
}
|
|
1609
|
+
case "workspace.update-settings":
|
|
1610
|
+
return {
|
|
1611
|
+
method: "PUT",
|
|
1612
|
+
endpoint: `/public/api/workspaces/${encodeURIComponent(id)}`,
|
|
1613
|
+
identifiers: { workspaceKey: id, },
|
|
1614
|
+
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
1615
|
+
};
|
|
1616
|
+
case "workspace.delete":
|
|
1617
|
+
return {
|
|
1618
|
+
method: "DELETE",
|
|
1619
|
+
endpoint: `/public/api/workspaces/${encodeURIComponent(id)}`,
|
|
1620
|
+
identifiers: { workspaceKey: id, },
|
|
1621
|
+
};
|
|
1622
|
+
case "workspace.add-object":
|
|
1623
|
+
return {
|
|
1624
|
+
method: "POST",
|
|
1625
|
+
endpoint: `/public/api/workspaces/${encodeURIComponent(id)}/objects`,
|
|
1626
|
+
identifiers: { workspaceKey: id, },
|
|
1627
|
+
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
1628
|
+
};
|
|
1629
|
+
case "meaning.create": {
|
|
1630
|
+
const body = jsonInput(flags) ?? {};
|
|
1631
|
+
const payload = {
|
|
1632
|
+
...body,
|
|
1633
|
+
id: args[0],
|
|
1634
|
+
label: args[1],
|
|
1635
|
+
type: args[2],
|
|
1636
|
+
description: body.description ?? null,
|
|
1637
|
+
entries: body.entries ?? null,
|
|
1638
|
+
mappings: body.mappings ?? null,
|
|
1639
|
+
pattern: body.pattern ?? null,
|
|
1640
|
+
normalizationMode: body.normalizationMode ?? null,
|
|
1641
|
+
detectable: body.detectable ?? false,
|
|
1642
|
+
};
|
|
1643
|
+
return {
|
|
1644
|
+
method: "POST",
|
|
1645
|
+
endpoint: "/public/api/meanings/",
|
|
1646
|
+
identifiers: { id: args[0], },
|
|
1647
|
+
payload,
|
|
1648
|
+
};
|
|
1649
|
+
}
|
|
1650
|
+
case "meaning.update":
|
|
1651
|
+
return {
|
|
1652
|
+
method: "PUT",
|
|
1653
|
+
endpoint: `/public/api/meanings/${encodeURIComponent(id)}`,
|
|
1654
|
+
identifiers: { id, },
|
|
1655
|
+
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
1656
|
+
};
|
|
1657
|
+
case "meaning.delete":
|
|
1658
|
+
return {
|
|
1659
|
+
method: "DELETE",
|
|
1660
|
+
endpoint: `/public/api/meanings/${encodeURIComponent(id)}`,
|
|
1661
|
+
identifiers: { id, },
|
|
1662
|
+
};
|
|
1663
|
+
case "business-app.save-settings":
|
|
1664
|
+
return {
|
|
1665
|
+
method: "PUT",
|
|
1666
|
+
endpoint: `/public/api/business-apps/${encodeURIComponent(id)}/settings`,
|
|
1667
|
+
identifiers: { id, },
|
|
1668
|
+
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
1669
|
+
};
|
|
1670
|
+
case "business-app.create-instance":
|
|
1671
|
+
return {
|
|
1672
|
+
method: "POST",
|
|
1673
|
+
endpoint: `/public/api/business-apps/${encodeURIComponent(id)}/instances`,
|
|
1674
|
+
identifiers: { id, },
|
|
1675
|
+
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
1676
|
+
};
|
|
1677
|
+
case "business-app.upgrade-instance":
|
|
1678
|
+
return {
|
|
1679
|
+
method: "POST",
|
|
1680
|
+
endpoint: `/public/api/business-apps/${encodeURIComponent(args[0])}/instances/${encodeURIComponent(args[1])}/upgrade`,
|
|
1681
|
+
identifiers: { id: args[0], projectKey: args[1], },
|
|
1682
|
+
payload: {},
|
|
1683
|
+
};
|
|
1684
|
+
case "business-app.install-from-archive":
|
|
1685
|
+
return {
|
|
1686
|
+
method: "POST",
|
|
1687
|
+
endpoint: "/public/api/business-apps/install-from-archive",
|
|
1688
|
+
identifiers: { filePath: id, },
|
|
1689
|
+
payload: uploadPayload(id),
|
|
1690
|
+
};
|
|
1691
|
+
case "app.create-instance":
|
|
1692
|
+
return {
|
|
1693
|
+
method: "POST",
|
|
1694
|
+
endpoint: `/public/api/apps/${encodeURIComponent(id)}/instances`,
|
|
1695
|
+
identifiers: { appId: id, },
|
|
1696
|
+
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
1697
|
+
};
|
|
1698
|
+
case "statistics.create-worksheet":
|
|
1699
|
+
return {
|
|
1700
|
+
method: "POST",
|
|
1701
|
+
endpoint: statisticsWorksheetsEndpoint(args[0]),
|
|
1702
|
+
identifiers: { dataset: args[0], },
|
|
1703
|
+
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
1704
|
+
};
|
|
1705
|
+
case "statistics.update-worksheet":
|
|
1706
|
+
return {
|
|
1707
|
+
method: "PUT",
|
|
1708
|
+
endpoint: statisticsWorksheetEndpoint(args[0], args[1]),
|
|
1709
|
+
identifiers: { dataset: args[0], worksheetId: args[1], },
|
|
1710
|
+
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
1711
|
+
};
|
|
1712
|
+
case "statistics.delete-worksheet":
|
|
1713
|
+
return {
|
|
1714
|
+
method: "DELETE",
|
|
1715
|
+
endpoint: statisticsWorksheetEndpoint(args[0], args[1]),
|
|
1716
|
+
identifiers: { dataset: args[0], worksheetId: args[1], },
|
|
1717
|
+
};
|
|
1718
|
+
case "statistics.run-worksheet":
|
|
1719
|
+
return {
|
|
1720
|
+
method: "POST",
|
|
1721
|
+
endpoint: `${statisticsWorksheetEndpoint(args[0], args[1])}/actions/run-card`,
|
|
1722
|
+
identifiers: { dataset: args[0], worksheetId: args[1], },
|
|
1723
|
+
};
|
|
1724
|
+
case "statistics.run-card":
|
|
1725
|
+
return {
|
|
1726
|
+
method: "POST",
|
|
1727
|
+
endpoint: `${statisticsWorksheetEndpoint(args[0], args[1])}/actions/run-card`,
|
|
1728
|
+
identifiers: { dataset: args[0], worksheetId: args[1], },
|
|
1729
|
+
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
1730
|
+
};
|
|
1731
|
+
case "statistics.run-computation":
|
|
1732
|
+
return {
|
|
1733
|
+
method: "POST",
|
|
1734
|
+
endpoint: `${statisticsWorksheetEndpoint(args[0], args[1])}/actions/run-computation`,
|
|
1735
|
+
identifiers: { dataset: args[0], worksheetId: args[1], },
|
|
1736
|
+
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
1737
|
+
};
|
|
1738
|
+
case "bundle.export":
|
|
1739
|
+
return {
|
|
1740
|
+
method: "PUT",
|
|
1741
|
+
endpoint: projectEndpoint(`/bundles/exported/${encodeURIComponent(id)}`),
|
|
1742
|
+
identifiers: { bundleId: id, },
|
|
1743
|
+
payload: {},
|
|
1744
|
+
};
|
|
1745
|
+
case "bundle.publish":
|
|
1746
|
+
return {
|
|
1747
|
+
method: "POST",
|
|
1748
|
+
endpoint: projectEndpoint(`/bundles/${encodeURIComponent(id)}/publish`),
|
|
1749
|
+
identifiers: { bundleId: id, },
|
|
1750
|
+
payload: {},
|
|
1751
|
+
};
|
|
1752
|
+
case "bundle.activate":
|
|
1753
|
+
return {
|
|
1754
|
+
method: "POST",
|
|
1755
|
+
endpoint: projectEndpoint(`/bundles/imported/${encodeURIComponent(id)}/actions/activate`),
|
|
1756
|
+
identifiers: { bundleId: id, },
|
|
1757
|
+
payload: {},
|
|
1758
|
+
};
|
|
1759
|
+
case "bundle.preload":
|
|
1760
|
+
return {
|
|
1761
|
+
method: "POST",
|
|
1762
|
+
endpoint: projectEndpoint(`/bundles/imported/${encodeURIComponent(id)}/actions/preload`),
|
|
1763
|
+
identifiers: { bundleId: id, },
|
|
1764
|
+
payload: {},
|
|
1765
|
+
};
|
|
1766
|
+
case "code-env.create":
|
|
1767
|
+
return {
|
|
1768
|
+
method: "POST",
|
|
1769
|
+
endpoint: "/public/api/admin/code-envs/",
|
|
1770
|
+
identifiers: { lang: args[0], name: args[1], },
|
|
1771
|
+
payload: {
|
|
1772
|
+
envLang: args[0],
|
|
1773
|
+
envName: args[1],
|
|
1774
|
+
deploymentMode: requiredPlanFlag(flags, "deployment-mode", entry.usage),
|
|
1775
|
+
params: codeEnvParams(flags),
|
|
1776
|
+
wait: codeEnvWait(flags),
|
|
1777
|
+
},
|
|
1778
|
+
wait: codeEnvWait(flags),
|
|
1779
|
+
};
|
|
1780
|
+
case "code-env.set-definition":
|
|
1781
|
+
return {
|
|
1782
|
+
method: "PUT",
|
|
1783
|
+
endpoint: `/public/api/admin/code-envs/${encodeURIComponent(args[0])}/${encodeURIComponent(args[1])}`,
|
|
1784
|
+
identifiers: { lang: args[0], name: args[1], },
|
|
1785
|
+
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
1786
|
+
};
|
|
1787
|
+
case "code-env.set-packages": {
|
|
1788
|
+
const installCorePackages = parseBooleanOption(flags["install-core-packages"], "--install-core-packages");
|
|
1789
|
+
const payload = {
|
|
1790
|
+
specPackageList: codeEnvPackageList(flags).join("\n"),
|
|
1791
|
+
};
|
|
1792
|
+
if (installCorePackages !== undefined) {
|
|
1793
|
+
payload.desc = { installCorePackages, };
|
|
1794
|
+
}
|
|
1795
|
+
return {
|
|
1796
|
+
method: "PUT",
|
|
1797
|
+
endpoint: codeEnvEndpoint(),
|
|
1798
|
+
identifiers: { lang: args[0], name: args[1], },
|
|
1799
|
+
payload,
|
|
1800
|
+
};
|
|
1801
|
+
}
|
|
1802
|
+
case "code-env.update-packages": {
|
|
1803
|
+
const versionToUpdate = typeof flags["env-version"] === "string"
|
|
1804
|
+
? flags["env-version"]
|
|
1805
|
+
: typeof flags["version"] === "string"
|
|
1806
|
+
? flags["version"]
|
|
1807
|
+
: undefined;
|
|
1808
|
+
return {
|
|
1809
|
+
method: "POST",
|
|
1810
|
+
endpoint: `${codeEnvEndpoint("/packages")}${querySuffix({
|
|
1811
|
+
forceRebuildEnv: flags["force-rebuild"] === true,
|
|
1812
|
+
versionToUpdate,
|
|
1813
|
+
wait: codeEnvWait(flags),
|
|
1814
|
+
})}`,
|
|
1815
|
+
identifiers: { lang: args[0], name: args[1], },
|
|
1816
|
+
wait: codeEnvWait(flags),
|
|
1817
|
+
};
|
|
1818
|
+
}
|
|
1819
|
+
case "code-env.set-jupyter": {
|
|
1820
|
+
const active = parseBooleanOption(flags["active"], "--active");
|
|
1821
|
+
if (active === undefined) {
|
|
1822
|
+
throw new UsageError("--active is required. Usage: dss code-env set-jupyter <lang> <name> --active true|false");
|
|
1823
|
+
}
|
|
1824
|
+
return {
|
|
1825
|
+
method: "POST",
|
|
1826
|
+
endpoint: `${codeEnvEndpoint("/jupyter")}${querySuffix({ active, wait: codeEnvWait(flags), })}`,
|
|
1827
|
+
identifiers: { lang: args[0], name: args[1], },
|
|
1828
|
+
wait: codeEnvWait(flags),
|
|
1829
|
+
};
|
|
1830
|
+
}
|
|
1831
|
+
case "code-env.delete":
|
|
1832
|
+
return {
|
|
1833
|
+
method: "DELETE",
|
|
1834
|
+
endpoint: `/public/api/admin/code-envs/${encodeURIComponent(args[0])}/${encodeURIComponent(args[1])}`,
|
|
1835
|
+
identifiers: { lang: args[0], name: args[1], },
|
|
1836
|
+
wait: codeEnvWait(flags),
|
|
1837
|
+
};
|
|
1838
|
+
case "notebook.save-jupyter":
|
|
1839
|
+
return {
|
|
1840
|
+
method: "PUT",
|
|
1841
|
+
endpoint: projectEndpoint(`/jupyter-notebooks/${encodeURIComponent(id)}`),
|
|
1842
|
+
identifiers: { name: id, },
|
|
1843
|
+
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
1844
|
+
};
|
|
1845
|
+
case "notebook.delete-jupyter":
|
|
1846
|
+
return {
|
|
1847
|
+
method: "DELETE",
|
|
1848
|
+
endpoint: projectEndpoint(`/jupyter-notebooks/${encodeURIComponent(id)}`),
|
|
1849
|
+
identifiers: { name: id, },
|
|
1850
|
+
};
|
|
1851
|
+
case "notebook.clear-jupyter-outputs":
|
|
1852
|
+
return {
|
|
1853
|
+
method: "PUT",
|
|
1854
|
+
endpoint: projectEndpoint(`/jupyter-notebooks/${encodeURIComponent(id)}`),
|
|
1855
|
+
identifiers: { name: id, },
|
|
1856
|
+
payload: { clearOutputs: true, },
|
|
1857
|
+
};
|
|
1858
|
+
case "notebook.unload-jupyter":
|
|
1859
|
+
return {
|
|
1860
|
+
method: "POST",
|
|
1861
|
+
endpoint: projectEndpoint(`/jupyter-notebooks/${encodeURIComponent(args[0])}/sessions/${encodeURIComponent(args[1])}/unload`),
|
|
1862
|
+
identifiers: { name: args[0], sessionId: args[1], },
|
|
1863
|
+
};
|
|
1864
|
+
case "notebook.save-sql":
|
|
1865
|
+
return {
|
|
1866
|
+
method: "PUT",
|
|
1867
|
+
endpoint: projectEndpoint(`/sql-notebooks/${encodeURIComponent(id)}`),
|
|
1868
|
+
identifiers: { id, },
|
|
1869
|
+
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
1870
|
+
};
|
|
1871
|
+
case "notebook.delete-sql":
|
|
1872
|
+
return {
|
|
1873
|
+
method: "DELETE",
|
|
1874
|
+
endpoint: projectEndpoint(`/sql-notebooks/${encodeURIComponent(id)}`),
|
|
1875
|
+
identifiers: { id, },
|
|
1876
|
+
};
|
|
1877
|
+
case "notebook.clear-sql-history":
|
|
1878
|
+
return {
|
|
1879
|
+
method: "PUT",
|
|
1880
|
+
endpoint: projectEndpoint(`/sql-notebooks/${encodeURIComponent(id)}/history`),
|
|
1881
|
+
identifiers: { id, cellId: flags["cell-id"], },
|
|
1882
|
+
payload: { retain: num(flags["retain"]), },
|
|
1883
|
+
};
|
|
1884
|
+
case "project.create": {
|
|
1885
|
+
const settings = jsonInput(flags) ?? null;
|
|
1886
|
+
return {
|
|
1887
|
+
method: "POST",
|
|
1888
|
+
endpoint: "/public/api/projects/",
|
|
1889
|
+
identifiers: { projectKey: args[0], name: args[1], },
|
|
1890
|
+
payload: {
|
|
1891
|
+
projectKey: args[0],
|
|
1892
|
+
name: args[1],
|
|
1893
|
+
owner: flags["owner"] ?? null,
|
|
1894
|
+
settings,
|
|
1895
|
+
description: null,
|
|
1896
|
+
permissions: [],
|
|
1897
|
+
tags: [],
|
|
1898
|
+
},
|
|
1899
|
+
};
|
|
1900
|
+
}
|
|
1901
|
+
case "project.delete":
|
|
1902
|
+
return {
|
|
1903
|
+
method: "DELETE",
|
|
1904
|
+
endpoint: `/public/api/projects/${encodeURIComponent(id)}${querySuffix({
|
|
1905
|
+
clearManagedDatasets: flags["drop-data"] === true,
|
|
1906
|
+
clearOutputManagedFolders: false,
|
|
1907
|
+
clearJobAndScenarioLogs: true,
|
|
1908
|
+
wait: true,
|
|
1909
|
+
})}`,
|
|
1910
|
+
identifiers: { projectKey: id, },
|
|
1911
|
+
};
|
|
1912
|
+
case "project.duplicate": {
|
|
1913
|
+
const options = jsonInput(flags);
|
|
1914
|
+
return {
|
|
1915
|
+
method: "POST",
|
|
1916
|
+
endpoint: `/public/api/projects/${encodeURIComponent(args[0])}/duplicate/`,
|
|
1917
|
+
identifiers: { sourceKey: args[0], targetKey: args[1], targetName: args[2], },
|
|
1918
|
+
payload: {
|
|
1919
|
+
targetProjectName: args[2],
|
|
1920
|
+
targetProjectKey: args[1],
|
|
1921
|
+
duplicationMode: options?.duplicationMode ?? "MINIMAL",
|
|
1922
|
+
exportAnalysisModels: options?.exportAnalysisModels ?? true,
|
|
1923
|
+
exportSavedModels: options?.exportSavedModels ?? true,
|
|
1924
|
+
exportGitRepository: options?.exportGitRepository ?? null,
|
|
1925
|
+
exportInsightsData: options?.exportInsightsData ?? true,
|
|
1926
|
+
remapping: options?.remapping ?? {},
|
|
1927
|
+
...(options?.targetProjectFolderId !== undefined
|
|
1928
|
+
? { targetProjectFolderId: options.targetProjectFolderId, }
|
|
1929
|
+
: {}),
|
|
1930
|
+
},
|
|
1931
|
+
};
|
|
1932
|
+
}
|
|
1933
|
+
case "project.export": {
|
|
1934
|
+
const output = requiredPlanFlag(flags, "output", entry.usage);
|
|
1935
|
+
return {
|
|
1936
|
+
method: "POST",
|
|
1937
|
+
endpoint: `/public/api/projects/${encodeURIComponent(id)}/export`,
|
|
1938
|
+
identifiers: { projectKey: id, output, },
|
|
1939
|
+
payload: jsonInput(flags) ?? {},
|
|
1940
|
+
localWrites: [{ path: output, source: "remote project archive", after: "POST", },],
|
|
1941
|
+
};
|
|
1942
|
+
}
|
|
1943
|
+
case "project.import":
|
|
1944
|
+
return {
|
|
1945
|
+
method: "POST",
|
|
1946
|
+
endpoint: "/public/api/projects/import/upload",
|
|
1947
|
+
identifiers: { filePath: id, },
|
|
1948
|
+
payload: {
|
|
1949
|
+
contentType: "multipart/form-data",
|
|
1950
|
+
fileField: "file",
|
|
1951
|
+
filePath: id,
|
|
1952
|
+
fileName: "tmp-import.zip",
|
|
1953
|
+
},
|
|
1954
|
+
};
|
|
1955
|
+
case "project.settings-set":
|
|
1956
|
+
return {
|
|
1957
|
+
method: "PUT",
|
|
1958
|
+
endpoint: projectEndpoint("/settings"),
|
|
1959
|
+
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
1960
|
+
};
|
|
1961
|
+
case "project.permissions-set":
|
|
1962
|
+
return {
|
|
1963
|
+
method: "PUT",
|
|
1964
|
+
endpoint: projectEndpoint("/permissions"),
|
|
1965
|
+
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
1966
|
+
};
|
|
1967
|
+
case "continuous-activity.start":
|
|
1968
|
+
return {
|
|
1969
|
+
method: "POST",
|
|
1970
|
+
endpoint: projectEndpoint(`/continuous-activities/${encodeURIComponent(id)}/start`),
|
|
1971
|
+
identifiers: { recipeId: id, },
|
|
1972
|
+
payload: jsonInput(flags) ?? {},
|
|
1973
|
+
};
|
|
1974
|
+
case "continuous-activity.stop":
|
|
1975
|
+
return {
|
|
1976
|
+
method: "POST",
|
|
1977
|
+
endpoint: projectEndpoint(`/continuous-activities/${encodeURIComponent(id)}/stop`),
|
|
1978
|
+
identifiers: { recipeId: id, },
|
|
1979
|
+
};
|
|
1980
|
+
case "metrics.dataset-compute":
|
|
1981
|
+
return {
|
|
1982
|
+
method: "POST",
|
|
1983
|
+
endpoint: projectEndpoint(`/datasets/${encodeURIComponent(id)}/actions/computeMetrics?partition=`),
|
|
1984
|
+
identifiers: { dataset: id, },
|
|
1985
|
+
};
|
|
1986
|
+
case "flow-zone.organize":
|
|
1987
|
+
return {
|
|
1988
|
+
method: "POST",
|
|
1989
|
+
endpoint: projectEndpoint("/flow/zones"),
|
|
1990
|
+
payload: jsonInput(flags),
|
|
1991
|
+
};
|
|
1992
|
+
default:
|
|
1993
|
+
return {
|
|
1994
|
+
method: action.startsWith("delete") || action === "abort" ? "DELETE" : "POST",
|
|
1995
|
+
endpoint: projectKey
|
|
1996
|
+
? projectEndpoint(`/${resource}s/${id ? encodeURIComponent(id) : ""}`)
|
|
1997
|
+
: undefined,
|
|
1998
|
+
identifiers: id ? { id, } : undefined,
|
|
1999
|
+
payload: jsonInput(flags),
|
|
2000
|
+
};
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
export function buildMutationPlan(resource, action, meta, args, flags) {
|
|
2004
|
+
const entry = buildRegistryEntry(resource, action, meta);
|
|
2005
|
+
if (!entry.mutatesDss && entry.sideEffect !== "write") {
|
|
2006
|
+
throw new UsageError(`--plan is only supported for mutating commands. Usage: ${meta.usage}`);
|
|
2007
|
+
}
|
|
2008
|
+
const requiredPositionals = requiredPlanPositionals(meta.usage);
|
|
2009
|
+
requireArgs(args, requiredPositionals.length, meta.usage);
|
|
2010
|
+
const projectKey = projectKeyForPlan(entry, flags);
|
|
2011
|
+
const shape = commandPlanShape(resource, action, args, flags, entry, projectKey);
|
|
2012
|
+
return planResult(resource, action, {
|
|
2013
|
+
...shape,
|
|
2014
|
+
asyncKind: entry.async,
|
|
2015
|
+
exitCodesOnFailure: exitCodesOnFailure(entry),
|
|
2016
|
+
idempotency: entry.idempotency,
|
|
2017
|
+
plannedAndDryRun: flags["dry-run"] === true,
|
|
2018
|
+
});
|
|
2019
|
+
}
|
|
2020
|
+
export const BATCH_USAGE = "dss batch (--data JSON|--data-file PATH|--stdin) [--continue-on-error] [--dry-run]";
|
|
2021
|
+
const BATCH_DESCRIPTION = "Run a sequence of dss commands from a JSON array of argv arrays. Fail-fast by default; returns one envelope with a per-step ok/result/error and exits non-zero if any step failed.";
|
|
2022
|
+
export const BATCH_HINT = 'Pass a JSON array of argv arrays, e.g. [["dataset","list"],["recipe","update","r","--data-file","p.json"]].';
|
|
2023
|
+
export const BATCH_EXAMPLE_PAYLOAD = [
|
|
2024
|
+
["recipe", "set-payload", "compute_orders", "--file", "code.py", "--no-backup",],
|
|
2025
|
+
["recipe", "update", "compute_orders", "--data-file", "env.json",],
|
|
2026
|
+
["dataset", "update", "orders", "--data-file", "ds.json",],
|
|
2027
|
+
];
|
|
2028
|
+
const BATCH_EXAMPLES = [
|
|
2029
|
+
"dss batch --data-file steps.json",
|
|
2030
|
+
"dss batch --stdin --continue-on-error",
|
|
2031
|
+
];
|