-
Notifications
You must be signed in to change notification settings - Fork 129
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5ea35a4
commit e3b4546
Showing
5 changed files
with
348 additions
and
70 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,15 @@ | ||
from pathlib import Path | ||
import subprocess | ||
from pprint import pprint | ||
from collections import namedtuple | ||
from typing import Generator | ||
|
||
import json | ||
import logging | ||
import os | ||
import shlex | ||
import shutil | ||
import subprocess | ||
import sys | ||
import tempfile | ||
import shlex | ||
import os | ||
from collections import namedtuple | ||
from pathlib import Path, PosixPath | ||
from typing import Generator, List | ||
from itertools import chain | ||
|
||
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) | ||
|
||
|
@@ -18,8 +18,8 @@ | |
'.ci', | ||
'.git', | ||
'.github', | ||
'archived', | ||
'lightning', | ||
'feeadjuster' | ||
] | ||
|
||
global_dependencies = [ | ||
|
@@ -42,6 +42,10 @@ | |
) | ||
|
||
|
||
def list_plugins(plugins): | ||
return ", ".join([p.name for p in sorted(plugins)]) | ||
|
||
|
||
def enumerate_plugins(basedir: Path) -> Generator[Plugin, None, None]: | ||
plugins = list([ | ||
x for x in basedir.iterdir() \ | ||
|
@@ -50,13 +54,17 @@ def enumerate_plugins(basedir: Path) -> Generator[Plugin, None, None]: | |
pip_pytest = [ | ||
x for x in plugins if (x / Path('requirements.txt')).exists() | ||
] | ||
print(f"Pip plugins: {list_plugins(pip_pytest)}") | ||
|
||
poetry_pytest = [ | ||
x for x in plugins if (x / Path("pyproject.toml")).exists() | ||
] | ||
print(poetry_pytest) | ||
print(f"Poetry plugins: {list_plugins(poetry_pytest)}") | ||
|
||
other_plugins = [x for x in plugins if x not in pip_pytest and x not in poetry_pytest] | ||
other_plugins = [ | ||
x for x in plugins if x not in pip_pytest and x not in poetry_pytest | ||
] | ||
print(f"Other plugins: {list_plugins(other_plugins)}") | ||
|
||
for p in sorted(pip_pytest): | ||
yield Plugin( | ||
|
@@ -227,20 +235,24 @@ def install_pyln_testing(pip_path): | |
stderr=subprocess.STDOUT, | ||
) | ||
|
||
def run_one(p: Plugin) -> bool: | ||
print("Running tests on plugin {p.name}".format(p=p)) | ||
|
||
testfiles = [ | ||
def get_testfiles(p: Plugin) -> List[PosixPath]: | ||
return [ | ||
x for x in p.path.iterdir() | ||
if (x.is_dir() and x.name == 'tests') | ||
or (x.name.startswith("test_") and x.name.endswith('.py')) | ||
] | ||
|
||
if len(testfiles) == 0: | ||
def has_testfiles(p: Plugin) -> bool: | ||
return len(get_testfiles(p)) > 0 | ||
|
||
def run_one(p: Plugin) -> bool: | ||
print("Running tests on plugin {p.name}".format(p=p)) | ||
|
||
if not has_testfiles(p): | ||
print("No test files found, skipping plugin {p.name}".format(p=p)) | ||
return True | ||
|
||
print("Found {ctestfiles} test files, creating virtualenv and running tests".format(ctestfiles=len(testfiles))) | ||
print("Found {ctestfiles} test files, creating virtualenv and running tests".format(ctestfiles=len(get_testfiles(p)))) | ||
print("##[group]{p.name}".format(p=p)) | ||
|
||
# Create a virtual env | ||
|
@@ -295,8 +307,65 @@ def run_one(p: Plugin) -> bool: | |
finally: | ||
print("##[endgroup]") | ||
|
||
|
||
def run_all(args): | ||
def configure_git(): | ||
# Git requires some user and email to be configured in order to work in the context of GitHub Actions. | ||
subprocess.run( | ||
["git", "config", "--global", "user.email", '"[email protected]"'] | ||
) | ||
subprocess.run(["git", "config", "--global", "user.name", '"lightningd"']) | ||
|
||
|
||
# gather data | ||
def collect_gather_data(results, success): | ||
gather_data = {} | ||
for t in results: | ||
p = t[0] | ||
if has_testfiles(p): | ||
if success or t[1]: | ||
gather_data[p.name] = "passed" | ||
else: | ||
gather_data[p.name] = "failed" | ||
return gather_data | ||
|
||
|
||
def push_gather_data(data, workflow, python_version): | ||
print("Pushing gather data...") | ||
configure_git() | ||
subprocess.run(["git", "fetch"]) | ||
subprocess.run(["git", "checkout", "badges"]) | ||
filenames_to_add = [] | ||
for plugin_name, result in data.items(): | ||
filenames_to_add.append(git_add_gather_data( | ||
plugin_name, result, workflow, python_version | ||
)) | ||
output = subprocess.check_output(list(chain(["git", "add", "-v"], filenames_to_add))).decode("utf-8") | ||
print(f"output from git add: {output}") | ||
if output != "": | ||
output = subprocess.check_output( | ||
[ | ||
"git", | ||
"commit", | ||
"-m", | ||
f"Update test result for Python{python_version} to ({workflow} workflow)", | ||
] | ||
).decode("utf-8") | ||
print(f"output from git commit: {output}") | ||
subprocess.run(["git", "push", "origin", "badges"]) | ||
print("Done.") | ||
|
||
|
||
def git_add_gather_data(plugin_name, result, workflow, python_version): | ||
_dir = f".badges/gather_data/{workflow}/{plugin_name}" | ||
filename = os.path.join(_dir, f"python{python_version}.txt") | ||
os.makedirs(_dir, exist_ok=True) | ||
with open(filename, "w") as file: | ||
print(f"Writing {filename}") | ||
file.write(result) | ||
|
||
return filename | ||
|
||
|
||
def run_all(workflow, python_version, update_badges, plugin_names): | ||
root_path = subprocess.check_output([ | ||
'git', | ||
'rev-parse', | ||
|
@@ -306,20 +375,35 @@ def run_all(args): | |
root = Path(root_path) | ||
|
||
plugins = list(enumerate_plugins(root)) | ||
if args != []: | ||
plugins = [p for p in plugins if p.name in args] | ||
if plugin_names != []: | ||
plugins = [p for p in plugins if p.name in plugin_names] | ||
print("Testing the following plugins: {names}".format(names=[p.name for p in plugins])) | ||
else: | ||
print("Testing all plugins in {root}".format(root=root)) | ||
|
||
results = [(p, run_one(p)) for p in plugins] | ||
success = all([t[1] for t in results]) | ||
|
||
if update_badges: | ||
push_gather_data(collect_gather_data(results, success), workflow, python_version) | ||
|
||
if not success: | ||
print("The following tests failed:") | ||
for t in filter(lambda t: not t[1], results): | ||
print(" - {p.name} ({p.path})".format(p=t[0])) | ||
sys.exit(1) | ||
else: | ||
print("All tests passed.") | ||
|
||
|
||
if __name__ == "__main__": | ||
run_all(sys.argv[1:]) | ||
import argparse | ||
|
||
parser = argparse.ArgumentParser(description='Plugins test script') | ||
parser.add_argument("workflow", type=str, help="Name of the GitHub workflow") | ||
parser.add_argument("python_version", type=str, help="Python version") | ||
parser.add_argument("--update-badges", action='store_true', help="Whether badges data should be updated") | ||
parser.add_argument("plugins", nargs="*", default=[], help="List of plugins") | ||
args = parser.parse_args() | ||
|
||
run_all(args.workflow, args.python_version, args.update_badges, args.plugins) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
import json | ||
import os | ||
import subprocess | ||
from collections import namedtuple | ||
from pathlib import Path, PosixPath | ||
from typing import Generator, List | ||
|
||
Plugin = namedtuple( | ||
"Plugin", | ||
[ | ||
"name", | ||
"path", | ||
"language", | ||
"framework", | ||
"details", | ||
], | ||
) | ||
|
||
exclude = [ | ||
".ci", | ||
".git", | ||
".github", | ||
"archived", | ||
"lightning", | ||
] | ||
|
||
|
||
def configure_git(): | ||
# Git needs some user and email to be configured in order to work in the context of GitHub Actions. | ||
subprocess.run( | ||
["git", "config", "--global", "user.email", '"[email protected]"'] | ||
) | ||
subprocess.run(["git", "config", "--global", "user.name", '"lightningd"']) | ||
|
||
|
||
def get_testfiles(p: Plugin) -> List[PosixPath]: | ||
return [ | ||
x | ||
for x in p.path.iterdir() | ||
if (x.is_dir() and x.name == "tests") | ||
or (x.name.startswith("test_") and x.name.endswith(".py")) | ||
] | ||
|
||
|
||
def has_testfiles(p: Plugin) -> bool: | ||
return len(get_testfiles(p)) > 0 | ||
|
||
|
||
def list_plugins(plugins): | ||
return ", ".join([p.name for p in sorted(plugins)]) | ||
|
||
|
||
def enumerate_plugins(basedir: Path) -> Generator[Plugin, None, None]: | ||
plugins = list( | ||
[x for x in basedir.iterdir() if x.is_dir() and x.name not in exclude] | ||
) | ||
pip_pytest = [x for x in plugins if (x / Path("requirements.txt")).exists()] | ||
print(f"Pip plugins: {list_plugins(pip_pytest)}") | ||
|
||
poetry_pytest = [x for x in plugins if (x / Path("pyproject.toml")).exists()] | ||
print(f"Poetry plugins: {list_plugins(poetry_pytest)}") | ||
|
||
other_plugins = [ | ||
x for x in plugins if x not in pip_pytest and x not in poetry_pytest | ||
] | ||
print(f"Other plugins: {list_plugins(other_plugins)}") | ||
|
||
for p in sorted(pip_pytest): | ||
yield Plugin( | ||
name=p.name, | ||
path=p, | ||
language="python", | ||
framework="pip", | ||
details={ | ||
"requirements": p / Path("requirements.txt"), | ||
"devrequirements": p / Path("requirements-dev.txt"), | ||
}, | ||
) | ||
|
||
for p in sorted(poetry_pytest): | ||
yield Plugin( | ||
name=p.name, | ||
path=p, | ||
language="python", | ||
framework="poetry", | ||
details={ | ||
"pyproject": p / Path("pyproject.toml"), | ||
}, | ||
) | ||
|
||
for p in sorted(other_plugins): | ||
yield Plugin( | ||
name=p.name, | ||
path=p, | ||
language="other", | ||
framework="generic", | ||
details={ | ||
"requirements": p / Path("tests/requirements.txt"), | ||
"setup": p / Path("tests/setup.sh"), | ||
}, | ||
) | ||
|
||
|
||
def update_and_commit_badge(plugin_name, passed, workflow): | ||
json_data = { "schemaVersion": 1, "label": "", "message": " ✔ ", "color": "green" } | ||
if not passed: | ||
json_data.update({"message": "✗", "color": "red"}) | ||
|
||
filename = os.path.join(".badges", f"{plugin_name}_{workflow}.json") | ||
with open(filename, "w") as file: | ||
file.write(json.dumps(json_data)) | ||
|
||
output = subprocess.check_output(["git", "add", "-v", filename]).decode("utf-8") | ||
if output != "": | ||
subprocess.run(["git", "commit", "-m", f'Update {plugin_name} badge to {"passed" if passed else "failed"} ({workflow})']) | ||
return True | ||
return False | ||
|
||
|
||
def push_badges_data(workflow, num_of_python_versions): | ||
print("Pushing badges data...") | ||
configure_git() | ||
subprocess.run(["git", "fetch"]) | ||
subprocess.run(["git", "checkout", "badges"]) | ||
subprocess.run(["git", "pull"]) | ||
|
||
root_path = ( | ||
subprocess.check_output(["git", "rev-parse", "--show-toplevel"]) | ||
.decode("ASCII") | ||
.strip() | ||
) | ||
plugins = list(enumerate_plugins(Path(root_path))) | ||
|
||
any_changes = False | ||
for plugin in plugins: | ||
results = [] | ||
_dir = f".badges/gather_data/main/{plugin.name}" | ||
if os.path.exists(_dir): | ||
for child in Path(_dir).iterdir(): | ||
result = child.read_text().strip() | ||
results.append(result) | ||
print(f"Results for {child}: {result}") | ||
|
||
passed = False | ||
if ( | ||
len(set(results)) == 1 | ||
and results[0] == "passed" | ||
# and len(results) == num_of_python_versions # TODO: Disabled as gather data for python versions is missing sporadingly. | ||
): | ||
passed = True | ||
any_changes |= update_and_commit_badge(plugin.name, passed, workflow) | ||
|
||
if any_changes: | ||
subprocess.run(["git", "push", "origin", "badges"]) | ||
print("Done.") | ||
|
||
|
||
if __name__ == "__main__": | ||
import argparse | ||
|
||
parser = argparse.ArgumentParser(description="Plugins completion script") | ||
parser.add_argument("workflow", type=str, help="Name of the GitHub workflow") | ||
parser.add_argument( | ||
"num_of_python_versions", type=str, help="Number of Python versions" | ||
) | ||
args = parser.parse_args() | ||
|
||
push_badges_data(args.workflow, int(args.num_of_python_versions)) |
Oops, something went wrong.