@blogic-cz/agent-tools 0.15.3 → 0.15.5
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/gh-tool/index.ts +5 -1
- package/src/gh-tool/issue/commands.ts +57 -1
- package/src/gh-tool/issue/core.ts +34 -0
- package/src/gh-tool/issue/index.ts +1 -0
- package/src/gh-tool/pr/commands.ts +25 -0
- package/src/gh-tool/pr/core.ts +17 -0
- package/src/gh-tool/pr/index.ts +1 -0
package/package.json
CHANGED
package/src/gh-tool/index.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
issueCloseCommand,
|
|
11
11
|
issueCommentCommand,
|
|
12
12
|
issueCommentsCommand,
|
|
13
|
+
issueCreateCommand,
|
|
13
14
|
issueEditCommand,
|
|
14
15
|
issueListCommand,
|
|
15
16
|
issueReopenCommand,
|
|
@@ -25,6 +26,7 @@ import {
|
|
|
25
26
|
prCloseCommand,
|
|
26
27
|
prEditCommand,
|
|
27
28
|
prMergeCommand,
|
|
29
|
+
prReadyCommand,
|
|
28
30
|
prThreadsCommand,
|
|
29
31
|
prCommentsCommand,
|
|
30
32
|
prIssueCommentsCommand,
|
|
@@ -81,6 +83,7 @@ const prCommand = Command.make("pr", {}).pipe(
|
|
|
81
83
|
prCloseCommand,
|
|
82
84
|
prEditCommand,
|
|
83
85
|
prMergeCommand,
|
|
86
|
+
prReadyCommand,
|
|
84
87
|
prWaitMergeableCommand,
|
|
85
88
|
prThreadsCommand,
|
|
86
89
|
prCommentsCommand,
|
|
@@ -107,7 +110,7 @@ const prCommand = Command.make("pr", {}).pipe(
|
|
|
107
110
|
|
|
108
111
|
const issueCommand = Command.make("issue", {}).pipe(
|
|
109
112
|
Command.withDescription(
|
|
110
|
-
"Issue operations (list, view, comments, triage, snapshot-batch, close, reopen, comment, edit)",
|
|
113
|
+
"Issue operations (list, view, comments, triage, snapshot-batch, create, close, reopen, comment, edit)",
|
|
111
114
|
),
|
|
112
115
|
Command.withSubcommands([
|
|
113
116
|
issueListCommand,
|
|
@@ -115,6 +118,7 @@ const issueCommand = Command.make("issue", {}).pipe(
|
|
|
115
118
|
issueCommentsCommand,
|
|
116
119
|
issueTriageCommand,
|
|
117
120
|
issueSnapshotBatchCommand,
|
|
121
|
+
issueCreateCommand,
|
|
118
122
|
issueCloseCommand,
|
|
119
123
|
issueReopenCommand,
|
|
120
124
|
issueCommentCommand,
|
|
@@ -2,11 +2,16 @@ import { Command, Flag } from "effect/unstable/cli";
|
|
|
2
2
|
import { Effect, Option } from "effect";
|
|
3
3
|
|
|
4
4
|
import { formatOption, logFormatted } from "#shared";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
resolveDefaultTextInput,
|
|
7
|
+
resolveOptionalTextInput,
|
|
8
|
+
resolveRequiredTextInput,
|
|
9
|
+
} from "#gh/text-input";
|
|
6
10
|
|
|
7
11
|
import {
|
|
8
12
|
closeIssue,
|
|
9
13
|
commentOnIssue,
|
|
14
|
+
createIssue,
|
|
10
15
|
editIssue,
|
|
11
16
|
fetchIssueComments,
|
|
12
17
|
listIssues,
|
|
@@ -192,6 +197,57 @@ export const issueReopenCommand = Command.make(
|
|
|
192
197
|
),
|
|
193
198
|
).pipe(Command.withDescription("Reopen a closed issue"));
|
|
194
199
|
|
|
200
|
+
export const issueCreateCommand = Command.make(
|
|
201
|
+
"create",
|
|
202
|
+
{
|
|
203
|
+
assignee: Flag.string("assignee").pipe(
|
|
204
|
+
Flag.withDescription("Assignee login (comma-separated for multiple)"),
|
|
205
|
+
Flag.optional,
|
|
206
|
+
),
|
|
207
|
+
body: Flag.string("body").pipe(Flag.withDescription("Issue body"), Flag.optional),
|
|
208
|
+
bodyFile: Flag.string("body-file").pipe(
|
|
209
|
+
Flag.withDescription("Read issue body from a file path or '-' for stdin"),
|
|
210
|
+
Flag.optional,
|
|
211
|
+
),
|
|
212
|
+
bodyStdin: Flag.boolean("body-stdin").pipe(
|
|
213
|
+
Flag.withDescription("Read issue body from stdin"),
|
|
214
|
+
Flag.withDefault(false),
|
|
215
|
+
),
|
|
216
|
+
format: formatOption,
|
|
217
|
+
labels: Flag.string("labels").pipe(
|
|
218
|
+
Flag.withDescription("Labels to apply (comma-separated)"),
|
|
219
|
+
Flag.optional,
|
|
220
|
+
),
|
|
221
|
+
repo: repoOption,
|
|
222
|
+
title: Flag.string("title").pipe(Flag.withDescription("Issue title")),
|
|
223
|
+
},
|
|
224
|
+
({ assignee, body, bodyFile, bodyStdin, format, labels, repo, title }) =>
|
|
225
|
+
withRepo(
|
|
226
|
+
repo,
|
|
227
|
+
Effect.gen(function* () {
|
|
228
|
+
const resolvedBody = yield* resolveDefaultTextInput({
|
|
229
|
+
command: "gh-tool issue create",
|
|
230
|
+
value: Option.getOrNull(body),
|
|
231
|
+
fileValue: Option.getOrNull(bodyFile),
|
|
232
|
+
stdin: bodyStdin,
|
|
233
|
+
valueFlag: "--body",
|
|
234
|
+
fileFlag: "--body-file",
|
|
235
|
+
stdinFlag: "--body-stdin",
|
|
236
|
+
label: "body",
|
|
237
|
+
defaultValue: "",
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
const result = yield* createIssue({
|
|
241
|
+
assignee: Option.getOrNull(assignee),
|
|
242
|
+
body: resolvedBody,
|
|
243
|
+
labels: Option.getOrNull(labels),
|
|
244
|
+
title,
|
|
245
|
+
});
|
|
246
|
+
yield* logFormatted(result, format);
|
|
247
|
+
}),
|
|
248
|
+
),
|
|
249
|
+
).pipe(Command.withDescription("Create a new issue"));
|
|
250
|
+
|
|
195
251
|
export const issueCommentCommand = Command.make(
|
|
196
252
|
"comment",
|
|
197
253
|
{
|
|
@@ -257,6 +257,40 @@ export const commentOnIssue = Effect.fn("issue.commentOnIssue")(function* (opts:
|
|
|
257
257
|
};
|
|
258
258
|
});
|
|
259
259
|
|
|
260
|
+
export const createIssue = Effect.fn("issue.createIssue")(function* (opts: {
|
|
261
|
+
title: string;
|
|
262
|
+
body: string;
|
|
263
|
+
assignee: string | null;
|
|
264
|
+
labels: string | null;
|
|
265
|
+
}) {
|
|
266
|
+
const gh = yield* GitHubService;
|
|
267
|
+
|
|
268
|
+
const args = ["issue", "create", "--title", opts.title, "--body", opts.body];
|
|
269
|
+
|
|
270
|
+
if (opts.assignee !== null) {
|
|
271
|
+
args.push("--assignee", opts.assignee);
|
|
272
|
+
}
|
|
273
|
+
if (opts.labels !== null) {
|
|
274
|
+
args.push("--label", opts.labels);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const result = yield* gh.runGh(args);
|
|
278
|
+
|
|
279
|
+
const urlMatch = result.stdout.match(/\/issues\/(\d+)/);
|
|
280
|
+
if (!urlMatch?.[1]) {
|
|
281
|
+
return yield* Effect.fail(
|
|
282
|
+
new GitHubCommandError({
|
|
283
|
+
command: "gh issue create",
|
|
284
|
+
exitCode: 0,
|
|
285
|
+
stderr: "Issue was created but its number could not be parsed from the output.",
|
|
286
|
+
message: "Issue was created but its number could not be parsed from the output.",
|
|
287
|
+
}),
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return yield* viewIssue(Number(urlMatch[1]));
|
|
292
|
+
});
|
|
293
|
+
|
|
260
294
|
export const editIssue = Effect.fn("issue.editIssue")(function* (opts: {
|
|
261
295
|
issue: number;
|
|
262
296
|
title: string | null;
|
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
fetchFailedChecks,
|
|
39
39
|
listPRs,
|
|
40
40
|
mergePR,
|
|
41
|
+
readyPR,
|
|
41
42
|
rerunChecks,
|
|
42
43
|
triggerChecks,
|
|
43
44
|
watchPRs,
|
|
@@ -644,6 +645,30 @@ export const prMergeCommand = Command.make(
|
|
|
644
645
|
),
|
|
645
646
|
).pipe(Command.withDescription("Merge a PR (dry-run by default, use --confirm to execute)"));
|
|
646
647
|
|
|
648
|
+
export const prReadyCommand = Command.make(
|
|
649
|
+
"ready",
|
|
650
|
+
{
|
|
651
|
+
format: formatOption,
|
|
652
|
+
pr: Flag.integer("pr").pipe(
|
|
653
|
+
Flag.withDescription("PR number (default: current branch PR)"),
|
|
654
|
+
Flag.optional,
|
|
655
|
+
),
|
|
656
|
+
repo: repoOption,
|
|
657
|
+
},
|
|
658
|
+
({ format, pr, repo }) =>
|
|
659
|
+
withRepo(
|
|
660
|
+
repo,
|
|
661
|
+
Effect.gen(function* () {
|
|
662
|
+
const result = yield* readyPR({ pr: Option.getOrNull(pr) });
|
|
663
|
+
yield* logFormatted(result, format);
|
|
664
|
+
}),
|
|
665
|
+
),
|
|
666
|
+
).pipe(
|
|
667
|
+
Command.withDescription(
|
|
668
|
+
"Mark a draft PR as ready for review (no-op if it's already ready for review)",
|
|
669
|
+
),
|
|
670
|
+
);
|
|
671
|
+
|
|
647
672
|
export const prChecksCommand = Command.make(
|
|
648
673
|
"checks",
|
|
649
674
|
{
|
package/src/gh-tool/pr/core.ts
CHANGED
|
@@ -972,6 +972,23 @@ export const closePR = Effect.fn("pr.closePR")(function* (opts: {
|
|
|
972
972
|
return yield* viewPR(opts.pr);
|
|
973
973
|
});
|
|
974
974
|
|
|
975
|
+
export const readyPR = Effect.fn("pr.readyPR")(function* (opts: { pr: number | null }) {
|
|
976
|
+
const gh = yield* GitHubService;
|
|
977
|
+
|
|
978
|
+
const info = yield* viewPR(opts.pr);
|
|
979
|
+
|
|
980
|
+
// Idempotent: a PR that's already ready needs no mutation, and `gh pr ready` on a
|
|
981
|
+
// non-draft PR is a no-op that would just add a pointless call.
|
|
982
|
+
if (!info.isDraft) {
|
|
983
|
+
return { ...info, wasAlreadyReady: true };
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
yield* gh.runGh(["pr", "ready", String(info.number)]);
|
|
987
|
+
|
|
988
|
+
const updated = yield* viewPR(info.number);
|
|
989
|
+
return { ...updated, wasAlreadyReady: false };
|
|
990
|
+
});
|
|
991
|
+
|
|
975
992
|
export const editPR = Effect.fn("pr.editPR")(function* (opts: {
|
|
976
993
|
pr: number;
|
|
977
994
|
title: string | null;
|