aboutsummaryrefslogtreecommitdiff
path: root/llvm_tools
diff options
context:
space:
mode:
authorChristopher Di Bella <cjdb@google.com>2021-02-05 23:35:53 +0000
committerManoj Gupta <manojgupta@chromium.org>2021-02-12 16:15:36 +0000
commitf5dbbbe456585460ac20f2eb661b7d0fc436d68b (patch)
tree6af30666dddb4b312ad13f572ec814458a5e747f /llvm_tools
parent21929ca0b632ed328920391488eeaae4811eb617 (diff)
downloadtoolchain-utils-f5dbbbe456585460ac20f2eb661b7d0fc436d68b.tar.gz
adds cherry-picking to the nightly revert checker
BUG=chromium:1085465 TEST=nightly_revert_checker_test.py Change-Id: I8069bb3f6ca8d07f54568b85373910a192d11ea5 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/toolchain-utils/+/2680123 Auto-Submit: Christopher Di Bella <cjdb@google.com> Tested-by: Manoj Gupta <manojgupta@chromium.org> Reviewed-by: George Burgess <gbiv@chromium.org>
Diffstat (limited to 'llvm_tools')
-rw-r--r--llvm_tools/README.md16
-rwxr-xr-xllvm_tools/cherrypick_cl.py198
-rwxr-xr-xllvm_tools/git.py22
-rwxr-xr-xllvm_tools/nightly_revert_checker.py237
-rwxr-xr-xllvm_tools/nightly_revert_checker_test.py18
5 files changed, 332 insertions, 159 deletions
diff --git a/llvm_tools/README.md b/llvm_tools/README.md
index 783ec22d..8eff98ba 100644
--- a/llvm_tools/README.md
+++ b/llvm_tools/README.md
@@ -542,11 +542,23 @@ parents of 123abc.
This is an automated wrapper around `revert_checker.py`. It checks to see if any
new reverts happened across toolchains that we're trying to ship since it was
-last run. If so, it sends emails to appropriate groups.
+last run. If so, it either automatically cherry-picks the reverts, or sends
+emails to appropriate groups.
-Usage example:
+Usage example for cherry-picking:
+```
+PYTHONPATH=../ ./nightly_revert_checker.py \
+ cherry-pick
+ --state_file state.json \
+ --llvm_dir llvm-project-copy \
+ --chromeos_dir ../../../../
+ --reviewers=chromium-os-mage@google.com
+```
+
+Usage example for email:
```
PYTHONPATH=../ ./nightly_revert_checker.py \
+ email
--state_file state.json \
--llvm_dir llvm-project-copy \
--chromeos_dir ../../../../
diff --git a/llvm_tools/cherrypick_cl.py b/llvm_tools/cherrypick_cl.py
index 9e306725..ff385f97 100755
--- a/llvm_tools/cherrypick_cl.py
+++ b/llvm_tools/cherrypick_cl.py
@@ -17,6 +17,8 @@ import os
import shlex
import subprocess
import sys
+import typing as t
+from datetime import datetime
import chroot
import get_llvm_hash
@@ -141,6 +143,123 @@ def get_package_names(sha: str, llvm_dir: str) -> list:
return packages
+def add_cherrypicks_for_packages(packages: t.List[str], symlinks: t.List[str],
+ start_rev: git_llvm_rev.Rev,
+ rev: git_llvm_rev.Rev, sha: str,
+ llvm_config: git_llvm_rev.LLVMConfig):
+ """Create a patch and add its metadata for each package"""
+ for package, symlink in zip(packages, symlinks):
+ symlink_dir = os.path.dirname(symlink)
+ patches_json_path = os.path.join(symlink_dir, 'files/PATCHES.json')
+ relative_patches_dir = 'cherry' if package == 'llvm' else ''
+ patches_dir = os.path.join(symlink_dir, 'files', relative_patches_dir)
+ logging.info('Cherrypicking %s (%s) into %s', rev, sha, package)
+ add_cherrypick(patches_json_path, patches_dir, relative_patches_dir,
+ start_rev, llvm_config.dir, rev, sha, package)
+
+
+def make_cl(symlinks_to_uprev: t.List[str], llvm_symlink_dir: str, branch: str,
+ commit_messages: t.List[str], reviewers: t.Optional[t.List[str]],
+ cc: t.Optional[t.List[str]]):
+ symlinks_to_uprev = sorted(set(symlinks_to_uprev))
+ for symlink in symlinks_to_uprev:
+ update_chromeos_llvm_hash.UprevEbuildSymlink(symlink)
+ subprocess.check_output(['git', 'add', '--all'],
+ cwd=os.path.dirname(symlink))
+ git.UploadChanges(llvm_symlink_dir, branch, commit_messages, reviewers, cc)
+ git.DeleteBranch(llvm_symlink_dir, branch)
+
+
+def resolve_symbolic_sha(start_sha: str, llvm_symlink_dir: str) -> str:
+ if start_sha == 'llvm':
+ return parse_ebuild_for_assignment(llvm_symlink_dir, 'LLVM_HASH')
+
+ if start_sha == 'llvm-next':
+ return parse_ebuild_for_assignment(llvm_symlink_dir, 'LLVM_NEXT_HASH')
+
+ return start_sha
+
+
+def find_commits_and_make_cl(chroot_path: str, shas: t.List[str],
+ start_rev: git_llvm_rev.Rev,
+ llvm_config: git_llvm_rev.LLVMConfig,
+ llvm_symlink_dir: str, create_cl: bool,
+ reviewers: t.Optional[t.List[str]],
+ cc: t.Optional[t.List[str]]):
+ if create_cl:
+ branch = f'cherry-pick-{datetime.now().strftime("%Y%m%d%H%M%S%f")}'
+ git.CreateBranch(llvm_symlink_dir, branch)
+ symlinks_to_uprev = []
+ commit_messages = [
+ 'llvm: cherry-pick CLs from upstream\n',
+ ]
+
+ for sha in shas:
+ sha = resolve_llvm_ref(llvm_config.dir, sha)
+ rev = git_llvm_rev.translate_sha_to_rev(llvm_config, sha)
+ # Find out the llvm projects changed in this commit
+ packages = get_package_names(sha, llvm_config.dir)
+ # Find out the ebuild symlinks of the corresponding ChromeOS packages
+ symlinks = chroot.GetChrootEbuildPaths(chroot_path, [
+ 'sys-devel/llvm' if package == 'llvm' else 'sys-libs/' + package
+ for package in packages
+ ])
+ symlinks = chroot.ConvertChrootPathsToAbsolutePaths(chroot_path, symlinks)
+
+ add_cherrypicks_for_packages(packages, symlinks, start_rev, rev, sha,
+ llvm_config)
+ if create_cl:
+ symlinks_to_uprev.extend(symlinks)
+ commit_messages.extend([
+ '\n\nreviews.llvm.org/rG%s\n' % sha,
+ subprocess.check_output(['git', 'log', '-n1', '--oneline', sha],
+ cwd=llvm_config.dir,
+ encoding='utf-8')
+ ])
+
+ if create_cl:
+ make_cl(symlinks_to_uprev, llvm_symlink_dir, branch, commit_messages,
+ reviewers, cc)
+
+
+def do_cherrypick(chroot_path: str,
+ create_cl: bool,
+ start_sha: str,
+ shas: t.List[str],
+ reviewers: t.List[str] = None,
+ cc: t.List[str] = None):
+ llvm_symlink = chroot.ConvertChrootPathsToAbsolutePaths(
+ chroot_path, chroot.GetChrootEbuildPaths(chroot_path,
+ ['sys-devel/llvm']))[0]
+ llvm_symlink_dir = os.path.dirname(llvm_symlink)
+
+ git_status = subprocess.check_output(['git', 'status', '-s'],
+ cwd=llvm_symlink_dir,
+ encoding='utf-8')
+
+ if git_status:
+ error_path = os.path.dirname(os.path.dirname(llvm_symlink_dir))
+ raise ValueError(f'Uncommited changes detected in {error_path}')
+
+ start_sha = resolve_symbolic_sha(start_sha, llvm_symlink_dir)
+ logging.info('Base llvm hash == %s', start_sha)
+
+ llvm_config = git_llvm_rev.LLVMConfig(
+ remote='origin', dir=get_llvm_hash.GetAndUpdateLLVMProjectInLLVMTools())
+ start_sha = resolve_llvm_ref(llvm_config.dir, start_sha)
+
+ find_commits_and_make_cl(
+ chroot_path=chroot_path,
+ shas=shas,
+ start_rev=git_llvm_rev.translate_sha_to_rev(llvm_config, start_sha),
+ llvm_config=llvm_config,
+ llvm_symlink_dir=llvm_symlink_dir,
+ create_cl=create_cl,
+ reviewers=reviewers,
+ cc=cc)
+ logging.info('Complete.')
+
+
def main():
chroot.VerifyOutsideChroot()
logging.basicConfig(
@@ -170,80 +289,11 @@ def main():
help='Automatically create a CL if specified')
args = parser.parse_args()
- llvm_symlink = chroot.ConvertChrootPathsToAbsolutePaths(
- args.chroot_path,
- chroot.GetChrootEbuildPaths(args.chroot_path, ['sys-devel/llvm']))[0]
- llvm_symlink_dir = os.path.dirname(llvm_symlink)
-
- git_status = subprocess.check_output(['git', 'status', '-s'],
- cwd=llvm_symlink_dir,
- encoding='utf-8')
- if git_status:
- raise ValueError('Uncommited changes detected in %s' %
- os.path.dirname(os.path.dirname(llvm_symlink_dir)))
-
- start_sha = args.start_sha
- if start_sha == 'llvm':
- start_sha = parse_ebuild_for_assignment(llvm_symlink_dir, 'LLVM_HASH')
- elif start_sha == 'llvm-next':
- start_sha = parse_ebuild_for_assignment(llvm_symlink_dir, 'LLVM_NEXT_HASH')
- logging.info('Base llvm hash == %s', start_sha)
-
- llvm_config = git_llvm_rev.LLVMConfig(
- remote='origin', dir=get_llvm_hash.GetAndUpdateLLVMProjectInLLVMTools())
-
- start_sha = resolve_llvm_ref(llvm_config.dir, start_sha)
- start_rev = git_llvm_rev.translate_sha_to_rev(llvm_config, start_sha)
-
- if args.create_cl:
- branch = 'cherry-pick'
- git.CreateBranch(llvm_symlink_dir, branch)
- symlinks_to_uprev = []
- commit_messages = [
- 'llvm: cherry-pick CLs from upstream\n',
- ]
-
- for sha in args.sha:
- sha = resolve_llvm_ref(llvm_config.dir, sha)
- rev = git_llvm_rev.translate_sha_to_rev(llvm_config, sha)
- # Find out the llvm projects changed in this commit
- packages = get_package_names(sha, llvm_config.dir)
- # Find out the ebuild symlinks of the corresponding ChromeOS packages
- symlinks = chroot.GetChrootEbuildPaths(args.chroot_path, [
- 'sys-devel/llvm' if package == 'llvm' else 'sys-libs/' + package
- for package in packages
- ])
- symlinks = chroot.ConvertChrootPathsToAbsolutePaths(args.chroot_path,
- symlinks)
-
- # Create a patch and add its metadata for each package
- for package, symlink in zip(packages, symlinks):
- symlink_dir = os.path.dirname(symlink)
- patches_json_path = os.path.join(symlink_dir, 'files/PATCHES.json')
- relative_patches_dir = 'cherry' if package == 'llvm' else ''
- patches_dir = os.path.join(symlink_dir, 'files', relative_patches_dir)
- logging.info('Cherrypicking %s (%s) into %s', rev, sha, package)
-
- add_cherrypick(patches_json_path, patches_dir, relative_patches_dir,
- start_rev, llvm_config.dir, rev, sha, package)
- if args.create_cl:
- symlinks_to_uprev.extend(symlinks)
- commit_messages.extend([
- '\n\nreviews.llvm.org/rG%s\n' % sha,
- subprocess.check_output(['git', 'log', '-n1', '--oneline', sha],
- cwd=llvm_config.dir,
- encoding='utf-8')
- ])
-
- logging.info('Complete.')
-
- if args.create_cl:
- symlinks_to_uprev = list(sorted(set(symlinks_to_uprev)))
- for symlink in symlinks_to_uprev:
- update_chromeos_llvm_hash.UprevEbuildSymlink(symlink)
- subprocess.check_output(['git', 'add', '--all'], cwd=symlink_dir)
- git.UploadChanges(llvm_symlink_dir, branch, commit_messages)
- git.DeleteBranch(llvm_symlink_dir, branch)
+ do_cherrypick(
+ chroot_path=args.chroot_path,
+ create_cl=args.create_cl,
+ start_sha=args.start_sha,
+ shas=args.sha)
if __name__ == '__main__':
diff --git a/llvm_tools/git.py b/llvm_tools/git.py
index 5d057a75..22c7002a 100755
--- a/llvm_tools/git.py
+++ b/llvm_tools/git.py
@@ -72,7 +72,7 @@ def DeleteBranch(repo, branch):
subprocess.check_output(['git', '-C', repo, 'branch', '-D', branch])
-def UploadChanges(repo, branch, commit_messages):
+def UploadChanges(repo, branch, commit_messages, reviewers=None, cc=None):
"""Uploads the changes in the specifed branch of the given repo for review.
Args:
@@ -80,6 +80,8 @@ def UploadChanges(repo, branch, commit_messages):
branch: The name of the branch to upload.
commit_messages: A string of commit message(s) (i.e. '[message]'
of the changes made.
+ reviewers: A list of reviewers to add to the CL.
+ cc: A list of contributors to CC about the CL.
Returns:
A nametuple that has two (key, value) pairs, where the first pair is the
@@ -101,12 +103,24 @@ def UploadChanges(repo, branch, commit_messages):
subprocess.check_output(['git', 'commit', '-F', f.name], cwd=repo)
# Upload the changes for review.
+ git_args = [
+ 'repo',
+ 'upload',
+ '--yes',
+ f'--reviewers={",".join(reviewers)}' if reviewers else '--ne',
+ '--no-verify',
+ f'--br={branch}',
+ ]
+
+ if cc:
+ git_args.append(f'--cc={",".join(cc)}')
+
out = subprocess.check_output(
- ['repo', 'upload', '--yes', '--ne', '--no-verify',
- '--br=%s' % branch],
+ git_args,
stderr=subprocess.STDOUT,
cwd=repo,
- encoding='utf-8')
+ encoding='utf-8',
+ )
print(out)
diff --git a/llvm_tools/nightly_revert_checker.py b/llvm_tools/nightly_revert_checker.py
index 3a23890a..6b4ac53c 100755
--- a/llvm_tools/nightly_revert_checker.py
+++ b/llvm_tools/nightly_revert_checker.py
@@ -6,8 +6,8 @@
"""Checks for new reverts in LLVM on a nightly basis.
-If any reverts are found that were previously unknown, this fires off an email.
-All LLVM SHAs to monitor are autodetected.
+If any reverts are found that were previously unknown, this cherry-picks them or
+fires off an email. All LLVM SHAs to monitor are autodetected.
"""
# pylint: disable=cros-logging-import
@@ -29,12 +29,13 @@ import cros_utils.tiny_render as tiny_render
import get_llvm_hash
import git_llvm_rev
import revert_checker
+import cherrypick_cl
State = t.Any
-def _find_interesting_android_shas(
- android_llvm_toolchain_dir: str) -> t.List[t.Tuple[str]]:
+def _find_interesting_android_shas(android_llvm_toolchain_dir: str
+ ) -> t.List[t.Tuple[str, str]]:
llvm_project = os.path.join(android_llvm_toolchain_dir,
'toolchain/llvm-project')
@@ -55,8 +56,8 @@ def _find_interesting_android_shas(
return result
-def _parse_llvm_ebuild_for_shas(
- ebuild_file: io.TextIOWrapper) -> t.List[t.Tuple[str]]:
+def _parse_llvm_ebuild_for_shas(ebuild_file: io.TextIOWrapper
+ ) -> t.List[t.Tuple[str, str]]:
def parse_ebuild_assignment(line: str) -> str:
no_comments = line.split('#')[0]
@@ -84,7 +85,8 @@ def _parse_llvm_ebuild_for_shas(
return results
-def _find_interesting_chromeos_shas(chromeos_base: str) -> t.List[t.Tuple[str]]:
+def _find_interesting_chromeos_shas(chromeos_base: str
+ ) -> t.List[t.Tuple[str, str]]:
llvm_dir = os.path.join(chromeos_base,
'src/third_party/chromiumos-overlay/sys-devel/llvm')
candidate_ebuilds = [
@@ -193,18 +195,114 @@ def _read_state(state_file: str) -> State:
return {}
-def main(argv: t.List[str]) -> None:
+def find_shas(llvm_dir: str, interesting_shas: t.List[t.Tuple[str, str]],
+ state: State, new_state: State):
+ for friendly_name, sha in interesting_shas:
+ logging.info('Finding reverts across %s (%s)', friendly_name, sha)
+ all_reverts = revert_checker.find_reverts(
+ llvm_dir, sha, root='origin/' + git_llvm_rev.MAIN_BRANCH)
+ logging.info('Detected the following revert(s) across %s:\n%s',
+ friendly_name, pprint.pformat(all_reverts))
+
+ new_state[sha] = [r.sha for r in all_reverts]
+
+ if sha not in state:
+ logging.info('SHA %s is new to me', sha)
+ existing_reverts = set()
+ else:
+ existing_reverts = set(state[sha])
+
+ new_reverts = [r for r in all_reverts if r.sha not in existing_reverts]
+ if not new_reverts:
+ logging.info('...All of which have been reported.')
+ continue
+
+ yield (friendly_name, sha, new_reverts)
+
+
+def do_cherrypick(chroot_path: str, llvm_dir: str,
+ interesting_shas: t.List[t.Tuple[str, str]], state: State,
+ reviewers: t.List[str], cc: t.List[str]) -> State:
+ new_state: State = {}
+ seen: t.Set[str] = set()
+ for friendly_name, _sha, reverts in find_shas(llvm_dir, interesting_shas,
+ state, new_state):
+ if friendly_name in seen:
+ continue
+ seen.add(friendly_name)
+ for sha, reverted_sha in reverts:
+ cherrypick_cl.do_cherrypick(
+ chroot_path=chroot_path,
+ create_cl=True,
+ start_sha=reverted_sha,
+ shas=[sha],
+ reviewers=reviewers,
+ cc=cc)
+ return new_state
+
+
+def do_email(is_dry_run: bool, llvm_dir: str, repository: str,
+ interesting_shas: t.List[t.Tuple[str, str]], state: State,
+ recipients: _EmailRecipients) -> State:
+
+ def prettify_sha(sha: str) -> tiny_render.Piece:
+ rev = get_llvm_hash.GetVersionFrom(llvm_dir, sha)
+
+ # 12 is arbitrary, but should be unambiguous enough.
+ short_sha = sha[:12]
+ return tiny_render.Switch(
+ text=f'r{rev} ({short_sha})',
+ html=tiny_render.Link(
+ href='https://reviews.llvm.org/rG' + sha, inner='r' + str(rev)),
+ )
+
+ def get_sha_description(sha: str) -> tiny_render.Piece:
+ return subprocess.check_output(
+ ['git', 'log', '-n1', '--format=%s', sha],
+ cwd=llvm_dir,
+ encoding='utf-8',
+ ).strip()
+
+ new_state: State = {}
+ for friendly_name, sha, new_reverts in find_shas(llvm_dir, interesting_shas,
+ state, new_state):
+ email = _generate_revert_email(repository, friendly_name, sha, prettify_sha,
+ get_sha_description, new_reverts)
+ if is_dry_run:
+ logging.info('Would send email:\nSubject: %s\nBody:\n%s\n', email.subject,
+ tiny_render.render_text_pieces(email.body))
+ else:
+ logging.info('Sending email with subject %r...', email.subject)
+ _send_revert_email(recipients, email)
+ logging.info('Email sent.')
+ return new_state
+
+
+def parse_args(argv: t.List[str]) -> t.Any:
parser = argparse.ArgumentParser(
description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument(
+ 'action',
+ choices=['cherry-pick', 'email', 'dry-run'],
+ help='Automatically cherry-pick upstream reverts, send an email, or '
+ 'write to stdout.')
+ parser.add_argument(
'--state_file', required=True, help='File to store persistent state in.')
parser.add_argument(
'--llvm_dir', required=True, help='Up-to-date LLVM directory to use.')
- parser.add_argument(
- '--dry_run',
- action='store_true',
- help='Print email contents, rather than sending them.')
parser.add_argument('--debug', action='store_true')
+ parser.add_argument(
+ '--reviewers',
+ type=str,
+ nargs='*',
+ help='Requests reviews from REVIEWERS. All REVIEWERS must have existing '
+ 'accounts.')
+ parser.add_argument(
+ '--cc',
+ type=str,
+ nargs='*',
+ help='CCs the CL to the recipients. All recipients must have existing '
+ 'accounts.')
subparsers = parser.add_subparsers(dest='repository')
subparsers.required = True
@@ -219,91 +317,72 @@ def main(argv: t.List[str]) -> None:
required=True,
help='Up-to-date android-llvm-toolchain directory to use.')
- opts = parser.parse_args(argv)
+ return parser.parse_args(argv)
+
+
+def find_chroot(opts: t.Any, reviewers: t.List[str], cc: t.List[str]
+ ) -> t.Tuple[str, t.List[t.Tuple[str, str]], _EmailRecipients]:
+ recipients = reviewers + cc
+ if opts.repository == 'chromeos':
+ chroot_path = opts.chromeos_dir
+ return (chroot_path, _find_interesting_chromeos_shas(chroot_path),
+ _EmailRecipients(well_known=['mage'], direct=recipients))
+ elif opts.repository == 'android':
+ if opts.action == 'cherry-pick':
+ raise RuntimeError(
+ "android doesn't currently support automatic cherry-picking.")
+
+ chroot_path = opts.android_llvm_toolchain_dir
+ return (chroot_path, _find_interesting_android_shas(chroot_path),
+ _EmailRecipients(
+ well_known=[],
+ direct=['android-llvm-dev@google.com'] + recipients))
+ else:
+ raise ValueError(f'Unknown repository {opts.repository}')
+
+
+def main(argv: t.List[str]) -> int:
+ opts = parse_args(argv)
logging.basicConfig(
format='%(asctime)s: %(levelname)s: %(filename)s:%(lineno)d: %(message)s',
level=logging.DEBUG if opts.debug else logging.INFO,
)
- dry_run = opts.dry_run
+ action = opts.action
llvm_dir = opts.llvm_dir
repository = opts.repository
state_file = opts.state_file
+ reviewers = opts.reviewers if opts.reviewers else []
+ cc = opts.cc if opts.cc else []
- if repository == 'chromeos':
- interesting_shas = _find_interesting_chromeos_shas(opts.chromeos_dir)
- recipients = _EmailRecipients(well_known=['mage'], direct=[])
- elif repository == 'android':
- interesting_shas = _find_interesting_android_shas(
- opts.android_llvm_toolchain_dir)
- recipients = _EmailRecipients(
- well_known=[], direct=['android-llvm-dev@google.com'])
- else:
- raise ValueError('Unknown repository %s' % opts.repository)
-
+ chroot_path, interesting_shas, recipients = find_chroot(opts, reviewers, cc)
logging.info('Interesting SHAs were %r', interesting_shas)
state = _read_state(state_file)
logging.info('Loaded state\n%s', pprint.pformat(state))
- def prettify_sha(sha: str) -> tiny_render.Piece:
- rev = get_llvm_hash.GetVersionFrom(llvm_dir, sha)
-
- # 12 is arbitrary, but should be unambiguous enough.
- short_sha = sha[:12]
- return tiny_render.Switch(
- text='r%s (%s)' % (rev, short_sha),
- html=tiny_render.Link(
- href='https://reviews.llvm.org/rG' + sha, inner='r' + str(rev)),
- )
-
- def get_sha_description(sha: str) -> tiny_render.Piece:
- return subprocess.check_output(
- ['git', 'log', '-n1', '--format=%s', sha],
- cwd=llvm_dir,
- encoding='utf-8',
- ).strip()
-
- new_state: State = {}
- revert_emails_to_send: t.List[t.Tuple[str, t.List[revert_checker
- .Revert]]] = []
- for friendly_name, sha in interesting_shas:
- logging.info('Finding reverts across %s (%s)', friendly_name, sha)
- all_reverts = revert_checker.find_reverts(
- llvm_dir, sha, root='origin/' + git_llvm_rev.MAIN_BRANCH)
- logging.info('Detected the following revert(s) across %s:\n%s',
- friendly_name, pprint.pformat(all_reverts))
-
- new_state[sha] = [r.sha for r in all_reverts]
-
- if sha not in state:
- logging.info('SHA %s is new to me', sha)
- existing_reverts = set()
- else:
- existing_reverts = set(state[sha])
-
- new_reverts = [r for r in all_reverts if r.sha not in existing_reverts]
- if not new_reverts:
- logging.info('...All of which have been reported.')
- continue
-
- revert_emails_to_send.append(
- _generate_revert_email(repository, friendly_name, sha, prettify_sha,
- get_sha_description, new_reverts))
-
# We want to be as free of obvious side-effects as possible in case something
- # above breaks. Hence, send the email as late as possible.
- for email in revert_emails_to_send:
- if dry_run:
- logging.info('Would send email:\nSubject: %s\nBody:\n%s\n', email.subject,
- tiny_render.render_text_pieces(email.body))
- else:
- logging.info('Sending email with subject %r...', email.subject)
- _send_revert_email(recipients, email)
- logging.info('Email sent.')
+ # above breaks. Hence, action as late as possible.
+ if action == 'cherry-pick':
+ new_state = do_cherrypick(
+ chroot_path=chroot_path,
+ llvm_dir=llvm_dir,
+ interesting_shas=interesting_shas,
+ state=state,
+ reviewers=reviewers,
+ cc=cc)
+ else:
+ new_state = do_email(
+ is_dry_run=action == 'dry-run',
+ llvm_dir=llvm_dir,
+ repository=repository,
+ interesting_shas=interesting_shas,
+ state=state,
+ recipients=recipients)
_write_state(state_file, new_state)
+ return 0
if __name__ == '__main__':
diff --git a/llvm_tools/nightly_revert_checker_test.py b/llvm_tools/nightly_revert_checker_test.py
index 68338a59..72c51f81 100755
--- a/llvm_tools/nightly_revert_checker_test.py
+++ b/llvm_tools/nightly_revert_checker_test.py
@@ -10,6 +10,7 @@ from __future__ import print_function
import io
import unittest
+from unittest.mock import patch
import cros_utils.tiny_render as tiny_render
import nightly_revert_checker
@@ -153,6 +154,23 @@ class Test(unittest.TestCase):
self.assertIn('Failed to detect SHAs', str(e.exception))
+ @patch('revert_checker.find_reverts')
+ @patch('cherrypick_cl.do_cherrypick')
+ def test_do_cherrypick_is_called(self, do_cherrypick, find_reverts):
+ find_reverts.return_value = [
+ revert_checker.Revert('12345abcdef', 'fedcba54321')
+ ]
+ nightly_revert_checker.do_cherrypick(
+ chroot_path='/path/to/chroot',
+ llvm_dir='/path/to/llvm',
+ interesting_shas=[('12345abcdef', 'fedcba54321')],
+ state={},
+ reviewers=['meow@chromium.org'],
+ cc=['purr@chromium.org'])
+
+ do_cherrypick.assert_called_once()
+ find_reverts.assert_called_once()
+
if __name__ == '__main__':
unittest.main()