From a93fe574879c6f853f2fcef49c20d43dcdeeb23f Mon Sep 17 00:00:00 2001 From: jordan Date: Wed, 28 Jan 2026 18:36:10 -0700 Subject: [PATCH] fix: Expose pipeline errors in API response - Add PipelineErrorResponse struct to handler - Add Errors field to PipelineResponse struct - Add mapPipelineErrors helper function - Include errors in both ListPipelines and GetPipeline responses Root cause of CI failures: Woodpecker trust level doesn't allow privileged mode for docker steps. Errors were being returned by Woodpecker but not exposed. Co-Authored-By: Claude Opus 4.5 --- internal/handlers/infrastructure_pipelines.go | 47 +++++++++++++++---- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/internal/handlers/infrastructure_pipelines.go b/internal/handlers/infrastructure_pipelines.go index 9e88d42..6628a72 100644 --- a/internal/handlers/infrastructure_pipelines.go +++ b/internal/handlers/infrastructure_pipelines.go @@ -8,21 +8,30 @@ import ( "time" "github.com/go-chi/chi/v5" + "github.com/orchard9/rdev/internal/domain" "github.com/orchard9/rdev/pkg/api" ) +// PipelineErrorResponse is the JSON representation of a pipeline error. +type PipelineErrorResponse struct { + Type string `json:"type"` + Message string `json:"message"` + IsWarning bool `json:"is_warning"` +} + // PipelineResponse is the JSON representation of a CI pipeline. type PipelineResponse struct { - ID int64 `json:"id"` - Number int64 `json:"number"` - Status string `json:"status"` - Event string `json:"event"` - Branch string `json:"branch"` - Commit string `json:"commit"` - Message string `json:"message"` - Author string `json:"author"` - Started string `json:"started,omitempty"` - Finished string `json:"finished,omitempty"` + ID int64 `json:"id"` + Number int64 `json:"number"` + Status string `json:"status"` + Event string `json:"event"` + Branch string `json:"branch"` + Commit string `json:"commit"` + Message string `json:"message"` + Author string `json:"author"` + Started string `json:"started,omitempty"` + Finished string `json:"finished,omitempty"` + Errors []PipelineErrorResponse `json:"errors,omitempty"` } // ListPipelines returns recent CI pipeline executions for a project. @@ -61,6 +70,7 @@ func (h *InfrastructureHandler) ListPipelines(w http.ResponseWriter, r *http.Req Author: p.Author, Started: formatTime(p.Started), Finished: formatTime(p.Finished), + Errors: mapPipelineErrors(p.Errors), } } @@ -108,6 +118,7 @@ func (h *InfrastructureHandler) GetPipeline(w http.ResponseWriter, r *http.Reque Author: p.Author, Started: formatTime(p.Started), Finished: formatTime(p.Finished), + Errors: mapPipelineErrors(p.Errors), }) } @@ -118,3 +129,19 @@ func formatTime(t time.Time) string { } return t.Format(time.RFC3339) } + +// mapPipelineErrors converts domain pipeline errors to response format. +func mapPipelineErrors(errors []domain.CIPipelineError) []PipelineErrorResponse { + if len(errors) == 0 { + return nil + } + resp := make([]PipelineErrorResponse, len(errors)) + for i, e := range errors { + resp[i] = PipelineErrorResponse{ + Type: e.Type, + Message: e.Message, + IsWarning: e.IsWarning, + } + } + return resp +}