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