using gradle plugin from flatDir source - java

How to amend Gradle plugins {} management repository for custom plugins? is not duplicated in this post, because it does not cover use of flatDir.
Question
How do I use a Gradle plugin defined in a local JAR, using the new plugin {} semantics, instead of the deprecated apply() semantics?
Current Status
Not having any resolution, after posting the question and searching at considerable length, I filed an issue, wondering whether this use, which ought to be common and straightforward, is unsupported, either by design or oversight, within Gradle's revised plugin semantics.
Unfortunately, my report was closed, with no useful information provided.
I requested clarification in a new issue, but am still waiting.
I am frustrated, having expected that the community would be interested in at least discussing this problem.
If you can contribute information, please do so.
First Update
Following the clarification about the new style for configuring plugin sources, I updated my settings.gradle file to open with the following block. However, I regret that I see no improvement by this change alone. (For the plugin id field referenced in the build.gradle file, I have tried both the global ID published in the JAR metadata, and the basename of the JAR fie. Both fail equally.)
pluginManagement {
repositories {
gradlePluginPortal()
jcenter()
flatDir {
dirs 'lib`'
}
}
}
The documentation explains how to use custom repositories, but appears to overlook the case of a trivial flat directory.
Second Update
I get some improvement if I add a version number to the JAR file and to the corresponding statement in the plugins {} block. In this case, the message becomes:
Plugin [id: 'plugin-id', version: '1.0.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 'plugin-id:plugin-id.gradle.plugin:1.0.0')
Searched in the following repositories:
Gradle Central Plugin Repository
BintrayJCenter
flatDir(/absolute/path/to/lib)
In this case, the directory is added to the list of sources searched.
It is strange that the .gradle.plugin suffix is being appended to my ID in the printed artifact. It is also strange that adding the version number to what is being searched for affects the list of places being searched.
So my project still cannot build. I appreciate any further help.
Original Background
I placed a JAR file containing a custom plugin definition in the lib directory of a project. With the build.gradle build file as below, the build runs successfully.
buildscript {
repositories {
flatDir {
dirs 'lib'
}
}
}
apply plugin: 'plugin-id'
However, the apply() semantics are deprecated, favoring a plugins {} block, so I tried updating the build file as below.
plugins {
id 'plugin-id'
}
repositories {
flatDir {
dirs 'lib'
}
}
I understand that the plugins {} contents can draw from the repositories {} definitions.
However, the change creates a failure:
* What went wrong:
Plugin [id: 'plugin-id'] was not found in any of the following sources:
- Gradle Core Plugins (plugin is not in 'org.gradle' namespace)
- Plugin Repositories (plugin dependency must include a version number for this source)
Keeping the plugin {} block but moving the repositories {} block back into a leading buildscript {} block does not resolve the error. That is, the error persists even if I revert to the earlier version only replacing the apply() statement with the plugin {} block.
Finally, it has no effect to add to the repositories {} block a dependencies { classpath: ':jarname' } block, which some sources suggest is necessary, though I don't know why it would be.

This works. Tested with gradle 6.3.
build.gradle:
plugins {
id 'plugin-id'
}
settings.gradle:
pluginManagement {
buildscript {
repositories {
flatDir {
dirs '/plugin-folder/build/libs'
}
}
dependencies {
classpath ':plugin-jar:0.0.1'
}
}
}
Update: I just found out today that it is possible to have your plugin jar resolved without using the dependencies block above. In that case you should name your plugin jar as [plugin-id].gradle.plugin[-version].jar. Note that the [-version] part is optional and plugin-id.gradle.plugin.jar will also work.
NB: Flat dir repositories are discouraged and local maven repo folder should be used instead. Especially in the case when you want to override locally an artifact which exists on a remote repo. See https://docs.gradle.org/current/userguide/declaring_repositories.html#sub:flat_dir_resolver. It seems impossible to fully move away from maven in favour of gradle, considering that installing local artifacts in a maven repo folder is not supported by gradle itself.

Related

Gradle maven publish plugin fails in a multi-module project with error "Artifact wasn't produced by this build"

I have a multi-module project which supports maven and gradle builds hence it contains pom.xml files along side with build.gradle. I'm working on a demo and I would like to show how to build and deploy to nexus the same project using either gradle or maven. That's why I have two different build systems in case you wonder why.
You may see the project structure below.
You may look into the code here.
I've configured the gradle maven-publish plugin in order to publish all modules to my local nexus repository however when I run gradle publish I hit this error:
Execution failed for task ':publishMavenJavaPublicationToMavenRepository'.
> Failed to publish publication 'mavenJava' to repository 'maven'
> Artifact machinery-config-0.0.1.jar wasn't produced by this build.
The issue is related with having the publishing section within $rootDir/build.gradle.
It's confusing maven-publish somehow which is trying to publish an artifact that doesn't exist machinery-config-0.0.1.jar, machinery-config is the name of the rootProject.
One workaround could be to remove the publishing section from the rootProject and duplicate it in the sub-projects. I don't like that approach cuz I will end up with a lot of duplicated code.
Could you point me out a better way to use maven-publish within a multi-module project ?
After some digging I realized that I had two issues:
publishing section was outside of subprojects section, then gradle tried to deploy an artifact using rootProject.name ignoring the included modules.
group & version properties were outside subprojects therefore deployed artifacts had undefined as version number, e.g machinery-config-core-undefined.jar
In order to fix issue number two I had moved group & version into subprojects section.
My build also produces a BOM artifact hence I need two publications from components.java and from components.javaPlatform, so I wrote this script gradle/ext/publish-common.gradle which exports two functions I will use later on both publications to keep code duplication at bay.
def pom(it) {
it.licenses {
license {
name = 'The Apache License, Version 2.0'
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
it.developers {
developer {
id = 'eljaiek'
name = 'Eduardo Eljaiek'
email = 'eduardo.eljaiek#gmail.com'
}
}
it.scm {
connection = 'scm:git:git://github.com/eljaiek/machinery-config.git'
developerConnection = 'scm:git:git#github.com:eljaiek/machinery-config.git'
url = 'https://github.com/eljaiek/machinery-config'
}
}
def nexusRepository(it) {
it.url = version.endsWith('SNAPSHOT') ? project.nexusSnapshotsUrl : project.nexusReleasesUrl
it.credentials {
username project.nexusUser
password project.nexusPasswd
}
}
ext {
pom = this.&pom
nexusRepository = this.&nexusRepository
}
I had added from components.javaPlatform publication into machinery-config-dependencies/build.gradle in order to deploy the BOM artifact
apply plugin: 'maven-publish'
apply from: "$rootDir/gradle/ext/publish-common.gradle"
publishing {
publications {
mavenBom(MavenPublication) {
from components.javaPlatform
pom { x -> pom(x)}
}
}
repositories {
maven { x -> nexusRepository(x) }
}
}
apply from: "$rootDir/gradle/ext/publish-common.gradle" will aplly the script I wrote, this is required in order to import pom() and nexusRepository() functions into my build script.
To deploy from components.java artifacts I had added a publishing section in subprojects under if (it.name != 'machinery-config-dependencies') statement into $rootDir/build.gradle
apply plugin: 'ru.vyarus.pom'
apply from: "$rootDir/gradle/ext/publish-common.gradle"
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
pom { x -> pom(x)}
}
}
repositories {
maven { x -> nexusRepository(x) }
}
}
I had used Gradle POM plugin instead of maven-publish. It provides maven's dependencies declaration simplicity and implicitly applies maven-publish plugin.
See the code here
References
Extract common methods from Gradle build script
The Java Platform Plugin

