Skip to content

Commit d0a4101

Browse files
committed
CI: add reckless install test
1 parent 0a6a917 commit d0a4101

File tree

9 files changed

+1737
-27
lines changed

9 files changed

+1737
-27
lines changed

.ci/reckless/conftest.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import pytest
2+
3+
4+
def pytest_addoption(parser):
5+
parser.addoption("--plugin", action="store", help="plugin name to pass to test")
6+
7+
8+
@pytest.fixture
9+
def plugin_name(request):
10+
return request.config.getoption("--plugin")

.ci/reckless/pyproject.toml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[project]
2+
name = "reckless-testing"
3+
version = "0.1.0"
4+
description = "A little helper for testing reckless installs of plugins"
5+
readme = "README.md"
6+
requires-python = ">=3.9.2"
7+
8+
[dependency-groups]
9+
dev = [
10+
"pytest>=7.4,<9",
11+
"pytest-timeout>=2.4,<3",
12+
"pyln-testing>=24.11.1",
13+
"pyln-client>=24.11.1",
14+
"pyln-proto>=24.11.1",
15+
]

.ci/reckless/test_reckless.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import logging
2+
import os
3+
import pytest
4+
import time
5+
import subprocess
6+
from pathlib import Path
7+
8+
from pyln.testing.fixtures import * # noqa: F403
9+
10+
LOGGER = logging.getLogger(__name__)
11+
12+
13+
def test_plugin_install_raw(node_factory, plugin_name):
14+
LOGGER.info(f"Testing reckless raw with: {plugin_name}")
15+
16+
l1 = node_factory.get_node()
17+
18+
ln_dir = str(Path(l1.info["lightning-dir"]).parent)
19+
20+
subprocess.run(
21+
[
22+
"reckless",
23+
"-v",
24+
"--json",
25+
"-l",
26+
ln_dir,
27+
"--network",
28+
"regtest",
29+
"source",
30+
"remove",
31+
"https://github.com/lightningd/plugins",
32+
],
33+
input="Y\n",
34+
text=True,
35+
capture_output=True,
36+
)
37+
38+
subprocess.check_call(
39+
[
40+
"reckless",
41+
"-v",
42+
"--json",
43+
"-l",
44+
ln_dir,
45+
"--network",
46+
"regtest",
47+
"source",
48+
"add",
49+
f"{os.environ['GITHUB_WORKSPACE']}",
50+
]
51+
)
52+
53+
subprocess.check_call(
54+
[
55+
"reckless",
56+
"-v",
57+
"--json",
58+
"-l",
59+
ln_dir,
60+
"--network",
61+
"regtest",
62+
"install",
63+
plugin_name,
64+
]
65+
)
66+
67+
plugin_list = l1.rpc.call("plugin", ["list"])
68+
69+
for plugin in plugin_list["plugins"]:
70+
if plugin_name in plugin["name"]:
71+
return
72+
pytest.fail(f"Plugin {plugin_name} not installed")
73+
74+
75+
# def test_plugin_install(node_factory, plugin_name):
76+
# LOGGER.info(f"Testing reckless with: {plugin_name}")
77+
78+
# l1 = node_factory.get_node()
79+
80+
# l1.rpc.call(
81+
# "reckless", ["source", "remove", "https://github.com/lightningd/plugins"]
82+
# )
83+
84+
# l1.rpc.call("reckless", ["source", "add", f"{os.environ['GITHUB_WORKSPACE']}"])
85+
86+
# l1.rpc.call("reckless", ["install", plugin_name])
87+
88+
# plugin_list = l1.rpc.call("plugin", ["list"])
89+
90+
# for plugin in plugin_list["plugins"]:
91+
# if plugin_name in plugin["name"]:
92+
# return
93+
# pytest.fail(f"Plugin {plugin_name} not installed")

.ci/reckless/uv.lock

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

.ci/test.py

Lines changed: 83 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -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

384428
def 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.")

.ci/update_badges.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@
88

99

