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
changes/46/38446/1
Victor Seva 6 years ago
parent 17709467f0
commit e6a6f46e26

@ -23,8 +23,8 @@
"branch": "mr8.1", "branch": "mr8.1",
"release": "release-mr8.1", "release": "release-mr8.1",
"distribution": "buster", "distribution": "buster",
"projects": "kamailio,lua-ngcp-kamailio,ngcp-panel", "projects": "asterisk-voicemail,lua-ngcp-kamailio,ngcp-panel",
"built_projects": "kamailio,lua-ngcp-kamailio" "built_projects": null
} }
} }
] ]

@ -19,7 +19,7 @@ from django.db.models import signals
from .br import BuildRelease from .br import BuildRelease
from build.tasks import build_release from build.tasks import build_release
from build.utils import trigger_build from build.tasks import build_resume
from repoapi.models import JenkinsBuildInfo from repoapi.models import JenkinsBuildInfo
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -66,31 +66,7 @@ def jbi_manage(sender, **kwargs):
logger.debug("BuildRelease:%s jbi:%s skip", br, jbi) logger.debug("BuildRelease:%s jbi:%s skip", br, jbi)
return return
br.remove_triggered(jbi) br.remove_triggered(jbi)
params = { build_resume.delay(br.id)
"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
post_save = signals.post_save.connect post_save = signals.post_save.connect

@ -96,6 +96,7 @@ class BuildRelease(models.Model):
failed_projects = models.TextField(null=True, editable=False) failed_projects = models.TextField(null=True, editable=False)
pool_size = models.SmallIntegerField(default=0, editable=False) pool_size = models.SmallIntegerField(default=0, editable=False)
objects = BuildReleaseManager() objects = BuildReleaseManager()
release_jobs_len = len(",".join(settings.RELEASE_JOBS))
def __str__(self): def __str__(self):
return "%s[%s]" % (self.release, self.uuid) return "%s[%s]" % (self.release, self.uuid)
@ -104,6 +105,17 @@ class BuildRelease(models.Model):
self.projects = ",".join(self.config.projects) self.projects = ",".join(self.config.projects)
self.save() 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 @property
def projects_list(self): def projects_list(self):
return [x.strip() for x in self.projects.split(",")] return [x.strip() for x in self.projects.split(",")]
@ -207,9 +219,7 @@ class BuildRelease(models.Model):
def _next(self): def _next(self):
if self.built_projects is None: if self.built_projects is None:
return self.build_deps[0][0] return self.build_deps[0][0]
built_len = len(self.built_projects) if self.done:
release_jobs_len = len(",".join(settings.RELEASE_JOBS))
if built_len == release_jobs_len + 1 + len(self.projects):
return return
t_list = self.triggered_projects_list t_list = self.triggered_projects_list
built_list = self.built_projects_list built_list = self.built_projects_list

@ -15,6 +15,7 @@
import logging import logging
from celery import shared_task from celery import shared_task
from django.conf import settings
from build.models.br import BuildRelease from build.models.br import BuildRelease
from build.utils import trigger_build from build.utils import trigger_build
@ -55,3 +56,37 @@ def build_project(pk, project):
) )
br.pool_size += 1 br.pool_size += 1
logger.info("%s triggered" % url) 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

@ -12,7 +12,6 @@
# #
# You should have received a copy of the GNU General Public License along # You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>. # with this program. If not, see <http://www.gnu.org/licenses/>.
from unittest.mock import call
from unittest.mock import MagicMock from unittest.mock import MagicMock
from unittest.mock import patch from unittest.mock import patch
@ -20,7 +19,6 @@ from django.test import override_settings
from django.test import TestCase from django.test import TestCase
from build.models import BuildRelease from build.models import BuildRelease
from build.models import jbi_manage
from repoapi.models import JenkinsBuildInfo from repoapi.models import JenkinsBuildInfo
from repoapi.test.base import BaseTest from repoapi.test.base import BaseTest
@ -140,8 +138,14 @@ class BuildReleaseTestCase(TestCase):
@override_settings(DEBUG=True) @override_settings(DEBUG=True)
class BuildReleaseStepsTest(TestCase): class BuildReleaseStepsTest(TestCase):
fixtures = [
"test_models",
]
release = "release-mr8.1"
release_uuid = "dbe569f7-eab6-4532-a6d1-d31fb559648b"
def setUp(self): 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.br.pool_size = 1
self.jbi = MagicMock() self.jbi = MagicMock()
self.jbi.result = "SUCCESS" self.jbi.result = "SUCCESS"
@ -296,17 +300,18 @@ class BuildReleaseStepsTest(TestCase):
self.assertIsNone(self.br.next) self.assertIsNone(self.br.next)
@override_settings( @override_settings(DEBUG=True, JBI_ALLOWED_HOSTS=["fake.local"])
DEBUG=True,
JBI_ALLOWED_HOSTS=["fake.local"],
CELERY_EAGER_PROPAGATES_EXCEPTIONS=True,
)
@patch("repoapi.utils.dlfile") @patch("repoapi.utils.dlfile")
@patch("build.models.build_resume")
class JBIManageTest(TestCase): class JBIManageTest(TestCase):
@patch("build.models.trigger_build") fixtures = [
def test_jbi_manage_ko(self, tb, dl): "test_models",
BuildRelease.objects.create_build_release("AAA", "trunk") ]
jbi = JenkinsBuildInfo.objects.create( 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/", job_url="http://fake.local/job/release-copy-debs-yml/",
projectname="release-copy-debs-yml", projectname="release-copy-debs-yml",
jobname="release-copy-debs-yml", jobname="release-copy-debs-yml",
@ -316,173 +321,82 @@ class JBIManageTest(TestCase):
buildnumber=1, buildnumber=1,
result="SUCCESS", result="SUCCESS",
) )
params = {"instance": jbi, "created": True} build_resume.delay.assert_not_called()
jbi_manage(JenkinsBuildInfo, **params)
tb.assert_not_called()
@patch("build.models.trigger_build") def test_jbi_manage_ko_url(self, build_resume, dl):
def test_jbi_manage_ok_release_job(self, tb, dl): JenkinsBuildInfo.objects.create(
br = BuildRelease.objects.create_build_release("UUID_mr8.1", "mr8.1") 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) self.assertEqual(br.pool_size, 0)
JenkinsBuildInfo.objects.create( JenkinsBuildInfo.objects.create(
job_url="http://fake.local/job/release-copy-debs-yml/", job_url="http://fake.local/job/release-copy-debs-yml/",
projectname="release-copy-debs-yml", projectname="release-copy-debs-yml",
jobname="release-copy-debs-yml", jobname="release-copy-debs-yml",
tag="UUIDA", tag="UUIDA",
param_release="mr8.1", param_release=self.release,
param_release_uuid="UUID_mr8.1", param_release_uuid=self.release_uuid,
buildnumber=1, buildnumber=1,
result="SUCCESS", result="SUCCESS",
) )
br = BuildRelease.objects.get(pk=br.pk) br = BuildRelease.objects.get(pk=br.pk)
self.assertEqual(br.built_projects, "release-copy-debs-yml") self.assertEqual(br.built_projects, "release-copy-debs-yml")
params = { build_resume.delay.assert_called_once_with(br.pk)
"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")
@patch("build.models.trigger_build") def test_jbi_manage_skip(self, build_resume, dl):
def test_jbi_manage_skip(self, tb, dl): br = BuildRelease.objects.get(uuid=self.release_uuid)
br = BuildRelease.objects.create_build_release("UUID_mr8.1", "mr8.1")
br.pool_size = 1 br.pool_size = 1
br.triggered_projects = "kamailio" br.triggered_projects = "kamailio"
br.save() br.save()
jbi = JenkinsBuildInfo.objects.create( JenkinsBuildInfo.objects.create(
job_url="http://fake.local/job/kamailio-get-code/", job_url="http://fake.local/job/kamailio-binaries/",
projectname="kamailio", projectname="kamailio",
jobname="kamailio-get-code", jobname="kamailio-binaries",
tag="UUIDA", tag="UUIDA",
param_release="mr8.1", param_release=self.release,
param_release_uuid="UUID_mr8.1", param_release_uuid=self.release_uuid,
buildnumber=1, buildnumber=1,
result="SUCCESS", result="SUCCESS",
) )
br = BuildRelease.objects.get(pk=br.pk) br = BuildRelease.objects.get(pk=br.pk)
self.assertIsNone(br.built_projects) self.assertIsNone(br.built_projects)
params = {"instance": jbi, "created": True} build_resume.delay.assert_not_called()
jbi_manage(JenkinsBuildInfo, **params)
tb.assert_not_called()
self.assertEqual(br.pool_size, 1) self.assertEqual(br.pool_size, 1)
self.assertEqual(br.triggered_projects, "kamailio") self.assertEqual(br.triggered_projects, "kamailio")
@override_settings(BUILD_POOL=2)
@patch("build.models.trigger_build") @override_settings(DEBUG=True)
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,
)
class BRManageTest(TestCase): class BRManageTest(TestCase):
@patch("build.tasks.trigger_copy_deps") @patch("build.tasks.trigger_copy_deps")
@patch("build.models.trigger_build") @patch("build.models.build_resume")
def test_br_manage(self, tb, rb): def test_br_manage(self, build_resume, trigger_copy_deps):
br = BuildRelease.objects.create_build_release("UUID_mr8.1", "mr8.1") br = BuildRelease.objects.create_build_release("UUID_mr8.1", "mr8.1")
tb.assert_not_called() build_resume.delay.assert_not_called()
rb.assert_called_once_with( trigger_copy_deps.assert_called_once_with(
internal=True, release=br.release, release_uuid=br.uuid internal=True, release=br.release, release_uuid=br.uuid
) )
@override_settings(DEBUG=True) @override_settings(DEBUG=True)
class BuildReleaseRetriggerTest(TestCase): class BuildReleaseRetriggerTest(TestCase):
fixtures = [
"test_models",
]
release = "release-mr8.1"
release_uuid = "dbe569f7-eab6-4532-a6d1-d31fb559648b"
def setUp(self): 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 = MagicMock()
self.jbi.result = "SUCCESS" self.jbi.result = "SUCCESS"

