|
1 | | -// This file provides validation for workflow lock file schema compatibility. |
| 1 | +// This file provides validation for workflow lock files. |
2 | 2 | // |
3 | | -// # Lock File Schema Validation |
| 3 | +// # Lock File Validation |
4 | 4 | // |
5 | | -// This file validates that lock files use a schema version that the current |
6 | | -// build of gh-aw supports. It provides actionable error messages when a |
7 | | -// lock file was generated by an incompatible version. |
| 5 | +// This file validates lock files at two levels: |
| 6 | +// - Schema compatibility: ensures the lock file's schema version is supported by the |
| 7 | +// current build of gh-aw, providing actionable error messages when a lock file |
| 8 | +// was generated by an incompatible version. |
| 9 | +// - Action SHA freshness: checks whether pinned GitHub Actions SHAs are up to date |
| 10 | +// and emits warnings when newer SHAs are available. |
8 | 11 | // |
9 | 12 | // # Validation Functions |
10 | 13 | // |
11 | 14 | // - ValidateLockSchemaCompatibility() - Validates lock file schema version |
| 15 | +// - ValidateActionSHAsInLockFile() - Validates action SHAs and emits update warnings |
12 | 16 | // |
13 | 17 | // # When to Add Validation Here |
14 | 18 | // |
15 | 19 | // Add validation to this file when: |
16 | 20 | // - Adding new lock file format constraints |
17 | 21 | // - Adding migration validation for schema upgrades |
| 22 | +// - Adding user-facing orchestration that validates lock file content |
18 | 23 |
|
19 | 24 | package workflow |
20 | 25 |
|
21 | 26 | import ( |
22 | 27 | "fmt" |
| 28 | + "os" |
23 | 29 | "strings" |
| 30 | + |
| 31 | + "github.com/github/gh-aw/pkg/console" |
24 | 32 | ) |
25 | 33 |
|
26 | 34 | // ValidateLockSchemaCompatibility validates that a lock file's schema is compatible. |
@@ -57,3 +65,68 @@ func ValidateLockSchemaCompatibility(content string, lockFilePath string) error |
57 | 65 | lockSchemaLog.Printf("Lock file schema validated: %s (version=%s)", lockFilePath, metadata.SchemaVersion) |
58 | 66 | return nil |
59 | 67 | } |
| 68 | + |
| 69 | +// ValidateActionSHAsInLockFile validates action SHAs in a lock file and emits warnings |
| 70 | +func ValidateActionSHAsInLockFile(lockFilePath string, cache *ActionCache, verbose bool) error { |
| 71 | + actionSHACheckerLog.Printf("Validating action SHAs in: %s", lockFilePath) |
| 72 | + |
| 73 | + // Extract actions from lock file |
| 74 | + actions, err := ExtractActionsFromLockFile(lockFilePath) |
| 75 | + if err != nil { |
| 76 | + return fmt.Errorf("failed to extract actions: %w", err) |
| 77 | + } |
| 78 | + |
| 79 | + if len(actions) == 0 { |
| 80 | + actionSHACheckerLog.Print("No pinned actions found in lock file") |
| 81 | + if verbose { |
| 82 | + fmt.Fprintln(os.Stderr, console.FormatInfoMessage("No pinned actions to validate")) |
| 83 | + } |
| 84 | + return nil |
| 85 | + } |
| 86 | + |
| 87 | + // Create resolver for checking latest SHAs |
| 88 | + resolver := NewActionResolver(cache) |
| 89 | + |
| 90 | + // Check for updates |
| 91 | + checks := CheckActionSHAUpdates(actions, resolver) |
| 92 | + |
| 93 | + // Count and report updates |
| 94 | + updateCount := 0 |
| 95 | + for _, check := range checks { |
| 96 | + if check.NeedsUpdate { |
| 97 | + updateCount++ |
| 98 | + // Emit warning (FormatWarningMessage adds the warning emoji) |
| 99 | + warningMsg := fmt.Sprintf("%s@%s has a newer SHA available: %s → %s", |
| 100 | + check.Action.Repo, |
| 101 | + check.Action.Version, |
| 102 | + check.Action.SHA[:7], |
| 103 | + check.LatestSHA[:7]) |
| 104 | + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(warningMsg)) |
| 105 | + |
| 106 | + // Show full SHA in verbose mode |
| 107 | + if verbose { |
| 108 | + fmt.Fprintf(os.Stderr, " Current: %s\n", check.Action.SHA) |
| 109 | + fmt.Fprintf(os.Stderr, " Latest: %s\n", check.LatestSHA) |
| 110 | + } |
| 111 | + } |
| 112 | + } |
| 113 | + |
| 114 | + if updateCount > 0 { |
| 115 | + actionSHACheckerLog.Printf("Found %d actions that need updating", updateCount) |
| 116 | + // Save the cache with updated SHAs so the next compilation will use them |
| 117 | + if err := cache.Save(); err != nil { |
| 118 | + actionSHACheckerLog.Printf("Warning: failed to save action cache: %v", err) |
| 119 | + } else { |
| 120 | + actionSHACheckerLog.Print("Saved updated action cache") |
| 121 | + } |
| 122 | + // Provide suggestion to fix the issue |
| 123 | + fmt.Fprintln(os.Stderr, console.FormatInfoMessage("To apply updated action SHAs, recompile with: gh aw compile")) |
| 124 | + if verbose { |
| 125 | + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Found %d action(s) with available updates", updateCount))) |
| 126 | + } |
| 127 | + } else { |
| 128 | + actionSHACheckerLog.Print("All actions are up to date") |
| 129 | + } |
| 130 | + |
| 131 | + return nil |
| 132 | +} |
0 commit comments