Naming deployed jar file with gradle publish? - maven

We're looking at ditching artifactory and are intending to move to reposilite, because artifactory is just too big and maintenance-heavy for our small team.
However, when using gradle publish to deploy to reposilite, I am unable to get control of the name of the actual jar. The pushed jar is always named project-x.x.x-{build-number}.jar.
I would like to do it the way the artifactory plugin did it, which deployed a properly named snapshot jar (just project-x.x.x-SNAPSHOT.jar), letting subsequent snapshots of the same version overwrite each other, which is a more convenient arrangement for us for several reasons that I won't go into right now.
Long story short, is there any way I can tell gradle publish how to name the deployed jar exactly? Our usual setup currently looks like this:
configure<PublishingExtension> {
publications {
create<MavenPublication>("myproject") {
from(components["java"])
groupId = "our.company.myproject"
artifactId = "myproject"
artifact(sourceJar)
}
}
repositories {
maven {
credentials {
username = $mavenUser
password = $mavenPassword
}
url = uri("http://localhost:8080/snapshots") # while testing
authentication {
create<BasicAuthentication>("basic")
}
}
}
}
There isn't really a problem with that configuration. It works. All I want to do is control the exact name of the jar file being deployed in addition to what I'm doing here, and I can't find a way to do it. The jar that is put to the build/libs directory is named properly, it's just the publication throwing me a curve ball.

Related

How to create multi project fat jar as bundle of some libraries with buildSrc

