Gradle script to move artifacts between Maven repos - repository

I'm working on a Gradle script to copy an artifact from one Maven repo to another. I was trying to hack it by putting the artifact as a dependency and then us setting that as an archive.
I've tried using the configuration.files() method but I haven't been able to build a dependency object that it will accept.
dependencies {
compile group: artGroup, name: artName, version: artVersion
}
artifacts {
archives configurations.default.files(
/* I have not been able to build an argument this method accepts */
)
}
uploadArchives {
repositories {
mavenDeployer {
repository(url: 'file:../../../repo')
}
}
}

We did this already in other environment (copying files from remote to local), and it looks like you got some misconceptions with Gradle DSL.
First the artifacts { archives {}} is used to ADD deployable artifacts to the archives configurations. You cannot use it (in term of doing something with the configurations files) in this block.
Second, you cannot upload what you resolved "as-is". Upload is for artifacts produced or manual added (they have a special type) by the build.
For us the solution was to create a new Gradle task "copyArtifacts" that actually copy all the files of resolved configuration into the local folder.
Hope this helps.

Related

Multi-project Gradle+Kotlin: How to create Jar containing all sub-projects using Kotlin DSL?

I have a Gradle project with two subprojects. The parent does not contain any code; all the Kotlin code is in the two subprojects. All Gradle build files are defined in the Kotlin DSL.
Upon building, Gradle generates two JAR files, one in the build subfolder of each subproject. I believe this is the intended default behavior of Gradle. But this is not what I want.
I want to publish the JAR file of the parent project as a Maven artifact. Therefore, I need both subprojects to be included in one JAR file. How can I achieve this?
Note: On this web page, the author seems to achieve pretty much what I would need in this code snippet:
apply plugin: "java"
subprojects.each { subproject -> evaluationDependsOn(subproject.path)}
task allJar(type: Jar, dependsOn: subprojects.jar) {
baseName = 'multiproject-test'
subprojects.each { subproject ->
from subproject.configurations.archives.allArtifacts.files.collect {
zipTree(it)
}
}
}
artifacts {
archives allJar
}
However, this is defined in Gradle's native Groovy DSL. And I find myself unable to translate it into the Kotlin DSL. I tried to put a Groovy build file (*.gradle) besides the Kotlin build file (*.gradle.kts), but this led to a strange build error. I'm not sure if mixed build file languages are supported. Besides, I would consider it bad practice too. Better only define all build files in just one language.
Also, the example above pertains to the Java programming language. But I do not expect this to be a big problem, as both Java and Kotlin produce JVM bytecode as compile output.
More clarification:
I am not talking about a "fat JAR". Dependencies and the Kotlin library are not supposed to be included in the JAR.
I do not care if the JAR files for the subprojects are still getting built or not. I'm only interested in the integrated JAR that contains both subprojects.
The main point is getting the combined JAR for the binaries. Combined JARs for the sources and JavaDoc would be a nice-to-have, but are not strictly required.
I would use the Gradle guide Creating "uber" or "fat" JARs from the Gradle documentation as a basis. What you want is essentially the same thing. It's also much better than the Groovy example you found, as it doesn't use the discouraged subprojects util, or 'simple sharing' that requires knowing how the other projects are configured.
Create a configuration for resolving other projects.
// build.gradle.kts
val mergedJar by configurations.creating<Configuration> {
// we're going to resolve this config here, in this project
isCanBeResolved = true
// this configuration will not be consumed by other projects
isCanBeConsumed = false
// don't make this visible to other projects
isVisible = false
}
Use the new configuration to add dependencies on the projects we want to add into our combined Jar
dependencies {
mergedJar(project(":my-subproject-alpha"))
mergedJar(project(":my-subproject-beta"))
}
Now copy the guide from the docs, except instead of using configurations.runtimeClasspath we can use the mergedJar configuration, which will only create the subprojects we specified.
However we need to make some modifications.
I've adjusted the example to edit the existing Jar task rather than creating a new 'fatJar' task.
for some reason, setting isTransitive = false causes Gradle to fail resolution. Instead I've added a filter (it.path.contains(rootDir.path)) to make sure the Jars we're consuming are inside the project.
tasks.jar {
dependsOn(mergedJar)
from({
mergedJar
.filter {
it.name.endsWith("jar") && it.path.contains(rootDir.path)
}
.map {
logger.lifecycle("depending on $it")
zipTree(it)
}
})
}

"No main manifest attribute" when creating Kotlin jar using IntelliJ IDEA

