Skip to content

Pipeline version consistency check #3643

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Jul 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions nf_core/pipelines/lint/version_consistency.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import os
from pathlib import Path

from ruamel.yaml import YAML


def version_consistency(self):
Expand All @@ -7,14 +10,15 @@ def version_consistency(self):
.. note:: This test only runs when the ``--release`` flag is set for ``nf-core pipelines lint``,
or ``$GITHUB_REF`` is equal to ``main``.

This lint fetches the pipeline version number from three possible locations:
This lint fetches the pipeline version number from four possible locations:

* The pipeline config, ``manifest.version``
* The docker container in the pipeline config, ``process.container``

Some pipelines may not have this set on a pipeline level. If it is not found, it is ignored.

* ``$GITHUB_REF``, if it looks like a release tag (``refs/tags/<something>``)
* The YAML file .nf-core.yml

The test then checks that:

Expand Down Expand Up @@ -45,6 +49,12 @@ def version_consistency(self):
):
versions["GITHUB_REF"] = os.path.basename(os.environ["GITHUB_REF"].strip(" '\""))

# Get version from the .nf-core.yml template
yaml = YAML()
nfcore_yml = yaml.load(Path(self.wf_path) / ".nf-core.yml")
if nfcore_yml["template"] and "version" in nfcore_yml["template"]:
versions["nfcore_yml.version"] = nfcore_yml["template"]["version"].strip(" '\"")

# Check if they are all numeric
for v_type, version in versions.items():
if not version.replace(".", "").isdigit():
Expand All @@ -57,7 +67,7 @@ def version_consistency(self):
", ".join([f"{k} = {v}" for k, v in versions.items()])
)
)

passed.append("Version tags are numeric and consistent between container, release tag and config.")
else:
passed.append("Version tags are consistent: {}".format(", ".join([f"{k} = {v}" for k, v in versions.items()])))

return {"passed": passed, "failed": failed}
75 changes: 69 additions & 6 deletions tests/pipelines/lint/test_version_consistency.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,82 @@
import re
from pathlib import Path

from ruamel.yaml import YAML

import nf_core.pipelines.create.create
import nf_core.pipelines.lint
from nf_core.utils import NFCoreYamlConfig

from ..test_lint import TestLint


class TestLintVersionConsistency(TestLint):
def test_version_consistency(self):
"""Tests that config variable existence test fails with bad pipeline name"""
new_pipeline = self._make_pipeline_copy()
lint_obj = nf_core.pipelines.lint.PipelineLint(new_pipeline)
def setUp(self) -> None:
super().setUp()
self.new_pipeline = self._make_pipeline_copy()
self.nf_core_yml_path = Path(self.new_pipeline) / ".nf-core.yml"
self.yaml = YAML()
self.nf_core_yml: NFCoreYamlConfig = self.yaml.load(self.nf_core_yml_path)

def test_version_consistency_pass(self):
"""Tests that pipeline version consistency test passes with good pipeline version"""
# Declare the pipeline version in the .nf-core.yml file
self.nf_core_yml["template"]["version"] = "1.0.0"
self.yaml.dump(self.nf_core_yml, self.nf_core_yml_path)

# Set the version in the nextflow.config file
nf_conf_file = Path(self.new_pipeline, "nextflow.config")
with open(nf_conf_file) as f:
content = f.read()
pass_content = re.sub(r"(?m)^(?P<indent>\s*version\s*=\s*)'[^']+'", rf"\g<indent>'{'1.0.0'}'", content)
with open(nf_conf_file, "w") as f:
f.write(pass_content)

lint_obj = nf_core.pipelines.lint.PipelineLint(self.new_pipeline)
lint_obj.load_pipeline_config()
lint_obj.nextflow_config()
# Set the version for the container
lint_obj.nf_config["process.container"] = "nfcore/pipeline:1.0.0"
result = lint_obj.version_consistency()
assert result["passed"] == [
"Version tags are consistent: manifest.version = 1.0.0, process.container = 1.0.0, nfcore_yml.version = 1.0.0",
]
assert result["failed"] == []

def test_version_consistency_not_numeric(self):
"""Tests that pipeline version consistency test fails with non-numeric version numbers"""
self.nf_core_yml["template"]["version"] = "1.0.0dev"
self.yaml.dump(self.nf_core_yml, self.nf_core_yml_path)

lint_obj = nf_core.pipelines.lint.PipelineLint(self.new_pipeline)
lint_obj.load_pipeline_config()
lint_obj.nextflow_config()
result = lint_obj.version_consistency()
assert result["passed"] == [
"Version tags are numeric and consistent between container, release tag and config."
"Version tags are consistent: manifest.version = 1.0.0dev, nfcore_yml.version = 1.0.0dev"
]
assert result["failed"] == [
"manifest.version was not numeric: 1.0.0dev!",
"nfcore_yml.version was not numeric: 1.0.0dev!",
]

def test_version_consistency_not_consistent(self):
"""Tests that pipeline version consistency test fails with inconsistent version numbers"""
self.nf_core_yml["template"]["version"] = "0.0.0"
self.yaml.dump(self.nf_core_yml, self.nf_core_yml_path)
nf_conf_file = Path(self.new_pipeline, "nextflow.config")
with open(nf_conf_file) as f:
content = f.read()
fail_content = re.sub(r"(?m)^(?P<indent>\s*version\s*=\s*)'[^']+'", rf"\g<indent>'{'1.0.0'}'", content)
with open(nf_conf_file, "w") as f:
f.write(fail_content)
lint_obj = nf_core.pipelines.lint.PipelineLint(self.new_pipeline)
lint_obj.load_pipeline_config()
lint_obj.nextflow_config()

lint_obj.nf_config["process.container"] = "nfcore/pipeline:0.1"
result = lint_obj.version_consistency()
assert len(result["passed"]) == 0
assert result["failed"] == [
"The versioning is not consistent between container, release tag and config. Found manifest.version = 1.0.0, process.container = 0.1, nfcore_yml.version = 0.0.0",
]
assert result["failed"] == ["manifest.version was not numeric: 1.0.0dev!"]