Gradle manage plugins on generated POM using maven plugin - maven

I'm on a team where maven and gradle is used, and I have a gradle project that wants to generate a functioning pom file so that our maven users can keep using maven.
I have solved this problem so far as generating a pom with appropriate dependencies as follows:
build.gradle excerpt:
task createpom(dependsOn: 'build') << {
pom {
project {
groupId project.group
artifactId project.name
version project.version
}
}.writeTo("pom.xml")
}
build.finalizedBy(createpom)
This works well for creating just the dependencies on a pom, but gradle's maven plugin API does not seem to support defining the contents of the <build> tag, which I need to import certain plugins for a successful maven build.
In short, I need one of the following:
Postprocessing the build tag into the generated POM. I could do it by manipulating the file directly, but prefer not to.
Splitting the POM into two parts, one with only gradle managed dependencies, and one with only the human managed things. Unfortunately, I don't see any means of arbitrarily naming a pom dependency by file name; only solutions that involve adding a pom only project or using multi-module builds, neither of which I like considering that I have no need for a shareable parent pom or multi-module project. I would much prefer something akin to <import>my/arbitrary/path/buildstuff.xml</import>, since all a really need to do is glue two halves of a POM for the same project/lifecycle together.
Is there a better way of accomplishing this other than what I've found so far?

I went with the XML tweaking solution, which proved to be far more elegant than I anticipated. Implementation involved adding an unmanaged pom to my project directory to hold the human-managed parts of the build, and modifying my createpom task as such:
task createpom(dependsOn: 'build') << {
pom {
project {
groupId project.group
artifactId project.name
version project.version
}
}.withXml {
def templateXml = (new XmlParser()).parse('pom-unmanaged.xml')
asNode().append(templateXml.build)
}.writeTo("pom.xml")
}
pom-unmanaged.xml takes the form of a typical pom, minus the bits that my gradle build script generates.

Related

Gradle: How do you include your own library as part of build?

I have a commons gradle project which is a shared library for all my other projects.
In the build.gradle of dependent project, I included the commons jar as following:
dependencies {
...
runtime files('../commons/build/libs/commons-1.0.jar')
}
And this builds fine with the relative path. But this feels like hard-coding a specific library. What is the standard way to achieve the builds in this case?
You can publish the common jar to Your local maven repository. But If You are developing with in a team, You should publish to a repository manager where other parties have also access to.
And in the dependent projects You simply add this common jar, like You are adding a third party library. With this way You don't have to store dependent jar files on Your version control system. When projects are developed by different parties, this way would be more convenient.
Example of using mavenlocal
// Common project build.gradle
apply plugin: 'maven-publish'
version = '2.0'
...
publishing {
publications {
maven(MavenPublication) {
groupId = 'com.gradle.sample'
artifactId = 'project1-sample'
from components.java
}
}
}
You can use gradle publishToMavenLocal to publish common project to mavenlocal. (Dependent projects can not use the new versions of common jar, unless You publish it to mavenlocal in this case)
// Dependent project build.gradle
repositories {
mavenLocal()
}
dependencies {
implementation 'com.gradle.sample:project1-sample:2.0'
....
}
Check the following link for details.
https://docs.gradle.org/current/userguide/publishing_maven.html

Publish reusable gradle tasks

I would like to publish some common parts of build.gradle file to be reusable in different projects (using apply from: url_to_file construction). To achieve this I've created a project called gradle-common that contains those common build files, with this build.gradle file:
group 'org.example'
version '0.1.0'
apply plugin: 'maven-publish'
publishing {
publications {
mavenJava(MavenPublication) {
artifact source: file('files/first.gradle'), classifier: 'first'
}
mavenJava(MavenPublication) {
artifact source: file('files/second.gradle'), classifier: 'second'
}
}
repositories {
mavenLocal()
}
}
Files after publishing in maven repository there are files like:
gradle-common-0.1.0-first.gradle
gradle-common-0.1.0-second.gradle
And my question is: how can I remove version number from published artifacts and the classfier? For me ideal files would be:
first.gradle
second.gradle
There are many different answers to your question, but I think you are trying to create something that a plugin usually does without creating a plugin.
The best way to add functionality to multiple gradle projects is to create a plugin. You can also leverage Rules which this simple tutorial doesn't show, but you can inspect some of the gradle native plugins, such as maven-publish.
To answer your question, it is not possible to publish an artifact to a maven repository without a version. You have to download it with a version (you can use my-artifact:1+ to download the latest) and then strip the version yourself.
I am also wondering how are you planning to include these files to your specific gradle files. You won't be able to use them as dependencies, since the dependency resolution happens after the scripts are read. If you are downloading them somehow before the script runs, then you probably don't need a maven repository for that.

Gradle include jar produced by another project in war

