# 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. # noqa: E402 pylint: disable=invalid-name """Contains all the pre-upload and pre-commit validation checks for SuiteSets""" # Optional but recommended PRESUBMIT_VERSION = "2.0.0" # Mandatory: run under Python 3 USE_PYTHON3 = True def CheckProtosAreUpToDate(input_api, output_api): """CheckProtosAreUpToDate validates the generated protos are up-to-date.""" suite_set_root = input_api.PresubmitLocalPath() err = _generate_protos(input_api, suite_set_root) if err: return [output_api.PresubmitError(err)] proto_dir = input_api.os_path.join(suite_set_root, "generated") proto_diff, err = _git_diff(input_api, proto_dir) if err: return [output_api.PresubmitError(err)] if proto_diff: err_msg = ( "The generated proto files are not up-to-date.\n\n" "Amend the commit to include the unstaged changes\n" "to the generated proto files." ) return [output_api.PresubmitError(err_msg)] return [] def CheckSuiteSetsAreWellFormed(input_api, output_api): """CheckSuiteSetsAreWellFormed checks the wellformedness of the protos.""" script_path = input_api.os_path.join( input_api.PresubmitLocalPath(), "presubmit/validate_suite_sets.py" ) suite_sets_proto_file = input_api.os_path.join( input_api.PresubmitLocalPath(), "generated/suite_sets.jsonpb" ) suites_proto_file = input_api.os_path.join( input_api.PresubmitLocalPath(), "generated/suites.jsonpb" ) any_file_affected = ( _is_affected_file(input_api, script_path) or _is_affected_file(input_api, suite_sets_proto_file) or _is_affected_file(input_api, suites_proto_file) ) if not any_file_affected: return [] cmd_name = "validate_suite_sets" cmd = [ input_api.python3_executable, script_path, "--suite_set_file", suite_sets_proto_file, "--suite_file", suites_proto_file, ] presubmit_cmd = input_api.Command( name=cmd_name, cmd=cmd, kwargs={}, message=output_api.PresubmitPromptWarning, ) print("Running " + cmd_name) return input_api.RunTests([presubmit_cmd]) def _generate_protos(input_api, suite_set_root): """_generate_protos calls the given script.""" generate_script = input_api.os_path.join(suite_set_root, "generate.sh") cmd = [generate_script] proc = input_api.subprocess.Popen( args=cmd, stdout=input_api.subprocess.PIPE, stderr=input_api.subprocess.PIPE, universal_newlines=True, ) _, err = proc.communicate() if proc.returncode and err: return f"Error when calling {generate_script}: {str(err)}" return None def _git_diff(input_api, path): """_git_diff returns the string generated by git diff for the given path.""" cmd = ["git", "diff", path] proc = input_api.subprocess.Popen( args=cmd, stdout=input_api.subprocess.PIPE, stderr=input_api.subprocess.PIPE, universal_newlines=True, ) out, err = proc.communicate() if proc.returncode and err: return None, f"Error when calling git diff: {str(err)}" return out.strip(), None def _is_affected_file(input_api, file_to_check): """_is_affected_file returns True if given file in the affected files.""" def is_file_to_check(file): norm_f_path = input_api.os_path.normpath(file.AbsoluteLocalPath()) norm_f_to_check_path = input_api.os_path.normpath(file_to_check) return norm_f_path == norm_f_to_check_path affected_files = input_api.AffectedFiles(file_filter=is_file_to_check) return len(affected_files) > 0