Gradle Core plugin isn't loaded from custom repository

First of all, I’ve thought the core plugins are included in the Gradle distribution and doesn’t need to be downloaded. In my case, I’m trying to force the download of all plugins from our internal Nexus repository server.

In my build script, I’ve got

plugins {
    `kotlin-dsl`
}

In the settings.gradle.kts, I’ve got

pluginManagement {
    repositories {
        maven(url = "https://nexus.example.com/repository/gradle-plugins/")
        // gradlePluginPortal()
    }
}

As soon as gradlePluginPortal is commented out AND the dependencies are not cached yet, the build will fail:

Plugin [id: 'org.gradle.kotlin.kotlin-dsl', version: '4.1.0'] was not found in any of the following sources:

* Try:
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.

* Exception is:
org.gradle.api.plugins.UnknownPluginException: Plugin [id: 'org.gradle.kotlin.kotlin-dsl', version: '4.1.0'] was not found in any of the following sources:

- Gradle Core Plugins (plugin is not in 'org.gradle' namespace)
- Plugin Repositories (could not resolve plugin artifact 'org.gradle.kotlin.kotlin-dsl:org.gradle.kotlin.kotlin-dsl.gradle.plugin:4.1.0')
  Searched in the following repositories:
    maven(https://nexus.example.com/repository/gradle-plugins/)
	at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.resolveToFoundResult(DefaultPluginRequestApplicator.java:237)
	...

Am I missing something? The issue is that our Nexus isn’t requested at all. But if gradlePluginPortal is enabled, the (other) dependencies are loaded from the Nexus repository. I’m also confused by the message that the plugin is not found in “Gradle Core Plugins (plugin is not in ‘org.gradle’ namespace)”.

Yes, that’s correct.
The built-in plugins are in the org.gradle namespace, so for example org.gradle.java.
org.gradle.kotlin.kotlin-dsl is in the org.gradle.kotlin namespace which is different.
The convenience accessor kotlin-dsl just expands to the full id with compatible version automatically, similar to what you get when you do kotlin("jvm") for example.
So that plugin indeed is not a built-in plugin, but taken from repository.

I don’t understand what you mean with “our Nexus isn’t requested at all” though.
Your error message shows that it was asked:

Oh, I’ve missed that Java packages aren’t hierarchical.

The error message is misleading / wrong. I’m monitoring the request.log on the Nexus repository server and I see no request. Only after I’ve added gradlePluginPortal to the repositories, the request.log is showing requests to the gradle-plugins repository. But not for org.gradle.kotlin.kotlin-dsl, which seems to be loaded from the Gradle Plugin Portal.

So it feels like the kotlin-dsl plugin is somehow forced to be loaded from the Gradle Plugin Portal. I hope I can provide a demonstrator project between the years.

Oh, I’ve missed that Java packages aren’t hierarchical.

While this is correct, and the common practice to speak of “sub-packages” is not really technically correct, this is even irrelevant here. We are talking about Plugin ID namespace, not Java packages. Plugin IDs are not related to any Java package in any way, except if someone happens to choose them to be the same as they usually look similar. But it is for example also quite common to have dashes in plugin IDs which you cannot have in Java packages. :slight_smile:

The error message is misleading / wrong

It is not.
Either your monitoring is wrong, or you are within a timeframe where Gradle remembers that the repository does not have the dependency you try to resolve in which case it would not do a fresh request. If you try with --refresh-dependencies or wait long enough, it should be retried.

So it feels like the kotlin-dsl plugin is somehow forced to be loaded from the Gradle Plugin Portal. I hope I can provide a demonstrator project between the years.

It is not and you will not be able to. :slight_smile:
Spoiler: I do resolve the plugin from our Nexus. :slight_smile:
It is in no way special, except that it has a convenience accessor.

Thanks for your input and the tip to use --refresh-dependencies, it makes debugging much easier. :slight_smile:

I’ve pinpointed the issue I was facing.

The task generateExternalPluginSpecBuilders from kotlin-dsl attempts to load the POM from a repository. Specifically, AbstractRepositoryMetadataSource#parseMetaDataFromArtifact(…) gets invoked for moduleComponentIdentifier „org.gradle.kotlin.kotlin-dsl:org.gradle.kotlin.kotlin-dsl.gradle.plugin:4.2.1“.

This process was causing an exception due to server certificate validation issues: When initializing the trust store in SystemDefaultSSLContextFactory#getTrustManagers(), the javax.net.ssl.trustStore property wasn’t set yet. Consequently, Java’s default trust store was used, preventing kotlin-dsl from loading from my custom repository. I didn’t saw the request in the log of Nexus Repository, because the request ended at the reverse proxy (Traefik).

The javax.net.ssl.trustStore wasn’t available early enough because I set it during the evaluation phase, not in gradle.properties. This is a workaround for Eclipse compatibility, as Eclipse doesn’t handle relative trust store paths in gradle.properties well.

I do not have to support Eclipse anymore, switching to gradle.properties for these settings resolved the issue. An Eclipse compatible workaround would be to set the properties in a buildscript-block. The generateExternalPluginSpecBuilders task could then successfully fetch its dependencies through my Nexus via Traefik, as shown in the logs:

traefik  | redacted - - [11/Jan/2024:14:41:51 +0000] "HEAD /repository/gradle-plugins/org/gradle/kotlin/kotlin-dsl/org.gradle.kotlin.kotlin-dsl.gradle.plugin/4.2.1/org.gradle.kotlin.kotlin-dsl.gradle.plugin-4.2.1.pom HTTP/1.1" 200 0 "-" "-" 562 "nexus@docker" "http://172.16.1.4:8081" 4141ms
traefik  | redacted - - [11/Jan/2024:14:41:55 +0000] "GET /repository/gradle-plugins/org/gradle/kotlin/kotlin-dsl/org.gradle.kotlin.kotlin-dsl.gradle.plugin/4.2.1/org.gradle.kotlin.kotlin-dsl.gradle.plugin-4.2.1.pom.sha1 HTTP/1.1" 200 40 "-" "-" 564 "nexus@docker" "http://172.16.1.4:8081" 2044ms
traefik  | redacted - - [11/Jan/2024:14:41:57 +0000] "HEAD /repository/gradle-plugins/org/gradle/kotlin/kotlin-dsl/org.gradle.kotlin.kotlin-dsl.gradle.plugin/4.2.1/org.gradle.kotlin.kotlin-dsl.gradle.plugin-4.2.1.jar HTTP/1.1" 404 0 "-" "-" 566 "nexus@docker" "http://172.16.1.4:8081" 2226ms
traefik  | redacted - - [11/Jan/2024:14:41:59 +0000] "HEAD /repository/gradle-plugins/org/gradle/kotlin/gradle-kotlin-dsl-plugins/4.2.1/gradle-kotlin-dsl-plugins-4.2.1.pom HTTP/1.1" 200 0 "-" "-" 568 "nexus@docker" "http://172.16.1.4:8081" 794ms
traefik  | redacted - - [11/Jan/2024:14:42:00 +0000] "GET /repository/gradle-plugins/org/gradle/kotlin/gradle-kotlin-dsl-plugins/4.2.1/gradle-kotlin-dsl-plugins-4.2.1.pom.sha1 HTTP/1.1" 200 40 "-" "-" 569 "nexus@docker" "http://172.16.1.4:8081" 263ms
traefik  | redacted - - [11/Jan/2024:14:42:01 +0000] "HEAD /repository/gradle-plugins/org/gradle/kotlin/gradle-kotlin-dsl-plugins/4.2.1/gradle-kotlin-dsl-plugins-4.2.1.module HTTP/1.1" 200 0 "-" "-" 570 "nexus@docker" "http://172.16.1.4:8081" 388ms
traefik  | redacted - - [11/Jan/2024:14:42:01 +0000] "GET /repository/gradle-plugins/org/gradle/kotlin/gradle-kotlin-dsl-plugins/4.2.1/gradle-kotlin-dsl-plugins-4.2.1.module.sha1 HTTP/1.1" 200 40 "-" "-" 571 "nexus@docker" "http://172.16.1.4:8081" 523ms
traefik  | redacted - - [11/Jan/2024:14:42:02 +0000] "HEAD /repository/gradle-plugins/org/jetbrains/kotlin/kotlin-gradle-plugin/1.9.20/kotlin-gradle-plugin-1.9.20.pom HTTP/1.1" 200 0 "-" "-" 572 "nexus@docker" "http://172.16.1.4:8081" 530ms
traefik  | redacted - - [11/Jan/2024:14:42:02 +0000] "HEAD /repository/gradle-plugins/org/jetbrains/kotlin/kotlin-assignment/1.9.20/kotlin-assignment-1.9.20.pom HTTP/1.1" 200 0 "-" "-" 573 "nexus@docker" "http://172.16.1.4:8081" 639ms
traefik  | redacted - - [11/Jan/2024:14:42:02 +0000] "GET /repository/gradle-plugins/org/jetbrains/kotlin/kotlin-gradle-plugin/1.9.20/kotlin-gradle-plugin-1.9.20.pom.sha1 HTTP/1.1" 200 40 "-" "-" 575 "nexus@docker" "http://172.16.1.4:8081" 233ms
traefik  | redacted - - [11/Jan/2024:14:42:02 +0000] "GET /repository/gradle-plugins/org/jetbrains/kotlin/kotlin-assignment/1.9.20/kotlin-assignment-1.9.20.pom.sha1 HTTP/1.1" 200 40 "-" "-" 577 "nexus@docker" "http://172.16.1.4:8081" 462ms
traefik  | redacted - - [11/Jan/2024:14:42:02 +0000] "HEAD /repository/gradle-plugins/org/jetbrains/kotlin/kotlin-sam-with-receiver/1.9.20/kotlin-sam-with-receiver-1.9.20.pom HTTP/1.1" 200 0 "-" "-" 574 "nexus@docker" "http://172.16.1.4:8081" 1319ms
...

Great that you found the issue. :ok_hand:

An Eclipse compatible workaround would be to set the properties in a buildscript -block.

One of the earliest things that you can control, besides an init script, is the pluginManagement { ... } block in the settings script. This should be the very first thing of a project that is evaluated to determine the repositories and settings for resolving settings plugins. This is for example the place where I check for Java version in builds that require a specific Java version range to get a meaningful error message instead of “class version unsupported”.

Good point. I’ve just given it a try, because that location indeed feels cleaner.

And it works, but I need to use System.setProperty("javax.net.ssl.trustStore", "${rootDir}/../gradle/truststore.jks") rather than System.setProperty("javax.net.ssl.trustStore", "${projectDir}/../gradle/truststore.jks"), because $projectDir isn’t accessible at this stage.

1 Like