Skip to content

Commit c4ae6fe

Browse files
github updates from cli/builder/runner. unified update messaging from github<->cli (#253)
* checking pending builds with cli * WIP on PR githubupdate builder/runner * benchmark runner is now properly pushing updates to github PR on every test progress * Added PR comment about build start. * try/catch on metric exporting and redis shutdown on coordinator. fixed memtier_benchmark-1Mkeys-string-get-2MB test given it required 2tb of memory * Including test upper and lower limit on stream (per benchmark suite) and on runner (default) * Updated PR comment on benchmark start * Ensuring git hash on PR comment is string * Adding regression comment in case of PR run of coordinator * benchmark coordinator is accepting benchmark group filters
1 parent b442d8d commit c4ae6fe

File tree

15 files changed

+1504
-841
lines changed

15 files changed

+1504
-841
lines changed

poetry.lock

Lines changed: 35 additions & 208 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "redis-benchmarks-specification"
3-
version = "0.1.75"
3+
version = "0.1.205"
44
description = "The Redis benchmarks specification describes the cross-language/tools requirements and expectations to foster performance and observability standards around redis related technologies. Members from both industry and academia, including organizations and individuals are encouraged to contribute."
55
authors = ["filipecosta90 <[email protected]>","Redis Performance Group <[email protected]>"]
66
readme = "Readme.md"
@@ -14,7 +14,7 @@ marshmallow = "^3.12.2"
1414
argparse = "^1.4.0"
1515
Flask-HTTPAuth = "^4.4.0"
1616
PyYAML = "^6.0"
17-
docker = "^5.0.0"
17+
docker = "^7.1.0"
1818
redisbench-admin = "^0.9.23"
1919
psutil = "^5.9.4"
2020
PyGithub = "^1.55"
@@ -29,8 +29,7 @@ pytest = "^7.2.0"
2929
pytest-cov = "^4.0.0"
3030
black = "22.10.0"
3131
flake8 = "^6.0.0"
32-
tox-poetry-installer = {extras = ["poetry"], version = "^0.10.2"}
33-
tox-docker = {extras = ["poetry"], version = "^3.1.0"}
32+
tox-poetry-installer = {extras = ["poetry"], version = "^0.10.3"}
3433

3534
[build-system]
3635
requires = ["poetry_core>=1.0.0"]

redis_benchmarks_specification/__api__/app.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,13 @@ def base():
8686
event_type = "Ignored event from webhook"
8787
use_event = False
8888
# Pull request labeled
89+
pull_request_number = None
8990
trigger_label = PULL_REQUEST_TRIGGER_LABEL
9091
if "pull_request" in request_data:
9192
action = request_data["action"]
9293
if should_action(action):
9394
pull_request_dict = request_data["pull_request"]
95+
9496
head_dict = pull_request_dict["head"]
9597
repo_dict = head_dict["repo"]
9698
labels = []
@@ -107,9 +109,8 @@ def base():
107109
label_name = label["name"]
108110
if trigger_label == label_name:
109111
use_event = True
110-
event_type = "Pull request labeled with '{}'".format(
111-
trigger_label
112-
)
112+
pull_request_number = request_data["number"]
113+
event_type = f"Pull request #{pull_request_number} labeled with '{trigger_label}'"
113114
detected_label = True
114115
if detected_label is False:
115116
app.logger.info(
@@ -161,6 +162,8 @@ def base():
161162
"gh_repo": gh_repo,
162163
"gh_org": gh_org,
163164
}
165+
if pull_request_number is not None:
166+
fields_after["pull_request"] = pull_request_number
164167
app.logger.info(
165168
"Using event {} to trigger benchmark. final fields: {}".format(
166169
event_type, fields_after
@@ -174,7 +177,6 @@ def base():
174177
event_type, response_data
175178
)
176179
)
177-
178180
else:
179181
app.logger.info(
180182
"{}. input json was: {}".format(event_type, request_data)

redis_benchmarks_specification/__builder__/builder.py

Lines changed: 167 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import argparse
2+
import datetime
23
import io
34
import json
45
import logging
@@ -31,11 +32,20 @@
3132
REDIS_SOCKET_TIMEOUT,
3233
REDIS_BINS_EXPIRE_SECS,
3334
)
35+
from redis_benchmarks_specification.__common__.github import (
36+
check_github_available_and_actionable,
37+
generate_build_finished_pr_comment,
38+
update_comment_if_needed,
39+
create_new_pr_comment,
40+
generate_build_started_pr_comment,
41+
)
3442
from redis_benchmarks_specification.__common__.package import (
3543
populate_with_poetry_data,
3644
get_version_string,
3745
)
3846

47+
PERFORMANCE_GH_TOKEN = os.getenv("PERFORMANCE_GH_TOKEN", None)
48+
3949

4050
class ZipFileWithPermissions(ZipFile):
4151
def _extract_member(self, member, targetpath, pwd):
@@ -80,6 +90,8 @@ def main():
8090
action="store_true",
8191
help="Store the docker images in redis keys.",
8292
)
93+
parser.add_argument("--github_token", type=str, default=PERFORMANCE_GH_TOKEN)
94+
parser.add_argument("--pull-request", type=str, default=None, nargs="?", const="")
8395
args = parser.parse_args()
8496
if args.logname is not None:
8597
print("Writting log to {}".format(args.logname))
@@ -138,16 +150,18 @@ def main():
138150
build_spec_image_prefetch(builders_folder, different_build_specs)
139151

