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