Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 24 additions & 11 deletions pkg/cli/compile_command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,32 +152,37 @@ func TestTrackWorkflowFailure(t *testing.T) {
name string
workflowPath string
errorCount int
errorMessages []string
expectedDetails WorkflowFailure
}{
{
name: "single error",
workflowPath: ".github/workflows/test.md",
errorCount: 1,
name: "single error",
workflowPath: ".github/workflows/test.md",
errorCount: 1,
errorMessages: []string{"test error message"},
expectedDetails: WorkflowFailure{
Path: ".github/workflows/test.md",
ErrorCount: 1,
Path: ".github/workflows/test.md",
ErrorCount: 1,
ErrorMessages: []string{"test error message"},
},
},
{
name: "multiple errors",
workflowPath: ".github/workflows/complex.md",
errorCount: 5,
name: "multiple errors",
workflowPath: ".github/workflows/complex.md",
errorCount: 5,
errorMessages: []string{"error 1", "error 2"},
expectedDetails: WorkflowFailure{
Path: ".github/workflows/complex.md",
ErrorCount: 5,
Path: ".github/workflows/complex.md",
ErrorCount: 5,
ErrorMessages: []string{"error 1", "error 2"},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
stats := &CompilationStats{}
trackWorkflowFailure(stats, tt.workflowPath, tt.errorCount)
trackWorkflowFailure(stats, tt.workflowPath, tt.errorCount, tt.errorMessages)

// Check that FailedWorkflows was updated
if len(stats.FailedWorkflows) != 1 {
Expand All @@ -196,6 +201,14 @@ func TestTrackWorkflowFailure(t *testing.T) {
if detail.ErrorCount != tt.expectedDetails.ErrorCount {
t.Errorf("Expected error count %d, got %d", tt.expectedDetails.ErrorCount, detail.ErrorCount)
}
if len(detail.ErrorMessages) != len(tt.expectedDetails.ErrorMessages) {
t.Errorf("Expected %d error messages, got %d", len(tt.expectedDetails.ErrorMessages), len(detail.ErrorMessages))
}
for i, msg := range detail.ErrorMessages {
if i < len(tt.expectedDetails.ErrorMessages) && msg != tt.expectedDetails.ErrorMessages[i] {
t.Errorf("Expected error message %q, got %q", tt.expectedDetails.ErrorMessages[i], msg)
}
}
})
}
}
Expand Down
5 changes: 3 additions & 2 deletions pkg/cli/compile_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ type CompileConfig struct {

// WorkflowFailure represents a failed workflow with its error count
type WorkflowFailure struct {
Path string // File path of the workflow
ErrorCount int // Number of errors in this workflow
Path string // File path of the workflow
ErrorCount int // Number of errors in this workflow
ErrorMessages []string // Actual error messages to display to the user
}

// CompilationStats tracks the results of workflow compilation
Expand Down
18 changes: 9 additions & 9 deletions pkg/cli/compile_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,14 +344,15 @@ func handleFileDeleted(mdFile string, verbose bool) {
}

// trackWorkflowFailure adds a workflow failure to the compilation statistics
func trackWorkflowFailure(stats *CompilationStats, workflowPath string, errorCount int) {
func trackWorkflowFailure(stats *CompilationStats, workflowPath string, errorCount int, errorMessages []string) {
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider making errorMessages variadic (errorMessages ...string) instead of []string. This makes call sites clearer for the common single-message case and avoids forcing callers to allocate slices like []string{err.Error()} just to pass one message.

Copilot uses AI. Check for mistakes.
// Add to FailedWorkflows for backward compatibility
stats.FailedWorkflows = append(stats.FailedWorkflows, filepath.Base(workflowPath))

// Add detailed failure information
stats.FailureDetails = append(stats.FailureDetails, WorkflowFailure{
Path: workflowPath,
ErrorCount: errorCount,
Path: workflowPath,
ErrorCount: errorCount,
ErrorMessages: errorMessages,
})
}

Expand All @@ -367,15 +368,14 @@ func printCompilationSummary(stats *CompilationStats) {
// Use different formatting based on whether there were errors
if stats.Errors > 0 {
fmt.Fprintln(os.Stderr, console.FormatErrorMessage(summary))
// List the failed workflows with their error counts
// Display actual error messages from each failed workflow
// Error messages already include workflow path in format: file:line:col: error: message
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment asserts error messages “already include workflow path…”, but at least one caller passes err.Error() directly (e.g., resolution errors), which may not include the workflow path/line/col. Either (a) adjust the comment to reflect that messages may be raw, or (b) ensure call sites consistently prefix messages with workflowPath (and location when available) before storing/printing.

Suggested change
// Error messages already include workflow path in format: file:line:col: error: message
// Error messages may already include workflow path/position (e.g., "file:line:col: error: message").
// Callers are responsible for adding path/position context when available.

Copilot uses AI. Check for mistakes.
if len(stats.FailureDetails) > 0 {
fmt.Fprintln(os.Stderr, console.FormatErrorMessage("Failed workflows:"))
for _, failure := range stats.FailureDetails {
errorWord := "error"
if failure.ErrorCount > 1 {
errorWord = "errors"
// Display the actual error messages for each failed workflow
for _, errMsg := range failure.ErrorMessages {
fmt.Fprintln(os.Stderr, errMsg)
Comment on lines +376 to +377
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

printCompilationSummary will print nothing for failures that have FailureDetails entries but an empty ErrorMessages slice (e.g., if validation produced zero messages or a caller passes nil/empty). Since the else if len(stats.FailedWorkflows) > 0 fallback won’t run when FailureDetails is non-empty, users can lose all indication of which workflows failed. Add an in-loop fallback when len(failure.ErrorMessages)==0 (e.g., print failure.Path and failure.ErrorCount, or a generic “failed workflow” line) so failures are still visible even without messages.

Suggested change
for _, errMsg := range failure.ErrorMessages {
fmt.Fprintln(os.Stderr, errMsg)
if len(failure.ErrorMessages) > 0 {
for _, errMsg := range failure.ErrorMessages {
fmt.Fprintln(os.Stderr, errMsg)
}
} else {
// Fallback when there are no individual error messages for this failure
if failure.Path != "" {
fmt.Fprintln(
os.Stderr,
console.FormatErrorMessage(
fmt.Sprintf("Failed workflow %s (%d error(s))", failure.Path, failure.ErrorCount),
),
)
} else {
fmt.Fprintln(
os.Stderr,
console.FormatErrorMessage(
fmt.Sprintf("Failed workflow (%d error(s))", failure.ErrorCount),
),
)
}

Copilot uses AI. Check for mistakes.
}
fmt.Fprintf(os.Stderr, " - %s (%d %s)\n", failure.Path, failure.ErrorCount, errorWord)
}
} else if len(stats.FailedWorkflows) > 0 {
// Fallback for backward compatibility if FailureDetails is not populated
Expand Down
22 changes: 18 additions & 4 deletions pkg/cli/compile_orchestration.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func compileSpecificFiles(
errorMessages = append(errorMessages, err.Error())
errorCount++
stats.Errors++
trackWorkflowFailure(stats, markdownFile, 1)
trackWorkflowFailure(stats, markdownFile, 1, []string{err.Error()})
result.Valid = false
result.Errors = append(result.Errors, CompileValidationError{
Type: "resolution_error",
Expand All @@ -104,8 +104,17 @@ func compileSpecificFiles(
if !fileResult.success {
errorCount++
stats.Errors++
trackWorkflowFailure(stats, resolvedFile, 1)
errorMessages = append(errorMessages, fileResult.validationResult.Errors[0].Message)
// Collect error messages from validation result for display in summary
var errMsgs []string
for _, verr := range fileResult.validationResult.Errors {
errMsgs = append(errMsgs, verr.Message)
}
trackWorkflowFailure(stats, resolvedFile, 1, errMsgs)
Comment on lines +107 to +112
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The “collect error messages from validation result” loop is duplicated (also in compileAllFilesInDirectory). Consider extracting a small helper (e.g., collectValidationMessages(errors []CompileValidationError) []string) to avoid repetition and keep message selection rules consistent in one place.

Copilot uses AI. Check for mistakes.
// Only append first error to errorMessages for the return error value
// (all errors are already displayed in the summary via printCompilationSummary)
if len(fileResult.validationResult.Errors) > 0 {
errorMessages = append(errorMessages, fileResult.validationResult.Errors[0].Message)
}
} else {
compiledCount++
workflowDataList = append(workflowDataList, fileResult.workflowData)
Expand Down Expand Up @@ -259,7 +268,12 @@ func compileAllFilesInDirectory(
if !fileResult.success {
errorCount++
stats.Errors++
trackWorkflowFailure(stats, file, 1)
// Collect error messages from validation result
var errMsgs []string
for _, verr := range fileResult.validationResult.Errors {
errMsgs = append(errMsgs, verr.Message)
}
trackWorkflowFailure(stats, file, 1, errMsgs)
Comment on lines +271 to +276
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same duplication as above—prefer reusing a shared helper for collecting verr.Message so future changes (filtering, formatting, truncation) don’t require editing multiple compilation paths.

Copilot uses AI. Check for mistakes.
} else {
successCount++
workflowDataList = append(workflowDataList, fileResult.workflowData)
Expand Down
Loading