|
import { writeCSVObjects } from "https://deno.land/x/csv/mod.ts"; |
|
import { |
|
GetResponseDataTypeFromEndpointMethod, |
|
} from "https://cdn.skypack.dev/@octokit/types?dts"; |
|
import { octokit } from "./github-api.ts"; |
|
|
|
|
|
type RunsKey = "workflow_runs"; |
|
|
|
type WorkflowRun = GetResponseDataTypeFromEndpointMethod< |
|
typeof octokit.rest.actions.listWorkflowRuns |
|
>[RunsKey][0]; |
|
|
|
|
|
export type SelectedWorkflowData = Pick< |
|
WorkflowRun, |
|
| "id" |
|
| "name" |
|
| "head_branch" |
|
| "run_number" |
|
| "head_sha" |
|
| "status" |
|
| "conclusion" |
|
| "created_at" |
|
| "updated_at" |
|
| "run_attempt" |
|
>; |
|
|
|
type StringsObject<T> = { |
|
[Property in keyof T]: string; |
|
}; |
|
|
|
const header = [ |
|
"id", |
|
"name", |
|
"head_branch", |
|
"run_number", |
|
"head_sha", |
|
"status", |
|
"conclusion", |
|
"created_at", |
|
"updated_at", |
|
"run_attempt", |
|
]; |
|
|
|
|
|
export async function scrapeWorkflowRuns( |
|
workflow: string | number, |
|
outputPath: string, |
|
dateFilter?: string, |
|
fileOptions: Deno.OpenOptions = { |
|
write: true, |
|
create: true, |
|
append: true, |
|
}, |
|
) { |
|
|
|
console.log(`Scraping: ${workflow}`); |
|
|
|
const runsIterator = octokit.paginate.iterator( |
|
octokit.rest.actions.listWorkflowRuns, |
|
{ |
|
owner: "guardian", |
|
repo: "dotcom-rendering", |
|
workflow_id: `${workflow}.yml`, |
|
per_page: 100, |
|
created: dateFilter, |
|
} |
|
); |
|
|
|
const processor = async function* (iterator: typeof runsIterator) { |
|
for await (const response of iterator) { |
|
yield* response.data?.map((run) => { |
|
return processWorkflowRun(run); |
|
}); |
|
} |
|
}; |
|
|
|
const f = await Deno.open(outputPath, fileOptions); |
|
|
|
await writeCSVObjects(f, processor(runsIterator), { header }); |
|
|
|
f.close(); |
|
console.log("done!"); |
|
} |
|
|
|
// --- |
|
|
|
function processWorkflowRun( |
|
run: WorkflowRun |
|
): StringsObject<SelectedWorkflowData> { |
|
const fillerString = "Not set"; |
|
return { |
|
// Deno's csv module seems to expect strings |
|
id: run.id.toString(), |
|
name: run.name ?? fillerString, |
|
head_branch: run.head_branch ?? fillerString, |
|
run_number: run.run_number.toString(), |
|
head_sha: run.head_sha, |
|
status: run.status ?? fillerString, |
|
conclusion: run.conclusion ?? fillerString, |
|
created_at: run.created_at, |
|
updated_at: run.updated_at, |
|
run_attempt: run.run_attempt?.toString(), |
|
}; |
|
} |