diff --git a/buildstatus/cancelled.svg b/buildstatus/cancelled.svg new file mode 100644 index 000000000..0e565cf97 --- /dev/null +++ b/buildstatus/cancelled.svg @@ -0,0 +1 @@ +containercontainercancelledcancelled diff --git a/config.py b/config.py index 42b6aa491..dc647cd30 100644 --- a/config.py +++ b/config.py @@ -128,7 +128,7 @@ class DefaultConfig(object): # Status tag config 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') with open(tag_path) as tag_svg: STATUS_TAGS[tag_name] = tag_svg.read() diff --git a/data/model/build.py b/data/model/build.py index 13e727edc..90b3d8bb1 100644 --- a/data/model/build.py +++ b/data/model/build.py @@ -13,6 +13,7 @@ PRESUMED_DEAD_BUILD_AGE = timedelta(days=15) PHASES_NOT_ALLOWED_TO_CANCEL_FROM = (BUILD_PHASE.PUSHING, BUILD_PHASE.COMPLETE, 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): 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): """ A function to cancel the build before it starts to push """ def cancel_build(): - original_phase = build.phase if build.phase in PHASES_NOT_ALLOWED_TO_CANCEL_FROM: return False - build.phase = BUILD_PHASE.CANCELLED - build.save() + return build_canceller.try_cancel_build(build.uuid) - if not build_canceller.try_cancel_build(build.uuid): - build.phase = original_phase - build.save() - return False - - return True return cancel_build @@ -213,22 +206,23 @@ def cancel_repository_build(build, build_queue): cancel_builds = [create_cancel_build_in_queue(build, build_queue), create_cancel_build_in_manager(build, build_canceller), ] + original_phase = build.phase for cancelled in cancel_builds: if cancelled(): - # Delete the build row. - # TODO Charlie 2016-11-11 Add in message that says build was cancelled and remove the delete build. - build.delete_instance() + build.phase = BUILD_PHASE.CANCELLED + build.save() return True - + build.phase = original_phase + build.save() return False def get_archivable_build(): presumed_dead_date = datetime.utcnow() - PRESUMED_DEAD_BUILD_AGE + candidates = (RepositoryBuild .select(RepositoryBuild.id) - .where((RepositoryBuild.phase == BUILD_PHASE.COMPLETE) | - (RepositoryBuild.phase == BUILD_PHASE.ERROR) | + .where((RepositoryBuild.phase << ARCHIVABLE_BUILD_PHASES) | (RepositoryBuild.started < presumed_dead_date), RepositoryBuild.logs_archived == False) .limit(50) diff --git a/endpoints/api/build.py b/endpoints/api/build.py index cac1fdea1..7efedc993 100644 --- a/endpoints/api/build.py +++ b/endpoints/api/build.py @@ -318,7 +318,7 @@ class RepositoryBuildResource(RepositoryParamResource): @require_repo_admin @nickname('cancelRepoBuild') 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: build = model.build.get_repository_build(build_uuid) except model.build.InvalidRepositoryBuildException: diff --git a/endpoints/web.py b/endpoints/web.py index 4b7b2b65f..f08efd800 100644 --- a/endpoints/web.py +++ b/endpoints/web.py @@ -440,6 +440,8 @@ def build_status_badge(namespace_name, repo_name): status_name = 'ready' elif recent_build and recent_build.phase == 'error': status_name = 'failed' + elif recent_build and recent_build.phase == 'cancelled': + status_name = 'cancelled' elif recent_build and recent_build.phase != 'complete': status_name = 'building' else: diff --git a/static/css/directives/ui/build-state-icon.css b/static/css/directives/ui/build-state-icon.css index 125b0723e..acf9a8dd3 100644 --- a/static/css/directives/ui/build-state-icon.css +++ b/static/css/directives/ui/build-state-icon.css @@ -20,4 +20,8 @@ .build-state-icon .complete { color: #2fcc66; -} \ No newline at end of file +} + +.build-state-icon .cancelled { + color: #9b9b9b; +} diff --git a/static/directives/build-state-icon.html b/static/directives/build-state-icon.html index f0408f339..bcc251269 100644 --- a/static/directives/build-state-icon.html +++ b/static/directives/build-state-icon.html @@ -5,5 +5,6 @@ + diff --git a/static/js/directives/ui/build-mini-status.js b/static/js/directives/ui/build-mini-status.js index a6698bd74..c48d7ea21 100644 --- a/static/js/directives/ui/build-mini-status.js +++ b/static/js/directives/ui/build-mini-status.js @@ -12,10 +12,10 @@ angular.module('quay').directive('buildMiniStatus', function () { 'build': '=build', 'isAdmin': '=isAdmin' }, - 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) }; } }; diff --git a/static/js/services/build-service.js b/static/js/services/build-service.js index 280419b06..0f68edec2 100644 --- a/static/js/services/build-service.js +++ b/static/js/services/build-service.js @@ -2,9 +2,9 @@ * Service which provides helper methods for reasoning about builds. */ angular.module('quay').factory('BuildService', [function() { - var buildService = {} + var buildService = {}; 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) { @@ -51,6 +51,10 @@ angular.module('quay').factory('BuildService', [function() { case 'internalerror': 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.'; + } }; diff --git a/static/partials/build-view.html b/static/partials/build-view.html index 2fbf99750..3b379c691 100644 --- a/static/partials/build-view.html +++ b/static/partials/build-view.html @@ -41,8 +41,7 @@ Show Timestamps - + Cancel Build diff --git a/test/test_api_usage.py b/test/test_api_usage.py index bde1f3175..b356049a9 100644 --- a/test/test_api_usage.py +++ b/test/test_api_usage.py @@ -2191,7 +2191,8 @@ class TestRepositoryBuildResource(ApiTestCase): json = self.getJsonResponse(RepositoryBuildList, 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. try: