@blogic-cz/agent-tools 0.8.17 → 0.8.18
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/pr/core.ts +94 -15
package/package.json
CHANGED
package/src/gh-tool/pr/core.ts
CHANGED
|
@@ -20,6 +20,16 @@ import { runLocalCommand } from "./helpers";
|
|
|
20
20
|
const CHECK_JSON_FIELDS = "name,state,bucket,link";
|
|
21
21
|
const GITHUB_ACTIONS_RUN_ID_RE = /github\.com\/[^/]+\/[^/]+\/actions\/runs\/(\d+)/;
|
|
22
22
|
|
|
23
|
+
type WorkflowRunJobsForRerun = {
|
|
24
|
+
databaseId: number;
|
|
25
|
+
jobs: Array<{
|
|
26
|
+
databaseId: number;
|
|
27
|
+
name: string;
|
|
28
|
+
status: string;
|
|
29
|
+
conclusion: string | null;
|
|
30
|
+
}>;
|
|
31
|
+
};
|
|
32
|
+
|
|
23
33
|
const buildChecksCommand = (pr: number | null, includeWatch: boolean): string =>
|
|
24
34
|
`bun agent-tools-gh pr checks${pr !== null ? ` --pr ${pr}` : ""}${includeWatch ? " --watch" : ""}`;
|
|
25
35
|
|
|
@@ -36,6 +46,47 @@ const extractRunIdFromCheckLink = (link: string): number | null => {
|
|
|
36
46
|
return Number.isFinite(runId) ? runId : null;
|
|
37
47
|
};
|
|
38
48
|
|
|
49
|
+
const isFailedWorkflowJob = (job: { status: string; conclusion: string | null }) =>
|
|
50
|
+
job.conclusion === "failure" || job.status === "failure";
|
|
51
|
+
|
|
52
|
+
const getCheckJobNameCandidates = (checkName: string): string[] => {
|
|
53
|
+
const exact = checkName.trim();
|
|
54
|
+
const suffixParts = exact.split("/").map((part) => part.trim());
|
|
55
|
+
let suffix: string | undefined;
|
|
56
|
+
for (let index = suffixParts.length - 1; index >= 0; index -= 1) {
|
|
57
|
+
const part = suffixParts[index];
|
|
58
|
+
if (part !== undefined && part.length > 0) {
|
|
59
|
+
suffix = part;
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return [...new Set([exact, suffix].filter((value): value is string => value !== undefined))];
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const resolveJobIdsForFailedChecks = (
|
|
68
|
+
checks: CheckResult[],
|
|
69
|
+
jobs: WorkflowRunJobsForRerun["jobs"],
|
|
70
|
+
): number[] | null => {
|
|
71
|
+
const failedJobs = jobs.filter(isFailedWorkflowJob);
|
|
72
|
+
const jobIds = new Set<number>();
|
|
73
|
+
|
|
74
|
+
for (const check of checks) {
|
|
75
|
+
const candidates = getCheckJobNameCandidates(check.name);
|
|
76
|
+
const matches = failedJobs.filter((job) =>
|
|
77
|
+
candidates.some((candidate) => job.name.toLowerCase() === candidate.toLowerCase()),
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
if (matches.length !== 1) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
jobIds.add(matches[0].databaseId);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return [...jobIds];
|
|
88
|
+
};
|
|
89
|
+
|
|
39
90
|
const fetchWorkflowRunFailureContext = Effect.fn("pr.fetchWorkflowRunFailureContext")(function* (
|
|
40
91
|
runId: number,
|
|
41
92
|
) {
|
|
@@ -680,21 +731,20 @@ export const rerunChecks = Effect.fn("pr.rerunChecks")(function* (
|
|
|
680
731
|
) {
|
|
681
732
|
const gh = yield* GitHubService;
|
|
682
733
|
|
|
683
|
-
const checks = yield*
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
link: string;
|
|
687
|
-
bucket: string;
|
|
688
|
-
state: string;
|
|
689
|
-
}>
|
|
690
|
-
>(["pr", "checks", ...(pr !== null ? [String(pr)] : []), "--json", "name,link,bucket,state"]);
|
|
734
|
+
const checks = yield* fetchCheckResults(pr);
|
|
735
|
+
|
|
736
|
+
const targetChecks = failedOnly ? checks.filter((check) => check.bucket === "fail") : checks;
|
|
691
737
|
|
|
692
738
|
// Extract unique GitHub Actions run IDs from links
|
|
693
739
|
const runIds = new Set<string>();
|
|
694
|
-
|
|
695
|
-
|
|
740
|
+
const checksByRun = new Map<string, CheckResult[]>();
|
|
741
|
+
for (const check of targetChecks) {
|
|
742
|
+
const match = check.link.match(GITHUB_ACTIONS_RUN_ID_RE);
|
|
696
743
|
if (match?.[1]) {
|
|
697
744
|
runIds.add(match[1]);
|
|
745
|
+
const existing = checksByRun.get(match[1]) ?? [];
|
|
746
|
+
existing.push(check);
|
|
747
|
+
checksByRun.set(match[1], existing);
|
|
698
748
|
}
|
|
699
749
|
}
|
|
700
750
|
|
|
@@ -712,11 +762,40 @@ export const rerunChecks = Effect.fn("pr.rerunChecks")(function* (
|
|
|
712
762
|
success: boolean;
|
|
713
763
|
}> = [];
|
|
714
764
|
for (const runId of runIds) {
|
|
715
|
-
const
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
765
|
+
const success = yield* Effect.gen(function* () {
|
|
766
|
+
if (!failedOnly) {
|
|
767
|
+
return yield* gh.runGh(["run", "rerun", runId]).pipe(
|
|
768
|
+
Effect.map(() => true),
|
|
769
|
+
Effect.catch(() => Effect.succeed(false)),
|
|
770
|
+
);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
const checksForRun = checksByRun.get(runId) ?? [];
|
|
774
|
+
const run = yield* gh
|
|
775
|
+
.runGhJson<WorkflowRunJobsForRerun>(["run", "view", runId, "--json", "databaseId,jobs"])
|
|
776
|
+
.pipe(Effect.catchTag("GitHubCommandError", () => Effect.succeed(null)));
|
|
777
|
+
|
|
778
|
+
const jobIds = run === null ? null : resolveJobIdsForFailedChecks(checksForRun, run.jobs);
|
|
779
|
+
if (jobIds === null || jobIds.length === 0) {
|
|
780
|
+
return yield* gh.runGh(["run", "rerun", runId, "--failed"]).pipe(
|
|
781
|
+
Effect.map(() => true),
|
|
782
|
+
Effect.catch(() => Effect.succeed(false)),
|
|
783
|
+
);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
const rerunResults = yield* Effect.forEach(
|
|
787
|
+
jobIds,
|
|
788
|
+
(jobId) =>
|
|
789
|
+
gh.runGh(["run", "rerun", "--job", String(jobId)]).pipe(
|
|
790
|
+
Effect.map(() => true),
|
|
791
|
+
Effect.catch(() => Effect.succeed(false)),
|
|
792
|
+
),
|
|
793
|
+
{ concurrency: 1 },
|
|
794
|
+
);
|
|
795
|
+
|
|
796
|
+
return rerunResults.every(Boolean);
|
|
797
|
+
});
|
|
798
|
+
|
|
720
799
|
results.push({ runId, success });
|
|
721
800
|
}
|
|
722
801
|
|