Skip to content

Commit

Permalink
CI:use dev dependencies for nightly
Browse files Browse the repository at this point in the history
  • Loading branch information
daywalker90 authored and chrisguida committed Jul 2, 2024
1 parent 1671b92 commit 9081f78
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 58 deletions.
117 changes: 66 additions & 51 deletions .ci/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,18 @@
pip_opts = ['-qq']


def prepare_env(p: Plugin, directory: Path) -> bool:
def prepare_env(p: Plugin, directory: Path, env: dict, workflow: str) -> bool:
""" Returns whether we can run at all. Raises error if preparing failed.
"""
subprocess.check_call(['python3', '-m', 'venv', '--clear', directory])
os.environ['PATH'] += f":{directory}"

if p.framework == "pip":
return prepare_env_pip(p, directory)
return prepare_env_pip(p, directory, workflow)
elif p.framework == "poetry":
return prepare_env_poetry(p, directory)
elif p.framework == "generic":
return prepare_generic(p, directory)
return prepare_generic(p, directory, env, workflow)
else:
raise ValueError(f"Unknown framework {p.framework}")

Expand All @@ -47,7 +47,7 @@ def prepare_env_poetry(p: Plugin, directory: Path) -> bool:
subprocess.check_call(['which', 'python3'])

subprocess.check_call([
pip3, 'install', '-U', *pip_opts, 'pip', 'wheel', 'poetry==1.7.1'
pip3, 'install', '-U', *pip_opts, 'pip', 'wheel', 'poetry'
], cwd=p.path.parent)

# Install pytest (eventually we'd want plugin authors to include
Expand All @@ -63,59 +63,56 @@ def prepare_env_poetry(p: Plugin, directory: Path) -> bool:

logging.info(f"Using poetry at {poetry} ({python3}) to run tests in {workdir}")

# Don't let poetry create a self-managed virtualenv (paths get confusing)
# Now we can proceed with the actual implementation
logging.info(f"Exporting poetry {poetry} dependencies from {p.details['pyproject']}")
subprocess.check_call([
poetry, 'config', 'virtualenvs.create', 'false'
poetry, 'export', '--with=dev', '--without-hashes', '-f', 'requirements.txt',
'--output', 'requirements.txt'
], cwd=workdir)

# Now we can proceed with the actual implementation
logging.info(f"Installing poetry {poetry} dependencies from {p.details['pyproject']}")
subprocess.check_call([
poetry, 'install', '--with=dev', '--no-interaction',
], cwd=workdir)
pip3, 'install', *pip_opts, '-r', str(workdir) + "/requirements.txt",
], stderr=subprocess.STDOUT)

subprocess.check_call([pip3, 'freeze'])
return True


def prepare_env_pip(p: Plugin, directory: Path):
def prepare_env_pip(p: Plugin, directory: Path, workflow: str) -> bool:
print("Installing a new pip virtualenv")
pip_path = directory / 'bin' / 'pip3'

# Install pytest (eventually we'd want plugin authors to include
# it in their requirements-dev.txt, but for now let's help them a
# bit).
subprocess.check_call(
[pip_path, 'install', *pip_opts, *global_dependencies],
stderr=subprocess.STDOUT,
)
if workflow == "nightly":
install_dev_pyln_testing(pip_path)
else:
install_pyln_testing(pip_path)

# Now install all the requirements
print(f"Installing requirements from {p.details['requirements']}")
subprocess.check_call(
[pip_path, 'install', '-U', *pip_opts, '-r', p.details['requirements']],
[pip_path, 'install', *pip_opts, '-r', p.details['requirements']],
stderr=subprocess.STDOUT,
)

if p.details['devrequirements'].exists():
print(f"Installing requirements from {p.details['devrequirements']}")
subprocess.check_call(
[pip_path, 'install', '-U', *pip_opts, '-r', p.details['devrequirements']],
[pip_path, 'install', *pip_opts, '-r', p.details['devrequirements']],
stderr=subprocess.STDOUT,
)
install_pyln_testing(pip_path)

subprocess.check_call([pip_path, 'freeze'])
return True


def prepare_generic(p: Plugin, directory: Path):
def prepare_generic(p: Plugin, directory: Path, env: dict, workflow: str) -> bool:
print("Installing a new generic virtualenv")
pip_path = directory / 'bin' / 'pip3'

# Install pytest (eventually we'd want plugin authors to include
# it in their requirements-dev.txt, but for now let's help them a
# bit).
subprocess.check_call(
[pip_path, 'install', *pip_opts, *global_dependencies],
stderr=subprocess.STDOUT,
)
if workflow == "nightly":
install_dev_pyln_testing(pip_path)
else:
install_pyln_testing(pip_path)