Gradle dependency platform in parent module

I have a gradle project with a lot of subprojects and I want a BOM file to apply to all the subprojects.
I tried to put this in some subproject and it works fine:
dependencies{
implementation enforcedPlatform('group:bom-artifact:version')
}
But when I put it a parent gradle.build, or wrap it like:
allprojects {
dependencies {
implementation enforcedPlatform('group:bom-artifact:version')
}
}
It ends with error:
> Could not find method implementation() for arguments [DefaultExternalModuleDependency{group='group', name='bom-artifact', version='version', configuration='default'}] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
Can't figure out what's wrong. How to fix this? Or is there a better way to apply one BOM to all subprojects and manage it from one place?
I don't think the issue is the platform itself here
The message you're getting usually appears if you have not (yet) applied the Java plugin.
Gradle's configuration scopes like implementation, api and compileOnly are initialized as part of the Java plugin's init phase.
So depending on the structure of your subproject you might have one or more subprojects that don't use the Java plugin that does not recorgnize the scope. I'm not quite sure about the execution order between subprojects, this might play also play a role.
A simple solution would be to apply the plugin also into the allprojects closure, like
allprojects {
apply plugin: 'java'
dependencies {
implementation enforcedPlatform('group:bom-artifact:version')
}
}

MissingPropertyException for Gradle Plugin - Cannot find task type

