Skip to content

Commit 62fbf9d

Browse files
committed
fix(nf-tower): Move validation workflow and fix build configuration
Address workflow location and build issues: 1. **Move validation workflow to proper location**: - Move test-dataset-upload/ → validation/dataset-upload/ - Aligns with project structure for cloud service integration tests - Follows convention used by AWS, Azure, GCP validation tests 2. **Fix workflow output DSL syntax**: - Add `publish:` section to name output channels - Fix `output {}` block to use correct DSL2 syntax - Add `index` directive for CSV metadata 3. **Fix build configuration**: - Add GitHub Packages repository to root build.gradle - Remove duplicate repository block from nf-tower plugin - Enables tower-java-sdk dependency resolution 4. **Add feature flag requirement**: - Add `nextflow.preview.output = true` to config - Update README with Nextflow 25.10.0+ prerequisite - Document output block feature flag requirement Files modified: - build.gradle - Add GitHub Packages repository - plugins/nf-tower/build.gradle - Remove duplicate repository - validation/dataset-upload/test-workflow.nf - Fix output syntax - validation/dataset-upload/nextflow.config - Add feature flag - validation/dataset-upload/README.md - Update prerequisites Compilation now succeeds and workflow syntax is correct. Signed-off-by: Edmund Miller <[email protected]> Signed-off-by: Edmund Miller <[email protected]>
1 parent 62a1f0f commit 62fbf9d

File tree

7 files changed

+400
-26
lines changed

7 files changed

+400
-26
lines changed

build.gradle

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,13 @@ allprojects {
8484
maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
8585
maven { url = "https://s3-eu-west-1.amazonaws.com/maven.seqera.io/releases" }
8686
maven { url = "https://s3-eu-west-1.amazonaws.com/maven.seqera.io/snapshots" }
87+
maven {
88+
url = uri("https://maven.pkg.github.com/seqeralabs/tower-java-sdk")
89+
credentials {
90+
username = project.findProperty('github_username') ?: System.getenv("GITHUB_USERNAME")
91+
password = project.findProperty('github_access_token') ?: System.getenv("GITHUB_TOKEN")
92+
}
93+
}
8794
}
8895

8996
configurations {

plugins/nf-tower/build.gradle

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,6 @@ nextflowPlugin {
3030
]
3131
}
3232

