Skip to content
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

dev -> main for 3.2.0 release #3428

Merged
merged 47 commits into from
Jan 27, 2025
Merged
Show file tree
Hide file tree
Changes from 45 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
fd0016c
bump version to 3.2.0dev
mirpedrol Jan 20, 2025
0716d91
Merge pull request #3409 from mirpedrol/bump-to-3.2.0
mirpedrol Jan 20, 2025
c1692f5
fix(1929): more type-gating
awgymer Oct 28, 2024
90978ea
fix CHANGELOG.md
nf-core-bot Oct 28, 2024
a5bb0f0
fix(1929): update subworkflow tests and add lint test markdown
awgymer Oct 28, 2024
732c786
Apply suggestions from code review
awgymer Oct 29, 2024
7ba6f79
feat(1929): allow missing files when linting local modules
awgymer Oct 29, 2024
8a1d44a
feat(1929): local linting option now *only* lints local modules. Add …
awgymer Oct 29, 2024
6c9c1b1
feat(1929): don't ask for a module/subworkflow name to lint if lintin…
awgymer Oct 29, 2024
19df044
feat(1929): add test for new pipeline lint check of local component dirs
awgymer Oct 29, 2024
5d1d44b
feat(1929): run todo linting on local subworkflows
awgymer Oct 30, 2024
5689ff6
fix: Update to latest CHANGELOG
awgymer Jan 21, 2025
3f76e99
fix: Clean up CHANGELOG.md
awgymer Jan 21, 2025
660c8a7
Update pre-commit hook editorconfig-checker/editorconfig-checker.pyth…
renovate[bot] Jan 21, 2025
8d33662
[automated] Update CHANGELOG.md
nf-core-bot Jan 21, 2025
d1f6dc7
Fix 'process.shell' in nextflow.config
ewels Jan 21, 2025
ca8b93d
Merge branch 'dev' into fix-process-shell
mashehu Jan 21, 2025
702e00c
[automated] Update CHANGELOG.md
nf-core-bot Jan 21, 2025
0b6b151
Merge pull request #3416 from ewels/fix-process-shell
ewels Jan 21, 2025
bee0520
Remove automated release tweets
ewels Jan 21, 2025
078e4ee
[automated] Update CHANGELOG.md
nf-core-bot Jan 21, 2025
48ee89c
[automated] Update CHANGELOG.md
nf-core-bot Jan 21, 2025
ed1667f
Merge pull request #3419 from ewels/remove-twitter-release-notifications
ewels Jan 21, 2025
391ae2c
Merge branch 'dev' into 1929-local-modules-use-remote-format
awgymer Jan 22, 2025
3dd2e00
fix: broken test. Need to assign component_dir to the parent dir if a…
awgymer Jan 22, 2025
262dea3
fix: Add new lint test to lint config pydantic model
awgymer Jan 22, 2025
583809c
Update python:3.12-slim Docker digest to 123be56 (#3421)
renovate[bot] Jan 23, 2025
1283406
Update pre-commit hook astral-sh/ruff-pre-commit to v0.9.3
renovate[bot] Jan 23, 2025
52e8d4b
[automated] Fix code linting
nf-core-bot Jan 23, 2025
bc3417a
Merge pull request #3256 from awgymer/1929-local-modules-use-remote-f…
awgymer Jan 24, 2025
3048627
Merge branch 'dev' into renovate/astral-sh-ruff-pre-commit-0.x
mashehu Jan 27, 2025
3be4b60
chore(deps): update dawidd6/action-download-artifact action to v8 (#3…
renovate[bot] Jan 27, 2025
61d9710
fix mypy error
mashehu Jan 27, 2025
2f71183
Merge pull request #3413 from nf-core/renovate/astral-sh-ruff-pre-com…
mashehu Jan 27, 2025
dcf27d9
Merge branch 'dev' into renovate/editorconfig-checker-editorconfig-ch…
mashehu Jan 27, 2025
f8b099c
Separate -o pipefail into separate list elements
ewels Jan 27, 2025
2d7e1a6
[automated] Update CHANGELOG.md
nf-core-bot Jan 27, 2025
df9d892
Merge pull request #3414 from nf-core/renovate/editorconfig-checker-e…
mashehu Jan 27, 2025
2e01c36
Merge pull request #3425 from ewels/o-pipefail-newline
ewels Jan 27, 2025
008dabb
update template components
mirpedrol Jan 27, 2025
ae92258
[automated] Update CHANGELOG.md
nf-core-bot Jan 27, 2025
5236c85
Merge pull request #3426 from mirpedrol/update-template-modules
mirpedrol Jan 27, 2025
92408c3
bump to v3.2.0
mirpedrol Jan 27, 2025
0d9a4f1
template line break fixes
mirpedrol Jan 27, 2025
a7d86d8
Merge pull request #3427 from mirpedrol/bump-to-3.2.0
mirpedrol Jan 27, 2025
381a6b4
update changelog
mirpedrol Jan 27, 2025
0355435
Merge pull request #3429 from mirpedrol/changelog-updates
mirpedrol Jan 27, 2025
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
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.6
rev: v0.9.3
hooks:
- id: ruff # linter
args: [--fix, --exit-non-zero-on-fix] # sort imports and fix
Expand All @@ -13,7 +13,7 @@ repos:
- [email protected]

- repo: https://github.com/editorconfig-checker/editorconfig-checker.python
rev: "3.0.3"
rev: "3.1.2"
hooks:
- id: editorconfig-checker
alias: ec
Expand Down
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# nf-core/tools: Changelog

## [v3.2.0 - Pewter Pangolin](https://github.com/nf-core/tools/releases/tag/3.2.0) - [2025-01-27]

### Template

- Remove automated release tweets ([#3419](https://github.com/nf-core/tools/pull/3419))
- Update template components ([#3426](https://github.com/nf-core/tools/pull/3426))
mirpedrol marked this conversation as resolved.
Show resolved Hide resolved

### Modules

- Modules created in pipelines "local" dir now use the full template ([#3256](https://github.com/nf-core/tools/pull/3256))

### Subworkflows

- Subworkflows created in pipelines "local" dir now use the full template ([#3256](https://github.com/nf-core/tools/pull/3256))

### General

- Update pre-commit hook editorconfig-checker/editorconfig-checker.python to v3.1.2 ([#3414](https://github.com/nf-core/tools/pull/3414))
- Fix `process.shell` in `nextflow.config` ([#3416](https://github.com/nf-core/tools/pull/3416))
- Update python:3.12-slim Docker digest to 123be56 ([#3421](https://github.com/nf-core/tools/pull/3421))
- `-o pipefail` newline ([#3425](https://github.com/nf-core/tools/pull/3425))
mirpedrol marked this conversation as resolved.
Show resolved Hide resolved

## [v3.1.2 - Brass Boxfish Patch](https://github.com/nf-core/tools/releases/tag/3.1.2) - [2025-01-20]

### Template
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.12-slim@sha256:10f3aaab98db50cba827d3b33a91f39dc9ec2d02ca9b85cbc5008220d07b17f3
FROM python:3.12-slim@sha256:123be5684f39d8476e64f47a5fddf38f5e9d839baff5c023c815ae5bdfae0df7
LABEL authors="[email protected],[email protected]" \
description="Docker image containing requirements for nf-core/tools"

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# modules_structure

```{eval-rst}
.. automethod:: nf_core.pipelines.lint.PipelineLint.local_component_structure
```
4 changes: 4 additions & 0 deletions nf_core/components/components_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ def get_local_components(self) -> List[str]:
"""
local_component_dir = Path(self.directory, self.component_type, "local")
return [
str(Path(directory).relative_to(local_component_dir))
for directory, _, files in os.walk(local_component_dir)
if "main.nf" in files
] + [
str(path.relative_to(local_component_dir)) for path in local_component_dir.iterdir() if path.suffix == ".nf"
]

Expand Down
4 changes: 1 addition & 3 deletions nf_core/components/components_differ.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,9 +271,7 @@ def print_diff(
console = Console(force_terminal=nf_core.utils.rich_force_colors())
if current_version is not None and new_version is not None:
log.info(
f"Changes in component '{Path(repo_path, component)}' between"
f" ({current_version}) and"
f" ({new_version})"
f"Changes in component '{Path(repo_path, component)}' between ({current_version}) and ({new_version})"
)
else:
log.info(f"Changes in component '{Path(repo_path, component)}'")
Expand Down
96 changes: 36 additions & 60 deletions nf_core/components/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,11 @@ def create(self) -> bool:
e.g bam_sort or bam_sort_samtools, respectively.

If <directory> is a pipeline, this function creates a file called:
'<directory>/modules/local/tool.nf'
'<directory>/modules/local/tool/main.nf'
OR
'<directory>/modules/local/tool_subtool.nf'
'<directory>/modules/local/tool/subtool/main.nf'
OR for subworkflows
'<directory>/subworkflows/local/subworkflow_name.nf'
'<directory>/subworkflows/local/subworkflow_name/main.nf'

If <directory> is a clone of nf-core/modules, it creates or modifies the following files:

Expand Down Expand Up @@ -355,70 +355,46 @@ def _get_component_dirs(self) -> Dict[str, Path]:
"""
file_paths = {}
if self.repo_type == "pipeline":
local_component_dir = Path(self.directory, self.component_type, "local")
# Check whether component file already exists
component_file = local_component_dir / f"{self.component_name}.nf"
if component_file.exists() and not self.force_overwrite:
raise UserWarning(
f"{self.component_type[:-1].title()} file exists already: '{component_file}'. Use '--force' to overwrite"
)

if self.component_type == "modules":
# If a subtool, check if there is a module called the base tool name already
if self.subtool and (local_component_dir / f"{self.component}.nf").exists():
raise UserWarning(
f"Module '{self.component}' exists already, cannot make subtool '{self.component_name}'"
)

# If no subtool, check that there isn't already a tool/subtool
tool_glob = glob.glob(f"{local_component_dir}/{self.component}_*.nf")
if not self.subtool and tool_glob:
raise UserWarning(
f"Module subtool '{tool_glob[0]}' exists already, cannot make tool '{self.component_name}'"
)

# Set file paths
file_paths["main.nf"] = component_file
component_dir = Path(self.directory, self.component_type, "local", self.component_dir)

elif self.repo_type == "modules":
component_dir = Path(self.directory, self.component_type, self.org, self.component_dir)
# Check if module/subworkflow directories exist already
if component_dir.exists() and not self.force_overwrite and not self.migrate_pytest:
raise UserWarning(
f"{self.component_type[:-1]} directory exists: '{component_dir}'. Use '--force' to overwrite"
)
else:
raise ValueError("`repo_type` not set correctly")

if self.component_type == "modules":
# If a subtool, check if there is a module called the base tool name already
parent_tool_main_nf = Path(
self.directory,
self.component_type,
self.org,
self.component,
"main.nf",
# Check if module/subworkflow directories exist already
if component_dir.exists() and not self.force_overwrite and not self.migrate_pytest:
raise UserWarning(
f"{self.component_type[:-1]} directory exists: '{component_dir}'. Use '--force' to overwrite"
)

if self.component_type == "modules":
# If a subtool, check if there is a module called the base tool name already
parent_tool_main_nf = Path(
self.directory,
self.component_type,
self.org,
self.component,
"main.nf",
)
if self.subtool and parent_tool_main_nf.exists() and not self.migrate_pytest:
raise UserWarning(
f"Module '{parent_tool_main_nf}' exists already, cannot make subtool '{self.component_name}'"
)
if self.subtool and parent_tool_main_nf.exists() and not self.migrate_pytest:
raise UserWarning(
f"Module '{parent_tool_main_nf}' exists already, cannot make subtool '{self.component_name}'"
)

# If no subtool, check that there isn't already a tool/subtool
tool_glob = glob.glob(
f"{Path(self.directory, self.component_type, self.org, self.component)}/*/main.nf"
# If no subtool, check that there isn't already a tool/subtool
tool_glob = glob.glob(f"{Path(self.directory, self.component_type, self.org, self.component)}/*/main.nf")
if not self.subtool and tool_glob and not self.migrate_pytest:
raise UserWarning(
f"Module subtool '{tool_glob[0]}' exists already, cannot make tool '{self.component_name}'"
)
if not self.subtool and tool_glob and not self.migrate_pytest:
raise UserWarning(
f"Module subtool '{tool_glob[0]}' exists already, cannot make tool '{self.component_name}'"
)
# Set file paths
# For modules - can be tool/ or tool/subtool/ so can't do in template directory structure
file_paths["main.nf"] = component_dir / "main.nf"
file_paths["meta.yml"] = component_dir / "meta.yml"
if self.component_type == "modules":
file_paths["environment.yml"] = component_dir / "environment.yml"
file_paths["tests/main.nf.test.j2"] = component_dir / "tests" / "main.nf.test"
else:
raise ValueError("`repo_type` not set correctly")
# Set file paths
# For modules - can be tool/ or tool/subtool/ so can't do in template directory structure
file_paths["main.nf"] = component_dir / "main.nf"
file_paths["meta.yml"] = component_dir / "meta.yml"
if self.component_type == "modules":
file_paths["environment.yml"] = component_dir / "environment.yml"
file_paths["tests/main.nf.test.j2"] = component_dir / "tests" / "main.nf.test"

return file_paths

Expand Down
4 changes: 2 additions & 2 deletions nf_core/components/info.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,9 +265,9 @@ def generate_component_info_help(self):
intro_text.append(
Text.from_markup(
":globe_with_meridians: Repository: "
f"{ '[link={self.remote_location}]' if self.remote_location.startswith('http') else ''}"
f"{'[link={self.remote_location}]' if self.remote_location.startswith('http') else ''}"
f"{self.remote_location}"
f"{'[/link]' if self.remote_location.startswith('http') else '' }"
f"{'[/link]' if self.remote_location.startswith('http') else ''}"
"\n"
)
)
Expand Down
6 changes: 5 additions & 1 deletion nf_core/components/lint/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def __init__(
continue
if isinstance(components, str):
raise LookupError(
f"Error parsing modules.json: {components}. " f"Please check the file for errors or try again."
f"Error parsing modules.json: {components}. Please check the file for errors or try again."
)
for org, comp in components:
self.all_remote_components.append(
Expand Down Expand Up @@ -162,6 +162,10 @@ def _set_registry(self, registry) -> None:
self.registry = registry
log.debug(f"Registry set to {self.registry}")

@property
def local_module_exclude_tests(self):
return ["module_version", "module_changes", "modules_patch"]

@staticmethod
def get_all_module_lint_tests(is_pipeline):
if is_pipeline:
Expand Down
30 changes: 19 additions & 11 deletions nf_core/components/nfcore_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ def __init__(
repo_dir = self.component_dir.parts[:name_index][-1]

self.org = repo_dir
self.nftest_testdir = Path(self.component_dir, "tests")
self.nftest_main_nf = Path(self.nftest_testdir, "main.nf.test")
self.nftest_testdir: Optional[Path] = Path(self.component_dir, "tests")
self.nftest_main_nf: Optional[Path] = Path(self.nftest_testdir, "main.nf.test")

if self.repo_type == "pipeline":
patch_fn = f"{self.component_name.replace('/', '-')}.diff"
Expand All @@ -85,15 +85,23 @@ def __init__(
self.patch_path = patch_path
else:
# The main file is just the local module
self.main_nf = self.component_dir
self.component_name = self.component_dir.stem
# These attributes are only used by nf-core modules
# so just initialize them to None
self.meta_yml = None
self.environment_yml = None
self.test_dir = None
self.test_yml = None
self.test_main_nf = None
if self.component_dir.is_dir():
self.main_nf = Path(self.component_dir, "main.nf")
self.component_name = self.component_dir.stem
# These attributes are only required by nf-core modules
# so just set them to None if they don't exist
self.meta_yml = p if (p := Path(self.component_dir, "meta.yml")).exists() else None
self.environment_yml = p if (p := Path(self.component_dir, "environment.yml")).exists() else None
self.nftest_testdir = p if (p := Path(self.component_dir, "tests")).exists() else None
if self.nftest_testdir is not None:
self.nftest_main_nf = p if (p := Path(self.nftest_testdir, "main.nf.test")).exists() else None
else:
self.main_nf = self.component_dir
self.component_dir = self.component_dir.parent
self.meta_yml = None
self.environment_yml = None
self.nftest_testdir = None
self.nftest_main_nf = None

self.process_name: str = self._get_process_name()

Expand Down
2 changes: 1 addition & 1 deletion nf_core/components/remove.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,6 @@ def remove(self, component, removed_by=None, removed_components=None, force=Fals
f"Did not remove '{component}', because it was also manually installed. Only updated 'installed_by' entry in modules.json."
)
log.info(
f"""Did not remove {self.component_type[:-1]} '{component}', because it was also installed by {', '.join(f"'{d}'" for d in installed_by)}. Only updated the 'installed_by' entry in modules.json."""
f"""Did not remove {self.component_type[:-1]} '{component}', because it was also installed by {", ".join(f"'{d}'" for d in installed_by)}. Only updated the 'installed_by' entry in modules.json."""
)
return removed
22 changes: 19 additions & 3 deletions nf_core/modules/lint/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def lint(
"""
# TODO: consider unifying modules and subworkflows lint() function and add it to the ComponentLint class
# Prompt for module or all
if module is None and not all_modules and len(self.all_remote_components) > 0:
if module is None and not (local or all_modules) and len(self.all_remote_components) > 0:
questions = [
{
"type": "list",
Expand Down Expand Up @@ -170,7 +170,7 @@ def lint(
self.lint_modules(local_modules, registry=registry, local=True, fix_version=fix_version)

# Lint nf-core modules
if len(remote_modules) > 0:
if not local and len(remote_modules) > 0:
self.lint_modules(remote_modules, registry=registry, local=False, fix_version=fix_version)

if print_results:
Expand Down Expand Up @@ -234,7 +234,23 @@ def lint_module(
# TODO: consider unifying modules and subworkflows lint_module() function and add it to the ComponentLint class
# Only check the main script in case of a local module
if local:
self.main_nf(mod, fix_version, self.registry, progress_bar)
mod.get_inputs_from_main_nf()
mod.get_outputs_from_main_nf()
# Update meta.yml file if requested
if self.fix and mod.meta_yml is not None:
self.update_meta_yml_file(mod)

for test_name in self.lint_tests:
if test_name in self.local_module_exclude_tests:
continue
if test_name == "main_nf":
getattr(self, test_name)(mod, fix_version, self.registry, progress_bar)
elif test_name in ["meta_yml", "environment_yml"]:
# Allow files to be missing for local
getattr(self, test_name)(mod, allow_missing=True)
else:
getattr(self, test_name)(mod)

self.passed += [LintResult(mod, *m) for m in mod.passed]
warned = [LintResult(mod, *m) for m in (mod.warned + mod.failed)]
if not self.fail_warned:
Expand Down
11 changes: 10 additions & 1 deletion nf_core/modules/lint/environment_yml.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
log = logging.getLogger(__name__)


def environment_yml(module_lint_object: ComponentLint, module: NFCoreComponent) -> None:
def environment_yml(module_lint_object: ComponentLint, module: NFCoreComponent, allow_missing: bool = False) -> None:
"""
Lint an ``environment.yml`` file.

Expand All @@ -23,6 +23,15 @@ def environment_yml(module_lint_object: ComponentLint, module: NFCoreComponent)
env_yml = None
# load the environment.yml file
if module.environment_yml is None:
if allow_missing:
module.warned.append(
(
"environment_yml_exists",
"Module's `environment.yml` does not exist",
Path(module.component_dir, "environment.yml"),
),
)
return
raise LintExceptionError("Module does not have an `environment.yml` file")
try:
with open(module.environment_yml) as fh:
Expand Down
16 changes: 10 additions & 6 deletions nf_core/modules/lint/meta_yml.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
log = logging.getLogger(__name__)


def meta_yml(module_lint_object: ComponentLint, module: NFCoreComponent) -> None:
def meta_yml(module_lint_object: ComponentLint, module: NFCoreComponent, allow_missing: bool = False) -> None:
"""
Lint a ``meta.yml`` file

Expand Down Expand Up @@ -42,7 +42,13 @@ def meta_yml(module_lint_object: ComponentLint, module: NFCoreComponent) -> None
module (NFCoreComponent): The module to lint

"""

if module.meta_yml is None:
if allow_missing:
module.warned.append(
("meta_yml_exists", "Module `meta.yml` does not exist", Path(module.component_dir, "meta.yml"))
)
return
raise LintExceptionError("Module does not have a `meta.yml` file")
# Check if we have a patch file, get original file in that case
meta_yaml = read_meta_yml(module_lint_object, module)
if module.is_patched and module_lint_object.modules_repo.repo_path is not None:
Expand All @@ -56,9 +62,7 @@ def meta_yml(module_lint_object: ComponentLint, module: NFCoreComponent) -> None
).get("meta.yml")
if lines is not None:
yaml = ruamel.yaml.YAML()
meta_yaml = yaml.safe_load("".join(lines))
if module.meta_yml is None:
raise LintExceptionError("Module does not have a `meta.yml` file")
meta_yaml = yaml.load("".join(lines))
if meta_yaml is None:
module.failed.append(("meta_yml_exists", "Module `meta.yml` does not exist", module.meta_yml))
return
Expand All @@ -78,7 +82,7 @@ def meta_yml(module_lint_object: ComponentLint, module: NFCoreComponent) -> None
if len(e.path) > 0:
hint = f"\nCheck the entry for `{e.path[0]}`."
if e.message.startswith("None is not of type 'object'") and len(e.path) > 2:
hint = f"\nCheck that the child entries of {str(e.path[0])+'.'+str(e.path[2])} are indented correctly."
hint = f"\nCheck that the child entries of {str(e.path[0]) + '.' + str(e.path[2])} are indented correctly."
if e.schema and isinstance(e.schema, dict) and "message" in e.schema:
e.message = e.schema["message"]
incorrect_value = meta_yaml
Expand Down
Loading
Loading