diff --git a/modules/nextflow/src/main/groovy/nextflow/Session.groovy b/modules/nextflow/src/main/groovy/nextflow/Session.groovy index cea04f8856..eb5e55e852 100644 --- a/modules/nextflow/src/main/groovy/nextflow/Session.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/Session.groovy @@ -88,7 +88,6 @@ import nextflow.util.NameGenerator import nextflow.util.SysHelper import nextflow.util.ThreadPoolManager import nextflow.util.Threads -import nextflow.util.VersionNumber import org.apache.commons.lang3.exception.ExceptionUtils import sun.misc.Signal import sun.misc.SignalHandler @@ -686,7 +685,6 @@ class Session implements ISession { throw new IllegalStateException("Not a valid config env object: $config.env") } - @Memoized Manifest getManifest() { if( !config.manifest ) return new Manifest() @@ -890,13 +888,6 @@ class Session implements ISession { ExecutorService getExecService() { execService } - /** - * Check preconditions before run the main script - */ - protected void validate() { - checkVersion() - } - @PackageScope void checkConfig() { final enabled = config.navigate('nextflow.enable.configProcessNamesValidation', true) as boolean if( enabled ) { @@ -918,36 +909,6 @@ class Session implements ISession { config.navigate('workflow.failOnIgnore', false) as boolean } - @PackageScope VersionNumber getCurrentVersion() { - new VersionNumber(BuildInfo.version) - } - - @PackageScope void checkVersion() { - def version = manifest.getNextflowVersion()?.trim() - if( !version ) - return - - // when the version string is prefix with a `!` - // an exception is thrown is the version does not match - boolean important = false - if( version.startsWith('!') ) { - important = true - version = version.substring(1).trim() - } - - if( !getCurrentVersion().matches(version) ) { - important ? showVersionError(version) : showVersionWarning(version) - } - } - - @PackageScope void showVersionError(String ver) { - throw new AbortOperationException("Nextflow version $BuildInfo.version does not match workflow required version: $ver") - } - - @PackageScope void showVersionWarning(String ver) { - log.warn "Nextflow version $BuildInfo.version does not match workflow required version: $ver -- Execution will continue, but things may break!" - } - /** * Validate the config file * @@ -1090,7 +1051,6 @@ class Session implements ISession { } void notifyBeforeWorkflowExecution() { - validate() } void notifyAfterWorkflowExecution() { diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy index daa686b878..2c625e23c6 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy @@ -38,6 +38,7 @@ import nextflow.SysEnv import nextflow.config.ConfigBuilder import nextflow.config.ConfigMap import nextflow.config.ConfigValidator +import nextflow.config.Manifest import nextflow.exception.AbortOperationException import nextflow.file.FileHelper import nextflow.plugin.Plugins @@ -49,6 +50,7 @@ import nextflow.secret.SecretsLoader import nextflow.util.CustomPoolFactory import nextflow.util.Duration import nextflow.util.HistoryFile +import nextflow.util.VersionNumber import org.apache.commons.lang3.StringUtils import org.fusesource.jansi.AnsiConsole import org.yaml.snakeyaml.Yaml @@ -360,6 +362,9 @@ class CmdRun extends CmdBase implements HubOptions { ConfigMap config = builder.build() Map configParams = builder.getConfigParams() + // -- Check Nextflow version + checkVersion(config) + // -- Load plugins (may register secret providers) Plugins.load(config) @@ -677,6 +682,45 @@ class CmdRun extends CmdBase implements HubOptions { return result } + /** + * Check the Nextflow version against the version required by + * the pipeline via `manifest.nextflowVersion`. + * + * When the version spec is prefixed with '!', the run will fail + * if the Nextflow version does not match. + * + * @param config + */ + protected void checkVersion(Map config) { + final manifest = new Manifest(config.manifest as Map ?: Collections.emptyMap()) + String version = manifest.nextflowVersion?.trim() + if( !version ) + return + + final important = version.startsWith('!') + if( important ) + version = version.substring(1).trim() + + if( !getCurrentVersion().matches(version) ) { + if( important ) + showVersionError(version) + else + showVersionWarning(version) + } + } + + protected VersionNumber getCurrentVersion() { + return new VersionNumber(BuildInfo.version) + } + + protected void showVersionError(String ver) { + throw new AbortOperationException("Nextflow version ${BuildInfo.version} does not match version required by pipeline: ${ver}") + } + + protected void showVersionWarning(String ver) { + log.warn "Nextflow version ${BuildInfo.version} does not match version required by pipeline: ${ver} -- execution will continue, but things might break!" + } + @Memoized // <-- avoid parse multiple times the same file and params Map parsedParams(Map configVars) { diff --git a/modules/nextflow/src/test/groovy/nextflow/SessionTest.groovy b/modules/nextflow/src/test/groovy/nextflow/SessionTest.groovy index 18710b064a..76487c6a10 100644 --- a/modules/nextflow/src/test/groovy/nextflow/SessionTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/SessionTest.groovy @@ -317,7 +317,7 @@ class SessionTest extends Specification { when: def session = new Session([manifest: MAN]) then: - session.manifest.with { + session.getManifest().with { author == 'pablo' nextflowVersion == '1.2.3' name == 'foo' @@ -401,49 +401,6 @@ class SessionTest extends Specification { session.fetchContainers() == 'ngi/rnaseq:1.2' } - - def 'should validate version'() { - - given: - def manifest = Mock(Manifest) - def session = Spy(Session) - - when: - session.checkVersion() - then: - session.getManifest() >> manifest - 1 * session.getCurrentVersion() >> new VersionNumber('1.1') - 1 * manifest.getNextflowVersion() >> '>= 1.0' - 0 * session.showVersionWarning(_) - - when: - session.checkVersion() - then: - session.getManifest() >> manifest - 1 * session.getCurrentVersion() >> new VersionNumber('1.1') - 1 * manifest.getNextflowVersion() >> '>= 1.2' - 1 * session.showVersionWarning('>= 1.2') - - when: - session.checkVersion() - then: - session.getManifest() >> manifest - 1 * session.getCurrentVersion() >> new VersionNumber('1.1') - 1 * manifest.getNextflowVersion() >> '! >= 1.2' - 1 * session.showVersionError('>= 1.2') - thrown(AbortOperationException) - - when: - session.checkVersion() - then: - session.getManifest() >> manifest - 1 * manifest.getNextflowVersion() >> null - 0 * session.getCurrentVersion() >> null - 0 * session.showVersionWarning(_) - 0 * session.showVersionError(_) - - } - @Unroll def 'should get module binaries status'() { given: diff --git a/modules/nextflow/src/test/groovy/nextflow/cli/CmdRunTest.groovy b/modules/nextflow/src/test/groovy/nextflow/cli/CmdRunTest.groovy index 250319d84a..333e20a9e6 100644 --- a/modules/nextflow/src/test/groovy/nextflow/cli/CmdRunTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/cli/CmdRunTest.groovy @@ -23,6 +23,7 @@ import nextflow.NextflowMeta import nextflow.SysEnv import nextflow.config.ConfigMap import nextflow.exception.AbortOperationException +import nextflow.util.VersionNumber import spock.lang.Specification import spock.lang.Unroll @@ -438,4 +439,37 @@ class CmdRunTest extends Specification { true | [:] | [NXF_ENABLE_STRICT: true ] | true } + + def 'should validate Nextflow version against version required by pipeline'() { + + given: + def cmd = Spy(new CmdRun()) + + when: + cmd.checkVersion([manifest: [nextflowVersion: '>= 1.0']]) + then: + 1 * cmd.getCurrentVersion() >> new VersionNumber('1.1') + 0 * cmd.showVersionWarning(_) + + when: + cmd.checkVersion([manifest: [nextflowVersion: '>= 1.2']]) + then: + 1 * cmd.getCurrentVersion() >> new VersionNumber('1.1') + 1 * cmd.showVersionWarning('>= 1.2') + + when: + cmd.checkVersion([manifest: [nextflowVersion: '! >= 1.2']]) + then: + 1 * cmd.getCurrentVersion() >> new VersionNumber('1.1') + 1 * cmd.showVersionError('>= 1.2') + thrown(AbortOperationException) + + when: + cmd.checkVersion([:]) + then: + 0 * cmd.getCurrentVersion() + 0 * cmd.showVersionWarning(_) + 0 * cmd.showVersionError(_) + } + }