Merge pull request #1681 from coreos-inc/no-retry-builds
Fix display for builds which have fully expired
This commit is contained in:
commit
fb0a1f9728
12 changed files with 164 additions and 149 deletions
|
@ -112,13 +112,13 @@ def _get_build_status(build_obj):
|
|||
if datetime.datetime.utcnow() - heartbeat > datetime.timedelta(minutes=1):
|
||||
phase = database.BUILD_PHASE.INTERNAL_ERROR
|
||||
|
||||
# If the phase is internal error, return 'error' instead if the number of retries
|
||||
# on the queue item is 0.
|
||||
if phase == database.BUILD_PHASE.INTERNAL_ERROR:
|
||||
retry = (build_obj.queue_id and
|
||||
dockerfile_build_queue.has_retries_remaining(build_obj.queue_id))
|
||||
if not retry:
|
||||
phase = database.BUILD_PHASE.ERROR
|
||||
# If the phase is internal error, return 'expired' instead if the number of retries
|
||||
# on the queue item is 0.
|
||||
if phase == database.BUILD_PHASE.INTERNAL_ERROR:
|
||||
retry = (build_obj.queue_id and
|
||||
dockerfile_build_queue.has_retries_remaining(build_obj.queue_id))
|
||||
if not retry:
|
||||
phase = 'expired'
|
||||
|
||||
return (phase, status, error)
|
||||
|
||||
|
|
|
@ -7,11 +7,15 @@
|
|||
}
|
||||
|
||||
.build-state-icon .error {
|
||||
color: red;
|
||||
color: #D64456;
|
||||
}
|
||||
|
||||
.build-state-icon .expired {
|
||||
color: #FCA657;
|
||||
}
|
||||
|
||||
.build-state-icon .internalerror {
|
||||
color: #DFFF00;
|
||||
color: #99BA45;
|
||||
}
|
||||
|
||||
.build-state-icon .complete {
|
||||
|
|
38
static/css/directives/ui/build-status.css
Normal file
38
static/css/directives/ui/build-status.css
Normal file
|
@ -0,0 +1,38 @@
|
|||
.build-status {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.build-status-container {
|
||||
padding: 4px;
|
||||
margin-bottom: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
width: 350px;
|
||||
}
|
||||
|
||||
.build-status-container .build-message {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
font-size: 14px;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.build-status-container .progress {
|
||||
height: 10px;
|
||||
margin: 0px;
|
||||
margin-top: 10px;
|
||||
margin-left: 20px;
|
||||
width: 310px;
|
||||
}
|
||||
|
||||
.build-status-container .timing {
|
||||
margin-left: 20px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.build-status-container:last-child {
|
||||
margin-bottom: 0px;
|
||||
border-bottom: 0px solid white;
|
||||
}
|
48
static/css/directives/ui/phase-icon.css
Normal file
48
static/css/directives/ui/phase-icon.css
Normal file
|
@ -0,0 +1,48 @@
|
|||
.phase-icon {
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.active .build-tab-link .phase-icon {
|
||||
box-shadow: 0px 0px 10px #FFFFFF, 0px 0px 10px #FFFFFF;
|
||||
}
|
||||
|
||||
.build-status .phase-icon {
|
||||
margin-top: 4px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.phase-icon.error {
|
||||
background-color: #D64456;
|
||||
}
|
||||
|
||||
.phase-icon.expired {
|
||||
background-color: #FCA657;
|
||||
}
|
||||
|
||||
.phase-icon.internalerror {
|
||||
background-color: #99BA45;
|
||||
}
|
||||
|
||||
.phase-icon.waiting, .phase-icon.build-scheduled {
|
||||
background-color: rgba(66, 139, 202, 0.2);
|
||||
}
|
||||
|
||||
.phase-icon.unpacking, .phase-icon.starting, .phase-icon.initializing {
|
||||
background-color: rgba(66, 139, 202, 0.4);
|
||||
}
|
||||
|
||||
.phase-icon.pulling, .phase-icon.priming-cache, .phase-icon.checking-cache {
|
||||
background-color: rgba(66, 139, 202, 0.6);
|
||||
}
|
||||
|
||||
.phase-icon.pushing, .phase-icon.building {
|
||||
background-color: rgba(66, 139, 202, 0.8);
|
||||
}
|
||||
|
||||
.phase-icon.complete {
|
||||
background-color: #2fcc66;
|
||||
}
|
|
@ -565,90 +565,6 @@ i.toggle-icon:hover {
|
|||
border-bottom: 0px;
|
||||
}
|
||||
|
||||
.phase-icon {
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.active .build-tab-link .phase-icon {
|
||||
box-shadow: 0px 0px 10px #FFFFFF, 0px 0px 10px #FFFFFF;
|
||||
}
|
||||
|
||||
.build-status .phase-icon {
|
||||
margin-top: 4px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.phase-icon.error {
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
.phase-icon.internalerror {
|
||||
background-color: #DFFF00;
|
||||
}
|
||||
|
||||
.phase-icon.waiting, .phase-icon.build-scheduled {
|
||||
background-color: rgba(66, 139, 202, 0.2);
|
||||
}
|
||||
|
||||
.phase-icon.unpacking, .phase-icon.starting, .phase-icon.initializing {
|
||||
background-color: rgba(66, 139, 202, 0.4);
|
||||
}
|
||||
|
||||
.phase-icon.pulling, .phase-icon.priming-cache, .phase-icon.checking-cache {
|
||||
background-color: rgba(66, 139, 202, 0.6);
|
||||
}
|
||||
|
||||
.phase-icon.pushing, .phase-icon.building {
|
||||
background-color: rgba(66, 139, 202, 0.8);
|
||||
}
|
||||
|
||||
.phase-icon.complete {
|
||||
background-color: #2fcc66;
|
||||
}
|
||||
|
||||
.build-status {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.build-status-container {
|
||||
padding: 4px;
|
||||
margin-bottom: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
width: 350px;
|
||||
}
|
||||
|
||||
.build-status-container .build-message {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
font-size: 14px;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.build-status-container .progress {
|
||||
height: 10px;
|
||||
margin: 0px;
|
||||
margin-top: 10px;
|
||||
margin-left: 20px;
|
||||
width: 310px;
|
||||
}
|
||||
|
||||
.build-status-container .timing {
|
||||
margin-left: 20px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.build-status-container:last-child {
|
||||
margin-bottom: 0px;
|
||||
border-bottom: 0px solid white;
|
||||
}
|
||||
|
||||
.repo-circle {
|
||||
position: relative;
|
||||
background: #eee;
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
<span class="cor-loader"></span>
|
||||
</div>
|
||||
|
||||
<div ng-show="!loadError && !pollChannel.skipping">
|
||||
<div ng-show="!loadError && !pollChannel.skipping && currentBuild.phase != 'expired'">
|
||||
<span class="no-logs" ng-if="!logEntries.length && currentBuild.phase == 'waiting'">
|
||||
(Waiting for build to start)
|
||||
</span>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
<span ng-if="!isBuilding(build)">
|
||||
<i class="fa fa-check-circle" ng-if="build.phase == 'complete'"></i>
|
||||
<i class="fa fa-times-circle" ng-if="build.phase == 'error'"></i>
|
||||
<i class="fa fa-exclamation-circle" ng-if="build.phase == 'expired'"></i>
|
||||
<i class="fa fa-exclamation-circle" ng-if="build.phase == 'internalerror'"></i>
|
||||
</span>
|
||||
</span>
|
||||
|
|
|
@ -11,49 +11,9 @@ angular.module('quay').directive('buildMessage', function () {
|
|||
scope: {
|
||||
'phase': '=phase'
|
||||
},
|
||||
controller: function($scope, $element) {
|
||||
controller: function($scope, $element, BuildService) {
|
||||
$scope.getBuildMessage = function (phase) {
|
||||
switch (phase) {
|
||||
case 'cannot_load':
|
||||
return 'Cannot load build status';
|
||||
|
||||
case 'starting':
|
||||
case 'initializing':
|
||||
return 'Starting Dockerfile build';
|
||||
|
||||
case 'waiting':
|
||||
return 'Waiting for available build worker';
|
||||
|
||||
case 'unpacking':
|
||||
return 'Unpacking build package';
|
||||
|
||||
case 'pulling':
|
||||
return 'Pulling base image';
|
||||
|
||||
case 'building':
|
||||
return 'Building image from Dockerfile';
|
||||
|
||||
case 'checking-cache':
|
||||
return 'Looking up cached images';
|
||||
|
||||
case 'priming-cache':
|
||||
return 'Priming cache for build';
|
||||
|
||||
case 'build-scheduled':
|
||||
return 'Preparing build node';
|
||||
|
||||
case 'pushing':
|
||||
return 'Pushing image built from Dockerfile';
|
||||
|
||||
case 'complete':
|
||||
return 'Dockerfile build completed and pushed';
|
||||
|
||||
case 'error':
|
||||
return 'Dockerfile build failed';
|
||||
|
||||
case 'internalerror':
|
||||
return 'An internal system error occurred while building; the build will be retried in the next few minutes.';
|
||||
}
|
||||
return BuildService.getBuildMessage(phase);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -11,10 +11,10 @@ angular.module('quay').directive('buildStateIcon', function () {
|
|||
scope: {
|
||||
'build': '=build'
|
||||
},
|
||||
controller: function($scope, $element) {
|
||||
controller: function($scope, $element, BuildService) {
|
||||
$scope.isBuilding = function(build) {
|
||||
if (!build) { return true; }
|
||||
return build.phase != 'complete' && build.phase != 'error';
|
||||
return BuildService.isActive(build);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -66,10 +66,5 @@
|
|||
$scope.setUpdatedBuild = function(build) {
|
||||
$scope.build = build;
|
||||
};
|
||||
|
||||
$scope.isBuilding = function(build) {
|
||||
if (!build) { return true; }
|
||||
return build.phase != 'complete' && build.phase != 'error' && build.phase != 'internalerror';
|
||||
};
|
||||
}
|
||||
})();
|
||||
|
|
58
static/js/services/build-service.js
Normal file
58
static/js/services/build-service.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* Service which provides helper methods for reasoning about builds.
|
||||
*/
|
||||
angular.module('quay').factory('BuildService', [function() {
|
||||
var buildService = {}
|
||||
buildService.isActive = function(build) {
|
||||
return build.phase != 'complete' && build.phase != 'error' && build.phase != 'expired';
|
||||
};
|
||||
|
||||
buildService.getBuildMessage = function(phase) {
|
||||
switch (phase) {
|
||||
case 'cannot_load':
|
||||
return 'Cannot load build status';
|
||||
|
||||
case 'starting':
|
||||
case 'initializing':
|
||||
return 'Starting Dockerfile build';
|
||||
|
||||
case 'waiting':
|
||||
return 'Waiting for available build worker';
|
||||
|
||||
case 'unpacking':
|
||||
return 'Unpacking build package';
|
||||
|
||||
case 'pulling':
|
||||
return 'Pulling base image';
|
||||
|
||||
case 'building':
|
||||
return 'Building image from Dockerfile';
|
||||
|
||||
case 'checking-cache':
|
||||
return 'Looking up cached images';
|
||||
|
||||
case 'priming-cache':
|
||||
return 'Priming cache for build';
|
||||
|
||||
case 'build-scheduled':
|
||||
return 'Preparing build node';
|
||||
|
||||
case 'pushing':
|
||||
return 'Pushing image built from Dockerfile';
|
||||
|
||||
case 'complete':
|
||||
return 'Dockerfile build completed and pushed';
|
||||
|
||||
case 'error':
|
||||
return 'Dockerfile build failed';
|
||||
|
||||
case 'expired':
|
||||
return 'Build did not complete after 3 attempts. Re-submit this build to try again.';
|
||||
|
||||
case 'internalerror':
|
||||
return 'An internal system error occurred while building; the build will be retried in the next few minutes.';
|
||||
}
|
||||
};
|
||||
|
||||
return buildService;
|
||||
}]);
|
|
@ -28,12 +28,7 @@
|
|||
<!-- Current Status -->
|
||||
<div class="build-status-header" ng-show="!originalBuild.error">
|
||||
<span class="build-icon-message" ng-class="build.phase">
|
||||
<span class="cor-loader-inline" ng-if="isBuilding(build)"></span>
|
||||
<span ng-if="!isBuilding(build)">
|
||||
<i class="fa fa-check-circle" ng-if="build.phase == 'complete'"></i>
|
||||
<i class="fa fa-times-circle" ng-if="build.phase == 'error'"></i>
|
||||
<i class="fa fa-exclamation-circle" ng-if="build.phase == 'internalerror'"></i>
|
||||
</span>
|
||||
<span class="build-state-icon" build="build"></span>
|
||||
<span class="build-message" phase="build.phase"></span>
|
||||
</span>
|
||||
|
||||
|
|
Reference in a new issue