I am currently in the process of re-organizing and re-structuring some of the projects we use at work.
One of my goals is to integrate a project's unit tests correctly. I have upgraded the root projects Gradle to the latest version (5.6.2) and I have made all the necessary DSL changes.
Right now I'm in the process of including the project's integration tests under its source code. For this I created a new subproject.
So far so good but when I attempt to build the project it fails with following exception:
Caused by: groovy.lang.MissingPropertyException: Could not get unknown property 'StartServerTask' for project ':integration-tests' of type org.gradle.api.Project.
at org.gradle.internal.metaobject.AbstractDynamicObject.getMissingProperty(AbstractDynamicObject.java:84)
at org.gradle.groovy.scripts.BasicScript$ScriptDynamicObject.getMissingProperty(BasicScript.java:156)
at org.gradle.internal.metaobject.AbstractDynamicObject.getProperty(AbstractDynamicObject.java:61)
at org.gradle.groovy.scripts.BasicScript.getProperty(BasicScript.java:65)
Now, the task in question comes for a Gradle plugin a colleague created in the past. Said plugin is fetched from a maven repository as a dependency like so:
buildscript {
repositories {
maven { url 'maven_link' }
}
dependencies {
classpath 'fts.gradle:start-server:0.3'
}
}
plugins {
id 'java'
id 'application'
id 'eclipse'
}
And applied like
apply plugin: 'fts.gradle'
I have tried almost everything, even changing the package structure of the plugin, but I am unable to include it properly in the build file.
If I copy paste the code directly within the project's build.gradle everything works fine but it doesn't so if I try to remote fetch and include the plugin.
Can anyone provide any insight to this?

How to amend Gradle plugins {} management repository for custom plugins?

My company proxy/firewall settings are blocking jcenter and mavencentral etc, therefore, I can't get Gradle custom plugins from GitHub.
I'm using gradle 4.7 and still using that old way of getting plugins with buildscript{} - which is Gradle 1.x. I would like to use plugins{} and just put id's inside that block but I can't because of the default repository is trying to fetch it from.
Is there a way to amend plugins repo? Maybe in init.gradle or a cmd arg?
Or maybe just add another one to look at. I found a few links but those already expired and my last resort would be just to check the source code. I hope there is a simple answer to this.
Gradle 2.1 and higher want to use this
plugins {
id "de.undercouch.download" version "3.4.3"
}
Gradle 1.x and 2.0 using this at the moment
buildscript {
repositories {
mynexusrepo()
}
dependencies {
classpath 'de.undercouch:gradle-download-task:3.4.3'
}
}
apply plugin: 'de.undercouch.download'
I found a working solution. It changed a few times already but for the 4.7 version of Gradle, this looks like a working solution.
Remember that some of the plugins need to be in GString "" !
This need to be in settings.gradle as the first block to work.
pluginManagement {
repositories {
maven { url "http://cdlnexus01:8081/nexus/content/groups/GradlePlugins/" }
maven { url "http://cdlnexus01:8081/nexus/content/groups/public/" }
maven { url "https://plugins.gradle.org/m2/" }
}
}

