@devflow-one/cli 0.1.10 → 0.1.11
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/package.json +1 -1
- package/src/cli.js +9 -5
- package/src/client.js +21 -1
- package/src/commands.js +9 -0
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { parseArgs } from "./args.js";
|
|
6
6
|
import { resolveConfig, ConfigError } from "./config.js";
|
|
7
|
-
import { gatewayRequest, GatewayError } from "./client.js";
|
|
7
|
+
import { gatewayRequest, GatewayError, retryHint } from "./client.js";
|
|
8
8
|
import { resolveCommand, listCommands, UsageError } from "./commands.js";
|
|
9
9
|
import {
|
|
10
10
|
createContextQuery,
|
|
@@ -86,17 +86,21 @@ function printWarnings(result, stderr) {
|
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
/** Print an error, honoring --json, to stderr. */
|
|
90
|
-
function printError(err, json, stderr) {
|
|
89
|
+
/** Print an error (plus an optional retry hint), honoring --json, to stderr. */
|
|
90
|
+
function printError(err, json, stderr, hint) {
|
|
91
91
|
const code = err instanceof GatewayError ? err.code : err.name;
|
|
92
92
|
|
|
93
93
|
if (json) {
|
|
94
|
-
|
|
94
|
+
const error = { code, message: err.message, delivered: err.delivered, hint };
|
|
95
|
+
|
|
96
|
+
stderr(JSON.stringify({ ok: false, error }, null, 2));
|
|
95
97
|
|
|
96
98
|
return;
|
|
97
99
|
}
|
|
98
100
|
|
|
99
101
|
stderr(`error${code ? ` [${code}]` : ""}: ${err.message}`);
|
|
102
|
+
|
|
103
|
+
if (hint) stderr(`hint: ${hint}`);
|
|
100
104
|
}
|
|
101
105
|
|
|
102
106
|
/**
|
|
@@ -231,7 +235,7 @@ export async function run(argv, io = {}) {
|
|
|
231
235
|
return 0;
|
|
232
236
|
} catch (err) {
|
|
233
237
|
if (err instanceof UsageError || err instanceof GatewayError) {
|
|
234
|
-
printError(err, Boolean(flags.json), stderr);
|
|
238
|
+
printError(err, Boolean(flags.json), stderr, retryHint(err, command.retryUnsafe));
|
|
235
239
|
|
|
236
240
|
return 1;
|
|
237
241
|
}
|
package/src/client.js
CHANGED
|
@@ -9,15 +9,34 @@ export class GatewayError extends Error {
|
|
|
9
9
|
* @param {string} [code]
|
|
10
10
|
* @param {unknown} [result] the envelope's `result`, which some failures still
|
|
11
11
|
* carry — `/context` reports its ambiguity candidates there.
|
|
12
|
+
* @param {boolean} [delivered] on a TIMEOUT, whether the profile had already
|
|
13
|
+
* picked the action up (undefined from daemons that predate the flag).
|
|
12
14
|
*/
|
|
13
|
-
constructor(message, code, result) {
|
|
15
|
+
constructor(message, code, result, delivered) {
|
|
14
16
|
super(message);
|
|
15
17
|
this.name = "GatewayError";
|
|
16
18
|
this.code = code;
|
|
17
19
|
this.result = result;
|
|
20
|
+
this.delivered = delivered;
|
|
18
21
|
}
|
|
19
22
|
}
|
|
20
23
|
|
|
24
|
+
export const RETRY_HINT =
|
|
25
|
+
"The action may have completed — verify (e.g. findPrByIssueKey) before retrying.";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The "verify before retrying" hint for a TIMEOUT of a retry-unsafe action
|
|
29
|
+
* that may already have run; undefined when a retry is safe.
|
|
30
|
+
* @param {unknown} err
|
|
31
|
+
* @param {boolean} [retryUnsafe]
|
|
32
|
+
*/
|
|
33
|
+
export function retryHint(err, retryUnsafe) {
|
|
34
|
+
const mayHaveRun =
|
|
35
|
+
err instanceof GatewayError && err.code === "TIMEOUT" && err.delivered !== false;
|
|
36
|
+
|
|
37
|
+
return retryUnsafe && mayHaveRun ? RETRY_HINT : undefined;
|
|
38
|
+
}
|
|
39
|
+
|
|
21
40
|
/**
|
|
22
41
|
* Turn a network-level failure into an actionable message. ECONNREFUSED almost
|
|
23
42
|
* always means the daemon isn't running.
|
|
@@ -83,5 +102,6 @@ export async function gatewayRequest(config, method, path, body) {
|
|
|
83
102
|
error.message ?? `Gateway error (HTTP ${response.status}).`,
|
|
84
103
|
error.code,
|
|
85
104
|
envelope?.result,
|
|
105
|
+
error.delivered,
|
|
86
106
|
);
|
|
87
107
|
}
|
package/src/commands.js
CHANGED
|
@@ -93,6 +93,7 @@ export class UsageError extends Error {
|
|
|
93
93
|
* @property {string} [path] For GET commands.
|
|
94
94
|
* @property {string} [action] Gateway action name for POST commands.
|
|
95
95
|
* @property {boolean} [destructive] Requires --force/--yes (gated by cli.js).
|
|
96
|
+
* @property {boolean} [retryUnsafe] A retry may repeat its side effect; a TIMEOUT warns to verify first.
|
|
96
97
|
* @property {(pos: string[], flags: Record<string, unknown>, context?: object) => unknown[]} [buildArgs]
|
|
97
98
|
* @property {string} usage One-line usage string.
|
|
98
99
|
*/
|
|
@@ -118,6 +119,7 @@ const COMMANDS = {
|
|
|
118
119
|
|
|
119
120
|
"branch create": {
|
|
120
121
|
method: "POST",
|
|
122
|
+
retryUnsafe: true,
|
|
121
123
|
action: "createBranch",
|
|
122
124
|
usage: "branch create <branchName> [--issue KEY] [--project KEY]",
|
|
123
125
|
buildArgs: ([branchName]) => {
|
|
@@ -128,6 +130,7 @@ const COMMANDS = {
|
|
|
128
130
|
},
|
|
129
131
|
"branch delete": {
|
|
130
132
|
method: "POST",
|
|
133
|
+
retryUnsafe: true,
|
|
131
134
|
action: "deleteBranch",
|
|
132
135
|
destructive: true,
|
|
133
136
|
usage: "branch delete <branchName> [--issue KEY] [--project KEY] --force",
|
|
@@ -140,6 +143,7 @@ const COMMANDS = {
|
|
|
140
143
|
|
|
141
144
|
"commit template": {
|
|
142
145
|
method: "POST",
|
|
146
|
+
retryUnsafe: true,
|
|
143
147
|
action: "commitByTemplate",
|
|
144
148
|
usage:
|
|
145
149
|
'commit template <worktreePath> [--values \'{"key":"val"}\'] [--no-push] [--issue KEY] [--project KEY]' +
|
|
@@ -159,6 +163,7 @@ const COMMANDS = {
|
|
|
159
163
|
|
|
160
164
|
"mr create": {
|
|
161
165
|
method: "POST",
|
|
166
|
+
retryUnsafe: true,
|
|
162
167
|
action: "createPullRequest",
|
|
163
168
|
usage:
|
|
164
169
|
"mr create <title> <headBranch> [--body <text>] [--base <branch>] [--type <idOrLabel>]" +
|
|
@@ -199,6 +204,7 @@ const COMMANDS = {
|
|
|
199
204
|
},
|
|
200
205
|
"mr close": {
|
|
201
206
|
method: "POST",
|
|
207
|
+
retryUnsafe: true,
|
|
202
208
|
action: "closePullRequest",
|
|
203
209
|
destructive: true,
|
|
204
210
|
usage: "mr close <prId> [--issue KEY] [--project KEY] --force",
|
|
@@ -206,6 +212,7 @@ const COMMANDS = {
|
|
|
206
212
|
},
|
|
207
213
|
"mr merge": {
|
|
208
214
|
method: "POST",
|
|
215
|
+
retryUnsafe: true,
|
|
209
216
|
action: "mergePullRequest",
|
|
210
217
|
destructive: true,
|
|
211
218
|
usage:
|
|
@@ -309,6 +316,7 @@ const COMMANDS = {
|
|
|
309
316
|
},
|
|
310
317
|
"pipeline retry": {
|
|
311
318
|
method: "POST",
|
|
319
|
+
retryUnsafe: true,
|
|
312
320
|
action: "restartFailedJobs",
|
|
313
321
|
usage: "pipeline retry <pipelineOrRunId> [--all] [--job <jobId>] [--issue KEY] [--project KEY]",
|
|
314
322
|
buildArgs: ([id], flags) => {
|
|
@@ -329,6 +337,7 @@ const COMMANDS = {
|
|
|
329
337
|
|
|
330
338
|
"slack notify": {
|
|
331
339
|
method: "POST",
|
|
340
|
+
retryUnsafe: true,
|
|
332
341
|
action: "notifySlack",
|
|
333
342
|
usage:
|
|
334
343
|
'slack notify <message> [--channel ID] [--values \'{"key":"val"}\'] [--issue KEY] [--project KEY]',
|