1010
def update_and_commit_badge(
11-
plugin_name: str, passed: bool, workflow: str, has_tests: bool
11+
plugin_name: str, passed: bool, workflow: str, has_tests: bool, suffix: str = ""
1212
) -> bool:
1313
json_data = {"schemaVersion": 1, "label": "", "message": "✔", "color": "green"}
1414
if not passed:
1515
json_data.update({"message": "✗", "color": "red"})
1616
if not has_tests:
1717
json_data.update({"message": "?", "color": "orange"})
1818

19-
filename = os.path.join(".badges", f"{plugin_name}_{workflow}.json")
19+
filename = os.path.join(".badges" + (f"_{suffix}" if suffix else ""), f"{plugin_name}_{workflow}.json")
2020
with open(filename, "w") as file:
2121
file.write(json.dumps(json_data))
2222

@@ -58,8 +58,8 @@ def check_wanted_result(result_file: str, python_versions_tested: list) -> bool:
5858
return False
5959

6060

61-
def push_badges_data(workflow: str, python_versions_tested: list):
62-
print("Pushing badges data...")
61+
def push_badges_data(workflow: str, python_versions_tested: list, suffix: str = ""):
62+
print("Pushing" + (f" {suffix}" if suffix else " ") + "badges data...")
6363
configure_git()
6464

6565
root_path = (
@@ -76,7 +76,7 @@ def push_badges_data(workflow: str, python_versions_tested: list):
7676
any_changes = False
7777
for plugin in plugins:
7878
results = []
79-
_dir = f".badges/gather_data/{workflow}/{plugin.name}"
79+
_dir = ".badges" + (f"_{suffix}" if suffix else "") + f"/gather_data/{workflow}/{plugin.name}"
8080
if os.path.exists(_dir):
8181
for child in Path(_dir).iterdir():
8282
if not check_wanted_result(child.name, python_versions_tested):
@@ -93,9 +93,9 @@ def push_badges_data(workflow: str, python_versions_tested: list):
9393
and len(results) == len(python_versions_tested)
9494
):
9595
passed = True
96-
any_changes |= update_and_commit_badge(plugin.name, passed, workflow, True)
96+
any_changes |= update_and_commit_badge(plugin.name, passed, workflow, True, suffix)
9797
else:
98-
any_changes |= update_and_commit_badge(plugin.name, False, workflow, False)
98+
any_changes |= update_and_commit_badge(plugin.name, False, workflow, False, suffix)
9999

100100
if any_changes:
101101
for _ in range(10):
@@ -130,3 +130,4 @@ def push_badges_data(workflow: str, python_versions_tested: list):
130130
args = parser.parse_args()
131131

132132
push_badges_data(args.workflow, args.python_versions_tested)
133+
push_badges_data(args.workflow, args.python_versions_tested, "reckless")

.github/workflows/main.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ jobs:
123123
with:
124124
path: |
125125
/usr/local/bin/lightning*
126+
/usr/local/bin/reckless
126127
/usr/local/libexec/c-lightning
127128
key: cache-cln-${{ matrix.cln-version }}-${{ steps.exact_versions.outputs.os_version }}
128129

@@ -142,6 +143,7 @@ jobs:
142143
with:
143144
path: |
144145
/usr/local/bin/lightning*
146+
/usr/local/bin/reckless
145147
/usr/local/libexec/c-lightning
146148
key: cache-cln-${{ matrix.cln-version }}-${{ steps.exact_versions.outputs.os_version }}
147149

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ This is a list of plugin managers that can help you install these plugins:
5858
| Name | Short description |
5959
| ------------------------------------ | ------------------------------------------------------------------------------------------- |
6060
| [coffee][coffee] | Reference implementation for a flexible core lightning plugin manager |
61-
| [reckless][reckless] | Comes with CLN. Reckless currently supports python and javascript plugins. |
61+
| [reckless][reckless] | Comes with CLN. Reckless support can be checked here: [Reckless](Reckless.md). |
6262

6363
## Archived plugins
6464

0 commit comments

Comments
 (0)