import githubRequest from 'kody:@kentcdodds/github/request' import { frictionLabel, owner, repo, type FrictionIssue, type IssueComment } from './shared.ts' type GithubRequestResult = { ok?: boolean status?: number data?: unknown text?: string } type GithubIssue = { number?: number title?: string | null body?: string | null html_url?: string | null user?: { login?: string | null } | null created_at?: string | null updated_at?: string | null pull_request?: unknown labels?: Array<{ name?: string } | string> } type GithubComment = { id?: number body?: string | null created_at?: string | null user?: { login?: string | null } | null } function requireOk(result: GithubRequestResult, path: string) { if (result?.ok === false || (result.status && result.status >= 400)) { throw new Error( `GitHub ${path} failed (${result.status}): ${String(result.text || '').slice(0, 200)}`, ) } return result.data } function asIssues(data: unknown): Array { return Array.isArray(data) ? (data as Array) : [] } function asComments(data: unknown): Array { return Array.isArray(data) ? (data as Array) : [] } async function listLabeledIssues() { const issues: Array = [] for (let page = 1; page <= 10; page += 1) { const path = `/repos/${owner}/${repo}/issues?labels=${encodeURIComponent(frictionLabel)}&state=open&per_page=100&page=${page}` const data = requireOk(await githubRequest({ account: 'bot', path }), path) const pageIssues = asIssues(data).filter((issue) => !issue.pull_request) issues.push(...pageIssues) if (asIssues(data).length < 100) break } return issues } async function listIssueComments(issueNumber: number) { const comments: Array = [] for (let page = 1; page <= 10; page += 1) { const path = `/repos/${owner}/${repo}/issues/${issueNumber}/comments?per_page=100&page=${page}` const data = requireOk(await githubRequest({ account: 'bot', path }), path) const pageComments = asComments(data) comments.push(...pageComments) if (pageComments.length < 100) break } return comments } function toComment(comment: GithubComment): IssueComment { return { id: Number(comment.id || 0), userLogin: String(comment.user?.login || ''), createdAt: String(comment.created_at || ''), body: String(comment.body || ''), } } function issueLabels(issue: GithubIssue) { return (issue.labels || []) .map((label) => (typeof label === 'string' ? label : String(label?.name || ''))) .filter(Boolean) } export async function loadFrictionIssues(): Promise> { const listed = await listLabeledIssues() const issues: Array = [] for (const issue of listed) { const number = Number(issue.number || 0) if (!number) continue const comments = await listIssueComments(number) issues.push({ number, title: String(issue.title || ''), body: String(issue.body || ''), htmlUrl: String(issue.html_url || ''), userLogin: String(issue.user?.login || ''), createdAt: String(issue.created_at || ''), updatedAt: String(issue.updated_at || ''), labels: issueLabels(issue), comments: comments.map(toComment), }) } issues.sort((left, right) => Date.parse(left.createdAt) - Date.parse(right.createdAt)) return issues }