# Copyright 2018 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.
"""Constants and util methods to interact with skylab inventory repo."""
import logging
import re
import common
from autotest_lib.client.common_lib import revision_control
from chromite.lib import gob_util
try:
from skylab_inventory import text_manager
except ImportError:
pass
INTERNAL_GERRIT_HOST = 'chrome-internal-review.googlesource.com'
INTERNAL_GERRIT_HOST_URL = 'https://%s' % INTERNAL_GERRIT_HOST
# The git url of the internal skylab_inventory
INTERNAL_INVENTORY_REPO_URL = ('https://chrome-internal.googlesource.com/'
'chromeos/infra_internal/skylab_inventory.git')
INTERNAL_INVENTORY_CHANGE_PATTERN = (
r'https://chrome-internal-review.googlesource.com/c/chromeos/'
'infra_internal/skylab_inventory/\\+/([0-9]*)')
MSG_INVALID_IN_SKYLAB = 'This is currently not supported with --skylab.'
MSG_ONLY_VALID_IN_SKYLAB = 'This only applies to actions on skylab inventory.'
class SkylabInventoryNotImported(Exception):
"""skylab_inventory is not imported."""
class InventoryRepoChangeNotFound(Exception):
"""Error raised when no inventory repo change number is found."""
class InventoryRepoDirNotClean(Exception):
"""Error raised when the given inventory_repo_dir contains local changes."""
def get_cl_url(change_number):
return INTERNAL_GERRIT_HOST_URL + '/' + str(change_number)
def get_cl_message(change_number):
return ('Please submit the CL at %s to make the change effective.' %
get_cl_url(change_number))
def construct_commit_message(subject, bug=None, test=None):
"""Construct commit message for skylab inventory repo commit.
@param subject: Commit message subject.
@param bug: Bug number of the commit.
@param test: Tests of the commit.
@return: A commit message string.
"""
return '\n'.join([subject, '', 'BUG=%s' % bug, 'TEST=%s' % test])
def extract_inventory_change(output):
"""Extract the change number from the output.
@param output: The git command output containing the change gerrit url.
@return: The change number (int) of the inventory change.
"""
m = re.search(INTERNAL_INVENTORY_CHANGE_PATTERN, output)
if not m:
raise InventoryRepoChangeNotFound(
'Could not extract CL number from "%r"' % output)
return int(m.group(1))
def submit_inventory_change(change_number):
"""Set review labels and submit the inventory change.
@param change_number: The change number (int) of the inventory change.
"""
logging.info('Setting review labels for %s.',
get_cl_url(change_number))
gob_util.SetReview(
INTERNAL_GERRIT_HOST,
change=change_number,
labels={'Code-Review': 2, 'Verified': 1},
msg='Set TBR by "atest --skylab"',
notify='OWNER')
logging.info('Submitting the change.')
gob_util.SubmitChange(
INTERNAL_GERRIT_HOST,
change=change_number)
class InventoryRepo(object):
"""Class to present a inventory repository."""
def __init__(self, inventory_repo_dir):
self.inventory_repo_dir = inventory_repo_dir
self.git_repo = None
def initialize(self):
"""Initialize inventory repo at the given dir."""
self.git_repo = revision_control.GitRepo(
self.inventory_repo_dir,
giturl=INTERNAL_INVENTORY_REPO_URL,
abs_work_tree=self.inventory_repo_dir)
if self.git_repo.is_repo_initialized():
if self.git_repo.status():
raise InventoryRepoDirNotClean(
'The inventory_repo_dir "%s" contains uncommitted '
'changes. Please clean up the local repo directory or '
'use another clean directory.' % self.inventory_repo_dir)
logging.info('Inventory repo was already initialized, start '
'pulling.')
self.git_repo.checkout('master')
self.git_repo.pull()
else:
logging.info('No inventory repo was found, start cloning.')
self.git_repo.clone(shallow=True)
def get_data_dir(self, data_subdir='skylab'):
"""Get path to the data dir."""
return text_manager.get_data_dir(self.inventory_repo_dir, data_subdir)
def upload_change(self, commit_message, draft=False, dryrun=False,
submit=False):
"""Commit and upload the change to gerrit.
@param commit_message: Commit message of the CL to upload.
@param draft: Boolean indicating whether to upload the CL as a draft.
@param dryrun: Boolean indicating whether to run upload as a dryrun.
@param submit: Boolean indicating whether to submit the CL directly.
@return: Change number (int) of the CL if it's uploaded to Gerrit.
"""
self.git_repo.commit(commit_message)
remote = self.git_repo.remote()
output = self.git_repo.upload_cl(
remote, 'master', draft=draft, dryrun=dryrun)
if not dryrun:
change_number = extract_inventory_change(output)
if submit:
submit_inventory_change(change_number)
return change_number