@sanity/workflow-cli 0.7.1 → 0.8.1
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 +20 -20
- package/dist/commands/abort.js +1 -1
- package/dist/commands/definition/delete.d.ts +8 -4
- package/dist/commands/definition/delete.js +2 -2
- package/dist/commands/definition/diff.js +9 -4
- package/dist/commands/definition/list.d.ts +2 -2
- package/dist/commands/definition/list.js +3 -3
- package/dist/commands/definition/show.d.ts +5 -3
- package/dist/commands/definition/show.js +17 -13
- package/dist/commands/deploy.js +5 -6
- package/dist/commands/diagnose.d.ts +6 -2
- package/dist/commands/diagnose.js +30 -27
- package/dist/commands/fire-action.d.ts +13 -5
- package/dist/commands/fire-action.js +32 -28
- package/dist/commands/list.d.ts +2 -2
- package/dist/commands/list.js +8 -8
- package/dist/commands/move-stage.d.ts +6 -1
- package/dist/commands/move-stage.js +13 -4
- package/dist/commands/{retry-task.d.ts → retry-activity.d.ts} +2 -2
- package/dist/commands/{retry-task.js → retry-activity.js} +3 -3
- package/dist/commands/set-stage.js +1 -1
- package/dist/commands/show.d.ts +1 -1
- package/dist/commands/show.js +10 -10
- package/dist/commands/tail.js +2 -2
- package/dist/lib/definitions.js +1 -1
- package/dist/lib/diff.d.ts +2 -1
- package/dist/lib/diff.js +2 -2
- package/dist/lib/operation-args.d.ts +5 -1
- package/dist/lib/operation-args.js +1 -1
- package/dist/lib/ops-report.d.ts +5 -1
- package/dist/lib/ops-report.js +1 -1
- package/dist/lib/ui.d.ts +6 -4
- package/dist/lib/ui.js +3 -5
- package/oclif.manifest.json +22 -22
- package/package.json +4 -4
|
@@ -44,8 +44,8 @@ function reasonText(reason) {
|
|
|
44
44
|
switch (reason.kind) {
|
|
45
45
|
case 'filter-failed':
|
|
46
46
|
return `action filter not satisfied${reason.detail ? ` (${reason.detail})` : ''}`;
|
|
47
|
-
case '
|
|
48
|
-
return `
|
|
47
|
+
case 'activity-not-active':
|
|
48
|
+
return `activity is ${reason.status}`;
|
|
49
49
|
case 'stage-terminal':
|
|
50
50
|
return `stage '${reason.stage}' is terminal`;
|
|
51
51
|
case 'mutation-guard-denied':
|
|
@@ -63,7 +63,7 @@ function actionLines(a) {
|
|
|
63
63
|
const mark = a.allowed ? logSymbols.success : logSymbols.error;
|
|
64
64
|
const title = a.title !== undefined ? styleText('dim', ` (${a.title})`) : '';
|
|
65
65
|
const lines = [
|
|
66
|
-
` ${mark} ${a.
|
|
66
|
+
` ${mark} ${a.activity} → ${a.action}${title} ${styleText('dim', `[activity ${a.activityStatus}]`)}`,
|
|
67
67
|
];
|
|
68
68
|
if (a.params.length > 0) {
|
|
69
69
|
lines.push(styleText('dim', ` params: ${a.params.map(paramLabel).join(', ')}`));
|
|
@@ -74,20 +74,20 @@ function actionLines(a) {
|
|
|
74
74
|
return lines;
|
|
75
75
|
}
|
|
76
76
|
/**
|
|
77
|
-
* The list-mode body: every action on the current stage's
|
|
77
|
+
* The list-mode body: every action on the current stage's activities, marked
|
|
78
78
|
* fireable or not (with the disabling reason), plus a hint showing the
|
|
79
79
|
* flags to fire one. Pure so the populated/empty permutations assert
|
|
80
80
|
* without a live evaluation.
|
|
81
81
|
*/
|
|
82
|
-
export function renderAvailableActions(actions, stage, instanceId) {
|
|
82
|
+
export function renderAvailableActions({ actions, stage, instanceId, }) {
|
|
83
83
|
if (actions.length === 0) {
|
|
84
|
-
return [`No actions on the
|
|
84
|
+
return [`No actions on the activities of the current stage ('${stage}').`];
|
|
85
85
|
}
|
|
86
86
|
const lines = [styleText('bold', `Actions on stage '${stage}':`), ''];
|
|
87
87
|
for (const a of actions) {
|
|
88
88
|
lines.push(...actionLines(a));
|
|
89
89
|
}
|
|
90
|
-
lines.push('', styleText('dim', 'Fire one with:'), styleText('dim', ` fire-action ${instanceId} --
|
|
90
|
+
lines.push('', styleText('dim', 'Fire one with:'), styleText('dim', ` fire-action ${instanceId} --activity <activity> --action <action>`));
|
|
91
91
|
return lines;
|
|
92
92
|
}
|
|
93
93
|
/** The `--json` payload for a fired action — the structured counterpart of
|
|
@@ -95,7 +95,7 @@ export function renderAvailableActions(actions, stage, instanceId) {
|
|
|
95
95
|
export function fireResultJson(result, ids) {
|
|
96
96
|
return {
|
|
97
97
|
instanceId: ids.instanceId,
|
|
98
|
-
|
|
98
|
+
activity: ids.activity,
|
|
99
99
|
action: ids.action,
|
|
100
100
|
fired: result.fired,
|
|
101
101
|
cascaded: result.cascaded,
|
|
@@ -108,37 +108,37 @@ export function fireResultJson(result, ids) {
|
|
|
108
108
|
* the fired / no-op / cascaded / ops permutations assert without a live
|
|
109
109
|
* fire.
|
|
110
110
|
*/
|
|
111
|
-
export function fireActionReport(result,
|
|
111
|
+
export function fireActionReport({ result, activity, action, }) {
|
|
112
112
|
const stage = styleText('bold', result.instance.currentStage);
|
|
113
113
|
if (!result.fired) {
|
|
114
114
|
return {
|
|
115
115
|
fired: false,
|
|
116
|
-
message: `fireAction returned without firing —
|
|
116
|
+
message: `fireAction returned without firing — activity '${activity}' is no longer active`,
|
|
117
117
|
opsLines: [],
|
|
118
118
|
};
|
|
119
119
|
}
|
|
120
120
|
const tail = result.cascaded > 0 ? `, then cascaded ${result.cascaded} auto-transition(s)` : '';
|
|
121
121
|
return {
|
|
122
122
|
fired: true,
|
|
123
|
-
message: `Fired ${styleText('bold', action)} on ${styleText('bold',
|
|
123
|
+
message: `Fired ${styleText('bold', action)} on ${styleText('bold', activity)} — now at ${stage}${tail}`,
|
|
124
124
|
opsLines: opsAppliedLines(result.ranOps),
|
|
125
125
|
};
|
|
126
126
|
}
|
|
127
127
|
export default class FireAction extends Command {
|
|
128
|
-
static description = "Fire an action on an instance — act on a user's behalf to unstick a waiting
|
|
128
|
+
static description = "Fire an action on an instance — act on a user's behalf to unstick a waiting activity. Omit --action to list what can be fired.";
|
|
129
129
|
static examples = [
|
|
130
130
|
'<%= config.bin %> fire-action wf-instance.abc123',
|
|
131
|
-
'<%= config.bin %> fire-action wf-instance.abc123 --
|
|
132
|
-
'<%= config.bin %> fire-action wf-instance.abc123 --
|
|
133
|
-
'<%= config.bin %> fire-action wf-instance.abc123 --
|
|
131
|
+
'<%= config.bin %> fire-action wf-instance.abc123 --activity approve --action approve',
|
|
132
|
+
'<%= config.bin %> fire-action wf-instance.abc123 --activity approve --action approve --as user.xyz --as-role editor',
|
|
133
|
+
'<%= config.bin %> fire-action wf-instance.abc123 --activity publish --action publish --param note=shipping',
|
|
134
134
|
];
|
|
135
135
|
static args = {
|
|
136
136
|
instanceId: Args.string({ required: true, description: 'Workflow instance id.' }),
|
|
137
137
|
};
|
|
138
138
|
static flags = {
|
|
139
139
|
...tagFlags,
|
|
140
|
-
|
|
141
|
-
description: '
|
|
140
|
+
activity: Flags.string({
|
|
141
|
+
description: 'Activity the action belongs to. Required to fire; omit --action to list.',
|
|
142
142
|
}),
|
|
143
143
|
action: Flags.string({
|
|
144
144
|
description: 'Action to fire. Omit to list the actions available on the instance.',
|
|
@@ -167,24 +167,24 @@ export default class FireAction extends Command {
|
|
|
167
167
|
const client = loadClient();
|
|
168
168
|
const actor = failOnThrow('fire-action usage error:', () => resolveActor(flags.as, flags['as-role']));
|
|
169
169
|
if (flags.action === undefined) {
|
|
170
|
-
await this.listActions(client, config, args.instanceId, actor, flags.json);
|
|
170
|
+
await this.listActions({ client, config, instanceId: args.instanceId, actor, json: flags.json });
|
|
171
171
|
return;
|
|
172
172
|
}
|
|
173
|
-
if (flags.
|
|
174
|
-
fail('fire-action usage error:', 'specify --
|
|
173
|
+
if (flags.activity === undefined) {
|
|
174
|
+
fail('fire-action usage error:', 'specify --activity for the action (or omit --action to list what can be fired)');
|
|
175
175
|
}
|
|
176
176
|
await this.fireOne({
|
|
177
177
|
client,
|
|
178
178
|
config,
|
|
179
179
|
instanceId: args.instanceId,
|
|
180
180
|
actor,
|
|
181
|
-
|
|
181
|
+
activity: flags.activity,
|
|
182
182
|
action: flags.action,
|
|
183
183
|
params: flags.param,
|
|
184
184
|
json: flags.json,
|
|
185
185
|
});
|
|
186
186
|
}
|
|
187
|
-
async listActions(client, config, instanceId, actor, json) {
|
|
187
|
+
async listActions({ client, config, instanceId, actor, json, }) {
|
|
188
188
|
const { evaluation, actions } = await workflow
|
|
189
189
|
.availableActions({
|
|
190
190
|
client,
|
|
@@ -201,19 +201,19 @@ export default class FireAction extends Command {
|
|
|
201
201
|
}
|
|
202
202
|
this.log(instanceHeader(evaluation.instance));
|
|
203
203
|
this.log('');
|
|
204
|
-
for (const line of renderAvailableActions(actions, stage, instanceId)) {
|
|
204
|
+
for (const line of renderAvailableActions({ actions, stage, instanceId })) {
|
|
205
205
|
this.log(line);
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
async fireOne(opts) {
|
|
209
|
-
const { client, config, instanceId, actor,
|
|
209
|
+
const { client, config, instanceId, actor, activity, action, json } = opts;
|
|
210
210
|
const params = failOnThrow('Invalid --param:', () => parseParams(opts.params));
|
|
211
211
|
const fireArgs = {
|
|
212
212
|
client,
|
|
213
213
|
tag: config.tag,
|
|
214
214
|
workflowResource: config.workflowResource,
|
|
215
215
|
instanceId,
|
|
216
|
-
|
|
216
|
+
activity,
|
|
217
217
|
action,
|
|
218
218
|
access: { actor },
|
|
219
219
|
params,
|
|
@@ -222,13 +222,17 @@ export default class FireAction extends Command {
|
|
|
222
222
|
const result = await workflow
|
|
223
223
|
.fireAction(fireArgs)
|
|
224
224
|
.catch((error) => fail('fireAction error:', errorMessage(error)));
|
|
225
|
-
this.log(JSON.stringify(fireResultJson(result, { instanceId,
|
|
225
|
+
this.log(JSON.stringify(fireResultJson(result, { instanceId, activity, action }), null, 2));
|
|
226
226
|
return;
|
|
227
227
|
}
|
|
228
|
-
const spinner = ora(`Firing ${action} on ${
|
|
228
|
+
const spinner = ora(`Firing ${action} on ${activity}…`).start();
|
|
229
229
|
try {
|
|
230
230
|
const result = await workflow.fireAction(fireArgs);
|
|
231
|
-
emitWriteReport(
|
|
231
|
+
emitWriteReport({
|
|
232
|
+
spinner,
|
|
233
|
+
report: fireActionReport({ result, activity, action }),
|
|
234
|
+
log: (line) => this.log(line),
|
|
235
|
+
});
|
|
232
236
|
}
|
|
233
237
|
catch (error) {
|
|
234
238
|
spinner.fail('Action rejected');
|
package/dist/commands/list.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ type InstanceStatus = 'aborted' | 'completed' | 'in-flight';
|
|
|
12
12
|
interface ListFlags {
|
|
13
13
|
'in-flight': boolean;
|
|
14
14
|
failed: boolean;
|
|
15
|
-
'workflow-
|
|
15
|
+
'workflow-name'?: string | undefined;
|
|
16
16
|
tag?: string | undefined;
|
|
17
17
|
limit: number;
|
|
18
18
|
}
|
|
@@ -41,7 +41,7 @@ export default class List extends Command {
|
|
|
41
41
|
static flags: {
|
|
42
42
|
'in-flight': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
43
43
|
failed: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
44
|
-
'workflow-
|
|
44
|
+
'workflow-name': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
45
45
|
limit: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
46
46
|
tag: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
47
47
|
};
|
package/dist/commands/list.js
CHANGED
|
@@ -15,11 +15,11 @@ export function buildListQuery(flags) {
|
|
|
15
15
|
const filters = [`_type == "${WORKFLOW_INSTANCE_TYPE}"`];
|
|
16
16
|
if (flags['in-flight'])
|
|
17
17
|
filters.push('!defined(completedAt)');
|
|
18
|
-
if (flags['workflow-
|
|
18
|
+
if (flags['workflow-name'])
|
|
19
19
|
filters.push('definition == $definition');
|
|
20
|
-
// Cheap approximation of --failed: any
|
|
20
|
+
// Cheap approximation of --failed: any activity in any stage with status "failed".
|
|
21
21
|
if (flags.failed)
|
|
22
|
-
filters.push('count(stages[].
|
|
22
|
+
filters.push('count(stages[].activities[status == "failed"]) > 0');
|
|
23
23
|
if (flags.tag)
|
|
24
24
|
filters.push(tagScopeFilter());
|
|
25
25
|
const groq = `*[${filters.join(' && ')}] | order(lastChangedAt desc) [0...$limit]{
|
|
@@ -32,8 +32,8 @@ export function buildListQuery(flags) {
|
|
|
32
32
|
lastChangedAt
|
|
33
33
|
}`;
|
|
34
34
|
const params = { limit: flags.limit };
|
|
35
|
-
if (flags['workflow-
|
|
36
|
-
params['definition'] = flags['workflow-
|
|
35
|
+
if (flags['workflow-name'])
|
|
36
|
+
params['definition'] = flags['workflow-name'];
|
|
37
37
|
if (flags.tag)
|
|
38
38
|
params['tag'] = flags.tag;
|
|
39
39
|
return { groq, params };
|
|
@@ -68,7 +68,7 @@ export default class List extends Command {
|
|
|
68
68
|
static examples = [
|
|
69
69
|
'<%= config.bin %> list',
|
|
70
70
|
'<%= config.bin %> list --in-flight',
|
|
71
|
-
'<%= config.bin %> list --workflow-
|
|
71
|
+
'<%= config.bin %> list --workflow-name productLaunch',
|
|
72
72
|
'<%= config.bin %> list --tag prod',
|
|
73
73
|
];
|
|
74
74
|
static flags = {
|
|
@@ -78,10 +78,10 @@ export default class List extends Command {
|
|
|
78
78
|
default: false,
|
|
79
79
|
}),
|
|
80
80
|
failed: Flags.boolean({
|
|
81
|
-
description: 'Only instances with at least one failed
|
|
81
|
+
description: 'Only instances with at least one failed activity.',
|
|
82
82
|
default: false,
|
|
83
83
|
}),
|
|
84
|
-
'workflow-
|
|
84
|
+
'workflow-name': Flags.string({
|
|
85
85
|
description: 'Filter by workflow definition name.',
|
|
86
86
|
}),
|
|
87
87
|
limit: Flags.integer({
|
|
@@ -17,7 +17,12 @@ export default class MoveStage extends Command {
|
|
|
17
17
|
}
|
|
18
18
|
/** The shared operation args ({@link buildOperationArgs}) plus the
|
|
19
19
|
* setStage-specific target. */
|
|
20
|
-
export declare function buildSetStageArgs(config
|
|
20
|
+
export declare function buildSetStageArgs({ config, instanceId, targetStage, reason, }: {
|
|
21
|
+
config: WorkflowConfig;
|
|
22
|
+
instanceId: string;
|
|
23
|
+
targetStage: string;
|
|
24
|
+
reason: string | undefined;
|
|
25
|
+
}): Omit<SetStageArgs, 'client'>;
|
|
21
26
|
interface SetStageOutcome {
|
|
22
27
|
fired: boolean;
|
|
23
28
|
cascaded: number;
|
|
@@ -38,9 +38,18 @@ export default class MoveStage extends Command {
|
|
|
38
38
|
try {
|
|
39
39
|
const result = await workflow.setStage({
|
|
40
40
|
client,
|
|
41
|
-
...buildSetStageArgs(
|
|
41
|
+
...buildSetStageArgs({
|
|
42
|
+
config,
|
|
43
|
+
instanceId: args.instanceId,
|
|
44
|
+
targetStage: flags.to,
|
|
45
|
+
reason: flags.reason,
|
|
46
|
+
}),
|
|
47
|
+
});
|
|
48
|
+
emitWriteReport({
|
|
49
|
+
spinner,
|
|
50
|
+
report: moveStageReport(result, flags.to),
|
|
51
|
+
log: (line) => this.log(line),
|
|
42
52
|
});
|
|
43
|
-
emitWriteReport(spinner, moveStageReport(result, flags.to), (line) => this.log(line));
|
|
44
53
|
}
|
|
45
54
|
catch (error) {
|
|
46
55
|
spinner.fail('Move rejected');
|
|
@@ -51,8 +60,8 @@ export default class MoveStage extends Command {
|
|
|
51
60
|
}
|
|
52
61
|
/** The shared operation args ({@link buildOperationArgs}) plus the
|
|
53
62
|
* setStage-specific target. */
|
|
54
|
-
export function buildSetStageArgs(config, instanceId, targetStage, reason) {
|
|
55
|
-
return { ...buildOperationArgs(config, instanceId, reason), targetStage };
|
|
63
|
+
export function buildSetStageArgs({ config, instanceId, targetStage, reason, }) {
|
|
64
|
+
return { ...buildOperationArgs({ config, instanceId, reason }), targetStage };
|
|
56
65
|
}
|
|
57
66
|
/**
|
|
58
67
|
* Turn a `setStage` result into the spinner message + ops block. Pure so
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { StubCommand } from '../lib/stub.ts';
|
|
2
|
-
export default class
|
|
2
|
+
export default class RetryActivity extends StubCommand {
|
|
3
3
|
static hidden: boolean;
|
|
4
4
|
static description: string;
|
|
5
5
|
static args: {
|
|
6
6
|
instanceId: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
-
|
|
7
|
+
activity: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
8
8
|
};
|
|
9
9
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Args } from '@oclif/core';
|
|
2
2
|
import { StubCommand } from "../lib/stub.js";
|
|
3
|
-
export default class
|
|
3
|
+
export default class RetryActivity extends StubCommand {
|
|
4
4
|
// Stubbed, so kept off the help + published surface until it's wired.
|
|
5
5
|
static hidden = true;
|
|
6
|
-
static description = 'Re-invoke a failed
|
|
6
|
+
static description = 'Re-invoke a failed activity on an in-flight instance.';
|
|
7
7
|
static args = {
|
|
8
8
|
instanceId: Args.string({ required: true, description: 'Workflow instance id.' }),
|
|
9
|
-
|
|
9
|
+
activity: Args.string({ required: true, description: 'Activity name within the current stage.' }),
|
|
10
10
|
};
|
|
11
11
|
}
|
|
@@ -4,7 +4,7 @@ export default class SetStage extends StubCommand {
|
|
|
4
4
|
// Stubbed, so kept off the help + published surface until it's wired.
|
|
5
5
|
static hidden = true;
|
|
6
6
|
// Engine note: workflow.setStage currently always runs guards + stage
|
|
7
|
-
// entry (
|
|
7
|
+
// entry (activity activation, effects). A "manual override" that bypasses
|
|
8
8
|
// them is engine work that hasn't landed; this command stub captures
|
|
9
9
|
// the intended surface only.
|
|
10
10
|
static description = "Force-set an instance's current stage, bypassing guards + effects (manual override).";
|
package/dist/commands/show.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export default class Show extends Command {
|
|
|
15
15
|
* `fire-action`): a bold workflow + id title, then aligned detail rows. */
|
|
16
16
|
export declare function instanceHeader(instance: WorkflowInstance): string;
|
|
17
17
|
/**
|
|
18
|
-
* The per-instance body lines: every stage with its
|
|
18
|
+
* The per-instance body lines: every stage with its activities, any pending
|
|
19
19
|
* effects, and (optionally) the history log. Pure so it can be asserted
|
|
20
20
|
* without driving the oclif command.
|
|
21
21
|
*/
|
package/dist/commands/show.js
CHANGED
|
@@ -3,9 +3,9 @@ import { Args, Command, Flags } from '@oclif/core';
|
|
|
3
3
|
import { abortReason } from '@sanity/workflow-engine';
|
|
4
4
|
import logSymbols from 'log-symbols';
|
|
5
5
|
import { loadClient } from "../lib/client.js";
|
|
6
|
-
import { formatKeyValue, formatTimestamp, sectionHeader,
|
|
6
|
+
import { formatKeyValue, formatTimestamp, sectionHeader, activityIcon } from "../lib/ui.js";
|
|
7
7
|
export default class Show extends Command {
|
|
8
|
-
static description = 'Show the state,
|
|
8
|
+
static description = 'Show the state, activities, and effects of a workflow instance.';
|
|
9
9
|
static examples = [
|
|
10
10
|
'<%= config.bin %> show wf-instance.abc123',
|
|
11
11
|
'<%= config.bin %> show wf-instance.abc123 --include history',
|
|
@@ -46,8 +46,8 @@ const HEADER_PAD = 9; // "Completed" — the longest label in the block
|
|
|
46
46
|
export function instanceHeader(instance) {
|
|
47
47
|
const title = `${styleText('bold', `${instance.definition} v${instance.pinnedVersion}`)} ${styleText('cyan', instance._id)}`;
|
|
48
48
|
const rows = [
|
|
49
|
-
formatKeyValue('Stage', instance.currentStage,
|
|
50
|
-
formatKeyValue('Started', formatTimestamp(instance.startedAt),
|
|
49
|
+
formatKeyValue({ key: 'Stage', value: instance.currentStage, padTo: HEADER_PAD }),
|
|
50
|
+
formatKeyValue({ key: 'Started', value: formatTimestamp(instance.startedAt), padTo: HEADER_PAD }),
|
|
51
51
|
];
|
|
52
52
|
// Aborted instances also carry a completedAt stamped at the abort, so the
|
|
53
53
|
// abort line stands in for completion — showing a green "Completed" too would
|
|
@@ -56,19 +56,19 @@ export function instanceHeader(instance) {
|
|
|
56
56
|
const reason = abortReason(instance);
|
|
57
57
|
const tail = reason ? ` — ${reason}` : '';
|
|
58
58
|
const value = styleText('yellow', `${formatTimestamp(instance.abortedAt)}${tail}`);
|
|
59
|
-
rows.push(formatKeyValue('Aborted', value,
|
|
59
|
+
rows.push(formatKeyValue({ key: 'Aborted', value, padTo: HEADER_PAD }));
|
|
60
60
|
}
|
|
61
61
|
else {
|
|
62
62
|
const completed = instance.completedAt
|
|
63
63
|
? styleText('green', formatTimestamp(instance.completedAt))
|
|
64
64
|
: styleText('dim', '—');
|
|
65
|
-
rows.push(formatKeyValue('Completed', completed,
|
|
65
|
+
rows.push(formatKeyValue({ key: 'Completed', value: completed, padTo: HEADER_PAD }));
|
|
66
66
|
}
|
|
67
|
-
rows.push(formatKeyValue('Tag', instance.tag,
|
|
67
|
+
rows.push(formatKeyValue({ key: 'Tag', value: instance.tag, padTo: HEADER_PAD }));
|
|
68
68
|
return [title, ...rows].join('\n');
|
|
69
69
|
}
|
|
70
70
|
/**
|
|
71
|
-
* The per-instance body lines: every stage with its
|
|
71
|
+
* The per-instance body lines: every stage with its activities, any pending
|
|
72
72
|
* effects, and (optionally) the history log. Pure so it can be asserted
|
|
73
73
|
* without driving the oclif command.
|
|
74
74
|
*/
|
|
@@ -79,8 +79,8 @@ export function describeInstance(instance, options) {
|
|
|
79
79
|
? styleText('dim', ` (exited ${formatTimestamp(stage.exitedAt)})`)
|
|
80
80
|
: styleText('cyan', ' (current)');
|
|
81
81
|
lines.push(` • ${stage.name}${marker}`);
|
|
82
|
-
for (const
|
|
83
|
-
lines.push(` ${
|
|
82
|
+
for (const activity of stage.activities) {
|
|
83
|
+
lines.push(` ${activityIcon[activity.status]} ${activity.name} ${styleText('dim', `[${activity.status}]`)}`);
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
if (instance.pendingEffects.length > 0) {
|
package/dist/commands/tail.js
CHANGED
|
@@ -33,7 +33,7 @@ export default class Tail extends Command {
|
|
|
33
33
|
.subscribe({
|
|
34
34
|
next: async () => {
|
|
35
35
|
try {
|
|
36
|
-
seen = await this.printNewEntries(client, args.instanceId, seen);
|
|
36
|
+
seen = await this.printNewEntries({ client, instanceId: args.instanceId, seen });
|
|
37
37
|
}
|
|
38
38
|
catch (err) {
|
|
39
39
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -61,7 +61,7 @@ export default class Tail extends Command {
|
|
|
61
61
|
* given high-water mark, return the new mark. Pulled out so the
|
|
62
62
|
* async work in the subscription's `next` handler stays tidy.
|
|
63
63
|
*/
|
|
64
|
-
async printNewEntries(client, instanceId, seen) {
|
|
64
|
+
async printNewEntries({ client, instanceId, seen, }) {
|
|
65
65
|
const next = await client.getDocument(instanceId);
|
|
66
66
|
if (!next)
|
|
67
67
|
return seen;
|
package/dist/lib/definitions.js
CHANGED
|
@@ -115,7 +115,7 @@ export function collectValidationErrors(defs) {
|
|
|
115
115
|
}
|
|
116
116
|
catch (err) {
|
|
117
117
|
const message = err instanceof Error ? err.message : String(err);
|
|
118
|
-
errors.push(` · ${d.name}
|
|
118
|
+
errors.push(` · ${d.name}: ${message}`);
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
return errors;
|
package/dist/lib/diff.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { DiffEntry } from '@sanity/workflow-engine';
|
|
2
|
-
/** One summary line per diff entry, tagged create /
|
|
2
|
+
/** One summary line per diff entry, tagged create / unchanged. Definitions are
|
|
3
|
+
* immutable, so a content change is a new version (`create`), never an update. */
|
|
3
4
|
export declare function summaryLines(entries: DiffEntry[]): string[];
|
|
4
5
|
/** Render a JSON diff of `oldObj` → `newObj` as `+`/`-`/context lines. */
|
|
5
6
|
export declare function diffLines(oldObj: object, newObj: object): string[];
|
package/dist/lib/diff.js
CHANGED
|
@@ -2,11 +2,11 @@ import { styleText } from 'node:util';
|
|
|
2
2
|
import { diffJson } from 'diff';
|
|
3
3
|
import logSymbols from 'log-symbols';
|
|
4
4
|
import { sectionHeader } from "./ui.js";
|
|
5
|
-
/** One summary line per diff entry, tagged create /
|
|
5
|
+
/** One summary line per diff entry, tagged create / unchanged. Definitions are
|
|
6
|
+
* immutable, so a content change is a new version (`create`), never an update. */
|
|
6
7
|
export function summaryLines(entries) {
|
|
7
8
|
const tags = {
|
|
8
9
|
create: styleText('green', '+ create '),
|
|
9
|
-
update: styleText('yellow', '~ update '),
|
|
10
10
|
unchanged: styleText('dim', ' unchanged'),
|
|
11
11
|
};
|
|
12
12
|
return entries.map((e) => {
|
|
@@ -20,6 +20,10 @@ export declare function resolveActor(as: string | undefined, roles: string[]): A
|
|
|
20
20
|
* conditionally because the engine's optional field rejects an explicit
|
|
21
21
|
* `undefined` under `exactOptionalPropertyTypes`.
|
|
22
22
|
*/
|
|
23
|
-
export declare function buildOperationArgs(config
|
|
23
|
+
export declare function buildOperationArgs({ config, instanceId, reason, }: {
|
|
24
|
+
config: WorkflowConfig;
|
|
25
|
+
instanceId: string;
|
|
26
|
+
reason: string | undefined;
|
|
27
|
+
}): Omit<OperationArgs, 'client'> & {
|
|
24
28
|
reason?: string;
|
|
25
29
|
};
|
|
@@ -39,7 +39,7 @@ export function resolveActor(as, roles) {
|
|
|
39
39
|
* conditionally because the engine's optional field rejects an explicit
|
|
40
40
|
* `undefined` under `exactOptionalPropertyTypes`.
|
|
41
41
|
*/
|
|
42
|
-
export function buildOperationArgs(config, instanceId, reason) {
|
|
42
|
+
export function buildOperationArgs({ config, instanceId, reason, }) {
|
|
43
43
|
return {
|
|
44
44
|
...baseEngineArgs(config),
|
|
45
45
|
instanceId,
|
package/dist/lib/ops-report.d.ts
CHANGED
|
@@ -27,4 +27,8 @@ export interface WriteReport {
|
|
|
27
27
|
* Shared by every write command so the fired / not-fired branches stay
|
|
28
28
|
* consistent.
|
|
29
29
|
*/
|
|
30
|
-
export declare function emitWriteReport(spinner
|
|
30
|
+
export declare function emitWriteReport({ spinner, report, log, }: {
|
|
31
|
+
spinner: Ora;
|
|
32
|
+
report: WriteReport;
|
|
33
|
+
log: (line: string) => void;
|
|
34
|
+
}): void;
|
package/dist/lib/ops-report.js
CHANGED
|
@@ -18,7 +18,7 @@ export function opsAppliedLines(ranOps) {
|
|
|
18
18
|
* Shared by every write command so the fired / not-fired branches stay
|
|
19
19
|
* consistent.
|
|
20
20
|
*/
|
|
21
|
-
export function emitWriteReport(spinner, report, log) {
|
|
21
|
+
export function emitWriteReport({ spinner, report, log, }) {
|
|
22
22
|
if (!report.fired) {
|
|
23
23
|
spinner.warn(report.message);
|
|
24
24
|
return;
|
package/dist/lib/ui.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ActivityStatus } from '@sanity/workflow-engine';
|
|
2
2
|
/**
|
|
3
3
|
* A bold `Title:` section heading. Mirrors the Sanity CLI's `sectionHeader`
|
|
4
4
|
* (name + shape) so it folds into the shared helper when this CLI merges in.
|
|
@@ -9,13 +9,15 @@ export declare function sectionHeader(title: string): string;
|
|
|
9
9
|
* the Sanity CLI's `formatKeyValue` so it folds into the shared helper on
|
|
10
10
|
* merge; pass `padTo` (the longest key's length) to align a block of rows.
|
|
11
11
|
*/
|
|
12
|
-
export declare function formatKeyValue(key
|
|
12
|
+
export declare function formatKeyValue({ key, value, indent, padTo, }: {
|
|
13
|
+
key: string;
|
|
14
|
+
value: string;
|
|
13
15
|
indent?: number;
|
|
14
16
|
padTo?: number;
|
|
15
17
|
}): string;
|
|
16
|
-
/** Status glyph per
|
|
18
|
+
/** Status glyph per activity state. log-symbols ship pre-colored (green ✔, red ✖),
|
|
17
19
|
* so those need no extra wrap; the rest carry their own state color. */
|
|
18
|
-
export declare const
|
|
20
|
+
export declare const activityIcon: Record<ActivityStatus, string>;
|
|
19
21
|
/** An engine ISO-8601 timestamp as an absolute `yyyy-MM-dd HH:mm:ss` — the
|
|
20
22
|
* Sanity CLI's audit-log format (see `backups/list`). For detail views. */
|
|
21
23
|
export declare function formatTimestamp(iso: string): string;
|
package/dist/lib/ui.js
CHANGED
|
@@ -15,15 +15,13 @@ export function sectionHeader(title) {
|
|
|
15
15
|
* the Sanity CLI's `formatKeyValue` so it folds into the shared helper on
|
|
16
16
|
* merge; pass `padTo` (the longest key's length) to align a block of rows.
|
|
17
17
|
*/
|
|
18
|
-
export function formatKeyValue(key, value,
|
|
19
|
-
const indent = options?.indent ?? 2;
|
|
20
|
-
const padTo = options?.padTo ?? 0;
|
|
18
|
+
export function formatKeyValue({ key, value, indent = 2, padTo = 0, }) {
|
|
21
19
|
const paddedKey = `${key}:`.padEnd(padTo > 0 ? padTo + 1 : key.length + 1);
|
|
22
20
|
return `${' '.repeat(indent)}${styleText('dim', paddedKey)} ${value}`;
|
|
23
21
|
}
|
|
24
|
-
/** Status glyph per
|
|
22
|
+
/** Status glyph per activity state. log-symbols ship pre-colored (green ✔, red ✖),
|
|
25
23
|
* so those need no extra wrap; the rest carry their own state color. */
|
|
26
|
-
export const
|
|
24
|
+
export const activityIcon = {
|
|
27
25
|
done: logSymbols.success,
|
|
28
26
|
active: styleText('cyan', '●'),
|
|
29
27
|
pending: styleText('dim', '○'),
|