Skip to content

Commit a71e08c

Browse files
authored
Merge pull request #93 from nebula-plugins/enhance-facets-api
Add API to Facets that can be used in Kotlin DSL
2 parents 73eee6a + 5fe6eef commit a71e08c

File tree

5 files changed

+363
-10
lines changed

5 files changed

+363
-10
lines changed

src/main/groovy/nebula/plugin/responsible/NebulaFacetPlugin.groovy

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,60 @@ class NebulaFacetPlugin implements Plugin<Project> {
187187
return instantiator.newInstance(NamedContainerProperOrder.class, type, instantiator, factory, decorator)
188188
}
189189

190+
/**
191+
* Creates and configures a test facet programmatically using an Action.
192+
* This is a type-safe alternative to using the container's create method,
193+
* particularly useful for plugins written in Kotlin or Java.
194+
*
195+
* @param name the name of the test facet
196+
* @param configureAction the action to configure the test facet
197+
* @return the created and configured test facet
198+
*/
199+
TestFacetDefinition createTestFacet(String name, Action<? super TestFacetDefinition> configureAction) {
200+
TestFacetDefinition facet = new TestFacetDefinition(name)
201+
configureAction.execute(facet)
202+
extension.add(facet)
203+
return facet
204+
}
205+
206+
/**
207+
* Creates a test facet with default configuration.
208+
*
209+
* @param name the name of the test facet
210+
* @return the created test facet
211+
*/
212+
TestFacetDefinition createTestFacet(String name) {
213+
TestFacetDefinition facet = new TestFacetDefinition(name)
214+
extension.add(facet)
215+
return facet
216+
}
217+
218+
/**
219+
* Creates and configures a regular (non-test) facet programmatically using an Action.
220+
*
221+
* @param name the name of the facet
222+
* @param configureAction the action to configure the facet
223+
* @return the created and configured facet
224+
*/
225+
FacetDefinition createFacet(String name, Action<? super FacetDefinition> configureAction) {
226+
FacetDefinition facet = new FacetDefinition(name)
227+
configureAction.execute(facet)
228+
extension.add(facet)
229+
return facet
230+
}
231+
232+
/**
233+
* Creates a regular facet with default configuration.
234+
*
235+
* @param name the name of the facet
236+
* @return the created facet
237+
*/
238+
FacetDefinition createFacet(String name) {
239+
FacetDefinition facet = new FacetDefinition(name)
240+
extension.add(facet)
241+
return facet
242+
}
243+
190244
// TODO React to changes on a FacetDefinition, and re-create source set
191245
}
192246

src/main/groovy/nebula/plugin/responsible/NebulaIntegTestPlugin.groovy

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package nebula.plugin.responsible
22

33
import groovy.transform.CompileStatic
4+
import org.gradle.api.Action
45
import org.gradle.api.Plugin
56
import org.gradle.api.Project
67
import org.gradle.api.plugins.JavaPlugin
@@ -22,11 +23,15 @@ class NebulaIntegTestPlugin implements Plugin<Project> {
2223
NebulaFacetPlugin facetPlugin = project.plugins.apply(NebulaFacetPlugin) as NebulaFacetPlugin
2324

2425
project.plugins.withType(JavaPlugin) {
25-
facetPlugin.extension.create(FACET_NAME) { TestFacetDefinition facet ->
26-
facet.setTestTaskName(TASK_NAME)
27-
facet.setParentSourceSet(PARENT_SOURCE_SET)
28-
facet.setIncludeInCheckLifecycle(shouldIncludeInCheckLifecycle())
29-
}
26+
// Use the type-safe helper method - works with Java, Kotlin, and Groovy
27+
facetPlugin.createTestFacet(FACET_NAME, new Action<TestFacetDefinition>() {
28+
@Override
29+
void execute(TestFacetDefinition facet) {
30+
facet.setTestTaskName(TASK_NAME)
31+
facet.setParentSourceSet(PARENT_SOURCE_SET)
32+
facet.setIncludeInCheckLifecycle(shouldIncludeInCheckLifecycle())
33+
}
34+
})
3035
}
3136
}
3237

