Skip to content

Commit 76fe68a

Browse files
pditommasoclaude
andcommitted
Fix extensions.idx inclusion in JAR files
The ExtensionPointsTask generates extensions.idx at build/resources/main/META-INF/extensions.idx, but this file was not being included in the final JAR, causing PF4J to fail discovering plugin extension points during tests. Changes: - Modified NextflowPlugin.groovy to add extensionPoints task outputs to jar task inputs - Added comprehensive tests to verify extensions.idx is included in JAR - Ensured consistency between JAR and ZIP packaging (both use same extensions.idx) This resolves test failures where plugins like nf-amazon couldn't load S3PathFactory and other extension points due to missing META-INF/extensions.idx in JAR files. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 8620fad commit 76fe68a

File tree

2 files changed

+102
-3
lines changed

2 files changed

+102
-3
lines changed

src/main/groovy/io/nextflow/gradle/NextflowPlugin.groovy

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,11 @@ class NextflowPlugin implements Plugin<Project> {
8181
// Custom tasks
8282
// -----------------------------
8383
// extensionPoints - generates extensions.idx file
84-
project.tasks.register('extensionPoints', ExtensionPointsTask)
85-
project.tasks.jar.dependsOn << project.tasks.extensionPoints
86-
project.tasks.compileTestGroovy.dependsOn << project.tasks.extensionPoints
84+
def extensionPointsTask = project.tasks.register('extensionPoints', ExtensionPointsTask)
85+
project.tasks.jar.dependsOn << extensionPointsTask
86+
// ensure the generated extensions.idx is included in the JAR
87+
project.tasks.jar.from(extensionPointsTask.get().outputs)
88+
project.tasks.compileTestGroovy.dependsOn << extensionPointsTask
8789

8890
// packagePlugin - builds the zip file
8991
project.tasks.register('packagePlugin', PluginPackageTask)

src/test/groovy/io/nextflow/gradle/NextflowPluginTest.groovy

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,4 +228,101 @@ class NextflowPluginTest extends Specification {
228228
compileOnlyDeps.find { it.group == 'org.pf4j' && it.name == 'pf4j' && it.version == '3.4.1' }
229229
}
230230

231+
def "should configure jar task to include extensions.idx file"() {
232+
given:
233+
project.nextflowPlugin {
234+
description = 'A test plugin'
235+
provider = 'Test Author'
236+
className = 'com.example.TestPlugin'
237+
nextflowVersion = '24.04.0'
238+
extensionPoints = ['com.example.TestExtension', 'com.example.AnotherExtension']
239+
}
240+
241+
when:
242+
project.evaluate()
243+
244+
then: "jar task should depend on extensionPoints task"
245+
def jarTask = project.tasks.jar
246+
def extensionPointsTask = project.tasks.extensionPoints
247+
jarTask.taskDependencies.getDependencies(jarTask).contains(extensionPointsTask)
248+
249+
and: "extensionPoints task should be registered"
250+
extensionPointsTask != null
251+
}
252+
253+
def "should include extensions.idx file in built JAR"() {
254+
given:
255+
// Create a minimal source file to satisfy the jar task
256+
def srcDir = project.file('src/main/groovy/com/example')
257+
srcDir.mkdirs()
258+
def pluginFile = new File(srcDir, 'TestPlugin.groovy')
259+
pluginFile.text = '''
260+
package com.example
261+
import org.pf4j.Plugin
262+
263+
class TestPlugin extends Plugin {
264+
}
265+
'''.stripIndent()
266+
267+
project.nextflowPlugin {
268+
description = 'A test plugin'
269+
provider = 'Test Author'
270+
className = 'com.example.TestPlugin'
271+
nextflowVersion = '24.04.0'
272+
extensionPoints = ['com.example.TestExtension', 'com.example.AnotherExtension']
273+
}
274+
275+
when:
276+
project.evaluate()
277+
278+
// First run the extensionPoints task to generate the extensions.idx
279+
def extensionPointsTask = project.tasks.extensionPoints
280+
extensionPointsTask.run()
281+
282+
// Verify the extensions.idx was generated
283+
def extensionsFile = extensionPointsTask.outputFile.get().asFile
284+
extensionsFile.exists()
285+
286+
// Now check that the jar task includes this file in its inputs
287+
def jarTask = project.tasks.jar
288+
def jarInputFiles = jarTask.source.files
289+
290+
then:
291+
extensionsFile.exists()
292+
extensionsFile.text.trim() == 'com.example.TestExtension\ncom.example.AnotherExtension'
293+
294+
and: "jar task should include the extensions.idx in its source files"
295+
jarInputFiles.contains(extensionsFile)
296+
}
297+
298+
def "should have consistent extensions.idx between jar and packagePlugin tasks"() {
299+
given:
300+
project.nextflowPlugin {
301+
description = 'A test plugin'
302+
provider = 'Test Author'
303+
className = 'com.example.TestPlugin'
304+
nextflowVersion = '24.04.0'
305+
extensionPoints = ['com.example.TestExtension']
306+
}
307+
308+
when:
309+
project.evaluate()
310+
311+
then: "both jar and packagePlugin should depend on the same extensionPoints task"
312+
def extensionPointsTask = project.tasks.extensionPoints
313+
def jarTask = project.tasks.jar
314+
def packageTask = project.tasks.packagePlugin
315+
316+
jarTask.taskDependencies.getDependencies(jarTask).contains(extensionPointsTask)
317+
packageTask.taskDependencies.getDependencies(packageTask).contains(extensionPointsTask)
318+
319+
and: "both tasks use the same extensionPoints task instance"
320+
extensionPointsTask != null
321+
322+
and: "packagePlugin includes jar contents via 'with' directive"
323+
// The packagePlugin uses 'with project.tasks.jar' in its constructor
324+
// so it will include whatever the jar task produces, ensuring consistency
325+
packageTask != null
326+
}
327+
231328
}

0 commit comments

Comments
 (0)