@@ -59,12 +59,14 @@ def __init__(
5959 builds_scheduler : str ,
6060 skipped_builds_scheduler : str ,
6161 jobs : list [dict [str , Any ]],
62+ report_status : bool ,
6263 ** kwargs : Any ,
6364 ) -> None :
6465 if "name" not in kwargs :
6566 kwargs ["name" ] = "trigger"
6667 self .project = project
6768 self .jobs = jobs
69+ self .report_status = report_status
6870 self .config = None
6971 self .builds_scheduler = builds_scheduler
7072 self .skipped_builds_scheduler = skipped_builds_scheduler
@@ -102,6 +104,7 @@ def getSchedulersAndProperties(self) -> list[tuple[str, Properties]]: # noqa: N
102104 props .setProperty ("virtual_builder_name" , name , source )
103105 props .setProperty ("status_name" , f"nix-build .#checks.{ attr } " , source )
104106 props .setProperty ("virtual_builder_tags" , "" , source )
107+ props .setProperty ("report_status" , self .report_status , source )
105108
106109 drv_path = job .get ("drvPath" )
107110 system = job .get ("system" )
@@ -145,6 +148,15 @@ def getCurrentSummary(self) -> dict[str, str]: # noqa: N802
145148 return {"step" : f"({ ', ' .join (summary )} )" }
146149
147150
151+ class NixBuildCombined (steps .BuildStep ):
152+ """Shows the error message of a failed evaluation."""
153+
154+ name = "nix-build-combined"
155+
156+ def run (self ) -> Generator [Any , object , Any ]:
157+ return self .build .results
158+
159+
148160class NixEvalCommand (buildstep .ShellMixin , steps .BuildStep ):
149161 """Parses the output of `nix-eval-jobs` and triggers a `nix-build` build for
150162 every attribute.
@@ -153,14 +165,19 @@ class NixEvalCommand(buildstep.ShellMixin, steps.BuildStep):
153165 project : GitProject
154166
155167 def __init__ (
156- self , project : GitProject , supported_systems : list [str ], ** kwargs : Any
168+ self ,
169+ project : GitProject ,
170+ supported_systems : list [str ],
171+ job_report_limit : int | None ,
172+ ** kwargs : Any ,
157173 ) -> None :
158174 kwargs = self .setupShellMixin (kwargs )
159175 super ().__init__ (** kwargs )
160176 self .project = project
161177 self .observer = logobserver .BufferLogObserver ()
162178 self .addLogObserver ("stdio" , self .observer )
163179 self .supported_systems = supported_systems
180+ self .job_report_limit = job_report_limit
164181
165182 @defer .inlineCallbacks
166183 def run (self ) -> Generator [Any , object , Any ]:
@@ -190,6 +207,8 @@ def run(self) -> Generator[Any, object, Any]:
190207 if not system or system in self .supported_systems : # report eval errors
191208 filtered_jobs .append (job )
192209
210+ self .number_of_jobs = len (filtered_jobs )
211+
193212 self .build .addStepsAfterCurrentStep (
194213 [
195214 BuildTrigger (
@@ -198,8 +217,28 @@ def run(self) -> Generator[Any, object, Any]:
198217 skipped_builds_scheduler = f"{ project_id } -nix-skipped-build" ,
199218 name = "build flake" ,
200219 jobs = filtered_jobs ,
220+ report_status = (
221+ self .job_report_limit is None
222+ or self .number_of_jobs <= self .job_report_limit
223+ ),
201224 ),
202- ],
225+ ]
226+ + (
227+ [
228+ Trigger (
229+ waitForFinish = True ,
230+ schedulerNames = [f"{ project_id } -nix-build-combined" ],
231+ haltOnFailure = True ,
232+ flunkOnFailure = True ,
233+ sourceStamps = [],
234+ alwaysUseLatest = False ,
235+ updateSourceStamp = False ,
236+ ),
237+ ]
238+ if self .job_report_limit is not None
239+ and self .number_of_jobs > self .job_report_limit
240+ else []
241+ ),
203242 )
204243
205244 return result
@@ -360,6 +399,7 @@ def nix_eval_config(
360399 eval_lock : MasterLock ,
361400 worker_count : int ,
362401 max_memory_size : int ,
402+ job_report_limit : int | None ,
363403) -> BuilderConfig :
364404 """Uses nix-eval-jobs to evaluate hydraJobs from flake.nix in parallel.
365405 For each evaluated attribute a new build pipeline is started.
@@ -385,6 +425,7 @@ def nix_eval_config(
385425 env = {},
386426 name = "evaluate flake" ,
387427 supported_systems = supported_systems ,
428+ job_report_limit = job_report_limit ,
388429 command = [
389430 "nix-eval-jobs" ,
390431 "--workers" ,
@@ -492,6 +533,7 @@ def nix_build_config(
492533 updateSourceStamp = False ,
493534 doStepIf = do_register_gcroot_if ,
494535 copy_properties = ["out_path" , "attr" ],
536+ set_properties = {"report_status" : False },
495537 ),
496538 )
497539 factory .addStep (
@@ -556,6 +598,7 @@ def nix_skipped_build_config(
556598 updateSourceStamp = False ,
557599 doStepIf = do_register_gcroot_if ,
558600 copy_properties = ["out_path" , "attr" ],
601+ set_properties = {"report_status" : False },
559602 ),
560603 )
561604 return util .BuilderConfig (
@@ -601,6 +644,24 @@ def nix_register_gcroot_config(
601644 )
602645
603646
647+ def nix_build_combined_config (
648+ project : GitProject ,
649+ worker_names : list [str ],
650+ ) -> BuilderConfig :
651+ factory = util .BuildFactory ()
652+ factory .addStep (NixBuildCombined ())
653+
654+ return util .BuilderConfig (
655+ name = f"{ project .name } /nix-build-combined" ,
656+ project = project .name ,
657+ workernames = worker_names ,
658+ collapseRequests = False ,
659+ env = {},
660+ factory = factory ,
661+ properties = dict (status_name = "nix-build-combined" ),
662+ )
663+
664+
604665def config_for_project (
605666 config : dict [str , Any ],
606667 project : GitProject ,
@@ -610,6 +671,7 @@ def config_for_project(
610671 nix_eval_max_memory_size : int ,
611672 eval_lock : MasterLock ,
612673 post_build_steps : list [steps .BuildStep ],
674+ job_report_limit : int | None ,
613675 outputs_path : Path | None = None ,
614676 build_retries : int = 1 ,
615677) -> None :
@@ -653,6 +715,11 @@ def config_for_project(
653715 name = f"{ project .project_id } -nix-skipped-build" ,
654716 builderNames = [f"{ project .name } /nix-skipped-build" ],
655717 ),
718+ # this is triggered from `nix-eval` when the build contains too many outputs
719+ schedulers .Triggerable (
720+ name = f"{ project .project_id } -nix-build-combined" ,
721+ builderNames = [f"{ project .name } /nix-build-combined" ],
722+ ),
656723 schedulers .Triggerable (
657724 name = f"{ project .project_id } -nix-register-gcroot" ,
658725 builderNames = [f"{ project .name } /nix-register-gcroot" ],
@@ -680,6 +747,7 @@ def config_for_project(
680747 worker_names ,
681748 git_url = project .get_project_url (),
682749 supported_systems = nix_supported_systems ,
750+ job_report_limit = job_report_limit ,
683751 worker_count = nix_eval_worker_count ,
684752 max_memory_size = nix_eval_max_memory_size ,
685753 eval_lock = eval_lock ,
@@ -693,6 +761,7 @@ def config_for_project(
693761 ),
694762 nix_skipped_build_config (project , [SKIPPED_BUILDER_NAME ]),
695763 nix_register_gcroot_config (project , worker_names ),
764+ nix_build_combined_config (project , worker_names ),
696765 ],
697766 )
698767
@@ -842,7 +911,7 @@ def configure(self, config: dict[str, Any]) -> None:
842911 backends ["github" ] = GithubBackend (self .config .github , self .config .url )
843912
844913 if self .config .gitea is not None :
845- backends ["gitea" ] = GiteaBackend (self .config .gitea )
914+ backends ["gitea" ] = GiteaBackend (self .config .gitea , self . config . url )
846915
847916 auth : AuthBase | None = (
848917 backends [self .config .auth_backend ].create_auth ()
@@ -895,6 +964,7 @@ def configure(self, config: dict[str, Any]) -> None:
895964 self .config .eval_max_memory_size ,
896965 eval_lock ,
897966 [x .to_buildstep () for x in self .config .post_build_steps ],
967+ self .config .job_report_limit ,
898968 self .config .outputs_path ,
899969 self .config .build_retries ,
900970 )
0 commit comments