Adding in UI for cancel anytime.

This commit is contained in:
Charlton Austin 2016-11-16 13:51:07 -05:00
parent f6fe9023a4
commit 2fe74e4057
11 changed files with 31 additions and 25 deletions

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="123" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><mask id="a"><rect width="123" height="20" rx="3" fill="#fff"/></mask><g mask="url(#a)"><path fill="#555" d="M0 0h63v20H0z"/><path fill="#9f9f9f" d="M63 0h60v20H63z"/><path fill="url(#b)" d="M0 0h123v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"><text x="32.5" y="15" fill="#010101" fill-opacity=".3">container</text><text x="32.5" y="14">container</text><text x="92" y="15" fill="#010101" fill-opacity=".3">cancelled</text><text x="92" y="14">cancelled</text></g></svg>

After

Width:  |  Height:  |  Size: 751 B

View file

@ -128,7 +128,7 @@ class DefaultConfig(object):
# Status tag config # Status tag config
STATUS_TAGS = {} STATUS_TAGS = {}
for tag_name in ['building', 'failed', 'none', 'ready']: for tag_name in ['building', 'failed', 'none', 'ready', 'cancelled']:
tag_path = os.path.join('buildstatus', tag_name + '.svg') tag_path = os.path.join('buildstatus', tag_name + '.svg')
with open(tag_path) as tag_svg: with open(tag_path) as tag_svg:
STATUS_TAGS[tag_name] = tag_svg.read() STATUS_TAGS[tag_name] = tag_svg.read()

View file

@ -13,6 +13,7 @@ PRESUMED_DEAD_BUILD_AGE = timedelta(days=15)
PHASES_NOT_ALLOWED_TO_CANCEL_FROM = (BUILD_PHASE.PUSHING, BUILD_PHASE.COMPLETE, PHASES_NOT_ALLOWED_TO_CANCEL_FROM = (BUILD_PHASE.PUSHING, BUILD_PHASE.COMPLETE,
BUILD_PHASE.ERROR, BUILD_PHASE.INTERNAL_ERROR) BUILD_PHASE.ERROR, BUILD_PHASE.INTERNAL_ERROR)
ARCHIVABLE_BUILD_PHASES = [BUILD_PHASE.COMPLETE, BUILD_PHASE.ERROR, BUILD_PHASE.CANCELLED]
def update_build_trigger(trigger, config, auth_token=None): def update_build_trigger(trigger, config, auth_token=None):
trigger.config = json.dumps(config or {}) trigger.config = json.dumps(config or {})
@ -184,19 +185,11 @@ def create_cancel_build_in_queue(build, build_queue):
def create_cancel_build_in_manager(build, build_canceller): def create_cancel_build_in_manager(build, build_canceller):
""" A function to cancel the build before it starts to push """ """ A function to cancel the build before it starts to push """
def cancel_build(): def cancel_build():
original_phase = build.phase
if build.phase in PHASES_NOT_ALLOWED_TO_CANCEL_FROM: if build.phase in PHASES_NOT_ALLOWED_TO_CANCEL_FROM:
return False return False
build.phase = BUILD_PHASE.CANCELLED return build_canceller.try_cancel_build(build.uuid)
build.save()
if not build_canceller.try_cancel_build(build.uuid):
build.phase = original_phase
build.save()
return False
return True
return cancel_build return cancel_build
@ -213,22 +206,23 @@ def cancel_repository_build(build, build_queue):
cancel_builds = [create_cancel_build_in_queue(build, build_queue), cancel_builds = [create_cancel_build_in_queue(build, build_queue),
create_cancel_build_in_manager(build, build_canceller), ] create_cancel_build_in_manager(build, build_canceller), ]
original_phase = build.phase
for cancelled in cancel_builds: for cancelled in cancel_builds:
if cancelled(): if cancelled():
# Delete the build row. build.phase = BUILD_PHASE.CANCELLED
# TODO Charlie 2016-11-11 Add in message that says build was cancelled and remove the delete build. build.save()
build.delete_instance()
return True return True
build.phase = original_phase
build.save()
return False return False
def get_archivable_build(): def get_archivable_build():
presumed_dead_date = datetime.utcnow() - PRESUMED_DEAD_BUILD_AGE presumed_dead_date = datetime.utcnow() - PRESUMED_DEAD_BUILD_AGE
candidates = (RepositoryBuild candidates = (RepositoryBuild
.select(RepositoryBuild.id) .select(RepositoryBuild.id)
.where((RepositoryBuild.phase == BUILD_PHASE.COMPLETE) | .where((RepositoryBuild.phase << ARCHIVABLE_BUILD_PHASES) |
(RepositoryBuild.phase == BUILD_PHASE.ERROR) |
(RepositoryBuild.started < presumed_dead_date), (RepositoryBuild.started < presumed_dead_date),
RepositoryBuild.logs_archived == False) RepositoryBuild.logs_archived == False)
.limit(50) .limit(50)

View file

@ -318,7 +318,7 @@ class RepositoryBuildResource(RepositoryParamResource):
@require_repo_admin @require_repo_admin
@nickname('cancelRepoBuild') @nickname('cancelRepoBuild')
def delete(self, namespace, repository, build_uuid): def delete(self, namespace, repository, build_uuid):
""" Cancels a repository build if it has not yet been picked up by a build worker. """ """ Cancels a repository build. """
try: try:
build = model.build.get_repository_build(build_uuid) build = model.build.get_repository_build(build_uuid)
except model.build.InvalidRepositoryBuildException: except model.build.InvalidRepositoryBuildException:

View file

@ -440,6 +440,8 @@ def build_status_badge(namespace_name, repo_name):
status_name = 'ready' status_name = 'ready'
elif recent_build and recent_build.phase == 'error': elif recent_build and recent_build.phase == 'error':
status_name = 'failed' status_name = 'failed'
elif recent_build and recent_build.phase == 'cancelled':
status_name = 'cancelled'
elif recent_build and recent_build.phase != 'complete': elif recent_build and recent_build.phase != 'complete':
status_name = 'building' status_name = 'building'
else: else:

View file

@ -20,4 +20,8 @@
.build-state-icon .complete { .build-state-icon .complete {
color: #2fcc66; color: #2fcc66;
} }
.build-state-icon .cancelled {
color: #9b9b9b;
}

View file

@ -5,5 +5,6 @@
<i class="fa fa-times-circle" ng-if="build.phase == 'error'"></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 == 'expired'"></i>
<i class="fa fa-exclamation-circle" ng-if="build.phase == 'internalerror'"></i> <i class="fa fa-exclamation-circle" ng-if="build.phase == 'internalerror'"></i>
<i class="fa fa-minus-circle" ng-if="build.phase == 'cancelled'"></i>
</span> </span>
</span> </span>

View file

@ -12,10 +12,10 @@ angular.module('quay').directive('buildMiniStatus', function () {
'build': '=build', 'build': '=build',
'isAdmin': '=isAdmin' 'isAdmin': '=isAdmin'
}, },
controller: function($scope, $element) { controller: function($scope, $element, BuildService) {
$scope.isBuilding = function(build) { $scope.isBuilding = function(build) {
if (!build) { return true; } if (!build) { return true; }
return build.phase != 'complete' && build.phase != 'error'; return BuildService.isActive(build)
}; };
} }
}; };

View file

@ -2,9 +2,9 @@
* Service which provides helper methods for reasoning about builds. * Service which provides helper methods for reasoning about builds.
*/ */
angular.module('quay').factory('BuildService', [function() { angular.module('quay').factory('BuildService', [function() {
var buildService = {} var buildService = {};
buildService.isActive = function(build) { buildService.isActive = function(build) {
return build.phase != 'complete' && build.phase != 'error' && build.phase != 'expired'; return build.phase != 'complete' && build.phase != 'error' && build.phase != 'expired' && build.phase != 'cancelled';
}; };
buildService.getBuildMessage = function(phase) { buildService.getBuildMessage = function(phase) {
@ -51,6 +51,10 @@ angular.module('quay').factory('BuildService', [function() {
case 'internalerror': case 'internalerror':
return 'An internal system error occurred while building; the build will be retried in the next few minutes.'; return 'An internal system error occurred while building; the build will be retried in the next few minutes.';
case 'cancelled':
return 'This build was previously cancelled.';
} }
}; };

View file

@ -41,8 +41,7 @@
<i class="fa fa-clock-o"></i> Show Timestamps <i class="fa fa-clock-o"></i> Show Timestamps
</span> </span>
</span> </span>
<span class="cor-option" option-click="askCancelBuild(build)" <span class="cor-option" option-click="askCancelBuild(build)">
ng-if="build.phase == 'waiting'">
<i class="fa fa-times"></i> Cancel Build <i class="fa fa-times"></i> Cancel Build
</span> </span>
</span> </span>

View file

@ -2191,7 +2191,8 @@ class TestRepositoryBuildResource(ApiTestCase):
json = self.getJsonResponse(RepositoryBuildList, json = self.getJsonResponse(RepositoryBuildList,
params=dict(repository=ADMIN_ACCESS_USER + '/simple')) params=dict(repository=ADMIN_ACCESS_USER + '/simple'))
self.assertEquals(0, len(json['builds'])) self.assertEquals(1, len(json['builds']))
self.assertEquals('cancelled', json['builds'][0]['phase'])
# Check for the build's queue item. # Check for the build's queue item.
try: try: