aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Burgess IV <gbiv@google.com>2024-04-16 12:40:54 -0600
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2024-04-18 18:59:24 +0000
commit3ea4177ab04f9ed248f5f90ed3e0a5ff82efc9c0 (patch)
tree09a53abc4300b7525ac536f42978612f5a5b8aeb
parent98826b0c2996fd795d5d991ed023d7846c5936a8 (diff)
downloadtoolchain-utils-3ea4177ab04f9ed248f5f90ed3e0a5ff82efc9c0.tar.gz
llvm_tools: overhaul update_packages_and_run_tests
This is a full rewrite, dropping a lot of the no-longer-needed functionality here on the floor. BUG=b:333462347 TEST=crrev.com/i/7190043 and crrev.com/c/5459856 Change-Id: Ia997bbb986660aaa3a1bfe644959cb847c6da41b Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/toolchain-utils/+/5458719 Reviewed-by: Jordan Abrahams-Whitehead <ajordanr@google.com> Commit-Queue: George Burgess <gbiv@chromium.org> Tested-by: George Burgess <gbiv@chromium.org>
-rw-r--r--cros_utils/git_utils.py52
-rw-r--r--llvm_tools/manifest_utils.py39
-rwxr-xr-xllvm_tools/update_packages_and_run_tests.py824
-rwxr-xr-xllvm_tools/update_packages_and_run_tests_unittest.py568
-rwxr-xr-xllvm_tools/upload_llvm_testing_helper_cl.py34
5 files changed, 426 insertions, 1091 deletions
diff --git a/cros_utils/git_utils.py b/cros_utils/git_utils.py
index f249db90..cf299b77 100644
--- a/cros_utils/git_utils.py
+++ b/cros_utils/git_utils.py
@@ -17,6 +17,11 @@ from typing import Generator, Iterable, List
# Email address used to tag the detective as a reviewer.
REVIEWER_DETECTIVE = "c-compiler-chrome@google.com"
+# Default git naming conventions throughout ChromeOS.
+CROS_EXTERNAL_REMOTE = "cros"
+CROS_INTERNAL_REMOTE = "cros-internal"
+CROS_MAIN_BRANCH = "main"
+
def _parse_cls_from_upload_output(upload_output: str) -> List[int]:
"""Returns the CL number in the given upload output."""
@@ -157,3 +162,50 @@ def create_worktree(git_directory: Path) -> Generator[Path, None, None]:
check=False,
stdin=subprocess.DEVNULL,
)
+
+
+def resolve_ref(git_dir: Path, ref: str) -> str:
+ """Resolves the given ref or SHA shorthand to a full SHA.
+
+ Raises:
+ subprocess.CalledProcessError if resolution fails
+ """
+ return subprocess.run(
+ ["git", "rev-parse", ref],
+ check=True,
+ cwd=git_dir,
+ stdin=subprocess.DEVNULL,
+ stdout=subprocess.PIPE,
+ encoding="utf-8",
+ ).stdout.strip()
+
+
+def commit_all_changes(git_dir: Path, message: str) -> str:
+ """Commits all changes in `git_dir`, with the given commit message.
+
+ This also commits any untracked files in `git_dir`.
+
+ Args:
+ git_dir: Anywhere in the git directory in which changes should be
+ committed.
+ message: Message of the commit message.
+
+ Returns:
+ The SHA of the committed change.
+ """
+ # Explicitly add using `git add -A`, since that stages all unstaged changes
+ # & adds any files that aren't tracked. `git commit -a` skips adding
+ # untracked files.
+ subprocess.run(
+ ["git", "add", "-A"],
+ check=True,
+ cwd=git_dir,
+ stdin=subprocess.DEVNULL,
+ )
+ subprocess.run(
+ ["git", "commit", "-m", message],
+ check=True,
+ cwd=git_dir,
+ stdin=subprocess.DEVNULL,
+ )
+ return resolve_ref(git_dir, "HEAD")
diff --git a/llvm_tools/manifest_utils.py b/llvm_tools/manifest_utils.py
index e53afa6d..48159b0f 100644
--- a/llvm_tools/manifest_utils.py
+++ b/llvm_tools/manifest_utils.py
@@ -86,6 +86,20 @@ def extract_current_llvm_hash_from_xml(xmlroot: ElementTree.Element) -> str:
return revision
+def update_chromeos_manifest_in_manifest_dir(
+ revision: str, manifest_dir: Path
+) -> Path:
+ """update_chromeos_manifest, taking the directory to manifest-interal."""
+ manifest_path = get_chromeos_manifest_path_from_manifest_dir(manifest_dir)
+ parser = make_xmlparser()
+ xmltree = ElementTree.parse(manifest_path, parser)
+ update_chromeos_manifest_tree(revision, xmltree.getroot())
+ with atomic_write_file.atomic_write(manifest_path, mode="wb") as f:
+ xmltree.write(f, encoding="utf-8")
+ format_manifest(manifest_path)
+ return manifest_path
+
+
def update_chromeos_manifest(revision: str, src_tree: Path) -> Path:
"""Replaces the manifest project revision with 'revision'.
@@ -107,19 +121,26 @@ def update_chromeos_manifest(revision: str, src_tree: Path) -> Path:
UpdateManifestError: The manifest could not be changed.
FormattingError: The manifest could not be reformatted.
"""
- manifest_path = get_chromeos_manifest_path(src_tree)
- parser = make_xmlparser()
- xmltree = ElementTree.parse(manifest_path, parser)
- update_chromeos_manifest_tree(revision, xmltree.getroot())
- with atomic_write_file.atomic_write(manifest_path, mode="wb") as f:
- xmltree.write(f, encoding="utf-8")
- format_manifest(manifest_path)
- return manifest_path
+ return update_chromeos_manifest_in_manifest_dir(
+ revision, get_manifest_internal_path(src_tree)
+ )
+
+
+def get_manifest_internal_path(src_tree: Path) -> Path:
+ """Return the path to manifest-internal inside of the CrOS tree."""
+ return src_tree / "manifest-internal"
def get_chromeos_manifest_path(src_tree: Path) -> Path:
"""Return the path to the toolchain manifest."""
- return src_tree / "manifest-internal" / "_toolchain.xml"
+ return get_chromeos_manifest_path_from_manifest_dir(
+ get_manifest_internal_path(src_tree)
+ )
+
+
+def get_chromeos_manifest_path_from_manifest_dir(manifest_dir: Path) -> Path:
+ """Return the path to the toolchain manifest in a manifest dir."""
+ return manifest_dir / "_toolchain.xml"
def update_chromeos_manifest_tree(revision: str, xmlroot: ElementTree.Element):
diff --git a/llvm_tools/update_packages_and_run_tests.py b/llvm_tools/update_packages_and_run_tests.py
index 34837630..7bb127eb 100755
--- a/llvm_tools/update_packages_and_run_tests.py
+++ b/llvm_tools/update_packages_and_run_tests.py
@@ -1,603 +1,359 @@
#!/usr/bin/env python3
-# Copyright 2019 The ChromiumOS Authors
+# Copyright 2024 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Runs a tryjob/tryjobs after updating the packages."""
+"""Uploads CLs necessary to run LLVM testing at an arbitrary SHA.
+
+Also has the ability to:
+- kick off a CQ run
+- keep track of the last SHA that testing was requested on, and skip
+ re-uploading if the SHA has not changed.
+"""
import argparse
-import datetime
+import dataclasses
import json
-import os
+import logging
from pathlib import Path
import subprocess
-from typing import Any, Dict, Iterable, List, Optional, Union
+import sys
+import textwrap
+from typing import List, Optional
+import atomic_write_file
import chroot
-import failure_modes
+from cros_utils import git_utils
import get_llvm_hash
-import update_chromeos_llvm_hash
+import llvm_next
+import manifest_utils
+import upload_llvm_testing_helper_cl
-VALID_CQ_TRYBOTS = ("llvm", "llvm-next")
+def resolve_llvm_sha(chromeos_tree: Path, sha_or_special: str) -> str:
+ """Resolves the `--sha` flag to an LLVM SHA."""
+ if sha_or_special == "llvm-next":
+ return llvm_next.LLVM_NEXT_HASH
+ if sha_or_special == "google3":
+ return get_llvm_hash.LLVMHash().GetGoogle3LLVMHash()
+ if sha_or_special == "google3-unstable":
+ return get_llvm_hash.LLVMHash().GetGoogle3LLVMHash()
+ return git_utils.resolve_ref(chromeos_tree, sha_or_special)
-def GetCommandLineArgs() -> argparse.Namespace:
- """Parses the command line for the command line arguments.
+def read_last_tried_sha(retry_state: Path) -> Optional[str]:
+ """Reads the last tried SHA from the state file."""
+ try:
+ with retry_state.open(encoding="utf-8") as f:
+ return json.load(f)["last_tried_sha"]
+ except FileNotFoundError:
+ return None
- Returns:
- The log level to use when retrieving the LLVM hash or google3 LLVM
- version, the chroot path to use for executing chroot commands,
- a list of a package or packages to update their LLVM next hash,
- and the LLVM version to use when retrieving the LLVM hash.
- """
- # Default path to the chroot if a path is not specified.
- cros_root = os.path.expanduser("~")
- cros_root = os.path.join(cros_root, "chromiumos")
+def write_last_tried_sha(retry_state: Path, sha: str):
+ """Writes the last tried SHA to the state file."""
+ with atomic_write_file.atomic_write(retry_state) as f:
+ json.dump({"last_tried_sha": sha}, f)
- # Create parser and add optional command-line arguments.
- parser = argparse.ArgumentParser(
- description="Update an LLVM hash of packages and run tests."
- )
- # Add argument for other change lists that want to run alongside the tryjob
- # which has a change list of updating a package's git hash.
- parser.add_argument(
- "--extra_change_lists",
- type=int,
- nargs="+",
- default=[],
- help="change lists that would like to be run alongside the change list "
- "of updating the packages",
- )
+@dataclasses.dataclass(frozen=True)
+class UploadedCLs:
+ """Listing of CL numbers uploaded by a function."""
- # Add argument for a specific chroot path.
- parser.add_argument(
- "--chromeos_path",
- default=cros_root,
- help="the path to the ChromeOS tree (default: %(default)s)",
- )
+ internal: List[int]
+ external: List[int]
- # Add argument for a specific chroot path.
- parser.add_argument(
- "--chroot_name",
- default="chroot",
- help="""
- the name of the chroot to use in the CrOS checkout. Defaults to
- 'chroot'.
- """,
- )
- parser.add_argument(
- "--chroot_out",
- help="""
- the name of the chroot to use in the CrOS checkout. Defaults to
- 'out' if the chroot's name is 'chroot'; otherwise, defaults to
- '${chroot_name}_out'.
- """,
- )
+def upload_one_cl_to_main(git_dir: Path, sha: str, remote: str) -> int:
+ """Uploads exactly one SHA from `git_dir`. Returns the CL number.
- # Add argument to choose between llvm and llvm-next.
- parser.add_argument(
- "--is_llvm_next",
- action="store_true",
- help="which llvm hash to update. Update LLVM_NEXT_HASH if specified. "
- "Otherwise, update LLVM_HASH",
+ Raises:
+ AssertionError if more than one CL was uploaded.
+ """
+ cl_ids = git_utils.upload_to_gerrit(
+ git_dir,
+ remote=remote,
+ branch=git_utils.CROS_MAIN_BRANCH,
+ ref=sha,
)
+ assert len(cl_ids) == 1, f"Expected to upload one CL; uploaded {cl_ids}"
+ return cl_ids[0]
- # Add argument for the absolute path to the file that contains information
- # on the previous tested svn version.
- parser.add_argument(
- "--last_tested",
- help="the absolute path to the file that contains the last tested "
- "arguments.",
- )
- # Add argument for the LLVM version to use.
- parser.add_argument(
- "--llvm_version",
- type=get_llvm_hash.IsSvnOption,
- required=True,
- help="which git hash of LLVM to find "
- "{google3, ToT, <svn_version>} "
- "(default: finds the git hash of the google3 LLVM "
- "version)",
- )
+def create_and_upload_test_helpers_cl(
+ chromeos_tree: Path, dry_run: bool
+) -> int:
+ """Creates & uploads the LLVM 'test helper' CL.
- # Add argument to add reviewers for the created CL.
- parser.add_argument(
- "--reviewers",
- nargs="+",
- default=[],
- help="The reviewers for the package update changelist",
+ Returns:
+ The CL number of the test-helper CL, an int referencing an external CL.
+ If dry_run is passed, returns 0.
+ """
+ chromiumos_overlay = (
+ chromeos_tree / "src" / "third_party" / "chromiumos-overlay"
)
-
- subparsers = parser.add_subparsers(dest="subparser_name")
- subparser_names = []
- # Testing with the tryjobs.
- tryjob_subparser = subparsers.add_parser("tryjobs")
- subparser_names.append("tryjobs")
- tryjob_subparser.add_argument(
- "--builders",
- required=True,
- nargs="+",
- default=[],
- help="builders to use for the tryjob testing",
+ sha = upload_llvm_testing_helper_cl.create_helper_cl_commit_in_worktree_of(
+ chromiumos_overlay
)
-
- # Add argument for custom options for the tryjob.
- tryjob_subparser.add_argument(
- "--options",
- required=False,
- nargs="+",
- default=[],
- help="options to use for the tryjob testing",
+ if dry_run:
+ logging.info(
+ "--dry-run passed; skipping upload of test-helpers CL %s", sha
+ )
+ return 0
+ return upload_one_cl_to_main(
+ chromiumos_overlay, sha, remote=git_utils.CROS_EXTERNAL_REMOTE
)
- # Testing with the recipe builders
- recipe_subparser = subparsers.add_parser("recipe")
- subparser_names.append("recipe")
- recipe_subparser.add_argument(
- "--options",
- required=False,
- nargs="+",
- default=[],
- help="options passed to the recipe builders",
- )
- recipe_subparser.add_argument(
- "--builders",
- required=True,
- nargs="+",
- default=[],
- help="recipe builders to launch",
- )
+def build_manifest_commit_message(
+ llvm_sha: str,
+ llvm_rev: int,
+ cq_depend_external: Optional[int],
+) -> str:
+ msg = textwrap.dedent(
+ f"""\
+ toolchain.xml: update llvm to {llvm_sha} (r{llvm_rev})
- # Testing with CQ.
- cq_subparser = subparsers.add_parser("cq")
- subparser_names.append("cq")
-
- # Add argument for specify a cq trybot to test along with other cq builders
- # e.g. llvm, llvm-next or llvm-tot
- cq_subparser.add_argument(
- "--cq_trybot",
- choices=VALID_CQ_TRYBOTS,
- help="include the trybot to test together with other cq builders "
- "available: %(choices)s",
+ BUG=None
+ TEST=CQ
+ """
)
-
- args_output = parser.parse_args()
-
- if args_output.subparser_name not in subparser_names:
- parser.error("one of %s must be specified" % subparser_names)
-
- if not args_output.chroot_out:
- chroot_name = args_output.chroot_name
- if chroot_name == "chroot":
- out = "out"
- else:
- out = f"{chroot_name}_out"
- args_output.chroot_out = out
-
- return args_output
+ if cq_depend_external:
+ msg += f"\n\nCq-Depend: chromium:{cq_depend_external}"
+ return msg
-def UnchangedSinceLastRun(
- last_tested_file: Optional[Union[Path, str]],
- arg_dict: Dict,
-) -> bool:
- """Gets the arguments used for last run
-
- Args:
- last_tested_file: The absolute path to the file that contains the
- arguments for the last run.
- arg_dict: The arguments used for this run.
+def create_and_upload_manifest_cl(
+ chromeos_tree: Path,
+ llvm_sha: str,
+ llvm_rev: int,
+ cq_depend_external: Optional[int],
+ dry_run: bool,
+) -> int:
+ """Creates & uploads the LLVM update manifest CL.
Returns:
- Return true if the arguments used for last run exist and are the
- same as the arguments used for this run. Otherwise return false.
- """
-
- if not last_tested_file:
- return False
-
- # Get the last tested svn version if the file exists.
- last_arg_dict = None
- try:
- with open(last_tested_file, encoding="utf-8") as f:
- last_arg_dict = json.load(f)
-
- except (IOError, ValueError):
- return False
-
- return arg_dict == last_arg_dict
-
-
-def AddReviewers(
- cl: int,
- reviewers: Iterable[str],
- chromeos_path: Union[Path, str],
-) -> None:
- """Add reviewers for the created CL.
-
- Args:
- cl: The CL number to add reviewers to.
- reviewers: Email addresses of reviewers to add.
- chromeos_path: The absolute path to the chromeos tree.
- """
-
- gerrit_abs_path = os.path.join(chromeos_path, "chromite/bin/gerrit")
- for reviewer in reviewers:
- cmd = [gerrit_abs_path, "reviewers", str(cl), reviewer]
-
- subprocess.check_output(cmd)
-
-
-def AddLinksToCL(
- tests: Iterable[Dict[str, Any]],
- cl: int,
- chromeos_path: Union[Path, str],
-) -> None:
- """Adds the test link(s) to the CL as a comment.
-
- Args:
- tests: Links to the tests.
- cl: The number of the CL to add the test links to.
- chromeos_path: Absolute path to the chromeos tree.
- """
-
- # NOTE: Invoking `cros_sdk` does not make each tryjob link appear on its
- # own line, so invoking the `gerrit` command directly instead of using
- # `cros_sdk` to do it for us.
- #
- # FIXME: Need to figure out why `cros_sdk` does not add each tryjob link as
- # a newline.
- gerrit_abs_path = os.path.join(chromeos_path, "chromite/bin/gerrit")
-
- links = ["Started the following tests:"]
- links.extend(test["link"] for test in tests)
-
- add_message_cmd = [gerrit_abs_path, "message", str(cl), "\n".join(links)]
-
- subprocess.check_output(add_message_cmd)
-
-
-# Testing with tryjobs
-def GetCurrentTimeInUTC() -> datetime.datetime:
- """Returns the current time via `datetime.datetime.utcnow()`."""
- return datetime.datetime.utcnow()
-
-
-def GetTryJobCommand(
- change_list: int,
- extra_change_lists: Iterable[int],
- options: Iterable[str],
- builder: str,
-) -> List[str]:
- """Constructs the 'tryjob' command.
-
- Args:
- change_list: The CL obtained from updating the packages.
- extra_change_lists: Extra change lists that would like to be run
- alongside the change list of updating the packages.
- options: Options to be passed into the tryjob command.
- builder: The builder to be passed into the tryjob command.
-
- Returns:
- The 'tryjob' command with the change list of updating the packages and
- any extra information that was passed into the command line.
- """
-
- tryjob_cmd = ["cros", "tryjob", "--yes", "--json", "-g", "%d" % change_list]
-
- if extra_change_lists:
- for extra_cl in extra_change_lists:
- tryjob_cmd.extend(["-g", "%d" % extra_cl])
-
- if options:
- tryjob_cmd.extend("--%s" % option for option in options)
-
- tryjob_cmd.append(builder)
-
- return tryjob_cmd
-
-
-def RunTryJobs(
- cl_number: int,
- extra_change_lists: List[int],
- options: List[str],
- builders: Iterable[str],
- chromeos_path: Union[Path, str],
-) -> List[Dict]:
- """Runs a tryjob/tryjobs.
-
- Args:
- cl_number: The CL created by updating the packages.
- extra_change_lists: Any extra change lists that would run alongside the
- CL that was created by updating the packages ('cl_number').
- options: Any options to be passed into the 'tryjob' command.
- builders: All the builders to run the 'tryjob' with.
- chromeos_path: The absolute path to the chromeos tree.
-
- Returns:
- A list that contains stdout contents of each tryjob, where stdout is
- information (a hashmap) about the tryjob. The hashmap also contains
- stderr if there was an error when running a tryjob.
-
- Raises:
- ValueError: Failed to submit a tryjob.
+ The CL number of the manifest CL, an int referencing an internal CL. If
+ dry_run is passed, returns `0`.
"""
-
- # Contains the results of each builder.
- tests = []
-
- # Run tryjobs with the change list number obtained from updating the
- # packages and append additional changes lists and options obtained from the
- # command line.
- for builder in builders:
- cmd = GetTryJobCommand(cl_number, extra_change_lists, options, builder)
-
- out = subprocess.check_output(cmd, cwd=chromeos_path, encoding="utf-8")
-
- test_output = json.loads(out)
-
- buildbucket_id = int(test_output[0]["id"])
-
- tests.append(
- {
- "launch_time": str(GetCurrentTimeInUTC()),
- "link": "http://ci.chromium.org/b/%s" % buildbucket_id,
- "buildbucket_id": buildbucket_id,
- "extra_cls": extra_change_lists,
- "options": options,
- "builder": [builder],
- }
+ manifest_internal = chromeos_tree / "manifest-internal"
+ with git_utils.create_worktree(manifest_internal) as worktree:
+ manifest_utils.update_chromeos_manifest_in_manifest_dir(
+ llvm_sha, worktree
)
+ commit_msg = build_manifest_commit_message(
+ llvm_sha, llvm_rev, cq_depend_external
+ )
+ sha = git_utils.commit_all_changes(worktree, commit_msg)
- AddLinksToCL(tests, cl_number, chromeos_path)
-
- return tests
+ if dry_run:
+ logging.info("--dry-run passed; skipping upload of manifest CL %s", sha)
+ return 0
+ return upload_one_cl_to_main(
+ manifest_internal,
+ sha,
+ remote=git_utils.CROS_INTERNAL_REMOTE,
+ )
-def StartRecipeBuilders(
- cl_number: int,
- extra_change_lists: List[int],
- options: List[str],
- builders: List[str],
- chromeos_path: Union[Path, str],
-) -> List[Dict]:
- """Launch recipe builders.
- Args:
- cl_number: The CL created by updating the packages.
- extra_change_lists: Any extra change lists that would run alongside the
- CL that was created by updating the packages ('cl_number').
- options: Any options to be passed into the 'tryjob' command.
- builders: All the builders to run the 'tryjob' with.
- chromeos_path: The absolute path to the chromeos tree.
+def add_cl_comment(
+ chromeos_tree: Path,
+ cl_id: int,
+ internal: bool,
+ comment: str,
+):
+ """Creates & uploads the LLVM update manifest CL.
Returns:
- A list that contains stdout contents of each builder, where stdout is
- information (a hashmap) about the tryjob. The hashmap also contains
- stderr if there was an error when running a tryjob.
-
- Raises:
- ValueError: Failed to start a builder.
+ The CL number of the manifest CL, an int referencing an internal CL.
"""
+ cmd = ["gerrit"]
+ if internal:
+ cmd.append("--internal")
+ cmd += ("message", str(cl_id), comment)
+ subprocess.run(
+ cmd,
+ check=True,
+ cwd=chromeos_tree,
+ stdin=subprocess.DEVNULL,
+ )
- # Contains the results of each builder.
- tests = []
-
- # Launch a builders with the change list number obtained from updating the
- # packages and append additional changes lists and options obtained from the
- # command line.
- for builder in builders:
- cmd = ["bb", "add", "-json"]
-
- if cl_number:
- cmd.extend(["-cl", "crrev.com/c/%d" % cl_number])
-
- if extra_change_lists:
- for cl in extra_change_lists:
- cmd.extend(["-cl", "crrev.com/c/%d" % cl])
-
- if options:
- cmd.extend(options)
-
- cmd.append(builder)
-
- out = subprocess.check_output(cmd, cwd=chromeos_path, encoding="utf-8")
-
- test_output = json.loads(out)
- tests.append(
- {
- "launch_time": test_output["createTime"],
- "link": "http://ci.chromium.org/b/%s" % test_output["id"],
- "buildbucket_id": test_output["id"],
- "extra_cls": extra_change_lists,
- "options": options,
- "builder": [builder],
- }
+def create_and_upload_cls(
+ chromeos_tree: Path,
+ llvm_sha: str,
+ llvm_rev: int,
+ include_test_helpers: bool,
+ dry_run: bool,
+) -> UploadedCLs:
+ external_cls = []
+ if include_test_helpers:
+ logging.info("Uploading test-helper CL...")
+ test_helper_cl = create_and_upload_test_helpers_cl(
+ chromeos_tree, dry_run
)
+ external_cls.append(test_helper_cl)
+ else:
+ test_helper_cl = None
+ logging.info("Creating LLVM update CL...")
+ manifest_cl = create_and_upload_manifest_cl(
+ chromeos_tree,
+ llvm_sha,
+ llvm_rev,
+ test_helper_cl,
+ dry_run,
+ )
+ # Notably, this is meant to catch `test_helper_cl == 0` (dry_run) or
+ # `test_helper_cl == None` (if none was uploaded)
+ if test_helper_cl:
+ add_cl_comment(
+ chromeos_tree,
+ test_helper_cl,
+ internal=False,
+ comment=f"Corresponding Manifest update: crrev.com/i/{manifest_cl}",
+ )
+ return UploadedCLs(
+ internal=[manifest_cl],
+ external=external_cls,
+ )
- AddLinksToCL(tests, cl_number, chromeos_path)
-
- return tests
-
-
-# Testing with CQ
-def GetCQDependString(dependent_cls: List[int]) -> Optional[str]:
- """Get CQ dependency string e.g. `Cq-Depend: chromium:MM, chromium:NN`."""
-
- if not dependent_cls:
- return None
-
- # Cq-Depend must start a new paragraph prefixed with "Cq-Depend".
- return "Cq-Depend: " + ", ".join(f"chromium:{x}" for x in dependent_cls)
-
-
-def GetCQIncludeTrybotsString(trybot: Optional[str]) -> Optional[str]:
- """Get Cq-Include-Trybots string, for more llvm testings"""
-
- if not trybot:
- return None
-
- if trybot not in VALID_CQ_TRYBOTS:
- raise ValueError("%s is not a valid llvm trybot" % trybot)
-
- # Cq-Include-Trybots must start a new paragraph prefixed
- # with "Cq-Include-Trybots".
- return "Cq-Include-Trybots:chromeos/cq:cq-%s-orchestrator" % trybot
-
-
-def StartCQDryRun(
- cl: int,
- dependent_cls: List[int],
- chromeos_path: Union[Path, str],
-) -> None:
- """Start CQ dry run for the changelist and dependencies."""
-
- gerrit_abs_path = os.path.join(chromeos_path, "chromite/bin/gerrit")
-
- cl_list = [cl]
- cl_list.extend(dependent_cls)
-
- for changes in cl_list:
- cq_dry_run_cmd = [gerrit_abs_path, "label-cq", str(changes), "1"]
-
- subprocess.check_output(cq_dry_run_cmd)
-
-
-def main():
- """Updates the packages' LLVM hash and run tests.
-
- Raises:
- AssertionError: The script was run inside the chroot.
- """
- chroot.VerifyOutsideChroot()
+def make_gerrit_cq_dry_run_command(cls: List[int], internal: bool) -> List[str]:
+ assert cls, "Can't make a dry-run command with no CLs to dry-run."
+ cmd = ["gerrit"]
+ if internal:
+ cmd.append("--internal")
+ cmd.append("label-cq")
+ cmd += (str(x) for x in cls)
+ cmd.append("1")
+ return cmd
+
+
+def cq_dry_run_cls(chromeos_tree: Path, cls: UploadedCLs):
+ """Sets CQ+1 on the given uploaded CL listing."""
+ # At the time of writing, this is expected given the context of the script.
+ # Can easily refactor to make `cls.internal` optional, though.
+ gerrit_cmds = []
+ assert cls.internal, "LLVM update without internal CLs?"
+ gerrit_cmds.append(
+ make_gerrit_cq_dry_run_command(cls.internal, internal=True)
+ )
+ if cls.external:
+ gerrit_cmds.append(
+ make_gerrit_cq_dry_run_command(cls.external, internal=False)
+ )
+ for cmd in gerrit_cmds:
+ subprocess.run(
+ cmd,
+ check=True,
+ cwd=chromeos_tree,
+ stdin=subprocess.DEVNULL,
+ )
- args_output = GetCommandLineArgs()
- chroot.VerifyChromeOSRoot(args_output.chromeos_path)
+def parse_opts(argv: List[str]) -> argparse.Namespace:
+ """Parse command-line options."""
+ parser = argparse.ArgumentParser(
+ description=__doc__,
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ )
+ parser.add_argument(
+ "--chromeos-tree",
+ type=Path,
+ help="""
+ ChromeOS tree to make modifications in. Will be inferred if none
+ is passed.
+ """,
+ )
+ parser.add_argument(
+ "--cq",
+ action="store_true",
+ help="After uploading, set CQ+1 on the CL(s) that were uploaded.",
+ )
+ parser.add_argument(
+ "--dry-run",
+ action="store_true",
+ help="If passed, only commit changes locally; don't upload them.",
+ )
+ parser.add_argument(
+ "--include-llvm-test-helper-cls",
+ action="store_true",
+ help="""
+ Also upload CL(s) meant to ease LLVM testing. Namely, this will include
+ logic to disable `-Werror` on packages, and logic to disable patches
+ that no longer apply to LLVM.
+ """,
+ )
+ parser.add_argument(
+ "--retry-state",
+ type=Path,
+ help="""
+ If passed, this will keep script state in the given file. At the
+ moment, this file is only used to ensure that subsequent runs of this
+ script don't trigger identical uploads.
+ """,
+ )
+ parser.add_argument(
+ "--sha",
+ required=True,
+ help="""
+ SHA to use. This can either be an LLVM SHA, or a special value:
+ `llvm-next`, `google3` or `google3-unstable`.
+ """,
+ )
+ return parser.parse_args(argv)
- svn_option = args_output.llvm_version
- git_hash, svn_version = get_llvm_hash.GetLLVMHashAndVersionFromSVNOption(
- svn_option
+def main(argv: List[str]) -> None:
+ my_dir = Path(__file__).parent.resolve()
+ logging.basicConfig(
+ format=">> %(asctime)s: %(levelname)s: %(filename)s:%(lineno)d: "
+ "%(message)s",
+ level=logging.INFO,
)
- # There is no need to run tryjobs when all the key parameters remain
- # unchanged from last time.
-
- # If --last_tested is specified, check if the current run has the same
- # arguments last time --last_tested is used.
- if args_output.last_tested:
- chroot_file_paths = chroot.GetChrootEbuildPaths(
- args_output.chromeos_path,
- update_chromeos_llvm_hash.DEFAULT_PACKAGES,
- args_output.chroot_name,
- args_output.chroot_out,
- )
- arg_dict = {
- "svn_version": svn_version,
- "ebuilds": chroot_file_paths,
- "extra_cls": args_output.extra_change_lists,
- }
- if args_output.subparser_name in ("tryjobs", "recipe"):
- arg_dict["builders"] = args_output.builders
- arg_dict["tryjob_options"] = args_output.options
- if UnchangedSinceLastRun(args_output.last_tested, arg_dict):
- print(
- "svn version (%d) matches the last tested svn version in %s"
- % (svn_version, args_output.last_tested)
- )
+ opts = parse_opts(argv)
+ dry_run = opts.dry_run
+ chromeos_tree = opts.chromeos_tree
+ if not chromeos_tree:
+ chromeos_tree = chroot.FindChromeOSRootAbove(my_dir)
+
+ new_sha = resolve_llvm_sha(chromeos_tree, opts.sha)
+ logging.info("Using LLVM SHA %s...", new_sha)
+ if opts.retry_state:
+ last_tried_sha = read_last_tried_sha(opts.retry_state)
+ if last_tried_sha == new_sha:
+ logging.info("New SHA is the same as the last tried SHA; quit.")
return
+ logging.info(
+ "New SHA is different than the last tried SHA (%s).", last_tried_sha
+ )
- llvm_variant = update_chromeos_llvm_hash.LLVMVariant.current
- if args_output.is_llvm_next:
- llvm_variant = update_chromeos_llvm_hash.LLVMVariant.next
-
- extra_commit_msg_lines = []
- if args_output.subparser_name == "cq":
- footers = []
- cq_depend_msg = GetCQDependString(args_output.extra_change_lists)
- if cq_depend_msg:
- footers.append(cq_depend_msg)
- cq_trybot_msg = GetCQIncludeTrybotsString(args_output.cq_trybot)
- if cq_trybot_msg:
- footers.append(cq_trybot_msg)
-
- # We want a single blank line before any of these, so Git properly
- # interprets them as a footer.
- if footers:
- extra_commit_msg_lines.append("")
- extra_commit_msg_lines += footers
-
- change_list = update_chromeos_llvm_hash.UpdatePackages(
- packages=update_chromeos_llvm_hash.DEFAULT_PACKAGES,
- manifest_packages=[],
- llvm_variant=llvm_variant,
- git_hash=git_hash,
- svn_version=svn_version,
- chroot_opts=update_chromeos_llvm_hash.ChrootOpts(
- chromeos_root=Path(args_output.chromeos_path),
- chroot_name=args_output.chroot_name,
- out_name=args_output.chroot_out,
- ),
- mode=failure_modes.FailureModes.DISABLE_PATCHES,
- git_hash_source=svn_option,
- extra_commit_msg_lines=extra_commit_msg_lines,
- # b/331607705: set WIP on these changes, so the code-review-nudger bot
- # doesn't ping them.
- wip=True,
+ logging.info("Getting LLVM revision for SHA %s...", new_sha)
+ new_rev = get_llvm_hash.GetVersionFrom(
+ get_llvm_hash.GetAndUpdateLLVMProjectInLLVMTools(), new_sha
)
-
- AddReviewers(
- change_list.cl_number, args_output.reviewers, args_output.chromeos_path
+ logging.info("LLVM SHA %s == r%d", new_sha, new_rev)
+ uploaded_cls = create_and_upload_cls(
+ chromeos_tree,
+ new_sha,
+ new_rev,
+ opts.include_llvm_test_helper_cls,
+ dry_run,
)
- print("Successfully updated packages to %d" % svn_version)
- print("Gerrit URL: %s" % change_list.url)
- print("Change list number: %d" % change_list.cl_number)
-
- if args_output.subparser_name == "tryjobs":
- tests = RunTryJobs(
- change_list.cl_number,
- args_output.extra_change_lists,
- args_output.options,
- args_output.builders,
- args_output.chromeos_path,
- )
- print("Tests:")
- for test in tests:
- print(test)
- elif args_output.subparser_name == "recipe":
- tests = StartRecipeBuilders(
- change_list.cl_number,
- args_output.extra_change_lists,
- args_output.options,
- args_output.builders,
- args_output.chromeos_path,
- )
- print("Tests:")
- for test in tests:
- print(test)
+ if dry_run:
+ logging.info("--dry-run passed; exiting")
+ return
- else:
- StartCQDryRun(
- change_list.cl_number,
- args_output.extra_change_lists,
- args_output.chromeos_path,
- )
+ if opts.cq:
+ logging.info("Setting CQ+1 on the CLs...")
+ cq_dry_run_cls(chromeos_tree, uploaded_cls)
- # If --last_tested is specified, record the arguments used
- if args_output.last_tested:
- with open(args_output.last_tested, "w", encoding="utf-8") as f:
- json.dump(arg_dict, f, indent=2)
+ if opts.retry_state:
+ write_last_tried_sha(opts.retry_state, new_sha)
if __name__ == "__main__":
- main()
+ main(sys.argv[1:])
diff --git a/llvm_tools/update_packages_and_run_tests_unittest.py b/llvm_tools/update_packages_and_run_tests_unittest.py
index 9abdc199..8954893f 100755
--- a/llvm_tools/update_packages_and_run_tests_unittest.py
+++ b/llvm_tools/update_packages_and_run_tests_unittest.py
@@ -1,548 +1,82 @@
#!/usr/bin/env python3
-# Copyright 2019 The ChromiumOS Authors
+# Copyright 2024 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unittests for running tests after updating packages."""
+"""Tests for update_packages_and_run_tests.py"""
-import json
+from pathlib import Path
+import shutil
import subprocess
+import tempfile
import unittest
from unittest import mock
-import chroot
-import get_llvm_hash
-import git
-import test_helpers
-import update_chromeos_llvm_hash
import update_packages_and_run_tests
-# Testing with tryjobs.
-class UpdatePackagesAndRunTryjobsTest(unittest.TestCase):
- """Unittests when running tryjobs after updating packages."""
+class Test(unittest.TestCase):
+ """Tests for update_packages_and_run_tests.py"""
- def testNoLastTestedFile(self):
- self.assertEqual(
- update_packages_and_run_tests.UnchangedSinceLastRun(None, {}), False
- )
+ def make_tempdir(self) -> Path:
+ tempdir = tempfile.mkdtemp("run_llvm_tests_at_sha_test_")
+ self.addCleanup(shutil.rmtree, tempdir)
+ return Path(tempdir)
- def testEmptyLastTestedFile(self):
- with test_helpers.CreateTemporaryFile() as temp_file:
- self.assertEqual(
- update_packages_and_run_tests.UnchangedSinceLastRun(
- temp_file, {}
- ),
- False,
+ def test_sha_state_file_handles_file_not_existing(self):
+ tempdir = self.make_tempdir()
+ self.assertIsNone(
+ update_packages_and_run_tests.read_last_tried_sha(
+ tempdir / "does-not-exist"
)
-
- def testLastTestedFileDoesNotExist(self):
- # Simulate 'open()' on a lasted tested file that does not exist.
- mock.mock_open(read_data="")
-
- self.assertEqual(
- update_packages_and_run_tests.UnchangedSinceLastRun(
- "/some/file/that/does/not/exist.txt", {}
- ),
- False,
)
- def testMatchedLastTestedFile(self):
- with test_helpers.CreateTemporaryFile() as last_tested_file:
- arg_dict = {
- "svn_version": 1234,
- "ebuilds": [
- "/path/to/package1-r2.ebuild",
- "/path/to/package2/package2-r3.ebuild",
- ],
- "builders": [
- "kevin-llvm-next-toolchain-tryjob",
- "eve-llvm-next-toolchain-tryjob",
- ],
- "extra_cls": [10, 1],
- "tryjob_options": ["latest-toolchain", "hwtest"],
- }
-
- with open(last_tested_file, "w", encoding="utf-8") as f:
- f.write(json.dumps(arg_dict, indent=2))
-
- self.assertEqual(
- update_packages_and_run_tests.UnchangedSinceLastRun(
- last_tested_file, arg_dict
- ),
- True,
- )
-
- def testGetTryJobCommandWithNoExtraInformation(self):
- change_list = 1234
-
- builder = "nocturne"
-
- expected_cmd = [
- "cros",
- "tryjob",
- "--yes",
- "--json",
- "-g",
- "%d" % change_list,
- builder,
- ]
-
+ def test_sha_state_file_round_trips(self):
+ tempdir = self.make_tempdir()
+ state_file = tempdir / "state.json"
+ sha = "a" * 40
+ update_packages_and_run_tests.write_last_tried_sha(state_file, sha)
self.assertEqual(
- update_packages_and_run_tests.GetTryJobCommand(
- change_list, None, None, builder
- ),
- expected_cmd,
+ update_packages_and_run_tests.read_last_tried_sha(state_file), sha
)
- def testGetTryJobCommandWithExtraInformation(self):
- change_list = 4321
- extra_cls = [1000, 10]
- options = ["option1", "option2"]
- builder = "kevin"
-
- expected_cmd = [
- "cros",
- "tryjob",
- "--yes",
- "--json",
- "-g",
- "%d" % change_list,
- "-g",
- "%d" % extra_cls[0],
- "-g",
- "%d" % extra_cls[1],
- "--%s" % options[0],
- "--%s" % options[1],
- builder,
- ]
-
- self.assertEqual(
- update_packages_and_run_tests.GetTryJobCommand(
- change_list, extra_cls, options, builder
+ @mock.patch.object(subprocess, "run")
+ def test_gerrit_cq_dry_run_runs_correct_gerrit_commands(self, mock_run):
+ chromeos_tree = self.make_tempdir()
+ update_packages_and_run_tests.cq_dry_run_cls(
+ chromeos_tree,
+ update_packages_and_run_tests.UploadedCLs(
+ internal=[123],
+ external=[456, 789],
),
- expected_cmd,
- )
-
- @mock.patch.object(
- update_packages_and_run_tests,
- "GetCurrentTimeInUTC",
- return_value="2019-09-09",
- )
- @mock.patch.object(update_packages_and_run_tests, "AddLinksToCL")
- @mock.patch.object(subprocess, "check_output")
- def testSuccessfullySubmittedTryJob(
- self, mock_cmd, mock_add_links_to_cl, mock_launch_time
- ):
- expected_cmd = [
- "cros",
- "tryjob",
- "--yes",
- "--json",
- "-g",
- "%d" % 900,
- "-g",
- "%d" % 1200,
- "--some_option",
- "builder1",
- ]
-
- bb_id = "1234"
- url = "http://ci.chromium.org/b/%s" % bb_id
-
- mock_cmd.return_value = json.dumps([{"id": bb_id, "url": url}])
-
- chromeos_path = "/some/path/to/chromeos"
- cl = 900
- extra_cls = [1200]
- options = ["some_option"]
- builders = ["builder1"]
-
- tests = update_packages_and_run_tests.RunTryJobs(
- cl, extra_cls, options, builders, chromeos_path
- )
-
- expected_tests = [
- {
- "launch_time": mock_launch_time.return_value,
- "link": url,
- "buildbucket_id": int(bb_id),
- "extra_cls": extra_cls,
- "options": options,
- "builder": builders,
- }
- ]
-
- self.assertEqual(tests, expected_tests)
-
- mock_cmd.assert_called_once_with(
- expected_cmd, cwd=chromeos_path, encoding="utf-8"
- )
-
- mock_add_links_to_cl.assert_called_once()
-
- @mock.patch.object(update_packages_and_run_tests, "AddLinksToCL")
- @mock.patch.object(subprocess, "check_output")
- def testSuccessfullySubmittedRecipeBuilders(
- self, mock_cmd, mock_add_links_to_cl
- ):
- expected_cmd = [
- "bb",
- "add",
- "-json",
- "-cl",
- "crrev.com/c/%s" % 900,
- "-cl",
- "crrev.com/c/%s" % 1200,
- "some_option",
- "builder1",
- ]
-
- bb_id = "1234"
- create_time = "2020-04-18T00:03:53.978767Z"
-
- mock_cmd.return_value = json.dumps(
- {"id": bb_id, "createTime": create_time}
- )
-
- chromeos_path = "/some/path/to/chromeos"
- cl = 900
- extra_cls = [1200]
- options = ["some_option"]
- builders = ["builder1"]
-
- tests = update_packages_and_run_tests.StartRecipeBuilders(
- cl, extra_cls, options, builders, chromeos_path
)
-
- expected_tests = [
- {
- "launch_time": create_time,
- "link": "http://ci.chromium.org/b/%s" % bb_id,
- "buildbucket_id": bb_id,
- "extra_cls": extra_cls,
- "options": options,
- "builder": builders,
- }
- ]
-
- self.assertEqual(tests, expected_tests)
-
- mock_cmd.assert_called_once_with(
- expected_cmd, cwd=chromeos_path, encoding="utf-8"
+ self.assertEqual(mock_run.call_count, 2)
+ mock_run.assert_any_call(
+ ["gerrit", "label-cq", "456", "789", "1"],
+ check=True,
+ cwd=chromeos_tree,
+ stdin=subprocess.DEVNULL,
)
-
- mock_add_links_to_cl.assert_called_once()
-
- @mock.patch.object(subprocess, "check_output", return_value=None)
- def testSuccessfullyAddedTestLinkToCL(self, mock_exec_cmd):
- chromeos_path = "/abs/path/to/chromeos"
-
- test_cl_number = 1000
-
- tests = [{"link": "https://some_tryjob_link.com"}]
-
- update_packages_and_run_tests.AddLinksToCL(
- tests, test_cl_number, chromeos_path
+ mock_run.assert_any_call(
+ ["gerrit", "--internal", "label-cq", "123", "1"],
+ check=True,
+ cwd=chromeos_tree,
+ stdin=subprocess.DEVNULL,
)
- expected_gerrit_message = [
- "%s/chromite/bin/gerrit" % chromeos_path,
- "message",
- str(test_cl_number),
- "Started the following tests:\n%s" % tests[0]["link"],
- ]
-
- mock_exec_cmd.assert_called_once_with(expected_gerrit_message)
-
- @mock.patch.object(update_packages_and_run_tests, "RunTryJobs")
- @mock.patch.object(update_chromeos_llvm_hash, "UpdatePackages")
- @mock.patch.object(update_packages_and_run_tests, "GetCommandLineArgs")
- @mock.patch.object(get_llvm_hash, "GetLLVMHashAndVersionFromSVNOption")
- @mock.patch.object(chroot, "VerifyChromeOSRoot")
- @mock.patch.object(chroot, "VerifyOutsideChroot", return_value=True)
- @mock.patch.object(chroot, "GetChrootEbuildPaths")
- def testUpdatedLastTestedFileWithNewTestedRevision(
- self,
- mock_get_chroot_build_paths,
- mock_outside_chroot,
- mock_chromeos_root,
- mock_get_hash_and_version,
- mock_get_commandline_args,
- mock_update_packages,
- mock_run_tryjobs,
+ @mock.patch.object(subprocess, "run")
+ def test_gerrit_cq_dry_run_only_runs_one_command_if_necessary(
+ self, mock_run
):
- # Create a temporary file to simulate the last tested file that
- # contains a revision.
- with test_helpers.CreateTemporaryFile() as last_tested_file:
- builders = [
- "kevin-llvm-next-toolchain-tryjob",
- "eve-llvm-next-toolchain-tryjob",
- ]
- extra_cls = [10, 1]
- tryjob_options = ["latest-toolchain", "hwtest"]
- ebuilds = [
- "/path/to/package1/package1-r2.ebuild",
- "/path/to/package2/package2-r3.ebuild",
- ]
-
- arg_dict = {
- "svn_version": 100,
- "ebuilds": ebuilds,
- "builders": builders,
- "extra_cls": extra_cls,
- "tryjob_options": tryjob_options,
- }
- # Parepared last tested file
- with open(last_tested_file, "w", encoding="utf-8") as f:
- json.dump(arg_dict, f, indent=2)
-
- # Call with a changed LLVM svn version
- args_output = test_helpers.ArgsOutputTest()
- args_output.chroot_name = "custom-chroot"
- args_output.chroot_out = "custom-chroot_out"
- args_output.is_llvm_next = True
- args_output.extra_change_lists = extra_cls
- args_output.last_tested = last_tested_file
- args_output.reviewers = []
-
- args_output.subparser_name = "tryjobs"
- args_output.builders = builders
- args_output.options = tryjob_options
-
- mock_get_commandline_args.return_value = args_output
-
- mock_get_chroot_build_paths.return_value = ebuilds
-
- mock_get_hash_and_version.return_value = ("a123testhash2", 200)
-
- mock_update_packages.return_value = git.CommitContents(
- url="https://some_cl_url.com", cl_number=12345
- )
-
- mock_run_tryjobs.return_value = [
- {"link": "https://some_tryjob_url.com", "buildbucket_id": 1234}
- ]
-
- update_packages_and_run_tests.main()
-
- # Verify that the lasted tested file has been updated to the new
- # LLVM revision.
- with open(last_tested_file, encoding="utf-8") as f:
- arg_dict = json.load(f)
-
- self.assertEqual(arg_dict["svn_version"], 200)
-
- mock_outside_chroot.assert_called_once()
-
- mock_chromeos_root.assert_called_once()
-
- mock_get_commandline_args.assert_called_once()
-
- mock_get_hash_and_version.assert_called_once()
-
- mock_run_tryjobs.assert_called_once()
-
- mock_update_packages.assert_called_once()
- commit_msg_lines = mock_update_packages.call_args[1][
- "extra_commit_msg_lines"
- ]
- self.assertTrue(
- isinstance(commit_msg_lines, list), repr(commit_msg_lines)
- )
-
-
-class UpdatePackagesAndRunTestCQTest(unittest.TestCase):
- """Unittests for CQ dry run after updating packages."""
-
- def testGetCQDependString(self):
- test_no_changelists = []
- test_single_changelist = [1234]
- test_multiple_changelists = [1234, 5678]
-
- self.assertIsNone(
- update_packages_and_run_tests.GetCQDependString(test_no_changelists)
- )
-
- self.assertEqual(
- update_packages_and_run_tests.GetCQDependString(
- test_single_changelist
- ),
- "Cq-Depend: chromium:1234",
- )
-
- self.assertEqual(
- update_packages_and_run_tests.GetCQDependString(
- test_multiple_changelists
- ),
- "Cq-Depend: chromium:1234, chromium:5678",
- )
-
- def testGetCQIncludeTrybotsString(self):
- test_no_trybot = None
- test_valid_trybot = "llvm-next"
- test_invalid_trybot = "invalid-name"
-
- self.assertIsNone(
- update_packages_and_run_tests.GetCQIncludeTrybotsString(
- test_no_trybot
- )
- )
-
- self.assertEqual(
- update_packages_and_run_tests.GetCQIncludeTrybotsString(
- test_valid_trybot
+ chromeos_tree = self.make_tempdir()
+ update_packages_and_run_tests.cq_dry_run_cls(
+ chromeos_tree,
+ update_packages_and_run_tests.UploadedCLs(
+ internal=[123],
+ external=[],
),
- "Cq-Include-Trybots:chromeos/cq:cq-llvm-next-orchestrator",
- )
-
- with self.assertRaises(ValueError) as context:
- update_packages_and_run_tests.GetCQIncludeTrybotsString(
- test_invalid_trybot
- )
-
- self.assertIn("is not a valid llvm trybot", str(context.exception))
-
- @mock.patch.object(subprocess, "check_output", return_value=None)
- def testStartCQDryRunNoDeps(self, mock_exec_cmd):
- chromeos_path = "/abs/path/to/chromeos"
- test_cl_number = 1000
-
- # test with no deps cls.
- extra_cls = []
- update_packages_and_run_tests.StartCQDryRun(
- test_cl_number, extra_cls, chromeos_path
- )
-
- expected_gerrit_message = [
- "%s/chromite/bin/gerrit" % chromeos_path,
- "label-cq",
- str(test_cl_number),
- "1",
- ]
-
- mock_exec_cmd.assert_called_once_with(expected_gerrit_message)
-
- # Mock ExecCommandAndCaptureOutput for the gerrit command execution.
- @mock.patch.object(subprocess, "check_output", return_value=None)
- # test with a single deps cl.
- def testStartCQDryRunSingleDep(self, mock_exec_cmd):
- chromeos_path = "/abs/path/to/chromeos"
- test_cl_number = 1000
-
- extra_cls = [2000]
- update_packages_and_run_tests.StartCQDryRun(
- test_cl_number, extra_cls, chromeos_path
- )
-
- expected_gerrit_cmd_1 = [
- "%s/chromite/bin/gerrit" % chromeos_path,
- "label-cq",
- str(test_cl_number),
- "1",
- ]
- expected_gerrit_cmd_2 = [
- "%s/chromite/bin/gerrit" % chromeos_path,
- "label-cq",
- str(2000),
- "1",
- ]
-
- self.assertEqual(mock_exec_cmd.call_count, 2)
- self.assertEqual(
- mock_exec_cmd.call_args_list[0], mock.call(expected_gerrit_cmd_1)
- )
- self.assertEqual(
- mock_exec_cmd.call_args_list[1], mock.call(expected_gerrit_cmd_2)
- )
-
- # Mock ExecCommandAndCaptureOutput for the gerrit command execution.
- @mock.patch.object(subprocess, "check_output", return_value=None)
- def testStartCQDryRunMultipleDep(self, mock_exec_cmd):
- chromeos_path = "/abs/path/to/chromeos"
- test_cl_number = 1000
-
- # test with multiple deps cls.
- extra_cls = [3000, 4000]
- update_packages_and_run_tests.StartCQDryRun(
- test_cl_number, extra_cls, chromeos_path
- )
-
- expected_gerrit_cmd_1 = [
- "%s/chromite/bin/gerrit" % chromeos_path,
- "label-cq",
- str(test_cl_number),
- "1",
- ]
- expected_gerrit_cmd_2 = [
- "%s/chromite/bin/gerrit" % chromeos_path,
- "label-cq",
- str(3000),
- "1",
- ]
- expected_gerrit_cmd_3 = [
- "%s/chromite/bin/gerrit" % chromeos_path,
- "label-cq",
- str(4000),
- "1",
- ]
-
- self.assertEqual(mock_exec_cmd.call_count, 3)
- self.assertEqual(
- mock_exec_cmd.call_args_list[0], mock.call(expected_gerrit_cmd_1)
- )
- self.assertEqual(
- mock_exec_cmd.call_args_list[1], mock.call(expected_gerrit_cmd_2)
- )
- self.assertEqual(
- mock_exec_cmd.call_args_list[2], mock.call(expected_gerrit_cmd_3)
- )
-
- # Mock ExecCommandAndCaptureOutput for the gerrit command execution.
- @mock.patch.object(subprocess, "check_output", return_value=None)
- # test with no reviewers.
- def testAddReviewersNone(self, mock_exec_cmd):
- chromeos_path = "/abs/path/to/chromeos"
- reviewers = []
- test_cl_number = 1000
-
- update_packages_and_run_tests.AddReviewers(
- test_cl_number, reviewers, chromeos_path
- )
- self.assertTrue(mock_exec_cmd.not_called)
-
- # Mock ExecCommandAndCaptureOutput for the gerrit command execution.
- @mock.patch.object(subprocess, "check_output", return_value=None)
- # test with multiple reviewers.
- def testAddReviewersMultiple(self, mock_exec_cmd):
- chromeos_path = "/abs/path/to/chromeos"
- reviewers = ["none1@chromium.org", "none2@chromium.org"]
- test_cl_number = 1000
-
- update_packages_and_run_tests.AddReviewers(
- test_cl_number, reviewers, chromeos_path
- )
-
- expected_gerrit_cmd_1 = [
- "%s/chromite/bin/gerrit" % chromeos_path,
- "reviewers",
- str(test_cl_number),
- "none1@chromium.org",
- ]
- expected_gerrit_cmd_2 = [
- "%s/chromite/bin/gerrit" % chromeos_path,
- "reviewers",
- str(test_cl_number),
- "none2@chromium.org",
- ]
-
- self.assertEqual(mock_exec_cmd.call_count, 2)
- self.assertEqual(
- mock_exec_cmd.call_args_list[0], mock.call(expected_gerrit_cmd_1)
- )
- self.assertEqual(
- mock_exec_cmd.call_args_list[1], mock.call(expected_gerrit_cmd_2)
)
+ mock_run.assert_called_once()
if __name__ == "__main__":
diff --git a/llvm_tools/upload_llvm_testing_helper_cl.py b/llvm_tools/upload_llvm_testing_helper_cl.py
index a66e3fbf..97fafa26 100755
--- a/llvm_tools/upload_llvm_testing_helper_cl.py
+++ b/llvm_tools/upload_llvm_testing_helper_cl.py
@@ -13,7 +13,6 @@ These CLs make the validation of LLVM easier, and do things like:
import argparse
import logging
from pathlib import Path
-import subprocess
import sys
from typing import List
@@ -100,33 +99,6 @@ def add_disable_warnings_block(chromiumos_overlay: Path):
f.write(DISABLE_WARNINGS_BLOCK)
-def commit_all_changes(git_dir: Path, message: str) -> str:
- """Commits all changes in `git_dir`, with the given commit message."""
- # Explicitly add using `git add -A`, since that stages all unstaged changes
- # & adds any files that aren't tracked. `git commit -a` skips adding
- # untracked files.
- subprocess.run(
- ["git", "add", "-A"],
- check=True,
- cwd=git_dir,
- stdin=subprocess.DEVNULL,
- )
- subprocess.run(
- ["git", "commit", "-m", message],
- check=True,
- cwd=git_dir,
- stdin=subprocess.DEVNULL,
- )
- return subprocess.run(
- ["git", "rev-parse", "HEAD"],
- check=True,
- cwd=git_dir,
- stdin=subprocess.DEVNULL,
- stdout=subprocess.PIPE,
- encoding="utf-8",
- ).stdout.strip()
-
-
def create_helper_cl_commit_in_worktree_of(chromiumos_overlay: Path) -> str:
"""Creates a commit containing the helper CL diff. Returns the SHA.commit"""
with git_utils.create_worktree(chromiumos_overlay) as worktree:
@@ -134,7 +106,7 @@ def create_helper_cl_commit_in_worktree_of(chromiumos_overlay: Path) -> str:
add_force_rebuild_markers(worktree)
add_use_force_block(worktree)
add_disable_warnings_block(worktree)
- return commit_all_changes(worktree, COMMIT_MESSAGE)
+ return git_utils.commit_all_changes(worktree, COMMIT_MESSAGE)
def main(argv: List[str]) -> None:
@@ -182,8 +154,8 @@ def main(argv: List[str]) -> None:
# This logs the CL information, so no need to print anything after this.
git_utils.upload_to_gerrit(
git_repo=chromiumos_overlay,
- remote="cros",
- branch="main",
+ remote=git_utils.CROS_EXTERNAL_REMOTE,
+ branch=git_utils.CROS_MAIN_BRANCH,
ref=helper_sha,
)