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  }