99 "strconv"
1010 "strings"
1111
12+ ghErrors "github.com/github/github-mcp-server/pkg/errors"
1213 "github.com/github/github-mcp-server/pkg/translations"
1314 "github.com/google/go-github/v72/github"
1415 "github.com/mark3labs/mcp-go/mcp"
@@ -644,7 +645,7 @@ func handleFailedJobLogs(ctx context.Context, client *github.Client, owner, repo
644645 Filter : "latest" ,
645646 })
646647 if err != nil {
647- return mcp . NewToolResultError ( fmt . Sprintf ( "failed to list workflow jobs: %v " , err ) ), nil
648+ return ghErrors . NewGitHubAPIErrorResponse ( ctx , "failed to list workflow jobs" , resp , err ), nil
648649 }
649650 defer func () { _ = resp .Body .Close () }()
650651
@@ -670,15 +671,18 @@ func handleFailedJobLogs(ctx context.Context, client *github.Client, owner, repo
670671 // Collect logs for all failed jobs
671672 var logResults []map [string ]any
672673 for _ , job := range failedJobs {
673- jobResult , err := getJobLogData (ctx , client , owner , repo , job .GetID (), job .GetName (), returnContent )
674+ jobResult , resp , err := getJobLogData (ctx , client , owner , repo , job .GetID (), job .GetName (), returnContent )
674675 if err != nil {
675676 // Continue with other jobs even if one fails
676677 jobResult = map [string ]any {
677678 "job_id" : job .GetID (),
678679 "job_name" : job .GetName (),
679680 "error" : err .Error (),
680681 }
682+ // Enable reporting of status codes and error causes
683+ ghErrors .NewGitHubAPIErrorToCtx (ctx , "failed to get job logs" , resp , err )
681684 }
685+
682686 logResults = append (logResults , jobResult )
683687 }
684688
@@ -701,9 +705,9 @@ func handleFailedJobLogs(ctx context.Context, client *github.Client, owner, repo
701705
702706// handleSingleJobLogs gets logs for a single job
703707func handleSingleJobLogs (ctx context.Context , client * github.Client , owner , repo string , jobID int64 , returnContent bool ) (* mcp.CallToolResult , error ) {
704- jobResult , err := getJobLogData (ctx , client , owner , repo , jobID , "" , returnContent )
708+ jobResult , resp , err := getJobLogData (ctx , client , owner , repo , jobID , "" , returnContent )
705709 if err != nil {
706- return mcp . NewToolResultError ( err . Error () ), nil
710+ return ghErrors . NewGitHubAPIErrorResponse ( ctx , "failed to get job logs" , resp , err ), nil
707711 }
708712
709713 r , err := json .Marshal (jobResult )
@@ -715,11 +719,11 @@ func handleSingleJobLogs(ctx context.Context, client *github.Client, owner, repo
715719}
716720
717721// getJobLogData retrieves log data for a single job, either as URL or content
718- func getJobLogData (ctx context.Context , client * github.Client , owner , repo string , jobID int64 , jobName string , returnContent bool ) (map [string ]any , error ) {
722+ func getJobLogData (ctx context.Context , client * github.Client , owner , repo string , jobID int64 , jobName string , returnContent bool ) (map [string ]any , * github. Response , error ) {
719723 // Get the download URL for the job logs
720724 url , resp , err := client .Actions .GetWorkflowJobLogs (ctx , owner , repo , jobID , 1 )
721725 if err != nil {
722- return nil , fmt .Errorf ("failed to get job logs for job %d: %w" , jobID , err )
726+ return nil , resp , fmt .Errorf ("failed to get job logs for job %d: %w" , jobID , err )
723727 }
724728 defer func () { _ = resp .Body .Close () }()
725729
@@ -732,9 +736,10 @@ func getJobLogData(ctx context.Context, client *github.Client, owner, repo strin
732736
733737 if returnContent {
734738 // Download and return the actual log content
735- content , err := downloadLogContent (url .String ())
739+ // TODO we can use a generic http error or an interface instead of github.Response
740+ content , _ , err := downloadLogContent (url .String ())
736741 if err != nil {
737- return nil , fmt .Errorf ("failed to download log content for job %d: %w" , jobID , err )
742+ return nil , nil , fmt .Errorf ("failed to download log content for job %d: %w" , jobID , err )
738743 }
739744 result ["logs_content" ] = content
740745 result ["message" ] = "Job logs content retrieved successfully"
@@ -745,29 +750,29 @@ func getJobLogData(ctx context.Context, client *github.Client, owner, repo strin
745750 result ["note" ] = "The logs_url provides a download link for the individual job logs in plain text format. Use return_content=true to get the actual log content."
746751 }
747752
748- return result , nil
753+ return result , resp , nil
749754}
750755
751756// downloadLogContent downloads the actual log content from a GitHub logs URL
752- func downloadLogContent (logURL string ) (string , error ) {
757+ func downloadLogContent (logURL string ) (string , * http. Response , error ) {
753758 httpResp , err := http .Get (logURL ) //nolint:gosec // URLs are provided by GitHub API and are safe
754759 if err != nil {
755- return "" , fmt .Errorf ("failed to download logs: %w" , err )
760+ return "" , httpResp , fmt .Errorf ("failed to download logs: %w" , err )
756761 }
757762 defer func () { _ = httpResp .Body .Close () }()
758763
759764 if httpResp .StatusCode != http .StatusOK {
760- return "" , fmt .Errorf ("failed to download logs: HTTP %d" , httpResp .StatusCode )
765+ return "" , httpResp , fmt .Errorf ("failed to download logs: HTTP %d" , httpResp .StatusCode )
761766 }
762767
763768 content , err := io .ReadAll (httpResp .Body )
764769 if err != nil {
765- return "" , fmt .Errorf ("failed to read log content: %w" , err )
770+ return "" , httpResp , fmt .Errorf ("failed to read log content: %w" , err )
766771 }
767772
768773 // Clean up and format the log content for better readability
769774 logContent := strings .TrimSpace (string (content ))
770- return logContent , nil
775+ return logContent , httpResp , nil
771776}
772777
773778// RerunWorkflowRun creates a tool to re-run an entire workflow run
@@ -813,7 +818,7 @@ func RerunWorkflowRun(getClient GetClientFn, t translations.TranslationHelperFun
813818
814819 resp , err := client .Actions .RerunWorkflowByID (ctx , owner , repo , runID )
815820 if err != nil {
816- return nil , fmt . Errorf ( "failed to rerun workflow run: %w " , err )
821+ return ghErrors . NewGitHubAPIErrorResponse ( ctx , "failed to rerun workflow run" , resp , err ), nil
817822 }
818823 defer func () { _ = resp .Body .Close () }()
819824
@@ -876,7 +881,7 @@ func RerunFailedJobs(getClient GetClientFn, t translations.TranslationHelperFunc
876881
877882 resp , err := client .Actions .RerunFailedJobsByID (ctx , owner , repo , runID )
878883 if err != nil {
879- return nil , fmt . Errorf ( "failed to rerun failed jobs: %w " , err )
884+ return ghErrors . NewGitHubAPIErrorResponse ( ctx , "failed to rerun failed jobs" , resp , err ), nil
880885 }
881886 defer func () { _ = resp .Body .Close () }()
882887
@@ -939,7 +944,7 @@ func CancelWorkflowRun(getClient GetClientFn, t translations.TranslationHelperFu
939944
940945 resp , err := client .Actions .CancelWorkflowRunByID (ctx , owner , repo , runID )
941946 if err != nil {
942- return nil , fmt . Errorf ( "failed to cancel workflow run: %w " , err )
947+ return ghErrors . NewGitHubAPIErrorResponse ( ctx , "failed to cancel workflow run" , resp , err ), nil
943948 }
944949 defer func () { _ = resp .Body .Close () }()
945950
@@ -1024,7 +1029,7 @@ func ListWorkflowRunArtifacts(getClient GetClientFn, t translations.TranslationH
10241029
10251030 artifacts , resp , err := client .Actions .ListWorkflowRunArtifacts (ctx , owner , repo , runID , opts )
10261031 if err != nil {
1027- return nil , fmt . Errorf ( "failed to list workflow run artifacts: %w " , err )
1032+ return ghErrors . NewGitHubAPIErrorResponse ( ctx , "failed to list workflow run artifacts" , resp , err ), nil
10281033 }
10291034 defer func () { _ = resp .Body .Close () }()
10301035
@@ -1081,7 +1086,7 @@ func DownloadWorkflowRunArtifact(getClient GetClientFn, t translations.Translati
10811086 // Get the download URL for the artifact
10821087 url , resp , err := client .Actions .DownloadArtifact (ctx , owner , repo , artifactID , 1 )
10831088 if err != nil {
1084- return nil , fmt . Errorf ( "failed to get artifact download URL: %w " , err )
1089+ return ghErrors . NewGitHubAPIErrorResponse ( ctx , "failed to get artifact download URL" , resp , err ), nil
10851090 }
10861091 defer func () { _ = resp .Body .Close () }()
10871092
@@ -1146,7 +1151,7 @@ func DeleteWorkflowRunLogs(getClient GetClientFn, t translations.TranslationHelp
11461151
11471152 resp , err := client .Actions .DeleteWorkflowRunLogs (ctx , owner , repo , runID )
11481153 if err != nil {
1149- return nil , fmt . Errorf ( "failed to delete workflow run logs: %w " , err )
1154+ return ghErrors . NewGitHubAPIErrorResponse ( ctx , "failed to delete workflow run logs" , resp , err ), nil
11501155 }
11511156 defer func () { _ = resp .Body .Close () }()
11521157
@@ -1209,7 +1214,7 @@ func GetWorkflowRunUsage(getClient GetClientFn, t translations.TranslationHelper
12091214
12101215 usage , resp , err := client .Actions .GetWorkflowRunUsageByID (ctx , owner , repo , runID )
12111216 if err != nil {
1212- return nil , fmt . Errorf ( "failed to get workflow run usage: %w " , err )
1217+ return ghErrors . NewGitHubAPIErrorResponse ( ctx , "failed to get workflow run usage" , resp , err ), nil
12131218 }
12141219 defer func () { _ = resp .Body .Close () }()
12151220
0 commit comments