blob: 1bee5779fb53e0a55727e42e4b12a9e27b86c95d [file] [log] [blame]
# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Module that handles interactions with a Validation Pool.
The validation pool is the set of commits that are ready to be validated i.e.
ready for the commit queue to try.
"""
import constants
import json
import logging
from chromite.buildbot import patch as cros_patch
from chromite.lib import cros_build_lib
class _GerritServer():
"""Helper class to manage interaction with Gerrit server."""
def __init__(self, branch, internal):
"""Initializes variables for interaction with a gerrit server."""
self.internal = internal
if self.internal:
ssh_port = constants.GERRIT_INT_PORT
ssh_host = constants.GERRIT_INT_HOST
else:
ssh_port = constants.GERRIT_PORT
ssh_host = constants.GERRIT_HOST
ssh_prefix = ['ssh', '-p', ssh_port, ssh_host]
ready_for_commit_query = ('gerrit query --format=json status:open '
'AND CodeReview=+2 AND Verified=1 AND '
'branch:%s' % branch).split()
self.ssh_query_cmd = ssh_prefix + ready_for_commit_query
def GrabChangesReadyForCommit(self):
"""Returns the list of changes to try.
This methods returns an array of GerritPatch's that are ready to be
committed.
"""
changes_to_commit = []
raw_results = cros_build_lib.RunCommand(self.ssh_query_cmd,
redirect_stdout=True)
# Each line return is a json dict.
for raw_result in raw_results.output.splitlines():
result_dict = json.loads(raw_result)
if not 'number' in result_dict:
logging.debug('No change number found in %s' % result_dict)
continue
change_number = result_dict['number']
logging.info('Found change %s ready and pending' % change_number)
if self.internal:
changes_to_commit.append('*' + change_number)
else:
changes_to_commit.append(change_number)
return cros_patch.GetGerritPatchInfo(changes_to_commit)
class ValidationPool(object):
"""Class that handles interactions with a validation pool.
This class can be used to acquire a set of commits that form a pool of
commits ready to be validated and committed.
Usage: Use ValidationPoo.AcquirePool -- a static
method that grabs the commits that are ready for validation.
"""
def __init__(self):
"""Initializes an instance by setting default valuables to instance vars.
Generally use AcquirePool as an entry pool to a pool rather than this
method.
"""
self._changes = None
@classmethod
def _IsTreeOpen(cls):
"""Returns True if the tree is open for submitting changes."""
# TODO(sosa): crosbug.com/17709.
return True
@classmethod
def AcquirePool(cls, branch, internal):
"""Acquires the current pool from Gerrit.
Polls Gerrit and checks for which change's are ready to be committed.
Returns: ValidationPool object.
"""
if cls._IsTreeOpen():
pool = ValidationPool()
pool._changes = _GerritServer(
branch, internal).GrabChangesReadyForCommit()
return pool
else:
return None
def ApplyPoolIntoRepo(self, repo):
"""Cherry picks changes from pool into repository."""
non_applied_changes = []
for change in self._changes:
try:
change.Apply(repo.directory)
except cros_patch.ApplyPatchException:
non_applied_changes.add(change)
if non_applied_changes:
logging.debug('Some changes could not be applied cleanly.')
self.HandleApplicationFailure(non_applied_changes)
self._changes = list(set(self._changes) - set(non_applied_changes))
def SubmitPool(self):
"""Commits changes to Gerrit from Pool."""
# TODO(sosa): crosbug.com/17707.
for change in self._changes:
logging.info('Change %s will be submitted' % change)
def HandleApplicationFailure(self, changes):
"""Handles changes that were not able to be applied cleanly."""
# TODO(sosa): crosbug.com/17708.
for change in changes:
logging.info('Change %s did not apply cleanly.' % change)
def HandleValidationFailure(self):
"""Handles failed changes by removing them from next Validation Pools."""
# TODO(sosa): crosbug.com/17708.
for change in self._changes:
logging.info('Validation failed for change %s.' % change)