blob: b315a05291082281c3ddec56e4a353a05d5e590c [file] [log] [blame]
# -*- coding: utf-8 -*-
# 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.
"""Commits files to the chromium git repository."""
from __future__ import print_function
import os
import sys
from chromite.lib import constants
from chromite.lib import commandline
from chromite.lib import cros_build_lib
from chromite.lib import cros_logging as logging
from chromite.lib import git
from chromite.lib import osutils
assert sys.version_info >= (3, 6), 'This module requires Python 3.6+'
class CommitError(Exception):
"""Raised if the commit failed."""
class ChromeCommitter(object):
"""Committer object responsible for committing a git change."""
def __init__(self, user_email, workdir, dryrun=False):
logging.info('user_email=%s, checkout_dir=%s', user_email, workdir)
self.author = user_email
self._checkout_dir = workdir
self._git_committer_args = ['-c', 'user.email=%s' % user_email,
'-c', 'user.name=%s' % user_email]
self._commit_msg = ''
self._dryrun = dryrun
def __del__(self):
self.Cleanup()
def FullPath(self, file_path):
"""Returns the full path in the source tree given a relative path.
Args:
file_path: Path of file.
Returns:
Full path rooted in source checkout.
"""
if os.path.isabs(file_path):
return file_path
return os.path.join(self._checkout_dir, file_path)
def Checkout(self, sparse_checkout):
"""Checks out chrome into tmp checkout dir.
Args:
sparse_checkout: List of file paths to fetch.
"""
assert isinstance(sparse_checkout, list)
sparse_checkout += ['codereview.settings', 'WATCHLISTS']
git.ShallowFetch(self._checkout_dir, constants.CHROMIUM_GOB_URL,
sparse_checkout=sparse_checkout)
git.CreateBranch(self._checkout_dir, 'auto-commit-branch',
branch_point='origin/master')
def Commit(self, file_paths, commit_msg):
"""Commits files listed in |file_paths|.
Args:
file_paths: List of files to commit.
commit_msg: Message to use in commit.
"""
assert file_paths and isinstance(file_paths, list)
# Make paths absolute and ensure they exist.
for i, file_path in enumerate(file_paths):
if not os.path.isabs(file_path):
file_paths[i] = self.FullPath(file_path)
if not os.path.exists(file_paths[i]):
raise CommitError('Invalid path: %s' % file_paths[i])
self._commit_msg = 'Automated Commit: ' + commit_msg
try:
for file_path in file_paths:
git.AddPath(file_path)
commit_args = ['commit', '-m', self._commit_msg]
git.RunGit(self._checkout_dir, self._git_committer_args + commit_args,
print_cmd=True, stderr=True, capture_output=False)
except cros_build_lib.RunCommandError as e:
raise CommitError('Could not create git commit: %r' % e)
def Upload(self):
"""Uploads the change to gerrit."""
logging.info('Uploading commit.')
try:
# Run 'git cl upload' with --bypass-hooks to skip running scripts that are
# not part of the shallow checkout, -f to skip editing the CL message,
upload_args = self._git_committer_args + [
'cl', 'upload', '-v', '-m', self._commit_msg, '--bypass-hooks', '-f',
'--tbrs', constants.CHROME_GARDENER_REVIEW_EMAIL]
# Marks CL as ready.
upload_args += ['--send-mail']
if self._dryrun:
upload_args += ['--dry-run']
else:
upload_args += ['--use-commit-queue']
git.RunGit(self._checkout_dir, upload_args, print_cmd=True,
stderr=True, capture_output=False)
except cros_build_lib.RunCommandError as e:
# Log the change for debugging.
git.RunGit(self._checkout_dir, ['--no-pager', 'log', '--pretty=full'],
capture_output=False)
raise CommitError('Could not submit: %r' % e)
logging.info('Submitted to CQ.')
def Cleanup(self):
"""Remove chrome checkout."""
osutils.RmDir(self._checkout_dir, ignore_missing=True)
@staticmethod
def GetParser():
"""Returns parser for ChromeCommitter.
Returns:
Parser for ChromeCommitter.
"""
# We need to use the account used by the builder to upload git CLs when
# generating CLs.
default_git_account = None
if cros_build_lib.HostIsCIBuilder(golo_only=True):
default_git_account = 'chromeos-commit-bot@chromium.org'
elif cros_build_lib.HostIsCIBuilder(gce_only=True):
default_git_account = '3su6n15k.default@developer.gserviceaccount.com'
parser = commandline.ArgumentParser(usage=__doc__, add_help=False)
parser.add_argument('--dryrun', action='store_true', default=False,
help="Don't commit changes or send out emails.")
parser.add_argument('--user_email', required=False,
default=default_git_account,
help='Email address to use when comitting changes.')
parser.add_argument('--workdir',
default=os.path.join(os.getcwd(), 'chrome_src'),
help=('Path to a checkout of the chrome src. '
'Defaults to PWD/chrome_src'))
return parser