← Public packages
@gsimone/pr-health
Flag your open PRs that are stuck: red CI, merge conflicts, unanswered review-bot comments, or gone quiet.
src/daily-check.ts
69 lines · 2.0 KB · TypeScriptimport { kody, packageStorage } from 'kody:runtime'
import checkPrHealth from './index.ts'
const STATE_KEY = 'last-seen-fingerprints'
type SeenState = Record<string, string>
/**
* Job entry: check PR health and mail the account inbox only when something
* changed since the last run. A PR that was already failing yesterday and is
* still failing today is not news, so it does not send mail — an unconditional
* daily digest trains you to ignore the real one.
*
* @returns Counts for the run plus whether mail was sent
*
* @example
* import dailyCheck from 'kody:@gsimone/pr-health/daily-check'
*
* await dailyCheck()
*/
export default async function dailyCheck(): Promise<{
examined: number
stuck: number
changed: number
notified: boolean
}> {
const storage = packageStorage()
const previous = ((await storage.get(STATE_KEY)) ?? {}) as SeenState
const { examined, findings, accessWarning } = await checkPrHealth()
const current: SeenState = {}
for (const finding of findings) {
current[`${finding.repo}#${finding.number}`] = finding.fingerprint
}
// News = newly stuck, or stuck for a different reason than last time.
const changed = findings.filter((finding) => {
const key = `${finding.repo}#${finding.number}`
return previous[key] !== finding.fingerprint
})
await storage.set(STATE_KEY, current)
if (changed.length === 0) {
return { examined, stuck: findings.length, changed: 0, notified: false }
}
const noun = changed.length === 1 ? 'PR' : 'PRs'
const lines = changed.map((finding) => {
const why = finding.reasons.map((reason) => reason.detail).join('; ')
return `${finding.repo} #${finding.number} — ${finding.title}\n ${why}\n ${finding.url}`
})
const footer = [`(${findings.length} stuck total, ${examined} examined.)`]
if (accessWarning) footer.push(accessWarning)
await kody.emailSend({
subject: `${changed.length} ${noun} need attention`,
text: `${lines.join('\n\n')}\n\n${footer.join('\n')}`,
})
return {
examined,
stuck: findings.length,
changed: changed.length,
notified: true,
}
}