140152
builder_consumer_group_create(conn)
141-
153+
if args.github_token is not None:
154+
logging.info("detected a github token. will update as much as possible!!! =)")
142155
previous_id = args.consumer_start_id
143156
while True:
144-
previous_id, new_builds_count = builder_process_stream(
157+
previous_id, new_builds_count, _ = builder_process_stream(
145158
builders_folder,
146159
conn,
147160
different_build_specs,
148161
previous_id,
149162
args.docker_air_gap,
150163
arch,
164+
args.github_token,
151165
)
152166

153167

@@ -172,15 +186,29 @@ def builder_consumer_group_create(conn, id="$"):
172186
)
173187

174188

189+
def check_benchmark_build_comment(comments):
190+
res = False
191+
pos = -1
192+
for n, comment in enumerate(comments):
193+
body = comment.body
194+
if "CE Performance Automation : step 1 of 2" in body:
195+
res = True
196+
pos = n
197+
return res, pos
198+
199+
175200
def builder_process_stream(
176201
builders_folder,
177202
conn,
178203
different_build_specs,
179204
previous_id,
180205
docker_air_gap=False,
181206
arch="amd64",
207+
github_token=None,
182208
):
183209
new_builds_count = 0
210+
auto_approve_github_comments = True
211+
build_stream_fields_arr = []
184212
logging.info("Entering blocking read waiting for work.")
185213
consumer_name = "{}-proc#{}".format(STREAM_GH_EVENTS_COMMIT_BUILDERS_CG, "1")
186214
newTestInfo = conn.xreadgroup(
@@ -215,12 +243,58 @@ def builder_process_stream(
215243
buffer = conn.get(binary_zip_key)
216244
git_timestamp_ms = None
217245
use_git_timestamp = False
246+
commit_datetime = "n/a"
247+
if b"commit_datetime" in testDetails:
248+
commit_datetime = testDetails[b"commit_datetime"].decode()
249+
commit_summary = "n/a"
250+
if b"commit_summary" in testDetails:
251+
commit_summary = testDetails[b"commit_summary"].decode()
218252
git_branch, git_version = get_branch_version_from_test_details(testDetails)
219253
if b"use_git_timestamp" in testDetails:
220254
use_git_timestamp = bool(testDetails[b"use_git_timestamp"])
221255
if b"git_timestamp_ms" in testDetails:
222256
git_timestamp_ms = int(testDetails[b"git_timestamp_ms"].decode())
257+
tests_regexp = ".*"
258+
if b"tests_regexp" in testDetails:
259+
tests_regexp = testDetails[b"tests_regexp"].decode()
260+
tests_priority_upper_limit = 10000
261+
if b"tests_priority_upper_limit" in testDetails:
262+
tests_priority_upper_limit = int(
263+
testDetails[b"tests_priority_upper_limit"].decode()
264+
)
265+
tests_priority_lower_limit = 0
266+
if b"tests_priority_lower_limit" in testDetails:
267+
tests_priority_lower_limit = int(
268+
testDetails[b"tests_priority_lower_limit"].decode()
269+
)
270+
tests_groups_regexp = ".*"
271+
if b"tests_groups_regexp" in testDetails:
272+
tests_groups_regexp = testDetails[b"tests_groups_regexp"].decode()
273+
274+
# github updates
275+
is_actionable_pr = False
276+
contains_regression_comment = False
277+
github_pr = None
278+
old_regression_comment_body = ""
279+
pr_link = ""
280+
regression_comment = ""
281+
pull_request = None
282+
if b"pull_request" in testDetails:
283+
pull_request = testDetails[b"pull_request"].decode()
284+
logging.info(f"Detected PR info in builder. PR: {pull_request}")
285+
verbose = True
223286

287+
fn = check_benchmark_build_comment
288+
(
289+
contains_regression_comment,
290+
github_pr,
291+
is_actionable_pr,
292+
old_regression_comment_body,
293+
pr_link,
294+
regression_comment,
295+
) = check_github_available_and_actionable(
296+
fn, github_token, pull_request, "redis", "redis", verbose
297+
)
224298
for build_spec in different_build_specs:
225299
build_config, id = get_build_config(builders_folder + "/" + build_spec)
226300
build_config_metadata = get_build_config_metadata(build_config)
@@ -306,9 +380,41 @@ def builder_process_stream(
306380
"redis-server",
307381
build_vars_str,
308382
)
383+
build_start_datetime = datetime.datetime.utcnow()
309384
logging.info(
310-
"Using the following build command {}".format(build_command)
385+
"Using the following build command {}.".format(build_command)
311386
)
387+
if is_actionable_pr:
388+
logging.info(
389+
f"updating on github we'll start the build at {build_start_datetime}"
390+
)
391+
comment_body = generate_build_started_pr_comment(
392+
build_start_datetime,
393+
commit_datetime,
394+
commit_summary,
395+
git_branch,
396+
git_hash,
397+
tests_groups_regexp,
398+
tests_priority_lower_limit,
399+
tests_priority_upper_limit,
400+
tests_regexp,
401+
)
402+
if contains_regression_comment:
403+
update_comment_if_needed(
404+
auto_approve_github_comments,
405+
comment_body,
406+
old_regression_comment_body,
407+
regression_comment,
408+
verbose,
409+
)
410+
else:
411+
regression_comment = create_new_pr_comment(
412+
auto_approve_github_comments,
413+
comment_body,
414+
github_pr,
415+
pr_link,
416+
)
417+
312418
docker_client.containers.run(
313419
image=build_image,
314420
volumes={
@@ -319,6 +425,10 @@ def builder_process_stream(
319425
working_dir="/mnt/redis/",
320426
command=build_command,
321427
)
428+
build_end_datetime = datetime.datetime.utcnow()
429+
build_duration = build_end_datetime - build_start_datetime
430+
build_duration_secs = build_duration.total_seconds()
431+
322432
build_stream_fields = {
323433
"id": id,
324434
"git_hash": git_hash,
@@ -333,7 +443,13 @@ def builder_process_stream(
333443
"build_command": build_command,
334444
"metadata": json.dumps(build_config_metadata),
335445
"build_artifacts": ",".join(build_artifacts),
446+
"tests_regexp": tests_regexp,
447+
"tests_priority_upper_limit": tests_priority_upper_limit,
448+
"tests_priority_lower_limit": tests_priority_lower_limit,
449+
"tests_groups_regexp": tests_groups_regexp,
336450
}
451+
if pull_request is not None:
452+
build_stream_fields["pull_request"] = pull_request
337453
if git_branch is not None:
338454
build_stream_fields["git_branch"] = git_branch
339455
if git_version is not None:
@@ -356,16 +472,61 @@ def builder_process_stream(
356472
if b"platform" in testDetails:
357473
build_stream_fields["platform"] = testDetails[b"platform"]
358474
if result is True:
359-
stream_id = conn.xadd(
475+
benchmark_stream_id = conn.xadd(
360476
STREAM_KEYNAME_NEW_BUILD_EVENTS, build_stream_fields
361477
)
362478
logging.info(
363479
"sucessfully built build variant {} for redis git_sha {}. Stream id: {}".format(
364-
id, git_hash, stream_id
480+
id, git_hash, benchmark_stream_id
365481
)
366482
)
483+
streamId_decoded = streamId.decode()
484+
benchmark_stream_id_decoded = benchmark_stream_id.decode()
485+
builder_list_completed = (
486+
f"builder:{streamId_decoded}:builds_completed"
487+
)
488+
conn.lpush(builder_list_completed, benchmark_stream_id_decoded)
489+
conn.expire(builder_list_completed, REDIS_BINS_EXPIRE_SECS)
490+
logging.info(
491+
f"Adding information of build->benchmark stream info in list {builder_list_completed}. Adding benchmark stream id: {benchmark_stream_id_decoded}"
492+
)
493+
benchmark_stream_ids = [benchmark_stream_id_decoded]
494+
495+
if is_actionable_pr:
496+
logging.info(
497+
f"updating on github that the build finished after {build_duration_secs} seconds"
498+
)
499+
comment_body = generate_build_finished_pr_comment(
500+
benchmark_stream_ids,
501+
commit_datetime,
502+
commit_summary,
503+
git_branch,
504+
git_hash,
505+
tests_groups_regexp,
506+
tests_priority_lower_limit,
507+
tests_priority_upper_limit,
508+
tests_regexp,
509+
build_start_datetime,
510+
build_duration_secs,
511+
)
512+
if contains_regression_comment:
513+
update_comment_if_needed(
514+
auto_approve_github_comments,
515+
comment_body,
516+
old_regression_comment_body,
517+
regression_comment,
518+
verbose,
519+
)
520+
else:
521+
create_new_pr_comment(
522+
auto_approve_github_comments,
523+
comment_body,
524+
github_pr,
525+
pr_link,
526+
)
367527
shutil.rmtree(temporary_dir, ignore_errors=True)
368528
new_builds_count = new_builds_count + 1
529+
build_stream_fields_arr.append(build_stream_fields)
369530
ack_reply = conn.xack(
370531
STREAM_KEYNAME_GH_EVENTS_COMMIT,
371532
STREAM_GH_EVENTS_COMMIT_BUILDERS_CG,
@@ -387,7 +548,7 @@ def builder_process_stream(
387548
)
388549
else:
389550
logging.error("Missing commit information within received message.")
390-
return previous_id, new_builds_count
551+
return previous_id, new_builds_count, build_stream_fields_arr
391552

392553

393554
def build_spec_image_prefetch(builders_folder, different_build_specs):

0 commit comments

Comments
 (0)