First of all, sorry for my poor english.
Goal
I want create multi project containing some custom libraries as subproject with gradle.
For centralized dependency version control, using buildSrc and setting versions (spring-boot, detekt, ktlint etc.)
my-core-project(root)
+buildSrc
+-src/main/kotlin
+--int-test-convention.gradle.kts
+--library-convention.gradle.kts
+library-A
+-src
+--main/kotlin
+--test/kotlin
+-build.gradle.kts
+library-B
+-src
+--main/kotlin
+--test/kotlin
+-build.gradle.kts
+build.gradle.kts
+setting.gradle.kts
buildSrc contains common tasks for libraries(integration test, detekt, etc.)
library-A and library-B are custom libraries based on spring boot.
There is no application module or any main method.
my goal is using method of library-A and/or library-B with another separated project with adding my-core-project to dependency.
Problem
./gradlew build created 3 jar files
my-core-project
+build/libs
+-my-core-project.jar
+library-A
+-build/libs
+--library-A.jar
+library-B
+-build/libs
+--library-B.jar
copied 3 jar files to libs directory under project which actually using these library,
tried adding dependency created jar
with implementation(files("libs/library-A.jar")), class and methods are resolved well.
but with implementation(files("libs/my-core-project.jar")),
class and methods are not unresolved.
when check my-core-project.jar, recognized that any information of sub projects contained.
Here is my setting.gradle.kts and build.gradle.kts of root directory.
# setting.gradle.kts
pluginManagement {
repositories {
mavenCentral()
gradlePluginPortal()
}
}
rootProject.name = "my-core-project"
include(
"library-A",
"library-B"
)
# build.gradle.kts
plugins {
id("java-library")
id("io.spring.dependency-management")
}
group = "com.demo"
version = "0.0.1-SNAPSHOT"
dependencies {
api(project(":library-A"))
api(project(":library-B"))
}
repositories {
mavenCentral()
}
Tried things
In my opinion, my-core-project.jar should be fatJar(uberJar),
so i added FatJar task like this
val fatJar = task("fatJar", type = Jar::class) {
archiveBaseName.set("${project.name}-fat")
from(configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) })
with(tasks.jar.get() as CopySpec)
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
tasks {
"build" {
dependsOn(fatJar)
}
}
but cannot resolve class and method,
additionally occurs version conflict with other dependency of projects using this package, due to library-A created as fatJar too.
Question
Is there a simple way packaging/bundling sub-modules into one jar file?
if there are tasks like this already in gradle, prefer to use that.
Modifying fatJar task like "add jar of submodules, not contained dependencies" can solve this problem?(even couldn't try completely newbie to gradle and kts.)
if so, can you show me how to modify task?
tried shadowJar already. that solved version-conflict problem with relocate option. but still couldn't resolve package in library-A
If structure has problem, is there a good practice/example for "bundle of library"?
thanks for reading.
TL;DR
If someone faced this problem, try set archive name shorter than current one.
For someone who faced same problem, sharing some informations.
as result, resolved this problem.(maybe even not problem)
current shadowJar configure is as following
tasks.named<ShadowJar>("shadowJar").configure {
archiveBaseName.set("shorten-name")
archiveClassifier.set("")
exclude("**/*.kotlin_metadata")
exclude("**/*.kotlin_builtins")
}
exclude kotlin_metadata, kotlin_builtins
set shorten name(original project name was 30 long characters)
I have no idea but shorten jar file name has no problem.
Interesting one is, upload in artifactory package with original(long) name worked well.
I don't know Gradle declaring dependency with files has length constraints.
implementation(files("path/to/package"))
And now it works well with original name with local jar package file.

How can I add/change a Maven publishing repository in a Gradle init script

I'd like an init script that lets me take arbitrary Gradle projects and change the Maven repository location that they publish artifacts to.
Adding a repository is easy enough when you edit the build file directly, just add a maven{} block inside publishing { repositories { } }. However, trying to do this generically leads to frustration and failure. I tried this:
allprojects {
beforeEvaluate {
pluginManager.withPlugin("maven-publish") {
extensions.getByType<PublishingExtension>().publications {
repositories {
maven {
url = uri("file:///my/path")
name = "myrepo"
}
}
}
}
}
}
but, no luck. No such repository appears. I suspect there is a timing issue here: although my code does run, it presumably runs after the publishing plugin has created these tasks. What I want to do is register a callback that is run before the publish plugin gets a chance to do that, but I don't know how.

Missing checksum files when using Gradle maven-publish and signing plugins

I have a Java project that makes use of Gradle to build and package. My purpose is to create artifacts that are published to Maven Central.
As a first step, I configured my Gradle project as shown in the following example from the documentation:
https://docs.gradle.org/current/userguide/publishing_maven.html#publishing_maven:complete_example
When I run gradle publishToMavenLocal, I get the following files installed in my local repository:
maven-metadata-local.xml
my-library-1.0.2-SNAPSHOT.jar
my-library-1.0.2-SNAPSHOT.jar.asc
my-library-1.0.2-SNAPSHOT-javadoc.jar
my-library-1.0.2-SNAPSHOT-javadoc.jar.asc
my-library-1.0.2-SNAPSHOT.pom
my-library-1.0.2-SNAPSHOT.pom.asc
my-library-1.0.2-SNAPSHOT-sources.jar
my-library-1.0.2-SNAPSHOT-sources.jar.asc
The files are all OK. The only issue I have is that checksum files (md5 and sha1) are not generated. However, checksum files are a requirement to have artifacts deployed on Maven Central via OSS Sonatype.
How can I generate the missing checksum files? It seems the maven-publish or signing plugins do not have an option for this purpose? what is wrong?
The solution I found was to use shadow along with ant.checksum:
tasks.withType(Jar) { task ->
task.doLast {
ant.checksum algorithm: 'md5', file: it.archivePath
ant.checksum algorithm: 'sha1', file: it.archivePath
ant.checksum algorithm: 'sha-256', file: it.archivePath, fileext: '.sha256'
ant.checksum algorithm: 'sha-512', file: it.archivePath, fileext: '.sha512'
}
}
Invoking gradle publishShadowPublicationToMavenLocal will generate the signatures as needed, although won't publish them to ~/.m2.
At first I thought those signatures should have been automatic, so I opened https://github.com/johnrengelman/shadow/issues/718 to discuss.
I thought this was a bug in Gradle and I opened an issue, but as described here this actually mimics mvn install behavior. It sounds like Maven Local works a little different than a Maven Repository.
The proper way to test this locally is to use a file based repository. Since you're only using it to test (and not to actually share things with other projects) I think putting that into the build directory is best. Add the repositories section from below to the publishing block. Then when you ./gradlew publish it will publish to your build directory.
Kotlin
repositories {
maven {
// change URLs to point to your repos, e.g. http://my.org/repo
val releasesRepoUrl = uri(layout.buildDirectory.dir("repos/releases"))
val snapshotsRepoUrl = uri(layout.buildDirectory.dir("repos/snapshots"))
url = if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl
}
}
Groovy
repositories {
maven {
// change URLs to point to your repos, e.g. http://my.org/repo
def releasesRepoUrl = layout.buildDirectory.dir('repos/releases')
def snapshotsRepoUrl = layout.buildDirectory.dir('repos/snapshots')
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
}
}
These two samples are actually from the link you shared. It's possible they were added later or you (like me) thought that publishToMavenLocal should behave the same as publish (apart from where the files actually go).

ivy module.xml doesn't contain all artifacts when gradle publish is used

I believe this may be related to publish artifact overwrite other artifact in Gradle
if I have a set of publications such as
publishing {
publications {
serverpub(IvyPublication) {
artifact(ejbJar) {
name 'ejb'
}
}
clientpub(IvyPublication) {
artifact(clientEjbJar) {
name 'client-ejb'
}
}
modulepub(IvyPublication) {
artifact(moduleJar) {
name 'cname-core'
}
}
persistpub(IvyPublication) {
artifact(persistenceJar) {
name 'core-entities'
}
}
}
}
After doing a 'publish' the
<Project Name>/ivy/<version>/ivy/ivy-<version>.xml
file only contains the first item in the list of publications
<artifact name="ejb" type="jar" ext="jar"/>
If I make all of the artifacts fall under a single publication ie. serverpub then the ivy.xml file will contain all of the correct artifacts but the jar files themselves are all identical thus I have the same error as the previous link.
Am I doing something wrong because so far Gradle has proved a pain in the parenthesis for publishing artifacts.
You have declared four independent publications, each of which will produce its own module descriptor. To produce an Ivy module containing multiple artifacts, you'll have to list them under the same publication. Regarding the "Jar files are identical" problem, a minimal self-contained reproducible example would help.
Note that the new ivy-publish plugin that you are using is still incubating and may have shortcomings. We are grateful for feedback to make it better. The best place to reach Gradle developers and experts is http://forums.gradle.org.

In gradle, how can I generate the ivy.xml and pom.xml files?

Currently, our gradle setup is geared to publish to certain maven repositories when a build is done. For a particular customer, I need to zip up the jars, license files, pom.xml, and ivy.xml files, and send it all in a zip. To do this, I just need to define an alternate location to publish it to. All the documentation on the gradle site seems aimed at writing one set of publishing rules, not an alternative set.
I was hoping to simply write a different task which would focus on building this customer-specific zip file. So far, I have it collecting all the jars (which includes source and runnable code) along with the license and notice file. But I haven't cracked the nut on defining a local ivy repository and a local maven repository that is only part of this alt task.
task alt {
dependsOn subprojects*.tasks*.matching { task -> task.name == 'assemble' }
subprojects.each{project ->
if (project.hasProperty('sourceJar')) {
evaluationDependsOn(project.name)
}
}
File altDir = mkdir("$buildDir/alt")
subprojects.each { project ->
if (project.hasProperty('sourceJar')) {
// Extra the module name from the path of the sub-project
String submodule = project.projectDir.absolutePath.split(File.separator).last()
File subfolder = mkdir(altDir.absolutePath + "/${project.group}/${group}.${submodule}/$version")
project.tasks.withType(Jar).each {archiveTask ->
copy {
from archiveTask.archivePath
from("$rootDir") {
include 'license.txt'
include 'notice.txt'
}
into subfolder
}
}
}
}
}
Here's the gradle docs that tells you how to generate the pom. Also if you are looking to install that file to your local repository you could use the mechanism described in this blog entry . Essentially all you have to do
configure(install.repositories.mavenInstaller) {
pom.project {
version '1.0'
artifactId 'your.artifact.id'
groupId 'your.group.id'
}
}
It doesn't look like it possible at the moment to generate the ivy.xml through gradle, but once you have your pom file you could use ivy itself to generate the ivy file described here.
Section 64.5 of http://www.gradle.org/docs/current/userguide/publishing_ivy.html covers "Generating the Ivy module descriptor file without publishing".
The documentation is a little broken (eg inconsistent naming conventions). The following works for me:
apply plugin: 'ivy-publish'
publishing {
publications {
aoeu(IvyPublication)
}
}
This will generate a target generateDescriptorFileForAoeuPublication.

Resources