@toloka-platform/sdk 0.1.0-preview.9 → 0.1.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 +5 -4
- package/dist/cli/toloka.js +138 -136
- package/dist/cli/toloka.js.jsc +0 -0
- package/dist/cli/toloka.js.jsc.sha256 +1 -1
- package/dist/cli/toloka.js.sha256 +1 -1
- package/docs/authoring.md +9 -4
- package/docs/cli-v2.md +2 -2
- package/docs/cli.md +13 -2
- package/docs/getting-started.md +3 -3
- package/docs/limitations.md +2 -2
- package/package.json +3 -3
- package/skills/catalog.json +4 -4
- package/skills/toloka-build/SKILL.md +1 -1
- package/skills/toloka-build/references/node-semantics.md +2 -2
- package/skills/toloka-build/references/workflow-and-cli.md +2 -1
- package/skills/toloka-report-issue/references/report-template.md +1 -1
- package/src/authoring/index.ts +10 -0
- package/src/cli/auto-update.ts +1 -5
- package/src/cli/check.ts +91 -30
- package/src/cli/cost.ts +7 -1
- package/src/cli/program.ts +28 -2
- package/src/cli/project-context.ts +47 -2
- package/src/cli/project.ts +53 -10
- package/src/cli/version.ts +68 -0
- package/src/index.ts +2 -0
package/src/cli/project.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { dirname, join, resolve } from "node:path";
|
|
|
4
4
|
import type {
|
|
5
5
|
PipelineGraphSnapshot,
|
|
6
6
|
PipelineGraphV1,
|
|
7
|
+
PipelineValidationIssue,
|
|
7
8
|
PipelineValidationReport,
|
|
8
9
|
} from "../../openapi/gen/models";
|
|
9
10
|
import { resolvePipelineDefinition, validatePipelineDefinition } from "../authoring";
|
|
@@ -83,10 +84,13 @@ export type ApplyProjectResult = {
|
|
|
83
84
|
|
|
84
85
|
export type ValidateProjectOptions = PlanProjectOptions;
|
|
85
86
|
|
|
87
|
+
export type PipelineValidationStatus = "valid" | "invalid" | "checks_pending";
|
|
88
|
+
|
|
86
89
|
export type PipelineValidationResult = {
|
|
87
90
|
readonly sourceDirectory: string;
|
|
88
91
|
readonly pipelineId?: string;
|
|
89
92
|
readonly report?: PipelineValidationReport;
|
|
93
|
+
readonly status?: PipelineValidationStatus;
|
|
90
94
|
readonly skipped?: string;
|
|
91
95
|
};
|
|
92
96
|
|
|
@@ -860,10 +864,47 @@ export async function applyProject(
|
|
|
860
864
|
const issueLocation = (issue: { nodeId?: string; checkId?: string }) =>
|
|
861
865
|
[issue.nodeId, issue.checkId].filter((value): value is string => value !== undefined).join("/");
|
|
862
866
|
|
|
867
|
+
const PENDING_CHECK_CODE = "not_ran_node_check";
|
|
868
|
+
|
|
869
|
+
const normalizeValidationIssue = (issue: PipelineValidationIssue): PipelineValidationIssue =>
|
|
870
|
+
issue.code === "empty_node_checks"
|
|
871
|
+
? { ...issue, message: "No stored check cases are configured for this node" }
|
|
872
|
+
: issue;
|
|
873
|
+
|
|
874
|
+
const normalizeValidationReport = (
|
|
875
|
+
report: PipelineValidationReport,
|
|
876
|
+
): { readonly report: PipelineValidationReport; readonly status: PipelineValidationStatus } => {
|
|
877
|
+
const seen = new Set<string>();
|
|
878
|
+
const issues = report.issues.flatMap((rawIssue) => {
|
|
879
|
+
const issue = normalizeValidationIssue(rawIssue);
|
|
880
|
+
const key = [
|
|
881
|
+
issue.code,
|
|
882
|
+
issue.severity,
|
|
883
|
+
issue.nodeId ?? "",
|
|
884
|
+
issue.checkId ?? "",
|
|
885
|
+
issue.message,
|
|
886
|
+
].join("\n");
|
|
887
|
+
if (seen.has(key)) return [];
|
|
888
|
+
seen.add(key);
|
|
889
|
+
return [issue];
|
|
890
|
+
});
|
|
891
|
+
const pending = issues.some((issue) => issue.code === PENDING_CHECK_CODE);
|
|
892
|
+
const blocking = issues.some(
|
|
893
|
+
(issue) => issue.severity === "error" && issue.code !== PENDING_CHECK_CODE,
|
|
894
|
+
);
|
|
895
|
+
const status: PipelineValidationStatus =
|
|
896
|
+
blocking || (!report.valid && !pending) ? "invalid" : pending ? "checks_pending" : "valid";
|
|
897
|
+
return {
|
|
898
|
+
status,
|
|
899
|
+
report: { ...report, valid: status !== "invalid", issues },
|
|
900
|
+
};
|
|
901
|
+
};
|
|
902
|
+
|
|
863
903
|
const formatValidationIssues = (report: PipelineValidationReport) =>
|
|
864
904
|
report.issues.map((issue) => {
|
|
865
905
|
const location = issueLocation(issue);
|
|
866
|
-
|
|
906
|
+
const severity = issue.code === PENDING_CHECK_CODE ? "pending" : issue.severity;
|
|
907
|
+
return ` ${severity} ${issue.code}${location.length === 0 ? "" : ` ${location}`}: ${issue.message}`;
|
|
867
908
|
});
|
|
868
909
|
|
|
869
910
|
export async function validateProject(
|
|
@@ -898,24 +939,26 @@ export async function validateProject(
|
|
|
898
939
|
resolvePipelineDefinition(pipeline.source.definition, { datasetId: dataset.id }),
|
|
899
940
|
pipeline.snapshot.graph,
|
|
900
941
|
);
|
|
901
|
-
const
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
942
|
+
const normalized = normalizeValidationReport(
|
|
943
|
+
await client.pipelines.validateGraph({
|
|
944
|
+
pipelineId: pipeline.pipeline.id,
|
|
945
|
+
graph,
|
|
946
|
+
}),
|
|
947
|
+
);
|
|
905
948
|
results.push({
|
|
906
949
|
sourceDirectory: pipeline.source.sourceDirectory,
|
|
907
950
|
pipelineId: pipeline.pipeline.id,
|
|
908
|
-
report,
|
|
951
|
+
report: normalized.report,
|
|
952
|
+
status: normalized.status,
|
|
909
953
|
});
|
|
910
954
|
}
|
|
911
|
-
const valid = results.every((result) => result.
|
|
955
|
+
const valid = results.every((result) => result.status !== "invalid");
|
|
912
956
|
const lines = results.flatMap((result) => {
|
|
913
957
|
if (result.skipped !== undefined)
|
|
914
958
|
return [`- ${result.sourceDirectory}: skipped (${result.skipped})`];
|
|
915
959
|
assert(result.report, `Pipeline ${result.sourceDirectory} is missing a validation report`);
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
: `- ${result.sourceDirectory}: invalid`;
|
|
960
|
+
assert(result.status, `Pipeline ${result.sourceDirectory} is missing a validation status`);
|
|
961
|
+
const header = `- ${result.sourceDirectory}: ${result.status.replace("_", "-")}`;
|
|
919
962
|
return [header, ...formatValidationIssues(result.report)];
|
|
920
963
|
});
|
|
921
964
|
return {
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { realpathSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join, resolve, sep } from "node:path";
|
|
4
|
+
|
|
5
|
+
import { assert } from "es-toolkit";
|
|
6
|
+
import { SDK_VERSION } from "./init";
|
|
7
|
+
|
|
8
|
+
export type CliInstallChannel = "global-registry" | "linked" | "project-local";
|
|
9
|
+
|
|
10
|
+
type VersionInfoOptions = {
|
|
11
|
+
readonly globalBinDirectory?: string;
|
|
12
|
+
readonly globalPackageDirectory?: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const GLOBAL_PACKAGE_MARKER = `${sep}install${sep}global${sep}`;
|
|
16
|
+
|
|
17
|
+
const realpathOrSelf = (path: string): string => {
|
|
18
|
+
try {
|
|
19
|
+
return realpathSync(path);
|
|
20
|
+
} catch {
|
|
21
|
+
return path;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const classifyInstallChannel = (
|
|
26
|
+
entryPath: string,
|
|
27
|
+
packageRoot: string,
|
|
28
|
+
globalBinDirectory: string,
|
|
29
|
+
globalPackageDirectory: string,
|
|
30
|
+
): CliInstallChannel => {
|
|
31
|
+
const resolvedEntryPath = realpathOrSelf(entryPath);
|
|
32
|
+
if (resolvedEntryPath.includes(GLOBAL_PACKAGE_MARKER)) return "global-registry";
|
|
33
|
+
if (realpathOrSelf(globalPackageDirectory) === packageRoot) return "linked";
|
|
34
|
+
if (dirname(resolve(entryPath)) === resolve(globalBinDirectory)) return "linked";
|
|
35
|
+
return "project-local";
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const cliVersionInfo = (entryPath = process.argv[1], options: VersionInfoOptions = {}) => {
|
|
39
|
+
assert(entryPath, "CLI entry path is unavailable");
|
|
40
|
+
const globalBinDirectory =
|
|
41
|
+
options.globalBinDirectory ??
|
|
42
|
+
resolve(process.env.BUN_INSTALL ?? join(homedir(), ".bun"), "bin");
|
|
43
|
+
const globalPackageDirectory =
|
|
44
|
+
options.globalPackageDirectory ??
|
|
45
|
+
resolve(
|
|
46
|
+
globalBinDirectory,
|
|
47
|
+
"..",
|
|
48
|
+
"install",
|
|
49
|
+
"global",
|
|
50
|
+
"node_modules",
|
|
51
|
+
"@toloka-platform",
|
|
52
|
+
"sdk",
|
|
53
|
+
);
|
|
54
|
+
const packageRoot = resolve(dirname(realpathOrSelf(entryPath)), "..");
|
|
55
|
+
const channel = classifyInstallChannel(
|
|
56
|
+
entryPath,
|
|
57
|
+
packageRoot,
|
|
58
|
+
globalBinDirectory,
|
|
59
|
+
globalPackageDirectory,
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
version: SDK_VERSION,
|
|
64
|
+
commit: process.env.TOLOKA_BUILD_COMMIT ?? null,
|
|
65
|
+
channel,
|
|
66
|
+
...(channel === "linked" ? { path: packageRoot } : {}),
|
|
67
|
+
};
|
|
68
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -69,6 +69,7 @@ export {
|
|
|
69
69
|
connect,
|
|
70
70
|
definePipeline,
|
|
71
71
|
field,
|
|
72
|
+
optional,
|
|
72
73
|
generation,
|
|
73
74
|
isPipelineDefinition,
|
|
74
75
|
match,
|
|
@@ -91,6 +92,7 @@ export type {
|
|
|
91
92
|
InputPort,
|
|
92
93
|
MatchAuthoringSettings,
|
|
93
94
|
OutputPort,
|
|
95
|
+
OptionalFieldBinding,
|
|
94
96
|
PipelineDefinition,
|
|
95
97
|
PipelineDefinitionBindings,
|
|
96
98
|
PipelineDefinitionInput,
|