FE: Resolve "Performance issues when processing large build traces with Ansi2html"
This commit is contained in:
parent
9216f59a3f
commit
8ca5afdf27
|
@ -1,24 +1,28 @@
|
||||||
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-use-before-define, no-param-reassign, quotes, yoda, no-else-return, consistent-return, comma-dangle, object-shorthand, prefer-template, one-var, one-var-declaration-per-line, no-unused-vars, max-len, vars-on-top */
|
/* eslint-disable func-names, wrap-iife, no-use-before-define,
|
||||||
|
consistent-return, prefer-rest-params */
|
||||||
/* global Breakpoints */
|
/* global Breakpoints */
|
||||||
|
|
||||||
var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; };
|
const bind = function (fn, me) { return function () { return fn.apply(me, arguments); }; };
|
||||||
var AUTO_SCROLL_OFFSET = 75;
|
const AUTO_SCROLL_OFFSET = 75;
|
||||||
var DOWN_BUILD_TRACE = '#down-build-trace';
|
const DOWN_BUILD_TRACE = '#down-build-trace';
|
||||||
|
|
||||||
window.Build = (function() {
|
window.Build = (function () {
|
||||||
Build.timeout = null;
|
Build.timeout = null;
|
||||||
|
|
||||||
Build.state = null;
|
Build.state = null;
|
||||||
|
|
||||||
function Build(options) {
|
function Build(options) {
|
||||||
options = options || $('.js-build-options').data();
|
this.options = options || $('.js-build-options').data();
|
||||||
this.pageUrl = options.pageUrl;
|
|
||||||
this.buildUrl = options.buildUrl;
|
this.pageUrl = this.options.pageUrl;
|
||||||
this.buildStatus = options.buildStatus;
|
this.buildUrl = this.options.buildUrl;
|
||||||
this.state = options.logState;
|
this.buildStatus = this.options.buildStatus;
|
||||||
this.buildStage = options.buildStage;
|
this.state = this.options.logState;
|
||||||
this.updateDropdown = bind(this.updateDropdown, this);
|
this.buildStage = this.options.buildStage;
|
||||||
this.$document = $(document);
|
this.$document = $(document);
|
||||||
|
|
||||||
|
this.updateDropdown = bind(this.updateDropdown, this);
|
||||||
|
|
||||||
this.$body = $('body');
|
this.$body = $('body');
|
||||||
this.$buildTrace = $('#build-trace');
|
this.$buildTrace = $('#build-trace');
|
||||||
this.$autoScrollContainer = $('.autoscroll-container');
|
this.$autoScrollContainer = $('.autoscroll-container');
|
||||||
|
@ -29,112 +33,110 @@ window.Build = (function() {
|
||||||
this.$scrollTopBtn = $('#scroll-top');
|
this.$scrollTopBtn = $('#scroll-top');
|
||||||
this.$scrollBottomBtn = $('#scroll-bottom');
|
this.$scrollBottomBtn = $('#scroll-bottom');
|
||||||
this.$buildRefreshAnimation = $('.js-build-refresh');
|
this.$buildRefreshAnimation = $('.js-build-refresh');
|
||||||
|
this.$buildScroll = $('#js-build-scroll');
|
||||||
|
this.$truncatedInfo = $('.js-truncated-info');
|
||||||
|
|
||||||
clearTimeout(Build.timeout);
|
clearTimeout(Build.timeout);
|
||||||
// Init breakpoint checker
|
// Init breakpoint checker
|
||||||
this.bp = Breakpoints.get();
|
this.bp = Breakpoints.get();
|
||||||
|
|
||||||
this.initSidebar();
|
this.initSidebar();
|
||||||
this.$buildScroll = $('#js-build-scroll');
|
|
||||||
|
|
||||||
this.populateJobs(this.buildStage);
|
this.populateJobs(this.buildStage);
|
||||||
this.updateStageDropdownText(this.buildStage);
|
this.updateStageDropdownText(this.buildStage);
|
||||||
this.sidebarOnResize();
|
this.sidebarOnResize();
|
||||||
|
|
||||||
this.$document.off('click', '.js-sidebar-build-toggle').on('click', '.js-sidebar-build-toggle', this.sidebarOnClick.bind(this));
|
this.$document
|
||||||
this.$document.off('click', '.stage-item').on('click', '.stage-item', this.updateDropdown);
|
.off('click', '.js-sidebar-build-toggle')
|
||||||
|
.on('click', '.js-sidebar-build-toggle', this.sidebarOnClick.bind(this));
|
||||||
|
|
||||||
|
this.$document
|
||||||
|
.off('click', '.stage-item')
|
||||||
|
.on('click', '.stage-item', this.updateDropdown);
|
||||||
|
|
||||||
this.$document.on('scroll', this.initScrollMonitor.bind(this));
|
this.$document.on('scroll', this.initScrollMonitor.bind(this));
|
||||||
$(window).off('resize.build').on('resize.build', this.sidebarOnResize.bind(this));
|
|
||||||
$('a', this.$buildScroll).off('click.stepTrace').on('click.stepTrace', this.stepTrace);
|
$(window)
|
||||||
|
.off('resize.build')
|
||||||
|
.on('resize.build', this.sidebarOnResize.bind(this));
|
||||||
|
|
||||||
|
$('a', this.$buildScroll)
|
||||||
|
.off('click.stepTrace')
|
||||||
|
.on('click.stepTrace', this.stepTrace);
|
||||||
|
|
||||||
this.updateArtifactRemoveDate();
|
this.updateArtifactRemoveDate();
|
||||||
if ($('#build-trace').length) {
|
this.initScrollButtonAffix();
|
||||||
this.getInitialBuildTrace();
|
|
||||||
this.initScrollButtonAffix();
|
|
||||||
}
|
|
||||||
this.invokeBuildTrace();
|
this.invokeBuildTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
Build.prototype.initSidebar = function() {
|
Build.prototype.initSidebar = function () {
|
||||||
this.$sidebar = $('.js-build-sidebar');
|
this.$sidebar = $('.js-build-sidebar');
|
||||||
this.$sidebar.niceScroll();
|
this.$sidebar.niceScroll();
|
||||||
this.$document.off('click', '.js-sidebar-build-toggle').on('click', '.js-sidebar-build-toggle', this.toggleSidebar);
|
this.$document
|
||||||
|
.off('click', '.js-sidebar-build-toggle')
|
||||||
|
.on('click', '.js-sidebar-build-toggle', this.toggleSidebar);
|
||||||
};
|
};
|
||||||
|
|
||||||
Build.prototype.location = function() {
|
Build.prototype.invokeBuildTrace = function () {
|
||||||
return window.location.href.split("#")[0];
|
return this.getBuildTrace();
|
||||||
};
|
};
|
||||||
|
|
||||||
Build.prototype.invokeBuildTrace = function() {
|
Build.prototype.getBuildTrace = function () {
|
||||||
var continueRefreshStatuses = ['running', 'pending'];
|
|
||||||
// Continue to update build trace when build is running or pending
|
|
||||||
if (continueRefreshStatuses.indexOf(this.buildStatus) !== -1) {
|
|
||||||
// Check for new build output if user still watching build page
|
|
||||||
// Only valid for runnig build when output changes during time
|
|
||||||
Build.timeout = setTimeout((function(_this) {
|
|
||||||
return function() {
|
|
||||||
if (_this.location() === _this.pageUrl) {
|
|
||||||
return _this.getBuildTrace();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
})(this), 4000);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Build.prototype.getInitialBuildTrace = function() {
|
|
||||||
var removeRefreshStatuses = ['success', 'failed', 'canceled', 'skipped'];
|
|
||||||
|
|
||||||
return $.ajax({
|
return $.ajax({
|
||||||
url: this.pageUrl + "/trace.json",
|
url: `${this.pageUrl}/trace.json`,
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
success: function(buildData) {
|
data: {
|
||||||
$('.js-build-output').html(buildData.html);
|
state: this.state,
|
||||||
gl.utils.setCiStatusFavicon(`${this.pageUrl}/status.json`);
|
},
|
||||||
if (window.location.hash === DOWN_BUILD_TRACE) {
|
success: ((log) => {
|
||||||
$("html,body").scrollTop(this.$buildTrace.height());
|
const $buildContainer = $('.js-build-output');
|
||||||
|
|
||||||
|
if (log.state) {
|
||||||
|
this.state = log.state;
|
||||||
}
|
}
|
||||||
if (removeRefreshStatuses.indexOf(buildData.status) !== -1) {
|
|
||||||
|
if (log.append) {
|
||||||
|
$buildContainer.append(log.html);
|
||||||
|
} else {
|
||||||
|
$buildContainer.html(log.html);
|
||||||
|
if (log.truncated) {
|
||||||
|
$('.js-truncated-info-size').html(` ${log.size} `);
|
||||||
|
this.$truncatedInfo.removeClass('hidden');
|
||||||
|
this.initAffixTruncatedInfo();
|
||||||
|
} else {
|
||||||
|
this.$truncatedInfo.addClass('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.checkAutoscroll();
|
||||||
|
|
||||||
|
if (!log.complete) {
|
||||||
|
Build.timeout = setTimeout(() => {
|
||||||
|
this.invokeBuildTrace();
|
||||||
|
}, 4000);
|
||||||
|
} else {
|
||||||
this.$buildRefreshAnimation.remove();
|
this.$buildRefreshAnimation.remove();
|
||||||
return this.initScrollMonitor();
|
|
||||||
}
|
}
|
||||||
}.bind(this)
|
|
||||||
|
if (log.status !== this.buildStatus) {
|
||||||
|
let pageUrl = this.pageUrl;
|
||||||
|
|
||||||
|
if (this.$autoScrollStatus.data('state') === 'enabled') {
|
||||||
|
pageUrl += DOWN_BUILD_TRACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gl.utils.visitUrl(pageUrl);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
error: () => {
|
||||||
|
this.$buildRefreshAnimation.remove();
|
||||||
|
return this.initScrollMonitor();
|
||||||
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Build.prototype.getBuildTrace = function() {
|
Build.prototype.checkAutoscroll = function () {
|
||||||
return $.ajax({
|
if (this.$autoScrollStatus.data('state') === 'enabled') {
|
||||||
url: this.pageUrl + "/trace.json?state=" + (encodeURIComponent(this.state)),
|
return $('html,body').scrollTop(this.$buildTrace.height());
|
||||||
dataType: "json",
|
|
||||||
success: (function(_this) {
|
|
||||||
return function(log) {
|
|
||||||
var pageUrl;
|
|
||||||
|
|
||||||
if (log.state) {
|
|
||||||
_this.state = log.state;
|
|
||||||
}
|
|
||||||
_this.invokeBuildTrace();
|
|
||||||
if (log.status === "running") {
|
|
||||||
if (log.append) {
|
|
||||||
$('.js-build-output').append(log.html);
|
|
||||||
} else {
|
|
||||||
$('.js-build-output').html(log.html);
|
|
||||||
}
|
|
||||||
return _this.checkAutoscroll();
|
|
||||||
} else if (log.status !== _this.buildStatus) {
|
|
||||||
pageUrl = _this.pageUrl;
|
|
||||||
if (_this.$autoScrollStatus.data('state') === 'enabled') {
|
|
||||||
pageUrl += DOWN_BUILD_TRACE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return gl.utils.visitUrl(pageUrl);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
})(this)
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Build.prototype.checkAutoscroll = function() {
|
|
||||||
if (this.$autoScrollStatus.data("state") === "enabled") {
|
|
||||||
return $("html,body").scrollTop(this.$buildTrace.height());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle a situation where user started new build
|
// Handle a situation where user started new build
|
||||||
|
@ -146,7 +148,7 @@ window.Build = (function() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Build.prototype.initScrollButtonAffix = function() {
|
Build.prototype.initScrollButtonAffix = function () {
|
||||||
// Hide everything initially
|
// Hide everything initially
|
||||||
this.$scrollTopBtn.hide();
|
this.$scrollTopBtn.hide();
|
||||||
this.$scrollBottomBtn.hide();
|
this.$scrollBottomBtn.hide();
|
||||||
|
@ -167,15 +169,17 @@ window.Build = (function() {
|
||||||
// - Show Top Arrow button
|
// - Show Top Arrow button
|
||||||
// - Show Bottom Arrow button
|
// - Show Bottom Arrow button
|
||||||
// - Disable Autoscroll and hide indicator (when build is running)
|
// - Disable Autoscroll and hide indicator (when build is running)
|
||||||
Build.prototype.initScrollMonitor = function() {
|
Build.prototype.initScrollMonitor = function () {
|
||||||
if (!gl.utils.isInViewport(this.$upBuildTrace.get(0)) && !gl.utils.isInViewport(this.$downBuildTrace.get(0))) {
|
if (!gl.utils.isInViewport(this.$upBuildTrace.get(0)) &&
|
||||||
|
!gl.utils.isInViewport(this.$downBuildTrace.get(0))) {
|
||||||
// User is somewhere in middle of Build Log
|
// User is somewhere in middle of Build Log
|
||||||
|
|
||||||
this.$scrollTopBtn.show();
|
this.$scrollTopBtn.show();
|
||||||
|
|
||||||
if (this.buildStatus === 'success' || this.buildStatus === 'failed') { // Check if Build is completed
|
if (this.buildStatus === 'success' || this.buildStatus === 'failed') { // Check if Build is completed
|
||||||
this.$scrollBottomBtn.show();
|
this.$scrollBottomBtn.show();
|
||||||
} else if (this.$buildRefreshAnimation.is(':visible') && !gl.utils.isInViewport(this.$buildRefreshAnimation.get(0))) {
|
} else if (this.$buildRefreshAnimation.is(':visible') &&
|
||||||
|
!gl.utils.isInViewport(this.$buildRefreshAnimation.get(0))) {
|
||||||
this.$scrollBottomBtn.show();
|
this.$scrollBottomBtn.show();
|
||||||
} else {
|
} else {
|
||||||
this.$scrollBottomBtn.hide();
|
this.$scrollBottomBtn.hide();
|
||||||
|
@ -186,10 +190,13 @@ window.Build = (function() {
|
||||||
this.$autoScrollContainer.hide();
|
this.$autoScrollContainer.hide();
|
||||||
this.$autoScrollStatusText.removeClass('animate');
|
this.$autoScrollStatusText.removeClass('animate');
|
||||||
} else {
|
} else {
|
||||||
this.$autoScrollContainer.css({ top: this.$body.outerHeight() - AUTO_SCROLL_OFFSET }).show();
|
this.$autoScrollContainer.css({
|
||||||
|
top: this.$body.outerHeight() - AUTO_SCROLL_OFFSET,
|
||||||
|
}).show();
|
||||||
this.$autoScrollStatusText.addClass('animate');
|
this.$autoScrollStatusText.addClass('animate');
|
||||||
}
|
}
|
||||||
} else if (gl.utils.isInViewport(this.$upBuildTrace.get(0)) && !gl.utils.isInViewport(this.$downBuildTrace.get(0))) {
|
} else if (gl.utils.isInViewport(this.$upBuildTrace.get(0)) &&
|
||||||
|
!gl.utils.isInViewport(this.$downBuildTrace.get(0))) {
|
||||||
// User is at Top of Build Log
|
// User is at Top of Build Log
|
||||||
|
|
||||||
this.$scrollTopBtn.hide();
|
this.$scrollTopBtn.hide();
|
||||||
|
@ -197,17 +204,22 @@ window.Build = (function() {
|
||||||
|
|
||||||
this.$autoScrollContainer.hide();
|
this.$autoScrollContainer.hide();
|
||||||
this.$autoScrollStatusText.removeClass('animate');
|
this.$autoScrollStatusText.removeClass('animate');
|
||||||
} else if ((!gl.utils.isInViewport(this.$upBuildTrace.get(0)) && gl.utils.isInViewport(this.$downBuildTrace.get(0))) ||
|
} else if ((!gl.utils.isInViewport(this.$upBuildTrace.get(0)) &&
|
||||||
(this.$buildRefreshAnimation.is(':visible') && gl.utils.isInViewport(this.$buildRefreshAnimation.get(0)))) {
|
gl.utils.isInViewport(this.$downBuildTrace.get(0))) ||
|
||||||
|
(this.$buildRefreshAnimation.is(':visible') &&
|
||||||
|
gl.utils.isInViewport(this.$buildRefreshAnimation.get(0)))) {
|
||||||
// User is at Bottom of Build Log
|
// User is at Bottom of Build Log
|
||||||
|
|
||||||
this.$scrollTopBtn.show();
|
this.$scrollTopBtn.show();
|
||||||
this.$scrollBottomBtn.hide();
|
this.$scrollBottomBtn.hide();
|
||||||
|
|
||||||
// Show and Reposition Autoscroll Status Indicator
|
// Show and Reposition Autoscroll Status Indicator
|
||||||
this.$autoScrollContainer.css({ top: this.$body.outerHeight() - AUTO_SCROLL_OFFSET }).show();
|
this.$autoScrollContainer.css({
|
||||||
|
top: this.$body.outerHeight() - AUTO_SCROLL_OFFSET,
|
||||||
|
}).show();
|
||||||
this.$autoScrollStatusText.addClass('animate');
|
this.$autoScrollStatusText.addClass('animate');
|
||||||
} else if (gl.utils.isInViewport(this.$upBuildTrace.get(0)) && gl.utils.isInViewport(this.$downBuildTrace.get(0))) {
|
} else if (gl.utils.isInViewport(this.$upBuildTrace.get(0)) &&
|
||||||
|
gl.utils.isInViewport(this.$downBuildTrace.get(0))) {
|
||||||
// Build Log height is small
|
// Build Log height is small
|
||||||
|
|
||||||
this.$scrollTopBtn.hide();
|
this.$scrollTopBtn.hide();
|
||||||
|
@ -218,65 +230,81 @@ window.Build = (function() {
|
||||||
this.$autoScrollStatusText.removeClass('animate');
|
this.$autoScrollStatusText.removeClass('animate');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.buildStatus === "running" || this.buildStatus === "pending") {
|
if (this.buildStatus === 'running' || this.buildStatus === 'pending') {
|
||||||
// Check if Refresh Animation is in Viewport and enable Autoscroll, disable otherwise.
|
// Check if Refresh Animation is in Viewport and enable Autoscroll, disable otherwise.
|
||||||
this.$autoScrollStatus.data("state", gl.utils.isInViewport(this.$buildRefreshAnimation.get(0)) ? 'enabled' : 'disabled');
|
this.$autoScrollStatus.data(
|
||||||
|
'state',
|
||||||
|
gl.utils.isInViewport(this.$buildRefreshAnimation.get(0)) ? 'enabled' : 'disabled',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Build.prototype.shouldHideSidebarForViewport = function() {
|
Build.prototype.shouldHideSidebarForViewport = function () {
|
||||||
var bootstrapBreakpoint;
|
const bootstrapBreakpoint = this.bp.getBreakpointSize();
|
||||||
bootstrapBreakpoint = this.bp.getBreakpointSize();
|
|
||||||
return bootstrapBreakpoint === 'xs' || bootstrapBreakpoint === 'sm';
|
return bootstrapBreakpoint === 'xs' || bootstrapBreakpoint === 'sm';
|
||||||
};
|
};
|
||||||
|
|
||||||
Build.prototype.toggleSidebar = function(shouldHide) {
|
Build.prototype.toggleSidebar = function (shouldHide) {
|
||||||
var shouldShow = typeof shouldHide === 'boolean' ? !shouldHide : undefined;
|
const shouldShow = typeof shouldHide === 'boolean' ? !shouldHide : undefined;
|
||||||
|
|
||||||
this.$buildScroll.toggleClass('sidebar-expanded', shouldShow)
|
this.$buildScroll.toggleClass('sidebar-expanded', shouldShow)
|
||||||
.toggleClass('sidebar-collapsed', shouldHide);
|
.toggleClass('sidebar-collapsed', shouldHide);
|
||||||
|
this.$truncatedInfo.toggleClass('sidebar-expanded', shouldShow)
|
||||||
|
.toggleClass('sidebar-collapsed', shouldHide);
|
||||||
this.$sidebar.toggleClass('right-sidebar-expanded', shouldShow)
|
this.$sidebar.toggleClass('right-sidebar-expanded', shouldShow)
|
||||||
.toggleClass('right-sidebar-collapsed', shouldHide);
|
.toggleClass('right-sidebar-collapsed', shouldHide);
|
||||||
};
|
};
|
||||||
|
|
||||||
Build.prototype.sidebarOnResize = function() {
|
Build.prototype.sidebarOnResize = function () {
|
||||||
this.toggleSidebar(this.shouldHideSidebarForViewport());
|
this.toggleSidebar(this.shouldHideSidebarForViewport());
|
||||||
};
|
};
|
||||||
|
|
||||||
Build.prototype.sidebarOnClick = function() {
|
Build.prototype.sidebarOnClick = function () {
|
||||||
if (this.shouldHideSidebarForViewport()) this.toggleSidebar();
|
if (this.shouldHideSidebarForViewport()) this.toggleSidebar();
|
||||||
};
|
};
|
||||||
|
|
||||||
Build.prototype.updateArtifactRemoveDate = function() {
|
Build.prototype.updateArtifactRemoveDate = function () {
|
||||||
var $date, date;
|
const $date = $('.js-artifacts-remove');
|
||||||
$date = $('.js-artifacts-remove');
|
|
||||||
if ($date.length) {
|
if ($date.length) {
|
||||||
date = $date.text();
|
const date = $date.text();
|
||||||
return $date.text(gl.utils.timeFor(new Date(date.replace(/([0-9]+)-([0-9]+)-([0-9]+)/g, '$1/$2/$3')), ' '));
|
return $date.text(
|
||||||
|
gl.utils.timeFor(new Date(date.replace(/([0-9]+)-([0-9]+)-([0-9]+)/g, '$1/$2/$3')), ' '),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Build.prototype.populateJobs = function(stage) {
|
Build.prototype.populateJobs = function (stage) {
|
||||||
$('.build-job').hide();
|
$('.build-job').hide();
|
||||||
$('.build-job[data-stage="' + stage + '"]').show();
|
$(`.build-job[data-stage="${stage}"]`).show();
|
||||||
};
|
};
|
||||||
|
|
||||||
Build.prototype.updateStageDropdownText = function(stage) {
|
Build.prototype.updateStageDropdownText = function (stage) {
|
||||||
$('.stage-selection').text(stage);
|
$('.stage-selection').text(stage);
|
||||||
};
|
};
|
||||||
|
|
||||||
Build.prototype.updateDropdown = function(e) {
|
Build.prototype.updateDropdown = function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var stage = e.currentTarget.text;
|
const stage = e.currentTarget.text;
|
||||||
this.updateStageDropdownText(stage);
|
this.updateStageDropdownText(stage);
|
||||||
this.populateJobs(stage);
|
this.populateJobs(stage);
|
||||||
};
|
};
|
||||||
|
|
||||||
Build.prototype.stepTrace = function(e) {
|
Build.prototype.stepTrace = function (e) {
|
||||||
var $currentTarget;
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
$currentTarget = $(e.currentTarget);
|
|
||||||
|
const $currentTarget = $(e.currentTarget);
|
||||||
$.scrollTo($currentTarget.attr('href'), {
|
$.scrollTo($currentTarget.attr('href'), {
|
||||||
offset: 0
|
offset: 0,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Build.prototype.initAffixTruncatedInfo = function () {
|
||||||
|
const offsetTop = this.$buildTrace.offset().top;
|
||||||
|
|
||||||
|
this.$truncatedInfo.affix({
|
||||||
|
offset: {
|
||||||
|
top: offsetTop,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,37 @@
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.truncated-info {
|
||||||
|
text-align: center;
|
||||||
|
border-bottom: 1px solid;
|
||||||
|
background-color: $black-transparent;
|
||||||
|
height: 45px;
|
||||||
|
|
||||||
|
&.affix {
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// with sidebar
|
||||||
|
&.affix.sidebar-expanded {
|
||||||
|
right: 312px;
|
||||||
|
left: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// without sidebar
|
||||||
|
&.affix.sidebar-collapsed {
|
||||||
|
right: 20px;
|
||||||
|
left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.affix-top {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
margin: 0 auto;
|
||||||
|
right: 5px;
|
||||||
|
left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.scroll-controls {
|
.scroll-controls {
|
||||||
|
@ -186,6 +217,7 @@
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
.fa-refresh {
|
.fa-refresh {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
|
|
|
@ -71,6 +71,11 @@
|
||||||
= custom_icon('scroll_down_hover_active')
|
= custom_icon('scroll_down_hover_active')
|
||||||
#up-build-trace
|
#up-build-trace
|
||||||
%pre.build-trace#build-trace
|
%pre.build-trace#build-trace
|
||||||
|
.js-truncated-info.truncated-info.hidden
|
||||||
|
%span<
|
||||||
|
Showing last
|
||||||
|
%span.js-truncated-info-size><
|
||||||
|
KiB of log
|
||||||
%code.bash.js-build-output
|
%code.bash.js-build-output
|
||||||
.build-loader-animation.js-build-refresh
|
.build-loader-animation.js-build-refresh
|
||||||
|
|
||||||
|
|
|
@ -64,58 +64,33 @@ describe('Build', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('initial build trace', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
new Build();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('displays the initial build trace', () => {
|
|
||||||
expect($.ajax.calls.count()).toBe(1);
|
|
||||||
const [{ url, dataType, success, context }] = $.ajax.calls.argsFor(0);
|
|
||||||
expect(url).toBe(
|
|
||||||
`${BUILD_URL}/trace.json`,
|
|
||||||
);
|
|
||||||
expect(dataType).toBe('json');
|
|
||||||
expect(success).toEqual(jasmine.any(Function));
|
|
||||||
spyOn(gl.utils, 'setCiStatusFavicon').and.callFake(() => {});
|
|
||||||
|
|
||||||
success.call(context, { html: '<span>Example</span>', status: 'running' });
|
|
||||||
|
|
||||||
expect($('#build-trace .js-build-output').text()).toMatch(/Example/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('removes the spinner', () => {
|
|
||||||
const [{ success, context }] = $.ajax.calls.argsFor(0);
|
|
||||||
spyOn(gl.utils, 'setCiStatusFavicon').and.callFake(() => {});
|
|
||||||
success.call(context, { trace_html: '<span>Example</span>', status: 'success' });
|
|
||||||
|
|
||||||
expect($('.js-build-refresh').length).toBe(0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('running build', () => {
|
describe('running build', () => {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
$('.js-build-options').data('buildStatus', 'running');
|
|
||||||
this.build = new Build();
|
this.build = new Build();
|
||||||
spyOn(this.build, 'location').and.returnValue(BUILD_URL);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('updates the build trace on an interval', function () {
|
it('updates the build trace on an interval', function () {
|
||||||
|
spyOn(gl.utils, 'visitUrl');
|
||||||
|
|
||||||
jasmine.clock().tick(4001);
|
jasmine.clock().tick(4001);
|
||||||
|
|
||||||
expect($.ajax.calls.count()).toBe(2);
|
expect($.ajax.calls.count()).toBe(1);
|
||||||
let [{ url, dataType, success, context }] = $.ajax.calls.argsFor(1);
|
|
||||||
expect(url).toBe(
|
|
||||||
`${BUILD_URL}/trace.json?state=`,
|
|
||||||
);
|
|
||||||
expect(dataType).toBe('json');
|
|
||||||
expect(success).toEqual(jasmine.any(Function));
|
|
||||||
|
|
||||||
success.call(context, {
|
// We have to do it this way to prevent Webpack to fail to compile
|
||||||
|
// when destructuring assignments and reusing
|
||||||
|
// the same variables names inside the same scope
|
||||||
|
let args = $.ajax.calls.argsFor(0)[0];
|
||||||
|
|
||||||
|
expect(args.url).toBe(`${BUILD_URL}/trace.json`);
|
||||||
|
expect(args.dataType).toBe('json');
|
||||||
|
expect(args.success).toEqual(jasmine.any(Function));
|
||||||
|
|
||||||
|
args.success.call($, {
|
||||||
html: '<span>Update<span>',
|
html: '<span>Update<span>',
|
||||||
status: 'running',
|
status: 'running',
|
||||||
state: 'newstate',
|
state: 'newstate',
|
||||||
append: true,
|
append: true,
|
||||||
|
complete: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect($('#build-trace .js-build-output').text()).toMatch(/Update/);
|
expect($('#build-trace .js-build-output').text()).toMatch(/Update/);
|
||||||
|
@ -123,17 +98,20 @@ describe('Build', () => {
|
||||||
|
|
||||||
jasmine.clock().tick(4001);
|
jasmine.clock().tick(4001);
|
||||||
|
|
||||||
expect($.ajax.calls.count()).toBe(3);
|
expect($.ajax.calls.count()).toBe(2);
|
||||||
[{ url, dataType, success, context }] = $.ajax.calls.argsFor(2);
|
|
||||||
expect(url).toBe(`${BUILD_URL}/trace.json?state=newstate`);
|
|
||||||
expect(dataType).toBe('json');
|
|
||||||
expect(success).toEqual(jasmine.any(Function));
|
|
||||||
|
|
||||||
success.call(context, {
|
args = $.ajax.calls.argsFor(1)[0];
|
||||||
|
expect(args.url).toBe(`${BUILD_URL}/trace.json`);
|
||||||
|
expect(args.dataType).toBe('json');
|
||||||
|
expect(args.data.state).toBe('newstate');
|
||||||
|
expect(args.success).toEqual(jasmine.any(Function));
|
||||||
|
|
||||||
|
args.success.call($, {
|
||||||
html: '<span>More</span>',
|
html: '<span>More</span>',
|
||||||
status: 'running',
|
status: 'running',
|
||||||
state: 'finalstate',
|
state: 'finalstate',
|
||||||
append: true,
|
append: true,
|
||||||
|
complete: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect($('#build-trace .js-build-output').text()).toMatch(/UpdateMore/);
|
expect($('#build-trace .js-build-output').text()).toMatch(/UpdateMore/);
|
||||||
|
@ -141,19 +119,22 @@ describe('Build', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('replaces the entire build trace', () => {
|
it('replaces the entire build trace', () => {
|
||||||
|
spyOn(gl.utils, 'visitUrl');
|
||||||
|
|
||||||
jasmine.clock().tick(4001);
|
jasmine.clock().tick(4001);
|
||||||
let [{ success, context }] = $.ajax.calls.argsFor(1);
|
let args = $.ajax.calls.argsFor(0)[0];
|
||||||
success.call(context, {
|
args.success.call($, {
|
||||||
html: '<span>Update</span>',
|
html: '<span>Update</span>',
|
||||||
status: 'running',
|
status: 'running',
|
||||||
append: true,
|
append: false,
|
||||||
|
complete: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect($('#build-trace .js-build-output').text()).toMatch(/Update/);
|
expect($('#build-trace .js-build-output').text()).toMatch(/Update/);
|
||||||
|
|
||||||
jasmine.clock().tick(4001);
|
jasmine.clock().tick(4001);
|
||||||
[{ success, context }] = $.ajax.calls.argsFor(2);
|
args = $.ajax.calls.argsFor(1)[0];
|
||||||
success.call(context, {
|
args.success.call($, {
|
||||||
html: '<span>Different</span>',
|
html: '<span>Different</span>',
|
||||||
status: 'running',
|
status: 'running',
|
||||||
append: false,
|
append: false,
|
||||||
|
@ -163,15 +144,34 @@ describe('Build', () => {
|
||||||
expect($('#build-trace .js-build-output').text()).toMatch(/Different/);
|
expect($('#build-trace .js-build-output').text()).toMatch(/Different/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('shows information about truncated log', () => {
|
||||||
|
jasmine.clock().tick(4001);
|
||||||
|
const [{ success }] = $.ajax.calls.argsFor(0);
|
||||||
|
|
||||||
|
success.call($, {
|
||||||
|
html: '<span>Update</span>',
|
||||||
|
status: 'success',
|
||||||
|
append: false,
|
||||||
|
truncated: true,
|
||||||
|
size: '50',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
$('#build-trace .js-truncated-info').text().trim(),
|
||||||
|
).toContain('Showing last 50 KiB of log');
|
||||||
|
expect($('#build-trace .js-truncated-info-size').text()).toMatch('50');
|
||||||
|
});
|
||||||
|
|
||||||
it('reloads the page when the build is done', () => {
|
it('reloads the page when the build is done', () => {
|
||||||
spyOn(gl.utils, 'visitUrl');
|
spyOn(gl.utils, 'visitUrl');
|
||||||
|
|
||||||
jasmine.clock().tick(4001);
|
jasmine.clock().tick(4001);
|
||||||
const [{ success, context }] = $.ajax.calls.argsFor(1);
|
const [{ success }] = $.ajax.calls.argsFor(0);
|
||||||
success.call(context, {
|
success.call($, {
|
||||||
html: '<span>Final</span>',
|
html: '<span>Final</span>',
|
||||||
status: 'passed',
|
status: 'passed',
|
||||||
append: true,
|
append: true,
|
||||||
|
complete: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(gl.utils.visitUrl).toHaveBeenCalledWith(BUILD_URL);
|
expect(gl.utils.visitUrl).toHaveBeenCalledWith(BUILD_URL);
|
||||||
|
|
Loading…
Reference in New Issue