also looking at this
fix(ci): land the lock-file repair instead of describing it
#1408
6 files
+193
-15
| @@ -35,8 +35,15 @@ export interface FixOptions { | ||
| 35 | 35 | maxAttempts?: number |
| 36 | 36 | /** Client for agent-driven repair; absent means analysis only */ |
| 37 | 37 | ai?: AiClient | null |
| 38 | /** Run the mechanical repair for a stale lock file */ | |
| 39 | regenerateLockfile?: () => Promise<boolean> | |
| 38 | /** | |
| 39 | * Run the mechanical repair for a stale lock file. | |
| 40 | * | |
| 41 | * Returns what actually happened, because regenerating a file and landing it | |
| 42 | * on the branch are different outcomes and the report distinguishes them. | |
| 43 | */ | |
| 44 | regenerateLockfile?: () => Promise<LockfileRepair> | |
| 45 | /** Diagnose and report without changing anything */ | |
| 46 | dryRun?: boolean | |
| 40 | 47 | logger?: Logger |
| 41 | 48 | } |
| 42 | 49 | |
| @@ -56,6 +63,35 @@ export interface FixOptions { | ||
| 56 | 63 | * await provider.createComment(pr, outcome.report) |
| 57 | 64 | * ``` |
| 58 | 65 | */ |
| 66 | /** What the mechanical lock-file repair managed to do. */ | |
| 67 | export interface LockfileRepair { | |
| 68 | /** The lock file was rewritten in the workspace */ | |
| 69 | regenerated: boolean | |
| 70 | /** The rewritten file was committed and pushed to the branch */ | |
| 71 | pushed: boolean | |
| 72 | } | |
| 73 | ||
| 74 | /** | |
| 75 | * Describe a lock-file repair without overstating it. | |
| 76 | * | |
| 77 | * This message claimed "and pushed the result" long before anything pushed | |
| 78 | * anything, which is the worst kind of report: confident, specific and wrong. | |
| 79 | * | |
| 80 | * @param regenerated - Whether the file was rewritten | |
| 81 | * @param pushed - Whether the rewrite reached the branch | |
| 82 | */ | |
| 83 | function lockfileReport(regenerated: boolean, pushed: boolean): string { | |
| 84 | if (!regenerated) | |
| 85 | return 'Tried to regenerate the lock file, but the install did not succeed.' | |
| 86 | ||
| 87 | if (!pushed) { | |
| 88 | return 'Regenerated the lock file, but could not push it to the branch. ' | |
| 89 | + 'The change is in the workspace only, so the run will still be red until someone commits it.' | |
| 90 | } | |
| 91 | ||
| 92 | return 'Regenerated the lock file and pushed the result. No model was needed.' | |
| 93 | } | |
| 94 | ||
| 59 | 95 | export async function attemptFix(options: FixOptions): Promise<FixOutcome> { |
| 60 | 96 | const logger = options.logger ?? getDefaultLogger() |
| 61 | 97 | const failure = classifyFailure(options.log) |
| @@ -85,19 +121,26 @@ export async function attemptFix(options: FixOptions): Promise<FixOutcome> { | ||
| 85 | 121 | } |
| 86 | 122 | |
| 87 | 123 | if (failure.kind === 'lockfile-drift' && options.regenerateLockfile) { |
| 124 | if (options.dryRun) { | |
| 125 | return { | |
| 126 | failure, | |
| 127 | action: 'mechanical-fix', | |
| 128 | fixed: false, | |
| 129 | report: report(failure, 'Regenerating the lock file would fix this. No model would be needed. ' | |
| 130 | + 'Nothing was changed, because this was a dry run.'), | |
| 131 | } | |
| 132 | } | |
| 133 | ||
| 88 | 134 | logger.info('🔧 Regenerating the lock file') |
| 89 | const regenerated = await options.regenerateLockfile() | |
| 135 | const { regenerated, pushed } = await options.regenerateLockfile() | |
| 90 | 136 | |
| 91 | 137 | return { |
| 92 | 138 | failure, |
| 93 | 139 | action: 'mechanical-fix', |
| 94 | fixed: regenerated, | |
| 95 | report: report( | |
| 96 | failure, | |
| 97 | regenerated | |
| 98 | ? 'Regenerated the lock file and pushed the result. No model was needed.' | |
| 99 | : 'Tried to regenerate the lock file, but the install did not succeed.', | |
| 100 | ), | |
| 140 | // Only a pushed fix has actually repaired the run. A regenerated file | |
| 141 | // sitting in a workspace that is about to be discarded has not. | |
| 142 | fixed: pushed, | |
| 143 | report: report(failure, lockfileReport(regenerated, pushed)), | |
| 101 | 144 | } |
| 102 | 145 | } |
| 103 | 146 | |