Gradle won't resolve dependency (Maven will)

My project has dependencies configured through gradle. I would like to add the following dependency:
compile group: 'org.restlet.jse', name: 'org.restlet.ext.apispark', version: '2.3.1'
Which can be found in the following repository (which I have added to my build.gradle):
maven {
url "http://maven.restlet.org"
}
However when I do that I get the following error:
Could not find org.restlet.jse:org.restlet.lib.swagger-models:1.5.0-SNAPSHOT.
http://maven.restlet.org/org/restlet/jse/org.restlet.lib.swagger-models/1.5.0-SNAPSHOT/maven-metadata.xml
http://maven.restlet.org/org/restlet/jse/org.restlet.lib.swagger-models/1.5.0-SNAPSHOT/org.restlet.lib.swagger-models-1.5.0-null-null.pom
http://maven.restlet.org/org/restlet/jse/org.restlet.lib.swagger-models/1.5.0-SNAPSHOT/org.restlet.lib.swagger-models-1.5.0-null-null.jar
Required by: org.restlet.jse:org.restlet.ext.apispark:2.3.1
I can see that the jar is in fact in the repository however Gradle is not looking for it in the right location for reasons unknown to me. Why is it not using the version in the filename but rather 1.5.0-null-null.
I have made a made a Maven project with the same dependency defined in the pom.xml which works.
Link to working pom.xml that has same dependency
How can this issue be resolved? I'm at this point also interesting in more manual solutions :) Thank you.
Diagnosis
It seems to be related to snapshot "uniqueness". For information on Maven repositories, snapshots artifacts can be deployed "unique" or "non-unique".
Unique snapshots: Each time you deploy a snapshot, it is tagged with a timestamp and a buildNumber, these timestamp and buildNumber are written in the maven-metadata.xml file and they are appended to its name that ends up like: artifactName-version-timestamp-buildNumber.jar.
Non-unique snapshots: Each time you deploy a snapshot it overwrites the previous version, his name ends up like: artifactName-version.jar.
It is recommended to use unique snapshot as one can refer precisely to one version of the artifact if needed.
The problem is that "http://maven.restlet.org" seems to use non-unique snapshots and sadly, gradle seems to have problems to deal with non-unique snapshots: https://issues.gradle.org/browse/GRADLE-3164.
If you look at http://maven.restlet.com/org/restlet/jse/org.restlet.lib.org.restlet.lib.swagger-models/1.5.0-SNAPSHOT/maven-metadata.xml you can clearly see null in timestamp and buildNumber tags:
<metadata>
[...]
<versioning>
<snapshot>
<timestamp>null</timestamp>
<buildNumber>null</buildNumber>
</snapshot>
<lastUpdated>null</lastUpdated>
</versioning>
</metadata>
I think that's where the "null-null" comes from.
Solution 1 - flatDir
To deal with it you can manually download the artifact, put it in a directory, for example "lib" and create a flatDir repository:
repositories {
[...]
flatDir {
dirs 'lib'
}
[...]
}
It's not an ideal solution, but it works.
Solution 2 - jcenter repository
Suggested by Opal
Add the jcenter repository that contains your missing dependency and that Gradle handles well.
Since Gradle 1.7 you can simply define it with:
repositories {
[...]
jcenter()
[...]
}
It seems that you need other repositories to download all the dependencies. Probably maven handle this transparently. The following script downloads all dependencies successfully when cp task is run:
apply plugin: 'java'
configurations {
lol
}
repositories {
jcenter()
mavenCentral()
maven {
url "http://maven.restlet.org"
}
maven {
url "https://repository.mulesoft.org/nexus/content/repositories/public/"
}
}
dependencies {
lol group: 'org.restlet.jse', name: 'org.restlet.ext.apispark', version: '2.3.1'
}
task cp(type: Copy) {
from configurations.lol
into 'deps'
}

Categories