Get full build interface working
This commit is contained in:
parent
7c081f029c
commit
ea45c3b77f
7 changed files with 326 additions and 35 deletions
|
@ -1742,10 +1742,96 @@ p.editable:hover i {
|
||||||
background: #222;
|
background: #222;
|
||||||
color: white;
|
color: white;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
font-family: Consolas, "Lucida Console", Monaco, monospace;
|
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.repo-build .build-pane .build-logs .command-logs {
|
||||||
|
margin: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.repo-build .build-pane .build-logs .command-entry,
|
||||||
|
.repo-build .build-pane .build-logs .log-entry {
|
||||||
|
font-family: Consolas, "Lucida Console", Monaco, monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.repo-build .build-pane .build-logs .command-entry {
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.repo-build .build-pane .build-logs .command-entry i.fa.chevron {
|
||||||
|
color: #666;
|
||||||
|
margin-right: 4px;
|
||||||
|
width: 14px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.repo-build .build-pane .build-logs .command-entry .label {
|
||||||
|
text-align: center;
|
||||||
|
margin-right: 4px;
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 86px;
|
||||||
|
display: inline-block;
|
||||||
|
background-color: #aaa;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
left: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.repo-build .build-pane .build-logs .command-entry .command-title {
|
||||||
|
display: block;
|
||||||
|
padding-left: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label.FROM {
|
||||||
|
background-color: #5bc0de !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label.CMD, .label.EXPOSE, .label.ENTRYPOINT {
|
||||||
|
background-color: #428bca !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label.RUN, .label.ADD {
|
||||||
|
background-color: #5cb85c !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label.ENV, .label.VOLUME, .label.USER, .label.WORKDIR {
|
||||||
|
background-color: #f0ad4e !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label.MAINTAINER {
|
||||||
|
background-color: #aaa !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.repo-build .build-pane .build-logs .log-entry {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.repo-build .build-pane .build-logs .log-entry .message {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 46px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.repo-build .build-pane .build-logs .log-entry .id {
|
||||||
|
color: #aaa;
|
||||||
|
padding-right: 6px;
|
||||||
|
margin-right: 6px;
|
||||||
|
text-align: right;
|
||||||
|
font-size: 12px;
|
||||||
|
width: 40px;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
top: 4px;
|
||||||
|
left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.repo-admin .right-info {
|
.repo-admin .right-info {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
|
|
|
@ -103,7 +103,7 @@ function getMarkedDown(string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the application code itself.
|
// Start the application code itself.
|
||||||
quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'restangular', 'angularMoment', 'angulartics', /*'angulartics.google.analytics',*/ 'angulartics.mixpanel', '$strap.directives', 'ngCookies', 'ngSanitize', 'angular-md5'], function($provide, cfpLoadingBarProvider) {
|
quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'restangular', 'angularMoment', 'angulartics', /*'angulartics.google.analytics',*/ 'angulartics.mixpanel', '$strap.directives', 'ngCookies', 'ngSanitize', 'angular-md5', 'pasvaz.bindonce'], function($provide, cfpLoadingBarProvider) {
|
||||||
cfpLoadingBarProvider.includeSpinner = false;
|
cfpLoadingBarProvider.includeSpinner = false;
|
||||||
|
|
||||||
$provide.factory('UtilService', ['$sanitize', function($sanitize) {
|
$provide.factory('UtilService', ['$sanitize', function($sanitize) {
|
||||||
|
@ -151,7 +151,7 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
|
||||||
$provide.factory('ApiService', ['Restangular', function(Restangular) {
|
$provide.factory('ApiService', ['Restangular', function(Restangular) {
|
||||||
var apiService = {};
|
var apiService = {};
|
||||||
|
|
||||||
var getResource = function(path) {
|
var getResource = function(path, opt_background) {
|
||||||
var resource = {};
|
var resource = {};
|
||||||
resource.url = path;
|
resource.url = path;
|
||||||
resource.withOptions = function(options) {
|
resource.withOptions = function(options) {
|
||||||
|
@ -169,6 +169,12 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
|
||||||
'hasError': false
|
'hasError': false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (opt_background) {
|
||||||
|
performer.withHttpConfig({
|
||||||
|
'ignoreLoadingBar': true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
performer.get(options).then(function(resp) {
|
performer.get(options).then(function(resp) {
|
||||||
result.value = processor(resp);
|
result.value = processor(resp);
|
||||||
result.loading = false;
|
result.loading = false;
|
||||||
|
@ -240,27 +246,33 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
|
||||||
var buildMethodsForEndpoint = function(endpoint) {
|
var buildMethodsForEndpoint = function(endpoint) {
|
||||||
var method = endpoint.methods[0].toLowerCase();
|
var method = endpoint.methods[0].toLowerCase();
|
||||||
var methodName = formatMethodName(endpoint['name']);
|
var methodName = formatMethodName(endpoint['name']);
|
||||||
apiService[methodName] = function(opt_options, opt_parameters) {
|
apiService[methodName] = function(opt_options, opt_parameters, opt_background) {
|
||||||
return Restangular.one(buildUrl(endpoint['path'], opt_parameters))['custom' + method.toUpperCase()](opt_options);
|
var one = Restangular.one(buildUrl(endpoint['path'], opt_parameters));
|
||||||
|
if (opt_background) {
|
||||||
|
one.withHttpConfig({
|
||||||
|
'ignoreLoadingBar': true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return one['custom' + method.toUpperCase()](opt_options);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (method == 'get') {
|
if (method == 'get') {
|
||||||
apiService[methodName + 'AsResource'] = function(opt_parameters) {
|
apiService[methodName + 'AsResource'] = function(opt_parameters, opt_background) {
|
||||||
return getResource(buildUrl(endpoint['path'], opt_parameters));
|
return getResource(buildUrl(endpoint['path'], opt_parameters), opt_background);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (endpoint['user_method']) {
|
if (endpoint['user_method']) {
|
||||||
apiService[getGenericMethodName(endpoint['user_method'])] = function(orgname, opt_options, opt_parameters) {
|
apiService[getGenericMethodName(endpoint['user_method'])] = function(orgname, opt_options, opt_parameters, opt_background) {
|
||||||
if (orgname) {
|
if (orgname) {
|
||||||
if (orgname.name) {
|
if (orgname.name) {
|
||||||
orgname = orgname.name;
|
orgname = orgname.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
var params = jQuery.extend({'orgname' : orgname}, opt_parameters || {});
|
var params = jQuery.extend({'orgname' : orgname}, opt_parameters || {}, opt_background);
|
||||||
return apiService[methodName](opt_options, params);
|
return apiService[methodName](opt_options, params);
|
||||||
} else {
|
} else {
|
||||||
return apiService[formatMethodName(endpoint['user_method'])](opt_options, opt_parameters);
|
return apiService[formatMethodName(endpoint['user_method'])](opt_options, opt_parameters, opt_background);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -529,13 +529,11 @@ function RepoCtrl($scope, $sanitize, Restangular, ImageMetadataService, ApiServi
|
||||||
};
|
};
|
||||||
|
|
||||||
var getBuildInfo = function(repo) {
|
var getBuildInfo = function(repo) {
|
||||||
// Note: We use restangular manually here because we need to turn off the loading bar.
|
var params = {
|
||||||
var buildInfo = Restangular.one('repository/' + repo.namespace + '/' + repo.name + '/build/');
|
'repository': repo.namespace + '/' + repo.name
|
||||||
buildInfo.withHttpConfig({
|
};
|
||||||
'ignoreLoadingBar': true
|
|
||||||
});
|
|
||||||
|
|
||||||
buildInfo.get().then(function(resp) {
|
ApiService.getRepoBuilds(null, params, true).then(function(resp) {
|
||||||
var runningBuilds = [];
|
var runningBuilds = [];
|
||||||
for (var i = 0; i < resp.builds.length; ++i) {
|
for (var i = 0; i < resp.builds.length; ++i) {
|
||||||
var build = resp.builds[i];
|
var build = resp.builds[i];
|
||||||
|
@ -621,11 +619,41 @@ function RepoCtrl($scope, $sanitize, Restangular, ImageMetadataService, ApiServi
|
||||||
loadViewInfo();
|
loadViewInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope, $location, $interval) {
|
function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope, $location, $interval, $sanitize) {
|
||||||
var namespace = $routeParams.namespace;
|
var namespace = $routeParams.namespace;
|
||||||
var name = $routeParams.name;
|
var name = $routeParams.name;
|
||||||
var pollTimerHandle = null;
|
var pollTimerHandle = null;
|
||||||
|
|
||||||
|
var registryHandlers = {
|
||||||
|
'quay.io': function(pieces) {
|
||||||
|
var rnamespace = pieces[pieces.length - 2];
|
||||||
|
var rname = pieces[pieces.length - 1];
|
||||||
|
return '/repository/' + rnamespace + '/' + rname + '/';
|
||||||
|
},
|
||||||
|
|
||||||
|
'': function(pieces) {
|
||||||
|
var rnamespace = pieces.length == 1 ? '_' : pieces[0];
|
||||||
|
var rname = pieces[pieces.length - 1];
|
||||||
|
return 'https://index.docker.io/' + rnamespace + '/' + rname + '/';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var kindHandlers = {
|
||||||
|
'FROM': function(title) {
|
||||||
|
var pieces = title.split('/');
|
||||||
|
var registry = pieces.length < 2 ? '' : pieces[0];
|
||||||
|
if (!registryHandlers[registry]) {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
return '<i class="fa fa-hdd-o"></i> <a href="' + registryHandlers[registry](pieces) + '">' + title + '</a>';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.$on('$destroy', function() {
|
||||||
|
stopPollTimer();
|
||||||
|
});
|
||||||
|
|
||||||
// Watch for changes to the current parameter.
|
// Watch for changes to the current parameter.
|
||||||
$scope.$on('$routeUpdate', function(){
|
$scope.$on('$routeUpdate', function(){
|
||||||
if ($location.search().current) {
|
if ($location.search().current) {
|
||||||
|
@ -645,6 +673,44 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
|
||||||
return id.substr(lastIndex + 1);
|
return id.substr(lastIndex + 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.getCommandKind = function(fullTitle) {
|
||||||
|
var colon = fullTitle.indexOf(':');
|
||||||
|
var title = getTitleWithoutStep(fullTitle);
|
||||||
|
if (!title) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var space = title.indexOf(' ');
|
||||||
|
return title.substring(0, space);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.getCommandTitleHtml = function(fullTitle) {
|
||||||
|
var title = getTitleWithoutStep(fullTitle) || fullTitle;
|
||||||
|
var space = title.indexOf(' ');
|
||||||
|
if (space <= 0) {
|
||||||
|
return $sanitize(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
var kind = $scope.getCommandKind(fullTitle);
|
||||||
|
var sanitized = $sanitize(title.substring(space + 1));
|
||||||
|
|
||||||
|
var handler = kindHandlers[kind || ''];
|
||||||
|
if (handler) {
|
||||||
|
return handler(sanitized);
|
||||||
|
} else {
|
||||||
|
return sanitized;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.toggleCommand = function(command) {
|
||||||
|
command.expanded = !command.expanded;
|
||||||
|
|
||||||
|
if (command.expanded && !command.logs) {
|
||||||
|
// Load the logs for the command.
|
||||||
|
loadCommandLogs(command);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
$scope.setCurrentBuild = function(buildId, opt_updateURL) {
|
$scope.setCurrentBuild = function(buildId, opt_updateURL) {
|
||||||
// Find the build.
|
// Find the build.
|
||||||
for (var i = 0; i < $scope.builds.length; ++i) {
|
for (var i = 0; i < $scope.builds.length; ++i) {
|
||||||
|
@ -656,9 +722,16 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.setCurrentBuildInternal = function(build, opt_updateURL) {
|
$scope.setCurrentBuildInternal = function(build, opt_updateURL) {
|
||||||
|
if (build == $scope.currentBuild) { return; }
|
||||||
|
|
||||||
stopPollTimer();
|
stopPollTimer();
|
||||||
|
|
||||||
|
$scope.commands = null;
|
||||||
|
$scope.commandMap = {};
|
||||||
|
$scope.logs = null;
|
||||||
|
$scope.logStartIndex = 0;
|
||||||
$scope.currentBuild = build;
|
$scope.currentBuild = build;
|
||||||
|
|
||||||
if (opt_updateURL) {
|
if (opt_updateURL) {
|
||||||
if (build) {
|
if (build) {
|
||||||
$location.search('current', build.id);
|
$location.search('current', build.id);
|
||||||
|
@ -677,6 +750,15 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
|
||||||
checkPollTimer();
|
checkPollTimer();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var getTitleWithoutStep = function(fullTitle) {
|
||||||
|
var colon = fullTitle.indexOf(':');
|
||||||
|
if (colon <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $.trim(fullTitle.substring(colon + 1));
|
||||||
|
}
|
||||||
|
|
||||||
var checkPollTimer = function() {
|
var checkPollTimer = function() {
|
||||||
var build = $scope.currentBuild;
|
var build = $scope.currentBuild;
|
||||||
if (!build) {
|
if (!build) {
|
||||||
|
@ -686,8 +768,10 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
|
||||||
|
|
||||||
if (build['phase'] != 'complete' && build['phase'] != 'error') {
|
if (build['phase'] != 'complete' && build['phase'] != 'error') {
|
||||||
startPollTimer();
|
startPollTimer();
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
stopPollTimer();
|
stopPollTimer();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -697,25 +781,99 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
|
||||||
|
|
||||||
var startPollTimer = function() {
|
var startPollTimer = function() {
|
||||||
stopPollTimer();
|
stopPollTimer();
|
||||||
pollTimerHandle = $interval(getBuildStatus, 1000);
|
pollTimerHandle = $interval(getBuildStatusAndLogs, 2000);
|
||||||
};
|
};
|
||||||
|
|
||||||
var getBuildStatus = function() {
|
var processLogs = function(logs, startIndex) {
|
||||||
if (!$scope.currentBuild) { return; }
|
var currentCommand = $scope.commands.length > 0 ? $scope.commands[$scope.commands.length - 1] : null;
|
||||||
|
for (var i = 0; i < logs.length; ++i) {
|
||||||
|
var entry = logs[i];
|
||||||
|
if (entry['is_command']) {
|
||||||
|
var existing = $scope.commandMap[entry['message']];
|
||||||
|
if (existing) {
|
||||||
|
currentCommand = existing;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Note: We use restangular manually here because we need to turn off the loading bar.
|
currentCommand = {
|
||||||
var buildStatus = Restangular.one('repository/' + namespace + '/' + name + '/build/' + $scope.currentBuild.id + '/status');
|
'message': entry['message'],
|
||||||
buildStatus.withHttpConfig({
|
'index': startIndex + i
|
||||||
'ignoreLoadingBar': true
|
};
|
||||||
|
$scope.commands.push(currentCommand);
|
||||||
|
$scope.commandMap[entry['message']] = currentCommand;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!currentCommand.logs) {
|
||||||
|
currentCommand.logs = [];
|
||||||
|
}
|
||||||
|
currentCommand.logs.push(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentCommand.expanded == null) {
|
||||||
|
currentCommand.expanded = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var loadCommandLogs = function(command) {
|
||||||
|
var start = command['index'] + 1;
|
||||||
|
var end = null;
|
||||||
|
|
||||||
|
var currentCommandIndex = jQuery.inArray(command, $scope.commands);
|
||||||
|
if (currentCommandIndex >= 0 && currentCommandIndex < $scope.commands.length - 1) {
|
||||||
|
var nextCommand = $scope.commands[currentCommandIndex + 1];
|
||||||
|
end = nextCommand.index ? nextCommand.index - 1 : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var params = {
|
||||||
|
'repository': namespace + '/' + name,
|
||||||
|
'build_uuid': $scope.currentBuild.id
|
||||||
|
};
|
||||||
|
|
||||||
|
var options = {
|
||||||
|
'start': start
|
||||||
|
};
|
||||||
|
|
||||||
|
if (end != null) {
|
||||||
|
options['end'] = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ApiService.getRepoBuildLogsAsResource(params, true).withOptions(options).get(function(resp) {
|
||||||
|
if (resp['logs']) {
|
||||||
|
command.logs = resp['logs'];
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var getBuildStatusAndLogs = function() {
|
||||||
|
if (!$scope.currentBuild || $scope.polling) { return; }
|
||||||
|
|
||||||
$scope.polling = true;
|
$scope.polling = true;
|
||||||
buildStatus.get().then(function(resp) {
|
|
||||||
|
var params = {
|
||||||
|
'repository': namespace + '/' + name,
|
||||||
|
'build_uuid': $scope.currentBuild.id
|
||||||
|
};
|
||||||
|
|
||||||
|
ApiService.getRepoBuildStatus(null, params, true).then(function(resp) {
|
||||||
// Note: We use extend here rather than replacing as Angular is depending on the
|
// Note: We use extend here rather than replacing as Angular is depending on the
|
||||||
// root build object to remain the same object.
|
// root build object to remain the same object.
|
||||||
$.extend(true, $scope.currentBuild, resp);
|
$.extend(true, $scope.currentBuild, resp);
|
||||||
$scope.polling = false;
|
|
||||||
checkPollTimer();
|
checkPollTimer();
|
||||||
|
|
||||||
|
// Load the updated logs for the build.
|
||||||
|
var options = {
|
||||||
|
'commands': $scope.commands == null,
|
||||||
|
'start': $scope.logStartIndex
|
||||||
|
};
|
||||||
|
ApiService.getRepoBuildLogsAsResource(params, true).withOptions(options).get(function(resp) {
|
||||||
|
if (resp['commands']) {
|
||||||
|
$scope.commands = resp['commands'];
|
||||||
|
}
|
||||||
|
|
||||||
|
processLogs(resp.logs, $scope.logStartIndex);
|
||||||
|
$scope.logStartIndex = resp['total'];
|
||||||
|
$scope.polling = false;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -725,18 +883,15 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
|
||||||
$scope.repository = ApiService.getRepoAsResource(params).get(function(repo) {
|
$scope.repository = ApiService.getRepoAsResource(params).get(function(repo) {
|
||||||
$rootScope.title = 'Repository Builds';
|
$rootScope.title = 'Repository Builds';
|
||||||
$scope.repo = repo;
|
$scope.repo = repo;
|
||||||
getBuildInfo();
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var getBuildInfo = function(repo) {
|
var getBuildInfo = function(repo) {
|
||||||
// Note: We use restangular manually here because we need to turn off the loading bar.
|
var params = {
|
||||||
var buildInfo = Restangular.one('repository/' + namespace + '/' + name + '/build/');
|
'repository': namespace + '/' + name
|
||||||
buildInfo.withHttpConfig({
|
};
|
||||||
'ignoreLoadingBar': true
|
|
||||||
});
|
|
||||||
|
|
||||||
buildInfo.get().then(function(resp) {
|
ApiService.getRepoBuilds(null, params).then(function(resp) {
|
||||||
$scope.builds = resp.builds;
|
$scope.builds = resp.builds;
|
||||||
|
|
||||||
if ($location.search().current) {
|
if ($location.search().current) {
|
||||||
|
@ -748,6 +903,7 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchRepository();
|
fetchRepository();
|
||||||
|
getBuildInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
function RepoAdminCtrl($scope, Restangular, ApiService, $routeParams, $rootScope) {
|
function RepoAdminCtrl($scope, Restangular, ApiService, $routeParams, $rootScope) {
|
||||||
|
|
1
static/lib/bindonce.min.js
vendored
Normal file
1
static/lib/bindonce.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -40,7 +40,29 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="build-logs">
|
<div class="build-logs">
|
||||||
some logs here
|
<div ng-show="!commands">
|
||||||
|
<span class="quay-spinner"></span>
|
||||||
|
</div>
|
||||||
|
<div class="command" ng-repeat="command in commands">
|
||||||
|
<div class="command-entry" ng-click="toggleCommand(command)">
|
||||||
|
<i class="fa chevron" ng-class="command.expanded ? 'fa-chevron-down' : 'fa-chevron-right'"></i>
|
||||||
|
<span bindonce>
|
||||||
|
<span class="label" bo-class="getCommandKind(command.message)" bo-show="getCommandKind(command.message)"
|
||||||
|
bo-text="getCommandKind(command.message)">
|
||||||
|
</span>
|
||||||
|
<span class="command-title" bo-html="getCommandTitleHtml(command.message)"></span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="command-logs panel-collapse collapse" ng-class="command.expanded ? 'in' : 'out'">
|
||||||
|
<div class="log-entry" bindonce ng-repeat="log in command.logs">
|
||||||
|
<span class="id" bo-text="$index + command.index + 1"></span>
|
||||||
|
<span class="message" bo-text="log.message"></span>
|
||||||
|
</div>
|
||||||
|
<div ng-show="!command.logs">
|
||||||
|
<span class="quay-spinner"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="quay-spinner" ng-show="polling"></span>
|
<span class="quay-spinner" ng-show="polling"></span>
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
<script src="static/lib/angulartics-mixpanel.js"></script>
|
<script src="static/lib/angulartics-mixpanel.js"></script>
|
||||||
<script src="static/lib/angulartics-google-analytics.js"></script>
|
<script src="static/lib/angulartics-google-analytics.js"></script>
|
||||||
<script src="static/lib/angular-md5.js"></script>
|
<script src="static/lib/angular-md5.js"></script>
|
||||||
|
<script src="static/lib/bindonce.min.js"></script>
|
||||||
|
|
||||||
<script src="static/lib/angular-moment.min.js"></script>
|
<script src="static/lib/angular-moment.min.js"></script>
|
||||||
<script src="static/lib/angular-cookies.min.js"></script>
|
<script src="static/lib/angular-cookies.min.js"></script>
|
||||||
|
|
|
@ -5,6 +5,7 @@ from random import SystemRandom
|
||||||
from loremipsum import get_sentence
|
from loremipsum import get_sentence
|
||||||
|
|
||||||
from data.buildlogs import BuildLogs
|
from data.buildlogs import BuildLogs
|
||||||
|
from random import choice
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -24,10 +25,22 @@ class TestBuildLogs(BuildLogs):
|
||||||
self.request_counter = 0
|
self.request_counter = 0
|
||||||
self._generate_logs()
|
self._generate_logs()
|
||||||
|
|
||||||
|
def _get_random_command(self):
|
||||||
|
COMMANDS = ['FROM', 'MAINTAINER', 'RUN', 'CMD', 'EXPOSE', 'ENV', 'ADD',
|
||||||
|
'ENTRYPOINT', 'VOLUME', 'USER', 'WORKDIR']
|
||||||
|
|
||||||
|
return choice(COMMANDS)
|
||||||
|
|
||||||
def _generate_command(self):
|
def _generate_command(self):
|
||||||
self.last_command += 1
|
self.last_command += 1
|
||||||
|
|
||||||
|
sentence = get_sentence()
|
||||||
|
command = self._get_random_command()
|
||||||
|
if command == 'FROM':
|
||||||
|
sentence = choice(['ubuntu', 'quay.io/devtable/simple', 'quay.io/buynlarge/orgrepo', 'stackbrew/ubuntu:precise'])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'message': 'Step %s : %s' % (self.last_command, get_sentence()),
|
'message': 'Step %s: %s %s' % (self.last_command, command, sentence),
|
||||||
'is_command': True,
|
'is_command': True,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in a new issue