collectWorkflowFiles collects the workflow .md file, its corresponding .lock.yml file, and the transitive closure of all imported files. Note: This function always recompiles the workflow to ensure the lock file is up-to-date, regardless of the frontmatter hash status.
(ctx context.Context, workflowPath string, verbose bool, approve bool)
| 28 | // Note: This function always recompiles the workflow to ensure the lock file is up-to-date, |
| 29 | // regardless of the frontmatter hash status. |
| 30 | func collectWorkflowFiles(ctx context.Context, workflowPath string, verbose bool, approve bool) ([]string, error) { |
| 31 | runPushLog.Printf("Collecting files for workflow: %s", workflowPath) |
| 32 | |
| 33 | files := make(map[string]struct { // Use map to avoid duplicates |
| 34 | }) |
| 35 | visited := make(map[string]struct { |
| 36 | }) |
| 37 | |
| 38 | // Get absolute path for the workflow |
| 39 | absWorkflowPath, err := filepath.Abs(workflowPath) |
| 40 | if err != nil { |
| 41 | runPushLog.Printf("Failed to get absolute path for %s: %v", workflowPath, err) |
| 42 | return nil, fmt.Errorf("failed to get absolute path for workflow: %w", err) |
| 43 | } |
| 44 | runPushLog.Printf("Resolved absolute workflow path: %s", absWorkflowPath) |
| 45 | |
| 46 | // Validate the absolute path |
| 47 | absWorkflowPath, err = fileutil.ValidateAbsolutePath(absWorkflowPath) |
| 48 | if err != nil { |
| 49 | runPushLog.Printf("Invalid workflow path: %v", err) |
| 50 | return nil, fmt.Errorf("invalid workflow path: %w", err) |
| 51 | } |
| 52 | |
| 53 | // Add the workflow .md file |
| 54 | files[absWorkflowPath] = struct { |
| 55 | }{} |
| 56 | runPushLog.Printf("Added workflow file: %s", absWorkflowPath) |
| 57 | |
| 58 | // Check lock file and log hash status for observability |
| 59 | lockFilePath := stringutil.MarkdownToLockFile(absWorkflowPath) |
| 60 | runPushLog.Printf("Checking lock file: %s", lockFilePath) |
| 61 | |
| 62 | // Always recompile, but check and log hash status for observability |
| 63 | if fileutil.FileExists(lockFilePath) { |
| 64 | runPushLog.Printf("Lock file exists: %s", lockFilePath) |
| 65 | // Check frontmatter hash for observability |
| 66 | runPushLog.Print("Checking frontmatter hash for observability") |
| 67 | if hashMismatch, err := checkFrontmatterHashMismatch(absWorkflowPath, lockFilePath); err != nil { |
| 68 | runPushLog.Printf("Error checking frontmatter hash: %v", err) |
| 69 | // Don't fail, just log the error |
| 70 | } else if hashMismatch { |
| 71 | runPushLog.Print("Lock file frontmatter hash changed (will recompile)") |
| 72 | if verbose { |
| 73 | fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Frontmatter hash changed, recompiling workflow...")) |
| 74 | } |
| 75 | } else { |
| 76 | runPushLog.Print("Lock file frontmatter hash unchanged (will still recompile)") |
| 77 | if verbose { |
| 78 | fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Recompiling workflow...")) |
| 79 | } |
| 80 | } |
| 81 | } else if os.IsNotExist(err) { |
| 82 | // Lock file doesn't exist |
| 83 | runPushLog.Printf("Lock file not found: %s", lockFilePath) |
| 84 | if verbose { |
| 85 | fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Lock file not found, compiling workflow...")) |
| 86 | } |
| 87 | } else { |