aboutsummaryrefslogtreecommitdiff
path: root/llvm_tools/update_tryjob_status.py
diff options
context:
space:
mode:
Diffstat (limited to 'llvm_tools/update_tryjob_status.py')
-rwxr-xr-xllvm_tools/update_tryjob_status.py459
1 files changed, 252 insertions, 207 deletions
diff --git a/llvm_tools/update_tryjob_status.py b/llvm_tools/update_tryjob_status.py
index f25fadca..49c48658 100755
--- a/llvm_tools/update_tryjob_status.py
+++ b/llvm_tools/update_tryjob_status.py
@@ -1,12 +1,11 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
-# Copyright 2019 The Chromium OS Authors. All rights reserved.
+# 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.
"""Updates the status of a tryjob."""
-from __future__ import print_function
import argparse
import enum
@@ -20,245 +19,291 @@ from test_helpers import CreateTemporaryJsonFile
class TryjobStatus(enum.Enum):
- """Values for the 'status' field of a tryjob."""
+ """Values for the 'status' field of a tryjob."""
- GOOD = 'good'
- BAD = 'bad'
- PENDING = 'pending'
- SKIP = 'skip'
+ GOOD = "good"
+ BAD = "bad"
+ PENDING = "pending"
+ SKIP = "skip"
- # Executes the script passed into the command line (this script's exit code
- # determines the 'status' value of the tryjob).
- CUSTOM_SCRIPT = 'custom_script'
+ # Executes the script passed into the command line (this script's exit code
+ # determines the 'status' value of the tryjob).
+ CUSTOM_SCRIPT = "custom_script"
class CustomScriptStatus(enum.Enum):
- """Exit code values of a custom script."""
+ """Exit code values of a custom script."""
- # NOTE: Not using 1 for 'bad' because the custom script can raise an
- # exception which would cause the exit code of the script to be 1, so the
- # tryjob's 'status' would be updated when there is an exception.
- #
- # Exit codes are as follows:
- # 0: 'good'
- # 124: 'bad'
- # 125: 'skip'
- GOOD = 0
- BAD = 124
- SKIP = 125
+ # NOTE: Not using 1 for 'bad' because the custom script can raise an
+ # exception which would cause the exit code of the script to be 1, so the
+ # tryjob's 'status' would be updated when there is an exception.
+ #
+ # Exit codes are as follows:
+ # 0: 'good'
+ # 124: 'bad'
+ # 125: 'skip'
+ GOOD = 0
+ BAD = 124
+ SKIP = 125
custom_script_exit_value_mapping = {
CustomScriptStatus.GOOD.value: TryjobStatus.GOOD.value,
CustomScriptStatus.BAD.value: TryjobStatus.BAD.value,
- CustomScriptStatus.SKIP.value: TryjobStatus.SKIP.value
+ CustomScriptStatus.SKIP.value: TryjobStatus.SKIP.value,
}
def GetCommandLineArgs():
- """Parses the command line for the command line arguments."""
-
- # Default absoute path to the chroot if 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='Updates the status of 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 sets the 'status' field to that value.
- parser.add_argument(
- '--set_status',
- required=True,
- choices=[tryjob_status.value for tryjob_status in TryjobStatus],
- help='Sets the "status" field of 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 set its status.')
-
- # Add argument for the custom script to execute for the 'custom_script'
- # option in '--set_status'.
- parser.add_argument(
- '--custom_script',
- help='The absolute path to the custom script to execute (its exit code '
- 'should be %d for "good", %d for "bad", or %d for "skip")' %
- (CustomScriptStatus.GOOD.value, CustomScriptStatus.BAD.value,
- CustomScriptStatus.SKIP.value))
-
- args_output = parser.parse_args()
-
- if not (os.path.isfile(
- args_output.status_file and
- 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.set_status == TryjobStatus.CUSTOM_SCRIPT.value and
- not args_output.custom_script):
- raise ValueError('Please provide the absolute path to the script to '
- 'execute.')
-
- return args_output
+ """Parses the command line for the command line arguments."""
+
+ # Default absoute path to the chroot if 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="Updates the status of 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 sets the 'status' field to that value.
+ parser.add_argument(
+ "--set_status",
+ required=True,
+ choices=[tryjob_status.value for tryjob_status in TryjobStatus],
+ help='Sets the "status" field of 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 set its status.",
+ )
+
+ # Add argument for the custom script to execute for the 'custom_script'
+ # option in '--set_status'.
+ parser.add_argument(
+ "--custom_script",
+ help="The absolute path to the custom script to execute (its exit code "
+ 'should be %d for "good", %d for "bad", or %d for "skip")'
+ % (
+ CustomScriptStatus.GOOD.value,
+ CustomScriptStatus.BAD.value,
+ CustomScriptStatus.SKIP.value,
+ ),
+ )
+
+ args_output = parser.parse_args()
+
+ if not (
+ os.path.isfile(
+ args_output.status_file
+ and 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.set_status == TryjobStatus.CUSTOM_SCRIPT.value
+ and not args_output.custom_script
+ ):
+ raise ValueError(
+ "Please provide the absolute path to the script to " "execute."
+ )
+
+ return args_output
def FindTryjobIndex(revision, tryjobs_list):
- """Searches the list of tryjob dictionaries to find 'revision'.
+ """Searches the list of tryjob dictionaries to find 'revision'.
- Uses the key 'rev' for each dictionary and compares the value against
- 'revision.'
+ Uses the key 'rev' for each dictionary and compares the value against
+ 'revision.'
- Args:
- revision: The revision to search for in the tryjobs.
- tryjobs_list: A list of tryjob dictionaries of the format:
- {
- 'rev' : [REVISION],
- 'url' : [URL_OF_CL],
- 'cl' : [CL_NUMBER],
- 'link' : [TRYJOB_LINK],
- 'status' : [TRYJOB_STATUS],
- 'buildbucket_id': [BUILDBUCKET_ID]
- }
+ Args:
+ revision: The revision to search for in the tryjobs.
+ tryjobs_list: A list of tryjob dictionaries of the format:
+ {
+ 'rev' : [REVISION],
+ 'url' : [URL_OF_CL],
+ 'cl' : [CL_NUMBER],
+ 'link' : [TRYJOB_LINK],
+ 'status' : [TRYJOB_STATUS],
+ 'buildbucket_id': [BUILDBUCKET_ID]
+ }
- Returns:
- The index within the list or None to indicate it was not found.
- """
+ Returns:
+ The index within the list or None to indicate it was not found.
+ """
- for cur_index, cur_tryjob_dict in enumerate(tryjobs_list):
- if cur_tryjob_dict['rev'] == revision:
- return cur_index
+ for cur_index, cur_tryjob_dict in enumerate(tryjobs_list):
+ if cur_tryjob_dict["rev"] == revision:
+ return cur_index
- return None
+ return None
def GetCustomScriptResult(custom_script, status_file, tryjob_contents):
- """Returns the conversion of the exit code of the custom script.
-
- Args:
- custom_script: Absolute path to the script to be executed.
- status_file: Absolute path to the file that contains information about the
- bisection of LLVM.
- tryjob_contents: A dictionary of the contents of the tryjob (e.g. 'status',
- 'url', 'link', 'buildbucket_id', etc.).
-
- Returns:
- The exit code conversion to either return 'good', 'bad', or 'skip'.
-
- Raises:
- ValueError: The custom script failed to provide the correct exit code.
- """
-
- # Create a temporary file to write the contents of the tryjob at index
- # 'tryjob_index' (the temporary file path will be passed into the custom
- # script as a command line argument).
- with CreateTemporaryJsonFile() as temp_json_file:
- with open(temp_json_file, 'w') as tryjob_file:
- json.dump(tryjob_contents, tryjob_file, indent=4, separators=(',', ': '))
-
- exec_script_cmd = [custom_script, temp_json_file]
-
- # Execute the custom script to get the exit code.
- exec_script_cmd_obj = subprocess.Popen(
- exec_script_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- _, stderr = exec_script_cmd_obj.communicate()
-
- # Invalid exit code by the custom script.
- if exec_script_cmd_obj.returncode not in custom_script_exit_value_mapping:
- # Save the .JSON file to the directory of 'status_file'.
- name_of_json_file = os.path.join(
- os.path.dirname(status_file), os.path.basename(temp_json_file))
-
- os.rename(temp_json_file, name_of_json_file)
-
- raise ValueError(
- 'Custom script %s exit code %d did not match '
- 'any of the expected exit codes: %d for "good", %d '
- 'for "bad", or %d for "skip".\nPlease check %s for information '
- 'about the tryjob: %s' %
- (custom_script, exec_script_cmd_obj.returncode,
- CustomScriptStatus.GOOD.value, CustomScriptStatus.BAD.value,
- CustomScriptStatus.SKIP.value, name_of_json_file, stderr))
-
- return custom_script_exit_value_mapping[exec_script_cmd_obj.returncode]
+ """Returns the conversion of the exit code of the custom script.
+
+ Args:
+ custom_script: Absolute path to the script to be executed.
+ status_file: Absolute path to the file that contains information about the
+ bisection of LLVM.
+ tryjob_contents: A dictionary of the contents of the tryjob (e.g. 'status',
+ 'url', 'link', 'buildbucket_id', etc.).
+
+ Returns:
+ The exit code conversion to either return 'good', 'bad', or 'skip'.
+
+ Raises:
+ ValueError: The custom script failed to provide the correct exit code.
+ """
+
+ # Create a temporary file to write the contents of the tryjob at index
+ # 'tryjob_index' (the temporary file path will be passed into the custom
+ # script as a command line argument).
+ with CreateTemporaryJsonFile() as temp_json_file:
+ with open(temp_json_file, "w") as tryjob_file:
+ json.dump(
+ tryjob_contents, tryjob_file, indent=4, separators=(",", ": ")
+ )
+
+ exec_script_cmd = [custom_script, temp_json_file]
+
+ # Execute the custom script to get the exit code.
+ exec_script_cmd_obj = subprocess.Popen(
+ exec_script_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE
+ )
+ _, stderr = exec_script_cmd_obj.communicate()
+
+ # Invalid exit code by the custom script.
+ if (
+ exec_script_cmd_obj.returncode
+ not in custom_script_exit_value_mapping
+ ):
+ # Save the .JSON file to the directory of 'status_file'.
+ name_of_json_file = os.path.join(
+ os.path.dirname(status_file), os.path.basename(temp_json_file)
+ )
+
+ os.rename(temp_json_file, name_of_json_file)
+
+ raise ValueError(
+ "Custom script %s exit code %d did not match "
+ 'any of the expected exit codes: %d for "good", %d '
+ 'for "bad", or %d for "skip".\nPlease check %s for information '
+ "about the tryjob: %s"
+ % (
+ custom_script,
+ exec_script_cmd_obj.returncode,
+ CustomScriptStatus.GOOD.value,
+ CustomScriptStatus.BAD.value,
+ CustomScriptStatus.SKIP.value,
+ name_of_json_file,
+ stderr,
+ )
+ )
+
+ return custom_script_exit_value_mapping[exec_script_cmd_obj.returncode]
def UpdateTryjobStatus(revision, set_status, status_file, custom_script):
- """Updates a tryjob's 'status' field based off of 'set_status'.
-
- Args:
- revision: The revision associated with the tryjob.
- set_status: What to update the 'status' field to.
- Ex: TryjobStatus.Good, TryjobStatus.BAD, TryjobStatus.PENDING, or
- TryjobStatus.
- status_file: The .JSON file that contains the tryjobs.
- custom_script: The absolute path to a script that will be executed which
- will determine the 'status' value of the tryjob.
- """
-
- # 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']:
- sys.exit('No tryjobs in %s' % status_file)
-
- tryjob_index = FindTryjobIndex(revision, bisect_contents['jobs'])
-
- # 'FindTryjobIndex()' returns None if the revision was not found.
- if tryjob_index is None:
- raise ValueError('Unable to find tryjob for %d in %s' %
- (revision, status_file))
-
- # Set 'status' depending on 'set_status' for the tryjob.
- if set_status == TryjobStatus.GOOD:
- bisect_contents['jobs'][tryjob_index]['status'] = TryjobStatus.GOOD.value
- elif set_status == TryjobStatus.BAD:
- bisect_contents['jobs'][tryjob_index]['status'] = TryjobStatus.BAD.value
- elif set_status == TryjobStatus.PENDING:
- bisect_contents['jobs'][tryjob_index]['status'] = TryjobStatus.PENDING.value
- elif set_status == TryjobStatus.SKIP:
- bisect_contents['jobs'][tryjob_index]['status'] = TryjobStatus.SKIP.value
- elif set_status == TryjobStatus.CUSTOM_SCRIPT:
- bisect_contents['jobs'][tryjob_index]['status'] = GetCustomScriptResult(
- custom_script, status_file, bisect_contents['jobs'][tryjob_index])
- else:
- raise ValueError('Invalid "set_status" option provided: %s' % set_status)
-
- with open(status_file, 'w') as update_tryjobs:
- json.dump(bisect_contents, update_tryjobs, indent=4, separators=(',', ': '))
+ """Updates a tryjob's 'status' field based off of 'set_status'.
+
+ Args:
+ revision: The revision associated with the tryjob.
+ set_status: What to update the 'status' field to.
+ Ex: TryjobStatus.Good, TryjobStatus.BAD, TryjobStatus.PENDING, or
+ TryjobStatus.
+ status_file: The .JSON file that contains the tryjobs.
+ custom_script: The absolute path to a script that will be executed which
+ will determine the 'status' value of the tryjob.
+ """
+
+ # 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"]:
+ sys.exit("No tryjobs in %s" % status_file)
+
+ tryjob_index = FindTryjobIndex(revision, bisect_contents["jobs"])
+
+ # 'FindTryjobIndex()' returns None if the revision was not found.
+ if tryjob_index is None:
+ raise ValueError(
+ "Unable to find tryjob for %d in %s" % (revision, status_file)
+ )
+
+ # Set 'status' depending on 'set_status' for the tryjob.
+ if set_status == TryjobStatus.GOOD:
+ bisect_contents["jobs"][tryjob_index][
+ "status"
+ ] = TryjobStatus.GOOD.value
+ elif set_status == TryjobStatus.BAD:
+ bisect_contents["jobs"][tryjob_index]["status"] = TryjobStatus.BAD.value
+ elif set_status == TryjobStatus.PENDING:
+ bisect_contents["jobs"][tryjob_index][
+ "status"
+ ] = TryjobStatus.PENDING.value
+ elif set_status == TryjobStatus.SKIP:
+ bisect_contents["jobs"][tryjob_index][
+ "status"
+ ] = TryjobStatus.SKIP.value
+ elif set_status == TryjobStatus.CUSTOM_SCRIPT:
+ bisect_contents["jobs"][tryjob_index]["status"] = GetCustomScriptResult(
+ custom_script, status_file, bisect_contents["jobs"][tryjob_index]
+ )
+ else:
+ raise ValueError(
+ 'Invalid "set_status" option provided: %s' % set_status
+ )
+
+ with open(status_file, "w") as update_tryjobs:
+ json.dump(
+ bisect_contents, update_tryjobs, indent=4, separators=(",", ": ")
+ )
def main():
- """Updates the status of a tryjob."""
+ """Updates the status of a tryjob."""
- chroot.VerifyOutsideChroot()
+ chroot.VerifyOutsideChroot()
- args_output = GetCommandLineArgs()
+ args_output = GetCommandLineArgs()
- UpdateTryjobStatus(args_output.revision, TryjobStatus(args_output.set_status),
- args_output.status_file, args_output.custom_script)
+ UpdateTryjobStatus(
+ args_output.revision,
+ TryjobStatus(args_output.set_status),
+ args_output.status_file,
+ args_output.custom_script,
+ )
-if __name__ == '__main__':
- main()
+if __name__ == "__main__":
+ main()