diff --git a/frontends/nextjs/src/lib/github/download-job-logs-archive.ts b/frontends/nextjs/src/lib/github/download-job-logs-archive.ts new file mode 100644 index 000000000..c8fc485f4 --- /dev/null +++ b/frontends/nextjs/src/lib/github/download-job-logs-archive.ts @@ -0,0 +1,34 @@ +import type { Octokit } from 'octokit' + +export async function downloadJobLogsArchive(options: { + client: Octokit + owner: string + repo: string + jobId: number +}) { + const response = await options.client.request( + 'GET /repos/{owner}/{repo}/actions/jobs/{job_id}/logs', + { + owner: options.owner, + repo: options.repo, + job_id: options.jobId, + request: { redirect: 'manual' }, + } + ) + + const location = response.headers.location + if (!location) { + const error = new Error('GitHub did not return a log archive location') + ;(error as Error & { status?: number }).status = 502 + throw error + } + + const archiveResponse = await fetch(location) + if (!archiveResponse.ok) { + const error = new Error(`Failed to download log archive (${archiveResponse.status})`) + ;(error as Error & { status?: number }).status = archiveResponse.status + throw error + } + + return archiveResponse.arrayBuffer() +} diff --git a/frontends/nextjs/src/lib/github/extract-job-logs.ts b/frontends/nextjs/src/lib/github/extract-job-logs.ts new file mode 100644 index 000000000..7d1772bcc --- /dev/null +++ b/frontends/nextjs/src/lib/github/extract-job-logs.ts @@ -0,0 +1,23 @@ +import JSZip from 'jszip' + +export async function extractJobLogs(archive: ArrayBuffer) { + const zip = await JSZip.loadAsync(archive) + const files = Object.keys(zip.files) + const sections: string[] = [] + + for (const fileName of files) { + const entry = zip.files[fileName] + if (entry.dir) { + continue + } + const content = await entry.async('string') + sections.push(`----- ${fileName} -----`) + sections.push(content) + } + + if (sections.length === 0) { + return '[No log output found in archive]' + } + + return sections.join('\n') +}