Skip to content

Add Seqera Platform Automation side quest#968

Draft
adamrtalbot wants to merge 22 commits into
masterfrom
platform-automation-side-quest
Draft

Add Seqera Platform Automation side quest#968
adamrtalbot wants to merge 22 commits into
masterfrom
platform-automation-side-quest

Conversation

@adamrtalbot

Copy link
Copy Markdown
Collaborator

Summary

Adds a new Seqera Platform Automation side quest that walks the Platform's programmatic surface across three workspace roles of decreasing privilege (Admin → Maintain → Launch), each handing an artifact to the next.

  • Lesson: docs/en/docs/side_quests/platform_automation/index.md — create compute environments (Batch Forge UI + Terraform), add pipelines to the Launchpad four ways (UI, tw, seqerakit, Terraform), and launch (GUI, tw, seqerakit, Actions). The throughline is declarative existence (Terraform) vs imperative actions (UI, tw, seqerakit).
  • Runnable assets: side-quests/platform_automation/terraform/compute-env/, terraform/pipeline/, and seqerakit/ with *.tfvars.example templates.
  • Devcontainer: adds Terraform (hashicorp.terraform extension), tw (0.32.0), and seqerakit (0.5.7) to the toolchain.

Notes

Verification

  • uv run .github/check_headings.py docs/en/docs/side_quests/platform_automation/index.md → 0 errors
  • npx prettier --check on the lesson → passes
  • git check-ignore confirms terraform.tfvars/*.tfstate are ignored while *.tfvars.example stay tracked

Generated by Claude Code

Port the Platform Automation training module from the standalone
m42-platform-advanced-training repo into the training collection as a
single-page side quest, following the side_quests convention.

- docs/en/docs/side_quests/platform_automation/index.md: the guide,
  with codespace badge, asset paths, and cd commands retargeted to
  nextflow-io/training and side-quests/platform_automation/.
- side-quests/platform_automation/{terraform,seqerakit}: the Terraform
  (compute-env, pipeline) and seqerakit assets, verbatim aside from
  path/reference fixes and repaired code fences in the seqerakit README.
- .editorconfig: add 2-space rule for *.tf/*.tfvars (terraform fmt style).

Intentionally not added to the mkdocs nav or the side_quests index table.
Passes pre-commit (prettier, editorconfig, whitespace, eof), the heading
checker, terraform validate, and a non-strict mkdocs build.

Generated by Claude Code
The platform_automation side quest needs Terraform, the Seqera CLI (tw),
and seqerakit. Add them to the dev image the same way the rest of the
toolchain is managed (features baked into the codespaces-dev/local-dev
image), not via setup.sh:

- terraform: official devcontainers/features/terraform feature, pinned to
  1.9.8 with tflint/terragrunt disabled.
- tw: new local-features/seqera-cli feature, mirroring tower-agent but
  arch-aware (x86_64/arm64) so the multi-arch image build stays green.
- seqerakit: added to the existing uv-tools feature (pure-Python uv tool).
- hashicorp.terraform VS Code extension added to all three configs.

The tools land in the prebuilt image once docker-devcontainer rebuilds on
merge to master; the production devcontainer pulls that image.

Generated by Claude Code
The assets moved from the repo root into side-quests/platform_automation/,
so the root-relative `cd` commands broke mid-sequence: after cd-ing into
terraform/compute-env, a later `cd side-quests/platform_automation/seqerakit`
fails. Make every `cd` absolute (/workspaces/training/...) so each step works
from wherever the previous one left the learner, matching the absolute-path
convention used elsewhere in the side quests.

Also drop the stale "ends with 'Toolchain ready'" line: that string came from
the standalone repo's setup.sh and is not printed by the training devcontainer.

Generated by Claude Code
…st next step

Add Terraform ignore rules so learner-generated terraform.tfvars and
*.tfstate (both contain Azure credentials) are not committed; the
committed *.tfvars.example files stay tracked.

Point the "What's next?" cross-reference at the in-site Building with
Seqera AI (CoScientist) side quest instead of a generic GitHub link.

Generated by Claude Code
@netlify

netlify Bot commented Jun 16, 2026

Copy link
Copy Markdown

Deploy Preview for nextflow-training ready!

Name Link
🔨 Latest commit cf8756d
🔍 Latest deploy log https://app.netlify.com/projects/nextflow-training/deploys/6a356ef727abf3000805372a
😎 Deploy Preview https://deploy-preview-968--nextflow-training.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Nextflow linting complete!

⚠️ 35 files had 70 warnings
✅ 189 files had no errors
🔧 136 files would be changed by auto-formatting

💡 Tip: Click filename locations to go directly to that code.

View all 70 issues
Type Location Message
Warning hello-nf-core/solutions/composable-hello/hello.nf:36:5 Emit name should be omitted when there is only one emit
Warning hello-nf-core/solutions/core-hello-part2/subworkflows/local/utils_nfcore_hello_pipeline/main.nf:30:5 Parameter was not used -- prefix with _ to suppress warning
Warning hello-nf-core/solutions/core-hello-part2/subworkflows/local/utils_nfcore_hello_pipeline/main.nf:33:5 Parameter was not used -- prefix with _ to suppress warning
Warning hello-nf-core/solutions/core-hello-part2/subworkflows/local/utils_nfcore_hello_pipeline/main.nf:98:5 Parameter was not used -- prefix with _ to suppress warning
Warning hello-nf-core/solutions/core-hello-part2/subworkflows/local/utils_nfcore_hello_pipeline/main.nf:102:5 Variable was declared but not used
Warning hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nextflow_pipeline/main.nf:43:5 Emit name should be omitted when there is only one emit
Warning hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfcore_pipeline/main.nf:16:5 Variable was declared but not used
Warning hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfcore_pipeline/main.nf:20:5 Emit name should be omitted when there is only one emit
Warning hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfschema_plugin/main.nf:72:5 Emit name should be omitted when there is only one emit
Warning hello-nf-core/solutions/core-hello-part2/workflows/hello.nf:43:26 The use of Channel to access channel factories is deprecated -- use channel instead
Warning hello-nf-core/solutions/core-hello-part2/workflows/hello.nf:67:17 Variable was declared but not used
Warning hello-nf-core/solutions/core-hello-part3/subworkflows/local/utils_nfcore_hello_pipeline/main.nf:30:5 Parameter was not used -- prefix with _ to suppress warning
Warning hello-nf-core/solutions/core-hello-part3/subworkflows/local/utils_nfcore_hello_pipeline/main.nf:33:5 Parameter was not used -- prefix with _ to suppress warning
Warning hello-nf-core/solutions/core-hello-part3/subworkflows/local/utils_nfcore_hello_pipeline/main.nf:98:5 Parameter was not used -- prefix with _ to suppress warning
Warning hello-nf-core/solutions/core-hello-part3/subworkflows/local/utils_nfcore_hello_pipeline/main.nf:102:5 Variable was declared but not used
Warning hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nextflow_pipeline/main.nf:43:5 Emit name should be omitted when there is only one emit
Warning hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfcore_pipeline/main.nf:16:5 Variable was declared but not used
Warning hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfcore_pipeline/main.nf:20:5 Emit name should be omitted when there is only one emit
Warning hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfschema_plugin/main.nf:72:5 Emit name should be omitted when there is only one emit
Warning hello-nf-core/solutions/core-hello-part3/workflows/hello.nf:44:55 Parameter was not used -- prefix with _ to suppress warning
Warning hello-nf-core/solutions/core-hello-part3/workflows/hello.nf:52:26 The use of Channel to access channel factories is deprecated -- use channel instead
Warning hello-nf-core/solutions/core-hello-part3/workflows/hello.nf:76:17 Variable was declared but not used
Warning hello-nf-core/solutions/core-hello-part4/modules/local/cowpy/main.nf:30:9 Variable was declared but not used
Warning hello-nf-core/solutions/core-hello-part4/subworkflows/local/utils_nfcore_hello_pipeline/main.nf:30:5 Parameter was not used -- prefix with _ to suppress warning
Warning hello-nf-core/solutions/core-hello-part4/subworkflows/local/utils_nfcore_hello_pipeline/main.nf:33:5 Parameter was not used -- prefix with _ to suppress warning
Warning hello-nf-core/solutions/core-hello-part4/subworkflows/local/utils_nfcore_hello_pipeline/main.nf:98:5 Parameter was not used -- prefix with _ to suppress warning
Warning hello-nf-core/solutions/core-hello-part4/subworkflows/local/utils_nfcore_hello_pipeline/main.nf:102:5 Variable was declared but not used
Warning hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nextflow_pipeline/main.nf:43:5 Emit name should be omitted when there is only one emit
Warning hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfcore_pipeline/main.nf:16:5 Variable was declared but not used
Warning hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfcore_pipeline/main.nf:20:5 Emit name should be omitted when there is only one emit
Warning hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfschema_plugin/main.nf:72:5 Emit name should be omitted when there is only one emit
Warning hello-nf-core/solutions/core-hello-part4/workflows/hello.nf:49:26 The use of Channel to access channel factories is deprecated -- use channel instead
Warning hello-nf-core/solutions/core-hello-part4/workflows/hello.nf:73:17 Variable was declared but not used
Warning hello-nf-core/solutions/core-hello-part5/modules/local/cowpy/main.nf:30:9 Variable was declared but not used
Warning hello-nf-core/solutions/core-hello-part5/subworkflows/local/utils_nfcore_hello_pipeline/main.nf:30:5 Parameter was not used -- prefix with _ to suppress warning
Warning hello-nf-core/solutions/core-hello-part5/subworkflows/local/utils_nfcore_hello_pipeline/main.nf:33:5 Parameter was not used -- prefix with _ to suppress warning
Warning hello-nf-core/solutions/core-hello-part5/subworkflows/local/utils_nfcore_hello_pipeline/main.nf:97:5 Parameter was not used -- prefix with _ to suppress warning
Warning hello-nf-core/solutions/core-hello-part5/subworkflows/local/utils_nfcore_hello_pipeline/main.nf:101:5 Variable was declared but not used
Warning hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nextflow_pipeline/main.nf:43:5 Emit name should be omitted when there is only one emit
Warning hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfcore_pipeline/main.nf:16:5 Variable was declared but not used
Warning hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfcore_pipeline/main.nf:20:5 Emit name should be omitted when there is only one emit
Warning hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfschema_plugin/main.nf:72:5 Emit name should be omitted when there is only one emit
Warning hello-nf-core/solutions/core-hello-part5/workflows/hello.nf:49:26 The use of Channel to access channel factories is deprecated -- use channel instead
Warning hello-nf-core/solutions/core-hello-part5/workflows/hello.nf:73:17 Variable was declared but not used
Warning hello-nf-core/solutions/core-hello-start/subworkflows/local/utils_nfcore_hello_pipeline/main.nf:29:5 Parameter was not used -- prefix with _ to suppress warning
Warning hello-nf-core/solutions/core-hello-start/subworkflows/local/utils_nfcore_hello_pipeline/main.nf:32:5 Parameter was not used -- prefix with _ to suppress warning
Warning hello-nf-core/solutions/core-hello-start/subworkflows/local/utils_nfcore_hello_pipeline/main.nf:68:5 The use of Channel to access channel factories is deprecated -- use channel instead
Warning hello-nf-core/solutions/core-hello-start/subworkflows/local/utils_nfcore_hello_pipeline/main.nf:102:5 Parameter was not used -- prefix with _ to suppress warning
Warning hello-nf-core/solutions/core-hello-start/subworkflows/local/utils_nfcore_hello_pipeline/main.nf:106:5 Variable was declared but not used
Warning hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nextflow_pipeline/main.nf:43:5 Emit name should be omitted when there is only one emit
Warning hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfcore_pipeline/main.nf:16:5 Variable was declared but not used
Warning hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfcore_pipeline/main.nf:20:5 Emit name should be omitted when there is only one emit
Warning hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfschema_plugin/main.nf:44:5 Emit name should be omitted when there is only one emit
Warning hello-nf-core/solutions/core-hello-start/workflows/hello.nf:18:5 Parameter was not used -- prefix with _ to suppress warning
Warning hello-nf-core/solutions/core-hello-start/workflows/hello.nf:26:26 The use of Channel to access channel factories is deprecated -- use channel instead
Warning hello-nf-core/solutions/core-hello-start/workflows/hello.nf:50:17 Variable was declared but not used
Warning hello-nf-core/solutions/core-hello-start/workflows/hello.nf:54:5 Emit name should be omitted when there is only one emit
Warning side-quests/solutions/debugging/buggy_workflow.nf:91:44 Implicit closure parameter is deprecated, declare an explicit parameter instead
Warning side-quests/solutions/essential_scripting_patterns/main.nf:59:25 Parameter was not used -- prefix with _ to suppress warning
Warning side-quests/solutions/essential_scripting_patterns/main.nf:63:53 Parameter was not used -- prefix with _ to suppress warning
Warning side-quests/solutions/essential_scripting_patterns/main.nf:68:5 Variable was declared but not used
Warning side-quests/solutions/essential_scripting_patterns/main.nf:69:5 Variable was declared but not used
Warning side-quests/solutions/metadata/1.2/main.nf:5:5 Variable was declared but not used
Warning side-quests/solutions/metadata/2.4/main.nf:42:22 Parameter was not used -- prefix with _ to suppress warning
Warning side-quests/solutions/metadata/3.2/main.nf:42:22 Parameter was not used -- prefix with _ to suppress warning
Warning side-quests/solutions/splitting_and_grouping/main.nf:11:25 Parameter was not used -- prefix with _ to suppress warning
Warning side-quests/solutions/splitting_and_grouping/main.nf:14:25 Parameter was not used -- prefix with _ to suppress warning
Warning side-quests/solutions/splitting_and_grouping/main.nf:29:5 Variable was declared but not used
Warning side-quests/solutions/working_with_files/6/main.nf:10:43 Variable was declared but not used
Warning side-quests/solutions/working_with_files/6/main.nf:30:22 Parameter was not used -- prefix with _ to suppress warning
View formatting changes
FileDiff
hello-nextflow/solutions/1-hello-world/hello-world-2.nf
View
@@ -4,7 +4,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     output:
     path 'output.txt'
 
hello-nextflow/solutions/1-hello-world/hello-world-3.nf
View
@@ -4,7 +4,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     input:
     val greeting
 
hello-nextflow/solutions/2-hello-channels/hello-channels-1.nf
View
@@ -4,7 +4,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     input:
     val greeting
 
@@ -29,7 +28,7 @@ workflow {
     main:
     // create a channel for inputs
     greeting_ch = channel.of('Hello Channels!')
-                        .view()
+        .view()
     // emit a greeting
... (truncated)
hello-nextflow/solutions/2-hello-channels/hello-channels-2.nf
View
@@ -4,7 +4,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     input:
     val greeting
 
@@ -29,7 +28,7 @@ workflow {
     main:
     // create a channel for inputs
     greeting_ch = channel.of('Hello', 'Bonjour', 'Hola')
-                        .view()
+        .view()
     // emit a greeting
... (truncated)
hello-nextflow/solutions/2-hello-channels/hello-channels-3.nf
View
@@ -4,7 +4,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     input:
     val greeting
 
@@ -28,12 +27,12 @@ workflow {
 
     main:
     // declare an array of input greetings
-    greetings_array = ['Hello','Bonjour','Hola']
+    greetings_array = ['Hello', 'Bonjour', 'Hola']
     // create a channel for inputs
... (truncated)
hello-nextflow/solutions/2-hello-channels/hello-channels-4.nf
View
@@ -4,7 +4,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     input:
     val greeting
 
@@ -29,11 +28,11 @@ workflow {
     main:
     // create a channel for inputs from a CSV file
     greeting_ch = channel.fromPath(params.input)
-                        .view { csv -> "Before splitCsv: $csv" }
-                        .splitCsv()
-                        .view { csv -> "After splitCsv: $csv" }
... (truncated)
hello-nextflow/solutions/3-hello-workflow/hello-workflow-1.nf
View
@@ -4,7 +4,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     input:
     val greeting
 
@@ -21,7 +20,6 @@ process sayHello {
  * Use a text replacement tool to convert the greeting to uppercase
  */
 process convertToUpper {
-
     input:
     path input_file
... (truncated)
hello-nextflow/solutions/3-hello-workflow/hello-workflow-2.nf
View
@@ -4,7 +4,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     input:
     val greeting
 
@@ -21,7 +20,6 @@ process sayHello {
  * Use a text replacement tool to convert the greeting to uppercase
  */
 process convertToUpper {
-
     input:
     path input_file
... (truncated)
hello-nextflow/solutions/3-hello-workflow/hello-workflow-3.nf
View
@@ -4,7 +4,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     input:
     val greeting
 
@@ -21,7 +20,6 @@ process sayHello {
  * Use a text replacement tool to convert the greeting to uppercase
  */
 process convertToUpper {
-
     input:
     path input_file
... (truncated)
hello-nextflow/solutions/3-hello-workflow/hello-workflow-4.nf
View
@@ -4,7 +4,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     input:
     val greeting
 
@@ -21,7 +20,6 @@ process sayHello {
  * Use a text replacement tool to convert the greeting to uppercase
  */
 process convertToUpper {
-
     input:
     path input_file
... (truncated)
hello-nextflow/solutions/4-hello-modules/hello-modules-2.nf
View
@@ -7,7 +7,6 @@ include { sayHello } from './modules/sayHello.nf'
  * Use a text replacement tool to convert the greeting to uppercase
  */
 process convertToUpper {
-
     input:
     path input_file
 
@@ -24,7 +23,6 @@ process convertToUpper {
  * Collect uppercase greetings into a single output file
  */
 process collectGreetings {
-
     input:
     path input_files
... (truncated)
hello-nextflow/solutions/4-hello-modules/hello-modules-3.nf
View
@@ -8,7 +8,6 @@ include { convertToUpper } from './modules/convertToUpper.nf'
  * Collect uppercase greetings into a single output file
  */
 process collectGreetings {
-
     input:
     path input_files
     val batch_name
@@ -38,8 +37,8 @@ workflow {
     main:
     // create a channel for inputs from a CSV file
     greeting_ch = channel.fromPath(params.input)
-                        .splitCsv()
-                        .map { line -> line[0] }
+        .splitCsv()
... (truncated)
hello-nextflow/solutions/4-hello-modules/hello-modules-4.nf
View
@@ -18,8 +18,8 @@ workflow {
     main:
     // create a channel for inputs from a CSV file
     greeting_ch = channel.fromPath(params.input)
-                        .splitCsv()
-                        .map { line -> line[0] }
+        .splitCsv()
+        .map { line -> line[0] }
     // emit a greeting
     sayHello(greeting_ch)
     // convert the greeting to uppercase
hello-nextflow/solutions/4-hello-modules/modules/collectGreetings.nf
View
@@ -2,7 +2,6 @@
  * Collect uppercase greetings into a single output file
  */
 process collectGreetings {
-
     input:
     path input_files
     val batch_name
hello-nextflow/solutions/4-hello-modules/modules/convertToUpper.nf
View
@@ -2,7 +2,6 @@
  * Use a text replacement tool to convert the greeting to uppercase
  */
 process convertToUpper {
-
     input:
     path input_file
 
hello-nextflow/solutions/4-hello-modules/modules/sayHello.nf
View
@@ -2,7 +2,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     input:
     val greeting
 
hello-nextflow/solutions/5-hello-containers/hello-containers-2.nf
View
@@ -20,8 +20,8 @@ workflow {
     main:
     // create a channel for inputs from a CSV file
     greeting_ch = channel.fromPath(params.input)
-                        .splitCsv()
-                        .map { line -> line[0] }
+        .splitCsv()
+        .map { line -> line[0] }
     // emit a greeting
     sayHello(greeting_ch)
     // convert the greeting to uppercase
hello-nextflow/solutions/5-hello-containers/modules/collectGreetings.nf
View
@@ -2,7 +2,6 @@
  * Collect uppercase greetings into a single output file
  */
 process collectGreetings {
-
     input:
     path input_files
     val batch_name
hello-nextflow/solutions/5-hello-containers/modules/convertToUpper.nf
View
@@ -2,7 +2,6 @@
  * Use a text replacement tool to convert the greeting to uppercase
  */
 process convertToUpper {
-
     input:
     path input_file
 
hello-nextflow/solutions/5-hello-containers/modules/sayHello.nf
View
@@ -2,7 +2,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     input:
     val greeting
 
hello-nextflow/solutions/6-hello-config/hello-config.nf
View
@@ -20,8 +20,8 @@ workflow {
     main:
     // create a channel for inputs from a CSV file
     greeting_ch = channel.fromPath(params.input)
-                        .splitCsv()
-                        .map { line -> line[0] }
+        .splitCsv()
+        .map { line -> line[0] }
     // emit a greeting
     sayHello(greeting_ch)
     // convert the greeting to uppercase
hello-nextflow/solutions/6-hello-config/modules/collectGreetings.nf
View
@@ -2,7 +2,6 @@
  * Collect uppercase greetings into a single output file
  */
 process collectGreetings {
-
     input:
     path input_files
     val batch_name
hello-nextflow/solutions/6-hello-config/modules/convertToUpper.nf
View
@@ -2,7 +2,6 @@
  * Use a text replacement tool to convert the greeting to uppercase
  */
 process convertToUpper {
-
     input:
     path input_file
 
hello-nextflow/solutions/6-hello-config/modules/sayHello.nf
View
@@ -2,7 +2,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     input:
     val greeting
 
hello-nextflow/solutions/6-hello-config/nextflow.config
View
@@ -6,7 +6,7 @@ conda.enabled = true
 */
 process {
     memory = 1.GB
-    withName: 'cowpy' {
+    withName: cowpy {
         memory = 2.GB
         cpus = 2
     }
@@ -32,11 +32,7 @@ profiles {
     univ_hpc {
         process.executor = 'slurm'
         conda.enabled = true
-        process.resourceLimits = [
-            memory: 750.GB,
... (truncated)
hello-nf-core/solutions/composable-hello/hello.nf
View
@@ -14,9 +14,7 @@ include { collectGreetings } from './modules/collectGreetings.nf'
 include { cowpy } from './modules/cowpy.nf'
 
 workflow HELLO {
-
     take:
-    // channel of greetings
     greeting_ch
 
     main:
hello-nf-core/solutions/composable-hello/main.nf
View
@@ -9,12 +9,12 @@ params.greeting = 'greetings.csv'
 workflow {
     // create a channel for inputs from a CSV file
     greeting_ch = channel.fromPath(params.greeting)
-                        .splitCsv()
-                        .map { line -> line[0] }
+        .splitCsv()
+        .map { line -> line[0] }
 
     // call the imported workflow on the channel of greetings
     HELLO(greeting_ch)
 
     // view the outputs emitted by the workflow
-    HELLO.out.view { output -> "Output: $output" }
+    HELLO.out.view { output -> "Output: ${output}" }
... (truncated)
hello-nf-core/solutions/composable-hello/modules/collectGreetings.nf
View
@@ -10,8 +10,8 @@ process collectGreetings {
     val batch_name
 
     output:
-    path "COLLECTED-${batch_name}-output.txt" , emit: outfile
-    val count_greetings , emit: count
+    path "COLLECTED-${batch_name}-output.txt", emit: outfile
+    val count_greetings, emit: count
 
     script:
     count_greetings = input_files.size()
hello-nf-core/solutions/composable-hello/modules/convertToUpper.nf
View
@@ -13,6 +13,6 @@ process convertToUpper {
 
     script:
     """
-    cat '$input_file' | tr '[a-z]' '[A-Z]' > 'UPPER-${input_file}'
+    cat '${input_file}' | tr '[a-z]' '[A-Z]' > 'UPPER-${input_file}'
     """
 }
hello-nf-core/solutions/composable-hello/modules/cowpy.nf
View
@@ -15,6 +15,6 @@ process cowpy {
 
     script:
     """
-    cat $input_file | cowpy -c "$character" > cowpy-${input_file}
+    cat ${input_file} | cowpy -c "${character}" > cowpy-${input_file}
     """
 }
hello-nf-core/solutions/composable-hello/modules/sayHello.nf
View
@@ -13,6 +13,6 @@ process sayHello {
 
     script:
     """
-    echo '$greeting' > '$greeting-output.txt'
+    echo '${greeting}' > '${greeting}-output.txt'
     """
 }
hello-nf-core/solutions/core-hello-part2/conf/base.config
View
@@ -11,13 +11,13 @@
 process {
 
     // TODO nf-core: Check the defaults for all processes
-    cpus   = { 1      * task.attempt }
-    memory = { 6.GB   * task.attempt }
-    time   = { 4.h    * task.attempt }
+    cpus = { 1 * task.attempt }
+    memory = { 6.GB * task.attempt }
+    time = { 4.h * task.attempt }
 
     errorStrategy = { task.exitStatus in ((130..145) + 104 + 175) ? 'retry' : 'finish' }
-    maxRetries    = 1
-    maxErrors     = '-1'
+    maxRetries = 1
... (truncated)
hello-nf-core/solutions/core-hello-part2/conf/modules.config
View
@@ -12,10 +12,5 @@
 
 process {
 
-    publishDir = [
-        path: { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" },
-        mode: params.publish_dir_mode,
-        saveAs: { filename -> filename.equals('versions.yml') ? null : filename }
-    ]
-
+    publishDir = [path: { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }]
 }
hello-nf-core/solutions/core-hello-part2/conf/test.config
View
@@ -11,21 +11,17 @@
 */
 
 process {
-    resourceLimits = [
-        cpus: 2,
-        memory: '4.GB',
-        time: '1.h'
-    ]
+    resourceLimits = [cpus: 2, memory: '4.GB', time: '1.h']
 }
 
 params {
-    config_profile_name        = 'Test profile'
+    config_profile_name = 'Test profile'
... (truncated)
hello-nf-core/solutions/core-hello-part2/conf/test_full.config
View
@@ -11,7 +11,7 @@
 */
 
 params {
-    config_profile_name        = 'Full test profile'
+    config_profile_name = 'Full test profile'
     config_profile_description = 'Full test dataset to check pipeline function'
 
     // Input data for full size test
hello-nf-core/solutions/core-hello-part2/main.nf
View
@@ -13,9 +13,9 @@
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
 
-include { HELLO  } from './workflows/hello'
+include { HELLO } from './workflows/hello'
 include { PIPELINE_INITIALISATION } from './subworkflows/local/utils_nfcore_hello_pipeline'
-include { PIPELINE_COMPLETION     } from './subworkflows/local/utils_nfcore_hello_pipeline'
+include { PIPELINE_COMPLETION } from './subworkflows/local/utils_nfcore_hello_pipeline'
 /*
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     NAMED WORKFLOWS FOR PIPELINE
@@ -26,7 +26,6 @@ include { PIPELINE_COMPLETION     } from './subworkflows/local/utils_nfcore_hell
 // WORKFLOW: Run main analysis pipeline depending on type of input
 //
... (truncated)
hello-nf-core/solutions/core-hello-part2/modules/local/collectGreetings.nf
View
@@ -10,8 +10,8 @@ process collectGreetings {
     val batch_name
 
     output:
-    path "COLLECTED-${batch_name}-output.txt" , emit: outfile
-    val count_greetings , emit: count
+    path "COLLECTED-${batch_name}-output.txt", emit: outfile
+    val count_greetings, emit: count
 
     script:
     count_greetings = input_files.size()
hello-nf-core/solutions/core-hello-part2/modules/local/convertToUpper.nf
View
@@ -13,6 +13,6 @@ process convertToUpper {
 
     script:
     """
-    cat '$input_file' | tr '[a-z]' '[A-Z]' > 'UPPER-${input_file}'
+    cat '${input_file}' | tr '[a-z]' '[A-Z]' > 'UPPER-${input_file}'
     """
 }
hello-nf-core/solutions/core-hello-part2/modules/local/cowpy.nf
View
@@ -7,14 +7,14 @@ process cowpy {
     conda 'conda-forge::cowpy==1.1.5'
 
     input:
-        path input_file
-        val character
+    path input_file
+    val character
 
     output:
-        path "cowpy-${input_file}"
+    path "cowpy-${input_file}"
 
     script:
     """
... (truncated)
hello-nf-core/solutions/core-hello-part2/modules/local/sayHello.nf
View
@@ -13,6 +13,6 @@ process sayHello {
 
     script:
     """
-    echo '$greeting' > '$greeting-output.txt'
+    echo '${greeting}' > '${greeting}-output.txt'
     """
 }
hello-nf-core/solutions/core-hello-part2/nextflow.config
View
@@ -11,30 +11,30 @@ params {
 
     // TODO nf-core: Specify your pipeline's command line flags
     // Input options
-    input                      = null
+    input = null
 
     // Boilerplate options
-    outdir                       = null
-    publish_dir_mode             = 'copy'
-    monochrome_logs              = false
-    help                         = false
-    help_full                    = false
-    show_hidden                  = false
-    version                      = false
... (truncated)
hello-nf-core/solutions/core-hello-part2/subworkflows/local/utils_nfcore_hello_pipeline/main.nf
View
@@ -8,13 +8,13 @@
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
 
-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'
+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'
... (truncated)
hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nextflow_pipeline/main.nf
View
@@ -10,9 +10,9 @@
 
 workflow UTILS_NEXTFLOW_PIPELINE {
     take:
-    print_version        // boolean: print version
-    dump_parameters      // boolean: dump parameters
-    outdir               //    path: base directory used to publish pipeline results
+    print_version // boolean: print version
+    dump_parameters // boolean: dump parameters
+    outdir //    path: base directory used to publish pipeline results
     check_conda_channels // boolean: check conda channels
 
     main:
@@ -72,10 +72,10 @@ def getWorkflowVersion() {
 //
... (truncated)
hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config
View
@@ -1,9 +1,9 @@
 manifest {
-    name            = 'nextflow_workflow'
-    author          = """nf-core"""
-    homePage        = 'https://127.0.0.1'
-    description     = """Dummy pipeline"""
+    name = 'nextflow_workflow'
+    author = """nf-core"""
+    homePage = 'https://127.0.0.1'
+    description = """Dummy pipeline"""
     nextflowVersion = '!>=23.04.0'
-    version         = '9.9.9'
-    doi             = 'https://doi.org/10.5281/zenodo.5070524'
+    version = '9.9.9'
+    doi = 'https://doi.org/10.5281/zenodo.5070524'
... (truncated)
hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfcore_pipeline/main.nf
View
@@ -125,12 +125,12 @@ def paramsSummaryMultiqc(summary_params) {
         }
 
     def yaml_file_text = "id: '${workflow.manifest.name.replace('/', '-')}-summary'\n" as String
-    yaml_file_text     += "description: ' - this information is collected when the pipeline is started.'\n"
-    yaml_file_text     += "section_name: '${workflow.manifest.name} Workflow Summary'\n"
-    yaml_file_text     += "section_href: 'https://github.com/${workflow.manifest.name}'\n"
-    yaml_file_text     += "plot_type: 'html'\n"
-    yaml_file_text     += "data: |\n"
-    yaml_file_text     += "${summary_section}"
+    yaml_file_text += "description: ' - this information is collected when the pipeline is started.'\n"
+    yaml_file_text += "section_name: '${workflow.manifest.name} Workflow Summary'\n"
+    yaml_file_text += "section_href: 'https://github.com/${workflow.manifest.name}'\n"
+    yaml_file_text += "plot_type: 'html'\n"
+    yaml_file_text += "data: |\n"
... (truncated)
hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfschema_plugin/main.nf(truncated)
hello-nf-core/solutions/core-hello-part2/workflows/hello.nf(truncated)
hello-nf-core/solutions/core-hello-part3/conf/base.config(truncated)
hello-nf-core/solutions/core-hello-part3/conf/modules.config(truncated)
hello-nf-core/solutions/core-hello-part3/conf/test.config(truncated)
hello-nf-core/solutions/core-hello-part3/conf/test_full.config(truncated)
hello-nf-core/solutions/core-hello-part3/main.nf(truncated)
hello-nf-core/solutions/core-hello-part3/modules/local/collectGreetings.nf(truncated)
hello-nf-core/solutions/core-hello-part3/modules/local/convertToUpper.nf(truncated)
hello-nf-core/solutions/core-hello-part3/modules/local/cowpy.nf(truncated)
hello-nf-core/solutions/core-hello-part3/modules/local/sayHello.nf(truncated)
hello-nf-core/solutions/core-hello-part3/modules/nf-core/find/concatenate/main.nf(truncated)
hello-nf-core/solutions/core-hello-part3/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part3/subworkflows/local/utils_nfcore_hello_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nextflow_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfcore_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfschema_plugin/main.nf(truncated)
hello-nf-core/solutions/core-hello-part3/workflows/hello.nf(truncated)
hello-nf-core/solutions/core-hello-part4/conf/base.config(truncated)
hello-nf-core/solutions/core-hello-part4/conf/modules.config(truncated)
hello-nf-core/solutions/core-hello-part4/conf/test.config(truncated)
hello-nf-core/solutions/core-hello-part4/conf/test_full.config(truncated)
hello-nf-core/solutions/core-hello-part4/main.nf(truncated)
hello-nf-core/solutions/core-hello-part4/modules/local/collectGreetings.nf(truncated)
hello-nf-core/solutions/core-hello-part4/modules/local/convertToUpper.nf(truncated)
hello-nf-core/solutions/core-hello-part4/modules/local/cowpy.nf(truncated)
hello-nf-core/solutions/core-hello-part4/modules/local/cowpy/main.nf(truncated)
hello-nf-core/solutions/core-hello-part4/modules/local/sayHello.nf(truncated)
hello-nf-core/solutions/core-hello-part4/modules/nf-core/find/concatenate/main.nf(truncated)
hello-nf-core/solutions/core-hello-part4/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part4/subworkflows/local/utils_nfcore_hello_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nextflow_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfcore_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfschema_plugin/main.nf(truncated)
hello-nf-core/solutions/core-hello-part4/workflows/hello.nf(truncated)
hello-nf-core/solutions/core-hello-part5/conf/base.config(truncated)
hello-nf-core/solutions/core-hello-part5/conf/modules.config(truncated)
hello-nf-core/solutions/core-hello-part5/conf/test.config(truncated)

tower-cli publishes no tw-linux-arm64 asset, so the multi-arch image
build 404'd on the arm64 leg. Keep the native binary on x86_64 and
fall back to the arch-independent tw-jar.jar (run via Java) on arm64.

Generated by Claude Code
Section 0 jumped from opening the Codespace straight to creating a token,
never walking participants into the working directory or showing its
contents. Add "Move into the project directory" (cd + code .) and
"Review the materials" (directory tree) subsections, matching the
debugging side quest pattern.

Generated by Claude Code
… workshop handle

Review pass on the Platform Automation side quest:

- Reset terraform/pipeline revision to master so the §2.4 pin-a-tag exercise
  starts from the right state
- Sync §1.3 walkthrough with compute-env/main.tf (head VM size, worker
  ignore_changes, random_string, a note on the azcopy/Fusion start task)
- Replace the $USER/$USERNAME interpolation mess with a single, dot-free
  WORKSHOP_USER handle set once and reused across the UI, tw, seqerakit and
  Terraform; tighten the Terraform username validation to reject dots
- Register the page in mkdocs nav; refresh the §0 directory tree
- Add seqerakit/launch-rnaseq-multiple.yml; drop per-directory READMEs
- gitignore agent/terraform local state (.omc, .claude/.local, lock files)

Generated by Claude Code
- !!! Tip -> !!! tip (lowercase type)
- !!! Note Using a params.yml -> !!! note "Using a params file"
  (the unquoted title was parsed as CSS classes and dropped)

Generated by Claude Code
Comment thread docs/en/docs/side_quests/platform_automation/index.md Outdated
Comment thread docs/en/docs/side_quests/platform_automation/index.md Outdated
Comment thread docs/en/docs/side_quests/platform_automation/index.md Outdated
Comment thread docs/en/docs/side_quests/platform_automation/index.md Outdated
Comment thread docs/en/docs/side_quests/platform_automation/index.md Outdated
Co-authored-by: Luisa Santus <luisa.santus@seqera.io>
Co-authored-by: Adam Talbot <12817534+adamrtalbot@users.noreply.github.com>

@pinin4fjords pinin4fjords left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just submitting intermediate review while I continue

└── launch-rnaseq-multiple.yml
```

### Create an access token

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
### Create an access token
### Log in to Platform and go to the organisation and workspaces your trainer directs you to
.... or something
### Create an access token

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


```bash
export TOWER_ACCESS_TOKEN=<paste-token>
export SEQERA_ACCESS_TOKEN=$TOWER_ACCESS_TOKEN

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why both?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One was needed for Seqera CLI but we aren't using it here. let's remove.

e532fe6


This only exists in a single terminal session, if you open a new terminal you will need to export them again.

For Seqera Enterprise, also set `SEQERA_API_URL` (and the `server_url` Terraform variable) to your install's API URL. Everything else is identical.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example? How do folks find that?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


## 1. Admin: compute environments and cloud

**Requires:** Owner or Admin role, and permissions in the cloud environment. If you are using a Cloud provider, authenticate with them first via their CLI.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're skipping over credentials here. Don't we want to 1) ensure that trainers do that in advance, so that keys are in place and 2) have the users go look at the creds, understand what they are?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't sure about this.

Credentials are complex and cause many problems. I'd rather leave them to docs if possible and, for the purposes of a tutorial, assume they exist. I'll add a quick sentence saying they have to exist

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

- Provisioning model should be Spot, using Spot instances for nodes which run Nextflow tasks.

**Azure**

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of ways this can go wrong- should we encourage some sensible values?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These were about as tight as I could get the values before the setting depends on a bunch of stuff in your own cloud account 😢


The manual marker: `head_pool` is set to the pool Terraform just made and there is **no `forge` block**. That one difference is what makes the compute environment manual instead of Forge. `nextflow_config` routes tasks to the worker pool.

Let's walk the key blocks of `terraform/compute-env/main.tf`.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Too much 'just talking' about tf below, I'd hate to teach that and just waffle on about terraform code blocks for 5 mins straight. We should have folks running pieces more, e.g. do the 'init' up front.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Snipped right down and told users to open the Terraform file themselves if they want to explore it. Suggested the key points that it refers to variables and resources from the Terraform.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also simplified the heck out of it.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

```bash
# you may need to log in to the cloud provider with `az login`
terraform init
terraform apply

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This asks the user for a whole bunch of stuff we haven't told them how to find out.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you mean the subscription ID and stuff? Good point, I'll add some quick bullet points.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

terraform output compute_env_id
```

On the Azure side, open the Batch account in the portal. You will see the head and worker pools Terraform created, sitting idle with no jobs yet. Once you launch a pipeline (sections 2 and 3), jobs and tasks stack onto these pools, and you can drill into a task's logs and exit code. That is the whole point of the Admin tier: the Platform submits to Azure Batch, and Azure Batch runs the work. Maintain- and Launch-role users see only the compute environment in the workspace, not the cloud behind it.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this make sense to include? Are we ever going to give trainees access to cloud consoles?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is strictly for admins who have access to their own cloud portal. In a live training I might show access to the relevant resources with a screen share.


Click **Add**. The pipeline appears on the Launchpad with no run started. Adding a pipeline only saves a launch configuration; it does not run anything.

To remove from the workspace, you can click the hamburger menu on the top right and click **Delete**.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hamburger?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

```bash
tw pipelines add \
--name="rnaseq-nf-$WORKSHOP_USER" \
--compute-env="azure-batch-manual" \

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will we guarantee 'azure-batch-manual'? What to do if we're not doing 'admin'?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's hard coded in the Terraform.

I left it because the Terraform spins up a few hot nodes to work on 😉 so the training will go much faster.

It probably needs a comment to acknowledge your compute env name might be different 🤔

@pinin4fjords pinin4fjords left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few specific points below. General ones:

  1. Should try and make sure everything is runnable without having to think too hard, make sure different flavours of the same commands don't conflict.
  2. Is it worth teaching Seqerakit, or should we just do TF for infra and tw for e.g. pipeline runs? I've never found seqerakit's IaC to make much sense for runs.
  3. Need screenshots for Platform pieces.


```bash
tw pipelines add \
--name="rnaseq-nf-$WORKSHOP_USER" \

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
--name="rnaseq-nf-$WORKSHOP_USER" \
--name="rnaseq-nf-$WORKSHOP_USER-tw" \

prevent clash with manual creation

tw pipelines delete --name="rnaseq-nf-$WORKSHOP_USER"
```

### 2.3. Add a pipeline with `seqerakit`

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it even worth teaching seqerakit with the Terraform provider available now?


```yaml
pipelines:
- name: "rnaseq-nf-${WORKSHOP_USER}"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- name: "rnaseq-nf-${WORKSHOP_USER}"
- name: "rnaseq-nf-${WORKSHOP_USER}-sk"

Prevent clashes

url: "https://github.com/nextflow-io/rnaseq-nf"
workspace: "${TOWER_WORKSPACE_ID}"
description: "Added with seqerakit"
compute-env: "azure-batch-manual"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
compute-env: "azure-batch-manual"
compute-env: "<CE name>"

unless guaranteed

`side-quests/platform_automation/terraform/pipeline` adds the same pipeline declaratively. You describe the pipeline that should exist; Terraform makes the workspace match. Like the imperative methods above, the config tracks the `master` branch; you will pin it to a release tag below to see Terraform update the pipeline in place.

```bash
cd /workspaces/training/side-quests/platform_automation/terraform/pipeline

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why, but I can't make this work

seqera_pipeline.rnaseq_nf: Creating...
╷
│ Error: unexpected response from API. Got an unexpected response code 403
│ 
│   with seqera_pipeline.rnaseq_nf,
│   on main.tf line 27, in resource "seqera_pipeline" "rnaseq_nf":
│   27: resource "seqera_pipeline" "rnaseq_nf" {
│ 
│ **Request**:
│ POST /pipelines?workspaceId=75541431575041 HTTP/1.1
│ Host: api.cloud.seqera.io
│ Accept: application/json
│ Authorization: (sensitive)
│ Content-Type: application/json
│ User-Agent: speakeasy-sdk/terraform 0.40.1 2.903.0 1.153.0
│ github.com/seqeralabs/terraform-provider-seqera/internal/sdk
│ 
│ 
│ **Response**:
│ HTTP/2.0 403 Forbidden
│ Content-Length: 0
│ Date: Thu, 18 Jun 2026 15:28:47 GMT
│ 
│ 

@pinin4fjords pinin4fjords left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ran the Platform side of this end to end in a container (terraform 1.9.8, tw 0.32.0, seqerakit 0.5.7, against an Azure Batch workspace). Notes from actually executing it, plus code-block formatting / pedagogy suggestions inline.

Verified works exactly as written:

  • 2.4 Terraform: create, idempotent re-apply (No changes), and the master->v2.4 update-in-place all match the documented console output verbatim. Nice bit of teaching.
  • 2.2 tw pipelines add second-run "already exists" error is accurate.

Needs attention:

  • The forge-ce.json block is not what tw emits - real tw compute-envs export returns a flat object keyed by discriminator, with no computeEnv/config wrapper. Suggestion inline.
  • Name clashes between the four add methods. The UI, tw, seqerakit, and Terraform steps all add the same rnaseq-nf-$WORKSHOP_USER. Running the section top to bottom, seqerakit add errors on its first run because the tw add step already created that name, so the "run it again and it errors" point lands for the wrong reason. Suffixing each method's name (e.g. -tw, -sk, -tf) keeps them independent.
  • The Terraform pipeline create can return a 403 depending on the token's workspace role. The same main.tf and provider 0.40.1 created the pipeline fine with a Maintain-capable token, so this is environmental rather than a code bug. Worth a troubleshooting note ("403 = your token's role can't create pipelines in this workspace") rather than a code change.
  • azure-batch-manual isn't guaranteed for Maintain/Launch-only learners (they never run section 1), so the hardcoded compute-env name needs to be a placeholder. I ran the quest's commands against an existing CE with a different name to confirm the rest holds.

Couldn't exercise: 1.1/1.3/1.4 (Azure provisioning + cloud console), the UI steps, and real launches (didn't fire runs).

Comment on lines +210 to +236
```json title="forge-ce.json"
{
"computeEnv": {
"name": "azure-batch",
"platform": "azure-batch",
"config": {
"workDir": "az://work",
"region": "eastus",
"waveEnabled": true,
"fusion2Enabled": true,
"forge": {
"headPool": {
"vmType": "Standard_D2s_v3",
"vmCount": 1,
"autoScale": true
},
"workerPool": {
"vmType": "Standard_D4s_v3",
"vmCount": 4,
"autoScale": true
},
"disposeOnDeletion": true
}
}
}
}
```

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tw compute-envs export (0.32.0) does not emit a computeEnv/config wrapper. The real output is a flat object keyed by discriminator, with the config fields hoisted to the top level. I ran this against an Azure Batch Forge CE and got the shape below. The actual file also carries default/null fields (deleteJobsOnCompletion, managedIdentityClientId, labels, ...) that aren't worth showing here. The forge block survives, so the prose still lands.

Suggested change
```json title="forge-ce.json"
{
"computeEnv": {
"name": "azure-batch",
"platform": "azure-batch",
"config": {
"workDir": "az://work",
"region": "eastus",
"waveEnabled": true,
"fusion2Enabled": true,
"forge": {
"headPool": {
"vmType": "Standard_D2s_v3",
"vmCount": 1,
"autoScale": true
},
"workerPool": {
"vmType": "Standard_D4s_v3",
"vmCount": 4,
"autoScale": true
},
"disposeOnDeletion": true
}
}
}
}
```
```json title="forge-ce.json" hl_lines="2 7"
{
"discriminator": "azure-batch",
"region": "eastus",
"workDir": "az://work",
"waveEnabled": true,
"fusion2Enabled": true,
"forge": {
"headPool": { "vmType": "Standard_D2s_v3", "vmCount": 1, "autoScale": true },
"workerPool": { "vmType": "Standard_D4s_v3", "vmCount": 4, "autoScale": true },
"disposeOnDeletion": true,
"dualPoolConfig": true
}
}
```


The first block declares the providers and pins their versions. The `seqera` provider is pinned to exactly `0.40.1`:

```terraform

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Title the excerpt and highlight the pinned seqera provider line the prose calls out.

Suggested change
```terraform
```terraform title="terraform/compute-env/main.tf" hl_lines="5"


Next we configure the providers. The `seqera` provider reads `TOWER_ACCESS_TOKEN` from the environment, so there is no token argument here:

```terraform

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```terraform
```terraform title="terraform/compute-env/main.tf"


Next we can define some variables we can use throughout our deployment. In this case, we will set the node sizes and details once and reuse them throughout the configuration:

```terraform

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Highlight the VM sizes, since the surrounding text is about node sizing.

Suggested change
```terraform
```terraform title="terraform/compute-env/main.tf" hl_lines="2 3"


Next we can refer to resources that already exist. These are called `data` in Terraform. Here we refer to the Azure Batch account:

```terraform

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```terraform
```terraform title="terraform/compute-env/main.tf"


This only exists in a single terminal session, if you open a new terminal you will need to export them again.

For Seqera Enterprise, also set `SEQERA_API_URL` (and the `server_url` Terraform variable) to your install's API URL. Everything else is identical.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double-check the variable name here: tw (and therefore seqerakit) read the Enterprise endpoint from TOWER_API_ENDPOINT, not SEQERA_API_URL. The Terraform server_url variable is correct. Worth being precise so Enterprise users don't set a var nothing reads.


In the side bar, open **Compute Environments** and click **Create compute environment**. Give it a name, pick your cloud platform, and select the credentials for that cloud. The rest of the form differs by provider; recommended settings:

**AWS**

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1.1 walks both AWS and Azure, but everything after it (the 1.2 export example, the 1.3 Terraform, and the az://work work-dir throughout 2-3) is Azure-only. An AWS learner who follows 1.1 hits a wall at 1.3 with no path forward. Either say up front "the rest of this quest assumes Azure Batch" or note where AWS users diverge.

Comment thread docs/en/docs/side_quests/platform_automation/index.md Outdated

The dry run shows the underlying `tw` command. Run it twice and you get two runs. That is the imperative model: do the thing, now.

One advantage of using Seqerakit is the YAML forms a template of actions to perform. Because of this we can do two more things: firstly, we can save it and re-use it later. Secondly, we can launch the same pipeline several times by adding more launch blocks to the YAML file. This is useful if you want to launch the same pipeline with different parameters or on different compute environments. Let's try and launch the pipeline now with

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seqerakit should be `seqerakit` (lowercase, backticked) to match the rest of the doc, and this is a long run-on. Suggest splitting.


## What's next?

- The AI half of the workshop is the [Building with Seqera AI (CoScientist)](../co_scientist/index.md) side quest. It uses the same `rnaseq-nf` pipeline and API endpoints, but drives them via AI agents.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heads up that this relative link 404s until #963 merges (the PR description notes it). If #968 can merge first, consider temporarily pointing at the side-quests index, or gating merge order, so master never ships a broken link.

@pinin4fjords pinin4fjords left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A second pass, this time on teaching style, lining the quest up with the conventions in the other side quests (essential_scripting_patterns, metadata, working_with_files, ...). The framing (learning goals, role table) and the wrap-up (per-section Takeaways, Summary, the declarative-vs-imperative table) already match the house style well, and the idempotency demonstrations (run tw add twice, apply Terraform twice) are exactly the "run and observe" loop those quests are built on. These suggestions push the rest of the body toward the same "do, then explain" rhythm.

  • Collapsible command output. The other quests wrap expected output in ??? success/??? failure "Command output" so the page stays scannable and learners self-check. Converted the four bare console blocks inline.
  • Make the hand-off artifact visible from the CLI. 1.2/1.4 read the compute environment back over the API; mirrored that for the Maintain tier so the Launchpad pipeline is something the learner sees, not just reads about.
  • Less passive code-walking in 1.3. Reframed the "walk every block" lead-in inline. The fuller restructure (too big for a clean suggestion): once terraform.tfvars is filled, run terraform init + terraform plan up front so learners see the two pools and the CE the config will create, then explain only the manual-marker block against that plan and drop the providers/locals/pools into a ??? abstract for reference. No other quest narrates eight blocks before the first run.
  • Voice. Minor nudge from tour-guide "we build" to second-person "you'll build".

One diagram (recommendation, no code to suggest): the Admin -> Maintain -> Launch artifact hand-off and the Platform -> Batch -> VM submission relationship are the quest's core mental model and are inherently spatial. A single .excalidraw.svg (per the repo's diagram convention) would anchor the whole quest; the other quests use images where the idea is spatial.

The CE-name placeholder edit is already covered by existing threads plus the hl_lines highlight in my earlier review, so I haven't duplicated it here.


**Requires:** Owner or Admin role, and permissions in the cloud environment. If you are using a Cloud provider, authenticate with them first via their CLI (e.g. `aws sso login`).

The same compute environment can be created with increasing control over the cloud. We build it two ways.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small voice nudge toward the second person the other quests use ("you'll build", not "we build").

Suggested change
The same compute environment can be created with increasing control over the cloud. We build it two ways.
The same compute environment can be created with increasing control over the cloud. You'll build it two ways.


The manual marker: `head_pool` is set to the pool Terraform just made and there is **no `forge` block**. That one difference is what makes the compute environment manual instead of Forge. `nextflow_config` routes tasks to the worker pool.

Let's walk the key blocks of `terraform/compute-env/main.tf`.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other quests never narrate eight code blocks before the learner runs anything; they run early and explain against real output. Reframe the lead-in so the providers/locals/pools read as reference and the focus lands on the one block that encodes the lesson. (See the review summary for the fuller plan-first restructure: init + plan once terraform.tfvars is filled, then collapse the boilerplate into a ??? abstract.)

Suggested change
Let's walk the key blocks of `terraform/compute-env/main.tf`.
The whole file is in the repo to read at your own pace, and most of it is standard Terraform: the providers, the locals, and the two Azure Batch pools. Only one block encodes the lesson that makes this compute environment _manual_, so we'll focus there and treat the rest as reference.

Comment on lines +556 to +558
```console
The pipelines resource already exists and will not be created. Please set 'on_exists: overwrite' to replace the resource or set 'on_exists: ignore' to ignore this error.
```

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other quests wrap expected output in collapsible ??? success/??? failure "Command output" blocks so the page stays scannable and learners can self-check. This one is an error, so failure.

Suggested change
```console
The pipelines resource already exists and will not be created. Please set 'on_exists: overwrite' to replace the resource or set 'on_exists: ignore' to ignore this error.
```
??? failure "Command output"
```console
The pipelines resource already exists and will not be created. Please set 'on_exists: overwrite' to replace the resource or set 'on_exists: ignore' to ignore this error.
```

Comment on lines +582 to +584
```console
No changes. Your infrastructure matches the configuration.
```

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Collapsible output, matching the house style.

Suggested change
```console
No changes. Your infrastructure matches the configuration.
```
??? success "Command output"
```console
No changes. Your infrastructure matches the configuration.
```

Comment on lines +616 to +628
```console
Terraform will perform the following actions:

# seqera_pipeline.rnaseq_nf will be updated in-place
~ resource "seqera_pipeline" "rnaseq_nf" {
~ launch = {
~ revision = "master" -> "v2.4"
# (4 unchanged attributes hidden)
}
}

Plan: 0 to add, 1 to change, 0 to destroy.
```

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Collapsible output, matching the house style.

Suggested change
```console
Terraform will perform the following actions:
# seqera_pipeline.rnaseq_nf will be updated in-place
~ resource "seqera_pipeline" "rnaseq_nf" {
~ launch = {
~ revision = "master" -> "v2.4"
# (4 unchanged attributes hidden)
}
}
Plan: 0 to add, 1 to change, 0 to destroy.
```
??? success "Command output"
```console
Terraform will perform the following actions:
# seqera_pipeline.rnaseq_nf will be updated in-place
~ resource "seqera_pipeline" "rnaseq_nf" {
~ launch = {
~ revision = "master" -> "v2.4"
# (4 unchanged attributes hidden)
}
}
Plan: 0 to add, 1 to change, 0 to destroy.
```

Comment on lines +662 to +666
```console
Workflow 2ZXaU1AzEn7Onk submitted at [Organization / Workspace] workspace.

https://cloud.seqera.io/orgs/Organization/workspaces/Workspace/watch/2ZXaU1AzEn7Onk
```

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Collapsible output, matching the house style.

Suggested change
```console
Workflow 2ZXaU1AzEn7Onk submitted at [Organization / Workspace] workspace.
https://cloud.seqera.io/orgs/Organization/workspaces/Workspace/watch/2ZXaU1AzEn7Onk
```
??? success "Command output"
```console
Workflow 2ZXaU1AzEn7Onk submitted at [Organization / Workspace] workspace.
https://cloud.seqera.io/orgs/Organization/workspaces/Workspace/watch/2ZXaU1AzEn7Onk
```


Copy `terraform.tfvars.example` to `terraform.tfvars` and fill it in so you stop passing `-var` flags.

Open the Launchpad: `rnaseq-nf-$WORKSHOP_USER` is there, with no run. Now apply again:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Section 1.2/1.4 read the compute environment back over the API; mirror that here so the learner watches the Launchpad pipeline appear (the artifact handed to the Launch tier), instead of only being told it's there.

Suggested change
Open the Launchpad: `rnaseq-nf-$WORKSHOP_USER` is there, with no run. Now apply again:
Confirm it landed, in the UI (open the Launchpad) or from the terminal, the same way you read the compute environment back in section 1.2:
```bash
tw pipelines list
```
`rnaseq-nf-$WORKSHOP_USER` is there, with no run. Now apply again:

adamrtalbot and others added 13 commits June 18, 2026 18:09
Surface the role/tier table at the top of the side quest so
participants pick their starting section before any setup. Reword
the Admin/Maintain/Launch guidance and update the table's Produces
column.

Generated by Claude Code
Co-authored-by: Jonathan Manning <jonathan.manning@seqera.io>
Co-authored-by: Jonathan Manning <jonathan.manning@seqera.io>
Co-authored-by: Jonathan Manning <jonathan.manning@seqera.io>
- Correct forge-ce.json to the flat discriminator-keyed shape tw export emits
- Add titles and hl_lines to the Terraform/pipeline code blocks
- Wrap command output in collapsible ??? success blocks (house style)
- Add tw pipelines list step so the Launchpad pipeline is visible
- Note the quest assumes Azure Batch after 1.1
- Make the tw compute-env a placeholder and delete an explicit pre-Terraform step
- Voice/casing/run-on cleanups; drop the removed seqerakit add-rnaseq.yml

Generated by Claude Code
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants