gradle / gradle

Adaptable, fast automation for all
https://gradle.org
Apache License 2.0
16.65k stars 4.66k forks source link

Shared Build Service can't have parameters of domain types #23539

Open vlsi opened 1 year ago

vlsi commented 1 year ago

Expected Behavior

Shared build service parameters should support managed domain objects.

Current Behavior

Caused by: java.lang.NullPointerException
    at org.gradle.api.internal.provider.ManagedFactories$PropertyManagedFactory.fromState(ManagedFactories.java:70)
    at org.gradle.internal.snapshot.impl.IsolatedManagedValue.isolate(IsolatedManagedValue.java:42)
    at org.gradle.internal.snapshot.impl.IsolatedArray.isolate(IsolatedArray.java:52)
    at org.gradle.internal.snapshot.impl.IsolatedArray.isolate(IsolatedArray.java:26)
    at org.gradle.internal.snapshot.impl.IsolatedManagedValue.isolate(IsolatedManagedValue.java:42)
    at org.gradle.api.services.internal.BuildServiceProvider.instantiate(BuildServiceProvider.java:137)
    at org.gradle.api.services.internal.BuildServiceProvider.getInstance(BuildServiceProvider.java:128)
    at org.gradle.api.services.internal.BuildServiceProvider.calculateOwnValue(BuildServiceProvider.java:121)
    at org.gradle.api.internal.provider.AbstractMinimalProvider.get(AbstractMinimalProvider.java:83)

I suspect the root cause is that org.gradle.api.internal.provider.ManagedFactories uses type.isAssignableFrom(PUBLIC_TYPE), however, most likely the proper call is PUBLIC_TYPE.isAssignableFrom(type).

https://github.com/gradle/gradle/blob/4e3064ffb94a820888447cee2d4f533c8fc8349f/subprojects/model-core/src/main/java/org/gradle/api/internal/provider/ManagedFactories.java#L40

Context

I have trouble with moving Sigstore signing to a shared service.

Steps to Reproduce

abstract class Entity: Named
val entities = objects.domainObjectContainer(Entity::class)
val testEntity: Provider<Entity> by entities.registering

abstract class TestService: BuildService<TestService.Params> {
    interface Params: BuildServiceParameters {
        val entity: Property<Entity>
    }
}

val testService = gradle.sharedServices.registerIfAbsent("testService", TestService::class) {
    parameters {
        entity.set(testEntity)
    }
}

println("testService: ${testService.get()}")

See

breakpoint in ManagedFactories

Your Environment

Gradle 7.6

vlsi commented 1 year ago

The workaround is to map testEntity provider.

In other words, this somehow works:

abstract class Entity: Named
val entities = objects.domainObjectContainer(Entity::class)
val testEntity: Provider<Entity> by entities.registering

abstract class TestService: BuildService<TestService.Params> {
    interface Params: BuildServiceParameters {
        val entity: Property<Entity>
    }
}

val testService = gradle.sharedServices.registerIfAbsent("testService", TestService::class) {
    parameters {
        entity.set(testEntity.map { it }) // map { it } fixes NPE
    }
}

println("testService: ${testService.get()}")
ljacomet commented 1 year ago

Thank you for providing a valid reproducer.

The issue is in the backlog of the relevant team and prioritized by them.