parseAndDisplayActionlintOutput parses actionlint JSON output and displays it in the desired format Returns the total number of errors found and a breakdown by kind
(stdout string, verbose bool)
| 410 | // parseAndDisplayActionlintOutput parses actionlint JSON output and displays it in the desired format |
| 411 | // Returns the total number of errors found and a breakdown by kind |
| 412 | func parseAndDisplayActionlintOutput(stdout string, verbose bool) (int, map[string]int, error) { |
| 413 | // Skip if no output |
| 414 | if stdout == "" || strings.TrimSpace(stdout) == "" { |
| 415 | actionlintLog.Print("No actionlint output to parse") |
| 416 | return 0, make(map[string]int), nil |
| 417 | } |
| 418 | |
| 419 | // Parse JSON errors from stdout - actionlint outputs a single JSON array |
| 420 | var errors []actionlintError |
| 421 | if err := json.Unmarshal([]byte(stdout), &errors); err != nil { |
| 422 | return 0, nil, fmt.Errorf("failed to parse actionlint JSON output: %w", err) |
| 423 | } |
| 424 | |
| 425 | totalErrors := len(errors) |
| 426 | actionlintLog.Printf("Parsed %d actionlint errors from output", totalErrors) |
| 427 | |
| 428 | // Track errors by kind |
| 429 | errorsByKind := make(map[string]int) |
| 430 | |
| 431 | // Display errors using CompilerError format |
| 432 | for _, err := range errors { |
| 433 | // Track error kind |
| 434 | if err.Kind != "" { |
| 435 | errorsByKind[err.Kind]++ |
| 436 | } |
| 437 | |
| 438 | // Use snippet from actionlint JSON output for context display. |
| 439 | // actionlint's snippet includes a caret ("^~~~") pointer line; we only |
| 440 | // keep the actual source line so console.FormatError can render its own |
| 441 | // underline based on Column and keep line numbers aligned. |
| 442 | var context []string |
| 443 | if err.Snippet != "" { |
| 444 | lines := strings.Split(err.Snippet, "\n") |
| 445 | if len(lines) > 0 { |
| 446 | context = []string{lines[0]} |
| 447 | } |
| 448 | } |
| 449 | |
| 450 | // Map kind to error type |
| 451 | // Most actionlint errors are actual errors, not warnings |
| 452 | errorType := "error" |
| 453 | if strings.Contains(strings.ToLower(err.Kind), "warning") { |
| 454 | errorType = "warning" |
| 455 | } |
| 456 | |
| 457 | // Build message with kind and documentation URL if available |
| 458 | message := err.Message |
| 459 | if err.Kind != "" { |
| 460 | docsURL := getActionlintDocsURL(err.Kind) |
| 461 | message = fmt.Sprintf("[%s] %s\n\n 📖 %s", err.Kind, err.Message, docsURL) |
| 462 | } |
| 463 | |
| 464 | // Create and format CompilerError |
| 465 | compilerErr := console.CompilerError{ |
| 466 | Position: console.ErrorPosition{ |
| 467 | File: err.Filepath, |
| 468 | Line: err.Line, |
| 469 | Column: err.Column, |