mirror of
https://github.com/anthropics/claude-code-action.git
synced 2026-08-22 03:18:54 +08:00
fix: paginate GitHub Actions MCP responses (#1629)
This commit is contained in:
@@ -0,0 +1,19 @@
|
|||||||
|
import type { Octokit } from "@octokit/rest";
|
||||||
|
|
||||||
|
type ActionsClient = Octokit["actions"];
|
||||||
|
|
||||||
|
export type WorkflowRunsParams = Parameters<
|
||||||
|
ActionsClient["listWorkflowRunsForRepo"]
|
||||||
|
>[0];
|
||||||
|
|
||||||
|
export type WorkflowJobsParams = Parameters<
|
||||||
|
ActionsClient["listJobsForWorkflowRun"]
|
||||||
|
>[0];
|
||||||
|
|
||||||
|
export function listWorkflowRuns(client: Octokit, params: WorkflowRunsParams) {
|
||||||
|
return client.paginate(client.actions.listWorkflowRunsForRepo, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function listWorkflowJobs(client: Octokit, params: WorkflowJobsParams) {
|
||||||
|
return client.paginate(client.actions.listJobsForWorkflowRun, params);
|
||||||
|
}
|
||||||
@@ -6,6 +6,10 @@ import { z } from "zod";
|
|||||||
import { GITHUB_API_URL } from "../github/api/config";
|
import { GITHUB_API_URL } from "../github/api/config";
|
||||||
import { mkdir, writeFile } from "fs/promises";
|
import { mkdir, writeFile } from "fs/promises";
|
||||||
import { Octokit } from "@octokit/rest";
|
import { Octokit } from "@octokit/rest";
|
||||||
|
import {
|
||||||
|
listWorkflowJobs,
|
||||||
|
listWorkflowRuns,
|
||||||
|
} from "./github-actions-pagination";
|
||||||
|
|
||||||
const REPO_OWNER = process.env.REPO_OWNER;
|
const REPO_OWNER = process.env.REPO_OWNER;
|
||||||
const REPO_NAME = process.env.REPO_NAME;
|
const REPO_NAME = process.env.REPO_NAME;
|
||||||
@@ -66,7 +70,7 @@ server.tool(
|
|||||||
});
|
});
|
||||||
const headSha = prData.head.sha;
|
const headSha = prData.head.sha;
|
||||||
|
|
||||||
const { data: runsData } = await client.actions.listWorkflowRunsForRepo({
|
const runs = await listWorkflowRuns(client, {
|
||||||
owner: REPO_OWNER!,
|
owner: REPO_OWNER!,
|
||||||
repo: REPO_NAME!,
|
repo: REPO_NAME!,
|
||||||
head_sha: headSha,
|
head_sha: headSha,
|
||||||
@@ -74,7 +78,6 @@ server.tool(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Process runs to create summary
|
// Process runs to create summary
|
||||||
const runs = runsData.workflow_runs || [];
|
|
||||||
const summary = {
|
const summary = {
|
||||||
total_runs: runs.length,
|
total_runs: runs.length,
|
||||||
failed: 0,
|
failed: 0,
|
||||||
@@ -148,13 +151,13 @@ server.tool(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Get jobs for this workflow run
|
// Get jobs for this workflow run
|
||||||
const { data: jobsData } = await client.actions.listJobsForWorkflowRun({
|
const jobs = await listWorkflowJobs(client, {
|
||||||
owner: REPO_OWNER!,
|
owner: REPO_OWNER!,
|
||||||
repo: REPO_NAME!,
|
repo: REPO_NAME!,
|
||||||
run_id,
|
run_id,
|
||||||
});
|
});
|
||||||
|
|
||||||
const processedJobs = jobsData.jobs.map((job: any) => {
|
const processedJobs = jobs.map((job: any) => {
|
||||||
// Extract failed steps
|
// Extract failed steps
|
||||||
const failedSteps = (job.steps || [])
|
const failedSteps = (job.steps || [])
|
||||||
.filter((step: any) => step.conclusion === "failure")
|
.filter((step: any) => step.conclusion === "failure")
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import { describe, expect, test } from "bun:test";
|
||||||
|
import type { Octokit } from "@octokit/rest";
|
||||||
|
import {
|
||||||
|
listWorkflowJobs,
|
||||||
|
listWorkflowRuns,
|
||||||
|
} from "../src/mcp/github-actions-pagination";
|
||||||
|
|
||||||
|
function createPaginatedClient<T>(pages: T[][]) {
|
||||||
|
const request = async () => ({ data: pages[0] });
|
||||||
|
const client = {
|
||||||
|
actions: {
|
||||||
|
listWorkflowRunsForRepo: request,
|
||||||
|
listJobsForWorkflowRun: request,
|
||||||
|
},
|
||||||
|
paginate: async () => pages.flat(),
|
||||||
|
} as unknown as Octokit;
|
||||||
|
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("GitHub Actions pagination", () => {
|
||||||
|
test("returns workflow runs from every page", async () => {
|
||||||
|
const firstPage = [{ id: 1 }, { id: 2 }];
|
||||||
|
const secondPage = [{ id: 3 }];
|
||||||
|
const client = createPaginatedClient([firstPage, secondPage]);
|
||||||
|
|
||||||
|
const runs = await listWorkflowRuns(client, {
|
||||||
|
owner: "owner",
|
||||||
|
repo: "repo",
|
||||||
|
head_sha: "sha",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(runs.map((run) => run.id)).toEqual([1, 2, 3]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns workflow jobs from every page", async () => {
|
||||||
|
const firstPage = [{ id: 1 }, { id: 2 }];
|
||||||
|
const secondPage = [{ id: 3 }];
|
||||||
|
const client = createPaginatedClient([firstPage, secondPage]);
|
||||||
|
|
||||||
|
const jobs = await listWorkflowJobs(client, {
|
||||||
|
owner: "owner",
|
||||||
|
repo: "repo",
|
||||||
|
run_id: 123,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(jobs.map((job) => job.id)).toEqual([1, 2, 3]);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user