diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index aa21f91d43..3b3706fb17 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,7 +22,8 @@ repos: .*\.snap$| nf_core/pipeline-template/subworkflows/.*| nf_core/pipeline-template/modules/.*| - tests/pipelines/__snapshots__/.* + tests/pipelines/__snapshots__/.*| + tests/configs/__snapshots__/.* )$ - id: end-of-file-fixer exclude: | @@ -30,7 +31,8 @@ repos: .*\.snap$| nf_core/pipeline-template/subworkflows/.*| nf_core/pipeline-template/modules/.*| - tests/pipelines/__snapshots__/.* + tests/pipelines/__snapshots__/.*| + tests/configs/__snapshots__/.* )$ - repo: https://github.com/pre-commit/mirrors-mypy rev: "v2.0.0" diff --git a/MANIFEST.in b/MANIFEST.in index 66fc1afdb4..84baedbeeb 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -9,4 +9,5 @@ include nf_core/assets/logo/nf-core-repo-logo-base-darkbg.png include nf_core/assets/logo/placeholder_logo.svg include nf_core/assets/logo/MavenPro-Bold.ttf include nf_core/pipelines/create/create.tcss +include nf_core/configs/create/create.tcss include nf_core/pipelines/create/template_features.yml diff --git a/nf_core/__main__.py b/nf_core/__main__.py index 4cbe98b603..51aa4239b2 100644 --- a/nf_core/__main__.py +++ b/nf_core/__main__.py @@ -877,6 +877,37 @@ def command_pipelines_schema_docs(directory, schema_file, output, output_format, pipelines_schema_docs(Path(directory, schema_file), output, output_format, force, columns) +# nf-core configs subcommands +@nf_core_cli.group(aliases=["c", "config"]) +@click.pass_context +def configs(ctx): + """ + Commands to manage nf-core configs. + """ + # ensure that ctx.obj exists and is a dict (in case `cli()` is called + # by means other than the `if` block below) + ctx.ensure_object(dict) + + +# nf-core configs create +@configs.command("create") +@click.pass_context +def create_configs(ctx): + """ + Command to interactively create a nextflow or nf-core config + """ + from nf_core.configs.create import ConfigsCreateApp + + try: + log.info("Launching interactive nf-core configs creation tool.") + app = ConfigsCreateApp() + app.run() + sys.exit(app.return_code or 0) + except UserWarning as e: + log.error(e) + sys.exit(1) + + # nf-core modules subcommands @nf_core_cli.group(aliases=["m", "module"]) @click.option( diff --git a/nf_core/configs/__init__.py b/nf_core/configs/__init__.py new file mode 100644 index 0000000000..95c830c1b4 --- /dev/null +++ b/nf_core/configs/__init__.py @@ -0,0 +1 @@ +from .create import ConfigsCreateApp diff --git a/nf_core/configs/create/__init__.py b/nf_core/configs/create/__init__.py new file mode 100644 index 0000000000..01e78dad34 --- /dev/null +++ b/nf_core/configs/create/__init__.py @@ -0,0 +1,137 @@ +"""A Textual app to create a config.""" + +import logging + +import click +from rich.logging import RichHandler + +## Textual objects +from textual.app import App +from textual.widgets import Button + +from nf_core.configs.create import utils + +## nf-core question page (screen) imports +from nf_core.configs.create.basicdetails import BasicDetails +from nf_core.configs.create.configtype import ChooseConfigType +from nf_core.configs.create.defaultprocessres import DefaultProcess +from nf_core.configs.create.final import FinalScreen +from nf_core.configs.create.finalinfradetails import FinalInfraDetails +from nf_core.configs.create.hpccustomisation import HpcCustomisation +from nf_core.configs.create.hpcquestion import ChooseHpc +from nf_core.configs.create.multiprocessres import MultiLabelledProcessConfig, MultiNamedProcessConfig +from nf_core.configs.create.nfcorequestion import ChooseNfcoreConfig +from nf_core.configs.create.pipelineconfigquestion import PipelineConfigQuestion + +## General utilities +from nf_core.configs.create.utils import LoggingConsole +from nf_core.configs.create.welcome import WelcomeScreen + +## Logging +logger = logging.getLogger(__name__) +rich_log_handler = RichHandler( + console=LoggingConsole(classes="log_console"), + level=logging.INFO, + rich_tracebacks=True, + show_time=False, + show_path=False, + markup=True, + tracebacks_suppress=[click], +) +logger.addHandler(rich_log_handler) + + +## Main workflow +class ConfigsCreateApp(App[utils.ConfigsCreateConfig]): + """A Textual app to create nf-core configs.""" + + CSS_PATH = "create.tcss" + TITLE = "nf-core configs create" + SUB_TITLE = "Create a new nextflow config with an interactive interface" + BINDINGS = [ + ("d", "toggle_dark", "Toggle dark mode"), + ("q", "quit", "Quit"), + ] + + ## New question screens (sections) loaded here + SCREENS = { + "welcome": WelcomeScreen, + "choose_type": ChooseConfigType, + "nfcore_question": ChooseNfcoreConfig, + "basic_details": BasicDetails, + "final": FinalScreen, + "hpc_question": ChooseHpc, + "hpc_customisation": HpcCustomisation, + "pipeline_config_question": PipelineConfigQuestion, + "default_process_resources": DefaultProcess, + "multi_named_process_config": MultiNamedProcessConfig, + "multi_labelled_process_config": MultiLabelledProcessConfig, + "final_infra_details": FinalInfraDetails, + } + + # Initialise config as empty + TEMPLATE_CONFIG = utils.ConfigsCreateConfig() + + # Tracking variables + CONFIG_TYPE = None + NFCORE_CONFIG = True + INFRA_ISHPC = False + PIPE_CONF_NAMED = False + PIPE_CONF_LABELLED = False + PIPE_CONF_HPC = False + + # Log handler + LOG_HANDLER = rich_log_handler + # Logging state + LOGGING_STATE = None + + ## Question dialogue order defined here + def on_mount(self) -> None: + self.push_screen("welcome") + + def on_button_pressed(self, event: Button.Pressed) -> None: + """Handle all button pressed events.""" + if event.button.id == "lets_go": + self.push_screen("choose_type") + elif event.button.id == "type_infrastructure": + self.CONFIG_TYPE = "infrastructure" + utils.CONFIG_ISINFRASTRUCTURE_GLOBAL = True + self.push_screen("nfcore_question") + elif event.button.id == "type_nfcore": + self.NFCORE_CONFIG = True + utils.NFCORE_CONFIG_GLOBAL = True + self.push_screen("basic_details") + elif event.button.id == "type_pipeline": + self.CONFIG_TYPE = "pipeline" + utils.CONFIG_ISINFRASTRUCTURE_GLOBAL = False + self.push_screen("nfcore_question") + elif event.button.id == "type_custom": + self.NFCORE_CONFIG = False + utils.NFCORE_CONFIG_GLOBAL = False + self.push_screen("basic_details") + elif event.button.id == "type_hpc": + self.INFRA_ISHPC = True + utils.INFRA_ISHPC_GLOBAL = True + self.push_screen("hpc_customisation") + elif event.button.id == "type_local": + self.INFRA_ISHPC = False + utils.INFRA_ISHPC_GLOBAL = False + self.push_screen("final_infra_details") + ## General options + if event.button.id == "back": + self.pop_screen() + + def close_app(self): + self.exit(return_code=0) + + ## User theme options + def action_toggle_dark(self) -> None: + """An action to toggle dark mode.""" + self.theme: str = "textual-dark" if self.theme == "textual-light" else "textual-light" + + def get_context(self): + return { + "is_nfcore": self.NFCORE_CONFIG, + "is_infrastructure": self.CONFIG_TYPE == "infrastructure", + "is_hpc": self.INFRA_ISHPC, + } diff --git a/nf_core/configs/create/basicdetails.py b/nf_core/configs/create/basicdetails.py new file mode 100644 index 0000000000..d9bd686c6e --- /dev/null +++ b/nf_core/configs/create/basicdetails.py @@ -0,0 +1,189 @@ +"""Get basic contact information to set in params to help with debugging. By +displaying such info in the pipeline run header on run execution""" + +from textwrap import dedent + +from requests import get +from requests.exceptions import RequestException +from textual import on +from textual.app import ComposeResult +from textual.containers import Center, Horizontal +from textual.events import Mount, ScreenResume +from textual.screen import Screen +from textual.widgets import Button, Footer, Header, Input, Markdown, Select + +from nf_core.configs.create.utils import ConfigsCreateConfig, TextInput, add_hide_class, init_context, remove_hide_class + +config_exists_warn = """ +> ⚠️ **The config file you are trying to create already exists.** +> +> If you continue, you will **overwrite** the existing config. +> Please change the config name to create a different config!. +""" + + +class BasicDetails(Screen): + """Name, description, author, etc.""" + + def __init__(self) -> None: + super().__init__() + self.nf_core_pipelines = self.get_valid_nfcore_pipelines() + + def compose(self) -> ComposeResult: + yield Header() + yield Footer() + yield Markdown( + dedent( + """ + # Basic details + """ + ) + ) + ## TODO Add validation, .conf already exists? + yield TextInput( + "general_config_name", + "custom", + "Config Name. Used for naming resulting file.", + "", + classes="column", + ) + with Horizontal(): + yield TextInput( + "config_profile_contact", + "Boaty McBoatFace", + "Author full name.", + classes="column hide" if self.parent.CONFIG_TYPE == "pipeline" else "column", + ) + yield TextInput( + "config_profile_handle", + "@BoatyMcBoatFace", + "Author Git(Hub) handle.", + classes="column hide" if self.parent.CONFIG_TYPE == "pipeline" else "column", + ) + yield Markdown( + "Pipeline name.", + id="config_pipeline_name_text", + classes="hide" + if self.parent.CONFIG_TYPE == "infrastructure" or not self.parent.NFCORE_CONFIG + else "field_help", + ) + yield Select( + [(c, c) for c in self.nf_core_pipelines], + prompt="The name of the nf-core pipeline you want to configure", + id="config_pipeline_name", + allow_blank=True, + type_to_search=True, + classes="hide" if self.parent.CONFIG_TYPE == "infrastructure" or not self.parent.NFCORE_CONFIG else "", + ) + yield TextInput( + "config_pipeline_path", + "Pipeline path", + "The path to the pipeline you want to create the config for.", + classes="hide" if self.parent.CONFIG_TYPE == "infrastructure" or self.parent.NFCORE_CONFIG else "", + ) + + yield TextInput( + "config_profile_description", + "Description", + "A short description of your config.", + ) + yield TextInput( + "config_profile_url", + "https://nf-co.re", + "URL of infrastructure website or owning institution (infrastructure configs only).", + classes="hide" if self.parent.CONFIG_TYPE == "pipeline" else "", + ) + yield Center( + Button("Back", id="back", variant="default"), + Button("Next", id="next", variant="success"), + classes="cta", + ) + + def get_valid_nfcore_pipelines(self) -> list[str]: + """Get a list of valid pipeline names. If the list can't be pulled, return an empty list.""" + url = "https://raw.githubusercontent.com/nf-core/website/refs/heads/main/public/pipeline_names.json" + try: + response = get(url) + except RequestException: + return [] + if response.status_code != 200: + return [] + data = response.json() + if not isinstance(data, dict): + return [] + if "pipeline" not in data: + return [] + pipelines = data["pipeline"] + if not isinstance(pipelines, list): + return [] + if not len(pipelines) > 0: + return [] + if not all(isinstance(p, str) for p in pipelines): + return [] + return pipelines + + ## Updates the __init__ initialised TEMPLATE_CONFIG object (which is built from the ConfigsCreateConfig class) with the values from the text inputs + @on(Button.Pressed) + def on_button_pressed(self, event: Button.Pressed) -> None: + """Save fields to the config.""" + config = {} + for text_input in self.query("TextInput"): + if "hide" in text_input.classes: + continue + this_input = text_input.query_one(Input) + validation_result = this_input.validate(this_input.value) + config[text_input.field_id] = this_input.value + config["is_infrastructure"] = self.parent.CONFIG_TYPE == "infrastructure" + if not validation_result.is_valid: + text_input.query_one(".validation_msg").update("\n".join(validation_result.failure_descriptions)) + else: + text_input.query_one(".validation_msg").update("") + if self.parent.CONFIG_TYPE == "pipeline" and self.parent.NFCORE_CONFIG: + select = self.query_one("#config_pipeline_name", Select) + if select.value != Select.BLANK: + config["config_pipeline_name"] = select.value + elif not config.get("config_pipeline_name", ""): + config["config_pipeline_name"] = "" + try: + with init_context(self.parent.get_context()): + self.parent.TEMPLATE_CONFIG = ConfigsCreateConfig(**config) + if event.button.id == "next": + if self.parent.CONFIG_TYPE == "infrastructure": + self.parent.push_screen("hpc_question") + elif self.parent.CONFIG_TYPE == "pipeline": + self.parent.push_screen("pipeline_config_question") + except ValueError: + pass + + @on(Mount) + @on(ScreenResume) + def show_hide_fields(self) -> None: + """Show/hide fields depending on config type.""" + # Show/hide nf-core required fields + if self.parent.NFCORE_CONFIG: + remove_hide_class(self.parent, "config_profile_contact") + remove_hide_class(self.parent, "config_profile_handle") + remove_hide_class(self.parent, "config_profile_url") + else: + add_hide_class(self.parent, "config_profile_contact") + add_hide_class(self.parent, "config_profile_handle") + add_hide_class(self.parent, "config_profile_url") + + # Hide pipeline fields when in infrastructure mode + if self.parent.CONFIG_TYPE == "infrastructure": + add_hide_class(self.parent, "config_pipeline_name") + add_hide_class(self.parent, "config_pipeline_name_text") + add_hide_class(self.parent, "config_pipeline_path") + return + + # Hide pipeline name fields and show pipeline path field for custom pipeline configs + if not self.parent.NFCORE_CONFIG: + remove_hide_class(self.parent, "config_pipeline_path") + add_hide_class(self.parent, "config_pipeline_name") + add_hide_class(self.parent, "config_pipeline_name_text") + return + + # For nf-core pipelines, hide the pipeline path field and show the dropdown box + add_hide_class(self.parent, "config_pipeline_path") + remove_hide_class(self.parent, "config_pipeline_name") + remove_hide_class(self.parent, "config_pipeline_name_text") diff --git a/nf_core/configs/create/configtype.py b/nf_core/configs/create/configtype.py new file mode 100644 index 0000000000..ad1c0bdca4 --- /dev/null +++ b/nf_core/configs/create/configtype.py @@ -0,0 +1,84 @@ +"""Select which type of config to create to guide questions and order""" + +from textual.app import ComposeResult +from textual.containers import Center, Grid +from textual.screen import Screen +from textual.widgets import Button, Footer, Header, Markdown + +markdown_intro = """ +# Choose config type +""" + +markdown_type_nfcore = """ +## Choose _"Infrastructure config"_ if: + +* You want to only define the computational environment you will run all pipelines on. + + +""" +markdown_type_custom = """ +## Choose _"Pipeline config"_ if: + +* You just want to tweak resources of a particular step of a specific pipeline. +""" + +markdown_details = """ +## What's the difference? + +_Infrastructure_ configs: + +- Are pipeline agnostic. +- Describe the basic necessary information for any nf-core pipeline to +execute. +- Define things such as which container engine to use, if there is a scheduler and +which queues to use etc. +- Are suitable for _all_ users on a given computing environment. +- Can be uploaded to [nf-core +configs](https://github.com/nf-core/tools/configs) to be directly accessible +in a nf-core pipeline with `-profile `. +- Are not used to adjust scientific parameters of a given pipeline (such as a process or +module). + +_Pipeline_ configs + +- Are pipeline specific. +- Are config files that target specific component of a particular pipeline or pipeline run. + - Example: you have a particular step of the pipeline that often runs out +of memory using the pipeline's default settings. You would use this config to +increase the amount of memory Nextflow supplies that given task. +- Are normally only used by a _single or small group_ of users. +- _May_ also be shared amongst multiple users on the same +computing environment if running similar data with the same pipeline. +- Can _sometimes_ be uploaded to [nf-core +configs](https://github.com/nf-core/tools/configs) as a 'pipeline-specific' +config. + + +""" + + +class ChooseConfigType(Screen): + """Choose whether this will be an infrastructure or pipeline config.""" + + def compose(self) -> ComposeResult: + yield Header() + yield Footer() + yield Markdown(markdown_intro) + yield Grid( + Center( + Markdown(markdown_type_nfcore), + Center( + Button( + "Infrastructure config", + id="type_infrastructure", + variant="success", + ) + ), + ), + Center( + Markdown(markdown_type_custom), + Center(Button("Pipeline config", id="type_pipeline", variant="primary")), + ), + classes="col-2 pipeline-type-grid", + ) + yield Markdown(markdown_details) diff --git a/nf_core/configs/create/create.py b/nf_core/configs/create/create.py new file mode 100644 index 0000000000..6b227f0d2c --- /dev/null +++ b/nf_core/configs/create/create.py @@ -0,0 +1,37 @@ +"""Creates a nextflow config matching the current +nf-core organization specification. +""" + +from pathlib import Path +from re import sub + +from nf_core.configs.create.serial import NextflowSerial +from nf_core.configs.create.utils import ConfigsCreateConfig + + +class ConfigCreate: + def __init__(self, template_config: ConfigsCreateConfig, config_type: str, config_dir: Path | str = Path()): + self.template_config = template_config + self.config_type = config_type + config_dir_path = config_dir if isinstance(config_dir, Path) else Path(config_dir) + assert not config_dir_path.is_file(), f'Error: the path "{str(config_dir_path)}" is a file.' + # Create directory if it doesn't already exist + config_dir_path.mkdir(parents=True, exist_ok=True) + self.config_dir = config_dir_path + + def write_to_file(self): + ## File name option + config_name = str(self.template_config.general_config_name).strip() + config_name_clean = sub(r"\W+", "_", config_name) + config_name_clean = sub(r"_+$", "", config_name_clean) + filename = f"{config_name_clean}.conf" + filename = self.config_dir / filename + + if not (self.config_type == "pipeline" or self.config_type == "infrastructure"): + raise ValueError(f"Invalid config type: {self.config_type}") + + serial_data = NextflowSerial.dumps(self.template_config.serial(), drop_null=True) + + with open(filename, "w+") as file: + ## Write params + file.write(serial_data) diff --git a/nf_core/configs/create/create.tcss b/nf_core/configs/create/create.tcss new file mode 100644 index 0000000000..437130a799 --- /dev/null +++ b/nf_core/configs/create/create.tcss @@ -0,0 +1,169 @@ +#logo { + width: 100%; + content-align-horizontal: center; + content-align-vertical: middle; +} +.cta { + layout: horizontal; + margin-bottom: 1; +} +.cta Button { + margin: 0 3; +} + +.pipeline-type-grid { + height: auto; + margin-bottom: 2; +} + +.custom_grid { + height: auto; +} +.custom_grid Switch { + width: auto; +} +.custom_grid Static { + width: 1fr; + margin: 1 8; +} +.custom_grid Button { + width: auto; +} +.custom-process-id { + width: 4fr; + min-width: 10; +} +.custom-process-number { + width: 1fr; + min-width: 10; +} +.custom-process-queue { + width: 2fr; + min-width: 10; +} +.remove-process-group { + padding: 1 0 1 0; + content-align-vertical: middle; + height: 100%; + width: 10; +} +.remove-process-group-filler { + padding: 1 1 1 1; + content-align-vertical: middle; +} +.remove-process-button { + margin: 1 0 1 0; + padding: 0 0 0 0; + align-vertical: middle; + min-width: 7; + width: 7; +} +.text-input-grid { + padding: 1 1 1 1; + grid-size: 1 3; + grid-rows: 3 3 auto; + height: auto; +} +.field_help { + padding: 1 1 0 1; + color: $text-muted; + text-style: italic; +} +.validation_msg { + padding: 0 1; + color: $error; +} +.-valid { + border: tall $success-darken-3; +} + +Horizontal{ + width: 100%; + height: auto; +} +.column { + width: 1fr; +} + +HorizontalScroll { + width: 100%; +} +.feature_subtitle { + color: grey; +} + +Vertical{ + height: auto; +} + +.features-container { + padding: 0 4 1 4; +} + +/* Display help messages */ + +.help_box { + background: #333333; + padding: 1 3 0 3; + margin: 0 5 2 5; + overflow-y: auto; + transition: height 50ms; + display: none; + height: 0; +} +.displayed .help_box { + display: block; + height: 12; +} +.show_help { + display: block; +} +.hide_help { + display: none; +} +.displayed .show_help { + display: none; +} +.displayed .hide_help { + display: block; +} + +/* Show password */ + +#show_password { + display: block; +} +#hide_password { + display: none; +} +.displayed #show_password { + display: none; +} +.displayed #hide_password { + display: block; +} + +/* Logging console */ + +.log_console { + height: auto; + background: #333333; + padding: 1 3; + margin: 0 4 2 4; +} + +.hide { + display: none; +} + +/* Layouts */ +.col-2 { + grid-size: 2 1; +} + +.ghrepo-cols { + margin: 0 4; +} +.ghrepo-cols Button { + margin-top: 2; +} diff --git a/nf_core/configs/create/defaultprocessres.py b/nf_core/configs/create/defaultprocessres.py new file mode 100644 index 0000000000..a1a1b51106 --- /dev/null +++ b/nf_core/configs/create/defaultprocessres.py @@ -0,0 +1,121 @@ +"""Get information about which process/label the user wants to configure.""" + +from textwrap import dedent + +from textual import on +from textual.app import ComposeResult +from textual.containers import Center +from textual.screen import Screen +from textual.widgets import Button, Footer, Header, Input, Markdown + +from nf_core.configs.create.utils import ConfigsCreateConfig, TextInput, init_context + +markdown_explain = """ +Use the following fields to specify the **default** number of +CPUs, memory (in GB) and walltime (in hours) for your pipeline. + +These values will be used by any process that haven't been specifically configured +to request a particular resource. For example, if a process is configured to +request 2 CPUs and 8GB of memory, but no walltime is specified, +the walltime value below will be used. + +All values are optional, but recommended. + +Use the `Skip` button to skip setting default resource values. +""" + + +class DefaultProcess(Screen): + """Get default process resource requirements.""" + + def compose(self) -> ComposeResult: + yield Header() + yield Footer() + yield Markdown( + dedent( + """ + # Default process resources + """ + ) + ) + yield Markdown(markdown_explain) + yield TextInput( + "default_process_ncpus", + "CPUs (OPTIONAL)", + "Number of CPUs to use by default for all processes.", + "1", + classes="column", + ) + yield TextInput( + "default_process_memgb", + "Memory (GB) (OPTIONAL)", + "Amount of memory in GB to use by default for all processes.", + "2", + classes="column", + ) + yield TextInput( + "default_process_hours", + "Time (hours) (OPTIONAL)", + "The default number of hours of walltime required for processes:", + "1", + classes="column", + ) + yield Center( + Button("Back", id="back", variant="default"), + Button("Skip", id="skip", variant="default"), + Button("Next", id="next", variant="success"), + classes="cta", + ) + + @on(Button.Pressed, "#skip") + def skip_to_next_screen(self) -> None: + # Skip to the next screen without saving + if self.parent.PIPE_CONF_NAMED: + self.parent.push_screen("multi_named_process_config") + elif self.parent.PIPE_CONF_LABELLED: + self.parent.push_screen("multi_labelled_process_config") + else: + self.parent.push_screen("final") + + # Updates the __init__ initialised TEMPLATE_CONFIG object (which is built from the ConfigsCreateConfig class) with the values from the text inputs + @on(Button.Pressed, "#next") + def on_next_button(self, event: Button.Pressed) -> None: + """Save fields to the config.""" + new_config = {} + for text_input in self.query("TextInput"): + this_input = text_input.query_one(Input) + validation_result = this_input.validate(this_input.value) + new_config[text_input.field_id] = this_input.value + if not validation_result.is_valid: + text_input.query_one(".validation_msg").update("\n".join(validation_result.failure_descriptions)) + else: + text_input.query_one(".validation_msg").update("") + try: + with init_context(self.parent.get_context()): + # First, validate the new config data + ConfigsCreateConfig(**new_config) + # If that passes validation, update the existing config + self.parent.TEMPLATE_CONFIG = self.parent.TEMPLATE_CONFIG.model_copy(update=new_config) + # Push the next screen + if self.parent.PIPE_CONF_NAMED: + self.parent.push_screen("multi_named_process_config") + elif self.parent.PIPE_CONF_LABELLED: + self.parent.push_screen("multi_labelled_process_config") + else: + self.parent.push_screen("final") + except ValueError: + pass + + @on(Button.Pressed, "#back") + def on_back_button(self, event: Button.Pressed) -> None: + """Clear the default config info""" + blank_config = {} + for text_input in self.query("TextInput"): + if getattr(self.parent.TEMPLATE_CONFIG, text_input.field_id, None): + blank_config[text_input.field_id] = "" + try: + with init_context(self.parent.get_context()): + # Update the existing config with the blank values + self.parent.TEMPLATE_CONFIG = self.parent.TEMPLATE_CONFIG.model_copy(update=blank_config) + except ValueError: + pass diff --git a/nf_core/configs/create/final.py b/nf_core/configs/create/final.py new file mode 100644 index 0000000000..3908404975 --- /dev/null +++ b/nf_core/configs/create/final.py @@ -0,0 +1,57 @@ +from textual import on +from textual.app import ComposeResult +from textual.containers import Center +from textual.screen import Screen +from textual.widgets import Button, Footer, Header, Input, Markdown + +from nf_core.configs.create.create import ConfigCreate +from nf_core.configs.create.utils import ConfigsCreateConfig, TextInput, init_context + + +class FinalScreen(Screen): + """A welcome screen for the app.""" + + def compose(self) -> ComposeResult: + yield Header() + yield Footer() + yield Markdown( + """ +# Final step +""" + ) + yield TextInput( + "savelocation", + ".", + "In which directory would you like to save the config?", + ".", + classes="row", + ) + yield Center( + Button("Back", id="back", variant="default"), + Button("Save and close!", id="close_app", variant="success"), + classes="cta", + ) + + def _create_config(self, config_dir=".") -> None: + """Create the config.""" + create_obj = ConfigCreate( + template_config=self.parent.TEMPLATE_CONFIG, + config_type=self.parent.CONFIG_TYPE, + config_dir=config_dir, + ) + create_obj.write_to_file() + + @on(Button.Pressed, "#close_app") + def on_button_pressed(self, event: Button.Pressed) -> None: + """Save fields to the config.""" + # Validate the save location + save_location = self.query_one("TextInput") + save_location_text = save_location.query_one(Input) + try: + with init_context(self.parent.get_context()): + ConfigsCreateConfig(savelocation=save_location_text.value) + # If validation passes, create the config + self._create_config(config_dir=save_location_text.value) + self.parent.close_app() + except ValueError: + pass diff --git a/nf_core/configs/create/finalinfradetails.py b/nf_core/configs/create/finalinfradetails.py new file mode 100644 index 0000000000..073ea2b7b1 --- /dev/null +++ b/nf_core/configs/create/finalinfradetails.py @@ -0,0 +1,304 @@ +import os +import subprocess + +from textual import on +from textual.app import ComposeResult +from textual.containers import Center, Horizontal, Vertical +from textual.screen import Screen +from textual.widgets import Button, Footer, Header, Input, Markdown, Select, Static, Switch + +from nf_core.configs.create.utils import ( + CACHED_CONTAINERS, + SUPPORTED_CONTAINERS, + ConfigsCreateConfig, + TextInput, + add_hide_class, + init_context, + remove_hide_class, +) + +markdown_intro = """ +# Configure the options for your infrastructure config +""" + +markdown_max_resources = """ +## Set maximum available resources + +### REQUIRED + +The following fields let you set the maximum available resrouces +**across all compute nodes** on your infrastructure. + +Memory, CPUs, and time must be filled out and all processes run with this +configuration will be capped at these values. +""" + +markdown_queue_info = """ +## Set job queue information + +### OPTIONAL + +The queue size, poll interval, and submit rate fields specify how many jobs +can be run at once, how frequently Nextflow checks for job termination, and +how quickly new jobs can be submitted. + +These fields are optional, since +Nextflow has built-in defaults for these values. Consult the Nextflow +documentation for further details on these default values. +""" + +markdown_global_dirs = """ +## Define global directories + +The following fields let you define global directories for +a container/conda image cache, an iGenomes cache, and +a scratch directory in which to run your jobs. + +Each field is optional, but must contain the **full (absolute) path** to +these directories if specified. They may also contain references to +environment variables (e.g. `$CACHEDIR`) and may use the `~` symbol to +refer to your home directory. +""" + + +class FinalInfraDetails(Screen): + """Customise the options to create a config for an infrastructure.""" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.container_system = self._get_container_system() + self.container_system_list = SUPPORTED_CONTAINERS + self.cache_dirs = { + self.container_system: self._get_container_cache_directory(), + } + self.cache_environment = self.container_system in CACHED_CONTAINERS + + def compose(self) -> ComposeResult: + yield Header() + yield Footer() + yield Markdown(markdown_intro) + + yield Markdown("Select the container/software management system available on your infrastructure.") + yield Select( + [(c, c) for c in self.container_system_list], + prompt="Select container/software management system", + id="container_system", + value=self.container_system, + ) + yield Markdown(markdown_max_resources) + with Horizontal(): + yield TextInput( + "memory", + "Memory (REQUIRED)", + "Max. memory (GB) available on your infrastructure.", + classes="column", + ) + yield TextInput( + "cpus", + "CPUs (REQUIRED)", + "Max. number of CPUs available on your infrastructure.", + classes="column", + ) + yield TextInput( + "time", + "Time (REQUIRED)", + "Max. time (hours) available to jobs on your infrastructure.", + classes="column", + ) + yield Markdown(markdown_queue_info) + with Horizontal(): + yield TextInput( + "queue_size", + "Queue size (OPTIONAL)", + "Max. number of jobs that can be submitted simultaneously on your infrastructure.", + classes="column", + ) + yield TextInput( + "poll_interval", + "Poll interval (OPTIONAL)", + "How often (in minutes) to check for job completion.", + classes="column", + ) + yield TextInput( + "submit_rate", + "Jobs per minutes (OPTIONAL)", + "Max. number of jobs that can be submitted per minute.", + classes="column", + ) + yield Markdown(markdown_global_dirs) + yield TextInput( + "cachedir", + "/path/to/cache/dir (OPTIONAL)", + "If you have a global container/conda cache directory, specify the **full path** here.", + classes="hide" if not self.cache_environment else "", + default=self._get_container_cache_directory(), + ) + yield TextInput( + "igenomes_cachedir", + "iGenomes cache directory (OPTIONAL)", + "If you have an iGenomes cache directory, specify the **full path** here.", + classes="hide" if not self.parent.NFCORE_CONFIG else "", + ) + yield TextInput( + "scratch_dir", + "Scratch directory (OPTIONAL)", + "If you want your jobs to run within a scratch directory, specify the full path here.", + classes="", + ) + with Horizontal(classes="ghrepo-cols"): + yield Switch(value=False, id="toggle-delete-work") + with Vertical(): + yield Static("Clean up work directory", classes="") + yield Markdown( + "Select if you want to delete the files in the `work/` directory on successful completion of a run (**prevents `resume` functionality**).", + classes="feature_subtitle", + ) + yield TextInput( + "retries", + "Number of retries", + "Specify how many times Nextflow will retry a failed task before the pipeline fails.", + default="1", + classes="", + ) + yield Center( + Button("Back", id="back", variant="default"), + Button("Finish", id="finish", variant="success"), + classes="cta", + ) + + def _get_container_system(self) -> str: + """Get the default container system to use for software handling.""" + module_system_used = self._detect_module_system() + container_systems = SUPPORTED_CONTAINERS + for system in container_systems: + # First, see if the container system is available natively + try: + output = subprocess.check_output([system], stderr=subprocess.STDOUT).decode("utf-8") + if output: + return system + except FileNotFoundError: + pass + except subprocess.CalledProcessError: + pass + # If not available natively, check if module exists + if module_system_used: + try: + output = subprocess.check_output( + ["module", "avail", "|", "grep", system], stderr=subprocess.STDOUT + ).decode("utf-8") + if output: + return system + except subprocess.CalledProcessError: + pass + # Return the first supported container by default + return container_systems[0] + + def _detect_module_system(self) -> bool: + """Detect if a module system is used""" + try: + subprocess.check_output(["module", "--version"]) + except FileNotFoundError: + return False + except subprocess.CalledProcessError: + return False + return True + + def _get_set_directory(self, directory: str) -> str | None: + """Get the available cache directories""" + if directory: + set_dir = os.environ.get(directory) + if set_dir: + return set_dir + return None + + def _get_container_cache_directory(self) -> str: + """Try to get the cache directory for the current container system.""" + if not self.container_system: + return "" + cachedir_path = self._get_set_directory(f"NXF_{self.container_system.upper()}_CACHEDIR") + return cachedir_path or "" + + def get_container_cache_directory(self) -> str: + """Look up the cache directory for the current container system.""" + if not self.container_system: + return "" + if not self.cache_dirs.get(self.container_system, None): + self.cache_dirs[self.container_system] = self._get_container_cache_directory() + return self.cache_dirs[self.container_system] + + @on(Input.Changed) + @on(Input.Submitted) + def set_cache_directory(self) -> None: + """Set the container system cache dir value""" + if not self.container_system: + return None + for text_input in self.query("TextInput"): + this_input = text_input.query_one(Input) + if text_input.field_id == "cachedir": + cachedir_path = str(this_input.value) + self.cache_dirs[self.container_system] = cachedir_path + + @on(Select.Changed, "#container_system") + def get_container_system(self, event: Select.Changed) -> None: + """Get the container system from dropdown.""" + self.container_system = str(event.value) + cachedir_text_input = self.query_one("#cachedir") + cachedir_input = cachedir_text_input.query_one(Input) + if self.container_system: + cachedir_input.value = self.get_container_cache_directory() + self.cache_environment = self.container_system in CACHED_CONTAINERS + if self.cache_environment: + remove_hide_class(self.parent, "cachedir") + else: + add_hide_class(self.parent, "cachedir") + + @on(Button.Pressed, "#finish") + def on_finish_button(self, event: Button.Pressed) -> None: + """Save fields to the config.""" + new_config = {} + + # collect dropdown value + select = self.query_one("#container_system", Select) + new_config["container_system"] = select.value + + for text_input in self.query("TextInput"): + if "hide" in text_input.classes: + continue + this_input = text_input.query_one(Input) + validation_result = this_input.validate(this_input.value) + new_config[text_input.field_id] = this_input.value + if not validation_result.is_valid: + text_input.query_one(".validation_msg").update("\n".join(validation_result.failure_descriptions)) + else: + text_input.query_one(".validation_msg").update("") + + # collect switch value + delete_work_switch = self.query_one("#toggle-delete-work") + new_config["delete_work_dir"] = delete_work_switch.value + new_config["module"] = self._detect_module_system() + + # Validate and update the config + try: + with init_context(self.parent.get_context()): + # First, validate the new config data + ConfigsCreateConfig(**new_config) + # If that passes validation, update the existing config + self.parent.TEMPLATE_CONFIG = self.parent.TEMPLATE_CONFIG.model_copy(update=new_config) + # Push the next screen + self.parent.push_screen("final") + except ValueError: + pass + + @on(Button.Pressed, "#back") + def on_back_button(self, event: Button.Pressed) -> None: + """Clear the default config info""" + blank_config = {} + for text_input in self.query("TextInput"): + if getattr(self.parent.TEMPLATE_CONFIG, text_input.field_id, None): + blank_config[text_input.field_id] = "" + try: + with init_context(self.parent.get_context()): + # Update the existing config with the blank values + self.parent.TEMPLATE_CONFIG = self.parent.TEMPLATE_CONFIG.model_copy(update=blank_config) + except ValueError: + pass diff --git a/nf_core/configs/create/hpccustomisation.py b/nf_core/configs/create/hpccustomisation.py new file mode 100644 index 0000000000..339acecf8b --- /dev/null +++ b/nf_core/configs/create/hpccustomisation.py @@ -0,0 +1,238 @@ +import io +import json +import subprocess + +from textual import on +from textual.app import ComposeResult +from textual.containers import Center +from textual.screen import Screen +from textual.widgets import Button, Footer, Header, Input, Markdown, Select + +from nf_core.configs.create.utils import ConfigsCreateConfig, TextInput, init_context + +markdown_intro = """ +# Configure the options for your HPC + +Use the following fields to provide important details about your HPC. +""" + +markdown_scheduler = """ +First, select your HPC's scheduler. +The program will attempt to automatically determine your HPC's scheduler. +If it was unsuccessful, you can select one of the supported schedulers from +the drop-down list. +You can also select "Local execution" which will result in jobs defaulting +to run on the same node as Nextflow; this is generally not recommended. +""" + +markdown_queue = """ +Next, supply your HPC's default queue, if required. Again, this will be +auto-filled if possible. +You can leave this field blank if your HPC automatically submits jobs +to a default queue when not specified. + +For more complex queue selection (e.g. based on memory or CPU requirements), +you will need to manually edit the configuration file after completion. + +If you wish to submit different processes to different queues, you will +need to additionally create a pipeline configuration, which will let you +specify alternative HPC queues for each process. +""" + +markdown_queuestat = """ +Finally, use the following field to control how frequently (in minutes) Nextflow should +request the queue status from the scheduler. This is optional, and will +default to 1 minute if not provided. +""" + + +class HpcCustomisation(Screen): + """Customise the options to create a config for an HPC.""" + + def compose(self) -> ComposeResult: + yield Header() + yield Footer() + scheduler = self._get_scheduler() + queues = self._get_queues(scheduler) + default_queue = self._get_default_queue(scheduler) + module_system_used = self._detect_module_system() + supported_schedulers = { + "Local execution": "local", + "PBS/Torque": "pbs", + "PBS Pro": "pbspro", + "SLURM": "slurm", + } + yield Markdown(markdown_intro) + yield Markdown(markdown_scheduler) + yield Select( + list(supported_schedulers.items()), + prompt="Select your HPC's scheduler.", + value=scheduler if scheduler is not None else "local", + classes="column", + id="scheduler", + ) + yield Markdown(markdown_queue) + yield TextInput( + "queue", + "Queue name (OPTIONAL)", + "The default queue in your HPC (leave blank if not required).", + default=default_queue if default_queue else "", + classes="column", + suggestions=queues, + ) + yield TextInput( + "queue_stat_interval", + "Queue stat interval (minutes) (OPTIONAL)", + "How often (in minutes) to get the queue status from the scheduler (optional).", + classes="column", + ) + yield TextInput( + "module_system", + "Other modules to load (OPTIONAL)", + "Do you need to load other software using the module system for your compute nodes? Separate multiple modules by spaces.", + classes="hide" if not module_system_used else "", + ) + yield Center( + Button("Back", id="back", variant="default"), + Button("Continue", id="toconfiguration", variant="success"), + classes="cta", + ) + + def _get_scheduler(self) -> str | None: + """Get the used scheduler""" + try: + subprocess.run(["sinfo", "--version"]) + return "slurm" + except FileNotFoundError: + pass + except subprocess.CalledProcessError: + pass + try: + subprocess.run(["qstat", "--version"]) + return "pbspro" + except FileNotFoundError: + pass + except subprocess.CalledProcessError: + pass + try: + subprocess.run(["qstat", "-help"]) + return "sge" + except FileNotFoundError: + pass + except subprocess.CalledProcessError: + pass + return "local" + + def _get_queues(self, scheduler: str | None) -> list[str]: + """Get the available queues to use for the jobs""" + if scheduler == "slurm": + try: + queues = subprocess.check_output(["sinfo", "-h", "-o", "%P"]).decode("utf-8") + # Remove default * flag + return [i.strip().replace("*", "") for i in queues.split("\n") if i] + except subprocess.CalledProcessError: + pass + elif scheduler == "pbspro": + try: + queues = json.loads(subprocess.check_output(["qstat", "-Q", "-f", "-F", "json"]).decode("utf-8")) + return list(queues["Queue"].keys()) + except subprocess.CalledProcessError: + pass + elif scheduler == "sge": + try: + queues = subprocess.check_output(["qhost", "-q"]).decode("utf-8") + return queues.split("\n") + except subprocess.CalledProcessError: + pass + return [] + + def _get_default_queue(self, scheduler: str | None) -> str: + """Get the default queue for the scheduler""" + if scheduler == "slurm": + try: + return self._slurm_get_default_queue() + except FileNotFoundError: + pass + elif scheduler == "pbspro": + try: + return self._pbs_get_default_queue() + except subprocess.CalledProcessError: + pass + # TODO: Implement SGE here + return "" + + def _slurm_get_default_queue(self) -> str: + """Get the default queue for Slurm""" + config = None + # TODO: If slurm is built from source, the config file path can be different + with open("/etc/slurm/slurm.conf") as fp: + config = self._parse_slurm_config(fp) + + for conf in config: + if conf.get("Default", "NO") == "YES": + return conf["PartitionName"] + + # If no default is set, use the first option + return config[0]["PartitionName"] + + def _pbs_get_default_queue(self) -> str: + pbs_raw_config = subprocess.check_output(["qmgr", "-c", "list server"]).decode("utf-8") + config = self._pbs_parse_config(pbs_raw_config) + return config["default_queue"] + + def _parse_slurm_config(self, fp: io.TextIOWrapper) -> list[dict]: + """Parse the Slurm configuration file""" + config = [] + for line in fp.readlines(): + if line.startswith("PartitionName"): + tokens = [i.rsplit("=", 1) for i in line.split()] + config.append({i[0]: i[1] for i in tokens}) + return config + + def _pbs_parse_config(self, raw: str) -> dict: + """Parse the PBS configuration file""" + config = {} + for line in [r.strip() for r in raw.split("\n")]: + if "=" not in line: + continue + k, v = [token.strip() for token in line.split("=", 1)] + config[k] = v + return config + + def _detect_module_system(self) -> bool: + """Detect if a module system is used""" + try: + subprocess.check_output(["module", "--version"]) + except FileNotFoundError: + return False + except subprocess.CalledProcessError: + return False + return True + + @on(Button.Pressed, "#toconfiguration") + def on_button_pressed(self, event: Button.Pressed) -> None: + """Save fields to the config.""" + new_config = {} + + # Get scheduler value + select = self.query_one("#scheduler", Select) + new_config["scheduler"] = select.value + + for text_input in self.query("TextInput"): + this_input = text_input.query_one(Input) + validation_result = this_input.validate(this_input.value) + new_config[text_input.field_id] = this_input.value + if not validation_result.is_valid: + text_input.query_one(".validation_msg").update("\n".join(validation_result.failure_descriptions)) + else: + text_input.query_one(".validation_msg").update("") + try: + with init_context(self.parent.get_context()): + # First, validate the new config data + ConfigsCreateConfig(**new_config) + # If that passes validation, update the existing config + self.parent.TEMPLATE_CONFIG = self.parent.TEMPLATE_CONFIG.model_copy(update=new_config) + # Push the next screen + self.parent.push_screen("final_infra_details") + except ValueError: + pass diff --git a/nf_core/configs/create/hpcquestion.py b/nf_core/configs/create/hpcquestion.py new file mode 100644 index 0000000000..9e2b951fb2 --- /dev/null +++ b/nf_core/configs/create/hpcquestion.py @@ -0,0 +1,58 @@ +from textual.app import ComposeResult +from textual.containers import Center, Grid +from textual.screen import Screen +from textual.widgets import Button, Footer, Header, Markdown + +markdown_intro = """ +# Is this configuration file for an HPC config? +""" + +markdown_type_hpc = """ +## Choose _"HPC"_ if: + +You want to create a config file for an HPC. +""" +markdown_type_local = """ +## Choose _"local"_ if: + +You want to create a config file to run your pipeline on a local computer. +""" + +markdown_details = """ +## What's the difference? + +Choosing _"HPC"_ will add the following configurations: + +* Provide a scheduler +* Provide the name of a queue +* Select if a module system is used +* Select if you need to load other modules +""" + +cloud_note = """ +**Note:** Currently, only local and HPC executor configurations are supported. +Support for cloud executor configuration will be supported in a future release. +""" + + +class ChooseHpc(Screen): + """Choose whether this will be a config for an HPC or not.""" + + def compose(self) -> ComposeResult: + yield Header() + yield Footer() + yield Markdown(markdown_intro) + yield Grid( + Center( + Markdown(markdown_type_hpc), + Center(Button("HPC", id="type_hpc", variant="success")), + ), + Center( + Markdown(markdown_type_local), + Center(Button("local", id="type_local", variant="primary")), + ), + classes="col-2 pipeline-type-grid", + ) + yield Markdown(markdown_details) + yield Markdown(cloud_note) + yield Center(Button("Back", id="back", variant="default"), classes="cta") diff --git a/nf_core/configs/create/multiprocessres.py b/nf_core/configs/create/multiprocessres.py new file mode 100644 index 0000000000..071af78e7f --- /dev/null +++ b/nf_core/configs/create/multiprocessres.py @@ -0,0 +1,227 @@ +"""Get information about which process/label the user wants to configure.""" + +from textual import on +from textual.app import ComposeResult +from textual.containers import Center, HorizontalGroup, Vertical, VerticalScroll +from textual.events import Mount, ScreenResume +from textual.screen import Screen +from textual.widgets import Button, Footer, Header, Input, Label, Markdown, Static + +from nf_core.configs.create.utils import ConfigsCreateConfig, TextInput, init_context + +markdown_process_name = """ +Use the following fields to configure the basic resource requirements +for your pipeline's processes. The only required field is the process name; +all other fields can be left blank to use the pipeline or infrastructure defaults. +""" + +markdown_process_label = """ +Use the following fields to configure the basic resource requirements +for your pipeline's labels. The only required field is the process label; +all other fields can be left blank to use the pipeline or infrastructure defaults. +""" + +markdown_process_common = """ +Use the `Add another process` button to configure additional processes. + +Use the read `—` buttons to remove a process configuration from the list. +""" + +markdown_skip_name = """ +Use the `Skip` button to skip setting process-specific resource configurations. +""" + +markdown_skip_label = """ +Use the `Skip` button to skip setting label-specific resource configurations. +""" + +markdown_warn_name = """ +**NOTE:** Process names are **not** checked for validity. +Please verify that the name is correct before continuing. +""" + +markdown_warn_label = """ +**NOTE:** Process labels are **not** checked for validity. +Please verify that the label is correct before continuing. +""" + + +class ProcessConfig(HorizontalGroup): + """Get resource requirements for a single process.""" + + def __init__(self, selector: str, hpc: bool) -> None: + super().__init__() + assert selector in ["name", "label"] + self.selector = selector + self.hpc = hpc + + def compose(self) -> ComposeResult: + yield TextInput( + f"custom_process_{self.selector}_id", + f"Process {self.selector} (REQUIRED)", + f"Process {self.selector}:", + "", + classes="custom-process-id", + ) + yield TextInput( + "custom_process_ncpus", + "CPUs", + "# CPUs:", + "", + classes="custom-process-number", + ) + yield TextInput( + "custom_process_memgb", + "Mem", + "Memory (GB):", + "", + classes="custom-process-number", + ) + yield TextInput( + "custom_process_hours", + "Time", + "Walltime (hours):", + "", + classes="custom-process-number", + ) + yield TextInput( + "custom_process_queue", + "queue name (OPTIONAL)", + "HPC queue (optional):", + "", + classes=("custom-process-queue" + (" hide" if not self.hpc else "")), + ) + with Vertical(classes="remove-process-group"): + yield Label("Remove", id="remove-process-config", classes="field_help") + yield Button("—", id="remove", variant="error", classes="remove-process-button") + yield Static(classes="remove-process-group-filler") # Filler + + @on(Button.Pressed, "#remove") + def remove_widget(self) -> None: + self.remove() + + def update_hpc_status(self, hpc: bool) -> None: + self.hpc = hpc + field_id = "custom_process_queue" + if self.hpc: + self.get_widget_by_id(field_id).remove_class("hide") + else: + self.get_widget_by_id(field_id).add_class("hide") + + +class MultiProcessConfig(Screen): + """Get resource requirements for multiple processes.""" + + def __init__(self, selector_type: str, config_key: str, title: str) -> None: + super().__init__() + assert isinstance(title, str) and title + self.title = title + assert isinstance(selector_type, str) and selector_type + assert selector_type in ["name", "label"] + self.selector_type = selector_type + assert isinstance(config_key, str) and config_key + self.config_key = config_key + self.intro = markdown_process_name if self.selector_type == "name" else markdown_process_label + self.skip = markdown_skip_name if self.selector_type == "name" else markdown_skip_label + self.warning = markdown_warn_name if self.selector_type == "name" else markdown_warn_label + + def _set_next_screen(self, next_screen: str) -> None: + assert isinstance(next_screen, str) + self.next_screen = next_screen + + def compose(self) -> ComposeResult: + yield Header() + yield Footer() + yield Markdown(f"# {self.title}") + yield Markdown(self.intro) + yield Markdown(markdown_process_common) + yield Markdown(self.skip) + yield Markdown(self.warning) + yield VerticalScroll( + ProcessConfig(selector=self.selector_type, hpc=self.parent.PIPE_CONF_HPC), + id="configs", + ) + yield Center(Button("Add another process", id="another", variant="success")) + yield Center( + Button("Back", id="back", variant="default"), + Button("Skip", id="skip", variant="default"), + Button("Next", id="next", variant="success"), + classes="cta", + ) + + @on(Button.Pressed, "#another") + def add_config(self) -> None: + new_config = ProcessConfig(selector=self.selector_type, hpc=self.parent.PIPE_CONF_HPC) + self.query_one("#configs").mount(new_config) + + @on(Button.Pressed, "#next") + def save_and_load_next_screen(self) -> None: + try: + config_list = [] + for config_widget in self.query("ProcessConfig"): + tmp_config = {} + for text_input in config_widget.query("TextInput"): + if "hide" in text_input.classes: + continue + this_input = text_input.query_one(Input) + validation_result = this_input.validate(this_input.value) + tmp_config[text_input.field_id] = this_input.value + if not validation_result.is_valid: + text_input.query_one(".validation_msg").update( + "\n".join(validation_result.failure_descriptions) + ) + else: + text_input.query_one(".validation_msg").update("") + # Validate the config + with init_context(self.parent.get_context()): + ConfigsCreateConfig(**tmp_config) + # Add to the config list + config_list.append(tmp_config) + # Add to the final config + new_config = {} + for tmp_config in config_list: + process_id_field = f"custom_process_{self.selector_type}_id" + process_id = tmp_config.get(process_id_field) + new_config[process_id] = tmp_config + self.parent.TEMPLATE_CONFIG = self.parent.TEMPLATE_CONFIG.model_copy(update={self.config_key: new_config}) + # Push the next screen + self.parent.push_screen(self.next_screen) + except ValueError: + pass + + @on(Button.Pressed, "#skip") + def skip_to_next_screen(self) -> None: + self.parent.push_screen(self.next_screen) + + @on(Mount) + @on(ScreenResume) + def update_hide_class(self) -> None: + for config_widget in self.query("ProcessConfig"): + config_widget.update_hpc_status(self.parent.PIPE_CONF_HPC) + + +class MultiNamedProcessConfig(MultiProcessConfig): + def __init__(self) -> None: + super().__init__( + title="Configure processes by name", selector_type="name", config_key="named_process_resources" + ) + + @on(Mount) + @on(ScreenResume) + def set_next_screen(self) -> None: + next_screen = "final" + if self.parent.PIPE_CONF_LABELLED: + next_screen = "multi_labelled_process_config" + self._set_next_screen(next_screen) + + +class MultiLabelledProcessConfig(MultiProcessConfig): + def __init__(self) -> None: + super().__init__( + title="Configure processes by label", selector_type="label", config_key="labelled_process_resources" + ) + + @on(Mount) + @on(ScreenResume) + def set_next_screen(self) -> None: + self._set_next_screen("final") diff --git a/nf_core/configs/create/nfcorequestion.py b/nf_core/configs/create/nfcorequestion.py new file mode 100644 index 0000000000..fa9eac382a --- /dev/null +++ b/nf_core/configs/create/nfcorequestion.py @@ -0,0 +1,65 @@ +from textual.app import ComposeResult +from textual.containers import Center, Grid +from textual.screen import Screen +from textual.widgets import Button, Footer, Header, Markdown + +markdown_intro = """ +# Will this configuration file be part of the nf-core organisation? +""" + +markdown_type_nfcore = """ +## Choose _"nf-core"_ if: + +Infrastructure configs: +* You want to add the configuration file to the nf-core/configs repository. + +Pipeline configs: +* The configuration file is for an nf-core pipeline. +""" +markdown_type_custom = """ +## Choose _"Custom"_ if: + +All configs: +* You want full control over *all* parameters or options in the config + (including those that are mandatory for nf-core). + +Infrastructure configs: +* You will _never_ add the configuration file to the nf-core/configs repository. + +Pipeline configs: +* The configuration file is for a custom pipeline which will _never_ be part of nf-core. +""" + +markdown_details = """ +## What's the difference? + +Choosing _"nf-core"_ will make the following of the options mandatory: + +Infrastructure configs: +* Providing the name and github handle of the author and contact person. +* Providing a description of the config. +* Providing the URL of the owning institution. +* Setting up `resourceLimits` to set the maximum resources. +""" + + +class ChooseNfcoreConfig(Screen): + """Choose whether this will be an nf-core config or not.""" + + def compose(self) -> ComposeResult: + yield Header() + yield Footer() + yield Markdown(markdown_intro) + yield Grid( + Center( + Markdown(markdown_type_nfcore), + Center(Button("nf-core", id="type_nfcore", variant="success")), + ), + Center( + Markdown(markdown_type_custom), + Center(Button("Custom", id="type_custom", variant="primary")), + ), + classes="col-2 pipeline-type-grid", + ) + yield Markdown(markdown_details) + yield Center(Button("Back", id="back", variant="default"), classes="cta") diff --git a/nf_core/configs/create/pipelineconfigquestion.py b/nf_core/configs/create/pipelineconfigquestion.py new file mode 100644 index 0000000000..9dc3ff396d --- /dev/null +++ b/nf_core/configs/create/pipelineconfigquestion.py @@ -0,0 +1,143 @@ +"""Get information about which process/label the user wants to configure.""" + +from textwrap import dedent + +from textual import on +from textual.app import ComposeResult +from textual.containers import Center, Horizontal +from textual.screen import Screen +from textual.widgets import Button, Footer, Header, Label, Markdown, Switch + +markdown_explain = """ +The following pages will let you configure the CPU, memory, and walltime +resources for your pipeline. Use the toggles below to specify whether +you want to configure these values for specific processes or lables, +and if you want to set the defaults for these values. + +- If you want to set the **default** CPU, memory, and walltime resources for **every process**, +toggle `Configure default resources for processes?`. +- If you want to configure the resources for individual processes by name, +toggle `Configure specific processes by name?`. +- If you want to configure groups of processes that share a particular **[label](https://docs.seqera.io/nextflow/reference/process#label)**, +toggle `Configure processes by label?`. + +Remember, process-specific resource configurations take precedence over +label configurations. If neither is set for a given process and resource type, the +default resource configuration will be used. +""" + + +class PipelineConfigQuestion(Screen): + """Determine whether the user wants to configure the default resources and/or specific process names/labels.""" + + def __init__(self) -> None: + super().__init__() + self.config_defaults = False + self.config_named_processes = False + self.config_labels = False + self.config_hpc = False + + def compose(self) -> ComposeResult: + yield Header() + yield Footer() + yield Markdown( + dedent( + """ + # What would you like to configure? + """ + ) + ) + yield Markdown(markdown_explain) + with Horizontal(): + yield Label("Configure default resources for processes?", id="toggle_configure_defaults_label") + yield Switch( + id="toggle_configure_defaults", + value=self.config_defaults, + ) + yield Label("Yes" if self.config_defaults else "No", id="toggle_configure_defaults_state_label") + with Horizontal(): + yield Label("Configure specific processes by name?", id="toggle_configure_names_label") + yield Switch( + id="toggle_configure_names", + value=self.config_named_processes, + ) + yield Label("Yes" if self.config_named_processes else "No", id="toggle_configure_names_state_label") + with Horizontal(): + yield Label("Configure processes by label?", id="toggle_configure_labels_label") + yield Switch( + id="toggle_configure_labels", + value=self.config_labels, + ) + yield Label("Yes" if self.config_labels else "No", id="toggle_configure_labels_state_label") + yield Markdown( + dedent( + """ + # Will you be using this configuration exclusively on an HPC? + + ## Choose _"Yes"_ if: + + You are configuring processes specifically for running on an HPC. + + ## Choose _"No"_ if: + + This config file will be used across different platforms. + + ## What's the difference? + + Choosing _"Yes"_ will allow you to additionally specify an HPC `queue` for each process or label. + **Note** that this field can be left blank to use the default queue. + """ + ) + ) + with Horizontal(): + yield Label("Configure HPC-specific resources?", id="toggle_configure_hpc_resources_label") + yield Switch( + id="toggle_configure_hpc_resources", + value=self.config_hpc, + ) + yield Label("Yes" if self.config_hpc else "No", id="toggle_configure_hpc_resources_state_label") + yield Center( + Button("Back", id="back", variant="default"), + Button("Next", id="next", variant="success"), + classes="cta", + ) + + @on(Switch.Changed) + def on_toggle_switch(self, event: Switch.Changed) -> None: + """Handle toggling the switches that determine which pipeline resources to configure""" + valid_toggles = { + "toggle_configure_defaults": "config_defaults", + "toggle_configure_names": "config_named_processes", + "toggle_configure_labels": "config_labels", + "toggle_configure_hpc_resources": "config_hpc", + } + + if event.switch.id not in valid_toggles: + return + + attr = valid_toggles[event.switch.id] + self.__setattr__(attr, event.value) + + # Update the switch label + for label in self.query(Label): + if label.id == f"{event.switch.id}_state_label": + label.update("Yes" if event.value else "No") + + # Updates the __init__ initialised TEMPLATE_CONFIG object (which is built from the ConfigsCreateConfig class) with the values from the text inputs + @on(Button.Pressed, "#next") + def on_next_button_pressed(self, event: Button.Pressed) -> None: + """Save configuration options and then move to the next screen.""" + # Update app tracking variables for whether to configure named and/or labelled processes + self.parent.PIPE_CONF_NAMED = self.config_named_processes + self.parent.PIPE_CONF_LABELLED = self.config_labels + self.parent.PIPE_CONF_HPC = self.config_hpc + + # Proceed to next screen depending on what choices the user has made + if self.config_defaults: + self.parent.push_screen("default_process_resources") + elif self.config_named_processes: + self.parent.push_screen("multi_named_process_config") + elif self.config_labels: + self.parent.push_screen("multi_labelled_process_config") + else: + self.parent.push_screen("final") diff --git a/nf_core/configs/create/serial.py b/nf_core/configs/create/serial.py new file mode 100644 index 0000000000..5f14202635 --- /dev/null +++ b/nf_core/configs/create/serial.py @@ -0,0 +1,93 @@ +from typing import Any + + +class NextflowSerial: + def __init__(self, data_dict: dict | None, tab_indent: int | None = 4): + self.data_dict = data_dict + + def __getitem__(self, key: Any | None) -> Any: + """Returns value from data""" + if not isinstance(self.data_dict, dict): + raise ValueError("NextflowSerial object is not initialised, cannot index.") + return self.data_dict[key] + + def __setitem__(self, key: Any | None, value: Any | None) -> None: + """Sets value in data""" + if not isinstance(self.data_dict, dict): + raise ValueError("NextflowSerial object is not initialised, cannot index.") + self.data_dict[key] = value + + @staticmethod + def _stringify(data: Any | None, quote: bool = True) -> str: + """Return nextflow compatible value""" + quote_char = "'" if quote else "" + if isinstance(data, str): + return f"{quote_char}{data}{quote_char}" + if isinstance(data, bool): + return "true" if data else "false" + if isinstance(data, type(None)): + return "null" + return str(data) # Fallback on the Python str function if no matches + + @staticmethod + def dumps( + data_dict: Any | None, + tab_indent: int = 4, + current_indent: int = 0, + end: str = "\n", + indent_start: bool = True, + one_line: bool = False, + drop_null: bool = False, + ) -> str: + """Recursive function to create configuration file""" + output = "" + if isinstance(data_dict, dict): + for k, v in data_dict.items(): + if drop_null and v is None: + continue + if isinstance(v, dict): + output += " " * current_indent * int(indent_start) + output += f"{k} {{\n" + output += NextflowSerial.dumps( + v, + tab_indent=tab_indent, + current_indent=current_indent + tab_indent, + end=end, + drop_null=drop_null, + ) + output += " " * current_indent + output += f"}}{end}" + elif isinstance(v, list): + output += " " * current_indent + output += f"{k} = [" + vi = [] + for i in v: + oneliner = bool(len(i.keys()) != 1) + if isinstance(i, dict): + vi.append( + "{" * oneliner + + NextflowSerial.dumps( + i, + tab_indent, + current_indent=0, + end="", + indent_start=False, + one_line=not oneliner, + drop_null=drop_null, + ) + + "}" * oneliner + ) + continue + vi.append(NextflowSerial.dumps(i, tab_indent, current_indent=0, end=end, drop_null=drop_null)) + output += ", ".join(vi) + output += f"]{end}" + else: + output += " " * current_indent * indent_start + if one_line: + # False is set here to disable quotes on strings + output += f"{k}: {NextflowSerial._stringify(v)}{end}" + else: + output += f"{k} = {NextflowSerial._stringify(v)}{end}" + return output + else: + return NextflowSerial._stringify(data_dict) diff --git a/nf_core/configs/create/utils.py b/nf_core/configs/create/utils.py new file mode 100644 index 0000000000..089b0d7063 --- /dev/null +++ b/nf_core/configs/create/utils.py @@ -0,0 +1,740 @@ +"""Config creation specific functions and classes""" + +import re +from collections.abc import Iterator +from contextlib import contextmanager +from contextvars import ContextVar +from math import ceil +from pathlib import Path +from typing import Any + +from pydantic import BaseModel, ConfigDict, ValidationError, ValidationInfo, field_validator +from textual import on +from textual.app import ComposeResult +from textual.containers import Grid +from textual.suggester import SuggestFromList +from textual.validation import ValidationResult, Validator +from textual.widget import Widget +from textual.widgets import Input, RichLog, Static + +# Use ContextVar to define a context on the model initialization +_init_context_var: ContextVar = ContextVar("_init_context_var", default=None) +_init_context_var.set({}) + + +@contextmanager +def init_context(value: dict[str, Any]) -> Iterator[None]: + token = _init_context_var.set(value) + try: + yield + finally: + _init_context_var.reset(token) + + +# Define a global variable to store the config type +CONFIG_ISINFRASTRUCTURE_GLOBAL: bool = True +NFCORE_CONFIG_GLOBAL: bool = True +INFRA_ISHPC_GLOBAL: bool = False +_PATH_PATTERN = re.compile(r"(\/|~\/|~$|\$\{?\w+\}?)(.*)") +# Used by finalinfradetails as it already imports create.utils +SUPPORTED_CONTAINERS = ["singularity", "docker", "apptainer", "charliecloud", "podman", "sarus", "shifter", "conda"] +CACHED_CONTAINERS = ["singularity", "apptainer", "charliecloud", "conda"] +SUPPORTED_SCHEDULERS = ["local", "pbs", "pbspro", "slurm", "sge"] + + +class ConfigsCreateConfig(BaseModel): + """Pydantic model for the nf-core configs create config.""" + + is_infrastructure: bool | None = False + """ Config variable to define if this is infrastructure or pipeline """ + config_pipeline_name: str | None = None + """ The name of the pipeline """ + config_pipeline_path: str | None = None + """ The path to the pipeline """ + general_config_name: str | None = None + """ Config name """ + config_profile_contact: str | None = None + """ Config contact name """ + config_profile_handle: str | None = None + """ Config contact GitHub handle """ + config_profile_description: str | None = None + """ Config description """ + config_profile_url: str | None = None + """ Config institution URL """ + default_process_ncpus: str | None = None + """ Default number of CPUs """ + default_process_memgb: str | None = None + """ Default amount of memory """ + default_process_hours: str | None = None + """ Default walltime - hours """ + custom_process_name_id: str | None = None + """" Name of a process to configure """ + custom_process_label_id: str | None = None + """" Label of a process to configure """ + custom_process_ncpus: str | None = None + """ Number of CPUs for process """ + custom_process_memgb: str | None = None + """ Amount of memory for process """ + custom_process_hours: str | None = None + """ Walltime for process - hours """ + custom_process_queue: str | None = None + """ Custom queue for process to override default """ + named_process_resources: dict | None = None + """ Dictionary containing custom resource requirements for named processes """ + labelled_process_resources: dict | None = None + """ Dictionary containing custom resource requirements for labelled processes """ + is_nfcore: bool | None = None + """ Whether the config is part of the nf-core organisation """ + savelocation: str | None = None + """ Final location of the configuration file """ + scheduler: str | None = None + """ The scheduler that the HPC uses """ + queue: str | None = None + """ The default queue that the HPC uses """ + module_system: str | None = None + """ Modules to load when running processes """ + container_system: str | None = None + """ The container system the HPC uses """ + memory: str | None = None + """ The maximum memory available to processes """ + cpus: str | None = None + """ The maximum number of CPUs available to processes """ + time: str | None = None + """ The maximum walltime available to processes """ + cachedir: str | None = None + """ An environment variable to hold a custom Nextflow container cachedir """ + igenomes_cachedir: str | None = None + """ A cachedir for iGenomes """ + scratch_dir: str | None = None + """ A scratch directory to use """ + retries: str | None = None + """ Number of retries for failed jobs """ + module: bool | None = False + """ Whether the infrastructure uses a module system """ + delete_work_dir: bool | None = False + """ Whether to clean up the work directory upon successful completion """ + queue_stat_interval: str | None = None + """ How often to check the HPC queue status. """ + queue_size: str | None = None + """ How many jobs can be submitted to the queue at once. """ + poll_interval: str | None = None + """ How often to check for successful completion of processes. """ + submit_rate: str | None = None + """ How many jobs can be submitted per minute. """ + + model_config = ConfigDict(extra="allow") + + def __init__(self, /, **data: Any) -> None: + """Custom init method to allow using a context on the model initialization.""" + self.__pydantic_validator__.validate_python( + data, + self_instance=self, + context=_init_context_var.get(), + ) + + def _remove_empty_sections(self, config_dict: dict): + # Takes a config dict produced by serial_hpc() or serial_pipeline() + # and removes keys with null or empty values + ret = {} + for k, v in config_dict.items(): + if isinstance(v, dict): + v2 = self._remove_empty_sections(v) + else: + v2 = v + if v2: + ret[k] = v2 + return ret + + def _format_resource_request(self, value_str: str, unit_str: str) -> str: + # Format a resource request to an integer + # and update the units if required + # E.g. 1.0h -> 1h; 1.0GB -> 1GB + # and 0.5h -> 30min; 0.5GB -> 512MB + + # Make sure unit_str is valid + assert unit_str in ["h", "min", "GB"], f'Invalid unit: "{unit_str}"' + + # Turn the value string into a float + v = float(value_str) + u = unit_str + if v.is_integer(): + v = int(v) + if v == 0: + v = 1 + elif v < 1: + if unit_str == "min": + v = ceil(v * 60) + u = "s" + elif unit_str == "h": + v = ceil(v * 60) + u = "min" + elif unit_str == "GB": + v = ceil(v * 1024) + u = "MB" + return f"{v} {u}" + + def serial_params(self): + # Determine contact info + contact = "" + if self.config_profile_contact: + contact = self.config_profile_contact + if self.config_profile_handle: + contact += f" ({self.config_profile_handle})" + elif self.config_profile_handle: + contact = self.config_profile_handle + else: + contact = None + ret = { + "params": { + "config_profile_contact": contact, + "config_profile_description": self.config_profile_description or None, + "config_profile_url": self.config_profile_url or None, + "igenomes_base": self.igenomes_cachedir or None, + }, + } + return self._remove_empty_sections(ret) + + def serial_hpc(self): + """Returns a dictionary of the config""" + # Get params section + params = self.serial_params() + # Determine modules to load + modules_to_load = self.container_system if self.module and self.container_system else "" + if self.module_system: + if modules_to_load: + modules_to_load += " " + modules_to_load += re.sub(r"\s+", ":", self.module_system) + ret = { + **params, + "executor": { + "queueStatInterval": self._format_resource_request(self.queue_stat_interval, "min") + if self.queue_stat_interval + else None, + "queueSize": int(self.queue_size) if self.queue_size else None, + "pollInterval": self._format_resource_request(self.poll_interval, "min") + if self.poll_interval + else None, + "submitRateLimit": self._format_resource_request(self.submit_rate, "min") if self.submit_rate else None, + }, + "process": { + "executor": self.scheduler or None, + "queue": self.queue or None, + "resourceLimits": [ + {"cpus": int(self.cpus) if self.cpus else None}, + {"memory": self._format_resource_request(self.memory, "GB") if self.memory else None}, + {"time": self._format_resource_request(self.time, "h") if self.time else None}, + ], + "scratch": self.scratch_dir or None, + "maxRetries": int(self.retries) if self.retries else None, + "module": modules_to_load or None, + }, + self.container_system: { + "enabled": True, + "cacheDir": self.cachedir + if self.container_system in CACHED_CONTAINERS + else None, + "autoMounts": True if self.container_system in ["singularity", "apptainer"] else None, + }, + "cleanup": self.delete_work_dir, + } + + return self._remove_empty_sections(ret) + + def serial_pipeline(self): + """Returns a dictionary of the pipeline config""" + # Get params section + params = self.serial_params() + ret = { + **params, + "process": { + "cpus": int(self.default_process_ncpus) if self.default_process_ncpus else None, + "memory": self._format_resource_request(self.default_process_memgb, "GB") + if self.default_process_memgb + else None, + "time": self._format_resource_request(self.default_process_hours, "h") + if self.default_process_hours + else None, + }, + } + # Get custom process resources + for selector in ["withName", "withLabel"]: + custom_resources_dict = ( + self.named_process_resources if selector == "withName" else self.labelled_process_resources + ) + if not custom_resources_dict: + continue + for process_id, process_resources in custom_resources_dict.items(): + ret["process"][f"{selector}: '{process_id}'"] = { + "cpus": ( + int(process_resources["custom_process_ncpus"]) + if process_resources["custom_process_ncpus"] + else None + ), + "memory": ( + self._format_resource_request(process_resources["custom_process_memgb"], "GB") + if process_resources["custom_process_memgb"] + else None + ), + "time": ( + self._format_resource_request(process_resources["custom_process_hours"], "h") + if process_resources["custom_process_hours"] + else None + ), + } + if "custom_process_queue" in process_resources: + ret["process"][f"{selector}: '{process_id}'"]["queue"] = ( + process_resources["custom_process_queue"] if process_resources["custom_process_queue"] else None + ) + if "executor" in process_resources: + ret["process"][f"{selector}: '{process_id}'"]["executor"] = ( + process_resources["executor"] if process_resources["executor"] else None + ) + return self._remove_empty_sections(ret) + + def serial(self): + if self.is_infrastructure: + return self.serial_hpc() + else: + return self.serial_pipeline() + + @field_validator("general_config_name") + @classmethod + def notempty(cls, v: str) -> str: + """Check that string values are not empty.""" + if v.strip() == "": + raise ValueError("Cannot be left empty.") + return v + + @field_validator("config_profile_description") + @classmethod + def notempty_nfcore(cls, v: str, info: ValidationInfo) -> str: + """Check that string values are not empty.""" + context = info.context + if context and context["is_nfcore"] and v.strip() == "": + raise ValueError("Cannot be left empty.") + return v + + @field_validator("general_config_name") + @classmethod + def all_lower_case(cls, v: str, info: ValidationInfo) -> str: + """Check that string values are all lower-case.""" + context = info.context + if context and context["is_nfcore"] and not v.islower(): + raise ValueError("Config names must not contain upper-case letters.") + return v + + @field_validator("config_pipeline_path") + @classmethod + def path_valid(cls, v: str, info: ValidationInfo) -> str: + """Check that a path is valid.""" + context = info.context + if context and not context["is_infrastructure"] and not context["is_nfcore"]: + if v.strip() == "": + raise ValueError("Cannot be left empty.") + if not Path(v).is_dir(): + raise ValueError("Must be a valid path.") + return v + + @field_validator("savelocation") + @classmethod + def final_path_valid(cls, v: str, info: ValidationInfo) -> str: + """Check that the final save directory is valid.""" + if v.strip() == "": + raise ValueError("Cannot be left empty.") + if not Path(v).is_dir(): + raise ValueError("Must be a valid path to a directory.") + return v + + @field_validator("config_pipeline_name") + @classmethod + def nfcore_name_valid(cls, v: str, info: ValidationInfo) -> str: + """Check that an nf-core pipeline name is valid.""" + context = info.context + if context and not context["is_infrastructure"] and context["is_nfcore"] and v.strip() == "": + raise ValueError("Cannot be left empty.") + return v + + @field_validator("config_profile_contact") + @classmethod + def notempty_contact(cls, v: str, info: ValidationInfo) -> str: + """Check that contact values are not empty when the config is nf-core.""" + context = info.context + if context and context["is_nfcore"] and v.strip() == "": + raise ValueError("Cannot be left empty.") + return v + + @field_validator( + "config_profile_handle", + ) + @classmethod + def handle_prefix(cls, v: str, info: ValidationInfo) -> str: + """Check that GitHub handles start with '@'. + Make providing a handle mandatory for nf-core configs""" + context = info.context + if context and context["is_nfcore"]: + if v.strip() == "": + raise ValueError("Cannot be left empty.") + if not re.match(r"^@[aA-zZ\d](?:[aA-zZ\d]|-(?=[aA-zZ\d])){0,38}$", v): + ## Regex adapted from: https://github.com/shinnn/github-username-regex + raise ValueError("Handle must start with '@'.") + return v + + @field_validator( + "config_profile_url", + ) + @classmethod + def url_prefix(cls, v: str, info: ValidationInfo) -> str: + """Check that institutional web links start with valid URL prefix.""" + context = info.context + if context and context["is_nfcore"]: + if v.strip() == "": + raise ValueError("Cannot be left empty.") + elif not re.match( + r"https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)", + v, + ): ## Regex from: https://stackoverflow.com/a/3809435 + raise ValueError( + "Handle must be a valid URL starting with 'https://' or 'http://' and include the domain (e.g. .com)." + ) + return v + + @field_validator("custom_process_name_id") + @classmethod + def valid_process_name(cls, v: str, info: ValidationInfo) -> str: + """Check that the custom process name isn't empty and is valid.""" + context = info.context + if context and not context["is_infrastructure"]: + if v.strip() == "": + raise ValueError("Cannot be left empty.") + if context["is_nfcore"] and not re.match( + r"^[A-Z0-9_:.*]+$", + v, + ): + raise ValueError("Must be uppercase and contain only letters, numbers, `_`, `:`, `.`, and `*`") + return v + + @field_validator("custom_process_label_id") + @classmethod + def valid_process_label(cls, v: str, info: ValidationInfo) -> str: + """Check that the custom process label isn't empty and is valid.""" + context = info.context + if context and not context["is_infrastructure"]: + if v.strip() == "": + raise ValueError("Cannot be left empty.") + if context["is_nfcore"] and not re.match( + r"^[a-z0-9_]+$", + v, + ): + raise ValueError("Must be lowercase and contain only letters, numbers, and `_`") + return v + + @field_validator("default_process_ncpus", "default_process_memgb", "custom_process_ncpus", "custom_process_memgb") + @classmethod + def pos_integer_valid(cls, v: str, info: ValidationInfo) -> str: + """Check that integer values are either empty or positive. + + This contains the same validation as self.pos_integer_valid_infra(). + However, keep infrastructure and pipeline methods decoupled for + easier refactoring in future. + """ + context = info.context + if context and not context["is_infrastructure"]: + if v.strip() == "": + return v + try: + v_int = int(v.strip()) + except ValueError: + raise ValueError("Must be an integer.") from None + if not v_int > 0: + raise ValueError("Must be a positive integer.") + return v + + @field_validator("default_process_hours", "custom_process_hours") + @classmethod + def non_neg_float_valid(cls, v: str, info: ValidationInfo) -> str: + """Check that numeric values are either empty or non-negative.""" + context = info.context + if context and not context["is_infrastructure"]: + if v.strip() == "": + return v + try: + vf = float(v.strip()) + except ValueError: + raise ValueError("Must be a number.") from None + if not vf >= 0: + raise ValueError("Must be a non-negative number.") + return v + + @field_validator("custom_process_queue") + @classmethod + def valid_custom_queue(cls, v: str, info: ValidationInfo) -> str: + """Check that a custom queue is either not set or is a valid string""" + context = info.context + if context and not context["is_infrastructure"]: + if v.strip() == "": + return v + if " " in v.strip(): + raise ValueError("Cannot contain spaces") + # TODO: Any other invalid characters? + return v + + @field_validator("cpus", "memory", "retries") + @classmethod + def pos_integer_valid_infra(cls, v: str, info: ValidationInfo) -> str: + """ + Check that integer values are positive. + + This contains the same validation as self.pos_integer_valid(). + However, keep infrastructure and pipeline methods decoupled for + easier refactoring in future. + """ + context = info.context + if context and context["is_infrastructure"]: + if v.strip() == "": + raise ValueError("Cannot be empty.") + try: + v_int = int(v.strip()) + except ValueError: + raise ValueError("Must be an integer.") from None + if not v_int > 0: + raise ValueError("Must be a positive integer.") + return v + + @field_validator("queue_size", "submit_rate") + @classmethod + def pos_integer_optional_valid_infra(cls, v: str, info: ValidationInfo) -> str: + """ + Check that integer values are either empty or positive. + + This contains the same validation as self.pos_integer_valid_infra(), + but allows for empty values as well + """ + context = info.context + if context and context["is_infrastructure"]: + if v.strip() == "": + return v + try: + v_int = int(v.strip()) + except ValueError: + raise ValueError("Must be an integer.") from None + if not v_int > 0: + raise ValueError("Must be a positive integer.") + return v + + @field_validator("time") + @classmethod + def non_neg_float_valid_infra(cls, v: str, info: ValidationInfo) -> str: + """Check that numeric values are either empty or non-negative.""" + context = info.context + if context and context["is_infrastructure"]: + if v.strip() == "": + raise ValueError("Cannot be empty.") + try: + vf = float(v.strip()) + except ValueError: + raise ValueError("Must be a number.") from None + if not vf >= 0: + raise ValueError("Must be a non-negative number.") + return v + + @field_validator("poll_interval") + @classmethod + def pos_float_valid_infra(cls, v: str, info: ValidationInfo) -> str: + """Check that numeric values are positive.""" + context = info.context + if context and context["is_infrastructure"]: + if v.strip() == "": + return v + try: + vf = float(v.strip()) + except ValueError: + raise ValueError("Must be a number.") from None + if not vf > 0: + raise ValueError("Must be a positive number.") + return v + + @field_validator("scheduler") + @classmethod + def nonemtpy_hpc_details(cls, v: str, info: ValidationInfo) -> str: + """Check that HPC infrastructure details are non-empty""" + context = info.context + if context and context["is_infrastructure"] and context["is_hpc"] and v.strip() == "": + raise ValueError("Cannot be left empty.") + return v + + @field_validator("scheduler") + @classmethod + def valid_scheduler(cls, v: str, info: ValidationInfo) -> str: + """Check that the HPC scheduler is supported""" + context = info.context + if context and context["is_infrastructure"] and context["is_hpc"] and v.strip() not in SUPPORTED_SCHEDULERS: + raise ValueError(f"Must be one of: {', '.join(SUPPORTED_SCHEDULERS)}") + return v + + @field_validator("cachedir", "scratch_dir") + @classmethod + def is_path_ondisk(cls, v: str, info: ValidationInfo) -> str: + """ + Check that a path looks valid. Does not check if it exists. + + Skip if field is empty. + + Accept: + - absolute paths (^/.+) + - env var prefixed paths (${INFRA_SPECIFIC_VAR}/..., ${HOME}/..., ${projectDir}) + - tilde-prefixed paths (~/...) + """ + v = v.strip() + if v == "": + return v # optional + + if not _PATH_PATTERN.match(v): + raise ValueError( + "Must be an absolute path (/data/scratch), " + "a path relative to home (~/scratch), " + "or a path with an environmental variable (e.g. ${DIR}/scratch)" + ) + return v + + @field_validator("igenomes_cachedir") + @classmethod + def is_path_or_uri(cls, v: str, info: ValidationInfo) -> str: + v = v.strip() + if v == "": + return v # optional + + uri_pattern = re.compile(r"^\w+:\/\/\w+") + if not _PATH_PATTERN.match(v) and not uri_pattern.match(v): + raise ValueError( + "Must be an absolute path with optional environmental variables " + "(e.g. /data/cache, ~/cache, ${DIR}/cache), " + "or a URI (e.g. s3://ngi-igenomes/igenomes/)" + ) + return v + + @field_validator("container_system") + @classmethod + def container_system_valid(cls, v: str, info: ValidationInfo) -> str: + v = v.strip() + if v != "" and v not in SUPPORTED_CONTAINERS: + raise ValueError(f"Must be one of: {', '.join(SUPPORTED_CONTAINERS)}") + return v + + @field_validator("queue_stat_interval") + @classmethod + def pos_hpc_interval_valid(cls, v: str, info: ValidationInfo) -> str: + """Check that HPC interval values are positive.""" + context = info.context + if context and context["is_infrastructure"] and context["is_hpc"]: + if v.strip() == "": + return v + try: + vf = float(v.strip()) + except ValueError: + raise ValueError("Must be a number.") from None + if not vf > 0: + raise ValueError("Must be a positive number.") + return v + + +## TODO Duplicated from pipelines utils - move to common location if possible (validation seems to be context specific so possibly not) +class TextInput(Static): + """Widget for text inputs. + + Provides standard interface for a text input with help text + and validation messages. + """ + + def __init__( + self, field_id, placeholder, description, default=None, password=None, suggestions=None, **kwargs + ) -> None: + """Initialise the widget with our values. + + Pass on kwargs upstream for standard usage.""" + super().__init__(**kwargs) + self.field_id: str = field_id + self.id: str = field_id + self.placeholder: str = placeholder + self.description: str = description + self.default: str = default + self.password: bool = password + self.suggestions: list[str] = suggestions or [] + + def compose(self) -> ComposeResult: + yield Grid( + Static(self.description, classes="field_help"), + Input( + placeholder=self.placeholder, + validators=[ValidateConfig(self.field_id)], + value=self.default, + password=self.password, + suggester=SuggestFromList(self.suggestions, case_sensitive=False), + ), + Static(classes="validation_msg"), + classes="text-input-grid", + ) + + @on(Input.Changed) + @on(Input.Submitted) + def show_invalid_reasons(self, event: Input.Changed | Input.Submitted) -> None: + """Validate the text input and show errors if invalid.""" + val_msg = self.query_one(".validation_msg") + if not isinstance(val_msg, Static): + raise ValueError("Validation message not found.") + + if event.validation_result is not None and not event.validation_result.is_valid: + # check that val_msg is instance of Static + if isinstance(val_msg, Static): + val_msg.update("\n".join(event.validation_result.failure_descriptions)) + else: + val_msg.update("") + + +## TODO Duplicated from pipelines utils - move to common location if possible (validation seems to be context specific so possibly not) +class ValidateConfig(Validator): + """Validate any config value, using Pydantic.""" + + def __init__(self, key) -> None: + """Initialise the validator with the model key to validate.""" + super().__init__() + self.key = key + + def validate(self, value: str) -> ValidationResult: + """Try creating a Pydantic object with this key set to this value. + + If it fails, return the error messages.""" + try: + with init_context( + { + "is_nfcore": NFCORE_CONFIG_GLOBAL, + "is_infrastructure": CONFIG_ISINFRASTRUCTURE_GLOBAL, + "is_hpc": INFRA_ISHPC_GLOBAL, + } + ): + ConfigsCreateConfig(**{f"{self.key}": value}) + return self.success() + except ValidationError as e: + return self.failure(", ".join([err["msg"] for err in e.errors()])) + + +def generate_config_entry(self, key, value): + parsed_entry = " " + key + ' = "' + value + '"\n' + return parsed_entry + + +class LoggingConsole(RichLog): + file = False + console: Widget + + def print(self, content): + self.write(content) + + +def add_hide_class(app, widget_id: str) -> None: + """Add class 'hide' to a widget. Not display widget.""" + app.get_widget_by_id(widget_id).add_class("hide") + + +def remove_hide_class(app, widget_id: str) -> None: + """Remove class 'hide' to a widget. Display widget.""" + app.get_widget_by_id(widget_id).remove_class("hide") diff --git a/nf_core/configs/create/welcome.py b/nf_core/configs/create/welcome.py new file mode 100644 index 0000000000..aae51efde3 --- /dev/null +++ b/nf_core/configs/create/welcome.py @@ -0,0 +1,43 @@ +"""Intro information to help inform user what we are about to do""" + +from textual.app import ComposeResult +from textual.containers import Center +from textual.screen import Screen +from textual.widgets import Button, Footer, Header, Markdown, Static + +from nf_core.utils import nfcore_logo + +markdown = """ +# Welcome to the nf-core config creation wizard + +This app will help you create **nf-core compatible** Nextflow configuration +files for both: + +- **Infrastructure** configs for defining computing environment for all + pipelines, and +- **Pipeline** configs for defining pipeline-specific resource requirements + +## Using Configs + +The resulting config file can be used with a pipeline with adding `-c +.conf` to a `nextflow run` command. + +They can also be added to the centralised +[nf-core/configs](https://github.com/nf-core/configs) repository, where they +can be used directly by anyone running nf-core pipelines on your infrastructure +specifying `nextflow run -profile `. +""" + + +class WelcomeScreen(Screen): + """A welcome screen for the app.""" + + def compose(self) -> ComposeResult: + yield Header() + yield Footer() + yield Static( + "\n" + "\n".join(nfcore_logo) + "\n", + id="logo", + ) + yield Markdown(markdown) + yield Center(Button("Let's go!", id="lets_go", variant="success"), classes="cta") diff --git a/tests/configs/__init__.py b/tests/configs/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/configs/__snapshots__/test_create_app/test_choose_infra_type.svg b/tests/configs/__snapshots__/test_create_app/test_choose_infra_type.svg new file mode 100644 index 0000000000..00b40ae41f --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_choose_infra_type.svg @@ -0,0 +1,272 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Is this configuration file part of the nf-core organisation? + + + +Choose "nf-core" if:Choose "Custom" if: + +Infrastructure configs:All configs: + +• You want to add the configuration file to• You want full control over all parameters or +the nf-core/configs repository.options in the config (including those that +are mandatory for nf-core). +Pipeline configs: +Infrastructure configs: +• The configuration file is for an nf-core +pipeline.• You will never add the configuration file to +the nf-core/configs repository. +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + nf-core Pipeline configs: +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ +• The configuration file is for a custom +pipeline which will never be part of +nf-core. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Custom  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +What's the difference? + +Choosing "nf-core" will make the following of the options mandatory: + +Infrastructure configs: + +• Providing the name and github handle of the author and contact person. +• Providing a description of the config. +• Providing the URL of the owning institution. +• Setting up resourceLimits to set the maximum resources. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + d Toggle dark mode  q Quit ^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_choose_pipe_type.svg b/tests/configs/__snapshots__/test_create_app/test_choose_pipe_type.svg new file mode 100644 index 0000000000..00b40ae41f --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_choose_pipe_type.svg @@ -0,0 +1,272 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Is this configuration file part of the nf-core organisation? + + + +Choose "nf-core" if:Choose "Custom" if: + +Infrastructure configs:All configs: + +• You want to add the configuration file to• You want full control over all parameters or +the nf-core/configs repository.options in the config (including those that +are mandatory for nf-core). +Pipeline configs: +Infrastructure configs: +• The configuration file is for an nf-core +pipeline.• You will never add the configuration file to +the nf-core/configs repository. +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + nf-core Pipeline configs: +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ +• The configuration file is for a custom +pipeline which will never be part of +nf-core. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Custom  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +What's the difference? + +Choosing "nf-core" will make the following of the options mandatory: + +Infrastructure configs: + +• Providing the name and github handle of the author and contact person. +• Providing a description of the config. +• Providing the URL of the owning institution. +• Setting up resourceLimits to set the maximum resources. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + d Toggle dark mode  q Quit ^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_choose_type.svg b/tests/configs/__snapshots__/test_create_app/test_choose_type.svg new file mode 100644 index 0000000000..0a7a032f0a --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_choose_type.svg @@ -0,0 +1,270 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Choose config type + + + +Choose "Infrastructure config" if:Choose "Pipeline config" if: + +• You want to only define the computational• You just want to tweak resources of a +environment you will run all pipelines on.particular step of a specific pipeline. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Infrastructure config  Pipeline config  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +What's the difference? + +Infrastructure configs: + +• Describe the basic necessary information for any nf-core pipeline to execute. +• Define things such as which container engine to use, if there is a scheduler and which queues +to use etc. +• Are suitable for all users on a given computing environment. +• Can be uploaded to nf-core configs to be directly accessible in a nf-core pipeline with +-profile <infrastructure_name>. +• Are not used to tweak specific parts of a given pipeline (such as a process or module). + +Pipeline configs + +• Are config files that target specific component of a particular pipeline or pipeline run. +▪ Example: you have a particular step of the pipeline that often runs out. of memory using the +pipeline's default settings. You would use this config to increase the amount of memory +Nextflow supplies that given task. +• Are normally only used by a single or small group of users. +• May also be shared amongst multiple users on the same computing environment if running similar +data with the same pipeline. +• Can sometimes be uploaded to nf-core configs as a 'pipeline-specific' config. + + + + + + + + + d Toggle dark mode  q Quit ^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_enter_pipe_custom_default_res.svg b/tests/configs/__snapshots__/test_create_app/test_enter_pipe_custom_default_res.svg new file mode 100644 index 0000000000..6c27d90418 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_enter_pipe_custom_default_res.svg @@ -0,0 +1,468 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Default process resources + + + +Number of CPUs to use by default for all processes. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +2                                                                                            +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Amount of memory in GB to use by default for all processes. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +8                                                                                            +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +The default number of hours of walltime required for processes: + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +9.5                                                                                          +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Skip  Next  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + d Toggle dark mode  q Quit ^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_enter_pipe_custom_labelled_proc_res.svg b/tests/configs/__snapshots__/test_create_app/test_enter_pipe_custom_labelled_proc_res.svg new file mode 100644 index 0000000000..0819d56990 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_enter_pipe_custom_labelled_proc_res.svg @@ -0,0 +1,472 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + Configure processes by label — Create a new nextflow config with an interactive i… + + +Configure processes by label + + + +Process label:#MemoryWalltiHPC queueRemove +CPUs:(GB):me(optional): +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +some_proc_label                 queue name -  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Process label:#MemoryWalltiHPC queueRemove +CPUs:(GB):me(optional): +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +another_label                   customqueue  -  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Process label:#MemoryWalltiHPC queueRemove +CPUs:(GB):me(optional): +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +a_third_label                   164queue name -  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Process label:#MemoryWalltiHPC queueRemove +CPUs:(GB):me(optional): +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +fourth_label                    6notherqueue -  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Add another process  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Skip  Next  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + +^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_enter_pipe_custom_named_proc_res.svg b/tests/configs/__snapshots__/test_create_app/test_enter_pipe_custom_named_proc_res.svg new file mode 100644 index 0000000000..f6dd589d1e --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_enter_pipe_custom_named_proc_res.svg @@ -0,0 +1,472 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + Configure processes by name — Create a new nextflow config with an interactive in… + + +Configure processes by name + + + +Process name:#MemoryWalltiHPC queueRemove +CPUs:(GB):me(optional): +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +some_proc                       queue name -  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Process name:#MemoryWalltiHPC queueRemove +CPUs:(GB):me(optional): +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +another_proc                    customqueue  -  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Add another process  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Skip  Next  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + d Toggle dark mode  q Quit ^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_enter_pipe_nfcore_default_res.svg b/tests/configs/__snapshots__/test_create_app/test_enter_pipe_nfcore_default_res.svg new file mode 100644 index 0000000000..6c27d90418 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_enter_pipe_nfcore_default_res.svg @@ -0,0 +1,468 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Default process resources + + + +Number of CPUs to use by default for all processes. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +2                                                                                            +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Amount of memory in GB to use by default for all processes. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +8                                                                                            +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +The default number of hours of walltime required for processes: + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +9.5                                                                                          +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Skip  Next  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + d Toggle dark mode  q Quit ^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_enter_pipe_nfcore_labelled_proc_res.svg b/tests/configs/__snapshots__/test_create_app/test_enter_pipe_nfcore_labelled_proc_res.svg new file mode 100644 index 0000000000..0819d56990 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_enter_pipe_nfcore_labelled_proc_res.svg @@ -0,0 +1,472 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + Configure processes by label — Create a new nextflow config with an interactive i… + + +Configure processes by label + + + +Process label:#MemoryWalltiHPC queueRemove +CPUs:(GB):me(optional): +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +some_proc_label                 queue name -  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Process label:#MemoryWalltiHPC queueRemove +CPUs:(GB):me(optional): +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +another_label                   customqueue  -  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Process label:#MemoryWalltiHPC queueRemove +CPUs:(GB):me(optional): +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +a_third_label                   164queue name -  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Process label:#MemoryWalltiHPC queueRemove +CPUs:(GB):me(optional): +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +fourth_label                    6notherqueue -  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Add another process  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Skip  Next  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + +^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_enter_pipe_nfcore_named_proc_res.svg b/tests/configs/__snapshots__/test_create_app/test_enter_pipe_nfcore_named_proc_res.svg new file mode 100644 index 0000000000..f5c611172f --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_enter_pipe_nfcore_named_proc_res.svg @@ -0,0 +1,472 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + Configure processes by name — Create a new nextflow config with an interactive in… + + +Configure processes by name + + + +Process name:#MemoryWalltiHPC queueRemove +CPUs:(GB):me(optional): +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +SOME:PROC.NAME*                 queue name -  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Process name:#MemoryWalltiHPC queueRemove +CPUs:(GB):me(optional): +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +ANOTHER:PROC_NAME               customqueue  -  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Add another process  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Skip  Next  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + d Toggle dark mode  q Quit ^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_entering_infra_custom_basic_details.svg b/tests/configs/__snapshots__/test_create_app/test_entering_infra_custom_basic_details.svg new file mode 100644 index 0000000000..a04066d1c3 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_entering_infra_custom_basic_details.svg @@ -0,0 +1,267 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Basic details + + + +Config Name. Used for naming resulting file. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +myconfig                                                                                     +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +A short description of your config. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +A cool description +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Next  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + + + + + +^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_entering_infra_custom_final_details_docker.svg b/tests/configs/__snapshots__/test_create_app/test_entering_infra_custom_final_details_docker.svg new file mode 100644 index 0000000000..841373cd77 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_entering_infra_custom_final_details_docker.svg @@ -0,0 +1,476 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Configure the options for your infrastructure config + +Select the container/software management system available on your infrastructure. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +docker +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +Set maximum available resources + +The following fields let you set the maximum available resrouces on your infrastructure. + +Memory, CPUs, and time must be filled out and all processes run with this configuration will be +capped at these values. + +The queue size, poll interval, and submit rate fields are optional, since Nextflow has built-in +defaults for these values. Consult the Nextflow documentation for further details on these +default values. + + + +Maximum memory (GB) availableMaximum number of CPUsMaximum time (hours) available +on your infrastructureavailable on yourto jobs on your infrastructure +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +128                      48                       9.5                        +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Maximum number of jobs thatHow often (in minutes) toMaximum number of jobs that +can be submittedcheck for successful processcan be submitted per minute +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +200                      0.25                     25                         +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Define global directories + +The following fields let you define global directories for a container/conda image cache, an +iGenomes cache, and a scratch directory in which to run your jobs. + +Each field is optional, but must contain the full (absolute) path to these directories if +specified. They may also contain references to environment variables (e.g. $CACHEDIR) and may +use the ~ symbol to refer to your home directory. + + + +If you have a global container/conda cache directory, specify the **full path** here. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +/path/to/cache/dir +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +If you want your jobs to run within a scratch directory, specify the full path here. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +/tmp/scratch                                                                                 +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔Clean up work directory +Select if you want to delete the files in the work/ directory on successful +▁▁▁▁▁▁▁▁completion of a run (prevents resume functionality). + + + +Specify the number of retries for a failed job. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +2 +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Finish  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + +^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_entering_infra_custom_final_details_singularity.svg b/tests/configs/__snapshots__/test_create_app/test_entering_infra_custom_final_details_singularity.svg new file mode 100644 index 0000000000..fffd03b168 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_entering_infra_custom_final_details_singularity.svg @@ -0,0 +1,475 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Configure the options for your infrastructure config + +Select the container/software management system available on your infrastructure. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +singularity +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +Set maximum available resources + +The following fields let you set the maximum available resrouces on your infrastructure. + +Memory, CPUs, and time must be filled out and all processes run with this configuration will be +capped at these values. + +The queue size, poll interval, and submit rate fields are optional, since Nextflow has built-in +defaults for these values. Consult the Nextflow documentation for further details on these +default values. + + + +Maximum memory (GB) availableMaximum number of CPUsMaximum time (hours) available +on your infrastructureavailable on yourto jobs on your infrastructure +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +128                      48                       9.5                        +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Maximum number of jobs thatHow often (in minutes) toMaximum number of jobs that +can be submittedcheck for successful processcan be submitted per minute +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +200                      0.25                     25                         +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Define global directories + +The following fields let you define global directories for a container/conda image cache, an +iGenomes cache, and a scratch directory in which to run your jobs. + +Each field is optional, but must contain the full (absolute) path to these directories if +specified. They may also contain references to environment variables (e.g. $CACHEDIR) and may +use the ~ symbol to refer to your home directory. + + + +If you have a global container/conda cache directory, specify the **full path** here. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +/singularity/cachedir                                                                        +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +If you want your jobs to run within a scratch directory, specify the full path here. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +/tmp/scratch                                                                                 +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔Clean up work directory +Select if you want to delete the files in the work/ directory on successful +▁▁▁▁▁▁▁▁completion of a run (prevents resume functionality). + + + +Specify the number of retries for a failed job. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +2 +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Finish  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + +^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_entering_infra_custom_hpc_details.svg b/tests/configs/__snapshots__/test_create_app/test_entering_infra_custom_hpc_details.svg new file mode 100644 index 0000000000..aa3cc3a1ba --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_entering_infra_custom_hpc_details.svg @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Configure the options for your HPC + +Use the following fields to provide important details about your HPC. + +First, select your HPC's scheduler. The program will attempt to automatically determine your +HPC's scheduler. If it was unsuccessful, you can select one of the supported schedulers from the +drop-down list. You can also select "Local execution" which will result in jobs defaulting to +run on the same node as Nextflow; this is generally not recommended. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +PBS Pro +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ +Next, supply your HPC's default queue, if required. Again, this will be auto-filled if possible. +You can leave this field blank if your HPC automatically submits jobs to a default queue when +not specified. + +For more complex queue selection (e.g. based on memory or CPU requirements), you will need to +manually edit the configuration file after completion. + +If you wish to submit different processes to different queues, you will need to additionally +create a pipeline configuration, which will let you specify alternative HPC queues for each +process. + + + +The default queue in your HPC (if required). + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +myqueue                                                                                      +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +How often to get the queue status from the scheduler (minutes). + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +0.75 +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Continue  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_entering_infra_final_details_docker.svg b/tests/configs/__snapshots__/test_create_app/test_entering_infra_final_details_docker.svg new file mode 100644 index 0000000000..74e9130fb8 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_entering_infra_final_details_docker.svg @@ -0,0 +1,476 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Configure the options for your infrastructure config + +Select the container/software management system available on your infrastructure. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +docker +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +Set maximum available resources + +The following fields let you set the maximum available resrouces on your infrastructure. + +Memory, CPUs, and time must be filled out and all processes run with this configuration will be +capped at these values. + +The queue size, poll interval, and submit rate fields are optional, since Nextflow has built-in +defaults for these values. Consult the Nextflow documentation for further details on these +default values. + + + +Maximum memory (GB) availableMaximum number of CPUsMaximum time (hours) available +on your infrastructureavailable on yourto jobs on your infrastructure +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +128                      48                       9.5                        +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Maximum number of jobs thatHow often (in minutes) toMaximum number of jobs that +can be submittedcheck for successful processcan be submitted per minute +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +200                      0.25                     25                         +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Define global directories + +The following fields let you define global directories for a container/conda image cache, an +iGenomes cache, and a scratch directory in which to run your jobs. + +Each field is optional, but must contain the full (absolute) path to these directories if +specified. They may also contain references to environment variables (e.g. $CACHEDIR) and may +use the ~ symbol to refer to your home directory. + + + +If you have a global container/conda cache directory, specify the **full path** here. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +/path/to/cache/dir +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +If you have an iGenomes cache directory, specify the **full path** here. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +/data/igenomes/cache                                                                         +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +If you want your jobs to run within a scratch directory, specify the full path here. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +/tmp/scratch                                                                                 +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔Clean up work directory +Select if you want to delete the files in the work/ directory on successful +▁▁▁▁▁▁▁▁completion of a run (prevents resume functionality). + + + +Specify the number of retries for a failed job. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +2 +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Finish  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_entering_infra_final_details_singularity.svg b/tests/configs/__snapshots__/test_create_app/test_entering_infra_final_details_singularity.svg new file mode 100644 index 0000000000..241571cf2b --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_entering_infra_final_details_singularity.svg @@ -0,0 +1,475 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Configure the options for your infrastructure config + +Select the container/software management system available on your infrastructure. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +singularity +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +Set maximum available resources + +The following fields let you set the maximum available resrouces on your infrastructure. + +Memory, CPUs, and time must be filled out and all processes run with this configuration will be +capped at these values. + +The queue size, poll interval, and submit rate fields are optional, since Nextflow has built-in +defaults for these values. Consult the Nextflow documentation for further details on these +default values. + + + +Maximum memory (GB) availableMaximum number of CPUsMaximum time (hours) available +on your infrastructureavailable on yourto jobs on your infrastructure +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +128                      48                       9.5                        +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Maximum number of jobs thatHow often (in minutes) toMaximum number of jobs that +can be submittedcheck for successful processcan be submitted per minute +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +200                      0.25                     25                         +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Define global directories + +The following fields let you define global directories for a container/conda image cache, an +iGenomes cache, and a scratch directory in which to run your jobs. + +Each field is optional, but must contain the full (absolute) path to these directories if +specified. They may also contain references to environment variables (e.g. $CACHEDIR) and may +use the ~ symbol to refer to your home directory. + + + +If you have a global container/conda cache directory, specify the **full path** here. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +/singularity/cachedir                                                                        +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +If you have an iGenomes cache directory, specify the **full path** here. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +/data/igenomes/cache                                                                         +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +If you want your jobs to run within a scratch directory, specify the full path here. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +/tmp/scratch                                                                                 +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔Clean up work directory +Select if you want to delete the files in the work/ directory on successful +▁▁▁▁▁▁▁▁completion of a run (prevents resume functionality). + + + +Specify the number of retries for a failed job. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +2 +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Finish  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_entering_infra_nfcore_basic_details.svg b/tests/configs/__snapshots__/test_create_app/test_entering_infra_nfcore_basic_details.svg new file mode 100644 index 0000000000..3f325136aa --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_entering_infra_nfcore_basic_details.svg @@ -0,0 +1,267 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Basic details + + + +Config Name. Used for naming resulting file. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +myconfig                                                                                     +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Author full name.Author Git(Hub) handle. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +my name                                   @myhandle                                  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +A short description of your config. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +A cool description                                                                           +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +URL of infrastructure website or owning institution (infrastructure configs only). + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +https://example.com +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Next  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + +^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_entering_infra_nfcore_hpc_details.svg b/tests/configs/__snapshots__/test_create_app/test_entering_infra_nfcore_hpc_details.svg new file mode 100644 index 0000000000..aa3cc3a1ba --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_entering_infra_nfcore_hpc_details.svg @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Configure the options for your HPC + +Use the following fields to provide important details about your HPC. + +First, select your HPC's scheduler. The program will attempt to automatically determine your +HPC's scheduler. If it was unsuccessful, you can select one of the supported schedulers from the +drop-down list. You can also select "Local execution" which will result in jobs defaulting to +run on the same node as Nextflow; this is generally not recommended. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +PBS Pro +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ +Next, supply your HPC's default queue, if required. Again, this will be auto-filled if possible. +You can leave this field blank if your HPC automatically submits jobs to a default queue when +not specified. + +For more complex queue selection (e.g. based on memory or CPU requirements), you will need to +manually edit the configuration file after completion. + +If you wish to submit different processes to different queues, you will need to additionally +create a pipeline configuration, which will let you specify alternative HPC queues for each +process. + + + +The default queue in your HPC (if required). + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +myqueue                                                                                      +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +How often to get the queue status from the scheduler (minutes). + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +0.75 +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Continue  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_entering_pipe_custom_basic_details.svg b/tests/configs/__snapshots__/test_create_app/test_entering_pipe_custom_basic_details.svg new file mode 100644 index 0000000000..a8fa593eab --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_entering_pipe_custom_basic_details.svg @@ -0,0 +1,267 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Basic details + + + +Config Name. Used for naming resulting file. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +myconfig                                                                                     +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +The path to the pipeline you want to create the config for. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +.                                                                                            +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +A short description of your config. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +A cool description +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Next  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + +^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_entering_pipe_nfcore_basic_details.svg b/tests/configs/__snapshots__/test_create_app/test_entering_pipe_nfcore_basic_details.svg new file mode 100644 index 0000000000..8bcba0fafd --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_entering_pipe_nfcore_basic_details.svg @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive inter… + + +Basic details + + + +Config Name. Used for naming resulting file. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +myconfig                                                                                   +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Author full name.Author Git(Hub) handle. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +my name                                  @myhandle                                 +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + +Pipeline name. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +scdownstream +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +A short description of your config. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +A cool description                                                                         +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +URL of infrastructure website or owning institution (infrastructure configs only). + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +https://example.com +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Next ▇▇ +^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_infra_custom_basic_details.svg b/tests/configs/__snapshots__/test_create_app/test_infra_custom_basic_details.svg new file mode 100644 index 0000000000..b14a4b6ead --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_infra_custom_basic_details.svg @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Basic details + + + +Config Name. Used for naming resulting file. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +custom +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +A short description of your config. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +Description +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Next  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + + + + + +^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_infra_nfcore_basic_details.svg b/tests/configs/__snapshots__/test_create_app/test_infra_nfcore_basic_details.svg new file mode 100644 index 0000000000..6666701dff --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_infra_nfcore_basic_details.svg @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Basic details + + + +Config Name. Used for naming resulting file. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +custom +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Author full name.Author Git(Hub) handle. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +Boaty McBoatFace@BoatyMcBoatFace +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +A short description of your config. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +Description +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +URL of infrastructure website or owning institution (infrastructure configs only). + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +https://nf-co.re +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Next  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + +^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_pipe_custom_basic_details.svg b/tests/configs/__snapshots__/test_create_app/test_pipe_custom_basic_details.svg new file mode 100644 index 0000000000..3613e08cec --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_pipe_custom_basic_details.svg @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Basic details + + + +Config Name. Used for naming resulting file. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +custom +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +The path to the pipeline you want to create the config for. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +Pipeline path +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +A short description of your config. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +Description +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Next  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + +^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_pipe_nfcore_basic_details.svg b/tests/configs/__snapshots__/test_create_app/test_pipe_nfcore_basic_details.svg new file mode 100644 index 0000000000..3e2f63c760 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_pipe_nfcore_basic_details.svg @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive inter… + + +Basic details + + + +Config Name. Used for naming resulting file. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +custom +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Author full name.Author Git(Hub) handle. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +Boaty McBoatFace@BoatyMcBoatFace +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + +Pipeline name. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +The name of the nf-core pipeline you want to configure +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +A short description of your config. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +Description +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +URL of infrastructure website or owning institution (infrastructure configs only). + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +https://nf-co.re +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Next ▇▇ +^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_setting_pipe_custom_options.svg b/tests/configs/__snapshots__/test_create_app/test_setting_pipe_custom_options.svg new file mode 100644 index 0000000000..c23b249f27 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_setting_pipe_custom_options.svg @@ -0,0 +1,473 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +What would you like to configure? + +Configure default process resources?▔▔▔▔▔▔▔▔Yes + +▁▁▁▁▁▁▁▁ +Configure specific named processes?▔▔▔▔▔▔▔▔Yes + +▁▁▁▁▁▁▁▁ +Configure labels?▔▔▔▔▔▔▔▔Yes + +▁▁▁▁▁▁▁▁ + + +Will you be using this configuration exclusively on an HPC? + + +Choose "Yes" if: + +You are configuring processes specifically for running on an HPC. + + +Choose "No" if: + +This config file will be used across different platforms. + + +What's the difference? + +Choosing "Yes" will allow you to additionally specify an HPC queue for each process or label. +Note that this field can be left blank to use the default queue. + +Configure HPC-specific resources?▔▔▔▔▔▔▔▔Yes + +▁▁▁▁▁▁▁▁ +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Next  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + d Toggle dark mode  q Quit ^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_setting_pipe_nfcore_options.svg b/tests/configs/__snapshots__/test_create_app/test_setting_pipe_nfcore_options.svg new file mode 100644 index 0000000000..c23b249f27 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_setting_pipe_nfcore_options.svg @@ -0,0 +1,473 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +What would you like to configure? + +Configure default process resources?▔▔▔▔▔▔▔▔Yes + +▁▁▁▁▁▁▁▁ +Configure specific named processes?▔▔▔▔▔▔▔▔Yes + +▁▁▁▁▁▁▁▁ +Configure labels?▔▔▔▔▔▔▔▔Yes + +▁▁▁▁▁▁▁▁ + + +Will you be using this configuration exclusively on an HPC? + + +Choose "Yes" if: + +You are configuring processes specifically for running on an HPC. + + +Choose "No" if: + +This config file will be used across different platforms. + + +What's the difference? + +Choosing "Yes" will allow you to additionally specify an HPC queue for each process or label. +Note that this field can be left blank to use the default queue. + +Configure HPC-specific resources?▔▔▔▔▔▔▔▔Yes + +▁▁▁▁▁▁▁▁ +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Next  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + d Toggle dark mode  q Quit ^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_submit_pipe_custom_default_res.svg b/tests/configs/__snapshots__/test_create_app/test_submit_pipe_custom_default_res.svg new file mode 100644 index 0000000000..bef311f2e9 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_submit_pipe_custom_default_res.svg @@ -0,0 +1,472 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + Configure processes by name — Create a new nextflow config with an interactive in… + + +Configure processes by name + + + +Process name:#MemoryWalltiHPC queueRemove +CPUs:(GB):me(optional): +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +queue name -  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Process name:#MemoryWalltiHPC queueRemove +CPUs:(GB):me(optional): +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +queue name -  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Process name:#MemoryWalltiHPC queueRemove +CPUs:(GB):me(optional): +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +queue name -  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Add another process  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Skip  Next  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + d Toggle dark mode  q Quit ^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_submit_pipe_custom_labelled_proc_res.svg b/tests/configs/__snapshots__/test_create_app/test_submit_pipe_custom_labelled_proc_res.svg new file mode 100644 index 0000000000..31f6e8e3f0 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_submit_pipe_custom_labelled_proc_res.svg @@ -0,0 +1,467 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Final step + + + +In which directory would you like to save the config? + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +. +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Save and close!  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_submit_pipe_custom_named_proc_res.svg b/tests/configs/__snapshots__/test_create_app/test_submit_pipe_custom_named_proc_res.svg new file mode 100644 index 0000000000..949a6e2262 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_submit_pipe_custom_named_proc_res.svg @@ -0,0 +1,472 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + Configure processes by label — Create a new nextflow config with an interactive i… + + +Configure processes by label + + + +Process label:#MemoryWalltiHPC queueRemove +CPUs:(GB):me(optional): +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +queue name -  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Process label:#MemoryWalltiHPC queueRemove +CPUs:(GB):me(optional): +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +queue name -  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Process label:#MemoryWalltiHPC queueRemove +CPUs:(GB):me(optional): +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +queue name -  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Add another process  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Skip  Next  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + d Toggle dark mode  q Quit ^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_submit_pipe_nfcore_default_res.svg b/tests/configs/__snapshots__/test_create_app/test_submit_pipe_nfcore_default_res.svg new file mode 100644 index 0000000000..bef311f2e9 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_submit_pipe_nfcore_default_res.svg @@ -0,0 +1,472 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + Configure processes by name — Create a new nextflow config with an interactive in… + + +Configure processes by name + + + +Process name:#MemoryWalltiHPC queueRemove +CPUs:(GB):me(optional): +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +queue name -  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Process name:#MemoryWalltiHPC queueRemove +CPUs:(GB):me(optional): +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +queue name -  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Process name:#MemoryWalltiHPC queueRemove +CPUs:(GB):me(optional): +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +queue name -  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Add another process  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Skip  Next  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + d Toggle dark mode  q Quit ^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_submit_pipe_nfcore_labelled_proc_res.svg b/tests/configs/__snapshots__/test_create_app/test_submit_pipe_nfcore_labelled_proc_res.svg new file mode 100644 index 0000000000..31f6e8e3f0 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_submit_pipe_nfcore_labelled_proc_res.svg @@ -0,0 +1,467 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Final step + + + +In which directory would you like to save the config? + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +. +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Save and close!  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_submit_pipe_nfcore_named_proc_res.svg b/tests/configs/__snapshots__/test_create_app/test_submit_pipe_nfcore_named_proc_res.svg new file mode 100644 index 0000000000..949a6e2262 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_submit_pipe_nfcore_named_proc_res.svg @@ -0,0 +1,472 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + Configure processes by label — Create a new nextflow config with an interactive i… + + +Configure processes by label + + + +Process label:#MemoryWalltiHPC queueRemove +CPUs:(GB):me(optional): +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +queue name -  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Process label:#MemoryWalltiHPC queueRemove +CPUs:(GB):me(optional): +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +queue name -  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Process label:#MemoryWalltiHPC queueRemove +CPUs:(GB):me(optional): +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +queue name -  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Add another process  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Skip  Next  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + d Toggle dark mode  q Quit ^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_submitting_infra_custom_basic_details.svg b/tests/configs/__snapshots__/test_create_app/test_submitting_infra_custom_basic_details.svg new file mode 100644 index 0000000000..eb77da4744 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_submitting_infra_custom_basic_details.svg @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Is this configuration file for an HPC config? + + + +Choose "HPC" if:Choose "local" if: + +You want to create a config file for an HPC.You want to create a config file to run your +pipeline on a local computer. +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + HPC ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ local  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +What's the difference? + +Choosing "HPC" will add the following configurations: + +• Provide a scheduler +• Provide the name of a queue +• Select if a module system is used +• Select if you need to load other modules + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + d Toggle dark mode  q Quit ^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_submitting_infra_custom_final_details_singularity.svg b/tests/configs/__snapshots__/test_create_app/test_submitting_infra_custom_final_details_singularity.svg new file mode 100644 index 0000000000..31f6e8e3f0 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_submitting_infra_custom_final_details_singularity.svg @@ -0,0 +1,467 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Final step + + + +In which directory would you like to save the config? + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +. +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Save and close!  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_submitting_infra_custom_hpc_details.svg b/tests/configs/__snapshots__/test_create_app/test_submitting_infra_custom_hpc_details.svg new file mode 100644 index 0000000000..99bb662059 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_submitting_infra_custom_hpc_details.svg @@ -0,0 +1,477 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Configure the options for your infrastructure config + +Select the container/software management system available on your infrastructure. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +singularity +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +Set maximum available resources + +The following fields let you set the maximum available resrouces on your infrastructure. + +Memory, CPUs, and time must be filled out and all processes run with this configuration will be +capped at these values. + +The queue size, poll interval, and submit rate fields are optional, since Nextflow has built-in +defaults for these values. Consult the Nextflow documentation for further details on these +default values. + + + +Maximum memory (GB) availableMaximum number of CPUsMaximum time (hours) available +on your infrastructureavailable on yourto jobs on your infrastructure +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +MemoryCPUsTime +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Maximum number of jobs thatHow often (in minutes) toMaximum number of jobs that +can be submittedcheck for successful processcan be submitted per minute +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +Queue sizePoll intervalJobs per minutes +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Define global directories + +The following fields let you define global directories for a container/conda image cache, an +iGenomes cache, and a scratch directory in which to run your jobs. + +Each field is optional, but must contain the full (absolute) path to these directories if +specified. They may also contain references to environment variables (e.g. $CACHEDIR) and may +use the ~ symbol to refer to your home directory. + + + +If you have a global container/conda cache directory, specify the **full path** here. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +/path/to/cache/dir +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +If you want your jobs to run within a scratch directory, specify the full path here. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +Scratch directory +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔Clean up work directory +Select if you want to delete the files in the work/ directory on successful +▁▁▁▁▁▁▁▁completion of a run (prevents resume functionality). + + + +Specify the number of retries for a failed job. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +1                                                                                            +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Finish  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + d Toggle dark mode  q Quit ^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_submitting_infra_final_details_singularity.svg b/tests/configs/__snapshots__/test_create_app/test_submitting_infra_final_details_singularity.svg new file mode 100644 index 0000000000..31f6e8e3f0 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_submitting_infra_final_details_singularity.svg @@ -0,0 +1,467 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Final step + + + +In which directory would you like to save the config? + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +. +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Save and close!  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_submitting_infra_nfcore_basic_details.svg b/tests/configs/__snapshots__/test_create_app/test_submitting_infra_nfcore_basic_details.svg new file mode 100644 index 0000000000..eb77da4744 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_submitting_infra_nfcore_basic_details.svg @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Is this configuration file for an HPC config? + + + +Choose "HPC" if:Choose "local" if: + +You want to create a config file for an HPC.You want to create a config file to run your +pipeline on a local computer. +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + HPC ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ local  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +What's the difference? + +Choosing "HPC" will add the following configurations: + +• Provide a scheduler +• Provide the name of a queue +• Select if a module system is used +• Select if you need to load other modules + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + d Toggle dark mode  q Quit ^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_submitting_infra_nfcore_hpc_details.svg b/tests/configs/__snapshots__/test_create_app/test_submitting_infra_nfcore_hpc_details.svg new file mode 100644 index 0000000000..28e4c03270 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_submitting_infra_nfcore_hpc_details.svg @@ -0,0 +1,477 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Configure the options for your infrastructure config + +Select the container/software management system available on your infrastructure. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +singularity +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +Set maximum available resources + +The following fields let you set the maximum available resrouces on your infrastructure. + +Memory, CPUs, and time must be filled out and all processes run with this configuration will be +capped at these values. + +The queue size, poll interval, and submit rate fields are optional, since Nextflow has built-in +defaults for these values. Consult the Nextflow documentation for further details on these +default values. + + + +Maximum memory (GB) availableMaximum number of CPUsMaximum time (hours) available +on your infrastructureavailable on yourto jobs on your infrastructure +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +MemoryCPUsTime +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Maximum number of jobs thatHow often (in minutes) toMaximum number of jobs that +can be submittedcheck for successful processcan be submitted per minute +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +Queue sizePoll intervalJobs per minutes +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Define global directories + +The following fields let you define global directories for a container/conda image cache, an +iGenomes cache, and a scratch directory in which to run your jobs. + +Each field is optional, but must contain the full (absolute) path to these directories if +specified. They may also contain references to environment variables (e.g. $CACHEDIR) and may +use the ~ symbol to refer to your home directory. + + + +If you have a global container/conda cache directory, specify the **full path** here. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +/path/to/cache/dir +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +If you have an iGenomes cache directory, specify the **full path** here. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +iGenomes cache directory +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +If you want your jobs to run within a scratch directory, specify the full path here. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +Scratch directory +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔Clean up work directory +Select if you want to delete the files in the work/ directory on successful +▁▁▁▁▁▁▁▁completion of a run (prevents resume functionality). + + + +Specify the number of retries for a failed job. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +1                                                                                            +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Finish  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + d Toggle dark mode  q Quit ^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_submitting_pipe_custom_basic_details.svg b/tests/configs/__snapshots__/test_create_app/test_submitting_pipe_custom_basic_details.svg new file mode 100644 index 0000000000..63231d430b --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_submitting_pipe_custom_basic_details.svg @@ -0,0 +1,273 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +What would you like to configure? + +Configure default process resources?▔▔▔▔▔▔▔▔No + +▁▁▁▁▁▁▁▁ +Configure specific named processes?▔▔▔▔▔▔▔▔No + +▁▁▁▁▁▁▁▁ +Configure labels?▔▔▔▔▔▔▔▔No + +▁▁▁▁▁▁▁▁ + + +Will you be using this configuration exclusively on an HPC? + + +Choose "Yes" if: + +You are configuring processes specifically for running on an HPC. + + +Choose "No" if: + +This config file will be used across different platforms. + + +What's the difference? + +Choosing "Yes" will allow you to additionally specify an HPC queue for each process or label. +Note that this field can be left blank to use the default queue. + +Configure HPC-specific resources?▔▔▔▔▔▔▔▔No + +▁▁▁▁▁▁▁▁ +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Next  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + d Toggle dark mode  q Quit ^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_submitting_pipe_custom_options.svg b/tests/configs/__snapshots__/test_create_app/test_submitting_pipe_custom_options.svg new file mode 100644 index 0000000000..1ddf877396 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_submitting_pipe_custom_options.svg @@ -0,0 +1,467 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Default process resources + + + +Number of CPUs to use by default for all processes. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +1 +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Amount of memory in GB to use by default for all processes. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +6                                                                                            +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +The default number of hours of walltime required for processes: + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +4                                                                                            +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Skip  Next  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_submitting_pipe_nfcore_basic_details.svg b/tests/configs/__snapshots__/test_create_app/test_submitting_pipe_nfcore_basic_details.svg new file mode 100644 index 0000000000..63231d430b --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_submitting_pipe_nfcore_basic_details.svg @@ -0,0 +1,273 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +What would you like to configure? + +Configure default process resources?▔▔▔▔▔▔▔▔No + +▁▁▁▁▁▁▁▁ +Configure specific named processes?▔▔▔▔▔▔▔▔No + +▁▁▁▁▁▁▁▁ +Configure labels?▔▔▔▔▔▔▔▔No + +▁▁▁▁▁▁▁▁ + + +Will you be using this configuration exclusively on an HPC? + + +Choose "Yes" if: + +You are configuring processes specifically for running on an HPC. + + +Choose "No" if: + +This config file will be used across different platforms. + + +What's the difference? + +Choosing "Yes" will allow you to additionally specify an HPC queue for each process or label. +Note that this field can be left blank to use the default queue. + +Configure HPC-specific resources?▔▔▔▔▔▔▔▔No + +▁▁▁▁▁▁▁▁ +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Next  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + d Toggle dark mode  q Quit ^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_submitting_pipe_nfcore_options.svg b/tests/configs/__snapshots__/test_create_app/test_submitting_pipe_nfcore_options.svg new file mode 100644 index 0000000000..1ddf877396 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_submitting_pipe_nfcore_options.svg @@ -0,0 +1,467 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + + +Default process resources + + + +Number of CPUs to use by default for all processes. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +1 +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +Amount of memory in GB to use by default for all processes. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +6                                                                                            +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + +The default number of hours of walltime required for processes: + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +4                                                                                            +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Back  Skip  Next  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +^p palette + + + diff --git a/tests/configs/__snapshots__/test_create_app/test_welcome.svg b/tests/configs/__snapshots__/test_create_app/test_welcome.svg new file mode 100644 index 0000000000..a00c894198 --- /dev/null +++ b/tests/configs/__snapshots__/test_create_app/test_welcome.svg @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nf-core configs create + + + + + + + + + + nf-core configs create — Create a new nextflow config with an interactive interfa… + +                                          ,--./,-. +          ___     __   __   __   ___     /,-._.--~\  +    |\ | |__  __ /  ` /  \ |__) |__         }  { +    | \| |       \__, \__/ |  \ |___     \`-._,-`-, +                                          `._,._,' + + + +Welcome to the nf-core config creation wizard + +This app will help you create Nextflow configuration files for both: + +• Infrastructure configs for defining computing environment for all pipelines, and +• Pipeline configs for defining pipeline-specific resource requirements + + +Using Configs + +The resulting config file can be used with a pipeline with adding -c <filename>.conf to a +nextflow run command. + +They can also be added to the centralised nf-core/configs repository, where they can be used +directly by anyone running nf-core pipelines on your infrastructure specifying nextflow run +-profile <configname>. + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Let's go!  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + + + + d Toggle dark mode  q Quit ^p palette + + + diff --git a/tests/configs/test_create_app.py b/tests/configs/test_create_app.py new file mode 100644 index 0000000000..6f6e6d39f2 --- /dev/null +++ b/tests/configs/test_create_app.py @@ -0,0 +1,1521 @@ +"""Test Config Create App""" + +from pathlib import Path +from tempfile import TemporaryDirectory + +from nf_core.configs.create import ConfigsCreateApp +from nf_core.configs.create.utils import SUPPORTED_CONTAINERS + +from ..test_configs import ( + INFRA_CUSTOM_SINGULARITY_CONFIG, + INFRA_SINGULARITY_CONFIG, + PIPE_CUSTOM_CONFIG, + PIPE_NFCORE_CONFIG, +) + +INIT_FILE = "../../nf_core/configs/create/__init__.py" + + +async def test_app_bindings(): + """Test that the app bindings work.""" + app = ConfigsCreateApp() + async with app.run_test() as pilot: + # Test pressing the D key + assert app.theme == "textual-dark" + await pilot.press("d") + assert app.theme == "textual-light" + await pilot.press("d") + assert app.theme == "textual-dark" + + # Test pressing the Q key + await pilot.press("q") + assert app.return_code == 0 + + +def test_welcome(snap_compare): + """Test snapshot for the first screen in the app. The welcome screen.""" + assert snap_compare(INIT_FILE, terminal_size=(100, 50)) + + +async def click_lets_go(pilot) -> None: + await pilot.click("#lets_go") + + +def test_choose_type(snap_compare): + """Test snapshot for the choose_type screen. + Steps to get to this screen: + screen welcome > press Let's go! > + screen choose_type + """ + + async def run_before(pilot) -> None: + await click_lets_go(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 50), run_before=run_before) + + +async def click_type_infrastructure(pilot) -> None: + await click_lets_go(pilot) + await pilot.click("#type_infrastructure") + + +def test_choose_infra_type(snap_compare): + """Test snapshot for the nfcore_question screen + via the Infrastructure config option. + Steps to get to this screen: + screen welcome > press Let's go! > + press Infrastructure config > + screen choose_type + """ + + async def run_before(pilot) -> None: + await click_type_infrastructure(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 50), run_before=run_before) + + +async def click_infra_nfcore(pilot) -> None: + await click_type_infrastructure(pilot) + await pilot.click("#type_nfcore") + + +def test_infra_nfcore_basic_details(snap_compare): + """Test snapshot for the nf-core basic_details screen + when configuring an infrastructure config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Infrastructure config > + press nf-core > + screen basic_details + """ + + async def run_before(pilot) -> None: + await click_infra_nfcore(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 50), run_before=run_before) + + +async def enter_infra_nfcore_basic_details(pilot) -> None: + await click_infra_nfcore(pilot) + await pilot.click("#general_config_name") + await pilot.press(*list("myconfig")) + await pilot.press("tab") + await pilot.press(*list("my name")) + await pilot.press("tab") + await pilot.press(*list("@myhandle")) + await pilot.press("tab") + await pilot.press(*list("A cool description")) + await pilot.press("tab") + await pilot.press(*list("https://example.com")) + + +async def submit_infra_nfcore_basic_details(pilot) -> None: + await enter_infra_nfcore_basic_details(pilot) + await pilot.click("#next") + + +def test_entering_infra_nfcore_basic_details(snap_compare): + """Test snapshot for the entering basic details + on the nf-core basic_details screen + when configuring an infrastructure config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Infrastructure config > + press nf-core > + screen basic_details + """ + + async def run_before(pilot) -> None: + await enter_infra_nfcore_basic_details(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 50), run_before=run_before) + + +def test_submitting_infra_nfcore_basic_details(snap_compare): + """Test snapshot for the entering basic details + on the nf-core basic_details screen + when configuring an infrastructure config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Infrastructure config > + press nf-core > + enter basic details > + click Next > + screen hpc_question + """ + + async def run_before(pilot) -> None: + await submit_infra_nfcore_basic_details(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 50), run_before=run_before) + + +async def enter_infra_nfcore_hpc_details(pilot) -> None: + await submit_infra_nfcore_basic_details(pilot) + await pilot.click("#type_hpc") + # Activate the drop-down and select the PBS Pro entry + await pilot.click("#scheduler") + await pilot.press(*list("PBS Pro")) + await pilot.press("enter") + await pilot.press("tab") + await pilot.press(*list("myqueue")) + await pilot.press("tab") + await pilot.press(*list("0.75")) + + +async def submit_infra_nfcore_hpc_details(pilot) -> None: + await enter_infra_nfcore_hpc_details(pilot) + await pilot.click("#toconfiguration") + + +def test_entering_infra_nfcore_hpc_details(snap_compare): + """Test snapshot for entering HPC details + when configuring an infrastructure config + for use with nf-core. + Steps to get to this screen: + screen welcome > press Let's go! > + press Infrastructure config > + press nf-core > + enter basic details > + click Next > + click HPC > + enter HPC details + """ + + async def run_before(pilot) -> None: + await enter_infra_nfcore_hpc_details(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 50), run_before=run_before) + + +def test_submitting_infra_nfcore_hpc_details(snap_compare): + """Test snapshot for entering HPC details + when configuring an infrastructure config + for use with nf-core. + Steps to get to this screen: + screen welcome > press Let's go! > + press Infrastructure config > + press nf-core > + enter basic details > + click Next > + click HPC > + enter HPC details > + click Continue > + screen final_infra_details + """ + + async def run_before(pilot) -> None: + await submit_infra_nfcore_hpc_details(pilot) + # Select singularity from the drop down to ensure consistency + await pilot.click("#container_system") + await pilot.press(*list("singularity")) + await pilot.press("enter") + + assert snap_compare(INIT_FILE, terminal_size=(100, 100), run_before=run_before) + + +def enter_infra_final_details(container): + assert container in SUPPORTED_CONTAINERS + + async def _enter_infra_final_details(pilot) -> None: + await submit_infra_nfcore_hpc_details(pilot) + await pilot.click("#container_system") + await pilot.press(*list(container)) + await pilot.press("enter") + await pilot.press("tab") + await pilot.press(*list("128")) + await pilot.press("tab") + await pilot.press(*list("48")) + await pilot.press("tab") + await pilot.press(*list("9.5")) + await pilot.press("tab") + await pilot.press(*list("200")) + await pilot.press("tab") + await pilot.press(*list("0.25")) + await pilot.press("tab") + await pilot.press(*list("25")) + await pilot.press("tab") + if container in ["singularity", "charliecloud", "apptainer", "conda"]: + await pilot.press(*list(f"/{container}/cachedir")) + await pilot.press("tab") + await pilot.press(*list("/data/igenomes/cache")) + await pilot.press("tab") + await pilot.press(*list("/tmp/scratch")) + await pilot.press("tab") + await pilot.press("enter") + await pilot.press("tab") + await pilot.press(*list("2")) + + return _enter_infra_final_details + + +def submit_infra_final_details(container): + async def _submit_infra_final_details(pilot) -> None: + await enter_infra_final_details(container)(pilot) + await pilot.click("#finish") + + return _submit_infra_final_details + + +def write_infra_details(container, outdir="."): + assert isinstance(outdir, str) + assert Path(outdir).is_dir() + + async def _write_infra_details(pilot) -> None: + await submit_infra_final_details(container)(pilot) + await pilot.click("#savelocation") + await pilot.press(*list(outdir)) + await pilot.click("#close_app") + + return _write_infra_details + + +def test_entering_infra_final_details_docker(snap_compare): + """Test snapshot for entering HPC details + when configuring an infrastructure config + for use with nf-core. + Steps to get to this screen: + screen welcome > press Let's go! > + press Infrastructure config > + press nf-core > + enter basic details > + click Next > + click HPC > + enter HPC details > + click Continue > + screen final_infra_details + """ + + async def run_before(pilot) -> None: + await enter_infra_final_details("docker")(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 100), run_before=run_before) + + +def test_entering_infra_final_details_singularity(snap_compare): + """Test snapshot for entering HPC details + when configuring an infrastructure config + for use with nf-core. + Steps to get to this screen: + screen welcome > press Let's go! > + press Infrastructure config > + press nf-core > + enter basic details > + click Next > + click HPC > + enter HPC details > + click Continue > + screen final_infra_details + """ + + async def run_before(pilot) -> None: + await enter_infra_final_details("singularity")(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 100), run_before=run_before) + + +def test_submitting_infra_final_details_singularity(snap_compare): + """Test snapshot for entering HPC details + when configuring an infrastructure config + for use with nf-core. + Steps to get to this screen: + screen welcome > press Let's go! > + press Infrastructure config > + press nf-core > + enter basic details > + click Next > + click HPC > + enter HPC details > + click Continue > + click Finish > + screen final + """ + + async def run_before(pilot) -> None: + await submit_infra_final_details("singularity")(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 100), run_before=run_before) + + +async def test_writing_infra_details_singularity(): + """Test snapshot for entering HPC details + when configuring an infrastructure config + for use with nf-core. + Steps to get to this screen: + screen welcome > press Let's go! > + press Infrastructure config > + press nf-core > + enter basic details > + click Next > + click HPC > + enter HPC details > + click Continue > + click Finish > + click Save and close! + """ + + app = ConfigsCreateApp() + async with app.run_test(size=(100, 100)) as pilot: + # Make a temporary directory to store the output + tmpdir = TemporaryDirectory() + + await write_infra_details("singularity", outdir=tmpdir.name)(pilot) + + config_file = Path(tmpdir.name) / "myconfig.conf" + with open(config_file) as f: + config = f.read() + assert config == INFRA_SINGULARITY_CONFIG + tmpdir.cleanup() + + +async def click_infra_custom(pilot) -> None: + await click_type_infrastructure(pilot) + await pilot.click("#type_custom") + + +def test_infra_custom_basic_details(snap_compare): + """Test snapshot for the custom pipeline basic_details screen + when configuring an infrastructure config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Infrastructure config > + press Custom > + screen basic_details + """ + + async def run_before(pilot) -> None: + await click_infra_custom(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 50), run_before=run_before) + + +async def enter_infra_custom_basic_details(pilot) -> None: + await click_infra_custom(pilot) + await pilot.click("#general_config_name") + await pilot.press(*list("myconfig")) + await pilot.press("tab") + await pilot.press(*list("A cool description")) + + +async def submit_infra_custom_basic_details(pilot) -> None: + await enter_infra_custom_basic_details(pilot) + await pilot.click("#next") + + +def test_entering_infra_custom_basic_details(snap_compare): + """Test snapshot for the entering basic details + on the custom basic_details screen + when configuring an infrastructure config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Infrastructure config > + press custom > + screen basic_details + """ + + async def run_before(pilot) -> None: + await enter_infra_custom_basic_details(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 50), run_before=run_before) + + +def test_submitting_infra_custom_basic_details(snap_compare): + """Test snapshot for the entering basic details + on the custom basic_details screen + when configuring an infrastructure config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Infrastructure config > + press custom > + enter basic details > + click Next > + screen hpc_question + """ + + async def run_before(pilot) -> None: + await submit_infra_custom_basic_details(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 50), run_before=run_before) + + +async def enter_infra_custom_hpc_details(pilot) -> None: + await submit_infra_custom_basic_details(pilot) + await pilot.click("#type_hpc") + # Activate the drop-down and select the PBS Pro entry + await pilot.click("#scheduler") + await pilot.press(*list("PBS Pro")) + await pilot.press("enter") + await pilot.press("tab") + await pilot.press(*list("myqueue")) + await pilot.press("tab") + await pilot.press(*list("0.75")) + + +async def submit_infra_custom_hpc_details(pilot) -> None: + await enter_infra_custom_hpc_details(pilot) + await pilot.click("#toconfiguration") + + +def test_entering_infra_custom_hpc_details(snap_compare): + """Test snapshot for entering HPC details + when configuring a custom infrastructure config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Infrastructure config > + press custom > + enter basic details > + click Next > + click HPC > + enter HPC details + """ + + async def run_before(pilot) -> None: + await enter_infra_custom_hpc_details(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 50), run_before=run_before) + + +def test_submitting_infra_custom_hpc_details(snap_compare): + """Test snapshot for entering HPC details + when configuring a custom infrastructure config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Infrastructure config > + press custom > + enter basic details > + click Next > + click HPC > + enter HPC details > + click Continue > + screen final_infra_details + """ + + async def run_before(pilot) -> None: + await submit_infra_custom_hpc_details(pilot) + # Select singularity from the drop down to ensure consistency + await pilot.click("#container_system") + await pilot.press(*list("singularity")) + await pilot.press("enter") + + assert snap_compare(INIT_FILE, terminal_size=(100, 100), run_before=run_before) + + +def enter_infra_custom_final_details(container): + assert container in SUPPORTED_CONTAINERS + + async def _enter_infra_custom_final_details(pilot) -> None: + await submit_infra_custom_hpc_details(pilot) + await pilot.click("#container_system") + await pilot.press(*list(container)) + await pilot.press("enter") + await pilot.press("tab") + await pilot.press(*list("128")) + await pilot.press("tab") + await pilot.press(*list("48")) + await pilot.press("tab") + await pilot.press(*list("9.5")) + await pilot.press("tab") + await pilot.press(*list("200")) + await pilot.press("tab") + await pilot.press(*list("0.25")) + await pilot.press("tab") + await pilot.press(*list("25")) + await pilot.press("tab") + if container in ["singularity", "charliecloud", "apptainer", "conda"]: + await pilot.press(*list(f"/{container}/cachedir")) + await pilot.press("tab") + await pilot.press(*list("/tmp/scratch")) + await pilot.press("tab") + await pilot.press("enter") + await pilot.press("tab") + await pilot.press(*list("2")) + + return _enter_infra_custom_final_details + + +def submit_infra_custom_final_details(container): + async def _submit_infra_custom_final_details(pilot) -> None: + await enter_infra_custom_final_details(container)(pilot) + await pilot.click("#finish") + + return _submit_infra_custom_final_details + + +def write_infra_custom_details(container, outdir="."): + assert isinstance(outdir, str) + assert Path(outdir).is_dir() + + async def _write_infra_custom_details(pilot) -> None: + await submit_infra_custom_final_details(container)(pilot) + await pilot.click("#savelocation") + await pilot.press(*list(outdir)) + await pilot.click("#close_app") + + return _write_infra_custom_details + + +def test_entering_infra_custom_final_details_docker(snap_compare): + """Test snapshot for entering HPC details + when configuring a custom infrastructure config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Infrastructure config > + press custom > + enter basic details > + click Next > + click HPC > + enter HPC details > + click Continue > + screen final_infra_details + """ + + async def run_before(pilot) -> None: + await enter_infra_custom_final_details("docker")(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 100), run_before=run_before) + + +def test_entering_infra_custom_final_details_singularity(snap_compare): + """Test snapshot for entering HPC details + when configuring a custom infrastructure config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Infrastructure config > + press custom > + enter basic details > + click Next > + click HPC > + enter HPC details > + click Continue > + screen final_infra_details + """ + + async def run_before(pilot) -> None: + await enter_infra_custom_final_details("singularity")(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 100), run_before=run_before) + + +def test_submitting_infra_custom_final_details_singularity(snap_compare): + """Test snapshot for entering HPC details + when configuring a custom infrastructure config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Infrastructure config > + press custom > + enter basic details > + click Next > + click HPC > + enter HPC details > + click Continue > + click Finish > + screen final + """ + + async def run_before(pilot) -> None: + await submit_infra_custom_final_details("singularity")(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 100), run_before=run_before) + + +async def test_writing_infra_custom_details_singularity(): + """Test snapshot for entering HPC details + when configuring a custom infrastructure config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Infrastructure config > + press custom > + enter basic details > + click Next > + click HPC > + enter HPC details > + click Continue > + click Finish > + click Save and close! + """ + + app = ConfigsCreateApp() + async with app.run_test(size=(100, 100)) as pilot: + # Make a temporary directory to store the output + tmpdir = TemporaryDirectory() + + await write_infra_custom_details("singularity", outdir=tmpdir.name)(pilot) + + config_file = Path(tmpdir.name) / "myconfig.conf" + with open(config_file) as f: + config = f.read() + assert config == INFRA_CUSTOM_SINGULARITY_CONFIG + tmpdir.cleanup() + + +async def click_type_pipe(pilot) -> None: + await click_lets_go(pilot) + await pilot.click("#type_pipeline") + + +def test_choose_pipe_type(snap_compare): + """Test snapshot for the nfcore_question screen + via the Pipeline config option. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + screen choose_type + """ + + async def run_before(pilot) -> None: + await click_type_pipe(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 50), run_before=run_before) + + +async def click_pipe_nfcore(pilot) -> None: + await click_type_pipe(pilot) + await pilot.click("#type_nfcore") + + +def test_pipe_nfcore_basic_details(snap_compare): + """Test snapshot for the nf-core basic details screen + when configuring a pipeline config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + press nf-core > + screen basic_details + """ + + async def run_before(pilot) -> None: + await click_pipe_nfcore(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 50), run_before=run_before) + + +async def enter_pipe_nfcore_basic_details(pilot) -> None: + await click_pipe_nfcore(pilot) + await pilot.click("#general_config_name") + await pilot.press(*list("myconfig")) + await pilot.press("tab") + await pilot.press(*list("my name")) + await pilot.press("tab") + await pilot.press(*list("@myhandle")) + await pilot.click("#config_pipeline_name") + await pilot.press(*list("scdownstream")) + await pilot.press("enter") + await pilot.press("tab") + await pilot.press(*list("A cool description")) + await pilot.press("tab") + await pilot.press(*list("https://example.com")) + + +async def submit_pipe_nfcore_basic_details(pilot) -> None: + await enter_pipe_nfcore_basic_details(pilot) + await pilot.click("#next") + + +def test_entering_pipe_nfcore_basic_details(snap_compare): + """Test snapshot for the entering basic details + on the nf-core basic_details screen + when configuring a pipeline config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + press nf-core > + screen basic_details + """ + + async def run_before(pilot) -> None: + await enter_pipe_nfcore_basic_details(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 50), run_before=run_before) + + +def test_submitting_pipe_nfcore_basic_details(snap_compare): + """Test snapshot for the entering basic details + on the nf-core basic_details screen + when configuring a pipeline config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + press nf-core > + enter basic details > + click Next > + screen pipeline_config_question + """ + + async def run_before(pilot) -> None: + await submit_pipe_nfcore_basic_details(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 50), run_before=run_before) + + +async def set_pipe_nfcore_options(pilot) -> None: + await submit_pipe_nfcore_basic_details(pilot) + await pilot.click("#toggle_configure_defaults") + await pilot.press("tab") + await pilot.press("enter") + await pilot.press("tab") + await pilot.press("enter") + await pilot.press("tab") + await pilot.press("enter") + + +async def submit_pipe_nfcore_options(pilot) -> None: + await set_pipe_nfcore_options(pilot) + await pilot.click("#next") + + +def test_setting_pipe_nfcore_options(snap_compare): + """Test snapshot for the setting the configure options + on the nf-core pipeline_config_question screen + when configuring a pipeline config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + press nf-core > + enter basic details > + click Next > + screen pipeline_config_question + """ + + async def run_before(pilot) -> None: + await set_pipe_nfcore_options(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 100), run_before=run_before) + + +def test_submitting_pipe_nfcore_options(snap_compare): + """Test snapshot for the setting the configure options + on the nf-core pipeline_config_question screen + when configuring a pipeline config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + press nf-core > + enter basic details > + click Next > + screen pipeline_config_question > + click Next > + screen default_process_resources + """ + + async def run_before(pilot) -> None: + await submit_pipe_nfcore_options(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 100), run_before=run_before) + + +async def enter_pipe_nfcore_default_res(pilot) -> None: + await submit_pipe_nfcore_options(pilot) + await pilot.click("#default_process_ncpus") + await pilot.press("2") + await pilot.press("tab") + await pilot.press("8") + await pilot.press("tab") + await pilot.press(*list("9.5")) + await pilot.press("tab") + + +async def submit_pipe_nfcore_default_res(pilot) -> None: + await enter_pipe_nfcore_default_res(pilot) + await pilot.click("#next") + + +async def enter_pipe_nfcore_named_proc_res(pilot) -> None: + await submit_pipe_nfcore_default_res(pilot) + await pilot.press("tab") + await pilot.press(*list("SOME:PROC.NAME*")) + await pilot.press("tab") + await pilot.press("3") + await pilot.press("tab") + await pilot.press("4") + await pilot.press("tab") + await pilot.press(*list("5.5")) + await pilot.press("tab") + await pilot.press("tab") + await pilot.press("tab") + await pilot.press(*list("ANOTHER:PROC_NAME")) + await pilot.press("tab") + await pilot.press("2") + await pilot.press("tab") + await pilot.press("3") + await pilot.press("tab") + await pilot.press(*list("4.4")) + await pilot.press("tab") + await pilot.press(*list("customqueue")) + await pilot.press("tab") + await pilot.press("tab") + await pilot.press("tab") + await pilot.press("tab") + await pilot.press("tab") + await pilot.press("tab") + await pilot.press("tab") + await pilot.press("enter") + + +async def submit_pipe_nfcore_named_proc_res(pilot) -> None: + await enter_pipe_nfcore_named_proc_res(pilot) + await pilot.click("#next") + + +async def enter_pipe_nfcore_labelled_proc_res(pilot) -> None: + await submit_pipe_nfcore_named_proc_res(pilot) + await pilot.press("tab") + await pilot.press(*list("some_proc_label")) + await pilot.press("tab") + await pilot.press("1") + await pilot.press("tab") + await pilot.press("1") + await pilot.press("tab") + await pilot.press(*list("1.1")) + await pilot.press("tab") + await pilot.press("tab") + await pilot.press("tab") + await pilot.press(*list("another_label")) + await pilot.press("tab") + await pilot.press("2") + await pilot.press("tab") + await pilot.press("2") + await pilot.press("tab") + await pilot.press(*list("2.2")) + await pilot.press("tab") + await pilot.press(*list("customqueue")) + await pilot.press("tab") + await pilot.press("tab") + await pilot.press(*list("a_third_label")) + await pilot.press("tab") + await pilot.press("backspace") + await pilot.press("tab") + await pilot.press("backspace") + await pilot.press("tab") + await pilot.press("backspace") + await pilot.click("#another") + await pilot.press("shift+tab") + await pilot.press("shift+tab") + await pilot.press("shift+tab") + await pilot.press("shift+tab") + await pilot.press("shift+tab") + await pilot.press("shift+tab") + await pilot.press(*list("fourth_label")) + await pilot.press("tab") + await pilot.press("4") + await pilot.press("tab") + await pilot.press("backspace") + await pilot.press("tab") + await pilot.press(*list("4.4")) + await pilot.press("tab") + await pilot.press(*list("anotherqueue")) + + +async def submit_pipe_nfcore_labelled_proc_res(pilot) -> None: + await enter_pipe_nfcore_labelled_proc_res(pilot) + await pilot.click("#next") + + +def test_enter_pipe_nfcore_default_res(snap_compare): + """Test snapshot for the entering default resources + when configuring a pipeline config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + press nf-core > + enter basic details > + click Next > + screen pipeline_config_question > + click Next > + screen default_process_resources + """ + + async def run_before(pilot) -> None: + await enter_pipe_nfcore_default_res(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 100), run_before=run_before) + + +def test_submit_pipe_nfcore_default_res(snap_compare): + """Test snapshot for the submitting default resources + when configuring a pipeline config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + press nf-core > + enter basic details > + click Next > + screen pipeline_config_question > + click Next > + screen default_process_resources > + click Next > + screen named_process_resources + """ + + async def run_before(pilot) -> None: + await submit_pipe_nfcore_default_res(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 100), run_before=run_before) + + +def test_enter_pipe_nfcore_named_proc_res(snap_compare): + """Test snapshot for the entering default resources + when configuring a pipeline config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + press nf-core > + enter basic details > + click Next > + screen pipeline_config_question > + click Next > + screen default_process_resources > + click Next > + screen named_process_resources + """ + + async def run_before(pilot) -> None: + await enter_pipe_nfcore_named_proc_res(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 100), run_before=run_before) + + +def test_submit_pipe_nfcore_named_proc_res(snap_compare): + """Test snapshot for the entering default resources + when configuring a pipeline config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + press nf-core > + enter basic details > + click Next > + screen pipeline_config_question > + click Next > + screen default_process_resources > + click Next > + screen named_process_resources > + click Next > + screen labelled_process_resources + """ + + async def run_before(pilot) -> None: + await submit_pipe_nfcore_named_proc_res(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 100), run_before=run_before) + + +def test_enter_pipe_nfcore_labelled_proc_res(snap_compare): + """Test snapshot for the entering default resources + when configuring a pipeline config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + press nf-core > + enter basic details > + click Next > + screen pipeline_config_question > + click Next > + screen default_process_resources > + click Next > + screen named_process_resources > + click Next > + screen labelled_process_resources + """ + + async def run_before(pilot) -> None: + await enter_pipe_nfcore_labelled_proc_res(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 100), run_before=run_before) + + +def test_submit_pipe_nfcore_labelled_proc_res(snap_compare): + """Test snapshot for the entering default resources + when configuring a pipeline config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + press nf-core > + enter basic details > + click Next > + screen pipeline_config_question > + click Next > + screen default_process_resources > + click Next > + screen named_process_resources > + click Next > + screen labelled_process_resources > + click Next > + screen labelled_process_resources > + click Next + """ + + async def run_before(pilot) -> None: + await submit_pipe_nfcore_labelled_proc_res(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 100), run_before=run_before) + + +def write_pipe_nfcore_details(outdir="."): + assert isinstance(outdir, str) + assert Path(outdir).is_dir() + + async def _write_pipe_nfcore_details(pilot) -> None: + await submit_pipe_nfcore_labelled_proc_res(pilot) + await pilot.click("#savelocation") + await pilot.press(*list(outdir)) + await pilot.click("#close_app") + + return _write_pipe_nfcore_details + + +async def test_writing_pipe_nfcore_details(): + """Test snapshot for writing a pipeline config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + press nf-core > + enter basic details > + click Next > + screen pipeline_config_question > + click Next > + screen default_process_resources > + enter resources > + click Next > + screen named_process_resources > + enter resources > + click Next > + screen labelled_process_resources > + enter resources > + click next > + click Save and close! + """ + + app = ConfigsCreateApp() + async with app.run_test(size=(100, 100)) as pilot: + # Make a temporary directory to store the output + tmpdir = TemporaryDirectory() + + await write_pipe_nfcore_details(outdir=tmpdir.name)(pilot) + + config_file = Path(tmpdir.name) / "myconfig.conf" + with open(config_file) as f: + config = f.read() + assert config == PIPE_NFCORE_CONFIG + tmpdir.cleanup() + + +async def click_pipe_custom(pilot) -> None: + await click_type_pipe(pilot) + await pilot.click("#type_custom") + + +def test_pipe_custom_basic_details(snap_compare): + """Test snapshot for the custom basic details screen + when configuring a pipeline config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + press custom > + screen basic_details + """ + + async def run_before(pilot) -> None: + await click_pipe_custom(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 50), run_before=run_before) + + +async def enter_pipe_custom_basic_details(pilot) -> None: + await click_pipe_custom(pilot) + await pilot.click("#general_config_name") + await pilot.press(*list("myconfig")) + await pilot.press("tab") + await pilot.press(*list(".")) + await pilot.press("tab") + await pilot.press(*list("A cool description")) + + +async def submit_pipe_custom_basic_details(pilot) -> None: + await enter_pipe_custom_basic_details(pilot) + await pilot.click("#next") + + +def test_entering_pipe_custom_basic_details(snap_compare): + """Test snapshot for the entering basic details + on the custom basic_details screen + when configuring a pipeline config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + press custom > + screen basic_details + """ + + async def run_before(pilot) -> None: + await enter_pipe_custom_basic_details(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 50), run_before=run_before) + + +def test_submitting_pipe_custom_basic_details(snap_compare): + """Test snapshot for the entering basic details + on the custom basic_details screen + when configuring a pipeline config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + press custom > + enter basic details > + click Next > + screen pipeline_config_question + """ + + async def run_before(pilot) -> None: + await submit_pipe_custom_basic_details(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 50), run_before=run_before) + + +async def set_pipe_custom_options(pilot) -> None: + await submit_pipe_custom_basic_details(pilot) + await pilot.click("#toggle_configure_defaults") + await pilot.press("tab") + await pilot.press("enter") + await pilot.press("tab") + await pilot.press("enter") + await pilot.press("tab") + await pilot.press("enter") + + +async def submit_pipe_custom_options(pilot) -> None: + await set_pipe_custom_options(pilot) + await pilot.click("#next") + + +def test_setting_pipe_custom_options(snap_compare): + """Test snapshot for the setting the configure options + on the custom pipeline_config_question screen + when configuring a pipeline config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + press custom > + enter basic details > + click Next > + screen pipeline_config_question + """ + + async def run_before(pilot) -> None: + await set_pipe_custom_options(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 100), run_before=run_before) + + +def test_submitting_pipe_custom_options(snap_compare): + """Test snapshot for the setting the configure options + on the custom pipeline_config_question screen + when configuring a pipeline config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + press custom > + enter basic details > + click Next > + screen pipeline_config_question > + click Next > + screen default_process_resources + """ + + async def run_before(pilot) -> None: + await submit_pipe_custom_options(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 100), run_before=run_before) + + +async def enter_pipe_custom_default_res(pilot) -> None: + await submit_pipe_custom_options(pilot) + await pilot.click("#default_process_ncpus") + await pilot.press("2") + await pilot.press("tab") + await pilot.press("8") + await pilot.press("tab") + await pilot.press(*list("9.5")) + await pilot.press("tab") + + +async def submit_pipe_custom_default_res(pilot) -> None: + await enter_pipe_custom_default_res(pilot) + await pilot.click("#next") + + +async def enter_pipe_custom_named_proc_res(pilot) -> None: + await submit_pipe_custom_default_res(pilot) + await pilot.press("tab") + await pilot.press(*list("some_proc")) + await pilot.press("tab") + await pilot.press("3") + await pilot.press("tab") + await pilot.press("4") + await pilot.press("tab") + await pilot.press(*list("5.5")) + await pilot.press("tab") + await pilot.press("tab") + await pilot.press("tab") + await pilot.press(*list("another_proc")) + await pilot.press("tab") + await pilot.press("2") + await pilot.press("tab") + await pilot.press("3") + await pilot.press("tab") + await pilot.press(*list("4.4")) + await pilot.press("tab") + await pilot.press(*list("customqueue")) + await pilot.press("tab") + await pilot.press("tab") + await pilot.press("tab") + await pilot.press("tab") + await pilot.press("tab") + await pilot.press("tab") + await pilot.press("tab") + await pilot.press("enter") + + +async def submit_pipe_custom_named_proc_res(pilot) -> None: + await enter_pipe_custom_named_proc_res(pilot) + await pilot.click("#next") + + +async def enter_pipe_custom_labelled_proc_res(pilot) -> None: + await submit_pipe_custom_named_proc_res(pilot) + await pilot.press("tab") + await pilot.press(*list("some_proc_label")) + await pilot.press("tab") + await pilot.press("1") + await pilot.press("tab") + await pilot.press("1") + await pilot.press("tab") + await pilot.press(*list("1.1")) + await pilot.press("tab") + await pilot.press("tab") + await pilot.press("tab") + await pilot.press(*list("another_label")) + await pilot.press("tab") + await pilot.press("2") + await pilot.press("tab") + await pilot.press("2") + await pilot.press("tab") + await pilot.press(*list("2.2")) + await pilot.press("tab") + await pilot.press(*list("customqueue")) + await pilot.press("tab") + await pilot.press("tab") + await pilot.press(*list("a_third_label")) + await pilot.press("tab") + await pilot.press("backspace") + await pilot.press("tab") + await pilot.press("backspace") + await pilot.press("tab") + await pilot.press("backspace") + await pilot.click("#another") + await pilot.press("shift+tab") + await pilot.press("shift+tab") + await pilot.press("shift+tab") + await pilot.press("shift+tab") + await pilot.press("shift+tab") + await pilot.press("shift+tab") + await pilot.press(*list("fourth_label")) + await pilot.press("tab") + await pilot.press("4") + await pilot.press("tab") + await pilot.press("backspace") + await pilot.press("tab") + await pilot.press(*list("4.4")) + await pilot.press("tab") + await pilot.press(*list("anotherqueue")) + + +async def submit_pipe_custom_labelled_proc_res(pilot) -> None: + await enter_pipe_custom_labelled_proc_res(pilot) + await pilot.click("#next") + + +def test_enter_pipe_custom_default_res(snap_compare): + """Test snapshot for the entering default resources + when configuring a pipeline config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + press custom > + enter basic details > + click Next > + screen pipeline_config_question > + click Next > + screen default_process_resources + """ + + async def run_before(pilot) -> None: + await enter_pipe_custom_default_res(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 100), run_before=run_before) + + +def test_submit_pipe_custom_default_res(snap_compare): + """Test snapshot for the submitting default resources + when configuring a pipeline config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + press custom > + enter basic details > + click Next > + screen pipeline_config_question > + click Next > + screen default_process_resources > + click Next > + screen named_process_resources + """ + + async def run_before(pilot) -> None: + await submit_pipe_custom_default_res(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 100), run_before=run_before) + + +def test_enter_pipe_custom_named_proc_res(snap_compare): + """Test snapshot for the entering default resources + when configuring a pipeline config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + press custom > + enter basic details > + click Next > + screen pipeline_config_question > + click Next > + screen default_process_resources > + click Next > + screen named_process_resources + """ + + async def run_before(pilot) -> None: + await enter_pipe_custom_named_proc_res(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 100), run_before=run_before) + + +def test_submit_pipe_custom_named_proc_res(snap_compare): + """Test snapshot for the entering default resources + when configuring a pipeline config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + press custom > + enter basic details > + click Next > + screen pipeline_config_question > + click Next > + screen default_process_resources > + click Next > + screen named_process_resources > + click Next > + screen labelled_process_resources + """ + + async def run_before(pilot) -> None: + await submit_pipe_custom_named_proc_res(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 100), run_before=run_before) + + +def test_enter_pipe_custom_labelled_proc_res(snap_compare): + """Test snapshot for the entering default resources + when configuring a pipeline config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + press custom > + enter basic details > + click Next > + screen pipeline_config_question > + click Next > + screen default_process_resources > + click Next > + screen named_process_resources > + click Next > + screen labelled_process_resources + """ + + async def run_before(pilot) -> None: + await enter_pipe_custom_labelled_proc_res(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 100), run_before=run_before) + + +def test_submit_pipe_custom_labelled_proc_res(snap_compare): + """Test snapshot for the entering default resources + when configuring a pipeline config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + press custom > + enter basic details > + click Next > + screen pipeline_config_question > + click Next > + screen default_process_resources > + click Next > + screen named_process_resources > + click Next > + screen labelled_process_resources > + click Next > + screen labelled_process_resources > + click Next + """ + + async def run_before(pilot) -> None: + await submit_pipe_custom_labelled_proc_res(pilot) + + assert snap_compare(INIT_FILE, terminal_size=(100, 100), run_before=run_before) + + +def write_pipe_custom_details(outdir="."): + assert isinstance(outdir, str) + assert Path(outdir).is_dir() + + async def _write_pipe_custom_details(pilot) -> None: + await submit_pipe_custom_labelled_proc_res(pilot) + await pilot.click("#savelocation") + await pilot.press(*list(outdir)) + await pilot.click("#close_app") + + return _write_pipe_custom_details + + +async def test_writing_pipe_custom_details(): + """Test snapshot for writing a pipeline config. + Steps to get to this screen: + screen welcome > press Let's go! > + press Pipeline config > + press custom > + enter basic details > + click Next > + screen pipeline_config_question > + click Next > + screen default_process_resources > + enter resources > + click Next > + screen named_process_resources > + enter resources > + click Next > + screen labelled_process_resources > + enter resources > + click next > + click Save and close! + """ + + app = ConfigsCreateApp() + async with app.run_test(size=(100, 100)) as pilot: + # Make a temporary directory to store the output + tmpdir = TemporaryDirectory() + + await write_pipe_custom_details(outdir=tmpdir.name)(pilot) + + config_file = Path(tmpdir.name) / "myconfig.conf" + with open(config_file) as f: + config = f.read() + assert config == PIPE_CUSTOM_CONFIG + tmpdir.cleanup() diff --git a/tests/configs/test_serial.py b/tests/configs/test_serial.py new file mode 100644 index 0000000000..7666bba541 --- /dev/null +++ b/tests/configs/test_serial.py @@ -0,0 +1,734 @@ +from pathlib import Path +from tempfile import TemporaryDirectory + +from pydantic import ValidationError + +from nf_core.configs.create.create import ConfigCreate +from nf_core.configs.create.serial import NextflowSerial +from nf_core.configs.create.utils import ConfigsCreateConfig, init_context + +from ..test_configs import ( + INFRA_CUSTOM_SINGULARITY_CONFIG, + INFRA_CUSTOM_SINGULARITY_LOCAL_CONFIG, + INFRA_NFCORE_SINGULARITY_LOCAL_CONFIG, + INFRA_SINGULARITY_CONFIG, + PIPE_CUSTOM_CONFIG, + PIPE_NFCORE_CONFIG, +) + +# Valid configs + +VALID_NFCORE_INFRA_HPC_CONFIG = { + "general_config_name": "myconfig", + "is_infrastructure": True, + "is_nfcore": True, + "config_profile_contact": "my name", + "config_profile_handle": "@myhandle", + "config_profile_description": "A cool description", + "config_profile_url": "https://example.com", + "scheduler": "pbspro", + "queue": "myqueue", + "module": False, + "module_system": "", + "container_system": "singularity", + "cpus": "48", + "memory": "128", + "time": "9.5", + "cachedir": "/singularity/cachedir", + "scratch_dir": "/tmp/scratch", + "igenomes_cachedir": "/data/igenomes/cache", + "retries": "2", + "delete_work_dir": True, + "queue_stat_interval": "0.75", + "poll_interval": "0.25", + "queue_size": "200", + "submit_rate": "25", + "savelocation": ".", +} + + +VALID_CUSTOM_INFRA_HPC_CONFIG = { + "general_config_name": "myconfig", + "is_infrastructure": True, + "is_nfcore": False, + "config_profile_description": "A cool description", + "scheduler": "pbspro", + "queue": "myqueue", + "module": False, + "module_system": "", + "container_system": "singularity", + "cpus": "48", + "memory": "128", + "time": "9.5", + "cachedir": "/singularity/cachedir", + "scratch_dir": "/tmp/scratch", + "retries": "2", + "delete_work_dir": True, + "queue_stat_interval": "0.75", + "poll_interval": "0.25", + "queue_size": "200", + "submit_rate": "25", + "savelocation": ".", +} + + +VALID_NFCORE_INFRA_LOCAL_CONFIG = { + "general_config_name": "myconfig", + "is_infrastructure": True, + "is_nfcore": True, + "config_profile_contact": "my name", + "config_profile_handle": "@myhandle", + "config_profile_description": "A cool description", + "config_profile_url": "https://example.com", + "container_system": "singularity", + "cpus": "8", + "memory": "32", + "time": "19.5", + "cachedir": "/singularity/cachedir", + "scratch_dir": "/tmp/scratch", + "igenomes_cachedir": "/data/igenomes/cache", + "retries": "2", + "delete_work_dir": True, + "savelocation": ".", +} + + +VALID_CUSTOM_INFRA_LOCAL_CONFIG = { + "general_config_name": "myconfig", + "is_infrastructure": True, + "is_nfcore": False, + "config_profile_description": "A cool description", + "container_system": "singularity", + "cpus": "8", + "memory": "32", + "time": "19.5", + "cachedir": "/singularity/cachedir", + "scratch_dir": "/tmp/scratch", + "retries": "2", + "delete_work_dir": True, + "savelocation": ".", +} + + +VALID_NFCORE_PIPE_HPC_CONFIG = { + "general_config_name": "myconfig", + "is_infrastructure": False, + "is_nfcore": True, + "config_pipeline_name": "rnaseq", + "config_profile_contact": "my name", + "config_profile_handle": "@myhandle", + "config_profile_description": "A cool description", + "config_profile_url": "https://example.com", + "default_process_ncpus": "2", + "default_process_memgb": "8", + "default_process_hours": "9.5", + "named_process_resources": { + "SOME:PROC.NAME*": { + "custom_process_name_id": "SOME:PROC.NAME*", + "custom_process_ncpus": "3", + "custom_process_memgb": "4", + "custom_process_hours": "5.5", + "custom_process_queue": "", + }, + "ANOTHER:PROC_NAME": { + "custom_process_name_id": "ANOTHER:PROC_NAME", + "custom_process_ncpus": "2", + "custom_process_memgb": "3", + "custom_process_hours": "4.4", + "custom_process_queue": "customqueue", + }, + }, + "labelled_process_resources": { + "some_proc_label": { + "custom_process_label_id": "some_proc_label", + "custom_process_ncpus": "1", + "custom_process_memgb": "1", + "custom_process_hours": "1.1", + "custom_process_queue": "", + }, + "another_label": { + "custom_process_label_id": "another_label", + "custom_process_ncpus": "2", + "custom_process_memgb": "2", + "custom_process_hours": "2.2", + "custom_process_queue": "customqueue", + }, + "a_third_label": { + "custom_process_label_id": "a_third_label", + "custom_process_ncpus": "", + "custom_process_memgb": "", + "custom_process_hours": "", + "custom_process_queue": "", + }, + "fourth_label": { + "custom_process_label_id": "fourth_label", + "custom_process_ncpus": "4", + "custom_process_memgb": "", + "custom_process_hours": "4.4", + "custom_process_queue": "anotherqueue", + }, + }, + "savelocation": ".", +} + + +VALID_CUSTOM_PIPE_HPC_CONFIG = { + "general_config_name": "myconfig", + "is_infrastructure": False, + "is_nfcore": False, + "config_profile_description": "A cool description", + "config_pipeline_path": ".", + "default_process_ncpus": "2", + "default_process_memgb": "8", + "default_process_hours": "9.5", + "named_process_resources": { + "some_proc": { + "custom_process_name_id": "some_proc", + "custom_process_ncpus": "3", + "custom_process_memgb": "4", + "custom_process_hours": "5.5", + "custom_process_queue": "", + }, + "another_proc": { + "custom_process_name_id": "another_proc", + "custom_process_ncpus": "2", + "custom_process_memgb": "3", + "custom_process_hours": "4.4", + "custom_process_queue": "customqueue", + }, + }, + "labelled_process_resources": { + "some_proc_label": { + "custom_process_label_id": "some_proc_label", + "custom_process_ncpus": "1", + "custom_process_memgb": "1", + "custom_process_hours": "1.1", + "custom_process_queue": "", + }, + "another_label": { + "custom_process_label_id": "another_label", + "custom_process_ncpus": "2", + "custom_process_memgb": "2", + "custom_process_hours": "2.2", + "custom_process_queue": "customqueue", + }, + "a_third_label": { + "custom_process_label_id": "a_third_label", + "custom_process_ncpus": "", + "custom_process_memgb": "", + "custom_process_hours": "", + "custom_process_queue": "", + }, + "fourth_label": { + "custom_process_label_id": "fourth_label", + "custom_process_ncpus": "4", + "custom_process_memgb": "", + "custom_process_hours": "4.4", + "custom_process_queue": "anotherqueue", + }, + }, + "savelocation": ".", +} + + +# Invalid configs + +INVALID_NFCORE_INFRA_HPC_CONFIG = { + "is_infrastructure": True, + "is_nfcore": True, + "config_profile_contact": "my name", + "config_profile_handle": "bad handle", + "config_profile_description": "A cool description", + "scheduler": "unsupported", + "queue": "myqueue", + "module": False, + "module_system": "", + "container_system": "noncontainer", + "cpus": "1.1", + "memory": "128.9", + "time": "9.5a", + "cachedir": "/singularity/cachedir", + "scratch_dir": "/tmp/scratch", + "igenomes_cachedir": "/data/igenomes/cache", + "retries": "2", + "delete_work_dir": True, + "queue_stat_interval": "0.75", + "poll_interval": "0.25", + "queue_size": "200", + "submit_rate": "25", + "savelocation": ".", +} + + +INVALID_CUSTOM_INFRA_HPC_CONFIG = { + "is_infrastructure": True, + "is_nfcore": False, + "config_profile_description": "A cool description", + "scheduler": "pbsprose", + "queue": "", + "module": False, + "module_system": "", + "container_system": "singularitay", + "cachedir": "singularity/cachedir", + "scratch_dir": "tmp/scratch", + "retries": "2", + "delete_work_dir": True, + "queue_stat_interval": "0.75", + "poll_interval": "0.25", + "queue_size": "200", + "submit_rate": "25", + "savelocation": ".", +} + + +INVALID_NFCORE_INFRA_LOCAL_CONFIG = { + "is_infrastructure": True, + "is_nfcore": True, + "config_profile_contact": "my name", + "config_profile_handle": "@myhandle", + "config_profile_description": "A cool description", + "config_profile_url": "bad_url", + "container_system": "", + "cpus": "8", + "memory": "32", + "time": "19.5", + "cachedir": "/singularity/cachedir", + "scratch_dir": "/tmp/scratch", + "igenomes_cachedir": "/data/igenomes/cache", + "retries": "2", + "delete_work_dir": True, + "savelocation": "_path_doesnt_exist_", +} + + +INVALID_CUSTOM_INFRA_LOCAL_CONFIG = { + "is_infrastructure": True, + "is_nfcore": False, + "config_profile_description": "A cool description", + "container_system": "apptianer", + "cpus": "8.0", + "memory": "32 GB", + "time": "19.5.1", + "cachedir": "singularity/cachedir", + "scratch_dir": "tmp/scratch", + "retries": "2", + "delete_work_dir": True, + "savelocation": ".", +} + + +INVALID_NFCORE_PIPE_HPC_CONFIG = { + "is_infrastructure": False, + "is_nfcore": True, + "config_pipeline_name": "", + "config_profile_contact": "my name", + "config_profile_handle": "@myhandle", + "config_profile_description": "A cool description", + "config_profile_url": "example.com", + "default_process_ncpus": "2", + "default_process_memgb": "8", + "default_process_hours": "9.5", + "named_process_resources": { + "SOME:PROC.NAME*": { + "custom_process_name_id": "SOME:PROC.NAME*", + "custom_process_ncpus": "3", + "custom_process_memgb": "4", + "custom_process_hours": "5.5", + "custom_process_queue": "", + }, + "ANOTHER:PROC_NAME": { + "custom_process_name_id": "ANOTHER:PROC_NAME", + "custom_process_ncpus": "2", + "custom_process_memgb": "3", + "custom_process_hours": "4.4", + "custom_process_queue": "customqueue", + }, + }, + "labelled_process_resources": { + "some_proc_label": { + "custom_process_label_id": "some_proc_label", + "custom_process_ncpus": "1", + "custom_process_memgb": "1", + "custom_process_hours": "1.1", + "custom_process_queue": "", + }, + "another_label": { + "custom_process_label_id": "another_label", + "custom_process_ncpus": "2", + "custom_process_memgb": "2", + "custom_process_hours": "2.2", + "custom_process_queue": "custom queue", + }, + "a_third_label": { + "custom_process_label_id": "a_third_label", + "custom_process_ncpus": "", + "custom_process_memgb": "", + "custom_process_hours": "", + "custom_process_queue": "", + }, + "fourth_label": { + "custom_process_label_id": "fourth_label", + "custom_process_ncpus": "4", + "custom_process_memgb": "", + "custom_process_hours": "4.4", + "custom_process_queue": "anotherqueue", + }, + }, + "savelocation": ".", +} + + +INVALID_CUSTOM_PIPE_HPC_CONFIG = { + "is_infrastructure": False, + "is_nfcore": False, + "config_profile_description": "A cool description", + "config_pipeline_path": "_this_path_doesnt_exist_", + "default_process_ncpus": "2", + "default_process_memgb": "8", + "default_process_hours": ".", + "named_process_resources": { + "some_proc": { + "custom_process_name_id": "some_proc", + "custom_process_ncpus": "3", + "custom_process_memgb": "4", + "custom_process_hours": "5.5", + "custom_process_queue": "", + }, + "another_proc": { + "custom_process_name_id": "another_proc", + "custom_process_ncpus": "2", + "custom_process_memgb": "3", + "custom_process_hours": "4.4", + "custom_process_queue": "customqueue", + }, + }, + "labelled_process_resources": { + "some_proc_label": { + "custom_process_label_id": "some_proc_label", + "custom_process_ncpus": "1", + "custom_process_memgb": "1", + "custom_process_hours": "1.1", + "custom_process_queue": "", + }, + "another_label": { + "custom_process_label_id": "another_label", + "custom_process_ncpus": "2", + "custom_process_memgb": "2", + "custom_process_hours": "2.2", + "custom_process_queue": "customqueue", + }, + "a_third_label": { + "custom_process_label_id": "a_third_label", + "custom_process_ncpus": "", + "custom_process_memgb": "", + "custom_process_hours": "", + "custom_process_queue": "", + }, + "fourth_label": { + "custom_process_label_id": "fourth_label", + "custom_process_ncpus": "4", + "custom_process_memgb": "", + "custom_process_hours": "4.4", + "custom_process_queue": "anotherqueue", + }, + }, + "savelocation": "_this_path_also_doesnt_exist_", +} + + +def test_serial_valid_nfcore_infra_hpc(): + with init_context( + { + "is_nfcore": True, + "is_infrastructure": True, + "is_hpc": True, + } + ): + c = ConfigsCreateConfig(**VALID_NFCORE_INFRA_HPC_CONFIG) + s = NextflowSerial.dumps(data_dict=c.serial(), drop_null=True) + assert s == INFRA_SINGULARITY_CONFIG + + # Test writing to file + tmpdir = TemporaryDirectory() + cf = ConfigCreate(template_config=c, config_type="infrastructure", config_dir=Path(tmpdir.name)) + cf.write_to_file() + config_file = Path(tmpdir.name) / "myconfig.conf" + with open(config_file) as f: + config = f.read() + tmpdir.cleanup() + assert config == INFRA_SINGULARITY_CONFIG + + +def test_serial_valid_custom_infra_hpc(): + with init_context( + { + "is_nfcore": False, + "is_infrastructure": True, + "is_hpc": True, + } + ): + c = ConfigsCreateConfig(**VALID_CUSTOM_INFRA_HPC_CONFIG) + s = NextflowSerial.dumps(data_dict=c.serial(), drop_null=True) + assert s == INFRA_CUSTOM_SINGULARITY_CONFIG + + # Test writing to file + tmpdir = TemporaryDirectory() + cf = ConfigCreate(template_config=c, config_type="infrastructure", config_dir=Path(tmpdir.name)) + cf.write_to_file() + config_file = Path(tmpdir.name) / "myconfig.conf" + with open(config_file) as f: + config = f.read() + tmpdir.cleanup() + assert config == INFRA_CUSTOM_SINGULARITY_CONFIG + + +def test_serial_valid_nfcore_pipe_hpc(): + with init_context( + { + "is_nfcore": True, + "is_infrastructure": False, + "is_hpc": True, + } + ): + c = ConfigsCreateConfig(**VALID_NFCORE_PIPE_HPC_CONFIG) + s = NextflowSerial.dumps(data_dict=c.serial(), drop_null=True) + assert s == PIPE_NFCORE_CONFIG + + # Test writing to file + tmpdir = TemporaryDirectory() + cf = ConfigCreate(template_config=c, config_type="pipeline", config_dir=Path(tmpdir.name)) + cf.write_to_file() + config_file = Path(tmpdir.name) / "myconfig.conf" + with open(config_file) as f: + config = f.read() + tmpdir.cleanup() + assert config == PIPE_NFCORE_CONFIG + + +def test_serial_valid_custom_pipe_hpc(): + with init_context( + { + "is_nfcore": False, + "is_infrastructure": False, + "is_hpc": True, + } + ): + c = ConfigsCreateConfig(**VALID_CUSTOM_PIPE_HPC_CONFIG) + s = NextflowSerial.dumps(data_dict=c.serial(), drop_null=True) + assert s == PIPE_CUSTOM_CONFIG + + # Test writing to file + tmpdir = TemporaryDirectory() + cf = ConfigCreate(template_config=c, config_type="pipeline", config_dir=Path(tmpdir.name)) + cf.write_to_file() + config_file = Path(tmpdir.name) / "myconfig.conf" + with open(config_file) as f: + config = f.read() + tmpdir.cleanup() + assert config == PIPE_CUSTOM_CONFIG + + +def test_serial_valid_nfcore_infra_local(): + with init_context( + { + "is_nfcore": True, + "is_infrastructure": True, + "is_hpc": False, + } + ): + c = ConfigsCreateConfig(**VALID_NFCORE_INFRA_LOCAL_CONFIG) + s = NextflowSerial.dumps(data_dict=c.serial(), drop_null=True) + assert s == INFRA_NFCORE_SINGULARITY_LOCAL_CONFIG + + # Test writing to file + tmpdir = TemporaryDirectory() + cf = ConfigCreate(template_config=c, config_type="infrastructure", config_dir=Path(tmpdir.name)) + cf.write_to_file() + config_file = Path(tmpdir.name) / "myconfig.conf" + with open(config_file) as f: + config = f.read() + tmpdir.cleanup() + assert config == INFRA_NFCORE_SINGULARITY_LOCAL_CONFIG + + +def test_serial_valid_custom_infra_local(): + with init_context( + { + "is_nfcore": False, + "is_infrastructure": True, + "is_hpc": False, + } + ): + c = ConfigsCreateConfig(**VALID_CUSTOM_INFRA_LOCAL_CONFIG) + s = NextflowSerial.dumps(data_dict=c.serial(), drop_null=True) + assert s == INFRA_CUSTOM_SINGULARITY_LOCAL_CONFIG + + # Test writing to file + tmpdir = TemporaryDirectory() + cf = ConfigCreate(template_config=c, config_type="infrastructure", config_dir=Path(tmpdir.name)) + cf.write_to_file() + config_file = Path(tmpdir.name) / "myconfig.conf" + with open(config_file) as f: + config = f.read() + tmpdir.cleanup() + assert config == INFRA_CUSTOM_SINGULARITY_LOCAL_CONFIG + + +# Invalid tests + + +def test_serial_invalid_nfcore_infra_hpc(): + with init_context( + { + "is_nfcore": True, + "is_infrastructure": True, + "is_hpc": True, + } + ): + expected_error = None + + try: + ConfigsCreateConfig(**INVALID_NFCORE_INFRA_HPC_CONFIG) + except ValidationError as e: + expected_error = e + + assert expected_error is not None + errors = expected_error.errors() + assert len(errors) == 6 + expected_error_msgs = { + "Value error, Must be a number.", + "Value error, Handle must start with '@'.", + "Value error, Must be one of: singularity, docker, apptainer, charliecloud, podman, sarus, shifter, conda", + "Value error, Must be one of: local, pbs, pbspro, slurm, sge", + "Value error, Must be an integer.", + } + assert {e["msg"] for e in errors} == expected_error_msgs + + +def test_serial_invalid_custom_infra_hpc(): + with init_context( + { + "is_nfcore": False, + "is_infrastructure": True, + "is_hpc": True, + } + ): + expected_error = None + + try: + ConfigsCreateConfig(**INVALID_CUSTOM_INFRA_HPC_CONFIG) + except ValidationError as e: + expected_error = e + + assert expected_error is not None + errors = expected_error.errors() + assert len(errors) == 4 + expected_error_msgs = { + "Value error, Must be one of: singularity, docker, apptainer, charliecloud, podman, sarus, shifter, conda", + "Value error, Must be one of: local, pbs, pbspro, slurm, sge", + "Value error, Must be an absolute path (/data/scratch), a path relative to home (~/scratch), or a path with an environmental variable (e.g. ${DIR}/scratch)", + } + assert {e["msg"] for e in errors} == expected_error_msgs + + +def test_serial_invalid_nfcore_pipe_hpc(): + with init_context( + { + "is_nfcore": True, + "is_infrastructure": False, + "is_hpc": True, + } + ): + expected_error = None + + try: + ConfigsCreateConfig(**INVALID_NFCORE_PIPE_HPC_CONFIG) + except ValidationError as e: + expected_error = e + + assert expected_error is not None + errors = expected_error.errors() + assert len(errors) == 2 + expected_error_msgs = { + "Value error, Handle must be a valid URL starting with 'https://' or 'http://' and include the domain (e.g. .com).", + "Value error, Cannot be left empty.", + } + assert {e["msg"] for e in errors} == expected_error_msgs + + +def test_serial_invalid_custom_pipe_hpc(): + with init_context( + { + "is_nfcore": False, + "is_infrastructure": False, + "is_hpc": True, + } + ): + expected_error = None + + try: + ConfigsCreateConfig(**INVALID_CUSTOM_PIPE_HPC_CONFIG) + except ValidationError as e: + expected_error = e + + assert expected_error is not None + errors = expected_error.errors() + assert len(errors) == 3 + expected_error_msgs = { + "Value error, Must be a valid path.", + "Value error, Must be a number.", + "Value error, Must be a valid path to a directory.", + } + assert {e["msg"] for e in errors} == expected_error_msgs + + +def test_serial_invalid_nfcore_infra_local(): + with init_context( + { + "is_nfcore": True, + "is_infrastructure": True, + "is_hpc": False, + } + ): + expected_error = None + + try: + ConfigsCreateConfig(**INVALID_NFCORE_INFRA_LOCAL_CONFIG) + except ValidationError as e: + expected_error = e + + assert expected_error is not None + errors = expected_error.errors() + assert len(errors) == 2 + expected_error_msgs = { + "Value error, Handle must be a valid URL starting with 'https://' or 'http://' and include the domain (e.g. .com).", + "Value error, Must be a valid path to a directory.", + } + assert {e["msg"] for e in errors} == expected_error_msgs + + +def test_serial_invalid_custom_infra_local(): + with init_context( + { + "is_nfcore": False, + "is_infrastructure": True, + "is_hpc": False, + } + ): + expected_error = None + + try: + ConfigsCreateConfig(**INVALID_CUSTOM_INFRA_LOCAL_CONFIG) + except ValidationError as e: + expected_error = e + + assert expected_error is not None + errors = expected_error.errors() + assert len(errors) == 6 + expected_error_msgs = { + "Value error, Must be a number.", + "Value error, Must be an integer.", + "Value error, Must be one of: singularity, docker, apptainer, charliecloud, podman, sarus, shifter, conda", + "Value error, Must be an absolute path (/data/scratch), a path relative to home (~/scratch), or a path with an environmental variable (e.g. ${DIR}/scratch)", + } + assert {e["msg"] for e in errors} == expected_error_msgs diff --git a/tests/configs/test_validation.py b/tests/configs/test_validation.py new file mode 100644 index 0000000000..7798c64eac --- /dev/null +++ b/tests/configs/test_validation.py @@ -0,0 +1,821 @@ +from enum import Enum + +from pydantic_core._pydantic_core import ValidationError + +from nf_core.configs.create.utils import SUPPORTED_CONTAINERS, SUPPORTED_SCHEDULERS, ConfigsCreateConfig, init_context + + +class Context(Enum): + NF_INFRA_HPC = { + "is_nfcore": True, + "is_infrastructure": True, + "is_hpc": True, + } + NF_INFRA_LOCAL = { + "is_nfcore": True, + "is_infrastructure": True, + "is_hpc": False, + } + NF_PIPE_HPC = { + "is_nfcore": True, + "is_infrastructure": False, + "is_hpc": True, + } + NF_PIPE_LOCAL = { + "is_nfcore": True, + "is_infrastructure": False, + "is_hpc": False, + } + CUSTOM_INFRA_HPC = { + "is_nfcore": False, + "is_infrastructure": True, + "is_hpc": True, + } + CUSTOM_INFRA_LOCAL = { + "is_nfcore": False, + "is_infrastructure": True, + "is_hpc": False, + } + CUSTOM_PIPE_HPC = { + "is_nfcore": False, + "is_infrastructure": False, + "is_hpc": True, + } + CUSTOM_PIPE_LOCAL = { + "is_nfcore": False, + "is_infrastructure": False, + "is_hpc": False, + } + + +def check_config(cfg: dict, fail: bool, ctx: dict) -> None: + assert isinstance(cfg, dict) + assert isinstance(fail, bool) + assert isinstance(ctx, dict) + + with init_context(ctx): + if fail: + failed = False + try: + ConfigsCreateConfig(**cfg) + except ValidationError: + failed = True + assert failed + else: + ConfigsCreateConfig(**cfg) + + +def test_pipe_name(): + cfg_valid = {"config_pipeline_name": "Some pipeline name."} + cfg_invalid = {"config_pipeline_name": ""} + + # Test nf-core pipeline context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.NF_PIPE_LOCAL.value) + # Should fail + check_config(cfg_invalid, fail=True, ctx=Context.NF_PIPE_LOCAL.value) + + # Test custom pipeline context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + check_config(cfg_invalid, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + + # Test custom infra context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_invalid, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + + # Test nf-core infra context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + check_config(cfg_invalid, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + + +def test_pipe_path(): + cfg_valid = {"config_pipeline_path": "."} + cfg_invalid_1 = {"config_pipeline_path": ""} + cfg_invalid_2 = {"config_pipeline_path": "./_this_path_doesnt_exist_"} + + # Test custom pipeline context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + # Should fail + check_config(cfg_invalid_1, fail=True, ctx=Context.CUSTOM_PIPE_LOCAL.value) + check_config(cfg_invalid_2, fail=True, ctx=Context.CUSTOM_PIPE_LOCAL.value) + + # Test nf-core pipeline context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.NF_PIPE_LOCAL.value) + check_config(cfg_invalid_1, fail=False, ctx=Context.NF_PIPE_LOCAL.value) + check_config(cfg_invalid_2, fail=False, ctx=Context.NF_PIPE_LOCAL.value) + + # Test custom infra context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_invalid_1, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_invalid_2, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + + # Test nf-core infra context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + check_config(cfg_invalid_1, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + check_config(cfg_invalid_2, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + + +def test_config_name(): + cfg_valid_custom = {"general_config_name": "A valid custom config Name"} + cfg_valid_nfcore = {"general_config_name": "a valid nfcore config name"} + cfg_invalid = {"general_config_name": ""} + + # Test custom infra config context + # Should succeed + check_config(cfg_valid_nfcore, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_valid_custom, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + # Should fail + check_config(cfg_invalid, fail=True, ctx=Context.CUSTOM_INFRA_LOCAL.value) + + # Test nfcore infra config context + # Should succeed + check_config(cfg_valid_nfcore, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + # Should fail + check_config(cfg_valid_custom, fail=True, ctx=Context.NF_INFRA_LOCAL.value) + check_config(cfg_invalid, fail=True, ctx=Context.NF_INFRA_LOCAL.value) + + # Test custom pipeline context + # Should succeed + check_config(cfg_valid_nfcore, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + check_config(cfg_valid_custom, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + # Should fail + check_config(cfg_invalid, fail=True, ctx=Context.CUSTOM_PIPE_LOCAL.value) + + # Test nf-core pipeline context + # Should succeed + check_config(cfg_valid_nfcore, fail=False, ctx=Context.NF_PIPE_LOCAL.value) + # Should fail + check_config(cfg_valid_custom, fail=True, ctx=Context.NF_PIPE_LOCAL.value) + check_config(cfg_invalid, fail=True, ctx=Context.NF_PIPE_LOCAL.value) + + +def test_contact_name(): + cfg_valid = {"config_profile_contact": "some name"} + cfg_invalid = {"config_profile_contact": ""} + + # Test nf-core pipeline context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.NF_PIPE_LOCAL.value) + # Should fail + check_config(cfg_invalid, fail=True, ctx=Context.NF_PIPE_LOCAL.value) + + # Test custom pipeline context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + check_config(cfg_invalid, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + + # Test custom infra context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_invalid, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + + # Test nf-core infra context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + # Should fail + check_config(cfg_invalid, fail=True, ctx=Context.NF_INFRA_LOCAL.value) + + +def test_handle(): + cfg_valid = {"config_profile_handle": "@someHandle"} + cfg_invalid = {"config_profile_handle": "BadHandle"} + cfg_empty = {"config_profile_handle": ""} + + # Test nf-core pipeline context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.NF_PIPE_LOCAL.value) + # Should fail + check_config(cfg_invalid, fail=True, ctx=Context.NF_PIPE_LOCAL.value) + check_config(cfg_empty, fail=True, ctx=Context.NF_PIPE_LOCAL.value) + + # Test custom pipeline context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + check_config(cfg_invalid, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + check_config(cfg_empty, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + + # Test custom infra context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_invalid, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_empty, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + + # Test nf-core infra context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + # Should fail + check_config(cfg_invalid, fail=True, ctx=Context.NF_INFRA_LOCAL.value) + check_config(cfg_empty, fail=True, ctx=Context.NF_INFRA_LOCAL.value) + + +def test_description(): + cfg_valid = {"config_profile_description": "A good description"} + cfg_invalid = {"config_profile_description": ""} + + # Test nf-core pipeline context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.NF_PIPE_LOCAL.value) + # Should fail + check_config(cfg_invalid, fail=True, ctx=Context.NF_PIPE_LOCAL.value) + + # Test custom pipeline context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + check_config(cfg_invalid, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + + # Test custom infra context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_invalid, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + + # Test nf-core infra context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + # Should fail + check_config(cfg_invalid, fail=True, ctx=Context.NF_INFRA_LOCAL.value) + + +def test_url(): + cfg_valid = {"config_profile_url": "http://some.url"} + cfg_invalid = {"config_profile_url": "a.bad.url"} + cfg_empty = {"config_profile_url": ""} + + # Test nf-core infra context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + # Should fail + check_config(cfg_invalid, fail=True, ctx=Context.NF_INFRA_LOCAL.value) + check_config(cfg_empty, fail=True, ctx=Context.NF_INFRA_LOCAL.value) + + # Test nf-core pipeline context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.NF_PIPE_LOCAL.value) + # Should fail + check_config(cfg_invalid, fail=True, ctx=Context.NF_PIPE_LOCAL.value) + check_config(cfg_empty, fail=True, ctx=Context.NF_PIPE_LOCAL.value) + + # Test custom pipeline context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + check_config(cfg_invalid, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + check_config(cfg_empty, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + + # Test custom infra context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_invalid, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_empty, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + + +def test_proc_cpu_mem(): + for field in [ + "default_process_ncpus", + "default_process_memgb", + "custom_process_ncpus", + "custom_process_memgb", + ]: + cfg_valid = {field: "2"} + cfg_invalid_str = {field: "hello"} + cfg_invalid_float = {field: "1.2"} + cfg_invalid_zero = {field: "0"} + cfg_invalid_neg = {field: "-2"} + cfg_empty = {field: ""} + + # Test nf-core pipeline context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.NF_PIPE_LOCAL.value) + check_config(cfg_empty, fail=False, ctx=Context.NF_PIPE_LOCAL.value) + # Should fail + check_config(cfg_invalid_str, fail=True, ctx=Context.NF_PIPE_LOCAL.value) + check_config(cfg_invalid_float, fail=True, ctx=Context.NF_PIPE_LOCAL.value) + check_config(cfg_invalid_zero, fail=True, ctx=Context.NF_PIPE_LOCAL.value) + check_config(cfg_invalid_neg, fail=True, ctx=Context.NF_PIPE_LOCAL.value) + + # Test custom pipeline context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + check_config(cfg_empty, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + # Should fail + check_config(cfg_invalid_str, fail=True, ctx=Context.CUSTOM_PIPE_LOCAL.value) + check_config(cfg_invalid_float, fail=True, ctx=Context.CUSTOM_PIPE_LOCAL.value) + check_config(cfg_invalid_zero, fail=True, ctx=Context.CUSTOM_PIPE_LOCAL.value) + check_config(cfg_invalid_neg, fail=True, ctx=Context.CUSTOM_PIPE_LOCAL.value) + + # Test custom infra context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_invalid_str, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_invalid_float, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_empty, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_invalid_zero, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_invalid_neg, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + + # Test nf-core infra context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + check_config(cfg_invalid_str, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + check_config(cfg_invalid_float, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + check_config(cfg_empty, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + check_config(cfg_invalid_zero, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + check_config(cfg_invalid_neg, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + + +def test_proc_hours(): + for field in [ + "default_process_hours", + "custom_process_hours", + ]: + cfg_valid = {field: "2"} + cfg_valid_float = {field: "1.2"} + cfg_valid_zero = {field: "0"} + cfg_invalid_str = {field: "hello"} + cfg_invalid_neg = {field: "-2"} + cfg_empty = {field: ""} + + # Test nf-core pipeline context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.NF_PIPE_LOCAL.value) + check_config(cfg_valid_float, fail=False, ctx=Context.NF_PIPE_LOCAL.value) + check_config(cfg_valid_zero, fail=False, ctx=Context.NF_PIPE_LOCAL.value) + check_config(cfg_empty, fail=False, ctx=Context.NF_PIPE_LOCAL.value) + # Should fail + check_config(cfg_invalid_str, fail=True, ctx=Context.NF_PIPE_LOCAL.value) + check_config(cfg_invalid_neg, fail=True, ctx=Context.NF_PIPE_LOCAL.value) + + # Test custom pipeline context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + check_config(cfg_valid_float, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + check_config(cfg_valid_zero, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + check_config(cfg_empty, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + # Should fail + check_config(cfg_invalid_str, fail=True, ctx=Context.CUSTOM_PIPE_LOCAL.value) + check_config(cfg_invalid_neg, fail=True, ctx=Context.CUSTOM_PIPE_LOCAL.value) + + # Test custom infra context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_valid_float, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_valid_zero, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_empty, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_invalid_str, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_invalid_neg, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + + # Test nf-core infra context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + check_config(cfg_valid_float, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + check_config(cfg_valid_zero, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + check_config(cfg_empty, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + check_config(cfg_invalid_str, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + check_config(cfg_invalid_neg, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + + +def test_proc_name(): + cfg_valid_nfcore = {"custom_process_name_id": "SOME.PROC_ESS:NAME*"} + cfg_valid_custom = {"custom_process_name_id": "a_process_name"} + cfg_empty = {"custom_process_name_id": ""} + + # Test nf-core pipeline context + # Should succeed + check_config(cfg_valid_nfcore, fail=False, ctx=Context.NF_PIPE_LOCAL.value) + # Should fail + check_config(cfg_valid_custom, fail=True, ctx=Context.NF_PIPE_LOCAL.value) + check_config(cfg_empty, fail=True, ctx=Context.NF_PIPE_LOCAL.value) + + # Test custom pipeline context + # Should succeed + check_config(cfg_valid_nfcore, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + check_config(cfg_valid_custom, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + # Should fail + check_config(cfg_empty, fail=True, ctx=Context.CUSTOM_PIPE_LOCAL.value) + + # Test nf-core infra context + # Should succeed + check_config(cfg_valid_nfcore, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + check_config(cfg_valid_custom, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + check_config(cfg_empty, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + + # Test custom infra context + # Should succeed + check_config(cfg_valid_nfcore, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_valid_custom, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_empty, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + + +def test_proc_label(): + cfg_valid_nfcore = {"custom_process_label_id": "some_label"} + cfg_valid_custom = {"custom_process_label_id": "ANOTHER_LABEL"} + cfg_empty = {"custom_process_label_id": ""} + + # Test nf-core pipeline context + # Should succeed + check_config(cfg_valid_nfcore, fail=False, ctx=Context.NF_PIPE_LOCAL.value) + # Should fail + check_config(cfg_valid_custom, fail=True, ctx=Context.NF_PIPE_LOCAL.value) + check_config(cfg_empty, fail=True, ctx=Context.NF_PIPE_LOCAL.value) + + # Test custom pipeline context + # Should succeed + check_config(cfg_valid_nfcore, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + check_config(cfg_valid_custom, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + # Should fail + check_config(cfg_empty, fail=True, ctx=Context.CUSTOM_PIPE_LOCAL.value) + + # Test nf-core infra context + # Should succeed + check_config(cfg_valid_nfcore, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + check_config(cfg_valid_custom, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + check_config(cfg_empty, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + + # Test custom infra context + # Should succeed + check_config(cfg_valid_nfcore, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_valid_custom, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_empty, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + + +def test_proc_queue(): + cfg_valid = {"custom_process_queue": "somequeue"} + cfg_valid_empty = {"custom_process_queue": ""} + cfg_invalid_spaces = {"custom_process_queue": "a bad queue"} + + # Test nf-core pipeline context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.NF_PIPE_LOCAL.value) + check_config(cfg_valid_empty, fail=False, ctx=Context.NF_PIPE_LOCAL.value) + # Should fail + check_config(cfg_invalid_spaces, fail=True, ctx=Context.NF_PIPE_LOCAL.value) + + # Test custom pipeline context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + check_config(cfg_valid_empty, fail=False, ctx=Context.CUSTOM_PIPE_LOCAL.value) + # Should fail + check_config(cfg_invalid_spaces, fail=True, ctx=Context.CUSTOM_PIPE_LOCAL.value) + + # Test nf-core infra context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + check_config(cfg_valid_empty, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + check_config(cfg_invalid_spaces, fail=False, ctx=Context.NF_INFRA_LOCAL.value) + + # Test custom infra context + # Should succeed + check_config(cfg_valid, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_valid_empty, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + check_config(cfg_invalid_spaces, fail=False, ctx=Context.CUSTOM_INFRA_LOCAL.value) + + +def test_save_loc(): + cfg_valid = {"savelocation": "."} + cfg_invalid_empty = {"savelocation": ""} + cfg_invalid_missing = {"savelocation": "./_this_path_doesnt_exist_"} + + # Test all contexts + for ctx in [ + Context.NF_PIPE_LOCAL.value, + Context.NF_PIPE_HPC.value, + Context.NF_INFRA_LOCAL.value, + Context.NF_INFRA_HPC.value, + Context.CUSTOM_PIPE_LOCAL.value, + Context.CUSTOM_PIPE_HPC.value, + Context.CUSTOM_INFRA_LOCAL.value, + Context.CUSTOM_INFRA_HPC.value, + ]: + # Should succeed + check_config(cfg_valid, fail=False, ctx=ctx) + # Should fail + check_config(cfg_invalid_empty, fail=True, ctx=ctx) + check_config(cfg_invalid_missing, fail=True, ctx=ctx) + + +def test_scheduler(): + cfg_empty = {"scheduler": ""} + cfg_unsupported = {"scheduler": "nonexistant_scheduler"} + + # Test all contexts other than INFRA_HPC + for ctx in [ + Context.NF_PIPE_LOCAL.value, + Context.NF_PIPE_HPC.value, + Context.NF_INFRA_LOCAL.value, + Context.CUSTOM_PIPE_LOCAL.value, + Context.CUSTOM_PIPE_HPC.value, + Context.CUSTOM_INFRA_LOCAL.value, + ]: + # Should succeed + check_config(cfg_empty, fail=False, ctx=ctx) + check_config(cfg_unsupported, fail=False, ctx=ctx) + + # Test INFRA_HPC contexts + for ctx in [ + Context.NF_INFRA_HPC.value, + Context.CUSTOM_INFRA_HPC.value, + ]: + # Should succeed + for sch in SUPPORTED_SCHEDULERS: + cfg_valid = {"scheduler": sch} + check_config(cfg_valid, fail=False, ctx=ctx) + # Should fail + check_config(cfg_empty, fail=True, ctx=ctx) + check_config(cfg_unsupported, fail=True, ctx=ctx) + + +def test_container(): + valid_cfgs = [{"container_system": ct} for ct in SUPPORTED_CONTAINERS] + invalid_cfg = {"container_system": "imaginary_container_system"} + empty_cfg = {"container_system": ""} + + # Test all contexts + for ctx in [ + Context.NF_PIPE_LOCAL.value, + Context.NF_PIPE_HPC.value, + Context.NF_INFRA_LOCAL.value, + Context.NF_INFRA_HPC.value, + Context.CUSTOM_PIPE_LOCAL.value, + Context.CUSTOM_PIPE_HPC.value, + Context.CUSTOM_INFRA_LOCAL.value, + Context.CUSTOM_INFRA_HPC.value, + ]: + # Should succeed + for cfg_valid in valid_cfgs: + check_config(cfg_valid, fail=False, ctx=ctx) + check_config(empty_cfg, fail=False, ctx=ctx) + # Shoudl fail + check_config(invalid_cfg, fail=True, ctx=ctx) + + +def test_cpu_mem_retries(): + for field in [ + "cpus", + "memory", + "retries", + ]: + cfg_valid = {field: "2"} + cfg_invalid_str = {field: "hello"} + cfg_invalid_float = {field: "1.2"} + cfg_invalid_zero = {field: "0"} + cfg_invalid_neg = {field: "-2"} + cfg_empty = {field: ""} + + # Test all INFRA contexts + for ctx in [ + Context.NF_INFRA_LOCAL.value, + Context.NF_INFRA_HPC.value, + Context.CUSTOM_INFRA_LOCAL.value, + Context.CUSTOM_INFRA_HPC.value, + ]: + # Should succeed + check_config(cfg_valid, fail=False, ctx=ctx) + # Shoudl fail + check_config(cfg_invalid_str, fail=True, ctx=ctx) + check_config(cfg_invalid_float, fail=True, ctx=ctx) + check_config(cfg_invalid_zero, fail=True, ctx=ctx) + check_config(cfg_invalid_neg, fail=True, ctx=ctx) + check_config(cfg_empty, fail=True, ctx=ctx) + + # Test all PIPE contexts + for ctx in [ + Context.NF_PIPE_LOCAL.value, + Context.NF_PIPE_HPC.value, + Context.CUSTOM_PIPE_LOCAL.value, + Context.CUSTOM_PIPE_HPC.value, + ]: + # Should succeed + check_config(cfg_valid, fail=False, ctx=ctx) + check_config(cfg_invalid_str, fail=False, ctx=ctx) + check_config(cfg_invalid_float, fail=False, ctx=ctx) + check_config(cfg_invalid_zero, fail=False, ctx=ctx) + check_config(cfg_invalid_neg, fail=False, ctx=ctx) + check_config(cfg_empty, fail=False, ctx=ctx) + + +def test_hours(): + cfg_valid = {"time": "2"} + cfg_valid_float = {"time": "1.2"} + cfg_valid_zero = {"time": "0"} + cfg_invalid_str = {"time": "hello"} + cfg_invalid_neg = {"time": "-2"} + cfg_empty = {"time": ""} + + # Test all INFRA contexts + for ctx in [ + Context.NF_INFRA_LOCAL.value, + Context.NF_INFRA_HPC.value, + Context.CUSTOM_INFRA_LOCAL.value, + Context.CUSTOM_INFRA_HPC.value, + ]: + # Should succeed + check_config(cfg_valid, fail=False, ctx=ctx) + check_config(cfg_valid_float, fail=False, ctx=ctx) + check_config(cfg_valid_zero, fail=False, ctx=ctx) + # Shoudl fail + check_config(cfg_invalid_str, fail=True, ctx=ctx) + check_config(cfg_invalid_neg, fail=True, ctx=ctx) + check_config(cfg_empty, fail=True, ctx=ctx) + + # Test all PIPE contexts + for ctx in [ + Context.NF_PIPE_LOCAL.value, + Context.NF_PIPE_HPC.value, + Context.CUSTOM_PIPE_LOCAL.value, + Context.CUSTOM_PIPE_HPC.value, + ]: + # Should succeed + check_config(cfg_valid, fail=False, ctx=ctx) + check_config(cfg_valid_float, fail=False, ctx=ctx) + check_config(cfg_valid_zero, fail=False, ctx=ctx) + check_config(cfg_invalid_str, fail=False, ctx=ctx) + check_config(cfg_invalid_neg, fail=False, ctx=ctx) + check_config(cfg_empty, fail=False, ctx=ctx) + + +def test_cache_scratch_dirs(): + for field in [ + "cachedir", + "scratch_dir", + ]: + cfg_valid_abs = {field: "/an/absolute/path"} + cfg_valid_home = {field: "~/a/path/in/home"} + cfg_valid_env = {field: "${SOME}/env/prefixed/path"} + cfg_empty = {field: ""} + cfg_invalid_rel = {field: "a/relative/path"} + + # Test all contexts + for ctx in [ + Context.NF_PIPE_LOCAL.value, + Context.NF_PIPE_HPC.value, + Context.NF_INFRA_LOCAL.value, + Context.NF_INFRA_HPC.value, + Context.CUSTOM_PIPE_LOCAL.value, + Context.CUSTOM_PIPE_HPC.value, + Context.CUSTOM_INFRA_LOCAL.value, + Context.CUSTOM_INFRA_HPC.value, + ]: + # Should succeed + check_config(cfg_valid_abs, fail=False, ctx=ctx) + check_config(cfg_valid_home, fail=False, ctx=ctx) + check_config(cfg_valid_env, fail=False, ctx=ctx) + check_config(cfg_empty, fail=False, ctx=ctx) + # Should fail + check_config(cfg_invalid_rel, fail=True, ctx=ctx) + + +def test_igenomes(): + cfg_valid_abs = {"igenomes_cachedir": "/an/absolute/path"} + cfg_valid_home = {"igenomes_cachedir": "~/a/path/in/home"} + cfg_valid_env = {"igenomes_cachedir": "${SOME}/env/prefixed/path"} + cfg_valid_s3 = {"igenomes_cachedir": "s3://some/s3/bucket"} + cfg_empty = {"igenomes_cachedir": ""} + cfg_invalid_rel = {"igenomes_cachedir": "a/relative/path"} + + # Test all contexts + for ctx in [ + Context.NF_PIPE_LOCAL.value, + Context.NF_PIPE_HPC.value, + Context.NF_INFRA_LOCAL.value, + Context.NF_INFRA_HPC.value, + Context.CUSTOM_PIPE_LOCAL.value, + Context.CUSTOM_PIPE_HPC.value, + Context.CUSTOM_INFRA_LOCAL.value, + Context.CUSTOM_INFRA_HPC.value, + ]: + # Should succeed + check_config(cfg_valid_abs, fail=False, ctx=ctx) + check_config(cfg_valid_home, fail=False, ctx=ctx) + check_config(cfg_valid_env, fail=False, ctx=ctx) + check_config(cfg_empty, fail=False, ctx=ctx) + check_config(cfg_valid_s3, fail=False, ctx=ctx) + # Should fail + check_config(cfg_invalid_rel, fail=True, ctx=ctx) + + +def test_queue_stat_int(): + cfg_valid = {"queue_stat_interval": "2"} + cfg_valid_float = {"queue_stat_interval": "1.2"} + cfg_invalid_zero = {"queue_stat_interval": "0"} + cfg_invalid_str = {"queue_stat_interval": "hello"} + cfg_invalid_neg = {"queue_stat_interval": "-2"} + cfg_empty = {"queue_stat_interval": ""} + + # Test all INFRA_HPC contexts + for ctx in [ + Context.NF_INFRA_HPC.value, + Context.CUSTOM_INFRA_HPC.value, + ]: + # Should succeed + check_config(cfg_valid, fail=False, ctx=ctx) + check_config(cfg_valid_float, fail=False, ctx=ctx) + check_config(cfg_empty, fail=False, ctx=ctx) + # Shoudl fail + check_config(cfg_invalid_zero, fail=True, ctx=ctx) + check_config(cfg_invalid_str, fail=True, ctx=ctx) + check_config(cfg_invalid_neg, fail=True, ctx=ctx) + + # Test all PIPE and INFRA_LOCAL contexts + for ctx in [ + Context.NF_INFRA_LOCAL.value, + Context.NF_PIPE_LOCAL.value, + Context.NF_PIPE_HPC.value, + Context.CUSTOM_INFRA_LOCAL.value, + Context.CUSTOM_PIPE_LOCAL.value, + Context.CUSTOM_PIPE_HPC.value, + ]: + # Should succeed + check_config(cfg_valid, fail=False, ctx=ctx) + check_config(cfg_valid_float, fail=False, ctx=ctx) + check_config(cfg_invalid_zero, fail=False, ctx=ctx) + check_config(cfg_invalid_str, fail=False, ctx=ctx) + check_config(cfg_invalid_neg, fail=False, ctx=ctx) + check_config(cfg_empty, fail=False, ctx=ctx) + + +def test_queue_size_submit_rate(): + for field in [ + "queue_size", + "submit_rate", + ]: + cfg_valid = {field: "2"} + cfg_invalid_str = {field: "hello"} + cfg_invalid_float = {field: "1.2"} + cfg_invalid_zero = {field: "0"} + cfg_invalid_neg = {field: "-2"} + cfg_empty = {field: ""} + + # Test all INFRA contexts + for ctx in [ + Context.NF_INFRA_LOCAL.value, + Context.NF_INFRA_HPC.value, + Context.CUSTOM_INFRA_LOCAL.value, + Context.CUSTOM_INFRA_HPC.value, + ]: + # Should succeed + check_config(cfg_valid, fail=False, ctx=ctx) + check_config(cfg_empty, fail=False, ctx=ctx) + # Shoudl fail + check_config(cfg_invalid_str, fail=True, ctx=ctx) + check_config(cfg_invalid_float, fail=True, ctx=ctx) + check_config(cfg_invalid_zero, fail=True, ctx=ctx) + check_config(cfg_invalid_neg, fail=True, ctx=ctx) + + # Test all PIPE contexts + for ctx in [ + Context.NF_PIPE_LOCAL.value, + Context.NF_PIPE_HPC.value, + Context.CUSTOM_PIPE_LOCAL.value, + Context.CUSTOM_PIPE_HPC.value, + ]: + # Should succeed + check_config(cfg_valid, fail=False, ctx=ctx) + check_config(cfg_invalid_str, fail=False, ctx=ctx) + check_config(cfg_invalid_float, fail=False, ctx=ctx) + check_config(cfg_invalid_zero, fail=False, ctx=ctx) + check_config(cfg_invalid_neg, fail=False, ctx=ctx) + check_config(cfg_empty, fail=False, ctx=ctx) + + +def test_poll_int(): + cfg_valid = {"poll_interval": "2"} + cfg_valid_float = {"poll_interval": "1.2"} + cfg_invalid_zero = {"poll_interval": "0"} + cfg_invalid_str = {"poll_interval": "hello"} + cfg_invalid_neg = {"poll_interval": "-2"} + cfg_empty = {"poll_interval": ""} + + # Test all INFRA contexts + for ctx in [ + Context.NF_INFRA_LOCAL.value, + Context.NF_INFRA_HPC.value, + Context.CUSTOM_INFRA_LOCAL.value, + Context.CUSTOM_INFRA_HPC.value, + ]: + # Should succeed + check_config(cfg_valid, fail=False, ctx=ctx) + check_config(cfg_valid_float, fail=False, ctx=ctx) + check_config(cfg_empty, fail=False, ctx=ctx) + # Shoudl fail + check_config(cfg_invalid_zero, fail=True, ctx=ctx) + check_config(cfg_invalid_str, fail=True, ctx=ctx) + check_config(cfg_invalid_neg, fail=True, ctx=ctx) + + # Test all PIPE contexts + for ctx in [ + Context.NF_PIPE_LOCAL.value, + Context.NF_PIPE_HPC.value, + Context.CUSTOM_PIPE_LOCAL.value, + Context.CUSTOM_PIPE_HPC.value, + ]: + # Should succeed + check_config(cfg_valid, fail=False, ctx=ctx) + check_config(cfg_valid_float, fail=False, ctx=ctx) + check_config(cfg_invalid_zero, fail=False, ctx=ctx) + check_config(cfg_invalid_str, fail=False, ctx=ctx) + check_config(cfg_invalid_neg, fail=False, ctx=ctx) + check_config(cfg_empty, fail=False, ctx=ctx) diff --git a/tests/test_configs.py b/tests/test_configs.py new file mode 100644 index 0000000000..6bca8e487a --- /dev/null +++ b/tests/test_configs.py @@ -0,0 +1,175 @@ +INFRA_SINGULARITY_CONFIG = """\ +params { + config_profile_contact = 'my name (@myhandle)' + config_profile_description = 'A cool description' + config_profile_url = 'https://example.com' + igenomes_base = '/data/igenomes/cache' +} +executor { + queueStatInterval = '0.75m' + queueSize = 200 + pollInterval = '0.25m' + submitRateLimit = '25min' +} +process { + executor = 'pbspro' + queue = 'myqueue' + resourceLimits = [cpus: 48, memory: '128.0GB', time: '9.5h'] + scratch = '/tmp/scratch' + maxRetries = 2 +} +singularity { + enabled = true + cacheDir = '/singularity/cachedir' + autoMounts = true +} +cleanup = true +""" + +INFRA_CUSTOM_SINGULARITY_CONFIG = """\ +params { + config_profile_description = 'A cool description' +} +executor { + queueStatInterval = '0.75m' + queueSize = 200 + pollInterval = '0.25m' + submitRateLimit = '25min' +} +process { + executor = 'pbspro' + queue = 'myqueue' + resourceLimits = [cpus: 48, memory: '128.0GB', time: '9.5h'] + scratch = '/tmp/scratch' + maxRetries = 2 +} +singularity { + enabled = true + cacheDir = '/singularity/cachedir' + autoMounts = true +} +cleanup = true +""" + +PIPE_NFCORE_CONFIG = """\ +params { + config_profile_contact = 'my name (@myhandle)' + config_profile_description = 'A cool description' + config_profile_url = 'https://example.com' +} +process { + cpus = 2 + memory = '8.0GB' + time = '9.5h' + withName: 'SOME:PROC.NAME*' { + cpus = 3 + memory = '4.0GB' + time = '5.5h' + } + withName: 'ANOTHER:PROC_NAME' { + cpus = 2 + memory = '3.0GB' + time = '4.4h' + queue = 'customqueue' + } + withLabel: 'some_proc_label' { + cpus = 1 + memory = '1.0GB' + time = '1.1h' + } + withLabel: 'another_label' { + cpus = 2 + memory = '2.0GB' + time = '2.2h' + queue = 'customqueue' + } + withLabel: 'a_third_label' { + } + withLabel: 'fourth_label' { + cpus = 4 + time = '4.4h' + queue = 'anotherqueue' + } +} +""" + +PIPE_CUSTOM_CONFIG = """\ +params { + config_profile_description = 'A cool description' +} +process { + cpus = 2 + memory = '8.0GB' + time = '9.5h' + withName: 'some_proc' { + cpus = 3 + memory = '4.0GB' + time = '5.5h' + } + withName: 'another_proc' { + cpus = 2 + memory = '3.0GB' + time = '4.4h' + queue = 'customqueue' + } + withLabel: 'some_proc_label' { + cpus = 1 + memory = '1.0GB' + time = '1.1h' + } + withLabel: 'another_label' { + cpus = 2 + memory = '2.0GB' + time = '2.2h' + queue = 'customqueue' + } + withLabel: 'a_third_label' { + } + withLabel: 'fourth_label' { + cpus = 4 + time = '4.4h' + queue = 'anotherqueue' + } +} +""" + +INFRA_NFCORE_SINGULARITY_LOCAL_CONFIG = """\ +params { + config_profile_contact = 'my name (@myhandle)' + config_profile_description = 'A cool description' + config_profile_url = 'https://example.com' + igenomes_base = '/data/igenomes/cache' +} +executor { +} +process { + resourceLimits = [cpus: 8, memory: '32.0GB', time: '19.5h'] + scratch = '/tmp/scratch' + maxRetries = 2 +} +singularity { + enabled = true + cacheDir = '/singularity/cachedir' + autoMounts = true +} +cleanup = true +""" + +INFRA_CUSTOM_SINGULARITY_LOCAL_CONFIG = """\ +params { + config_profile_description = 'A cool description' +} +executor { +} +process { + resourceLimits = [cpus: 8, memory: '32.0GB', time: '19.5h'] + scratch = '/tmp/scratch' + maxRetries = 2 +} +singularity { + enabled = true + cacheDir = '/singularity/cachedir' + autoMounts = true +} +cleanup = true +"""