From e6a6f46e26cf0702689a276d7174126de77e4478 Mon Sep 17 00:00:00 2001 From: Victor Seva Date: Wed, 11 Mar 2020 14:04:31 +0100 Subject: [PATCH] TT#43813 build: support resume from panel * move build_resume logic to a task * move build_resume logic tests to test_task Change-Id: I6eafc2d0af14174cce7c96fa35998b63d6545f47 --- build/fixtures/test_models.json | 4 +- build/models/__init__.py | 28 +--- build/models/br.py | 16 +- build/tasks.py | 35 +++++ build/test/test_models.py | 200 +++++++----------------- build/test/test_rest.py | 8 +- build/test/test_tasks.py | 149 ++++++++++++++++++ build/views.py | 8 +- panel/static/panel/js/panel_release.js | 55 +++++++ panel/templates/panel/release_info.html | 10 +- 10 files changed, 333 insertions(+), 180 deletions(-) create mode 100644 build/test/test_tasks.py diff --git a/build/fixtures/test_models.json b/build/fixtures/test_models.json index 6989732..afe52e2 100644 --- a/build/fixtures/test_models.json +++ b/build/fixtures/test_models.json @@ -23,8 +23,8 @@ "branch": "mr8.1", "release": "release-mr8.1", "distribution": "buster", - "projects": "kamailio,lua-ngcp-kamailio,ngcp-panel", - "built_projects": "kamailio,lua-ngcp-kamailio" + "projects": "asterisk-voicemail,lua-ngcp-kamailio,ngcp-panel", + "built_projects": null } } ] diff --git a/build/models/__init__.py b/build/models/__init__.py index 474687c..8c7afd1 100644 --- a/build/models/__init__.py +++ b/build/models/__init__.py @@ -19,7 +19,7 @@ from django.db.models import signals from .br import BuildRelease from build.tasks import build_release -from build.utils import trigger_build +from build.tasks import build_resume from repoapi.models import JenkinsBuildInfo logger = logging.getLogger(__name__) @@ -66,31 +66,7 @@ def jbi_manage(sender, **kwargs): logger.debug("BuildRelease:%s jbi:%s skip", br, jbi) return br.remove_triggered(jbi) - params = { - "release_uuid": br.uuid, - "trigger_release": br.release, - "trigger_branch_or_tag": br.branch_or_tag, - "trigger_distribution": br.distribution, - } - size = settings.BUILD_POOL - br.pool_size - if size <= 0: - logger.info( - "BuildRelease:%s No more room for new builds," - " wait for next slot", - br, - ) - for step in range(size): - prj = br.next - if prj: - params["project"] = "{}-get-code".format(prj) - logger.debug( - "trigger:%s for BuildRelease:%s", params["project"], br - ) - trigger_build(**params) - br.append_triggered(prj) - else: - logger.debug("BuildRelease:%s has no next", br) - break + build_resume.delay(br.id) post_save = signals.post_save.connect diff --git a/build/models/br.py b/build/models/br.py index d3b5182..d72fca4 100644 --- a/build/models/br.py +++ b/build/models/br.py @@ -96,6 +96,7 @@ class BuildRelease(models.Model): failed_projects = models.TextField(null=True, editable=False) pool_size = models.SmallIntegerField(default=0, editable=False) objects = BuildReleaseManager() + release_jobs_len = len(",".join(settings.RELEASE_JOBS)) def __str__(self): return "%s[%s]" % (self.release, self.uuid) @@ -104,6 +105,17 @@ class BuildRelease(models.Model): self.projects = ",".join(self.config.projects) self.save() + def resume(self): + if not self.done: + from build.tasks import build_resume + + build_resume.delay(self.id) + + @property + def done(self): + built_len = len(self.built_projects) + return built_len == self.release_jobs_len + 1 + len(self.projects) + @property def projects_list(self): return [x.strip() for x in self.projects.split(",")] @@ -207,9 +219,7 @@ class BuildRelease(models.Model): def _next(self): if self.built_projects is None: return self.build_deps[0][0] - built_len = len(self.built_projects) - release_jobs_len = len(",".join(settings.RELEASE_JOBS)) - if built_len == release_jobs_len + 1 + len(self.projects): + if self.done: return t_list = self.triggered_projects_list built_list = self.built_projects_list diff --git a/build/tasks.py b/build/tasks.py index 8101ff3..aba2b70 100644 --- a/build/tasks.py +++ b/build/tasks.py @@ -15,6 +15,7 @@ import logging from celery import shared_task +from django.conf import settings from build.models.br import BuildRelease from build.utils import trigger_build @@ -55,3 +56,37 @@ def build_project(pk, project): ) br.pool_size += 1 logger.info("%s triggered" % url) + + +@shared_task(ignore_result=True) +def build_resume(pk): + try: + br = BuildRelease.objects.get(id=pk) + except BuildRelease.DoesNotExist: + logger.error("can't resume on unknown release with id:%s", pk) + return + params = { + "release_uuid": br.uuid, + "trigger_release": br.release, + "trigger_branch_or_tag": br.branch_or_tag, + "trigger_distribution": br.distribution, + } + size = settings.BUILD_POOL - br.pool_size + if size <= 0: + logger.info( + "BuildRelease:%s No more room for new builds," + " wait for next slot", + br, + ) + for step in range(size): + prj = br.next + if prj: + params["project"] = "{}-get-code".format(prj) + logger.debug( + "trigger:%s for BuildRelease:%s", params["project"], br + ) + trigger_build(**params) + br.append_triggered(prj) + else: + logger.debug("BuildRelease:%s has no next", br) + break diff --git a/build/test/test_models.py b/build/test/test_models.py index 6d860e1..8f5a274 100644 --- a/build/test/test_models.py +++ b/build/test/test_models.py @@ -12,7 +12,6 @@ # # You should have received a copy of the GNU General Public License along # with this program. If not, see . -from unittest.mock import call from unittest.mock import MagicMock from unittest.mock import patch @@ -20,7 +19,6 @@ from django.test import override_settings from django.test import TestCase from build.models import BuildRelease -from build.models import jbi_manage from repoapi.models import JenkinsBuildInfo from repoapi.test.base import BaseTest @@ -140,8 +138,14 @@ class BuildReleaseTestCase(TestCase): @override_settings(DEBUG=True) class BuildReleaseStepsTest(TestCase): + fixtures = [ + "test_models", + ] + release = "release-mr8.1" + release_uuid = "dbe569f7-eab6-4532-a6d1-d31fb559648b" + def setUp(self): - self.br = BuildRelease.objects.create_build_release("AAA", "trunk") + self.br = BuildRelease.objects.get(uuid=self.release_uuid) self.br.pool_size = 1 self.jbi = MagicMock() self.jbi.result = "SUCCESS" @@ -296,17 +300,18 @@ class BuildReleaseStepsTest(TestCase): self.assertIsNone(self.br.next) -@override_settings( - DEBUG=True, - JBI_ALLOWED_HOSTS=["fake.local"], - CELERY_EAGER_PROPAGATES_EXCEPTIONS=True, -) +@override_settings(DEBUG=True, JBI_ALLOWED_HOSTS=["fake.local"]) @patch("repoapi.utils.dlfile") +@patch("build.models.build_resume") class JBIManageTest(TestCase): - @patch("build.models.trigger_build") - def test_jbi_manage_ko(self, tb, dl): - BuildRelease.objects.create_build_release("AAA", "trunk") - jbi = JenkinsBuildInfo.objects.create( + fixtures = [ + "test_models", + ] + release = "release-mr8.1" + release_uuid = "dbe569f7-eab6-4532-a6d1-d31fb559648b" + + def test_jbi_manage_ko(self, build_resume, dl): + JenkinsBuildInfo.objects.create( job_url="http://fake.local/job/release-copy-debs-yml/", projectname="release-copy-debs-yml", jobname="release-copy-debs-yml", @@ -316,173 +321,82 @@ class JBIManageTest(TestCase): buildnumber=1, result="SUCCESS", ) - params = {"instance": jbi, "created": True} - jbi_manage(JenkinsBuildInfo, **params) - tb.assert_not_called() + build_resume.delay.assert_not_called() - @patch("build.models.trigger_build") - def test_jbi_manage_ok_release_job(self, tb, dl): - br = BuildRelease.objects.create_build_release("UUID_mr8.1", "mr8.1") + def test_jbi_manage_ko_url(self, build_resume, dl): + JenkinsBuildInfo.objects.create( + job_url="http://other.local/job/release-copy-debs-yml/", + projectname="release-copy-debs-yml", + jobname="release-copy-debs-yml", + param_tag="UUIDA", + param_release=self.release, + param_release_uuid=self.release_uuid, + buildnumber=1, + result="SUCCESS", + ) + build_resume.delay.assert_not_called() + + def test_jbi_manage_ok_release_job(self, build_resume, dl): + br = BuildRelease.objects.get(uuid=self.release_uuid) self.assertEqual(br.pool_size, 0) JenkinsBuildInfo.objects.create( job_url="http://fake.local/job/release-copy-debs-yml/", projectname="release-copy-debs-yml", jobname="release-copy-debs-yml", tag="UUIDA", - param_release="mr8.1", - param_release_uuid="UUID_mr8.1", + param_release=self.release, + param_release_uuid=self.release_uuid, buildnumber=1, result="SUCCESS", ) br = BuildRelease.objects.get(pk=br.pk) self.assertEqual(br.built_projects, "release-copy-debs-yml") - params = { - "project": "data-hal-get-code", - "release_uuid": br.uuid, - "trigger_release": br.release, - "trigger_branch_or_tag": br.branch_or_tag, - "trigger_distribution": br.distribution, - } - tb.assert_called_once_with(**params) - self.assertEqual(br.pool_size, 1) - self.assertEqual(br.triggered_projects, "data-hal") + build_resume.delay.assert_called_once_with(br.pk) - @patch("build.models.trigger_build") - def test_jbi_manage_skip(self, tb, dl): - br = BuildRelease.objects.create_build_release("UUID_mr8.1", "mr8.1") + def test_jbi_manage_skip(self, build_resume, dl): + br = BuildRelease.objects.get(uuid=self.release_uuid) br.pool_size = 1 br.triggered_projects = "kamailio" br.save() - jbi = JenkinsBuildInfo.objects.create( - job_url="http://fake.local/job/kamailio-get-code/", + JenkinsBuildInfo.objects.create( + job_url="http://fake.local/job/kamailio-binaries/", projectname="kamailio", - jobname="kamailio-get-code", + jobname="kamailio-binaries", tag="UUIDA", - param_release="mr8.1", - param_release_uuid="UUID_mr8.1", + param_release=self.release, + param_release_uuid=self.release_uuid, buildnumber=1, result="SUCCESS", ) br = BuildRelease.objects.get(pk=br.pk) self.assertIsNone(br.built_projects) - params = {"instance": jbi, "created": True} - jbi_manage(JenkinsBuildInfo, **params) - tb.assert_not_called() + build_resume.delay.assert_not_called() self.assertEqual(br.pool_size, 1) self.assertEqual(br.triggered_projects, "kamailio") - @override_settings(BUILD_POOL=2) - @patch("build.models.trigger_build") - def test_jbi_manage_pool(self, tb, dl): - br = BuildRelease.objects.create_build_release("UUID_mr8.1", "mr8.1") - self.assertEqual(br.pool_size, 0) - JenkinsBuildInfo.objects.create( - job_url="http://fake.local/job/release-copy-debs-yml/", - projectname="release-copy-debs-yml", - jobname="release-copy-debs-yml", - tag="UUIDA", - param_release="mr8.1", - param_release_uuid="UUID_mr8.1", - buildnumber=1, - result="SUCCESS", - ) - br = BuildRelease.objects.get(pk=br.pk) - self.assertEqual(br.built_projects, "release-copy-debs-yml") - params = { - "project": "data-hal-get-code", - "release_uuid": br.uuid, - "trigger_release": br.release, - "trigger_branch_or_tag": br.branch_or_tag, - "trigger_distribution": br.distribution, - } - calls = [call(**params)] - params["project"] = "libinewrate-get-code" - calls.append(call(**params)) - tb.assert_has_calls(calls) - self.assertEqual(br.pool_size, 2) - self.assertEqual(br.triggered_projects, "data-hal,libinewrate") - - @override_settings(BUILD_POOL=2) - @patch("build.models.trigger_build") - def test_jbi_manage_pool_building(self, tb, dl): - self.test_jbi_manage_pool() - br = BuildRelease.objects.first() - self.assertEqual(br.pool_size, 2) - JenkinsBuildInfo.objects.create( - job_url="http://fake.local/job/data-hal-binaries/", - projectname="data-hal", - jobname="data-hal-binaries", - tag="UUIDA", - param_release="release-mr8.1", - param_release_uuid="UUID_mr8.1", - buildnumber=1, - result="SUCCESS", - ) - br = BuildRelease.objects.first() - self.assertEqual(br.pool_size, 2) - self.assertEqual(br.triggered_projects, "data-hal,libinewrate") - JenkinsBuildInfo.objects.create( - job_url="http://fake.local/job/libinewrate-binaries/", - projectname="libinewrate", - jobname="libinewrate-binaries", - tag="UUIDA", - param_release="release-mr8.1", - param_release_uuid="UUID_mr8.1", - buildnumber=1, - result="SUCCESS", - ) - br = BuildRelease.objects.first() - self.assertEqual(br.pool_size, 2) - self.assertEqual(br.triggered_projects, "data-hal,libinewrate") - - @override_settings(BUILD_POOL=2) - @patch("build.models.trigger_build") - def test_jbi_manage_pool_next(self, tb, dl): - self.test_jbi_manage_pool() - br = BuildRelease.objects.first() - self.assertEqual(br.pool_size, 2) - JenkinsBuildInfo.objects.create( - job_url="http://fake.local/job/data-hal-repos/", - projectname="data-hal", - jobname="data-hal-repos", - tag="UUIDA", - param_release="release-mr8.1", - param_release_uuid="UUID_mr8.1", - buildnumber=1, - result="SUCCESS", - ) - br = BuildRelease.objects.get(pk=br.pk) - self.assertEqual(br.built_projects, "release-copy-debs-yml,data-hal") - params = { - "project": "libswrate-get-code", - "release_uuid": br.uuid, - "trigger_release": br.release, - "trigger_branch_or_tag": br.branch_or_tag, - "trigger_distribution": br.distribution, - } - tb.assert_called_once_with(**params) - self.assertEqual(br.pool_size, 2) - self.assertEqual(br.triggered_projects, "libinewrate,libswrate") - - -@override_settings( - DEBUG=True, CELERY_EAGER_PROPAGATES_EXCEPTIONS=True, -) + +@override_settings(DEBUG=True) class BRManageTest(TestCase): @patch("build.tasks.trigger_copy_deps") - @patch("build.models.trigger_build") - def test_br_manage(self, tb, rb): + @patch("build.models.build_resume") + def test_br_manage(self, build_resume, trigger_copy_deps): br = BuildRelease.objects.create_build_release("UUID_mr8.1", "mr8.1") - tb.assert_not_called() - rb.assert_called_once_with( + build_resume.delay.assert_not_called() + trigger_copy_deps.assert_called_once_with( internal=True, release=br.release, release_uuid=br.uuid ) @override_settings(DEBUG=True) class BuildReleaseRetriggerTest(TestCase): + fixtures = [ + "test_models", + ] + release = "release-mr8.1" + release_uuid = "dbe569f7-eab6-4532-a6d1-d31fb559648b" + def setUp(self): - self.br = BuildRelease.objects.create_build_release("AAA", "trunk") + self.br = BuildRelease.objects.get(uuid=self.release_uuid) self.jbi = MagicMock() self.jbi.result = "SUCCESS" diff --git a/build/test/test_rest.py b/build/test/test_rest.py index 943bab6..57186ce 100644 --- a/build/test/test_rest.py +++ b/build/test/test_rest.py @@ -35,7 +35,7 @@ class APIAuthenticatedTestCase(BaseTest, APITestCase): self.client.credentials(HTTP_API_KEY=self.app_key.key) -@override_settings(DEBUG=True) +@override_settings(DEBUG=True, JBI_ALLOWED_HOSTS=["fake.local"]) class TestRest(APIAuthenticatedTestCase): def setUp(self): super(TestRest, self).setUp() @@ -103,7 +103,7 @@ class TestRest(APIAuthenticatedTestCase): self.assertEqual(len(projects), 75) -@override_settings(DEBUG=True) +@override_settings(DEBUG=True, JBI_ALLOWED_HOSTS=["fake.local"]) class TestBuildRest(APIAuthenticatedTestCase): fixtures = [ "test_models", @@ -120,7 +120,7 @@ class TestBuildRest(APIAuthenticatedTestCase): self.assertEqual(response.status_code, status.HTTP_201_CREATED) -@override_settings(DEBUG=True) +@override_settings(DEBUG=True, JBI_ALLOWED_HOSTS=["fake.local"]) class TestBuildDeleteRest(APIAuthenticatedTestCase): fixtures = [ "test_models", @@ -184,7 +184,7 @@ class TestBuildDeleteRest(APIAuthenticatedTestCase): ) -@override_settings(DEBUG=True) +@override_settings(DEBUG=True, JBI_ALLOWED_HOSTS=["fake.local"]) class TestBuildPatchRest(APIAuthenticatedTestCase): fixtures = [ "test_models", diff --git a/build/test/test_tasks.py b/build/test/test_tasks.py new file mode 100644 index 0000000..4c93c62 --- /dev/null +++ b/build/test/test_tasks.py @@ -0,0 +1,149 @@ +# Copyright (C) 2017 The Sipwise Team - http://sipwise.com +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +from unittest.mock import call +from unittest.mock import patch + +from django.test import override_settings +from django.test import TestCase + +from build.models import BuildRelease +from repoapi.models import JenkinsBuildInfo + + +@override_settings(DEBUG=True, JBI_ALLOWED_HOSTS=["fake.local"]) +@patch("repoapi.utils.dlfile") +@patch("build.tasks.trigger_build") +class JBIManageTest(TestCase): + fixtures = [ + "test_models", + ] + release = "release-mr8.1" + release_uuid = "dbe569f7-eab6-4532-a6d1-d31fb559648b" + + def test_jbi_manage_ok_release_job(self, tb, dl): + br = BuildRelease.objects.get(uuid=self.release_uuid) + self.assertEqual(br.pool_size, 0) + JenkinsBuildInfo.objects.create( + job_url="http://fake.local/job/release-copy-debs-yml/", + projectname="release-copy-debs-yml", + jobname="release-copy-debs-yml", + tag="UUIDA", + param_release=self.release, + param_release_uuid=self.release_uuid, + buildnumber=1, + result="SUCCESS", + ) + params = { + "project": "data-hal-get-code", + "release_uuid": br.uuid, + "trigger_release": br.release, + "trigger_branch_or_tag": br.branch_or_tag, + "trigger_distribution": br.distribution, + } + tb.assert_called_once_with(**params) + br = BuildRelease.objects.get(uuid=self.release_uuid) + self.assertEqual(br.pool_size, 1) + self.assertEqual(br.triggered_projects, "data-hal") + + @override_settings(BUILD_POOL=2) + def test_jbi_manage_pool(self, tb, dl): + br = BuildRelease.objects.get(uuid=self.release_uuid) + self.assertEqual(br.pool_size, 0) + JenkinsBuildInfo.objects.create( + job_url="http://fake.local/job/release-copy-debs-yml/", + projectname="release-copy-debs-yml", + jobname="release-copy-debs-yml", + tag="UUIDA", + param_release="mr8.1", + param_release_uuid=self.release_uuid, + buildnumber=1, + result="SUCCESS", + ) + br = BuildRelease.objects.get(id=br.pk) + self.assertEqual(br.built_projects, "release-copy-debs-yml") + params = { + "project": "data-hal-get-code", + "release_uuid": br.uuid, + "trigger_release": br.release, + "trigger_branch_or_tag": br.branch_or_tag, + "trigger_distribution": br.distribution, + } + calls = [call(**params)] + params["project"] = "libinewrate-get-code" + calls.append(call(**params)) + tb.assert_has_calls(calls) + br = BuildRelease.objects.get(pk=br.pk) + self.assertEqual(br.pool_size, 2) + self.assertEqual(br.triggered_projects, "data-hal,libinewrate") + + @override_settings(BUILD_POOL=2) + def test_jbi_manage_pool_building(self, tb, dl): + self.test_jbi_manage_pool() + br = BuildRelease.objects.get(uuid=self.release_uuid) + self.assertEqual(br.pool_size, 2) + JenkinsBuildInfo.objects.create( + job_url="http://fake.local/job/data-hal-binaries/", + projectname="data-hal", + jobname="data-hal-binaries", + tag="UUIDA", + param_release=self.release, + param_release_uuid=self.release_uuid, + buildnumber=1, + result="SUCCESS", + ) + br = BuildRelease.objects.get(id=br.pk) + self.assertEqual(br.pool_size, 2) + self.assertEqual(br.triggered_projects, "data-hal,libinewrate") + JenkinsBuildInfo.objects.create( + job_url="http://fake.local/job/libinewrate-binaries/", + projectname="libinewrate", + jobname="libinewrate-binaries", + tag="UUIDA", + param_release=self.release, + param_release_uuid=self.release_uuid, + buildnumber=1, + result="SUCCESS", + ) + br = BuildRelease.objects.get(pk=br.pk) + self.assertEqual(br.pool_size, 2) + self.assertEqual(br.triggered_projects, "data-hal,libinewrate") + + @override_settings(BUILD_POOL=2) + def test_jbi_manage_pool_next(self, tb, dl): + self.test_jbi_manage_pool() + br = BuildRelease.objects.get(uuid=self.release_uuid) + self.assertEqual(br.pool_size, 2) + JenkinsBuildInfo.objects.create( + job_url="http://fake.local/job/data-hal-repos/", + projectname="data-hal", + jobname="data-hal-repos", + tag="UUIDA", + param_release=self.release, + param_release_uuid=self.release_uuid, + buildnumber=1, + result="SUCCESS", + ) + br = BuildRelease.objects.get(pk=br.pk) + self.assertEqual(br.built_projects, "release-copy-debs-yml,data-hal") + params = { + "project": "libswrate-get-code", + "release_uuid": br.uuid, + "trigger_release": br.release, + "trigger_branch_or_tag": br.branch_or_tag, + "trigger_distribution": br.distribution, + } + tb.assert_called_once_with(**params) + self.assertEqual(br.pool_size, 2) + self.assertEqual(br.triggered_projects, "libinewrate,libswrate") diff --git a/build/views.py b/build/views.py index 7b652a1..a356255 100644 --- a/build/views.py +++ b/build/views.py @@ -63,11 +63,17 @@ class BuildReleaseDetail(generics.RetrieveDestroyAPIView): def patch(self, request, *args, **kwargs): action = request.data.get("action") + if action is None: + return JsonResponse({"error": "No action"}, status=400) + instance = self.get_object() if action == "refresh": - instance = self.get_object() instance.refresh_projects() serializer = self.get_serializer(instance) return Response(serializer.data) + elif action == "resume": + instance.resume() + serializer = self.get_serializer(instance) + return Response(serializer.data) return JsonResponse({"error": "Action unknown"}, status=400) diff --git a/panel/static/panel/js/panel_release.js b/panel/static/panel/js/panel_release.js index 235537e..c7dcca7 100644 --- a/panel/static/panel/js/panel_release.js +++ b/panel/static/panel/js/panel_release.js @@ -4,6 +4,45 @@ function click_retrigger( e, project ) { e.preventDefault(); } +/* eslint-disable-next-line no-unused-vars*/ // used at onClick +function click_resume( e, id ) { + resume_build( id ); + e.preventDefault(); +} + +function resume_build( id ) { + + function successFunc( _data, _textStatus, _jqXHR ) { + $( "#resume" ).prop( "disabled", true ); + } + + function errorFunc( _jqXHR, _status, error ) { + $( "#release_error" ).html( error ); + } + var csrftoken = jQuery( "[name=csrfmiddlewaretoken]" ).val(); + function csrfSafeMethod( method ) { + + // these HTTP methods do not require CSRF protection + return ( /^(GET|HEAD|OPTIONS|TRACE)$/.test( method ) ); + } + $.ajaxSetup( { + beforeSend: function( xhr, settings ) { + if ( !csrfSafeMethod( settings.type ) && !this.crossDomain ) { + xhr.setRequestHeader( "X-CSRFToken", csrftoken ); + } + } + } ); + $.ajax( { + url: "/build/" + id + "/?format=json", + data: JSON.stringify( { action: "resume" } ), + method: "PATCH", + contentType: "application/json; charset=utf-8", + dataType: "json", + success: successFunc, + error: errorFunc + } ); +} + function clean_all_uuids( project ) { for ( var uuid of $.release[ project ].uuids ) { $( "#" + project + "-" + uuid ).remove(); @@ -134,6 +173,19 @@ function is_project_done( project ) { return $.release[ project ][ uuid ].jobs.has( project + "-repos" ); } + +function is_stuck() { + var success = parseInt( $( "#stats-success" ).text(), 10 ); + var failed = parseInt( $( "#stats-danger" ).text(), 10 ); + var queued = parseInt( $( "#stats-queued" ).text(), 10 ); + var building = parseInt( $( "#stats-created" ).text(), 10 ); + + if ( failed === 0 && queued > 0 && building === 0 && success > 0 ) { + return true; + } + return false; +} + /* eslint-disable-next-line no-unused-vars */ // used on templates function update_release_info( release ) { if ( $.release.release_jobs.size < $.release.release_jobs_size ) { @@ -147,4 +199,7 @@ function update_release_info( release ) { get_uuids_for_project( release, project ); } } + if ( is_stuck() ) { + $( "#resume" ).prop( "disabled", false ); + } } diff --git a/panel/templates/panel/release_info.html b/panel/templates/panel/release_info.html index 0e2bd80..fb7d53c 100644 --- a/panel/templates/panel/release_info.html +++ b/panel/templates/panel/release_info.html @@ -8,13 +8,21 @@ tag branch started_at + Action {{ build_release.config.debian_release }} {{ build_release.tag }} {{ build_release.branch }} {{ build_release.start_date }} + + + - \ No newline at end of file + + \ No newline at end of file