dataiku-sdk 3.1.0 → 3.2.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/README.md +124 -12
- package/dist/build-metadata.json +1 -1
- package/dist/src/auth.js +1 -1
- package/dist/src/cli/coerce.js +11 -2
- package/dist/src/cli/commands/analysis.js +4 -3
- package/dist/src/cli/commands/api-service.js +5 -3
- package/dist/src/cli/commands/app.js +4 -3
- package/dist/src/cli/commands/bundle.js +2 -1
- package/dist/src/cli/commands/code-env.js +10 -9
- package/dist/src/cli/commands/dashboard.js +7 -6
- package/dist/src/cli/commands/data-quality.js +9 -8
- package/dist/src/cli/commands/dataset.js +9 -8
- package/dist/src/cli/commands/doctor.js +4 -2
- package/dist/src/cli/commands/flow-zone.js +9 -8
- package/dist/src/cli/commands/folder.js +9 -8
- package/dist/src/cli/commands/future.js +2 -1
- package/dist/src/cli/commands/insight.js +8 -7
- package/dist/src/cli/commands/job.js +4 -3
- package/dist/src/cli/commands/meaning.js +5 -4
- package/dist/src/cli/commands/ml-task.js +3 -2
- package/dist/src/cli/commands/model-evaluation-store.js +4 -3
- package/dist/src/cli/commands/notebook.js +11 -10
- package/dist/src/cli/commands/project-library.js +7 -6
- package/dist/src/cli/commands/project.js +3 -2
- package/dist/src/cli/commands/recipe.js +14 -13
- package/dist/src/cli/commands/saved-model.js +4 -3
- package/dist/src/cli/commands/scenario.js +9 -8
- package/dist/src/cli/commands/sql.js +3 -2
- package/dist/src/cli/commands/statistics.js +7 -6
- package/dist/src/cli/commands/variable.js +2 -1
- package/dist/src/cli/commands/webapp.js +2 -1
- package/dist/src/cli/commands/wiki.js +7 -6
- package/dist/src/cli/contract.d.ts +1 -1
- package/dist/src/cli/contract.js +100 -82
- package/dist/src/cli/flags.d.ts +4 -0
- package/dist/src/cli/flags.js +20 -1
- package/dist/src/cli.js +92 -68
- package/dist/src/client.d.ts +3 -1
- package/dist/src/client.js +78 -21
- package/dist/src/errors.js +2 -0
- package/dist/src/resources/folders.js +2 -1
- package/dist/src/resources/projects.d.ts +0 -2
- package/dist/src/resources/projects.js +3 -17
- package/dist/src/resources/sql.js +1 -1
- package/dist/src/skill.d.ts +13 -4
- package/dist/src/skill.js +75 -24
- package/dist/src/utils/response-file.d.ts +2 -0
- package/dist/src/utils/response-file.js +34 -0
- package/package.json +6 -4
- package/plugin.json +1 -1
- package/skills/dataiku-dss/SKILL.md +44 -224
- package/skills/dataiku-dss/references/app-releases.md +27 -0
- package/skills/dataiku-dss/references/authentication.md +39 -0
- package/skills/dataiku-dss/references/coding.md +8 -0
- package/skills/dataiku-dss/references/discovery.md +30 -0
- package/skills/dataiku-dss/references/flow-maps.md +12 -0
- package/skills/dataiku-dss/references/mutations.md +33 -0
- package/skills/dataiku-dss/references/troubleshooting.md +29 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ClientValidationError, } from "../../errors.js";
|
|
2
2
|
import { deepMerge, } from "../../utils/deep-merge.js";
|
|
3
|
+
import { executionMode, } from "../flags.js";
|
|
3
4
|
import { ensureFlowZonePlanTarget, findFlowZoneForPlan, flowZoneColor, flowZoneContains, flowZoneCurrentPosition, flowZoneDetailSummary, flowZoneId, flowZoneMoveDelta, flowZoneMoveItems, flowZoneName, flowZoneOrganizeStep, flowZonePlanFromZones, flowZonePlanItemKeys, flowZonePruneItems, flowZoneSamePosition, flowZoneSummary, readFlowZoneOrganizePlan, resolveFlowZoneIdFromFlags, throwFlowZoneValidationError, validateFlowZoneOrganizeObjects, } from "../helpers/flow-zone.js";
|
|
4
5
|
import { readIfExists, skipResult, } from "../output.js";
|
|
5
6
|
import { requireArgs, UsageError, } from "../usage.js";
|
|
@@ -63,13 +64,13 @@ export const flowZoneCommands = {
|
|
|
63
64
|
color: flowZoneColor(f["color"]),
|
|
64
65
|
projectKey: pk,
|
|
65
66
|
};
|
|
66
|
-
if (f["if-not-exists"] === true || f
|
|
67
|
+
if (f["if-not-exists"] === true || executionMode(f).dryRun) {
|
|
67
68
|
const list = await c.flowZones.list(pk);
|
|
68
69
|
const existing = list.find((zone) => zone.name === name);
|
|
69
|
-
if (existing && f["if-not-exists"] === true && f
|
|
70
|
+
if (existing && f["if-not-exists"] === true && !executionMode(f).dryRun) {
|
|
70
71
|
return skipResult("flow-zone", existing.id, "exists", { current: existing, });
|
|
71
72
|
}
|
|
72
|
-
if (f
|
|
73
|
+
if (executionMode(f).dryRun) {
|
|
73
74
|
return {
|
|
74
75
|
dryRun: true,
|
|
75
76
|
action: "create",
|
|
@@ -103,7 +104,7 @@ export const flowZoneCommands = {
|
|
|
103
104
|
color: flowZoneColor(f["color"]),
|
|
104
105
|
projectKey: pk,
|
|
105
106
|
};
|
|
106
|
-
if (f
|
|
107
|
+
if (executionMode(f).dryRun) {
|
|
107
108
|
const current = await c.flowZones.get(zoneId, pk);
|
|
108
109
|
const next = deepMerge(current, patch);
|
|
109
110
|
return { dryRun: true, action: "update", resource: "flow-zone", id: zoneId, current, next, };
|
|
@@ -118,11 +119,11 @@ export const flowZoneCommands = {
|
|
|
118
119
|
handler: async (c, a, f) => {
|
|
119
120
|
requireArgs(a, 1, "dss flow-zone delete <id>");
|
|
120
121
|
const zoneId = flowZoneId(a[0]);
|
|
121
|
-
if (f
|
|
122
|
+
if (executionMode(f).dryRun || f["if-exists"] === true) {
|
|
122
123
|
const current = await readIfExists(() => c.flowZones.get(zoneId, f["project-key"]));
|
|
123
124
|
if (!current)
|
|
124
125
|
return skipResult("flow-zone", zoneId, "missing");
|
|
125
|
-
if (f
|
|
126
|
+
if (executionMode(f).dryRun) {
|
|
126
127
|
return { dryRun: true, action: "delete", resource: "flow-zone", id: zoneId, current, };
|
|
127
128
|
}
|
|
128
129
|
}
|
|
@@ -147,7 +148,7 @@ export const flowZoneCommands = {
|
|
|
147
148
|
if (items.length === 0) {
|
|
148
149
|
throw new UsageError("At least one object is required. Use --dataset, --recipe, --folder, or --object TYPE:ID.");
|
|
149
150
|
}
|
|
150
|
-
if (f
|
|
151
|
+
if (executionMode(f).dryRun) {
|
|
151
152
|
return {
|
|
152
153
|
dryRun: true,
|
|
153
154
|
action: "move",
|
|
@@ -206,7 +207,7 @@ export const flowZoneCommands = {
|
|
|
206
207
|
const pruneItems = Array.isArray(step.pruneItems) ? step.pruneItems : [];
|
|
207
208
|
return count + pruneItems.length;
|
|
208
209
|
}, 0);
|
|
209
|
-
if (f
|
|
210
|
+
if (executionMode(f).dryRun) {
|
|
210
211
|
return {
|
|
211
212
|
dryRun: true,
|
|
212
213
|
action: "organize",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { deepMerge, } from "../../utils/deep-merge.js";
|
|
2
2
|
import { jsonInput, } from "../coerce.js";
|
|
3
|
+
import { executionMode, } from "../flags.js";
|
|
3
4
|
import { addTransientTargetContext, encodedProjectEndpoint, readIfExists, skipResult, } from "../output.js";
|
|
4
5
|
import { requireArgs, UsageError, } from "../usage.js";
|
|
5
6
|
async function resolveFolderId(client, nameOrId, flags) {
|
|
@@ -28,13 +29,13 @@ export const folderCommands = {
|
|
|
28
29
|
path: f["path"],
|
|
29
30
|
projectKey: pk,
|
|
30
31
|
};
|
|
31
|
-
if (f["if-not-exists"] === true || f
|
|
32
|
+
if (f["if-not-exists"] === true || executionMode(f).dryRun) {
|
|
32
33
|
const list = await c.folders.list(pk);
|
|
33
34
|
const existing = list.find((folder) => folder.name === name);
|
|
34
|
-
if (existing && f["if-not-exists"] === true && f
|
|
35
|
+
if (existing && f["if-not-exists"] === true && !executionMode(f).dryRun) {
|
|
35
36
|
return skipResult("folder", existing.id ?? name, "exists", { current: existing, });
|
|
36
37
|
}
|
|
37
|
-
if (f
|
|
38
|
+
if (executionMode(f).dryRun) {
|
|
38
39
|
return {
|
|
39
40
|
dryRun: true,
|
|
40
41
|
action: "create",
|
|
@@ -74,7 +75,7 @@ export const folderCommands = {
|
|
|
74
75
|
}
|
|
75
76
|
const pk = f["project-key"];
|
|
76
77
|
const folderId = await resolveFolderId(c, a[0], f);
|
|
77
|
-
if (f
|
|
78
|
+
if (executionMode(f).dryRun) {
|
|
78
79
|
const current = await c.folders.get(folderId, pk);
|
|
79
80
|
const next = deepMerge(current, data);
|
|
80
81
|
return {
|
|
@@ -102,11 +103,11 @@ export const folderCommands = {
|
|
|
102
103
|
requireArgs(a, 1, "dss folder delete <name-or-id>");
|
|
103
104
|
const pk = f["project-key"];
|
|
104
105
|
const folderId = await resolveFolderId(c, a[0], f);
|
|
105
|
-
if (f
|
|
106
|
+
if (executionMode(f).dryRun || f["if-exists"] === true) {
|
|
106
107
|
const current = await readIfExists(() => c.folders.get(folderId, pk));
|
|
107
108
|
if (!current)
|
|
108
109
|
return skipResult("folder", folderId, "missing");
|
|
109
|
-
if (f
|
|
110
|
+
if (executionMode(f).dryRun) {
|
|
110
111
|
return {
|
|
111
112
|
dryRun: true,
|
|
112
113
|
action: "delete",
|
|
@@ -167,7 +168,7 @@ export const folderCommands = {
|
|
|
167
168
|
requireArgs(a, 3, "dss folder upload <name-or-id> <path> <localPath>");
|
|
168
169
|
const pk = f["project-key"];
|
|
169
170
|
const folderId = await resolveFolderId(c, a[0], f);
|
|
170
|
-
if (f
|
|
171
|
+
if (executionMode(f).dryRun) {
|
|
171
172
|
return {
|
|
172
173
|
dryRun: true,
|
|
173
174
|
action: "upload",
|
|
@@ -190,7 +191,7 @@ export const folderCommands = {
|
|
|
190
191
|
"delete-file": {
|
|
191
192
|
handler: async (c, a, f) => {
|
|
192
193
|
requireArgs(a, 2, "dss folder delete-file <name-or-id> <path>");
|
|
193
|
-
if (f
|
|
194
|
+
if (executionMode(f).dryRun) {
|
|
194
195
|
return { dryRun: true, action: "delete-file", resource: "folder", folder: a[0], path: a[1], };
|
|
195
196
|
}
|
|
196
197
|
await c.folders.deleteFile(await resolveFolderId(c, a[0], f), a[1], f["project-key"]);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { num, } from "../coerce.js";
|
|
2
|
+
import { executionMode, } from "../flags.js";
|
|
2
3
|
import { planResult, } from "../output.js";
|
|
3
4
|
import { requireArgs, } from "../usage.js";
|
|
4
5
|
export const futureCommands = {
|
|
@@ -36,7 +37,7 @@ export const futureCommands = {
|
|
|
36
37
|
handler: async (c, a, f) => {
|
|
37
38
|
requireArgs(a, 1, "dss future abort <id>");
|
|
38
39
|
const id = a[0];
|
|
39
|
-
if (f
|
|
40
|
+
if (executionMode(f).dryRun) {
|
|
40
41
|
return planResult("future", "abort", {
|
|
41
42
|
method: "POST",
|
|
42
43
|
endpoint: `/public/api/futures/${encodeURIComponent(id)}/abort`,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { deepMerge, } from "../../utils/deep-merge.js";
|
|
2
2
|
import { json, jsonInput, parseBooleanOption, textInput, } from "../coerce.js";
|
|
3
|
+
import { executionMode, } from "../flags.js";
|
|
3
4
|
import { readIfExists, skipResult, } from "../output.js";
|
|
4
5
|
import { requireArgs, UsageError, } from "../usage.js";
|
|
5
6
|
export const insightCommands = {
|
|
@@ -40,17 +41,17 @@ export const insightCommands = {
|
|
|
40
41
|
if (params !== undefined)
|
|
41
42
|
prototype.params = params;
|
|
42
43
|
const pk = f["project-key"];
|
|
43
|
-
if (f["if-not-exists"] === true || f
|
|
44
|
+
if (f["if-not-exists"] === true || executionMode(f).dryRun) {
|
|
44
45
|
const existing = name
|
|
45
46
|
? (await c.insights.list(pk)).find((insight) => insight.name === name)
|
|
46
47
|
: undefined;
|
|
47
|
-
if (existing && f["if-not-exists"] === true && f
|
|
48
|
+
if (existing && f["if-not-exists"] === true && !executionMode(f).dryRun) {
|
|
48
49
|
return skipResult("insight", existing.id, "exists", { current: existing, });
|
|
49
50
|
}
|
|
50
|
-
if (f["if-not-exists"] === true && !name && f
|
|
51
|
+
if (f["if-not-exists"] === true && !name && !executionMode(f).dryRun) {
|
|
51
52
|
throw new UsageError("--if-not-exists requires --name for insight create.");
|
|
52
53
|
}
|
|
53
|
-
if (f
|
|
54
|
+
if (executionMode(f).dryRun) {
|
|
54
55
|
return {
|
|
55
56
|
dryRun: true,
|
|
56
57
|
action: "create",
|
|
@@ -95,7 +96,7 @@ export const insightCommands = {
|
|
|
95
96
|
&& contentType === undefined && payload === undefined) {
|
|
96
97
|
throw new UsageError("--name, --listed, --params, --content, --file, --data, --data-file, or --stdin is required.");
|
|
97
98
|
}
|
|
98
|
-
if (f
|
|
99
|
+
if (executionMode(f).dryRun) {
|
|
99
100
|
const current = await c.insights.get(a[0], f["project-key"]);
|
|
100
101
|
const next = deepMerge(current, data ?? {});
|
|
101
102
|
if (name !== undefined)
|
|
@@ -138,11 +139,11 @@ export const insightCommands = {
|
|
|
138
139
|
handler: async (c, a, f) => {
|
|
139
140
|
requireArgs(a, 1, "dss insight delete <id>");
|
|
140
141
|
const pk = f["project-key"];
|
|
141
|
-
if (f
|
|
142
|
+
if (executionMode(f).dryRun || f["if-exists"] === true) {
|
|
142
143
|
const current = await readIfExists(() => c.insights.get(a[0], pk));
|
|
143
144
|
if (!current)
|
|
144
145
|
return skipResult("insight", a[0], "missing");
|
|
145
|
-
if (f
|
|
146
|
+
if (executionMode(f).dryRun) {
|
|
146
147
|
return { dryRun: true, action: "delete", resource: "insight", id: a[0], current, };
|
|
147
148
|
}
|
|
148
149
|
}
|
|
@@ -2,6 +2,7 @@ import { mkdir, writeFile, } from "node:fs/promises";
|
|
|
2
2
|
import { dirname, resolve, } from "node:path";
|
|
3
3
|
import { parseJobLogProgress, } from "../../resources/jobs.js";
|
|
4
4
|
import { jobBuildTargetTypeFromFlags, jobLogFilterFromFlag, maxLogLinesFromFlags, num, plainRecord, } from "../coerce.js";
|
|
5
|
+
import { executionMode, } from "../flags.js";
|
|
5
6
|
import { encodedProjectEndpoint, } from "../output.js";
|
|
6
7
|
import { requireArgs, UsageError, } from "../usage.js";
|
|
7
8
|
// ---------------------------------------------------------------------------
|
|
@@ -276,7 +277,7 @@ export const jobCommands = {
|
|
|
276
277
|
targetType: jobBuildTargetTypeFromFlags(f),
|
|
277
278
|
timeoutMs: num(f["timeout"], "--timeout"),
|
|
278
279
|
};
|
|
279
|
-
if (f
|
|
280
|
+
if (executionMode(f).dryRun) {
|
|
280
281
|
return {
|
|
281
282
|
dryRun: true,
|
|
282
283
|
action: "build",
|
|
@@ -315,7 +316,7 @@ export const jobCommands = {
|
|
|
315
316
|
summary: f["summary"] === true,
|
|
316
317
|
targetType: jobBuildTargetTypeFromFlags(f),
|
|
317
318
|
};
|
|
318
|
-
if (f
|
|
319
|
+
if (executionMode(f).dryRun) {
|
|
319
320
|
return {
|
|
320
321
|
dryRun: true,
|
|
321
322
|
action: "build-and-wait",
|
|
@@ -399,7 +400,7 @@ export const jobCommands = {
|
|
|
399
400
|
handler: async (c, a, f) => {
|
|
400
401
|
requireArgs(a, 1, "dss job abort <id>");
|
|
401
402
|
const pk = f["project-key"];
|
|
402
|
-
if (f
|
|
403
|
+
if (executionMode(f).dryRun) {
|
|
403
404
|
return {
|
|
404
405
|
dryRun: true,
|
|
405
406
|
action: "abort",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsonInput, requiredJsonInput, } from "../coerce.js";
|
|
2
|
+
import { executionMode, } from "../flags.js";
|
|
2
3
|
import { isNotFoundError, planResult, skipResult, } from "../output.js";
|
|
3
4
|
import { requireArgs, } from "../usage.js";
|
|
4
5
|
const MEANING_PLAN_FAILURE_CODES = { usage: 1, error: 2, transient: 3, };
|
|
@@ -40,7 +41,7 @@ export const meaningCommands = {
|
|
|
40
41
|
requireArgs(a, 3, "dss meaning create <id> <label> <type> [--data JSON|--data-file PATH|--stdin] [--dry-run]");
|
|
41
42
|
const body = jsonInput(f) ?? {};
|
|
42
43
|
const payload = meaningCreatePayload(a[0], a[1], a[2], body);
|
|
43
|
-
if (f
|
|
44
|
+
if (executionMode(f).dryRun) {
|
|
44
45
|
return planResult("meaning", "create", {
|
|
45
46
|
asyncKind: "none",
|
|
46
47
|
method: "POST",
|
|
@@ -62,7 +63,7 @@ export const meaningCommands = {
|
|
|
62
63
|
handler: async (c, a, f) => {
|
|
63
64
|
requireArgs(a, 1, "dss meaning update <meaningId> (--data JSON|--data-file PATH|--stdin) [--dry-run]");
|
|
64
65
|
const body = requiredJsonInput(f, "--data, --data-file, or --stdin is required (meaning definition).");
|
|
65
|
-
if (f
|
|
66
|
+
if (executionMode(f).dryRun) {
|
|
66
67
|
return planResult("meaning", "update", {
|
|
67
68
|
asyncKind: "none",
|
|
68
69
|
method: "PUT",
|
|
@@ -83,7 +84,7 @@ export const meaningCommands = {
|
|
|
83
84
|
delete: {
|
|
84
85
|
handler: async (c, a, f) => {
|
|
85
86
|
requireArgs(a, 1, "dss meaning delete <meaningId>");
|
|
86
|
-
if (f
|
|
87
|
+
if (executionMode(f).dryRun || f["if-exists"] === true) {
|
|
87
88
|
const current = await c.meanings.get(a[0]).catch((error) => {
|
|
88
89
|
if (isNotFoundError(error)
|
|
89
90
|
|| (error instanceof Error && /unknown meaning/i.test(error.message))) {
|
|
@@ -93,7 +94,7 @@ export const meaningCommands = {
|
|
|
93
94
|
});
|
|
94
95
|
if (!current)
|
|
95
96
|
return skipResult("meaning", a[0], "missing");
|
|
96
|
-
if (f
|
|
97
|
+
if (executionMode(f).dryRun) {
|
|
97
98
|
return planResult("meaning", "delete", {
|
|
98
99
|
asyncKind: "none",
|
|
99
100
|
method: "DELETE",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { requiredJsonInput, requiredStringFlag, } from "../coerce.js";
|
|
2
|
+
import { executionMode, } from "../flags.js";
|
|
2
3
|
import { requireArgs, UsageError, } from "../usage.js";
|
|
3
4
|
function optionalStringFlag(flags, name) {
|
|
4
5
|
const value = flags[name];
|
|
@@ -127,7 +128,7 @@ export const mlTaskCommands = {
|
|
|
127
128
|
testDatasetRef: optionalStringFlag(f, "test-dataset"),
|
|
128
129
|
projectKey: f["project-key"],
|
|
129
130
|
};
|
|
130
|
-
if (f
|
|
131
|
+
if (executionMode(f).dryRun) {
|
|
131
132
|
return {
|
|
132
133
|
dryRun: true,
|
|
133
134
|
action: "deploy",
|
|
@@ -148,7 +149,7 @@ export const mlTaskCommands = {
|
|
|
148
149
|
handler: async (c, a, f) => {
|
|
149
150
|
requireArgs(a, 2, "dss ml-task delete <analysisId> <mlTaskId> [--dry-run] [--project-key KEY]");
|
|
150
151
|
const projectKey = f["project-key"];
|
|
151
|
-
if (f
|
|
152
|
+
if (executionMode(f).dryRun) {
|
|
152
153
|
return {
|
|
153
154
|
dryRun: true,
|
|
154
155
|
action: "delete",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { requiredStringFlag, } from "../coerce.js";
|
|
2
|
+
import { executionMode, } from "../flags.js";
|
|
2
3
|
import { readIfExists, skipResult, } from "../output.js";
|
|
3
4
|
import { requireArgs, } from "../usage.js";
|
|
4
5
|
export const modelEvaluationStoreCommands = {
|
|
@@ -23,7 +24,7 @@ export const modelEvaluationStoreCommands = {
|
|
|
23
24
|
const name = requiredStringFlag(f, "name", usage);
|
|
24
25
|
const projectKey = f["project-key"];
|
|
25
26
|
const options = { name, projectKey, };
|
|
26
|
-
if (f
|
|
27
|
+
if (executionMode(f).dryRun) {
|
|
27
28
|
return {
|
|
28
29
|
dryRun: true,
|
|
29
30
|
action: "create",
|
|
@@ -56,11 +57,11 @@ export const modelEvaluationStoreCommands = {
|
|
|
56
57
|
handler: async (c, a, f) => {
|
|
57
58
|
requireArgs(a, 1, "dss model-evaluation-store delete <storeId> [--if-exists] [--dry-run] [--project-key KEY]");
|
|
58
59
|
const projectKey = f["project-key"];
|
|
59
|
-
if (f
|
|
60
|
+
if (executionMode(f).dryRun || f["if-exists"] === true) {
|
|
60
61
|
const current = await readIfExists(() => c.modelEvaluationStores.get(a[0], projectKey));
|
|
61
62
|
if (!current)
|
|
62
63
|
return skipResult("model-evaluation-store", a[0], "missing");
|
|
63
|
-
if (f
|
|
64
|
+
if (executionMode(f).dryRun) {
|
|
64
65
|
return {
|
|
65
66
|
dryRun: true,
|
|
66
67
|
action: "delete",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsonInput, num, parseBooleanOption, } from "../coerce.js";
|
|
2
|
+
import { executionMode, } from "../flags.js";
|
|
2
3
|
import { encodedProjectEndpoint, readIfExists, skipResult, } from "../output.js";
|
|
3
4
|
import { requireArgs, requireNoArgs, UsageError, } from "../usage.js";
|
|
4
5
|
export const notebookCommands = {
|
|
@@ -26,11 +27,11 @@ export const notebookCommands = {
|
|
|
26
27
|
handler: async (c, a, f) => {
|
|
27
28
|
requireArgs(a, 1, "dss notebook delete-jupyter <name>");
|
|
28
29
|
const pk = f["project-key"];
|
|
29
|
-
if (f
|
|
30
|
+
if (executionMode(f).dryRun || f["if-exists"] === true) {
|
|
30
31
|
const current = await readIfExists(() => c.notebooks.getJupyter(a[0], pk));
|
|
31
32
|
if (!current)
|
|
32
33
|
return skipResult("jupyter-notebook", a[0], "missing");
|
|
33
|
-
if (f
|
|
34
|
+
if (executionMode(f).dryRun) {
|
|
34
35
|
return { dryRun: true, action: "delete", resource: "jupyter-notebook", name: a[0], current, };
|
|
35
36
|
}
|
|
36
37
|
}
|
|
@@ -45,7 +46,7 @@ export const notebookCommands = {
|
|
|
45
46
|
handler: async (c, a, f) => {
|
|
46
47
|
requireArgs(a, 1, "dss notebook clear-jupyter-outputs <name>");
|
|
47
48
|
const pk = f["project-key"];
|
|
48
|
-
if (f
|
|
49
|
+
if (executionMode(f).dryRun) {
|
|
49
50
|
// The real mutation is a single server-side DELETE of the
|
|
50
51
|
// outputs endpoint, so the dry run can only report the current
|
|
51
52
|
// content (read-only) and the exact request that would run; the
|
|
@@ -82,7 +83,7 @@ export const notebookCommands = {
|
|
|
82
83
|
const pk = f["project-key"];
|
|
83
84
|
if (f["all"] === true) {
|
|
84
85
|
requireNoArgs(a, "dss notebook unload-jupyter --all [--dry-run] [--project-key KEY]");
|
|
85
|
-
if (f
|
|
86
|
+
if (executionMode(f).dryRun) {
|
|
86
87
|
const planned = [];
|
|
87
88
|
for (const notebook of await c.notebooks.listJupyter(pk, { active: true, })) {
|
|
88
89
|
for (const session of await c.notebooks.listJupyterSessions(notebook.name, pk)) {
|
|
@@ -106,7 +107,7 @@ export const notebookCommands = {
|
|
|
106
107
|
return { unloaded, resource: "jupyter-notebook", all: true, };
|
|
107
108
|
}
|
|
108
109
|
requireArgs(a, 2, "dss notebook unload-jupyter <name> <sessionId>");
|
|
109
|
-
if (f
|
|
110
|
+
if (executionMode(f).dryRun) {
|
|
110
111
|
const sessions = await c.notebooks.listJupyterSessions(a[0], pk);
|
|
111
112
|
const current = sessions.find((session) => session.sessionId === a[1]);
|
|
112
113
|
return {
|
|
@@ -149,11 +150,11 @@ export const notebookCommands = {
|
|
|
149
150
|
handler: async (c, a, f) => {
|
|
150
151
|
requireArgs(a, 1, "dss notebook delete-sql <id>");
|
|
151
152
|
const pk = f["project-key"];
|
|
152
|
-
if (f
|
|
153
|
+
if (executionMode(f).dryRun || f["if-exists"] === true) {
|
|
153
154
|
const current = await readIfExists(() => c.notebooks.getSql(a[0], pk));
|
|
154
155
|
if (!current)
|
|
155
156
|
return skipResult("sql-notebook", a[0], "missing");
|
|
156
|
-
if (f
|
|
157
|
+
if (executionMode(f).dryRun) {
|
|
157
158
|
return { dryRun: true, action: "delete", resource: "sql-notebook", id: a[0], current, };
|
|
158
159
|
}
|
|
159
160
|
}
|
|
@@ -181,7 +182,7 @@ export const notebookCommands = {
|
|
|
181
182
|
throw new UsageError("--data, --data-file, or --stdin is required (notebook JSON content).");
|
|
182
183
|
}
|
|
183
184
|
const pk = f["project-key"];
|
|
184
|
-
if (f
|
|
185
|
+
if (executionMode(f).dryRun) {
|
|
185
186
|
const current = await readIfExists(() => c.notebooks.getJupyter(a[0], pk));
|
|
186
187
|
return {
|
|
187
188
|
dryRun: true,
|
|
@@ -217,7 +218,7 @@ export const notebookCommands = {
|
|
|
217
218
|
throw new UsageError("--data, --data-file, or --stdin is required (SQL notebook content JSON).");
|
|
218
219
|
}
|
|
219
220
|
const pk = f["project-key"];
|
|
220
|
-
if (f
|
|
221
|
+
if (executionMode(f).dryRun) {
|
|
221
222
|
const current = await readIfExists(() => c.notebooks.getSql(a[0], pk));
|
|
222
223
|
return {
|
|
223
224
|
dryRun: true,
|
|
@@ -251,7 +252,7 @@ export const notebookCommands = {
|
|
|
251
252
|
numRunsToRetain: num(f["retain"], "--retain"),
|
|
252
253
|
projectKey: pk,
|
|
253
254
|
};
|
|
254
|
-
if (f
|
|
255
|
+
if (executionMode(f).dryRun) {
|
|
255
256
|
const current = await c.notebooks.getSqlHistory(a[0], pk);
|
|
256
257
|
return {
|
|
257
258
|
dryRun: true,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import { encodeLibraryPath, EXPECT_SHA256_PATTERN, validateLibraryDestinationPath, validateLibraryName, validateLibraryPath, } from "../../resources/project-library.js";
|
|
3
3
|
import { numFlag, readStdinText, sha256Hex, } from "../coerce.js";
|
|
4
|
+
import { executionMode, } from "../flags.js";
|
|
4
5
|
import { encodedProjectEndpoint, planResult, skipResult, } from "../output.js";
|
|
5
6
|
import { requireArgs, UsageError, } from "../usage.js";
|
|
6
7
|
const PROJECT_LIBRARY_EXIT_CODES = { usage: 1, error: 2, transient: 3, };
|
|
@@ -100,7 +101,7 @@ export const projectLibraryCommands = {
|
|
|
100
101
|
requireArgs(a, 1, "dss project-library create-file <path> [--if-not-exists] [--dry-run] [--project-key KEY]");
|
|
101
102
|
const pk = f["project-key"];
|
|
102
103
|
validateLibraryPath(a[0]);
|
|
103
|
-
if (f
|
|
104
|
+
if (executionMode(f).dryRun) {
|
|
104
105
|
return projectLibraryPlan("create-file", {
|
|
105
106
|
method: "POST",
|
|
106
107
|
endpoint: projectLibraryContentsEndpoint(c, pk, a[0]),
|
|
@@ -126,7 +127,7 @@ export const projectLibraryCommands = {
|
|
|
126
127
|
requireArgs(a, 1, "dss project-library create-folder <path> [--if-not-exists] [--dry-run] [--project-key KEY]");
|
|
127
128
|
const pk = f["project-key"];
|
|
128
129
|
validateLibraryPath(a[0]);
|
|
129
|
-
if (f
|
|
130
|
+
if (executionMode(f).dryRun) {
|
|
130
131
|
return projectLibraryPlan("create-folder", {
|
|
131
132
|
method: "POST",
|
|
132
133
|
endpoint: projectLibraryFolderEndpoint(c, pk, a[0]),
|
|
@@ -153,7 +154,7 @@ export const projectLibraryCommands = {
|
|
|
153
154
|
const pk = f["project-key"];
|
|
154
155
|
const expectSha256 = expectSha256FromFlags(f);
|
|
155
156
|
validateLibraryPath(a[0]);
|
|
156
|
-
if (f
|
|
157
|
+
if (executionMode(f).dryRun) {
|
|
157
158
|
return projectLibraryPlan("put", {
|
|
158
159
|
method: "POST",
|
|
159
160
|
endpoint: projectLibraryContentsEndpoint(c, pk, a[0]),
|
|
@@ -206,7 +207,7 @@ export const projectLibraryCommands = {
|
|
|
206
207
|
requireArgs(a, 1, "dss project-library delete <path> [--dry-run] [--project-key KEY]");
|
|
207
208
|
const pk = f["project-key"];
|
|
208
209
|
validateLibraryPath(a[0]);
|
|
209
|
-
if (f
|
|
210
|
+
if (executionMode(f).dryRun) {
|
|
210
211
|
return projectLibraryPlan("delete", {
|
|
211
212
|
method: "DELETE",
|
|
212
213
|
endpoint: projectLibraryContentsEndpoint(c, pk, a[0]),
|
|
@@ -226,7 +227,7 @@ export const projectLibraryCommands = {
|
|
|
226
227
|
const pk = f["project-key"];
|
|
227
228
|
const validPath = validateLibraryPath(a[0]);
|
|
228
229
|
const validName = validateLibraryName(a[1]);
|
|
229
|
-
if (f
|
|
230
|
+
if (executionMode(f).dryRun) {
|
|
230
231
|
return projectLibraryPlan("rename", {
|
|
231
232
|
method: "POST",
|
|
232
233
|
endpoint: projectLibraryActionEndpoint(c, pk, "rename/"),
|
|
@@ -247,7 +248,7 @@ export const projectLibraryCommands = {
|
|
|
247
248
|
const pk = f["project-key"];
|
|
248
249
|
const validPath = validateLibraryPath(a[0]);
|
|
249
250
|
const destination = validateLibraryDestinationPath(a[1]);
|
|
250
|
-
if (f
|
|
251
|
+
if (executionMode(f).dryRun) {
|
|
251
252
|
return projectLibraryPlan("move", {
|
|
252
253
|
method: "POST",
|
|
253
254
|
endpoint: projectLibraryActionEndpoint(c, pk, "move"),
|
|
@@ -3,6 +3,7 @@ import { deepMerge, } from "../../utils/deep-merge.js";
|
|
|
3
3
|
import { inspectProjectArchive, } from "../../utils/project-archive.js";
|
|
4
4
|
import { projectIncarnationHash, } from "../../utils/project-incarnation.js";
|
|
5
5
|
import { jsonInput, num, requiredJsonInput, requiredStringFlag, } from "../coerce.js";
|
|
6
|
+
import { executionMode, } from "../flags.js";
|
|
6
7
|
import { CommandResultFailure, } from "../output.js";
|
|
7
8
|
import { requireArgs, UsageError, } from "../usage.js";
|
|
8
9
|
const INSPECT_ARCHIVE_USAGE = "dss project inspect-archive <file>";
|
|
@@ -91,7 +92,7 @@ export const projectCommands = {
|
|
|
91
92
|
throw new UsageError("--expect-project-incarnation must be a 64-character lowercase SHA-256 hash.", "validation_failed");
|
|
92
93
|
}
|
|
93
94
|
const guarded = f["if-exists"] === true
|
|
94
|
-
|| f
|
|
95
|
+
|| executionMode(f).dryRun
|
|
95
96
|
|| expectedIncarnation !== undefined;
|
|
96
97
|
if (!guarded) {
|
|
97
98
|
// Purely user-requested delete without any guard flag: keep the
|
|
@@ -128,7 +129,7 @@ export const projectCommands = {
|
|
|
128
129
|
}
|
|
129
130
|
throw error;
|
|
130
131
|
}
|
|
131
|
-
if (f
|
|
132
|
+
if (executionMode(f).dryRun) {
|
|
132
133
|
return {
|
|
133
134
|
deleted: false,
|
|
134
135
|
dryRun: true,
|
|
@@ -3,6 +3,7 @@ import { writeFile, } from "node:fs/promises";
|
|
|
3
3
|
import { join, } from "node:path";
|
|
4
4
|
import { deepMerge, } from "../../utils/deep-merge.js";
|
|
5
5
|
import { jobLogFilterFromFlag, jsonInput, maxLogLinesFromFlags, normalizeLineEndings, num, recipeInputDatasetsFromFlags, requiredStringFlag, rewritePairsFromFlags, sha256Hex, splitCsvFlag, stableHash, } from "../coerce.js";
|
|
6
|
+
import { executionMode, } from "../flags.js";
|
|
6
7
|
import { moveCreatedItemsToZone, resolveFlowZoneIdFromFlags, } from "../helpers/flow-zone.js";
|
|
7
8
|
import { ensureRecipeBackupDir, readRecipeBackup, recipeBackupDocument, recipeBackupPath, recipeCodeEnv, recipeGraph, recipeInputItemRef, recipeRoleInputItems, recipeRunShouldWait, writeRecipeBackup, } from "../helpers/recipe.js";
|
|
8
9
|
import { encodedProjectEndpoint, readIfExists, skipResult, } from "../output.js";
|
|
@@ -109,7 +110,7 @@ export const recipeCommands = {
|
|
|
109
110
|
summary: f["summary"] === true,
|
|
110
111
|
wait,
|
|
111
112
|
};
|
|
112
|
-
if (f
|
|
113
|
+
if (executionMode(f).dryRun) {
|
|
113
114
|
const outputs = await c.recipes.resolveRunOutputs(a[0], {
|
|
114
115
|
partition: options.partition,
|
|
115
116
|
projectKey: pk,
|
|
@@ -139,11 +140,11 @@ export const recipeCommands = {
|
|
|
139
140
|
handler: async (c, a, f) => {
|
|
140
141
|
requireArgs(a, 1, "dss recipe delete <name>");
|
|
141
142
|
const pk = f["project-key"];
|
|
142
|
-
if (f
|
|
143
|
+
if (executionMode(f).dryRun || f["if-exists"] === true) {
|
|
143
144
|
const current = await readIfExists(() => c.recipes.get(a[0], { projectKey: pk, includePayload: true, }));
|
|
144
145
|
if (!current)
|
|
145
146
|
return skipResult("recipe", a[0], "missing");
|
|
146
|
-
if (f
|
|
147
|
+
if (executionMode(f).dryRun) {
|
|
147
148
|
return { dryRun: true, action: "delete", resource: "recipe", name: a[0], current, };
|
|
148
149
|
}
|
|
149
150
|
}
|
|
@@ -241,13 +242,13 @@ export const recipeCommands = {
|
|
|
241
242
|
const zoneMove = zoneId && name
|
|
242
243
|
? [{ objectId: name, objectType: "RECIPE", },]
|
|
243
244
|
: undefined;
|
|
244
|
-
if ((f["if-not-exists"] === true || f
|
|
245
|
+
if ((f["if-not-exists"] === true || executionMode(f).dryRun) && name) {
|
|
245
246
|
const list = await c.recipes.list(pk);
|
|
246
247
|
const existing = list.find((r) => r.name === name);
|
|
247
|
-
if (existing && f["if-not-exists"] === true && f
|
|
248
|
+
if (existing && f["if-not-exists"] === true && !executionMode(f).dryRun) {
|
|
248
249
|
return skipResult("recipe", name, "exists", { current: existing, });
|
|
249
250
|
}
|
|
250
|
-
if (f
|
|
251
|
+
if (executionMode(f).dryRun) {
|
|
251
252
|
return {
|
|
252
253
|
dryRun: true,
|
|
253
254
|
action: "create",
|
|
@@ -259,7 +260,7 @@ export const recipeCommands = {
|
|
|
259
260
|
};
|
|
260
261
|
}
|
|
261
262
|
}
|
|
262
|
-
if (f
|
|
263
|
+
if (executionMode(f).dryRun) {
|
|
263
264
|
return {
|
|
264
265
|
dryRun: true,
|
|
265
266
|
action: "create",
|
|
@@ -328,7 +329,7 @@ export const recipeCommands = {
|
|
|
328
329
|
throw new UsageError("Cannot reuse --path or --metastore-table for multiple cloned output datasets.", "invalid_enum");
|
|
329
330
|
}
|
|
330
331
|
const zoneId = await resolveFlowZoneIdFromFlags(c, f, pk);
|
|
331
|
-
if (f
|
|
332
|
+
if (executionMode(f).dryRun) {
|
|
332
333
|
return {
|
|
333
334
|
dryRun: true,
|
|
334
335
|
action: "clone",
|
|
@@ -391,7 +392,7 @@ export const recipeCommands = {
|
|
|
391
392
|
throw new UsageError("--data, --data-file, or --stdin is required. Usage: dss recipe update <name> [--data '{...}' | --data-file PATH | --stdin]");
|
|
392
393
|
}
|
|
393
394
|
const pk = f["project-key"];
|
|
394
|
-
if (f
|
|
395
|
+
if (executionMode(f).dryRun) {
|
|
395
396
|
const current = await c.recipes.get(a[0], { projectKey: pk, includePayload: true, });
|
|
396
397
|
const currentRecipe = current.recipe;
|
|
397
398
|
const next = {
|
|
@@ -430,7 +431,7 @@ export const recipeCommands = {
|
|
|
430
431
|
}
|
|
431
432
|
const nextItems = [...items, { ref: a[1], deps: [], },];
|
|
432
433
|
const inputs = nextItems.map(recipeInputItemRef).filter((ref) => Boolean(ref));
|
|
433
|
-
if (f
|
|
434
|
+
if (executionMode(f).dryRun) {
|
|
434
435
|
return {
|
|
435
436
|
dryRun: true,
|
|
436
437
|
action: "add-input",
|
|
@@ -467,7 +468,7 @@ export const recipeCommands = {
|
|
|
467
468
|
}
|
|
468
469
|
const nextItems = items.filter((item) => recipeInputItemRef(item) !== a[1]);
|
|
469
470
|
const inputs = nextItems.map(recipeInputItemRef).filter((ref) => Boolean(ref));
|
|
470
|
-
if (f
|
|
471
|
+
if (executionMode(f).dryRun) {
|
|
471
472
|
return {
|
|
472
473
|
dryRun: true,
|
|
473
474
|
action: "remove-input",
|
|
@@ -542,7 +543,7 @@ export const recipeCommands = {
|
|
|
542
543
|
projectKey: pk,
|
|
543
544
|
includePayload: true,
|
|
544
545
|
});
|
|
545
|
-
if (f
|
|
546
|
+
if (executionMode(f).dryRun) {
|
|
546
547
|
return {
|
|
547
548
|
dryRun: true,
|
|
548
549
|
action: "set-payload",
|
|
@@ -593,7 +594,7 @@ export const recipeCommands = {
|
|
|
593
594
|
const next = f["payload-only"] === true || !restoredRecipe
|
|
594
595
|
? { ...current, payload, }
|
|
595
596
|
: { ...current, recipe: restoredRecipe, payload, };
|
|
596
|
-
if (f
|
|
597
|
+
if (executionMode(f).dryRun) {
|
|
597
598
|
return {
|
|
598
599
|
dryRun: true,
|
|
599
600
|
action: "restore",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { executionMode, } from "../flags.js";
|
|
1
2
|
import { readIfExists, skipResult, } from "../output.js";
|
|
2
3
|
import { requireArgs, } from "../usage.js";
|
|
3
4
|
export const savedModelCommands = {
|
|
@@ -40,7 +41,7 @@ export const savedModelCommands = {
|
|
|
40
41
|
handler: async (c, a, f) => {
|
|
41
42
|
requireArgs(a, 2, "dss saved-model set-active <modelId> <versionId> [--dry-run] [--project-key KEY]");
|
|
42
43
|
const projectKey = f["project-key"];
|
|
43
|
-
if (f
|
|
44
|
+
if (executionMode(f).dryRun) {
|
|
44
45
|
return {
|
|
45
46
|
dryRun: true,
|
|
46
47
|
action: "set-active",
|
|
@@ -64,11 +65,11 @@ export const savedModelCommands = {
|
|
|
64
65
|
handler: async (c, a, f) => {
|
|
65
66
|
requireArgs(a, 1, "dss saved-model delete <modelId> [--if-exists] [--dry-run] [--project-key KEY]");
|
|
66
67
|
const projectKey = f["project-key"];
|
|
67
|
-
if (f
|
|
68
|
+
if (executionMode(f).dryRun || f["if-exists"] === true) {
|
|
68
69
|
const current = await readIfExists(() => c.savedModels.get(a[0], projectKey));
|
|
69
70
|
if (!current)
|
|
70
71
|
return skipResult("saved-model", a[0], "missing");
|
|
71
|
-
if (f
|
|
72
|
+
if (executionMode(f).dryRun) {
|
|
72
73
|
return { dryRun: true, action: "delete", resource: "saved-model", id: a[0], current, };
|
|
73
74
|
}
|
|
74
75
|
}
|