When creating a jar from my Kotlin code and running it, it says "No main manifest attribute".
When looking at the manifest.mf, it has this content:
Manifest-Version: 1.0
When looking at the file in the source, it has this content:
Manifest-Version: 1.0
Main-Class: MyMainClass
When manually copying the source manifest to the jar, it runs perfectly.
Screenshot of my artifact settings
I got this error with Gradle and Kotlin.
I had to add in my build.gradle.kts an explicit manifest attribute:
tasks.withType<Jar> {
manifest {
attributes["Main-Class"] = "com.example.MainKt"
}
}
From the gradle documentation, it's better to create a fatJar task to englobe all of the runtime dependencies in case you encounter java.lang.NoClassDefFoundError errors
If any of the dependent jars has a MANIFEST.MF file, it will override your custom one which defines the Main-Class.
In order to address this problem you should do the following:
Disable the alphabetical ordering
Change items ordering so that item which has META-INF/MANIFEST.MF file is the first in the list
Your custom MANIFEST.MF will be picked up by IntelliJ IDEA and displayed for the jar artifact.
See the related issue for more details.
You can also use Gradle or Maven to generate the fat jar instead.
1.Add the following task definition in the build script
tasks.jar {
manifest {
attributes["Main-Class"] = "MainKt"
}
configurations["compileClasspath"].forEach { file: File ->
from(zipTree(file.absoluteFile))
}
}
Then the jar tasks (Tasks | build | jar) again from the right hand sidebar.
For Spring boot apps:
What worked for me (gradle kotlin) in build.gradle.kts
add spring boots plugin &. apply dependency management
plugins {
id("org.springframework.boot") version "2.6.7"
}
apply(plugin = "io.spring.dependency-management")
set your main class
springBoot {
mainClass.set("com.example.Application")
}
Found this all by reading up on spring-boot docs found here

Where does intelliJ put kotlin.js in a Multiplatform Project

When using IntelliJ to create a Multiplatform Project, it doesn't seem to create kotlin.js (the std lib) like it does for a js project.
As said in the docs where the kotlin.js is mentioned:
Note: ... In a Maven or Gradle build, no library files are copied by default to the compilation output directory, see the corresponding tutorials for the instructions.
The Kotlin Multiplatform project builds are always run with Gradle, and you need to refer to the Gradle tutorial, which says:
By default, Gradle does not expand the JARs in the build process, so we need to add an additional step in our build to do so:
task assembleWeb(type: Sync) {
configurations.compile.each { File file ->
from(zipTree(file.absolutePath), {
includeEmptyDirs = false
include { fileTreeElement ->
def path = fileTreeElement.path
path.endsWith(".js") && (path.startsWith("META-INF/resources/") ||
!path.startsWith("META-INF/"))
}
})
}
from compileKotlin2Js.destinationDir
into "${projectDir}/web"
dependsOn classes
}
assemble.dependsOn assembleWeb
This task copies both dependencies runtime files and the compilation output to the web directory.

Attaching Gradle sources in IntelliJ IDEA

Once after I create a Gradle project in IntelliJ using the default gradle wrapper and create directories option I see the project structure gets created with build.gradle file.
IntelliJ tips me to "You can configure Gradle wrapper to use distribution with sources. It will provide IDE with Gradle API/DSL documentation" - but I am not able to attach the sources even after clicking "Ok, apply suggestion". The Gradle project is getting refreshed but the sources are not attached.
We are using a Nexus repository.
To improve on #anon58192932 answer you can use only gradleVersion and distributionType fields of Wrapper task and don't need to manually create distributionUrl which is more error prone since you could change gradle version in one place, but not in the other.
task wrapper(type: Wrapper) {
gradleVersion = '4.2'
distributionType = Wrapper.DistributionType.ALL
}
#edit
gradle 4.8+ will produce error for above. Use instead
wrapper {
gradleVersion = '4.2'
distributionType = Wrapper.DistributionType.ALL
}
Sounds like some IntelliJ problem. To do this manually, change gradle-bin to gradle-all in $projectDir/gradle/wrapper/gradle-wrapper.properties.
Peter's answer is not correct. The gradle-wrapper.properties and gradle-wrapper.jar files are generated by the 'wrapper' task which is shown in IntelliJ as a build task to perform.
When wrapper is performed it will build out the .jar and .properties file based on your settings therefore you should NOT be editing these files manually as they are GENERATED.
You can call the wrapper task manually very easily in your project folder: ./gradlew wrapper for *nix platforms. This will generate updated gradle-wrapper.properties and gradle-wrapper.jar files for your project.
If you want to specify to use all sources or not you can easily modify your main build.gradle file with the following:
allprojects {
task wrapper(type: Wrapper) {
gradleVersion = '4.1'
distributionUrl = 'https://services.gradle.org/distributions/gradle-4.1-bin.zip'
}
}
Substitute gradle-4.1-bin.zip for gradle-4.1-all.zip to include gradle sources, documentation, and examples.

