Skip to content

Instantly share code, notes, and snippets.

@indygreg
Created May 13, 2016 18:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save indygreg/cbb68fe1aab0c877a559f64b92fb3065 to your computer and use it in GitHub Desktop.
Save indygreg/cbb68fe1aab0c877a559f64b92fb3065 to your computer and use it in GitHub Desktop.
Draw Gantt Charts of Firefox Automation Scheduling
<!DOCTYPE html>
<html>
<head>
<title>Automation Job Scheduling</title>
</head>
<body>
<script type="application/javascript;version=1.8">
// Perform a Treeherder API request and obtain the JSON.
function thRequest(path) {
return new Promise((resolve, reject) => {
let req = new Request('https://treeherder.mozilla.org/api/' + path,
{mode: "cors"});
fetch(req).then((res) => {
res.json().then((data) => {
resolve(data);
});
});
});
}
function renderProjectRevision(project, revision) {
thRequest('project/' + project + '/resultset/?revision=' + revision).then((data) => {
if (data.meta.count != 1) {
alert('could not find data for requested revision');
return;
}
let rsid = data.results[0].id;
thRequest('project/' + project + '/jobs/?result_set_id=' + rsid + '&count=5000').then((data) => {
renderData(data.results);
});
});
}
let SCHEDULE_COLOR = "rgb(230, 230, 255)";
let RUN_COLOR = "rgb(255, 0, 0)";
let RUN_ETA_COLOR = "rgb(255, 179, 179)";
let ROW_HEIGHT = 20;
function renderData(data) {
let earliestTime = 999999999999999;
let latestTime = 0;
for (let job of data) {
if (job.submit_timestamp < earliestTime) {
earliestTime = job.submit_timestamp;
}
if (job.start_timestamp > latestTime) {
latestTime = job.start_timestamp;
}
if (job.end_timestamp > latestTime) {
latestTime = job.end_timestamp;
}
if (job.end_timestamp == 0 && job.start_timestamp > 0) {
if (job.start_timestamp + job.running_eta > latestTime) {
latestTime = job.start_timestamp + job.running_eta;
}
}
}
let totalDuration = latestTime - earliestTime;
let canvas = document.getElementById('timeline');
canvas.height = data.length * (ROW_HEIGHT + 1);
let drawWidth = canvas.offsetWidth;
let drawHeight = canvas.offsetHeight;
let secondsPerPixel = totalDuration / drawWidth;
let now = Date.now() / 1000;
let nowX = (now - earliestTime) / secondsPerPixel;
let ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, drawWidth, drawHeight);
let yOffset = 0;
for (let job of data) {
let submitTime = job.submit_timestamp;
let startTime = job.start_timestamp;
let endTime = job.end_timestamp;
let endX = (endTime - earliestTime) / secondsPerPixel;
// let submitX = (submitTime - earliestTime) / secondsPerPixel;
//ctx.fillStyle = SCHEDULE_COLOR;
//ctx.fillRect(submitX, yOffset, startX - submitX, ROW_HEIGHT);
if (startTime > 0) {
let startX = (startTime - earliestTime) / secondsPerPixel;
let runEndX;
if (endTime > 0) {
runEndX = (endTime - earliestTime) / secondsPerPixel;
}
// Job is still running. Only use the run color for part that has
// completed.
else {
runEndX = (now - earliestTime) / secondsPerPixel;
let eta = startTime + job.running_eta;
let etaX = (eta - earliestTime) / secondsPerPixel;
ctx.fillStyle = RUN_ETA_COLOR;
ctx.fillRect(runEndX, yOffset, etaX - runEndX, ROW_HEIGHT);
}
ctx.fillStyle = RUN_COLOR;
ctx.fillRect(startX, yOffset, runEndX - startX, ROW_HEIGHT);
}
ctx.fillStyle = "rgb(0, 0, 0)";
ctx.fillText(job.ref_data_name, 5, yOffset + 12);
yOffset += ROW_HEIGHT + 1;
}
}
function populateProjects() {
thRequest("repository/").then((data) => {
let projects = document.getElementById('projects');
for (let repo of data) {
let opt = document.createElement('option');
opt.text = repo.name;
opt.value = repo.name;
projects.options.add(opt);
}
});
}
document.addEventListener('DOMContentLoaded', function() {
populateProjects();
let renderButton = document.getElementById('renderButton');
renderButton.onclick = function() {
let projects = document.getElementById('projects');
let revision = document.getElementById('revision');
let project = projects[projects.selectedIndex].value;
renderProjectRevision(project, revision.value);
};
}, false);
</script>
<div>
<select id="projects"></select>
<input id="revision" type="text" />
<input id="renderButton" type="button" value="Show Timeline" />
</div>
<canvas id="timeline" width="1024" height="2000"></canvas>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment