(projectRoot, options = {})
| 174 | } |
| 175 | |
| 176 | function assessReadiness(projectRoot, options = {}) { |
| 177 | const root = path.resolve(projectRoot || process.cwd()); |
| 178 | const branch = options.branch || runGit(root, ['branch', '--show-current']) || 'detached'; |
| 179 | const head = runGit(root, ['rev-parse', '--short', 'HEAD']); |
| 180 | const verificationProfile = selectVerificationProfile(root, { |
| 181 | changedFiles: options.changedFiles, |
| 182 | }); |
| 183 | const verificationCommand = options.verification || verificationProfile.primaryCommand; |
| 184 | verificationProfile.primaryCommand = verificationCommand; |
| 185 | verificationProfile.commands = Array.from(new Set([ |
| 186 | verificationCommand, |
| 187 | ...verificationProfile.commands, |
| 188 | ])); |
| 189 | const verification = options.runVerification |
| 190 | ? runVerification(root, verificationCommand) |
| 191 | : { status: 'not-run', command: verificationCommand || '', exitCode: null, stdout: '', stderr: '' }; |
| 192 | const snapshot = collectDashboard({ projectRoot: root }); |
| 193 | const dashboard = summarizeDashboard(snapshot); |
| 194 | const prIssue = validatePrUrl(options.pr || ''); |
| 195 | |
| 196 | const gates = { |
| 197 | prUrl: { |
| 198 | pass: !prIssue, |
| 199 | detail: prIssue || options.pr, |
| 200 | }, |
| 201 | git: { |
| 202 | pass: !snapshot.gitStatus?.dirty, |
| 203 | detail: snapshot.gitStatus?.dirty ? `${snapshot.gitStatus.changedFiles} uncommitted file(s)` : 'clean', |
| 204 | }, |
| 205 | dashboard: { |
| 206 | pass: dashboard.issues.length === 0, |
| 207 | detail: dashboard.issues.length === 0 ? 'no queued repairs' : dashboard.issues.join('; '), |
| 208 | }, |
| 209 | verification: { |
| 210 | pass: verification.status === 'pass', |
| 211 | detail: verification.status === 'pass' |
| 212 | ? `${verification.command} exited 0` |
| 213 | : (verification.status === 'not-run' ? 'verification was not run by this finalizer' : `${verification.command} exited ${verification.exitCode}`), |
| 214 | }, |
| 215 | }; |
| 216 | |
| 217 | const blockers = Object.entries(gates) |
| 218 | .filter(([, gate]) => !gate.pass) |
| 219 | .map(([name, gate]) => `${name}: ${gate.detail}`); |
| 220 | |
| 221 | const readiness = { |
| 222 | generatedAt: options.now || new Date().toISOString(), |
| 223 | projectRoot: root, |
| 224 | branch, |
| 225 | head, |
| 226 | pr: options.pr || '', |
| 227 | ready: blockers.length === 0, |
| 228 | blockers, |
| 229 | gates, |
| 230 | verification, |
| 231 | verificationProfile, |
| 232 | dashboard: { |
| 233 | pending: snapshot.pending, |
no test coverage detected