Skip to content

Commit a57bc1e

Browse files
MagicRBMic92
authored andcommitted
Use custom buildbot mq events for combined build reports
Signed-off-by: magic_rb <[email protected]>
1 parent 4233701 commit a57bc1e

File tree

2 files changed

+161
-79
lines changed

2 files changed

+161
-79
lines changed

buildbot_nix/__init__.py

Lines changed: 67 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
from datetime import UTC, datetime
1111
from pathlib import Path
1212
from typing import TYPE_CHECKING, Any
13+
import typing
14+
import copy
1315

1416
from buildbot.config.builder import BuilderConfig
1517
from buildbot.configurators import ConfiguratorBase
@@ -69,11 +71,10 @@ class BuildbotNixError(Exception):
6971
class BuildTrigger(buildstep.ShellMixin, steps.BuildStep):
7072
"""Dynamic trigger that creates a build for every attribute."""
7173

72-
project: GitProject
7374

7475
successful_jobs: list[NixEvalJobSuccess]
7576
failed_jobs: list[NixEvalJobError]
76-
report_status: bool
77+
combined_build: bool
7778
drv_info: dict[str, NixDerivation]
7879
builds_scheduler: str
7980
skipped_builds_scheduler: str
@@ -108,21 +109,19 @@ def __iter__(self) -> Generator[Any, None, None]:
108109

109110
def __init__(
110111
self,
111-
project: GitProject,
112112
builds_scheduler: str,
113113
skipped_builds_scheduler: str,
114114
failed_eval_scheduler: str,
115115
dependency_failed_scheduler: str,
116116
cached_failure_scheduler: str,
117117
successful_jobs: list[NixEvalJobSuccess],
118118
failed_jobs: list[NixEvalJobError],
119-
report_status: bool,
119+
combine_builds: bool,
120120
**kwargs: Any,
121121
) -> None:
122-
self.project = project
123122
self.successful_jobs = successful_jobs
124123
self.failed_jobs = failed_jobs
125-
self.report_status = report_status
124+
self.combine_builds = combine_builds
126125
self.config = None
127126
self.builds_scheduler = builds_scheduler
128127
self.skipped_builds_scheduler = skipped_builds_scheduler
@@ -170,35 +169,33 @@ def set_common_properties(
170169
props: Properties,
171170
source: str,
172171
job: NixEvalJob,
173-
report_status: bool,
174172
) -> Properties:
175173
props.setProperty("virtual_builder_name", f".#checks.{job.attr}", source)
176174
props.setProperty("status_name", f"nix-build .#checks.{job.attr}", source)
177175
props.setProperty("virtual_builder_tags", "", source)
178176
props.setProperty("attr", job.attr, source)
179-
props.setProperty("report_status", report_status, source)
180177

181178
return props
182179

183180
def schedule_eval_failure(
184-
self, job: NixEvalJobError, report_status: bool
181+
self, job: NixEvalJobError
185182
) -> tuple[str, Properties]:
186183
source = "nix-eval-nix"
187184

188185
props = BuildTrigger.set_common_properties(
189-
Properties(), source, job, report_status
186+
Properties(), source, job
190187
)
191188
props.setProperty("error", job.error, source)
192189

193190
return (self.failed_eval_scheduler, props)
194191

195192
def schedule_cached_failure(
196-
self, job: NixEvalJobSuccess, report_status: bool, first_failure: datetime
193+
self, job: NixEvalJobSuccess, first_failure: datetime
197194
) -> tuple[str, Properties]:
198195
source = "nix-eval-nix"
199196

200197
props = BuildTrigger.set_common_properties(
201-
Properties(), source, job, report_status
198+
Properties(), source, job
202199
)
203200
props.setProperty("first_failure", str(first_failure), source)
204201

@@ -208,12 +205,11 @@ def schedule_dependency_failed(
208205
self,
209206
job: NixEvalJobSuccess,
210207
dependency: NixEvalJobSuccess,
211-
report_status: bool,
212208
) -> tuple[str, Properties]:
213209
source = "nix-eval-nix"
214210

215211
props = BuildTrigger.set_common_properties(
216-
Properties(), source, job, report_status
212+
Properties(), source, job
217213
)
218214
props.setProperty("dependency.attr", dependency.attr, source)
219215

@@ -223,7 +219,6 @@ def schedule_success(
223219
self,
224220
build_props: Properties,
225221
job: NixEvalJobSuccess,
226-
report_status: bool,
227222
) -> tuple[str, Properties]:
228223
source = "nix-eval-nix"
229224

