Home | History | Annotate | Download | only in cli
      1 # Copyright 2018 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 """Constants and util methods to interact with skylab inventory repo."""
      6 
      7 import logging
      8 import re
      9 
     10 import common
     11 
     12 from autotest_lib.client.common_lib import revision_control
     13 from chromite.lib import gob_util
     14 
     15 try:
     16     from skylab_inventory import text_manager
     17 except ImportError:
     18     pass
     19 
     20 
     21 INTERNAL_GERRIT_HOST = 'chrome-internal-review.googlesource.com'
     22 INTERNAL_GERRIT_HOST_URL = 'https://%s' % INTERNAL_GERRIT_HOST
     23 # The git url of the internal skylab_inventory
     24 INTERNAL_INVENTORY_REPO_URL = ('https://chrome-internal.googlesource.com/'
     25                                'chromeos/infra_internal/skylab_inventory.git')
     26 INTERNAL_INVENTORY_CHANGE_PATTERN = (
     27         r'https://chrome-internal-review.googlesource.com/c/chromeos/'
     28         'infra_internal/skylab_inventory/\\+/([0-9]*)')
     29 MSG_INVALID_IN_SKYLAB = 'This is currently not supported with --skylab.'
     30 MSG_ONLY_VALID_IN_SKYLAB = 'This only applies to actions on skylab inventory.'
     31 
     32 
     33 class SkylabInventoryNotImported(Exception):
     34     """skylab_inventory is not imported."""
     35 
     36 
     37 class InventoryRepoChangeNotFound(Exception):
     38     """Error raised when no inventory repo change number is found."""
     39 
     40 
     41 class InventoryRepoDirNotClean(Exception):
     42     """Error raised when the given inventory_repo_dir contains local changes."""
     43 
     44 
     45 def get_cl_url(change_number):
     46     return INTERNAL_GERRIT_HOST_URL + '/' + str(change_number)
     47 
     48 
     49 def get_cl_message(change_number):
     50     return ('Please submit the CL at %s to make the change effective.' %
     51             get_cl_url(change_number))
     52 
     53 
     54 def construct_commit_message(subject, bug=None, test=None):
     55     """Construct commit message for skylab inventory repo commit.
     56 
     57     @param subject: Commit message subject.
     58     @param bug: Bug number of the commit.
     59     @param test: Tests of the commit.
     60 
     61     @return: A commit message string.
     62     """
     63     return '\n'.join([subject, '', 'BUG=%s' % bug, 'TEST=%s' % test])
     64 
     65 
     66 def extract_inventory_change(output):
     67     """Extract the change number from the output.
     68 
     69     @param output: The git command output containing the change gerrit url.
     70 
     71     @return: The change number (int) of the inventory change.
     72     """
     73     m = re.search(INTERNAL_INVENTORY_CHANGE_PATTERN, output)
     74 
     75     if not m:
     76         raise InventoryRepoChangeNotFound(
     77                 'Could not extract CL number from "%r"' % output)
     78 
     79     return int(m.group(1))
     80 
     81 
     82 def submit_inventory_change(change_number):
     83     """Set review labels and submit the inventory change.
     84 
     85     @param change_number: The change number (int) of the inventory change.
     86     """
     87     logging.info('Setting review labels for %s.',
     88                   get_cl_url(change_number))
     89     gob_util.SetReview(
     90         INTERNAL_GERRIT_HOST,
     91         change=change_number,
     92         labels={'Code-Review': 2, 'Verified': 1},
     93         msg='Set TBR by "atest --skylab"',
     94         notify='OWNER')
     95 
     96     logging.info('Submitting the change.')
     97     gob_util.SubmitChange(
     98         INTERNAL_GERRIT_HOST,
     99         change=change_number)
    100 
    101 
    102 class InventoryRepo(object):
    103     """Class to present a inventory repository."""
    104 
    105 
    106     def __init__(self, inventory_repo_dir):
    107         self.inventory_repo_dir = inventory_repo_dir
    108         self.git_repo = None
    109 
    110 
    111     def initialize(self):
    112         """Initialize inventory repo at the given dir."""
    113         self.git_repo = revision_control.GitRepo(
    114                 self.inventory_repo_dir,
    115                 giturl=INTERNAL_INVENTORY_REPO_URL,
    116                 abs_work_tree=self.inventory_repo_dir)
    117 
    118         if self.git_repo.is_repo_initialized():
    119             if self.git_repo.status():
    120                 raise InventoryRepoDirNotClean(
    121                        'The inventory_repo_dir "%s" contains uncommitted '
    122                        'changes. Please clean up the local repo directory or '
    123                        'use another clean directory.' % self.inventory_repo_dir)
    124 
    125             logging.info('Inventory repo was already initialized, start '
    126                          'pulling.')
    127             self.git_repo.checkout('master')
    128             self.git_repo.pull()
    129         else:
    130             logging.info('No inventory repo was found, start cloning.')
    131             self.git_repo.clone(shallow=True)
    132 
    133 
    134     def get_data_dir(self, data_subdir='skylab'):
    135         """Get path to the data dir."""
    136         return text_manager.get_data_dir(self.inventory_repo_dir, data_subdir)
    137 
    138 
    139     def upload_change(self, commit_message, draft=False, dryrun=False,
    140                       submit=False):
    141         """Commit and upload the change to gerrit.
    142 
    143         @param commit_message: Commit message of the CL to upload.
    144         @param draft: Boolean indicating whether to upload the CL as a draft.
    145         @param dryrun: Boolean indicating whether to run upload as a dryrun.
    146         @param submit: Boolean indicating whether to submit the CL directly.
    147 
    148         @return: Change number (int) of the CL if it's uploaded to Gerrit.
    149         """
    150         self.git_repo.commit(commit_message)
    151 
    152         remote = self.git_repo.remote()
    153         output = self.git_repo.upload_cl(
    154                 remote, 'master', draft=draft, dryrun=dryrun)
    155 
    156         if not dryrun:
    157             change_number = extract_inventory_change(output)
    158 
    159             if submit:
    160                 submit_inventory_change(change_number)
    161 
    162             return change_number
    163