From ba91a902542b2f5b16ac24478eb394be5c9cf6ef Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 12:07:21 +0100 Subject: [PATCH 01/42] Bump NXF_VER to 26.04.4 in devcontainers [skip ci] --- .devcontainer/codespaces-dev/devcontainer.json | 2 +- .devcontainer/devcontainer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.devcontainer/codespaces-dev/devcontainer.json b/.devcontainer/codespaces-dev/devcontainer.json index 84812c4ccf..1a2d92eddf 100644 --- a/.devcontainer/codespaces-dev/devcontainer.json +++ b/.devcontainer/codespaces-dev/devcontainer.json @@ -32,7 +32,7 @@ // Nextflow installation version "NXF_HOME": "/workspaces/.nextflow", "NXF_EDGE": "0", - "NXF_VER": "25.10.4", + "NXF_VER": "26.04.4", "NXF_SYNTAX_PARSER": "v2", // Other env vars "HOST_PROJECT_PATH": "/workspaces/training", diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index fa99bfe859..cb7b6794ab 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -12,7 +12,7 @@ // Nextflow installation version "NXF_HOME": "/workspaces/.nextflow", "NXF_EDGE": "0", - "NXF_VER": "25.10.4", + "NXF_VER": "26.04.4", "NXF_SYNTAX_PARSER": "v2", // Other env vars "HOST_PROJECT_PATH": "/workspaces/training", From 6d21f0d6e7500b0e40037fd0a8472683e2176f51 Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 12:09:42 +0100 Subject: [PATCH 02/42] docs: reflect v2 parser as default from Nextflow 26.04 in version notes [skip ci] --- docs/en/docs/info/nxf_versions.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/en/docs/info/nxf_versions.md b/docs/en/docs/info/nxf_versions.md index 50fc3899df..8e69b27f23 100644 --- a/docs/en/docs/info/nxf_versions.md +++ b/docs/en/docs/info/nxf_versions.md @@ -11,11 +11,12 @@ hide: As of version 3.0 of the training portal, all our training courses are compatible with Nextflow version 25.10.2 or later unless otherwise specified on the course index page. (This does not include deprecated or otherwise archived materials which may not have a version notice). -The version of Nextflow currently loaded by default in our training environment is **Nextflow 25.10.4**. +The version of Nextflow currently loaded by default in our training environment is **Nextflow 26.04.4**. Because the courses now use typed inputs at the workflow level as well as workflow-level output directives, they require the use of the V2 syntax parser, **unless otherwise specified**. +The V2 parser is the default from Nextflow 26.04 onward, so on the version we load you don't need to enable it manually. If you plan to use the environment we provide through [Github Codespaces](../envsetup/01_setup.md) or [local devcontainers](../envsetup/03_devcontainer.md), you don't need to do anything unless specifically noted in the course instructions. -However, if you are planning to work through the trainings in your own environment ([Manual install](../envsetup/02_local.md)), you will need to make sure to use Nextflow version 25.10.2 or later with the v2 syntax parser enabled. +However, if you are planning to work through the trainings in your own environment ([Manual install](../envsetup/02_local.md)), you will need to make sure to use Nextflow version 25.10.2 or later, and to enable the v2 syntax parser if you are on a version before 26.04. ## Older versions of the training materials @@ -38,7 +39,7 @@ All modern Nextflow code uses DSL2. The v1 parser is the original, more permissive parser. The v2 parser is stricter and enables new language features such as static typing (typed inputs and outputs) and workflow-level output directives. The v2 parser also provides better error messages and catches more errors at parse time rather than at runtime. -The v2 parser will become the default in Nextflow 26.04. +The v2 parser is the default from Nextflow 26.04 onward. In summary: DSL2 is the language you write; the syntax parser version determines how strictly that language is interpreted and what advanced features are available. @@ -50,21 +51,22 @@ For more information about how to update your version of Nextflow, please see th ### Enabling the v2 syntax parser +From Nextflow 26.04 onward the v2 parser is the default, so the steps below are only needed on versions before 26.04. + To **enable** the v2 syntax parser for your current session, run the following command in your terminal: ```bash export NXF_SYNTAX_PARSER=v2 ``` -To make this permanent (pending v2 becoming the default in Nextflow 26.04), add the export command to your shell profile (`~/.bashrc`, `~/.zshrc`, etc.): +To make this permanent, add the export command to your shell profile (`~/.bashrc`, `~/.zshrc`, etc.): ```bash echo 'export NXF_SYNTAX_PARSER=v2' >> ~/.bashrc source ~/.bashrc ``` -Note that the `NXF_SYNTAX_PARSER=v2` environment variable is a temporary requirement. -From Nextflow 26.04 onward, the v2 parser will become the default and this setting will no longer be needed. +Note that on Nextflow versions before 26.04 the `NXF_SYNTAX_PARSER=v2` environment variable is required to access the v2 features used in these courses. ### Disabling the v2 syntax parser From 673bd79022730577d1da0db9ea7b226e94dcfd2d Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 12:30:33 +0100 Subject: [PATCH 03/42] docs(hello_nextflow): refresh tutorial output for Nextflow 26.04 [skip ci] --- docs/en/docs/hello_nextflow/01_hello_world.md | 82 +++++++-- .../docs/hello_nextflow/02_hello_channels.md | 125 ++++++++++--- .../docs/hello_nextflow/03_hello_workflow.md | 89 +++++++-- .../docs/hello_nextflow/04_hello_modules.md | 37 ++-- .../hello_nextflow/05_hello_containers.md | 57 ++++-- .../en/docs/hello_nextflow/06_hello_config.md | 174 ++++++++++++------ 6 files changed, 415 insertions(+), 149 deletions(-) diff --git a/docs/en/docs/hello_nextflow/01_hello_world.md b/docs/en/docs/hello_nextflow/01_hello_world.md index f9fa616ebe..02eed42d53 100644 --- a/docs/en/docs/hello_nextflow/01_hello_world.md +++ b/docs/en/docs/hello_nextflow/01_hello_world.md @@ -213,9 +213,9 @@ nextflow run hello-world.nf ??? success "Command output" ```console hl_lines="6" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-world.nf` [goofy_torvalds] DSL2 - revision: c33d41f479 + Launching `hello-world.nf` [goofy_torvalds] revision: c33d41f479 executor > local (1) [65/7be2fa] sayHello | 1 of 1 ✔ @@ -484,17 +484,23 @@ nextflow run hello-world.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-world.nf` [jovial_mayer] DSL2 - revision: 35bd3425e5 + Launching `hello-world.nf` [jovial_mayer] revision: 35bd3425e5 executor > local (1) [9f/48ef97] sayHello | 1 of 1 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/results + + first_output: output.txt ``` -The terminal output should look familiar. Externally, nothing has changed. +The terminal output now ends with an `Outputs:` summary listing the published outputs and the directory they were written to. -However, check your file explorer: this time, Nextflow has created a new directory called `results/`. +Check your file explorer: this time, Nextflow has also created a new directory called `results/`. ??? abstract "Directory contents" @@ -572,12 +578,18 @@ nextflow run hello-world.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-world.nf` [tiny_shaw] DSL2 - revision: 757723adc1 + Launching `hello-world.nf` [tiny_shaw] revision: 757723adc1 executor > local (1) - [8c/79499c] process > sayHello [100%] 1 of 1 ✔ + [8c/79499c] sayHello | 1 of 1 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/results + + first_output: hello_world/output.txt ``` This time the result gets written under the specified subdirectory. @@ -651,12 +663,18 @@ nextflow run hello-world.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-world.nf` [tiny_shaw] DSL2 - revision: 757723adc1 + Launching `hello-world.nf` [tiny_shaw] revision: 757723adc1 executor > local (1) - [df/521638] process > sayHello [100%] 1 of 1 ✔ + [df/521638] sayHello | 1 of 1 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/results + + first_output: hello_world/output.txt ``` This time, if you look at the results, the file is a proper copy instead of just a symlink. @@ -835,12 +853,18 @@ nextflow run hello-world.nf --input 'Bonjour le monde!' ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-world.nf` [elated_lavoisier] DSL2 - revision: 7c031b42ea + Launching `hello-world.nf` [elated_lavoisier] revision: 7c031b42ea executor > local (1) [4b/654319] sayHello | 1 of 1 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/results + + first_output: hello_world/output.txt ``` If you made all these edits correctly, you should get another successful execution. @@ -904,12 +928,18 @@ nextflow run hello-world.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-world.nf` [determined_edison] DSL2 - revision: 3539118582 + Launching `hello-world.nf` [determined_edison] revision: 3539118582 executor > local (1) [72/394147] sayHello | 1 of 1 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/results + + first_output: hello_world/output.txt ``` ??? question "If it didn't work" @@ -963,12 +993,18 @@ nextflow run hello-world.nf --input 'Konnichiwa!' ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-world.nf` [elegant_faraday] DSL2 - revision: 3539118582 + Launching `hello-world.nf` [elegant_faraday] revision: 3539118582 executor > local (1) [6f/a12a91] sayHello | 1 of 1 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/results + + first_output: hello_world/output.txt ``` Once again, you should find the corresponding updated output in your results directory. @@ -1026,11 +1062,17 @@ nextflow run hello-world.nf -resume ??? success "Command output" ```console hl_lines="5" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-world.nf` [golden_cantor] DSL2 - revision: 35bd3425e5 + Launching `hello-world.nf` [golden_cantor] revision: 35bd3425e5 [62/49a1f8] sayHello | 1 of 1, cached: 1 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/results + + first_output: hello_world/output.txt ``` The console output should look familiar, but there's one thing that's a little different compared to before. diff --git a/docs/en/docs/hello_nextflow/02_hello_channels.md b/docs/en/docs/hello_nextflow/02_hello_channels.md index ae46e392e2..f0694b5389 100644 --- a/docs/en/docs/hello_nextflow/02_hello_channels.md +++ b/docs/en/docs/hello_nextflow/02_hello_channels.md @@ -50,12 +50,18 @@ nextflow run hello-channels.nf --input 'Hello Channels!' ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-channels.nf` [wise_jennings] DSL2 - revision: b24f4902d6 + Launching `hello-channels.nf` [wise_jennings] revision: b24f4902d6 executor > local (1) - [6f/824bc1] process > sayHello [100%] 1 of 1 ✔ + [6f/824bc1] sayHello | 1 of 1 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/results + + first_output: hello_channels/output.txt ``` As previously, you will find the output file named `output.txt` in the `results/hello_channels` directory (as specified in the `output` block of the workflow script, shown above). @@ -194,12 +200,19 @@ nextflow run hello-channels.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-channels.nf` [fabulous_crick] DSL2 - revision: 23e20f76e8 + Launching `hello-channels.nf` [fabulous_crick] revision: 23e20f76e8 executor > local (1) - [c0/4f1872] process > sayHello (1) [100%] 1 of 1 ✔ + [c0/4f1872] sayHello (1) | 1 of 1 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/results + + first_output: + - hello_channels/output.txt ``` If you made both edits correctly, you should get a successful execution. @@ -269,13 +282,20 @@ nextflow run hello-channels.nf ??? success "Command output" ```console hl_lines="7" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-channels.nf` [scruffy_shaw] DSL2 - revision: 2ede41e14a + Launching `hello-channels.nf` [scruffy_shaw] revision: 2ede41e14a executor > local (1) - [ef/f7e40a] sayHello (1) [100%] 1 of 1 ✔ + [ef/f7e40a] sayHello (1) | 1 of 1 ✔ Hello Channels! + + Outputs: + + /workspaces/training/hello-nextflow/results + + first_output: + - hello_channels/output.txt ``` As you can see, this outputs the channel contents to the console. @@ -335,15 +355,24 @@ nextflow run hello-channels.nf ??? success "Command output" ```console hl_lines="6" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-channels.nf` [amazing_crick] DSL2 - revision: 59a9a5888a + Launching `hello-channels.nf` [amazing_crick] revision: 59a9a5888a executor > local (3) - [f4/c9962c] process > sayHello (1) [100%] 3 of 3 ✔ + [f4/c9962c] sayHello (1) | 3 of 3 ✔ Hello Bonjour Hola + + Outputs: + + /workspaces/training/hello-nextflow/results + + first_output: + - hello_channels/output.txt + - hello_channels/output.txt + - hello_channels/output.txt ``` It certainly seems to have run just fine. @@ -418,14 +447,23 @@ nextflow run hello-channels.nf -ansi-log false ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 - Launching `hello-channels.nf` [desperate_monod] DSL2 - revision: 59a9a5888a + N E X T F L O W ~ version 26.04.4 + Launching `hello-channels.nf` [desperate_monod] - revision: 59a9a5888a Hello Bonjour Hola [23/871c7e] Submitted process > sayHello (2) [7f/21e2c2] Submitted process > sayHello (1) [f4/ea10a6] Submitted process > sayHello (3) + + Outputs: + + /workspaces/training/hello-nextflow/results + + first_output: + - hello_channels/output.txt + - hello_channels/output.txt + - hello_channels/output.txt ``` This time we see all three process runs and their associated work subdirectories listed in the output. @@ -579,15 +617,24 @@ nextflow run hello-channels.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-channels.nf` [sharp_minsky] DSL2 - revision: 16a291febe + Launching `hello-channels.nf` [sharp_minsky] revision: 16a291febe executor > local (3) - [e8/33ee64] sayHello (2) [100%] 3 of 3 ✔ + [e8/33ee64] sayHello (2) | 3 of 3 ✔ Hello Bonjour Hola + + Outputs: + + /workspaces/training/hello-nextflow/results + + first_output: + - hello_channels/Bonjour-output.txt + - hello_channels/Hola-output.txt + - hello_channels/Hello-output.txt ``` Reverting back to the summary view, the output is summarized on one line again. @@ -759,9 +806,9 @@ nextflow run hello-channels.nf ??? failure "Command output" ```console hl_lines="7 11 16" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-channels.nf` [friendly_koch] DSL2 - revision: 97256837a7 + Launching `hello-channels.nf` [friendly_koch] revision: 97256837a7 executor > local (1) [a8/1f6ead] sayHello (1) | 0 of 1 @@ -939,16 +986,25 @@ nextflow run hello-channels.nf ??? success "Command output" ```console hl_lines="7-10" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-channels.nf` [sleepy_gutenberg] DSL2 - revision: 1db4f760ee + Launching `hello-channels.nf` [sleepy_gutenberg] revision: 1db4f760ee executor > local (3) - [b1/6a1e15] sayHello (2) [100%] 3 of 3 ✔ + [b1/6a1e15] sayHello (2) | 3 of 3 ✔ Before flatten: [Hello, Bonjour, Hola] After flatten: Hello After flatten: Bonjour After flatten: Hola + + Outputs: + + /workspaces/training/hello-nextflow/results + + first_output: + - hello_channels/Bonjour-output.txt + - hello_channels/Hola-output.txt + - hello_channels/Hello-output.txt ``` This time it works AND gives us the additional insight into what the contents of the channel look like before and after we run the `flatten()` operator. @@ -1093,9 +1149,9 @@ nextflow run hello-channels.nf ??? failure "Command output" ```console hl_lines="5 6 9 15" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-channels.nf` [peaceful_poisson] DSL2 - revision: a286c08ad5 + Launching `hello-channels.nf` [peaceful_poisson] revision: a286c08ad5 [- ] sayHello [ 0%] 0 of 1 Before flatten: /workspaces/training/hello-nextflow/data/greetings.csv @@ -1196,12 +1252,12 @@ nextflow run hello-channels.nf ??? failure "Command output" ```console hl_lines="7-11 14 19" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-channels.nf` [insane_fermat] DSL2 - revision: 8e62fcbeb1 + Launching `hello-channels.nf` [insane_fermat] revision: 8e62fcbeb1 executor > local (3) - [24/76da2f] sayHello (2) [ 0%] 0 of 3 ✘ + [24/76da2f] sayHello (2) | 0 of 3 ✘ Before splitCsv: /workspaces/training/hello-nextflow/data/greetings.csv After splitCsv: [Hello, English, 123] After splitCsv: [Bonjour, French, 456] @@ -1316,12 +1372,12 @@ nextflow run hello-channels.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-channels.nf` [focused_volhard] DSL2 - revision: de435e45be + Launching `hello-channels.nf` [focused_volhard] revision: de435e45be executor > local (3) - [54/6eebe3] sayHello (3) [100%] 3 of 3 ✔ + [54/6eebe3] sayHello (3) | 3 of 3 ✔ Before splitCsv: /workspaces/training/hello-nextflow/data/greetings.csv After splitCsv: [Hello, English, 123] After splitCsv: [Bonjour, French, 456] @@ -1329,6 +1385,15 @@ nextflow run hello-channels.nf After map: Hello After map: Bonjour After map: Hola + + Outputs: + + /workspaces/training/hello-nextflow/results + + first_output: + - hello_channels/Hola-output.txt + - hello_channels/Bonjour-output.txt + - hello_channels/Hello-output.txt ``` This time it should run without error. diff --git a/docs/en/docs/hello_nextflow/03_hello_workflow.md b/docs/en/docs/hello_nextflow/03_hello_workflow.md index 1d8a240910..13159446da 100644 --- a/docs/en/docs/hello_nextflow/03_hello_workflow.md +++ b/docs/en/docs/hello_nextflow/03_hello_workflow.md @@ -65,12 +65,21 @@ nextflow run hello-workflow.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-workflow.nf` [admiring_lamarr] DSL2 - revision: 4d4053520d + Launching `hello-workflow.nf` [admiring_lamarr] revision: 4d4053520d executor > local (3) - [b1/5826b5] process > sayHello (2) [100%] 3 of 3 ✔ + [b1/5826b5] sayHello (2) | 3 of 3 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/results + + first_output: + - hello_workflow/Bonjour-output.txt + - hello_workflow/Hello-output.txt + - hello_workflow/Hola-output.txt ``` As previously, you will find the output files in the location specified in the `output` block. @@ -309,13 +318,26 @@ nextflow run hello-workflow.nf -resume ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-workflow.nf` [high_cantor] DSL2 - revision: d746983511 + Launching `hello-workflow.nf` [high_cantor] revision: d746983511 executor > local (3) - [ab/816321] process > sayHello (3) [100%] 3 of 3, cached: 3 ✔ - [e0/ecf81b] process > convertToUpper (3) [100%] 3 of 3 ✔ + [ab/816321] sayHello (3) | 3 of 3, cached: 3 ✔ + [e0/ecf81b] convertToUpper (3) | 3 of 3 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/results + + first_output: + - hello_workflow/Hello-output.txt + - hello_workflow/Hola-output.txt + - hello_workflow/Bonjour-output.txt + uppercased: + - hello_workflow/UPPER-Hola-output.txt + - hello_workflow/UPPER-Hello-output.txt + - hello_workflow/UPPER-Bonjour-output.txt ``` There is now an extra line in the console output that corresponds to the new process we just added. @@ -606,9 +628,9 @@ nextflow run hello-workflow.nf -resume ??? success "Command output" ```console hl_lines="8" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-workflow.nf` [mad_gilbert] DSL2 - revision: 6acfd5e28d + Launching `hello-workflow.nf` [mad_gilbert] revision: 6acfd5e28d executor > local (3) [79/33b2f0] sayHello (2) | 3 of 3, cached: 3 ✔ @@ -616,6 +638,8 @@ nextflow run hello-workflow.nf -resume [47/50fe4a] collectGreetings (1) | 3 of 3 ✔ ``` + The terminal output now also ends with an `Outputs:` summary block. We've omitted it here to focus on the process status lines. + It runs successfully, including the third step. However, look at the number of calls for `collectGreetings()` on the last line. @@ -705,9 +729,9 @@ nextflow run hello-workflow.nf -resume ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-workflow.nf` [soggy_franklin] DSL2 - revision: bc8e1b2726 + Launching `hello-workflow.nf` [soggy_franklin] revision: bc8e1b2726 [d6/cdf466] sayHello (1) | 3 of 3, cached: 3 ✔ [99/79394f] convertToUpper (2) | 3 of 3, cached: 3 ✔ @@ -938,14 +962,28 @@ nextflow run hello-workflow.nf -resume --batch trio ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-workflow.nf` [confident_rutherford] DSL2 - revision: bc58af409c + Launching `hello-workflow.nf` [confident_rutherford] revision: bc58af409c executor > local (1) [79/33b2f0] sayHello (2) | 3 of 3, cached: 3 ✔ [99/79394f] convertToUpper (2) | 3 of 3, cached: 3 ✔ [b5/f19efe] collectGreetings | 1 of 1 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/results + + first_output: + - hello_workflow/Bonjour-output.txt + - hello_workflow/Hello-output.txt + - hello_workflow/Hola-output.txt + uppercased: + - hello_workflow/UPPER-Bonjour-output.txt + - hello_workflow/UPPER-Hola-output.txt + - hello_workflow/UPPER-Hello-output.txt + collected: hello_workflow/COLLECTED-trio-output.txt ``` It runs successfully and produces the desired output: @@ -1154,14 +1192,29 @@ nextflow run hello-workflow.nf -resume --batch trio ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-workflow.nf` [ecstatic_wilson] DSL2 - revision: c80285f8c8 + Launching `hello-workflow.nf` [ecstatic_wilson] revision: c80285f8c8 executor > local (1) - [c5/4c6ca9] sayHello (3) [100%] 3 of 3, cached: 3 ✔ - [0e/6cbc59] convertToUpper (3) [100%] 3 of 3, cached: 3 ✔ - [02/61ead2] collectGreetings [100%] 1 of 1 ✔ + [c5/4c6ca9] sayHello (3) | 3 of 3, cached: 3 ✔ + [0e/6cbc59] convertToUpper (3) | 3 of 3, cached: 3 ✔ + [02/61ead2] collectGreetings | 1 of 1 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/results + + first_output: + - hello_workflow/Bonjour-output.txt + - hello_workflow/Hello-output.txt + - hello_workflow/Hola-output.txt + uppercased: + - hello_workflow/UPPER-Bonjour-output.txt + - hello_workflow/UPPER-Hola-output.txt + - hello_workflow/UPPER-Hello-output.txt + collected: hello_workflow/COLLECTED-trio-output.txt + batch_report: hello_workflow/trio-report.txt ``` If you look in the `results/hello_workflow/` directory, you'll find the new report file, `trio-report.txt`. diff --git a/docs/en/docs/hello_nextflow/04_hello_modules.md b/docs/en/docs/hello_nextflow/04_hello_modules.md index 0128d2dc66..eeb4d62863 100644 --- a/docs/en/docs/hello_nextflow/04_hello_modules.md +++ b/docs/en/docs/hello_nextflow/04_hello_modules.md @@ -67,14 +67,29 @@ nextflow run hello-modules.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-modules.nf` [hopeful_avogadro] DSL2 - revision: b09af1237d + Launching `hello-modules.nf` [hopeful_avogadro] revision: b09af1237d executor > local (7) - [0f/8795c9] sayHello (3) [100%] 3 of 3 ✔ - [6a/eb2510] convertToUpper (3) [100%] 3 of 3 ✔ - [af/479117] collectGreetings [100%] 1 of 1 ✔ + [0f/8795c9] sayHello (3) | 3 of 3 ✔ + [6a/eb2510] convertToUpper (3) | 3 of 3 ✔ + [af/479117] collectGreetings | 1 of 1 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/results + + first_output: + - hello_modules/Hola-output.txt + - hello_modules/Bonjour-output.txt + - hello_modules/Hello-output.txt + uppercased: + - hello_modules/UPPER-Hola-output.txt + - hello_modules/UPPER-Bonjour-output.txt + - hello_modules/UPPER-Hello-output.txt + collected: hello_modules/COLLECTED-batch-output.txt + batch_report: hello_modules/batch-report.txt ``` As previously, you will find the output files in the directory specified in the `output` block (here, `results/hello_modules/`). @@ -200,9 +215,9 @@ nextflow run hello-modules.nf -resume ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-modules.nf` [romantic_poisson] DSL2 - revision: 96edfa9ad3 + Launching `hello-modules.nf` [romantic_poisson] revision: 96edfa9ad3 [f6/cc0107] sayHello (1) | 3 of 3, cached: 3 ✔ [3c/4058ba] convertToUpper (2) | 3 of 3, cached: 3 ✔ @@ -309,9 +324,9 @@ nextflow run hello-modules.nf -resume ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-modules.nf` [nauseous_heisenberg] DSL2 - revision: a04a9f2da0 + Launching `hello-modules.nf` [nauseous_heisenberg] revision: a04a9f2da0 [c9/763d42] sayHello (3) | 3 of 3, cached: 3 ✔ [60/bc6831] convertToUpper (3) | 3 of 3, cached: 3 ✔ @@ -413,9 +428,9 @@ nextflow run hello-modules.nf -resume ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-modules.nf` [friendly_coulomb] DSL2 - revision: 7aa2b9bc0f + Launching `hello-modules.nf` [friendly_coulomb] revision: 7aa2b9bc0f [f6/cc0107] sayHello (1) | 3 of 3, cached: 3 ✔ [3c/4058ba] convertToUpper (2) | 3 of 3, cached: 3 ✔ diff --git a/docs/en/docs/hello_nextflow/05_hello_containers.md b/docs/en/docs/hello_nextflow/05_hello_containers.md index c35516585f..f717afbc1a 100644 --- a/docs/en/docs/hello_nextflow/05_hello_containers.md +++ b/docs/en/docs/hello_nextflow/05_hello_containers.md @@ -70,15 +70,29 @@ nextflow run hello-containers.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-containers.nf` [nice_escher] DSL2 - revision: d5dfdc9872 + Launching `hello-containers.nf` [nice_escher] revision: d5dfdc9872 - executor > local (7) - [5a/ec1fa1] sayHello (2) [100%] 3 of 3 ✔ - [30/32b5b8] convertToUpper (3) [100%] 3 of 3 ✔ - [d3/be01bc] collectGreetings [100%] 1 of 1 ✔ + executor > local (7) + [5a/ec1fa1] sayHello (2) | 3 of 3 ✔ + [30/32b5b8] convertToUpper (3) | 3 of 3 ✔ + [d3/be01bc] collectGreetings | 1 of 1 ✔ + Outputs: + + /workspaces/training/hello-nextflow/results + + first_output: + - hello_containers/Hola-output.txt + - hello_containers/Bonjour-output.txt + - hello_containers/Hello-output.txt + uppercased: + - hello_containers/UPPER-Bonjour-output.txt + - hello_containers/UPPER-Hola-output.txt + - hello_containers/UPPER-Hello-output.txt + collected: hello_containers/COLLECTED-batch-output.txt + batch_report: hello_containers/batch-report.txt ``` As previously, you will find the output files in the directory specified in the `output` block (`results/hello_containers/`). @@ -672,15 +686,15 @@ nextflow run hello-containers.nf -resume ??? failure "Command output (edited for clarity)" ```console hl_lines="10 13 20-21 26-27" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-containers.nf` [lonely_woese] DSL2 - revision: abf1dccf7f + Launching `hello-containers.nf` [lonely_woese] revision: abf1dccf7f executor > local (1) - [c9/f5c686] sayHello (3) [100%] 3 of 3, cached: 3 ✔ - [ef/3135a8] convertToUpper (3) [100%] 3 of 3, cached: 3 ✔ - [7f/f435e3] collectGreetings [100%] 1 of 1, cached: 1 ✔ - [9b/02e776] cowpy [ 0%] 0 of 1 ✘ + [c9/f5c686] sayHello (3) | 3 of 3, cached: 3 ✔ + [ef/3135a8] convertToUpper (3) | 3 of 3, cached: 3 ✔ + [7f/f435e3] collectGreetings | 1 of 1, cached: 1 ✔ + [9b/02e776] cowpy | 0 of 1 ✘ ERROR ~ Error executing process > 'cowpy' Caused by: @@ -809,15 +823,22 @@ nextflow run hello-containers.nf -resume ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-containers.nf` [drunk_perlman] DSL2 - revision: abf1dccf7f + Launching `hello-containers.nf` [drunk_perlman] revision: abf1dccf7f executor > local (1) - [c9/f5c686] sayHello (3) [100%] 3 of 3, cached: 3 ✔ - [ef/3135a8] convertToUpper (3) [100%] 3 of 3, cached: 3 ✔ - [7f/f435e3] collectGreetings [100%] 1 of 1, cached: 1 ✔ - [98/656c6c] cowpy [100%] 1 of 1 ✔ + [c9/f5c686] sayHello (3) | 3 of 3, cached: 3 ✔ + [ef/3135a8] convertToUpper (3) | 3 of 3, cached: 3 ✔ + [7f/f435e3] collectGreetings | 1 of 1, cached: 1 ✔ + [98/656c6c] cowpy | 1 of 1 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/results + + batch_report: hello_containers/batch-report.txt + cowpy_art: hello_containers/cowpy-COLLECTED-batch-output.txt ``` This time it does indeed work! diff --git a/docs/en/docs/hello_nextflow/06_hello_config.md b/docs/en/docs/hello_nextflow/06_hello_config.md index 58e19cb5bd..3751b0e38d 100644 --- a/docs/en/docs/hello_nextflow/06_hello_config.md +++ b/docs/en/docs/hello_nextflow/06_hello_config.md @@ -75,15 +75,22 @@ nextflow run hello-config.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-config.nf` [nice_escher] DSL2 - revision: d5dfdc9872 + Launching `hello-config.nf` [nice_escher] revision: d5dfdc9872 - executor > local (7) - [6a/bc46a6] sayHello (2) [100%] 3 of 3 ✔ - [33/67bc48] convertToUpper (3) [100%] 3 of 3 ✔ - [b5/de03ba] collectGreetings [100%] 1 of 1 ✔ + executor > local (8) + [6a/bc46a6] sayHello (2) | 3 of 3 ✔ + [33/67bc48] convertToUpper (3) | 3 of 3 ✔ + [b5/de03ba] collectGreetings | 1 of 1 ✔ [98/c6b57b] cowpy | 1 of 1 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/results + + batch_report: hello_config/batch-report.txt + cowpy_art: hello_config/cowpy-COLLECTED-batch-output.txt ``` As previously, you will find the output files in the directory specified in the `output` block (`results/hello_config/`). @@ -235,15 +242,22 @@ nextflow run hello-config.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-config.nf` [disturbed_einstein] DSL2 - revision: ede9037d02 + Launching `hello-config.nf` [disturbed_einstein] revision: ede9037d02 executor > local (8) [f0/35723c] sayHello (2) | 3 of 3 ✔ [40/3efd1a] convertToUpper (3) | 3 of 3 ✔ [17/e97d32] collectGreetings | 1 of 1 ✔ [98/c6b57b] cowpy | 1 of 1 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/results + + batch_report: hello_config/batch-report.txt + cowpy_art: hello_config/cowpy-COLLECTED-batch-output.txt ``` This still produces the same output as previously. @@ -331,15 +345,22 @@ nextflow run ../hello-config.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `../hello-config.nf` [trusting_escher] DSL2 - revision: 356df0818d + Launching `../hello-config.nf` [trusting_escher] revision: 356df0818d executor > local (8) - [59/b66913] sayHello (2) [100%] 3 of 3 ✔ - [ad/f06364] convertToUpper (3) [100%] 3 of 3 ✔ - [10/714895] collectGreetings [100%] 1 of 1 ✔ - [88/3ece98] cowpy [100%] 1 of 1 ✔ + [59/b66913] sayHello (2) | 3 of 3 ✔ + [ad/f06364] convertToUpper (3) | 3 of 3 ✔ + [10/714895] collectGreetings | 1 of 1 ✔ + [88/3ece98] cowpy | 1 of 1 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/tux-run/results + + batch_report: hello_config/batch-report.txt + cowpy_art: hello_config/cowpy-COLLECTED-experiment-output.txt ``` This will create a new set of directories under `tux-run/` including `tux-run/work/` and `tux-run/results/`. @@ -417,15 +438,22 @@ nextflow run hello-config.nf -params-file test-params.yaml ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-config.nf` [disturbed_sammet] DSL2 - revision: ede9037d02 + Launching `hello-config.nf` [disturbed_sammet] revision: ede9037d02 executor > local (8) [f0/35723c] sayHello (2) | 3 of 3 ✔ [40/3efd1a] convertToUpper (3) | 3 of 3 ✔ [17/e97d32] collectGreetings | 1 of 1 ✔ [98/c6b57b] cowpy | 1 of 1 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/results + + batch_report: hello_config/yaml-report.txt + cowpy_art: hello_config/cowpy-COLLECTED-yaml-output.txt ``` The final output file should contain the stegosaurus character saying the greetings. @@ -498,15 +526,22 @@ nextflow run hello-config.nf -output-dir custom-outdir-cli/ ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-config.nf` [prickly_kay] DSL2 - revision: 32ecc4fba2 + Launching `hello-config.nf` [prickly_kay] revision: 32ecc4fba2 executor > local (8) - [9f/332636] sayHello (1) [100%] 3 of 3 ✔ - [03/a55991] convertToUpper (3) [100%] 3 of 3 ✔ - [e5/ab7893] collectGreetings [100%] 1 of 1 ✔ - [a8/97338e] cowpy [100%] 1 of 1 ✔ + [9f/332636] sayHello (1) | 3 of 3 ✔ + [03/a55991] convertToUpper (3) | 3 of 3 ✔ + [e5/ab7893] collectGreetings | 1 of 1 ✔ + [a8/97338e] cowpy | 1 of 1 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/custom-outdir-cli + + batch_report: hello_config/batch-report.txt + cowpy_art: hello_config/cowpy-COLLECTED-batch-output.txt ``` This publishes outputs to `custom-outdir-cli/` instead of `results/`: @@ -830,15 +865,22 @@ nextflow run hello-config.nf -output-dir custom-outdir-config-2 --batch rep2 ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-config.nf` [mad_curry] DSL2 - revision: 668a98ccb9 + Launching `hello-config.nf` [mad_curry] revision: 668a98ccb9 executor > local (8) - [9e/6095e0] sayHello (1) [100%] 3 of 3 ✔ - [05/454d52] convertToUpper (3) [100%] 3 of 3 ✔ - [ed/e3ddfb] collectGreetings [100%] 1 of 1 ✔ - [39/5e063a] cowpy [100%] 1 of 1 ✔ + [9e/6095e0] sayHello (1) | 3 of 3 ✔ + [05/454d52] convertToUpper (3) | 3 of 3 ✔ + [ed/e3ddfb] collectGreetings | 1 of 1 ✔ + [39/5e063a] cowpy | 1 of 1 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/custom-outdir-config-2 + + batch_report: rep2/collectGreetings/rep2-report.txt + cowpy_art: rep2/cowpy/cowpy-COLLECTED-rep2-output.txt ``` This publishes outputs to `custom-outdir-config-2/rep2/`, with the specified base path _and_ the batch name subdirectory _and_ results grouped by process: @@ -960,15 +1002,22 @@ nextflow run hello-config.nf -output-dir config-output-mode ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-config.nf` [small_stone] DSL2 - revision: 024d6361b5 + Launching `hello-config.nf` [small_stone] revision: 024d6361b5 executor > local (8) - [e8/a0e93e] sayHello (1) [100%] 3 of 3 ✔ - [14/176c9d] convertToUpper (3) [100%] 3 of 3 ✔ - [23/d667ca] collectGreetings [100%] 1 of 1 ✔ - [e6/1dc80e] cowpy [100%] 1 of 1 ✔ + [e8/a0e93e] sayHello (1) | 3 of 3 ✔ + [14/176c9d] convertToUpper (3) | 3 of 3 ✔ + [23/d667ca] collectGreetings | 1 of 1 ✔ + [e6/1dc80e] cowpy | 1 of 1 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/config-output-mode + + batch_report: batch/collectGreetings/batch-report.txt + cowpy_art: batch/cowpy/cowpy-COLLECTED-batch-output.txt ``` This publishes outputs to `config-output-mode/`, and they are still all proper copies, not symlinks. @@ -1092,15 +1141,22 @@ nextflow run hello-config.nf --batch conda ??? success "Command output" ```console title="Output" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-config.nf` [friendly_lamport] DSL2 - revision: 024d6361b5 + Launching `hello-config.nf` [friendly_lamport] revision: 024d6361b5 executor > local (8) - [e8/91c116] sayHello (2) [100%] 3 of 3 ✔ - [fe/6a70ce] convertToUpper (3) [100%] 3 of 3 ✔ - [99/7cc493] collectGreetings [100%] 1 of 1 ✔ - [3c/09fb59] cowpy [100%] 1 of 1 ✔ + [e8/91c116] sayHello (2) | 3 of 3 ✔ + [fe/6a70ce] convertToUpper (3) | 3 of 3 ✔ + [99/7cc493] collectGreetings | 1 of 1 ✔ + [3c/09fb59] cowpy | 1 of 1 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/custom-outdir-config + + batch_report: conda/collectGreetings/conda-report.txt + cowpy_art: conda/cowpy/cowpy-COLLECTED-conda-output.txt ``` This should work without issue and produce the same outputs as previously under `custom-outdir-config/conda`. @@ -1486,15 +1542,22 @@ nextflow run hello-config.nf -profile my_laptop ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-config.nf` [hungry_sanger] DSL2 - revision: 024d6361b5 + Launching `hello-config.nf` [hungry_sanger] revision: 024d6361b5 executor > local (8) - [b0/fb2ec9] sayHello (3) [100%] 3 of 3 ✔ - [4a/e039f0] convertToUpper (3) [100%] 3 of 3 ✔ - [6f/408fa9] collectGreetings [100%] 1 of 1 ✔ - [f1/fd6520] cowpy [100%] 1 of 1 ✔ + [b0/fb2ec9] sayHello (3) | 3 of 3 ✔ + [4a/e039f0] convertToUpper (3) | 3 of 3 ✔ + [6f/408fa9] collectGreetings | 1 of 1 ✔ + [f1/fd6520] cowpy | 1 of 1 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/custom-outdir-config + + batch_report: batch/collectGreetings/batch-report.txt + cowpy_art: batch/cowpy/cowpy-COLLECTED-batch-output.txt ``` As you can see, this allows us to toggle between configurations very conveniently at runtime. @@ -1570,15 +1633,22 @@ nextflow run hello-config.nf -profile my_laptop,test ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `hello-config.nf` [modest_becquerel] DSL2 - revision: 024d6361b5 + Launching `hello-config.nf` [modest_becquerel] revision: 024d6361b5 executor > local (8) - [4c/fe2580] sayHello (1) [100%] 3 of 3 ✔ - [fd/7d9017] convertToUpper (3) [100%] 3 of 3 ✔ - [13/1523bd] collectGreetings [100%] 1 of 1 ✔ - [06/a1ee14] cowpy [100%] 1 of 1 ✔ + [4c/fe2580] sayHello (1) | 3 of 3 ✔ + [fd/7d9017] convertToUpper (3) | 3 of 3 ✔ + [13/1523bd] collectGreetings | 1 of 1 ✔ + [06/a1ee14] cowpy | 1 of 1 ✔ + + Outputs: + + /workspaces/training/hello-nextflow/custom-outdir-config + + batch_report: test/collectGreetings/test-report.txt + cowpy_art: test/cowpy/cowpy-COLLECTED-test-output.txt ``` This will use Docker where possible and produce outputs under `custom-outdir-config/test`, and this time the character is the comedic duo `dragonandcow`. From 3db993b57b539f186714905cbfd287e51792aa3f Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 12:31:08 +0100 Subject: [PATCH 04/42] docs(hello_nextflow): clarify v2 parser is default from 26.04 in troubleshooting note [skip ci] --- docs/en/docs/hello_nextflow/01_hello_world.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/hello_nextflow/01_hello_world.md b/docs/en/docs/hello_nextflow/01_hello_world.md index 02eed42d53..ebb7730d83 100644 --- a/docs/en/docs/hello_nextflow/01_hello_world.md +++ b/docs/en/docs/hello_nextflow/01_hello_world.md @@ -964,7 +964,8 @@ nextflow run hello-world.nf This was mentioned at the start of the course, but maybe you missed it. Check the [Nextflow versions](../info/nxf_versions.md) help material. - In short, if you're using Nextflow `25.10` then you need to enable the v2 language parser: + The v2 parser is the default from Nextflow 26.04 onward, so you will only see this on earlier versions. + On a version before 26.04 you need to enable the v2 language parser: ```bash export NXF_SYNTAX_PARSER=v2 From bb54f7d56a0936ffb57825173e3bdf0b68aba9f8 Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 12:47:00 +0100 Subject: [PATCH 05/42] docs(hello_nextflow): correct truncated Outputs blocks with full real 26.04 output [skip ci] --- .../hello_nextflow/05_hello_containers.md | 9 ++ .../en/docs/hello_nextflow/06_hello_config.md | 93 ++++++++++++++++++- 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/hello_nextflow/05_hello_containers.md b/docs/en/docs/hello_nextflow/05_hello_containers.md index f717afbc1a..a11714d148 100644 --- a/docs/en/docs/hello_nextflow/05_hello_containers.md +++ b/docs/en/docs/hello_nextflow/05_hello_containers.md @@ -837,6 +837,15 @@ nextflow run hello-containers.nf -resume /workspaces/training/hello-nextflow/results + first_output: + - hello_containers/intermediates/Bonjour-output.txt + - hello_containers/intermediates/Hola-output.txt + - hello_containers/intermediates/Hello-output.txt + uppercased: + - hello_containers/intermediates/UPPER-Hola-output.txt + - hello_containers/intermediates/UPPER-Bonjour-output.txt + - hello_containers/intermediates/UPPER-Hello-output.txt + collected: hello_containers/intermediates/COLLECTED-batch-output.txt batch_report: hello_containers/batch-report.txt cowpy_art: hello_containers/cowpy-COLLECTED-batch-output.txt ``` diff --git a/docs/en/docs/hello_nextflow/06_hello_config.md b/docs/en/docs/hello_nextflow/06_hello_config.md index 3751b0e38d..4eb6da92b1 100644 --- a/docs/en/docs/hello_nextflow/06_hello_config.md +++ b/docs/en/docs/hello_nextflow/06_hello_config.md @@ -89,6 +89,15 @@ nextflow run hello-config.nf /workspaces/training/hello-nextflow/results + first_output: + - hello_config/intermediates/Bonjour-output.txt + - hello_config/intermediates/Hello-output.txt + - hello_config/intermediates/Hola-output.txt + uppercased: + - hello_config/intermediates/UPPER-Bonjour-output.txt + - hello_config/intermediates/UPPER-Hello-output.txt + - hello_config/intermediates/UPPER-Hola-output.txt + collected: hello_config/intermediates/COLLECTED-batch-output.txt batch_report: hello_config/batch-report.txt cowpy_art: hello_config/cowpy-COLLECTED-batch-output.txt ``` @@ -256,6 +265,15 @@ nextflow run hello-config.nf /workspaces/training/hello-nextflow/results + first_output: + - hello_config/intermediates/Hello-output.txt + - hello_config/intermediates/Hola-output.txt + - hello_config/intermediates/Bonjour-output.txt + uppercased: + - hello_config/intermediates/UPPER-Hola-output.txt + - hello_config/intermediates/UPPER-Hello-output.txt + - hello_config/intermediates/UPPER-Bonjour-output.txt + collected: hello_config/intermediates/COLLECTED-batch-output.txt batch_report: hello_config/batch-report.txt cowpy_art: hello_config/cowpy-COLLECTED-batch-output.txt ``` @@ -359,7 +377,16 @@ nextflow run ../hello-config.nf /workspaces/training/hello-nextflow/tux-run/results - batch_report: hello_config/batch-report.txt + first_output: + - hello_config/intermediates/Hola-output.txt + - hello_config/intermediates/Hello-output.txt + - hello_config/intermediates/Bonjour-output.txt + uppercased: + - hello_config/intermediates/UPPER-Bonjour-output.txt + - hello_config/intermediates/UPPER-Hello-output.txt + - hello_config/intermediates/UPPER-Hola-output.txt + collected: hello_config/intermediates/COLLECTED-experiment-output.txt + batch_report: hello_config/experiment-report.txt cowpy_art: hello_config/cowpy-COLLECTED-experiment-output.txt ``` @@ -452,6 +479,15 @@ nextflow run hello-config.nf -params-file test-params.yaml /workspaces/training/hello-nextflow/results + first_output: + - hello_config/intermediates/Hola-output.txt + - hello_config/intermediates/Bonjour-output.txt + - hello_config/intermediates/Hello-output.txt + uppercased: + - hello_config/intermediates/UPPER-Hello-output.txt + - hello_config/intermediates/UPPER-Hola-output.txt + - hello_config/intermediates/UPPER-Bonjour-output.txt + collected: hello_config/intermediates/COLLECTED-yaml-output.txt batch_report: hello_config/yaml-report.txt cowpy_art: hello_config/cowpy-COLLECTED-yaml-output.txt ``` @@ -540,6 +576,15 @@ nextflow run hello-config.nf -output-dir custom-outdir-cli/ /workspaces/training/hello-nextflow/custom-outdir-cli + first_output: + - hello_config/intermediates/Hola-output.txt + - hello_config/intermediates/Hello-output.txt + - hello_config/intermediates/Bonjour-output.txt + uppercased: + - hello_config/intermediates/UPPER-Bonjour-output.txt + - hello_config/intermediates/UPPER-Hello-output.txt + - hello_config/intermediates/UPPER-Hola-output.txt + collected: hello_config/intermediates/COLLECTED-batch-output.txt batch_report: hello_config/batch-report.txt cowpy_art: hello_config/cowpy-COLLECTED-batch-output.txt ``` @@ -879,6 +924,15 @@ nextflow run hello-config.nf -output-dir custom-outdir-config-2 --batch rep2 /workspaces/training/hello-nextflow/custom-outdir-config-2 + first_output: + - rep2/intermediates/sayHello/Bonjour-output.txt + - rep2/intermediates/sayHello/Hello-output.txt + - rep2/intermediates/sayHello/Hola-output.txt + uppercased: + - rep2/intermediates/convertToUpper/UPPER-Hello-output.txt + - rep2/intermediates/convertToUpper/UPPER-Bonjour-output.txt + - rep2/intermediates/convertToUpper/UPPER-Hola-output.txt + collected: rep2/intermediates/collectGreetings/COLLECTED-rep2-output.txt batch_report: rep2/collectGreetings/rep2-report.txt cowpy_art: rep2/cowpy/cowpy-COLLECTED-rep2-output.txt ``` @@ -1016,6 +1070,15 @@ nextflow run hello-config.nf -output-dir config-output-mode /workspaces/training/hello-nextflow/config-output-mode + first_output: + - batch/intermediates/sayHello/Hola-output.txt + - batch/intermediates/sayHello/Bonjour-output.txt + - batch/intermediates/sayHello/Hello-output.txt + uppercased: + - batch/intermediates/convertToUpper/UPPER-Bonjour-output.txt + - batch/intermediates/convertToUpper/UPPER-Hola-output.txt + - batch/intermediates/convertToUpper/UPPER-Hello-output.txt + collected: batch/intermediates/collectGreetings/COLLECTED-batch-output.txt batch_report: batch/collectGreetings/batch-report.txt cowpy_art: batch/cowpy/cowpy-COLLECTED-batch-output.txt ``` @@ -1150,11 +1213,21 @@ nextflow run hello-config.nf --batch conda [fe/6a70ce] convertToUpper (3) | 3 of 3 ✔ [99/7cc493] collectGreetings | 1 of 1 ✔ [3c/09fb59] cowpy | 1 of 1 ✔ + Creating env using conda: conda-forge::cowpy==1.1.5 [cache /workspaces/training/hello-nextflow/work/conda/env-898314d566668b6587ad714ae06b8520] Outputs: /workspaces/training/hello-nextflow/custom-outdir-config + first_output: + - conda/intermediates/sayHello/Bonjour-output.txt + - conda/intermediates/sayHello/Hola-output.txt + - conda/intermediates/sayHello/Hello-output.txt + uppercased: + - conda/intermediates/convertToUpper/UPPER-Bonjour-output.txt + - conda/intermediates/convertToUpper/UPPER-Hola-output.txt + - conda/intermediates/convertToUpper/UPPER-Hello-output.txt + collected: conda/intermediates/collectGreetings/COLLECTED-conda-output.txt batch_report: conda/collectGreetings/conda-report.txt cowpy_art: conda/cowpy/cowpy-COLLECTED-conda-output.txt ``` @@ -1556,6 +1629,15 @@ nextflow run hello-config.nf -profile my_laptop /workspaces/training/hello-nextflow/custom-outdir-config + first_output: + - batch/intermediates/sayHello/Bonjour-output.txt + - batch/intermediates/sayHello/Hola-output.txt + - batch/intermediates/sayHello/Hello-output.txt + uppercased: + - batch/intermediates/convertToUpper/UPPER-Bonjour-output.txt + - batch/intermediates/convertToUpper/UPPER-Hola-output.txt + - batch/intermediates/convertToUpper/UPPER-Hello-output.txt + collected: batch/intermediates/collectGreetings/COLLECTED-batch-output.txt batch_report: batch/collectGreetings/batch-report.txt cowpy_art: batch/cowpy/cowpy-COLLECTED-batch-output.txt ``` @@ -1647,6 +1729,15 @@ nextflow run hello-config.nf -profile my_laptop,test /workspaces/training/hello-nextflow/custom-outdir-config + first_output: + - test/intermediates/sayHello/Hello-output.txt + - test/intermediates/sayHello/Hola-output.txt + - test/intermediates/sayHello/Bonjour-output.txt + uppercased: + - test/intermediates/convertToUpper/UPPER-Hola-output.txt + - test/intermediates/convertToUpper/UPPER-Hello-output.txt + - test/intermediates/convertToUpper/UPPER-Bonjour-output.txt + collected: test/intermediates/collectGreetings/COLLECTED-test-output.txt batch_report: test/collectGreetings/test-report.txt cowpy_art: test/cowpy/cowpy-COLLECTED-test-output.txt ``` From d2a8d03c7056386d28f1e28e497daaf469619922 Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 12:47:15 +0100 Subject: [PATCH 06/42] docs(nextflow_run): refresh tutorial output for Nextflow 26.04 [skip ci] --- docs/en/docs/nextflow_run/01_basics.md | 41 +++- docs/en/docs/nextflow_run/02_pipeline.md | 118 +++++++++-- docs/en/docs/nextflow_run/03_config.md | 244 ++++++++++++++++++++--- 3 files changed, 347 insertions(+), 56 deletions(-) diff --git a/docs/en/docs/nextflow_run/01_basics.md b/docs/en/docs/nextflow_run/01_basics.md index bcaa81b971..a110cfba9e 100644 --- a/docs/en/docs/nextflow_run/01_basics.md +++ b/docs/en/docs/nextflow_run/01_basics.md @@ -89,12 +89,18 @@ nextflow run 1-hello.nf --input 'Hello World!' ??? success "Command output" ```console hl_lines="6" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `1-hello.nf` [goofy_torvalds] DSL2 - revision: c33d41f479 + Launching `1-hello.nf` [goofy_torvalds] revision: c33d41f479 executor > local (1) [a3/7be2fa] sayHello | 1 of 1 ✔ + + Outputs: + + /workspaces/training/nextflow-run/results + + first_output: 1-hello/output.txt ``` If your console output looks something like that, then congratulations, you just ran your first Nextflow workflow! @@ -113,13 +119,14 @@ If your console output looks something like that, then congratulations, you just This was mentioned at the start of the course, but maybe you missed it. Check the [Nextflow versions](../info/nxf_versions.md) help material. - In short, if you're using Nextflow `25.10` then you need to enable the v2 language parser: + The v2 parser is the default from Nextflow 26.04 onward, so you will only see this on earlier versions. + On a version before 26.04 you need to enable the v2 language parser: ```bash export NXF_SYNTAX_PARSER=v2 ``` -The most important output here is the last line, which is highlighted in the output above: +The most important part here is the highlighted line: ```console [a3/7be2fa] sayHello | 1 of 1 ✔ @@ -166,12 +173,18 @@ nextflow run 1-hello.nf --input 'Hello World!' -output-dir hello_results ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `1-hello.nf` [hungry_celsius] DSL2 - revision: f048d6ea78 + Launching `1-hello.nf` [hungry_celsius] revision: f048d6ea78 executor > local (1) - [a3/1e1535] sayHello [100%] 1 of 1 ✔ + [a3/1e1535] sayHello | 1 of 1 ✔ + + Outputs: + + /workspaces/training/nextflow-run/hello_results + + first_output: 1-hello/output.txt ``` You should see that your outputs are now published to a directory called `hello_results` instead of `results`: @@ -204,7 +217,7 @@ That may sound confusing, so let's see what that looks like in practice. Going back to the console output for the workflow we ran earlier, we had this line: ```console -[a3/1e1535] sayHello [100%] 1 of 1 ✔ +[a3/1e1535] sayHello | 1 of 1 ✔ ``` See how the line starts with `[a3/1e1535]`? @@ -621,11 +634,17 @@ nextflow run 1-hello.nf --input 'Hello World!' -resume ??? success "Command output" ```console linenums="1" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `1-hello.nf` [tiny_noyce] DSL2 - revision: c33d41f479 + Launching `1-hello.nf` [tiny_noyce] revision: c33d41f479 [a3/7be2fa] sayHello | 1 of 1, cached: 1 ✔ + + Outputs: + + /workspaces/training/nextflow-run/results + + first_output: 1-hello/output.txt ``` The console output should look familiar, but there's one thing that's a little different compared to before. @@ -792,7 +811,7 @@ Learn more: [2.4. Re-run the workflow with different greetings](#24-re-run-the-w What does this console output indicate? ```console -[skipped ] process > sayHello (1) [100%] 1 of 1, cached: 1 ✔ +[a3/7be2fa] sayHello | 1 of 1, cached: 1 ✔ ``` - [ ] The task failed and was skipped diff --git a/docs/en/docs/nextflow_run/02_pipeline.md b/docs/en/docs/nextflow_run/02_pipeline.md index f57da44339..9169602995 100644 --- a/docs/en/docs/nextflow_run/02_pipeline.md +++ b/docs/en/docs/nextflow_run/02_pipeline.md @@ -40,12 +40,21 @@ nextflow run 2a-inputs.nf --input data/greetings.csv ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `2a-inputs.nf` [mighty_sammet] DSL2 - revision: 29fb5352b3 + Launching `2a-inputs.nf` [mighty_sammet] revision: 29fb5352b3 executor > local (3) - [8e/0eb066] sayHello (2) [100%] 3 of 3 ✔ + [8e/0eb066] sayHello (2) | 3 of 3 ✔ + + Outputs: + + /workspaces/training/nextflow-run/results + + first_output: + - 2a-inputs/Hello-output.txt + - 2a-inputs/Bonjour-output.txt + - 2a-inputs/Hola-output.txt ``` Excitingly, this seems to indicate that '3 of 3' calls were made for the process, which is encouraging, since there were three rows of data in the CSV we provided as input. @@ -122,11 +131,20 @@ nextflow run 2a-inputs.nf --input data/greetings.csv -ansi-log false ??? success "Command output" ```console linenums="1" - N E X T F L O W ~ version 25.10.4 - Launching `2a-inputs.nf` [pedantic_hamilton] DSL2 - revision: 6bbc42e49f + N E X T F L O W ~ version 26.04.4 + Launching `2a-inputs.nf` [pedantic_hamilton] - revision: 6bbc42e49f [ab/1a8ece] Submitted process > sayHello (1) [0d/2cae24] Submitted process > sayHello (2) [b5/0df1d6] Submitted process > sayHello (3) + + Outputs: + + /workspaces/training/nextflow-run/results + + first_output: + - 2a-inputs/Hello-output.txt + - 2a-inputs/Bonjour-output.txt + - 2a-inputs/Hola-output.txt ``` This time we see all three process runs and their associated work subdirectories listed in the output. @@ -360,13 +378,31 @@ nextflow run 2b-multistep.nf --input data/greetings.csv ??? success "Command output" ```console linenums="1" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `2b-multistep.nf` [soggy_franklin] DSL2 - revision: bc8e1b2726 + Launching `2b-multistep.nf` [soggy_franklin] revision: bc8e1b2726 [d6/cdf466] sayHello (1) | 3 of 3 ✔ [99/79394f] convertToUpper (2) | 3 of 3 ✔ [1e/83586c] collectGreetings | 1 of 1 ✔ + + Outputs: + + /workspaces/training/nextflow-run/results + + first_output: + - 2b-multistep/intermediates/Hello-output.txt + - 2b-multistep/intermediates/Bonjour-output.txt + - 2b-multistep/intermediates/Hola-output.txt + + uppercased: + - 2b-multistep/intermediates/UPPER-Hello-output.txt + - 2b-multistep/intermediates/UPPER-Bonjour-output.txt + - 2b-multistep/intermediates/UPPER-Hola-output.txt + + collected: 2b-multistep/COLLECTED-batch-output.txt + + batch_report: 2b-multistep/batch-report.txt ``` You see that as promised, multiple steps were run as part of the workflow; the first two (`sayHello` and `convertToUpper`) were presumably run on each individual greeting, and the third (`collectGreetings`) will have been run only once, on the outputs of all three of the `convertToUpper` calls. @@ -668,13 +704,31 @@ nextflow run 2b-multistep.nf --input data/greetings.csv --batch test ??? success "Command output" ```console linenums="1" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `2b-multistep.nf` [soggy_franklin] DSL2 - revision: bc8e1b2726 + Launching `2b-multistep.nf` [soggy_franklin] revision: bc8e1b2726 [a5/cdff26] sayHello (1) | 3 of 3 ✔ [c5/78794f] convertToUpper (2) | 3 of 3 ✔ [d3/b4d86c] collectGreetings | 1 of 1 ✔ + + Outputs: + + /workspaces/training/nextflow-run/results + + first_output: + - 2b-multistep/intermediates/Bonjour-output.txt + - 2b-multistep/intermediates/Hello-output.txt + - 2b-multistep/intermediates/Hola-output.txt + + uppercased: + - 2b-multistep/intermediates/UPPER-Hola-output.txt + - 2b-multistep/intermediates/UPPER-Bonjour-output.txt + - 2b-multistep/intermediates/UPPER-Hello-output.txt + + collected: 2b-multistep/COLLECTED-test-output.txt + + batch_report: 2b-multistep/test-report.txt ``` You should see new final outputs named with your custom batch name. @@ -919,13 +973,31 @@ nextflow run 2c-modules.nf --input data/greetings.csv -resume ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `2c-modules.nf` [soggy_franklin] DSL2 - revision: bc8e1b2726 + Launching `2c-modules.nf` [soggy_franklin] revision: bc8e1b2726 [d6/cdf466] sayHello (1) | 3 of 3, cached: 3 ✔ [99/79394f] convertToUpper (2) | 3 of 3, cached: 3 ✔ [1e/83586c] collectGreetings | 1 of 1, cached: 1 ✔ + + Outputs: + + /workspaces/training/nextflow-run/results + + first_output: + - 2c-modules/intermediates/Hello-output.txt + - 2c-modules/intermediates/Bonjour-output.txt + - 2c-modules/intermediates/Hola-output.txt + + uppercased: + - 2c-modules/intermediates/UPPER-Hello-output.txt + - 2c-modules/intermediates/UPPER-Bonjour-output.txt + - 2c-modules/intermediates/UPPER-Hola-output.txt + + collected: 2c-modules/COLLECTED-batch-output.txt + + batch_report: 2c-modules/batch-report.txt ``` You'll notice that the process executions all cached successfully, meaning that Nextflow recognized that it has already done the requested work, even though the code has been split up and the main workflow file has been renamed. @@ -1296,15 +1368,35 @@ nextflow run 2d-container.nf --input data/greetings.csv --character turkey -resu ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `2d-container.nf` [elegant_brattain] DSL2 - revision: 028a841db1 + Launching `2d-container.nf` [elegant_brattain] revision: 028a841db1 executor > local (1) [95/fa0bac] sayHello (3) | 3 of 3, cached: 3 ✔ [92/32533f] convertToUpper (3) | 3 of 3, cached: 3 ✔ [aa/e697a2] collectGreetings | 1 of 1, cached: 1 ✔ [7f/caf718] cowpy | 1 of 1 ✔ + + Outputs: + + /workspaces/training/nextflow-run/results + + first_output: + - 2d-container/intermediates/Bonjour-output.txt + - 2d-container/intermediates/Hola-output.txt + - 2d-container/intermediates/Hello-output.txt + + uppercased: + - 2d-container/intermediates/UPPER-Hola-output.txt + - 2d-container/intermediates/UPPER-Hello-output.txt + - 2d-container/intermediates/UPPER-Bonjour-output.txt + + collected: 2d-container/intermediates/COLLECTED-batch-output.txt + + batch_report: 2d-container/batch-report.txt + + cowpy_art: 2d-container/cowpy-COLLECTED-batch-output.txt ``` The first three steps cached since we've already run them before, but the `cowpy` process is new so that actually gets run. diff --git a/docs/en/docs/nextflow_run/03_config.md b/docs/en/docs/nextflow_run/03_config.md index d1f4126169..eb8e2ff4e7 100644 --- a/docs/en/docs/nextflow_run/03_config.md +++ b/docs/en/docs/nextflow_run/03_config.md @@ -116,15 +116,35 @@ nextflow run 3-main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `3-main.nf` [disturbed_einstein] DSL2 - revision: ede9037d02 + Launching `3-main.nf` [disturbed_einstein] revision: ede9037d02 executor > local (8) [f0/35723c] sayHello (2) | 3 of 3 ✔ [40/3efd1a] convertToUpper (3) | 3 of 3 ✔ [17/e97d32] collectGreetings | 1 of 1 ✔ [98/c6b57b] cowpy | 1 of 1 ✔ + + Outputs: + + /workspaces/training/nextflow-run/results + + first_output: + - 3-main/intermediates/Hello-output.txt + - 3-main/intermediates/Bonjour-output.txt + - 3-main/intermediates/Hola-output.txt + + uppercased: + - 3-main/intermediates/UPPER-Hello-output.txt + - 3-main/intermediates/UPPER-Bonjour-output.txt + - 3-main/intermediates/UPPER-Hola-output.txt + + collected: 3-main/intermediates/COLLECTED-batch-output.txt + + batch_report: 3-main/batch-report.txt + + cowpy_art: 3-main/cowpy-COLLECTED-batch-output.txt ``` This still produces the same output as previously. @@ -215,15 +235,35 @@ nextflow run ../3-main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `../3-main.nf` [trusting_escher] DSL2 - revision: 356df0818d + Launching `../3-main.nf` [trusting_escher] revision: 356df0818d executor > local (8) - [59/b66913] sayHello (2) [100%] 3 of 3 ✔ - [ad/f06364] convertToUpper (3) [100%] 3 of 3 ✔ - [10/714895] collectGreetings [100%] 1 of 1 ✔ - [88/3ece98] cowpy [100%] 1 of 1 ✔ + [59/b66913] sayHello (2) | 3 of 3 ✔ + [ad/f06364] convertToUpper (3) | 3 of 3 ✔ + [10/714895] collectGreetings | 1 of 1 ✔ + [88/3ece98] cowpy | 1 of 1 ✔ + + Outputs: + + /workspaces/training/nextflow-run/tux-run/results + + first_output: + - 3-main/intermediates/Hola-output.txt + - 3-main/intermediates/Bonjour-output.txt + - 3-main/intermediates/Hello-output.txt + + uppercased: + - 3-main/intermediates/UPPER-Bonjour-output.txt + - 3-main/intermediates/UPPER-Hello-output.txt + - 3-main/intermediates/UPPER-Hola-output.txt + + collected: 3-main/intermediates/COLLECTED-experiment-output.txt + + batch_report: 3-main/experiment-report.txt + + cowpy_art: 3-main/cowpy-COLLECTED-experiment-output.txt ``` This will create a new set of directories under `tux-run/` including `tux-run/work/` and `tux-run/results/`. @@ -305,15 +345,35 @@ nextflow run 3-main.nf -params-file test-params.yaml ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `3-main.nf` [disturbed_sammet] DSL2 - revision: ede9037d02 + Launching `3-main.nf` [disturbed_sammet] revision: ede9037d02 executor > local (8) [2b/9a7d1e] sayHello (2) | 3 of 3 ✔ [5c/8f3b2a] convertToUpper (3) | 3 of 3 ✔ [a3/29d8fb] collectGreetings | 1 of 1 ✔ [b7/83ef12] cowpy | 1 of 1 ✔ + + Outputs: + + /workspaces/training/nextflow-run/results + + first_output: + - 3-main/intermediates/Hola-output.txt + - 3-main/intermediates/Hello-output.txt + - 3-main/intermediates/Bonjour-output.txt + + uppercased: + - 3-main/intermediates/UPPER-Hola-output.txt + - 3-main/intermediates/UPPER-Hello-output.txt + - 3-main/intermediates/UPPER-Bonjour-output.txt + + collected: 3-main/intermediates/COLLECTED-yaml-output.txt + + batch_report: 3-main/yaml-report.txt + + cowpy_art: 3-main/cowpy-COLLECTED-yaml-output.txt ``` The final output file should contain the stegosaurus character saying the greetings. @@ -492,15 +552,35 @@ nextflow run 3-main.nf --batch outdir ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `3-main.nf` [amazing_church] DSL2 - revision: 6e18cd130e + Launching `3-main.nf` [amazing_church] revision: 6e18cd130e executor > local (8) - [9c/6a03ea] sayHello (2) [100%] 3 of 3 ✔ - [11/9e58a6] convertToUpper (3) [100%] 3 of 3 ✔ - [c8/1977e5] collectGreetings [100%] 1 of 1 ✔ - [38/f01eda] cowpy [100%] 1 of 1 ✔ + [9c/6a03ea] sayHello (2) | 3 of 3 ✔ + [11/9e58a6] convertToUpper (3) | 3 of 3 ✔ + [c8/1977e5] collectGreetings | 1 of 1 ✔ + [38/f01eda] cowpy | 1 of 1 ✔ + + Outputs: + + /workspaces/training/nextflow-run/results_config/outdir + + first_output: + - intermediates/Bonjour-output.txt + - intermediates/Hello-output.txt + - intermediates/Hola-output.txt + + uppercased: + - intermediates/UPPER-Bonjour-output.txt + - intermediates/UPPER-Hola-output.txt + - intermediates/UPPER-Hello-output.txt + + collected: intermediates/COLLECTED-outdir-output.txt + + batch_report: outdir-report.txt + + cowpy_art: cowpy-COLLECTED-outdir-output.txt ``` This still produces the same output as previously, except this time we find our outputs under `results_config/outdir/`. @@ -600,15 +680,35 @@ nextflow run 3-main.nf --batch pnames ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `3-main.nf` [jovial_mcclintock] DSL2 - revision: ede9037d02 + Launching `3-main.nf` [jovial_mcclintock] revision: ede9037d02 executor > local (8) [4a/c2e6b8] sayHello (2) | 3 of 3 ✔ [6f/d4a172] convertToUpper (3) | 3 of 3 ✔ [e8/4f19d7] collectGreetings | 1 of 1 ✔ [f2/a85c36] cowpy | 1 of 1 ✔ + + Outputs: + + /workspaces/training/nextflow-run/results_config/pnames + + first_output: + - sayHello/Bonjour-output.txt + - sayHello/Hola-output.txt + - sayHello/Hello-output.txt + + uppercased: + - convertToUpper/UPPER-Bonjour-output.txt + - convertToUpper/UPPER-Hola-output.txt + - convertToUpper/UPPER-Hello-output.txt + + collected: collectGreetings/COLLECTED-pnames-output.txt + + batch_report: collectGreetings/pnames-report.txt + + cowpy_art: cowpy/cowpy-COLLECTED-pnames-output.txt ``` This still produces the same output as previously, except this time we find our outputs under `results_config/pnames/`, and they are grouped by process. @@ -732,15 +832,35 @@ nextflow run 3-main.nf --batch outmode ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `3-main.nf` [rowdy_sagan] DSL2 - revision: ede9037d02 + Launching `3-main.nf` [rowdy_sagan] revision: ede9037d02 executor > local (8) [5b/d91e3c] sayHello (2) | 3 of 3 ✔ [8a/f6c241] convertToUpper (3) | 3 of 3 ✔ [89/cd3a48] collectGreetings | 1 of 1 ✔ [9e/71fb52] cowpy | 1 of 1 ✔ + + Outputs: + + /workspaces/training/nextflow-run/results_config/outmode + + first_output: + - sayHello/Bonjour-output.txt + - sayHello/Hola-output.txt + - sayHello/Hello-output.txt + + uppercased: + - convertToUpper/UPPER-Bonjour-output.txt + - convertToUpper/UPPER-Hola-output.txt + - convertToUpper/UPPER-Hello-output.txt + + collected: collectGreetings/COLLECTED-outmode-output.txt + + batch_report: collectGreetings/outmode-report.txt + + cowpy_art: cowpy/cowpy-COLLECTED-outmode-output.txt ``` This still produces the same output as previously, except this time we find our outputs under `results_config/outmode/`. @@ -866,15 +986,35 @@ nextflow run 3-main.nf --batch conda ??? success "Command output" ```console title="Output" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `3-main.nf` [trusting_lovelace] DSL2 - revision: 028a841db1 + Launching `3-main.nf` [trusting_lovelace] revision: 028a841db1 executor > local (8) [ee/4ca1f2] sayHello (3) | 3 of 3 ✔ [20/2596a7] convertToUpper (1) | 3 of 3 ✔ [b3/e15de5] collectGreetings | 1 of 1 ✔ [c5/af5f88] cowpy | 1 of 1 ✔ + + Outputs: + + /workspaces/training/nextflow-run/results_config/conda + + first_output: + - sayHello/Bonjour-output.txt + - sayHello/Hola-output.txt + - sayHello/Hello-output.txt + + uppercased: + - convertToUpper/UPPER-Bonjour-output.txt + - convertToUpper/UPPER-Hello-output.txt + - convertToUpper/UPPER-Hola-output.txt + + collected: collectGreetings/COLLECTED-conda-output.txt + + batch_report: collectGreetings/conda-report.txt + + cowpy_art: cowpy/cowpy-COLLECTED-conda-output.txt ``` This should work without issue and produce the same outputs as previously under `results_config/conda`. @@ -1213,15 +1353,35 @@ nextflow run 3-main.nf -profile my_laptop ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `3-main.nf` [gigantic_brazil] DSL2 - revision: ede9037d02 + Launching `3-main.nf` [gigantic_brazil] revision: ede9037d02 executor > local (8) [58/da9437] sayHello (3) | 3 of 3 ✔ [35/9cbe77] convertToUpper (2) | 3 of 3 ✔ [67/857d05] collectGreetings | 1 of 1 ✔ [37/7b51b5] cowpy | 1 of 1 ✔ + + Outputs: + + /workspaces/training/nextflow-run/results_config/batch + + first_output: + - sayHello/Hello-output.txt + - sayHello/Hola-output.txt + - sayHello/Bonjour-output.txt + + uppercased: + - convertToUpper/UPPER-Hello-output.txt + - convertToUpper/UPPER-Hola-output.txt + - convertToUpper/UPPER-Bonjour-output.txt + + collected: collectGreetings/COLLECTED-batch-output.txt + + batch_report: collectGreetings/batch-report.txt + + cowpy_art: cowpy/cowpy-COLLECTED-batch-output.txt ``` As you can see, this allows us to toggle between configurations very conveniently at runtime. @@ -1301,15 +1461,35 @@ nextflow run 3-main.nf -profile my_laptop,test ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `3-main.nf` [jovial_coulomb] DSL2 - revision: 46a6763141 + Launching `3-main.nf` [jovial_coulomb] revision: 46a6763141 executor > local (8) [9b/687cdc] sayHello (2) | 3 of 3 ✔ [ca/552187] convertToUpper (3) | 3 of 3 ✔ [e8/83e306] collectGreetings | 1 of 1 ✔ [fd/e84fa9] cowpy | 1 of 1 ✔ + + Outputs: + + /workspaces/training/nextflow-run/results_config/test + + first_output: + - sayHello/Hola-output.txt + - sayHello/Bonjour-output.txt + - sayHello/Hello-output.txt + + uppercased: + - convertToUpper/UPPER-Bonjour-output.txt + - convertToUpper/UPPER-Hola-output.txt + - convertToUpper/UPPER-Hello-output.txt + + collected: collectGreetings/COLLECTED-test-output.txt + + batch_report: collectGreetings/test-report.txt + + cowpy_art: cowpy/cowpy-COLLECTED-test-output.txt ``` This will use Docker where possible and produce outputs under `results_config/test`, and this time the character is the comedic duo `dragonandcow`. @@ -1486,14 +1666,14 @@ nextflow run nextflow-io/hello ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 Pulling nextflow-io/hello ... downloaded from https://github.com/nextflow-io/hello.git - Launching `https://github.com/nextflow-io/hello` [sleepy_swanson] DSL2 - revision: 2ce0b0e294 [master] + Launching `https://github.com/nextflow-io/hello` [sleepy_swanson] revision: 3c2cdc9823 [master] executor > local (4) - [ba/08236d] sayHello (4) [100%] 4 of 4 ✔ + [ba/08236d] sayHello (4) | 4 of 4 ✔ Ciao world! Hello world! @@ -1518,12 +1698,12 @@ nextflow run nextflow-io/hello -r v1.3 ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `https://github.com/nextflow-io/hello` [sick_carson] DSL2 - revision: 2ce0b0e294 [v1.3] + Launching `https://github.com/nextflow-io/hello` [sick_carson] revision: 2ce0b0e294 [v1.3] executor > local (4) - [61/e11f77] sayHello (4) [100%] 4 of 4 ✔ + [61/e11f77] sayHello (4) | 4 of 4 ✔ Ciao world! Bonjour world! From f56e753dcf00ae1cd03163a9a0235a2ac1cc7c06 Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 12:56:51 +0100 Subject: [PATCH 07/42] docs(nf4_science): refresh genomics + rnaseq output for Nextflow 26.04 [skip ci] --- .../nf4_science/_template/02_single_sample.md | 11 +- .../genomics/02_per_sample_variant_calling.md | 101 +++++++- .../nf4_science/genomics/03_joint_calling.md | 50 +++- .../nf4_science/rnaseq/02_single-sample.md | 66 ++++- .../nf4_science/rnaseq/03_multi-sample.md | 236 ++++++++++++++++-- 5 files changed, 421 insertions(+), 43 deletions(-) diff --git a/docs/en/docs/nf4_science/_template/02_single_sample.md b/docs/en/docs/nf4_science/_template/02_single_sample.md index 61e6b43c65..e740206dfe 100644 --- a/docs/en/docs/nf4_science/_template/02_single_sample.md +++ b/docs/en/docs/nf4_science/_template/02_single_sample.md @@ -141,12 +141,19 @@ nextflow run {DOMAIN_DIR}.nf -profile test ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - ┃ Launching `{DOMAIN_DIR}.nf` [{RUN_NAME}] DSL2 - revision: {HASH} + Launching `{DOMAIN_DIR}.nf` [{RUN_NAME}] revision: {HASH} executor > local (1) [{HASH}] {PROCESS_A_NAME} (1) | 1 of 1 ✔ + + Outputs: + + /workspaces/training/nf4-science/{DOMAIN_DIR}/results + + {OUTPUT_NAME}: + - {OUTPUT_SUBDIR}/{OUTPUT_FILE} ``` {VERIFY_OUTPUT_INSTRUCTIONS} diff --git a/docs/en/docs/nf4_science/genomics/02_per_sample_variant_calling.md b/docs/en/docs/nf4_science/genomics/02_per_sample_variant_calling.md index 8bc7f927e2..51fb97bbaa 100644 --- a/docs/en/docs/nf4_science/genomics/02_per_sample_variant_calling.md +++ b/docs/en/docs/nf4_science/genomics/02_per_sample_variant_calling.md @@ -400,12 +400,19 @@ nextflow run genomics.nf -profile test ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - ┃ Launching `genomics.nf` [reverent_sinoussi] DSL2 - revision: 41d43ad7fe + Launching `genomics.nf` [reverent_sinoussi] revision: 41d43ad7fe executor > local (1) [2a/e69536] SAMTOOLS_INDEX (1) | 1 of 1 ✔ + + Outputs: + + /workspaces/training/nf4-science/genomics/results + + bam_index: + - bam/reads_mother.bam.bai ``` You can check that the index file has been generated correctly by looking in the work directory or in the results directory. @@ -767,13 +774,26 @@ nextflow run genomics.nf -profile test -resume ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - ┃ Launching `genomics.nf` [grave_volta] DSL2 - revision: 4790abc96a + Launching `genomics.nf` [grave_volta] revision: 4790abc96a executor > local (1) [2a/e69536] SAMTOOLS_INDEX (1) | 1 of 1, cached: 1 ✔ [53/e18e98] GATK_HAPLOTYPECALLER (1) | 1 of 1 ✔ + + Outputs: + + /workspaces/training/nf4-science/genomics/results + + bam_index: + - bam/reads_mother.bam.bai + + vcf: + - vcf/reads_mother.bam.vcf + + vcf_idx: + - vcf/reads_mother.bam.vcf.idx ``` Now if we look at the console output, we see the two processes listed. @@ -889,13 +909,32 @@ Funny thing: this _might work_, OR it _might fail_. For example, here's a run th ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - ┃ Launching `genomics.nf` [peaceful_yalow] DSL2 - revision: a256d113ad + Launching `genomics.nf` [peaceful_yalow] revision: a256d113ad executor > local (6) [4f/7071b0] SAMTOOLS_INDEX (3) | 3 of 3, cached: 1 ✔ [7a/89bc43] GATK_HAPLOTYPECALLER (2) | 3 of 3, cached: 1 ✔ + + Outputs: + + /workspaces/training/nf4-science/genomics/results + + bam_index: + - bam/reads_mother.bam.bai + - bam/reads_father.bam.bai + - bam/reads_son.bam.bai + + vcf: + - vcf/reads_mother.bam.vcf + - vcf/reads_father.bam.vcf + - vcf/reads_son.bam.vcf + + vcf_idx: + - vcf/reads_mother.bam.vcf.idx + - vcf/reads_father.bam.vcf.idx + - vcf/reads_son.bam.vcf.idx ``` If your workflow run succeeded, run it again until you get an error like this: @@ -903,9 +942,9 @@ If your workflow run succeeded, run it again until you get an error like this: ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - ┃ Launching `genomics.nf` [loving_pasteur] DSL2 - revision: d2a8e63076 + Launching `genomics.nf` [loving_pasteur] revision: d2a8e63076 executor > local (4) [01/eea165] SAMTOOLS_INDEX (2) | 3 of 3, cached: 1 ✔ @@ -1162,13 +1201,32 @@ This time (and every time) everything should run correctly: ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - ┃ Launching `genomics.nf` [special_goldstine] DSL2 - revision: 4cbbf6ea3e + Launching `genomics.nf` [special_goldstine] revision: 4cbbf6ea3e executor > local (6) [d6/10c2c4] SAMTOOLS_INDEX (1) | 3 of 3 ✔ [88/1783aa] GATK_HAPLOTYPECALLER (2) | 3 of 3 ✔ + + Outputs: + + /workspaces/training/nf4-science/genomics/results + + indexed_bam: + - [bam/reads_mother.bam, bam/reads_mother.bam.bai] + - [bam/reads_father.bam, bam/reads_father.bam.bai] + - [bam/reads_son.bam, bam/reads_son.bam.bai] + + vcf: + - vcf/reads_mother.bam.vcf + - vcf/reads_father.bam.vcf + - vcf/reads_son.bam.vcf + + vcf_idx: + - vcf/reads_mother.bam.vcf.idx + - vcf/reads_father.bam.vcf.idx + - vcf/reads_son.bam.vcf.idx ``` The results directory now contains both BAM and BAI files for each sample (from the tuple), along with the VCF outputs: @@ -1325,13 +1383,32 @@ nextflow run genomics.nf -profile test ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - ┃ Launching `genomics.nf` [sick_albattani] DSL2 - revision: 46d84642f6 + Launching `genomics.nf` [sick_albattani] revision: 46d84642f6 executor > local (6) [18/23b4bb] SAMTOOLS_INDEX (1) | 3 of 3 ✔ [12/f727bb] GATK_HAPLOTYPECALLER (3) | 3 of 3 ✔ + + Outputs: + + /workspaces/training/nf4-science/genomics/results + + indexed_bam: + - [bam/reads_mother.bam, bam/reads_mother.bam.bai] + - [bam/reads_father.bam, bam/reads_father.bam.bai] + - [bam/reads_son.bam, bam/reads_son.bam.bai] + + vcf: + - vcf/reads_mother.bam.vcf + - vcf/reads_father.bam.vcf + - vcf/reads_son.bam.vcf + + vcf_idx: + - vcf/reads_mother.bam.vcf.idx + - vcf/reads_father.bam.vcf.idx + - vcf/reads_son.bam.vcf.idx ``` This should produce the same result as before. Our simple variant calling workflow now has all the basic features we wanted. diff --git a/docs/en/docs/nf4_science/genomics/03_joint_calling.md b/docs/en/docs/nf4_science/genomics/03_joint_calling.md index 636309945a..0e422433c0 100644 --- a/docs/en/docs/nf4_science/genomics/03_joint_calling.md +++ b/docs/en/docs/nf4_science/genomics/03_joint_calling.md @@ -205,13 +205,32 @@ nextflow run genomics.nf -profile test ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - ┃ Launching `genomics.nf` [nostalgic_franklin] DSL2 - revision: f2c0a93c6a + Launching `genomics.nf` [nostalgic_franklin] revision: f2c0a93c6a executor > local (6) [cc/fbc705] SAMTOOLS_INDEX (3) | 3 of 3 ✔ [27/0d7eb9] GATK_HAPLOTYPECALLER (2) | 3 of 3 ✔ + + Outputs: + + /workspaces/training/nf4-science/genomics/results + + indexed_bam: + - [indexed_bam/reads_mother.bam, indexed_bam/reads_mother.bam.bai] + - [indexed_bam/reads_father.bam, indexed_bam/reads_father.bam.bai] + - [indexed_bam/reads_son.bam, indexed_bam/reads_son.bam.bai] + + gvcf: + - gvcf/reads_mother.bam.g.vcf + - gvcf/reads_father.bam.g.vcf + - gvcf/reads_son.bam.g.vcf + + gvcf_idx: + - gvcf/reads_mother.bam.g.vcf.idx + - gvcf/reads_father.bam.g.vcf.idx + - gvcf/reads_son.bam.g.vcf.idx ``` The Nextflow output looks the same as before, but the `.g.vcf` files and their index files are now organized in subdirectories. @@ -647,14 +666,37 @@ nextflow run genomics.nf -profile test -resume ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - ┃ Launching `genomics.nf` [crazy_marconi] DSL2 - revision: 5da9afc841 + Launching `genomics.nf` [crazy_marconi] revision: 5da9afc841 executor > local (1) [9a/c7a873] SAMTOOLS_INDEX (2) | 3 of 3, cached: 3 ✔ [e4/4ed55e] GATK_HAPLOTYPECALLER (2) | 3 of 3, cached: 3 ✔ [a6/7cc8ed] GATK_JOINTGENOTYPING | 1 of 1 ✔ + + Outputs: + + /workspaces/training/nf4-science/genomics/results + + indexed_bam: + - [indexed_bam/reads_mother.bam, indexed_bam/reads_mother.bam.bai] + - [indexed_bam/reads_father.bam, indexed_bam/reads_father.bam.bai] + - [indexed_bam/reads_son.bam, indexed_bam/reads_son.bam.bai] + + gvcf: + - gvcf/reads_mother.bam.g.vcf + - gvcf/reads_father.bam.g.vcf + - gvcf/reads_son.bam.g.vcf + + gvcf_idx: + - gvcf/reads_mother.bam.g.vcf.idx + - gvcf/reads_father.bam.g.vcf.idx + - gvcf/reads_son.bam.g.vcf.idx + + joint_vcf: family_trio.joint.vcf + + joint_vcf_idx: family_trio.joint.vcf.idx ``` The first two steps are cached from the previous run, and the new `GATK_JOINTGENOTYPING` step runs once on the collected inputs from all three samples. diff --git a/docs/en/docs/nf4_science/rnaseq/02_single-sample.md b/docs/en/docs/nf4_science/rnaseq/02_single-sample.md index 29617ed0d3..4066947fc8 100644 --- a/docs/en/docs/nf4_science/rnaseq/02_single-sample.md +++ b/docs/en/docs/nf4_science/rnaseq/02_single-sample.md @@ -475,12 +475,22 @@ nextflow run rnaseq.nf -profile test ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `rnaseq.nf` [mad_lorenz] DSL2 - revision: 5846a164d2 + Launching `rnaseq.nf` [mad_lorenz] revision: 5846a164d2 executor > local (1) [7b/8ee79e] FASTQC (1) | 1 of 1 ✔ + + Outputs: + + /workspaces/training/nf4-science/rnaseq/results + + fastqc_zip: + - fastqc/ENCSR000COQ1_1_fastqc.zip + + fastqc_html: + - fastqc/ENCSR000COQ1_1_fastqc.html ``` This should run very quickly if you worked through Part 1 and have already pulled the container. @@ -736,13 +746,32 @@ nextflow run rnaseq.nf -profile test ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `rnaseq.nf` [gloomy_becquerel] DSL2 - revision: bb11055736 + Launching `rnaseq.nf` [gloomy_becquerel] revision: bb11055736 executor > local (2) [f6/c8ef2e] FASTQC (1) | 1 of 1 ✔ [58/c58d8a] TRIM_GALORE (1) | 1 of 1 ✔ + + Outputs: + + /workspaces/training/nf4-science/rnaseq/results + + fastqc_zip: + - fastqc/ENCSR000COQ1_1_fastqc.zip + + fastqc_html: + - fastqc/ENCSR000COQ1_1_fastqc.html + + trimmed_reads: + - trimming/ENCSR000COQ1_1_trimmed.fq.gz + + trimming_reports: + - trimming/ENCSR000COQ1_1.fastq.gz_trimming_report.txt + + trimming_fastqc: + - [trimming/ENCSR000COQ1_1_trimmed_fastqc.html, trimming/ENCSR000COQ1_1_trimmed_fastqc.zip] ``` This should run very quickly too, since we're running on such a small input file. @@ -1083,14 +1112,39 @@ nextflow run rnaseq.nf -profile test ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `rnaseq.nf` [elated_stonebraker] DSL2 - revision: e8e57d0cdd + Launching `rnaseq.nf` [elated_stonebraker] revision: e8e57d0cdd executor > local (3) [e8/fa29d6] FASTQC (1) | 1 of 1 ✔ [ca/ffdde2] TRIM_GALORE (1) | 1 of 1 ✔ [b6/1c6ca3] HISAT2_ALIGN (1) | 1 of 1 ✔ + + Outputs: + + /workspaces/training/nf4-science/rnaseq/results + + fastqc_zip: + - fastqc/ENCSR000COQ1_1_fastqc.zip + + fastqc_html: + - fastqc/ENCSR000COQ1_1_fastqc.html + + trimmed_reads: + - trimming/ENCSR000COQ1_1_trimmed.fq.gz + + trimming_reports: + - trimming/ENCSR000COQ1_1.fastq.gz_trimming_report.txt + + trimming_fastqc: + - [trimming/ENCSR000COQ1_1_trimmed_fastqc.html, trimming/ENCSR000COQ1_1_trimmed_fastqc.zip] + + bam: + - align/ENCSR000COQ1_1_trimmed.bam + + align_log: + - align/ENCSR000COQ1_1_trimmed.hisat2.log ``` You can find the alignment outputs in the results directory. diff --git a/docs/en/docs/nf4_science/rnaseq/03_multi-sample.md b/docs/en/docs/nf4_science/rnaseq/03_multi-sample.md index 5ae341fb69..79881034e2 100644 --- a/docs/en/docs/nf4_science/rnaseq/03_multi-sample.md +++ b/docs/en/docs/nf4_science/rnaseq/03_multi-sample.md @@ -161,14 +161,74 @@ nextflow run rnaseq.nf -profile test ??? success "Command output" ```console - N E X T F L O W ~ version 24.10.0 + N E X T F L O W ~ version 26.04.4 - Launching `rnaseq.nf` [golden_curry] DSL2 - revision: 2a5ba5be1e + Launching `rnaseq.nf` [golden_curry] revision: 2a5ba5be1e executor > local (18) - [07/3ff9c5] FASTQC (6) [100%] 6 of 6 ✔ - [cc/16859f] TRIM_GALORE (6) [100%] 6 of 6 ✔ - [68/4c27b5] HISAT2_ALIGN (6) [100%] 6 of 6 ✔ + [07/3ff9c5] FASTQC (6) | 6 of 6 ✔ + [cc/16859f] TRIM_GALORE (6) | 6 of 6 ✔ + [68/4c27b5] HISAT2_ALIGN (6) | 6 of 6 ✔ + + Outputs: + + /workspaces/training/nf4-science/rnaseq/results + + fastqc_zip: + - fastqc/ENCSR000COQ1_1_fastqc.zip + - fastqc/ENCSR000COQ2_1_fastqc.zip + - fastqc/ENCSR000COR1_1_fastqc.zip + - fastqc/ENCSR000COR2_1_fastqc.zip + - fastqc/ENCSR000CPO1_1_fastqc.zip + - fastqc/ENCSR000CPO2_1_fastqc.zip + + fastqc_html: + - fastqc/ENCSR000COQ1_1_fastqc.html + - fastqc/ENCSR000COQ2_1_fastqc.html + - fastqc/ENCSR000COR1_1_fastqc.html + - fastqc/ENCSR000COR2_1_fastqc.html + - fastqc/ENCSR000CPO1_1_fastqc.html + - fastqc/ENCSR000CPO2_1_fastqc.html + + trimmed_reads: + - trimming/ENCSR000COQ1_1_trimmed.fq.gz + - trimming/ENCSR000COQ2_1_trimmed.fq.gz + - trimming/ENCSR000COR1_1_trimmed.fq.gz + - trimming/ENCSR000COR2_1_trimmed.fq.gz + - trimming/ENCSR000CPO1_1_trimmed.fq.gz + - trimming/ENCSR000CPO2_1_trimmed.fq.gz + + trimming_reports: + - trimming/ENCSR000COQ1_1.fastq.gz_trimming_report.txt + - trimming/ENCSR000COQ2_1.fastq.gz_trimming_report.txt + - trimming/ENCSR000COR1_1.fastq.gz_trimming_report.txt + - trimming/ENCSR000COR2_1.fastq.gz_trimming_report.txt + - trimming/ENCSR000CPO1_1.fastq.gz_trimming_report.txt + - trimming/ENCSR000CPO2_1.fastq.gz_trimming_report.txt + + trimming_fastqc: + - [trimming/ENCSR000COQ1_1_trimmed_fastqc.html, trimming/ENCSR000COQ1_1_trimmed_fastqc.zip] + - [trimming/ENCSR000COQ2_1_trimmed_fastqc.html, trimming/ENCSR000COQ2_1_trimmed_fastqc.zip] + - [trimming/ENCSR000COR1_1_trimmed_fastqc.html, trimming/ENCSR000COR1_1_trimmed_fastqc.zip] + - [trimming/ENCSR000COR2_1_trimmed_fastqc.html, trimming/ENCSR000COR2_1_trimmed_fastqc.zip] + - [trimming/ENCSR000CPO1_1_trimmed_fastqc.html, trimming/ENCSR000CPO1_1_trimmed_fastqc.zip] + - [trimming/ENCSR000CPO2_1_trimmed_fastqc.html, trimming/ENCSR000CPO2_1_trimmed_fastqc.zip] + + bam: + - align/ENCSR000COQ1_1_trimmed.bam + - align/ENCSR000COQ2_1_trimmed.bam + - align/ENCSR000COR1_1_trimmed.bam + - align/ENCSR000COR2_1_trimmed.bam + - align/ENCSR000CPO1_1_trimmed.bam + - align/ENCSR000CPO2_1_trimmed.bam + + align_log: + - align/ENCSR000COQ1_1_trimmed.hisat2.log + - align/ENCSR000COQ2_1_trimmed.hisat2.log + - align/ENCSR000COR1_1_trimmed.hisat2.log + - align/ENCSR000COR2_1_trimmed.hisat2.log + - align/ENCSR000CPO1_1_trimmed.hisat2.log + - align/ENCSR000CPO2_1_trimmed.hisat2.log ``` This time each step gets run 6 times, once for each sample in the CSV file. @@ -507,15 +567,79 @@ nextflow run rnaseq.nf -profile test -resume ??? success "Command output" ```console - N E X T F L O W ~ version 24.10.0 + N E X T F L O W ~ version 26.04.4 - Launching `rnaseq.nf` [modest_pare] DSL2 - revision: fc724d3b49 + Launching `rnaseq.nf` [modest_pare] revision: fc724d3b49 executor > local (1) - [07/3ff9c5] FASTQC (6) [100%] 6 of 6, cached: 6 ✔ - [2c/8d8e1e] TRIM_GALORE (5) [100%] 6 of 6, cached: 6 ✔ - [a4/7f9c44] HISAT2_ALIGN (6) [100%] 6 of 6, cached: 6 ✔ - [56/e1f102] MULTIQC [100%] 1 of 1 ✔ + [07/3ff9c5] FASTQC (6) | 6 of 6, cached: 6 ✔ + [2c/8d8e1e] TRIM_GALORE (5) | 6 of 6, cached: 6 ✔ + [a4/7f9c44] HISAT2_ALIGN (6) | 6 of 6, cached: 6 ✔ + [56/e1f102] MULTIQC | 1 of 1 ✔ + + Outputs: + + /workspaces/training/nf4-science/rnaseq/results + + fastqc_zip: + - fastqc/ENCSR000COQ1_1_fastqc.zip + - fastqc/ENCSR000COQ2_1_fastqc.zip + - fastqc/ENCSR000COR1_1_fastqc.zip + - fastqc/ENCSR000COR2_1_fastqc.zip + - fastqc/ENCSR000CPO1_1_fastqc.zip + - fastqc/ENCSR000CPO2_1_fastqc.zip + + fastqc_html: + - fastqc/ENCSR000COQ1_1_fastqc.html + - fastqc/ENCSR000COQ2_1_fastqc.html + - fastqc/ENCSR000COR1_1_fastqc.html + - fastqc/ENCSR000COR2_1_fastqc.html + - fastqc/ENCSR000CPO1_1_fastqc.html + - fastqc/ENCSR000CPO2_1_fastqc.html + + trimmed_reads: + - trimming/ENCSR000COQ1_1_trimmed.fq.gz + - trimming/ENCSR000COQ2_1_trimmed.fq.gz + - trimming/ENCSR000COR1_1_trimmed.fq.gz + - trimming/ENCSR000COR2_1_trimmed.fq.gz + - trimming/ENCSR000CPO1_1_trimmed.fq.gz + - trimming/ENCSR000CPO2_1_trimmed.fq.gz + + trimming_reports: + - trimming/ENCSR000COQ1_1.fastq.gz_trimming_report.txt + - trimming/ENCSR000COQ2_1.fastq.gz_trimming_report.txt + - trimming/ENCSR000COR1_1.fastq.gz_trimming_report.txt + - trimming/ENCSR000COR2_1.fastq.gz_trimming_report.txt + - trimming/ENCSR000CPO1_1.fastq.gz_trimming_report.txt + - trimming/ENCSR000CPO2_1.fastq.gz_trimming_report.txt + + trimming_fastqc: + - [trimming/ENCSR000COQ1_1_trimmed_fastqc.html, trimming/ENCSR000COQ1_1_trimmed_fastqc.zip] + - [trimming/ENCSR000COQ2_1_trimmed_fastqc.html, trimming/ENCSR000COQ2_1_trimmed_fastqc.zip] + - [trimming/ENCSR000COR1_1_trimmed_fastqc.html, trimming/ENCSR000COR1_1_trimmed_fastqc.zip] + - [trimming/ENCSR000COR2_1_trimmed_fastqc.html, trimming/ENCSR000COR2_1_trimmed_fastqc.zip] + - [trimming/ENCSR000CPO1_1_trimmed_fastqc.html, trimming/ENCSR000CPO1_1_trimmed_fastqc.zip] + - [trimming/ENCSR000CPO2_1_trimmed_fastqc.html, trimming/ENCSR000CPO2_1_trimmed_fastqc.zip] + + bam: + - align/ENCSR000COQ1_1_trimmed.bam + - align/ENCSR000COQ2_1_trimmed.bam + - align/ENCSR000COR1_1_trimmed.bam + - align/ENCSR000COR2_1_trimmed.bam + - align/ENCSR000CPO1_1_trimmed.bam + - align/ENCSR000CPO2_1_trimmed.bam + + align_log: + - align/ENCSR000COQ1_1_trimmed.hisat2.log + - align/ENCSR000COQ2_1_trimmed.hisat2.log + - align/ENCSR000COR1_1_trimmed.hisat2.log + - align/ENCSR000COR2_1_trimmed.hisat2.log + - align/ENCSR000CPO1_1_trimmed.hisat2.log + - align/ENCSR000CPO2_1_trimmed.hisat2.log + + multiqc_report: multiqc/all_single-end.html + + multiqc_data: multiqc/all_single-end_data ``` A single call to MULTIQC has been added after the cached process calls. @@ -534,6 +658,7 @@ tree -L 2 results/multiqc │ ├── cutadapt_filtered_reads_plot.txt │ ├── cutadapt_trimmed_sequences_plot_3_Counts.txt │ ├── cutadapt_trimmed_sequences_plot_3_Obs_Exp.txt + │ ├── fastqc-status-check-heatmap.txt │ ├── fastqc_adapter_content_plot.txt │ ├── fastqc_overrepresented_sequences_plot.txt │ ├── fastqc_per_base_n_content_plot.txt @@ -544,16 +669,17 @@ tree -L 2 results/multiqc │ ├── fastqc_sequence_counts_plot.txt │ ├── fastqc_sequence_duplication_levels_plot.txt │ ├── fastqc_sequence_length_distribution_plot.txt - │ ├── fastqc-status-check-heatmap.txt │ ├── fastqc_top_overrepresented_sequences_table.txt │ ├── hisat2_se_plot.txt + │ ├── llms-full.txt + │ ├── multiqc.log + │ ├── multiqc.parquet │ ├── multiqc_citations.txt │ ├── multiqc_cutadapt.txt │ ├── multiqc_data.json │ ├── multiqc_fastqc.txt │ ├── multiqc_general_stats.txt │ ├── multiqc_hisat2.txt - │ ├── multiqc.log │ ├── multiqc_software_versions.txt │ └── multiqc_sources.txt └── all_single-end.html @@ -964,15 +1090,87 @@ nextflow run rnaseq_pe.nf -profile test_pe ??? success "Command output" ```console - N E X T F L O W ~ version 24.10.0 + N E X T F L O W ~ version 26.04.4 - Launching `rnaseq_pe.nf` [reverent_kare] DSL2 - revision: 9c376cc219 + Launching `rnaseq_pe.nf` [reverent_kare] revision: 9c376cc219 executor > local (19) - [c5/cbde15] FASTQC (5) [100%] 6 of 6 ✔ - [e4/fa2784] TRIM_GALORE (5) [100%] 6 of 6 ✔ - [3a/e23049] HISAT2_ALIGN (5) [100%] 6 of 6 ✔ - [e6/a3ccd9] MULTIQC [100%] 1 of 1 ✔ + [c5/cbde15] FASTQC (5) | 6 of 6 ✔ + [e4/fa2784] TRIM_GALORE (5) | 6 of 6 ✔ + [3a/e23049] HISAT2_ALIGN (5) | 6 of 6 ✔ + [e6/a3ccd9] MULTIQC | 1 of 1 ✔ + + Outputs: + + /workspaces/training/nf4-science/rnaseq/results + + fastqc_zip: + - [fastqc/ENCSR000COQ1_1_fastqc.zip, fastqc/ENCSR000COQ1_2_fastqc.zip] + - [fastqc/ENCSR000COQ2_1_fastqc.zip, fastqc/ENCSR000COQ2_2_fastqc.zip] + - [fastqc/ENCSR000COR1_1_fastqc.zip, fastqc/ENCSR000COR1_2_fastqc.zip] + - [fastqc/ENCSR000COR2_1_fastqc.zip, fastqc/ENCSR000COR2_2_fastqc.zip] + - [fastqc/ENCSR000CPO1_1_fastqc.zip, fastqc/ENCSR000CPO1_2_fastqc.zip] + - [fastqc/ENCSR000CPO2_1_fastqc.zip, fastqc/ENCSR000CPO2_2_fastqc.zip] + + fastqc_html: + - [fastqc/ENCSR000COQ1_1_fastqc.html, fastqc/ENCSR000COQ1_2_fastqc.html] + - [fastqc/ENCSR000COQ2_1_fastqc.html, fastqc/ENCSR000COQ2_2_fastqc.html] + - [fastqc/ENCSR000COR1_1_fastqc.html, fastqc/ENCSR000COR1_2_fastqc.html] + - [fastqc/ENCSR000COR2_1_fastqc.html, fastqc/ENCSR000COR2_2_fastqc.html] + - [fastqc/ENCSR000CPO1_1_fastqc.html, fastqc/ENCSR000CPO1_2_fastqc.html] + - [fastqc/ENCSR000CPO2_1_fastqc.html, fastqc/ENCSR000CPO2_2_fastqc.html] + + trimmed_reads: + - [trimming/ENCSR000COQ1_1_val_1.fq.gz, trimming/ENCSR000COQ1_2_val_2.fq.gz] + - [trimming/ENCSR000COQ2_1_val_1.fq.gz, trimming/ENCSR000COQ2_2_val_2.fq.gz] + - [trimming/ENCSR000COR1_1_val_1.fq.gz, trimming/ENCSR000COR1_2_val_2.fq.gz] + - [trimming/ENCSR000COR2_1_val_1.fq.gz, trimming/ENCSR000COR2_2_val_2.fq.gz] + - [trimming/ENCSR000CPO1_1_val_1.fq.gz, trimming/ENCSR000CPO1_2_val_2.fq.gz] + - [trimming/ENCSR000CPO2_1_val_1.fq.gz, trimming/ENCSR000CPO2_2_val_2.fq.gz] + + trimming_reports: + - [trimming/ENCSR000COQ1_1.fastq.gz_trimming_report.txt, trimming/ENCSR000COQ1_2.fastq.gz_trimming_report.txt] + - [trimming/ENCSR000COQ2_1.fastq.gz_trimming_report.txt, trimming/ENCSR000COQ2_2.fastq.gz_trimming_report.txt] + - [trimming/ENCSR000COR1_1.fastq.gz_trimming_report.txt, trimming/ENCSR000COR1_2.fastq.gz_trimming_report.txt] + - [trimming/ENCSR000COR2_1.fastq.gz_trimming_report.txt, trimming/ENCSR000COR2_2.fastq.gz_trimming_report.txt] + - [trimming/ENCSR000CPO1_1.fastq.gz_trimming_report.txt, trimming/ENCSR000CPO1_2.fastq.gz_trimming_report.txt] + - [trimming/ENCSR000CPO2_1.fastq.gz_trimming_report.txt, trimming/ENCSR000CPO2_2.fastq.gz_trimming_report.txt] + + trimming_fastqc_1: + - [trimming/ENCSR000COQ1_1_val_1_fastqc.html, trimming/ENCSR000COQ1_1_val_1_fastqc.zip] + - [trimming/ENCSR000COQ2_1_val_1_fastqc.html, trimming/ENCSR000COQ2_1_val_1_fastqc.zip] + - [trimming/ENCSR000COR1_1_val_1_fastqc.html, trimming/ENCSR000COR1_1_val_1_fastqc.zip] + - [trimming/ENCSR000COR2_1_val_1_fastqc.html, trimming/ENCSR000COR2_1_val_1_fastqc.zip] + - [trimming/ENCSR000CPO1_1_val_1_fastqc.html, trimming/ENCSR000CPO1_1_val_1_fastqc.zip] + - [trimming/ENCSR000CPO2_1_val_1_fastqc.html, trimming/ENCSR000CPO2_1_val_1_fastqc.zip] + + trimming_fastqc_2: + - [trimming/ENCSR000COQ1_2_val_2_fastqc.html, trimming/ENCSR000COQ1_2_val_2_fastqc.zip] + - [trimming/ENCSR000COQ2_2_val_2_fastqc.html, trimming/ENCSR000COQ2_2_val_2_fastqc.zip] + - [trimming/ENCSR000COR1_2_val_2_fastqc.html, trimming/ENCSR000COR1_2_val_2_fastqc.zip] + - [trimming/ENCSR000COR2_2_val_2_fastqc.html, trimming/ENCSR000COR2_2_val_2_fastqc.zip] + - [trimming/ENCSR000CPO1_2_val_2_fastqc.html, trimming/ENCSR000CPO1_2_val_2_fastqc.zip] + - [trimming/ENCSR000CPO2_2_val_2_fastqc.html, trimming/ENCSR000CPO2_2_val_2_fastqc.zip] + + bam: + - align/ENCSR000COQ1_1_val_1.bam + - align/ENCSR000COQ2_1_val_1.bam + - align/ENCSR000COR1_1_val_1.bam + - align/ENCSR000COR2_1_val_1.bam + - align/ENCSR000CPO1_1_val_1.bam + - align/ENCSR000CPO2_1_val_1.bam + + align_log: + - align/ENCSR000COQ1_1_val_1.hisat2.log + - align/ENCSR000COQ2_1_val_1.hisat2.log + - align/ENCSR000COR1_1_val_1.hisat2.log + - align/ENCSR000COR2_1_val_1.hisat2.log + - align/ENCSR000CPO1_1_val_1.hisat2.log + - align/ENCSR000CPO2_1_val_1.hisat2.log + + multiqc_report: multiqc/all_paired-end.html + + multiqc_data: multiqc/all_paired-end_data ``` Now we have two slightly divergent versions of our workflow, one for single-end read data and one for paired-end data. From cf2aafdae1fe5ced1d25cee46ca7071cffb92f83 Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 12:59:12 +0100 Subject: [PATCH 08/42] docs(hello_nextflow): fix stale 'greeting' param to 'input' in lesson 4 snippets [skip ci] --- docs/en/docs/hello_nextflow/04_hello_modules.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/en/docs/hello_nextflow/04_hello_modules.md b/docs/en/docs/hello_nextflow/04_hello_modules.md index eeb4d62863..63c7cffc0d 100644 --- a/docs/en/docs/hello_nextflow/04_hello_modules.md +++ b/docs/en/docs/hello_nextflow/04_hello_modules.md @@ -185,7 +185,7 @@ Let's insert that above the `params` block and fill it out appropriately. * Pipeline parameters */ params { - greeting: Path = 'data/greetings.csv' + input: Path = 'data/greetings.csv' batch: String = 'batch' } ``` @@ -197,7 +197,7 @@ Let's insert that above the `params` block and fill it out appropriately. * Pipeline parameters */ params { - greeting: Path = 'data/greetings.csv' + input: Path = 'data/greetings.csv' batch: String = 'batch' } ``` @@ -291,7 +291,7 @@ Insert the include declaration above the `params` block and fill it out appropri * Pipeline parameters */ params { - greeting: Path = 'data/greetings.csv' + input: Path = 'data/greetings.csv' batch: String = 'batch' } ``` @@ -306,7 +306,7 @@ Insert the include declaration above the `params` block and fill it out appropri * Pipeline parameters */ params { - greeting: Path = 'data/greetings.csv' + input: Path = 'data/greetings.csv' batch: String = 'batch' } ``` @@ -394,7 +394,7 @@ Insert the include declaration above the `params` block and fill it out appropri * Pipeline parameters */ params { - greeting: Path = 'data/greetings.csv' + input: Path = 'data/greetings.csv' batch: String = 'batch' } ``` @@ -410,7 +410,7 @@ Insert the include declaration above the `params` block and fill it out appropri * Pipeline parameters */ params { - greeting: Path = 'data/greetings.csv' + input: Path = 'data/greetings.csv' batch: String = 'batch' } ``` From 8bb02623fd4aaec8f6b6d96b4e15f5a8c02cea50 Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 13:05:13 +0100 Subject: [PATCH 09/42] docs: fix cowpy demos to use stdin so documented output is genuine The positional form 'cowpy "Hello Containers"' does not put the text in the speech bubble (cowpy reads the message from stdin); it printed the cowacter self-description. Use the stdin form, matching how the pipeline module invokes cowpy, so the documented output is what the command actually produces. [skip ci] --- .../hello_nextflow/05_hello_containers.md | 14 +++++----- docs/en/docs/nextflow_run/02_pipeline.md | 28 +++++++++---------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/docs/en/docs/hello_nextflow/05_hello_containers.md b/docs/en/docs/hello_nextflow/05_hello_containers.md index a11714d148..f932d0ca1c 100644 --- a/docs/en/docs/hello_nextflow/05_hello_containers.md +++ b/docs/en/docs/hello_nextflow/05_hello_containers.md @@ -271,22 +271,22 @@ Now that you are inside the container, you can run the `cowpy` command directly For example, the tool documentation says we can change the character ('cowacter') with `-c`. ```bash -cowpy "Hello Containers" -c tux +echo "Hello Containers" | cowpy -c tux ``` ??? success "Command output" ```console - __________________ + __________________ < Hello Containers > - ------------------ - \ + ------------------ + \ \ .--. - |o_o | - |:_/ | + |o_o | + |:_/ | // \ \ - (| | ) + (| | ) /'\_ _/`\ \___)=(___/ ``` diff --git a/docs/en/docs/nextflow_run/02_pipeline.md b/docs/en/docs/nextflow_run/02_pipeline.md index 9169602995..ec7a4bc5db 100644 --- a/docs/en/docs/nextflow_run/02_pipeline.md +++ b/docs/en/docs/nextflow_run/02_pipeline.md @@ -1145,20 +1145,20 @@ You see that the filesystem inside the container is different from the filesyste From inside the container, you can run the `cowpy` command directly. ```bash -cowpy "Hello Containers" +echo "Hello Containers" | cowpy ``` ??? success "Command output" ```console - ______________________________________________________ + __________________ < Hello Containers > - ------------------------------------------------------ - \ ^__^ + ------------------ + \ ^__^ \ (oo)\_______ - (__)\ )\/\ - ||----w | - || || + (__)\ )\/\ + ||----w | + || || ``` This produces ASCII art of the default cow character (or 'cowacter') with a speech bubble containing the text we specified. @@ -1167,22 +1167,22 @@ Now that you have tested the basic usage, you can try giving it some parameters. For example, the tool documentation says we can set the character with `-c`. ```bash -cowpy "Hello Containers" -c tux +echo "Hello Containers" | cowpy -c tux ``` ??? success "Command output" ```console - __________________ + __________________ < Hello Containers > - ------------------ - \ + ------------------ + \ \ .--. - |o_o | - |:_/ | + |o_o | + |:_/ | // \ \ - (| | ) + (| | ) /'\_ _/`\ \___)=(___/ ``` From 14c5d418a06af34deffb882a67f567ece73150c2 Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 13:36:39 +0100 Subject: [PATCH 10/42] docs(side_quests): refresh nf_test + plugin_development for Nextflow 26.04 [skip ci] --- docs/en/docs/side_quests/nf_test/index.md | 53 ++++++++++++++----- .../plugin_development/02_create_project.md | 2 +- .../plugin_development/03_custom_functions.md | 16 +++--- .../plugin_development/05_observers.md | 6 +-- .../2-create-project/nf-greeting/build.gradle | 2 +- .../nf-greeting/build.gradle | 2 +- .../4-build-and-test/nf-greeting/build.gradle | 2 +- .../5-observers/nf-greeting/build.gradle | 2 +- .../6-configuration/nf-greeting/build.gradle | 2 +- 9 files changed, 57 insertions(+), 30 deletions(-) diff --git a/docs/en/docs/side_quests/nf_test/index.md b/docs/en/docs/side_quests/nf_test/index.md index 72ca64f083..f86c7ece08 100644 --- a/docs/en/docs/side_quests/nf_test/index.md +++ b/docs/en/docs/side_quests/nf_test/index.md @@ -181,13 +181,27 @@ nextflow run main.nf ``` ```console title="Result of running the workflow" - N E X T F L O W ~ version 24.10.2 + N E X T F L O W ~ version 26.04.4 -Launching `main.nf` [soggy_linnaeus] DSL2 - revision: bbf79d5c31 +Launching `main.nf` [trusting_mendel] revision: 405c90f891 executor > local (6) -[f7/c3be66] sayHello (3) | 3 of 3 ✔ -[cd/e15303] convertToUpper (3) | 3 of 3 ✔ +[6c/d7ae4e] sayHello (3) | 3 of 3 ✔ +[72/5fa770] convertToUpper (2) | 3 of 3 ✔ + +Outputs: + + /workspaces/training/side-quests/nf-test/results + + greetings: + - Hola-output.txt + - Hello-output.txt + - Bonjour-output.txt + + upper_greetings: + - UPPER-Hola-output.txt + - UPPER-Bonjour-output.txt + - UPPER-Hello-output.txt ``` CONGRATULATIONS! You just ran a test! @@ -458,15 +472,28 @@ https://www.nf-test.com Test Workflow main.nf Test [693ba951] 'Should run without failures' - > Nextflow 24.10.4 is available - Please consider updating your version to it - > N E X T F L O W ~ version 24.10.0 - > Launching `/workspaces/training/side-quests/nf-test/main.nf` [zen_ampere] DSL2 - revision: bbf79d5c31 - > [2b/61e453] Submitted process > sayHello (2) - > [31/4e1606] Submitted process > sayHello (1) - > [bb/5209ee] Submitted process > sayHello (3) - > [83/83db6f] Submitted process > convertToUpper (2) - > [9b/3428b1] Submitted process > convertToUpper (1) - > [ca/0ba51b] Submitted process > convertToUpper (3) + > N E X T F L O W ~ version 26.04.4 + > Launching `/workspaces/training/side-quests/nf-test/main.nf` [maniac_mcclintock] - revision: 405c90f891 + > [fc/6965c3] Submitted process > sayHello (1) + > [14/640c84] Submitted process > sayHello (2) + > [d6/3594c9] Submitted process > sayHello (3) + > [d7/f14d58] Submitted process > convertToUpper (1) + > [76/cb9122] Submitted process > convertToUpper (2) + > [d1/92b304] Submitted process > convertToUpper (3) + > + > Outputs: + > + > /workspaces/training/side-quests/nf-test/.nf-test/tests/84ba145929856dd1582dc2e0d9c5c1de/results + > + > greetings: + > - Bonjour-output.txt + > - Hello-output.txt + > - Hola-output.txt + > + > upper_greetings: + > - UPPER-Bonjour-output.txt + > - UPPER-Hola-output.txt + > - UPPER-Hello-output.txt PASSED (5.206s) diff --git a/docs/en/docs/side_quests/plugin_development/02_create_project.md b/docs/en/docs/side_quests/plugin_development/02_create_project.md index f176754455..0956aef7c7 100644 --- a/docs/en/docs/side_quests/plugin_development/02_create_project.md +++ b/docs/en/docs/side_quests/plugin_development/02_create_project.md @@ -168,7 +168,7 @@ Update it to match your installed Nextflow version for full compatibility: ```groovy title="build.gradle" hl_lines="2" nextflowPlugin { - nextflowVersion = '25.10.0' + nextflowVersion = '26.04.0' provider = 'training' ``` diff --git a/docs/en/docs/side_quests/plugin_development/03_custom_functions.md b/docs/en/docs/side_quests/plugin_development/03_custom_functions.md index 6437492166..f434d10062 100644 --- a/docs/en/docs/side_quests/plugin_development/03_custom_functions.md +++ b/docs/en/docs/side_quests/plugin_development/03_custom_functions.md @@ -264,16 +264,16 @@ nextflow run greet.nf ??? example "Output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `greet.nf` [elated_marconi] DSL2 - revision: cd8d52c97c + Launching `greet.nf` [elated_marconi] revision: cd8d52c97c Pipeline is starting! 🚀 executor > local (5) - [fe/109754] process > SAY_HELLO (5) [100%] 5 of 5 ✔ + [fe/109754] SAY_HELLO (5) | 5 of 5 ✔ Reversed: olleH Reversed: ruojnoB - Reversed: àloH + Reversed: aloH Reversed: oaiC Reversed: ollaH Output: Hello @@ -441,16 +441,16 @@ nextflow run greet.nf ??? example "Output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `greet.nf` [elated_marconi] DSL2 - revision: cd8d52c97c + Launching `greet.nf` [elated_marconi] revision: cd8d52c97c Pipeline is starting! 🚀 executor > local (5) - [fe/109754] process > SAY_HELLO (5) [100%] 5 of 5 ✔ + [fe/109754] SAY_HELLO (5) | 5 of 5 ✔ Reversed: olleH Reversed: ruojnoB - Reversed: àloH + Reversed: aloH Reversed: oaiC Reversed: ollaH Decorated: *** Hello *** diff --git a/docs/en/docs/side_quests/plugin_development/05_observers.md b/docs/en/docs/side_quests/plugin_development/05_observers.md index 5c5e228109..ded7307d09 100644 --- a/docs/en/docs/side_quests/plugin_development/05_observers.md +++ b/docs/en/docs/side_quests/plugin_development/05_observers.md @@ -308,12 +308,12 @@ nextflow run greet.nf -ansi-log false ??? example "Output" ```console - N E X T F L O W ~ version 25.10.4 - Launching `greet.nf` [pensive_engelbart] DSL2 - revision: 85fefd90d0 + N E X T F L O W ~ version 26.04.4 + Launching `greet.nf` [pensive_engelbart] - revision: 85fefd90d0 Pipeline is starting! 🚀 Reversed: olleH Reversed: ruojnoB - Reversed: àloH + Reversed: aloH Reversed: oaiC Reversed: ollaH [be/bd8e72] Submitted process > SAY_HELLO (2) diff --git a/side-quests/plugin_development/solutions/2-create-project/nf-greeting/build.gradle b/side-quests/plugin_development/solutions/2-create-project/nf-greeting/build.gradle index 317ba7806d..6ce02c8e80 100644 --- a/side-quests/plugin_development/solutions/2-create-project/nf-greeting/build.gradle +++ b/side-quests/plugin_development/solutions/2-create-project/nf-greeting/build.gradle @@ -5,7 +5,7 @@ plugins { version = '0.1.0' nextflowPlugin { - nextflowVersion = '25.10.0' + nextflowVersion = '26.04.0' provider = 'training' className = 'training.plugin.GreetingPlugin' diff --git a/side-quests/plugin_development/solutions/3-custom-functions/nf-greeting/build.gradle b/side-quests/plugin_development/solutions/3-custom-functions/nf-greeting/build.gradle index 317ba7806d..6ce02c8e80 100644 --- a/side-quests/plugin_development/solutions/3-custom-functions/nf-greeting/build.gradle +++ b/side-quests/plugin_development/solutions/3-custom-functions/nf-greeting/build.gradle @@ -5,7 +5,7 @@ plugins { version = '0.1.0' nextflowPlugin { - nextflowVersion = '25.10.0' + nextflowVersion = '26.04.0' provider = 'training' className = 'training.plugin.GreetingPlugin' diff --git a/side-quests/plugin_development/solutions/4-build-and-test/nf-greeting/build.gradle b/side-quests/plugin_development/solutions/4-build-and-test/nf-greeting/build.gradle index 317ba7806d..6ce02c8e80 100644 --- a/side-quests/plugin_development/solutions/4-build-and-test/nf-greeting/build.gradle +++ b/side-quests/plugin_development/solutions/4-build-and-test/nf-greeting/build.gradle @@ -5,7 +5,7 @@ plugins { version = '0.1.0' nextflowPlugin { - nextflowVersion = '25.10.0' + nextflowVersion = '26.04.0' provider = 'training' className = 'training.plugin.GreetingPlugin' diff --git a/side-quests/plugin_development/solutions/5-observers/nf-greeting/build.gradle b/side-quests/plugin_development/solutions/5-observers/nf-greeting/build.gradle index 317ba7806d..6ce02c8e80 100644 --- a/side-quests/plugin_development/solutions/5-observers/nf-greeting/build.gradle +++ b/side-quests/plugin_development/solutions/5-observers/nf-greeting/build.gradle @@ -5,7 +5,7 @@ plugins { version = '0.1.0' nextflowPlugin { - nextflowVersion = '25.10.0' + nextflowVersion = '26.04.0' provider = 'training' className = 'training.plugin.GreetingPlugin' diff --git a/side-quests/plugin_development/solutions/6-configuration/nf-greeting/build.gradle b/side-quests/plugin_development/solutions/6-configuration/nf-greeting/build.gradle index 6fbbb0534d..7b0677f5db 100644 --- a/side-quests/plugin_development/solutions/6-configuration/nf-greeting/build.gradle +++ b/side-quests/plugin_development/solutions/6-configuration/nf-greeting/build.gradle @@ -5,7 +5,7 @@ plugins { version = '0.1.0' nextflowPlugin { - nextflowVersion = '25.10.0' + nextflowVersion = '26.04.0' provider = 'training' className = 'training.plugin.GreetingPlugin' From 8d7437e0eccd7ac10521395eda893678e54426d9 Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 13:37:08 +0100 Subject: [PATCH 11/42] docs(side_quests): refresh working_with_files for Nextflow 26.04 [skip ci] --- .../side_quests/working_with_files/index.md | 250 +++++++++++++----- 1 file changed, 185 insertions(+), 65 deletions(-) diff --git a/docs/en/docs/side_quests/working_with_files/index.md b/docs/en/docs/side_quests/working_with_files/index.md index 7dbe1ce8aa..ded42e2236 100644 --- a/docs/en/docs/side_quests/working_with_files/index.md +++ b/docs/en/docs/side_quests/working_with_files/index.md @@ -161,11 +161,17 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [romantic_chandrasekhar] DSL2 - revision: 5a4a89bc3a + Launching `main.nf` [romantic_chandrasekhar] revision: 5a4a89bc3a data/patientA_rep1_normal_R1_001.fastq.gz is of class class java.lang.String + + Outputs: + + /workspaces/training/side-quests/working_with_files/results + + analysis_results: ``` As you can see, Nextflow printed the string path exactly as we wrote it. @@ -209,11 +215,17 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [kickass_coulomb] DSL2 - revision: 5af44b1b59 + Launching `main.nf` [kickass_coulomb] revision: 5af44b1b59 /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R1_001.fastq.gz is of class class sun.nio.fs.UnixPath + + Outputs: + + /workspaces/training/side-quests/working_with_files/results + + analysis_results: ``` This time, you see the full absolute path instead of the relative path we provided as input. @@ -273,15 +285,21 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [ecstatic_ampere] DSL2 - revision: f3fa3dcb48 + Launching `main.nf` [ecstatic_ampere] revision: f3fa3dcb48 File object class: class sun.nio.fs.UnixPath File name: patientA_rep1_normal_R1_001.fastq.gz Simple name: patientA_rep1_normal_R1_001 Extension: gz Parent directory: /workspaces/training/side-quests/working_with_files/data + + Outputs: + + /workspaces/training/side-quests/working_with_files/results + + analysis_results: ``` You see the various file attributes printed to the console above. @@ -390,9 +408,9 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [cheeky_hypatia] DSL2 - revision: 281d13c414 + Launching `main.nf` [cheeky_hypatia] revision: 281d13c414 File object class: class sun.nio.fs.UnixPath File name: patientA_rep1_normal_R1_001.fastq.gz @@ -400,9 +418,15 @@ nextflow run main.nf Extension: gz Parent directory: /workspaces/training/side-quests/working_with_files/data executor > local (1) - [e9/341c05] COUNT_LINES [100%] 1 of 1 ✔ - Processing file: /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R1_001.fastq.gz + [e9/341c05] COUNT_LINES | 1 of 1 ✔ + Processing file: patientA_rep1_normal_R1_001.fastq.gz 40 + + Outputs: + + /workspaces/training/side-quests/working_with_files/results + + analysis_results: ``` This shows we are able to operate on the file appropriately inside a process. @@ -473,10 +497,11 @@ nextflow run main.nf ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [friendly_goodall] DSL2 - revision: ae50609b20 + Launching `main.nf` [friendly_goodall] revision: ae50609b20 + File object class: class java.lang.String [- ] COUNT_LINES - ERROR ~ Error executing process > 'COUNT_LINES' @@ -485,9 +510,9 @@ nextflow run main.nf - Tip: view the complete command output by changing to the process work dir and entering the command `cat .command.out` + Tip: you can replicate the issue by changing to the process work dir and entering the command `bash .command.run` - -- Check '.nextflow.log' file for details + -- Check '.nextflow.log' file for details ``` This is the important bit: @@ -541,12 +566,13 @@ nextflow run main.nf ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [soggy_golick] DSL2 - revision: ae50609b20 + Launching `main.nf` [soggy_golick] revision: ae50609b20 + File object class: class java.lang.String executor > local (1) - [b3/b3023c] COUNT_LINES [ 0%] 0 of 1 ✘ + [b3/b3023c] COUNT_LINES | 0 of 1 ✘ ERROR ~ Error executing process > 'COUNT_LINES' Caused by: @@ -574,9 +600,9 @@ nextflow run main.nf Work dir: /workspaces/training/side-quests/working_with_files/work/b3/b3023cb2ccb986851301d8e369e79f - Tip: when you have fixed the problem you can continue the execution adding the option `-resume` to the run command line + Tip: you can replicate the issue by changing to the process work dir and entering the command `bash .command.run` - -- Check '.nextflow.log' file for details + -- Check '.nextflow.log' file for details ``` This shows a lot of details about the error because the process is set to output debugging information, as noted above. @@ -690,9 +716,9 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [insane_swartz] DSL2 - revision: fff18abe6d + Launching `main.nf` [insane_swartz] revision: fff18abe6d File object class: class nextflow.file.http.XPath File name: patientA_rep1_normal_R1_001.fastq.gz @@ -700,9 +726,15 @@ nextflow run main.nf Extension: gz Parent directory: /nextflow-io/training/master/side-quests/working_with_files/data executor > local (1) - [8a/2ab7ca] COUNT_LINES [100%] 1 of 1 ✔ + [8a/2ab7ca] COUNT_LINES | 1 of 1 ✔ Processing file: patientA_rep1_normal_R1_001.fastq.gz 40 + + Outputs: + + /workspaces/training/side-quests/working_with_files/results + + analysis_results: ``` It works! You can see that very little has changed. @@ -875,11 +907,17 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [grave_meucci] DSL2 - revision: b09964a583 + Launching `main.nf` [grave_meucci] revision: b09964a583 Found file: /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R1_001.fastq.gz + + Outputs: + + /workspaces/training/side-quests/working_with_files/results + + analysis_results: ``` As you can see, the file path is being loaded as a `Path` type object in the channel. @@ -932,12 +970,12 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [furious_swanson] DSL2 - revision: c35c34950d + Launching `main.nf` [furious_swanson] revision: c35c34950d executor > local (1) - [9d/6701a6] COUNT_LINES (1) [100%] 1 of 1 ✔ + [9d/6701a6] COUNT_LINES (1) | 1 of 1 ✔ File object class: class sun.nio.fs.UnixPath File name: patientA_rep1_normal_R1_001.fastq.gz Simple name: patientA_rep1_normal_R1_001 @@ -945,6 +983,12 @@ nextflow run main.nf Parent directory: /workspaces/training/side-quests/working_with_files/data Processing file: patientA_rep1_normal_R1_001.fastq.gz 40 + + Outputs: + + /workspaces/training/side-quests/working_with_files/results + + analysis_results: ``` And there you are, same results as before but now we have the file in a channel, so we can add more. @@ -1001,12 +1045,12 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [boring_sammet] DSL2 - revision: d2aa789c9a + Launching `main.nf` [boring_sammet] revision: d2aa789c9a executor > local (2) - [3c/a65de5] COUNT_LINES (2) [100%] 2 of 2 ✔ + [3c/a65de5] COUNT_LINES (2) | 2 of 2 ✔ File object class: class sun.nio.fs.UnixPath File name: patientA_rep1_normal_R1_001.fastq.gz Simple name: patientA_rep1_normal_R1_001 @@ -1022,6 +1066,12 @@ nextflow run main.nf Processing file: patientA_rep1_normal_R2_001.fastq.gz 40 + + Outputs: + + /workspaces/training/side-quests/working_with_files/results + + analysis_results: ``` As you can see, we now have two Path objects in our channel, which shows that Nextflow has done the filename expansion correctly, and has loaded and processed both files as expected. @@ -1106,19 +1156,25 @@ nextflow run main.nf ??? success "Command output" ```console hl_lines="7-8" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [suspicious_mahavira] DSL2 - revision: ae8edc4e48 + Launching `main.nf` [suspicious_mahavira] revision: ae8edc4e48 executor > local (2) - [e9/55774b] COUNT_LINES (2) [100%] 2 of 2 ✔ - [patientA_rep1_normal_R2_001, /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R2_001.fastq.gz] + [e9/55774b] COUNT_LINES (2) | 2 of 2 ✔ [patientA_rep1_normal_R1_001, /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R1_001.fastq.gz] - Processing file: patientA_rep1_normal_R1_001.fastq.gz + [patientA_rep1_normal_R2_001, /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R2_001.fastq.gz] + Processing file: patientA_rep1_normal_R2_001.fastq.gz 40 - Processing file: patientA_rep1_normal_R2_001.fastq.gz + Processing file: patientA_rep1_normal_R1_001.fastq.gz 40 + + Outputs: + + /workspaces/training/side-quests/working_with_files/results + + analysis_results: ``` Each element in the channel is now a tuple containing the `simpleName` and the original file object. @@ -1162,19 +1218,25 @@ nextflow run main.nf ??? success "Command output" ```console hl_lines="7-8" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [gigantic_gauss] DSL2 - revision: a39baabb57 + Launching `main.nf` [gigantic_gauss] revision: a39baabb57 executor > local (2) - [e7/da2f4b] COUNT_LINES (2) [100%] 2 of 2 ✔ - [[patientA, rep1, normal, R2, 001], /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R2_001.fastq.gz] + [e7/da2f4b] COUNT_LINES (2) | 2 of 2 ✔ [[patientA, rep1, normal, R1, 001], /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R1_001.fastq.gz] + [[patientA, rep1, normal, R2, 001], /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R2_001.fastq.gz] Processing file: patientA_rep1_normal_R2_001.fastq.gz 40 Processing file: patientA_rep1_normal_R1_001.fastq.gz 40 + + Outputs: + + /workspaces/training/side-quests/working_with_files/results + + analysis_results: ``` Now the tuple for each element in our channel contains the list of metadata (_e.g._ `[patientA, rep1, normal, R1, 001]`) and the original file object. @@ -1263,19 +1325,25 @@ nextflow run main.nf ??? success "Command output" ```console hl_lines="7-8" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [infallible_swartz] DSL2 - revision: 7f4e68c0cb + Launching `main.nf` [infallible_swartz] revision: 7f4e68c0cb executor > local (2) - [1b/e7fb27] COUNT_LINES (1) [100%] 2 of 2 ✔ - [[id:patientA, replicate:1, type:normal, readNum:2], /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R2_001.fastq.gz] + [1b/e7fb27] COUNT_LINES (1) | 2 of 2 ✔ [[id:patientA, replicate:1, type:normal, readNum:1], /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R1_001.fastq.gz] + [[id:patientA, replicate:1, type:normal, readNum:2], /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R2_001.fastq.gz] Processing file: patientA_rep1_normal_R2_001.fastq.gz 40 Processing file: patientA_rep1_normal_R1_001.fastq.gz 40 + + Outputs: + + /workspaces/training/side-quests/working_with_files/results + + analysis_results: ``` Now the metadata is neatly labeled (_e.g._ `[id:patientA, replicate:1, type:normal, readNum:2]`) so it's a lot easier to tell what is what. @@ -1381,12 +1449,11 @@ nextflow run main.nf ??? failure "Command output" - ```console hl_lines="7-8" - N E X T F L O W ~ version 25.10.4 + ```console hl_lines="6-7" + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [angry_koch] DSL2 - revision: 44fdf66105 + Launching `main.nf` [angry_koch] revision: 44fdf66105 - [- ] COUNT_LINES - [- ] COUNT_LINES - [patientA_rep1_normal_R, [/workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R1_001.fastq.gz, /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R2_001.fastq.gz]] ERROR ~ Error executing process > 'COUNT_LINES (1)' @@ -1396,9 +1463,9 @@ nextflow run main.nf - Tip: when you have fixed the problem you can continue the execution adding the option `-resume` to the run command line + Tip: you can replicate the issue by changing to the process work dir and entering the command `bash .command.run` - -- Check '.nextflow.log' file for details + -- Check '.nextflow.log' file for details ``` Uh-oh, this time the run failed! @@ -1449,11 +1516,17 @@ nextflow run main.nf ??? success "Command output" ```console hl_lines="5" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [fabulous_davinci] DSL2 - revision: 22b53268dc + Launching `main.nf` [fabulous_davinci] revision: 22b53268dc [patientA_rep1_normal_R, [/workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R1_001.fastq.gz, /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R2_001.fastq.gz]] + + Outputs: + + /workspaces/training/side-quests/working_with_files/results + + analysis_results: ``` Yay, this time the workflow succeeds! @@ -1524,11 +1597,17 @@ nextflow run main.nf ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [prickly_stonebraker] DSL2 - revision: f62ab10a3f + Launching `main.nf` [prickly_stonebraker] revision: f62ab10a3f [[id:patientA, replicate:1, type:normal], [/workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R1_001.fastq.gz, /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R2_001.fastq.gz]] + + Outputs: + + /workspaces/training/side-quests/working_with_files/results + + analysis_results: ``` And there it is: we have the metadata map (`[id:patientA, replicate:1, type:normal]`) in the first position of the output tuple, followed by the tuple of paired files, as intended. @@ -1684,11 +1763,17 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [goofy_kirch] DSL2 - revision: 3313283e42 + Launching `main.nf` [goofy_kirch] revision: 3313283e42 [[id:patientA, replicate:1, type:normal], [/workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R1_001.fastq.gz, /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R2_001.fastq.gz]] + + Outputs: + + /workspaces/training/side-quests/working_with_files/results + + analysis_results: ``` This confirms we can now refer to the channel by name. @@ -1782,12 +1867,19 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `./main.nf` [shrivelled_cori] DSL2 - revision: b546a31769 + Launching `main.nf` [shrivelled_cori] revision: b546a31769 executor > local (1) - [b5/110360] process > ANALYZE_READS (patientA) [100%] 1 of 1 ✔ + [b5/110360] ANALYZE_READS (patientA) | 1 of 1 ✔ + + Outputs: + + /workspaces/training/side-quests/working_with_files/results + + analysis_results: + - [{id: patientA, replicate: '1', type: normal}, patientA/patientA_stats.txt] ``` The outputs are published to a `results` directory, so have a look in there. @@ -1847,12 +1939,26 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `./main.nf` [big_stonebraker] DSL2 - revision: f7f9b8a76c + Launching `main.nf` [big_stonebraker] revision: f7f9b8a76c executor > local (8) - [d5/441891] process > ANALYZE_READS (patientC) [100%] 8 of 8 ✔ + [d5/441891] ANALYZE_READS (patientC) | 8 of 8 ✔ + + Outputs: + + /workspaces/training/side-quests/working_with_files/results + + analysis_results: + - [{id: patientB, replicate: '1', type: tumor}, patientB/patientB_stats.txt] + - [{id: patientA, replicate: '2', type: tumor}, patientA/patientA_stats.txt] + - [{id: patientC, replicate: '1', type: normal}, patientC/patientC_stats.txt] + - [{id: patientB, replicate: '1', type: normal}, patientB/patientB_stats.txt] + - [{id: patientA, replicate: '1', type: normal}, patientA/patientA_stats.txt] + - [{id: patientA, replicate: '1', type: tumor}, patientA/patientA_stats.txt] + - [{id: patientA, replicate: '2', type: normal}, patientA/patientA_stats.txt] + - [{id: patientC, replicate: '1', type: tumor}, patientC/patientC_stats.txt] ``` The results directory should now contain results for all the available data. @@ -1909,12 +2015,26 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `./main.nf` [insane_swartz] DSL2 - revision: fff18abe6d + Launching `main.nf` [insane_swartz] revision: fff18abe6d executor > local (8) - [e3/449081] process > ANALYZE_READS (patientC) [100%] 8 of 8 ✔ + [e3/449081] ANALYZE_READS (patientC) | 8 of 8 ✔ + + Outputs: + + /workspaces/training/side-quests/working_with_files/results + + analysis_results: + - [{id: patientB, replicate: '1', type: normal}, normal/patientB/1/patientB_stats.txt] + - [{id: patientB, replicate: '1', type: tumor}, tumor/patientB/1/patientB_stats.txt] + - [{id: patientC, replicate: '1', type: normal}, normal/patientC/1/patientC_stats.txt] + - [{id: patientA, replicate: '1', type: tumor}, tumor/patientA/1/patientA_stats.txt] + - [{id: patientA, replicate: '1', type: normal}, normal/patientA/1/patientA_stats.txt] + - [{id: patientA, replicate: '2', type: normal}, normal/patientA/2/patientA_stats.txt] + - [{id: patientC, replicate: '1', type: tumor}, tumor/patientC/1/patientC_stats.txt] + - [{id: patientA, replicate: '2', type: tumor}, tumor/patientA/2/patientA_stats.txt] ``` Check the results directory now: From d6eacef56acc64e3eda3cea3e8fca7e1dc8f0e2e Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 13:37:50 +0100 Subject: [PATCH 12/42] docs(hello_nf-core): refresh tutorial output for Nextflow 26.04 (runs under v1 parser) [skip ci] --- docs/en/docs/hello_nf-core/01_run_demo.md | 12 +-- .../en/docs/hello_nf-core/02_rewrite_hello.md | 24 +++--- docs/en/docs/hello_nf-core/03_use_module.md | 12 +-- docs/en/docs/hello_nf-core/04_make_module.md | 76 +++++++++---------- .../docs/hello_nf-core/05_input_validation.md | 8 +- 5 files changed, 66 insertions(+), 66 deletions(-) diff --git a/docs/en/docs/hello_nf-core/01_run_demo.md b/docs/en/docs/hello_nf-core/01_run_demo.md index 967c3b642c..8a12de3684 100644 --- a/docs/en/docs/hello_nf-core/01_run_demo.md +++ b/docs/en/docs/hello_nf-core/01_run_demo.md @@ -80,7 +80,7 @@ nextflow pull nf-core/demo ```console Checking nf-core/demo ... - downloaded from https://github.com/nf-core/demo.git - revision: 04060b4644 [master] + downloaded from https://github.com/nf-core/demo.git - revision: 45904cb9d1 [master] ``` Nextflow does a `pull` of the pipeline code, meaning it downloads the full repository to your local drive. @@ -303,9 +303,9 @@ nextflow run nf-core/demo -profile docker,test --outdir demo-results ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `https://github.com/nf-core/demo` [magical_pauling] DSL2 - revision: 45904cb9d1 [master] + Launching `https://github.com/nf-core/demo` [magical_pauling] revision: 45904cb9d1 [master] ------------------------------------------------------ @@ -369,7 +369,7 @@ There's a header that includes a summary of the pipeline's version, inputs and o Notice the line near the top of the output: ```console -Launching `https://github.com/nf-core/demo` [magical_pauling] DSL2 - revision: 45904cb9d1 [master] +Launching `https://github.com/nf-core/demo` [magical_pauling] revision: 45904cb9d1 [master] ``` This tells you which revision of the pipeline was used. @@ -489,9 +489,9 @@ nextflow run nf-core/demo --help ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `https://github.com/nf-core/demo` [run_name] DSL2 - revision: 45904cb9d1 [master] + Launching `https://github.com/nf-core/demo` [run_name] revision: 45904cb9d1 [master] ---------------------------------------------------- ,--./,-. diff --git a/docs/en/docs/hello_nf-core/02_rewrite_hello.md b/docs/en/docs/hello_nf-core/02_rewrite_hello.md index ea592f79a0..a87a7852be 100644 --- a/docs/en/docs/hello_nf-core/02_rewrite_hello.md +++ b/docs/en/docs/hello_nf-core/02_rewrite_hello.md @@ -350,9 +350,9 @@ nextflow run ./core-hello -profile docker,test --outdir core-hello-results ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `./core-hello/main.nf` [scruffy_marconi] DSL2 - revision: b9e9b3b8de + Launching `./core-hello/main.nf` [scruffy_marconi] revision: b9e9b3b8de Downloading plugin nf-schema@2.5.1 Input/output options @@ -573,9 +573,9 @@ nextflow run original-hello/hello.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `original-hello/hello.nf` [goofy_babbage] DSL2 - revision: e9e72441e9 + Launching `original-hello/hello.nf` [goofy_babbage] revision: e9e72441e9 executor > local (8) [a4/081cec] sayHello (1) | 3 of 3 ✔ @@ -876,9 +876,9 @@ If you made all the changes correctly, this should run to completion. ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `original-hello/main.nf` [friendly_wright] DSL2 - revision: 1ecd2d9c0a + Launching `original-hello/main.nf` [friendly_wright] revision: 1ecd2d9c0a executor > local (8) [24/c6c0d8] HELLO:sayHello (3) | 3 of 3 ✔ @@ -1607,9 +1607,9 @@ If you've done all of the modifications correctly, it should run to completion. ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `core-hello/main.nf` [condescending_allen] DSL2 - revision: b9e9b3b8de + Launching `core-hello/main.nf` [condescending_allen] revision: b9e9b3b8de Input/output options input : /workspaces/training/hello-nf-core/core-hello/assets/greetings.csv @@ -1636,10 +1636,10 @@ If you've done all of the modifications correctly, it should run to completion. !! Only displaying parameters that differ from the pipeline defaults !! ------------------------------------------------------ executor > local (1) - [ed/727b7e] CORE_HELLO:HELLO:sayHello (3) [100%] 3 of 3 ✔ - [45/bb6096] CORE_HELLO:HELLO:convertToUpper (3) [100%] 3 of 3 ✔ - [81/7e2e34] CORE_HELLO:HELLO:collectGreetings [100%] 1 of 1 ✔ - [96/9442a1] CORE_HELLO:HELLO:cowpy [100%] 1 of 1 ✔ + [ed/727b7e] CORE_HELLO:HELLO:sayHello (3) | 3 of 3 ✔ + [45/bb6096] CORE_HELLO:HELLO:convertToUpper (3) | 3 of 3 ✔ + [81/7e2e34] CORE_HELLO:HELLO:collectGreetings | 1 of 1 ✔ + [96/9442a1] CORE_HELLO:HELLO:cowpy | 1 of 1 ✔ -[core/hello] Pipeline completed successfully- ``` diff --git a/docs/en/docs/hello_nf-core/03_use_module.md b/docs/en/docs/hello_nf-core/03_use_module.md index 434e82ff64..39d4602e69 100644 --- a/docs/en/docs/hello_nf-core/03_use_module.md +++ b/docs/en/docs/hello_nf-core/03_use_module.md @@ -768,9 +768,9 @@ This should run reasonably quickly. ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `./main.nf` [evil_pike] DSL2 - revision: b9e9b3b8de + Launching `./main.nf` [evil_pike] revision: b9e9b3b8de Input/output options input : /workspaces/training/hello-nf-core/core-hello/assets/greetings.csv @@ -797,10 +797,10 @@ This should run reasonably quickly. !! Only displaying parameters that differ from the pipeline defaults !! ------------------------------------------------------ executor > local (8) - [b3/f005fd] CORE_HELLO:HELLO:sayHello (3) [100%] 3 of 3 ✔ - [08/f923d0] CORE_HELLO:HELLO:convertToUpper (3) [100%] 3 of 3 ✔ - [34/3729a9] CORE_HELLO:HELLO:FIND_CONCATENATE (test) [100%] 1 of 1 ✔ - [24/df918a] CORE_HELLO:HELLO:cowpy [100%] 1 of 1 ✔ + [b3/f005fd] CORE_HELLO:HELLO:sayHello (3) | 3 of 3 ✔ + [08/f923d0] CORE_HELLO:HELLO:convertToUpper (3) | 3 of 3 ✔ + [34/3729a9] CORE_HELLO:HELLO:FIND_CONCATENATE (test) | 1 of 1 ✔ + [24/df918a] CORE_HELLO:HELLO:cowpy | 1 of 1 ✔ -[core/hello] Pipeline completed successfully- ``` diff --git a/docs/en/docs/hello_nf-core/04_make_module.md b/docs/en/docs/hello_nf-core/04_make_module.md index 6f80d916e9..aa4ae1192b 100644 --- a/docs/en/docs/hello_nf-core/04_make_module.md +++ b/docs/en/docs/hello_nf-core/04_make_module.md @@ -251,9 +251,9 @@ nextflow run . --outdir core-hello-results -profile test,docker --validate_param ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `./main.nf` [elegant_plateau] DSL2 - revision: b9e9b3b8de + Launching `./main.nf` [elegant_plateau] revision: b9e9b3b8de Input/output options input : /workspaces/training/hello-nf-core/core-hello/assets/greetings.csv @@ -399,9 +399,9 @@ nextflow run . --outdir core-hello-results -profile test,docker --validate_param ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `./main.nf` [modest_saha] DSL2 - revision: b9e9b3b8de + Launching `./main.nf` [modest_saha] revision: b9e9b3b8de Downloading plugin nf-schema@2.5.1 Input/output options @@ -429,10 +429,10 @@ nextflow run . --outdir core-hello-results -profile test,docker --validate_param !! Only displaying parameters that differ from the pipeline defaults !! ------------------------------------------------------ executor > local (8) - [a8/447993] CORE_HELLO:HELLO:sayHello (3) [100%] 3 of 3 ✔ - [00/1fc59c] CORE_HELLO:HELLO:convertToUpper (3) [100%] 3 of 3 ✔ - [57/ac800d] CORE_HELLO:HELLO:FIND_CONCATENATE (test) [100%] 1 of 1 ✔ - [b7/092f2b] CORE_HELLO:HELLO:COWPY [100%] 1 of 1 ✔ + [a8/447993] CORE_HELLO:HELLO:sayHello (3) | 3 of 3 ✔ + [00/1fc59c] CORE_HELLO:HELLO:convertToUpper (3) | 3 of 3 ✔ + [57/ac800d] CORE_HELLO:HELLO:FIND_CONCATENATE (test) | 1 of 1 ✔ + [b7/092f2b] CORE_HELLO:HELLO:COWPY | 1 of 1 ✔ -[core/hello] Pipeline completed successfully- ``` @@ -627,9 +627,9 @@ nextflow run . --outdir core-hello-results -profile test,docker --validate_param ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `./main.nf` [exotic_planck] DSL2 - revision: b9e9b3b8de + Launching `./main.nf` [exotic_planck] revision: b9e9b3b8de Input/output options input : /workspaces/training/hello-nf-core/core-hello/assets/greetings.csv @@ -656,10 +656,10 @@ nextflow run . --outdir core-hello-results -profile test,docker --validate_param !! Only displaying parameters that differ from the pipeline defaults !! ------------------------------------------------------ executor > local (8) - [13/9e3c0e] CORE_HELLO:HELLO:sayHello (3) [100%] 3 of 3 ✔ - [e2/5b0ee5] CORE_HELLO:HELLO:convertToUpper (3) [100%] 3 of 3 ✔ - [b6/4fb569] CORE_HELLO:HELLO:FIND_CONCATENATE (test) [100%] 1 of 1 ✔ - [38/eb29ea] CORE_HELLO:HELLO:COWPY [100%] 1 of 1 ✔ + [13/9e3c0e] CORE_HELLO:HELLO:sayHello (3) | 3 of 3 ✔ + [e2/5b0ee5] CORE_HELLO:HELLO:convertToUpper (3) | 3 of 3 ✔ + [b6/4fb569] CORE_HELLO:HELLO:FIND_CONCATENATE (test) | 1 of 1 ✔ + [38/eb29ea] CORE_HELLO:HELLO:COWPY | 1 of 1 ✔ -[core/hello] Pipeline completed successfully- ``` @@ -845,9 +845,9 @@ nextflow run . --outdir core-hello-results -profile test,docker --validate_param ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `./main.nf` [admiring_turing] DSL2 - revision: b9e9b3b8de + Launching `./main.nf` [admiring_turing] revision: b9e9b3b8de Input/output options input : /workspaces/training/hello-nf-core/core-hello/assets/greetings.csv @@ -874,10 +874,10 @@ nextflow run . --outdir core-hello-results -profile test,docker --validate_param !! Only displaying parameters that differ from the pipeline defaults !! ------------------------------------------------------ executor > local (8) - [b2/e08524] CORE_HELLO:HELLO:sayHello (3) [100%] 3 of 3 ✔ - [13/88939f] CORE_HELLO:HELLO:convertToUpper (3) [100%] 3 of 3 ✔ - [23/4554e1] CORE_HELLO:HELLO:FIND_CONCATENATE (test) [100%] 1 of 1 ✔ - [a3/c6cbe9] CORE_HELLO:HELLO:COWPY [100%] 1 of 1 ✔ + [b2/e08524] CORE_HELLO:HELLO:sayHello (3) | 3 of 3 ✔ + [13/88939f] CORE_HELLO:HELLO:convertToUpper (3) | 3 of 3 ✔ + [23/4554e1] CORE_HELLO:HELLO:FIND_CONCATENATE (test) | 1 of 1 ✔ + [a3/c6cbe9] CORE_HELLO:HELLO:COWPY | 1 of 1 ✔ -[core/hello] Pipeline completed successfully- ``` @@ -982,9 +982,9 @@ nextflow run . --outdir core-hello-results -profile test,docker --validate_param ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `./main.nf` [silly_caravaggio] DSL2 - revision: b9e9b3b8de + Launching `./main.nf` [silly_caravaggio] revision: b9e9b3b8de Input/output options input : /workspaces/training/hello-nf-core/core-hello/assets/greetings.csv @@ -1011,10 +1011,10 @@ nextflow run . --outdir core-hello-results -profile test,docker --validate_param !! Only displaying parameters that differ from the pipeline defaults !! ------------------------------------------------------ executor > local (8) - [db/39978e] CORE_HELLO:HELLO:sayHello (3) [100%] 3 of 3 ✔ - [b5/bf6a8d] CORE_HELLO:HELLO:convertToUpper (3) [100%] 3 of 3 ✔ - [b7/c61842] CORE_HELLO:HELLO:FIND_CONCATENATE (test) [100%] 1 of 1 ✔ - [46/5839d6] CORE_HELLO:HELLO:COWPY [100%] 1 of 1 ✔ + [db/39978e] CORE_HELLO:HELLO:sayHello (3) | 3 of 3 ✔ + [b5/bf6a8d] CORE_HELLO:HELLO:convertToUpper (3) | 3 of 3 ✔ + [b7/c61842] CORE_HELLO:HELLO:FIND_CONCATENATE (test) | 1 of 1 ✔ + [46/5839d6] CORE_HELLO:HELLO:COWPY | 1 of 1 ✔ -[core/hello] Pipeline completed successfully- ``` @@ -1166,17 +1166,17 @@ nextflow run . --outdir core-hello-results -profile test,docker --validate_param ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `./main.nf` [silly_fermat] DSL2 - revision: b9e9b3b8de + Launching `./main.nf` [silly_fermat] revision: b9e9b3b8de ... executor > local (8) - [8d/f3a091] CORE_HELLO:HELLO:sayHello (3) [100%] 3 of 3 ✔ - [2e/b5c742] CORE_HELLO:HELLO:convertToUpper (3) [100%] 3 of 3 ✔ - [6a/d9e183] CORE_HELLO:HELLO:FIND_CONCATENATE (test) [100%] 1 of 1 ✔ - [3c/f20b54] CORE_HELLO:HELLO:COWPY [100%] 1 of 1 ✔ + [8d/f3a091] CORE_HELLO:HELLO:sayHello (3) | 3 of 3 ✔ + [2e/b5c742] CORE_HELLO:HELLO:convertToUpper (3) | 3 of 3 ✔ + [6a/d9e183] CORE_HELLO:HELLO:FIND_CONCATENATE (test) | 1 of 1 ✔ + [3c/f20b54] CORE_HELLO:HELLO:COWPY | 1 of 1 ✔ -[core/hello] Pipeline completed successfully- ``` @@ -1580,9 +1580,9 @@ nextflow run . --outdir core-hello-results -profile test,docker --validate_param ??? success "Command output" ```console hl_lines="33" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `./main.nf` [prickly_neumann] DSL2 - revision: b9e9b3b8de + Launching `./main.nf` [prickly_neumann] revision: b9e9b3b8de Input/output options input : /workspaces/training/hello-nf-core/core-hello/assets/greetings.csv @@ -1609,10 +1609,10 @@ nextflow run . --outdir core-hello-results -profile test,docker --validate_param !! Only displaying parameters that differ from the pipeline defaults !! ------------------------------------------------------ executor > local (8) - [e9/008ede] CORE_HELLO:HELLO:sayHello (3) [100%] 3 of 3 ✔ - [f0/d70cfe] CORE_HELLO:HELLO:convertToUpper (3) [100%] 3 of 3 ✔ - [be/0ecc58] CORE_HELLO:HELLO:FIND_CONCATENATE (test) [100%] 1 of 1 ✔ - [11/8e082f] CORE_HELLO:HELLO:COWPY (test) [100%] 1 of 1 ✔ + [e9/008ede] CORE_HELLO:HELLO:sayHello (3) | 3 of 3 ✔ + [f0/d70cfe] CORE_HELLO:HELLO:convertToUpper (3) | 3 of 3 ✔ + [be/0ecc58] CORE_HELLO:HELLO:FIND_CONCATENATE (test) | 1 of 1 ✔ + [11/8e082f] CORE_HELLO:HELLO:COWPY (test) | 1 of 1 ✔ -[core/hello] Pipeline completed successfully- ``` diff --git a/docs/en/docs/hello_nf-core/05_input_validation.md b/docs/en/docs/hello_nf-core/05_input_validation.md index b991fa2221..97ad5bef2b 100644 --- a/docs/en/docs/hello_nf-core/05_input_validation.md +++ b/docs/en/docs/hello_nf-core/05_input_validation.md @@ -367,9 +367,9 @@ nextflow run . --input assets/greetings.csv --outdir results --batch my-batch -p ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `./main.nf` [peaceful_wozniak] DSL2 - revision: b9e9b3b8de + Launching `./main.nf` [peaceful_wozniak] revision: b9e9b3b8de executor > local (8) [de/a1b2c3] CORE_HELLO:HELLO:sayHello (3) | 3 of 3 ✔ @@ -732,9 +732,9 @@ nextflow run . --input assets/invalid_greetings.csv --outdir test-results -profi ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `./main.nf` [trusting_ochoa] DSL2 - revision: b9e9b3b8de + Launching `./main.nf` [trusting_ochoa] revision: b9e9b3b8de Input/output options input : assets/invalid_greetings.csv From a489d62c66edfaeb59ef4a2da7bd4509eb863d1b Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 13:38:39 +0100 Subject: [PATCH 13/42] docs(hello_nf-core): clarify v1 parser requirement overrides 26.04 v2 default [skip ci] --- docs/en/docs/hello_nf-core/00_orientation.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/hello_nf-core/00_orientation.md b/docs/en/docs/hello_nf-core/00_orientation.md index 8710e7f9b1..836c42dc48 100644 --- a/docs/en/docs/hello_nf-core/00_orientation.md +++ b/docs/en/docs/hello_nf-core/00_orientation.md @@ -20,7 +20,8 @@ If you are working through this course by yourself, please acquaint yourself wit ### Version requirements -This training works with **Nextflow 25.10.2** or later **with the v2 syntax parser DISABLED**. +This training works with **Nextflow 25.10.2** or later and **requires the v1 syntax parser**, because the nf-core conventions used in this course are not yet compatible with the v2 parser. +From Nextflow 26.04 the v2 parser is the default, so you must explicitly select v1 as shown below. #### If you are using our training environment: @@ -30,6 +31,8 @@ You MUST run the following command before going any further: export NXF_SYNTAX_PARSER=v1 ``` +On Nextflow 26.04 and later this is essential: it overrides the v2 parser that those versions enable by default (our training environment sets `NXF_SYNTAX_PARSER=v2` for the other courses). + #### If you are using a local or custom environment: Please make sure you are using the correct settings as documented [here](../info/nxf_versions.md). From ffd9b23698454b9f0143438b4ec279bdeedd53a1 Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 13:39:47 +0100 Subject: [PATCH 14/42] docs(side_quests): refresh metadata for Nextflow 26.04 [skip ci] --- docs/en/docs/side_quests/metadata/index.md | 259 +++++++++++++++------ 1 file changed, 185 insertions(+), 74 deletions(-) diff --git a/docs/en/docs/side_quests/metadata/index.md b/docs/en/docs/side_quests/metadata/index.md index 7c8bb794be..d39da144e7 100644 --- a/docs/en/docs/side_quests/metadata/index.md +++ b/docs/en/docs/side_quests/metadata/index.md @@ -210,9 +210,9 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [exotic_albattani] DSL2 - revision: c0d03cec83 + Launching `main.nf` [exotic_albattani] revision: c0d03cec83 [id:sampleA, character:squirrel, recording:/workspaces/training/side-quests/metadata/data/bonjour.txt] [id:sampleB, character:tux, recording:/workspaces/training/side-quests/metadata/data/guten_tag.txt] @@ -221,6 +221,12 @@ nextflow run main.nf [id:sampleE, character:stegosaurus, recording:/workspaces/training/side-quests/metadata/data/hola.txt] [id:sampleF, character:moose, recording:/workspaces/training/side-quests/metadata/data/salut.txt] [id:sampleG, character:turtle, recording:/workspaces/training/side-quests/metadata/data/ciao.txt] + + Outputs: + + /workspaces/training/side-quests/metadata/results + + cowpy_art: ``` As you can see, the operator has constructed a map of key-value pairs for each row in the CSV file, with the column headers as keys for the corresponding values. @@ -263,9 +269,9 @@ For example, we could access the file ID with `id` or the txt file path with `re And here's what you can expect to see in the output: ```console title="Output" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `map_demo.nf` [cheesy_plateau] DSL2 - revision: fae5b8496e + Launching `examples/map_demo.nf` [cheesy_plateau] revision: fae5b8496e map: [id:sampleA, character:squirrel] id: sampleA @@ -312,9 +318,9 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [exotic_albattani] DSL2 - revision: c0d03cec83 + Launching `main.nf` [exotic_albattani] revision: c0d03cec83 squirrel tux @@ -323,6 +329,12 @@ nextflow run main.nf stegosaurus moose turtle + + Outputs: + + /workspaces/training/side-quests/metadata/results + + cowpy_art: ``` This shows that we're able to access the values from the `character` column for each row. @@ -481,12 +493,25 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.2 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [clever_dijkstra] DSL2 - revision: a1b2c3d4e5 + Launching `main.nf` [clever_dijkstra] revision: a1b2c3d4e5 executor > local (7) - [3a/f1c290] COWPY (7) [100%] 7 of 7 ✔ + [3a/f1c290] COWPY (7) | 7 of 7 ✔ + + Outputs: + + /workspaces/training/side-quests/metadata/results + + cowpy_art: + - cowpy-bonjour.txt + - cowpy-guten_tag.txt + - cowpy-salut.txt + - cowpy-hola.txt + - cowpy-hello.txt + - cowpy-hallo.txt + - cowpy-ciao.txt ``` As you can see, `COWPY` ran on each file using the correct character for each one. @@ -652,12 +677,25 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.2 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [pedantic_lovelace] DSL2 - revision: b2c3d4e5f6 + Launching `main.nf` [pedantic_lovelace] revision: b2c3d4e5f6 executor > local (7) - [5e/2a1b34] COWPY (7) [100%] 7 of 7 ✔ + [5e/2a1b34] COWPY (7) | 7 of 7 ✔ + + Outputs: + + /workspaces/training/side-quests/metadata/results + + cowpy_art: + - cowpy-bonjour.txt + - cowpy-guten_tag.txt + - cowpy-salut.txt + - cowpy-hola.txt + - cowpy-hello.txt + - cowpy-hallo.txt + - cowpy-ciao.txt ``` The output is the same seven `cowpy-*.txt` files as before, now produced with a simpler call to `COWPY`. @@ -768,9 +806,9 @@ nextflow run main.nf ??? success "Command output" ```console title="View meta map" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [lethal_booth] DSL2 - revision: 0d8f844c07 + Launching `main.nf` [lethal_booth] revision: 0d8f844c07 [[id:sampleA, character:squirrel], /workspaces/training/side-quests/metadata/data/bonjour.txt] [[id:sampleB, character:tux], /workspaces/training/side-quests/metadata/data/guten_tag.txt] @@ -779,6 +817,12 @@ nextflow run main.nf [[id:sampleE, character:stegosaurus], /workspaces/training/side-quests/metadata/data/hola.txt] [[id:sampleF, character:moose], /workspaces/training/side-quests/metadata/data/salut.txt] [[id:sampleG, character:turtle], /workspaces/training/side-quests/metadata/data/ciao.txt] + + Outputs: + + /workspaces/training/side-quests/metadata/results + + cowpy_art: ``` Each element in the channel is now a two-element tuple: the meta map first, the file second. @@ -889,12 +933,25 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.2 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [wise_sammet] DSL2 - revision: 99797b1e92 + Launching `main.nf` [wise_sammet] revision: 99797b1e92 executor > local (7) - [5d/dffd4e] COWPY (7) [100%] 7 of 7 ✔ + [5d/dffd4e] COWPY (7) | 7 of 7 ✔ + + Outputs: + + /workspaces/training/side-quests/metadata/results + + cowpy_art: + - cowpy-bonjour.txt + - cowpy-guten_tag.txt + - cowpy-salut.txt + - cowpy-hola.txt + - cowpy-hello.txt + - cowpy-hallo.txt + - cowpy-ciao.txt ``` The results directory now contains the ASCII art files. @@ -1042,20 +1099,33 @@ nextflow run main.nf -resume ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [voluminous_mcnulty] DSL2 - revision: f9bcfebabb + Launching `main.nf` [voluminous_mcnulty] revision: f9bcfebabb - executor > local (14) - [5d/dffd4e] COWPY (7) [100%] 7 of 7, cached: 7 ✔ - [4e/f722fe] IDENTIFY_LANGUAGE (7) [100%] 7 of 7 ✔ - [[id:sampleA, character:squirrel], /workspaces/training/side-quests/metadata/work/eb/f7148ebdd898fbe1136bec6a714acb/bonjour.txt, fr] - [[id:sampleB, character:tux], /workspaces/training/side-quests/metadata/work/16/71d72410952c22cd0086d9bca03680/guten_tag.txt, de] - [[id:sampleD, character:turkey], /workspaces/training/side-quests/metadata/work/c4/b7562adddc1cc0b7d414ec45d436eb/hello.txt, en] - [[id:sampleC, character:sheep], /workspaces/training/side-quests/metadata/work/ea/04f5d979429e4455e14b9242fb3b45/hallo.txt, de] - [[id:sampleF, character:moose], /workspaces/training/side-quests/metadata/work/5a/6c2b84bf8fadb98e28e216426be079/salut.txt, fr] - [[id:sampleE, character:stegosaurus], /workspaces/training/side-quests/metadata/work/af/ee7c69bcab891c40d0529305f6b9e7/hola.txt, es] - [[id:sampleG, character:turtle], /workspaces/training/side-quests/metadata/work/4e/f722fe47271ba7ebcd69afa42964ca/ciao.txt, it] + executor > local (7) + [c9/34bfec] IDENTIFY_LANGUAGE (1) | 7 of 7 ✔ + [58/d865ee] COWPY (7) | 7 of 7, cached: 7 ✔ + [[id:sampleG, character:turtle], /workspaces/training/side-quests/metadata/work/f6/8544c23128c0ed7c4f11dbc729b167/ciao.txt, it] + [[id:sampleB, character:tux], /workspaces/training/side-quests/metadata/work/91/a2a307e970fa3950ceeeee6aa3b34c/guten_tag.txt, de] + [[id:sampleD, character:turkey], /workspaces/training/side-quests/metadata/work/5e/ebac0d3e7a45a5e914d0bca827fc02/hello.txt, en] + [[id:sampleF, character:moose], /workspaces/training/side-quests/metadata/work/08/7199b7ab1ca733267d76b8168e5f38/salut.txt, fr] + [[id:sampleE, character:stegosaurus], /workspaces/training/side-quests/metadata/work/7d/890c6fa79c485b4a600eaa89af2140/hola.txt, es] + [[id:sampleC, character:sheep], /workspaces/training/side-quests/metadata/work/d9/b360d0cd38e53c710ec41ac3b74bc3/hallo.txt, de] + [[id:sampleA, character:squirrel], /workspaces/training/side-quests/metadata/work/c9/34bfec04abaf808c2ef6c5cb8c8273/bonjour.txt, fr] + + Outputs: + + /workspaces/training/side-quests/metadata/results + + cowpy_art: + - cowpy-salut.txt + - cowpy-hallo.txt + - cowpy-bonjour.txt + - cowpy-hello.txt + - cowpy-hola.txt + - cowpy-guten_tag.txt + - cowpy-ciao.txt ``` We now have a language prediction for each file in the dataset. @@ -1204,19 +1274,32 @@ nextflow run main.nf -resume ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [cheeky_fermat] DSL2 - revision: d096281ee4 + Launching `main.nf` [cheeky_fermat] revision: d096281ee4 - [5d/dffd4e] COWPY (7) [100%] 7 of 7, cached: 7 ✔ - [4e/f722fe] IDENTIFY_LANGUAGE (7) [100%] 7 of 7, cached: 7 ✔ - [[id:sampleA, character:squirrel, lang:fr], /workspaces/training/side-quests/metadata/work/eb/f7148ebdd898fbe1136bec6a714acb/bonjour.txt] - [[id:sampleB, character:tux, lang:de], /workspaces/training/side-quests/metadata/work/16/71d72410952c22cd0086d9bca03680/guten_tag.txt] - [[id:sampleC, character:sheep, lang:de], /workspaces/training/side-quests/metadata/work/ea/04f5d979429e4455e14b9242fb3b45/hallo.txt] - [[id:sampleD, character:turkey, lang:en], /workspaces/training/side-quests/metadata/work/c4/b7562adddc1cc0b7d414ec45d436eb/hello.txt] - [[id:sampleF, character:moose, lang:fr], /workspaces/training/side-quests/metadata/work/5a/6c2b84bf8fadb98e28e216426be079/salut.txt] - [[id:sampleE, character:stegosaurus, lang:es], /workspaces/training/side-quests/metadata/work/af/ee7c69bcab891c40d0529305f6b9e7/hola.txt] - [[id:sampleG, character:turtle, lang:it], /workspaces/training/side-quests/metadata/work/4e/f722fe47271ba7ebcd69afa42964ca/ciao.txt] + [d9/b360d0] IDENTIFY_LANGUAGE (3) | 7 of 7, cached: 7 ✔ + [94/224450] COWPY (3) | 7 of 7, cached: 7 ✔ + [[id:sampleF, character:moose, lang:fr], /workspaces/training/side-quests/metadata/work/08/7199b7ab1ca733267d76b8168e5f38/salut.txt] + [[id:sampleC, character:sheep, lang:de], /workspaces/training/side-quests/metadata/work/d9/b360d0cd38e53c710ec41ac3b74bc3/hallo.txt] + [[id:sampleD, character:turkey, lang:en], /workspaces/training/side-quests/metadata/work/5e/ebac0d3e7a45a5e914d0bca827fc02/hello.txt] + [[id:sampleE, character:stegosaurus, lang:es], /workspaces/training/side-quests/metadata/work/7d/890c6fa79c485b4a600eaa89af2140/hola.txt] + [[id:sampleG, character:turtle, lang:it], /workspaces/training/side-quests/metadata/work/f6/8544c23128c0ed7c4f11dbc729b167/ciao.txt] + [[id:sampleA, character:squirrel, lang:fr], /workspaces/training/side-quests/metadata/work/c9/34bfec04abaf808c2ef6c5cb8c8273/bonjour.txt] + [[id:sampleB, character:tux, lang:de], /workspaces/training/side-quests/metadata/work/91/a2a307e970fa3950ceeeee6aa3b34c/guten_tag.txt] + + Outputs: + + /workspaces/training/side-quests/metadata/results + + cowpy_art: + - cowpy-guten_tag.txt + - cowpy-hallo.txt + - cowpy-bonjour.txt + - cowpy-hello.txt + - cowpy-hola.txt + - cowpy-salut.txt + - cowpy-ciao.txt ``` Yep, that checks out! @@ -1320,19 +1403,32 @@ nextflow run main.nf -resume ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 + + Launching `main.nf` [wise_almeida] revision: 46778c3cd0 - Launching `main.nf` [wise_almeida] DSL2 - revision: 46778c3cd0 + [c9/34bfec] IDENTIFY_LANGUAGE (1) | 7 of 7, cached: 7 ✔ + [e9/269aa0] COWPY (6) | 7 of 7, cached: 7 ✔ + [[id:sampleC, character:sheep, lang:de, lang_group:germanic], /workspaces/training/side-quests/metadata/work/d9/b360d0cd38e53c710ec41ac3b74bc3/hallo.txt] + [[id:sampleA, character:squirrel, lang:fr, lang_group:romance], /workspaces/training/side-quests/metadata/work/c9/34bfec04abaf808c2ef6c5cb8c8273/bonjour.txt] + [[id:sampleE, character:stegosaurus, lang:es, lang_group:romance], /workspaces/training/side-quests/metadata/work/7d/890c6fa79c485b4a600eaa89af2140/hola.txt] + [[id:sampleD, character:turkey, lang:en, lang_group:germanic], /workspaces/training/side-quests/metadata/work/5e/ebac0d3e7a45a5e914d0bca827fc02/hello.txt] + [[id:sampleB, character:tux, lang:de, lang_group:germanic], /workspaces/training/side-quests/metadata/work/91/a2a307e970fa3950ceeeee6aa3b34c/guten_tag.txt] + [[id:sampleG, character:turtle, lang:it, lang_group:romance], /workspaces/training/side-quests/metadata/work/f6/8544c23128c0ed7c4f11dbc729b167/ciao.txt] + [[id:sampleF, character:moose, lang:fr, lang_group:romance], /workspaces/training/side-quests/metadata/work/08/7199b7ab1ca733267d76b8168e5f38/salut.txt] - [5d/dffd4e] COWPY (7) [100%] 7 of 7, cached: 7 ✔ - [da/652cc6] IDENTIFY_LANGUAGE (7) [100%] 7 of 7, cached: 7 ✔ - [[id:sampleA, character:squirrel, lang:fr, lang_group:romance], /workspaces/training/side-quests/metadata/data/bonjour.txt] - [[id:sampleB, character:tux, lang:de, lang_group:germanic], /workspaces/training/side-quests/metadata/data/guten_tag.txt] - [[id:sampleC, character:sheep, lang:de, lang_group:germanic], /workspaces/training/side-quests/metadata/data/hallo.txt] - [[id:sampleD, character:turkey, lang:en, lang_group:germanic], /workspaces/training/side-quests/metadata/data/hello.txt] - [[id:sampleE, character:stegosaurus, lang:es, lang_group:romance], /workspaces/training/side-quests/metadata/data/hola.txt] - [[id:sampleF, character:moose, lang:fr, lang_group:romance], /workspaces/training/side-quests/metadata/data/salut.txt] - [[id:sampleG, character:turtle, lang:it, lang_group:romance], /workspaces/training/side-quests/metadata/data/ciao.txt] + Outputs: + + /workspaces/training/side-quests/metadata/results + + cowpy_art: + - cowpy-ciao.txt + - cowpy-salut.txt + - cowpy-guten_tag.txt + - cowpy-hallo.txt + - cowpy-bonjour.txt + - cowpy-hola.txt + - cowpy-hello.txt ``` The meta map now carries four fields: `id`, `character`, `lang`, and `lang_group`. @@ -1443,13 +1539,26 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [suspicious_crick] DSL2 - revision: 25541014c5 + Launching `main.nf` [suspicious_crick] revision: 25541014c5 executor > local (14) - [5d/dffd4e] IDENTIFY_LANGUAGE (7) [100%] 7 of 7 ✔ - [e7/317c18] COWPY (7) [100%] 7 of 7 ✔ + [99/64c59d] IDENTIFY_LANGUAGE (6) | 7 of 7 ✔ + [3c/0f1922] COWPY (7) | 7 of 7 ✔ + + Outputs: + + /workspaces/training/side-quests/metadata/results + + cowpy_art: + - [{id: sampleB, character: tux, lang: de, lang_group: germanic}, germanic/de-guten_tag.txt] + - [{id: sampleG, character: turtle, lang: it, lang_group: romance}, romance/it-ciao.txt] + - [{id: sampleC, character: sheep, lang: de, lang_group: germanic}, germanic/de-hallo.txt] + - [{id: sampleE, character: stegosaurus, lang: es, lang_group: romance}, romance/es-hola.txt] + - [{id: sampleA, character: squirrel, lang: fr, lang_group: romance}, romance/fr-bonjour.txt] + - [{id: sampleD, character: turkey, lang: en, lang_group: germanic}, germanic/en-hello.txt] + - [{id: sampleF, character: moose, lang: fr, lang_group: romance}, romance/fr-salut.txt] ``` The results directory is now organized by language family, with each file named after its detected language: @@ -1507,18 +1616,19 @@ When Nextflow substitutes `#!groovy ${meta.character}` into the command, the `CO ??? failure "Command output" - ```console hl_lines="8 11 16 28" - N E X T F L O W ~ version 25.10.4 + ```console hl_lines="7 12 17 29" + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [marvelous_hirsch] DSL2 - revision: 0dfeee3cc1 + Launching `main.nf` [marvelous_hirsch] revision: 0dfeee3cc1 - executor > local (9) - [c1/c5dd4f] process > IDENTIFY_LANGUAGE (7) [ 85%] 6 of 7 - [d3/b7c415] process > COWPY (2) [ 0%] 0 of 6 - ERROR ~ Error executing process > 'COWPY (1)' + executor > local (14) + [c1/c5dd4f] IDENTIFY_LANGUAGE (1) | 7 of 7 ✔ + [d3/b7c415] COWPY (3) | 5 of 7 + WARN: Killing running tasks (1) + ERROR ~ Error executing process > 'COWPY (7)' Caused by: - Process `COWPY (1)` terminated with an error exit status (2) + Process `COWPY (7)` terminated with an error exit status (2) Command executed: @@ -1538,7 +1648,7 @@ When Nextflow substitutes `#!groovy ${meta.character}` into the command, the `CO cowpy: error: argument -c/--cowacter: expected one argument Work dir: - /workspaces/training/side-quests/metadata/work/ca/9d49796612a54dec5ed466063c809b + /workspaces/training/side-quests/metadata/work/cc/dfe60ff2e14f0dd88488939eca57b8 Container: community.wave.seqera.io/library/cowpy:1.1.5--3db457ae1977a273 @@ -1567,23 +1677,24 @@ When the process script evaluates `#!groovy ${meta.character}`, the missing key ??? failure "Command output" - ```console hl_lines="8 11 16" - N E X T F L O W ~ version 25.10.4 + ```console hl_lines="7 12 17" + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [jovial_bohr] DSL2 - revision: eaaf375827 + Launching `main.nf` [jovial_bohr] revision: eaaf375827 - executor > local (9) - [0d/ada9db] process > IDENTIFY_LANGUAGE (5) [ 85%] 6 of 7 - [06/28065f] process > COWPY (2) [ 0%] 0 of 6 - ERROR ~ Error executing process > 'COWPY (2)' + executor > local (14) + [61/91663a] IDENTIFY_LANGUAGE (1) | 7 of 7 ✔ + [0e/99bfb0] COWPY (7) | 0 of 7 + WARN: Killing running tasks (5) + ERROR ~ Error executing process > 'COWPY (3)' Caused by: - Process `COWPY (2)` terminated with an error exit status (1) + Process `COWPY (3)` terminated with an error exit status (1) Command executed: - cat guten_tag.txt | cowpy -c null > de-guten_tag.txt + cat hola.txt | cowpy -c null > es-hola.txt Command exit status: 1 @@ -1608,7 +1719,7 @@ When the process script evaluates `#!groovy ${meta.character}`, the missing key TypeError: 'str' object is not callable Work dir: - /workspaces/training/side-quests/metadata/work/06/28065f7d9fd7d22bba084aa941b6d6 + /workspaces/training/side-quests/metadata/work/52/80c08666f6732690bce00f04993489 Container: community.wave.seqera.io/library/cowpy:1.1.5--3db457ae1977a273 From 9b175501fa058e6236648ae2bb66bef972a546e1 Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 13:44:33 +0100 Subject: [PATCH 15/42] docs(side_quests): refresh debugging + dev_environment for Nextflow 26.04 [skip ci] --- docs/en/docs/side_quests/debugging/index.md | 202 +++++++++--------- .../docs/side_quests/dev_environment/index.md | 2 +- 2 files changed, 98 insertions(+), 106 deletions(-) diff --git a/docs/en/docs/side_quests/debugging/index.md b/docs/en/docs/side_quests/debugging/index.md index 6c23af0c25..fb8b31b5e0 100644 --- a/docs/en/docs/side_quests/debugging/index.md +++ b/docs/en/docs/side_quests/debugging/index.md @@ -130,9 +130,9 @@ nextflow run bad_syntax.nf ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_syntax.nf` [stupefied_bhabha] DSL2 - revision: ca6327fad2 + Launching `bad_syntax.nf` [wise_wing] revision: 550b9a8873 Error bad_syntax.nf:24:1: Unexpected input: '' @@ -258,12 +258,12 @@ nextflow run bad_syntax.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_syntax.nf` [insane_faggin] DSL2 - revision: 961938ee2b + Launching `bad_syntax.nf` [nostalgic_lattes] revision: 961938ee2b executor > local (3) - [48/cd7f54] PROCESS_FILES (1) | 3 of 3 ✔ + [de/be1112] PROCESS_FILES (3) | 3 of 3 ✔ ``` ### 1.2. Using incorrect process keywords or directives @@ -279,9 +279,9 @@ nextflow run invalid_process.nf ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `invalid_process.nf` [nasty_jepsen] DSL2 - revision: da9758d614 + Launching `invalid_process.nf` [sharp_celsius] revision: f42559404a Error invalid_process.nf:3:1: Invalid process definition -- check for missing or out-of-order section labels │ 3 | process PROCESS_FILES { @@ -401,12 +401,12 @@ nextflow run invalid_process.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `invalid_process.nf` [silly_fermi] DSL2 - revision: 961938ee2b + Launching `invalid_process.nf` [serene_hilbert] revision: 961938ee2b executor > local (3) - [b7/76cd9d] PROCESS_FILES (2) | 3 of 3 ✔ + [37/9a7232] PROCESS_FILES (2) | 3 of 3 ✔ ``` ### 1.3. Using bad variable names @@ -422,9 +422,9 @@ nextflow run no_such_var.nf ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `no_such_var.nf` [gloomy_meninsky] DSL2 - revision: 0c4d3bc28c + Launching `no_such_var.nf` [scruffy_gautier] revision: 0c4d3bc28c Error no_such_var.nf:17:39: `undefined_var` is not defined │ 17 | echo "Using undefined variable: ${undefined_var}" >> ${output_pref @@ -542,12 +542,12 @@ nextflow run no_such_var.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `no_such_var.nf` [suspicious_venter] DSL2 - revision: 6ba490f7c5 + Launching `no_such_var.nf` [extravagant_brahmagupta] revision: 48ce21e688 executor > local (3) - [21/237300] PROCESS_FILES (2) | 3 of 3 ✔ + [57/5d63d0] PROCESS_FILES (3) | 3 of 3 ✔ ``` ### 1.4. Bad use of Bash variables @@ -563,9 +563,9 @@ nextflow run bad_bash_var.nf ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_bash_var.nf` [infallible_mandelbrot] DSL2 - revision: 0853c11080 + Launching `bad_bash_var.nf` [stupefied_dubinsky] revision: 0853c11080 Error bad_bash_var.nf:13:42: `prefix` is not defined │ 13 | echo "Processing ${sample_name}" > ${prefix}.txt @@ -662,12 +662,12 @@ nextflow run bad_bash_var.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_bash_var.nf` [naughty_franklin] DSL2 - revision: 58c1c83709 + Launching `bad_bash_var.nf` [gloomy_leakey] revision: 9d43ef6ca8 executor > local (3) - [4e/560285] PROCESS_FILES (2) | 3 of 3 ✔ + [fe/7bf0d2] PROCESS_FILES (2) | 3 of 3 ✔ ``` !!! tip "Groovy vs Bash Variables" @@ -698,11 +698,11 @@ nextflow run badpractice_syntax.nf ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `badpractice_syntax.nf` [intergalactic_colden] DSL2 - revision: 5e4b291bde + Launching `badpractice_syntax.nf` [golden_monod] revision: 5e4b291bde - Error badpractice_syntax.nf:3:1: Statements cannot be mixed with script declarations -- move statements into a process or workflow + Error badpractice_syntax.nf:3:1: Statements cannot be mixed with script declarations -- move statements into a process, workflow, or function │ 3 | input_ch = channel.of('sample1', 'sample2', 'sample3') ╰ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -820,12 +820,12 @@ nextflow run badpractice_syntax.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `badpractice_syntax.nf` [naughty_ochoa] DSL2 - revision: 5e4b291bde + Launching `badpractice_syntax.nf` [lonely_spence] revision: 48ce21e688 executor > local (3) - [6a/84a608] PROCESS_FILES (2) | 3 of 3 ✔ + [c3/8f1edb] PROCESS_FILES (1) | 3 of 3 ✔ ``` Keep your input channels defined within the workflow block, and in general follow any other recommendations the extension makes. @@ -865,9 +865,9 @@ nextflow run bad_number_inputs.nf ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_number_inputs.nf` [happy_swartz] DSL2 - revision: d83e58dcd3 + Launching `bad_number_inputs.nf` [pedantic_lamarck] revision: d83e58dcd3 Error bad_number_inputs.nf:23:5: Incorrect number of call arguments, expected 1 but received 2 │ 23 | PROCESS_FILES(samples_ch, files_ch) @@ -984,12 +984,12 @@ nextflow run bad_number_inputs.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_number_inputs.nf` [big_euler] DSL2 - revision: e302bd87be + Launching `bad_number_inputs.nf` [desperate_brown] revision: 69b260a1ca executor > local (3) - [48/497f7b] PROCESS_FILES (3) | 3 of 3 ✔ + [ed/8af08b] PROCESS_FILES (2) | 3 of 3 ✔ ``` More commonly than this example, you might add additional inputs to a process and forget to update the workflow call accordingly, which can lead to this type of error. Fortunately, this is one of the easier-to-understand and fix errors, as the error message is quite clear about the mismatch. @@ -1007,12 +1007,12 @@ nextflow run exhausted.nf ??? success "Command output" ```console title="Exhausted channel output" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 -Launching `exhausted.nf` [extravagant_gauss] DSL2 - revision: 08cff7ba2a +Launching `exhausted.nf` [sleepy_swirles] revision: 31a6ae1494 executor > local (1) -[bd/f61fff] PROCESS_FILES (1) [100%] 1 of 1 ✔ +[87/99c202] PROCESS_FILES (1) | 1 of 1 ✔ ``` This workflow completes without error, but it only processes a single sample! @@ -1131,9 +1131,9 @@ nextflow run exhausted.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `exhausted.nf` [maniac_leavitt] DSL2 - revision: f372a56a7d + Launching `exhausted.nf` [maniac_leavitt] revision: f372a56a7d executor > local (3) [80/0779e9] PROCESS_FILES (3) | 3 of 3 ✔ @@ -1154,20 +1154,21 @@ nextflow run bad_channel_shape.nf ??? failure "Command output" ```console - Launching `bad_channel_shape.nf` [hopeful_pare] DSL2 - revision: ffd66071a1 + N E X T F L O W ~ version 26.04.4 + + Launching `bad_channel_shape.nf` [elegant_hilbert] revision: 3046f86036 executor > local (3) - executor > local (3) - [3f/c2dcb3] PROCESS_FILES (3) [ 0%] 0 of 3 ✘ - ERROR ~ Error executing process > 'PROCESS_FILES (1)' + [ee/2e5e14] PROCESS_FILES (3) | 0 of 3 ✘ + ERROR ~ Error executing process > 'PROCESS_FILES (2)' Caused by: - Missing output file(s) `[sample1, file1.txt]_output.txt` expected by process `PROCESS_FILES (1)` + Missing output file(s) `[sample2, file2.txt]_output.txt` expected by process `PROCESS_FILES (2)` Command executed: - echo "Processing [sample1, file1.txt]" > [sample1, file1.txt]_output.txt + echo "Processing [sample2, file2.txt]" > [sample2, file2.txt]_output.txt Command exit status: 0 @@ -1176,11 +1177,11 @@ nextflow run bad_channel_shape.nf (empty) Work dir: - /workspaces/training/side-quests/debugging/work/d6/1fb69d1d93300bbc9d42f1875b981e + /workspaces/training/side-quests/debugging/work/e4/b992709ea21ddd433c3d1aa0d8e244 - Tip: when you have fixed the problem you can continue the execution adding the option `-resume` to the run command line + Tip: you can replicate the issue by changing to the process work dir and entering the command `bash .command.run` - -- Check '.nextflow.log' file for details + -- Check '.nextflow.log' file for details ``` #### Check the code @@ -1326,12 +1327,12 @@ nextflow run bad_channel_shape.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_channel_shape.nf` [clever_thompson] DSL2 - revision: 8cbcae3746 + Launching `bad_channel_shape.nf` [lethal_lagrange] revision: 2f265b77c4 executor > local (3) - [bb/80a958] PROCESS_FILES (2) | 3 of 3 ✔ + [21/baeae1] PROCESS_FILES (3) | 3 of 3 ✔ ``` ### 2.4. Channel Debugging Techniques @@ -1351,12 +1352,12 @@ nextflow run bad_channel_shape_viewed.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_channel_shape_viewed.nf` [maniac_poisson] DSL2 - revision: b4f24dc9da + Launching `bad_channel_shape_viewed.nf` [silly_bhaskara] revision: 03e79cdbad executor > local (3) - [c0/db76b3] PROCESS_FILES (3) [100%] 3 of 3 ✔ + [41/55f2b4] PROCESS_FILES (2) | 3 of 3 ✔ Channel content: [sample1, file1.txt] Channel content: [sample2, file2.txt] Channel content: [sample3, file3.txt] @@ -1416,12 +1417,12 @@ nextflow run bad_channel_shape_viewed.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_channel_shape_viewed.nf` [marvelous_koch] DSL2 - revision: 03e79cdbad + Launching `bad_channel_shape_viewed.nf` [silly_bhaskara] revision: 03e79cdbad executor > local (3) - [ff/d67cec] PROCESS_FILES (2) | 3 of 3 ✔ + [41/55f2b4] PROCESS_FILES (2) | 3 of 3 ✔ Channel content: [sample1, file1.txt] Channel content: [sample2, file2.txt] Channel content: [sample3, file3.txt] @@ -1457,13 +1458,12 @@ nextflow run missing_output.nf ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `missing_output.nf` [zen_stone] DSL2 - revision: 37ff61f926 + Launching `missing_output.nf` [zen_stone] revision: 37ff61f926 executor > local (3) - executor > local (3) - [fd/2642e9] process > PROCESS_FILES (2) [ 66%] 2 of 3, failed: 2 + [8d/ed23f7] PROCESS_FILES (3) | 0 of 3 ✘ ERROR ~ Error executing process > 'PROCESS_FILES (3)' Caused by: @@ -1481,11 +1481,11 @@ nextflow run missing_output.nf (empty) Work dir: - /workspaces/training/side-quests/debugging/work/02/9604d49fb8200a74d737c72a6c98ed + /workspaces/training/side-quests/debugging/work/0d/cdf010999df7e0c24c59fdac5c4cfa0d - Tip: when you have fixed the problem you can continue the execution adding the option `-resume` to the run command line + Tip: view the complete command output by changing to the process work dir and entering the command `cat .command.out` - -- Check '.nextflow.log' file for details + -- Check '.nextflow.log' file for details ``` #### Check the code @@ -1565,12 +1565,12 @@ nextflow run missing_output.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `missing_output.nf` [elated_hamilton] DSL2 - revision: 961938ee2b + Launching `missing_output.nf` [angry_carlsson] revision: 961938ee2b executor > local (3) - [16/1c437c] PROCESS_FILES (3) | 3 of 3 ✔ + [df/b63629] PROCESS_FILES (1) | 3 of 3 ✔ ``` ### 3.2. Missing software @@ -1652,12 +1652,12 @@ nextflow run missing_software.nf -profile docker ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `missing_software.nf` [awesome_stonebraker] DSL2 - revision: 0296d12839 + Launching `missing_software.nf` [disturbed_rubens] revision: 0296d12839 executor > local (3) - [38/ab20d1] PROCESS_FILES (1) | 3 of 3 ✔ + [d3/ed1784] PROCESS_FILES (3) | 3 of 3 ✔ ``` !!! note @@ -1679,36 +1679,22 @@ nextflow run bad_resources.nf -profile docker ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_resources.nf` [disturbed_elion] DSL2 - revision: 27d2066e86 + Launching `bad_resources.nf` [grave_lavoisier] revision: e6e544e786 executor > local (3) - [c0/ded8e1] PROCESS_FILES (3) | 0 of 3 ✘ + [52/204a69] PROCESS_FILES (3) | 0 of 3 ERROR ~ Error executing process > 'PROCESS_FILES (2)' Caused by: - Process exceeded running time limit (1ms) - - Command executed: + process hasn't exited - cowpy sample2 > sample2_output.txt - Command exit status: - - - - Command output: - (empty) - - Work dir: - /workspaces/training/side-quests/debugging/work/53/f0a4cc56d6b3dc2a6754ff326f1349 - - Container: - community.wave.seqera.io/library/cowpy:1.1.5--3db457ae1977a273 - - Tip: you can replicate the issue by changing to the process work dir and entering the command `bash .command.run` -- Check '.nextflow.log' file for details + + WARN: Killing running tasks (2) ``` #### Check the code @@ -1736,6 +1722,8 @@ process PROCESS_FILES { We know the process will take longer than a second (we've added a sleep in there to make sure), but the process is set to time out after 1 millisecond. Someone has been a little unrealistic with their configuration! +When the `local` executor hits the time limit it interrupts the still-running task, which Nextflow reports as `process hasn't exited` rather than a clean exit code. On a scheduler-backed executor (such as SLURM) you would instead see the scheduler kill the task and return an exit code. Either way, the fix is the same: configure a realistic time limit. + #### Fix the code Increase the time limit to a realistic value: @@ -1791,12 +1779,12 @@ nextflow run bad_resources.nf -profile docker ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_resources.nf` [friendly_mcclintock] DSL2 - revision: 381567d2c1 + Launching `bad_resources.nf` [big_leakey] revision: d7f4e98877 executor > local (3) - [c2/9b4c41] PROCESS_FILES (3) | 3 of 3 ✔ + [12/5630b4] PROCESS_FILES (2) | 3 of 3 ✔ ``` If you make sure to read your error messages failures like this should not puzzle you for too long. But make sure you understand the resource requirements of the commands you are running so that you can configure your resource directives appropriately. @@ -1820,9 +1808,9 @@ nextflow run missing_output.nf ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `missing_output.nf` [irreverent_payne] DSL2 - revision: 3d5117f7e2 + Launching `missing_output.nf` [irreverent_payne] revision: 3d5117f7e2 executor > local (3) [5d/d544a4] PROCESS_FILES (2) | 0 of 3 ✘ @@ -1978,12 +1966,12 @@ nextflow run bad_channel_shape_viewed_debug.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_channel_shape_viewed_debug.nf` [agitated_crick] DSL2 - revision: ea3676d9ec + Launching `bad_channel_shape_viewed_debug.nf` [boring_varahamihira] revision: 37cbda227b executor > local (3) - [c6/2dac51] process > PROCESS_FILES (3) [100%] 3 of 3 ✔ + [10/9a030e] PROCESS_FILES (2) | 3 of 3 ✔ Channel content: [sample1, file1.txt] Channel content: [sample2, file2.txt] Channel content: [sample3, file3.txt] @@ -2042,9 +2030,9 @@ nextflow run bad_syntax.nf -preview ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_syntax.nf` [magical_mercator] DSL2 - revision: 550b9a8873 + Launching `bad_syntax.nf` [magical_mercator] revision: 550b9a8873 Error bad_syntax.nf:24:1: Unexpected input: '' @@ -2108,12 +2096,12 @@ nextflow run missing_software_with_stub.nf -stub-run ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `missing_software_with_stub.nf` [astonishing_shockley] DSL2 - revision: f1f4f05d7d + Launching `missing_software_with_stub.nf` [curious_faggin] revision: f1f4f05d7d executor > local (3) - [b5/2517a3] PROCESS_FILES (3) | 3 of 3 ✔ + [8a/7f8465] PROCESS_FILES (3) | 3 of 3 ✔ ``` #### Check the code @@ -2247,16 +2235,20 @@ Now it's time to put the systematic debugging approach into practice. The workfl ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 + + Launching `buggy_workflow.nf` [sharp_marconi] revision: 8965814da5 - Launching `buggy_workflow.nf` [wise_ramanujan] DSL2 - revision: d51a8e83fd + Error buggy_workflow.nf:25:12: Unexpected input: '\n' + │ 25 | script: + ╰ | ^ - ERROR ~ Range [11, 12) out of bounds for length 11 + ERROR ~ Script compilation failed -- Check '.nextflow.log' file for details ``` - This cryptic error indicates a parsing problem around line 11-12 in the `params{}` block. The v2 parser catches structural issues early. + This error points at line 25 (the `script:` label), but the real problem is just above it: the trailing comma on the `output:` declaration leaves the parser expecting more, so it trips on the next line. The parser catches structural issues like this before any process runs. Apply the four-phase debugging method you've learned: @@ -2384,7 +2376,7 @@ Now it's time to put the systematic debugging approach into practice. The workfl echo "Heavy computation \${i} for ${sample_id}" ``` - Now we get `Process exceeded running time limit (1ms)`, so we fix the run time limit for the relevant process: + Now the `local` executor hits the 1 millisecond time limit and reports `process hasn't exited`, so we fix the run time limit for the relevant process: **Error 8: Resource Configuration Error** ```groovy linenums="36" diff --git a/docs/en/docs/side_quests/dev_environment/index.md b/docs/en/docs/side_quests/dev_environment/index.md index 9702f9124a..fd44bb1bba 100644 --- a/docs/en/docs/side_quests/dev_environment/index.md +++ b/docs/en/docs/side_quests/dev_environment/index.md @@ -72,7 +72,7 @@ tree . │ └── utils.nf └── nextflow.config -3 directories, 12 files +2 directories, 12 files ``` !!! note "About the Example Files" From b72b36b824f5a49bf62e96af971fdbe23fcede70 Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 13:45:27 +0100 Subject: [PATCH 16/42] docs(side_quests): refresh essential_scripting_patterns for Nextflow 26.04 [skip ci] --- .../essential_scripting_patterns/index.md | 171 +++++++++++------- 1 file changed, 104 insertions(+), 67 deletions(-) diff --git a/docs/en/docs/side_quests/essential_scripting_patterns/index.md b/docs/en/docs/side_quests/essential_scripting_patterns/index.md index 95fdb87d11..9bc43e2b56 100644 --- a/docs/en/docs/side_quests/essential_scripting_patterns/index.md +++ b/docs/en/docs/side_quests/essential_scripting_patterns/index.md @@ -127,7 +127,7 @@ nextflow run main.nf ??? success "Command output" ```console - Launching `main.nf` [marvelous_tuckerman] DSL2 - revision: 6113e05c17 + Launching `main.nf` [marvelous_tuckerman] revision: 6113e05c17 [sample_id:SAMPLE_001, organism:human, tissue_type:liver, sequencing_depth:30000000, file_path:data/sequences/SAMPLE_001_S1_L001_R1_001.fastq, quality_score:38.5] [sample_id:SAMPLE_002, organism:mouse, tissue_type:brain, sequencing_depth:25000000, file_path:data/sequences/SAMPLE_002_S2_L001_R1_001.fastq, quality_score:35.2] @@ -354,9 +354,9 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [peaceful_cori] DSL2 - revision: 4cc4a8340f + Launching `main.nf` [spontaneous_noether] revision: 7d43085af6 ID fields only: [id:sample_001, organism:human, tissue:liver] ID fields only: [id:sample_002, organism:mouse, tissue:brain] @@ -483,9 +483,9 @@ nextflow run collect.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `collect.nf` [loving_mendel] DSL2 - revision: e8d054a46e + Launching `collect.nf` [evil_roentgen] revision: 5b2b07e824 Individual channel item: sample_001 Individual channel item: sample_002 @@ -541,9 +541,9 @@ nextflow run collect.nf ??? success "Command output" ```console hl_lines="5" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `collect.nf` [cheeky_stonebraker] DSL2 - revision: 2d5039fb47 + Launching `collect.nf` [deadly_waddington] revision: 48f3dcbb7b List.collect() result: [SPECIMEN_001, SPECIMEN_002, SPECIMEN_003] (3 items transformed into 3) Individual channel item: sample_001 @@ -612,9 +612,9 @@ nextflow run collect.nf ??? success "Command output" ```console hl_lines="6" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `collect.nf` [cranky_galileo] DSL2 - revision: 5f3c8b2a91 + Launching `collect.nf` [cranky_galileo] revision: 5f3c8b2a91 List.collect() result: [SPECIMEN_001, SPECIMEN_002, SPECIMEN_003] (3 items transformed into 3) Spread operator result: [s1, s2, s3] @@ -741,9 +741,9 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [clever_pauling] DSL2 - revision: 605d2058b4 + Launching `main.nf` [clever_pauling] revision: 605d2058b4 [[id:sample_001, organism:human, tissue:liver, depth:30000000, quality:38.5, sample_num:1, lane:001, read:R1, chunk:001, priority:normal], /workspaces/training/side-quests/essential_scripting_patterns/data/sequences/SAMPLE_001_S1_L001_R1_001.fastq] [[id:sample_002, organism:mouse, tissue:brain, depth:25000000, quality:35.2, sample_num:2, lane:001, read:R1, chunk:001, priority:normal], /workspaces/training/side-quests/essential_scripting_patterns/data/sequences/SAMPLE_002_S2_L001_R1_001.fastq] @@ -881,13 +881,16 @@ nextflow run main.nf --out2 sample_003_trimmed_R2.fastq.gz \ --json sample_003.fastp.json \ --html sample_003.fastp.html \ - --thread 2 + --thread 1 Command exit status: 255 Command output: (empty) + + Command error: + ERROR: Failed to open file: null ``` You can see that the process is trying to run `fastp` with a `null` value for the second input file, which is causing it to fail. This is because our dataset contains single-end reads, but the process is hardcoded to expect paired-end reads (two input files at a time). @@ -951,12 +954,12 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [adoring_rosalind] DSL2 - revision: 04b1cd93e9 + Launching `main.nf` [adoring_rosalind] revision: 04b1cd93e9 executor > local (3) - [31/a8ad4d] process > FASTP (3) [100%] 3 of 3 ✔ + [31/a8ad4d] FASTP (3) | 3 of 3 ✔ ``` Looks good! If we check the actual commands that were run (customise for your task hash): @@ -974,7 +977,7 @@ fastp \ --out1 sample_003_trimmed.fastq.gz \ --json sample_003.fastp.json \ --html sample_003.fastp.html \ - --thread 2 + --thread 1 ``` Another common usage of dynamic script logic can be seen in [the Nextflow for Science Genomics module](../../nf4_science/genomics/03_joint_calling.md). In that module, the GATK process being called can take multiple input files, but each must be prefixed with `-V` to form a correct command line. The process uses scripting to transform a collection of input files (`all_gvcfs`) into the correct command arguments: @@ -1089,14 +1092,22 @@ Include the process in your `main.nf` and add it to the workflow: } ``` -Now run the workflow and check the generated reports in `results/reports/`. They should contain basic information about each sample. +Now run the workflow. The reports are generated in each process working directory and contain basic information about each sample. - +```bash +nextflow run main.nf +``` ??? success "Command output" ```console - + N E X T F L O W ~ version 26.04.4 + + Launching `main.nf` [gigantic_hodgkin] revision: 8ba7d0c7eb + + executor > local (6) + [d1/b520bb] FASTP (2) | 3 of 3 ✔ + [b6/6550d5] GENERATE_REPORT (3) | 3 of 3 ✔ ``` But what if we want to add information about when and where the processing occurred? Let's modify the process to use **shell** variables and a bit of command substitution to include the current user, hostname, and date in the report: @@ -1129,8 +1140,8 @@ If you run this, you'll notice an error - Nextflow tries to interpret `#!groovy ??? failure "Command output" ```console - Error modules/generate_report.nf:15:27: `USER` is not defined - │ 15 | echo "Processed by: ${USER}" >> ${meta.id}_report.txt + Error modules/generate_report.nf:13:27: `USER` is not defined + │ 13 | echo "Processed by: ${USER}" >> ${meta.id}_report.txt ╰ | ^^^^ ERROR ~ Script compilation failed @@ -1287,13 +1298,13 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [admiring_panini] DSL2 - revision: 8cc832e32f + Launching `main.nf` [admiring_panini] revision: 8cc832e32f executor > local (6) - [8c/2e3f91] process > FASTP (3) [100%] 3 of 3 ✔ - [7a/1b4c92] process > GENERATE_REPORT (3) [100%] 3 of 3 ✔ + [8c/2e3f91] FASTP (3) | 3 of 3 ✔ + [7a/1b4c92] GENERATE_REPORT (3) | 3 of 3 ✔ ``` The output should show both processes completing successfully. The workflow is now much cleaner and easier to maintain, with all the complex metadata processing logic encapsulated in the `separateMetadata` function. @@ -1357,8 +1368,8 @@ nextflow run main.nf -ansi-log false ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 - Launching `main.nf` [fervent_albattani] DSL2 - revision: fa8f249759 + N E X T F L O W ~ version 26.04.4 + Launching `main.nf` [fervent_albattani] - revision: fa8f249759 [bd/ff3d41] Submitted process > FASTP (2) [a4/a3aab2] Submitted process > FASTP (1) [48/6db0c9] Submitted process > FASTP (3) @@ -1554,14 +1565,14 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [adoring_galileo] DSL2 - revision: c9e83aaef1 + Launching `main.nf` [adoring_galileo] revision: c9e83aaef1 - executor > local (6) - [1d/0747ac] process > FASTP (2) [100%] 2 of 2 ✔ - [cc/c44caf] process > TRIMGALORE (1) [100%] 1 of 1 ✔ - [34/bd5a9f] process > GENERATE_REPORT (1) [100%] 3 of 3 ✔ + executor > local (8) + [1d/0747ac] FASTP (2) | 2 of 2, retries: 2 ✔ + [cc/c44caf] TRIMGALORE (1) | 1 of 1 ✔ + [34/bd5a9f] GENERATE_REPORT (1) | 3 of 3 ✔ ``` Here, we've used small but mighty conditional expressions inside the `.branch{}` operator to route samples based on their metadata. Human samples with high coverage go through `FASTP`, while all other samples go through `TRIMGALORE`. @@ -1622,8 +1633,8 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 - Launching `main.nf` [lonely_williams] DSL2 - revision: d0b3f121ec + N E X T F L O W ~ version 26.04.4 + Launching `main.nf` [lonely_williams] - revision: d0b3f121ec [94/b48eac] Submitted process > FASTP (2) [2c/d2b28f] Submitted process > GENERATE_REPORT (2) [65/2e3be4] Submitted process > GENERATE_REPORT (1) @@ -1706,9 +1717,9 @@ nextflow run main.nf ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [trusting_torvalds] DSL2 - revision: b56fbfbce2 + Launching `main.nf` [trusting_torvalds] revision: b56fbfbce2 ERROR ~ Cannot invoke method toUpperCase() on null object @@ -1762,7 +1773,14 @@ nextflow run main.nf ??? success "Command output" ```console - + N E X T F L O W ~ version 26.04.4 + + Launching `main.nf` [jovial_mercator] revision: 8d3f21a0c4 + + executor > local (8) + [10/4f3bfd] FASTP (1) | 2 of 2, retries: 2 ✔ + [e5/12deed] TRIMGALORE (1) | 1 of 1 ✔ + [c9/93a3e8] GENERATE_REPORT (1) | 3 of 3 ✔ ``` No crash! The workflow now handles the missing field gracefully. When `row.run_id` is `null`, the `?.` operator prevents the `.toUpperCase()` call, and `run_id` becomes `null` instead of causing an exception. @@ -1911,9 +1929,9 @@ nextflow run main.nf ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [confident_coulomb] DSL2 - revision: 07059399ed + Launching `main.nf` [confident_coulomb] revision: 07059399ed WARN: Access to undefined parameter `input` -- Initialise it to a default value eg. `params.input = some_value` Input CSV file path not provided. Please specify --input @@ -1930,9 +1948,9 @@ nextflow run main.nf --input ./data/nonexistent.csv ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [cranky_gates] DSL2 - revision: 26839ae3eb + Launching `main.nf` [cranky_gates] revision: 26839ae3eb Input CSV file not found: ./data/nonexistent.csv ``` @@ -1946,7 +1964,14 @@ nextflow run main.nf --input ./data/samples.csv ??? success "Command output" ```console - + N E X T F L O W ~ version 26.04.4 + + Launching `main.nf` [magical_hopper] revision: 0a1b2c3d4e + + executor > local (8) + [10/4f3bfd] FASTP (1) | 2 of 2, retries: 2 ✔ + [e5/12deed] TRIMGALORE (1) | 1 of 1 ✔ + [c9/93a3e8] GENERATE_REPORT (1) | 3 of 3 ✔ ``` This time it runs successfully. @@ -1985,14 +2010,14 @@ nextflow run main.nf --input ./data/samples.csv ??? warning "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [awesome_goldwasser] DSL2 - revision: a31662a7c1 + Launching `main.nf` [awesome_goldwasser] revision: a31662a7c1 - executor > local (5) - [ce/df5eeb] process > FASTP (2) [100%] 2 of 2 ✔ - [- ] process > TRIMGALORE - - [d1/7d2b4b] process > GENERATE_REPORT (3) [100%] 3 of 3 ✔ + executor > local (8) + [ce/df5eeb] FASTP (2) | 2 of 2, retries: 2 ✔ + [3e/0d8664] TRIMGALORE (1) | 1 of 1 ✔ + [d1/7d2b4b] GENERATE_REPORT (3) | 3 of 3 ✔ WARN: Low sequencing depth for sample_002: 25000000 ``` @@ -2062,19 +2087,24 @@ nextflow run main.nf --input ./data/samples.csv -ansi-log false ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 - Launching `main.nf` [marvelous_boltzmann] DSL2 - revision: a31662a7c1 + N E X T F L O W ~ version 26.04.4 + Launching `main.nf` [marvelous_boltzmann] - revision: a31662a7c1 WARN: Low sequencing depth for sample_002: 25000000 - [9b/d48e40] Submitted process > FASTP (2) - [6a/73867a] Submitted process > GENERATE_REPORT (2) + [9b/d48e40] Submitted process > GENERATE_REPORT (2) + [6a/73867a] Submitted process > TRIMGALORE (1) [79/ad0ac5] Submitted process > GENERATE_REPORT (1) - [f3/bda6cb] Submitted process > FASTP (1) - [34/d5b52f] Submitted process > GENERATE_REPORT (3) + [f3/bda6cb] Submitted process > FASTP (2) + [34/d5b52f] Submitted process > FASTP (1) + [d2/4a4a82] Submitted process > GENERATE_REPORT (3) + [f3/bda6cb] NOTE: Process `FASTP (2)` terminated with an error exit status (137) -- Execution is retried (1) + [34/d5b52f] NOTE: Process `FASTP (1)` terminated with an error exit status (137) -- Execution is retried (1) + [cd/f86446] Re-submitted process > FASTP (2) + [f9/6af250] Re-submitted process > FASTP (1) Pipeline execution summary: ========================== - Completed at: 2025-10-10T12:14:24.885384+01:00 - Duration : 2.9s + Completed at: 2026-06-23T12:28:41.754817244Z + Duration : 7.5s Success : true workDir : /workspaces/training/side-quests/essential_scripting_patterns/work exit status : 0 @@ -2133,24 +2163,31 @@ Let's make it more useful by adding conditional logic: Now we get an even more informative summary, including a success/failure message and the output directory if specified: - +```bash +nextflow run main.nf --input ./data/samples.csv -ansi-log false +``` ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 - Launching `main.nf` [boring_linnaeus] DSL2 - revision: a31662a7c1 + N E X T F L O W ~ version 26.04.4 + Launching `main.nf` [boring_linnaeus] - revision: a31662a7c1 WARN: Low sequencing depth for sample_002: 25000000 - [e5/242efc] Submitted process > FASTP (2) - [3b/74047c] Submitted process > GENERATE_REPORT (3) - [8a/7a57e6] Submitted process > GENERATE_REPORT (1) - [a8/b1a31f] Submitted process > GENERATE_REPORT (2) - [40/648429] Submitted process > FASTP (1) + [70/ba9e88] Submitted process > GENERATE_REPORT (3) + [ed/505613] Submitted process > TRIMGALORE (1) + [d5/3d2639] Submitted process > FASTP (2) + [51/185eb7] Submitted process > FASTP (1) + [1c/aad211] Submitted process > GENERATE_REPORT (2) + [88/1fcf7f] Submitted process > GENERATE_REPORT (1) + [51/185eb7] NOTE: Process `FASTP (1)` terminated with an error exit status (137) -- Execution is retried (1) + [d5/3d2639] NOTE: Process `FASTP (2)` terminated with an error exit status (137) -- Execution is retried (1) + [d0/865a28] Re-submitted process > FASTP (1) + [d7/709bed] Re-submitted process > FASTP (2) Pipeline execution summary: ========================== - Completed at: 2025-10-10T12:16:00.522569+01:00 - Duration : 3.6s + Completed at: 2026-06-23T12:28:41.754817244Z + Duration : 7.5s Success : true workDir : /workspaces/training/side-quests/essential_scripting_patterns/work exit status : 0 From e656fb4b8ffe0bf6533cf4c2c36339e0b4a8d6b5 Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 13:53:09 +0100 Subject: [PATCH 17/42] docs(side_quests): verify workflows_of_workflows on Nextflow 26.04 [skip ci] --- .../workflows_of_workflows/index.md | 104 ++++++++++++++---- 1 file changed, 80 insertions(+), 24 deletions(-) diff --git a/docs/en/docs/side_quests/workflows_of_workflows/index.md b/docs/en/docs/side_quests/workflows_of_workflows/index.md index 93df9997f5..4bbebdec22 100644 --- a/docs/en/docs/side_quests/workflows_of_workflows/index.md +++ b/docs/en/docs/side_quests/workflows_of_workflows/index.md @@ -139,12 +139,26 @@ nextflow run workflows/greeting.nf ??? success "Command output" ```console - N E X T F L O W ~ version 24.10.0 - Launching `workflows/greeting.nf` [peaceful_montalcini] DSL2 - revision: 90f61b7093 + N E X T F L O W ~ version 26.04.4 + Launching `workflows/greeting.nf` [loving_cuvier] revision: 22e91263dd executor > local (9) - [51/4f980f] process > VALIDATE_NAME (validating Bob) [100%] 3 of 3 ✔ - [2b/dd8dc2] process > SAY_HELLO (greeting Bob) [100%] 3 of 3 ✔ - [8e/882565] process > TIMESTAMP_GREETING (adding timestamp to greeting) [100%] 3 of 3 ✔ + [54/ec2442] VAL…TE_NAME (validating Alice) | 3 of 3 ✔ + [a5/3cf2ab] SAY_HELLO (greeting Charlie) | 3 of 3 ✔ + [df/6689ec] TIM…ing timestamp to greeting) | 3 of 3 ✔ + + Outputs: + + /workspaces/training/side-quests/workflows_of_workflows/results + + greetings: + - Alice-output.txt + - Bob-output.txt + - Charlie-output.txt + + timestamped: + - timestamped_Alice-output.txt + - timestamped_Bob-output.txt + - timestamped_Charlie-output.txt ``` To make it composable with other workflows, a few things need to change. @@ -276,8 +290,8 @@ nextflow run workflows/greeting.nf ??? failure "Command output" ```console - N E X T F L O W ~ version 24.10.0 - Launching `workflows/greeting.nf` [high_brahmagupta] DSL2 - revision: 8f5857af25 + N E X T F L O W ~ version 26.04.4 + Launching `workflows/greeting.nf` [ridiculous_mandelbrot] revision: e619235cf1 No entry workflow specified ``` @@ -361,12 +375,21 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 24.10.0 - Launching `main.nf` [goofy_mayer] DSL2 - revision: 543f8742fe + N E X T F L O W ~ version 26.04.4 + Launching `main.nf` [berserk_lalande] revision: 9a841b3c7f executor > local (9) - [05/3cc752] process > GREETING_WORKFLOW:VALIDATE_NAME (validating Char... [100%] 3 of 3 ✔ - [b1/b56ecf] process > GREETING_WORKFLOW:SAY_HELLO (greeting Charlie) [100%] 3 of 3 ✔ - [ea/342168] process > GREETING_WORKFLOW:TIMESTAMP_GREETING (adding tim... [100%] 3 of 3 ✔ + [31/c2931b] GRE…TE_NAME (validating Alice) | 3 of 3 ✔ + [2a/50592c] GRE…SAY_HELLO (greeting Alice) | 3 of 3 ✔ + [09/35e2d5] GRE…ing timestamp to greeting) | 3 of 3 ✔ + + Outputs: + + /workspaces/training/side-quests/workflows_of_workflows/results + + greetings: + - greetings/Charlie-output.txt + - greetings/Bob-output.txt + - greetings/Alice-output.txt ``` ??? abstract "Directory contents" @@ -454,11 +477,25 @@ nextflow run workflows/transform.nf ??? success "Command output" ```console - N E X T F L O W ~ version 24.10.0 - Launching `workflows/transform.nf` [blissful_curie] DSL2 - revision: 4e7b1c9f02 + N E X T F L O W ~ version 26.04.4 + Launching `workflows/transform.nf` [cranky_banach] revision: c040a64fcf executor > local (6) - [3e/a14c29] process > SAY_HELLO_UPPER (converting t... [100%] 3 of 3 ✔ - [c8/51b9e3] process > REVERSE_TEXT (reversing UPPER... [100%] 3 of 3 ✔ + [c8/cd04d9] SAY…estamped_Alice-output.txt) | 3 of 3 ✔ + [3d/2252c3] REV…estamped_Alice-output.txt) | 3 of 3 ✔ + + Outputs: + + /workspaces/training/side-quests/workflows_of_workflows/results + + upper: + - UPPER-timestamped_Bob-output.txt + - UPPER-timestamped_Charlie-output.txt + - UPPER-timestamped_Alice-output.txt + + reversed: + - REVERSED-UPPER-timestamped_Bob-output.txt + - REVERSED-UPPER-timestamped_Charlie-output.txt + - REVERSED-UPPER-timestamped_Alice-output.txt ``` To make it composable with `GREETING_WORKFLOW`, the same three changes from section 1.2 apply. @@ -583,14 +620,33 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 24.10.0 - Launching `main.nf` [sick_kimura] DSL2 - revision: 8dc45fc6a8 + N E X T F L O W ~ version 26.04.4 + Launching `main.nf` [focused_venter] revision: 03b08f23fc executor > local (15) - [83/1b51f4] process > GREETING_WORKFLOW:VALIDATE_NAME (validating Alice) [100%] 3 of 3 ✔ - [68/556150] process > GREETING_WORKFLOW:SAY_HELLO (greeting Alice) [100%] 3 of 3 ✔ - [de/511abd] process > GREETING_WORKFLOW:TIMESTAMP_GREETING (adding tim... [100%] 3 of 3 ✔ - [cd/e6a7e0] process > TRANSFORM_WORKFLOW:SAY_HELLO_UPPER (converting t... [100%] 3 of 3 ✔ - [f0/74ba4a] process > TRANSFORM_WORKFLOW:REVERSE_TEXT (reversing UPPER... [100%] 3 of 3 ✔ + [f6/cd1e04] GRE…TE_NAME (validating Alice) | 3 of 3 ✔ + [07/1139ba] GRE…SAY_HELLO (greeting Alice) | 3 of 3 ✔ + [d2/25e304] GRE…ing timestamp to greeting) | 3 of 3 ✔ + [90/64c33c] TRA…estamped_Alice-output.txt) | 3 of 3 ✔ + [bf/2f23b0] TRA…estamped_Alice-output.txt) | 3 of 3 ✔ + + Outputs: + + /workspaces/training/side-quests/workflows_of_workflows/results + + greetings: + - greetings/Charlie-output.txt + - greetings/Bob-output.txt + - greetings/Alice-output.txt + + upper: + - upper/UPPER-timestamped_Charlie-output.txt + - upper/UPPER-timestamped_Bob-output.txt + - upper/UPPER-timestamped_Alice-output.txt + + reversed: + - reversed/REVERSED-UPPER-timestamped_Charlie-output.txt + - reversed/REVERSED-UPPER-timestamped_Bob-output.txt + - reversed/REVERSED-UPPER-timestamped_Alice-output.txt ``` ??? abstract "Directory contents" @@ -614,7 +670,7 @@ nextflow run main.nf ??? abstract "File contents" ```console title="results/reversed/REVERSED-UPPER-timestamped_Alice-output.txt" - !ECILA ,OLLEH ]04:50:71 60-30-5202[ + !ECILA ,OLLEH ]71:15:11 32-60-6202[ ``` The pipeline is working end-to-end: the greeting has been uppercased and reversed. From 3a12a21eec824f0a8a2976070cdb374162b1e365 Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 13:58:54 +0100 Subject: [PATCH 18/42] docs(side_quests): verify+correct splitting_and_grouping for Nextflow 26.04 [skip ci] --- .../splitting_and_grouping/index.md | 74 ++++++++++--------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/docs/en/docs/side_quests/splitting_and_grouping/index.md b/docs/en/docs/side_quests/splitting_and_grouping/index.md index 8ba55a1cf9..2a522c9027 100644 --- a/docs/en/docs/side_quests/splitting_and_grouping/index.md +++ b/docs/en/docs/side_quests/splitting_and_grouping/index.md @@ -176,9 +176,9 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [deadly_mercator] DSL2 - revision: bd6b0224e9 + Launching `main.nf` [deadly_mercator] revision: bd6b0224e9 [[id:patientA, repeat:1, type:normal], patientA_rep1_normal.bam] [[id:patientA, repeat:1, type:tumor], patientA_rep1_tumor.bam] @@ -232,9 +232,9 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [admiring_brown] DSL2 - revision: 194d61704d + Launching `main.nf` [admiring_brown] revision: 194d61704d [[id:patientA, repeat:1, type:normal], patientA_rep1_normal.bam] [[id:patientA, repeat:2, type:normal], patientA_rep2_normal.bam] @@ -295,9 +295,9 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [trusting_poisson] DSL2 - revision: 639186ee74 + Launching `main.nf` [trusting_poisson] revision: 639186ee74 [[id:patientA, repeat:1, type:normal], patientA_rep1_normal.bam] [[id:patientA, repeat:2, type:normal], patientA_rep2_normal.bam] @@ -338,9 +338,9 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [maniac_boltzmann] DSL2 - revision: 3636b6576b + Launching `main.nf` [maniac_boltzmann] revision: 3636b6576b Tumor sample: [[id:patientA, repeat:1, type:tumor], patientA_rep1_tumor.bam] Tumor sample: [[id:patientA, repeat:2, type:tumor], patientA_rep2_tumor.bam] @@ -387,9 +387,9 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [maniac_boltzmann] DSL2 - revision: 3636b6576b + Launching `main.nf` [maniac_boltzmann] revision: 3636b6576b Tumor sample: [[id:patientA, repeat:1, type:tumor], patientA_rep1_tumor.bam] Tumor sample: [[id:patientA, repeat:2, type:tumor], patientA_rep2_tumor.bam] @@ -442,9 +442,9 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [mad_lagrange] DSL2 - revision: 9940b3f23d + Launching `main.nf` [mad_lagrange] revision: 9940b3f23d Tumor sample: [patientA, [id:patientA, repeat:1, type:tumor], patientA_rep1_tumor.bam] Tumor sample: [patientA, [id:patientA, repeat:2, type:tumor], patientA_rep2_tumor.bam] @@ -500,9 +500,9 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [soggy_wiles] DSL2 - revision: 3bc1979889 + Launching `main.nf` [soggy_wiles] revision: 3bc1979889 [patientA, [id:patientA, repeat:1, type:normal], patientA_rep1_normal.bam, [id:patientA, repeat:1, type:tumor], patientA_rep1_tumor.bam] [patientA, [id:patientA, repeat:2, type:normal], patientA_rep2_normal.bam, [id:patientA, repeat:2, type:tumor], patientA_rep2_tumor.bam] @@ -566,9 +566,9 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [prickly_wing] DSL2 - revision: 3bebf22dee + Launching `main.nf` [prickly_wing] revision: 3bebf22dee [[patientA, 1], [id:patientA, repeat:1, type:normal], patientA_rep1_normal.bam, [id:patientA, repeat:1, type:tumor], patientA_rep1_tumor.bam] [[patientA, 2], [id:patientA, repeat:2, type:normal], patientA_rep2_normal.bam, [id:patientA, repeat:2, type:tumor], patientA_rep2_tumor.bam] @@ -615,9 +615,9 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [reverent_wing] DSL2 - revision: 847016c3b7 + Launching `main.nf` [reverent_wing] revision: 847016c3b7 [[id:patientA, repeat:1], [id:patientA, repeat:1, type:normal], patientA_rep1_normal.bam, [id:patientA, repeat:1, type:tumor], patientA_rep1_tumor.bam] [[id:patientA, repeat:2], [id:patientA, repeat:2, type:normal], patientA_rep2_normal.bam, [id:patientA, repeat:2, type:tumor], patientA_rep2_tumor.bam] @@ -702,16 +702,18 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [angry_meninsky] DSL2 - revision: 2edc226b1d + Launching `main.nf` [evil_swartz] revision: 5ef9b852a4 - [[id:patientA, repeat:1], [id:patientA, repeat:1, type:normal], patientA_rep1_normal.bam, [id:patientA, repeat:1, type:tumor], patientA_rep1_tumor.bam] - [[id:patientA, repeat:2], [id:patientA, repeat:2, type:normal], patientA_rep2_normal.bam, [id:patientA, repeat:2, type:tumor], patientA_rep2_tumor.bam] - [[id:patientB, repeat:1], [id:patientB, repeat:1, type:normal], patientB_rep1_normal.bam, [id:patientB, repeat:1, type:tumor], patientB_rep1_tumor.bam] - [[id:patientC, repeat:1], [id:patientC, repeat:1, type:normal], patientC_rep1_normal.bam, [id:patientC, repeat:1, type:tumor], patientC_rep1_tumor.bam] + [[id:patientA, repeat:1], [id:patientA, repeat:1, type:normal], /workspaces/training/side-quests/splitting_and_grouping/patientA_rep1_normal.bam, [id:patientA, repeat:1, type:tumor], /workspaces/training/side-quests/splitting_and_grouping/patientA_rep1_tumor.bam] + [[id:patientA, repeat:2], [id:patientA, repeat:2, type:normal], /workspaces/training/side-quests/splitting_and_grouping/patientA_rep2_normal.bam, [id:patientA, repeat:2, type:tumor], /workspaces/training/side-quests/splitting_and_grouping/patientA_rep2_tumor.bam] + [[id:patientB, repeat:1], [id:patientB, repeat:1, type:normal], /workspaces/training/side-quests/splitting_and_grouping/patientB_rep1_normal.bam, [id:patientB, repeat:1, type:tumor], /workspaces/training/side-quests/splitting_and_grouping/patientB_rep1_tumor.bam] + [[id:patientC, repeat:1], [id:patientC, repeat:1, type:normal], /workspaces/training/side-quests/splitting_and_grouping/patientC_rep1_normal.bam, [id:patientC, repeat:1, type:tumor], /workspaces/training/side-quests/splitting_and_grouping/patientC_rep1_tumor.bam] ``` + Because the closure now wraps each path with `file()`, the file entries appear as resolved absolute paths rather than the bare filenames from the samplesheet. + Using a named closure allows us to reuse the same transformation in multiple places, reducing the risk of errors and making the code more readable and maintainable. ### 3.5. Reduce duplication of data @@ -764,6 +766,10 @@ nextflow run main.nf ??? success "Command output" ```console + N E X T F L O W ~ version 26.04.4 + + Launching `main.nf` [lonely_perlman] revision: 36bb08c483 + [[id:patientA, repeat:1], [type:normal], /workspaces/training/side-quests/splitting_and_grouping/patientA_rep1_normal.bam, [type:tumor], /workspaces/training/side-quests/splitting_and_grouping/patientA_rep1_tumor.bam] [[id:patientA, repeat:2], [type:normal], /workspaces/training/side-quests/splitting_and_grouping/patientA_rep2_normal.bam, [type:tumor], /workspaces/training/side-quests/splitting_and_grouping/patientA_rep2_tumor.bam] [[id:patientB, repeat:1], [type:normal], /workspaces/training/side-quests/splitting_and_grouping/patientB_rep1_normal.bam, [type:tumor], /workspaces/training/side-quests/splitting_and_grouping/patientB_rep1_tumor.bam] @@ -801,9 +807,9 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [confident_leavitt] DSL2 - revision: a2303895bd + Launching `main.nf` [confident_leavitt] revision: a2303895bd [[id:patientA, repeat:1], patientA_rep1_normal.bam, patientA_rep1_tumor.bam] [[id:patientA, repeat:2], patientA_rep2_normal.bam, patientA_rep2_tumor.bam] @@ -879,9 +885,9 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [mighty_tesla] DSL2 - revision: ae013ab70b + Launching `main.nf` [mighty_tesla] revision: ae013ab70b [[id:patientA, repeat:1], patientA_rep1_normal.bam, patientA_rep1_tumor.bam, chr1] [[id:patientA, repeat:1], patientA_rep1_normal.bam, patientA_rep1_tumor.bam, chr2] @@ -961,9 +967,9 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [sad_hawking] DSL2 - revision: 1f6f6250cd + Launching `main.nf` [sad_hawking] revision: 1f6f6250cd [[id:patientA, repeat:1, interval:chr1], patientA_rep1_normal.bam, patientA_rep1_tumor.bam] [[id:patientA, repeat:1, interval:chr2], patientA_rep1_normal.bam, patientA_rep1_tumor.bam] @@ -1062,9 +1068,9 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [hopeful_brenner] DSL2 - revision: 7f4f7fea76 + Launching `main.nf` [hopeful_brenner] revision: 7f4f7fea76 [[id:patientA, interval:chr1], patientA_rep1_normal.bam, patientA_rep1_tumor.bam] [[id:patientA, interval:chr2], patientA_rep1_normal.bam, patientA_rep1_tumor.bam] @@ -1126,9 +1132,9 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [friendly_jang] DSL2 - revision: a1bee1c55d + Launching `main.nf` [friendly_jang] revision: a1bee1c55d [[id:patientA, interval:chr1], [patientA_rep1_normal.bam, patientA_rep2_normal.bam], [patientA_rep1_tumor.bam, patientA_rep2_tumor.bam]] [[id:patientA, interval:chr2], [patientA_rep1_normal.bam, patientA_rep2_normal.bam], [patientA_rep1_tumor.bam, patientA_rep2_tumor.bam]] From ff639a1031630cfe2dca0c9d6c065e88c88405cd Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 14:52:09 +0100 Subject: [PATCH 19/42] docs(side_quests): add genuine 26.04 hint line to nf_test 2.1 failure block [skip ci] --- docs/en/docs/side_quests/nf_test/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/en/docs/side_quests/nf_test/index.md b/docs/en/docs/side_quests/nf_test/index.md index f86c7ece08..7840fd451b 100644 --- a/docs/en/docs/side_quests/nf_test/index.md +++ b/docs/en/docs/side_quests/nf_test/index.md @@ -755,6 +755,8 @@ Test Process sayHello Nextflow stdout: Process `sayHello` declares 1 input but was called with 0 arguments + + -- Check script '/workspaces/training/side-quests/nf-test/.nf-test-1eaad1186e16d8d0a9292ed1cc8a9f12.nf' at line: 30 or see '/workspaces/training/side-quests/nf-test/.nf-test/tests/1eaad1186e16d8d0a9292ed1cc8a9f12/meta/nextflow.log' file for more details Nextflow stderr: FAILURE: Executed 1 tests in 4.884s (1 failed) From bd9a61ae5e94a08756b98107db8ea69a975bff88 Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 14:57:00 +0100 Subject: [PATCH 20/42] Bump NXF_VER to 26.04.4 in local-dev devcontainer [skip ci] --- .devcontainer/local-dev/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/local-dev/devcontainer.json b/.devcontainer/local-dev/devcontainer.json index 130b120d66..70dc002322 100644 --- a/.devcontainer/local-dev/devcontainer.json +++ b/.devcontainer/local-dev/devcontainer.json @@ -33,7 +33,7 @@ // Nextflow installation version "NXF_HOME": "/workspaces/training/.nextflow", "NXF_EDGE": "0", - "NXF_VER": "25.10.4", + "NXF_VER": "26.04.4", "NXF_SYNTAX_PARSER": "v2", // Other env vars "HOST_PROJECT_PATH": "/workspaces/training", From f2db0a20c7ca38b233d3172a2021853f56e0a420 Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 15:01:18 +0100 Subject: [PATCH 21/42] docs(side_quests): re-verify plugin_development on 26.04; bump broken nf-co2footprint 1.2.0->1.3.0 [skip ci] --- .../plugin_development/01_plugin_basics.md | 13 ++++--------- .../plugin_development/02_create_project.md | 14 +++++++------- .../plugin_development/04_build_and_test.md | 2 +- .../plugin_development/06_configuration.md | 6 +++--- 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/docs/en/docs/side_quests/plugin_development/01_plugin_basics.md b/docs/en/docs/side_quests/plugin_development/01_plugin_basics.md index 32cc5d3e36..19507bd15d 100644 --- a/docs/en/docs/side_quests/plugin_development/01_plugin_basics.md +++ b/docs/en/docs/side_quests/plugin_development/01_plugin_basics.md @@ -509,7 +509,7 @@ Update `nextflow.config`: plugins { id 'nf-hello@0.5.0' id 'nf-schema@2.6.1' - id 'nf-co2footprint@1.2.0' + id 'nf-co2footprint@1.3.0' } ``` @@ -532,7 +532,7 @@ The plugin produces several INFO and WARN messages during execution. These are normal for a small example running on a local machine: ```console title="Output (partial)" -nf-co2footprint plugin ~ version 1.2.0 +nf-co2footprint plugin ~ version 1.3.0 WARN - [nf-co2footprint] Target zone null not found. Attempting to retrieve carbon intensity for fallback zone GLOBAL. INFO - [nf-co2footprint] Using fallback carbon intensity from GLOBAL from CI table: 480.0 gCO₂eq/kWh. WARN - [nf-co2footprint] Executor 'null' not mapped. @@ -598,7 +598,7 @@ Add a `co2footprint` block to `nextflow.config`: plugins { id 'nf-hello@0.5.0' id 'nf-schema@2.6.1' - id 'nf-co2footprint@1.2.0' + id 'nf-co2footprint@1.3.0' } co2footprint { @@ -612,7 +612,7 @@ Add a `co2footprint` block to `nextflow.config`: plugins { id 'nf-hello@0.5.0' id 'nf-schema@2.6.1' - id 'nf-co2footprint@1.2.0' + id 'nf-co2footprint@1.3.0' } ``` @@ -633,11 +633,6 @@ INFO - [nf-co2footprint] Using fallback carbon intensity from GB from CI table: The zone warning is gone. The plugin now uses GB-specific carbon intensity (163.92 gCO₂eq/kWh) instead of the global fallback (480.0 gCO₂eq/kWh). -!!! note - - You may also see a `WARN: Unrecognized config option 'co2footprint.location'` message. - This is cosmetic and can be safely ignored; the plugin still reads the value correctly. - In Part 6, you'll create a configuration scope for your own plugin. This plugin works entirely through the observer mechanism, hooking into workflow lifecycle events to collect resource metrics and generate its report when the pipeline completes. diff --git a/docs/en/docs/side_quests/plugin_development/02_create_project.md b/docs/en/docs/side_quests/plugin_development/02_create_project.md index 0956aef7c7..445e42caa0 100644 --- a/docs/en/docs/side_quests/plugin_development/02_create_project.md +++ b/docs/en/docs/side_quests/plugin_development/02_create_project.md @@ -61,15 +61,15 @@ You should see: ```console . -├── build.gradle ├── COPYING +├── Makefile +├── README.md +├── build.gradle ├── gradle │ └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew -├── Makefile -├── README.md ├── settings.gradle └── src ├── main @@ -129,13 +129,13 @@ The most important is the `nextflowPlugin` block: ```groovy title="build.gradle" plugins { - id 'io.nextflow.nextflow-plugin' version '1.0.0-beta.10' + id 'io.nextflow.nextflow-plugin' version '1.0.0-beta.15' } version = '0.1.0' nextflowPlugin { - nextflowVersion = '24.10.0' // (1)! + nextflowVersion = '25.10.0' // (1)! provider = 'training' // (2)! className = 'training.plugin.GreetingPlugin' // (3)! @@ -177,7 +177,7 @@ Update it to match your installed Nextflow version for full compatibility: ```groovy title="build.gradle" hl_lines="2" nextflowPlugin { - nextflowVersion = '24.10.0' + nextflowVersion = '25.10.0' provider = 'training' ``` @@ -246,7 +246,7 @@ make install Deprecated Gradle features were used in this build... BUILD SUCCESSFUL in 23s - 5 actionable tasks: 5 executed + 6 actionable tasks: 6 executed ``` **The warnings are expected.** diff --git a/docs/en/docs/side_quests/plugin_development/04_build_and_test.md b/docs/en/docs/side_quests/plugin_development/04_build_and_test.md index 8b802dd24c..6b2db86f40 100644 --- a/docs/en/docs/side_quests/plugin_development/04_build_and_test.md +++ b/docs/en/docs/side_quests/plugin_development/04_build_and_test.md @@ -213,7 +213,7 @@ make test ```console BUILD SUCCESSFUL in 5s - 6 actionable tasks: 6 executed + 7 actionable tasks: 7 executed ``` **Where are the test results?** Gradle hides detailed output when all tests pass. diff --git a/docs/en/docs/side_quests/plugin_development/06_configuration.md b/docs/en/docs/side_quests/plugin_development/06_configuration.md index aa31805a00..80e4f4b623 100644 --- a/docs/en/docs/side_quests/plugin_development/06_configuration.md +++ b/docs/en/docs/side_quests/plugin_development/06_configuration.md @@ -95,12 +95,12 @@ The build fails: ```console > Task :compileGroovy FAILED -GreetingExtension.groovy: 30: [Static type checking] - The variable [prefix] is undeclared. - @ line 30, column 9. +GreetingExtension.groovy: 34: [Static type checking] - The variable [prefix] is undeclared. + @ line 34, column 9. prefix = session.config.navigate('greeting.prefix', '***') as String ^ -GreetingExtension.groovy: 31: [Static type checking] - The variable [suffix] is undeclared. +GreetingExtension.groovy: 35: [Static type checking] - The variable [suffix] is undeclared. ``` In Groovy (and Java), you must _declare_ a variable before using it. From 2ad4d65367b4f77d161702d0de2377c5d14bc898 Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 15:01:48 +0100 Subject: [PATCH 22/42] docs(hello_nf-core): fix Part 1 nextflow-pull layout + genuine demo output for 26.04 (v1) [skip ci] --- docs/en/docs/hello_nf-core/01_run_demo.md | 89 ++++++++++++++--------- 1 file changed, 53 insertions(+), 36 deletions(-) diff --git a/docs/en/docs/hello_nf-core/01_run_demo.md b/docs/en/docs/hello_nf-core/01_run_demo.md index 8a12de3684..dab1298dd2 100644 --- a/docs/en/docs/hello_nf-core/01_run_demo.md +++ b/docs/en/docs/hello_nf-core/01_run_demo.md @@ -104,22 +104,26 @@ nextflow list You can try pulling a few other pipelines to see how they get listed when you have more than one. -#### 1.2.3. Find your pipelines in `$NXF_HOME/assets/` +#### 1.2.3. Find where the pipeline was downloaded You'll notice that the files are not in your current work directory. -By default, Nextflow saves them to `$NXF_HOME/assets`. +By default, Nextflow saves pulled pipelines under `$NXF_HOME/assets`. + +To find where a specific pipeline lives, ask Nextflow directly: ```bash -tree -L 2 $NXF_HOME/assets/ +nextflow info nf-core/demo ``` -```console title="Directory contents" -/workspaces/.nextflow/assets/ -└── nf-core - └── demo +??? success "Command output" -2 directories, 0 files -``` + ```console + project name: nf-core/demo + repository : https://github.com/nf-core/demo + local path : /workspaces/.nextflow/assets/.repos/nf-core/demo + main script : main.nf + description : An nf-core demo pipeline + ``` !!! note @@ -127,17 +131,21 @@ tree -L 2 $NXF_HOME/assets/ Nextflow keeps the downloaded source code intentionally 'out of the way' on the principle that these pipelines should be used more like libraries than code that you would directly interact with. +Under the hood, Nextflow stores each pulled pipeline as a git repository under `$NXF_HOME/assets/.repos/`, and checks out the code for each revision into a `clones//` subdirectory. +Because `.repos` is a hidden directory, a plain `tree -L 2 $NXF_HOME/assets/` will look empty. + #### 1.2.4. Create a symlink to access the source code easily We're not going to look at the code in detail, but let's take a quick peek just to get a sense of what the overall organization looks like. -To make it easier to browse the pipeline source code, create a symbolic link to the assets directory: +To make it easier to browse the pipeline source code, create a symbolic link pointing at the checked-out copy of the pipeline: ```bash -ln -s $NXF_HOME/assets pipelines +mkdir -p pipelines/nf-core +ln -s "$(echo $NXF_HOME/assets/.repos/nf-core/demo/clones/*/)" pipelines/nf-core/demo ``` -This creates a shortcut so you can explore the code with `tree -L 2 pipelines` or open files directly. +This creates a shortcut so you can explore the code with `tree -L 2 pipelines/nf-core/demo` or open files directly. #### 1.2.5. Overview of the code organization @@ -218,10 +226,10 @@ It's a great way to quickly try out a pipeline at small scale. It's good practice to check what a pipeline's test profile specifies before running it. The `test` profile for `nf-core/demo` lives in the configuration file `conf/test.config`. -You can find it locally inside the pipeline source that `nextflow pull` downloaded: +You can find it locally inside the pipeline source that `nextflow pull` downloaded, via the `pipelines` symlink created in section 1.2.4: ```bash -code $NXF_HOME/assets/nf-core/demo/conf/test.config +code pipelines/nf-core/demo/conf/test.config ``` Here is the content of that file: @@ -333,10 +341,10 @@ nextflow run nf-core/demo -profile docker,test --outdir demo-results containerEngine : docker launchDir : /workspaces/training/hello-nf-core workDir : /workspaces/training/hello-nf-core/work - projectDir : /workspaces/.nextflow/assets/nf-core/demo + projectDir : /workspaces/.nextflow/assets/.repos/nf-core/demo/clones/45904cb9d12db3d89900e6c479fe604ef71b297b userName : root profile : docker,test - configFiles : /workspaces/.nextflow/assets/nf-core/demo/nextflow.config + configFiles : /workspaces/.nextflow/assets/.repos/nf-core/demo/clones/45904cb9d12db3d89900e6c479fe604ef71b297b/nextflow.config !! Only displaying parameters that differ from the pipeline defaults !! ------------------------------------------------------ @@ -493,38 +501,40 @@ nextflow run nf-core/demo --help Launching `https://github.com/nf-core/demo` [run_name] revision: 45904cb9d1 [master] - ---------------------------------------------------- + + ------------------------------------------------------ ,--./,-. ___ __ __ __ ___ /,-._.--~' |\ | |__ __ / ` / \ |__) |__ } { | \| | \__, \__/ | \ |___ \`-._,-`-, `._,._,' nf-core/demo 1.1.0 - ---------------------------------------------------- + ------------------------------------------------------ Typical pipeline command: nextflow run nf-core/demo -profile --input samplesheet.csv --outdir + Input/output options - --input [string] Path to a metadata file containing information about the samples in the experiment. - --outdir [string] The output directory where the results will be saved. You have to use absolute paths to storage on Cloud infrastructure. - --email [string] Email address for completion summary. - --multiqc_title [string] MultiQC report title. Printed as page header, used for filename if not otherwise specified. + --input [string] Path to a metadata file containing information about the samples in the experiment. + --outdir [string] The output directory where the results will be saved. You have to use absolute paths to storage on Cloud infrastructure. + --email [string] Email address for completion summary. + --multiqc_title [string] MultiQC report title. Printed as page header, used for filename if not otherwise specified. Reference genome options - --genome [string] Name of iGenomes reference. - --fasta [string] Path to FASTA genome file. + --genome [string] Name of iGenomes reference. + --fasta [string] Path to FASTA genome file. Process skipping options - --skip_trim [boolean] Skip trimming fastq files with seqtk + --skip_trim [boolean] Skip trimming fastq files with seqtk Generic options - --multiqc_methods_description [string] Custom MultiQC yaml file containing HTML including a methods description. - --help [boolean, string] Display the help message. - --help_full [boolean] Display the full detailed help message. - --show_hidden [boolean] Display hidden parameters in the help message (only works when --help or --help_full are provided). - !! Hiding 20 param(s), use the `--show_hidden` parameter to show them !! - ---------------------------------------------------- + --multiqc_methods_description [string] Custom MultiQC yaml file containing HTML including a methods description. + --help [boolean, string] Display the help message. + --help_full [boolean] Display the full detailed help message. + --show_hidden [boolean] Display hidden parameters in the help message (only works when --help or --help_full are provided). + !! Hiding 20 param(s), use the `--showHidden` parameter to show them !! + ------------------------------------------------------ * The pipeline https://doi.org/10.5281/zenodo.12192442 @@ -722,11 +732,11 @@ Configuration in the strict sense controls **how** the pipeline runs: resource a nf-core pipelines include default configuration in `nextflow.config` and the `conf/` directory. Before overriding anything, it helps to know where the defaults live. -You already saw in section 2.1 that the pipeline source code lives in `$NXF_HOME/assets`. -List the config files to see what's available: +You already saw in section 2.1 that the pipeline source code lives under `$NXF_HOME/assets`. +Using the `pipelines` symlink from section 1.2.4, list the config files to see what's available: ```bash -ls $NXF_HOME/assets/nf-core/demo/conf/ +ls pipelines/nf-core/demo/conf/ ``` ```console @@ -840,9 +850,16 @@ cat work/ab/cd1234/.command.sh ??? success "Command output" ```console - #!/usr/bin/env bash + #!/usr/bin/env bash -e -u -o pipefail + printf "%s\n" sample1_R1.fastq.gz sample1_R2.fastq.gz | while read f; + do + seqtk \ + trimfq \ + -b 5 \ + $f \ + | gzip --no-name > SAMPLE1_PE_$(basename $f) + done ... - seqtk trimfq -b 5 SAMPLE3_SE.fastq.gz | gzip -c > SAMPLE3_SE.trimmed.fastq.gz ``` You should see `-b 5` in the `seqtk trimfq` command, confirming your `ext.args` override took effect. From 3fab7180a51d81d29cf74ec6bc3c166caf400b30 Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 15:50:04 +0100 Subject: [PATCH 23/42] ci: run full checks for Nextflow 26.04 bump Co-Authored-By: Claude Opus 4.8 From daa2cdd3a3f5ddb15e31bea67a48057e6502fc60 Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 16:51:11 +0100 Subject: [PATCH 24/42] feat(hello_nf-core): migrate solutions to nf-core 4.0.2 template + nf-schema 2.7.2, v2-clean All 5 solutions run to completion under Nextflow 26.04.4 v2 parser. validate_params handled via config boolean in parts 2-4 (preserves lesson 5's schema-validation exercise); part 5 keeps the greetings schema + validation on. [skip ci] --- .../solutions/core-hello-part2/.nf-core.yml | 2 +- .../core-hello-part2/conf/base.config | 2 +- .../solutions/core-hello-part2/main.nf | 4 +- .../solutions/core-hello-part2/modules.json | 4 +- .../core-hello-part2/nextflow.config | 10 ++- .../local/utils_nfcore_hello_pipeline/main.nf | 4 +- .../nf-core/utils_nfcore_pipeline/main.nf | 66 +------------------ .../utils_nfcore_pipeline/tests/main.nf.test | 29 ++++++++ .../tests/main.nf.test.snap | 19 ++++++ .../nf-core/utils_nfschema_plugin/main.nf | 3 +- .../tests/nextflow.config | 2 +- .../core-hello-part2/workflows/hello.nf | 3 +- .../solutions/core-hello-part3/.nf-core.yml | 2 +- .../core-hello-part3/conf/base.config | 2 +- .../solutions/core-hello-part3/main.nf | 4 +- .../solutions/core-hello-part3/modules.json | 4 +- .../core-hello-part3/nextflow.config | 10 ++- .../local/utils_nfcore_hello_pipeline/main.nf | 4 +- .../nf-core/utils_nfcore_pipeline/main.nf | 66 +------------------ .../utils_nfcore_pipeline/tests/main.nf.test | 29 ++++++++ .../tests/main.nf.test.snap | 19 ++++++ .../nf-core/utils_nfschema_plugin/main.nf | 3 +- .../tests/nextflow.config | 2 +- .../core-hello-part3/workflows/hello.nf | 3 +- .../solutions/core-hello-part4/.nf-core.yml | 2 +- .../core-hello-part4/conf/base.config | 2 +- .../solutions/core-hello-part4/main.nf | 4 +- .../solutions/core-hello-part4/modules.json | 4 +- .../core-hello-part4/nextflow.config | 10 ++- .../local/utils_nfcore_hello_pipeline/main.nf | 4 +- .../nf-core/utils_nfcore_pipeline/main.nf | 66 +------------------ .../utils_nfcore_pipeline/tests/main.nf.test | 29 ++++++++ .../tests/main.nf.test.snap | 19 ++++++ .../nf-core/utils_nfschema_plugin/main.nf | 3 +- .../tests/nextflow.config | 2 +- .../core-hello-part4/workflows/hello.nf | 3 +- .../solutions/core-hello-part5/.nf-core.yml | 2 +- .../core-hello-part5/conf/base.config | 2 +- .../solutions/core-hello-part5/main.nf | 4 +- .../solutions/core-hello-part5/modules.json | 4 +- .../core-hello-part5/nextflow.config | 8 ++- .../local/utils_nfcore_hello_pipeline/main.nf | 4 +- .../nf-core/utils_nfcore_pipeline/main.nf | 66 +------------------ .../utils_nfcore_pipeline/tests/main.nf.test | 29 ++++++++ .../tests/main.nf.test.snap | 19 ++++++ .../nf-core/utils_nfschema_plugin/main.nf | 3 +- .../tests/nextflow.config | 2 +- .../core-hello-part5/workflows/hello.nf | 3 +- .../core-hello-start/conf/base.config | 6 +- .../solutions/core-hello-start/main.nf | 9 ++- .../solutions/core-hello-start/modules.json | 9 +-- .../core-hello-start/nextflow.config | 54 ++++++++++----- .../core-hello-start/nextflow_schema.json | 25 ++++--- .../local/utils_nfcore_hello_pipeline/main.nf | 30 +++++++-- .../nf-core/utils_nfcore_pipeline/main.nf | 66 +------------------ .../utils_nfcore_pipeline/tests/main.nf.test | 29 ++++++++ .../tests/main.nf.test.snap | 19 ++++++ .../nf-core/utils_nfschema_plugin/main.nf | 40 +++++++++-- .../tests/nextflow.config | 2 +- .../core-hello-start/workflows/hello.nf | 15 ++--- 60 files changed, 449 insertions(+), 445 deletions(-) create mode 100644 hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test create mode 100644 hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap create mode 100644 hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test create mode 100644 hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap create mode 100644 hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test create mode 100644 hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap create mode 100644 hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test create mode 100644 hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap create mode 100644 hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test create mode 100644 hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap diff --git a/hello-nf-core/solutions/core-hello-part2/.nf-core.yml b/hello-nf-core/solutions/core-hello-part2/.nf-core.yml index 4b27e1dd63..a17e2d83a5 100644 --- a/hello-nf-core/solutions/core-hello-part2/.nf-core.yml +++ b/hello-nf-core/solutions/core-hello-part2/.nf-core.yml @@ -1,6 +1,6 @@ repository_type: pipeline -nf_core_version: 3.5.2 +nf_core_version: 4.0.2 lint: files_unchanged: diff --git a/hello-nf-core/solutions/core-hello-part2/conf/base.config b/hello-nf-core/solutions/core-hello-part2/conf/base.config index e0fe40762f..d0dfc7d1d1 100644 --- a/hello-nf-core/solutions/core-hello-part2/conf/base.config +++ b/hello-nf-core/solutions/core-hello-part2/conf/base.config @@ -15,7 +15,7 @@ process { memory = { 6.GB * task.attempt } time = { 4.h * task.attempt } - errorStrategy = { task.exitStatus in ((130..145) + 104 + 175) ? 'retry' : 'finish' } + errorStrategy = { task.exitStatus in ((130..145) + 104 + (175..177)) ? 'retry' : 'finish' } maxRetries = 1 maxErrors = '-1' diff --git a/hello-nf-core/solutions/core-hello-part2/main.nf b/hello-nf-core/solutions/core-hello-part2/main.nf index eb8d91361f..4bf5934fc5 100644 --- a/hello-nf-core/solutions/core-hello-part2/main.nf +++ b/hello-nf-core/solutions/core-hello-part2/main.nf @@ -36,7 +36,8 @@ workflow CORE_HELLO { // WORKFLOW: Run pipeline // HELLO ( - samplesheet + samplesheet, + params.outdir, ) } /* @@ -73,7 +74,6 @@ workflow { // SUBWORKFLOW: Run completion tasks // PIPELINE_COMPLETION ( - params.outdir, params.monochrome_logs, ) } diff --git a/hello-nf-core/solutions/core-hello-part2/modules.json b/hello-nf-core/solutions/core-hello-part2/modules.json index 0ef0a5149b..e897cf840e 100644 --- a/hello-nf-core/solutions/core-hello-part2/modules.json +++ b/hello-nf-core/solutions/core-hello-part2/modules.json @@ -15,12 +15,12 @@ }, "utils_nfcore_pipeline": { "branch": "master", - "git_sha": "271e7fc14eb1320364416d996fb077421f3faed2", + "git_sha": "a3fb7351b1fdb2b1de282b765816bbea190e86a8", "installed_by": ["subworkflows"] }, "utils_nfschema_plugin": { "branch": "master", - "git_sha": "4b406a74dc0449c0401ed87d5bfff4252fd277fd", + "git_sha": "fdc08b8b1ae74f56686ce21f7ea11ad11990ce57", "installed_by": ["subworkflows"] } } diff --git a/hello-nf-core/solutions/core-hello-part2/nextflow.config b/hello-nf-core/solutions/core-hello-part2/nextflow.config index c29d19a6df..c8048f3143 100644 --- a/hello-nf-core/solutions/core-hello-part2/nextflow.config +++ b/hello-nf-core/solutions/core-hello-part2/nextflow.config @@ -34,9 +34,13 @@ params { config_profile_url = null // Schema validation default options - validate_params = true + validate_params = false } +// Backwards compatibility for publishDir syntax +outputDir = params.outdir +workflow.output.mode = params.publish_dir_mode + // Load base.config by default for all pipelines includeConfig 'conf/base.config' @@ -234,14 +238,14 @@ manifest { description = """A basic nf-core style version of Hello Nextflow""" mainScript = 'main.nf' defaultBranch = 'master' - nextflowVersion = '!>=25.04.0' + nextflowVersion = '!>=25.10.4' version = '1.0.0dev' doi = '' } // Nextflow plugins plugins { - id 'nf-schema@2.5.1' // Validation of pipeline parameters and creation of an input channel from a sample sheet + id 'nf-schema@2.7.2' // Validation of pipeline parameters and creation of an input channel from a sample sheet } validation { diff --git a/hello-nf-core/solutions/core-hello-part2/subworkflows/local/utils_nfcore_hello_pipeline/main.nf b/hello-nf-core/solutions/core-hello-part2/subworkflows/local/utils_nfcore_hello_pipeline/main.nf index 1be4d08e8d..661797280d 100644 --- a/hello-nf-core/solutions/core-hello-part2/subworkflows/local/utils_nfcore_hello_pipeline/main.nf +++ b/hello-nf-core/solutions/core-hello-part2/subworkflows/local/utils_nfcore_hello_pipeline/main.nf @@ -95,11 +95,9 @@ workflow PIPELINE_INITIALISATION { workflow PIPELINE_COMPLETION { take: - outdir // path: Path to output directory where results will be published monochrome_logs // boolean: Disable ANSI colour codes in log output main: - summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") // // Completion email and summary @@ -110,7 +108,7 @@ workflow PIPELINE_COMPLETION { } workflow.onError { - log.error "Pipeline failed. Please refer to troubleshooting docs: https://nf-co.re/docs/usage/troubleshooting" + log.error "Pipeline failed. Please refer to troubleshooting docs: https://nf-co.re/docs/running/troubleshooting" } } diff --git a/hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfcore_pipeline/main.nf b/hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfcore_pipeline/main.nf index 2f30e9a463..afca543909 100644 --- a/hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfcore_pipeline/main.nf +++ b/hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfcore_pipeline/main.nf @@ -17,7 +17,7 @@ workflow UTILS_NFCORE_PIPELINE { checkProfileProvided(nextflow_cli_args) emit: - valid_config + valid_config = valid_config } /* @@ -353,67 +353,3 @@ def completionSummary(monochrome_logs=true) { log.info("-${colors.purple}[${workflow.manifest.name}]${colors.red} Pipeline completed with errors${colors.reset}-") } } - -// -// Construct and send a notification to a web server as JSON e.g. Microsoft Teams and Slack -// -def imNotification(summary_params, hook_url) { - def summary = [:] - summary_params - .keySet() - .sort() - .each { group -> - summary << summary_params[group] - } - - def misc_fields = [:] - misc_fields['start'] = workflow.start - misc_fields['complete'] = workflow.complete - misc_fields['scriptfile'] = workflow.scriptFile - misc_fields['scriptid'] = workflow.scriptId - if (workflow.repository) { - misc_fields['repository'] = workflow.repository - } - if (workflow.commitId) { - misc_fields['commitid'] = workflow.commitId - } - if (workflow.revision) { - misc_fields['revision'] = workflow.revision - } - misc_fields['nxf_version'] = workflow.nextflow.version - misc_fields['nxf_build'] = workflow.nextflow.build - misc_fields['nxf_timestamp'] = workflow.nextflow.timestamp - - def msg_fields = [:] - msg_fields['version'] = getWorkflowVersion() - msg_fields['runName'] = workflow.runName - msg_fields['success'] = workflow.success - msg_fields['dateComplete'] = workflow.complete - msg_fields['duration'] = workflow.duration - msg_fields['exitStatus'] = workflow.exitStatus - msg_fields['errorMessage'] = (workflow.errorMessage ?: 'None') - msg_fields['errorReport'] = (workflow.errorReport ?: 'None') - msg_fields['commandLine'] = workflow.commandLine.replaceFirst(/ +--hook_url +[^ ]+/, "") - msg_fields['projectDir'] = workflow.projectDir - msg_fields['summary'] = summary << misc_fields - - // Render the JSON template - def engine = new groovy.text.GStringTemplateEngine() - // Different JSON depending on the service provider - // Defaults to "Adaptive Cards" (https://adaptivecards.io), except Slack which has its own format - def json_path = hook_url.contains("hooks.slack.com") ? "slackreport.json" : "adaptivecard.json" - def hf = new File("${workflow.projectDir}/assets/${json_path}") - def json_template = engine.createTemplate(hf).make(msg_fields) - def json_message = json_template.toString() - - // POST - def post = new URL(hook_url).openConnection() - post.setRequestMethod("POST") - post.setDoOutput(true) - post.setRequestProperty("Content-Type", "application/json") - post.getOutputStream().write(json_message.getBytes("UTF-8")) - def postRC = post.getResponseCode() - if (!postRC.equals(200)) { - log.warn(post.getErrorStream().getText()) - } -} diff --git a/hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test b/hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test new file mode 100644 index 0000000000..8940d32d1e --- /dev/null +++ b/hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test @@ -0,0 +1,29 @@ +nextflow_workflow { + + name "Test Workflow UTILS_NFCORE_PIPELINE" + script "../main.nf" + config "subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config" + workflow "UTILS_NFCORE_PIPELINE" + tag "subworkflows" + tag "subworkflows_nfcore" + tag "utils_nfcore_pipeline" + tag "subworkflows/utils_nfcore_pipeline" + + test("Should run without failures") { + + when { + workflow { + """ + input[0] = [] + """ + } + } + + then { + assertAll( + { assert workflow.success }, + { assert snapshot(workflow.out).match() } + ) + } + } +} diff --git a/hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap b/hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap new file mode 100644 index 0000000000..859d1030fb --- /dev/null +++ b/hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap @@ -0,0 +1,19 @@ +{ + "Should run without failures": { + "content": [ + { + "0": [ + true + ], + "valid_config": [ + true + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-28T12:03:25.726491" + } +} \ No newline at end of file diff --git a/hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfschema_plugin/main.nf b/hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfschema_plugin/main.nf index ee4738c8d1..1df8b76fba 100644 --- a/hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfschema_plugin/main.nf +++ b/hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfschema_plugin/main.nf @@ -38,7 +38,7 @@ workflow UTILS_NFSCHEMA_PLUGIN { } log.info paramsHelp( help_options, - params.help instanceof String ? params.help : "", + (params.help instanceof String && params.help != "true") ? params.help : "", ) exit 0 } @@ -71,4 +71,3 @@ workflow UTILS_NFSCHEMA_PLUGIN { emit: dummy_emit = true } - diff --git a/hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config b/hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config index 8d8c73718a..fd71cb8f85 100644 --- a/hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config +++ b/hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config @@ -1,5 +1,5 @@ plugins { - id "nf-schema@2.5.1" + id "nf-schema@2.7.2" } validation { diff --git a/hello-nf-core/solutions/core-hello-part2/workflows/hello.nf b/hello-nf-core/solutions/core-hello-part2/workflows/hello.nf index 5d24486510..3bab6a6dfc 100644 --- a/hello-nf-core/solutions/core-hello-part2/workflows/hello.nf +++ b/hello-nf-core/solutions/core-hello-part2/workflows/hello.nf @@ -20,6 +20,7 @@ workflow HELLO { take: ch_samplesheet // channel: samplesheet read in from --input + outdir main: @@ -60,7 +61,7 @@ workflow HELLO { softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file)) .mix(topic_versions_string) .collectFile( - storeDir: "${params.outdir}/pipeline_info", + storeDir: "${outdir}/pipeline_info", name: 'hello_software_' + 'versions.yml', sort: true, newLine: true diff --git a/hello-nf-core/solutions/core-hello-part3/.nf-core.yml b/hello-nf-core/solutions/core-hello-part3/.nf-core.yml index 4b27e1dd63..a17e2d83a5 100644 --- a/hello-nf-core/solutions/core-hello-part3/.nf-core.yml +++ b/hello-nf-core/solutions/core-hello-part3/.nf-core.yml @@ -1,6 +1,6 @@ repository_type: pipeline -nf_core_version: 3.5.2 +nf_core_version: 4.0.2 lint: files_unchanged: diff --git a/hello-nf-core/solutions/core-hello-part3/conf/base.config b/hello-nf-core/solutions/core-hello-part3/conf/base.config index e0fe40762f..d0dfc7d1d1 100644 --- a/hello-nf-core/solutions/core-hello-part3/conf/base.config +++ b/hello-nf-core/solutions/core-hello-part3/conf/base.config @@ -15,7 +15,7 @@ process { memory = { 6.GB * task.attempt } time = { 4.h * task.attempt } - errorStrategy = { task.exitStatus in ((130..145) + 104 + 175) ? 'retry' : 'finish' } + errorStrategy = { task.exitStatus in ((130..145) + 104 + (175..177)) ? 'retry' : 'finish' } maxRetries = 1 maxErrors = '-1' diff --git a/hello-nf-core/solutions/core-hello-part3/main.nf b/hello-nf-core/solutions/core-hello-part3/main.nf index eb8d91361f..4bf5934fc5 100644 --- a/hello-nf-core/solutions/core-hello-part3/main.nf +++ b/hello-nf-core/solutions/core-hello-part3/main.nf @@ -36,7 +36,8 @@ workflow CORE_HELLO { // WORKFLOW: Run pipeline // HELLO ( - samplesheet + samplesheet, + params.outdir, ) } /* @@ -73,7 +74,6 @@ workflow { // SUBWORKFLOW: Run completion tasks // PIPELINE_COMPLETION ( - params.outdir, params.monochrome_logs, ) } diff --git a/hello-nf-core/solutions/core-hello-part3/modules.json b/hello-nf-core/solutions/core-hello-part3/modules.json index 7f25f2c231..4aa9c3870c 100644 --- a/hello-nf-core/solutions/core-hello-part3/modules.json +++ b/hello-nf-core/solutions/core-hello-part3/modules.json @@ -25,14 +25,14 @@ }, "utils_nfcore_pipeline": { "branch": "master", - "git_sha": "271e7fc14eb1320364416d996fb077421f3faed2", + "git_sha": "a3fb7351b1fdb2b1de282b765816bbea190e86a8", "installed_by": [ "subworkflows" ] }, "utils_nfschema_plugin": { "branch": "master", - "git_sha": "4b406a74dc0449c0401ed87d5bfff4252fd277fd", + "git_sha": "fdc08b8b1ae74f56686ce21f7ea11ad11990ce57", "installed_by": [ "subworkflows" ] diff --git a/hello-nf-core/solutions/core-hello-part3/nextflow.config b/hello-nf-core/solutions/core-hello-part3/nextflow.config index c29d19a6df..c8048f3143 100644 --- a/hello-nf-core/solutions/core-hello-part3/nextflow.config +++ b/hello-nf-core/solutions/core-hello-part3/nextflow.config @@ -34,9 +34,13 @@ params { config_profile_url = null // Schema validation default options - validate_params = true + validate_params = false } +// Backwards compatibility for publishDir syntax +outputDir = params.outdir +workflow.output.mode = params.publish_dir_mode + // Load base.config by default for all pipelines includeConfig 'conf/base.config' @@ -234,14 +238,14 @@ manifest { description = """A basic nf-core style version of Hello Nextflow""" mainScript = 'main.nf' defaultBranch = 'master' - nextflowVersion = '!>=25.04.0' + nextflowVersion = '!>=25.10.4' version = '1.0.0dev' doi = '' } // Nextflow plugins plugins { - id 'nf-schema@2.5.1' // Validation of pipeline parameters and creation of an input channel from a sample sheet + id 'nf-schema@2.7.2' // Validation of pipeline parameters and creation of an input channel from a sample sheet } validation { diff --git a/hello-nf-core/solutions/core-hello-part3/subworkflows/local/utils_nfcore_hello_pipeline/main.nf b/hello-nf-core/solutions/core-hello-part3/subworkflows/local/utils_nfcore_hello_pipeline/main.nf index 1be4d08e8d..661797280d 100644 --- a/hello-nf-core/solutions/core-hello-part3/subworkflows/local/utils_nfcore_hello_pipeline/main.nf +++ b/hello-nf-core/solutions/core-hello-part3/subworkflows/local/utils_nfcore_hello_pipeline/main.nf @@ -95,11 +95,9 @@ workflow PIPELINE_INITIALISATION { workflow PIPELINE_COMPLETION { take: - outdir // path: Path to output directory where results will be published monochrome_logs // boolean: Disable ANSI colour codes in log output main: - summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") // // Completion email and summary @@ -110,7 +108,7 @@ workflow PIPELINE_COMPLETION { } workflow.onError { - log.error "Pipeline failed. Please refer to troubleshooting docs: https://nf-co.re/docs/usage/troubleshooting" + log.error "Pipeline failed. Please refer to troubleshooting docs: https://nf-co.re/docs/running/troubleshooting" } } diff --git a/hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfcore_pipeline/main.nf b/hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfcore_pipeline/main.nf index 2f30e9a463..afca543909 100644 --- a/hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfcore_pipeline/main.nf +++ b/hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfcore_pipeline/main.nf @@ -17,7 +17,7 @@ workflow UTILS_NFCORE_PIPELINE { checkProfileProvided(nextflow_cli_args) emit: - valid_config + valid_config = valid_config } /* @@ -353,67 +353,3 @@ def completionSummary(monochrome_logs=true) { log.info("-${colors.purple}[${workflow.manifest.name}]${colors.red} Pipeline completed with errors${colors.reset}-") } } - -// -// Construct and send a notification to a web server as JSON e.g. Microsoft Teams and Slack -// -def imNotification(summary_params, hook_url) { - def summary = [:] - summary_params - .keySet() - .sort() - .each { group -> - summary << summary_params[group] - } - - def misc_fields = [:] - misc_fields['start'] = workflow.start - misc_fields['complete'] = workflow.complete - misc_fields['scriptfile'] = workflow.scriptFile - misc_fields['scriptid'] = workflow.scriptId - if (workflow.repository) { - misc_fields['repository'] = workflow.repository - } - if (workflow.commitId) { - misc_fields['commitid'] = workflow.commitId - } - if (workflow.revision) { - misc_fields['revision'] = workflow.revision - } - misc_fields['nxf_version'] = workflow.nextflow.version - misc_fields['nxf_build'] = workflow.nextflow.build - misc_fields['nxf_timestamp'] = workflow.nextflow.timestamp - - def msg_fields = [:] - msg_fields['version'] = getWorkflowVersion() - msg_fields['runName'] = workflow.runName - msg_fields['success'] = workflow.success - msg_fields['dateComplete'] = workflow.complete - msg_fields['duration'] = workflow.duration - msg_fields['exitStatus'] = workflow.exitStatus - msg_fields['errorMessage'] = (workflow.errorMessage ?: 'None') - msg_fields['errorReport'] = (workflow.errorReport ?: 'None') - msg_fields['commandLine'] = workflow.commandLine.replaceFirst(/ +--hook_url +[^ ]+/, "") - msg_fields['projectDir'] = workflow.projectDir - msg_fields['summary'] = summary << misc_fields - - // Render the JSON template - def engine = new groovy.text.GStringTemplateEngine() - // Different JSON depending on the service provider - // Defaults to "Adaptive Cards" (https://adaptivecards.io), except Slack which has its own format - def json_path = hook_url.contains("hooks.slack.com") ? "slackreport.json" : "adaptivecard.json" - def hf = new File("${workflow.projectDir}/assets/${json_path}") - def json_template = engine.createTemplate(hf).make(msg_fields) - def json_message = json_template.toString() - - // POST - def post = new URL(hook_url).openConnection() - post.setRequestMethod("POST") - post.setDoOutput(true) - post.setRequestProperty("Content-Type", "application/json") - post.getOutputStream().write(json_message.getBytes("UTF-8")) - def postRC = post.getResponseCode() - if (!postRC.equals(200)) { - log.warn(post.getErrorStream().getText()) - } -} diff --git a/hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test b/hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test new file mode 100644 index 0000000000..8940d32d1e --- /dev/null +++ b/hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test @@ -0,0 +1,29 @@ +nextflow_workflow { + + name "Test Workflow UTILS_NFCORE_PIPELINE" + script "../main.nf" + config "subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config" + workflow "UTILS_NFCORE_PIPELINE" + tag "subworkflows" + tag "subworkflows_nfcore" + tag "utils_nfcore_pipeline" + tag "subworkflows/utils_nfcore_pipeline" + + test("Should run without failures") { + + when { + workflow { + """ + input[0] = [] + """ + } + } + + then { + assertAll( + { assert workflow.success }, + { assert snapshot(workflow.out).match() } + ) + } + } +} diff --git a/hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap b/hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap new file mode 100644 index 0000000000..859d1030fb --- /dev/null +++ b/hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap @@ -0,0 +1,19 @@ +{ + "Should run without failures": { + "content": [ + { + "0": [ + true + ], + "valid_config": [ + true + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-28T12:03:25.726491" + } +} \ No newline at end of file diff --git a/hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfschema_plugin/main.nf b/hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfschema_plugin/main.nf index ee4738c8d1..1df8b76fba 100644 --- a/hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfschema_plugin/main.nf +++ b/hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfschema_plugin/main.nf @@ -38,7 +38,7 @@ workflow UTILS_NFSCHEMA_PLUGIN { } log.info paramsHelp( help_options, - params.help instanceof String ? params.help : "", + (params.help instanceof String && params.help != "true") ? params.help : "", ) exit 0 } @@ -71,4 +71,3 @@ workflow UTILS_NFSCHEMA_PLUGIN { emit: dummy_emit = true } - diff --git a/hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config b/hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config index 8d8c73718a..fd71cb8f85 100644 --- a/hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config +++ b/hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config @@ -1,5 +1,5 @@ plugins { - id "nf-schema@2.5.1" + id "nf-schema@2.7.2" } validation { diff --git a/hello-nf-core/solutions/core-hello-part3/workflows/hello.nf b/hello-nf-core/solutions/core-hello-part3/workflows/hello.nf index 4d7541491f..e8d4229e8c 100644 --- a/hello-nf-core/solutions/core-hello-part3/workflows/hello.nf +++ b/hello-nf-core/solutions/core-hello-part3/workflows/hello.nf @@ -20,6 +20,7 @@ workflow HELLO { take: ch_samplesheet // channel: samplesheet read in from --input + outdir main: @@ -69,7 +70,7 @@ workflow HELLO { softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file)) .mix(topic_versions_string) .collectFile( - storeDir: "${params.outdir}/pipeline_info", + storeDir: "${outdir}/pipeline_info", name: 'hello_software_' + 'versions.yml', sort: true, newLine: true diff --git a/hello-nf-core/solutions/core-hello-part4/.nf-core.yml b/hello-nf-core/solutions/core-hello-part4/.nf-core.yml index 4b27e1dd63..a17e2d83a5 100644 --- a/hello-nf-core/solutions/core-hello-part4/.nf-core.yml +++ b/hello-nf-core/solutions/core-hello-part4/.nf-core.yml @@ -1,6 +1,6 @@ repository_type: pipeline -nf_core_version: 3.5.2 +nf_core_version: 4.0.2 lint: files_unchanged: diff --git a/hello-nf-core/solutions/core-hello-part4/conf/base.config b/hello-nf-core/solutions/core-hello-part4/conf/base.config index e0fe40762f..d0dfc7d1d1 100644 --- a/hello-nf-core/solutions/core-hello-part4/conf/base.config +++ b/hello-nf-core/solutions/core-hello-part4/conf/base.config @@ -15,7 +15,7 @@ process { memory = { 6.GB * task.attempt } time = { 4.h * task.attempt } - errorStrategy = { task.exitStatus in ((130..145) + 104 + 175) ? 'retry' : 'finish' } + errorStrategy = { task.exitStatus in ((130..145) + 104 + (175..177)) ? 'retry' : 'finish' } maxRetries = 1 maxErrors = '-1' diff --git a/hello-nf-core/solutions/core-hello-part4/main.nf b/hello-nf-core/solutions/core-hello-part4/main.nf index eb8d91361f..4bf5934fc5 100644 --- a/hello-nf-core/solutions/core-hello-part4/main.nf +++ b/hello-nf-core/solutions/core-hello-part4/main.nf @@ -36,7 +36,8 @@ workflow CORE_HELLO { // WORKFLOW: Run pipeline // HELLO ( - samplesheet + samplesheet, + params.outdir, ) } /* @@ -73,7 +74,6 @@ workflow { // SUBWORKFLOW: Run completion tasks // PIPELINE_COMPLETION ( - params.outdir, params.monochrome_logs, ) } diff --git a/hello-nf-core/solutions/core-hello-part4/modules.json b/hello-nf-core/solutions/core-hello-part4/modules.json index 7f25f2c231..4aa9c3870c 100644 --- a/hello-nf-core/solutions/core-hello-part4/modules.json +++ b/hello-nf-core/solutions/core-hello-part4/modules.json @@ -25,14 +25,14 @@ }, "utils_nfcore_pipeline": { "branch": "master", - "git_sha": "271e7fc14eb1320364416d996fb077421f3faed2", + "git_sha": "a3fb7351b1fdb2b1de282b765816bbea190e86a8", "installed_by": [ "subworkflows" ] }, "utils_nfschema_plugin": { "branch": "master", - "git_sha": "4b406a74dc0449c0401ed87d5bfff4252fd277fd", + "git_sha": "fdc08b8b1ae74f56686ce21f7ea11ad11990ce57", "installed_by": [ "subworkflows" ] diff --git a/hello-nf-core/solutions/core-hello-part4/nextflow.config b/hello-nf-core/solutions/core-hello-part4/nextflow.config index c29d19a6df..c8048f3143 100644 --- a/hello-nf-core/solutions/core-hello-part4/nextflow.config +++ b/hello-nf-core/solutions/core-hello-part4/nextflow.config @@ -34,9 +34,13 @@ params { config_profile_url = null // Schema validation default options - validate_params = true + validate_params = false } +// Backwards compatibility for publishDir syntax +outputDir = params.outdir +workflow.output.mode = params.publish_dir_mode + // Load base.config by default for all pipelines includeConfig 'conf/base.config' @@ -234,14 +238,14 @@ manifest { description = """A basic nf-core style version of Hello Nextflow""" mainScript = 'main.nf' defaultBranch = 'master' - nextflowVersion = '!>=25.04.0' + nextflowVersion = '!>=25.10.4' version = '1.0.0dev' doi = '' } // Nextflow plugins plugins { - id 'nf-schema@2.5.1' // Validation of pipeline parameters and creation of an input channel from a sample sheet + id 'nf-schema@2.7.2' // Validation of pipeline parameters and creation of an input channel from a sample sheet } validation { diff --git a/hello-nf-core/solutions/core-hello-part4/subworkflows/local/utils_nfcore_hello_pipeline/main.nf b/hello-nf-core/solutions/core-hello-part4/subworkflows/local/utils_nfcore_hello_pipeline/main.nf index 1be4d08e8d..661797280d 100644 --- a/hello-nf-core/solutions/core-hello-part4/subworkflows/local/utils_nfcore_hello_pipeline/main.nf +++ b/hello-nf-core/solutions/core-hello-part4/subworkflows/local/utils_nfcore_hello_pipeline/main.nf @@ -95,11 +95,9 @@ workflow PIPELINE_INITIALISATION { workflow PIPELINE_COMPLETION { take: - outdir // path: Path to output directory where results will be published monochrome_logs // boolean: Disable ANSI colour codes in log output main: - summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") // // Completion email and summary @@ -110,7 +108,7 @@ workflow PIPELINE_COMPLETION { } workflow.onError { - log.error "Pipeline failed. Please refer to troubleshooting docs: https://nf-co.re/docs/usage/troubleshooting" + log.error "Pipeline failed. Please refer to troubleshooting docs: https://nf-co.re/docs/running/troubleshooting" } } diff --git a/hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfcore_pipeline/main.nf b/hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfcore_pipeline/main.nf index 2f30e9a463..afca543909 100644 --- a/hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfcore_pipeline/main.nf +++ b/hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfcore_pipeline/main.nf @@ -17,7 +17,7 @@ workflow UTILS_NFCORE_PIPELINE { checkProfileProvided(nextflow_cli_args) emit: - valid_config + valid_config = valid_config } /* @@ -353,67 +353,3 @@ def completionSummary(monochrome_logs=true) { log.info("-${colors.purple}[${workflow.manifest.name}]${colors.red} Pipeline completed with errors${colors.reset}-") } } - -// -// Construct and send a notification to a web server as JSON e.g. Microsoft Teams and Slack -// -def imNotification(summary_params, hook_url) { - def summary = [:] - summary_params - .keySet() - .sort() - .each { group -> - summary << summary_params[group] - } - - def misc_fields = [:] - misc_fields['start'] = workflow.start - misc_fields['complete'] = workflow.complete - misc_fields['scriptfile'] = workflow.scriptFile - misc_fields['scriptid'] = workflow.scriptId - if (workflow.repository) { - misc_fields['repository'] = workflow.repository - } - if (workflow.commitId) { - misc_fields['commitid'] = workflow.commitId - } - if (workflow.revision) { - misc_fields['revision'] = workflow.revision - } - misc_fields['nxf_version'] = workflow.nextflow.version - misc_fields['nxf_build'] = workflow.nextflow.build - misc_fields['nxf_timestamp'] = workflow.nextflow.timestamp - - def msg_fields = [:] - msg_fields['version'] = getWorkflowVersion() - msg_fields['runName'] = workflow.runName - msg_fields['success'] = workflow.success - msg_fields['dateComplete'] = workflow.complete - msg_fields['duration'] = workflow.duration - msg_fields['exitStatus'] = workflow.exitStatus - msg_fields['errorMessage'] = (workflow.errorMessage ?: 'None') - msg_fields['errorReport'] = (workflow.errorReport ?: 'None') - msg_fields['commandLine'] = workflow.commandLine.replaceFirst(/ +--hook_url +[^ ]+/, "") - msg_fields['projectDir'] = workflow.projectDir - msg_fields['summary'] = summary << misc_fields - - // Render the JSON template - def engine = new groovy.text.GStringTemplateEngine() - // Different JSON depending on the service provider - // Defaults to "Adaptive Cards" (https://adaptivecards.io), except Slack which has its own format - def json_path = hook_url.contains("hooks.slack.com") ? "slackreport.json" : "adaptivecard.json" - def hf = new File("${workflow.projectDir}/assets/${json_path}") - def json_template = engine.createTemplate(hf).make(msg_fields) - def json_message = json_template.toString() - - // POST - def post = new URL(hook_url).openConnection() - post.setRequestMethod("POST") - post.setDoOutput(true) - post.setRequestProperty("Content-Type", "application/json") - post.getOutputStream().write(json_message.getBytes("UTF-8")) - def postRC = post.getResponseCode() - if (!postRC.equals(200)) { - log.warn(post.getErrorStream().getText()) - } -} diff --git a/hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test b/hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test new file mode 100644 index 0000000000..8940d32d1e --- /dev/null +++ b/hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test @@ -0,0 +1,29 @@ +nextflow_workflow { + + name "Test Workflow UTILS_NFCORE_PIPELINE" + script "../main.nf" + config "subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config" + workflow "UTILS_NFCORE_PIPELINE" + tag "subworkflows" + tag "subworkflows_nfcore" + tag "utils_nfcore_pipeline" + tag "subworkflows/utils_nfcore_pipeline" + + test("Should run without failures") { + + when { + workflow { + """ + input[0] = [] + """ + } + } + + then { + assertAll( + { assert workflow.success }, + { assert snapshot(workflow.out).match() } + ) + } + } +} diff --git a/hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap b/hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap new file mode 100644 index 0000000000..859d1030fb --- /dev/null +++ b/hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap @@ -0,0 +1,19 @@ +{ + "Should run without failures": { + "content": [ + { + "0": [ + true + ], + "valid_config": [ + true + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-28T12:03:25.726491" + } +} \ No newline at end of file diff --git a/hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfschema_plugin/main.nf b/hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfschema_plugin/main.nf index ee4738c8d1..1df8b76fba 100644 --- a/hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfschema_plugin/main.nf +++ b/hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfschema_plugin/main.nf @@ -38,7 +38,7 @@ workflow UTILS_NFSCHEMA_PLUGIN { } log.info paramsHelp( help_options, - params.help instanceof String ? params.help : "", + (params.help instanceof String && params.help != "true") ? params.help : "", ) exit 0 } @@ -71,4 +71,3 @@ workflow UTILS_NFSCHEMA_PLUGIN { emit: dummy_emit = true } - diff --git a/hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config b/hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config index 8d8c73718a..fd71cb8f85 100644 --- a/hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config +++ b/hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config @@ -1,5 +1,5 @@ plugins { - id "nf-schema@2.5.1" + id "nf-schema@2.7.2" } validation { diff --git a/hello-nf-core/solutions/core-hello-part4/workflows/hello.nf b/hello-nf-core/solutions/core-hello-part4/workflows/hello.nf index 073d36235e..fdd8f4084c 100644 --- a/hello-nf-core/solutions/core-hello-part4/workflows/hello.nf +++ b/hello-nf-core/solutions/core-hello-part4/workflows/hello.nf @@ -20,6 +20,7 @@ workflow HELLO { take: ch_samplesheet // channel: samplesheet read in from --input + outdir main: @@ -66,7 +67,7 @@ workflow HELLO { softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file)) .mix(topic_versions_string) .collectFile( - storeDir: "${params.outdir}/pipeline_info", + storeDir: "${outdir}/pipeline_info", name: 'hello_software_' + 'versions.yml', sort: true, newLine: true diff --git a/hello-nf-core/solutions/core-hello-part5/.nf-core.yml b/hello-nf-core/solutions/core-hello-part5/.nf-core.yml index 4b27e1dd63..a17e2d83a5 100644 --- a/hello-nf-core/solutions/core-hello-part5/.nf-core.yml +++ b/hello-nf-core/solutions/core-hello-part5/.nf-core.yml @@ -1,6 +1,6 @@ repository_type: pipeline -nf_core_version: 3.5.2 +nf_core_version: 4.0.2 lint: files_unchanged: diff --git a/hello-nf-core/solutions/core-hello-part5/conf/base.config b/hello-nf-core/solutions/core-hello-part5/conf/base.config index e0fe40762f..d0dfc7d1d1 100644 --- a/hello-nf-core/solutions/core-hello-part5/conf/base.config +++ b/hello-nf-core/solutions/core-hello-part5/conf/base.config @@ -15,7 +15,7 @@ process { memory = { 6.GB * task.attempt } time = { 4.h * task.attempt } - errorStrategy = { task.exitStatus in ((130..145) + 104 + 175) ? 'retry' : 'finish' } + errorStrategy = { task.exitStatus in ((130..145) + 104 + (175..177)) ? 'retry' : 'finish' } maxRetries = 1 maxErrors = '-1' diff --git a/hello-nf-core/solutions/core-hello-part5/main.nf b/hello-nf-core/solutions/core-hello-part5/main.nf index eb8d91361f..4bf5934fc5 100644 --- a/hello-nf-core/solutions/core-hello-part5/main.nf +++ b/hello-nf-core/solutions/core-hello-part5/main.nf @@ -36,7 +36,8 @@ workflow CORE_HELLO { // WORKFLOW: Run pipeline // HELLO ( - samplesheet + samplesheet, + params.outdir, ) } /* @@ -73,7 +74,6 @@ workflow { // SUBWORKFLOW: Run completion tasks // PIPELINE_COMPLETION ( - params.outdir, params.monochrome_logs, ) } diff --git a/hello-nf-core/solutions/core-hello-part5/modules.json b/hello-nf-core/solutions/core-hello-part5/modules.json index 6b6a752e3c..34389d9fe0 100644 --- a/hello-nf-core/solutions/core-hello-part5/modules.json +++ b/hello-nf-core/solutions/core-hello-part5/modules.json @@ -21,12 +21,12 @@ }, "utils_nfcore_pipeline": { "branch": "master", - "git_sha": "271e7fc14eb1320364416d996fb077421f3faed2", + "git_sha": "a3fb7351b1fdb2b1de282b765816bbea190e86a8", "installed_by": ["subworkflows"] }, "utils_nfschema_plugin": { "branch": "master", - "git_sha": "4b406a74dc0449c0401ed87d5bfff4252fd277fd", + "git_sha": "fdc08b8b1ae74f56686ce21f7ea11ad11990ce57", "installed_by": ["subworkflows"] } } diff --git a/hello-nf-core/solutions/core-hello-part5/nextflow.config b/hello-nf-core/solutions/core-hello-part5/nextflow.config index c29d19a6df..88e6f1bc97 100644 --- a/hello-nf-core/solutions/core-hello-part5/nextflow.config +++ b/hello-nf-core/solutions/core-hello-part5/nextflow.config @@ -37,6 +37,10 @@ params { validate_params = true } +// Backwards compatibility for publishDir syntax +outputDir = params.outdir +workflow.output.mode = params.publish_dir_mode + // Load base.config by default for all pipelines includeConfig 'conf/base.config' @@ -234,14 +238,14 @@ manifest { description = """A basic nf-core style version of Hello Nextflow""" mainScript = 'main.nf' defaultBranch = 'master' - nextflowVersion = '!>=25.04.0' + nextflowVersion = '!>=25.10.4' version = '1.0.0dev' doi = '' } // Nextflow plugins plugins { - id 'nf-schema@2.5.1' // Validation of pipeline parameters and creation of an input channel from a sample sheet + id 'nf-schema@2.7.2' // Validation of pipeline parameters and creation of an input channel from a sample sheet } validation { diff --git a/hello-nf-core/solutions/core-hello-part5/subworkflows/local/utils_nfcore_hello_pipeline/main.nf b/hello-nf-core/solutions/core-hello-part5/subworkflows/local/utils_nfcore_hello_pipeline/main.nf index 07015a6615..a2252e16d4 100644 --- a/hello-nf-core/solutions/core-hello-part5/subworkflows/local/utils_nfcore_hello_pipeline/main.nf +++ b/hello-nf-core/solutions/core-hello-part5/subworkflows/local/utils_nfcore_hello_pipeline/main.nf @@ -94,11 +94,9 @@ workflow PIPELINE_INITIALISATION { workflow PIPELINE_COMPLETION { take: - outdir // path: Path to output directory where results will be published monochrome_logs // boolean: Disable ANSI colour codes in log output main: - summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") // // Completion email and summary @@ -109,7 +107,7 @@ workflow PIPELINE_COMPLETION { } workflow.onError { - log.error "Pipeline failed. Please refer to troubleshooting docs: https://nf-co.re/docs/usage/troubleshooting" + log.error "Pipeline failed. Please refer to troubleshooting docs: https://nf-co.re/docs/running/troubleshooting" } } diff --git a/hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfcore_pipeline/main.nf b/hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfcore_pipeline/main.nf index 2f30e9a463..afca543909 100644 --- a/hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfcore_pipeline/main.nf +++ b/hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfcore_pipeline/main.nf @@ -17,7 +17,7 @@ workflow UTILS_NFCORE_PIPELINE { checkProfileProvided(nextflow_cli_args) emit: - valid_config + valid_config = valid_config } /* @@ -353,67 +353,3 @@ def completionSummary(monochrome_logs=true) { log.info("-${colors.purple}[${workflow.manifest.name}]${colors.red} Pipeline completed with errors${colors.reset}-") } } - -// -// Construct and send a notification to a web server as JSON e.g. Microsoft Teams and Slack -// -def imNotification(summary_params, hook_url) { - def summary = [:] - summary_params - .keySet() - .sort() - .each { group -> - summary << summary_params[group] - } - - def misc_fields = [:] - misc_fields['start'] = workflow.start - misc_fields['complete'] = workflow.complete - misc_fields['scriptfile'] = workflow.scriptFile - misc_fields['scriptid'] = workflow.scriptId - if (workflow.repository) { - misc_fields['repository'] = workflow.repository - } - if (workflow.commitId) { - misc_fields['commitid'] = workflow.commitId - } - if (workflow.revision) { - misc_fields['revision'] = workflow.revision - } - misc_fields['nxf_version'] = workflow.nextflow.version - misc_fields['nxf_build'] = workflow.nextflow.build - misc_fields['nxf_timestamp'] = workflow.nextflow.timestamp - - def msg_fields = [:] - msg_fields['version'] = getWorkflowVersion() - msg_fields['runName'] = workflow.runName - msg_fields['success'] = workflow.success - msg_fields['dateComplete'] = workflow.complete - msg_fields['duration'] = workflow.duration - msg_fields['exitStatus'] = workflow.exitStatus - msg_fields['errorMessage'] = (workflow.errorMessage ?: 'None') - msg_fields['errorReport'] = (workflow.errorReport ?: 'None') - msg_fields['commandLine'] = workflow.commandLine.replaceFirst(/ +--hook_url +[^ ]+/, "") - msg_fields['projectDir'] = workflow.projectDir - msg_fields['summary'] = summary << misc_fields - - // Render the JSON template - def engine = new groovy.text.GStringTemplateEngine() - // Different JSON depending on the service provider - // Defaults to "Adaptive Cards" (https://adaptivecards.io), except Slack which has its own format - def json_path = hook_url.contains("hooks.slack.com") ? "slackreport.json" : "adaptivecard.json" - def hf = new File("${workflow.projectDir}/assets/${json_path}") - def json_template = engine.createTemplate(hf).make(msg_fields) - def json_message = json_template.toString() - - // POST - def post = new URL(hook_url).openConnection() - post.setRequestMethod("POST") - post.setDoOutput(true) - post.setRequestProperty("Content-Type", "application/json") - post.getOutputStream().write(json_message.getBytes("UTF-8")) - def postRC = post.getResponseCode() - if (!postRC.equals(200)) { - log.warn(post.getErrorStream().getText()) - } -} diff --git a/hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test b/hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test new file mode 100644 index 0000000000..8940d32d1e --- /dev/null +++ b/hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test @@ -0,0 +1,29 @@ +nextflow_workflow { + + name "Test Workflow UTILS_NFCORE_PIPELINE" + script "../main.nf" + config "subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config" + workflow "UTILS_NFCORE_PIPELINE" + tag "subworkflows" + tag "subworkflows_nfcore" + tag "utils_nfcore_pipeline" + tag "subworkflows/utils_nfcore_pipeline" + + test("Should run without failures") { + + when { + workflow { + """ + input[0] = [] + """ + } + } + + then { + assertAll( + { assert workflow.success }, + { assert snapshot(workflow.out).match() } + ) + } + } +} diff --git a/hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap b/hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap new file mode 100644 index 0000000000..859d1030fb --- /dev/null +++ b/hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap @@ -0,0 +1,19 @@ +{ + "Should run without failures": { + "content": [ + { + "0": [ + true + ], + "valid_config": [ + true + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-28T12:03:25.726491" + } +} \ No newline at end of file diff --git a/hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfschema_plugin/main.nf b/hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfschema_plugin/main.nf index ee4738c8d1..1df8b76fba 100644 --- a/hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfschema_plugin/main.nf +++ b/hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfschema_plugin/main.nf @@ -38,7 +38,7 @@ workflow UTILS_NFSCHEMA_PLUGIN { } log.info paramsHelp( help_options, - params.help instanceof String ? params.help : "", + (params.help instanceof String && params.help != "true") ? params.help : "", ) exit 0 } @@ -71,4 +71,3 @@ workflow UTILS_NFSCHEMA_PLUGIN { emit: dummy_emit = true } - diff --git a/hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config b/hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config index 8d8c73718a..fd71cb8f85 100644 --- a/hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config +++ b/hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config @@ -1,5 +1,5 @@ plugins { - id "nf-schema@2.5.1" + id "nf-schema@2.7.2" } validation { diff --git a/hello-nf-core/solutions/core-hello-part5/workflows/hello.nf b/hello-nf-core/solutions/core-hello-part5/workflows/hello.nf index 073d36235e..fdd8f4084c 100644 --- a/hello-nf-core/solutions/core-hello-part5/workflows/hello.nf +++ b/hello-nf-core/solutions/core-hello-part5/workflows/hello.nf @@ -20,6 +20,7 @@ workflow HELLO { take: ch_samplesheet // channel: samplesheet read in from --input + outdir main: @@ -66,7 +67,7 @@ workflow HELLO { softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file)) .mix(topic_versions_string) .collectFile( - storeDir: "${params.outdir}/pipeline_info", + storeDir: "${outdir}/pipeline_info", name: 'hello_software_' + 'versions.yml', sort: true, newLine: true diff --git a/hello-nf-core/solutions/core-hello-start/conf/base.config b/hello-nf-core/solutions/core-hello-start/conf/base.config index 1abcd9876f..d0dfc7d1d1 100644 --- a/hello-nf-core/solutions/core-hello-start/conf/base.config +++ b/hello-nf-core/solutions/core-hello-start/conf/base.config @@ -15,7 +15,7 @@ process { memory = { 6.GB * task.attempt } time = { 4.h * task.attempt } - errorStrategy = { task.exitStatus in ((130..145) + 104) ? 'retry' : 'finish' } + errorStrategy = { task.exitStatus in ((130..145) + 104 + (175..177)) ? 'retry' : 'finish' } maxRetries = 1 maxErrors = '-1' @@ -59,4 +59,8 @@ process { errorStrategy = 'retry' maxRetries = 2 } + withLabel: process_gpu { + ext.use_gpu = { workflow.profile.contains('gpu') } + accelerator = { workflow.profile.contains('gpu') ? 1 : null } + } } diff --git a/hello-nf-core/solutions/core-hello-start/main.nf b/hello-nf-core/solutions/core-hello-start/main.nf index f72a236660..4bf5934fc5 100644 --- a/hello-nf-core/solutions/core-hello-start/main.nf +++ b/hello-nf-core/solutions/core-hello-start/main.nf @@ -36,7 +36,8 @@ workflow CORE_HELLO { // WORKFLOW: Run pipeline // HELLO ( - samplesheet + samplesheet, + params.outdir, ) } /* @@ -57,7 +58,10 @@ workflow { params.monochrome_logs, args, params.outdir, - params.input + params.input, + params.help, + params.help_full, + params.show_hidden ) // @@ -70,7 +74,6 @@ workflow { // SUBWORKFLOW: Run completion tasks // PIPELINE_COMPLETION ( - params.outdir, params.monochrome_logs, ) } diff --git a/hello-nf-core/solutions/core-hello-start/modules.json b/hello-nf-core/solutions/core-hello-start/modules.json index e36947ce00..2c85357275 100644 --- a/hello-nf-core/solutions/core-hello-start/modules.json +++ b/hello-nf-core/solutions/core-hello-start/modules.json @@ -4,23 +4,24 @@ "repos": { "https://github.com/nf-core/modules.git": { "modules": { - "nf-core": {} + "nf-core": { + } }, "subworkflows": { "nf-core": { "utils_nextflow_pipeline": { "branch": "master", - "git_sha": "c2b22d85f30a706a3073387f30380704fcae013b", + "git_sha": "05954dab2ff481bcb999f24455da29a5828af08d", "installed_by": ["subworkflows"] }, "utils_nfcore_pipeline": { "branch": "master", - "git_sha": "51ae5406a030d4da1e49e4dab49756844fdd6c7a", + "git_sha": "a3fb7351b1fdb2b1de282b765816bbea190e86a8", "installed_by": ["subworkflows"] }, "utils_nfschema_plugin": { "branch": "master", - "git_sha": "2fd2cd6d0e7b273747f32e465fdc6bcc3ae0814e", + "git_sha": "fdc08b8b1ae74f56686ce21f7ea11ad11990ce57", "installed_by": ["subworkflows"] } } diff --git a/hello-nf-core/solutions/core-hello-start/nextflow.config b/hello-nf-core/solutions/core-hello-start/nextflow.config index d633adb989..08e1e1670f 100644 --- a/hello-nf-core/solutions/core-hello-start/nextflow.config +++ b/hello-nf-core/solutions/core-hello-start/nextflow.config @@ -22,7 +22,9 @@ params { show_hidden = false version = false pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/' - trace_report_suffix = new java.util.Date().format( 'yyyy-MM-dd_HH-mm-ss')// Config options + trace_report_suffix = new java.util.Date().format( 'yyyy-MM-dd_HH-mm-ss') + + // Config options config_profile_name = null config_profile_description = null @@ -35,6 +37,10 @@ params { validate_params = true } +// Backwards compatibility for publishDir syntax +outputDir = params.outdir +workflow.output.mode = params.publish_dir_mode + // Load base.config by default for all pipelines includeConfig 'conf/base.config' @@ -75,7 +81,18 @@ profiles { apptainer.enabled = false docker.runOptions = '-u $(id -u):$(id -g)' } - arm { + arm64 { + process.arch = 'arm64' + // TODO https://github.com/nf-core/modules/issues/6694 + // For now if you're using arm64 you have to use wave for the sake of the maintainers + // wave profile + apptainer.ociAutoPull = true + singularity.ociAutoPull = true + wave.enabled = true + wave.freeze = true + wave.strategy = 'conda,container' + } + emulate_amd64 { docker.runOptions = '-u $(id -u):$(id -g) --platform=linux/amd64' } singularity { @@ -132,16 +149,25 @@ profiles { wave.freeze = true wave.strategy = 'conda,container' } + gpu { + docker.runOptions = '-u $(id -u):$(id -g) --gpus all' + apptainer.runOptions = '--nv' + singularity.runOptions = '--nv' + } test { includeConfig 'conf/test.config' } test_full { includeConfig 'conf/test_full.config' } } -// Load nf-core custom profiles from different Institutions -includeConfig !System.getenv('NXF_OFFLINE') && params.custom_config_base ? "${params.custom_config_base}/nfcore_custom.config" : "/dev/null" +// Load nf-core custom profiles from different institutions + +// If params.custom_config_base is set AND either the NXF_OFFLINE environment variable is not set or params.custom_config_base is a local path, the nfcore_custom.config file from the specified base path is included. +// Load core/hello custom profiles from different institutions. +includeConfig params.custom_config_base && (!System.getenv('NXF_OFFLINE') || !params.custom_config_base.startsWith('http')) ? "${params.custom_config_base}/nfcore_custom.config" : "/dev/null" + // Load core/hello custom profiles from different institutions. // TODO nf-core: Optionally, you can add a pipeline-specific nf-core config at https://github.com/nf-core/configs -// includeConfig !System.getenv('NXF_OFFLINE') && params.custom_config_base ? "${params.custom_config_base}/pipeline/hello.config" : "/dev/null" +// includeConfig params.custom_config_base && (!System.getenv('NXF_OFFLINE') || !params.custom_config_base.startsWith('http')) ? "${params.custom_config_base}/pipeline/hello.config" : "/dev/null" // Set default registry for Apptainer, Docker, Podman, Charliecloud and Singularity independent of -profile // Will not be used unless Apptainer / Docker / Podman / Charliecloud / Singularity are enabled @@ -197,11 +223,10 @@ dag { manifest { name = 'core/hello' - author = """GG""" // The author field is deprecated from Nextflow version 24.10.0, use contributors instead contributors = [ // TODO nf-core: Update the field with the details of the contributors to your pipeline. New with Nextflow version 24.10.0 [ - name: 'GG', + name: 'your-name', affiliation: '', email: '', github: '', @@ -210,29 +235,22 @@ manifest { ], ] homePage = 'https://github.com/core/hello' - description = """basic nf-core style version of Hello Nextflow""" + description = """A basic nf-core style version of Hello Nextflow""" mainScript = 'main.nf' - defaultBranch = 'main' - nextflowVersion = '!>=24.04.2' + defaultBranch = 'master' + nextflowVersion = '!>=25.10.4' version = '1.0.0dev' doi = '' } // Nextflow plugins plugins { - id 'nf-schema@2.2.0' // Validation of pipeline parameters and creation of an input channel from a sample sheet + id 'nf-schema@2.7.2' // Validation of pipeline parameters and creation of an input channel from a sample sheet } validation { defaultIgnoreParams = ["genomes"] monochromeLogs = params.monochrome_logs - help { - enabled = true - command = "nextflow run core/hello -profile --input samplesheet.csv --outdir " - fullParameter = "help_full" - showHiddenParameter = "show_hidden" - } } - // Load modules.config for DSL2 module specific options includeConfig 'conf/modules.config' diff --git a/hello-nf-core/solutions/core-hello-start/nextflow_schema.json b/hello-nf-core/solutions/core-hello-start/nextflow_schema.json index 5ee5ec357f..dcc4cdf462 100644 --- a/hello-nf-core/solutions/core-hello-start/nextflow_schema.json +++ b/hello-nf-core/solutions/core-hello-start/nextflow_schema.json @@ -1,8 +1,8 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://raw.githubusercontent.com/core/hello/main/nextflow_schema.json", + "$id": "https://raw.githubusercontent.com/core/hello/master/nextflow_schema.json", "title": "core/hello pipeline parameters", - "description": "basic nf-core style version of Hello Nextflow", + "description": "A basic nf-core style version of Hello Nextflow", "type": "object", "$defs": { "input_output_options": { @@ -98,14 +98,7 @@ "description": "Method used to save pipeline results to output directory.", "help_text": "The Nextflow `publishDir` option specifies which intermediate files should be saved to the output directory. This option tells the pipeline what method should be used to move these files. See [Nextflow docs](https://www.nextflow.io/docs/latest/process.html#publishdir) for details.", "fa_icon": "fas fa-copy", - "enum": [ - "symlink", - "rellink", - "link", - "copy", - "copyNoFollow", - "move" - ], + "enum": ["symlink", "rellink", "link", "copy", "copyNoFollow", "move"], "hidden": true }, "monochrome_logs": { @@ -133,6 +126,18 @@ "fa_icon": "far calendar", "description": "Suffix to add to the trace report filename. Default is the date and time in the format yyyy-MM-dd_HH-mm-ss.", "hidden": true + }, + "help": { + "type": ["boolean", "string"], + "description": "Display the help message." + }, + "help_full": { + "type": "boolean", + "description": "Display the full detailed help message." + }, + "show_hidden": { + "type": "boolean", + "description": "Display hidden parameters in the help message (only works when --help or --help_full are provided)." } } } diff --git a/hello-nf-core/solutions/core-hello-start/subworkflows/local/utils_nfcore_hello_pipeline/main.nf b/hello-nf-core/solutions/core-hello-start/subworkflows/local/utils_nfcore_hello_pipeline/main.nf index b4aafb69bb..c65866b8a8 100644 --- a/hello-nf-core/solutions/core-hello-start/subworkflows/local/utils_nfcore_hello_pipeline/main.nf +++ b/hello-nf-core/solutions/core-hello-start/subworkflows/local/utils_nfcore_hello_pipeline/main.nf @@ -11,6 +11,7 @@ include { UTILS_NFSCHEMA_PLUGIN } from '../../nf-core/utils_nfschema_plugin' include { paramsSummaryMap } from 'plugin/nf-schema' include { samplesheetToList } from 'plugin/nf-schema' +include { paramsHelp } from 'plugin/nf-schema' include { completionSummary } from '../../nf-core/utils_nfcore_pipeline' include { UTILS_NFCORE_PIPELINE } from '../../nf-core/utils_nfcore_pipeline' include { UTILS_NEXTFLOW_PIPELINE } from '../../nf-core/utils_nextflow_pipeline' @@ -30,6 +31,9 @@ workflow PIPELINE_INITIALISATION { nextflow_cli_args // array: List of positional nextflow CLI args outdir // string: The output directory where the results will be saved input // string: Path to input samplesheet + help // boolean: Display help message and exit + help_full // boolean: Show the full help message + show_hidden // boolean: Show hidden parameters in the help message main: @@ -48,10 +52,25 @@ workflow PIPELINE_INITIALISATION { // // Validate parameters and generate parameter summary to stdout // + + def before_text = "" + def after_text = "" + if (monochrome_logs) { + before_text = before_text.replaceAll(/\033\[[0-9;]*m/, '') + } + + command = "nextflow run ${workflow.manifest.name} -profile --input samplesheet.csv --outdir " + UTILS_NFSCHEMA_PLUGIN ( workflow, validate_params, - null + null, + help, + help_full, + show_hidden, + before_text, + after_text, + command ) // @@ -65,8 +84,8 @@ workflow PIPELINE_INITIALISATION { // Create channel from input file provided through params.input // - Channel - .fromList(samplesheetToList(params.input, "${projectDir}/assets/schema_input.json")) + channel + .fromList(samplesheetToList(input, "${projectDir}/assets/schema_input.json")) .map { meta, fastq_1, fastq_2 -> if (!fastq_2) { @@ -99,11 +118,9 @@ workflow PIPELINE_INITIALISATION { workflow PIPELINE_COMPLETION { take: - outdir // path: Path to output directory where results will be published monochrome_logs // boolean: Disable ANSI colour codes in log output main: - summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") // // Completion email and summary @@ -111,10 +128,11 @@ workflow PIPELINE_COMPLETION { workflow.onComplete { completionSummary(monochrome_logs) + } workflow.onError { - log.error "Pipeline failed. Please refer to troubleshooting docs: https://nf-co.re/docs/usage/troubleshooting" + log.error "Pipeline failed. Please refer to troubleshooting docs for common issues: https://nf-co.re/docs/running/troubleshooting" } } diff --git a/hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfcore_pipeline/main.nf b/hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfcore_pipeline/main.nf index 2f30e9a463..afca543909 100644 --- a/hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfcore_pipeline/main.nf +++ b/hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfcore_pipeline/main.nf @@ -17,7 +17,7 @@ workflow UTILS_NFCORE_PIPELINE { checkProfileProvided(nextflow_cli_args) emit: - valid_config + valid_config = valid_config } /* @@ -353,67 +353,3 @@ def completionSummary(monochrome_logs=true) { log.info("-${colors.purple}[${workflow.manifest.name}]${colors.red} Pipeline completed with errors${colors.reset}-") } } - -// -// Construct and send a notification to a web server as JSON e.g. Microsoft Teams and Slack -// -def imNotification(summary_params, hook_url) { - def summary = [:] - summary_params - .keySet() - .sort() - .each { group -> - summary << summary_params[group] - } - - def misc_fields = [:] - misc_fields['start'] = workflow.start - misc_fields['complete'] = workflow.complete - misc_fields['scriptfile'] = workflow.scriptFile - misc_fields['scriptid'] = workflow.scriptId - if (workflow.repository) { - misc_fields['repository'] = workflow.repository - } - if (workflow.commitId) { - misc_fields['commitid'] = workflow.commitId - } - if (workflow.revision) { - misc_fields['revision'] = workflow.revision - } - misc_fields['nxf_version'] = workflow.nextflow.version - misc_fields['nxf_build'] = workflow.nextflow.build - misc_fields['nxf_timestamp'] = workflow.nextflow.timestamp - - def msg_fields = [:] - msg_fields['version'] = getWorkflowVersion() - msg_fields['runName'] = workflow.runName - msg_fields['success'] = workflow.success - msg_fields['dateComplete'] = workflow.complete - msg_fields['duration'] = workflow.duration - msg_fields['exitStatus'] = workflow.exitStatus - msg_fields['errorMessage'] = (workflow.errorMessage ?: 'None') - msg_fields['errorReport'] = (workflow.errorReport ?: 'None') - msg_fields['commandLine'] = workflow.commandLine.replaceFirst(/ +--hook_url +[^ ]+/, "") - msg_fields['projectDir'] = workflow.projectDir - msg_fields['summary'] = summary << misc_fields - - // Render the JSON template - def engine = new groovy.text.GStringTemplateEngine() - // Different JSON depending on the service provider - // Defaults to "Adaptive Cards" (https://adaptivecards.io), except Slack which has its own format - def json_path = hook_url.contains("hooks.slack.com") ? "slackreport.json" : "adaptivecard.json" - def hf = new File("${workflow.projectDir}/assets/${json_path}") - def json_template = engine.createTemplate(hf).make(msg_fields) - def json_message = json_template.toString() - - // POST - def post = new URL(hook_url).openConnection() - post.setRequestMethod("POST") - post.setDoOutput(true) - post.setRequestProperty("Content-Type", "application/json") - post.getOutputStream().write(json_message.getBytes("UTF-8")) - def postRC = post.getResponseCode() - if (!postRC.equals(200)) { - log.warn(post.getErrorStream().getText()) - } -} diff --git a/hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test b/hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test new file mode 100644 index 0000000000..8940d32d1e --- /dev/null +++ b/hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test @@ -0,0 +1,29 @@ +nextflow_workflow { + + name "Test Workflow UTILS_NFCORE_PIPELINE" + script "../main.nf" + config "subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config" + workflow "UTILS_NFCORE_PIPELINE" + tag "subworkflows" + tag "subworkflows_nfcore" + tag "utils_nfcore_pipeline" + tag "subworkflows/utils_nfcore_pipeline" + + test("Should run without failures") { + + when { + workflow { + """ + input[0] = [] + """ + } + } + + then { + assertAll( + { assert workflow.success }, + { assert snapshot(workflow.out).match() } + ) + } + } +} diff --git a/hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap b/hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap new file mode 100644 index 0000000000..859d1030fb --- /dev/null +++ b/hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap @@ -0,0 +1,19 @@ +{ + "Should run without failures": { + "content": [ + { + "0": [ + true + ], + "valid_config": [ + true + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-28T12:03:25.726491" + } +} \ No newline at end of file diff --git a/hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfschema_plugin/main.nf b/hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfschema_plugin/main.nf index 93de2a5245..1df8b76fba 100644 --- a/hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfschema_plugin/main.nf +++ b/hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfschema_plugin/main.nf @@ -4,6 +4,7 @@ include { paramsSummaryLog } from 'plugin/nf-schema' include { validateParameters } from 'plugin/nf-schema' +include { paramsHelp } from 'plugin/nf-schema' workflow UTILS_NFSCHEMA_PLUGIN { @@ -15,29 +16,56 @@ workflow UTILS_NFSCHEMA_PLUGIN { // when this input is empty it will automatically use the configured schema or // "${projectDir}/nextflow_schema.json" as default. This input should not be empty // for meta pipelines + help // boolean: show help message + help_full // boolean: show full help message + show_hidden // boolean: show hidden parameters in help message + before_text // string: text to show before the help message and parameters summary + after_text // string: text to show after the help message and parameters summary + command // string: an example command of the pipeline main: + if(help || help_full) { + help_options = [ + beforeText: before_text, + afterText: after_text, + command: command, + showHidden: show_hidden, + fullHelp: help_full, + ] + if(parameters_schema) { + help_options << [parametersSchema: parameters_schema] + } + log.info paramsHelp( + help_options, + (params.help instanceof String && params.help != "true") ? params.help : "", + ) + exit 0 + } + // // Print parameter summary to stdout. This will display the parameters // that differ from the default given in the JSON schema // + + summary_options = [:] if(parameters_schema) { - log.info paramsSummaryLog(input_workflow, parameters_schema:parameters_schema) - } else { - log.info paramsSummaryLog(input_workflow) + summary_options << [parametersSchema: parameters_schema] } + log.info before_text + log.info paramsSummaryLog(summary_options, input_workflow) + log.info after_text // // Validate the parameters using nextflow_schema.json or the schema // given via the validation.parametersSchema configuration option // if(validate_params) { + validateOptions = [:] if(parameters_schema) { - validateParameters(parameters_schema:parameters_schema) - } else { - validateParameters() + validateOptions << [parametersSchema: parameters_schema] } + validateParameters(validateOptions) } emit: diff --git a/hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config b/hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config index 478fb8a05f..fd71cb8f85 100644 --- a/hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config +++ b/hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config @@ -1,5 +1,5 @@ plugins { - id "nf-schema@2.1.0" + id "nf-schema@2.7.2" } validation { diff --git a/hello-nf-core/solutions/core-hello-start/workflows/hello.nf b/hello-nf-core/solutions/core-hello-start/workflows/hello.nf index d54c260170..e788a1414f 100644 --- a/hello-nf-core/solutions/core-hello-start/workflows/hello.nf +++ b/hello-nf-core/solutions/core-hello-start/workflows/hello.nf @@ -16,14 +16,16 @@ workflow HELLO { take: ch_samplesheet // channel: samplesheet read in from --input + outdir + main: - ch_versions = channel.empty() + def ch_versions = channel.empty() // // Collate and save software versions // - def topic_versions = Channel.topic("versions") + def topic_versions = channel.topic("versions") .distinct() .branch { entry -> versions_file: entry instanceof Path @@ -40,19 +42,16 @@ workflow HELLO { "${process}:\n${tool_versions.join('\n')}" } - softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file)) + def ch_collated_versions = softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file)) .mix(topic_versions_string) .collectFile( - storeDir: "${params.outdir}/pipeline_info", + storeDir: "${outdir}/pipeline_info", name: 'hello_software_' + 'versions.yml', sort: true, newLine: true - ).set { ch_collated_versions } - - + ) emit: versions = ch_versions // channel: [ path(versions.yml) ] - } /* From a90708d0ca0ab2a69fc627b2103a1f200a2947b5 Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 16:53:18 +0100 Subject: [PATCH 25/42] docs(side_quests): re-verify nf_test on 26.04 post-merge; fix nf-test hash consistency [skip ci] --- docs/en/docs/side_quests/nf_test/index.md | 48 +++++++++---------- .../tests/main.converttoupper.nf.test.snap | 8 ++-- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/docs/en/docs/side_quests/nf_test/index.md b/docs/en/docs/side_quests/nf_test/index.md index a472581da9..9d1f4271b3 100644 --- a/docs/en/docs/side_quests/nf_test/index.md +++ b/docs/en/docs/side_quests/nf_test/index.md @@ -450,10 +450,10 @@ https://www.nf-test.com Test Workflow main.nf - Test [1d4aaf12] 'Should run without failures' PASSED (1.619s) + Test [693ba951] 'Should run without failures' PASSED (2.879s) -SUCCESS: Executed 1 tests in 1.626s +SUCCESS: Executed 1 tests in 2.883s ``` Success! The pipeline runs successfully and the test passes. Run it as many times as you like and you will always get the same result! @@ -486,7 +486,7 @@ Test Workflow main.nf > > Outputs: > - > /workspaces/training/side-quests/nf-test/.nf-test/tests/84ba145929856dd1582dc2e0d9c5c1de/results + > /workspaces/training/side-quests/nf-test/.nf-test/tests/693ba951a20fec36a5a9292ed1cc8a9f/results > > greetings: > - Bonjour-output.txt @@ -562,10 +562,10 @@ https://www.nf-test.com Test Workflow main.nf - Test [1d4aaf12] 'Should run successfully with correct number of processes' PASSED (1.567s) + Test [8a64acb3] 'Should run successfully with correct number of processes' PASSED (2.876s) -SUCCESS: Executed 1 tests in 1.588s +SUCCESS: Executed 1 tests in 2.879s ``` Success! The pipeline runs successfully and the test passes. Now we have began to test the details of the pipeline, as well as the overall status. @@ -647,11 +647,11 @@ https://www.nf-test.com Test Workflow main.nf - Test [f0e08a68] 'Should run successfully with correct number of processes' PASSED (8.144s) - Test [d7e32a32] 'Should produce correct output files' PASSED (6.994s) + Test [8a64acb3] 'Should run successfully with correct number of processes' PASSED (3.055s) + Test [44ba6e13] 'Should produce correct output files' PASSED (2.941s) -SUCCESS: Executed 2 tests in 15.165s +SUCCESS: Executed 2 tests in 6.004s ``` Success! The tests pass because the pipeline completed successfully, the correct number of processes ran and the output files were created. This should also show you how useful it is to provide those informative names for your tests. @@ -759,7 +759,7 @@ Test Process sayHello Process `sayHello` declares 1 input but was called with 0 arguments - -- Check script '/workspaces/training/side-quests/nf-test/.nf-test-1eaad1186e16d8d0a9292ed1cc8a9f12.nf' at line: 30 or see '/workspaces/training/side-quests/nf-test/.nf-test/tests/1eaad1186e16d8d0a9292ed1cc8a9f12/meta/nextflow.log' file for more details + -- Check script '/workspaces/training/side-quests/nf-test/.nf-test-1eaad118145a1fd798cb07e7dd75d087.nf' at line: 30 or see '/workspaces/training/side-quests/nf-test/.nf-test/tests/1eaad118145a1fd798cb07e7dd75d087/meta/nextflow.log' file for more details Nextflow stderr: FAILURE: Executed 1 tests in 4.884s (1 failed) @@ -830,7 +830,7 @@ https://www.nf-test.com Test Process sayHello - Test [f91a1bcd] 'Should run without failures and produce correct output' PASSED (1.604s) + Test [d6837883] 'Should run without failures and produce correct output' PASSED (2.729s) Snapshots: 1 created [Should run without failures and produce correct output] @@ -838,7 +838,7 @@ Test Process sayHello Snapshot Summary: 1 created -SUCCESS: Executed 1 tests in 1.611s +SUCCESS: Executed 1 tests in 2.733s ``` Success! The test passes because the `sayHello` process ran successfully and the output was created. @@ -888,10 +888,10 @@ https://www.nf-test.com Test Process sayHello - Test [f91a1bcd] 'Should run without failures and produce correct output' PASSED (1.675s) + Test [d6837883] 'Should run without failures and produce correct output' PASSED (3.092s) -SUCCESS: Executed 1 tests in 1.685s +SUCCESS: Executed 1 tests in 3.097s ``` Success! The test passes because the `sayHello` process ran successfully and the output matched the snapshot. @@ -981,10 +981,10 @@ https://www.nf-test.com Test Process sayHello - Test [58df4e4b] 'Should run without failures and contain expected greeting' PASSED (7.196s) + Test [c1d07f15] 'Should run without failures and contain expected greeting' PASSED (2.459s) -SUCCESS: Executed 1 tests in 7.208s +SUCCESS: Executed 1 tests in 2.461s ``` ### 2.4. Test the `convertToUpper` process @@ -1100,7 +1100,7 @@ https://www.nf-test.com Test Process convertToUpper - Test [c59b6044] 'Should run without failures and produce correct output' PASSED (1.755s) + Test [f8de7d71] 'Should run without failures and produce correct output' PASSED (3.472s) Snapshots: 1 created [Should run without failures and produce correct output] @@ -1108,7 +1108,7 @@ Test Process convertToUpper Snapshot Summary: 1 created -SUCCESS: Executed 1 tests in 1.764s +SUCCESS: Executed 1 tests in 3.478s ``` Note, we have created a snapshot file for the `convertToUpper` process at `tests/main.converttoupper.nf.test.snap`. If we run the test again, we should see the nf-test passes again. @@ -1127,10 +1127,10 @@ https://www.nf-test.com Test Process convertToUpper - Test [c59b6044] 'Should run without failures and produce correct output' PASSED (1.798s) + Test [f8de7d71] 'Should run without failures and produce correct output' PASSED (2.387s) -SUCCESS: Executed 1 tests in 1.811s +SUCCESS: Executed 1 tests in 2.39s ``` ### Takeaway @@ -1169,19 +1169,19 @@ https://www.nf-test.com Test Process convertToUpper - Test [3d26d9af] 'Should run without failures and produce correct output' PASSED (4.155s) + Test [f8de7d71] 'Should run without failures and produce correct output' PASSED (3.472s) Test Workflow main.nf - Test [f183df37] 'Should run successfully with correct number of processes' PASSED (3.33s) - Test [d7e32a32] 'Should produce correct output files' PASSED (3.102s) + Test [8a64acb3] 'Should run successfully with correct number of processes' PASSED (3.156s) + Test [44ba6e13] 'Should produce correct output files' PASSED (3.124s) Test Process sayHello - Test [58df4e4b] 'Should run without failures and contain expected greeting' PASSED (2.614s) + Test [c1d07f15] 'Should run without failures and contain expected greeting' PASSED (5.782s) -SUCCESS: Executed 4 tests in 13.481s +SUCCESS: Executed 4 tests in 15.746s ``` Check that out! We ran 4 tests, 1 for each process and 2 for the whole pipeline with a single command. Imagine how powerful this is on a large codebase! diff --git a/side-quests/solutions/nf-test/tests/main.converttoupper.nf.test.snap b/side-quests/solutions/nf-test/tests/main.converttoupper.nf.test.snap index df7f1adb6d..95cb16afd4 100644 --- a/side-quests/solutions/nf-test/tests/main.converttoupper.nf.test.snap +++ b/side-quests/solutions/nf-test/tests/main.converttoupper.nf.test.snap @@ -7,10 +7,10 @@ ] } ], - "timestamp": "2026-06-08T10:35:50.126073832", "meta": { - "nf-test": "0.9.5", - "nextflow": "25.10.4" - } + "nf-test": "0.9.3", + "nextflow": "26.04.4" + }, + "timestamp": "2026-06-23T15:48:10.014026951" } } From 81e0c3410b472955ec648dff997254c85597189e Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 16:53:50 +0100 Subject: [PATCH 26/42] docs(side_quests): re-verify debugging on 26.04 post-merge (genuine error text + output) [skip ci] --- docs/en/docs/side_quests/debugging/index.md | 222 ++++++++++---------- 1 file changed, 106 insertions(+), 116 deletions(-) diff --git a/docs/en/docs/side_quests/debugging/index.md b/docs/en/docs/side_quests/debugging/index.md index 9ee566d6c8..f6f379f9a9 100644 --- a/docs/en/docs/side_quests/debugging/index.md +++ b/docs/en/docs/side_quests/debugging/index.md @@ -130,9 +130,9 @@ nextflow run bad_syntax.nf ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_syntax.nf` [stupefied_bhabha] DSL2 - revision: ca6327fad2 + Launching `bad_syntax.nf` [nice_kalam] revision: 550b9a8873 Error bad_syntax.nf:24:1: Unexpected input: '' @@ -258,12 +258,12 @@ nextflow run bad_syntax.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_syntax.nf` [insane_faggin] DSL2 - revision: 961938ee2b + Launching `bad_syntax.nf` [small_morse] revision: 961938ee2b executor > local (3) - [48/cd7f54] PROCESS_FILES (1) | 3 of 3 ✔ + [f5/dd6f46] PROCESS_FILES (1) | 3 of 3 ✔ ``` ### 1.2. Using incorrect process keywords or directives @@ -279,9 +279,9 @@ nextflow run invalid_process.nf ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `invalid_process.nf` [nasty_jepsen] DSL2 - revision: da9758d614 + Launching `invalid_process.nf` [astonishing_pesquet] revision: f42559404a Error invalid_process.nf:3:1: Invalid process definition -- check for missing or out-of-order section labels │ 3 | process PROCESS_FILES { @@ -401,12 +401,12 @@ nextflow run invalid_process.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `invalid_process.nf` [silly_fermi] DSL2 - revision: 961938ee2b + Launching `invalid_process.nf` [confident_banach] revision: 961938ee2b executor > local (3) - [b7/76cd9d] PROCESS_FILES (2) | 3 of 3 ✔ + [29/87d6b8] PROCESS_FILES (1) | 3 of 3 ✔ ``` ### 1.3. Using bad variable names @@ -422,9 +422,9 @@ nextflow run no_such_var.nf ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `no_such_var.nf` [gloomy_meninsky] DSL2 - revision: 0c4d3bc28c + Launching `no_such_var.nf` [spontaneous_pasteur] revision: 0c4d3bc28c Error no_such_var.nf:17:39: `undefined_var` is not defined │ 17 | echo "Using undefined variable: ${undefined_var}" >> ${output_pref @@ -542,12 +542,12 @@ nextflow run no_such_var.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `no_such_var.nf` [suspicious_venter] DSL2 - revision: 6ba490f7c5 + Launching `no_such_var.nf` [suspicious_venter] revision: 6ba490f7c5 executor > local (3) - [21/237300] PROCESS_FILES (2) | 3 of 3 ✔ + [26/b4370c] PROCESS_FILES (3) | 3 of 3 ✔ ``` ### 1.4. Bad use of Bash variables @@ -563,9 +563,9 @@ nextflow run bad_bash_var.nf ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_bash_var.nf` [infallible_mandelbrot] DSL2 - revision: 0853c11080 + Launching `bad_bash_var.nf` [hopeful_koch] revision: 0853c11080 Error bad_bash_var.nf:13:42: `prefix` is not defined │ 13 | echo "Processing ${sample_name}" > ${prefix}.txt @@ -662,12 +662,12 @@ nextflow run bad_bash_var.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_bash_var.nf` [naughty_franklin] DSL2 - revision: 58c1c83709 + Launching `bad_bash_var.nf` [naughty_franklin] revision: 58c1c83709 executor > local (3) - [4e/560285] PROCESS_FILES (2) | 3 of 3 ✔ + [cf/19a490] PROCESS_FILES (3) | 3 of 3 ✔ ``` !!! tip "Groovy vs Bash Variables" @@ -698,11 +698,11 @@ nextflow run badpractice_syntax.nf ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `badpractice_syntax.nf` [intergalactic_colden] DSL2 - revision: 5e4b291bde + Launching `badpractice_syntax.nf` [fervent_miescher] revision: 5e4b291bde - Error badpractice_syntax.nf:3:1: Statements cannot be mixed with script declarations -- move statements into a process or workflow + Error badpractice_syntax.nf:3:1: Statements cannot be mixed with script declarations -- move statements into a process, workflow, or function │ 3 | input_ch = channel.of('sample1', 'sample2', 'sample3') ╰ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -820,12 +820,12 @@ nextflow run badpractice_syntax.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `badpractice_syntax.nf` [naughty_ochoa] DSL2 - revision: 5e4b291bde + Launching `badpractice_syntax.nf` [naughty_ochoa] revision: 5e4b291bde executor > local (3) - [6a/84a608] PROCESS_FILES (2) | 3 of 3 ✔ + [f0/350ff4] PROCESS_FILES (2) | 3 of 3 ✔ ``` Keep your input channels defined within the workflow block, and in general follow any other recommendations the extension makes. @@ -865,9 +865,9 @@ nextflow run bad_number_inputs.nf ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_number_inputs.nf` [happy_swartz] DSL2 - revision: d83e58dcd3 + Launching `bad_number_inputs.nf` [desperate_carson] revision: d83e58dcd3 Error bad_number_inputs.nf:23:5: Incorrect number of call arguments, expected 1 but received 2 │ 23 | PROCESS_FILES(samples_ch, files_ch) @@ -984,12 +984,12 @@ nextflow run bad_number_inputs.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_number_inputs.nf` [big_euler] DSL2 - revision: e302bd87be + Launching `bad_number_inputs.nf` [big_euler] revision: e302bd87be executor > local (3) - [48/497f7b] PROCESS_FILES (3) | 3 of 3 ✔ + [47/1d039f] PROCESS_FILES (3) | 3 of 3 ✔ ``` More commonly than this example, you might add additional inputs to a process and forget to update the workflow call accordingly, which can lead to this type of error. Fortunately, this is one of the easier-to-understand and fix errors, as the error message is quite clear about the mismatch. @@ -1007,12 +1007,12 @@ nextflow run exhausted.nf ??? success "Command output" ```console title="Exhausted channel output" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `exhausted.nf` [extravagant_gauss] DSL2 - revision: 08cff7ba2a + Launching `exhausted.nf` [romantic_liskov] revision: 31a6ae1494 executor > local (1) - [bd/f61fff] PROCESS_FILES (1) [100%] 1 of 1 ✔ + [10/82e235] PROCESS_FILES (1) | 1 of 1 ✔ ``` This workflow completes without error, but it only processes a single sample! @@ -1131,12 +1131,12 @@ nextflow run exhausted.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `exhausted.nf` [maniac_leavitt] DSL2 - revision: f372a56a7d + Launching `exhausted.nf` [maniac_leavitt] revision: f372a56a7d executor > local (3) - [80/0779e9] PROCESS_FILES (3) | 3 of 3 ✔ + [d9/886888] PROCESS_FILES (2) | 3 of 3 ✔ ``` You should now see all three samples being processed instead of just one. @@ -1154,11 +1154,12 @@ nextflow run bad_channel_shape.nf ??? failure "Command output" ```console - Launching `bad_channel_shape.nf` [hopeful_pare] DSL2 - revision: ffd66071a1 + N E X T F L O W ~ version 26.04.4 + + Launching `bad_channel_shape.nf` [disturbed_hilbert] revision: 3046f86036 executor > local (3) - executor > local (3) - [3f/c2dcb3] PROCESS_FILES (3) [ 0%] 0 of 3 ✘ + [13/2d7cf7] PROCESS_FILES (2) | 0 of 3 ✘ ERROR ~ Error executing process > 'PROCESS_FILES (1)' Caused by: @@ -1176,7 +1177,7 @@ nextflow run bad_channel_shape.nf (empty) Work dir: - /workspaces/training/side-quests/debugging/work/d6/1fb69d1d93300bbc9d42f1875b981e + /workspaces/training/side-quests/debugging/work/fc/20d7bd091eb9f7f63b76ab3a802cac Tip: when you have fixed the problem you can continue the execution adding the option `-resume` to the run command line @@ -1326,12 +1327,12 @@ nextflow run bad_channel_shape.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_channel_shape.nf` [clever_thompson] DSL2 - revision: 8cbcae3746 + Launching `bad_channel_shape.nf` [clever_thompson] revision: 8cbcae3746 executor > local (3) - [bb/80a958] PROCESS_FILES (2) | 3 of 3 ✔ + [81/d0f3ea] PROCESS_FILES (1) | 3 of 3 ✔ ``` ### 2.4. Channel Debugging Techniques @@ -1351,12 +1352,12 @@ nextflow run bad_channel_shape_viewed.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_channel_shape_viewed.nf` [maniac_poisson] DSL2 - revision: b4f24dc9da + Launching `bad_channel_shape_viewed.nf` [sleepy_cajal] revision: 03e79cdbad executor > local (3) - [c0/db76b3] PROCESS_FILES (3) [100%] 3 of 3 ✔ + [dc/6e5c24] PROCESS_FILES (2) | 3 of 3 ✔ Channel content: [sample1, file1.txt] Channel content: [sample2, file2.txt] Channel content: [sample3, file3.txt] @@ -1416,12 +1417,12 @@ nextflow run bad_channel_shape_viewed.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_channel_shape_viewed.nf` [marvelous_koch] DSL2 - revision: 03e79cdbad + Launching `bad_channel_shape_viewed.nf` [marvelous_koch] revision: 03e79cdbad executor > local (3) - [ff/d67cec] PROCESS_FILES (2) | 3 of 3 ✔ + [dc/6e5c24] PROCESS_FILES (2) | 3 of 3 ✔ Channel content: [sample1, file1.txt] Channel content: [sample2, file2.txt] Channel content: [sample3, file3.txt] @@ -1457,13 +1458,12 @@ nextflow run missing_output.nf ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `missing_output.nf` [zen_stone] DSL2 - revision: 37ff61f926 + Launching `missing_output.nf` [evil_gilbert] revision: 3d5117f7e2 executor > local (3) - executor > local (3) - [fd/2642e9] process > PROCESS_FILES (2) [ 66%] 2 of 3, failed: 2 + [45/146e39] PROCESS_FILES (1) | 0 of 3 ✘ ERROR ~ Error executing process > 'PROCESS_FILES (3)' Caused by: @@ -1481,9 +1481,9 @@ nextflow run missing_output.nf (empty) Work dir: - /workspaces/training/side-quests/debugging/work/02/9604d49fb8200a74d737c72a6c98ed + /workspaces/training/side-quests/debugging/work/2b/85afc51ff8d820df3b97b8a7154a30 - Tip: when you have fixed the problem you can continue the execution adding the option `-resume` to the run command line + Tip: you can try to figure out what's wrong by changing to the process work dir and showing the script file named `.command.sh` -- Check '.nextflow.log' file for details ``` @@ -1565,12 +1565,12 @@ nextflow run missing_output.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `missing_output.nf` [elated_hamilton] DSL2 - revision: 961938ee2b + Launching `missing_output.nf` [elated_hamilton] revision: 961938ee2b executor > local (3) - [16/1c437c] PROCESS_FILES (3) | 3 of 3 ✔ + [70/6d4479] PROCESS_FILES (1) | 3 of 3 ✔ ``` ### 3.2. Missing software @@ -1586,15 +1586,15 @@ nextflow run missing_software.nf ??? failure "Command output" ```console hl_lines="12 18" - ERROR ~ Error executing process > 'PROCESS_FILES (3)' + ERROR ~ Error executing process > 'PROCESS_FILES (2)' Caused by: - Process `PROCESS_FILES (3)` terminated with an error exit status (127) + Process `PROCESS_FILES (2)` terminated with an error exit status (127) Command executed: - cowpy sample3 > sample3_output.txt + cowpy sample2 > sample2_output.txt Command exit status: 127 @@ -1606,9 +1606,9 @@ nextflow run missing_software.nf .command.sh: line 2: cowpy: command not found Work dir: - /workspaces/training/side-quests/debugging/work/82/42a5bfb60c9c6ee63ebdbc2d51aa6e + /workspaces/training/side-quests/debugging/work/2f/bcf8fad6fd101c76950c92062ce299 - Tip: you can try to figure out what's wrong by changing to the process work directory and showing the script file named `.command.sh` + Tip: when you have fixed the problem you can continue the execution adding the option `-resume` to the run command line -- Check '.nextflow.log' file for details ``` @@ -1652,12 +1652,12 @@ nextflow run missing_software.nf -profile docker ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `missing_software.nf` [awesome_stonebraker] DSL2 - revision: 0296d12839 + Launching `missing_software.nf` [awesome_stonebraker] revision: 0296d12839 executor > local (3) - [38/ab20d1] PROCESS_FILES (1) | 3 of 3 ✔ + [33/bf8d3e] PROCESS_FILES (3) | 3 of 3 ✔ ``` !!! note @@ -1679,34 +1679,19 @@ nextflow run bad_resources.nf -profile docker ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_resources.nf` [disturbed_elion] DSL2 - revision: 27d2066e86 + Launching `bad_resources.nf` [curious_escher] revision: e6e544e786 executor > local (3) - [c0/ded8e1] PROCESS_FILES (3) | 0 of 3 ✘ - ERROR ~ Error executing process > 'PROCESS_FILES (2)' + [83/c8c4af] PROCESS_FILES (2) | 0 of 3 + WARN: Killing running tasks (2) + ERROR ~ Error executing process > 'PROCESS_FILES (1)' Caused by: - Process exceeded running time limit (1ms) - - Command executed: - - cowpy sample2 > sample2_output.txt - - Command exit status: - - + process hasn't exited - Command output: - (empty) - - Work dir: - /workspaces/training/side-quests/debugging/work/53/f0a4cc56d6b3dc2a6754ff326f1349 - Container: - community.wave.seqera.io/library/cowpy:1.1.5--3db457ae1977a273 - - Tip: you can replicate the issue by changing to the process work dir and entering the command `bash .command.run` -- Check '.nextflow.log' file for details ``` @@ -1793,12 +1778,12 @@ nextflow run bad_resources.nf -profile docker ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_resources.nf` [friendly_mcclintock] DSL2 - revision: 381567d2c1 + Launching `bad_resources.nf` [friendly_mcclintock] revision: 381567d2c1 executor > local (3) - [c2/9b4c41] PROCESS_FILES (3) | 3 of 3 ✔ + [96/b70b83] PROCESS_FILES (3) | 3 of 3 ✔ ``` If you make sure to read your error messages failures like this should not puzzle you for too long. But make sure you understand the resource requirements of the commands you are running so that you can configure your resource directives appropriately. @@ -1822,20 +1807,21 @@ nextflow run missing_output.nf ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `missing_output.nf` [irreverent_payne] DSL2 - revision: 3d5117f7e2 + Launching `missing_output.nf` [irreverent_payne] revision: 3d5117f7e2 executor > local (3) - [5d/d544a4] PROCESS_FILES (2) | 0 of 3 ✘ - ERROR ~ Error executing process > 'PROCESS_FILES (1)' + [f0/42f283] PROCESS_FILES (2) | 0 of 3 ✘ + ERROR ~ Error executing process > 'PROCESS_FILES (2)' Caused by: - Missing output file(s) `sample1.txt` expected by process `PROCESS_FILES (1)` + Missing output file(s) `sample2.txt` expected by process `PROCESS_FILES (2)` + Command executed: - echo "Processing sample1" > sample1_output.txt + echo "Processing sample2" > sample2_output.txt Command exit status: 0 @@ -1844,9 +1830,9 @@ nextflow run missing_output.nf (empty) Work dir: - /workspaces/training/side-quests/debugging/work/1e/2011154d0b0f001cd383d7364b5244 + /workspaces/training/side-quests/debugging/work/f0/42f283a25543dad8d56b192e314f41 - Tip: you can replicate the issue by changing to the process work dir and entering the command `bash .command.run` + Tip: you can try to figure out what's wrong by changing to the process work dir and showing the script file named `.command.sh` -- Check '.nextflow.log' file for details ``` @@ -1980,22 +1966,22 @@ nextflow run bad_channel_shape_viewed_debug.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_channel_shape_viewed_debug.nf` [agitated_crick] DSL2 - revision: ea3676d9ec + Launching `bad_channel_shape_viewed_debug.nf` [infallible_shirley] revision: 37cbda227b executor > local (3) - [c6/2dac51] process > PROCESS_FILES (3) [100%] 3 of 3 ✔ + [a1/59e59a] PROCESS_FILES (3) | 3 of 3 ✔ Channel content: [sample1, file1.txt] Channel content: [sample2, file2.txt] Channel content: [sample3, file3.txt] After mapping: sample1 After mapping: sample2 After mapping: sample3 - Sample name inside process is sample2 - Sample name inside process is sample1 + Sample name inside process is sample2 + Sample name inside process is sample3 ``` @@ -2044,9 +2030,9 @@ nextflow run bad_syntax.nf -preview ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `bad_syntax.nf` [magical_mercator] DSL2 - revision: 550b9a8873 + Launching `bad_syntax.nf` [magical_mercator] revision: 550b9a8873 Error bad_syntax.nf:24:1: Unexpected input: '' @@ -2094,9 +2080,9 @@ nextflow run missing_software_with_stub.nf .command.sh: line 2: cowpy: command not found Work dir: - /workspaces/training/side-quests/debugging/work/82/42a5bfb60c9c6ee63ebdbc2d51aa6e + /workspaces/training/side-quests/debugging/work/cd/b8686a0d27df5be779a38fed616d01 - Tip: you can try to figure out what's wrong by changing to the process work directory and showing the script file named `.command.sh` + Tip: you can replicate the issue by changing to the process work dir and entering the command `bash .command.run` -- Check '.nextflow.log' file for details ``` @@ -2110,12 +2096,12 @@ nextflow run missing_software_with_stub.nf -stub-run ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `missing_software_with_stub.nf` [astonishing_shockley] DSL2 - revision: f1f4f05d7d + Launching `missing_software_with_stub.nf` [astonishing_shockley] revision: f1f4f05d7d executor > local (3) - [b5/2517a3] PROCESS_FILES (3) | 3 of 3 ✔ + [ba/416414] PROCESS_FILES (2) | 3 of 3 ✔ ``` #### Check the code @@ -2249,16 +2235,20 @@ Now it's time to put the systematic debugging approach into practice. The workfl ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 + + Launching `buggy_workflow.nf` [happy_aryabhata] revision: 6a296ff695 - Launching `buggy_workflow.nf` [wise_ramanujan] DSL2 - revision: d51a8e83fd + Error buggy_workflow.nf:25:12: Unexpected input: '\n' + │ 25 | script: + ╰ | ^ - ERROR ~ Range [11, 12) out of bounds for length 11 + ERROR ~ Script compilation failed -- Check '.nextflow.log' file for details ``` - This cryptic error indicates a parsing problem around line 11-12 in the `params{}` block. The v2 parser catches structural issues early. + The parser points at line 25 (`script:`), but the real culprit is just above it: the trailing comma after the `output:` declaration on line 23 leaves the parser expecting another output, so it fails when it reaches `script:`. This is the first of several syntax errors to work through. Apply the four-phase debugging method you've learned: @@ -2386,7 +2376,7 @@ Now it's time to put the systematic debugging approach into practice. The workfl echo "Heavy computation \${i} for ${sample_id}" ``` - Now we get `Process exceeded running time limit (1ms)`, so we fix the run time limit for the relevant process: + Now `heavyProcess` hits its time limit and we get `process hasn't exited` (alongside a `WARN: Killing running tasks` message), so we fix the run time limit for the relevant process: **Error 8: Resource Configuration Error** ```groovy linenums="36" From b009d41178d438afd40ff80d9009201d6663794a Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 17:03:10 +0100 Subject: [PATCH 27/42] docs(side_quests): re-verify essential_scripting_patterns on 26.04 post-merge with #961 publishing [skip ci] --- .../essential_scripting_patterns/index.md | 395 ++++++++++++------ 1 file changed, 273 insertions(+), 122 deletions(-) diff --git a/docs/en/docs/side_quests/essential_scripting_patterns/index.md b/docs/en/docs/side_quests/essential_scripting_patterns/index.md index c976f641ee..1a38bc5c2b 100644 --- a/docs/en/docs/side_quests/essential_scripting_patterns/index.md +++ b/docs/en/docs/side_quests/essential_scripting_patterns/index.md @@ -133,11 +133,19 @@ nextflow run main.nf ??? success "Command output" ```console - Launching `main.nf` [marvelous_tuckerman] DSL2 - revision: 6113e05c17 + N E X T F L O W ~ version 26.04.4 + + Launching `main.nf` [exotic_salas] revision: d915f0414b [sample_id:SAMPLE_001, organism:human, tissue_type:liver, sequencing_depth:30000000, file_path:data/sequences/SAMPLE_001_S1_L001_R1_001.fastq, quality_score:38.5] [sample_id:SAMPLE_002, organism:mouse, tissue_type:brain, sequencing_depth:25000000, file_path:data/sequences/SAMPLE_002_S2_L001_R1_001.fastq, quality_score:35.2] [sample_id:SAMPLE_003, organism:human, tissue_type:kidney, sequencing_depth:45000000, file_path:data/sequences/SAMPLE_003_S3_L001_R1_001.fastq, quality_score:42.1] + + Outputs: + + /workspaces/training/side-quests/essential_scripting_patterns/results + + reports: ``` #### 1.1.2. Adding the Map Operator @@ -360,16 +368,22 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [peaceful_cori] DSL2 - revision: 4cc4a8340f + Launching `main.nf` [focused_goldwasser] revision: d9c7a39dec ID fields only: [id:sample_001, organism:human, tissue:liver] - ID fields only: [id:sample_002, organism:mouse, tissue:brain] - ID fields only: [id:sample_003, organism:human, tissue:kidney] [id:sample_001, organism:human, tissue:liver, depth:30000000, quality:38.5, priority:normal] + ID fields only: [id:sample_002, organism:mouse, tissue:brain] [id:sample_002, organism:mouse, tissue:brain, depth:25000000, quality:35.2, priority:normal] + ID fields only: [id:sample_003, organism:human, tissue:kidney] [id:sample_003, organism:human, tissue:kidney, depth:45000000, quality:42.1, priority:high] + + Outputs: + + /workspaces/training/side-quests/essential_scripting_patterns/results + + reports: ``` This shows both the full metadata displayed by the `view()` operation and the extracted subset we printed with `println`. @@ -489,9 +503,9 @@ nextflow run collect.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `collect.nf` [loving_mendel] DSL2 - revision: e8d054a46e + Launching `collect.nf` [friendly_jones] revision: 5b2b07e824 Individual channel item: sample_001 Individual channel item: sample_002 @@ -547,9 +561,9 @@ nextflow run collect.nf ??? success "Command output" ```console hl_lines="5" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `collect.nf` [cheeky_stonebraker] DSL2 - revision: 2d5039fb47 + Launching `collect.nf` [lethal_caravaggio] revision: 48f3dcbb7b List.collect() result: [SPECIMEN_001, SPECIMEN_002, SPECIMEN_003] (3 items transformed into 3) Individual channel item: sample_001 @@ -618,9 +632,9 @@ nextflow run collect.nf ??? success "Command output" ```console hl_lines="6" - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `collect.nf` [cranky_galileo] DSL2 - revision: 5f3c8b2a91 + Launching `collect.nf` [adoring_visvesvaraya] revision: 915ce68e4d List.collect() result: [SPECIMEN_001, SPECIMEN_002, SPECIMEN_003] (3 items transformed into 3) Spread operator result: [s1, s2, s3] @@ -747,13 +761,19 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [clever_pauling] DSL2 - revision: 605d2058b4 + Launching `main.nf` [nasty_brazil] revision: 723ff4e5e6 [[id:sample_001, organism:human, tissue:liver, depth:30000000, quality:38.5, sample_num:1, lane:001, read:R1, chunk:001, priority:normal], /workspaces/training/side-quests/essential_scripting_patterns/data/sequences/SAMPLE_001_S1_L001_R1_001.fastq] [[id:sample_002, organism:mouse, tissue:brain, depth:25000000, quality:35.2, sample_num:2, lane:001, read:R1, chunk:001, priority:normal], /workspaces/training/side-quests/essential_scripting_patterns/data/sequences/SAMPLE_002_S2_L001_R1_001.fastq] [[id:sample_003, organism:human, tissue:kidney, depth:45000000, quality:42.1, sample_num:3, lane:001, read:R1, chunk:001, priority:high], /workspaces/training/side-quests/essential_scripting_patterns/data/sequences/SAMPLE_003_S3_L001_R1_001.fastq] + + Outputs: + + /workspaces/training/side-quests/essential_scripting_patterns/results + + reports: ``` This shows the metadata enriched from the file names. @@ -892,28 +912,41 @@ nextflow run main.nf ??? failure "Command output" ```console - ERROR ~ Error executing process > 'FASTP (3)' + ERROR ~ Error executing process > 'FASTP (2)' Caused by: - Process `FASTP (3)` terminated with an error exit status (255) + Process `FASTP (2)` terminated with an error exit status (255) Command executed: fastp \ - --in1 SAMPLE_003_S3_L001_R1_001.fastq \ + --in1 SAMPLE_002_S2_L001_R1_001.fastq \ --in2 null \ - --out1 sample_003_trimmed_R1.fastq.gz \ - --out2 sample_003_trimmed_R2.fastq.gz \ - --json sample_003.fastp.json \ - --html sample_003.fastp.html \ - --thread 2 + --out1 sample_002_trimmed_R1.fastq.gz \ + --out2 sample_002_trimmed_R2.fastq.gz \ + --json sample_002.fastp.json \ + --html sample_002.fastp.html \ + --thread 1 Command exit status: 255 Command output: (empty) + + Command error: + ERROR: Failed to open file: null + + Work dir: + /workspaces/training/side-quests/essential_scripting_patterns/work/8b/5b15c8cf35259a87db0137312d6d06 + + Container: + community.wave.seqera.io/library/fastp:0.24.0--62c97b06e8447690 + + Tip: you can replicate the issue by changing to the process work dir and entering the command `bash .command.run` + + -- Check '.nextflow.log' file for details ``` You can see that the process is trying to run `fastp` with a `null` value for the second input file, which is causing it to fail. This is because our dataset contains single-end reads, but the process is hardcoded to expect paired-end reads (two input files at a time). @@ -977,18 +1010,24 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [adoring_rosalind] DSL2 - revision: 04b1cd93e9 + Launching `main.nf` [distracted_bohr] revision: b9b1c249c1 executor > local (3) - [31/a8ad4d] process > FASTP (3) [100%] 3 of 3 ✔ + [d9/542a41] FASTP (1) | 3 of 3 ✔ + + Outputs: + + /workspaces/training/side-quests/essential_scripting_patterns/results + + reports: ``` Looks good! If we check the actual commands that were run (customise for your task hash): ```console title="Check commands executed" -cat work/31/a8ad4d95749e685a6d842d3007957f/.command.sh +cat work/d9/542a41xxxxxxxxxxxxxxxxxxxxxxxxxx/.command.sh ``` We can see that Nextflow correctly picked the right command for single-end reads: @@ -1000,7 +1039,7 @@ fastp \ --out1 sample_003_trimmed.fastq.gz \ --json sample_003.fastp.json \ --html sample_003.fastp.html \ - --thread 2 + --thread 1 ``` Another common usage of dynamic script logic can be seen in [the Nextflow for Science Genomics module](../../nf4_science/genomics/03_joint_calling.md). In that module, the GATK process being called can take multiple input files, but each must be prefixed with `-V` to form a correct command line. The process uses scripting to transform a collection of input files (`all_gvcfs`) into the correct command arguments: @@ -1144,14 +1183,23 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 - Launching `main.nf` [dreamy_stonebraker] DSL2 - revision: 8ba7d0c7eb - [44/717c58] Submitted process > FASTP (1) - [16/426f16] Submitted process > FASTP (2) - [7b/846764] Submitted process > GENERATE_REPORT (1) - [20/54a02e] Submitted process > FASTP (3) - [59/cdba3d] Submitted process > GENERATE_REPORT (2) - [33/a0e0da] Submitted process > GENERATE_REPORT (3) + N E X T F L O W ~ version 26.04.4 + Launching `main.nf` [festering_payne] - revision: 3690c7806d + [31/870279] Submitted process > FASTP (1) + [52/c9fb45] Submitted process > GENERATE_REPORT (1) + [a2/00d26a] Submitted process > GENERATE_REPORT (3) + [61/c169b0] Submitted process > FASTP (2) + [a1/11c8b1] Submitted process > GENERATE_REPORT (2) + [d8/40aa79] Submitted process > FASTP (3) + + Outputs: + + /workspaces/training/side-quests/essential_scripting_patterns/results + + reports: + - reports/sample_003_report.txt + - reports/sample_001_report.txt + - reports/sample_002_report.txt ``` But what if we want to add information about when and where the processing occurred? Let's modify the process to use **shell** variables and a bit of command substitution to include the current user, hostname, and date in the report: @@ -1184,11 +1232,18 @@ If you run this, you'll notice an error - Nextflow tries to interpret `#!groovy ??? failure "Command output" ```console + N E X T F L O W ~ version 26.04.4 + + Launching `main.nf` [furious_euclid] revision: 3690c7806d + Error modules/generate_report.nf:13:27: `USER` is not defined │ 13 | echo "Processed by: ${USER}" >> ${meta.id}_report.txt ╰ | ^^^^ + ERROR ~ Script compilation failed + + -- Check '.nextflow.log' file for details ``` We need to escape it so Bash can handle it instead. @@ -1362,13 +1417,22 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [admiring_panini] DSL2 - revision: 8cc832e32f + Launching `main.nf` [peaceful_plateau] revision: 918c15451f executor > local (6) - [8c/2e3f91] process > FASTP (3) [100%] 3 of 3 ✔ - [7a/1b4c92] process > GENERATE_REPORT (3) [100%] 3 of 3 ✔ + [a5/f542b1] FASTP (2) | 3 of 3 ✔ + [22/a94ad7] GENERATE_REPORT (2) | 3 of 3 ✔ + + Outputs: + + /workspaces/training/side-quests/essential_scripting_patterns/results + + reports: + - reports/sample_001_report.txt + - reports/sample_003_report.txt + - reports/sample_002_report.txt ``` The output should show both processes completing successfully. The workflow is now much cleaner and easier to maintain, with all the complex metadata processing logic encapsulated in the `separateMetadata` function. @@ -1432,26 +1496,35 @@ nextflow run main.nf -ansi-log false ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 - Launching `main.nf` [fervent_albattani] DSL2 - revision: fa8f249759 - [bd/ff3d41] Submitted process > FASTP (2) - [a4/a3aab2] Submitted process > FASTP (1) - [48/6db0c9] Submitted process > FASTP (3) - [ec/83439d] Submitted process > GENERATE_REPORT (3) - [bd/15d7cc] Submitted process > GENERATE_REPORT (2) - [42/699357] Submitted process > GENERATE_REPORT (1) + N E X T F L O W ~ version 26.04.4 + Launching `main.nf` [naughty_kay] - revision: 918c15451f + [1e/d9a972] Submitted process > GENERATE_REPORT (2) + [ef/820ed7] Submitted process > GENERATE_REPORT (3) + [f6/ab4b70] Submitted process > FASTP (1) + [5b/748d5a] Submitted process > GENERATE_REPORT (1) + [7b/d99953] Submitted process > FASTP (3) + [37/291870] Submitted process > FASTP (2) + + Outputs: + + /workspaces/training/side-quests/essential_scripting_patterns/results + + reports: + - reports/sample_002_report.txt + - reports/sample_003_report.txt + - reports/sample_001_report.txt ``` You can check the exact `docker` command that was run to see the CPU allocation for any given task: ```console title="Check docker command" -cat work/48/6db0c9e9d8aa65e4bb4936cd3bd59e/.command.run | grep "docker run" +cat work/7b/d999535cfcdfb6865b4e63cddc3987/.command.run | grep "docker run" ``` You should see something like: ```bash title="docker command" - docker run -i --cpu-shares 2048 --memory 2048m -e "NXF_TASK_WORKDIR" -v /workspaces/training/side-quests/essential_scripting_patterns:/workspaces/training/side-quests/essential_scripting_patterns -w "$NXF_TASK_WORKDIR" --name $NXF_BOXID community.wave.seqera.io/library/fastp:0.24.0--62c97b06e8447690 /bin/bash -ue /workspaces/training/side-quests/essential_scripting_patterns/work/48/6db0c9e9d8aa65e4bb4936cd3bd59e/.command.sh + docker run -i --cpu-shares 2048 --memory 2048m -e "NXF_TASK_WORKDIR" -v /workspaces/training/side-quests/essential_scripting_patterns:/workspaces/training/side-quests/essential_scripting_patterns -w "$NXF_TASK_WORKDIR" --name $NXF_BOXID community.wave.seqera.io/library/fastp:0.24.0--62c97b06e8447690 /bin/bash -ue /workspaces/training/side-quests/essential_scripting_patterns/work/7b/d999535cfcdfb6865b4e63cddc3987/.command.sh ``` In this example we've chosen an example that requested 2 CPUs (`--cpu-shares 2048`), because it was a high-depth sample, but you should see different CPU allocations depending on the sample depth. Try this for the other tasks as well. @@ -1505,7 +1578,7 @@ nextflow run main.nf Detecting adapter sequence for read1... No adapter detected for read1 - .command.sh: line 7: 101 Killed fastp --in1 SAMPLE_002_S2_L001_R1_001.fastq --out1 sample_002_trimmed.fastq.gz --json sample_002.fastp.json --html sample_002.fastp.html --thread 1 + .command.sh: line 7: 34 Killed fastp --in1 SAMPLE_001_S1_L001_R1_001.fastq --out1 sample_001_trimmed.fastq.gz --json sample_001.fastp.json --html sample_001.fastp.html --thread 1 ``` This indicates that the process was killed for exceeding memory limits. @@ -1629,14 +1702,26 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [adoring_galileo] DSL2 - revision: c9e83aaef1 + Launching `main.nf` [condescending_venter] revision: 02a7ca6f13 - executor > local (6) - [1d/0747ac] process > FASTP (2) [100%] 2 of 2 ✔ - [cc/c44caf] process > TRIMGALORE (1) [100%] 1 of 1 ✔ - [34/bd5a9f] process > GENERATE_REPORT (1) [100%] 3 of 3 ✔ + executor > local (8) + [8b/40c882] FASTP (1) | 2 of 2, retries: 2 ✔ + [59/988a68] TRIMGALORE (1) | 1 of 1 ✔ + [01/2df2d4] GENERATE_REPORT (3) | 3 of 3 ✔ + + Outputs: + + /workspaces/training/side-quests/essential_scripting_patterns/results + + reports: + - reports/sample_001_report.txt + - reports/sample_002_report.txt + - reports/sample_003_report.txt + + [0a/8bb1dd] NOTE: Process `FASTP (2)` terminated with an error exit status (137) -- Execution is retried (1) + [af/76bc6f] NOTE: Process `FASTP (1)` terminated with an error exit status (137) -- Execution is retried (1) ``` Here, we've used small but mighty conditional expressions inside the `.branch{}` operator to route samples based on their metadata. Human samples with high coverage go through `FASTP`, while all other samples go through `TRIMGALORE`. @@ -1697,18 +1782,27 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 - Launching `main.nf` [lonely_williams] DSL2 - revision: d0b3f121ec - [94/b48eac] Submitted process > FASTP (2) - [2c/d2b28f] Submitted process > GENERATE_REPORT (2) - [65/2e3be4] Submitted process > GENERATE_REPORT (1) - [94/b48eac] NOTE: Process `FASTP (2)` terminated with an error exit status (137) -- Execution is retried (1) - [3e/0d8664] Submitted process > TRIMGALORE (1) - [6a/9137b0] Submitted process > FASTP (1) - [6a/9137b0] NOTE: Process `FASTP (1)` terminated with an error exit status (137) -- Execution is retried (1) - [83/577ac0] Submitted process > GENERATE_REPORT (3) - [a2/5117de] Re-submitted process > FASTP (1) - [1f/a1a4ca] Re-submitted process > FASTP (2) + N E X T F L O W ~ version 26.04.4 + Launching `main.nf` [disturbed_jepsen] - revision: 7097b98dd8 + [5b/a38d75] Submitted process > FASTP (2) + [b3/cc56c7] Submitted process > FASTP (1) + [01/feef56] Submitted process > GENERATE_REPORT (3) + [9b/e944ae] Submitted process > GENERATE_REPORT (1) + [74/04af51] Submitted process > GENERATE_REPORT (2) + [24/939e1f] Submitted process > TRIMGALORE (1) + [b3/cc56c7] NOTE: Process `FASTP (1)` terminated with an error exit status (137) -- Execution is retried (1) + [b2/90425f] Re-submitted process > FASTP (1) + [5b/a38d75] NOTE: Process `FASTP (2)` terminated with an error exit status (137) -- Execution is retried (1) + [24/a79e73] Re-submitted process > FASTP (2) + + Outputs: + + /workspaces/training/side-quests/essential_scripting_patterns/results + + reports: + - reports/sample_003_report.txt + - reports/sample_001_report.txt + - reports/sample_002_report.txt ``` In this case all three samples satisfy the filter, so every sample continues down the pipeline. @@ -1782,13 +1876,13 @@ nextflow run main.nf ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [trusting_torvalds] DSL2 - revision: b56fbfbce2 + Launching `main.nf` [fervent_bassi] revision: c5d3df5c06 ERROR ~ Cannot invoke method toUpperCase() on null object - -- Check script 'main.nf' at line: 13 or see '.nextflow.log' file for more details + -- Check script 'main.nf' at line: 13 or see '.nextflow.log' file for more details ``` This crashes with a NullPointerException. @@ -1838,18 +1932,27 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 - Launching `main.nf` [lonely_torricelli] DSL2 - revision: 309f496f9a - [85/8117bf] Submitted process > TRIMGALORE (1) - [20/714ab9] Submitted process > FASTP (1) - [ca/de6fd3] Submitted process > GENERATE_REPORT (1) - [ca/ff5356] Submitted process > FASTP (2) - [10/aa6ea8] Submitted process > GENERATE_REPORT (2) - [9f/baa7fb] Submitted process > GENERATE_REPORT (3) - [20/714ab9] NOTE: Process `FASTP (1)` terminated with an error exit status (137) -- Execution is retried (1) - [ca/ff5356] NOTE: Process `FASTP (2)` terminated with an error exit status (137) -- Execution is retried (1) - [f2/2a5d19] Re-submitted process > FASTP (1) - [44/b23306] Re-submitted process > FASTP (2) + N E X T F L O W ~ version 26.04.4 + Launching `main.nf` [serene_jennings] - revision: d7cb8ec312 + [6f/754af4] Submitted process > GENERATE_REPORT (2) + [fe/9b03c7] Submitted process > GENERATE_REPORT (1) + [5c/a9a73c] Submitted process > FASTP (2) + [f8/e8ad5e] Submitted process > GENERATE_REPORT (3) + [55/0e4155] Submitted process > TRIMGALORE (1) + [cb/e00b43] Submitted process > FASTP (1) + [cb/e00b43] NOTE: Process `FASTP (1)` terminated with an error exit status (137) -- Execution is retried (1) + [5c/a9a73c] NOTE: Process `FASTP (2)` terminated with an error exit status (137) -- Execution is retried (1) + [49/fb02c9] Re-submitted process > FASTP (1) + [e3/d3cf5f] Re-submitted process > FASTP (2) + + Outputs: + + /workspaces/training/side-quests/essential_scripting_patterns/results + + reports: + - reports/sample_001_report.txt + - reports/sample_002_report.txt + - reports/sample_003_report.txt ``` No crash! The workflow now handles the missing field gracefully. When `row.run_id` is `null`, the `?.` operator prevents the `.toUpperCase()` call, and `run_id` becomes `null` instead of causing an exception. @@ -2000,9 +2103,9 @@ nextflow run main.nf ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [confident_coulomb] DSL2 - revision: 07059399ed + Launching `main.nf` [golden_lamarck] revision: e1d7259d32 WARN: Access to undefined parameter `input` -- Initialise it to a default value eg. `params.input = some_value` Input CSV file path not provided. Please specify --input @@ -2019,9 +2122,9 @@ nextflow run main.nf --input ./data/nonexistent.csv ??? failure "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 - Launching `main.nf` [cranky_gates] DSL2 - revision: 26839ae3eb + Launching `main.nf` [admiring_avogadro] revision: e1d7259d32 Input CSV file not found: ./data/nonexistent.csv ``` @@ -2035,18 +2138,27 @@ nextflow run main.nf --input ./data/samples.csv ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 - Launching `main.nf` [dreamy_archimedes] DSL2 - revision: dc24727993 - [bc/0527b6] Submitted process > FASTP (2) - [65/5bb40c] Submitted process > GENERATE_REPORT (1) - [b3/aa7df2] Submitted process > GENERATE_REPORT (2) - [39/9d740f] Submitted process > GENERATE_REPORT (3) - [06/1c0d94] Submitted process > TRIMGALORE (1) - [0e/23c643] Submitted process > FASTP (1) - [0e/23c643] NOTE: Process `FASTP (1)` terminated with an error exit status (137) -- Execution is retried (1) - [bc/0527b6] NOTE: Process `FASTP (2)` terminated with an error exit status (137) -- Execution is retried (1) - [12/aa9122] Re-submitted process > FASTP (1) - [b5/1eba3b] Re-submitted process > FASTP (2) + N E X T F L O W ~ version 26.04.4 + Launching `main.nf` [sad_hopper] - revision: e1d7259d32 + [1d/48ab44] Submitted process > TRIMGALORE (1) + [94/f6f423] Submitted process > FASTP (1) + [ca/6bbfae] Submitted process > GENERATE_REPORT (1) + [25/18c80b] Submitted process > GENERATE_REPORT (3) + [11/caf770] Submitted process > FASTP (2) + [a6/16ae06] Submitted process > GENERATE_REPORT (2) + [11/caf770] NOTE: Process `FASTP (2)` terminated with an error exit status (137) -- Execution is retried (1) + [94/f6f423] NOTE: Process `FASTP (1)` terminated with an error exit status (137) -- Execution is retried (1) + [a3/cb724c] Re-submitted process > FASTP (2) + [d6/8baf95] Re-submitted process > FASTP (1) + + Outputs: + + /workspaces/training/side-quests/essential_scripting_patterns/results + + reports: + - reports/sample_001_report.txt + - reports/sample_003_report.txt + - reports/sample_002_report.txt ``` This time it runs successfully. @@ -2085,14 +2197,24 @@ nextflow run main.nf --input ./data/samples.csv ??? warning "Command output" ```console - N E X T F L O W ~ version 25.10.4 + N E X T F L O W ~ version 26.04.4 + + Launching `main.nf` [jolly_colden] revision: 608f36a239 + + executor > local (8) + [3b/e1586c] FASTP (2) | 2 of 2, retries: 2 ✔ + [8b/4286b3] TRIMGALORE (1) | 1 of 1 ✔ + [a0/761239] GENERATE_REPORT (3) | 3 of 3 ✔ + + Outputs: + + /workspaces/training/side-quests/essential_scripting_patterns/results - Launching `main.nf` [awesome_goldwasser] DSL2 - revision: a31662a7c1 + reports: + - reports/sample_003_report.txt + - reports/sample_002_report.txt + - reports/sample_001_report.txt - executor > local (5) - [ce/df5eeb] process > FASTP (2) [100%] 2 of 2 ✔ - [- ] process > TRIMGALORE - - [d1/7d2b4b] process > GENERATE_REPORT (3) [100%] 3 of 3 ✔ WARN: Low sequencing depth for sample_002: 25000000 ``` @@ -2168,22 +2290,37 @@ nextflow run main.nf --input ./data/samples.csv -ansi-log false ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 - Launching `main.nf` [marvelous_boltzmann] DSL2 - revision: a31662a7c1 + N E X T F L O W ~ version 26.04.4 + Launching `main.nf` [sleepy_sax] - revision: 7f4b2a0423 WARN: Low sequencing depth for sample_002: 25000000 - [9b/d48e40] Submitted process > FASTP (2) - [6a/73867a] Submitted process > GENERATE_REPORT (2) - [79/ad0ac5] Submitted process > GENERATE_REPORT (1) - [f3/bda6cb] Submitted process > FASTP (1) - [34/d5b52f] Submitted process > GENERATE_REPORT (3) + [1d/85ba4a] Submitted process > TRIMGALORE (1) + [4c/7c429a] Submitted process > FASTP (2) + [22/e7faf8] Submitted process > GENERATE_REPORT (1) + [2a/ade0b2] Submitted process > FASTP (1) + [1f/193864] Submitted process > GENERATE_REPORT (3) + [60/712f82] Submitted process > GENERATE_REPORT (2) + [2a/ade0b2] NOTE: Process `FASTP (1)` terminated with an error exit status (137) -- Execution is retried (1) + [4c/7c429a] NOTE: Process `FASTP (2)` terminated with an error exit status (137) -- Execution is retried (1) + [85/b96cbc] Re-submitted process > FASTP (1) + [a7/55b62e] Re-submitted process > FASTP (2) Pipeline execution summary: ========================== - Completed at: 2025-10-10T12:14:24.885384+01:00 - Duration : 2.9s + Completed at: 2026-06-23T15:49:52.574354708Z + Duration : 4.5s Success : true workDir : /workspaces/training/side-quests/essential_scripting_patterns/work exit status : 0 + + + Outputs: + + /workspaces/training/side-quests/essential_scripting_patterns/results + + reports: + - reports/sample_001_report.txt + - reports/sample_003_report.txt + - reports/sample_002_report.txt ``` Let's make it more useful by adding conditional logic: @@ -2252,24 +2389,38 @@ nextflow run main.nf ??? success "Command output" ```console - N E X T F L O W ~ version 25.10.4 - Launching `main.nf` [boring_linnaeus] DSL2 - revision: a31662a7c1 + N E X T F L O W ~ version 26.04.4 + Launching `main.nf` [hopeful_waddington] - revision: 442ec086c8 WARN: Low sequencing depth for sample_002: 25000000 - [e5/242efc] Submitted process > FASTP (2) - [3b/74047c] Submitted process > GENERATE_REPORT (3) - [8a/7a57e6] Submitted process > GENERATE_REPORT (1) - [a8/b1a31f] Submitted process > GENERATE_REPORT (2) - [40/648429] Submitted process > FASTP (1) + [e5/a71364] Submitted process > FASTP (1) + [81/c69cdc] Submitted process > FASTP (2) + [d1/368dff] Submitted process > GENERATE_REPORT (3) + [f0/19394e] Submitted process > TRIMGALORE (1) + [e3/679e45] Submitted process > GENERATE_REPORT (2) + [48/406c85] Submitted process > GENERATE_REPORT (1) + [81/c69cdc] NOTE: Process `FASTP (2)` terminated with an error exit status (137) -- Execution is retried (1) + [e5/a71364] NOTE: Process `FASTP (1)` terminated with an error exit status (137) -- Execution is retried (1) + [f8/b10ac0] Re-submitted process > FASTP (2) + [9e/49f6e2] Re-submitted process > FASTP (1) Pipeline execution summary: ========================== - Completed at: 2025-10-10T12:16:00.522569+01:00 - Duration : 3.6s + Completed at: 2026-06-23T15:50:06.811854363Z + Duration : 4.4s Success : true workDir : /workspaces/training/side-quests/essential_scripting_patterns/work exit status : 0 ✅ Pipeline completed successfully! + + Outputs: + + /workspaces/training/side-quests/essential_scripting_patterns/results + + reports: + - reports/sample_003_report.txt + - reports/sample_002_report.txt + - reports/sample_001_report.txt ``` You can also write the summary to a file using file operations: From b7c54fce0022537ecc3fb18e281ee677b6b003bb Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 17:12:45 +0100 Subject: [PATCH 28/42] docs(side_quests): fix buggy_workflow error sequence + bad_resources prose for v2 static type checking [skip ci] --- docs/en/docs/side_quests/debugging/index.md | 61 ++++++++++++--------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/docs/en/docs/side_quests/debugging/index.md b/docs/en/docs/side_quests/debugging/index.md index f6f379f9a9..b46700244e 100644 --- a/docs/en/docs/side_quests/debugging/index.md +++ b/docs/en/docs/side_quests/debugging/index.md @@ -1786,7 +1786,7 @@ nextflow run bad_resources.nf -profile docker [96/b70b83] PROCESS_FILES (3) | 3 of 3 ✔ ``` -If you make sure to read your error messages failures like this should not puzzle you for too long. But make sure you understand the resource requirements of the commands you are running so that you can configure your resource directives appropriately. +On the `local` executor the error is less explicit than it would be on a scheduler: you get `process hasn't exited` and `WARN: Killing running tasks` rather than a message that names the time limit. The connection to make is that Nextflow kills a task when it overruns the resources you gave it, so when a process is terminated without a script-level error, check its resource directives. Here the culprit is the `time` directive, which is far too low for the work the process does. Make sure you understand the resource requirements of the commands you are running so that you can configure your resource directives appropriately. ### 3.4. Process Debugging Techniques @@ -2290,7 +2290,7 @@ Now it's time to put the systematic debugging approach into practice. The workfl ``` ??? solution - The `buggy_workflow.nf` contains 9 or 10 distinct errors (depending how you count) covering all major debugging categories. Here's a systematic breakdown of each error and how to fix it + The `buggy_workflow.nf` contains 10 distinct errors covering all major debugging categories. Here's a systematic breakdown of each error and how to fix it, in the order you actually encounter them on Nextflow 26.04. The compiler resolves the workflow in two passes: first it parses the syntax, then it statically checks that every variable is defined. So you clear the syntax errors first, then a batch of undefined-variable errors, before the workflow runs at all and the runtime errors begin. Let's start with those syntax errors: @@ -2305,6 +2305,8 @@ Now it's time to put the systematic debugging approach into practice. The workfl path "${sample_id}_result.txt" ``` + With the comma gone, the parser runs to the end of the file looking for the brace that should close `processFiles` and reports `Unexpected input: ''`. + **Error 2: Syntax Error - Missing Closing Brace** ```groovy linenums="24" script: @@ -2323,6 +2325,17 @@ Now it's time to put the systematic debugging approach into practice. The workfl } // Add missing closing brace ``` + Now the syntax parses, so the static type checker runs. It reports every undefined variable at once, before the workflow runs: + + ```console + Error buggy_workflow.nf:86:29: `sample_ids` is not defined + Error buggy_workflow.nf:27:25: `sample` is not defined + Error buggy_workflow.nf:28:27: `sample` is not defined + Error buggy_workflow.nf:49:33: `i` is not defined + ``` + + These four lines correspond to three distinct bugs, Errors 3, 4 and 5 below. The last of them, `i`, is a Bash variable that the type checker can't tell apart from a Nextflow variable, so it surfaces here at compile time rather than as a runtime failure. Fix all three before re-running. + **Error 3: Variable Name Error** ```groovy linenums="26" echo "Processing: ${sample}" // ERROR: should be sample_id @@ -2338,14 +2351,23 @@ Now it's time to put the systematic debugging approach into practice. The workfl ```groovy linenums="87" heavy_ch = heavyProcess(sample_ids) // ERROR: sample_ids undefined ``` - **Fix:** Use the correct channel and extract sample IDs + **Fix:** Use the correct channel ```groovy linenums="87" heavy_ch = heavyProcess(input_ch) ``` - At this point the workflow will run, but we'll still be getting errors (e.g. `Path value cannot be null` in `processFiles`), caused by bad channel structure. + **Error 5: Bash Variable Escaping Error** + ```groovy linenums="48" + echo "Heavy computation $i for ${sample_id}" // ERROR: $i looks like an undefined Nextflow variable + ``` + **Fix:** Escape the bash variable so Nextflow leaves it for the shell + ```groovy linenums="48" + echo "Heavy computation \${i} for ${sample_id}" + ``` + + With those resolved the workflow compiles and starts to run. The first runtime error comes from `processFiles`, which expects a tuple but is being fed a bare value: `Input tuple does not match tuple declaration in process 'processFiles' -- offending value: sample_003`. - **Error 5: Channel Structure Error - Wrong Map Output** + **Error 6: Channel Structure Error - Wrong Map Output** ```groovy linenums="83" .map { row -> row.sample_id } // ERROR: processFiles expects tuple ``` @@ -2354,29 +2376,18 @@ Now it's time to put the systematic debugging approach into practice. The workfl .map { row -> [row.sample_id, file(row.fastq_path)] } ``` - But this will break our for for running `heavyProcess()` above, so we'll need to use a map to pass just the sample IDs to that process: + That fixes `processFiles`, but `input_ch` now emits a two-element tuple, and `heavyProcess` is still being handed the whole tuple where it expects a single value. The tuple gets rendered into the script as `[sample_005, /path/sample_005.fastq.gz]`, which breaks the Bash command with a syntax error and an exit status of 2. - **Error 6: Bad channel structure for heavyProcess** + **Error 7: Bad channel structure for heavyProcess** ```groovy linenums="87" - heavy_ch = heavyProcess(input_ch) // ERROR: input_ch now has 2 elements per emission- heavyProcess only needs 1 (the first) + heavy_ch = heavyProcess(input_ch) // ERROR: input_ch now emits a 2-element tuple; heavyProcess needs only the first element ``` - **Fix:** Use the correct channel and extract sample IDs + **Fix:** Pass just the sample IDs ```groovy linenums="87" heavy_ch = heavyProcess(input_ch.map{it[0]}) ``` - Now we get a but further but receive an error about `No such variable: i`, because we didn't escape a Bash variable. - - **Error 7: Bash Variable Escaping Error** - ```groovy linenums="48" - echo "Heavy computation $i for ${sample_id}" // ERROR: $i not escaped - ``` - **Fix:** Escape the bash variable - ```groovy linenums="48" - echo "Heavy computation \${i} for ${sample_id}" - ``` - - Now `heavyProcess` hits its time limit and we get `process hasn't exited` (alongside a `WARN: Killing running tasks` message), so we fix the run time limit for the relevant process: + Now `heavyProcess` runs, but hits its time limit. On the `local` executor the message is `process hasn't exited` (alongside a `WARN: Killing running tasks` message) rather than an explicit timeout, so connect the killed task back to its `time` directive: **Error 8: Resource Configuration Error** ```groovy linenums="36" @@ -2387,7 +2398,7 @@ Now it's time to put the systematic debugging approach into practice. The workfl time '100 s' ``` - Next we have a `Missing output file(s)` error to resolve: + Next we have a `Missing output file(s)` error to resolve, because the script writes `${sample_id}.txt` but the output declaration expects `${sample_id}_heavy.txt`: **Error 9: Output File Name Mismatch** ```groovy linenums="49" @@ -2398,9 +2409,9 @@ Now it's time to put the systematic debugging approach into practice. The workfl done > ${sample_id}_heavy.txt ``` - The first two processes ran, but not the third. + The workflow now completes without an error, but the `files` output is empty: `handleFiles` never ran. Its input channel, `channel.fromPath("*.txt")`, matches no files in the launch directory, so the process is simply skipped rather than failing loudly. - **Error 10: Output File Name Mismatch** + **Error 10: Wrong Channel Source** ```groovy linenums="88" file_ch = channel.fromPath("*.txt") // Error: attempting to take input from the pwd rather than a process handleFiles(file_ch) @@ -2410,7 +2421,7 @@ Now it's time to put the systematic debugging approach into practice. The workfl file_ch = handleFiles(heavy_ch) ``` - With that, the whole workflow should run. + With that, the whole workflow runs end to end and all three outputs are populated. **Complete Corrected Workflow:** ```groovy linenums="1" From 001de7f1545c1294bc67b9156a74439d9b5d36b3 Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 17:12:58 +0100 Subject: [PATCH 29/42] ci: re-run checks after master merge + side-quest re-verification Co-Authored-By: Claude Opus 4.8 From 988c7780f6aecc410e71f9e35dc934a7a550d2b4 Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 17:44:17 +0100 Subject: [PATCH 30/42] docs(nf4_science/imaging): bring molkart course to 26.04, v2-clean via typed params.yaml Validated end-to-end on native x86 (22-task molkart run). Resolves the v2 integer-param typing issue (--flag value ints arrive as strings under the v2 parser) by switching documented commands to a typed params.yaml; also fixes a fabricated resume block and a wrong task count. [skip ci] --- docs/en/docs/nf4_science/imaging/01_basics.md | 35 ++-- .../nf4_science/imaging/02_run_molkart.md | 174 +++++++++--------- docs/en/docs/nf4_science/imaging/03_inputs.md | 25 ++- docs/en/docs/nf4_science/imaging/04_config.md | 11 +- nf4-science/imaging/params.yaml | 5 + 5 files changed, 124 insertions(+), 126 deletions(-) diff --git a/docs/en/docs/nf4_science/imaging/01_basics.md b/docs/en/docs/nf4_science/imaging/01_basics.md index 1690d12c2b..f19d9a4b14 100644 --- a/docs/en/docs/nf4_science/imaging/01_basics.md +++ b/docs/en/docs/nf4_science/imaging/01_basics.md @@ -18,12 +18,12 @@ nextflow run hello-world.nf --greeting 'Hello World!' Your console output should look something like this: ```console title="Output" linenums="1" - N E X T F L O W ~ version 25.04.3 + N E X T F L O W ~ version 26.04.4 -Launching `hello-world.nf` [goofy_torvalds] DSL2 - revision: c33d41f479 +Launching `hello-world.nf` [small_swirles] revision: 0fb8dbb23d executor > local (1) -[a3/7be2fa] sayHello | 1 of 1 ✔ +[71/8143bd] sayHello | 1 of 1 ✔ ``` Congratulations, you just ran your first Nextflow workflow! @@ -31,7 +31,7 @@ Congratulations, you just ran your first Nextflow workflow! The most important output here is the last line (line 6): ```console title="Output" linenums="6" -[a3/7be2fa] sayHello | 1 of 1 ✔ +[71/8143bd] sayHello | 1 of 1 ✔ ``` This tells us that the `sayHello` process was successfully executed once (`1 of 1 ✔`). @@ -82,19 +82,19 @@ That may sound confusing, so let's see what that looks like in practice. Going back to the console output for the workflow we ran earlier, we had this line: ```console title="Excerpt of command output" linenums="6" -[a3/7be2fa] sayHello | 1 of 1 ✔ +[71/8143bd] sayHello | 1 of 1 ✔ ``` -See how the line starts with `[a3/7be2fa]`? +See how the line starts with `[71/8143bd]`? That is a truncated form of the task directory path for that one process call, and tells you where to find the output of the `sayHello` process call within the `work/` directory path. -You can find the full path by typing the following command (replacing `a3/7be2fa` with what you see in your own terminal) and pressing the tab key to autocomplete the path or adding an asterisk: +You can find the full path by typing the following command (replacing `71/8143bd` with what you see in your own terminal) and pressing the tab key to autocomplete the path or adding an asterisk: ```bash -tree work/a3/7be2fa* +tree work/71/8143bd* ``` -This should yield the full path directory path: `work/a3/7be2fa7be2fad5e71e5f49998f795677fd68` +This should yield the full path directory path: `work/71/8143bd5ed3420e23c5f0dc1a05056d` Let's take a look at what's in there. @@ -114,8 +114,8 @@ The exact subdirectory names will be different on your system. ```console title="work/" work -└── a3 - └── 7be2fad5e71e5f49998f795677fd68 +└── 71 + └── 8143bd5ed3420e23c5f0dc1a05056d ├── .command.begin ├── .command.err ├── .command.log @@ -134,7 +134,7 @@ If you open it, you will find the `Hello World!` greeting again.
File contents of output.txt -```console title="work/a3/7be2fa7be2fad5e71e5f49998f795677fd68/output.txt" linenums="1" +```console title="work/71/8143bd5ed3420e23c5f0dc1a05056d/output.txt" linenums="1" Hello World! ``` @@ -157,10 +157,9 @@ The `.command.sh` file is especially useful because it shows you the main comman
File contents -```console title="work/a3/7be2fa7be2fad5e71e5f49998f795677fd68/.command.sh" linenums="1" +```console title="work/71/8143bd5ed3420e23c5f0dc1a05056d/.command.sh" linenums="1" #!/bin/bash -ue echo 'Hello World!' > output.txt - ```
@@ -355,14 +354,14 @@ nextflow run hello-world.nf --greeting 'Hello World!' -resume ??? success "Command output" ```console - N E X T F L O W ~ version 25.04.3 + N E X T F L O W ~ version 26.04.4 - Launching `hello-world.nf` [tiny_noyce] DSL2 - revision: c33d41f479 + Launching `hello-world.nf` [maniac_pasteur] revision: 0fb8dbb23d - [a3/7be2fa] process > sayHello [100%] 1 of 1, cached: 1 ✔ + [71/8143bd] sayHello | 1 of 1, cached: 1 ✔ ``` -Look for the `cached:` bit that has been added in the process status line (line 5), which means that Nextflow has recognized that it has already done this work and simply reused the result from the previous successful run. +Look for the `cached:` bit that has been added in the process status line, which means that Nextflow has recognized that it has already done this work and simply reused the result from the previous successful run. You can also see that the work subdirectory hash is the same as in the previous run. Nextflow is literally pointing you to the previous execution and saying "I already did that over there." diff --git a/docs/en/docs/nf4_science/imaging/02_run_molkart.md b/docs/en/docs/nf4_science/imaging/02_run_molkart.md index 02c21f75fb..0394de693b 100644 --- a/docs/en/docs/nf4_science/imaging/02_run_molkart.md +++ b/docs/en/docs/nf4_science/imaging/02_run_molkart.md @@ -68,26 +68,34 @@ This creates a `molkart/` directory containing the complete pipeline source code Before running the full pipeline, let's learn why containers are essential for nf-core pipelines. -Let's try running the pipeline using the test dataset and parameters from the molkart test configuration: - -```bash -nextflow run ./molkart \ - --input 'data/samplesheet.csv' \ - --mindagap_tilesize 90 \ - --mindagap_boxsize 7 \ - --mindagap_loopnum 100 \ - --clahe_pyramid_tile 368 \ - --segmentation_method "mesmer,cellpose,stardist" \ - --outdir results +We'll supply the pipeline's parameters using a parameter file. +A parameter file is a YAML file that lists each parameter and its value, which keeps typed values (such as integers) intact and keeps the command line short. + +A `params.yaml` file is already provided in the working directory: + +```yaml title="params.yaml" +input: "data/samplesheet.csv" +outdir: "results" +mindagap_tilesize: 90 +mindagap_boxsize: 7 +mindagap_loopnum: 100 +clahe_pyramid_tile: 368 +segmentation_method: "cellpose" ``` -Let's break down these parameters: +These parameters are: + +- `input`: Path to the samplesheet containing sample metadata +- `mindagap_tilesize`, `mindagap_boxsize`, `mindagap_loopnum`: Parameters for grid pattern filling +- `clahe_pyramid_tile`: Kernel size for contrast enhancement +- `segmentation_method`: Which algorithm(s) to use for cell segmentation +- `outdir`: Where to save the results + +Let's try running the pipeline using these parameters: -- `--input`: Path to the samplesheet containing sample metadata -- `--mindagap_tilesize`, `--mindagap_boxsize`, `--mindagap_loopnum`: Parameters for grid pattern filling -- `--clahe_pyramid_tile`: Kernel size for contrast enhancement -- `--segmentation_method`: Which algorithm(s) to use for cell segmentation -- `--outdir`: Where to save the results +```bash +nextflow run ./molkart -params-file params.yaml +``` !!! Warning "This command will fail - that's intentional!" @@ -170,17 +178,10 @@ process { } ``` -Now run the pipeline again with the same command: +Now run the pipeline again, this time running all three segmentation methods so we can compare them later: ```bash -nextflow run ./molkart \ - --input 'data/samplesheet.csv' \ - --mindagap_tilesize 90 \ - --mindagap_boxsize 7 \ - --mindagap_loopnum 100 \ - --clahe_pyramid_tile 368 \ - --segmentation_method "cellpose,mesmer,stardist" \ - --outdir results +nextflow run ./molkart -params-file params.yaml --segmentation_method "mesmer,cellpose,stardist" ``` This time, Nextflow will: @@ -207,12 +208,13 @@ As the pipeline runs, you'll see output similar to this: ??? success "Command output" ```console - Nextflow 25.04.8 is available - Please consider updating your version to it + N E X T F L O W ~ version 26.04.4 - N E X T F L O W ~ version 25.04.3 - - Launching `https://github.com/nf-core/molkart` [soggy_kalam] DSL2 - revision: 5e54b29cb3 [dev] + Launching `./molkart/main.nf` [exotic_banach] revision: e4152308ec + WARN: Unrecognized config option 'validation.help.enabled' + WARN: Unrecognized config option 'validation.defaultIgnoreParams' + WARN: Unrecognized config option 'validation.monochromeLogs' ------------------------------------------------------ ,--./,-. @@ -220,39 +222,34 @@ As the pipeline runs, you'll see output similar to this: |\ | |__ __ / ` / \ |__) |__ } { | \| | \__, \__/ | \ |___ \`-._,-`-, `._,._,' - nf-core/molkart 1.2.0dev + nf-core/molkart 1.2.0 ------------------------------------------------------ Segmentation methods and options - segmentation_method : mesmer,cellpose,stardist + segmentation_method: mesmer,cellpose,stardist Image preprocessing - mindagap_boxsize : 7 - mindagap_loopnum : 100 - clahe_kernel : 25 - mindagap_tilesize : 90 - clahe_pyramid_tile : 368 + mindagap_boxsize : 7 + mindagap_loopnum : 100 + clahe_kernel : 25 + mindagap_tilesize : 90 + clahe_pyramid_tile : 368 Input/output options - input : https://raw.githubusercontent.com/nf-core/test-datasets/molkart/test_data/samplesheets/samplesheet_membrane.csv - outdir : results - - Institutional config options - config_profile_name : Test profile - config_profile_description: Minimal test dataset to check pipeline function + input : data/samplesheet.csv + outdir : results Generic options - trace_report_suffix : 2025-10-18_22-22-21 + trace_report_suffix: 2026-06-23_16-25-30 Core Nextflow options - revision : dev - runName : soggy_kalam - containerEngine : docker - launchDir : /workspaces/training/nf4-science/imaging - workDir : /workspaces/training/nf4-science/imaging/work - projectDir : /workspaces/.nextflow/assets/nf-core/molkart - userName : root - profile : docker,test - configFiles : + runName : exotic_banach + containerEngine : docker + launchDir : /workspaces/training/nf4-science/imaging + workDir : /workspaces/training/nf4-science/imaging/work + projectDir : /workspaces/training/nf4-science/imaging/molkart + userName : root + profile : standard + configFiles : /workspaces/training/nf4-science/imaging/molkart/nextflow.config, /workspaces/training/nf4-science/imaging/nextflow.config !! Only displaying parameters that differ from the pipeline defaults !! ------------------------------------------------------ @@ -266,22 +263,22 @@ As the pipeline runs, you'll see output similar to this: https://github.com/nf-core/molkart/blob/master/CITATIONS.md executor > local (22) - [c1/da5009] NFCORE_MOLKART:MOLKART:MINDAGAP_MINDAGAP (mem_only) [100%] 2 of 2 ✔ - [73/8f5e8a] NFCORE_MOLKART:MOLKART:CLAHE (mem_only) [100%] 2 of 2 ✔ - [ec/8f84d5] NFCORE_MOLKART:MOLKART:CREATE_STACK (mem_only) [100%] 1 of 1 ✔ - [a2/99349b] NFCORE_MOLKART:MOLKART:MINDAGAP_DUPLICATEFINDER (mem_only) [100%] 1 of 1 ✔ - [95/c9b4b1] NFCORE_MOLKART:MOLKART:DEEPCELL_MESMER (mem_only) [100%] 1 of 1 ✔ - [d4/1ebd1e] NFCORE_MOLKART:MOLKART:STARDIST (mem_only) [100%] 1 of 1 ✔ - [3e/3c0736] NFCORE_MOLKART:MOLKART:CELLPOSE (mem_only) [100%] 1 of 1 ✔ - [a0/415c6a] NFCORE_MOLKART:MOLKART:MASKFILTER (mem_only) [100%] 3 of 3 ✔ - [14/a830c9] NFCORE_MOLKART:MOLKART:SPOT2CELL (mem_only) [100%] 3 of 3 ✔ - [b5/391836] NFCORE_MOLKART:MOLKART:CREATE_ANNDATA (mem_only) [100%] 3 of 3 ✔ - [77/aed558] NFCORE_MOLKART:MOLKART:MOLKARTQC (mem_only) [100%] 3 of 3 ✔ - [e6/b81475] NFCORE_MOLKART:MOLKART:MULTIQC [100%] 1 of 1 ✔ + [b4/e57ff1] NFC…NDAGAP_MINDAGAP (mem_only) | 2 of 2 ✔ + [2e/cf8910] NFC…T:MOLKART:CLAHE (mem_only) | 2 of 2 ✔ + [94/b1ef70] NFC…RT:CREATE_STACK (mem_only) | 1 of 1 ✔ + [58/4b6426] NFC…DUPLICATEFINDER (mem_only) | 1 of 1 ✔ + [c2/ef7002] NFC…DEEPCELL_MESMER (mem_only) | 1 of 1 ✔ + [4f/ddd328] NFC…OLKART:STARDIST (mem_only) | 1 of 1 ✔ + [8c/dd0362] NFC…OLKART:CELLPOSE (mem_only) | 1 of 1 ✔ + [08/2ddcb5] NFC…KART:MASKFILTER (mem_only) | 3 of 3 ✔ + [56/e30de0] NFC…LKART:SPOT2CELL (mem_only) | 3 of 3 ✔ + [b0/5aa635] NFC…:CREATE_ANNDATA (mem_only) | 3 of 3 ✔ + [5e/39d5d0] NFC…LKART:MOLKARTQC (mem_only) | 3 of 3 ✔ + [8e/8bd365] NFCORE_MOLKART:MOLKART:MULTIQC | 1 of 1 ✔ -[nf-core/molkart] Pipeline completed successfully- - Completed at: 19-Oct-2025 22:23:01 - Duration : 2m 52s - CPU hours : 0.1 + Completed at: 23-Jun-2026 16:31:40 + Duration : 6m 9s + CPU hours : (a few seconds) Succeeded : 22 ``` @@ -301,10 +298,10 @@ The executor line `executor > local (22)` tells you: Each process line shows: -- **Hash** (`[1a/2b3c4d]`): Work directory identifier (like before) +- **Hash** (`[b4/e57ff1]`): Work directory identifier (like before) - **Process name**: Full module path and process name - **Input identifier**: Sample name in parentheses -- **Progress**: Percentage complete and count (e.g., `1 of 1 ✔`) +- **Progress**: Task count and completion status (e.g., `1 of 1 ✔`) ### Takeaway @@ -445,7 +442,7 @@ Just like with our Hello World example, all the actual work happens in the `work ### 4.1. Understanding work directory structure The work directory contains a subdirectory for each task that was executed. -For this pipeline with 12 tasks, there will be 12 work subdirectories. +For this pipeline run with 22 tasks, there will be 22 work subdirectories. List the work directory: @@ -515,30 +512,29 @@ This is essential for long-running pipelines where failures might occur late in Run the same command again, but add `-resume`: ```bash -nextflow run ./molkart \ - --input 'data/samplesheet.csv' \ - --mindagap_tilesize 90 \ - --mindagap_boxsize 7 \ - --mindagap_loopnum 100 \ - --clahe_pyramid_tile 368 \ - --segmentation_method "cellpose" \ - --outdir results \ - -resume +nextflow run ./molkart -params-file params.yaml --segmentation_method "mesmer,cellpose,stardist" -resume ``` -You should see output like: +You should see output like: ```console -executor > local (0) -[1a/2b3c4d] NFCORE_MOLKART:MOLKART:MINDAGAP_MINDAGAP (mem_only) [100%] 2 of 2, cached: 2 ✔ -[5e/6f7g8h] NFCORE_MOLKART:MOLKART:CLAHE (mem_only) [100%] 2 of 2, cached: 2 ✔ -[7f/8g9h0i] NFCORE_MOLKART:MOLKART:CREATE_STACK (mem_only) [100%] 1 of 1, cached: 1 ✔ -[9h/0i1j2k] NFCORE_MOLKART:MOLKART:MINDAGAP_DUPLICATEFINDER (mem_only) [100%] 1 of 1, cached: 1 ✔ -[2k/3l4m5n] NFCORE_MOLKART:MOLKART:CELLPOSE (mem_only) [100%] 1 of 1, cached: 1 ✔ -... +executor > local (1) +[43/e03702] NFC…NDAGAP_MINDAGAP (mem_only) | 2 of 2, cached: 2 ✔ +[2e/cf8910] NFC…T:MOLKART:CLAHE (mem_only) | 2 of 2, cached: 2 ✔ +[94/b1ef70] NFC…RT:CREATE_STACK (mem_only) | 1 of 1, cached: 1 ✔ +[58/4b6426] NFC…DUPLICATEFINDER (mem_only) | 1 of 1, cached: 1 ✔ +[c2/ef7002] NFC…DEEPCELL_MESMER (mem_only) | 1 of 1, cached: 1 ✔ +[4f/ddd328] NFC…OLKART:STARDIST (mem_only) | 1 of 1, cached: 1 ✔ +[8c/dd0362] NFC…OLKART:CELLPOSE (mem_only) | 1 of 1, cached: 1 ✔ +[08/2ddcb5] NFC…KART:MASKFILTER (mem_only) | 3 of 3, cached: 3 ✔ +[56/e30de0] NFC…LKART:SPOT2CELL (mem_only) | 3 of 3, cached: 3 ✔ +[b0/5aa635] NFC…:CREATE_ANNDATA (mem_only) | 3 of 3, cached: 3 ✔ +[5e/39d5d0] NFC…LKART:MOLKARTQC (mem_only) | 3 of 3, cached: 3 ✔ +[73/239f45] NFCORE_MOLKART:MOLKART:MULTIQC | 1 of 1 ✔ +-[nf-core/molkart] Pipeline completed successfully- ``` -Notice `cached: 2` or `cached: 1` for each process - nothing was re-executed! +Notice the `cached: N` annotation on each preprocessing and segmentation process - those tasks were reused rather than re-executed. ### 5.3. When resume is useful diff --git a/docs/en/docs/nf4_science/imaging/03_inputs.md b/docs/en/docs/nf4_science/imaging/03_inputs.md index 85882230b5..bc60fe8451 100644 --- a/docs/en/docs/nf4_science/imaging/03_inputs.md +++ b/docs/en/docs/nf4_science/imaging/03_inputs.md @@ -7,26 +7,20 @@ Now we'll learn two better approaches for managing inputs: **parameter files** a ### 1.1. The problem with long command lines -Recall our command from Part 2: +In Part 2 we already used a parameter file to keep the command short and keep typed values (such as the integer preprocessing parameters) intact: ```bash -nextflow run ./molkart \ - --input 'data/samplesheet.csv' \ - --mindagap_tilesize 90 \ - --mindagap_boxsize 7 \ - --mindagap_loopnum 100 \ - --clahe_pyramid_tile 368 \ - --segmentation_method "cellpose" \ - --outdir results +nextflow run ./molkart -params-file params.yaml --segmentation_method "mesmer,cellpose,stardist" ``` -This works, but it's hard to reproduce, share, or modify. +Passing many parameters individually on the command line is hard to reproduce, share, or modify. What if you need to run the same analysis again next month? What if a collaborator wants to use your exact settings? +A parameter file solves this. -### 1.2. Solution: Use a parameter file +### 1.2. The parameter file -Create a file called `params.yaml`: +Here is the `params.yaml` file we have been using: ```yaml title="params.yaml" input: "data/samplesheet.csv" @@ -38,13 +32,16 @@ clahe_pyramid_tile: 368 segmentation_method: "cellpose" ``` -Now your command becomes: +Each parameter is written as a `key: value` pair. +Writing integers without quotes (for example `mindagap_tilesize: 90`) preserves their integer type, which the pipeline's parameter validation requires. + +Your command becomes: ```bash nextflow run ./molkart -params-file params.yaml -resume ``` -That's it! The parameter file documents your exact configuration and makes it easy to rerun or share. +The parameter file documents your exact configuration and makes it easy to rerun or share. ### 1.3. Overriding parameters diff --git a/docs/en/docs/nf4_science/imaging/04_config.md b/docs/en/docs/nf4_science/imaging/04_config.md index f174340350..9e19f9b2fb 100644 --- a/docs/en/docs/nf4_science/imaging/04_config.md +++ b/docs/en/docs/nf4_science/imaging/04_config.md @@ -129,15 +129,16 @@ Because we're using `-resume`, Nextflow will check if anything changed since the If the parameters, inputs, and code are the same, all tasks will be retrieved from cache and the pipeline will complete almost instantly. ```console title="Output (excerpt)" -executor > local (12) -... -[1a/2b3c4d] NFCORE_MOLKART:MOLKART:MINDAGAP_MINDAGAP (mem_only) [100%] 2 of 2, cached: 2 ✔ -[5e/6f7g8h] NFCORE_MOLKART:MOLKART:CLAHE (mem_only) [100%] 2 of 2, cached: 2 ✔ +executor > local (1) +[43/e03702] NFC…NDAGAP_MINDAGAP (mem_only) | 2 of 2, cached: 2 ✔ +[2e/cf8910] NFC…T:MOLKART:CLAHE (mem_only) | 2 of 2, cached: 2 ✔ ... +[5e/39d5d0] NFC…LKART:MOLKARTQC (mem_only) | 3 of 3, cached: 3 ✔ +[ef/d7b294] NFCORE_MOLKART:MOLKART:MULTIQC | 1 of 1 ✔ -[nf-core/molkart] Pipeline completed successfully- ``` -Notice all processes show `cached: 2` or `cached: 1` - nothing was re-executed! +Notice the `cached: N` annotation on each process - the cached preprocessing and segmentation tasks were not re-executed. ### 2.4. Test profiles diff --git a/nf4-science/imaging/params.yaml b/nf4-science/imaging/params.yaml index 533f617033..8c0f7646be 100644 --- a/nf4-science/imaging/params.yaml +++ b/nf4-science/imaging/params.yaml @@ -1,3 +1,8 @@ # Example parameter file for nf-core/molkart input: "data/samplesheet.csv" outdir: "results" +mindagap_tilesize: 90 +mindagap_boxsize: 7 +mindagap_loopnum: 100 +clahe_pyramid_tile: 368 +segmentation_method: "cellpose" From 5b962261db5312688a0614f70e2f7d7c528462fa Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 17:45:03 +0100 Subject: [PATCH 31/42] ci: re-run checks after folding imaging into the bump Co-Authored-By: Claude Opus 4.8 From 9b485e32f67af546331e2c27ecd54ee9205aed4a Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 23 Jun 2026 18:09:31 +0100 Subject: [PATCH 32/42] feat(hello_nf-core): migrate course docs to nf-core 4.0.2 + v2 parser Runs under the 26.04 default v2 parser (no NXF_SYNTAX_PARSER=v1). Boolean params set via params-file/config instead of bare CLI flags (which the v2 parser types as strings). Orientation rewritten to v2 + nf-core 4.0.2; devcontainer pin -> 4.0.2. All console output regenerated from genuine 4.0.2/v2 runs on x86. [skip ci] --- .../local-features/uv-tools/install.sh | 2 +- docs/en/docs/hello_nf-core/00_orientation.md | 25 +- docs/en/docs/hello_nf-core/01_run_demo.md | 91 ++++--- .../en/docs/hello_nf-core/02_rewrite_hello.md | 224 ++++++++++-------- docs/en/docs/hello_nf-core/03_use_module.md | 117 +++++---- docs/en/docs/hello_nf-core/04_make_module.md | 50 ++-- .../docs/hello_nf-core/05_input_validation.md | 45 ++-- 7 files changed, 309 insertions(+), 245 deletions(-) diff --git a/.devcontainer/local-features/uv-tools/install.sh b/.devcontainer/local-features/uv-tools/install.sh index 8537c04973..256cf0ca48 100644 --- a/.devcontainer/local-features/uv-tools/install.sh +++ b/.devcontainer/local-features/uv-tools/install.sh @@ -3,5 +3,5 @@ # Install python cli tools using uv uv tool install pre-commit -uv tool install nf-core==3.5.2 +uv tool install nf-core==4.0.2 uv tool install "mkdocs-quiz>=1.5.2" diff --git a/docs/en/docs/hello_nf-core/00_orientation.md b/docs/en/docs/hello_nf-core/00_orientation.md index 836c42dc48..e553ba4799 100644 --- a/docs/en/docs/hello_nf-core/00_orientation.md +++ b/docs/en/docs/hello_nf-core/00_orientation.md @@ -20,24 +20,17 @@ If you are working through this course by yourself, please acquaint yourself wit ### Version requirements -This training works with **Nextflow 25.10.2** or later and **requires the v1 syntax parser**, because the nf-core conventions used in this course are not yet compatible with the v2 parser. -From Nextflow 26.04 the v2 parser is the default, so you must explicitly select v1 as shown below. +This training works with Nextflow 25.10.2 or later **with the v2 syntax parser**, which is the default from Nextflow 26.04 onward. +In our training environment you don't need to do anything: it runs Nextflow 26.04.4 with the v2 parser. If you are using a local or custom environment, see the [version notes](../info/nxf_versions.md). -#### If you are using our training environment: +!!! warning "Setting boolean parameters on the command line" -You MUST run the following command before going any further: + With the v2 syntax parser, a value passed on the command line is always read as text. + A boolean parameter passed as a bare flag or as `--flag value` (for example `--skip_trim` or `--validate_params false`) is therefore read as the string `"true"` or `"false"` and will not behave as you expect. + Set boolean parameters in a `-params-file` or in the configuration instead, where they keep their real boolean type. + This course uses that pattern throughout. -```bash -export NXF_SYNTAX_PARSER=v1 -``` - -On Nextflow 26.04 and later this is essential: it overrides the v2 parser that those versions enable by default (our training environment sets `NXF_SYNTAX_PARSER=v2` for the other courses). - -#### If you are using a local or custom environment: - -Please make sure you are using the correct settings as documented [here](../info/nxf_versions.md). - -The training additionally requires **nf-core tools 3.5.2**. +This training additionally requires **nf-core tools 4.0.2**. If you use a different version of nf-core tooling, you may have difficulty following along. You can check what version is installed in your environment using the command `nf-core --version`. @@ -113,7 +106,7 @@ Think you're ready to dive in? - [ ] I understand the goal of this course and its prerequisites - [ ] My environment is up and running -- [ ] I've made certain that the syntax parser is set to **v1** +- [ ] I'm using nf-core tools 4.0.2 (check with `nf-core --version`) - [ ] I've set my working directory appropriately If you can check all the boxes, you're good to go. diff --git a/docs/en/docs/hello_nf-core/01_run_demo.md b/docs/en/docs/hello_nf-core/01_run_demo.md index dab1298dd2..7735e9e95f 100644 --- a/docs/en/docs/hello_nf-core/01_run_demo.md +++ b/docs/en/docs/hello_nf-core/01_run_demo.md @@ -123,6 +123,14 @@ nextflow info nf-core/demo local path : /workspaces/.nextflow/assets/.repos/nf-core/demo main script : main.nf description : An nf-core demo pipeline + revisions : + TEMPLATE + dev + > master (default) + 1.0.0 [t] + 1.0.1 [t] + 1.0.2 [t] + > 1.1.0 [t] ``` !!! note @@ -159,25 +167,27 @@ tree -L 1 pipelines/nf-core/demo ```console pipelines/nf-core/demo - ├── assets ├── CHANGELOG.md ├── CITATIONS.md ├── CODE_OF_CONDUCT.md + ├── LICENSE + ├── README.md + ├── assets ├── conf ├── docs - ├── LICENSE ├── main.nf ├── modules ├── modules.json ├── nextflow.config ├── nextflow_schema.json ├── nf-test.config - ├── README.md ├── ro-crate-metadata.json ├── subworkflows ├── tests ├── tower.yml └── workflows + + 7 directories, 12 files ``` As you can see, there's a lot going on in there, most of which you don't need to worry about. @@ -313,7 +323,7 @@ nextflow run nf-core/demo -profile docker,test --outdir demo-results ```console N E X T F L O W ~ version 26.04.4 - Launching `https://github.com/nf-core/demo` [magical_pauling] revision: 45904cb9d1 [master] + Launching `https://github.com/nf-core/demo` [scruffy_goldstine] revision: 45904cb9d1 [master] ------------------------------------------------------ @@ -333,11 +343,11 @@ nextflow run nf-core/demo -profile docker,test --outdir demo-results config_profile_description: Minimal test dataset to check pipeline function Generic options - trace_report_suffix : 2025-11-21_04-57-41 + trace_report_suffix : 2026-06-23_16-51-59 Core Nextflow options revision : master - runName : magical_pauling + runName : scruffy_goldstine containerEngine : docker launchDir : /workspaces/training/hello-nf-core workDir : /workspaces/training/hello-nf-core/work @@ -359,9 +369,9 @@ nextflow run nf-core/demo -profile docker,test --outdir demo-results executor > local (7) - [ff/a6976b] NFCORE_DEMO:DEMO:FASTQC (SAMPLE3_SE) | 3 of 3 ✔ - [39/731ab7] NFCORE_DEMO:DEMO:SEQTK_TRIM (SAMPLE3_SE) | 3 of 3 ✔ - [7c/78d96e] NFCORE_DEMO:DEMO:MULTIQC | 1 of 1 ✔ + [be/8d6f73] NFCORE_DEMO:DEMO:FASTQC (SAMPLE1_PE) | 3 of 3 ✔ + [8a/75c637] NFCORE_DEMO:DEMO:SEQTK_TRIM (SAMPLE1_PE) | 3 of 3 ✔ + [79/b859f7] NFCORE_DEMO:DEMO:MULTIQC | 1 of 1 ✔ -[nf-core/demo] Pipeline completed successfully- ``` @@ -377,7 +387,7 @@ There's a header that includes a summary of the pipeline's version, inputs and o Notice the line near the top of the output: ```console -Launching `https://github.com/nf-core/demo` [magical_pauling] revision: 45904cb9d1 [master] +Launching `https://github.com/nf-core/demo` [scruffy_goldstine] revision: 45904cb9d1 [master] ``` This tells you which revision of the pipeline was used. @@ -395,9 +405,9 @@ Moving on to the execution output, let's have a look at the lines that tell us w ```console executor > local (7) -[ff/a6976b] NFCORE_DEMO:DEMO:FASTQC (SAMPLE3_SE) | 3 of 3 ✔ -[39/731ab7] NFCORE_DEMO:DEMO:SEQTK_TRIM (SAMPLE3_SE) | 3 of 3 ✔ -[7c/78d96e] NFCORE_DEMO:DEMO:MULTIQC | 1 of 1 ✔ +[be/8d6f73] NFCORE_DEMO:DEMO:FASTQC (SAMPLE1_PE) | 3 of 3 ✔ +[8a/75c637] NFCORE_DEMO:DEMO:SEQTK_TRIM (SAMPLE1_PE) | 3 of 3 ✔ +[79/b859f7] NFCORE_DEMO:DEMO:MULTIQC | 1 of 1 ✔ -[nf-core/demo] Pipeline completed successfully- ``` @@ -432,12 +442,12 @@ tree -L 2 demo-results │ ├── multiqc_plots │ └── multiqc_report.html └── pipeline_info - ├── execution_report_2025-11-21_04-57-41.html - ├── execution_timeline_2025-11-21_04-57-41.html - ├── execution_trace_2025-11-21_04-57-41.txt + ├── execution_report_2026-06-23_16-51-59.html + ├── execution_timeline_2026-06-23_16-51-59.html + ├── execution_trace_2026-06-23_16-51-59.txt ├── nf_core_demo_software_mqc_versions.yml - ├── params_2025-11-21_04-57-46.json - └── pipeline_dag_2025-11-21_04-57-41.html + ├── params_2026-06-23_16-52-02.json + └── pipeline_dag_2026-06-23_16-51-59.html ``` That might seem like a lot. @@ -560,23 +570,42 @@ In plain Nextflow pipelines, `--help` only works if the developer implemented it As covered in [Hello Config](../hello_nextflow/06_hello_config.md), you can set parameter values on the command line with `--param_name` or collect a set of parameters in a YAML file and pass it with `-params-file`. Both approaches work the same way with nf-core pipelines. -For example, to skip the trimming step: +For example, to skip the trimming step, we want to set the boolean parameter `skip_trim` to `true`. +Create a parameter file called `skip_trim.yml`: + +```yaml title="skip_trim.yml" +skip_trim: true +``` + +Then pass it with `-params-file`: ```bash -nextflow run nf-core/demo -profile docker,test --outdir demo-results-notrim --skip_trim +nextflow run nf-core/demo -profile docker,test --outdir demo-results-notrim -params-file skip_trim.yml ``` ??? success "Command output" ```console executor > local (4) - [3f/a82c91] NFCORE_DEMO:DEMO:FASTQC (SAMPLE3_SE) | 3 of 3 ✔ - [7d/c5e014] NFCORE_DEMO:DEMO:MULTIQC | 1 of 1 ✔ + [80/17c104] NFCORE_DEMO:DEMO:FASTQC (SAMPLE3_SE) | 3 of 3 ✔ + [a0/6ea0cf] NFCORE_DEMO:DEMO:MULTIQC | 1 of 1 ✔ -[nf-core/demo] Pipeline completed successfully- ``` The `SEQTK_TRIM` process no longer appears in the output. +!!! warning + + Nextflow types values supplied on the command line as strings. + For a boolean parameter like `skip_trim`, passing it as a bare flag (`--skip_trim`) or as `--skip_trim true` sends the **string** `"true"`, which fails schema validation: + + ```console + * --skip_trim (true): Value is [string] but should be [boolean] + ``` + + To set a boolean parameter to a genuine `true`/`false` value, use a `-params-file` as shown above. + String, integer and file-path parameters are unaffected and can still be set directly on the command line. + !!! info Although it is technically possible to set pipeline parameters in a custom configuration file passed with `-c`, this may not override defaults already set in the pipeline's own `nextflow.config`, depending on Nextflow's configuration precedence rules. @@ -631,7 +660,7 @@ The following invalid input values have been detected: ``` The pipeline stops before any processes run, saving you from a failed or incorrect execution. -Boolean parameters should be passed as flags (`--skip_trim`) without a value, or set to `true`/`false` in a params file. +As shown in section 3.1.2, boolean parameters should be set to a genuine `true`/`false` value in a params file rather than passed on the command line, since command-line values are typed as strings. #### 3.1.4. Input validation @@ -790,9 +819,9 @@ nextflow run nf-core/demo -profile docker,test --outdir demo-results-custom -c c ```console executor > local (7) - [2a/f17b3e] NFCORE_DEMO:DEMO:FASTQC (SAMPLE3_SE) | 3 of 3 ✔ - [9c/e4d028] NFCORE_DEMO:DEMO:SEQTK_TRIM (SAMPLE3_SE) | 3 of 3 ✔ - [5b/a93c71] NFCORE_DEMO:DEMO:MULTIQC | 1 of 1 ✔ + [ac/23f5aa] NFCORE_DEMO:DEMO:FASTQC (SAMPLE1_PE) | 3 of 3 ✔ + [ff/eac89a] NFCORE_DEMO:DEMO:SEQTK_TRIM (SAMPLE1_PE) | 3 of 3 ✔ + [3c/94a7a0] NFCORE_DEMO:DEMO:MULTIQC | 1 of 1 ✔ -[nf-core/demo] Pipeline completed successfully- ``` @@ -835,16 +864,16 @@ nextflow run nf-core/demo -profile docker,test --outdir demo-results-extargs -c ```console executor > local (7) - [1e/b7a392] NFCORE_DEMO:DEMO:FASTQC (SAMPLE3_SE) | 3 of 3 ✔ - [ab/cd1234] NFCORE_DEMO:DEMO:SEQTK_TRIM (SAMPLE3_SE) | 3 of 3 ✔ - [4f/c8d105] NFCORE_DEMO:DEMO:MULTIQC | 1 of 1 ✔ + [95/b32876] NFCORE_DEMO:DEMO:FASTQC (SAMPLE1_PE) | 3 of 3 ✔ + [17/428668] NFCORE_DEMO:DEMO:SEQTK_TRIM (SAMPLE1_PE) | 3 of 3 ✔ + [cf/85991a] NFCORE_DEMO:DEMO:MULTIQC | 1 of 1 ✔ -[nf-core/demo] Pipeline completed successfully- ``` -To verify the argument was applied, find the `SEQTK_TRIM` work directory hash from the run output (e.g. `work/ab/cd1234...`) and check the `.command.sh` file inside it: +To verify the argument was applied, find the `SEQTK_TRIM` work directory hash from the run output (e.g. `work/17/428668...`) and check the `.command.sh` file inside it: ```bash -cat work/ab/cd1234/.command.sh +cat work/17/428668/.command.sh ``` ??? success "Command output" diff --git a/docs/en/docs/hello_nf-core/02_rewrite_hello.md b/docs/en/docs/hello_nf-core/02_rewrite_hello.md index a87a7852be..fb6384da79 100644 --- a/docs/en/docs/hello_nf-core/02_rewrite_hello.md +++ b/docs/en/docs/hello_nf-core/02_rewrite_hello.md @@ -264,13 +264,20 @@ Once the TUI closes, you should see the following console output. | \| | \__, \__/ | \ |___ \`-._,-`-, `._,._,' - nf-core/tools version 3.5.2 - https://nf-co.re + nf-core/tools version 4.0.2 - https://nf-co.re INFO Launching interactive nf-core pipeline creation tool. ``` -There is no explicit confirmation in the console output that the pipeline creation worked, but you should see a new directory called `core-hello`. +Once the TUI has finished, the tool reports that it created the pipeline and generated its container configuration: + +```console +INFO Creating new pipeline: 'hello' +INFO Generated container configs for the pipeline successfully. +``` + +You should now see a new directory called `core-hello`. View the contents of the new directory to see how much work you saved yourself by using the template. @@ -281,7 +288,7 @@ tree core-hello ??? abstract "Directory contents" ```console - core-hello/ + core-hello ├── README.md ├── assets │ ├── samplesheet.csv @@ -292,6 +299,7 @@ tree core-hello │ ├── test.config │ └── test_full.config ├── docs + │ ├── CONTRIBUTING.md │ ├── README.md │ ├── output.md │ └── usage.md @@ -318,6 +326,8 @@ tree core-hello │ │ └── tests │ │ ├── main.function.nf.test │ │ ├── main.function.nf.test.snap + │ │ ├── main.nf.test + │ │ ├── main.nf.test.snap │ │ ├── main.workflow.nf.test │ │ ├── main.workflow.nf.test.snap │ │ └── nextflow.config @@ -331,7 +341,7 @@ tree core-hello └── workflows └── hello.nf - 15 directories, 34 files + 14 directories, 37 files ``` That's a lot of files! @@ -352,9 +362,10 @@ nextflow run ./core-hello -profile docker,test --outdir core-hello-results ```console N E X T F L O W ~ version 26.04.4 - Launching `./core-hello/main.nf` [scruffy_marconi] revision: b9e9b3b8de + Launching `./core-hello/main.nf` [cheesy_avogadro] revision: d6bbba9521 - Downloading plugin nf-schema@2.5.1 + WARN: Unrecognized config option 'validation.defaultIgnoreParams' + WARN: Unrecognized config option 'validation.monochromeLogs' Input/output options input : https://raw.githubusercontent.com/nf-core/test-datasets/viralrecon/samplesheet/samplesheet_test_illumina_amplicon.csv outdir : core-hello-results @@ -364,10 +375,10 @@ nextflow run ./core-hello -profile docker,test --outdir core-hello-results config_profile_description: Minimal test dataset to check pipeline function Generic options - trace_report_suffix : 2025-11-21_04-47-18 + trace_report_suffix : 2026-06-23_16-56-58 Core Nextflow options - runName : scruffy_marconi + runName : cheesy_avogadro containerEngine : docker launchDir : /workspaces/training/hello-nf-core workDir : /workspaces/training/hello-nf-core/work @@ -381,6 +392,9 @@ nextflow run ./core-hello -profile docker,test --outdir core-hello-results -[core/hello] Pipeline completed successfully- ``` +The `WARN: Unrecognized config option 'validation.*'` lines come from the version of the nf-schema plugin pinned in the freshly created template. +They are harmless and do not affect the run. + This shows you that all the basic wiring is in place. So where are the outputs? Are there any? @@ -395,12 +409,12 @@ tree core-hello-results ```console core-hello-results └── pipeline_info - ├── execution_report_2025-11-21_04-47-18.html - ├── execution_timeline_2025-11-21_04-47-18.html - ├── execution_trace_2025-11-21_04-47-18.txt + ├── execution_report_2026-06-23_16-56-58.html + ├── execution_timeline_2026-06-23_16-56-58.html + ├── execution_trace_2026-06-23_16-56-58.txt ├── hello_software_versions.yml - ├── params_2025-11-21_04-47-18.json - └── pipeline_dag_2025-11-21_04-47-18.html + ├── params_2026-06-23_16-57-00.json + └── pipeline_dag_2026-06-23_16-56-58.html 1 directory, 6 files ``` @@ -433,7 +447,7 @@ Let's take a closer look. This serves as the placeholder for our analysis workflow, with some nf-core functionality already in place. -```groovy title="core-hello/workflows/hello.nf" linenums="1" hl_lines="15 17 19 53" +```groovy title="core-hello/workflows/hello.nf" linenums="1" hl_lines="15 18 21 53" /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IMPORT MODULES / SUBWORKFLOWS / FUNCTIONS @@ -452,14 +466,16 @@ workflow HELLO { take: ch_samplesheet // channel: samplesheet read in from --input + outdir + main: - ch_versions = channel.empty() + def ch_versions = channel.empty() // // Collate and save software versions // - def topic_versions = Channel.topic("versions") + def topic_versions = channel.topic("versions") .distinct() .branch { entry -> versions_file: entry instanceof Path @@ -476,19 +492,16 @@ workflow HELLO { "${process}:\n${tool_versions.join('\n')}" } - softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file)) + def ch_collated_versions = softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file)) .mix(topic_versions_string) .collectFile( - storeDir: "${params.outdir}/pipeline_info", + storeDir: "${outdir}/pipeline_info", name: 'hello_software_' + 'versions.yml', sort: true, newLine: true - ).set { ch_collated_versions } - - + ) emit: versions = ch_versions // channel: [ path(versions.yml) ] - } /* @@ -501,15 +514,15 @@ workflow HELLO { Compared to a basic Nextflow workflow like the one developed in [Hello Nextflow](../hello_nextflow/index.md), you'll notice a few things that are new here (highlighted lines above): - The workflow block has a name -- Workflow inputs are declared using the `take:` keyword and the channel construction is moved up to the parent workflow +- Workflow inputs are declared using the `take:` keyword (here a samplesheet channel and an output directory), and the channel construction is moved up to the parent workflow - Workflow content is placed inside a `main:` block - Outputs are declared using the `emit:` keyword These are optional features of Nextflow that make the workflow **composable**, meaning that it can be called from within another workflow. -??? note "The `Channel.topic` block" +??? note "The `channel.topic` block" - You may have noticed the `def topic_versions = Channel.topic("versions")` block starting at line 17. + You may have noticed the `def topic_versions = channel.topic("versions")` block starting at line 28. This is boilerplate housekeeping code that collects software version information from all modules automatically. nf-core is rolling out this mechanism across all pipelines in 2026, so you'll see it in all new pipelines going forward. Part 4 of this course explains how it works in detail. @@ -575,13 +588,13 @@ nextflow run original-hello/hello.nf ```console N E X T F L O W ~ version 26.04.4 - Launching `original-hello/hello.nf` [goofy_babbage] revision: e9e72441e9 + Launching `original-hello/hello.nf` [sharp_dijkstra] revision: 319b99ee58 executor > local (8) - [a4/081cec] sayHello (1) | 3 of 3 ✔ - [e7/7e9058] convertToUpper (3) | 3 of 3 ✔ - [0c/17263b] collectGreetings | 1 of 1 ✔ - [94/542280] cowpy | 1 of 1 ✔ + [23/4eb61e] sayHello (3) | 3 of 3 ✔ + [c8/81a076] convertToUpper (1) | 3 of 3 ✔ + [90/ea197e] collectGreetings | 1 of 1 ✔ + [da/3df79a] cowpy | 1 of 1 ✔ ``` If that works for you, you're ready to start hacking. @@ -878,14 +891,14 @@ If you made all the changes correctly, this should run to completion. ```console N E X T F L O W ~ version 26.04.4 - Launching `original-hello/main.nf` [friendly_wright] revision: 1ecd2d9c0a + Launching `original-hello/main.nf` [irreverent_cajal] revision: 619249b1d7 executor > local (8) - [24/c6c0d8] HELLO:sayHello (3) | 3 of 3 ✔ - [dc/721042] HELLO:convertToUpper (3) | 3 of 3 ✔ - [48/5ab2df] HELLO:collectGreetings | 1 of 1 ✔ - [e3/693b7e] HELLO:cowpy | 1 of 1 ✔ - Output: /workspaces/training/hello-nf-core/work/e3/693b7e48dc119d0c54543e0634c2e7/cowpy-COLLECTED-test-batch-output.txt + [50/b02a90] HELLO:sayHello (1) | 3 of 3 ✔ + [c0/3c336a] HELLO:convertToUpper (2) | 3 of 3 ✔ + [5c/47bb4f] HELLO:collectGreetings | 1 of 1 ✔ + [07/bfc706] HELLO:cowpy | 1 of 1 ✔ + Output: /workspaces/training/hello-nf-core/work/07/bfc7061fa521e86f4e1954191ab4c4/cowpy-COLLECTED-test-batch-output.txt ``` This means we've successfully upgraded our HELLO workflow to be composable. @@ -930,14 +943,16 @@ workflow HELLO { take: ch_samplesheet // channel: samplesheet read in from --input + outdir + main: - ch_versions = channel.empty() + def ch_versions = channel.empty() // // Collate and save software versions // - def topic_versions = Channel.topic("versions") + def topic_versions = channel.topic("versions") .distinct() .branch { entry -> versions_file: entry instanceof Path @@ -954,19 +969,16 @@ workflow HELLO { "${process}:\n${tool_versions.join('\n')}" } - softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file)) + def ch_collated_versions = softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file)) .mix(topic_versions_string) .collectFile( - storeDir: "${params.outdir}/pipeline_info", + storeDir: "${outdir}/pipeline_info", name: 'hello_software_' + 'versions.yml', sort: true, newLine: true - ).set { ch_collated_versions } - - + ) emit: versions = ch_versions // channel: [ path(versions.yml) ] - } /* @@ -976,8 +988,8 @@ workflow HELLO { */ ``` -The highlighted lines define the composable workflow structure: `workflow HELLO {`, `take:`, `main:`, and `emit:`. -The large block between lines 17–34 is more substantial: it handles software version capture using topic channels, a mechanism nf-core is rolling out across all pipelines in 2026. +This is the composable workflow structure: a named `workflow HELLO {` block with `take:`, `main:`, and `emit:`. +The block under `// Collate and save software versions` is more substantial: it handles software version capture using topic channels, a mechanism nf-core is rolling out across all pipelines in 2026. We'll explain it in Part 4; for now, treat it as boilerplate that you can leave untouched. We need to add the relevant code from the composable version of the original workflow that we developed in section 2. @@ -1077,9 +1089,10 @@ Two more interesting observations here: The nf-core project has a lot of prebuilt functionality around the concept of the samplesheet, which is typically a CSV file containing columnar data. Since that is essentially what our `greetings.csv` file is, we'll keep the current `take` declaration as is, and simply update the name of the input channel in the next step. -```groovy title="core-hello/workflows/hello.nf" linenums="21" +```groovy title="core-hello/workflows/hello.nf" linenums="17" take: ch_samplesheet // channel: samplesheet read in from --input + outdir ``` The input handling will be done upstream of this workflow (not in this code file). @@ -1109,20 +1122,21 @@ As a reminder, this is the relevant code in the original workflow, which didn't We need to copy the code that comes after `main:` into the new version of the workflow. There is already some code in there that has to do with capturing the versions of the tools that get run by the workflow. We're going to leave that alone for now (we'll deal with the tool versions later). -We'll keep the `ch_versions = channel.empty()` initialization at the top, then insert our workflow logic, keeping the version collation code at the end. +We'll keep the `def ch_versions = channel.empty()` initialization at the top, then insert our workflow logic, keeping the version collation code at the end. This ordering makes sense because in a real pipeline, the processes would emit version information that would be added to the `ch_versions` channel as the workflow runs. === "After" - ```groovy title="core-hello/workflows/hello.nf" linenums="19" hl_lines="10-20" + ```groovy title="core-hello/workflows/hello.nf" linenums="15" hl_lines="11-21" workflow HELLO { take: ch_samplesheet // channel: samplesheet read in from --input + outdir main: - ch_versions = channel.empty() + def ch_versions = channel.empty() // emit a greeting sayHello(greeting_ch) @@ -1139,7 +1153,7 @@ This ordering makes sense because in a real pipeline, the processes would emit v // // Collate and save software versions // - def topic_versions = Channel.topic("versions") + def topic_versions = channel.topic("versions") .distinct() .branch { entry -> versions_file: entry instanceof Path @@ -1156,37 +1170,36 @@ This ordering makes sense because in a real pipeline, the processes would emit v "${process}:\n${tool_versions.join('\n')}" } - softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file)) + def ch_collated_versions = softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file)) .mix(topic_versions_string) .collectFile( - storeDir: "${params.outdir}/pipeline_info", + storeDir: "${outdir}/pipeline_info", name: 'hello_software_' + 'versions.yml', sort: true, newLine: true - ).set { ch_collated_versions } - - + ) emit: versions = ch_versions // channel: [ path(versions.yml) ] - } ``` === "Before" - ```groovy title="core-hello/workflows/hello.nf" linenums="19" + ```groovy title="core-hello/workflows/hello.nf" linenums="15" workflow HELLO { take: ch_samplesheet // channel: samplesheet read in from --input + outdir + main: - ch_versions = channel.empty() + def ch_versions = channel.empty() // // Collate and save software versions // - def topic_versions = Channel.topic("versions") + def topic_versions = channel.topic("versions") .distinct() .branch { entry -> versions_file: entry instanceof Path @@ -1203,36 +1216,31 @@ This ordering makes sense because in a real pipeline, the processes would emit v "${process}:\n${tool_versions.join('\n')}" } - softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file)) + def ch_collated_versions = softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file)) .mix(topic_versions_string) .collectFile( - storeDir: "${params.outdir}/pipeline_info", + storeDir: "${outdir}/pipeline_info", name: 'hello_software_' + 'versions.yml', sort: true, newLine: true - ).set { ch_collated_versions } - - + ) emit: versions = ch_versions // channel: [ path(versions.yml) ] - } ``` -You'll notice that we also added a blank line before `main:` to make the code more readable. - This looks great, but we still need to update the name of the channel we're passing to the `sayHello()` process from `greeting_ch` to `ch_samplesheet` as shown below, to match what is written under the `take:` keyword. === "After" - ```groovy title="core-hello/workflows/hello.nf" linenums="26" + ```groovy title="core-hello/workflows/hello.nf" linenums="25" // emit a greeting (updated to use the nf-core convention for samplesheets) sayHello(ch_samplesheet) ``` === "Before" - ```groovy title="core-hello/workflows/hello.nf" linenums="26" + ```groovy title="core-hello/workflows/hello.nf" linenums="25" // emit a greeting sayHello(greeting_ch) ``` @@ -1245,7 +1253,7 @@ Finally, we need to update the `emit` block to include the declaration of the wo === "After" - ```groovy title="core-hello/workflows/hello.nf" linenums="69" hl_lines="2" + ```groovy title="core-hello/workflows/hello.nf" linenums="71" hl_lines="2" emit: cowpy_hellos = cowpy.out versions = ch_versions // channel: [ path(versions.yml) ] @@ -1253,7 +1261,7 @@ Finally, we need to update the `emit` block to include the declaration of the wo === "Before" - ```groovy title="core-hello/workflows/hello.nf" linenums="69" + ```groovy title="core-hello/workflows/hello.nf" linenums="71" emit: versions = ch_versions // channel: [ path(versions.yml) ] ``` @@ -1322,7 +1330,8 @@ workflow CORE_HELLO { // WORKFLOW: Run pipeline // HELLO ( - samplesheet + samplesheet, + params.outdir, ) } /* @@ -1359,7 +1368,6 @@ workflow { // SUBWORKFLOW: Run completion tasks // PIPELINE_COMPLETION ( - params.outdir, params.monochrome_logs, ) } @@ -1593,13 +1601,37 @@ And while we're at it, let's tighten the default resource limits to ensure this This completes the code modifications we need to do. -### 5.4. Run the pipeline with the test profile +### 5.4. Disable parameter validation + +We replaced the templated samplesheet parsing with our own simple channel construction, but the template still ships a `nextflow_schema.json` and `assets/schema_input.json` describing a fastq-based samplesheet. +Because we have not yet adapted those schemas to our `greetings.csv` format, we need to switch off parameter validation for now (we'll set it up properly later). + +Open `core-hello/nextflow.config` and set `validate_params` to `false`: + +=== "After" + + ```groovy title="core-hello/nextflow.config" linenums="37" + validate_params = false + ``` + +=== "Before" + + ```groovy title="core-hello/nextflow.config" linenums="37" + validate_params = true + ``` + +!!! warning + + Set this in the config file rather than on the command line. + Nextflow types values supplied on the command line as strings, so `--validate_params false` sends the **string** `"false"`, which is truthy and leaves validation switched on. + Boolean parameters must be set in a config file or a `-params-file` to take a genuine `true`/`false` value. + +### 5.5. Run the pipeline with the test profile That was a lot, but we can finally try running the pipeline! -Note that we have to add `--validate_params false` to the command line because we didn't set up the validation yet (that will come later). ```bash -nextflow run core-hello --outdir core-hello-results -profile test,docker --validate_params false +nextflow run core-hello --outdir core-hello-results -profile test,docker ``` If you've done all of the modifications correctly, it should run to completion. @@ -1609,7 +1641,7 @@ If you've done all of the modifications correctly, it should run to completion. ```console N E X T F L O W ~ version 26.04.4 - Launching `core-hello/main.nf` [condescending_allen] revision: b9e9b3b8de + Launching `core-hello/main.nf` [voluminous_caravaggio] revision: d6bbba9521 Input/output options input : /workspaces/training/hello-nf-core/core-hello/assets/greetings.csv @@ -1621,10 +1653,10 @@ If you've done all of the modifications correctly, it should run to completion. Generic options validate_params : false - trace_report_suffix : 2025-11-21_07-29-37 + trace_report_suffix : 2026-06-23_16-58-45 Core Nextflow options - runName : condescending_allen + runName : voluminous_caravaggio containerEngine : docker launchDir : /workspaces/training/hello-nf-core workDir : /workspaces/training/hello-nf-core/work @@ -1635,17 +1667,17 @@ If you've done all of the modifications correctly, it should run to completion. !! Only displaying parameters that differ from the pipeline defaults !! ------------------------------------------------------ - executor > local (1) - [ed/727b7e] CORE_HELLO:HELLO:sayHello (3) | 3 of 3 ✔ - [45/bb6096] CORE_HELLO:HELLO:convertToUpper (3) | 3 of 3 ✔ - [81/7e2e34] CORE_HELLO:HELLO:collectGreetings | 1 of 1 ✔ - [96/9442a1] CORE_HELLO:HELLO:cowpy | 1 of 1 ✔ + executor > local (8) + [30/fc3bdb] CORE_HELLO:HELLO:sayHello (1) | 3 of 3 ✔ + [55/58b611] CORE_HELLO:HELLO:convertToUpper (1) | 3 of 3 ✔ + [12/83c0bc] CORE_HELLO:HELLO:collectGreetings | 1 of 1 ✔ + [18/4894fd] CORE_HELLO:HELLO:cowpy | 1 of 1 ✔ -[core/hello] Pipeline completed successfully- ``` As you can see, this produced the typical nf-core summary at the start thanks to the initialisation subworkflow, and the lines for each module now show the full PIPELINE:WORKFLOW:module names. -### 5.5. Find the pipeline outputs +### 5.6. Find the pipeline outputs The question now is: where are the outputs of the pipeline? And the answer is quite interesting: there are now two different places to look for the results. @@ -1661,17 +1693,17 @@ tree core-hello-results ```console core-hello-results └── pipeline_info - ├── execution_report_2025-11-21_04-47-18.html - ├── execution_report_2025-11-21_07-29-37.html - ├── execution_timeline_2025-11-21_04-47-18.html - ├── execution_timeline_2025-11-21_07-29-37.html - ├── execution_trace_2025-11-21_04-47-18.txt - ├── execution_trace_2025-11-21_07-29-37.txt + ├── execution_report_2026-06-23_16-56-58.html + ├── execution_report_2026-06-23_16-58-45.html + ├── execution_timeline_2026-06-23_16-56-58.html + ├── execution_timeline_2026-06-23_16-58-45.html + ├── execution_trace_2026-06-23_16-56-58.txt + ├── execution_trace_2026-06-23_16-58-45.txt ├── hello_software_versions.yml - ├── params_2025-11-21_04-47-13.json - ├── params_2025-11-21_07-29-41.json - ├── pipeline_dag_2025-11-21_04-47-18.html - └── pipeline_dag_2025-11-21_07-29-37.html + ├── params_2026-06-23_16-57-00.json + ├── params_2026-06-23_16-58-47.json + ├── pipeline_dag_2026-06-23_16-56-58.html + └── pipeline_dag_2026-06-23_16-58-45.html 1 directory, 12 files ``` diff --git a/docs/en/docs/hello_nf-core/03_use_module.md b/docs/en/docs/hello_nf-core/03_use_module.md index 39d4602e69..ecdfcdcfad 100644 --- a/docs/en/docs/hello_nf-core/03_use_module.md +++ b/docs/en/docs/hello_nf-core/03_use_module.md @@ -23,7 +23,7 @@ To demonstrate how this works, we'll replace the custom `collectGreetings` modul You can test that it runs successfully by running the following command: ```bash - nextflow run . --outdir core-hello-results -profile test,docker --validate_params false + nextflow run . --outdir core-hello-results -profile test,docker ``` --- @@ -118,7 +118,8 @@ This displays documentation about the module, including its inputs, outputs, and | \| | \__, \__/ | \ |___ \`-._,-`-, `._,._,' - nf-core/tools version 3.5.2 - https://nf-co.re + nf-core/tools version 4.0.2 - https://nf-co.re + ╭─ Module: find/concatenate ──────────────────────────────────────────────────╮ @@ -210,20 +211,25 @@ The tool will proceed to install the module. | \| | \__, \__/ | \ |___ \`-._,-`-, `._,._,' - nf-core/tools version 3.5.2 - https://nf-co.re + nf-core/tools version 4.0.2 - https://nf-co.re INFO Installing 'find/concatenate' - INFO Use the following statement to include this module: - - include { FIND_CONCATENATE } from '../modules/nf-core/find/concatenate/main' + NotADirectoryError: [Errno 20] Not a directory: + 'modules/local/cowpy.nf/meta.yml' ``` The command automatically: - Downloads the module files to `modules/nf-core/find/concatenate/` - Updates `modules.json` to track the installed module -- Provides you with the correct `include` statement to use in your workflow + +!!! warning "Traceback with single-file local modules" + + nf-core/tools 4.0.2 expects every local module to live in its own directory (`modules/local//main.nf`). + Because our `core-hello` pipeline still uses single-file local modules (`modules/local/cowpy.nf` and friends), the install command prints a `NotADirectoryError` traceback after installing. + The `find/concatenate` module is still installed correctly and `modules.json` is still updated; the traceback is cosmetic and can be ignored for this exercise. + (We convert `cowpy` to the directory layout in Part 4.) !!! tip @@ -255,30 +261,13 @@ tree -L 4 modules 5 directories, 7 files ``` -You can also verify the installation by asking the nf-core utility to list locally installed modules: - -```bash -nf-core modules list local -``` +You can confirm the installation by inspecting `modules.json`, which now lists `find/concatenate` under the nf-core/modules repository, alongside the directory contents shown above. -??? success "Command output" +!!! note "`nf-core modules list local` and single-file modules" - ```console - INFO Repository type: pipeline - INFO Modules installed in '.': - - ┏━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓ - ┃ Module Name ┃ Repository ┃ Version SHA ┃ Message ┃ Date ┃ - ┡━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩ - │ find/concaten… │ nf-core/modules │ 6d46786 │ Support for │ 2026-04-23 │ - │ │ │ │ apptainer as │ │ - │ │ │ │ well as │ │ - │ │ │ │ singularity │ │ - │ │ │ │ for .sif in │ │ - │ │ │ │ `container` │ │ - │ │ │ │ (#11260) │ │ - └────────────────┴─────────────────┴─────────────┴────────────────┴────────────┘ - ``` + You might expect `nf-core modules list local` to report the newly installed module. + In nf-core/tools 4.0.2, that command returns an empty table whenever the pipeline contains single-file local modules (as `core-hello` does at this stage), because the tool only recognizes the directory layout (`modules/local//main.nf`). + Inspecting `modules.json` and the `modules/nf-core/` directory is the reliable check here. This confirms that the `find/concatenate` module is now part of your project's source code. @@ -760,7 +749,7 @@ Then it's just a matter of passing `ch_for_cowpy` to `cowpy` instead of `collect Let's test that the workflow works with the newly integrated `find/concatenate` module: ```bash -nextflow run . --outdir core-hello-results -profile test,docker --validate_params false +nextflow run . --outdir core-hello-results -profile test,docker ``` This should run reasonably quickly. @@ -768,40 +757,40 @@ This should run reasonably quickly. ??? success "Command output" ```console - N E X T F L O W ~ version 26.04.4 - - Launching `./main.nf` [evil_pike] revision: b9e9b3b8de - - Input/output options - input : /workspaces/training/hello-nf-core/core-hello/assets/greetings.csv - outdir : core-hello-results - - Institutional config options - config_profile_name : Test profile - config_profile_description: Minimal test dataset to check pipeline function - - Generic options - validate_params : false - trace_report_suffix : 2025-10-30_18-50-58 - - Core Nextflow options - runName : evil_pike - containerEngine : docker - launchDir : /workspaces/training/hello-nf-core/core-hello - workDir : /workspaces/training/hello-nf-core/core-hello/work - projectDir : /workspaces/training/hello-nf-core/core-hello - userName : root - profile : test,docker - configFiles : /workspaces/training/hello-nf-core/core-hello/nextflow.config - - !! Only displaying parameters that differ from the pipeline defaults !! - ------------------------------------------------------ - executor > local (8) - [b3/f005fd] CORE_HELLO:HELLO:sayHello (3) | 3 of 3 ✔ - [08/f923d0] CORE_HELLO:HELLO:convertToUpper (3) | 3 of 3 ✔ - [34/3729a9] CORE_HELLO:HELLO:FIND_CONCATENATE (test) | 1 of 1 ✔ - [24/df918a] CORE_HELLO:HELLO:cowpy | 1 of 1 ✔ - -[core/hello] Pipeline completed successfully- + N E X T F L O W ~ version 26.04.4 + + Launching `./main.nf` [cheesy_bhabha] revision: d6bbba9521 + + Input/output options + input : /home/ubuntu/hnc-scratch/core-hello/assets/greetings.csv + outdir : core-hello-results + + Institutional config options + config_profile_name : Test profile + config_profile_description: Minimal test dataset to check pipeline function + + Generic options + validate_params : false + trace_report_suffix : 2026-06-23_16-55-02 + + Core Nextflow options + runName : cheesy_bhabha + containerEngine : docker + launchDir : /home/ubuntu/hnc-scratch/core-hello + workDir : /home/ubuntu/hnc-scratch/core-hello/work + projectDir : /home/ubuntu/hnc-scratch/core-hello + userName : ubuntu + profile : test,docker + configFiles : /home/ubuntu/hnc-scratch/core-hello/nextflow.config + + !! Only displaying parameters that differ from the pipeline defaults !! + ------------------------------------------------------ + executor > local (8) + [bf/aa86d7] CORE_HELLO:HELLO:sayHello (3) | 3 of 3 ✔ + [0a/df448e] CORE_HELLO:HELLO:convertToUpper (3) | 3 of 3 ✔ + [82/ded72f] CORE_HELLO:HELLO:FIND_CONCATENATE (test) | 1 of 1 ✔ + [9d/0130bf] CORE_HELLO:HELLO:cowpy | 1 of 1 ✔ + -[core/hello] Pipeline completed successfully- ``` Notice that `FIND_CONCATENATE` now appears in the process execution list instead of `collectGreetings`. diff --git a/docs/en/docs/hello_nf-core/04_make_module.md b/docs/en/docs/hello_nf-core/04_make_module.md index aa4ae1192b..6d3c33a8fd 100644 --- a/docs/en/docs/hello_nf-core/04_make_module.md +++ b/docs/en/docs/hello_nf-core/04_make_module.md @@ -22,7 +22,7 @@ After that, we'll show you how to use the template-based module creation to work You can test that it runs successfully by running the following command: ```bash - nextflow run . --outdir core-hello-results -profile test,docker --validate_params false + nextflow run . --outdir core-hello-results -profile test,docker ``` --- @@ -245,7 +245,7 @@ Be sure to make **both** changes, otherwise you will get an error when you run t Let's run the workflow to test that everything is working correctly after these changes. ```bash -nextflow run . --outdir core-hello-results -profile test,docker --validate_params false +nextflow run . --outdir core-hello-results -profile test,docker ``` ??? success "Command output" @@ -393,7 +393,7 @@ This is technically not required, but it's good practice to refer to named outpu Let's run the workflow to test that everything is working correctly after these changes. ```bash -nextflow run . --outdir core-hello-results -profile test,docker --validate_params false +nextflow run . --outdir core-hello-results -profile test,docker ``` ??? success "Command output" @@ -403,7 +403,7 @@ nextflow run . --outdir core-hello-results -profile test,docker --validate_param Launching `./main.nf` [modest_saha] revision: b9e9b3b8de - Downloading plugin nf-schema@2.5.1 + Downloading plugin nf-schema@2.7.2 Input/output options input : /workspaces/training/hello-nf-core/core-hello/assets/greetings.csv outdir : core-hello-results @@ -621,7 +621,7 @@ Let's test that the workflow still works as expected, specifying a different cha Run this command using `kosh`, one of the more... enigmatic options: ```bash -nextflow run . --outdir core-hello-results -profile test,docker --validate_params false --character kosh +nextflow run . --outdir core-hello-results -profile test,docker --character kosh ``` ??? success "Command output" @@ -675,16 +675,16 @@ cat work/38/eb29ea*/cowpy-test.txt ??? success "Command output" ```console - _________ - / HELLO \ - | HOLA | - \ BONJOUR / - --------- - \ + _________ + / BONJOUR \ + | HELLO | + \ HOLA / + --------- \ + \ \ ___ _____ ___ - / \ / /| / \ + / \ / /| / \ | | / / | | | | | /____/ | | | | | | | | | | @@ -839,7 +839,7 @@ In case you're wondering, the `ext.prefix` closure has access to the correct pie Let's test that the workflow still works as expected. ```bash -nextflow run . --outdir core-hello-results -profile test,docker --validate_params false +nextflow run . --outdir core-hello-results -profile test,docker ``` ??? success "Command output" @@ -976,7 +976,7 @@ That's it! Let's have a look at what happens if we run the pipeline now. ```bash -nextflow run . --outdir core-hello-results -profile test,docker --validate_params false +nextflow run . --outdir core-hello-results -profile test,docker ``` ??? success "Command output" @@ -1160,7 +1160,7 @@ No changes to the script block are needed — the version is declared statically #### 1.6.2. Run the pipeline and inspect the versions report ```bash -nextflow run . --outdir core-hello-results -profile test,docker --validate_params false +nextflow run . --outdir core-hello-results -profile test,docker ``` ??? success "Command output" @@ -1189,6 +1189,9 @@ FIND_CONCATENATE: coreutils: 9.4 find: 4.6.0 pigz: 2.8 +Workflow: + core/hello: v1.0.0dev + Nextflow: 26.04.4 ``` The workflow-side collection — the `Channel.topic("versions")` block you saw in the placeholder workflow in Part 2 — subscribes to the topic and writes this combined report automatically. @@ -1283,16 +1286,16 @@ process COWPY { label 'process_single' conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + container "${ workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/YOUR-TOOL-HERE': - 'biocontainers/YOUR-TOOL-HERE' }" + 'quay.io/biocontainers/YOUR-TOOL-HERE' }" input: tuple val(meta), path(input) // Pattern 1: Metadata tuples ✓ output: tuple val(meta), path("*"), emit: output - tuple val("${task.process}"), val('cowpy'), val("1.1.5"), topic: versions, emit: versions_cowpy + tuple val("${task.process}"), val('cowpy'), eval("cowpy --version"), topic: versions, emit: versions_cowpy when: task.ext.when == null || task.ext.when @@ -1367,9 +1370,9 @@ The default code offers to toggle between Docker and Singularity, but we're goin label 'process_single' conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + container "${ workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/YOUR-TOOL-HERE': - 'biocontainers/YOUR-TOOL-HERE' }" + 'quay.io/biocontainers/YOUR-TOOL-HERE' }" ``` #### 2.2.2. Conda environment @@ -1437,13 +1440,13 @@ Update the input and output blocks: === "Before" - ```groovy title="modules/local/cowpy/main.nf" linenums="8" hl_lines="2 5" + ```groovy title="modules/local/cowpy/main.nf" linenums="8" hl_lines="2 5 6" input: tuple val(meta), path(input) output: tuple val(meta), path("*"), emit: output - tuple val("${task.process}"), val('cowpy'), val("1.1.5"), topic: versions , emit: versions_cowpy + tuple val("${task.process}"), val('cowpy'), eval("cowpy --version"), topic: versions , emit: versions_cowpy ``` This specifies: @@ -1451,6 +1454,7 @@ This specifies: - The input file parameter name (`input_file` instead of generic `input`) - The output filename using the configurable prefix pattern (`#!groovy ${prefix}.txt` instead of wildcard `*`) - A descriptive emit name (`cowpy_output` instead of generic `output`) +- A static version string (`#!groovy val("1.1.5")`) in place of the template's `#!groovy eval("cowpy --version")`, matching the manual module from section 1.6 (the `cowpy` tool does not expose a `--version` flag) If you're using the Nextflow language server to validate syntax, the `#!groovy ${prefix}` part will be flagged as an error at this stage because we haven't added it to the script block yet. Let's get to that now. @@ -1574,7 +1578,7 @@ All we need to do to try out this new version of the `COWPY` module is to switch Let's run the pipeline to test it. ```bash -nextflow run . --outdir core-hello-results -profile test,docker --validate_params false +nextflow run . --outdir core-hello-results -profile test,docker ``` ??? success "Command output" diff --git a/docs/en/docs/hello_nf-core/05_input_validation.md b/docs/en/docs/hello_nf-core/05_input_validation.md index 97ad5bef2b..9608bef4c3 100644 --- a/docs/en/docs/hello_nf-core/05_input_validation.md +++ b/docs/en/docs/hello_nf-core/05_input_validation.md @@ -18,7 +18,7 @@ In this fifth part of the Hello nf-core training course, we show you how to use You can test that it runs successfully by running the following command: ```bash - nextflow run . --outdir core-hello-results -profile test,docker --validate_params false + nextflow run . --outdir core-hello-results -profile test,docker ``` --- @@ -82,7 +82,7 @@ nf-schema is the successor to the deprecated nf-validation plugin and uses stand ```groovy plugins { - id 'nf-schema@2.1.1' + id 'nf-schema@2.7.2' } ``` @@ -140,23 +140,40 @@ Now let's apply these principles in practice, starting with parameter validation Let's start by adding parameter validation to our pipeline. This validates command-line flags like `--input`, `--outdir`, and `--batch`. -### 1.1. Configure validation to skip input file validation +### 1.1. Enable validation and skip input file validation The nf-core pipeline template comes with nf-schema already installed and configured: - The nf-schema plugin is installed via the `plugins{}` block in `nextflow.config` -- Parameter validation is enabled by default via `params.validate_params = true` +- Parameter validation is controlled by `params.validate_params` - The validation is performed by the `UTILS_NFSCHEMA_PLUGIN` subworkflow during pipeline initialization -The validation behavior is controlled through the `validation{}` scope in `nextflow.config`. +In Parts 3 and 4 we set `validate_params = false` so the pipeline could run before we had configured any schemas. +Now that we're ready to add validation, the first step is to turn it on. -Since we'll be working on parameter validation first (this section) and won't configure the input data schema until section 2, we need to temporarily tell nf-schema to skip validating the `input` parameter's file contents. +Open `nextflow.config` and find the `validate_params` parameter (around line 37), and set it to `true`: -Open `nextflow.config` and find the `validation` block (around line 247). Add `ignoreParams` to skip input file validation: +=== "After" + + ```groovy title="nextflow.config" hl_lines="1" linenums="37" + validate_params = true + ``` + +=== "Before" + + ```groovy title="nextflow.config" hl_lines="1" linenums="37" + validate_params = false + ``` + +The validation behavior itself is controlled through the `validation{}` scope in `nextflow.config`. + +Since we'll be working on parameter validation first (this section) and won't configure the input data schema until section 2, we also need to temporarily tell nf-schema to skip validating the `input` parameter's file contents. + +Find the `validation` block (around line 252) and add `ignoreParams` to skip input file validation: === "After" - ```groovy title="nextflow.config" hl_lines="3" linenums="247" + ```groovy title="nextflow.config" hl_lines="3" linenums="252" validation { defaultIgnoreParams = ["genomes"] ignoreParams = ['input'] @@ -166,7 +183,7 @@ Open `nextflow.config` and find the `validation` block (around line 247). Add `i === "Before" - ```groovy title="nextflow.config" linenums="247" + ```groovy title="nextflow.config" linenums="252" validation { defaultIgnoreParams = ["genomes"] monochromeLogs = params.monochrome_logs @@ -261,7 +278,7 @@ You should see something like this: | \| | \__, \__/ | \ |___ \`-._,-`-, `._,._,' - nf-core/tools version 3.5.2 - https://nf-co.re + nf-core/tools version 4.0.2 - https://nf-co.re INFO [✓] Default parameters match schema validation INFO [✓] Pipeline schema looks valid (found 17 params) @@ -350,7 +367,7 @@ nextflow run . --outdir test-results -profile docker ```console ERROR ~ Validation of pipeline parameters failed! - -- Check '.nextflow.log' file for details + -- Check '.nextflow.log' file for details The following invalid input values have been detected: * Missing required parameter(s): input, batch @@ -638,7 +655,7 @@ Open `nextflow.config` and remove the `ignoreParams` line from the `validation` === "After" - ```groovy title="nextflow.config" linenums="247" + ```groovy title="nextflow.config" linenums="252" validation { defaultIgnoreParams = ["genomes"] monochromeLogs = params.monochrome_logs @@ -647,7 +664,7 @@ Open `nextflow.config` and remove the `ignoreParams` line from the `validation` === "Before" - ```groovy title="nextflow.config" hl_lines="3" linenums="247" + ```groovy title="nextflow.config" hl_lines="3" linenums="252" validation { defaultIgnoreParams = ["genomes"] ignoreParams = ['input'] @@ -664,7 +681,7 @@ Let's verify that our validation works by testing both valid and invalid inputs. #### 2.7.1. Test with valid input First, confirm the pipeline runs successfully with valid input. -Note that we no longer need `--validate_params false` since validation is working! +With `validate_params = true` and the input schema in place, both parameter and input data validation now run for real. ```bash nextflow run . --outdir core-hello-results -profile test,docker From 5b72fd21bdaae73bad166eb7f2bb023a39ea8b5b Mon Sep 17 00:00:00 2001 From: Geraldine Van der Auwera Date: Fri, 3 Jul 2026 16:51:58 -0400 Subject: [PATCH 33/42] review(hello_nf-core): fix path leak, boolean warning placement, Part 3 section 1.4, v2 compat note - Fix leaked author path in Part 3 run output (replace /home/ubuntu/hnc-scratch with codespace paths) - Move boolean params warning from orientation to Part 1 section 3.1.2 where it first applies - Restructure Part 3 section 1.4: tip and NotADirectoryError explanation as prose, add modules.json content, rewrite nf-core modules list local note - Add v2 parser compatibility note for outputDir/workflow.output.mode in Part 2 section 5.4 Co-Authored-By: Claude Sonnet 4.6 --- docs/en/docs/hello_nf-core/00_orientation.md | 7 -- docs/en/docs/hello_nf-core/01_run_demo.md | 5 +- .../en/docs/hello_nf-core/02_rewrite_hello.md | 24 ++++- docs/en/docs/hello_nf-core/03_use_module.md | 102 ++++++++++++------ 4 files changed, 92 insertions(+), 46 deletions(-) diff --git a/docs/en/docs/hello_nf-core/00_orientation.md b/docs/en/docs/hello_nf-core/00_orientation.md index e553ba4799..66f84bf444 100644 --- a/docs/en/docs/hello_nf-core/00_orientation.md +++ b/docs/en/docs/hello_nf-core/00_orientation.md @@ -23,13 +23,6 @@ If you are working through this course by yourself, please acquaint yourself wit This training works with Nextflow 25.10.2 or later **with the v2 syntax parser**, which is the default from Nextflow 26.04 onward. In our training environment you don't need to do anything: it runs Nextflow 26.04.4 with the v2 parser. If you are using a local or custom environment, see the [version notes](../info/nxf_versions.md). -!!! warning "Setting boolean parameters on the command line" - - With the v2 syntax parser, a value passed on the command line is always read as text. - A boolean parameter passed as a bare flag or as `--flag value` (for example `--skip_trim` or `--validate_params false`) is therefore read as the string `"true"` or `"false"` and will not behave as you expect. - Set boolean parameters in a `-params-file` or in the configuration instead, where they keep their real boolean type. - This course uses that pattern throughout. - This training additionally requires **nf-core tools 4.0.2**. If you use a different version of nf-core tooling, you may have difficulty following along. diff --git a/docs/en/docs/hello_nf-core/01_run_demo.md b/docs/en/docs/hello_nf-core/01_run_demo.md index 7735e9e95f..4c358726df 100644 --- a/docs/en/docs/hello_nf-core/01_run_demo.md +++ b/docs/en/docs/hello_nf-core/01_run_demo.md @@ -594,7 +594,7 @@ nextflow run nf-core/demo -profile docker,test --outdir demo-results-notrim -par The `SEQTK_TRIM` process no longer appears in the output. -!!! warning +!!! warning "Setting boolean parameters on the command line" Nextflow types values supplied on the command line as strings. For a boolean parameter like `skip_trim`, passing it as a bare flag (`--skip_trim`) or as `--skip_trim true` sends the **string** `"true"`, which fails schema validation: @@ -603,8 +603,9 @@ The `SEQTK_TRIM` process no longer appears in the output. * --skip_trim (true): Value is [string] but should be [boolean] ``` - To set a boolean parameter to a genuine `true`/`false` value, use a `-params-file` as shown above. + To set a boolean parameter to a genuine `true`/`false` value, use a `-params-file` as shown above, or set it in a config file. String, integer and file-path parameters are unaffected and can still be set directly on the command line. + This course uses this pattern throughout for boolean parameters. !!! info diff --git a/docs/en/docs/hello_nf-core/02_rewrite_hello.md b/docs/en/docs/hello_nf-core/02_rewrite_hello.md index fb6384da79..4416cb8198 100644 --- a/docs/en/docs/hello_nf-core/02_rewrite_hello.md +++ b/docs/en/docs/hello_nf-core/02_rewrite_hello.md @@ -1620,11 +1620,27 @@ Open `core-hello/nextflow.config` and set `validate_params` to `false`: validate_params = true ``` -!!! warning +We set this in the config file rather than on the command line because starting in Nextflow version 26.04, all values supplied on the command line are typed as strings. +As a result, Boolean parameters must be set in a config file or a `-params-file` to take a genuine `true`/`false` value. - Set this in the config file rather than on the command line. - Nextflow types values supplied on the command line as strings, so `--validate_params false` sends the **string** `"false"`, which is truthy and leaves validation switched on. - Boolean parameters must be set in a config file or a `-params-file` to take a genuine `true`/`false` value. +For example, using `--validate_params false` here would evaluate as the **string** `"false"`, which leaves validation switched on. + +!!! tip "v2 parser compatibility lines in `nextflow.config`" + + Speaking of v2 syntax, you may notice these two lines just below the `params` block in the config file: + + ```groovy + outputDir = params.outdir + workflow.output.mode = params.publish_dir_mode + ``` + + These are required for compatibility with the v2 syntax parser. + + - With the v2 syntax, `params.*` variables cannot be referenced directly inside `publishDir` directives in process modules, so `outputDir` is defined here as a top-level config variable that those directives can access. + + - `workflow.output.mode` sets the default publishing mode for the v2 workflow output block. + + Both are generated automatically by the nf-core pipeline template and do not need to be modified. ### 5.5. Run the pipeline with the test profile diff --git a/docs/en/docs/hello_nf-core/03_use_module.md b/docs/en/docs/hello_nf-core/03_use_module.md index ecdfcdcfad..fbfede28c2 100644 --- a/docs/en/docs/hello_nf-core/03_use_module.md +++ b/docs/en/docs/hello_nf-core/03_use_module.md @@ -192,15 +192,13 @@ Now that we've found the module we want, we need to add it to our pipeline's sou The good news is that the nf-core project includes some tooling to make this part easy. Specifically, the `nf-core modules install` command makes it possible to automate retrieving the code and making it available to your project in a single step. -Navigate to your pipeline directory and run the installation command: +Make sure your working directory is the root of the `core-hello` pipeline project, then run the installation command: ```bash cd core-hello nf-core modules install find/concatenate ``` -The tool will proceed to install the module. - ??? success "Command output" ```console @@ -219,23 +217,12 @@ The tool will proceed to install the module. 'modules/local/cowpy.nf/meta.yml' ``` -The command automatically: - -- Downloads the module files to `modules/nf-core/find/concatenate/` -- Updates `modules.json` to track the installed module - -!!! warning "Traceback with single-file local modules" - - nf-core/tools 4.0.2 expects every local module to live in its own directory (`modules/local//main.nf`). - Because our `core-hello` pipeline still uses single-file local modules (`modules/local/cowpy.nf` and friends), the install command prints a `NotADirectoryError` traceback after installing. - The `find/concatenate` module is still installed correctly and `modules.json` is still updated; the traceback is cosmetic and can be ignored for this exercise. - (We convert `cowpy` to the directory layout in Part 4.) - -!!! tip - - Always make sure your current working directory is the root of your pipeline project before running the module installation command. +The command downloads the module files to `modules/nf-core/find/concatenate/` and updates `modules.json` to track the installed module. +You can ignore the `NotADirectoryError` at the end; it happens because nf-core/tools 4.0.2 expects every local module to live in its own directory (`modules/local//main.nf`), while `core-hello` still uses single-file local modules at this stage. +However, the `find/concatenate` module is installed correctly, and `modules.json` is updated as expected. +We'll convert `cowpy` to the directory layout in Part 4. -Let's check that the module was installed correctly: +Let's check that the module files are in place: ```bash tree -L 4 modules @@ -261,18 +248,67 @@ tree -L 4 modules 5 directories, 7 files ``` -You can confirm the installation by inspecting `modules.json`, which now lists `find/concatenate` under the nf-core/modules repository, alongside the directory contents shown above. - -!!! note "`nf-core modules list local` and single-file modules" - - You might expect `nf-core modules list local` to report the newly installed module. - In nf-core/tools 4.0.2, that command returns an empty table whenever the pipeline contains single-file local modules (as `core-hello` does at this stage), because the tool only recognizes the directory layout (`modules/local//main.nf`). - Inspecting `modules.json` and the `modules/nf-core/` directory is the reliable check here. +You can also confirm the installation by inspecting `modules.json`, which now lists `find/concatenate` under the nf-core/modules repository. + +??? abstract "modules.json" + + ```json title="modules.json" + { + "name": "core/hello", + "homePage": "https://github.com/core/hello", + "repos": { + "https://github.com/nf-core/modules.git": { + "modules": { + "nf-core": { + "find/concatenate": { + "branch": "master", + "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120", + "installed_by": [ + "modules" + ] + } + } + }, + "subworkflows": { + "nf-core": { + "utils_nextflow_pipeline": { + "branch": "master", + "git_sha": "05954dab2ff481bcb999f24455da29a5828af08d", + "installed_by": [ + "subworkflows" + ] + }, + "utils_nfcore_pipeline": { + "branch": "master", + "git_sha": "a3fb7351b1fdb2b1de282b765816bbea190e86a8", + "installed_by": [ + "subworkflows" + ] + }, + "utils_nfschema_plugin": { + "branch": "master", + "git_sha": "fdc08b8b1ae74f56686ce21f7ea11ad11990ce57", + "installed_by": [ + "subworkflows" + ] + } + } + } + } + } + } + ``` This confirms that the `find/concatenate` module is now part of your project's source code. - However, to actually use the new module, we need to import it into our pipeline. +!!! info "Checking installed modules with `nf-core modules list local`" + + The nf-core tools provide a command to list all modules currently installed in a pipeline: `nf-core modules list local`. + Under normal circumstances this is a convenient way to verify an installation. + However, in nf-core/tools 4.0.2, this command returns an empty table when the pipeline contains any single-file local modules (such as `modules/local/cowpy.nf`), because the tool only recognizes the newer directory layout (`modules/local//main.nf`). + Since `core-hello` still uses single-file local modules at this stage, `modules.json` and the `modules/nf-core/` directory are the reliable checks — as shown above. + ### 1.5. Update the module imports Let's replace the `include` statement for the `collectGreetings` module with the one for `FIND_CONCATENATE` in the imports section of the `workflows/hello.nf` workflow. @@ -762,7 +798,7 @@ This should run reasonably quickly. Launching `./main.nf` [cheesy_bhabha] revision: d6bbba9521 Input/output options - input : /home/ubuntu/hnc-scratch/core-hello/assets/greetings.csv + input : /workspaces/training/hello-nf-core/core-hello/assets/greetings.csv outdir : core-hello-results Institutional config options @@ -776,12 +812,12 @@ This should run reasonably quickly. Core Nextflow options runName : cheesy_bhabha containerEngine : docker - launchDir : /home/ubuntu/hnc-scratch/core-hello - workDir : /home/ubuntu/hnc-scratch/core-hello/work - projectDir : /home/ubuntu/hnc-scratch/core-hello - userName : ubuntu + launchDir : /workspaces/training/hello-nf-core/core-hello + workDir : /workspaces/training/hello-nf-core/core-hello/work + projectDir : /workspaces/training/hello-nf-core/core-hello + userName : root profile : test,docker - configFiles : /home/ubuntu/hnc-scratch/core-hello/nextflow.config + configFiles : /workspaces/training/hello-nf-core/core-hello/nextflow.config !! Only displaying parameters that differ from the pipeline defaults !! ------------------------------------------------------ From 6cd13abfc1032b61031f05e3815cdaf11fd1cfae Mon Sep 17 00:00:00 2001 From: Geraldine Van der Auwera Date: Fri, 3 Jul 2026 18:48:36 -0400 Subject: [PATCH 34/42] feat(hello_nf-core): provide my_params.yml and malformed_samplesheet.csv as course materials Replace learner-created files with pre-provided equivalents in Part 1: - Add my_params.yml (skip_trim: true) and malformed_samplesheet.csv to hello-nf-core/ - Update Part 1 section 3.1.2 and 3.1.4 to reference provided files instead of instructing learners to create them - Update orientation directory tree and file descriptions Co-Authored-By: Claude Sonnet 4.6 --- docs/en/docs/hello_nf-core/00_orientation.md | 6 + docs/en/docs/hello_nf-core/01_run_demo.md | 235 ++++++++++++------- hello-nf-core/malformed_samplesheet.csv | 2 + hello-nf-core/my_params.yml | 1 + 4 files changed, 165 insertions(+), 79 deletions(-) create mode 100644 hello-nf-core/malformed_samplesheet.csv create mode 100644 hello-nf-core/my_params.yml diff --git a/docs/en/docs/hello_nf-core/00_orientation.md b/docs/en/docs/hello_nf-core/00_orientation.md index 66f84bf444..a1f7a93600 100644 --- a/docs/en/docs/hello_nf-core/00_orientation.md +++ b/docs/en/docs/hello_nf-core/00_orientation.md @@ -70,6 +70,8 @@ tree . -L 2 ```console . ├── greetings.csv + ├── malformed_samplesheet.csv + ├── my_params.yml ├── original-hello │ ├── hello.nf │ ├── modules @@ -88,6 +90,10 @@ We use collapsible sections like this to include expected command output in a co - **The `greetings.csv` file** is a CSV containing some minimal columnar data we use for testing purposes. +- **The `malformed_samplesheet.csv` file** is an intentionally broken samplesheet used in Part 1 to demonstrate input validation. + +- **The `my_params.yml` file** is an example params file used in Part 1 to demonstrate how to pass boolean parameters to a pipeline. + - **The `original-hello` directory** contains a copy of the source code produced by working through the complete Hello Nextflow training series (with Docker enabled). - **The `solutions` directory** contains the completed workflow scripts that result from each step of the course. diff --git a/docs/en/docs/hello_nf-core/01_run_demo.md b/docs/en/docs/hello_nf-core/01_run_demo.md index 4c358726df..46f3b7c770 100644 --- a/docs/en/docs/hello_nf-core/01_run_demo.md +++ b/docs/en/docs/hello_nf-core/01_run_demo.md @@ -43,9 +43,10 @@ The `Introduction` tab provides an overview of the pipeline, including a visual ![pipeline subway map](./img/nf-core-demo-subway-cropped.png) -1. Read QC (FASTQC) -2. Adapter and quality trimming (SEQTK_TRIM) -3. Present QC for raw reads (MULTIQC) +1. Read QC ([FASTQC](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/)) +2. Adapter and quality trimming ([SEQTK_TRIM](https://github.com/lh3/seqtk)) +3. Present QC for raw reads ([MULTIQC](http://multiqc.info/)) +4. Generate a lighthearted text message from a cow ([COWPY](https://github.com/jeffbuttars/cowpy)) #### 1.1.2. Example command line @@ -80,7 +81,7 @@ nextflow pull nf-core/demo ```console Checking nf-core/demo ... - downloaded from https://github.com/nf-core/demo.git - revision: 45904cb9d1 [master] + downloaded from https://github.com/nf-core/demo.git - revision: 32893afef8 [master] ``` Nextflow does a `pull` of the pipeline code, meaning it downloads the full repository to your local drive. @@ -118,22 +119,39 @@ nextflow info nf-core/demo ??? success "Command output" ```console - project name: nf-core/demo - repository : https://github.com/nf-core/demo - local path : /workspaces/.nextflow/assets/.repos/nf-core/demo - main script : main.nf - description : An nf-core demo pipeline - revisions : - TEMPLATE - dev - > master (default) - 1.0.0 [t] - 1.0.1 [t] - 1.0.2 [t] - > 1.1.0 [t] + project name: nf-core/demo + repository : https://github.com/nf-core/demo + local path : /workspaces/.nextflow/assets/.repos/nf-core/demo + main script : main.nf + description : An nf-core demo pipeline + revisions : + TEMPLATE + bumper + dev + fix-nxfversion + manually-merge-3_0_2 + > master (default) + nf-core-template-merge-2.13.2.dev0 + nf-core-template-merge-2.14.0 + nf-core-template-merge-2.14.1 + nf-core-template-merge-3.0.0 + nf-core-template-merge-3.0.1 + nf-core-template-merge-3.0.2 + nf-core-template-merge-3.1.0 + nf-core-template-merge-3.1.2 + nf-core-template-merge-3.2.0 + nf-core-template-merge-3.2.1 + nf-core-template-merge-3.3.1 + nf-core-template-merge-3.3.2 + nf-core-template-merge-4.0.0 + 1.0.0 [t] + 1.0.1 [t] + 1.0.2 [t] + 1.1.0 [t] + > 1.2.0 [t] ``` -!!! note +!!! info The full path may differ on your system if you're not using our training environment. @@ -167,20 +185,20 @@ tree -L 1 pipelines/nf-core/demo ```console pipelines/nf-core/demo + ├── assets ├── CHANGELOG.md ├── CITATIONS.md ├── CODE_OF_CONDUCT.md - ├── LICENSE - ├── README.md - ├── assets ├── conf ├── docs + ├── LICENSE ├── main.nf ├── modules ├── modules.json ├── nextflow.config ├── nextflow_schema.json ├── nf-test.config + ├── README.md ├── ro-crate-metadata.json ├── subworkflows ├── tests @@ -209,7 +227,7 @@ We won't go over the pipeline code components in this part of the course, but we You can also browse any nf-core pipeline's source code on GitHub, e.g. [github.com/nf-core/demo](https://github.com/nf-core/demo). Every nf-core pipeline follows the same directory layout, so once you know the structure, you can find configuration files, modules, and workflows for any pipeline the same way. -But for now, on to running the pipeline! +For now, on to running the pipeline! ### Takeaway @@ -227,7 +245,7 @@ Conveniently, every nf-core pipeline comes with a test profile. This is a minimal set of configuration settings for the pipeline to run using a small test dataset hosted in the [nf-core/test-datasets](https://github.com/nf-core/test-datasets) repository. It's a great way to quickly try out a pipeline at small scale. -!!! note +!!! tip Nextflow's configuration profile system allows you to easily switch between different container engines or execution environments. For more details, see [Hello Nextflow Part 6: Configuration](../hello_nextflow/06_hello_config.md). @@ -303,16 +321,16 @@ SAMPLE3_SE,https://raw.githubusercontent.com/nf-core/test-datasets/viralrecon/il ``` This is called a samplesheet, and is the most common form of input to nf-core pipelines. +Don't worry if you're not familiar with the data formats and types, it's not important for what follows. -!!! note - - Don't worry if you're not familiar with the data formats and types, it's not important for what follows. - -So this confirms that we have everything we need to try out the pipeline. +We now have everything we need to try out the pipeline. ### 2.2. Run the pipeline -Let's decide to use Docker for the container system and `demo-results` as the output directory, and we're ready to run the test command: +As noted above, we can use the example testing command almost as-is; we just need to specify what software packaging to use, and what to name the output directory. +Here we'll use Docker for the container system and `demo-results`, respectively. + +With that, we can run the test command: ```bash nextflow run nf-core/demo -profile docker,test --outdir demo-results @@ -321,9 +339,10 @@ nextflow run nf-core/demo -profile docker,test --outdir demo-results ??? success "Command output" ```console - N E X T F L O W ~ version 26.04.4 + N E X T F L O W ~ version 26.04.4 - Launching `https://github.com/nf-core/demo` [scruffy_goldstine] revision: 45904cb9d1 [master] + Downloading plugin nf-schema@2.7.2 + Launching `https://github.com/nf-core/demo` [cranky_curry] revision: 32893afef8 [master] ------------------------------------------------------ @@ -332,8 +351,9 @@ nextflow run nf-core/demo -profile docker,test --outdir demo-results |\ | |__ __ / ` / \ |__) |__ } { | \| | \__, \__/ | \ |___ \`-._,-`-, `._,._,' - nf-core/demo 1.1.0 + nf-core/demo 1.2.0 ------------------------------------------------------ + Input/output options input : https://raw.githubusercontent.com/nf-core/test-datasets/viralrecon/samplesheet/samplesheet_test_illumina_amplicon.csv outdir : demo-results @@ -343,21 +363,22 @@ nextflow run nf-core/demo -profile docker,test --outdir demo-results config_profile_description: Minimal test dataset to check pipeline function Generic options - trace_report_suffix : 2026-06-23_16-51-59 + trace_report_suffix : 2026-07-03_21-31-35 Core Nextflow options revision : master - runName : scruffy_goldstine + runName : cranky_curry containerEngine : docker launchDir : /workspaces/training/hello-nf-core workDir : /workspaces/training/hello-nf-core/work - projectDir : /workspaces/.nextflow/assets/.repos/nf-core/demo/clones/45904cb9d12db3d89900e6c479fe604ef71b297b + projectDir : /workspaces/.nextflow/assets/.repos/nf-core/demo/clones/32893afef8076a03a2767a020b3f0cab2e0b40b2 userName : root profile : docker,test - configFiles : /workspaces/.nextflow/assets/.repos/nf-core/demo/clones/45904cb9d12db3d89900e6c479fe604ef71b297b/nextflow.config + configFiles : /workspaces/.nextflow/assets/.repos/nf-core/demo/clones/32893afef8076a03a2767a020b3f0cab2e0b40b2/nextflow.config !! Only displaying parameters that differ from the pipeline defaults !! ------------------------------------------------------ + * The pipeline https://doi.org/10.5281/zenodo.12192442 @@ -367,11 +388,11 @@ nextflow run nf-core/demo -profile docker,test --outdir demo-results * Software dependencies https://github.com/nf-core/demo/blob/master/CITATIONS.md - - executor > local (7) - [be/8d6f73] NFCORE_DEMO:DEMO:FASTQC (SAMPLE1_PE) | 3 of 3 ✔ - [8a/75c637] NFCORE_DEMO:DEMO:SEQTK_TRIM (SAMPLE1_PE) | 3 of 3 ✔ - [79/b859f7] NFCORE_DEMO:DEMO:MULTIQC | 1 of 1 ✔ + executor > local (8) + [ca/5b0f3e] NFCORE_DEMO:DEMO:FASTQC (SAMPLE3_SE) [100%] 3 of 3 ✔ + [b7/cb6812] NFCORE_DEMO:DEMO:SEQTK_TRIM (SAMPLE3_SE) [100%] 3 of 3 ✔ + [ff/6ebd98] NFCORE_DEMO:DEMO:COWPY [100%] 1 of 1 ✔ + [09/bbd1b4] NFCORE_DEMO:DEMO:MULTIQC (demo) [100%] 1 of 1 ✔ -[nf-core/demo] Pipeline completed successfully- ``` @@ -380,14 +401,14 @@ If your output matches that, congratulations! You've just run your first nf-core You'll notice that there is a lot more console output than when you run a basic Nextflow pipeline. There's a header that includes a summary of the pipeline's version, inputs and outputs, and a few elements of configuration. -!!! note +!!! info Your output will show different timestamps, execution names, and file paths, but the overall structure and process execution should be similar. Notice the line near the top of the output: ```console -Launching `https://github.com/nf-core/demo` [scruffy_goldstine] revision: 45904cb9d1 [master] +Launching `https://github.com/nf-core/demo` [cranky_curry] revision: 32893afef8 [master] ``` This tells you which revision of the pipeline was used. @@ -395,7 +416,7 @@ Because we did not specify a version, Nextflow used the latest commit on `master For reproducible runs, you should pin a specific release using the `-r` flag: ```bash -nextflow run nf-core/demo -r 1.1.0 -profile docker,test --outdir demo-results +nextflow run nf-core/demo -r 1.2.0 -profile docker,test --outdir demo-results ``` This ensures that the same pipeline code is used every time, regardless of new commits or releases. @@ -404,14 +425,15 @@ For this training we omit `-r` for simplicity, but in production you should alwa Moving on to the execution output, let's have a look at the lines that tell us what processes were run: ```console -executor > local (7) -[be/8d6f73] NFCORE_DEMO:DEMO:FASTQC (SAMPLE1_PE) | 3 of 3 ✔ -[8a/75c637] NFCORE_DEMO:DEMO:SEQTK_TRIM (SAMPLE1_PE) | 3 of 3 ✔ -[79/b859f7] NFCORE_DEMO:DEMO:MULTIQC | 1 of 1 ✔ +executor > local (8) +[ca/5b0f3e] NFCORE_DEMO:DEMO:FASTQC (SAMPLE3_SE) [100%] 3 of 3 ✔ +[b7/cb6812] NFCORE_DEMO:DEMO:SEQTK_TRIM (SAMPLE3_SE) [100%] 3 of 3 ✔ +[ff/6ebd98] NFCORE_DEMO:DEMO:COWPY [100%] 1 of 1 ✔ +[09/bbd1b4] NFCORE_DEMO:DEMO:MULTIQC (demo) [100%] 1 of 1 ✔ -[nf-core/demo] Pipeline completed successfully- ``` -This tells us that three processes were run, corresponding to the three tools shown in the pipeline documentation page on the nf-core website: FASTQC, SEQTK_TRIM and MULTIQC. +This tells us that four processes were run, corresponding to the three tools shown in the pipeline documentation page on the nf-core website: FASTQC, SEQTK_TRIM, MULTIQC and COWPY. The full process names as shown here, such as `NFCORE_DEMO:DEMO:MULTIQC`, are longer than what you may have seen in the introductory Hello Nextflow material. These include the names of their parent workflows and reflect the modularity of the pipeline code. @@ -429,6 +451,8 @@ tree -L 2 demo-results ```console demo-results + ├── cowpy + │ └── cowpy.txt ├── fastqc │ ├── SAMPLE1_PE │ ├── SAMPLE2_PE @@ -442,12 +466,14 @@ tree -L 2 demo-results │ ├── multiqc_plots │ └── multiqc_report.html └── pipeline_info - ├── execution_report_2026-06-23_16-51-59.html - ├── execution_timeline_2026-06-23_16-51-59.html - ├── execution_trace_2026-06-23_16-51-59.txt + ├── execution_report_2026-07-03_21-31-35.html + ├── execution_timeline_2026-07-03_21-31-35.html + ├── execution_trace_2026-07-03_21-31-35.txt ├── nf_core_demo_software_mqc_versions.yml - ├── params_2026-06-23_16-52-02.json - └── pipeline_dag_2026-06-23_16-51-59.html + ├── params_2026-07-03_21-31-43.json + └── pipeline_dag_2026-07-03_21-31-35.html + + 13 directories, 8 files ``` That might seem like a lot. @@ -459,7 +485,7 @@ For example, the `execution_timeline_*` file shows you what processes were run, ![execution timeline report](./img/execution_timeline.png) -!!! note +!!! info Here the tasks were not run in parallel because we are running on a minimalist machine in Github Codespaces. To see these run in parallel, try increasing the CPU allocation of your codespace and the resource limits in the test configuration. @@ -509,7 +535,7 @@ nextflow run nf-core/demo --help ```console N E X T F L O W ~ version 26.04.4 - Launching `https://github.com/nf-core/demo` [run_name] revision: 45904cb9d1 [master] + Launching `https://github.com/nf-core/demo` [adoring_meucci] revision: 32893afef8 [master] ------------------------------------------------------ @@ -518,16 +544,18 @@ nextflow run nf-core/demo --help |\ | |__ __ / ` / \ |__) |__ } { | \| | \__, \__/ | \ |___ \`-._,-`-, `._,._,' - nf-core/demo 1.1.0 + nf-core/demo 1.2.0 ------------------------------------------------------ Typical pipeline command: nextflow run nf-core/demo -profile --input samplesheet.csv --outdir + parameter will be printed. Input/output options --input [string] Path to a metadata file containing information about the samples in the experiment. --outdir [string] The output directory where the results will be saved. You have to use absolute paths to storage on Cloud infrastructure. + --email [string] Email address for completion summary. --multiqc_title [string] MultiQC report title. Printed as page header, used for filename if not otherwise specified. @@ -543,7 +571,7 @@ nextflow run nf-core/demo --help --help [boolean, string] Display the help message. --help_full [boolean] Display the full detailed help message. --show_hidden [boolean] Display hidden parameters in the help message (only works when --help or --help_full are provided). - !! Hiding 20 param(s), use the `--showHidden` parameter to show them !! + !! Hiding 19 param(s), use the `--showHidden` parameter to show them !! ------------------------------------------------------ * The pipeline @@ -571,33 +599,87 @@ As covered in [Hello Config](../hello_nextflow/06_hello_config.md), you can set Both approaches work the same way with nf-core pipelines. For example, to skip the trimming step, we want to set the boolean parameter `skip_trim` to `true`. -Create a parameter file called `skip_trim.yml`: +A params file called `my_params.yml` is provided in your working directory with that value already set: -```yaml title="skip_trim.yml" +```yaml title="my_params.yml" skip_trim: true ``` -Then pass it with `-params-file`: +Pass it with `-params-file`: ```bash -nextflow run nf-core/demo -profile docker,test --outdir demo-results-notrim -params-file skip_trim.yml +nextflow run nf-core/demo -profile docker,test --outdir demo-results-notrim -params-file my_params.yml ``` ??? success "Command output" ```console - executor > local (4) - [80/17c104] NFCORE_DEMO:DEMO:FASTQC (SAMPLE3_SE) | 3 of 3 ✔ - [a0/6ea0cf] NFCORE_DEMO:DEMO:MULTIQC | 1 of 1 ✔ + N E X T F L O W ~ version 26.04.4 + + Launching `https://github.com/nf-core/demo` [focused_heisenberg] revision: 32893afef8 [master] + + + ------------------------------------------------------ + ,--./,-. + ___ __ __ __ ___ /,-._.--~' + |\ | |__ __ / ` / \ |__) |__ } { + | \| | \__, \__/ | \ |___ \`-._,-`-, + `._,._,' + nf-core/demo 1.2.0 + ------------------------------------------------------ + + Input/output options + input : https://raw.githubusercontent.com/nf-core/test-datasets/viralrecon/samplesheet/samplesheet_test_illumina_amplicon.csv + outdir : demo-results-notrim + + Process skipping options + skip_trim : true + + Institutional config options + config_profile_name : Test profile + config_profile_description: Minimal test dataset to check pipeline function + + Generic options + trace_report_suffix : 2026-07-03_22-08-47 + + Core Nextflow options + revision : master + runName : focused_heisenberg + containerEngine : docker + launchDir : /workspaces/training/hello-nf-core + workDir : /workspaces/training/hello-nf-core/work + projectDir : /workspaces/.nextflow/assets/.repos/nf-core/demo/clones/32893afef8076a03a2767a020b3f0cab2e0b40b2 + userName : root + profile : docker,test + configFiles : /workspaces/.nextflow/assets/.repos/nf-core/demo/clones/32893afef8076a03a2767a020b3f0cab2e0b40b2/nextflow.config + + !! Only displaying parameters that differ from the pipeline defaults !! + ------------------------------------------------------ + + * The pipeline + https://doi.org/10.5281/zenodo.12192442 + + * The nf-core framework + https://doi.org/10.1038/s41587-020-0439-x + + * Software dependencies + https://github.com/nf-core/demo/blob/master/CITATIONS.md + + executor > local (5) + [7a/f3599e] NFCORE_DEMO:DEMO:FASTQC (SAMPLE3_SE) [100%] 3 of 3 ✔ + [b0/2f0bdc] NFCORE_DEMO:DEMO:COWPY [100%] 1 of 1 ✔ + [c3/3c2278] NFCORE_DEMO:DEMO:MULTIQC (demo) [100%] 1 of 1 ✔ -[nf-core/demo] Pipeline completed successfully- ``` The `SEQTK_TRIM` process no longer appears in the output. -!!! warning "Setting boolean parameters on the command line" +!!! warning "Important limitations about parameter inputs" - Nextflow types values supplied on the command line as strings. - For a boolean parameter like `skip_trim`, passing it as a bare flag (`--skip_trim`) or as `--skip_trim true` sends the **string** `"true"`, which fails schema validation: + **Setting boolean parameters on the command line** + + Starting with Nextflow version 26.04, all values supplied on the command line are typed as strings. + For a boolean parameter like `skip_trim`, passing it as a bare flag (`--skip_trim`) or as `--skip_trim true` is evaluated as the **string** `"true"`, which fails schema validation: ```console * --skip_trim (true): Value is [string] but should be [boolean] @@ -607,12 +689,12 @@ The `SEQTK_TRIM` process no longer appears in the output. String, integer and file-path parameters are unaffected and can still be set directly on the command line. This course uses this pattern throughout for boolean parameters. -!!! info + **Using custom configuration files** Although it is technically possible to set pipeline parameters in a custom configuration file passed with `-c`, this may not override defaults already set in the pipeline's own `nextflow.config`, depending on Nextflow's configuration precedence rules. Using `--param_name` on the command line or `-params-file` is more reliable, as these always take precedence. - **As a rule of thumb:** if it appears in the `--help` output, set it via the command line or a params file rather than a config file. + As a rule of thumb: If it appears in the `--help` output, set it via the command line or a params file rather than a config file. #### 3.1.3. Parameter validation @@ -641,7 +723,7 @@ WARN: The following invalid input values have been detected: ``` The pipeline still runs, but the warning alerts you right away that `--foobar` is not a recognized parameter. -This catches typos like `--outDir` instead of `--outdir` before you waste compute time wondering why the output went to the wrong place. +This is meant to draw your attention to non-breaking typos, like `--outDir` being used instead of `--outdir`, which can help you avoid wasting time and compute. ##### 3.1.3.2. Invalid parameter values @@ -661,7 +743,7 @@ The following invalid input values have been detected: ``` The pipeline stops before any processes run, saving you from a failed or incorrect execution. -As shown in section 3.1.2, boolean parameters should be set to a genuine `true`/`false` value in a params file rather than passed on the command line, since command-line values are typed as strings. +As noted in section 3.1.2, boolean parameters should be set to a genuine `true`/`false` value in a params file rather than passed on the command line, since command-line values are typed as strings. #### 3.1.4. Input validation @@ -716,9 +798,7 @@ This is defined in a schema file (`assets/schema_input.json`) that specifies the The schema specifies that `sample` and `fastq_1` are required, while `fastq_2` is optional (supporting both paired-end and single-end data). File paths are validated for existence and extension pattern. -##### 3.1.4.1. Create an invalid samplesheet - -Create a samplesheet with a missing column and a non-existent file path: +To demonstrate this, we provide a malformed samplesheet called `malformed_samplesheet.csv` in your working directory: ```csv title="malformed_samplesheet.csv" sample,fastq_2 @@ -726,11 +806,8 @@ SAMPLE1,/not/a/real/file.fastq.gz ``` This samplesheet is missing the required `fastq_1` column and has a non-existent file path in `fastq_2`. -Both issues will produce validation errors in the next step. - -##### 3.1.4.2. Run the demo pipeline with the invalid samplesheet -Run the demo pipeline using `malformed_samplesheet.csv` as the input. +Run the demo pipeline using `malformed_samplesheet.csv` as the input: ```bash nextflow run nf-core/demo -profile docker,test --outdir demo-results --input malformed_samplesheet.csv diff --git a/hello-nf-core/malformed_samplesheet.csv b/hello-nf-core/malformed_samplesheet.csv new file mode 100644 index 0000000000..4e743f0ae3 --- /dev/null +++ b/hello-nf-core/malformed_samplesheet.csv @@ -0,0 +1,2 @@ +sample,fastq_2 +SAMPLE1,/not/a/real/file.fastq.gz diff --git a/hello-nf-core/my_params.yml b/hello-nf-core/my_params.yml new file mode 100644 index 0000000000..0142125ab9 --- /dev/null +++ b/hello-nf-core/my_params.yml @@ -0,0 +1 @@ +skip_trim: true From d0800ab1b0e83e0dd10d2f4613502a39ca3a8e1d Mon Sep 17 00:00:00 2001 From: Geraldine Van der Auwera Date: Fri, 3 Jul 2026 18:49:21 -0400 Subject: [PATCH 35/42] chore(hello_nf-core): update screenshots and minor wording fix in Part 3 Co-Authored-By: Claude Sonnet 4.6 --- docs/en/docs/hello_nf-core/03_use_module.md | 2 +- .../img/nf-core-demo-subway-cropped.png | Bin 16075 -> 69503 bytes .../docs/hello_nf-core/img/search-results.png | Bin 103853 -> 68311 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/hello_nf-core/03_use_module.md b/docs/en/docs/hello_nf-core/03_use_module.md index fbfede28c2..4c593bef48 100644 --- a/docs/en/docs/hello_nf-core/03_use_module.md +++ b/docs/en/docs/hello_nf-core/03_use_module.md @@ -250,7 +250,7 @@ tree -L 4 modules You can also confirm the installation by inspecting `modules.json`, which now lists `find/concatenate` under the nf-core/modules repository. -??? abstract "modules.json" +??? abstract File contents ```json title="modules.json" { diff --git a/docs/en/docs/hello_nf-core/img/nf-core-demo-subway-cropped.png b/docs/en/docs/hello_nf-core/img/nf-core-demo-subway-cropped.png index ac07a8bc49bca61e9230745f9d4173f04b807d5b..b3cdbf4790001176a2f9857f8c5486ffcb9bd85d 100644 GIT binary patch literal 69503 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 QpUfs@d8}OeX|t>U2k^@zCjbBd literal 16075 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⋓D~Y5(+>9!XU*T}CZvlQz7*W@=II7~ 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 From 770e263636f678e0383d1c6d3940592fad8966ab Mon Sep 17 00:00:00 2001 From: Geraldine Van der Auwera Date: Fri, 3 Jul 2026 21:55:15 -0400 Subject: [PATCH 36/42] feat(hello_nf-core): provide custom.config and combine config override exercises in Part 1 - Add custom.config (FASTQC resource override + SEQTK_TRIM ext.args) to hello-nf-core/ - Merge sections 3.2.1 and 3.2.2 into a single exercise showing both overrides at once - Update orientation directory tree and file descriptions Co-Authored-By: Claude Sonnet 4.6 --- docs/en/docs/hello_nf-core/00_orientation.md | 3 + docs/en/docs/hello_nf-core/01_run_demo.md | 78 +++++--------------- hello-nf-core/custom.config | 9 +++ 3 files changed, 32 insertions(+), 58 deletions(-) create mode 100644 hello-nf-core/custom.config diff --git a/docs/en/docs/hello_nf-core/00_orientation.md b/docs/en/docs/hello_nf-core/00_orientation.md index a1f7a93600..2a2bd45c0e 100644 --- a/docs/en/docs/hello_nf-core/00_orientation.md +++ b/docs/en/docs/hello_nf-core/00_orientation.md @@ -69,6 +69,7 @@ tree . -L 2 ```console . + ├── custom.config ├── greetings.csv ├── malformed_samplesheet.csv ├── my_params.yml @@ -90,6 +91,8 @@ We use collapsible sections like this to include expected command output in a co - **The `greetings.csv` file** is a CSV containing some minimal columnar data we use for testing purposes. +- **The `custom.config` file** is an example Nextflow configuration file used in Part 1 to demonstrate process resource overrides and `ext.args`. + - **The `malformed_samplesheet.csv` file** is an intentionally broken samplesheet used in Part 1 to demonstrate input validation. - **The `my_params.yml` file** is an example params file used in Part 1 to demonstrate how to pass boolean parameters to a pipeline. diff --git a/docs/en/docs/hello_nf-core/01_run_demo.md b/docs/en/docs/hello_nf-core/01_run_demo.md index 46f3b7c770..85d64ef858 100644 --- a/docs/en/docs/hello_nf-core/01_run_demo.md +++ b/docs/en/docs/hello_nf-core/01_run_demo.md @@ -867,56 +867,18 @@ If you wish to modify any of the settings specified in these files, do not modif Instead, create your own config file and pass it with `-c`. The values you specify will override the default values set in those other files. -Let's run through a few exercises to do this in practice. +Let's try this in practice. -#### 3.2.1. Change resource allocation for a process +#### 3.2.1. Customize process resources and tool arguments -The demo pipeline assigns resources using labels defined in `base.config`. -For example, `FASTQC` uses the `process_medium` label, which allocates 6 CPUs and 36 GB of memory. +nf-core modules support two common types of configuration override: **resource allocation** (CPUs, memory, time) and **tool arguments** via `ext.args`. -The test profile caps resources via `resourceLimits`, but you can also override resources for specific processes. +Many command-line tools have arguments that are not commonly enough used to be exposed as pipeline parameters. +The `ext.args` convention lets you pass these arguments to the underlying tool through a config file instead. -Create a file called `custom.config`: +The `custom.config` file provided in your working directory demonstrates both overrides: ```groovy title="custom.config" linenums="1" -process { - withName: 'FASTQC' { - cpus = 2 - memory = 4.GB - } -} -``` - -Run the pipeline with your custom config: - -```bash -nextflow run nf-core/demo -profile docker,test --outdir demo-results-custom -c custom.config -``` - -??? success "Command output" - - ```console - executor > local (7) - [ac/23f5aa] NFCORE_DEMO:DEMO:FASTQC (SAMPLE1_PE) | 3 of 3 ✔ - [ff/eac89a] NFCORE_DEMO:DEMO:SEQTK_TRIM (SAMPLE1_PE) | 3 of 3 ✔ - [3c/94a7a0] NFCORE_DEMO:DEMO:MULTIQC | 1 of 1 ✔ - -[nf-core/demo] Pipeline completed successfully- - ``` - -The `-c` flag adds your config on top of the pipeline's built-in configuration. - -#### 3.2.2. Set tool argument values with `ext.args` - -Many command-line tools have arguments that are not required and are therefore not set up as pipeline parameters unless they are very commonly used. -For those tool arguments, nf-core modules use a Nextflow convention called `ext.args` to pass arguments to the underlying tool through a configuration file. - -For example, let's add a trimming argument to the `SEQTK_TRIM` module using `ext.args`. - -##### 3.2.2.1. Update the custom configuration - -Update your `custom.config`: - -```groovy title="custom.config" linenums="1" hl_lines="6 7 8" process { withName: 'FASTQC' { cpus = 2 @@ -928,14 +890,16 @@ process { } ``` -This tells `seqtk trimfq` to trim 5 bases from the beginning of each read in addition to quality trimming. +The first block overrides `FASTQC` resource allocation. +By default, `FASTQC` uses the `process_medium` label from `base.config`, which allocates 6 CPUs and 36 GB of memory; here we cap it at 2 CPUs and 4 GB. -##### 3.2.2.2. Run the pipeline +The second block passes an extra argument to `SEQTK_TRIM` via `ext.args`. +The `-b 5` flag tells `seqtk trimfq` to trim 5 bases from the beginning of each read in addition to quality trimming. -Run the pipeline again with this config to see the effect: +Run the pipeline with this config: ```bash -nextflow run nf-core/demo -profile docker,test --outdir demo-results-extargs -c custom.config +nextflow run nf-core/demo -profile docker,test --outdir demo-results-custom -c custom.config ``` ??? success "Command output" @@ -948,7 +912,9 @@ nextflow run nf-core/demo -profile docker,test --outdir demo-results-extargs -c -[nf-core/demo] Pipeline completed successfully- ``` -To verify the argument was applied, find the `SEQTK_TRIM` work directory hash from the run output (e.g. `work/17/428668...`) and check the `.command.sh` file inside it: +The `-c` flag adds your config on top of the pipeline's built-in configuration. + +To verify the `ext.args` override took effect, find the `SEQTK_TRIM` work directory hash from the run output (e.g. `work/17/428668...`) and check the `.command.sh` file inside it: ```bash cat work/17/428668/.command.sh @@ -969,12 +935,10 @@ cat work/17/428668/.command.sh ... ``` -You should see `-b 5` in the `seqtk trimfq` command, confirming your `ext.args` override took effect. +You should see `-b 5` in the `seqtk trimfq` command. -##### 3.2.2.3. Overriding default values - -Some modules have `ext.args` already set by default. -For example, the `FASTQC` module is configured with `ext.args = '--quiet'` by default (defined in `conf/modules.config`). +One important thing to know about `ext.args`: if a module already has a default value set, your value will **completely replace** it rather than append to it. +For example, `FASTQC` has `ext.args = '--quiet'` set by default in `conf/modules.config`: ```groovy title="conf/modules.config" linenums="21" hl_lines="2" withName: FASTQC { @@ -987,12 +951,10 @@ For example, the `FASTQC` module is configured with `ext.args = '--quiet'` by de } ``` -If you provide a value for `ext.args` via a custom configuration file, that value will completely replace the default set for that process. - -So for example, if the default was `'--quiet'` and you set `ext.args = '--kmers 8'`, the `--quiet` flag will no longer be applied. +If you set `ext.args = '--kmers 8'` for `FASTQC`, the `--quiet` flag will no longer be applied. To keep both, set `ext.args = '--quiet --kmers 8'`. -This does mean you are responsible for checking what is the default configuration of tools to which you want to provide argument values with `ext.args`. +You should always check a module's default configuration before overriding `ext.args`. ### Takeaway diff --git a/hello-nf-core/custom.config b/hello-nf-core/custom.config new file mode 100644 index 0000000000..ca08f44d8e --- /dev/null +++ b/hello-nf-core/custom.config @@ -0,0 +1,9 @@ +process { + withName: 'FASTQC' { + cpus = 2 + memory = 4.GB + } + withName: 'SEQTK_TRIM' { + ext.args = '-b 5' + } +} From e7e6d83d1ecaa981752400715fdec68b9ed0423c Mon Sep 17 00:00:00 2001 From: Geraldine Van der Auwera Date: Fri, 3 Jul 2026 21:58:02 -0400 Subject: [PATCH 37/42] docs(hello_nf-core): clarify Part 1 is a standalone stopping point for pipeline users Co-Authored-By: Claude Sonnet 4.6 --- docs/en/docs/hello_nf-core/01_run_demo.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/hello_nf-core/01_run_demo.md b/docs/en/docs/hello_nf-core/01_run_demo.md index 85d64ef858..a7ac46d1ea 100644 --- a/docs/en/docs/hello_nf-core/01_run_demo.md +++ b/docs/en/docs/hello_nf-core/01_run_demo.md @@ -962,4 +962,6 @@ You know how to get help from an nf-core pipeline, set parameters and understand ### What's next? -Take a break! When you're ready, move on to Part 2, where you will create your own nf-core compatible pipeline from scratch. +If you just want to run nf-core pipelines, you're done! + +If you want to learn to develop your own pipelines according to nf-core standards, take a break, and move on to Part 2 when you're ready. You will learn to create your own nf-core compatible pipeline using the nf-core template-based tools. From 39f0d9178a6b494ec981a7c77c3e463126a84a34 Mon Sep 17 00:00:00 2001 From: Geraldine Van der Auwera Date: Fri, 3 Jul 2026 22:27:09 -0400 Subject: [PATCH 38/42] fix(hello_nf-core): update Part 1 docs to match nf-core/demo 1.2.0 outputs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix process counts and add COWPY to all run outputs (1.2.0 added COWPY process) - Remove multiqc_plots from demo-results tree (no longer produced in 1.2.0) - Update directory count from 13 to 12 accordingly - Update conf/ listing to include container config files added in 1.2.0 - Update test.config snippet: trailing comma in resourceLimits, aligned input field - Update modules.config snippet: ext.args spacing to match actual file - Add missing ' -- Check .nextflow.log' line to validation error outputs - Fix tree ordering to Linux case-sensitive sort (uppercase before lowercase) - Fix 'three tools' → 'four tools' and backtick process names in prose - Fix 'Don't worry' to neutral phrasing - Update docs link from 1.1.0 to 1.2.0 Co-Authored-By: Claude Sonnet 4.6 --- docs/en/docs/hello_nf-core/01_run_demo.md | 46 +++++++++++++++-------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/docs/en/docs/hello_nf-core/01_run_demo.md b/docs/en/docs/hello_nf-core/01_run_demo.md index a7ac46d1ea..067bb7791d 100644 --- a/docs/en/docs/hello_nf-core/01_run_demo.md +++ b/docs/en/docs/hello_nf-core/01_run_demo.md @@ -185,20 +185,20 @@ tree -L 1 pipelines/nf-core/demo ```console pipelines/nf-core/demo - ├── assets ├── CHANGELOG.md ├── CITATIONS.md ├── CODE_OF_CONDUCT.md + ├── LICENSE + ├── README.md + ├── assets ├── conf ├── docs - ├── LICENSE ├── main.nf ├── modules ├── modules.json ├── nextflow.config ├── nextflow_schema.json ├── nf-test.config - ├── README.md ├── ro-crate-metadata.json ├── subworkflows ├── tests @@ -279,7 +279,7 @@ process { resourceLimits = [ cpus: 2, memory: '4.GB', - time: '1.h' + time: '1.h', ] } @@ -288,8 +288,7 @@ params { config_profile_description = 'Minimal test dataset to check pipeline function' // Input data - input = 'https://raw.githubusercontent.com/nf-core/test-datasets/viralrecon/samplesheet/samplesheet_test_illumina_amplicon.csv' - + input = 'https://raw.githubusercontent.com/nf-core/test-datasets/viralrecon/samplesheet/samplesheet_test_illumina_amplicon.csv' } ``` @@ -321,7 +320,7 @@ SAMPLE3_SE,https://raw.githubusercontent.com/nf-core/test-datasets/viralrecon/il ``` This is called a samplesheet, and is the most common form of input to nf-core pipelines. -Don't worry if you're not familiar with the data formats and types, it's not important for what follows. +Familiarity with the data formats and types is not required for what follows. We now have everything we need to try out the pipeline. @@ -433,7 +432,7 @@ executor > local (8) -[nf-core/demo] Pipeline completed successfully- ``` -This tells us that four processes were run, corresponding to the three tools shown in the pipeline documentation page on the nf-core website: FASTQC, SEQTK_TRIM, MULTIQC and COWPY. +This tells us that four processes were run, corresponding to the four tools shown in the pipeline documentation page on the nf-core website: `FASTQC`, `SEQTK_TRIM`, `MULTIQC` and `COWPY`. The full process names as shown here, such as `NFCORE_DEMO:DEMO:MULTIQC`, are longer than what you may have seen in the introductory Hello Nextflow material. These include the names of their parent workflows and reflect the modularity of the pipeline code. @@ -463,7 +462,6 @@ tree -L 2 demo-results │ └── SAMPLE3_SE ├── multiqc │ ├── multiqc_data - │ ├── multiqc_plots │ └── multiqc_report.html └── pipeline_info ├── execution_report_2026-07-03_21-31-35.html @@ -473,11 +471,11 @@ tree -L 2 demo-results ├── params_2026-07-03_21-31-43.json └── pipeline_dag_2026-07-03_21-31-35.html - 13 directories, 8 files + 12 directories, 8 files ``` That might seem like a lot. -To learn more about the `nf-core/demo` pipeline's outputs, check out its [documentation page](https://nf-co.re/demo/1.1.0/docs/output/). +To learn more about the `nf-core/demo` pipeline's outputs, check out its [documentation page](https://nf-co.re/demo/1.2.0/docs/output/). At this stage, what's important to observe is that the results are organized by module, and there is additionally a directory called `pipeline_info` containing various timestamped reports about the pipeline execution. @@ -737,6 +735,7 @@ nextflow run nf-core/demo -profile docker,test --outdir demo-results --skip_trim ```console ERROR ~ Validation of pipeline parameters failed! + -- Check '.nextflow.log' file for details The following invalid input values have been detected: * --skip_trim (yes): Value is [string] but should be [boolean] @@ -816,6 +815,7 @@ nextflow run nf-core/demo -profile docker,test --outdir demo-results --input mal ```console ERROR ~ Validation of pipeline parameters failed! + -- Check '.nextflow.log' file for details The following invalid input values have been detected: * --input (malformed_samplesheet.csv): Validation of file failed: @@ -847,7 +847,20 @@ ls pipelines/nf-core/demo/conf/ ``` ```console -base.config igenomes.config igenomes_ignored.config modules.config test.config test_full.config +base.config +containers_conda_lock_files_amd64.config +containers_conda_lock_files_arm64.config +containers_docker_amd64.config +containers_docker_arm64.config +containers_singularity_https_amd64.config +containers_singularity_https_arm64.config +containers_singularity_oras_amd64.config +containers_singularity_oras_arm64.config +igenomes.config +igenomes_ignored.config +modules.config +test.config +test_full.config ```
@@ -905,10 +918,11 @@ nextflow run nf-core/demo -profile docker,test --outdir demo-results-custom -c c ??? success "Command output" ```console - executor > local (7) + executor > local (8) [95/b32876] NFCORE_DEMO:DEMO:FASTQC (SAMPLE1_PE) | 3 of 3 ✔ [17/428668] NFCORE_DEMO:DEMO:SEQTK_TRIM (SAMPLE1_PE) | 3 of 3 ✔ - [cf/85991a] NFCORE_DEMO:DEMO:MULTIQC | 1 of 1 ✔ + [cf/85991a] NFCORE_DEMO:DEMO:COWPY | 1 of 1 ✔ + [3c/94a7a0] NFCORE_DEMO:DEMO:MULTIQC (demo) | 1 of 1 ✔ -[nf-core/demo] Pipeline completed successfully- ``` @@ -942,11 +956,11 @@ For example, `FASTQC` has `ext.args = '--quiet'` set by default in `conf/modules ```groovy title="conf/modules.config" linenums="21" hl_lines="2" withName: FASTQC { - ext.args = '--quiet' + ext.args = '--quiet' publishDir = [ path: { "${params.outdir}/fastqc/${meta.id}" }, mode: params.publish_dir_mode, - pattern: "*.{html,json}" + pattern: "*.{html,json}", ] } ``` From 6a0ab0be36534c3625528d8ec0168c1ddea8c37e Mon Sep 17 00:00:00 2001 From: Geraldine Van der Auwera Date: Fri, 3 Jul 2026 22:50:45 -0400 Subject: [PATCH 39/42] tiny fixes --- docs/en/docs/hello_nf-core/01_run_demo.md | 8 ++++---- docs/en/docs/hello_nf-core/02_rewrite_hello.md | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/en/docs/hello_nf-core/01_run_demo.md b/docs/en/docs/hello_nf-core/01_run_demo.md index 067bb7791d..ab865beffd 100644 --- a/docs/en/docs/hello_nf-core/01_run_demo.md +++ b/docs/en/docs/hello_nf-core/01_run_demo.md @@ -185,20 +185,20 @@ tree -L 1 pipelines/nf-core/demo ```console pipelines/nf-core/demo + ├── assets ├── CHANGELOG.md ├── CITATIONS.md ├── CODE_OF_CONDUCT.md - ├── LICENSE - ├── README.md - ├── assets ├── conf ├── docs + ├── LICENSE ├── main.nf ├── modules ├── modules.json ├── nextflow.config ├── nextflow_schema.json ├── nf-test.config + ├── README.md ├── ro-crate-metadata.json ├── subworkflows ├── tests @@ -320,7 +320,7 @@ SAMPLE3_SE,https://raw.githubusercontent.com/nf-core/test-datasets/viralrecon/il ``` This is called a samplesheet, and is the most common form of input to nf-core pipelines. -Familiarity with the data formats and types is not required for what follows. +Don't worry if you're not familiar with the data formats and types, it's not important for what follows. We now have everything we need to try out the pipeline. diff --git a/docs/en/docs/hello_nf-core/02_rewrite_hello.md b/docs/en/docs/hello_nf-core/02_rewrite_hello.md index 4416cb8198..118faba81c 100644 --- a/docs/en/docs/hello_nf-core/02_rewrite_hello.md +++ b/docs/en/docs/hello_nf-core/02_rewrite_hello.md @@ -289,7 +289,6 @@ tree core-hello ```console core-hello - ├── README.md ├── assets │ ├── samplesheet.csv │ └── schema_input.json @@ -300,13 +299,14 @@ tree core-hello │ └── test_full.config ├── docs │ ├── CONTRIBUTING.md - │ ├── README.md │ ├── output.md + │ ├── README.md │ └── usage.md ├── main.nf ├── modules.json ├── nextflow.config ├── nextflow_schema.json + ├── README.md ├── subworkflows │ ├── local │ │ └── utils_nfcore_hello_pipeline From 58bc6637e802f590b87a53e2d8c852d44b97c4da Mon Sep 17 00:00:00 2001 From: Geraldine Van der Auwera Date: Fri, 3 Jul 2026 23:02:30 -0400 Subject: [PATCH 40/42] tiny tweak --- docs/en/docs/hello_nf-core/02_rewrite_hello.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/en/docs/hello_nf-core/02_rewrite_hello.md b/docs/en/docs/hello_nf-core/02_rewrite_hello.md index 118faba81c..e2283941c8 100644 --- a/docs/en/docs/hello_nf-core/02_rewrite_hello.md +++ b/docs/en/docs/hello_nf-core/02_rewrite_hello.md @@ -16,10 +16,6 @@ If you're not familiar with the Hello pipeline or you could use a reminder, see - [Workflows of Workflows](../side_quests/workflows_of_workflows/index.md) - [Metadata and meta maps](../side_quests/metadata/index.md) -!!! note - - Make sure you are starting in the `hello-nf-core` directory in your terminal. - --- ## 1. Examine the pipeline code structure @@ -28,6 +24,7 @@ The nf-core project enforces strong guidelines for how pipelines are structured, Before we tackle our pipeline creation project, we need to understand that structure and organization. So let's have a look at how the pipeline code is organized in the `nf-core/demo` repository, using the `pipelines` symlink we created in Part 1. +Make sure you are starting in the `hello-nf-core` directory in your terminal. As a reminder, you can either use `tree` or use the file explorer to find and open the `nf-core/demo` directory. From 765cdb820855dfa0bea8704364a7246f79ccd7b9 Mon Sep 17 00:00:00 2001 From: Geraldine Van der Auwera Date: Fri, 3 Jul 2026 23:10:45 -0400 Subject: [PATCH 41/42] minor tweaks --- docs/en/docs/hello_nf-core/01_run_demo.md | 2 +- docs/en/docs/hello_nf-core/02_rewrite_hello.md | 14 +++++++------- docs/en/docs/hello_nf-core/03_use_module.md | 12 ++++++------ docs/en/docs/hello_nf-core/04_make_module.md | 8 ++++---- docs/en/docs/hello_nf-core/05_input_validation.md | 2 +- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/en/docs/hello_nf-core/01_run_demo.md b/docs/en/docs/hello_nf-core/01_run_demo.md index ab865beffd..ce7edd1fdd 100644 --- a/docs/en/docs/hello_nf-core/01_run_demo.md +++ b/docs/en/docs/hello_nf-core/01_run_demo.md @@ -756,7 +756,7 @@ We also cover this in more detail in [Part 5: Input Validation](05_input_validat The `nf-core/demo` pipeline expects a CSV file with columns `sample`, `fastq_1`, and `fastq_2`. This is defined in a schema file (`assets/schema_input.json`) that specifies the expected structure, column types, and constraints. -??? abstract "assets/schema_input.json" +??? abstract "Schema file for inputs" ```json title="assets/schema_input.json" { diff --git a/docs/en/docs/hello_nf-core/02_rewrite_hello.md b/docs/en/docs/hello_nf-core/02_rewrite_hello.md index e2283941c8..8f9ea32445 100644 --- a/docs/en/docs/hello_nf-core/02_rewrite_hello.md +++ b/docs/en/docs/hello_nf-core/02_rewrite_hello.md @@ -77,7 +77,7 @@ Here is what the relationships between the relevant code components look like: The unnamed workflow in `main.nf` is called an _entrypoint_ script. It acts as a wrapper for two kinds of nested workflows: the `DEMO` workflow containing the actual analysis logic, located in `workflows/demo.nf`, and a set of housekeeping workflows located under `subworkflows/`. The `demo.nf` workflow calls on **modules** located under `modules/`; these contain the **processes** that will perform the actual analysis steps. -!!! note +!!! info Subworkflows are not limited to housekeeping functions, and they can make use of process modules. @@ -102,7 +102,7 @@ We'll cover the relevant differences in the next part of this course, when we ta The `demo.nf` workflow calls on **modules** located under `modules/`, which we'll review next. -!!! note +!!! info Some nf-core analysis workflows display additional levels of nesting by calling on lower-level subworkflows. This is mostly used for wrapping two or more modules that are commonly used together into easily reusable pipeline segments. @@ -712,7 +712,7 @@ While we're at it, we can also comment out the line `params.greeting = 'greeting params.character = 'turkey' ``` -!!! note +!!! info If you have the Nextflow language server extension installed, the syntax checker will light up your code with red squiggles. That's because if you put in a `take:` statement, you have to also have a `main:`. @@ -859,7 +859,7 @@ There are two important observations to make here: - The syntax for calling the imported workflow is essentially the same as the syntax for calling modules. - Everything that is related to pulling the inputs into the workflow (input parameter and channel construction) is now declared in this parent workflow. -!!! note +!!! info Naming the entrypoint workflow file `main.nf` is a convention, not a requirement. @@ -998,7 +998,7 @@ We're going to tackle this in the following stages: 3. Add the workflow logic to the `main` block 4. Update the `emit` block -!!! note +!!! info We're going to ignore the version capture block for this first pass. Part 4 explains how it works. @@ -1427,7 +1427,7 @@ If we open up that file and scroll down, we come to this chunk of code: This is the channel factory that parses the samplesheet and passes it on in a form that is ready to be consumed by the HELLO workflow. -!!! note +!!! info The syntax above is a little different from what we've used previously, but basically this: @@ -1726,7 +1726,7 @@ This time you see all the tasks that were run as expected. ![execution timeline report for the Hello pipeline](./img/execution_timeline_hello.png) -!!! note +!!! info Once again the tasks were not run in parallel because we are running on a minimalist machine in Github Codespaces. To see these run in parallel, try increasing the CPU allocation of your codespace and the resource limits in the test configuration. diff --git a/docs/en/docs/hello_nf-core/03_use_module.md b/docs/en/docs/hello_nf-core/03_use_module.md index 4c593bef48..51442d2c44 100644 --- a/docs/en/docs/hello_nf-core/03_use_module.md +++ b/docs/en/docs/hello_nf-core/03_use_module.md @@ -48,7 +48,7 @@ Navigate to the modules page in your web browser and use the search bar to searc As you can see, there are quite a few results, many of them modules designed to concatenate very specific types of files. Among them, you should see one called `find_concatenate` that is general-purpose. -!!! note "Module naming convention" +!!! info "Module naming convention" The underscore (`_`) is used as a stand-in for the slash (`/`) character in module names. @@ -368,7 +368,7 @@ At this point, you might be tempted to dive in and start editing code, but it's We're going to tackle that as a separate section because it involves a new mechanism we haven't covered yet: metadata maps. -!!! note +!!! info You can optionally delete the `collectGreetings.nf` file: @@ -396,7 +396,7 @@ This will allow us to determine whether we can just treat the new module as a dr Ideally this is something you should do _before_ you even install the module, but hey, better late than never. (For what it's worth, there is an `uninstall` command to get rid of modules you decide you no longer want.) -!!! note +!!! info The FIND_CONCATENATE process includes some rather clever handling of different compression types, file extensions and so on that aren't strictly relevant to what we're trying to show you here, so we'll ignore most of it and focus only on the parts that are important. @@ -535,7 +535,7 @@ As mentioned earlier, the `tuple val(meta), path(files_in)` input setup is a sta Hopefully you can start to see how useful this can be. Not only does it allow you to name outputs based on metadata, but you can also do things like use it to apply different parameter values, and in combination with specific operators, you can even group, sort or filter out data as it flows through the pipeline. -!!! note "Learn more about metadata" +!!! info "Learn more about metadata" For a comprehensive introduction to working with metadata in Nextflow workflows, including how to read metadata from samplesheets and use it to customize processing, see the [Metadata in workflows](../side_quests/metadata/index.md) side quest. @@ -566,7 +566,7 @@ Now that you know everything about metamaps (or enough for the purposes of this For the sake of clarity, we'll break this down and cover each step separately. -!!! note +!!! info All the changes shown below are made to the workflow logic in the `main` block in the `core-hello/workflows/hello.nf` workflow file. @@ -776,7 +776,7 @@ The `#!groovy .map { meta, file -> file }` operation extracts the file from the Then it's just a matter of passing `ch_for_cowpy` to `cowpy` instead of `collectGreetings.out.outfile` in that last line. -!!! note +!!! info In the next part of the course, we'll update `cowpy` to work with metadata tuples directly, so this extraction step will no longer be necessary. diff --git a/docs/en/docs/hello_nf-core/04_make_module.md b/docs/en/docs/hello_nf-core/04_make_module.md index 6d3c33a8fd..950bd09ef5 100644 --- a/docs/en/docs/hello_nf-core/04_make_module.md +++ b/docs/en/docs/hello_nf-core/04_make_module.md @@ -531,7 +531,7 @@ You can see we made three changes. As a result, the module interface is now simpler: it only expects the essential metadata and file inputs. -!!! note +!!! info The `?:` operator is often called the 'Elvis operator' because it looks like a sideways Elvis Presley face, with the `?` character symbolizing the wave in his hair. @@ -729,7 +729,7 @@ To summarize the benefits of this approach: - **Portability**: Modules can be reused without hardcoded tool options - **No workflow changes**: Adding or changing tool options doesn't require updating workflow code -!!! note +!!! info The `ext.args` system has powerful additional capabilities not covered here, including switching argument values dynamically based on metadata. See the [nf-core module specifications](https://nf-co.re/docs/guidelines/components/modules) for more details. @@ -1055,7 +1055,7 @@ Now the `core-hello-results` also contains the outputs of the `COWPY` module. You can see that Nextflow created this hierarchy of directories based on the names of the workflow and of the module. -!!! note +!!! info You may notice `hello_software_versions.yml` in `pipeline_info/`. It currently only contains version information from `FIND_CONCATENATE`, because `COWPY` doesn't report its version yet. @@ -1196,7 +1196,7 @@ Workflow: The workflow-side collection — the `Channel.topic("versions")` block you saw in the placeholder workflow in Part 2 — subscribes to the topic and writes this combined report automatically. -!!! note "Backwards compatibility" +!!! info "Backwards compatibility" The `versions_file` branch in the workflow's topic channel block exists to handle modules that haven't yet been updated to use `topic: versions` and still write a `versions.yml` file in the script block with `emit: versions`. Both styles are supported simultaneously during the transition. diff --git a/docs/en/docs/hello_nf-core/05_input_validation.md b/docs/en/docs/hello_nf-core/05_input_validation.md index 9608bef4c3..5b97798616 100644 --- a/docs/en/docs/hello_nf-core/05_input_validation.md +++ b/docs/en/docs/hello_nf-core/05_input_validation.md @@ -196,7 +196,7 @@ This configuration tells nf-schema to: - **`ignoreParams`**: Skip validation of the `input` parameter's file contents (temporary; we'll re-enable this in section 2) - **`monochromeLogs`**: Disable colored output in validation messages when set to `true` (controlled by `params.monochrome_logs`) -!!! note "Why ignore the input parameter?" +!!! info "Why ignore the input parameter?" The `input` parameter in `nextflow_schema.json` has `"schema": "assets/schema_input.json"` which tells nf-schema to validate the *contents* of the input CSV file against that schema. Since we haven't configured that schema yet, we temporarily ignore this validation. From b55c2cd05ba12ed826e35e67643644d2c984bc46 Mon Sep 17 00:00:00 2001 From: Geraldine Van der Auwera Date: Fri, 3 Jul 2026 23:27:25 -0400 Subject: [PATCH 42/42] docs(hello_nf-core): convert note admonitions to info, add v2 parser compat warning, fix tree ordering - Replace all !!! note with !!! info across Parts 2-5 (18 instances) - Add v2 parser compatibility warning to orientation page - Fix tree ordering in Part 2 core-hello scaffold (README.md, docs/ subdir) - Revert style fix to 'Don't worry' line in Part 1 Co-Authored-By: Claude Sonnet 4.6 --- docs/en/docs/hello_nf-core/00_orientation.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/en/docs/hello_nf-core/00_orientation.md b/docs/en/docs/hello_nf-core/00_orientation.md index 2a2bd45c0e..98113e39af 100644 --- a/docs/en/docs/hello_nf-core/00_orientation.md +++ b/docs/en/docs/hello_nf-core/00_orientation.md @@ -28,6 +28,12 @@ If you use a different version of nf-core tooling, you may have difficulty follo You can check what version is installed in your environment using the command `nf-core --version`. +!!! warning "v2 parser compatibility" + + Many nf-core pipelines do not yet support the v2 syntax parser. + If you run an nf-core pipeline other than those used in this course and encounter errors, you may need to switch to the v1 parser by setting `export NXF_SYNTAX_PARSER=v1`. + See the [version notes](../info/nxf_versions.md) for details. + ## Get ready to work Once your codespace is running, there are two things you need to do before diving into the training: set your working directory for this specific course, and take a look at the materials provided.