diff --git a/nf_core/lint/nextflow_config.py b/nf_core/lint/nextflow_config.py index d22fa944ed..71c908b7b5 100644 --- a/nf_core/lint/nextflow_config.py +++ b/nf_core/lint/nextflow_config.py @@ -108,6 +108,11 @@ def nextflow_config(self): lint: nextflow_config: False + + **The configuration should contain the following or the test will fail:** + + * A ``test`` configuration profile should exist. + """ passed = [] warned = [] @@ -312,4 +317,32 @@ def nextflow_config(self): ) ) + # Check for the availability of the "test" configuration profile by parsing nextflow.config + with open(os.path.join(self.wf_path, "nextflow.config"), "r") as f: + content = f.read() + + # Remove comments + cleaned_content = re.sub(r"//.*", "", content) + cleaned_content = re.sub(r"/\*.*?\*/", "", content, flags=re.DOTALL) + + match = re.search(r"\bprofiles\s*{", cleaned_content) + if not match: + failed.append("nextflow.config does not contain `profiles` scope, but `test` profile is required") + else: + # Extract profiles scope content and check for test profile + start = match.end() + end = start + brace_count = 1 + while brace_count > 0 and end < len(content): + if cleaned_content[end] == "{": + brace_count += 1 + elif cleaned_content[end] == "}": + brace_count -= 1 + end += 1 + profiles_content = cleaned_content[start : end - 1].strip() + if re.search(r"\btest\s*{", profiles_content): + passed.append("nextflow.config contains configuration profile `test`") + else: + failed.append("nextflow.config does not contain configuration profile `test`") + return {"passed": passed, "warned": warned, "failed": failed, "ignored": ignored} diff --git a/tests/lint/nextflow_config.py b/tests/lint/nextflow_config.py index f53765dce9..1542b8cf65 100644 --- a/tests/lint/nextflow_config.py +++ b/tests/lint/nextflow_config.py @@ -1,3 +1,6 @@ +import os +import re + import nf_core.create import nf_core.lint @@ -33,3 +36,20 @@ def test_nextflow_config_dev_in_release_mode_failed(self): result = lint_obj.nextflow_config() assert len(result["failed"]) > 0 assert len(result["warned"]) == 0 + + +def test_nextflow_config_missing_test_profile_failed(self): + """Test failure if config file does not contain `test` profile.""" + new_pipeline = self._make_pipeline_copy() + # Change the name of the test profile so there is no such profile + nf_conf_file = os.path.join(new_pipeline, "nextflow.config") + with open(nf_conf_file, "r") as f: + content = f.read() + fail_content = re.sub(r"\btest\b", "testfail", content) + with open(nf_conf_file, "w") as f: + f.write(fail_content) + lint_obj = nf_core.lint.PipelineLint(new_pipeline) + lint_obj._load_pipeline_config() + result = lint_obj.nextflow_config() + assert len(result["failed"]) > 0 + assert len(result["warned"]) == 0 diff --git a/tests/test_lint.py b/tests/test_lint.py index e4e93bd1f4..67104e3ad0 100644 --- a/tests/test_lint.py +++ b/tests/test_lint.py @@ -213,6 +213,7 @@ def test_sphinx_md_files(self): test_nextflow_config_bad_name_fail, test_nextflow_config_dev_in_release_mode_failed, test_nextflow_config_example_pass, + test_nextflow_config_missing_test_profile_failed, ) from .lint.version_consistency import test_version_consistency