• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2016 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#      http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Common errors thrown when repo preupload checks fail."""
16
17import os
18import sys
19from typing import List, NamedTuple, Optional
20
21_path = os.path.realpath(__file__ + '/../..')
22if sys.path[0] != _path:
23    sys.path.insert(0, _path)
24del _path
25
26
27class HookResult(object):
28    """A single hook result."""
29
30    def __init__(self, hook, project, commit, error, files=(),
31                 fixup_cmd: Optional[List[str]] = None):
32        """Initialize.
33
34        Args:
35          hook: The name of the hook.
36          project: The name of the project.
37          commit: The git commit sha.
38          error: A string representation of the hook's result.  Empty on
39              success.
40          files: The list of files that were involved in the hook execution.
41          fixup_cmd: A command that can automatically fix errors found in the
42              hook's execution.  Can be None if the hook does not support
43              automatic fixups.
44        """
45        self.hook = hook
46        self.project = project
47        self.commit = commit
48        self.error = error
49        self.files = files
50        self.fixup_cmd = fixup_cmd
51
52    def __bool__(self):
53        """Whether this result is an error."""
54        return bool(self.error)
55
56    def is_warning(self):
57        """Whether this result is a non-fatal warning."""
58        return False
59
60
61class HookCommandResult(HookResult):
62    """A single hook result based on a CompletedProcess."""
63
64    def __init__(self, hook, project, commit, result, files=(),
65                 fixup_cmd=None):
66        HookResult.__init__(self, hook, project, commit,
67                            result.stderr if result.stderr else result.stdout,
68                            files=files, fixup_cmd=fixup_cmd)
69        self.result = result
70
71    def __bool__(self):
72        """Whether this result is an error."""
73        return self.result.returncode not in (None, 0, 77)
74
75    def is_warning(self):
76        """Whether this result is a non-fatal warning."""
77        return self.result.returncode == 77
78
79
80class ProjectResults(NamedTuple):
81    """All results for a single project."""
82
83    project: str
84    workdir: str
85
86    # All the results from running all the hooks.
87    results: List[HookResult] = []
88
89    # Whether there were any non-hook related errors.  For example, trying to
90    # parse the project configuration.
91    internal_failure: bool = False
92
93    def add_results(self, results: Optional[List[HookResult]]) -> None:
94        """Add |results| to our results."""
95        if results:
96            self.results.extend(results)
97
98    @property
99    def fixups(self):
100        """Yield results that have a fixup available."""
101        yield from (x for x in self.results if x and x.fixup_cmd)
102
103    def __bool__(self):
104        """Whether there are any errors in this set of results."""
105        return self.internal_failure or any(self.results)
106