Skip to content

Unify nf-lang config scopes with runtime classes #6271

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

bentsherman
Copy link
Member

@bentsherman bentsherman commented Jul 12, 2025

This PR moves the config schema annotations into the runtime so that we don't have to update config options in both places.

Plugin config scopes are now defined in the plugins themselves. Core plugins are typically only loaded when they are actually used (i.e. the awsbatch executor), so when Nextflow validates config at runtime, it will skip validation of core plugin config if the core plugin isn't loaded. This allows the lint command to work the same as before.

I will update the language server to extract this metadata at build-time with a custom Gradle task. For third-party plugins we will need to publish this metadata to the plugin registry, but that can be done later.

I have removed several config options that were undocumented or appeared to be legacy options. We can preserve them if needed. See my comments below.

TODO:

  • Update tests
  • Publish JSON artifact for language server

@bentsherman bentsherman requested review from a team as code owners July 12, 2025 00:35
Copy link

netlify bot commented Jul 12, 2025

Deploy Preview for nextflow-docs-staging canceled.

Name Link
🔨 Latest commit 9d5e6b8
🔍 Latest deploy log https://app.netlify.com/projects/nextflow-docs-staging/deploys/68816877709d14000759828d

Copy link
Collaborator

@christopher-hakkaart christopher-hakkaart left a comment

Choose a reason for hiding this comment

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

Docs look good. No comments.

@bentsherman bentsherman added this to the 25.10 milestone Jul 14, 2025
@bentsherman bentsherman force-pushed the config-scopes branch 3 times, most recently from 824523f to 8ca91ca Compare July 23, 2025 22:07
Comment on lines +33 to 35
default boolean entrypointOverride() {
return ContainerHelper.entrypointOverride()
}
Copy link
Member Author

Choose a reason for hiding this comment

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

The entrypointOverride is a hidden config option that can be set for docker, k8s, and the other container config scopes.

I made it so that it can only be enabled by setting the NXF_CONTAINER_ENTRYPOINT_OVERRIDE environment variable, since that seems simpler than adding a config option for every container scope.

If we want to preserve this behavior, I suggest we document this env var and add a note to the 25.10 migration notes.

Comment on lines +743 to 744
if( containerConfig.writableInputMounts()==false )
builder.params(readOnlyInputs: true)
Copy link
Member Author

Choose a reason for hiding this comment

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

It looks like some container scopes can specify writableInputMounts = false to mount folders into the container as read-only. There are tests for this option for apptainer, charliecloud, docker, podman, and singularity... so basically all of them.

If we want to keep this behavior, I suggest we add config option for each container scope where it's relevant. Or we could add an environment var.

Comment on lines 258 to 260
boolean getCleanup(boolean defValue=true) {
target.cleanup == null ? defValue : Boolean.valueOf( target.cleanup as String )
defValue
}
Copy link
Member Author

Choose a reason for hiding this comment

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

There is a hidden option k8s.cleanup which is enabled by default, but can be disabled to not delete any pods. Normally only successful pods are deleted. Not sure if we still need this setting.

Comment on lines 262 to 264
String getUserName() {
target.userName ?: System.properties.get('user.name')
System.properties.get('user.name')
}
Copy link
Member Author

Choose a reason for hiding this comment

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

There is a hidden config option k8s.userName to control the user name, which is used to set the default launchDir. Since we can set launchDir directly I'm not sure that we need this option.

Comment on lines 294 to 296
String getNextflowImageName() {
final defImage = "nextflow/nextflow:${BuildInfo.version}"
return target.navigate('nextflow.image', defImage)
}

boolean getAutoMountHostPaths() {
Boolean.valueOf( target.autoMountHostPaths as String )
return "nextflow/nextflow:${BuildInfo.version}"
}
Copy link
Member Author

Choose a reason for hiding this comment

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

There is a hidden option k8s.nextflow.image which controls the nextflow container image used by kuberun. This can already be controlled via CLI option so I don't think we need a config option for it.


if( target.httpConnectTimeout )
result.httpConnectTimeout = target.httpConnectTimeout as Duration
final result = clientDiscovery(context, namespace, serviceAccount)
Copy link
Member Author

Choose a reason for hiding this comment

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

There is a hidden scope k8s.client which can be used to define settings for the K8s client directly in Nextflow config. I think the best practice is to define these settings in .kube/config. If we want to keep this approach we should explicitly document it.

Comment on lines +195 to +196
void check(Map config, List<String> args) {
final store = LinStoreFactory.getOrCreate(LineageConfig.create(config), false)
Copy link
Member Author

Choose a reason for hiding this comment

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

@jorgee I refactored the lineage commands to not create a session since it was only used to create the LineageConfig and now isn't needed. However there are two failing unit tests:

LinCommandImplTest > should print error store is not found in diff FAILED
    org.spockframework.runtime.SpockComparisonFailure at LinCommandImplTest.groovy:467

LinCommandImplTest > should print correct validate path FAILED
    nextflow.exception.AbortOperationException at LinCommandImplTest.groovy:527

I wonder if it's a side effect of not creating the session? Do you know if the session is still needed (e.g. by the LID filesystem) for other purposes?

It would be nice to avoid creating a session since we aren't running a pipeline here, but if it requires deeper changes we could defer to a separate PR.

Signed-off-by: Ben Sherman <bentshermann@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants