@blogic-cz/agent-tools 0.18.0 → 0.18.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/dist/gh-tool/errors.d.ts
CHANGED
|
@@ -30,7 +30,7 @@ export declare class GitHubAuthError extends GitHubAuthError_base {
|
|
|
30
30
|
}
|
|
31
31
|
declare const GitHubMergeError_base: Schema.Class<GitHubMergeError, Schema.TaggedStruct<"GitHubMergeError", {
|
|
32
32
|
readonly message: Schema.String;
|
|
33
|
-
readonly reason: Schema.Literals<readonly ["conflicts", "checks_failing", "branch_protected", "unknown"]>;
|
|
33
|
+
readonly reason: Schema.Literals<readonly ["conflicts", "checks_failing", "branch_protected", "merge_queue", "unknown"]>;
|
|
34
34
|
readonly hint: Schema.optionalKey<Schema.String>;
|
|
35
35
|
readonly nextCommand: Schema.optionalKey<Schema.String>;
|
|
36
36
|
readonly retryable: Schema.optionalKey<Schema.Boolean>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/gh-tool/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;;;;;;;;;;AAEhC,qBAAa,kBAAmB,SAAQ,uBAWvC;CAAG;;;;;;;;;AAEJ,qBAAa,mBAAoB,SAAQ,wBAUxC;CAAG;;;;;;;AAEJ,qBAAa,eAAgB,SAAQ,oBAKnC;CAAG;;;;;;;;AAEL,qBAAa,gBAAiB,SAAQ,
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/gh-tool/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;;;;;;;;;;AAEhC,qBAAa,kBAAmB,SAAQ,uBAWvC;CAAG;;;;;;;;;AAEJ,qBAAa,mBAAoB,SAAQ,wBAUxC;CAAG;;;;;;;AAEJ,qBAAa,eAAgB,SAAQ,oBAKnC;CAAG;;;;;;;;AAEL,qBAAa,gBAAiB,SAAQ,qBAYpC;CAAG;;;;;;;;AAEL,qBAAa,kBAAmB,SAAQ,uBASvC;CAAG;AAEJ,MAAM,MAAM,kBAAkB,GAC1B,kBAAkB,GAClB,mBAAmB,GACnB,eAAe,GACf,gBAAgB,GAChB,kBAAkB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../src/gh-tool/pr/core.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,MAAM,EAAkB,MAAM,QAAQ,CAAC;AAE1E,OAAO,KAAK,EACV,cAAc,EACd,WAAW,EACX,iBAAiB,EAEjB,WAAW,EACX,aAAa,EACb,MAAM,EAGN,iBAAiB,EAIlB,MAAM,WAAW,CAAC;AAEnB,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAoL5C,eAAO,MAAM,qBAAqB,QAAwB,CAAC;AAiK3D,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;iBAY4C,MAAM;iBAAe,MAAM;6EAMxF,CAAC;AAEH,eAAO,MAAM,cAAc;;cAkBL,cAAc,EAAE;;;;;QAqIb,MAAM;;;;;;;;kGAQ7B,CAAC;AAEH,eAAO,MAAM,OAAO;WACX,MAAM;WACN,MAAM;YACL,MAAM,GAAG,IAAI;UACf,MAAM,GAAG,IAAI;UACb,MAAM,GAAG,IAAI;YACX,MAAM,GAAG,IAAI;wGAkBrB,CAAC;AAMH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;iBAvMkC,MAAM;iBAAe,MAAM;6EAoOxF,CAAC;AAEH,eAAO,MAAM,QAAQ;UACb,MAAM,GAAG,IAAI;WACZ,MAAM;UACP,MAAM;WACL,OAAO;UACR,MAAM,GAAG,IAAI;sGA8FnB,CAAC;
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../src/gh-tool/pr/core.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/gh-tool/errors.ts
CHANGED
|
@@ -34,7 +34,13 @@ export class GitHubAuthError extends Schema.TaggedError<GitHubAuthError>()("GitH
|
|
|
34
34
|
|
|
35
35
|
export class GitHubMergeError extends Schema.TaggedError<GitHubMergeError>()("GitHubMergeError", {
|
|
36
36
|
message: Schema.String,
|
|
37
|
-
reason: Schema.Literals([
|
|
37
|
+
reason: Schema.Literals([
|
|
38
|
+
"conflicts",
|
|
39
|
+
"checks_failing",
|
|
40
|
+
"branch_protected",
|
|
41
|
+
"merge_queue",
|
|
42
|
+
"unknown",
|
|
43
|
+
]),
|
|
38
44
|
hint: Schema.optionalKey(Schema.String),
|
|
39
45
|
nextCommand: Schema.optionalKey(Schema.String),
|
|
40
46
|
retryable: Schema.optionalKey(Schema.Boolean),
|
package/src/gh-tool/pr/core.ts
CHANGED
|
@@ -702,6 +702,99 @@ export const createPR = Effect.fn("pr.createPR")(function* (opts: {
|
|
|
702
702
|
);
|
|
703
703
|
});
|
|
704
704
|
|
|
705
|
+
// GitHub rejects GraphQL `mergePullRequest` for a PR that belongs to a native stack and points at
|
|
706
|
+
// the asynchronous REST merge instead. `gh pr merge` only speaks GraphQL.
|
|
707
|
+
const ASYNC_MERGE_REQUIRED_RE = /asynchronous merge/i;
|
|
708
|
+
const ASYNC_MERGE_POLL_INTERVAL_MS = 2000;
|
|
709
|
+
const MAX_ASYNC_MERGE_WAIT_SECONDS = 120;
|
|
710
|
+
|
|
711
|
+
type AsyncMergeResult = {
|
|
712
|
+
status: "pending" | "merged" | "enqueued" | "failed";
|
|
713
|
+
details?: { message?: string; uuid?: string; sha?: string };
|
|
714
|
+
};
|
|
715
|
+
|
|
716
|
+
const asyncMergeFailure = (
|
|
717
|
+
pr: number,
|
|
718
|
+
message: string,
|
|
719
|
+
hint: string,
|
|
720
|
+
reason: "merge_queue" | "unknown" = "unknown",
|
|
721
|
+
) =>
|
|
722
|
+
new GitHubMergeError({
|
|
723
|
+
message: `Failed to merge PR #${pr} asynchronously: ${message}`,
|
|
724
|
+
reason,
|
|
725
|
+
hint,
|
|
726
|
+
nextCommand: `agent-tools-gh pr view --pr ${pr}`,
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
const mergeViaAsyncApi = Effect.fn("pr.mergeViaAsyncApi")(function* (opts: {
|
|
730
|
+
pr: number;
|
|
731
|
+
strategy: MergeStrategy;
|
|
732
|
+
}) {
|
|
733
|
+
const gh = yield* GitHubService;
|
|
734
|
+
const repo = yield* gh.getRepoInfo();
|
|
735
|
+
const asyncPath = `repos/${repo.owner}/${repo.name}/pulls/${opts.pr}/merge-async`;
|
|
736
|
+
|
|
737
|
+
let latest = yield* gh.runGhJson<AsyncMergeResult>([
|
|
738
|
+
"api",
|
|
739
|
+
"--method",
|
|
740
|
+
"PUT",
|
|
741
|
+
asyncPath,
|
|
742
|
+
"-f",
|
|
743
|
+
`merge_method=${opts.strategy}`,
|
|
744
|
+
]);
|
|
745
|
+
|
|
746
|
+
const uuid = latest.details?.uuid;
|
|
747
|
+
if (latest.status === "pending" && uuid !== undefined) {
|
|
748
|
+
const start = yield* Clock.currentTimeMillis;
|
|
749
|
+
const deadlineMs = Number(start) + MAX_ASYNC_MERGE_WAIT_SECONDS * 1000;
|
|
750
|
+
let timedOut = false;
|
|
751
|
+
|
|
752
|
+
// Effect.whileLoop (not recursion) so TestClock.adjust can advance Effect.sleep without real waits.
|
|
753
|
+
yield* Effect.whileLoop({
|
|
754
|
+
while: () => latest.status === "pending" && !timedOut,
|
|
755
|
+
body: () =>
|
|
756
|
+
Effect.gen(function* () {
|
|
757
|
+
const now = yield* Clock.currentTimeMillis;
|
|
758
|
+
if (Number(now) >= deadlineMs) {
|
|
759
|
+
timedOut = true;
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
const remaining = deadlineMs - Number(now);
|
|
763
|
+
yield* Effect.sleep(Duration.millis(Math.min(ASYNC_MERGE_POLL_INTERVAL_MS, remaining)));
|
|
764
|
+
latest = yield* gh.runGhJson<AsyncMergeResult>(["api", `${asyncPath}/${uuid}`]);
|
|
765
|
+
}),
|
|
766
|
+
step: () => undefined,
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
if (latest.status === "merged") {
|
|
771
|
+
return latest.details?.sha ?? null;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
if (latest.status === "enqueued") {
|
|
775
|
+
return yield* asyncMergeFailure(
|
|
776
|
+
opts.pr,
|
|
777
|
+
latest.details?.message ?? "the pull request entered a merge queue",
|
|
778
|
+
"The merge queue owns the merge from here; it is not merged yet. Watch the PR until the queue drains.",
|
|
779
|
+
"merge_queue",
|
|
780
|
+
);
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
if (latest.status === "pending") {
|
|
784
|
+
return yield* asyncMergeFailure(
|
|
785
|
+
opts.pr,
|
|
786
|
+
`still pending after ${MAX_ASYNC_MERGE_WAIT_SECONDS}s`,
|
|
787
|
+
"The asynchronous merge is still running. Re-check the PR state before retrying so the merge is not requested twice.",
|
|
788
|
+
);
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
return yield* asyncMergeFailure(
|
|
792
|
+
opts.pr,
|
|
793
|
+
latest.details?.message ?? "the merge request failed",
|
|
794
|
+
"Inspect the PR state and branch protections, then retry.",
|
|
795
|
+
);
|
|
796
|
+
});
|
|
797
|
+
|
|
705
798
|
export const mergePR = Effect.fn("pr.mergePR")(function* (opts: {
|
|
706
799
|
pr: number;
|
|
707
800
|
strategy: MergeStrategy;
|
|
@@ -847,77 +940,92 @@ export const mergePR = Effect.fn("pr.mergePR")(function* (opts: {
|
|
|
847
940
|
|
|
848
941
|
const mergeArgs = ["pr", "merge", String(opts.pr), `--${opts.strategy}`];
|
|
849
942
|
|
|
850
|
-
const
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
rollbackFailed.length > 0
|
|
859
|
-
? ` ROLLBACK INCOMPLETE: dependent PR(s) ${rollbackFailed
|
|
860
|
-
.map((child) => `#${child}`)
|
|
861
|
-
.join(", ")} are still retargeted to \`${info.baseRefName}\`; ` +
|
|
862
|
-
`manually restore their base to \`${info.headRefName}\`.`
|
|
863
|
-
: "";
|
|
864
|
-
|
|
865
|
-
if (error._tag !== "GitHubCommandError") {
|
|
866
|
-
return rollbackNote === ""
|
|
867
|
-
? Effect.fail(error)
|
|
868
|
-
: Console.error(rollbackNote.trim()).pipe(Effect.andThen(Effect.fail(error)));
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
const stderr = error.stderr.toLowerCase();
|
|
872
|
-
|
|
873
|
-
if (stderr.includes("merge conflict") || stderr.includes("conflicts")) {
|
|
874
|
-
return Effect.fail(
|
|
875
|
-
new GitHubMergeError({
|
|
876
|
-
message: `PR #${opts.pr} has merge conflicts`,
|
|
877
|
-
reason: "conflicts",
|
|
878
|
-
hint: `Resolve merge conflicts locally, push the fix, then retry the merge.${rollbackNote}`,
|
|
879
|
-
nextCommand: `gh pr diff ${opts.pr}`,
|
|
880
|
-
}),
|
|
881
|
-
);
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
if (stderr.includes("required status check") || stderr.includes("checks")) {
|
|
885
|
-
return Effect.fail(
|
|
886
|
-
new GitHubMergeError({
|
|
887
|
-
message: `PR #${opts.pr} has failing required checks`,
|
|
888
|
-
reason: "checks_failing",
|
|
889
|
-
hint: `Wait for CI checks to pass or investigate failures before merging.${rollbackNote}`,
|
|
890
|
-
nextCommand: `agent-tools-gh pr checks --pr ${opts.pr}`,
|
|
891
|
-
retryable: true,
|
|
892
|
-
}),
|
|
893
|
-
);
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
if (stderr.includes("protected branch")) {
|
|
897
|
-
return Effect.fail(
|
|
898
|
-
new GitHubMergeError({
|
|
899
|
-
message: `PR #${opts.pr} targets a protected branch`,
|
|
900
|
-
reason: "branch_protected",
|
|
901
|
-
hint: `This branch has protection rules. Ensure required reviews and checks are satisfied, or ask a repo admin.${rollbackNote}`,
|
|
902
|
-
}),
|
|
903
|
-
);
|
|
904
|
-
}
|
|
905
|
-
|
|
906
|
-
return Effect.fail(
|
|
907
|
-
new GitHubMergeError({
|
|
908
|
-
message: `Failed to merge PR #${opts.pr}: ${error.stderr}`,
|
|
909
|
-
reason: "unknown",
|
|
910
|
-
hint: `Check the PR state and branch protections. The PR may already be merged or closed.${rollbackNote}`,
|
|
911
|
-
nextCommand: `agent-tools-gh pr view --pr ${opts.pr}`,
|
|
912
|
-
}),
|
|
913
|
-
);
|
|
914
|
-
},
|
|
915
|
-
),
|
|
943
|
+
const mergedSha = yield* gh
|
|
944
|
+
.runGh(mergeArgs)
|
|
945
|
+
.pipe(
|
|
946
|
+
Effect.map((result) => result.stdout.match(/([0-9a-f]{7,40})/)?.[1] ?? null),
|
|
947
|
+
Effect.catchTag("GitHubCommandError", (error) =>
|
|
948
|
+
ASYNC_MERGE_REQUIRED_RE.test(error.stderr)
|
|
949
|
+
? mergeViaAsyncApi({ pr: opts.pr, strategy: opts.strategy })
|
|
950
|
+
: Effect.fail(error),
|
|
916
951
|
),
|
|
917
|
-
)
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
952
|
+
)
|
|
953
|
+
.pipe(
|
|
954
|
+
Effect.catch((error) =>
|
|
955
|
+
// A queued merge still lands, and its head branch disappears with it. Rolling the
|
|
956
|
+
// dependents back onto that branch would close them (cli/cli#1168), so keep the retargets.
|
|
957
|
+
error._tag === "GitHubMergeError" && error.reason === "merge_queue"
|
|
958
|
+
? Effect.fail(error)
|
|
959
|
+
: rollbackRetargets.pipe(
|
|
960
|
+
Effect.andThen(
|
|
961
|
+
(
|
|
962
|
+
rollbackFailed,
|
|
963
|
+
): Effect.Effect<
|
|
964
|
+
never,
|
|
965
|
+
GitHubNotFoundError | GitHubAuthError | GitHubMergeError
|
|
966
|
+
> => {
|
|
967
|
+
const rollbackNote =
|
|
968
|
+
rollbackFailed.length > 0
|
|
969
|
+
? ` ROLLBACK INCOMPLETE: dependent PR(s) ${rollbackFailed
|
|
970
|
+
.map((child) => `#${child}`)
|
|
971
|
+
.join(", ")} are still retargeted to \`${info.baseRefName}\`; ` +
|
|
972
|
+
`manually restore their base to \`${info.headRefName}\`.`
|
|
973
|
+
: "";
|
|
974
|
+
|
|
975
|
+
if (error._tag !== "GitHubCommandError") {
|
|
976
|
+
return rollbackNote === ""
|
|
977
|
+
? Effect.fail(error)
|
|
978
|
+
: Console.error(rollbackNote.trim()).pipe(Effect.andThen(Effect.fail(error)));
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
const stderr = error.stderr.toLowerCase();
|
|
982
|
+
|
|
983
|
+
if (stderr.includes("merge conflict") || stderr.includes("conflicts")) {
|
|
984
|
+
return Effect.fail(
|
|
985
|
+
new GitHubMergeError({
|
|
986
|
+
message: `PR #${opts.pr} has merge conflicts`,
|
|
987
|
+
reason: "conflicts",
|
|
988
|
+
hint: `Resolve merge conflicts locally, push the fix, then retry the merge.${rollbackNote}`,
|
|
989
|
+
nextCommand: `gh pr diff ${opts.pr}`,
|
|
990
|
+
}),
|
|
991
|
+
);
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
if (stderr.includes("required status check") || stderr.includes("checks")) {
|
|
995
|
+
return Effect.fail(
|
|
996
|
+
new GitHubMergeError({
|
|
997
|
+
message: `PR #${opts.pr} has failing required checks`,
|
|
998
|
+
reason: "checks_failing",
|
|
999
|
+
hint: `Wait for CI checks to pass or investigate failures before merging.${rollbackNote}`,
|
|
1000
|
+
nextCommand: `agent-tools-gh pr checks --pr ${opts.pr}`,
|
|
1001
|
+
retryable: true,
|
|
1002
|
+
}),
|
|
1003
|
+
);
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
if (stderr.includes("protected branch")) {
|
|
1007
|
+
return Effect.fail(
|
|
1008
|
+
new GitHubMergeError({
|
|
1009
|
+
message: `PR #${opts.pr} targets a protected branch`,
|
|
1010
|
+
reason: "branch_protected",
|
|
1011
|
+
hint: `This branch has protection rules. Ensure required reviews and checks are satisfied, or ask a repo admin.${rollbackNote}`,
|
|
1012
|
+
}),
|
|
1013
|
+
);
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
return Effect.fail(
|
|
1017
|
+
new GitHubMergeError({
|
|
1018
|
+
message: `Failed to merge PR #${opts.pr}: ${error.stderr}`,
|
|
1019
|
+
reason: "unknown",
|
|
1020
|
+
hint: `Check the PR state and branch protections. The PR may already be merged or closed.${rollbackNote}`,
|
|
1021
|
+
nextCommand: `agent-tools-gh pr view --pr ${opts.pr}`,
|
|
1022
|
+
}),
|
|
1023
|
+
);
|
|
1024
|
+
},
|
|
1025
|
+
),
|
|
1026
|
+
),
|
|
1027
|
+
),
|
|
1028
|
+
);
|
|
921
1029
|
|
|
922
1030
|
// `gh pr merge --delete-branch` aborts its remote delete when the head branch is checked out in a
|
|
923
1031
|
// worktree; deleting the remote ref explicitly is worktree-independent. Local cleanup is separate.
|
|
@@ -944,7 +1052,7 @@ export const mergePR = Effect.fn("pr.mergePR")(function* (opts: {
|
|
|
944
1052
|
merged: true,
|
|
945
1053
|
strategy: opts.strategy,
|
|
946
1054
|
branchDeleted: willDeleteBranch,
|
|
947
|
-
sha:
|
|
1055
|
+
sha: mergedSha,
|
|
948
1056
|
retargetedChildren: retargetedChildren.length > 0 ? retargetedChildren : undefined,
|
|
949
1057
|
branchDeleteSkipped: branchDeleteSkipped ? true : undefined,
|
|
950
1058
|
};
|