Skip to content

Commit 68a8540

Browse files
committed
Add email notifications
1 parent ae04b8f commit 68a8540

File tree

1 file changed

+68
-24
lines changed

1 file changed

+68
-24
lines changed

mx.graalpython/mx_graalpython_bisect.py

Lines changed: 68 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import re
2-
import os
3-
import sys
41
import argparse
2+
import configparser
3+
import os
4+
import re
55
import shlex
6+
import sys
67
import types
7-
import configparser
88

99
import mx
1010

@@ -48,7 +48,7 @@ def run_bisect_benchmark(suite, bad, good, callback, threshold=None):
4848
abortOnError=True,
4949
).splitlines()
5050
if not commits:
51-
sys.exit("No merge commits found in the range. Did you swap good and bad?")
51+
raise RuntimeError("No merge commits found in the range. Did you swap good and bad?")
5252
downstream_suite = get_downstream_suite(suite)
5353
values = [None] * len(commits)
5454
if threshold is None:
@@ -60,7 +60,7 @@ def run_bisect_benchmark(suite, bad, good, callback, threshold=None):
6060
downstream_good = get_commit(downstream_suite)
6161
threshold = (values[bad_index] + values[good_index]) / 2
6262
if values[good_index] * 1.03 > values[bad_index]:
63-
sys.exit(
63+
raise RuntimeError(
6464
"Didn't detect a regression - less that 3% difference between good value "
6565
"{} and bad value {}".format(values[good_index], values[bad_index])
6666
)
@@ -118,25 +118,26 @@ def bad_commit(self):
118118

119119
def visualize(self, level=1):
120120
level_marker = '=' * level
121-
print(level_marker, self.repo_name)
121+
out = ["{} {}".format(level_marker, self.repo_name)]
122122
for index, (commit, value) in enumerate(zip(self.commits, self.values)):
123123
if value is not None:
124-
print("{} {} {:6.6} {}".format(level_marker, commit, value, get_message(self.suite, commit)))
124+
out.append("{} {} {:6.6} s {}".format(level_marker, commit, value, get_message(self.suite, commit)))
125125
if self.subresults and index in self.subresults:
126-
self.subresults[index].visualize(level + 1)
126+
out.append(self.subresults[index].visualize(level + 1))
127+
return '\n'.join(out)
127128

128129
def summarize(self):
129130
if self.bad_commit and self.good_commit:
130131
for subresult in self.subresults.values():
131-
if subresult.summarize():
132-
return True
133-
print("Detected bad commit in {} repository:\n{} {}"
134-
.format(self.repo_name, self.bad_commit, get_message(self.suite, self.bad_commit)))
135-
return True
136-
return False
132+
sub = subresult.summarize()
133+
if sub:
134+
return sub
135+
return ("Detected bad commit in {} repository:\n{} {}"
136+
.format(self.repo_name, self.bad_commit, get_message(self.suite, self.bad_commit)))
137+
return ''
137138

138139

139-
def bisect_benchmark(argv):
140+
def _bisect_benchmark(argv, initial_branch, email_to):
140141
if 'BISECT_BENCHMARK_CONFIG' in os.environ:
141142
cp = configparser.ConfigParser()
142143
cp.read(os.environ['BISECT_BENCHMARK_CONFIG'])
@@ -183,24 +184,67 @@ def benchmark_callback(suite, commit):
183184
env['MX_ALT_OUTPUT_ROOT'] = 'mxbuild-{}'.format(commit)
184185
retcode = mx.run(shlex.split(args.build_command), env=env, nonZeroIsFatal=False)
185186
if retcode:
186-
sys.exit("Failed to execute the build command for {}".format(commit))
187+
raise RuntimeError("Failed to execute the build command for {}".format(commit))
187188
output = mx.OutputCapture()
188-
retcode = mx.run(shlex.split(args.benchmark_command), env=env, out=mx.TeeOutputCapture(output), nonZeroIsFatal=False)
189+
retcode = mx.run(shlex.split(args.benchmark_command), env=env, out=mx.TeeOutputCapture(output),
190+
nonZeroIsFatal=False)
189191
if retcode:
190-
sys.exit("Failed to execute benchmark for {}".format(commit))
192+
raise RuntimeError("Failed to execute benchmark for {}".format(commit))
191193
match = re.search(r'{}.*duration: ([\d.]+)'.format(re.escape(args.benchmark_criterion)), output.data)
192194
if not match:
193-
sys.exit("Failed to get result from the benchmark")
195+
raise RuntimeError("Failed to get result from the benchmark")
194196
return float(match.group(1))
195197

196198
bad = get_commit(primary_suite, args.bad)
197199
good = get_commit(primary_suite, args.good)
198200
result = run_bisect_benchmark(primary_suite, bad, good, benchmark_callback)
201+
visualization = result.visualize()
202+
summary = result.summarize()
203+
199204
print()
200-
result.visualize()
201-
print()
202-
result.summarize()
205+
print(visualization)
203206
print()
207+
print(summary)
204208

205209
if 'CI' not in os.environ:
206-
print("You can rerun a benchmark for a particular commit using:\nMX_ALT_OUTPUT_ROOT=mxbuild-$commit {}".format(args.benchmark_command))
210+
print("You can rerun a benchmark for a particular commit using:\nMX_ALT_OUTPUT_ROOT=mxbuild-$commit {}".format(
211+
args.benchmark_command))
212+
213+
send_email(
214+
initial_branch,
215+
email_to,
216+
"Bisection job has finished successfully.\n{}\n".format(summary)
217+
+ "Note I'm just a script and I don't validate statistical significance of the above result.\n"
218+
+ "Please take a moment to also inspect the detailed results below.\n\n{}\n\n".format(visualization)
219+
+ os.environ.get('BUILD_URL', 'Unknown URL')
220+
)
221+
222+
223+
def bisect_benchmark(argv):
224+
suite = mx.primary_suite()
225+
initial_branch = suite.vc.git_command(suite.vc_dir, ['rev-parse', '--abbrev-ref', 'HEAD']).strip()
226+
email_to = suite.vc.git_command(suite.vc_dir, ['log', '--format=%cE', '-n', '1']).strip()
227+
try:
228+
_bisect_benchmark(argv, initial_branch, email_to)
229+
except Exception:
230+
send_email(initial_branch, email_to, "Job failed.\n {}".format(os.environ.get('BUILD_URL', 'Unknown URL')))
231+
raise
232+
233+
234+
def send_email(initial_branch, email_to, content):
235+
if 'BISECT_EMAIL_SMTP_SERVER' in os.environ:
236+
import smtplib
237+
from email.message import EmailMessage
238+
239+
msg = EmailMessage()
240+
msg['Subject'] = "Bisection result for {}".format(initial_branch)
241+
msg['From'] = os.environ['BISECT_EMAIL_FROM']
242+
validate_to = os.environ['BISECT_EMAIL_TO_PATTERN']
243+
if not re.match(validate_to, email_to):
244+
sys.exit("Email {} not allowed, aborting sending".format(email_to))
245+
msg['To'] = email_to
246+
msg.set_content(content)
247+
print(msg)
248+
smtp = smtplib.SMTP(os.environ['BISECT_EMAIL_SMTP_SERVER'])
249+
smtp.send_message(msg)
250+
smtp.quit()

0 commit comments

Comments
 (0)