Skip to content
Open
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# nf-core/tools: Changelog

## v4.2.0dev

### General

- Add `nf-core pipelines containers create-configs` to regenerate the pipeline `conf/containers_*.config` files ([#XXXX](https://github.com/nf-core/tools/pull/XXXX))

## [v4.1.0 - Marshalled Mamba](https://github.com/nf-core/tools/releases/tag/4.1.0) - [2026-07-29]

### General
Expand Down
33 changes: 32 additions & 1 deletion nf_core/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ def interface(ctx):
@nf_core_cli.group(aliases=["p", "pipeline"])
@click.command_panel("For users", commands=["download", "create-params-file", "launch", "list"])
@click.command_panel(
"For developers", commands=["bump-version", "create", "create-logo", "lint", "rocrate", "schema", "sync"]
"For developers",
commands=["bump-version", "containers", "create", "create-logo", "lint", "rocrate", "schema", "sync"],
)
@click.pass_context
def pipelines(ctx):
Expand Down Expand Up @@ -209,6 +210,36 @@ def command_pipelines_create(ctx, name, description, author, version, force, out
pipelines_create(ctx, name, description, author, version, force, outdir, template_yaml, organisation)


# nf-core pipelines containers subcommands
@pipelines.group("containers", aliases=["container"])
@click.pass_context
def pipelines_containers(ctx):
"""
Commands to manage pipeline containers.
"""
ctx.ensure_object(dict)


# nf-core pipelines containers create-configs
@pipelines_containers.command("create-configs")
@click.option(
"-d",
"--dir",
"directory",
type=click.Path(exists=True),
default=".",
help=r"Pipeline directory [dim]\[default: current working directory][/]",
)
@click.pass_context
def command_pipelines_containers_create_configs(ctx, directory):
"""
Regenerate the pipeline container config files.
"""
from nf_core.commands_pipelines import pipelines_containers_create_configs

pipelines_containers_create_configs(ctx, directory)


# nf-core pipelines lint
@pipelines.command("lint", aliases=["l"])
@click.option(
Expand Down
23 changes: 23 additions & 0 deletions nf_core/commands_pipelines.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,29 @@ def pipelines_bump_version(ctx, new_version, directory, nextflow):
sys.exit(1)


# nf-core pipelines containers create-configs
def pipelines_containers_create_configs(ctx, directory):
"""
Regenerate the pipeline container config files.

Scans all modules installed in the pipeline and rewrites the
`conf/containers_*.config` files from their `meta.yml` container entries.

Useful after resolving a template sync merge conflict in these files: the
contents are always regenerated from scratch, so whatever they contained
before is discarded.
"""
from nf_core.pipelines.containers_utils import ContainerConfigs
from nf_core.utils import is_pipeline_directory

try:
is_pipeline_directory(directory)
ContainerConfigs(Path(directory)).generate_container_configs()
except UserWarning as e:
log.error(e)
sys.exit(1)


# nf-core pipelines lint
def pipelines_lint(
ctx,
Expand Down
21 changes: 21 additions & 0 deletions tests/pipelines/test_container_configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import shutil

import pytest
import ruamel.yaml

from nf_core.commands_pipelines import pipelines_containers_create_configs
from nf_core.modules.install import ModuleInstall
from nf_core.pipelines.containers_utils import PLATFORMS, ContainerConfigs

Expand Down Expand Up @@ -99,3 +101,22 @@ def test_generate_container_configs_skips_meta_without_containers(self) -> None:
cfg_path = conf_dir / f"containers_{p_name}.config"
if cfg_path.exists():
assert "FAKE" not in cfg_path.read_text(), f"{cfg_path.name} contains entry for FAKE module"


class TestPipelinesContainersCommand(TestPipelines):
"""Tests for the ``nf-core pipelines containers`` command function."""

def test_regenerates_config_files(self) -> None:
"""Existing config file contents are replaced."""
cfg_path = self.pipeline_dir / "conf" / "containers_docker_amd64.config"
original = cfg_path.read_text()
cfg_path.write_text("not a container config\n")

pipelines_containers_create_configs(None, str(self.pipeline_dir))

assert cfg_path.read_text() == original

def test_exits_when_not_a_pipeline(self) -> None:
"""A directory without main.nf exits with an error."""
with pytest.raises(SystemExit):
pipelines_containers_create_configs(None, str(self.tmp_dir))
Loading