github.com/shashidharatd/test-infra@v0.0.0-20171006011030-71304e1ca560/gubernator/static/build.js (about) 1 // Given a DOM node, attempt to select it. 2 function select(node) { 3 var sel = window.getSelection(); 4 if (sel.toString() !== "") { 5 // User is already trying to do a drag-selection, don't prevent it. 6 return; 7 } 8 // Works in Chrome/Safari/FF/IE10+ 9 var range = document.createRange(); 10 range.selectNode(node); 11 sel.removeAllRanges(); 12 sel.addRange(range); 13 } 14 15 // Rewrite timestamps to respect the current locale. 16 function fix_timestamps() { 17 function replace(className, fmt) { 18 var tz = moment.tz.guess(); 19 var els = document.getElementsByClassName(className); 20 for (var i = 0; i < els.length; i++) { 21 var el = els[i]; 22 var epoch = el.getAttribute('data-epoch'); 23 if (epoch) { 24 var time = moment(1000 * epoch).tz(tz); 25 if (typeof fmt === 'function') { 26 el.innerText = fmt(time); 27 } else { 28 el.innerText = time.format(fmt); 29 } 30 } 31 } 32 } 33 replace('timestamp', 'YYYY-MM-DD HH:mm z') 34 replace('shorttimestamp', 'DD HH:mm') 35 replace('humantimestamp', function(t) { 36 var fmt = 'MMM D, Y'; 37 if (t.isAfter(moment().startOf('day'))) { 38 fmt = 'h:mm A'; 39 } else if (t.isAfter(moment().startOf('year'))) { 40 fmt = 'MMM D'; 41 } 42 return t.format(fmt); 43 }) 44 } 45 46 var get_cache = {}; 47 48 // Download a file from GCS or elsewhere, and run "callback" with its contents. 49 function get(uri, callback) { 50 if (get_cache[uri]) { 51 callback(get_cache[uri]); 52 return; 53 } 54 if (uri[0] === '/') { 55 // Matches gs://bucket/file/path -> [..., "bucket", "file/path"] 56 // /bucket/file/path -> [..., "bucket", "file/path"] 57 var groups = uri.match(/([^/:]+)\/(.*)/); 58 var bucket = groups[1], path = groups[2]; 59 var url = 'https://www.googleapis.com/storage/v1/b/' + bucket + '/o/' + 60 encodeURIComponent(path) + '?alt=media'; 61 } else { 62 var url = uri; 63 } 64 var req = new XMLHttpRequest(); 65 req.open('GET', url); 66 req.onload = function(resp) { 67 get_cache[uri] = req.response; 68 callback(req.response); 69 } 70 req.send(); 71 } 72 73 function expand_skipped(els) { 74 var src = els[0].parentElement.dataset['src']; 75 get(src, function(data) { 76 var lines = data.split('\n'); 77 var parent = els[0].parentElement; 78 for (var i = 0; i < els.length; i++) { 79 var el = els[i]; 80 var range = el.dataset['range'].split('-'); 81 var chunk = lines.slice(range[0], range[1]); 82 var chunk = chunk.join('\n'); 83 if (el.previousSibling) { 84 el.previousSibling.appendData(chunk); 85 el.remove(); 86 } else if (el.nextSibling) { 87 el.nextSibling.data = chunk + el.nextSibling.data; 88 el.remove(); 89 } 90 } 91 parent.normalize(); // merge adjacent text nodes 92 fix_escape_codes(); // colorize new segments 93 }); 94 document.querySelector('h2#log').innerHTML = 'Build Log'; 95 } 96 97 function expand_all(btn) { 98 var logs = document.querySelectorAll('pre[data-src]'); 99 for (var i = 0; i < logs.length; i++) { 100 var skips = logs[i].querySelectorAll('span.skip'); 101 if (skips.length > 0) { 102 expand_skipped(skips); 103 } 104 } 105 btn.remove(); 106 } 107 108 function expand_element(els) { 109 var parent = els[0].parentElement; 110 var hidden = parent.querySelectorAll(".hidden"); 111 for (var i = 0; i < hidden.length; i++) { 112 hidden[i].classList.toggle("hidden"); 113 } 114 els[0].classList.add("hidden"); 115 } 116 117 /* given a string containing ansi formatting directives, return a new one 118 with designated regions of text marked with the appropriate color directives, 119 and with all unknown directives stripped */ 120 function ansi_to_html(orig) { 121 // Given a cmd (like "32" or "0;97"), some enclosed body text, and the original string, 122 // either return the body wrapped in an element to achieve the desired result, or the 123 // original string if nothing works. 124 function annotate(cmd, body, orig) { 125 var code = +(cmd.replace('0;', '')); 126 if (code === 0) // reset 127 return body; 128 else if (code === 1) // bold 129 return '<em>' + body + '</em>'; 130 else if (30 <= code && code <= 37) // foreground color 131 return '<span class="ansi-' + (code - 30) + '">' + body + '</span>' 132 else if (90 <= code && code <= 97) // foreground color, bright 133 return '<span class="ansi-' + (code - 90 + 8) + '">' + body + '</span>' 134 return orig; // fallback: don't change anything 135 } 136 // Find commands, optionally followed by a bold command, with some content, then a reset command. 137 // Unpaired commands are *not* handled here, but they're very uncommon. 138 var filtered = orig.replace(/\033\[([0-9;]*)\w(\033\[1m)?([^\033]*?)\033\[0m/g, function(match, code, bold, body, offset, string) { 139 if (bold !== undefined) // normal code + bold 140 return '<em>' + annotate(code, body, string) + '</em>'; 141 return annotate(code, body, string); 142 }) 143 // Strip out anything left over. 144 return filtered.replace(/\033\[([0-9;]*\w)/g, function(match, cmd, offset, string) { 145 console.log('unhandled ansi code: ', cmd, "context:", JSON.stringify(filtered.slice(offset-50,offset+50))); 146 return ''; 147 }); 148 } 149 150 function fix_escape_codes() { 151 var logs = document.querySelectorAll('pre[data-src]'); 152 for (var i = 0; i < logs.length; i++) { 153 var orig = logs[i].innerHTML; 154 var newer = ansi_to_html(orig); 155 if (orig !== newer) { 156 logs[i].innerHTML = newer; 157 } 158 } 159 } 160 161 /* Remove unicode sequences caused by colorized output in junit.xml */ 162 function remove_unicode_escape_codes() { 163 var errors = document.querySelectorAll('pre.error') 164 for (var i = 0; i < errors.length; i++) { 165 var orig = errors[i].innerHTML 166 var newer = orig.replace(/\ufffd\[\d+m/g, "") 167 if (orig !== newer) { 168 errors[i].innerHTML = newer; 169 } 170 } 171 } 172 173 function init() { 174 fix_timestamps(); 175 fix_escape_codes(); 176 remove_unicode_escape_codes(); 177 document.body.onclick = function(evt) { 178 var target = evt.target; 179 if (target.nodeName === 'SPAN' && target.classList.contains('skip')) { 180 expand_skipped([target]); 181 evt.preventDefault(); 182 } 183 if (target.nodeName === 'SPAN' && target.classList.contains('expand')) { 184 expand_element([target]); 185 evt.preventDefault(); 186 } 187 } 188 } 189 190 if (typeof module !== 'undefined' && module.exports) { 191 // enable node.js `require('./build')` to work for testing 192 module.exports = { 193 ansi_to_html: ansi_to_html 194 } 195 } 196 197 // Acknowledge a PR to suppress it. If repo is "CLEAR", clear acks instead. 198 function ack(event, repo, number, latest) { 199 event.stopPropagation(); 200 var req = new XMLHttpRequest(); 201 req.open('POST', '/pr'); 202 req.onload = function(resp) { 203 if (req.status != 200) return; 204 var row = document.getElementById('needs-attention ' + repo + ' ' + number); 205 if (row) { 206 row.remove(); 207 } 208 } 209 req.send(JSON.stringify({ 210 command: 'ack', 211 repo: repo, 212 number: number, 213 latest: latest, 214 })); 215 } 216 217 // Reset the acknowledged PRs 218 function ack_clear() { 219 var req = new XMLHttpRequest(); 220 req.open('POST', '/pr'); 221 req.onload = function(resp) { 222 if (req.status != 200) return; 223 document.location = document.location; // refresh 224 } 225 req.send(JSON.stringify({ 226 command: 'ack-clear', 227 })); 228 }