Can I Publish Multiple Files To Nexus From Gradle In One Go? - gradle

I am using a closed source vendor application that occasionally sends me updates of jars in a zip file.
I want to refer to the zip in the Gradle build, unzip it and publish all the jars within it to my Nexus repo. I am assuming that they all have the same GroupId and that the name and version can be inferred from the file name itself.
Whilst testing out my script, I would rather not publish to Nexus and have to delete lots of test artifacts so I am using a flatDir repo for now.
So far I have this
apply plugin: 'maven'
configurations {
zipArchives
}
uploadResultArchives {
repositories {
mavenDeployer {
flatDir(dirs: 'mvn')
pom.groupId = 'com.stackoverflow.example'
}
}
}
artifacts{
zipArchives file: file('unzipdir/api-1.2.34.jar')
}
This suffers from multiple problems.
It requires me to manually add the files to the artifacts list
It creates a pom with dependencies from the rest of my project instead of a pom with no dependencies
I haven't parsed out the versionId yet
This solution looks like the versionId is going to be the same for all
Is there a better way to approach this?

Related

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.

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.

How can I easily convert between the groupId form of a library and its associated path in the local repository?

I am using gradle to install an Android AAR package (although, this could conceivably work with a JAR or any other artifact). I can install the artifact with ./gradlew install. This will install it to my local maven repository, by default ~/.m2/repository.
This works fine. Now, I need to create a new task that can work with the actual files of that repository. I can get all of the information I need, but I have the groupId in the form: com.somecompany.project, and I WANT it in the form: com/somecompany/project (since this is how it is stored in the local maven repository on the file system).
I know that I can just convert the . characters to ${file.separator}, but, given that maven has to do this operation internally, is there a quick method for doing this that's part of the maven plugin? I'm hoping to be able to do something like:
def groupDirStructure = maven.convertGroupToPath(project.group)
If you want to get at the file you should resolve it as a dependency rather than go searching for it on the file system.
repositories {
mavenLocal()
}
configurations {
local
}
dependencies {
local 'com.somecompany.project:module:1.0'
}
task copyArtifacts(type: Copy) {
from configurations.local
into "some/dir"
}

Gradle prefer repository on duplicate entries

I have a build tool thats tied the version to the SCM. I can't set the version of a jar when I build it locally. If someone were to change what I'm working on locally it would push the version number (which I can get), but when I publish to my local repo (Ivy) Gradle seems to prefer the external repo.
build.gradle
repositories {
mavenCentral()
ivy {
url "${System.properties['user.home']}/.ivy2/local/"
layout "pattern", {
artifact "[organization]/[module]/[revision]/[artifact](-[classifier]).[ext]"
ivy "[organization]/[module]/[revision]/ivy.xml"
}
}
ivy {
url "https://repo/"
layout "pattern", {
artifact myPattern
ivy myIvyPattern
}
}
}
Without changing the build for the jar that I'm editing. How can I have gradle always prefer the local repo? I have a feeling that resolutionStrategy might be the best way, but I don't know how accomplish this.
Edit 1
To help clarify, Artifactory has a jar (published by jenkins) with version 1.2.3. I have a jar that I build locally that saves into my local repository as 1.2.3. When I build a project having both repositories in my repository closure (with my local one on top) Gradle seems to pull in the one from Artifactory.
Edit 2
Dependency definition
dependencies {
compile ('company:project:1.2.+')
}
I don't really understand what you are saying, but Gradle searches repositories in their declared order, and picks the first matching module that it finds (as least as long as fixed versions are used).

Uploading multiple existing JARs to Maven repository with Gradle

I need to implement a Gradle task that will upload multiple existing JARs to the Maven repository.
The tricky part is that list of JARs is not known in advance. The way I want it to work is to dowload certain ".tar.gz" file first, untar it, then scan for JARs and upload them with some sort of naming convention (like use JAR names as artifactId's and version of the .tar.gz as version).
What would be the easiest way to do that with Gradle? Currently it is a simple bash script which searches for JARs and runs Maven deploy:deploy-file for each of them, but I need to incorporate that functionality in gradle build script.
Ideally, I need task like "deployJars" that would upload everything and depend on "downloadTarGz" task.
Update:
How about uploading POMs without any JAR attached to it? I need to generate several POMs that will depend on these dynamically detected JARs and upload them, too. "artifacts" requires me to specify file for upload.
To upload a jar via gradle you must declare that jar as a publish artifact and add it to a specific configuration using the artifacts closure:
apply plugin:'maven'
configurations{
allJars
}
artifacts{
allJars file("path/to/jarFile.jar")
}
now you can configure the dynamically created uploadAllJars task:
uploadAllJars {
repositories {
mavenDeployer {
repository(url: 'http://localhost:8081/artifactory/acme') {
authentication(userName: 'admin', password: 'password');
}
}
}
The problem is that you want to upload multiple artifacts. To achieve that you need some more dynamic in your build script. The dynamic creation of publishartifacts for all discovered jars can be wrapped in a task. In my example the discoverAllJars task simply looks in a specified folder for jar files. Here you need to implement your own logic to lookup the jars in your tgz archive.
group = "org.acme"
version = "1.0-SNAPSHOT"
task discoverAllJars{
ext.discoveredFiles = []
doLast{
file("jars").eachFile{file ->
if(file.name.endsWith("jar")){
println "found file ${file.name}"
discoveredFiles << file
artifacts{
allJars file
}
}
}
}
}
To be able to upload multiple artifacts within the uploadAllJars task you have to use pom filter. For details about pom filter have a look at the gradle userguide at http://www.gradle.org/docs/current/userguide/maven_plugin.html#uploading_to_maven_repositories
Since we moved the configuration of the published artifacts into the execution phase of gradle we must configure the uploadAllJars in the execution phase too. Therefore I'd create a configureUploadAllJars task. Note how we reference the jar files discovered by using 'discoverAllJars.discoveredFiles':
task configureUploadAllJars{
dependsOn discoverAllJars
doLast{
uploadAllJars {
repositories {
mavenDeployer {
repository(url: 'http://yourrepository/') {
authentication(userName: 'admin', password: 'password');
}
discoverAllJars.discoveredFiles.each{discoveredFile ->
def filterName = discoveredFile.name - ".jar"
addFilter(filterName) { artifact, file ->
file.name == discoveredFile.name
}
pom(filterName).artifactId = filterName
}
}
}
}
}
}
Now you just need to add a dependency between uploadAllJars and configureUploadAllJars:
uploadAllJars.dependsOn configureUploadAllJars
This example uses the same group and version for all discovered jar files and the jar name as artifactId. you can change this as you like using the pom filter mechanism.
hope that helped,
cheers,
René

Resources