forked from quantumlib/Cirq
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcheck.py
138 lines (108 loc) · 4.87 KB
/
check.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# Copyright 2018 The Cirq Developers
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Tuple, Optional, cast, Set
import abc
import os.path
from dev_tools import env_tools, shell_tools
class CheckResult:
"""Output of a status check that passed, failed, or error'ed."""
def __init__(
self, check: 'Check', success: bool, message: str, unexpected_error: Optional[Exception]
) -> None:
self.check = check
self.success = success
self.message = message
self.unexpected_error = unexpected_error
def __str__(self):
outcome = 'ERROR' if self.unexpected_error else 'pass' if self.success else 'FAIL'
msg = self.unexpected_error if self.unexpected_error else self.message
result = f'{outcome}: {self.check.context()} ({msg})'
return shell_tools.highlight(result, shell_tools.GREEN if self.success else shell_tools.RED)
class Check(metaclass=abc.ABCMeta):
"""A status check that can performed in a python environment."""
def __init__(self, *dependencies):
self.dependencies = dependencies
@abc.abstractmethod
def command_line_switch(self) -> str:
"""Used to identify this check from the command line."""
@abc.abstractmethod
def context(self) -> str:
"""The name of this status check, as shown on github."""
@abc.abstractmethod
def perform_check(self, env: env_tools.PreparedEnv, verbose: bool) -> Tuple[bool, str]:
"""Evaluates the status check and returns a pass/fail with message.
Args:
env: Describes a prepared python 3 environment in which to run.
verbose: When set, more progress output is produced.
Returns:
A tuple containing a pass/fail boolean and then a details message.
"""
def needs_python2_env(self) -> bool:
return False
def run(
self, env: env_tools.PreparedEnv, verbose: bool, previous_failures: Set['Check']
) -> CheckResult:
"""Evaluates this check.
Args:
env: The prepared python environment to run the check in.
verbose: When set, more progress output is produced.
previous_failures: Checks that have already run and failed.
Returns:
A CheckResult instance.
"""
# Skip if a dependency failed.
if previous_failures.intersection(self.dependencies):
print(
shell_tools.highlight('Skipped ' + self.command_line_switch(), shell_tools.YELLOW)
)
return CheckResult(self, False, 'Skipped due to dependency failing.', None)
print(shell_tools.highlight('Running ' + self.command_line_switch(), shell_tools.GREEN))
try:
success, message = self.perform_check(env, verbose=verbose)
result = CheckResult(self, success, message, None)
except Exception as ex:
result = CheckResult(self, False, 'Unexpected error.', ex)
print(
shell_tools.highlight(
'Finished ' + self.command_line_switch(),
shell_tools.GREEN if result.success else shell_tools.RED,
)
)
if verbose:
print(result)
return result
def pick_env_and_run_and_report(
self, env: env_tools.PreparedEnv, verbose: bool, previous_failures: Set['Check']
) -> CheckResult:
"""Evaluates this check in python 3 or 2.7, and reports to github.
If the prepared environments are not linked to a github repository,
with a known access token, reporting to github is skipped.
Args:
env: A prepared python 3 environment.
verbose: When set, more progress output is produced.
previous_failures: Checks that have already run and failed.
Returns:
A CheckResult instance.
"""
env.report_status_to_github('pending', 'Running...', self.context())
chosen_env = cast(env_tools.PreparedEnv, env)
os.chdir(cast(str, chosen_env.destination_directory))
result = self.run(chosen_env, verbose, previous_failures)
if result.unexpected_error is not None:
env.report_status_to_github('error', 'Unexpected error.', self.context())
else:
env.report_status_to_github(
'success' if result.success else 'failure', result.message, self.context()
)
return result