Currently I have two projects with gradle build.gradle. The first is going to create a fat jar file, which I would like to include in a war file. I thought compiling it would be enough, but it doesn't seem to be ending up in the /lib directory of my war file. Anyone have thoughts I am quite new to gradle.
dependencies {
compile project(':JarProject')
providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
providedCompile 'org.apache.tomcat:tomcat-jsp-api:7.0.55'
}
war {
archiveName 'WarProject.war'
from 'JarProject/build/libs'
webXml = file('src/web.xml')
}
Does the second project war need to be in providedRuntime? Or should I publish the jar from the other project in the local maven repo and include it that way?
The War task essentially behaves like a CopyTask with regards to stuff it packs in the war, so the documentation on working with files is useful. In essence, I think you need something like (untested):
from fileTree('JarProject/build/libs') {
into("lib")
}
That being said, using mavenLocal() and publishing there also works, but it can lead to unexpected results when the war includes some old version from local, picking up the jar explicitly from the file system like above is better.
I think the elegant solution would be to use multi project builds and project level dependencies. You would have the two builds as separate projects of the same Gradle build and add the "jar project" as a regular compile dependency.
How have you declared the dependency? I assume you have a multi-project build with subprojects A and B, both using the War plugin. I made an experiment using Gradle 2.4 and if I declare B/build.gradle like this:
apply plugin: 'war'
dependencies {
compile project(':A')
}
then B.war contains WEB-INF/lib/A.jar. If you correctly follow conventions of Gradle War plugin (place web resources in A/src/main/webapp/ and code-related resources in A/src/main/resources/), then A.jar should contain what you want.
see this

How can I get gradle to populate jars with dependency metadata?

So if I build a jar in Maven, say for example jackson-core-2.5.1.jar, I find the following in the artifact:
META-INF/maven/
META-INF/maven/com.fasterxml.jackson.core/
META-INF/maven/com.fasterxml.jackson.core/jackson-core/
META-INF/maven/com.fasterxml.jackson.core/jackson-core/pom.properties
META-INF/maven/com.fasterxml.jackson.core/jackson-core/pom.xml
Gradle, however, does not seem to create this data. Problem is that we have several components of our build, including a parent project, that aren't hosted in the same SCM location. For our large and complex build, how would Gradle know that a locally built artifact in one SCM location depends on a locally built artifact in another, if there's no metadata? What is the Gradle way to manage this situation?
Repositories contain a separate copy of pom.xml. It usually lives next to the JAR file in the physical structure on the disk. This applies to binary repositories like Nexus or Artifatory and also to your local Maven repository (under $HOME/.m2/repo).
If for some reason you want to copy the behavior of Maven you can tell Gradle to do create those files. We use this customization in subprojects closure that configures our multi-project Gradle build.
jar {
// until we have better solution
// https://discuss.gradle.org/t/jar-task-does-not-see-dependency-when-using-maven-publish/11091
if (project.tasks.findByName('generatePomFileForMavenJavaPublication')) {
dependsOn 'generatePomFileForMavenJavaPublication'
} else {
project.tasks.whenTaskAdded { addedTask ->
if (addedTask.name == 'generatePomFileForMavenJavaPublication') {
project.tasks.jar.dependsOn 'generatePomFileForMavenJavaPublication'
}
}
}
into("META-INF/maven/$project.group/$project.archivesBaseName") {
/*
from generatePomFileForMavenJavaPublication
*/
from new File(project.buildDir, 'publications/mavenJava')
rename ".*", "pom.xml"
}
}
It would be simpler if there wasn't a problem with generatePomFileForMavenJavaPublication task being created lazily sometimes. And you need to check how to create your properties file. I guess you can dump properties from a running Gradle process there.

Gradle/Maven project fork provides original artifact (only download fork)

Description
I have forked another project and uploaded it to my own maven repository. The dependency graph, however, pulls the original project too, meaning I two versions of the projects. The compilation works fine in command-line but not in eclipse as it reads the original project's jar first and then skips my forked project.
Dependency graph
+--- com.spiddekauga.gdx:gdx-spiddekauga (fork)
+--- com.badlogicgames.gdx:gdx-box2d
| \--- com.badlogicgames.gdx:gdx (original)
What I've tried
First I tried using the original name of com.badlogicgames.gdx:gdx but the project was downloaded from the original maven repository instead of mine even if my maven repository is listed before.
build.gradle
allprojects {
...
repositories {
maven { url "http://maven.MY-DOMAIN.org/" }
mavenCentral()
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
maven { url "https://oss.sonatype.org/content/repositories/releases/" }
}
...
}
Another thing I've search for is to make com.spiddekauga.gdx:gdx-spiddekauga provide com.badlogicgames.gdx:gdx so that it doesn't have to be downloaded, but I haven't found a way to do this in neither in gradle or maven.
Questions
How can I solve so that only my forked project is pulled? Either by a) renaming to com.badlogicgames.gdx:gdx so it searches my maven repository first; or b) by excluding the dependency com.badlogicgames.gdx:gdx.
[minor question] Is it possible to set that a maven project provides another artifact? E.g. like this:
pom.xml
<project>
<groupId>com.spiddekauga.gdx</groupId>
<artifactId>gdx-spiddekauga</artifactId>
<provides>
<project>
<groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx</gdx>
</project>
</provides>
</project>
Forking the project does not change the project coordinates (groupId, projectId and version) in the pomor gradle files. You would need to search and replace all of them for it to work.
Also the dependencies that you are referring to are available in mavenCentral, which is the first in the repositories list.

Resources