Skip to content

Instantly share code, notes, and snippets.

@menski
Last active August 29, 2015 14:25
Show Gist options
  • Save menski/280f6c788cf4c4f0838e to your computer and use it in GitHub Desktop.
Save menski/280f6c788cf4c4f0838e to your computer and use it in GitHub Desktop.
Jenkins Broken Jobs Overview
<!DOCTYPE html>
<html lang="en">
<head>
<title>Broken Jobs</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.0/css/materialize.min.css">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head>
<body>
<nav>
<div class="nav-wrapper red darken-3">
<div class="row">
<div class="col s12">
<span class="brand-logo">Broken Jobs</span>
<a href="#" data-activates="mobile-demo" class="button-collapse"><i class="material-icons">menu</i></a>
<ul class="right hide-on-med-and-down">
<li><a href="#!" onclick="buildAll()" ><i class="material-icons right">send</i>Build All</a></li>
</ul>
<ul class="side-nav" id="mobile-demo">
<li><a href="#!" onclick="buildAll()" ><i class="material-icons right">send</i>Build All</a></li>
</div>
</div>
</div>
</nav>
<div id="content" class="row">
<div id="preloader" class="col s8 offset-s2">
<h5 class="center-align grey-text">Loading...</h5>
<div class="progress">
<div id="bar" class="determinate"></div>
</div>
</div>
</div>
<script id="jenkins-card" type="text/x-handlebars-template">
<div class="col s12 m6 l4">
<div class="card">
<div class="card-content">
<span class="card-title grey-text">
<a href="{{jenkins.url}}view/Broken/" target="_blank" class="blue-grey-text">{{jenkins.name}}</a>
<span class="badge">
{{#if jenkins.error}}
<i class="material-icons amber-text" title="Unable to connect">report_problem</i>
{{else}}
{{jenkins.jobs.length}}
{{/if}}
</span>
</span>
{{{content}}}
</div>
</div>
</div>
</script>
<script id="jobs-collection" type="text/x-handlebars-template">
{{#if jobs}}
<ul class="collection">
{{#each jobs}}
<li class="collection-item">
<a href="{{url}}" target="_blank" class="blue-grey-text">{{name}}</a>
<a href="#!" title="Build Job" class="secondary-content" onclick="buildJob('{{name}}', '{{url}}')"><i class="material-icons {{color}}-text text-lighten-2">send</i></a>
</li>
{{/each}}
</ul>
{{/if}}
</script>
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.3/handlebars.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.0/js/materialize.min.js"></script>
<script>
// REST API path for jobs query
var queryPath = "view/Broken/api/json?tree=jobs[name,color,url]";
// REST API path to trigger build
var buildPath = "build";
// templates
var jenkinsCardTemplate = Handlebars.compile($("#jenkins-card").html());
var jobsCollectionTemplate = Handlebars.compile($("#jobs-collection").html());
// jenkis to query with display name
var jenkis = [
{ name: "Jenkins Datacenter", url: "https://app.camunda.com/jenkins/"},
{ name: "Jenkins 7.3", url: "https://hq2.camunda.com/jenkins/7.3/"},
{ name: "Jenkins 7.4", url: "https://hq2.camunda.com/jenkins/ci/"},
{ name: "Jenkins Release", url: "https://app.camunda.com/jenkins-release/"},
{ name: "Jenkins Infrastructure", url: "https://hq2.camunda.com/jenkins/infrastructure/"}
]
var jenkisLoaded = 0;
$(document).ready(function() {
$(".button-collapse").sideNav();
fetchData();
});
function fetchData() {
jenkis.forEach(function(jenkins) {
fetchJobs(jenkins);
});
}
function fetchJobs(jenkins) {
$.ajax({
url: jenkins.url + queryPath,
dataType: "json",
xhrFields: {
withCredentials: true
}
})
.done(function(data) {
jenkins.jobs = mapStatusColor(filterJobs(data.jobs));
})
.fail(function() {
jenkins.error = true;
jenkins.jobs = [];
})
.always(function() {
jenkisLoaded++;
if (jenkisLoaded >= jenkis.length) {
displayData();
}
else {
var $bar = $("#bar");
var done = jenkisLoaded * 100 / jenkis.length;
$bar.width(done + "%");
}
});
}
// ignore not build or successful jobs
function filterJobs(jobs) {
return $.grep(jobs, function(job) {
return job.color !== "notbuilt" && job.color !== "blue";
});
}
// map status to color
function mapStatusColor(jobs) {
return $.map(jobs, function(job) {
switch(job.color) {
case "blue_anime":
case "blue":
job.color = "green";
break;
case "red_anime":
case "red":
job.color = "red";
break;
case "yellow_anime":
case "yellow":
job.color = "amber";
break;
case "aborted_anime":
case "aborted":
job.color = "blue-grey";
break;
default:
job.color = "teal"
}
return job;
});
}
function displayData() {
jenkis.sort(function(a,b) {
return b.jobs.length - a.jobs.length;
});
$("#preloader").remove();
jenkis.forEach(displayJenkins);
}
function displayJenkins(jenkins) {
var content = jobsCollectionTemplate(jenkins);
var card = jenkinsCardTemplate({jenkins: jenkins, content: content});
$("#content").append(card);
}
function buildJob(jobName, jobUrl) {
$.ajax({
url: jobUrl + buildPath,
method: "POST",
xhrFields: {
withCredentials: true
}
})
.done(function(data) {
Materialize.toast("Build " + jobName + " started", 4000)
})
.fail(function() {
Materialize.toast("Unable to start " + jobName, 4000)
});
}
function buildAll() {
jenkis.forEach(function(jenkins) {
jenkins.jobs.forEach(function(job) {
buildJob(job.name, job.url);
});
});
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment