Merge "Builds: add "held" attribute"
This commit is contained in:
commit
6a5b97572f
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
Builds in the SQL reporter have a "held" attribute set to True if the build
|
||||
triggered a autohold request. Builds can be filtered by held status.
|
||||
upgrade:
|
||||
- |
|
||||
If using a SQL reporter, the zuul_builds table will be updated with a new
|
||||
'held' column. The `zuul-scheduler` and `zuul-web` services need to be restarted
|
||||
together for the change to take effect.
|
|
@ -75,7 +75,7 @@ class TestSQLConnection(ZuulDBTestCase):
|
|||
build_table = table_prefix + 'zuul_build'
|
||||
|
||||
self.assertEqual(16, len(insp.get_columns(buildset_table)))
|
||||
self.assertEqual(12, len(insp.get_columns(build_table)))
|
||||
self.assertEqual(13, len(insp.get_columns(build_table)))
|
||||
|
||||
def test_sql_tables_created(self):
|
||||
"Test the tables for storing results are created properly"
|
||||
|
|
|
@ -2080,6 +2080,46 @@ class TestTenantScopedWebApiTokenWithExpiry(BaseTestWeb):
|
|||
self.assertEqual("some reason", ah_request['reason'])
|
||||
|
||||
|
||||
class TestHeldAttributeInBuildInfo(ZuulDBTestCase, BaseTestWeb):
|
||||
config_file = 'zuul-sql-driver.conf'
|
||||
tenant_config_file = 'config/sql-driver/main.yaml'
|
||||
|
||||
def test_autohold_and_retrieve_held_build_info(self):
|
||||
"""Ensure the "held" attribute can be used to filter builds"""
|
||||
client = zuul.rpcclient.RPCClient('127.0.0.1',
|
||||
self.gearman_server.port)
|
||||
self.addCleanup(client.shutdown)
|
||||
r = client.autohold('tenant-one', 'org/project', 'project-test2',
|
||||
"", "", "reason text", 1)
|
||||
self.assertTrue(r)
|
||||
|
||||
B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
|
||||
self.executor_server.failJob('project-test2', B)
|
||||
self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
|
||||
self.waitUntilSettled()
|
||||
self.executor_server.hold_jobs_in_build = False
|
||||
self.executor_server.release()
|
||||
self.waitUntilSettled()
|
||||
|
||||
all_builds_resp = self.get_url("api/tenant/tenant-one/builds?"
|
||||
"project=org/project")
|
||||
held_builds_resp = self.get_url("api/tenant/tenant-one/builds?"
|
||||
"project=org/project&"
|
||||
"held=1")
|
||||
self.assertEqual(200,
|
||||
all_builds_resp.status_code,
|
||||
all_builds_resp.text)
|
||||
self.assertEqual(200,
|
||||
held_builds_resp.status_code,
|
||||
held_builds_resp.text)
|
||||
all_builds = all_builds_resp.json()
|
||||
held_builds = held_builds_resp.json()
|
||||
self.assertEqual(len(held_builds), 1, all_builds)
|
||||
held_build = held_builds[0]
|
||||
self.assertEqual('project-test2', held_build['job_name'], held_build)
|
||||
self.assertEqual(True, held_build['held'], held_build)
|
||||
|
||||
|
||||
class TestWebMulti(BaseTestWeb):
|
||||
config_file = 'zuul-gerrit-github.conf'
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""add held attribute to builds
|
||||
|
||||
Revision ID: 32e28a297c3e
|
||||
Revises: 16c1dc9054d0
|
||||
Create Date: 2020-05-19 11:19:19.263236
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '32e28a297c3e'
|
||||
down_revision = '269691d2220e'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def upgrade(table_prefix=''):
|
||||
op.add_column(
|
||||
table_prefix + 'zuul_build',
|
||||
sa.Column('held', sa.Boolean)
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
raise Exception("Downgrades not supported")
|
|
@ -60,7 +60,7 @@ class DatabaseSession(object):
|
|||
change=None, branch=None, patchset=None, ref=None,
|
||||
newrev=None, event_id=None, uuid=None, job_name=None,
|
||||
voting=None, node_name=None, result=None, provides=None,
|
||||
final=None, limit=50, offset=0):
|
||||
final=None, held=None, limit=50, offset=0):
|
||||
|
||||
build_table = self.connection.zuul_build_table
|
||||
buildset_table = self.connection.zuul_buildset_table
|
||||
|
@ -104,6 +104,7 @@ class DatabaseSession(object):
|
|||
q = self.listFilter(q, build_table.c.result, result)
|
||||
q = self.listFilter(q, build_table.c.final, final)
|
||||
q = self.listFilter(q, provides_table.c.name, provides)
|
||||
q = self.listFilter(q, build_table.c.held, held)
|
||||
|
||||
q = q.order_by(build_table.c.id.desc()).\
|
||||
limit(limit).\
|
||||
|
@ -296,6 +297,7 @@ class SQLConnection(BaseConnection):
|
|||
uuid = sa.Column(sa.String(36))
|
||||
job_name = sa.Column(sa.String(255))
|
||||
result = sa.Column(sa.String(255))
|
||||
held = sa.Column(sa.Boolean)
|
||||
start_time = sa.Column(sa.DateTime)
|
||||
end_time = sa.Column(sa.DateTime)
|
||||
voting = sa.Column(sa.Boolean)
|
||||
|
|
|
@ -59,6 +59,7 @@ class SQLReporter(BaseReporter):
|
|||
node_name=build.node_name,
|
||||
error_detail=build.error_detail,
|
||||
final=final,
|
||||
held=build.held,
|
||||
)
|
||||
|
||||
return db_build
|
||||
|
@ -100,7 +101,6 @@ class SQLReporter(BaseReporter):
|
|||
# stats about builds. It doesn't understand how to store
|
||||
# information about the change.
|
||||
continue
|
||||
|
||||
retry_builds = item.current_build_set.getRetryBuildsForJob(
|
||||
job.name
|
||||
)
|
||||
|
|
|
@ -1882,6 +1882,7 @@ class Build(object):
|
|||
self.canceled = False
|
||||
self.paused = False
|
||||
self.retry = False
|
||||
self.held = False
|
||||
self.parameters = {}
|
||||
self.worker = Worker()
|
||||
self.node_labels = []
|
||||
|
|
|
@ -1565,12 +1565,14 @@ class Scheduler(threading.Thread):
|
|||
# failed / retry_limit / post_failure and have an autohold request.
|
||||
hold_list = ["FAILURE", "RETRY_LIMIT", "POST_FAILURE", "TIMED_OUT"]
|
||||
if build.result not in hold_list:
|
||||
return
|
||||
return False
|
||||
|
||||
request = self._getAutoholdRequest(build)
|
||||
self.log.debug("Got autohold %s", request)
|
||||
if request is not None:
|
||||
self.log.debug("Got autohold %s", request)
|
||||
self.nodepool.holdNodeSet(build.nodeset, request, build)
|
||||
return True
|
||||
return False
|
||||
|
||||
def _doBuildCompletedEvent(self, event):
|
||||
build = event.build
|
||||
|
@ -1582,7 +1584,10 @@ class Scheduler(threading.Thread):
|
|||
# to pass this on to the pipeline manager, make sure we return
|
||||
# the nodes to nodepool.
|
||||
try:
|
||||
self._processAutohold(build)
|
||||
event.build.held = self._processAutohold(build)
|
||||
self.log.debug(
|
||||
'build "%s" held status set to %s' % (event.build,
|
||||
event.build.held))
|
||||
except Exception:
|
||||
log.exception("Unable to process autohold for %s" % build)
|
||||
try:
|
||||
|
|
|
@ -875,6 +875,7 @@ class ZuulWebAPI(object):
|
|||
'uuid': build.uuid,
|
||||
'job_name': build.job_name,
|
||||
'result': build.result,
|
||||
'held': build.held,
|
||||
'start_time': start_time,
|
||||
'end_time': end_time,
|
||||
'duration': duration,
|
||||
|
@ -934,7 +935,7 @@ class ZuulWebAPI(object):
|
|||
def builds(self, tenant, project=None, pipeline=None, change=None,
|
||||
branch=None, patchset=None, ref=None, newrev=None,
|
||||
uuid=None, job_name=None, voting=None, node_name=None,
|
||||
result=None, final=None, limit=50, skip=0):
|
||||
result=None, final=None, held=None, limit=50, skip=0):
|
||||
connection = self._get_connection(tenant)
|
||||
|
||||
# If final is None, we return all builds, both final and non-final
|
||||
|
@ -945,7 +946,7 @@ class ZuulWebAPI(object):
|
|||
tenant=tenant, project=project, pipeline=pipeline, change=change,
|
||||
branch=branch, patchset=patchset, ref=ref, newrev=newrev,
|
||||
uuid=uuid, job_name=job_name, voting=voting, node_name=node_name,
|
||||
result=result, final=final, limit=limit, offset=skip)
|
||||
result=result, final=final, held=held, limit=limit, offset=skip)
|
||||
|
||||
resp = cherrypy.response
|
||||
resp.headers['Access-Control-Allow-Origin'] = '*'
|
||||
|
|
Loading…
Reference in New Issue