Gradle: Make a 3rd party jar available to local gradle repository

currently, I'm testing Gradle as an alternative to Maven. In my projects, there are some 3rd party jars, which aren't available in any (Maven) repositories. My problem is now, how could I manage it to install these jars into my local .gradle repository. (If it's possible, I don't want to use the local Maven repository, because Gradle should run independently.) At the moment, I get a lot of exceptions because of missing jars. In Maven, it's quite simple by running the install command. However, my Google search for something similar to the Maven install command wasn't successful. Has anybody an idea?
you can include your file system JAR dependencies as:
dependencies {
runtime files('libs/a.jar', 'libs/b.jar')
runtime fileTree(dir: 'libs', include: '*.jar')
}
you may change runtime for compile/testCompile/etc..
A more comprehensive answer was given on a mailing list by Adam Murdoch at http://gradle.1045684.n5.nabble.com/Gradle-Make-a-3rd-party-jar-available-to-local-gradle-repository-td1431953.html
As of April 2010 there was no simple way to add a new jarfile to your ~/.gradle repository. Currently researching whether this has changed.
As of October 2014, this is still the case--because gradle does an md5 checksum of your jarfile, you can't simply download it and put it into a directory under .gradle/caches, and gradle doesn't, as far as I can tell, have any tasks which let you take a local file and push that file to its cache.
Used option (1) out of Adam Murdoch post (already linked above: http://gradle.1045684.n5.nabble.com/Gradle-Make-a-3rd-party-jar-available-to-local-gradle-repository-td1431953.html) with gradle-1.3 and it works just nicely!
Here his comment:
Copy the jars to a local directory and use a flatDir() repository to use them out of there. For example, you might copy them to
$projectDir/lib and in your build file do:
repositories {
flatDir(dirs: 'lib') }
The files in the lib directory must follow the naming scheme:
name-version-classifier.extension, where version and classifier are
optional. So, for example you might call them groovy-1.7.0.jar or even
groovy.jar
Then, you just declare the dependencies as normal:
dependencies {
compile 'groovy:groovy:1.7.0' }
There's a little more detail one flatDir() repository at:
http://gradle.org/0.9-preview-1/docs/userguide/dependency_management.html#sec:flat_dir_resolver
Similar to the above, but using an ivy resolver instead of flatDir(). This is pretty much the same as the above, but allows a
lot more options as far as naming and locations go.
There's some detail at:
http://gradle.org/0.9-preview-1/docs/userguide/dependency_management.html#sub:more_about_ivy_resolvers
Don't bother with declaring the dependencies. Just copy the jars to a local directory somewhere and add a file dependency. For example,
if the jars are in $projectDir/lib:
dependencies {
compile fileTree('lib') // this includes all the files under 'lib' in the compile classpath }
More details at:
http://gradle.org/0.9-preview-1/docs/userguide/dependency_management.html#N12EAD
Use maven install to install the dependencies into your local maven cache, and the use the maven cache as a repository:
repositories {
mavenRepo(urls: new File(System.properties['user.home'], '.m2/repository').toURI().toURL()) }
Maybe I'm missing something from my reading of your question, assuming your gradle repo is of the flatDir type, you should be able to copy the files there in the form myjar-1.0.jar and resolve them as myjar of version 1.0.
Not sure why should it be necessary for Gradle to run maven in order to access a local maven repository. You can just define the maven repos and it should resolve dependencies. You can use gradle upload to push the jars local or remote maven repos if you need to. In that case, it will execute maven.
In short: deploy to repository manager. It can local, on company LAN.
An altogether different way of thinking about this type of problem, specially if it happens often, is to use a repository manager. There are some great open source options out there such as Artifactory, Nexus or Archiva.
Lets assume you have a jar file from some dubious origin that needs to be included in your build until you have the opportunity of refactoring it out. A repository manager would allow you to upload the file to your own repository as, for the sake of this example, dubious-origin-UNKNOWN.jar
Then your build.gradle would look something like this:
repositories {
mavenRepo urls: "http://your.own.repository/url";
}
dependencies {
compile "dubious:origin:UNKNOWN";
}
There are a lot of other advantages to using a repository manager such as caching of remote artifacts, remove artifacts from scm, staging releases, more granular user permissions, and so forth.
On the down side, you would be adding a server which carries some maintenance overhead to keep your builds running.
Depends on the size if your project, I suppose.
I think something like this should work:
dependencies {
files('yourfile.jar')
}
Does it work for you?