blob: da978b4840d01bc9c5780d2a32db12c17812552e [file] [log] [blame]
Fathi Boudra422bf772019-12-02 11:10:16 +02001//<![CDATA[
2//
Leonardo Sandoval579c7372020-10-23 15:23:32 -05003// Copyright (c) 2019-2020 Arm Limited. All rights reserved.
Fathi Boudra422bf772019-12-02 11:10:16 +02004//
5// SPDX-License-Identifier: BSD-3-Clause
6//
7// Get rid of all unhelpful and annoying orbs that Jenkins barfs to indicate sub
8// job status. We'd have that in the HTML report anyway. Unhelpfully, Jenkins
9// doesn't ID the element, nor does it assign a class to them. So, we:
10//
11// - Look for a h2 element with text "Subproject Builds" or "Subprojects";
12//
13// - The orbs are placed in a <ul> immediately following the h2 element; so we
14// remove it altogether.
15//
16document.querySelectorAll("h2").forEach(function(el) {
17 if ((el.innerText !== "Subproject Builds") && (el.innerText !== "Subprojects"))
18 return;
19 if (el.nextSibling.tagName !== "UL")
20 return;
21 el.nextSibling.remove();
22 el.remove();
23});
24
25// For failed jobs, there's this large "Identified problems" table that has no
26// value. Get rid of that as well.
27document.querySelectorAll("h2").forEach(function(el) {
28 if (el.innerText !== "Identified problems")
29 return;
30 el.closest("table").remove();
31});
32
33function onResultHover(e) {
34 var title = this.getAttribute("title");
35 var commandPre = document.querySelector("#tf-selected-commands");
36 var localCmd = "";
37
38 if (!title || title === "") {
39 localCmd = "<i>No local command available!</i>";
40 } else {
41 var titleElement = '<span style="color: red;">' + title + '</span>';
42
43 localCmd = "workspace=/tmp/workspace test_run=1 test_groups=" + titleElement +
44 " script/run_local_ci.sh";
45 }
46
47 commandPre.innerHTML = localCmd;
48}
49
50// Disable re-trigger button
51function retriggerDisable() {
52 var button = document.getElementById("tf-rebuild-button");
53 button.setAttribute("disabled", "");
54}
55
56var checkedCount = 0;
57
58// Enable or disable retrigger button according to its count attribute
59function retriggerEffectCount() {
60 var button = document.getElementById("tf-rebuild-button");
61
62 if (checkedCount === 0)
63 button.setAttribute("disabled", "");
64 else
65 button.removeAttribute("disabled");
66}
67
68function resultCheckboxes() {
69 return document.querySelectorAll("#tf-report-main input[type=checkbox]");
70}
71
72function computeCheckCount() {
73 checkedCount = 0;
74
75 resultCheckboxes().forEach(function(el) {
76 if (el.checked)
77 checkedCount++;
78 });
79
80 retriggerEffectCount();
81}
82
83function onConfigChange(e) {
84 var button = document.getElementById("tf-rebuild-button");
85
86 computeCheckCount();
87
88 // Collapse the re-build frame upon changing config selection
89 document.getElementById("tf-rebuild-frame").style.display = "none";
90}
91
92var retryCount = 0;
93
94function retryRebuild(frame, selectedConfigs, embed) {
95 var doc = frame.contentDocument;
96 var form = doc.querySelector("form[action=configSubmit]");
97 var errMsg = "Error re-triggering. Are you logged in?" +
98 " If this happens repeatedly, please check the browser console for errors.";
99
100 if (!form || !form.querySelector("button")) {
101 retryCount++;
102 if (retryCount > 50)
103 alert(errMsg);
104 else
105 setTimeout(retryRebuild, 100, frame, selectedConfigs, embed);
106 return;
107 }
108
109 try {
110 var groups = form.querySelector("input[value=TEST_GROUPS]");
111 groups = groups.nextElementSibling;
112
113 // Set groups only if there were selections, or leave unchanged.
114 if (selectedConfigs)
115 groups.value = selectedConfigs.join(" ");
116
117 // Clear the parameters derived from clone_repos.sh that had been passed
118 // over to the present job, which have now become stale. They are no more
119 // valid for a re-trigger, and have to be freshly set.
120 const paramsToClear = ["CI_SCRATCH"];
121 paramsToClear.forEach(function(item) {
122 var el = form.querySelector("input[value=" + item + "]");
123 if (!el)
124 return;
125
126 // The value for this parameter is the next sibling, with name=value
127 // property attached.
128 el = el.nextElementSibling;
129 if (el.getAttribute("name") != "value")
130 throw "Unable to clear parameter '" + item + "'";
131
132 // Clear the parameter's value
133 el.value = "";
134 });
135
136 if (embed) {
137 // Leave only the parameter form
138 try {
139 doc.querySelector("#side-panel").remove();
140 doc.querySelector("#page-head").remove();
141 doc.querySelector("footer").remove();
142
143 var mainPanel = doc.querySelector("#main-panel");
144 mainPanel.style.marginLeft = "0px";
145 mainPanel.style.padding = "10px";
146
147 doc.body.style.padding = "0px";
148 } catch (e) {
149 }
150
151 // Have the frame disappear after clicking, and remove event listener
152 var closer = form.querySelector("button").addEventListener("click", function(e) {
153 setTimeout(function() {
154 frame.style.display = "none";
155
156 // We had disabled the retrigger button when we opened the frame. Now
157 // that we're closing the frame, leave the button in the appropriate
158 // state.
159 retriggerEffectCount();
160
161 e.target.removeEventListener(e.type, closer);
162 alert("Build re-triggered for selected configurations.");
163 });
164 });
165
166 frame.style.height = "700px";
167 frame.style.width = "100%";
168 frame.style.display = "block";
169
170 // Disable re-trigger until this frame is closed
171 retriggerDisable();
172
173 window.scrollTo(0, frame.getBoundingClientRect().top);
174 } else {
175 // Trigger rebuild
176 form.querySelector("button").click();
177 if (selectedConfigs)
178 alert("Build re-triggered for selected configurations.");
179 else
180 alert("Job re-triggered.");
181 }
182 } catch (e) {
183 alert("Error triggering job: " + e);
184 }
185}
186
187function onRebuild(e) {
188 var selectedConfigs = [];
189 var parent;
190 var embed;
191 var configs;
192
193 var loc = window.location.href.replace(/\/*$/, "").split("/");
194 var buildNo = loc[loc.length - 1];
195 if (!parseInt(buildNo)) {
196 alert("Please visit the page of a specifc build, and try again.");
197 return;
198 }
199
200 resultCheckboxes().forEach(function(el) {
201 if (el.checked === true) {
202 parent = el.closest("td");
203 selectedConfigs.push(parent.getAttribute("title"));
204 }
205 });
206
207 loc.push("rebuild");
208 loc.push("parameterized");
209
210 // If shift key was pressed when clicking, just open a retrigger window
211 retryCount = 0;
212 if (e.shiftKey)
213 embed = true;
214
215 var frame = document.getElementById("tf-rebuild-frame");
216 frame.style.display = "none";
217 frame.src = loc.join("/");
218
219 configs = (e.target.id === "tf-rebuild-button")? selectedConfigs: null;
220 setTimeout(retryRebuild, 250, frame, configs, embed);
221}
222
223function onSelectAll(e) {
224 var selectClass = e.target.innerHTML.toLowerCase();
225
226 if (selectClass === "none") {
227 resultCheckboxes().forEach(function(checkbox) {
228 checkbox.checked = false;
229 });
230 } else {
231 document.querySelectorAll("." + selectClass).forEach(function(result) {
232 var input = result.querySelector("input");
233 if (input)
234 input.checked = true;
235 });
236 }
237
238 computeCheckCount();
239}
240
241function init() {
242 // The whole of Jenkins job result page is rendered in an HTML table. This
243 // means that anything that alters the size of content elements will cause a
244 // disruptive page layout reflow. That's exactly what happens with local
245 // commands when job results are hovered over. To avoid jitter when result
246 // hovering, fix the width of the element to its initial value.
247 var localCommands = document.querySelector("#tf-selected-commands");
248 localCommands.style.width = window.getComputedStyle(localCommands).width;
249
250 // Add result hover listeners
251 [".success", ".failure", ".unstable"].map(function(sel) {
252 return "#tf-report-main " + sel;
253 }).forEach(function(sel) {
254 document.querySelectorAll(sel).forEach(function(result) {
255 result.addEventListener("mouseover", onResultHover);
256 });
257 });
258
259 // Add checkbox click listeners
260 resultCheckboxes().forEach(function(el) {
261 el.addEventListener("change", onConfigChange);
262 });
263
264 // Add re-trigger button listener
265 document.getElementById("tf-rebuild-button").addEventListener("click", onRebuild);
266 document.getElementById("tf-rebuild-all-button").addEventListener("click", onRebuild);
267
268 // Add listener for select all widgets
269 document.querySelectorAll(".select-all").forEach(function(widget) {
270 widget.addEventListener("click", onSelectAll);
271 });
272
273 computeCheckCount();
274}
275
276document.addEventListener("DOMContentLoaded", init);
277//]]>