From 735ab9f770e2097a097c3c99c27d4ae8b090ab22 Mon Sep 17 00:00:00 2001 From: Ben Sherman Date: Tue, 2 Sep 2025 12:23:56 -0500 Subject: [PATCH 1/3] Fix false error for executor.jobName config option Signed-off-by: Ben Sherman --- .../config/control/VariableScopeVisitor.java | 8 ++----- .../config/control/ConfigResolveTest.groovy | 23 ------------------- 2 files changed, 2 insertions(+), 29 deletions(-) diff --git a/modules/nf-lang/src/main/java/nextflow/config/control/VariableScopeVisitor.java b/modules/nf-lang/src/main/java/nextflow/config/control/VariableScopeVisitor.java index 21e5db49f4..9ea0eea348 100644 --- a/modules/nf-lang/src/main/java/nextflow/config/control/VariableScopeVisitor.java +++ b/modules/nf-lang/src/main/java/nextflow/config/control/VariableScopeVisitor.java @@ -119,12 +119,8 @@ public void visitConfigAssign(ConfigAssignNode node) { var scopes = currentConfigScopes(); inProcess = !scopes.isEmpty() && "process".equals(scopes.get(0)); inClosure = node.value instanceof ClosureExpression; - if( inClosure ) { - if( isWorkflowHandler(scopes, node) ) - vsc.addWarning("The use of workflow handlers in the config is deprecated -- use the entry workflow or a plugin instead", String.join(".", node.names), node); - else if( !inProcess ) - vsc.addError("Dynamic config options are only allowed in the `process` scope", node); - } + if( isWorkflowHandler(scopes, node) ) + vsc.addWarning("The use of workflow handlers in the config is deprecated -- use the entry workflow or a plugin instead", String.join(".", node.names), node); if( inClosure ) { vsc.pushScope(ScriptDsl.class); if( inProcess ) diff --git a/modules/nf-lang/src/test/groovy/nextflow/config/control/ConfigResolveTest.groovy b/modules/nf-lang/src/test/groovy/nextflow/config/control/ConfigResolveTest.groovy index 447f03ccf0..778caae112 100644 --- a/modules/nf-lang/src/test/groovy/nextflow/config/control/ConfigResolveTest.groovy +++ b/modules/nf-lang/src/test/groovy/nextflow/config/control/ConfigResolveTest.groovy @@ -63,29 +63,6 @@ class ConfigResolveTest extends Specification { errors[0].getOriginalMessage() == '`process` is not defined' } - def 'should report an error for an invalid dynamic config option' () { - when: - def errors = check( - '''\ - report.file = { "report.html" } - ''' - ) - then: - errors.size() == 1 - errors[0].getStartLine() == 1 - errors[0].getStartColumn() == 1 - errors[0].getOriginalMessage() == 'Dynamic config options are only allowed in the `process` scope' - - when: - errors = check( - '''\ - process.clusterOptions = { "--cpus ${task.cpus}" } - ''' - ) - then: - errors.size() == 0 - } - def 'should report an error for an invalid config include' () { given: def root = tempDir() From ce119d5353a104d738c515f72e8e1dc859b32f23 Mon Sep 17 00:00:00 2001 From: Ben Sherman Date: Mon, 13 Oct 2025 13:04:45 -0500 Subject: [PATCH 2/3] Support process DSL in `executor.jobName` closure Signed-off-by: Ben Sherman --- .../config/control/VariableScopeVisitor.java | 25 +++++++++++++------ .../config/control/ConfigResolveTest.groovy | 9 +++++++ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/modules/nf-lang/src/main/java/nextflow/config/control/VariableScopeVisitor.java b/modules/nf-lang/src/main/java/nextflow/config/control/VariableScopeVisitor.java index 9ea0eea348..1b0809de7a 100644 --- a/modules/nf-lang/src/main/java/nextflow/config/control/VariableScopeVisitor.java +++ b/modules/nf-lang/src/main/java/nextflow/config/control/VariableScopeVisitor.java @@ -107,7 +107,7 @@ public void visitConfigApply(ConfigApplyNode node) { checkMethodCall(node); } - private boolean inProcess; + private boolean inProcessScope; private boolean inClosure; @@ -117,30 +117,41 @@ public void visitConfigAssign(ConfigAssignNode node) { configScopes.add(node.names.get(i)); var scopes = currentConfigScopes(); - inProcess = !scopes.isEmpty() && "process".equals(scopes.get(0)); + inProcessScope = isProcessScope(scopes, node); inClosure = node.value instanceof ClosureExpression; if( isWorkflowHandler(scopes, node) ) vsc.addWarning("The use of workflow handlers in the config is deprecated -- use the entry workflow or a plugin instead", String.join(".", node.names), node); if( inClosure ) { vsc.pushScope(ScriptDsl.class); - if( inProcess ) + if( inProcessScope ) vsc.pushScope(ProcessDsl.class); } super.visitConfigAssign(node); if( inClosure ) { - if( inProcess ) + if( inProcessScope ) vsc.popScope(); vsc.popScope(); } inClosure = false; - inProcess = false; + inProcessScope = false; for( int i = 0; i < node.names.size() - 1; i++ ) configScopes.pop(); } + private static boolean isProcessScope(List scopes, ConfigAssignNode node) { + if( scopes.isEmpty() ) + return false; + if( "process".equals(scopes.get(0)) ) + return true; + var option = node.names.get(node.names.size() - 1); + return scopes.size() == 1 + && "executor".equals(scopes.get(0)) + && "jobName".equals(option); + } + private static boolean isWorkflowHandler(List scopes, ConfigAssignNode node) { var option = node.names.get(node.names.size() - 1); return scopes.size() == 1 @@ -153,7 +164,7 @@ public void visitMapEntryExpression(MapEntryExpression node) { node.getKeyExpression().visit(this); var ic = inClosure; - if( inProcess && node.getValueExpression() instanceof ClosureExpression ) + if( inProcessScope && node.getValueExpression() instanceof ClosureExpression ) inClosure = true; node.getValueExpression().visit(this); inClosure = ic; @@ -309,7 +320,7 @@ public void visitVariableExpression(VariableExpression node) { var name = node.getName(); Variable variable = vsc.findVariableDeclaration(name, node); if( variable == null ) { - if( inProcess && inClosure ) { + if( inProcessScope && inClosure ) { // dynamic process directives can reference process inputs which are not known at this point } else { diff --git a/modules/nf-lang/src/test/groovy/nextflow/config/control/ConfigResolveTest.groovy b/modules/nf-lang/src/test/groovy/nextflow/config/control/ConfigResolveTest.groovy index 778caae112..1acd686ae9 100644 --- a/modules/nf-lang/src/test/groovy/nextflow/config/control/ConfigResolveTest.groovy +++ b/modules/nf-lang/src/test/groovy/nextflow/config/control/ConfigResolveTest.groovy @@ -169,6 +169,15 @@ class ConfigResolveTest extends Specification { errors[0].getStartLine() == 2 errors[0].getStartColumn() == 23 errors[0].getOriginalMessage() == '`meta` is not defined' + + when: + errors = check( + '''\ + executor.jobName = { "$task.name - $task.hash" } + ''' + ) + then: + errors.size() == 0 } } From 9cc410b8553f4cb0ac485b5d2015799a9eab06f4 Mon Sep 17 00:00:00 2001 From: Ben Sherman Date: Tue, 14 Oct 2025 09:19:53 -0500 Subject: [PATCH 3/3] Add comments Signed-off-by: Ben Sherman --- .../nextflow/config/control/VariableScopeVisitor.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/modules/nf-lang/src/main/java/nextflow/config/control/VariableScopeVisitor.java b/modules/nf-lang/src/main/java/nextflow/config/control/VariableScopeVisitor.java index 1b0809de7a..7e3adc4e41 100644 --- a/modules/nf-lang/src/main/java/nextflow/config/control/VariableScopeVisitor.java +++ b/modules/nf-lang/src/main/java/nextflow/config/control/VariableScopeVisitor.java @@ -141,6 +141,15 @@ public void visitConfigAssign(ConfigAssignNode node) { configScopes.pop(); } + /** + * Determine whether a config option can access the process + * DSL for dynamic settings. + * + * This includes options in the `process` config scope and `executor.jobName`. + * + * @param scopes + * @param node + */ private static boolean isProcessScope(List scopes, ConfigAssignNode node) { if( scopes.isEmpty() ) return false;