| # Copyright 2017 The ChromiumOS Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """cros tryjob: Schedule a tryjob.""" |
| |
| import logging |
| import os |
| import time |
| |
| from chromite.third_party.google.protobuf import json_format |
| |
| from chromite.cbuildbot import trybot_patch_pool |
| from chromite.cli import command |
| from chromite.lib import config_lib |
| from chromite.lib import constants |
| from chromite.lib import cros_build_lib |
| from chromite.lib import git |
| from chromite.lib import request_build |
| from chromite.scripts import cbuildbot as cbuildbot_lib |
| from chromite.utils import pformat |
| |
| |
| REMOTE = "remote" |
| INFRA_TESTING = "infra-testing" |
| LOCAL = "local" |
| CBUILDBOT = "cbuildbot" |
| |
| |
| def ConfigsToPrint(site_config, production, build_config_fragments): |
| """Select a list of buildbot configs to print out. |
| |
| Args: |
| site_config: config_lib.SiteConfig containing all config info. |
| production: Display tryjob or production configs?. |
| build_config_fragments: List of strings to filter config names with. |
| |
| Returns: |
| List of config_lib.BuildConfig objects. |
| """ |
| configs = site_config.values() |
| |
| def optionsMatch(config): |
| # In this case, build_configs are config name fragments. If the config |
| # name doesn't contain any of the fragments, filter it out. |
| for build_config in build_config_fragments: |
| if build_config not in config.name: |
| return False |
| |
| return config_lib.isTryjobConfig(config) != production |
| |
| # All configs, filtered by optionsMatch. |
| configs = [config for config in configs if optionsMatch(config)] |
| |
| # Sort build type, then board. |
| # 'daisy-paladin-tryjob' -> ['tryjob', 'paladin', 'daisy'] |
| configs.sort(key=lambda c: list(reversed(c.name.split("-")))) |
| |
| return configs |
| |
| |
| def PrintKnownConfigs(site_config, production, build_config_fragments): |
| """Print a list of known buildbot configs. |
| |
| Args: |
| site_config: config_lib.SiteConfig containing all config info. |
| production: Display tryjob or production configs?. |
| build_config_fragments: List of strings to filter config names with. |
| """ |
| configs = ConfigsToPrint(site_config, production, build_config_fragments) |
| |
| COLUMN_WIDTH = max([0] + [len(c.name) for c in configs]) + 1 |
| if production: |
| print("Production configs:") |
| else: |
| print("Tryjob configs:") |
| |
| print("config".ljust(COLUMN_WIDTH), "description") |
| print("------".ljust(COLUMN_WIDTH), "-----------") |
| for config in configs: |
| desc = config.description or "" |
| print(config.name.ljust(COLUMN_WIDTH), desc) |
| |
| |
| def CbuildbotArgs(options): |
| """Function to generate cbuildbot command line args. |
| |
| This are pre-api version filtering. |
| |
| Args: |
| options: Parsed cros tryjob tryjob arguments. |
| |
| Returns: |
| List of strings in ['arg1', 'arg2'] format |
| """ |
| args = [] |
| |
| if options.where in (REMOTE, INFRA_TESTING): |
| if options.production: |
| args.append("--buildbot") |
| else: |
| args.append("--remote-trybot") |
| |
| elif options.where == LOCAL: |
| args.extend( |
| ( |
| "--buildroot", |
| options.buildroot, |
| "--git-cache-dir", |
| options.git_cache_dir, |
| "--no-buildbot-tags", |
| ) |
| ) |
| |
| if options.production: |
| # This is expected to fail on workstations without an explicit |
| # --debug. |
| args.append("--buildbot") |
| else: |
| args.append("--debug") |
| |
| elif options.where == CBUILDBOT: |
| args.extend( |
| ( |
| "--buildroot", |
| os.path.join(options.buildroot, "repository"), |
| "--workspace", |
| os.path.join(options.buildroot, "workspace"), |
| "--git-cache-dir", |
| options.git_cache_dir, |
| "--debug", |
| "--nobootstrap", |
| "--noreexec", |
| "--no-buildbot-tags", |
| ) |
| ) |
| |
| if options.production: |
| # This is expected to fail on workstations without an explicit |
| # --debug. |
| args.append("--buildbot") |
| |
| else: |
| raise Exception("Unknown options.where: %s" % (options.where,)) |
| |
| if options.branch: |
| args.extend(("-b", options.branch)) |
| |
| for g in options.gerrit_patches: |
| args.extend(("-g", g)) |
| |
| if options.hwtest_dut_dimensions: |
| args.extend( |
| ("--hwtest_dut_dimensions", " ".join(options.hwtest_dut_dimensions)) |
| ) |
| |
| if options.passthrough: |
| args.extend(options.passthrough) |
| |
| if options.passthrough_raw: |
| args.extend(options.passthrough_raw) |
| |
| return args |
| |
| |
| def CreateBuildrootIfNeeded(buildroot): |
| """Create the buildroot is it doesn't exist with confirmation prompt. |
| |
| Args: |
| buildroot: The buildroot path to create as a string. |
| |
| Returns: |
| boolean: Does the buildroot now exist? |
| """ |
| if os.path.exists(buildroot): |
| return True |
| |
| prompt = "Create %s as buildroot" % buildroot |
| if not cros_build_lib.BooleanPrompt(prompt=prompt, default=False): |
| print( |
| "Please specify a different buildroot via the --buildroot option." |
| ) |
| return False |
| |
| os.makedirs(buildroot) |
| return True |
| |
| |
| def RunLocal(options): |
| """Run a local tryjob. |
| |
| Args: |
| options: Parsed cros tryjob tryjob arguments. |
| |
| Returns: |
| Exit code of build as an int. |
| """ |
| if cros_build_lib.IsInsideChroot(): |
| cros_build_lib.Die("Local tryjobs cannot be started inside the chroot.") |
| |
| args = CbuildbotArgs(options) |
| |
| if not CreateBuildrootIfNeeded(options.buildroot): |
| return 1 |
| |
| # Define the command to run. |
| launcher = constants.CHROMITE_DIR / "scripts" / "cbuildbot_launch" |
| cmd = [launcher] + args + options.build_configs |
| |
| # Run the tryjob. |
| result = cros_build_lib.run( |
| cmd, debug_level=logging.CRITICAL, check=False, cwd=options.buildroot |
| ) |
| return result.returncode |
| |
| |
| def RunCbuildbot(options): |
| """Run a cbuildbot build. |
| |
| Args: |
| options: Parsed cros tryjob tryjob arguments. |
| |
| Returns: |
| Exit code of build as an int. |
| """ |
| if cros_build_lib.IsInsideChroot(): |
| cros_build_lib.Die( |
| "cbuildbot tryjobs cannot be started inside the chroot." |
| ) |
| |
| args = CbuildbotArgs(options) |
| |
| if not CreateBuildrootIfNeeded(options.buildroot): |
| return 1 |
| |
| # Define the command to run. |
| cbuildbot = constants.CHROMITE_BIN_DIR / "cbuildbot" |
| cmd = [cbuildbot] + args + options.build_configs |
| |
| # Run the tryjob. |
| result = cros_build_lib.run( |
| cmd, debug_level=logging.CRITICAL, check=False, cwd=options.buildroot |
| ) |
| return result.returncode |
| |
| |
| def DisplayLabel(site_config, options, build_config_name): |
| """Decide which display_label to use. |
| |
| Args: |
| site_config: config_lib.SiteConfig containing all config info. |
| options: Parsed command line options for cros tryjob. |
| build_config_name: Name of the build config we are scheduling. |
| |
| Returns: |
| String to use as the cbb_build_label value. |
| """ |
| # Production tryjobs always display as production tryjobs. |
| if options.production: |
| return config_lib.DISPLAY_LABEL_PRODUCTION_TRYJOB |
| |
| # Our site_config is only valid for the current branch. If the build |
| # config is known and has an explicit display_label, use it. |
| # to be 'main'. |
| if ( |
| options.branch == "main" |
| and build_config_name in site_config |
| and site_config[build_config_name].display_label |
| ): |
| return site_config[build_config_name].display_label |
| |
| # Fall back to default. |
| return config_lib.DISPLAY_LABEL_TRYJOB |
| |
| |
| def FindUserEmail(options): |
| """Decide which email address is submitting the job. |
| |
| Args: |
| options: Parsed command line options for cros tryjob. |
| |
| Returns: |
| Email address for the tryjob as a string. |
| """ |
| |
| if options.committer_email: |
| return options.committer_email |
| |
| cwd = os.path.dirname(os.path.realpath(__file__)) |
| return git.GetProjectUserEmail(cwd) |
| |
| |
| def PushLocalPatches(local_patches, user_email, dryrun=False): |
| """Push local changes to a remote ref, and generate args to send. |
| |
| Args: |
| local_patches: patch_pool.local_patches from verified patch_pool. |
| user_email: Unique id for user submitting this tryjob. |
| dryrun: Is this a dryrun? If so, don't really push. |
| |
| Returns: |
| List of strings to pass to builder to include these patches. |
| """ |
| manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT) |
| |
| current_time = str(int(time.time())) |
| ref_base = os.path.join("refs/tryjobs", user_email, current_time) |
| |
| extra_args = [] |
| for patch in local_patches: |
| # Isolate the name; if it's a tag or a remote, let through. |
| # Else if it's a branch, get the full branch name minus refs/heads. |
| local_branch = git.StripRefsHeads(patch.ref, False) |
| ref_final = os.path.join(ref_base, local_branch, patch.sha1) |
| |
| checkout = patch.GetCheckout(manifest) |
| checkout.AssertPushable() |
| print("Uploading patch %s" % patch) |
| patch.Upload(checkout["push_url"], ref_final, dryrun=dryrun) |
| |
| # TODO(crbug/216095): Pass in the remote instead of tag. |
| tag = constants.EXTERNAL_PATCH_TAG |
| if checkout["remote"] == config_lib.GetSiteParams().INTERNAL_REMOTE: |
| tag = constants.INTERNAL_PATCH_TAG |
| |
| extra_args.append( |
| "--remote-patches=%s:%s:%s:%s:%s" |
| % ( |
| patch.project, |
| local_branch, |
| ref_final, |
| patch.tracking_branch, |
| tag, |
| ) |
| ) |
| |
| return extra_args |
| |
| |
| def RunRemote( |
| site_config, options, patch_pool, infra_testing=False, production=False |
| ): |
| """Schedule remote tryjobs.""" |
| logging.info( |
| "Scheduling remote tryjob(s): %s", ", ".join(options.build_configs) |
| ) |
| |
| luci_builder = None |
| if infra_testing: |
| luci_builder = config_lib.LUCI_BUILDER_INFRA_TESTING |
| # Production tryjobs actually execute in the Release group |
| elif production: |
| luci_builder = config_lib.LUCI_BUILDER_RELEASE |
| |
| user_email = FindUserEmail(options) |
| |
| # Figure out the cbuildbot command line to pass in. |
| args = CbuildbotArgs(options) |
| args += PushLocalPatches(patch_pool.local_patches, user_email) |
| |
| if options.debug: |
| # default_debug template used to test email templates before they go |
| # live. |
| email_template = "default_debug" |
| else: |
| email_template = "tryjob" |
| |
| logging.info("Submitting tryjob...") |
| results = [] |
| for build_config in options.build_configs: |
| tryjob = request_build.RequestBuild( |
| build_config=build_config, |
| luci_builder=luci_builder, |
| display_label=DisplayLabel(site_config, options, build_config), |
| branch=options.branch, |
| extra_args=args, |
| user_email=user_email, |
| email_template=email_template, |
| ) |
| results.append(tryjob.Submit(dryrun=False)) |
| |
| if options.json: |
| # Convert Buildbucket Build object to dict, output as json. |
| print(pformat.json([json_format.MessageToDict(r) for r in results])) |
| else: |
| print("Tryjob submitted!") |
| print("To view your tryjobs, visit:") |
| for r in results: |
| print(f"{constants.CHROMEOS_MILO_HOST}{r.id}") |
| |
| |
| def VerifyOptions(options, site_config): |
| """Verify that our command line options make sense. |
| |
| Args: |
| options: Parsed cros tryjob tryjob arguments. |
| site_config: config_lib.SiteConfig containing all config info. |
| """ |
| # Handle --list before checking that everything else is valid. |
| if options.list: |
| PrintKnownConfigs( |
| site_config, options.production, options.build_configs |
| ) |
| raise cros_build_lib.DieSystemExit(0) # Exit with success code. |
| |
| # Validate specified build_configs. |
| if not options.build_configs: |
| cros_build_lib.Die("At least one build_config is required.") |
| |
| on_branch = options.branch != "main" |
| |
| if not (options.yes or on_branch): |
| unknown_build_configs = [ |
| b for b in options.build_configs if b not in site_config |
| ] |
| if unknown_build_configs: |
| prompt = ( |
| "Unknown build configs; are you sure you want to schedule " |
| "for %s?" % ", ".join(unknown_build_configs) |
| ) |
| if not cros_build_lib.BooleanPrompt(prompt=prompt, default=False): |
| cros_build_lib.Die("No confirmation.") |
| |
| unsupported_tryjobs = [] |
| for build_config in options.build_configs: |
| for suffix in ("-release", "-payloads", "-full"): |
| if suffix in build_config: |
| unsupported_tryjobs.append(build_config) |
| break |
| |
| # The user may have specified a --version but not a --branch, need to check |
| # both to determine `cros tryjob` support. |
| specified_version = None |
| if options.passthrough: |
| for i, val in enumerate(options.passthrough): |
| if val.startswith("--version"): |
| if "=" in val: |
| specified_version = val.split("=", 1)[-1] |
| else: |
| specified_version = options.passthrough[i + 1] |
| if unsupported_tryjobs: |
| unsupported_branch = False |
| version = specified_version |
| if not version and on_branch: |
| tokens = options.branch.split("-") |
| if tokens[0] in ("release", "stabilize", "firmware"): |
| version = tokens[-1] |
| if version: |
| if int(version.split(".")[0]) >= 15183: |
| unsupported_branch = True |
| if (not on_branch and not specified_version) or unsupported_branch: |
| cros_build_lib.Die( |
| "`cros tryjob` is unsupported for %s on milestones >= 108, " |
| "please use `cros try`.", |
| ",".join(unsupported_tryjobs), |
| ) |
| |
| # Ensure that production configs are only run with --production. |
| if not (on_branch or options.production or options.where == CBUILDBOT): |
| # We can't know if branched configs are tryjob safe. |
| # It should always be safe to run a tryjob config with --production. |
| prod_configs = [] |
| for b in options.build_configs: |
| if b in site_config and not config_lib.isTryjobConfig( |
| site_config[b] |
| ): |
| prod_configs.append(b) |
| |
| if prod_configs: |
| # Die, and explain why. |
| alternative_configs = ["%s-tryjob" % b for b in prod_configs] |
| msg = ( |
| "These configs are not tryjob safe:\n" |
| " %s\n" |
| "Consider these configs instead:\n" |
| " %s\n" |
| "See go/cros-explicit-tryjob-build-configs-psa." |
| % (", ".join(prod_configs), ", ".join(alternative_configs)) |
| ) |
| |
| if options.branch == "main": |
| # On main branch, we know the status of configs for sure. |
| cros_build_lib.Die(msg) |
| elif not options.yes: |
| # On branches, we are just guessing. Let people override. |
| prompt = "%s\nAre you sure you want to continue?" % msg |
| if not cros_build_lib.BooleanPrompt( |
| prompt=prompt, default=False |
| ): |
| cros_build_lib.Die("No confirmation.") |
| |
| patches_given = options.gerrit_patches or options.local_patches |
| if options.production: |
| # Make sure production builds don't have patches. |
| if patches_given and not options.debug: |
| cros_build_lib.Die( |
| "Patches cannot be included in production builds." |
| ) |
| elif options.where != CBUILDBOT: |
| # Ask for confirmation if there are no patches to test. |
| if not patches_given and not options.yes: |
| prompt = ( |
| "No patches were provided; are you sure you want to just " |
| "run a build of %s?" |
| % (options.branch if options.branch else "ToT") |
| ) |
| if not cros_build_lib.BooleanPrompt(prompt=prompt, default=False): |
| cros_build_lib.Die("No confirmation.") |
| |
| if options.where in (REMOTE, INFRA_TESTING): |
| if options.buildroot: |
| cros_build_lib.Die("--buildroot is not used for remote tryjobs.") |
| |
| if options.git_cache_dir: |
| cros_build_lib.Die( |
| "--git-cache-dir is not used for remote tryjobs." |
| ) |
| else: |
| if options.json: |
| cros_build_lib.Die("--json can only be used for remote tryjobs.") |
| |
| if options.hwtest_dut_dimensions: |
| has_board = has_model = has_pool = False |
| for dim in options.hwtest_dut_dimensions: |
| if dim.startswith(cbuildbot_lib.BOARD_DIM_LABEL): |
| has_board = True |
| elif dim.startswith(cbuildbot_lib.MODEL_DIM_LABEL): |
| has_model = True |
| elif dim.startswith(cbuildbot_lib.POOL_DIM_LABEL): |
| has_pool = True |
| |
| if not (has_board and has_model and has_pool): |
| cros_build_lib.Die( |
| "HWTest DUT dimensions must include board, model, and " |
| "pool (given %s)." % options.hwtest_dut_dimensions |
| ) |
| |
| |
| @command.command_decorator("tryjob") |
| class TryjobCommand(command.CliCommand): |
| """Schedule a tryjob.""" |
| |
| EPILOG = """ |
| Remote Examples: |
| cros tryjob -g 123 lumpy-compile-only-pre-cq |
| cros tryjob -g 123 -g 456 lumpy-compile-only-pre-cq daisy-pre-cq |
| cros tryjob -g *123 --hwtest daisy-paladin-tryjob |
| cros tryjob -p chromiumos/chromite lumpy-compile-only-pre-cq |
| cros tryjob -p chromiumos/chromite:foo_branch lumpy-paladin-tryjob |
| |
| Local Examples: |
| cros tryjob --local -g 123 daisy-paladin-tryjob |
| cros tryjob --local --buildroot /my/cool/path -g 123 daisy-paladin-tryjob |
| |
| Production Examples (danger, can break production if misused): |
| cros tryjob --production --branch release-R61-9765.B asuka-release |
| cros tryjob --production --version 9795.0.0 --channel canary lumpy-payloads |
| |
| List Examples: |
| cros tryjob --list |
| cros tryjob --production --list |
| cros tryjob --list lumpy |
| cros tryjob --list lumpy vmtest |
| """ |
| |
| @classmethod |
| def AddParser(cls, parser): |
| """Adds a parser.""" |
| super(cls, TryjobCommand).AddParser(parser) |
| parser.add_argument( |
| "build_configs", nargs="*", help="One or more configs to build." |
| ) |
| parser.add_argument( |
| "-b", |
| "--branch", |
| default="main", |
| help="The manifest branch to test. The branch to " |
| "check the buildroot out to.", |
| ) |
| parser.add_argument( |
| "--profile", |
| dest="passthrough", |
| action="append_option_value", |
| help="Name of profile to sub-specify board variant.", |
| ) |
| parser.add_argument( |
| "--yes", |
| action="store_true", |
| default=False, |
| help="Never prompt to confirm.", |
| ) |
| parser.add_argument( |
| "--production", |
| action="store_true", |
| default=False, |
| help="This is a production build, NOT a test build. " |
| "Confirm with Chrome OS deputy before use.", |
| ) |
| parser.add_argument( |
| "--pass-through", |
| dest="passthrough_raw", |
| action="append", |
| help="Arguments to pass to cbuildbot. To be avoided." |
| "Confirm with Chrome OS deputy before use.", |
| ) |
| parser.add_argument( |
| "--json", |
| action="store_true", |
| default=False, |
| help="Return details of remote tryjob in script friendly output.", |
| ) |
| |
| # Do we build locally, on on a trybot builder? |
| where_group = parser.add_argument_group( |
| "Where", description="Where do we run the tryjob?" |
| ) |
| where_ex = where_group.add_mutually_exclusive_group() |
| where_ex.add_argument( |
| "--remote", |
| dest="where", |
| action="store_const", |
| const=REMOTE, |
| default=REMOTE, |
| help="Run the tryjob on a remote builder. (default)", |
| ) |
| where_ex.add_argument( |
| "--infra-testing", |
| dest="where", |
| action="store_const", |
| const=INFRA_TESTING, |
| help="Run the tryjob against the infra-testing swarming pool.", |
| ) |
| where_ex.add_argument( |
| "--swarming", |
| dest="where", |
| action="store_const", |
| const=REMOTE, |
| help="Run the tryjob on a swarming builder. (deprecated)", |
| ) |
| where_ex.add_argument( |
| "--local", |
| dest="where", |
| action="store_const", |
| const=LOCAL, |
| help="Run the tryjob on your local machine.", |
| ) |
| where_ex.add_argument( |
| "--cbuildbot", |
| dest="where", |
| action="store_const", |
| const=CBUILDBOT, |
| help="Run special local build from current checkout in buildroot.", |
| ) |
| where_group.add_argument( |
| "-r", |
| "--buildroot", |
| type="path", |
| help="Root directory to use for the local tryjob. " |
| "NOT the current checkout.", |
| ) |
| where_group.add_argument( |
| "--git-cache-dir", |
| type="path", |
| help="Git cache directory to use for local tryjobs.", |
| ) |
| |
| # What patches do we include in the build? |
| what_group = parser.add_argument_group( |
| "Patch", |
| description="Which patches should be included with the tryjob?", |
| ) |
| what_group.add_argument( |
| "-g", |
| "--gerrit-patches", |
| action="split_extend", |
| default=[], |
| metavar="Id1 *int_Id2...IdN", |
| help="Space-separated list of short-form Gerrit " |
| "Change-Id's or change numbers to patch. " |
| "Please prepend '*' to internal Change-Id's", |
| ) |
| # We have to format metavar poorly to workaround an argparse bug. |
| # https://bugs.python.org/issue11874 |
| what_group.add_argument( |
| "-p", |
| "--local-patches", |
| action="split_extend", |
| default=[], |
| metavar="'<project1>[:<branch1>] ... <projectN>[:<branchN>] '", |
| help="Space-separated list of project branches with " |
| "patches to apply. Projects are specified by name. " |
| "If no branch is specified the current branch of the " |
| "project will be used. NOTE: -p is known to be buggy; " |
| "prefer using -g instead (see https://crbug.com/806963 " |
| "and https://crbug.com/807834).", |
| ) |
| |
| # Identifing the request. |
| who_group = parser.add_argument_group( |
| "Requestor", description="Who is submitting the jobs?" |
| ) |
| who_group.add_argument( |
| "--committer-email", help="Override default git committer email." |
| ) |
| |
| # Modify the build. |
| how_group = parser.add_argument_group( |
| "Modifiers", description="How do we modify build behavior?" |
| ) |
| how_group.add_argument( |
| "--latest-toolchain", |
| dest="passthrough", |
| action="append_option", |
| help="Use the latest toolchain.", |
| ) |
| how_group.add_argument( |
| "--nochromesdk", |
| dest="passthrough", |
| action="append_option", |
| help="Don't run the ChromeSDK stage which builds " |
| "Chrome outside of the chroot.", |
| ) |
| how_group.add_argument( |
| "--timeout", |
| dest="passthrough", |
| action="append_option_value", |
| help="Specify the maximum amount of time this job " |
| "can run for, at which point the build will be " |
| "aborted. If set to zero, then there is no " |
| "timeout.", |
| ) |
| how_group.add_argument( |
| "--confidence-check-build", |
| dest="passthrough", |
| action="append_option", |
| help="Run the build as a confidence check build.", |
| ) |
| how_group.add_argument( |
| "--chrome_version", |
| dest="passthrough", |
| action="append_option_value", |
| help="Used with SPEC logic to force a particular " |
| "git revision of chrome rather than the latest. " |
| "HEAD is a valid value.", |
| ) |
| how_group.add_argument( |
| "--debug-cidb", |
| dest="passthrough", |
| action="append_option", |
| help="Force Debug CIDB to be used.", |
| ) |
| how_group.add_argument( |
| "--no-publish-prebuilt-confs", |
| dest="passthrough", |
| action="append_option", |
| help="Force the tryjob to not publish commits to prebuilt.conf or " |
| "sdk_version.conf, even if run in production.", |
| ) |
| |
| # Overrides for the build configs testing behaviors. |
| test_group = parser.add_argument_group( |
| "Testing Flags", description="How do we change testing behavior?" |
| ) |
| test_group.add_argument( |
| "--hwtest", |
| dest="passthrough", |
| action="append_option", |
| help="Enable hwlab testing. Default false.", |
| ) |
| test_group.add_argument( |
| "--hwtest_dut_dimensions", |
| action="split_extend", |
| default=None, |
| help="Space-separated list of key:val Swarming bot " |
| "dimensions to run each builders SkylabHWTest " |
| "stages against (this overrides the configured " |
| "DUT dimensions for each test). Requires at least " |
| '"label-board", "label-model", and "label-pool".', |
| ) |
| test_group.add_argument( |
| "--notests", |
| dest="passthrough", |
| action="append_option", |
| help="Override values from buildconfig, run no " |
| "tests, and build no autotest artifacts.", |
| ) |
| test_group.add_argument( |
| "--novmtests", |
| dest="passthrough", |
| action="append_option", |
| help="Override values from buildconfig, run no vmtests.", |
| ) |
| test_group.add_argument( |
| "--noimagetests", |
| dest="passthrough", |
| action="append_option", |
| help="Override values from buildconfig and run no image tests.", |
| ) |
| |
| # <board>-payloads tryjob specific options. |
| payloads_group = parser.add_argument_group( |
| "Payloads", description="Options only used by payloads tryjobs." |
| ) |
| payloads_group.add_argument( |
| "--version", |
| dest="passthrough", |
| action="append_option_value", |
| help="Specify the release version for payload regeneration. " |
| "Ex: 9799.0.0", |
| ) |
| payloads_group.add_argument( |
| "--channel", |
| dest="passthrough", |
| action="append_option_value", |
| help="Specify a channel for a payloads trybot. Can " |
| "be specified multiple times. No valid for " |
| "non-payloads configs.", |
| ) |
| |
| configs_group = parser.add_argument_group( |
| "Configs", |
| description="Options for displaying available build configs.", |
| ) |
| configs_group.add_argument( |
| "-l", |
| "--list", |
| action="store_true", |
| dest="list", |
| default=False, |
| help="List the trybot configs (adjusted by --production).", |
| ) |
| |
| @classmethod |
| def ProcessOptions(cls, parser, options): |
| """Post process options.""" |
| if options.where == CBUILDBOT: |
| options.buildroot = options.buildroot or os.path.join( |
| os.path.dirname(constants.SOURCE_ROOT), "cbuild" |
| ) |
| |
| if options.where == LOCAL: |
| options.buildroot = options.buildroot or os.path.join( |
| os.path.dirname(constants.SOURCE_ROOT), "tryjob" |
| ) |
| |
| if options.buildroot: |
| options.git_cache_dir = options.git_cache_dir or os.path.join( |
| options.buildroot, ".git_cache" |
| ) |
| |
| def Run(self): |
| """Runs `cros tryjob`.""" |
| site_config = config_lib.GetConfig() |
| |
| VerifyOptions(self.options, site_config) |
| |
| logging.info("Verifying patches...") |
| patch_pool = trybot_patch_pool.TrybotPatchPool.FromOptions( |
| gerrit_patches=self.options.gerrit_patches, |
| local_patches=self.options.local_patches, |
| sourceroot=constants.SOURCE_ROOT, |
| remote_patches=[], |
| ) |
| |
| if self.options.where == REMOTE: |
| return RunRemote(site_config, self.options, patch_pool) |
| elif self.options.where == INFRA_TESTING: |
| return RunRemote( |
| site_config, self.options, patch_pool, infra_testing=True |
| ) |
| elif self.options.production: |
| return RunRemote( |
| site_config, self.options, patch_pool, production=True |
| ) |
| elif self.options.where == LOCAL: |
| return RunLocal(self.options) |
| elif self.options.where == CBUILDBOT: |
| return RunCbuildbot(self.options) |
| else: |
| raise Exception("Unknown options.where: %s" % (self.options.where,)) |