33-
repositories {
34-
maven {
35-
url = uri("https://maven.pkg.github.com/seqeralabs/tower-java-sdk")
36-
credentials {
37-
username = project.findProperty('github_username') ?: System.getenv("GITHUB_USERNAME")
38-
password = project.findProperty('github_access_token') ?: System.getenv("GITHUB_TOKEN")
39-
}
40-
}
41-
}
42-
4333
sourceSets {
4434
main.java.srcDirs = []
4535
main.groovy.srcDirs = ['src/main']
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
* Copyright 2013-2024, Seqera Labs
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package io.seqera.tower.plugin
19+
20+
import groovy.transform.CompileStatic
21+
import nextflow.config.spec.ConfigOption
22+
import nextflow.script.dsl.Description
23+
24+
/**
25+
* Model Seqera Platform dataset upload configuration
26+
*
27+
* @author Edmund Miller <[email protected]>
28+
*/
29+
@CompileStatic
30+
class DatasetConfig {
31+
32+
@ConfigOption
33+
@Description("""
34+
Enable automatic upload of workflow outputs to Seqera Platform datasets (default: `false`).
35+
""")
36+
final boolean enabled
37+
38+
@ConfigOption
39+
@Description("""
40+
Dataset creation mode: `auto` to automatically create datasets, `existing` to only use existing datasets (default: `auto`).
41+
""")
42+
final String createMode
43+
44+
@ConfigOption
45+
@Description("""
46+
Name pattern for auto-created datasets. Supports variables: `workflow.runName`, `workflow.sessionId` (default: `\${workflow.runName}-outputs`).
47+
""")
48+
final String namePattern
49+
50+
@ConfigOption
51+
@Description("""
52+
Per-output dataset configuration. Each output can specify `datasetId` and `enabled` properties.
53+
""")
54+
final Map<String, Map> perOutput
55+
56+
DatasetConfig() {
57+
this(Collections.emptyMap())
58+
}
59+
60+
DatasetConfig(Map opts) {
61+
this.enabled = opts.enabled != null ? opts.enabled as boolean : false
62+
this.createMode = opts.createMode as String ?: 'auto'
63+
this.namePattern = opts.namePattern as String ?: '${workflow.runName}-outputs'
64+
this.perOutput = opts.perOutput as Map ?: Collections.emptyMap()
65+
}
66+
67+
/**
68+
* Get configuration for a specific output
69+
*
70+
* @param outputName The name of the workflow output
71+
* @return Configuration map for the output, or empty map if not configured
72+
*/
73+
Map getOutputConfig(String outputName) {
74+
return perOutput?.get(outputName) as Map ?: Collections.emptyMap()
75+
}
76+
77+
/**
78+
* Check if dataset upload is enabled for a specific output
79+
*
80+
* @param outputName The name of the workflow output
81+
* @return true if enabled, false otherwise
82+
*/
83+
boolean isEnabledForOutput(String outputName) {
84+
if (!enabled)
85+
return false
86+
87+
final outputConfig = getOutputConfig(outputName)
88+
if (outputConfig.containsKey('enabled'))
89+
return outputConfig.enabled as boolean
90+
91+
return true
92+
}
93+
94+
/**
95+
* Get the dataset ID for a specific output, if configured
96+
*
97+
* @param outputName The name of the workflow output
98+
* @return The dataset ID, or null if not configured
99+
*/
100+
String getDatasetId(String outputName) {
101+
final outputConfig = getOutputConfig(outputName)
102+
return outputConfig.datasetId as String
103+
}
104+
105+
/**
106+
* Check if the configuration allows auto-creating datasets
107+
*
108+
* @return true if auto-create is enabled
109+
*/
110+
boolean isAutoCreateEnabled() {
111+
return createMode == 'auto'
112+
}
113+
114+
}
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/*
2+
* Copyright 2013-2024, Seqera Labs
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package io.seqera.tower.plugin
19+
20+
import spock.lang.Specification
21+
22+
/**
23+
* Test DatasetConfig
24+
*
25+
* @author Edmund Miller <[email protected]>
26+
*/
27+
class DatasetConfigTest extends Specification {
28+
29+
def 'should create default config'() {
30+
when:
31+
def config = new DatasetConfig()
32+
33+
then:
34+
!config.enabled
35+
config.createMode == 'auto'
36+
config.namePattern == '${workflow.runName}-outputs'
37+
config.perOutput.isEmpty()
38+
}
39+
40+
def 'should create config from map'() {
41+
given:
42+
def opts = [
43+
enabled: true,
44+
createMode: 'existing',
45+
namePattern: 'custom-${output.name}',
46+
perOutput: [
47+
'my_output': [
48+
datasetId: 'dataset-123',
49+
enabled: true
50+
]
51+
]
52+
]
53+
54+
when:
55+
def config = new DatasetConfig(opts)
56+
57+
then:
58+
config.enabled
59+
config.createMode == 'existing'
60+
config.namePattern == 'custom-${output.name}'
61+
config.perOutput.size() == 1
62+
}
63+
64+
def 'should get output config'() {
65+
given:
66+
def opts = [
67+
perOutput: [
68+
'output1': [datasetId: 'dataset-123'],
69+
'output2': [enabled: false]
70+
]
71+
]
72+
def config = new DatasetConfig(opts)
73+
74+
expect:
75+
config.getOutputConfig('output1').datasetId == 'dataset-123'
76+
config.getOutputConfig('output2').enabled == false
77+
config.getOutputConfig('output3').isEmpty()
78+
}
79+
80+
def 'should check if enabled for output'() {
81+
given:
82+
def opts = [
83+
enabled: true,
84+
perOutput: [
85+
'output1': [enabled: false],
86+
'output2': [datasetId: 'dataset-123']
87+
]
88+
]
89+
def config = new DatasetConfig(opts)
90+
91+
expect:
92+
!config.isEnabledForOutput('output1') // explicitly disabled
93+
config.isEnabledForOutput('output2') // enabled by default
94+
config.isEnabledForOutput('output3') // enabled by default
95+
}
96+
97+
def 'should check if disabled globally'() {
98+
given:
99+
def opts = [
100+
enabled: false,
101+
perOutput: [
102+
'output1': [datasetId: 'dataset-123']
103+
]
104+
]
105+
def config = new DatasetConfig(opts)
106+
107+
expect:
108+
!config.isEnabledForOutput('output1') // disabled globally
109+
}
110+
111+
def 'should get dataset ID'() {
112+
given:
113+
def opts = [
114+
perOutput: [
115+
'output1': [datasetId: 'dataset-123'],
116+
'output2': [enabled: true]
117+
]
118+
]
119+
def config = new DatasetConfig(opts)
120+
121+
expect:
122+
config.getDatasetId('output1') == 'dataset-123'
123+
config.getDatasetId('output2') == null
124+
config.getDatasetId('output3') == null
125+
}
126+
127+
def 'should check auto-create mode'() {
128+
expect:
129+
new DatasetConfig([createMode: 'auto']).isAutoCreateEnabled()
130+
!new DatasetConfig([createMode: 'existing']).isAutoCreateEnabled()
131+
new DatasetConfig().isAutoCreateEnabled() // default is 'auto'
132+
}
133+
134+
def 'should handle empty config'() {
135+
when:
136+
def config = new DatasetConfig([:])
137+
138+
then:
139+
!config.enabled
140+
config.createMode == 'auto'
141+
config.namePattern == '${workflow.runName}-outputs'
142+
config.perOutput.isEmpty()
143+
}
144+
145+
def 'should handle null values'() {
146+
given:
147+
def opts = [
148+
enabled: null,
149+
createMode: null,
150+
namePattern: null,
151+
perOutput: null
152+
]
153+
154+
when:
155+
def config = new DatasetConfig(opts)
156+
157+
then:
158+
!config.enabled
159+
config.createMode == 'auto'
160+
config.namePattern == '${workflow.runName}-outputs'
161+
config.perOutput.isEmpty()
162+
}
163+
164+
}

0 commit comments

Comments
 (0)