普通文本  |  163行  |  5.29 KB

# 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