blob: da978b4840d01bc9c5780d2a32db12c17812552e [file] [log] [blame]
//<![CDATA[
//
// Copyright (c) 2019-2020 Arm Limited. All rights reserved.
//
// SPDX-License-Identifier: BSD-3-Clause
//
// Get rid of all unhelpful and annoying orbs that Jenkins barfs to indicate sub
// job status. We'd have that in the HTML report anyway. Unhelpfully, Jenkins
// doesn't ID the element, nor does it assign a class to them. So, we:
//
// - Look for a h2 element with text "Subproject Builds" or "Subprojects";
//
// - The orbs are placed in a <ul> immediately following the h2 element; so we
// remove it altogether.
//
document.querySelectorAll("h2").forEach(function(el) {
if ((el.innerText !== "Subproject Builds") && (el.innerText !== "Subprojects"))
return;
if (el.nextSibling.tagName !== "UL")
return;
el.nextSibling.remove();
el.remove();
});
// For failed jobs, there's this large "Identified problems" table that has no
// value. Get rid of that as well.
document.querySelectorAll("h2").forEach(function(el) {
if (el.innerText !== "Identified problems")
return;
el.closest("table").remove();
});
function onResultHover(e) {
var title = this.getAttribute("title");
var commandPre = document.querySelector("#tf-selected-commands");
var localCmd = "";
if (!title || title === "") {
localCmd = "<i>No local command available!</i>";
} else {
var titleElement = '<span style="color: red;">' + title + '</span>';
localCmd = "workspace=/tmp/workspace test_run=1 test_groups=" + titleElement +
" script/run_local_ci.sh";
}
commandPre.innerHTML = localCmd;
}
// Disable re-trigger button
function retriggerDisable() {
var button = document.getElementById("tf-rebuild-button");
button.setAttribute("disabled", "");
}
var checkedCount = 0;
// Enable or disable retrigger button according to its count attribute
function retriggerEffectCount() {
var button = document.getElementById("tf-rebuild-button");
if (checkedCount === 0)
button.setAttribute("disabled", "");
else
button.removeAttribute("disabled");
}
function resultCheckboxes() {
return document.querySelectorAll("#tf-report-main input[type=checkbox]");
}
function computeCheckCount() {
checkedCount = 0;
resultCheckboxes().forEach(function(el) {
if (el.checked)
checkedCount++;
});
retriggerEffectCount();
}
function onConfigChange(e) {
var button = document.getElementById("tf-rebuild-button");
computeCheckCount();
// Collapse the re-build frame upon changing config selection
document.getElementById("tf-rebuild-frame").style.display = "none";
}
var retryCount = 0;
function retryRebuild(frame, selectedConfigs, embed) {
var doc = frame.contentDocument;
var form = doc.querySelector("form[action=configSubmit]");
var errMsg = "Error re-triggering. Are you logged in?" +
" If this happens repeatedly, please check the browser console for errors.";
if (!form || !form.querySelector("button")) {
retryCount++;
if (retryCount > 50)
alert(errMsg);
else
setTimeout(retryRebuild, 100, frame, selectedConfigs, embed);
return;
}
try {
var groups = form.querySelector("input[value=TEST_GROUPS]");
groups = groups.nextElementSibling;
// Set groups only if there were selections, or leave unchanged.
if (selectedConfigs)
groups.value = selectedConfigs.join(" ");
// Clear the parameters derived from clone_repos.sh that had been passed
// over to the present job, which have now become stale. They are no more
// valid for a re-trigger, and have to be freshly set.
const paramsToClear = ["CI_SCRATCH"];
paramsToClear.forEach(function(item) {
var el = form.querySelector("input[value=" + item + "]");
if (!el)
return;
// The value for this parameter is the next sibling, with name=value
// property attached.
el = el.nextElementSibling;
if (el.getAttribute("name") != "value")
throw "Unable to clear parameter '" + item + "'";
// Clear the parameter's value
el.value = "";
});
if (embed) {
// Leave only the parameter form
try {
doc.querySelector("#side-panel").remove();
doc.querySelector("#page-head").remove();
doc.querySelector("footer").remove();
var mainPanel = doc.querySelector("#main-panel");
mainPanel.style.marginLeft = "0px";
mainPanel.style.padding = "10px";
doc.body.style.padding = "0px";
} catch (e) {
}
// Have the frame disappear after clicking, and remove event listener
var closer = form.querySelector("button").addEventListener("click", function(e) {
setTimeout(function() {
frame.style.display = "none";
// We had disabled the retrigger button when we opened the frame. Now
// that we're closing the frame, leave the button in the appropriate
// state.
retriggerEffectCount();
e.target.removeEventListener(e.type, closer);
alert("Build re-triggered for selected configurations.");
});
});
frame.style.height = "700px";
frame.style.width = "100%";
frame.style.display = "block";
// Disable re-trigger until this frame is closed
retriggerDisable();
window.scrollTo(0, frame.getBoundingClientRect().top);
} else {
// Trigger rebuild
form.querySelector("button").click();
if (selectedConfigs)
alert("Build re-triggered for selected configurations.");
else
alert("Job re-triggered.");
}
} catch (e) {
alert("Error triggering job: " + e);
}
}
function onRebuild(e) {
var selectedConfigs = [];
var parent;
var embed;
var configs;
var loc = window.location.href.replace(/\/*$/, "").split("/");
var buildNo = loc[loc.length - 1];
if (!parseInt(buildNo)) {
alert("Please visit the page of a specifc build, and try again.");
return;
}
resultCheckboxes().forEach(function(el) {
if (el.checked === true) {
parent = el.closest("td");
selectedConfigs.push(parent.getAttribute("title"));
}
});
loc.push("rebuild");
loc.push("parameterized");
// If shift key was pressed when clicking, just open a retrigger window
retryCount = 0;
if (e.shiftKey)
embed = true;
var frame = document.getElementById("tf-rebuild-frame");
frame.style.display = "none";
frame.src = loc.join("/");
configs = (e.target.id === "tf-rebuild-button")? selectedConfigs: null;
setTimeout(retryRebuild, 250, frame, configs, embed);
}
function onSelectAll(e) {
var selectClass = e.target.innerHTML.toLowerCase();
if (selectClass === "none") {
resultCheckboxes().forEach(function(checkbox) {
checkbox.checked = false;
});
} else {
document.querySelectorAll("." + selectClass).forEach(function(result) {
var input = result.querySelector("input");
if (input)
input.checked = true;
});
}
computeCheckCount();
}
function init() {
// The whole of Jenkins job result page is rendered in an HTML table. This
// means that anything that alters the size of content elements will cause a
// disruptive page layout reflow. That's exactly what happens with local
// commands when job results are hovered over. To avoid jitter when result
// hovering, fix the width of the element to its initial value.
var localCommands = document.querySelector("#tf-selected-commands");
localCommands.style.width = window.getComputedStyle(localCommands).width;
// Add result hover listeners
[".success", ".failure", ".unstable"].map(function(sel) {
return "#tf-report-main " + sel;
}).forEach(function(sel) {
document.querySelectorAll(sel).forEach(function(result) {
result.addEventListener("mouseover", onResultHover);
});
});
// Add checkbox click listeners
resultCheckboxes().forEach(function(el) {
el.addEventListener("change", onConfigChange);
});
// Add re-trigger button listener
document.getElementById("tf-rebuild-button").addEventListener("click", onRebuild);
document.getElementById("tf-rebuild-all-button").addEventListener("click", onRebuild);
// Add listener for select all widgets
document.querySelectorAll(".select-all").forEach(function(widget) {
widget.addEventListener("click", onSelectAll);
});
computeCheckCount();
}
document.addEventListener("DOMContentLoaded", init);
//]]>