Skip to content

Commit 587a607

Browse files
fix(actions): check every job page in get_job_logs failed_only
Only the first 30 jobs of a run were listed, so in larger matrix runs a failed job past that page was reported as "No failed jobs found".
1 parent 71ef826 commit 587a607

2 files changed

Lines changed: 72 additions & 9 deletions

File tree

‎pkg/github/actions.go‎

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,27 @@ const (
4949
// handleFailedJobLogs gets logs for all failed jobs in a workflow run
5050
func handleFailedJobLogs(ctx context.Context, client *github.Client, owner, repo string, runID int64, returnContent bool, tailLines int, contentWindowSize int) (*mcp.CallToolResult, any, error) {
5151
// First, get all jobs for the workflow run
52-
jobs, resp, err := client.Actions.ListWorkflowJobs(ctx, owner, repo, runID, &github.ListWorkflowJobsOptions{
53-
Filter: "latest",
54-
})
55-
if err != nil {
56-
return ghErrors.NewGitHubAPIErrorResponse(ctx, "failed to list workflow jobs", resp, err), nil, nil
52+
opts := &github.ListWorkflowJobsOptions{
53+
Filter: "latest",
54+
ListOptions: github.ListOptions{PerPage: 100},
55+
}
56+
var allJobs []*github.WorkflowJob
57+
for {
58+
jobs, resp, err := client.Actions.ListWorkflowJobs(ctx, owner, repo, runID, opts)
59+
if err != nil {
60+
return ghErrors.NewGitHubAPIErrorResponse(ctx, "failed to list workflow jobs", resp, err), nil, nil
61+
}
62+
_ = resp.Body.Close()
63+
allJobs = append(allJobs, jobs.Jobs...)
64+
if resp.NextPage == 0 {
65+
break
66+
}
67+
opts.Page = resp.NextPage
5768
}
58-
defer func() { _ = resp.Body.Close() }()
5969

6070
// Filter for failed jobs
6171
var failedJobs []*github.WorkflowJob
62-
for _, job := range jobs.Jobs {
72+
for _, job := range allJobs {
6373
if job.GetConclusion() == "failure" {
6474
failedJobs = append(failedJobs, job)
6575
}
@@ -69,7 +79,7 @@ func handleFailedJobLogs(ctx context.Context, client *github.Client, owner, repo
6979
result := map[string]any{
7080
"message": "No failed jobs found in this workflow run",
7181
"run_id": runID,
72-
"total_jobs": len(jobs.Jobs),
82+
"total_jobs": len(allJobs),
7383
"failed_jobs": 0,
7484
}
7585
r, _ := json.Marshal(result)
@@ -97,7 +107,7 @@ func handleFailedJobLogs(ctx context.Context, client *github.Client, owner, repo
97107
result := map[string]any{
98108
"message": fmt.Sprintf("Retrieved logs for %d failed jobs", len(failedJobs)),
99109
"run_id": runID,
100-
"total_jobs": len(jobs.Jobs),
110+
"total_jobs": len(allJobs),
101111
"failed_jobs": len(failedJobs),
102112
"logs": logResults,
103113
"return_format": map[string]bool{"content": returnContent, "urls": !returnContent},

‎pkg/github/actions_test.go‎

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,4 +753,57 @@ func Test_ActionsGetJobLogs_FailedJobs(t *testing.T) {
753753
require.NoError(t, err)
754754
assert.Equal(t, "No failed jobs found in this workflow run", response["message"])
755755
})
756+
757+
t.Run("failed job on a later page", func(t *testing.T) {
758+
mockedClient := MockHTTPClientWithHandlers(map[string]http.HandlerFunc{
759+
GetReposActionsRunsJobsByOwnerByRepoByRunID: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
760+
jobs := &github.Jobs{TotalCount: new(31)}
761+
if r.URL.Query().Get("page") == "2" {
762+
jobs.Jobs = []*github.WorkflowJob{
763+
{ID: new(int64(31)), Name: new("test-job-31"), Conclusion: new("failure")},
764+
}
765+
} else {
766+
for i := int64(1); i <= 30; i++ {
767+
jobs.Jobs = append(jobs.Jobs, &github.WorkflowJob{
768+
ID: new(i),
769+
Name: new("passing-job"),
770+
Conclusion: new("success"),
771+
})
772+
}
773+
w.Header().Set("Link", `<https://api.github.com/repos/owner/repo/actions/runs/456/jobs?page=2>; rel="next"`)
774+
}
775+
w.WriteHeader(http.StatusOK)
776+
_ = json.NewEncoder(w).Encode(jobs)
777+
}),
778+
GetReposActionsJobsLogsByOwnerByRepoByJobID: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
779+
w.Header().Set("Location", "https://github.com/logs/job/31")
780+
w.WriteHeader(http.StatusFound)
781+
}),
782+
})
783+
784+
client := mustNewGHClient(t, mockedClient)
785+
deps := BaseDeps{
786+
Client: client,
787+
ContentWindowSize: 5000,
788+
}
789+
handler := toolDef.Handler(deps)
790+
791+
request := createMCPRequest(map[string]any{
792+
"owner": "owner",
793+
"repo": "repo",
794+
"run_id": float64(456),
795+
"failed_only": true,
796+
})
797+
result, err := handler(ContextWithDeps(context.Background(), deps), &request)
798+
799+
require.NoError(t, err)
800+
require.False(t, result.IsError)
801+
802+
textContent := getTextResult(t, result)
803+
var response map[string]any
804+
err = json.Unmarshal([]byte(textContent.Text), &response)
805+
require.NoError(t, err)
806+
assert.Equal(t, float64(1), response["failed_jobs"])
807+
assert.Equal(t, float64(31), response["total_jobs"])
808+
})
756809
}

0 commit comments

Comments
 (0)