• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2024 The ChromiumOS Authors
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4# noqa: E402 pylint: disable=invalid-name
5
6"""Contains all the pre-upload and pre-commit validation checks for SuiteSets"""
7
8# Optional but recommended
9PRESUBMIT_VERSION = "2.0.0"
10
11# Mandatory: run under Python 3
12USE_PYTHON3 = True
13
14
15def CheckProtosAreUpToDate(input_api, output_api):
16    """CheckProtosAreUpToDate validates the generated protos are up-to-date."""
17    suite_set_root = input_api.PresubmitLocalPath()
18    err = _generate_protos(input_api, suite_set_root)
19    if err:
20        return [output_api.PresubmitError(err)]
21
22    proto_dir = input_api.os_path.join(suite_set_root, "generated")
23    proto_diff, err = _git_diff(input_api, proto_dir)
24    if err:
25        return [output_api.PresubmitError(err)]
26    if proto_diff:
27        err_msg = (
28            "The generated proto files are not up-to-date.\n\n"
29            "Amend the commit to include the unstaged changes\n"
30            "to the generated proto files."
31        )
32        return [output_api.PresubmitError(err_msg)]
33    return []
34
35
36def CheckSuiteSetsAreWellFormed(input_api, output_api):
37    """CheckSuiteSetsAreWellFormed checks the wellformedness of the protos."""
38    script_path = input_api.os_path.join(
39        input_api.PresubmitLocalPath(), "presubmit/validate_suite_sets.py"
40    )
41    suite_sets_proto_file = input_api.os_path.join(
42        input_api.PresubmitLocalPath(), "generated/suite_sets.jsonpb"
43    )
44    suites_proto_file = input_api.os_path.join(
45        input_api.PresubmitLocalPath(), "generated/suites.jsonpb"
46    )
47    any_file_affected = (
48        _is_affected_file(input_api, script_path)
49        or _is_affected_file(input_api, suite_sets_proto_file)
50        or _is_affected_file(input_api, suites_proto_file)
51    )
52    if not any_file_affected:
53        return []
54
55    cmd_name = "validate_suite_sets"
56    cmd = [
57        input_api.python3_executable,
58        script_path,
59        "--suite_set_file",
60        suite_sets_proto_file,
61        "--suite_file",
62        suites_proto_file,
63    ]
64    presubmit_cmd = input_api.Command(
65        name=cmd_name,
66        cmd=cmd,
67        kwargs={},
68        message=output_api.PresubmitPromptWarning,
69    )
70    print("Running " + cmd_name)
71    return input_api.RunTests([presubmit_cmd])
72
73
74def _generate_protos(input_api, suite_set_root):
75    """_generate_protos calls the given script."""
76    generate_script = input_api.os_path.join(suite_set_root, "generate.sh")
77    cmd = [generate_script]
78    proc = input_api.subprocess.Popen(
79        args=cmd,
80        stdout=input_api.subprocess.PIPE,
81        stderr=input_api.subprocess.PIPE,
82        universal_newlines=True,
83    )
84    _, err = proc.communicate()
85    if proc.returncode and err:
86        return f"Error when calling {generate_script}: {str(err)}"
87    return None
88
89
90def _git_diff(input_api, path):
91    """_git_diff returns the string generated by git diff for the given path."""
92    cmd = ["git", "diff", path]
93    proc = input_api.subprocess.Popen(
94        args=cmd,
95        stdout=input_api.subprocess.PIPE,
96        stderr=input_api.subprocess.PIPE,
97        universal_newlines=True,
98    )
99    out, err = proc.communicate()
100    if proc.returncode and err:
101        return None, f"Error when calling git diff: {str(err)}"
102    return out.strip(), None
103
104
105def _is_affected_file(input_api, file_to_check):
106    """_is_affected_file returns True if given file in the affected files."""
107
108    def is_file_to_check(file):
109        norm_f_path = input_api.os_path.normpath(file.AbsoluteLocalPath())
110        norm_f_to_check_path = input_api.os_path.normpath(file_to_check)
111        return norm_f_path == norm_f_to_check_path
112
113    affected_files = input_api.AffectedFiles(file_filter=is_file_to_check)
114    return len(affected_files) > 0
115