# Now install all the requirements
if p.details['requirements'].exists():
Expand All @@ -129,24 +126,34 @@ def prepare_generic(p: Plugin, directory: Path):
print(f"Running setup script from {p.details['setup']}")
subprocess.check_call(
['bash', p.details['setup'], f'TEST_DIR={directory}'],
env=env,
stderr=subprocess.STDOUT,
)
install_pyln_testing(pip_path)

subprocess.check_call([pip_path, 'freeze'])
return True


def install_pyln_testing(pip_path):
# Many plugins only implicitly depend on pyln-testing, so let's help them
cln_path = os.environ['CLN_PATH']
pip_opts = ['-qq']

# Install pytest (eventually we'd want plugin authors to include
# it in their requirements-dev.txt, but for now let's help them a
# bit).
subprocess.check_call(
[pip_path, 'install', *pip_opts, *global_dependencies],
stderr=subprocess.STDOUT,
)

subprocess.check_call(
[pip_path, 'install', '-U', *pip_opts, 'pip', 'wheel'],
stderr=subprocess.STDOUT,
)

subprocess.check_call(
[
pip_path, 'install', '-U', *pip_opts,
pip_path, 'install', *pip_opts,
cln_path + "/contrib/pyln-client",
cln_path + "/contrib/pyln-testing",
"MarkupSafe>=2.0",
Expand All @@ -156,36 +163,31 @@ def install_pyln_testing(pip_path):
)


def run_one(p: Plugin) -> bool:
def install_dev_pyln_testing(pip_path):
# Many plugins only implicitly depend on pyln-testing, so let's help them
cln_path = os.environ['CLN_PATH']

subprocess.check_call([
pip_path, 'install', *pip_opts, '-r', cln_path + "/requirements.txt",
], stderr=subprocess.STDOUT)


def run_one(p: Plugin, workflow: str) -> bool:
print("Running tests on plugin {p.name}".format(p=p))

if not p.testfiles:
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(p.testfiles)))
print("##[group]{p.name}".format(p=p))
print("::group::{p.name}".format(p=p))

# Create a virtual env
vdir = tempfile.TemporaryDirectory()
vpath = Path(vdir.name)

if not prepare_env(p, vpath):
# Skipping is counted as a success
return True

bin_path = vpath / 'bin'
pytest_path = vpath / 'bin' / 'pytest'
poetry_path = vpath / 'bin' / 'poetry'

pytest = [str(pytest_path)]
if p.framework == "poetry":
pytest = [poetry_path, 'run', 'pytest']

if p.framework == "poetry":
subprocess.check_call([poetry_path, 'env', 'info'])
else:
logging.info(f"Virtualenv at {vpath}")

env = os.environ.copy()
env.update({
Expand All @@ -195,7 +197,20 @@ def run_one(p: Plugin) -> bool:
'LC_ALL': 'C.UTF-8',
'LANG': 'C.UTF-8',
})
cmd = [str(p) for p in pytest] + [

try:
if not prepare_env(p, vpath, env, workflow):
# Skipping is counted as a success
return True
except Exception as e:
print(f"Error creating test environment: {e}")
print("::endgroup::")
return False

logging.info(f"Virtualenv at {vpath}")

cmd = [
str(pytest_path),
'-vvv',
'--timeout=600',
'--timeout-method=thread',
Expand All @@ -216,7 +231,7 @@ def run_one(p: Plugin) -> bool:
logging.warning(f"Error while executing: {e}")
return False
finally:
print("##[endgroup]")
print("::endgroup::")


# gather data
Expand Down Expand Up @@ -320,7 +335,7 @@ def run_all(workflow: str, python_version: str, update_badges: bool, plugin_name
else:
print("Testing all plugins in {root}".format(root=root))

results = [(p, run_one(p)) for p in plugins]
results = [(p, run_one(p, workflow)) for p in plugins]
success = all([t[1] for t in results])

old_failures = []
Expand Down
15 changes: 8 additions & 7 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ name: Nightly Integration Tests (master)
on:
schedule:
- cron: "21 2 * * *"
workflow_dispatch:

jobs:
nightly-build-and-test:
Expand All @@ -22,6 +23,11 @@ jobs:
with:
submodules: recursive

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Download Bitcoin & install binaries
run: |
export BITCOIND_VERSION=${{ matrix.bitcoind-version }}
Expand Down Expand Up @@ -66,21 +72,16 @@ jobs:
pytest-custom-exit-code==0.3.0 \
pytest-json-report
poetry install
poetry install --with=dev
poetry update
poetry export --without-hashes -f requirements.txt --output requirements.txt
poetry export --with=dev --without-hashes -f requirements.txt --output requirements.txt
pip install --user -U -r requirements.txt
pip install --user contrib/pyln-client contrib/pyln-testing flaky
./configure --disable-valgrind
make -j 16
sudo make install
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Test with pytest
run: |
export EXPERIMENTAL_FEATURES=${{ matrix.experimental }}
Expand Down

0 comments on commit 9081f78

Please sign in to comment.