feat(gerrit-tvl): add Buildkite-backed Checks plugin implementation
This small(*) pile of JavaScript queries the Buildkite API for the latest builds for the depot and displays the results in the rebooted Check UI. Change-Id: I7025a1c6d0d0afa000a9df4682133e03824ea10d Reviewed-on: https://cl.tvl.fyi/c/depot/+/2881 Tested-by: BuildkiteCI Reviewed-by: tazjin <mail@tazj.in>
This commit is contained in:
parent
21765a1407
commit
6d008f6412
1 changed files with 131 additions and 0 deletions
|
@ -1,3 +1,134 @@
|
|||
// vim: set noai ts=2 sw=2 et: */
|
||||
|
||||
// This is a read-only Buildkite token: it was generated by lukegb@, and has
|
||||
// read_builds, read_build_logs, and read_pipelines permissions.
|
||||
const BUILDKITE_TOKEN = 'a150658fb61062e432f13a032962d70fa9352088';
|
||||
|
||||
function encodeParams(p) {
|
||||
const pieces = [];
|
||||
for (let k of Object.getOwnPropertyNames(p)) {
|
||||
pieces.push(`${encodeURIComponent(k)}=${encodeURIComponent(p[k])}`);
|
||||
}
|
||||
return pieces.join('&');
|
||||
}
|
||||
|
||||
function formatDuration(from, to) {
|
||||
const millisecondsTook = Math.floor(to.valueOf() - from.valueOf());
|
||||
if (millisecondsTook < 2000) return `${millisecondsTook} ms`;
|
||||
const secondsTook = Math.floor(millisecondsTook / 1000);
|
||||
if (secondsTook < 100) return `${secondsTook} seconds`;
|
||||
const minutesTook = Math.floor(secondsTook / 60);
|
||||
if (minutesTook < 60) return `${minutesTook} minutes`;
|
||||
const hoursTook = Math.floor(minutesTook / 60);
|
||||
const minutesRemainder = minutesTook - (hoursTook * 60);
|
||||
return `${hoursTook}hr ${minutesRemainder}min`;
|
||||
}
|
||||
|
||||
const tvlChecksProvider = {
|
||||
async fetch(change) {
|
||||
let {changeNumber, patchsetNumber, repo} = change;
|
||||
|
||||
const experiments = window.ENABLED_EXPERIMENTS || [];
|
||||
if (experiments.includes("UiFeature__tvl_check_debug")) {
|
||||
changeNumber = 2872;
|
||||
patchsetNumber = 4;
|
||||
repo = 'depot';
|
||||
}
|
||||
|
||||
if (repo !== 'depot') {
|
||||
// We only handle TVL's depot at the moment.
|
||||
return {responseCode: 'OK'};
|
||||
}
|
||||
|
||||
const params = {
|
||||
// besadii uses the patchset ref as the branch name.
|
||||
branch: `refs/changes/${changeNumber.toString().slice(-2)}/${changeNumber}/${patchsetNumber}`,
|
||||
};
|
||||
const url = `https://api.buildkite.com/v2/organizations/tvl/pipelines/depot/builds?${encodeParams(params)}`;
|
||||
const resp = await fetch(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${BUILDKITE_TOKEN}`,
|
||||
},
|
||||
});
|
||||
const respJSON = await resp.json();
|
||||
|
||||
const runs = [];
|
||||
for (let i = 0; i < respJSON.length; i++) {
|
||||
const attempt = respJSON.length - i;
|
||||
const build = respJSON[i];
|
||||
|
||||
for (let job of build.jobs) {
|
||||
// TODO(lukegb): add the ability to retry these (sometimes whitby runs out of disk...)
|
||||
const checkRun = {
|
||||
attempt: attempt,
|
||||
externalId: job.id,
|
||||
checkName: job.name,
|
||||
checkDescription: job.command,
|
||||
checkLink: job.web_url,
|
||||
status: {
|
||||
'running': 'RUNNING',
|
||||
'scheduled': 'RUNNABLE',
|
||||
'passed': 'COMPLETED',
|
||||
'failed': 'COMPLETED',
|
||||
'blocked': 'RUNNABLE',
|
||||
'canceled': 'COMPLETED',
|
||||
'canceling': 'RUNNING',
|
||||
'skipped': 'COMPLETED',
|
||||
'not_run': 'COMPLETED',
|
||||
}[job.state],
|
||||
labelName: 'Verified',
|
||||
};
|
||||
if (job.scheduled_at) {
|
||||
checkRun.scheduledTimestamp = new Date(job.scheduled_at);
|
||||
}
|
||||
if (job.started_at) {
|
||||
checkRun.startedTimestamp = new Date(job.started_at);
|
||||
}
|
||||
if (job.finished_at) {
|
||||
checkRun.finishedTimestamp = new Date(job.finished_at);
|
||||
}
|
||||
|
||||
let statusDescription = job.state;
|
||||
if (checkRun.startedTimestamp && checkRun.finishedTimestamp) {
|
||||
statusDescription = `${statusDescription} in ${formatDuration(checkRun.startedTimestamp, checkRun.finishedTimestamp)}`;
|
||||
} else if (checkRun.startedTimestamp) {
|
||||
statusDescription = `${statusDescription} for ${formatDuration(checkRun.startedTimestamp, new Date())}`;
|
||||
} else if (checkRun.scheduledTimestamp) {
|
||||
statusDescription = `${statusDescription} for ${formatDuration(checkRun.scheduledTimestamp, new Date())}`;
|
||||
}
|
||||
checkRun.statusDescription = statusDescription;
|
||||
|
||||
if (job.state === 'failed') {
|
||||
const result = {
|
||||
// TODO(lukegb): get the log as the message here (the Gerrit
|
||||
// implementation doesn't yet seem to support newlines in message
|
||||
// strings...)
|
||||
links: [{
|
||||
url: job.web_url,
|
||||
tooltip: "Buildkite",
|
||||
primary: true,
|
||||
icon: 'EXTERNAL',
|
||||
}],
|
||||
category: 'ERROR',
|
||||
summary: `${job.command} failed`,
|
||||
};
|
||||
checkRun.results = [result];
|
||||
}
|
||||
|
||||
console.log(checkRun);
|
||||
runs.push(checkRun);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
responseCode: 'OK',
|
||||
runs: runs,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
Gerrit.install(plugin => {
|
||||
console.log('TVL plugin initialising');
|
||||
|
||||
plugin.checks().register(tvlChecksProvider);
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue