@trayai/tray-sync-cli 1.0.12 → 1.0.13

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.
@@ -0,0 +1,38 @@
1
+ export async function getWorkflow(client, workflowId) {
2
+ return (await client.request("GET", `/v2/workflows/${workflowId}`));
3
+ }
4
+ export async function setWorkflowEnabled(client, workflowId, enabled) {
5
+ await client.request("PUT", `/v2/workflows/${workflowId}/unversioned`, { enabled });
6
+ }
7
+ export async function deleteWorkflow(client, workflowId) {
8
+ await client.request("DELETE", `/v2/workflows/${workflowId}`);
9
+ }
10
+ const EDITABLE_FIELDS = new Set([
11
+ "name",
12
+ "description",
13
+ "tags",
14
+ "alerting_workflow",
15
+ "legacy_error_handling",
16
+ ]);
17
+ export function assertValidWorkflowEditPayload(payload) {
18
+ const unknownKeys = Object.keys(payload).filter((key) => !EDITABLE_FIELDS.has(key));
19
+ if (unknownKeys.length > 0) {
20
+ throw new Error(`Unknown field(s) in edit payload: ${unknownKeys.join(", ")}. ` +
21
+ `Editable fields are: ${[...EDITABLE_FIELDS].join(", ")}.`);
22
+ }
23
+ }
24
+ export async function updateWorkflowUnversioned(client, workflowId, payload) {
25
+ const body = {};
26
+ if (payload.name !== undefined)
27
+ body.name = payload.name;
28
+ if (payload.description !== undefined)
29
+ body.description = { value: payload.description };
30
+ if (payload.tags !== undefined)
31
+ body.tags = payload.tags;
32
+ if (payload.alerting_workflow !== undefined)
33
+ body.alerting_workflow = { value: payload.alerting_workflow };
34
+ if (payload.legacy_error_handling !== undefined)
35
+ body.legacy_error_handling = payload.legacy_error_handling;
36
+ await client.request("PUT", `/v2/workflows/${workflowId}/unversioned`, body);
37
+ }
38
+ //# sourceMappingURL=workflow.js.map
@@ -1,5 +1,7 @@
1
1
  import { Command } from "commander";
2
2
  import { projectCommand } from "./project.js";
3
+ import { workflowCommand } from "./workflow.js";
3
4
  export const apiCommand = new Command("api").description("Direct, authenticated access to the Tray API");
4
5
  apiCommand.addCommand(projectCommand);
6
+ apiCommand.addCommand(workflowCommand);
5
7
  //# sourceMappingURL=api.js.map
