You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
382 lines
11 KiB
382 lines
11 KiB
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
# Copyright 2019 The ChromiumOS Authors
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
"""Modifies a tryjob based off of arguments."""
|
|
|
|
|
|
import argparse
|
|
import enum
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
import chroot
|
|
import failure_modes
|
|
import get_llvm_hash
|
|
import update_chromeos_llvm_hash
|
|
import update_packages_and_run_tests
|
|
import update_tryjob_status
|
|
|
|
|
|
class ModifyTryjob(enum.Enum):
|
|
"""Options to modify a tryjob."""
|
|
|
|
REMOVE = "remove"
|
|
RELAUNCH = "relaunch"
|
|
ADD = "add"
|
|
|
|
|
|
def GetCommandLineArgs():
|
|
"""Parses the command line for the command line arguments."""
|
|
|
|
# Default path to the chroot if a path is not specified.
|
|
cros_root = os.path.expanduser("~")
|
|
cros_root = os.path.join(cros_root, "chromiumos")
|
|
|
|
# Create parser and add optional command-line arguments.
|
|
parser = argparse.ArgumentParser(
|
|
description="Removes, relaunches, or adds a tryjob."
|
|
)
|
|
|
|
# Add argument for the JSON file to use for the update of a tryjob.
|
|
parser.add_argument(
|
|
"--status_file",
|
|
required=True,
|
|
help="The absolute path to the JSON file that contains the tryjobs used "
|
|
"for bisecting LLVM.",
|
|
)
|
|
|
|
# Add argument that determines what action to take on the revision specified.
|
|
parser.add_argument(
|
|
"--modify_tryjob",
|
|
required=True,
|
|
choices=[modify_tryjob.value for modify_tryjob in ModifyTryjob],
|
|
help="What action to perform on the tryjob.",
|
|
)
|
|
|
|
# Add argument that determines which revision to search for in the list of
|
|
# tryjobs.
|
|
parser.add_argument(
|
|
"--revision",
|
|
required=True,
|
|
type=int,
|
|
help="The revision to either remove or relaunch.",
|
|
)
|
|
|
|
# Add argument for other change lists that want to run alongside the tryjob.
|
|
parser.add_argument(
|
|
"--extra_change_lists",
|
|
type=int,
|
|
nargs="+",
|
|
help="change lists that would like to be run alongside the change list "
|
|
"of updating the packages",
|
|
)
|
|
|
|
# Add argument for custom options for the tryjob.
|
|
parser.add_argument(
|
|
"--options",
|
|
required=False,
|
|
nargs="+",
|
|
help="options to use for the tryjob testing",
|
|
)
|
|
|
|
# Add argument for the builder to use for the tryjob.
|
|
parser.add_argument(
|
|
"--builder", help="builder to use for the tryjob testing"
|
|
)
|
|
|
|
# Add argument for a specific chroot path.
|
|
parser.add_argument(
|
|
"--chroot_path",
|
|
default=cros_root,
|
|
help="the path to the chroot (default: %(default)s)",
|
|
)
|
|
|
|
# Add argument for whether to display command contents to `stdout`.
|
|
parser.add_argument(
|
|
"--verbose",
|
|
action="store_true",
|
|
help="display contents of a command to the terminal "
|
|
"(default: %(default)s)",
|
|
)
|
|
|
|
args_output = parser.parse_args()
|
|
|
|
if not os.path.isfile(
|
|
args_output.status_file
|
|
) or not args_output.status_file.endswith(".json"):
|
|
raise ValueError(
|
|
'File does not exist or does not ending in ".json" '
|
|
": %s" % args_output.status_file
|
|
)
|
|
|
|
if (
|
|
args_output.modify_tryjob == ModifyTryjob.ADD.value
|
|
and not args_output.builder
|
|
):
|
|
raise ValueError("A builder is required for adding a tryjob.")
|
|
elif (
|
|
args_output.modify_tryjob != ModifyTryjob.ADD.value
|
|
and args_output.builder
|
|
):
|
|
raise ValueError(
|
|
"Specifying a builder is only available when adding a " "tryjob."
|
|
)
|
|
|
|
return args_output
|
|
|
|
|
|
def GetCLAfterUpdatingPackages(
|
|
packages,
|
|
git_hash,
|
|
svn_version,
|
|
chroot_path,
|
|
patch_metadata_file,
|
|
svn_option,
|
|
):
|
|
"""Updates the packages' LLVM_NEXT."""
|
|
|
|
change_list = update_chromeos_llvm_hash.UpdatePackages(
|
|
packages=packages,
|
|
manifest_packages=[],
|
|
llvm_variant=update_chromeos_llvm_hash.LLVMVariant.next,
|
|
git_hash=git_hash,
|
|
svn_version=svn_version,
|
|
chroot_path=chroot_path,
|
|
mode=failure_modes.FailureModes.DISABLE_PATCHES,
|
|
git_hash_source=svn_option,
|
|
extra_commit_msg=None,
|
|
)
|
|
|
|
print("\nSuccessfully updated packages to %d" % svn_version)
|
|
print("Gerrit URL: %s" % change_list.url)
|
|
print("Change list number: %d" % change_list.cl_number)
|
|
|
|
return change_list
|
|
|
|
|
|
def CreateNewTryjobEntryForBisection(
|
|
cl, extra_cls, options, builder, chroot_path, cl_url, revision
|
|
):
|
|
"""Submits a tryjob and adds additional information."""
|
|
|
|
# Get the tryjob results after submitting the tryjob.
|
|
# Format of 'tryjob_results':
|
|
# [
|
|
# {
|
|
# 'link' : [TRYJOB_LINK],
|
|
# 'buildbucket_id' : [BUILDBUCKET_ID],
|
|
# 'extra_cls' : [EXTRA_CLS_LIST],
|
|
# 'options' : [EXTRA_OPTIONS_LIST],
|
|
# 'builder' : [BUILDER_AS_A_LIST]
|
|
# }
|
|
# ]
|
|
tryjob_results = update_packages_and_run_tests.RunTryJobs(
|
|
cl, extra_cls, options, [builder], chroot_path
|
|
)
|
|
print("\nTryjob:")
|
|
print(tryjob_results[0])
|
|
|
|
# Add necessary information about the tryjob.
|
|
tryjob_results[0]["url"] = cl_url
|
|
tryjob_results[0]["rev"] = revision
|
|
tryjob_results[0][
|
|
"status"
|
|
] = update_tryjob_status.TryjobStatus.PENDING.value
|
|
tryjob_results[0]["cl"] = cl
|
|
|
|
return tryjob_results[0]
|
|
|
|
|
|
def AddTryjob(
|
|
packages,
|
|
git_hash,
|
|
revision,
|
|
chroot_path,
|
|
patch_metadata_file,
|
|
extra_cls,
|
|
options,
|
|
builder,
|
|
verbose,
|
|
svn_option,
|
|
):
|
|
"""Submits a tryjob."""
|
|
|
|
update_chromeos_llvm_hash.verbose = verbose
|
|
|
|
change_list = GetCLAfterUpdatingPackages(
|
|
packages,
|
|
git_hash,
|
|
revision,
|
|
chroot_path,
|
|
patch_metadata_file,
|
|
svn_option,
|
|
)
|
|
|
|
tryjob_dict = CreateNewTryjobEntryForBisection(
|
|
change_list.cl_number,
|
|
extra_cls,
|
|
options,
|
|
builder,
|
|
chroot_path,
|
|
change_list.url,
|
|
revision,
|
|
)
|
|
|
|
return tryjob_dict
|
|
|
|
|
|
def PerformTryjobModification(
|
|
revision,
|
|
modify_tryjob,
|
|
status_file,
|
|
extra_cls,
|
|
options,
|
|
builder,
|
|
chroot_path,
|
|
verbose,
|
|
):
|
|
"""Removes, relaunches, or adds a tryjob.
|
|
|
|
Args:
|
|
revision: The revision associated with the tryjob.
|
|
modify_tryjob: What action to take on the tryjob.
|
|
Ex: ModifyTryjob.REMOVE, ModifyTryjob.RELAUNCH, ModifyTryjob.ADD
|
|
status_file: The .JSON file that contains the tryjobs.
|
|
extra_cls: Extra change lists to be run alongside tryjob
|
|
options: Extra options to pass into 'cros tryjob'.
|
|
builder: The builder to use for 'cros tryjob'.
|
|
chroot_path: The absolute path to the chroot (used by 'cros tryjob' when
|
|
relaunching a tryjob).
|
|
verbose: Determines whether to print the contents of a command to `stdout`.
|
|
"""
|
|
|
|
# Format of 'bisect_contents':
|
|
# {
|
|
# 'start': [START_REVISION_OF_BISECTION]
|
|
# 'end': [END_REVISION_OF_BISECTION]
|
|
# 'jobs' : [
|
|
# {[TRYJOB_INFORMATION]},
|
|
# {[TRYJOB_INFORMATION]},
|
|
# ...,
|
|
# {[TRYJOB_INFORMATION]}
|
|
# ]
|
|
# }
|
|
with open(status_file) as tryjobs:
|
|
bisect_contents = json.load(tryjobs)
|
|
|
|
if not bisect_contents["jobs"] and modify_tryjob != ModifyTryjob.ADD:
|
|
sys.exit("No tryjobs in %s" % status_file)
|
|
|
|
tryjob_index = update_tryjob_status.FindTryjobIndex(
|
|
revision, bisect_contents["jobs"]
|
|
)
|
|
|
|
# 'FindTryjobIndex()' returns None if the tryjob was not found.
|
|
if tryjob_index is None and modify_tryjob != ModifyTryjob.ADD:
|
|
raise ValueError(
|
|
"Unable to find tryjob for %d in %s" % (revision, status_file)
|
|
)
|
|
|
|
# Determine the action to take based off of 'modify_tryjob'.
|
|
if modify_tryjob == ModifyTryjob.REMOVE:
|
|
del bisect_contents["jobs"][tryjob_index]
|
|
|
|
print("Successfully deleted the tryjob of revision %d" % revision)
|
|
elif modify_tryjob == ModifyTryjob.RELAUNCH:
|
|
# Need to update the tryjob link and buildbucket ID.
|
|
tryjob_results = update_packages_and_run_tests.RunTryJobs(
|
|
bisect_contents["jobs"][tryjob_index]["cl"],
|
|
bisect_contents["jobs"][tryjob_index]["extra_cls"],
|
|
bisect_contents["jobs"][tryjob_index]["options"],
|
|
bisect_contents["jobs"][tryjob_index]["builder"],
|
|
chroot_path,
|
|
)
|
|
|
|
bisect_contents["jobs"][tryjob_index][
|
|
"status"
|
|
] = update_tryjob_status.TryjobStatus.PENDING.value
|
|
bisect_contents["jobs"][tryjob_index]["link"] = tryjob_results[0][
|
|
"link"
|
|
]
|
|
bisect_contents["jobs"][tryjob_index][
|
|
"buildbucket_id"
|
|
] = tryjob_results[0]["buildbucket_id"]
|
|
|
|
print(
|
|
"Successfully relaunched the tryjob for revision %d and updated "
|
|
"the tryjob link to %s" % (revision, tryjob_results[0]["link"])
|
|
)
|
|
elif modify_tryjob == ModifyTryjob.ADD:
|
|
# Tryjob exists already.
|
|
if tryjob_index is not None:
|
|
raise ValueError(
|
|
"Tryjob already exists (index is %d) in %s."
|
|
% (tryjob_index, status_file)
|
|
)
|
|
|
|
# Make sure the revision is within the bounds of the start and end of the
|
|
# bisection.
|
|
elif bisect_contents["start"] < revision < bisect_contents["end"]:
|
|
|
|
patch_metadata_file = "PATCHES.json"
|
|
|
|
(
|
|
git_hash,
|
|
revision,
|
|
) = get_llvm_hash.GetLLVMHashAndVersionFromSVNOption(revision)
|
|
|
|
tryjob_dict = AddTryjob(
|
|
update_chromeos_llvm_hash.DEFAULT_PACKAGES,
|
|
git_hash,
|
|
revision,
|
|
chroot_path,
|
|
patch_metadata_file,
|
|
extra_cls,
|
|
options,
|
|
builder,
|
|
verbose,
|
|
revision,
|
|
)
|
|
|
|
bisect_contents["jobs"].append(tryjob_dict)
|
|
|
|
print("Successfully added tryjob of revision %d" % revision)
|
|
else:
|
|
raise ValueError("Failed to add tryjob to %s" % status_file)
|
|
else:
|
|
raise ValueError(
|
|
'Invalid "modify_tryjob" option provided: %s' % modify_tryjob
|
|
)
|
|
|
|
with open(status_file, "w") as update_tryjobs:
|
|
json.dump(
|
|
bisect_contents, update_tryjobs, indent=4, separators=(",", ": ")
|
|
)
|
|
|
|
|
|
def main():
|
|
"""Removes, relaunches, or adds a tryjob."""
|
|
|
|
chroot.VerifyOutsideChroot()
|
|
|
|
args_output = GetCommandLineArgs()
|
|
|
|
PerformTryjobModification(
|
|
args_output.revision,
|
|
ModifyTryjob(args_output.modify_tryjob),
|
|
args_output.status_file,
|
|
args_output.extra_change_lists,
|
|
args_output.options,
|
|
args_output.builder,
|
|
args_output.chroot_path,
|
|
args_output.verbose,
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|