#!/usr/bin/env python # # run_unit_tests.py - Runs any pyfeeds tests which are present in the project # repository. # # Author: Paul McCarthy # import os.path as op import os import sys import glob from fsl_ci import sprun, add_credentials from fsl_ci.platform import get_platform_shortcut_if_not_applicable from fsl_ci.conda import (load_meta_yaml, get_project_repository_and_revision) def checkout_project_repository_shortcut_if_no_tests(project_dir): """Checks out the project source repository - this is done to get a copy of the project unit tests/data. """ # The FSLCONDA_REPOSITORY/REVISION vars are honoured if set repo, rev = get_project_repository_and_revision('meta.yaml')[:2] if (repo is None) or (rev is None): print('No repository or revision listed in meta.yaml - aborting test.') sys.exit(0) sprun(f'git clone {repo} {project_dir}') sprun(f'git checkout {rev}', cwd=project_dir) # If no feedsRun tests can be found, we abort the job hits = glob.glob(op.join(project_dir, '**', 'feedsRun*'), recursive=True) if len(hits) == 0: print(f'No feedsRun scripts found in project source repository ' f'({repo}:{rev} - aborting test.') sys.exit(0) def create_test_env(env_dir, build_dir): """Create a conda environment to run the tests, and install pyfeeds and the package being tested into it. """ pkgname = load_meta_yaml('meta.yaml')['package']['name'] # The FSLCONDA_INTENRAL variable is set # for internal/private FSL projects, and # determines whether we can install # dependencies from the internal channel internal = 'FSLCONDA_INTERNAL' in os.environ intchannel = os.environ['FSLCONDA_INTERNAL_CHANNEL_URL'] pubchannel = os.environ['FSLCONDA_PUBLIC_CHANNEL_URL'] username = os.environ.get('FSLCONDA_INTERNAL_CHANNEL_USERNAME', None) password = os.environ.get('FSLCONDA_INTERNAL_CHANNEL_PASSWORD', None) if username is not None: intchannel = add_credentials(intchannel, username, password) if internal: pkgchannels = [intchannel, pubchannel] else: pkgchannels = [pubchannel] pkgchannels = [f'-c {c}' for c in pkgchannels] pkgchannels = ' '.join(pkgchannels) # Install from local build dir # Install dependencies of from # Install pyfeeds from sprun(f'conda create -p {env_dir} ' f'-c {build_dir} {pkgchannels} ' '-c conda-forge -c defaults ' f'{pkgname} fsl-base cxx-compiler make fsl-pyfeeds') def run_tests(project_dir, test_output_dir, env_dir): """Runs the project tests using pyfeeds. """ cfg = op.join(project_dir, 'pyfeeds.cfg') if op.exists(cfg): cfg = f'-c {cfg}' else: cfg = '' commands = [] commands.append(f'. activate {env_dir}') commands.append(f'export FSLDIR={env_dir}') commands.append('. $FSLDIR/etc/fslconf/fsl.sh') commands.append(f'pyfeeds run -v -k {cfg} ' f'-o {test_output_dir} ' f'{project_dir}') commands = '; '.join(commands) result = sprun(commands, shell=True, check=False) return result.returncode def main(): recipe_name = os.environ['CI_PROJECT_NAME'] job_name = os.environ['CI_JOB_NAME'] skip_platforms = os.environ.get('FSLCONDA_SKIP_PLATFORM', '') skip_platforms = skip_platforms.split() meta = load_meta_yaml('meta.yaml') # get the platform name, so we know # which build directory to install # the package from (and abort if # this job is not relevant for the # project type) platform = get_platform_shortcut_if_not_applicable( meta, recipe_name, job_name, skip_platforms) build_dir = op.join(os.getcwd(), 'conda_build', f'_{platform}_') # We check out the project source # into a directory named with the # conda package name. Test outputs # are saved to pyfeeds_results project_dir = op.abspath(recipe_name) test_output_dir = op.abspath('pyfeeds_results') env_dir = op.abspath('test_env') checkout_project_repository_shortcut_if_no_tests(project_dir) create_test_env(env_dir, build_dir) return run_tests(project_dir, test_output_dir, env_dir) if __name__ == '__main__': sys.exit(main())