@@ -232,7 +227,7 @@ def schedule_success(
232227
out_path = job.outputs["out"] or None
233228

234229
props = BuildTrigger.set_common_properties(
235-
Properties(), source, job, report_status
230+
Properties(), source, job
236231
)
237232
props.setProperty("system", system, source)
238233
props.setProperty("drv_path", drv_path, source)
@@ -355,8 +350,33 @@ def get_failed_dependents(
355350

356351
return removed
357352

353+
@defer.inlineCallbacks
354+
def produceEventForBuilds(
355+
self,
356+
build_ids: list[int],
357+
event: str,
358+
result: None | int,
359+
) -> Generator[Any, object, None]:
360+
for build_id in build_ids:
361+
build = yield self.master.data.get(('builds', str(build_id)))
362+
buildT = typing.cast(dict[str, Any], build)
363+
if result is not None:
364+
buildT["results"] = result
365+
self.master.mq.produce(("builds", str(build_id), event), copy.deepcopy(buildT))
366+
367+
@defer.inlineCallbacks
368+
def produceEvent(
369+
self,
370+
event: str,
371+
result: None | int,
372+
) -> Generator[Any, object, None]:
373+
yield self.produceEventForBuilds([self.build.buildid], event, result)
374+
358375
@defer.inlineCallbacks
359376
def run(self) -> Generator[Any, Any, None]:
377+
if self.combine_builds:
378+
self.produceEvent("started-nix-build", None)
379+
360380
self.running = True
361381
build_props = self.build.getProperties()
362382
ss_for_trigger = self.prepare_sourcestamp_list_for_trigger()
@@ -370,7 +390,7 @@ def run(self) -> Generator[Any, Any, None]:
370390
scheduler_log.addStdout(f"\t- {failed_job.attr} failed eval\n")
371391
brids, _ = yield self.schedule(
372392
ss_for_trigger,
373-
*self.schedule_eval_failure(failed_job, self.report_status),
393+
*self.schedule_eval_failure(failed_job),
374394
)
375395
self.brids.extend(brids)
376396

@@ -411,12 +431,14 @@ def run(self) -> Generator[Any, Any, None]:
411431
brids, results_deferred = yield self.schedule(
412432
ss_for_trigger,
413433
*self.schedule_cached_failure(
414-
build, self.report_status, failed_build.time
434+
build, failed_build.time
415435
),
416436
)
417437
scheduled.append(
418438
BuildTrigger.ScheduledJob(build, brids, results_deferred)
419439
)
440+
if not self.combine_builds:
441+
self.produceEventForBuilds(brids.values(), "started-nix-build", None)
420442
self.brids.extend(brids.values())
421443
elif failed_build is not None and self.build.reason == "rebuild":
422444
failed_builds.remove_build(build.drvPath)
@@ -438,13 +460,15 @@ def run(self) -> Generator[Any, Any, None]:
438460
scheduler_log.addStdout(f"\t- {job.attr}\n")
439461
brids, results_deferred = yield self.schedule(
440462
ss_for_trigger,
441-
*self.schedule_success(build_props, job, self.report_status),
463+
*self.schedule_success(build_props, job),
442464
)
443465

444466
scheduled.append(
445467
BuildTrigger.ScheduledJob(job, brids, results_deferred)
446468
)
447469

470+
if not self.combine_builds:
471+
self.produceEventForBuilds(brids.values(), "started-nix-build", None)
448472
self.brids.extend(brids.values())
449473

450474
scheduler_log.addStdout("Waiting...\n")
@@ -467,6 +491,8 @@ def run(self) -> Generator[Any, Any, None]:
467491
scheduler_log.addStdout(
468492
f"Found finished build {job.attr}, result {util.Results[result].upper()}\n"
469493
)
494+
if not self.combine_builds:
495+
self.produceEventForBuilds(brids.values(), "finished-nix-build", result)
470496

471497
# if it failed, remove all dependent jobs, schedule placeholders and add them to the list of scheduled jobs
472498
if result != SUCCESS:
@@ -477,7 +503,7 @@ def run(self) -> Generator[Any, Any, None]:
477503
)
478504
for removed_job in removed:
479505
scheduler, props = self.schedule_dependency_failed(
480-
removed_job, job, self.report_status
506+
removed_job, job
481507
)
482508
brids, results_deferred = yield self.schedule(
483509
ss_for_trigger, scheduler, props
@@ -486,6 +512,8 @@ def run(self) -> Generator[Any, Any, None]:
486512
scheduled.append(
487513
BuildTrigger.ScheduledJob(removed_job, brids, results_deferred)
488514
)
515+
if not self.combine_builds:
516+
self.produceEventForBuilds(brids.values(), "started-nix-build", None)
489517
self.brids.extend(brids.values())
490518
scheduler_log.addStdout(
491519
"\t- removed jobs: "
@@ -501,7 +529,8 @@ def run(self) -> Generator[Any, Any, None]:
501529
for dep in job_closures:
502530
if job.drvPath in job_closures[dep]:
503531
job_closures[dep].remove(job.drvPath)
504-
532+
if self.combine_builds:
533+
self.produceEvent("finished-nix-build", overall_result)
505534
scheduler_log.addStdout("Done!\n")
506535
return overall_result
507536

@@ -517,15 +546,6 @@ def getCurrentSummary(self) -> dict[str, str]: # noqa: N802
517546
return {"step": f"({', '.join(summary)})"}
518547

519548

520-
class NixBuildCombined(steps.BuildStep):
521-
"""Shows the error message of a failed evaluation."""
522-
523-
name = "nix-build-combined"
524-
525-
def run(self) -> Generator[Any, object, Any]:
526-
return self.build.results
527-
528-
529549
class NixEvalCommand(buildstep.ShellMixin, steps.BuildStep):
530550
"""Parses the output of `nix-eval-jobs` and triggers a `nix-build` build for
531551
every attribute.
@@ -548,14 +568,28 @@ def __init__(
548568
self.supported_systems = supported_systems
549569
self.job_report_limit = job_report_limit
550570

571+
@defer.inlineCallbacks
572+
def produceEvent(
573+
self,
574+
event: str,
575+
result: None | int
576+
) -> Generator[Any, object, None]:
577+
build = yield self.master.data.get(('builds', str(self.build.buildid)))
578+
buildT = typing.cast(dict[str, Any], build)
579+
if result is not None:
580+
buildT["results"] = result
581+
self.master.mq.produce(("builds", str(self.build.buildid), event), copy.deepcopy(buildT))
582+
551583
@defer.inlineCallbacks
552584
def run(self) -> Generator[Any, object, Any]:
585+
self.produceEvent("started-nix-eval", None)
553586
# run nix-eval-jobs --flake .#checks to generate the dict of stages
554587
cmd: remotecommand.RemoteCommand = yield self.makeRemoteShellCommand()
555588
yield self.runCommand(cmd)
556589

557590
# if the command passes extract the list of stages
558591
result = cmd.results()
592+
self.produceEvent("finished-nix-eval", result)
559593
if result == util.SUCCESS:
560594
# create a ShellCommand for each stage and add them to the build
561595
jobs: list[NixEvalJob] = []
@@ -586,7 +620,6 @@ def run(self) -> Generator[Any, object, Any]:
586620
self.build.addStepsAfterCurrentStep(
587621
[
588622
BuildTrigger(
589-
self.project,
590623
builds_scheduler=f"{self.project.project_id}-nix-build",
591624
skipped_builds_scheduler=f"{self.project.project_id}-nix-skipped-build",
592625
failed_eval_scheduler=f"{self.project.project_id}-nix-failed-eval",
@@ -595,30 +628,12 @@ def run(self) -> Generator[Any, object, Any]:
595628
name="build flake",
596629
successful_jobs=successful_jobs,
597630
failed_jobs=failed_jobs,
598-
report_status=(
599-
self.job_report_limit is None
600-
or self.number_of_jobs <= self.job_report_limit
631+
combine_builds=(
632+
self.job_report_limit is not None
633+
and self.number_of_jobs > self.job_report_limit
601634
),
602635
),
603636
]
604-
+ (
605-
[
606-
Trigger(
607-
waitForFinish=True,
608-
schedulerNames=[
609-
f"{self.project.project_id}-nix-build-combined"
610-
],
611-
haltOnFailure=True,
612-
flunkOnFailure=True,
613-
sourceStamps=[],
614-
alwaysUseLatest=False,
615-
updateSourceStamp=False,
616-
),
617-
]
618-
if self.job_report_limit is not None
619-
and self.number_of_jobs > self.job_report_limit
620-
else []
621-
),
622637
)
623638

624639
return result
@@ -1091,24 +1106,6 @@ def nix_register_gcroot_config(
10911106
)
10921107

10931108

1094-
def nix_build_combined_config(
1095-
project: GitProject,
1096-
worker_names: list[str],
1097-
) -> BuilderConfig:
1098-
factory = util.BuildFactory()
1099-
factory.addStep(NixBuildCombined())
1100-
1101-
return util.BuilderConfig(
1102-
name=f"{project.name}/nix-build-combined",
1103-
project=project.name,
1104-
workernames=worker_names,
1105-
collapseRequests=False,
1106-
env={},
1107-
factory=factory,
1108-
properties=dict(status_name="nix-build-combined"),
1109-
)
1110-
1111-
11121109
def config_for_project(
11131110
config: dict[str, Any],
11141111
project: GitProject,
@@ -1176,11 +1173,6 @@ def config_for_project(
11761173
name=f"{project.project_id}-nix-cached-failure",
11771174
builderNames=[f"{project.name}/nix-cached-failure"],
11781175
),
1179-
# this is triggered from `nix-eval` when the build contains too many outputs
1180-
schedulers.Triggerable(
1181-
name=f"{project.project_id}-nix-build-combined",
1182-
builderNames=[f"{project.name}/nix-build-combined"],
1183-
),
11841176
schedulers.Triggerable(
11851177
name=f"{project.project_id}-nix-register-gcroot",
11861178
builderNames=[f"{project.name}/nix-register-gcroot"],
@@ -1224,7 +1216,6 @@ def config_for_project(
12241216
nix_dependency_failed_config(project, [SKIPPED_BUILDER_NAME]),
12251217
nix_cached_failure_config(project, [SKIPPED_BUILDER_NAME]),
12261218
nix_register_gcroot_config(project, worker_names),
1227-
nix_build_combined_config(project, worker_names),
12281219
],
12291220
)
12301221

0 commit comments

Comments
 (0)