@@ -0,0 +1,166 @@
1
+ import { Command, InvalidArgumentError } from "commander";
2
+ import ansis from "ansis";
3
+ import { assertValidWorkflowEditPayload, deleteWorkflow, getWorkflow, setWorkflowEnabled, updateWorkflowUnversioned, } from "../../api/resources/workflow.js";
4
+ import { isUuid } from "../../lib/uuid.js";
5
+ import { OutputFormats } from "../../lib/outputFormat.js";
6
+ import { printWorkflowDeletedResult, printWorkflowEditedResult, printWorkflowEnabledResult, printWorkflowShowResult, } from "../../views/api/workflow.v2.js";
7
+ import { printConfirmationJson } from "../../views/api/shared.js";
8
+ import { FAILURE_ICON } from "../../views/icons.js";
9
+ import { COMMAND_COLOR } from "../../views/help.js";
10
+ import { addCommonApiOptions, apiClientFor, realDeps, runApiAction, } from "./shared.js";
11
+ async function runWorkflowSetEnabled(deps, options, enabled) {
12
+ const client = apiClientFor(deps, options);
13
+ await setWorkflowEnabled(client, options.workflowId, enabled);
14
+ if (options.format === OutputFormats.JSON) {
15
+ printConfirmationJson(deps.stdout, { workflowId: options.workflowId, enabled });
16
+ }
17
+ else {
18
+ printWorkflowEnabledResult(deps.stdout, options.workflowId, enabled);
19
+ }
20
+ return 0;
21
+ }
22
+ export async function runWorkflowEnable(deps, options) {
23
+ return runWorkflowSetEnabled(deps, options, true);
24
+ }
25
+ export async function runWorkflowDisable(deps, options) {
26
+ return runWorkflowSetEnabled(deps, options, false);
27
+ }
28
+ export async function runWorkflowShow(deps, options) {
29
+ const client = apiClientFor(deps, options);
30
+ const workflow = await getWorkflow(client, options.workflowId);
31
+ if (options.format === OutputFormats.JSON) {
32
+ deps.stdout(JSON.stringify(workflow, null, 2));
33
+ }
34
+ else {
35
+ printWorkflowShowResult(deps.stdout, options.workflowId, workflow);
36
+ }
37
+ return 0;
38
+ }
39
+ export async function runWorkflowDelete(deps, options) {
40
+ const client = apiClientFor(deps, options);
41
+ await deleteWorkflow(client, options.workflowId);
42
+ if (options.format === OutputFormats.JSON) {
43
+ printConfirmationJson(deps.stdout, { workflowId: options.workflowId, deleted: true });
44
+ }
45
+ else {
46
+ printWorkflowDeletedResult(deps.stdout, options.workflowId);
47
+ }
48
+ return 0;
49
+ }
50
+ export async function runWorkflowEdit(deps, options) {
51
+ if (Object.keys(options.payload).length === 0) {
52
+ deps.stderr(`${FAILURE_ICON} Nothing to edit — payload has no fields.`);
53
+ return 1;
54
+ }
55
+ const client = apiClientFor(deps, options);
56
+ await updateWorkflowUnversioned(client, options.workflowId, options.payload);
57
+ if (options.format === OutputFormats.JSON) {
58
+ printConfirmationJson(deps.stdout, { workflowId: options.workflowId, edited: true });
59
+ }
60
+ else {
61
+ printWorkflowEditedResult(deps.stdout, options.workflowId);
62
+ }
63
+ return 0;
64
+ }
65
+ function parseWorkflowId(value) {
66
+ if (!isUuid(value)) {
67
+ throw new InvalidArgumentError("workflow id must be a UUID");
68
+ }
69
+ return value;
70
+ }
71
+ function parseEditPayload(value) {
72
+ let parsed;
73
+ try {
74
+ parsed = JSON.parse(value);
75
+ }
76
+ catch (err) {
77
+ throw new InvalidArgumentError(`payload is not valid JSON: ${err.message}`);
78
+ }
79
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
80
+ throw new InvalidArgumentError("payload must be a JSON object");
81
+ }
82
+ const record = parsed;
83
+ try {
84
+ assertValidWorkflowEditPayload(record);
85
+ }
86
+ catch (err) {
87
+ throw new InvalidArgumentError(err.message);
88
+ }
89
+ return record;
90
+ }
91
+ export const workflowCommand = new Command("workflow").description("Manage workflows");
92
+ addCommonApiOptions(workflowCommand
93
+ .command("enable")
94
+ .description("Enable a workflow")
95
+ .argument("<workflow-id>", "Tray workflow UUID", parseWorkflowId)).action(async (workflowId, opts) => {
96
+ const deps = realDeps();
97
+ await runApiAction(deps, () => runWorkflowEnable(deps, {
98
+ workflowId,
99
+ region: opts.region,
100
+ token: opts.token,
101
+ format: opts.format,
102
+ }));
103
+ });
104
+ addCommonApiOptions(workflowCommand
105
+ .command("disable")
106
+ .description("Disable a workflow")
107
+ .argument("<workflow-id>", "Tray workflow UUID", parseWorkflowId)).action(async (workflowId, opts) => {
108
+ const deps = realDeps();
109
+ await runApiAction(deps, () => runWorkflowDisable(deps, {
110
+ workflowId,
111
+ region: opts.region,
112
+ token: opts.token,
113
+ format: opts.format,
114
+ }));
115
+ });
116
+ addCommonApiOptions(workflowCommand
117
+ .command("show")
118
+ .description("Show a workflow")
119
+ .argument("<workflow-id>", "Tray workflow UUID", parseWorkflowId)).action(async (workflowId, opts) => {
120
+ const deps = realDeps();
121
+ await runApiAction(deps, () => runWorkflowShow(deps, {
122
+ workflowId,
123
+ region: opts.region,
124
+ token: opts.token,
125
+ format: opts.format,
126
+ }));
127
+ });
128
+ addCommonApiOptions(workflowCommand
129
+ .command("delete")
130
+ .description("Delete a workflow")
131
+ .argument("<workflow-id>", "Tray workflow UUID", parseWorkflowId)).action(async (workflowId, opts) => {
132
+ const deps = realDeps();
133
+ await runApiAction(deps, () => runWorkflowDelete(deps, {
134
+ workflowId,
135
+ region: opts.region,
136
+ token: opts.token,
137
+ format: opts.format,
138
+ }));
139
+ });
140
+ const teal = ansis.hex(COMMAND_COLOR);
141
+ const EDIT_PAYLOAD_EXAMPLE = `${ansis.bold("Example:")}
142
+ $ ${teal(`tray api workflow edit <workflow-id> '{"name": "New name", "tags": ["prod", "reviewed"]}'`)}
143
+
144
+ Editable fields (all optional, only the ones you include are changed):
145
+ ${teal("name")} string
146
+ ${teal("description")} string, or null to clear
147
+ ${teal("tags")} string[] — replaces the FULL tag list, does not add/remove single tags
148
+ ${teal("alerting_workflow")} string (a workflow id), or null to clear
149
+ ${teal("legacy_error_handling")} boolean
150
+ `;
151
+ addCommonApiOptions(workflowCommand
152
+ .command("edit")
153
+ .description("Edit a workflow's name, description, tags, alerting workflow, or legacy error handling")
154
+ .argument("<workflow-id>", "Tray workflow UUID", parseWorkflowId)
155
+ .argument("<payload>", "JSON object of fields to change", parseEditPayload)
156
+ .addHelpText("after", `\n${EDIT_PAYLOAD_EXAMPLE}`)).action(async (workflowId, payload, opts) => {
157
+ const deps = realDeps();
158
+ await runApiAction(deps, () => runWorkflowEdit(deps, {
159
+ workflowId,
160
+ payload,
161
+ region: opts.region,
162
+ token: opts.token,
163
+ format: opts.format,
164
+ }));
165
+ });
166
+ //# sourceMappingURL=workflow.js.map
@@ -0,0 +1,21 @@
1
+ import ansis from "ansis";
2
+ export function printWorkflowEnabledResult(stdout, workflowId, enabled) {
3
+ const verb = enabled ? "Enabled" : "Disabled";
4
+ stdout(`${ansis.bold(verb)} workflow ${ansis.bold(workflowId)}.`);
5
+ }
6
+ export function printWorkflowShowResult(stdout, workflowId, workflow) {
7
+ const data = workflow.unversioned_data;
8
+ stdout(`${ansis.bold(data.name)} (${workflowId})`);
9
+ stdout(` Enabled: ${data.enabled ? "yes" : "no"}`);
10
+ if (data.description)
11
+ stdout(` Description: ${data.description}`);
12
+ if (data.tags.length > 0)
13
+ stdout(` Tags: ${data.tags.join(", ")}`);
14
+ }
15
+ export function printWorkflowDeletedResult(stdout, workflowId) {
16
+ stdout(`${ansis.bold("Deleted")} workflow ${ansis.bold(workflowId)}.`);
17
+ }
18
+ export function printWorkflowEditedResult(stdout, workflowId) {
19
+ stdout(`${ansis.bold("Edited")} workflow ${ansis.bold(workflowId)}.`);
20
+ }
21
+ //# sourceMappingURL=workflow.v2.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trayai/tray-sync-cli",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "CLI tool to clone Tray projects and related assets to a local directory, and promote them between Tray environments",
5
5
  "bin": {
6
6
  "tray": "dist/cli.js"