pr-shepherd 0.42.0 → 0.44.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/.claude-plugin/plugin.json +1 -1
- package/README.md +24 -18
- package/bin/api.d.mts +3 -2
- package/bin/api.mjs +13 -18
- package/bin/checks/classify.d.mts +3 -1
- package/bin/checks/classify.mjs +5 -2
- package/bin/cli/args.mjs +14 -9
- package/bin/cli/default-poll.mjs +1 -0
- package/bin/cli/fix-formatter.mjs +20 -8
- package/bin/cli/handlers.mjs +1 -0
- package/bin/cli/help-command-pages.d.mts +9 -6
- package/bin/cli/help-command-pages.mjs +7 -4
- package/bin/cli/help-iterate-poll-pages.d.mts +2 -2
- package/bin/cli/help-iterate-poll-pages.mjs +9 -4
- package/bin/cli/help-top-page.d.mts +1 -1
- package/bin/cli/help-top-page.mjs +2 -2
- package/bin/cli/help.d.mts +10 -7
- package/bin/cli/iterate-flags.d.mts +1 -0
- package/bin/cli/iterate-flags.mjs +2 -0
- package/bin/cli/iterate-formatter.d.mts +1 -1
- package/bin/cli/iterate-formatter.mjs +9 -6
- package/bin/cli/iterate-instructions.mjs +15 -0
- package/bin/cli/iterate-lean.d.mts +1 -2
- package/bin/cli/iterate-lean.mjs +16 -17
- package/bin/cli/iterate-merge-formatter.d.mts +3 -0
- package/bin/cli/iterate-merge-formatter.mjs +52 -0
- package/bin/cli/iterate-verbose.d.mts +6 -0
- package/bin/cli/iterate-verbose.mjs +14 -0
- package/bin/cli/journal-formatter.mjs +3 -0
- package/bin/cli/journal-handler.mjs +11 -7
- package/bin/cli/list-formatters.d.mts +3 -1
- package/bin/cli/list-formatters.mjs +9 -7
- package/bin/cli/mark-files-as-viewed-formatter.mjs +7 -1
- package/bin/cli/mutate-formatter.mjs +4 -0
- package/bin/cli/poll-handler.mjs +1 -0
- package/bin/cli/runner.mjs +4 -3
- package/bin/commands/check-terminal-report.mjs +1 -0
- package/bin/commands/check.mjs +64 -7
- package/bin/commands/commit-suggestion-instruction.d.mts +1 -1
- package/bin/commands/commit-suggestion-instruction.mjs +2 -2
- package/bin/commands/commit-suggestion.mjs +3 -1
- package/bin/commands/iterate/base.d.mts +5 -0
- package/bin/commands/iterate/base.mjs +25 -0
- package/bin/commands/iterate/check-instructions.d.mts +5 -19
- package/bin/commands/iterate/check-instructions.mjs +24 -25
- package/bin/commands/iterate/classify.d.mts +2 -2
- package/bin/commands/iterate/classify.mjs +43 -25
- package/bin/commands/iterate/escalate.d.mts +3 -1
- package/bin/commands/iterate/escalate.mjs +29 -2
- package/bin/commands/iterate/fix-code.mjs +81 -26
- package/bin/commands/iterate/helpers.d.mts +0 -2
- package/bin/commands/iterate/helpers.mjs +6 -17
- package/bin/commands/iterate/index.mjs +31 -43
- package/bin/commands/iterate/mark-ready.d.mts +2 -0
- package/bin/commands/iterate/mark-ready.mjs +38 -0
- package/bin/commands/iterate/merge-state.d.mts +15 -0
- package/bin/commands/iterate/merge-state.mjs +82 -0
- package/bin/commands/iterate/merge.d.mts +13 -0
- package/bin/commands/iterate/merge.mjs +45 -0
- package/bin/commands/iterate/render.d.mts +2 -2
- package/bin/commands/iterate/render.mjs +19 -20
- package/bin/commands/iterate/stall.mjs +4 -2
- package/bin/commands/iterate/thread-mutation-routing.d.mts +9 -0
- package/bin/commands/iterate/thread-mutation-routing.mjs +29 -0
- package/bin/commands/journal/index.d.mts +5 -0
- package/bin/commands/journal/index.mjs +11 -2
- package/bin/commands/mark-files-as-viewed.d.mts +2 -1
- package/bin/commands/mark-files-as-viewed.mjs +5 -92
- package/bin/commands/poll.mjs +3 -1
- package/bin/commands/resolve-mutate.mjs +51 -9
- package/bin/commands/shepherd-journal.d.mts +1 -1
- package/bin/commands/shepherd-journal.mjs +2 -2
- package/bin/commands/suggestion-patch-item.d.mts +1 -1
- package/bin/commands/suggestion-patch-item.mjs +3 -11
- package/bin/commands/suggestion-patches.mjs +3 -3
- package/bin/comments/authors.d.mts +6 -0
- package/bin/comments/authors.mjs +5 -0
- package/bin/comments/marker.d.mts +6 -1
- package/bin/comments/marker.mjs +8 -1
- package/bin/comments/resolve.d.mts +4 -0
- package/bin/comments/thread-visibility.mjs +10 -10
- package/bin/comments/visible-comments.mjs +2 -1
- package/bin/config/load.d.mts +5 -1
- package/bin/config/load.mjs +34 -0
- package/bin/config/merge-command-args.d.mts +2 -0
- package/bin/config/merge-command-args.mjs +44 -0
- package/bin/config.json +3 -0
- package/bin/exit-codes.d.mts +2 -0
- package/bin/exit-codes.mjs +4 -0
- package/bin/github/batch-parse-checks.d.mts +3 -0
- package/bin/github/batch-parse-checks.mjs +29 -0
- package/bin/github/batch-parsers-rules.d.mts +3 -1
- package/bin/github/batch-parsers-rules.mjs +33 -0
- package/bin/github/batch-parsers.d.mts +2 -2
- package/bin/github/batch-parsers.mjs +40 -27
- package/bin/github/batch-raw-rules.d.mts +48 -0
- package/bin/github/batch-raw-types.d.mts +12 -0
- package/bin/github/batch-raw-types.mjs +0 -1
- package/bin/github/batch.mjs +3 -1
- package/bin/github/client.d.mts +1 -0
- package/bin/github/client.mjs +8 -1
- package/bin/github/gql/batch-pr-page.gql +6 -0
- package/bin/github/gql/batch-pr.gql +105 -0
- package/bin/github/gql/commit-check-contexts.gql +58 -0
- package/bin/github/gql/get-pr-body.gql +1 -0
- package/bin/github/gql/review-thread-comments.gql +1 -0
- package/bin/github/gql/suggestion-threads.gql +1 -0
- package/bin/github/merge-queue-checks.d.mts +4 -0
- package/bin/github/merge-queue-checks.mjs +48 -0
- package/bin/github/queries.d.mts +2 -0
- package/bin/github/queries.mjs +2 -0
- package/bin/github/suggestion-thread.mjs +1 -0
- package/bin/mcp/server.mjs +13 -6
- package/bin/pr-reference.d.mts +13 -0
- package/bin/pr-reference.mjs +23 -1
- package/bin/reporters/agent.mjs +11 -3
- package/bin/threads/transcript.d.mts +2 -0
- package/bin/threads/transcript.mjs +2 -0
- package/bin/types/activity.d.mts +2 -0
- package/bin/types/agent-thread.d.mts +1 -0
- package/bin/types/escalate.d.mts +35 -0
- package/bin/types/escalate.mjs +1 -0
- package/bin/types/github.d.mts +27 -0
- package/bin/types/github.mjs +0 -3
- package/bin/types/iterate.d.mts +23 -39
- package/bin/types/merge-action.d.mts +12 -0
- package/bin/types/merge-action.mjs +1 -0
- package/bin/types/merge-queue.d.mts +13 -0
- package/bin/types/merge-queue.mjs +1 -0
- package/bin/types/merge-requirements.d.mts +17 -0
- package/bin/types/report.d.mts +22 -1
- package/bin/types/review-thread.d.mts +1 -0
- package/bin/types/suggestion-patch.d.mts +1 -1
- package/bin/types.d.mts +3 -0
- package/bin/types.mjs +3 -0
- package/bin/util/markdown.d.mts +2 -0
- package/bin/util/markdown.mjs +7 -0
- package/package.json +1 -1
- package/plugins/pr-shepherd/.codex-plugin/plugin.json +1 -1
- package/plugins/pr-shepherd/.codex.mcp.json +1 -1
- package/plugins/pr-shepherd/.mcp.json +1 -1
- package/plugins/pr-shepherd/skills/mark-files-as-viewed/SKILL.md +3 -3
- package/plugins/pr-shepherd/skills/pr-shepherd/SKILL.md +17 -15
- package/bin/commands/iterate/reruns.d.mts +0 -20
- package/bin/commands/iterate/reruns.mjs +0 -105
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const MERGE_STRATEGY_FLAGS = new Map([
|
|
2
|
+
["--merge", "merge"],
|
|
3
|
+
["-m", "merge"],
|
|
4
|
+
["--squash", "squash"],
|
|
5
|
+
["-s", "squash"],
|
|
6
|
+
["--rebase", "rebase"],
|
|
7
|
+
["-r", "rebase"],
|
|
8
|
+
]);
|
|
9
|
+
/** Return active merge strategies while validating compound strategy syntax. */
|
|
10
|
+
export function findMergeStrategies(args) {
|
|
11
|
+
const strategies = [];
|
|
12
|
+
for (const arg of args) {
|
|
13
|
+
const exact = MERGE_STRATEGY_FLAGS.get(arg);
|
|
14
|
+
if (exact) {
|
|
15
|
+
strategies.push(exact);
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
const longAssignment = /^(--merge|--squash|--rebase)=(.*)$/.exec(arg);
|
|
19
|
+
const shortAssignment = /^(-[msr])=(.*)$/.exec(arg);
|
|
20
|
+
const assignment = longAssignment ?? shortAssignment;
|
|
21
|
+
if (assignment) {
|
|
22
|
+
if (assignment[2] !== "true" && assignment[2] !== "false") {
|
|
23
|
+
throw new Error(`Invalid config: merge.commandArgs strategy ${arg} must use true or false`);
|
|
24
|
+
}
|
|
25
|
+
if (assignment[2] === "true") {
|
|
26
|
+
strategies.push(MERGE_STRATEGY_FLAGS.get(assignment[1]));
|
|
27
|
+
}
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const shortBundle = /^-([dmrs]{2,})$/.exec(arg);
|
|
31
|
+
if (shortBundle) {
|
|
32
|
+
for (const flag of shortBundle[1]) {
|
|
33
|
+
const strategy = MERGE_STRATEGY_FLAGS.get(`-${flag}`);
|
|
34
|
+
if (strategy)
|
|
35
|
+
strategies.push(strategy);
|
|
36
|
+
}
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (/^-[dmrs].+/.test(arg)) {
|
|
40
|
+
throw new Error(`Invalid config: merge.commandArgs cannot safely parse compound short option ${arg}; use separate flags or long options`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return strategies;
|
|
44
|
+
}
|
package/bin/config.json
CHANGED
package/bin/exit-codes.d.mts
CHANGED
|
@@ -23,6 +23,8 @@ export declare const EXIT: Readonly<{
|
|
|
23
23
|
readonly ESCALATE: 13;
|
|
24
24
|
/** `cancel` + `closed` — PR closed without merging. */
|
|
25
25
|
readonly CLOSED: 14;
|
|
26
|
+
/** Agent should run the emitted merge or queue command. */
|
|
27
|
+
readonly MERGE: 15;
|
|
26
28
|
/** Bad/unknown flag, unknown subcommand, missing required arg, invalid duration. */
|
|
27
29
|
readonly USAGE: 64;
|
|
28
30
|
/** Malformed caller data: bad `--require-sha`, `PRRC_*` IDs, bad repo string. */
|
package/bin/exit-codes.mjs
CHANGED
|
@@ -22,6 +22,8 @@ export const EXIT = Object.freeze({
|
|
|
22
22
|
ESCALATE: 13,
|
|
23
23
|
/** `cancel` + `closed` — PR closed without merging. */
|
|
24
24
|
CLOSED: 14,
|
|
25
|
+
/** Agent should run the emitted merge or queue command. */
|
|
26
|
+
MERGE: 15,
|
|
25
27
|
/** Bad/unknown flag, unknown subcommand, missing required arg, invalid duration. */
|
|
26
28
|
USAGE: 64,
|
|
27
29
|
/** Malformed caller data: bad `--require-sha`, `PRRC_*` IDs, bad repo string. */
|
|
@@ -65,6 +67,8 @@ export function iterateResultToExitCode(result) {
|
|
|
65
67
|
return EXIT.FIX_CODE;
|
|
66
68
|
case "escalate":
|
|
67
69
|
return EXIT.ESCALATE;
|
|
70
|
+
case "merge":
|
|
71
|
+
return EXIT.MERGE;
|
|
68
72
|
}
|
|
69
73
|
}
|
|
70
74
|
export function errorToExitCode(err) {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { mapCheckRunNode, mapStatusContextState, parseCreatedAt } from "./batch-parser-helpers.mjs";
|
|
2
|
+
export function parseCheckNodes(nodes, mergeCommitOid) {
|
|
3
|
+
return (nodes ?? []).flatMap((node) => {
|
|
4
|
+
const scope = mergeCommitOid
|
|
5
|
+
? { scope: "merge_group", commitOid: mergeCommitOid }
|
|
6
|
+
: {};
|
|
7
|
+
if (node?.__typename === "CheckRun")
|
|
8
|
+
return [{ ...mapCheckRunNode(node), ...scope }];
|
|
9
|
+
if (node?.__typename !== "StatusContext")
|
|
10
|
+
return [];
|
|
11
|
+
const { status, conclusion } = mapStatusContextState(node.state);
|
|
12
|
+
const summary = node.description?.trim() || undefined;
|
|
13
|
+
const createdAtUnix = node.createdAt ? parseCreatedAt(node.createdAt) : undefined;
|
|
14
|
+
return [
|
|
15
|
+
{
|
|
16
|
+
name: node.context,
|
|
17
|
+
status,
|
|
18
|
+
conclusion,
|
|
19
|
+
source: "status_context",
|
|
20
|
+
detailsUrl: node.targetUrl ?? "",
|
|
21
|
+
event: null,
|
|
22
|
+
runId: null,
|
|
23
|
+
...scope,
|
|
24
|
+
...(createdAtUnix !== undefined && { createdAtUnix }),
|
|
25
|
+
...(summary !== undefined && { summary }),
|
|
26
|
+
},
|
|
27
|
+
];
|
|
28
|
+
});
|
|
29
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import type { BranchRules, MergeQueueEntryStatus, StackStatus } from "../types.mts";
|
|
1
|
+
import type { AutoMergeRequestStatus, BranchRules, MergeQueueEntryStatus, MergeQueueRemovalStatus, StackStatus } from "../types.mts";
|
|
2
2
|
import type { RawBaseRef, RawPrMergeFields } from "./batch-raw-rules.mts";
|
|
3
3
|
export declare const EMPTY_BRANCH_RULES: BranchRules;
|
|
4
4
|
export declare function parseBranchRules(baseRef: RawBaseRef | null | undefined): BranchRules;
|
|
5
5
|
export declare function parseMergeQueueEntry(raw: RawPrMergeFields["mergeQueueEntry"]): MergeQueueEntryStatus | null;
|
|
6
|
+
export declare function parseAutoMergeRequest(raw: RawPrMergeFields["autoMergeRequest"]): AutoMergeRequestStatus | null;
|
|
7
|
+
export declare function parseLatestMergeQueueRemoval(raw: RawPrMergeFields): MergeQueueRemovalStatus | null;
|
|
6
8
|
export declare function parseStack(raw: RawPrMergeFields): StackStatus | null;
|
|
@@ -32,8 +32,41 @@ export function parseMergeQueueEntry(raw) {
|
|
|
32
32
|
position: raw.position,
|
|
33
33
|
state: raw.state,
|
|
34
34
|
estimatedTimeToMerge: raw.estimatedTimeToMerge,
|
|
35
|
+
...(raw.headCommit?.oid && { headCommitOid: raw.headCommit.oid }),
|
|
36
|
+
...(raw.enqueuedAt && { enqueuedAtUnix: parseUnix(raw.enqueuedAt) }),
|
|
37
|
+
...(raw.enqueuer?.login && { enqueuer: raw.enqueuer.login }),
|
|
35
38
|
};
|
|
36
39
|
}
|
|
40
|
+
export function parseAutoMergeRequest(raw) {
|
|
41
|
+
if (!raw)
|
|
42
|
+
return null;
|
|
43
|
+
return {
|
|
44
|
+
enabledAtUnix: parseUnix(raw.enabledAt),
|
|
45
|
+
mergeMethod: raw.mergeMethod,
|
|
46
|
+
...(raw.enabledBy?.login && { enabledBy: raw.enabledBy.login }),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export function parseLatestMergeQueueRemoval(raw) {
|
|
50
|
+
const removal = raw.mergeQueueRemovals?.nodes[0];
|
|
51
|
+
if (!removal)
|
|
52
|
+
return null;
|
|
53
|
+
const lastAddedAt = raw.mergeQueueAdditions?.nodes[0]?.createdAt;
|
|
54
|
+
if (lastAddedAt && Date.parse(lastAddedAt) > Date.parse(removal.createdAt))
|
|
55
|
+
return null;
|
|
56
|
+
return {
|
|
57
|
+
reason: removal.reason,
|
|
58
|
+
createdAtUnix: parseUnix(removal.createdAt),
|
|
59
|
+
...(removal.actor?.login && { actor: removal.actor.login }),
|
|
60
|
+
...(removal.beforeCommit?.oid && { beforeCommitOid: removal.beforeCommit.oid }),
|
|
61
|
+
...(removal.beforeCommit?.parents && {
|
|
62
|
+
beforeCommitParentOids: removal.beforeCommit.parents.nodes.map((parent) => parent.oid),
|
|
63
|
+
}),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function parseUnix(value) {
|
|
67
|
+
const ms = Date.parse(value);
|
|
68
|
+
return Number.isFinite(ms) ? Math.floor(ms / 1000) : 0;
|
|
69
|
+
}
|
|
37
70
|
export function parseStack(raw) {
|
|
38
71
|
if (!raw.stack)
|
|
39
72
|
return null;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { BatchPrData } from "../types.mts";
|
|
2
|
-
import type { RawPr, RawThread, RawComment, RawReview, RawReviewSummary, RawContextNode } from "./batch-raw-types.mts";
|
|
3
|
-
export declare function parseRawPr(raw: RawPr, rawThreadPages: RawThread[], rawCommentNodes: RawComment[], rawReviewNodes: RawReview[], rawReviewSummaryNodes: RawReviewSummary[], rawApprovedReviewNodes: RawReviewSummary[], rawCheckNodes: RawContextNode[]): BatchPrData;
|
|
2
|
+
import type { RawBatchResponse, RawPr, RawThread, RawComment, RawReview, RawReviewSummary, RawContextNode } from "./batch-raw-types.mts";
|
|
3
|
+
export declare function parseRawPr(raw: RawPr, rawThreadPages: RawThread[], rawCommentNodes: RawComment[], rawReviewNodes: RawReview[], rawReviewSummaryNodes: RawReviewSummary[], rawApprovedReviewNodes: RawReviewSummary[], rawCheckNodes: RawContextNode[], repository?: Pick<NonNullable<RawBatchResponse["repository"]>, "viewerPermission" | "viewerCanAdminister">): BatchPrData;
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import { mapAuthorType, parseCreatedAt,
|
|
1
|
+
import { mapAuthorType, parseCreatedAt, latestApprovedLogins, isReviewStale, } from "./batch-parser-helpers.mjs";
|
|
2
|
+
import { parseCheckNodes } from "./batch-parse-checks.mjs";
|
|
3
|
+
import { requireContextNodes } from "./batch-response.mjs";
|
|
2
4
|
import { buildPrActivitySummary } from "./activity.mjs";
|
|
3
5
|
import { parseBranchProtection } from "./branch-protection.mjs";
|
|
4
|
-
import { parseBranchRules, parseMergeQueueEntry, parseStack } from "./batch-parsers-rules.mjs";
|
|
6
|
+
import { parseAutoMergeRequest, parseBranchRules, parseLatestMergeQueueRemoval, parseMergeQueueEntry, parseStack, } from "./batch-parsers-rules.mjs";
|
|
5
7
|
function parseReviewNode(r) {
|
|
6
8
|
const base = {
|
|
7
9
|
id: r.id,
|
|
8
10
|
author: r.author?.login ?? "unknown",
|
|
9
11
|
authorType: mapAuthorType(r.author?.__typename, r.author?.login),
|
|
10
12
|
...(r.authorAssociation !== undefined && { authorAssociation: r.authorAssociation }),
|
|
13
|
+
viewerCanMinimize: "viewerCanMinimize" in r && r.viewerCanMinimize === true,
|
|
11
14
|
body: r.body,
|
|
12
15
|
createdAtUnix: r.createdAt ? parseCreatedAt(r.createdAt) : 0,
|
|
13
16
|
};
|
|
@@ -16,7 +19,7 @@ function parseReviewNode(r) {
|
|
|
16
19
|
}
|
|
17
20
|
return base;
|
|
18
21
|
}
|
|
19
|
-
export function parseRawPr(raw, rawThreadPages, rawCommentNodes, rawReviewNodes, rawReviewSummaryNodes, rawApprovedReviewNodes, rawCheckNodes) {
|
|
22
|
+
export function parseRawPr(raw, rawThreadPages, rawCommentNodes, rawReviewNodes, rawReviewSummaryNodes, rawApprovedReviewNodes, rawCheckNodes, repository) {
|
|
20
23
|
const reviewRequests = (raw.reviewRequests?.nodes ?? []).flatMap((n) => {
|
|
21
24
|
const login = n.requestedReviewer?.login ?? n.requestedReviewer?.name;
|
|
22
25
|
return login ? [{ login }] : [];
|
|
@@ -35,6 +38,7 @@ export function parseRawPr(raw, rawThreadPages, rawCommentNodes, rawReviewNodes,
|
|
|
35
38
|
author: c.author?.login ?? "unknown",
|
|
36
39
|
authorType: mapAuthorType(c.author?.__typename, c.author?.login),
|
|
37
40
|
...(c.authorAssociation !== undefined && { authorAssociation: c.authorAssociation }),
|
|
41
|
+
...(c.viewerDidAuthor === true && { viewerDidAuthor: true }),
|
|
38
42
|
body: c.body,
|
|
39
43
|
url: c.url,
|
|
40
44
|
createdAtUnix: c.createdAt ? parseCreatedAt(c.createdAt) : 0,
|
|
@@ -44,6 +48,8 @@ export function parseRawPr(raw, rawThreadPages, rawCommentNodes, rawReviewNodes,
|
|
|
44
48
|
isResolved: t.isResolved,
|
|
45
49
|
isOutdated: t.isOutdated,
|
|
46
50
|
isMinimized: comment?.isMinimized ?? false,
|
|
51
|
+
viewerCanReply: t.viewerCanReply === true,
|
|
52
|
+
viewerCanResolve: t.viewerCanResolve === true,
|
|
47
53
|
path: t.path ?? comment?.path ?? null,
|
|
48
54
|
line: t.line ?? comment?.line ?? null,
|
|
49
55
|
startLine: t.startLine ?? comment?.startLine ?? null,
|
|
@@ -53,6 +59,7 @@ export function parseRawPr(raw, rawThreadPages, rawCommentNodes, rawReviewNodes,
|
|
|
53
59
|
...(comment?.authorAssociation !== undefined && {
|
|
54
60
|
authorAssociation: comment.authorAssociation,
|
|
55
61
|
}),
|
|
62
|
+
...(comment?.viewerDidAuthor === true && { viewerDidAuthor: true }),
|
|
56
63
|
body: comment?.body ?? "",
|
|
57
64
|
url: comment?.url ?? "",
|
|
58
65
|
createdAtUnix: comment?.createdAt ? parseCreatedAt(comment.createdAt) : 0,
|
|
@@ -62,6 +69,7 @@ export function parseRawPr(raw, rawThreadPages, rawCommentNodes, rawReviewNodes,
|
|
|
62
69
|
const comments = rawCommentNodes.map((c) => ({
|
|
63
70
|
id: c.id,
|
|
64
71
|
isMinimized: c.isMinimized,
|
|
72
|
+
viewerCanMinimize: c.viewerCanMinimize === true,
|
|
65
73
|
author: c.author?.login ?? "unknown",
|
|
66
74
|
authorType: mapAuthorType(c.author?.__typename, c.author?.login),
|
|
67
75
|
...(c.authorAssociation !== undefined && { authorAssociation: c.authorAssociation }),
|
|
@@ -86,30 +94,15 @@ export function parseRawPr(raw, rawThreadPages, rawCommentNodes, rawReviewNodes,
|
|
|
86
94
|
const approvedReviews = rawApprovedReviewNodes
|
|
87
95
|
.filter((r) => !r.isMinimized)
|
|
88
96
|
.map((r) => parseReviewNode(r));
|
|
89
|
-
const checks = rawCheckNodes
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
{
|
|
99
|
-
name: node.context,
|
|
100
|
-
status,
|
|
101
|
-
conclusion,
|
|
102
|
-
source: "status_context",
|
|
103
|
-
detailsUrl: node.targetUrl ?? "",
|
|
104
|
-
event: null,
|
|
105
|
-
runId: null,
|
|
106
|
-
...(createdAtUnix !== undefined && { createdAtUnix }),
|
|
107
|
-
...(summary !== undefined && { summary }),
|
|
108
|
-
},
|
|
109
|
-
];
|
|
110
|
-
}
|
|
111
|
-
return [];
|
|
112
|
-
});
|
|
97
|
+
const checks = parseCheckNodes(rawCheckNodes);
|
|
98
|
+
const queueHead = raw.mergeQueueEntry?.headCommit;
|
|
99
|
+
const removedQueueHead = raw.mergeQueueRemovals?.nodes[0]?.beforeCommit;
|
|
100
|
+
const mergeQueueChecks = parseCheckNodes(queueHead?.statusCheckRollup
|
|
101
|
+
? requireContextNodes(queueHead.statusCheckRollup.contexts.nodes)
|
|
102
|
+
: undefined, queueHead?.oid);
|
|
103
|
+
const removedMergeQueueChecks = parseCheckNodes(removedQueueHead?.statusCheckRollup
|
|
104
|
+
? requireContextNodes(removedQueueHead.statusCheckRollup.contexts.nodes)
|
|
105
|
+
: undefined, removedQueueHead?.oid);
|
|
113
106
|
return {
|
|
114
107
|
nodeId: raw.id,
|
|
115
108
|
number: raw.number,
|
|
@@ -121,6 +114,16 @@ export function parseRawPr(raw, rawThreadPages, rawCommentNodes, rawReviewNodes,
|
|
|
121
114
|
headRefOid: raw.headRefOid,
|
|
122
115
|
headRefName: raw.headRefName,
|
|
123
116
|
headRepoWithOwner: raw.headRepository?.nameWithOwner ?? null,
|
|
117
|
+
viewerAuthorization: {
|
|
118
|
+
repositoryPermission: repository?.viewerPermission ?? null,
|
|
119
|
+
viewerCanAdminister: repository?.viewerCanAdminister === true,
|
|
120
|
+
viewerDidAuthor: raw.viewerDidAuthor === true,
|
|
121
|
+
viewerCanUpdate: raw.viewerCanUpdate === true,
|
|
122
|
+
viewerCanEnableAutoMerge: raw.viewerCanEnableAutoMerge === true,
|
|
123
|
+
viewerCanEditFiles: raw.viewerCanEditFiles === true,
|
|
124
|
+
headRepositoryPermission: raw.headRepository?.viewerPermission ??
|
|
125
|
+
null,
|
|
126
|
+
},
|
|
124
127
|
baseRefName: raw.baseRefName,
|
|
125
128
|
reviewRequests,
|
|
126
129
|
latestReviews,
|
|
@@ -135,6 +138,16 @@ export function parseRawPr(raw, rawThreadPages, rawCommentNodes, rawReviewNodes,
|
|
|
135
138
|
isInMergeQueue: raw.isInMergeQueue ?? false,
|
|
136
139
|
isMergeQueueEnabled: raw.isMergeQueueEnabled ?? false,
|
|
137
140
|
mergeQueueEntry: parseMergeQueueEntry(raw.mergeQueueEntry),
|
|
141
|
+
autoMergeRequest: parseAutoMergeRequest(raw.autoMergeRequest),
|
|
142
|
+
latestMergeQueueRemoval: parseLatestMergeQueueRemoval(raw),
|
|
143
|
+
...(mergeQueueChecks.length > 0 && { mergeQueueChecks }),
|
|
144
|
+
...(queueHead?.statusCheckRollup?.contexts.pageInfo.hasNextPage && {
|
|
145
|
+
mergeQueueChecksIncomplete: true,
|
|
146
|
+
}),
|
|
147
|
+
...(removedMergeQueueChecks.length > 0 && { removedMergeQueueChecks }),
|
|
148
|
+
...(removedQueueHead?.statusCheckRollup?.contexts.pageInfo.hasNextPage && {
|
|
149
|
+
removedMergeQueueChecksIncomplete: true,
|
|
150
|
+
}),
|
|
138
151
|
stack: parseStack(raw),
|
|
139
152
|
activity: buildPrActivitySummary(raw, comments, reviewThreads, reviewSummaries, allChangesRequestedReviews, approvedReviews),
|
|
140
153
|
};
|
|
@@ -12,10 +12,49 @@ export interface RawBranchProtectionRule {
|
|
|
12
12
|
requiresDeployments?: boolean;
|
|
13
13
|
requiredDeploymentEnvironments?: string[] | null;
|
|
14
14
|
}
|
|
15
|
+
import type { RawContextNode } from "./batch-raw-types.mts";
|
|
16
|
+
interface RawCheckCommit {
|
|
17
|
+
oid: string;
|
|
18
|
+
committedDate?: string;
|
|
19
|
+
parents?: {
|
|
20
|
+
nodes: Array<{
|
|
21
|
+
oid: string;
|
|
22
|
+
}>;
|
|
23
|
+
};
|
|
24
|
+
statusCheckRollup: {
|
|
25
|
+
contexts: {
|
|
26
|
+
pageInfo: {
|
|
27
|
+
hasNextPage: boolean;
|
|
28
|
+
endCursor: string | null;
|
|
29
|
+
};
|
|
30
|
+
nodes: Array<RawContextNode | null>;
|
|
31
|
+
};
|
|
32
|
+
} | null;
|
|
33
|
+
}
|
|
15
34
|
interface RawMergeQueueEntry {
|
|
16
35
|
position: number;
|
|
17
36
|
state: string;
|
|
18
37
|
estimatedTimeToMerge: number | null;
|
|
38
|
+
headCommit?: RawCheckCommit | null;
|
|
39
|
+
enqueuedAt?: string;
|
|
40
|
+
enqueuer?: {
|
|
41
|
+
login: string;
|
|
42
|
+
} | null;
|
|
43
|
+
}
|
|
44
|
+
interface RawAutoMergeRequest {
|
|
45
|
+
enabledAt: string;
|
|
46
|
+
mergeMethod: string;
|
|
47
|
+
enabledBy?: {
|
|
48
|
+
login: string;
|
|
49
|
+
} | null;
|
|
50
|
+
}
|
|
51
|
+
interface RawMergeQueueRemoval {
|
|
52
|
+
reason: string | null;
|
|
53
|
+
actor?: {
|
|
54
|
+
login: string;
|
|
55
|
+
} | null;
|
|
56
|
+
createdAt: string;
|
|
57
|
+
beforeCommit?: RawCheckCommit | null;
|
|
19
58
|
}
|
|
20
59
|
interface RawStack {
|
|
21
60
|
number: number;
|
|
@@ -50,6 +89,15 @@ export interface RawPrMergeFields {
|
|
|
50
89
|
isInMergeQueue?: boolean;
|
|
51
90
|
isMergeQueueEnabled?: boolean;
|
|
52
91
|
mergeQueueEntry?: RawMergeQueueEntry | null;
|
|
92
|
+
autoMergeRequest?: RawAutoMergeRequest | null;
|
|
93
|
+
mergeQueueRemovals?: {
|
|
94
|
+
nodes: RawMergeQueueRemoval[];
|
|
95
|
+
} | null;
|
|
96
|
+
mergeQueueAdditions?: {
|
|
97
|
+
nodes: Array<{
|
|
98
|
+
createdAt: string;
|
|
99
|
+
}>;
|
|
100
|
+
} | null;
|
|
53
101
|
stack?: RawStack | null;
|
|
54
102
|
stackEntry?: {
|
|
55
103
|
position: number;
|
|
@@ -2,6 +2,8 @@ import type { CommentAuthorAssociation } from "../types/github.mts";
|
|
|
2
2
|
import type { RawPrMergeFields } from "./batch-raw-rules.mts";
|
|
3
3
|
export interface RawBatchResponse {
|
|
4
4
|
repository: {
|
|
5
|
+
viewerPermission: string | null;
|
|
6
|
+
viewerCanAdminister: boolean;
|
|
5
7
|
pullRequest: RawPr | null;
|
|
6
8
|
} | null;
|
|
7
9
|
}
|
|
@@ -10,6 +12,10 @@ export interface RawPr extends RawPrMergeFields {
|
|
|
10
12
|
number: number;
|
|
11
13
|
state: string;
|
|
12
14
|
isDraft: boolean;
|
|
15
|
+
viewerDidAuthor: boolean;
|
|
16
|
+
viewerCanUpdate: boolean;
|
|
17
|
+
viewerCanEnableAutoMerge: boolean;
|
|
18
|
+
viewerCanEditFiles: boolean;
|
|
13
19
|
mergeable: string;
|
|
14
20
|
mergeStateStatus: string;
|
|
15
21
|
reviewDecision: string | null;
|
|
@@ -17,6 +23,7 @@ export interface RawPr extends RawPrMergeFields {
|
|
|
17
23
|
headRefName: string;
|
|
18
24
|
headRepository: {
|
|
19
25
|
nameWithOwner: string;
|
|
26
|
+
viewerPermission: string | null;
|
|
20
27
|
} | null;
|
|
21
28
|
baseRefName: string;
|
|
22
29
|
baseRef: import("./batch-raw-rules.mts").RawBaseRef | null;
|
|
@@ -117,6 +124,7 @@ export interface RawThreadComment {
|
|
|
117
124
|
isMinimized: boolean;
|
|
118
125
|
url: string;
|
|
119
126
|
authorAssociation?: CommentAuthorAssociation;
|
|
127
|
+
viewerDidAuthor?: boolean;
|
|
120
128
|
author: RawAuthor | null;
|
|
121
129
|
pullRequestReview?: {
|
|
122
130
|
id: string;
|
|
@@ -131,6 +139,8 @@ export interface RawThread {
|
|
|
131
139
|
id: string;
|
|
132
140
|
isResolved: boolean;
|
|
133
141
|
isOutdated: boolean;
|
|
142
|
+
viewerCanReply: boolean;
|
|
143
|
+
viewerCanResolve: boolean;
|
|
134
144
|
path?: string | null;
|
|
135
145
|
line?: number | null;
|
|
136
146
|
startLine?: number | null;
|
|
@@ -157,6 +167,7 @@ export interface RawReviewThreadCommentsResponse {
|
|
|
157
167
|
export interface RawComment {
|
|
158
168
|
id: string;
|
|
159
169
|
isMinimized: boolean;
|
|
170
|
+
viewerCanMinimize: boolean;
|
|
160
171
|
url: string;
|
|
161
172
|
authorAssociation?: CommentAuthorAssociation;
|
|
162
173
|
author: RawAuthor | null;
|
|
@@ -176,6 +187,7 @@ export interface RawReview {
|
|
|
176
187
|
export interface RawReviewSummary {
|
|
177
188
|
id: string;
|
|
178
189
|
isMinimized: boolean;
|
|
190
|
+
viewerCanMinimize: boolean;
|
|
179
191
|
authorAssociation?: CommentAuthorAssociation;
|
|
180
192
|
author: RawAuthor | null;
|
|
181
193
|
body: string;
|
package/bin/github/batch.mjs
CHANGED
|
@@ -6,6 +6,7 @@ import { parseCheckSuitesComplete, parseSuiteStartupFailures } from "./batch-par
|
|
|
6
6
|
import { mergeStartupFailureChecks } from "../checks/startup-failures.mjs";
|
|
7
7
|
import { paginateBatchConnections } from "./batch-page.mjs";
|
|
8
8
|
import { requireRawPr } from "./batch-response.mjs";
|
|
9
|
+
import { hydrateMergeQueueChecks } from "./merge-queue-checks.mjs";
|
|
9
10
|
/**
|
|
10
11
|
* Fetch all PR data needed for a `shepherd check` in one (or a few, if paginating) GraphQL requests.
|
|
11
12
|
*/
|
|
@@ -16,9 +17,10 @@ export async function fetchPrBatch(pr, repo, opts = {}) {
|
|
|
16
17
|
pr,
|
|
17
18
|
});
|
|
18
19
|
const raw = requireRawPr(result.data, pr, repo);
|
|
20
|
+
await hydrateMergeQueueChecks(raw, repo);
|
|
19
21
|
const paged = await paginateBatchConnections(pr, repo, raw, opts, result.rateLimit);
|
|
20
22
|
const rawThreadPages = await hydrateThreadCommentPages(paged.threads);
|
|
21
|
-
const data = parseRawPr(raw, rawThreadPages, paged.comments, paged.changesRequested, paged.reviewSummaries, paged.approvedReviews, paged.checks);
|
|
23
|
+
const data = parseRawPr(raw, rawThreadPages, paged.comments, paged.changesRequested, paged.reviewSummaries, paged.approvedReviews, paged.checks, result.data.repository);
|
|
22
24
|
data.checks = mergeStartupFailureChecks(data.checks, parseSuiteStartupFailures(raw));
|
|
23
25
|
return {
|
|
24
26
|
data,
|
package/bin/github/client.d.mts
CHANGED
|
@@ -30,6 +30,7 @@ export declare function getPrHeadSha(pr: number, owner: string, name: string): P
|
|
|
30
30
|
export declare function getPullRequestBody(pr: number, owner: string, name: string): Promise<{
|
|
31
31
|
nodeId: string;
|
|
32
32
|
body: string;
|
|
33
|
+
viewerCanUpdate?: boolean;
|
|
33
34
|
}>;
|
|
34
35
|
/** Overwrites the PR body. */
|
|
35
36
|
export declare function updatePullRequestBody(pullRequestId: string, body: string): Promise<void>;
|
package/bin/github/client.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable max-lines */
|
|
1
2
|
/**
|
|
2
3
|
* High-level GitHub client — wraps http.mts for application-level concerns.
|
|
3
4
|
*
|
|
@@ -76,7 +77,13 @@ export async function getPullRequestBody(pr, owner, name) {
|
|
|
76
77
|
: "PR not found or access denied";
|
|
77
78
|
throw new Error(`Could not fetch body for ${owner}/${name} PR #${pr}: ${detail}`);
|
|
78
79
|
}
|
|
79
|
-
return {
|
|
80
|
+
return {
|
|
81
|
+
nodeId: pullRequest.id,
|
|
82
|
+
body: pullRequest.body ?? "",
|
|
83
|
+
...(pullRequest.viewerCanUpdate !== undefined && {
|
|
84
|
+
viewerCanUpdate: pullRequest.viewerCanUpdate,
|
|
85
|
+
}),
|
|
86
|
+
};
|
|
80
87
|
}
|
|
81
88
|
/** Overwrites the PR body. */
|
|
82
89
|
export async function updatePullRequestBody(pullRequestId, body) {
|
|
@@ -29,6 +29,8 @@ query BatchPrPage(
|
|
|
29
29
|
id
|
|
30
30
|
isResolved
|
|
31
31
|
isOutdated
|
|
32
|
+
viewerCanReply
|
|
33
|
+
viewerCanResolve
|
|
32
34
|
path
|
|
33
35
|
line
|
|
34
36
|
startLine
|
|
@@ -42,6 +44,7 @@ query BatchPrPage(
|
|
|
42
44
|
isMinimized
|
|
43
45
|
url
|
|
44
46
|
authorAssociation
|
|
47
|
+
viewerDidAuthor
|
|
45
48
|
author {
|
|
46
49
|
__typename
|
|
47
50
|
login
|
|
@@ -66,6 +69,7 @@ query BatchPrPage(
|
|
|
66
69
|
nodes {
|
|
67
70
|
id
|
|
68
71
|
isMinimized
|
|
72
|
+
viewerCanMinimize
|
|
69
73
|
url
|
|
70
74
|
authorAssociation
|
|
71
75
|
author {
|
|
@@ -108,6 +112,7 @@ query BatchPrPage(
|
|
|
108
112
|
nodes {
|
|
109
113
|
id
|
|
110
114
|
isMinimized
|
|
115
|
+
viewerCanMinimize
|
|
111
116
|
authorAssociation
|
|
112
117
|
author {
|
|
113
118
|
__typename
|
|
@@ -126,6 +131,7 @@ query BatchPrPage(
|
|
|
126
131
|
nodes {
|
|
127
132
|
id
|
|
128
133
|
isMinimized
|
|
134
|
+
viewerCanMinimize
|
|
129
135
|
authorAssociation
|
|
130
136
|
author {
|
|
131
137
|
__typename
|