@@ -281,7 +281,7 @@ def run_one(p: Plugin, workflow: str, timings: dict) -> bool:
281281 ctestfiles = len (p .testfiles )
282282 )
283283 )
284- print ("::group::{p.name}" .format (p = p ))
284+ print ("::group::{p.name}" .format (p = p ), flush = True )
285285
286286 start_env = time .perf_counter ()
287287 try :
@@ -325,30 +325,74 @@ def run_one(p: Plugin, workflow: str, timings: dict) -> bool:
325325 timings [p .name ]["tests" ] = time .perf_counter () - start_tests
326326 return False
327327 finally :
328- print ("::endgroup::" )
328+ print ("::endgroup::" , flush = True )
329+
330+
331+ def run_one_reckless (p : Plugin , workflow : str , timings : dict ) -> bool :
332+ print ("Running reckless with plugin {p.name}" .format (p = p ))
333+
334+ print ("::group::{p.name}-reckless" .format (p = p ), flush = True )
335+
336+ reckles_testing = os .environ ["GITHUB_WORKSPACE" ] + "/.ci/reckless"
337+
338+ if workflow == "nightly" :
339+ cln_path = os .environ ["CLN_PATH" ]
340+ subprocess .check_call (["uv" , "add" , "--dev" , "--editable" , cln_path + "/contrib/pyln-testing" , cln_path + "/contrib/pyln-client" , cln_path + "/contrib/pyln-proto" ], cwd = reckles_testing )
341+ else :
342+ pyln_version = re .sub (r'\.0(\d+)' , r'.\1' , workflow )
343+ subprocess .check_call (["uv" , "add" , "--dev" , f"pyln-testing=={ pyln_version } " , f"pyln-client=={ pyln_version } " , f"pyln-proto=={ pyln_version } " ], cwd = reckles_testing )
344+
345+ cmd = [
346+ "uv" ,
347+ "run" ,
348+ "pytest" ,
349+ "-vvv" ,
350+ "--timeout=600" ,
351+ "--timeout-method=thread" ,
352+ "--color=yes" ,
353+ "test_reckless.py" ,
354+ "--plugin" ,
355+ p .name
356+ ]
357+
358+ start_tests = time .perf_counter ()
359+ try :
360+ subprocess .check_call (
361+ cmd ,
362+ stderr = subprocess .STDOUT ,
363+ cwd = reckles_testing ,
364+ )
365+ timings [p .name ]["reckless" ] = time .perf_counter () - start_tests
366+ return True
367+ except Exception as e :
368+ logging .warning (f"Error while executing: { e } " )
369+ timings [p .name ]["reckless" ] = time .perf_counter () - start_tests
370+ return False
371+ finally :
372+ print ("::endgroup::" , flush = True )
329373
330374
331375# gather data
332- def collect_gather_data (results : list , success : bool ) -> dict :
376+ def collect_gather_data (results : list , success : bool , need_testfiles : bool = True ) -> dict :
333377 gather_data = {}
334378 for t in results :
335379 p = t [0 ]
336- if p .testfiles :
380+ if p .testfiles or not need_testfiles :
337381 if success or t [1 ]:
338382 gather_data [p .name ] = "passed"
339383 else :
340384 gather_data [p .name ] = "failed"
341385 return gather_data
342386
343387
344- def push_gather_data (data : dict , workflow : str , python_version : str ):
345- print ("Pushing gather data..." )
388+ def push_gather_data (data : dict , workflow : str , python_version : str , suffix : str = "" ):
389+ print ("Pushing" + ( f" { suffix } " if suffix else " " ) + " gather data..." )
346390 configure_git ()
347391 subprocess .run (["git" , "fetch" ])
348392 subprocess .run (["git" , "checkout" , "badges" ])
349393 filenames_to_add = []
350394 for plugin_name , result in data .items ():
351- filename = write_gather_data_file (plugin_name , result , workflow , python_version )
395+ filename = write_gather_data_file (plugin_name , result , workflow , python_version , suffix )
352396 filenames_to_add .append (filename )
353397 output = subprocess .check_output (
354398 list (chain (["git" , "add" , "-v" ], filenames_to_add ))
@@ -360,7 +404,7 @@ def push_gather_data(data: dict, workflow: str, python_version: str):
360404 "git" ,
361405 "commit" ,
362406 "-m" ,
363- f "Update test result for Python{ python_version } to ({ workflow } workflow)" ,
407+ "Update" + ( f" { suffix } " if suffix else " " ) + f" test result for Python{ python_version } to ({ workflow } workflow)" ,
364408 ]
365409 ).decode ("utf-8" )
366410 print (f"output from git commit: { output } " )
@@ -382,9 +426,9 @@ def push_gather_data(data: dict, workflow: str, python_version: str):
382426
383427
384428def write_gather_data_file (
385- plugin_name : str , result , workflow : str , python_version : str
429+ plugin_name : str , result , workflow : str , python_version : str , suffix : str = ""
386430) -> str :
387- _dir = f ".badges/gather_data/{ workflow } /{ plugin_name } "
431+ _dir = ".badges" + ( f"_ { suffix } " if suffix else "" ) + f" /gather_data/{ workflow } /{ plugin_name } "
388432 filename = os .path .join (_dir , f"python{ python_version } .txt" )
389433 os .makedirs (_dir , exist_ok = True )
390434 with open (filename , "w" ) as file :
@@ -394,16 +438,14 @@ def write_gather_data_file(
394438 return filename
395439
396440
397- def gather_old_failures (old_failures : list , workflow : str ):
398- print ("Gather old failures..." )
441+ def gather_old_failures (old_failures : list , workflow : str , suffix : str = "" ):
442+ print ("Gather old" + ( f" { suffix } " if suffix else " " ) + " failures..." )
399443 configure_git ()
400- # restore the pyproject.toml and uv.lock changes from adding the
401- # CLN specific pyln versions so we can switch branches
402- subprocess .run (["git" , "reset" , "--hard" ], check = True )
444+
403445 subprocess .run (["git" , "fetch" , "origin" , "badges" ], check = True )
404446 subprocess .run (["git" , "checkout" , "badges" ], check = True )
405447
406- directory = ".badges"
448+ directory = ".badges" + ( f"_ { suffix } " if suffix else "" )
407449
408450 for filename in os .listdir (directory ):
409451 if filename .endswith (f"_{ workflow } .json" ):
@@ -445,33 +487,55 @@ def run_all(
445487 results = [(p , run_one (p , workflow , timings )) for p in plugins ]
446488 success = all ([t [1 ] for t in results ])
447489
490+ results_reckless = [(p , run_one_reckless (p , workflow , timings )) for p in plugins ]
491+ success_reckless = all ([t [1 ] for t in results_reckless ])
492+
493+ # restore the pyproject.toml and uv.lock changes from adding the
494+ # CLN specific pyln versions so we can switch branches
495+ subprocess .run (["git" , "reset" , "--hard" ], check = True )
496+
448497 print ("Timings:" )
449498 for plugin , phases in timings .items ():
450499 env = phases .get ("env" )
451500 tests = phases .get ("tests" )
501+ reckless = phases .get ("reckless" )
452502
453503 env_str = f"{ env :9.2f} s" if env is not None else " (not run)"
454504 tests_str = f"{ tests :9.2f} s" if tests is not None else " (not run)"
505+ reckless_str = f"{ reckless :9.2f} s" if reckless is not None else " (not run)"
455506
456- print (f"{ plugin :<35} env:{ env_str } tests:{ tests_str } " )
507+ print (f"{ plugin :<35} env:{ env_str } tests:{ tests_str } reckless: { reckless_str } " )
457508
458509 old_failures = []
459510 if not success and plugin_names == []:
460511 gather_old_failures (old_failures , workflow )
461512
513+ old_failures_reckless = []
514+ if not success_reckless and plugin_names == []:
515+ gather_old_failures (old_failures_reckless , workflow , "reckless" )
516+
462517 if update_badges :
463518 push_gather_data (
464519 collect_gather_data (results , success ), workflow , python_version
465520 )
521+ push_gather_data (
522+ collect_gather_data (results_reckless , success_reckless , False ), workflow , python_version , "reckless"
523+ )
466524
467- if not success :
525+ if not success or not success_reckless :
468526 print ("The following tests failed:" )
469527 has_new_failure = False
470528 for t in filter (lambda t : not t [1 ], results ):
471529 if t [0 ].name not in old_failures :
472530 has_new_failure = True
473531 print (" - {p.name} ({p.path})" .format (p = t [0 ]))
474- if has_new_failure :
532+ print ("The following reckless tests failed:" )
533+ has_new_failure_reckless = False
534+ for t in filter (lambda t : not t [1 ], results_reckless ):
535+ if t [0 ].name not in old_failures_reckless :
536+ has_new_failure_reckless = True
537+ print (" - {p.name}-reckless ({p.path})" .format (p = t [0 ]))
538+ if has_new_failure or has_new_failure_reckless :
475539 sys .exit (1 )
476540 else :
477541 print ("All tests passed." )
0 commit comments