@ -35,7 +35,7 @@ class APIAuthenticatedTestCase(BaseTest, APITestCase):
self.client.credentials(HTTP_API_KEY=self.app_key.key) 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): class TestRest(APIAuthenticatedTestCase):
def setUp(self): def setUp(self):
super(TestRest, self).setUp() super(TestRest, self).setUp()
@ -103,7 +103,7 @@ class TestRest(APIAuthenticatedTestCase):
self.assertEqual(len(projects), 75) self.assertEqual(len(projects), 75)
@override_settings(DEBUG=True) @override_settings(DEBUG=True, JBI_ALLOWED_HOSTS=["fake.local"])
class TestBuildRest(APIAuthenticatedTestCase): class TestBuildRest(APIAuthenticatedTestCase):
fixtures = [ fixtures = [
"test_models", "test_models",
@ -120,7 +120,7 @@ class TestBuildRest(APIAuthenticatedTestCase):
self.assertEqual(response.status_code, status.HTTP_201_CREATED) 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): class TestBuildDeleteRest(APIAuthenticatedTestCase):
fixtures = [ fixtures = [
"test_models", "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): class TestBuildPatchRest(APIAuthenticatedTestCase):
fixtures = [ fixtures = [
"test_models", "test_models",

@ -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 <http://www.gnu.org/licenses/>.
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")

@ -63,11 +63,17 @@ class BuildReleaseDetail(generics.RetrieveDestroyAPIView):
def patch(self, request, *args, **kwargs): def patch(self, request, *args, **kwargs):
action = request.data.get("action") action = request.data.get("action")
if action == "refresh": if action is None:
return JsonResponse({"error": "No action"}, status=400)
instance = self.get_object() instance = self.get_object()
if action == "refresh":
instance.refresh_projects() instance.refresh_projects()
serializer = self.get_serializer(instance) serializer = self.get_serializer(instance)
return Response(serializer.data) 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) return JsonResponse({"error": "Action unknown"}, status=400)

@ -4,6 +4,45 @@ function click_retrigger( e, project ) {
e.preventDefault(); 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 ) { function clean_all_uuids( project ) {
for ( var uuid of $.release[ project ].uuids ) { for ( var uuid of $.release[ project ].uuids ) {
$( "#" + project + "-" + uuid ).remove(); $( "#" + project + "-" + uuid ).remove();
@ -134,6 +173,19 @@ function is_project_done( project ) {
return $.release[ project ][ uuid ].jobs.has( project + "-repos" ); 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 /* eslint-disable-next-line no-unused-vars */ // used on templates
function update_release_info( release ) { function update_release_info( release ) {
if ( $.release.release_jobs.size < $.release.release_jobs_size ) { if ( $.release.release_jobs.size < $.release.release_jobs_size ) {
@ -147,4 +199,7 @@ function update_release_info( release ) {
get_uuids_for_project( release, project ); get_uuids_for_project( release, project );
} }
} }
if ( is_stuck() ) {
$( "#resume" ).prop( "disabled", false );
}
} }

@ -8,13 +8,21 @@
<th>tag</th> <th>tag</th>
<th>branch</th> <th>branch</th>
<th>started_at</th> <th>started_at</th>
<th>Action</th>
</tr> </tr>
<tr class="active"> <tr class="active">
<td>{{ build_release.config.debian_release }}</td> <td>{{ build_release.config.debian_release }}</td>
<td>{{ build_release.tag }}</td> <td>{{ build_release.tag }}</td>
<td>{{ build_release.branch }}</td> <td>{{ build_release.branch }}</td>
<td>{{ build_release.start_date }}</td> <td>{{ build_release.start_date }}</td>
<td id="action_list">
<button type="button" id="resume"
disabled="disabled"
onclick="click_resume(event, '{{ build_release.id }}')"
class="btn btn-primary">Resume</button>
</td>
</td> </td>
</tr> </tr>
</table> </table>
</div> </div>
<div class="panel-footer error" id="release_error"></div>
Loading…
Cancel
Save