src/main/groovy/nebula/plugin/responsible/gradle/NamedContainerProperOrder.groovy

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package nebula.plugin.responsible.gradle
22

3+
import org.gradle.api.Action
34
import org.gradle.api.NamedDomainObjectFactory
45
import org.gradle.api.Namer
56
import org.gradle.api.internal.CollectionCallbackActionDecorator
@@ -31,13 +32,31 @@ class NamedContainerProperOrder<T> extends FactoryNamedDomainObjectContainer<T>
3132
}
3233

3334
@Override
34-
public T create(String name, Closure configureClosure) {
35-
assertCanAdd(name);
36-
T object = doCreate(name);
35+
T create(String name, Closure configureClosure) {
36+
assertCanAdd(name)
37+
T object = doCreate(name)
3738
// Configure the object BEFORE, adding and kicking off addEvents in doAdd
3839
ConfigureUtil.configure(configureClosure, object)
39-
add(object);
40-
return object;
40+
add(object)
41+
return object
42+
}
43+
44+
/**
45+
* Creates and configures a new object using an Action for Java/Kotlin interop.
46+
* This allows plugins written in Kotlin or Java to create and configure facets
47+
* programmatically without requiring Groovy closures.
48+
*
49+
* @param name the name of the object to create
50+
* @param configureAction the action to configure the object
51+
* @return the created and configured object
52+
*/
53+
T create(String name, Action<? super T> configureAction) {
54+
assertCanAdd(name)
55+
T object = doCreate(name)
56+
// Configure the object BEFORE adding, to maintain same semantics as closure version
57+
configureAction.execute(object)
58+
add(object)
59+
return object
4160
}
4261

4362
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package nebula.plugin.responsible
2+
3+
/**
4+
* Integration test using REAL Kotlin DSL (build.gradle.kts) to verify
5+
* the plugin works correctly with Kotlin build scripts and the programmatic API.
6+
*
7+
* This demonstrates that users can create facets programmatically from Kotlin DSL
8+
* build scripts using idiomatic Kotlin lambda syntax.
9+
*/
10+
class NebulaFacetPluginKotlinDslIntegrationSpec extends BaseIntegrationTestKitSpec {
11+
12+
def 'create test facet from Kotlin DSL with lambda syntax'() {
13+
given:
14+
// Use actual build.gradle.kts (Kotlin DSL) with Java source
15+
// This is a common real-world scenario: Kotlin build scripts with Java code
16+
def buildFileKts = new File(projectDir, 'build.gradle.kts')
17+
buildFileKts.text = '''
18+
plugins {
19+
java
20+
id("com.netflix.nebula.facet")
21+
}
22+
23+
import nebula.plugin.responsible.NebulaFacetPlugin
24+
25+
val facetPlugin = project.plugins.getPlugin(NebulaFacetPlugin::class.java)
26+
27+
// Idiomatic Kotlin lambda syntax - no Groovy closures required!
28+
facetPlugin.createTestFacet("integTest") {
29+
testTaskName = "integrationTest"
30+
parentSourceSet = "test"
31+
includeInCheckLifecycle = true
32+
}
33+
34+
repositories {
35+
mavenCentral()
36+
}
37+
38+
dependencies {
39+
testImplementation("junit:junit:4.13.2")
40+
}
41+
'''.stripIndent()
42+
43+
// Java test source (common scenario: Kotlin DSL + Java source)
44+
writeTest('src/integTest/java/', 'com.example', false)
45+
46+
when:
47+
def result = runTasks('integrationTest')
48+
49+
then:
50+
result.task(':integrationTest')
51+
fileExists('build/classes/java/integTest/com/example/HelloWorldTest.class')
52+
}
53+
54+
boolean fileExists(String path) {
55+
new File(projectDir, path).exists()
56+
}
57+
}

0 commit comments

Comments
 (0)