How to get the next build number in Gradle - java

Is there any way to get the next version when publishing to a repository in gradle?
For e.g. if I have the version 3.0.1 in my repository I want the published version to be 3.0.2.
ivy has a task for ant named buildnumber which does exactly that:
<project xmlns:ivy="antlib:org.apache.ivy.ant"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<target name="ivyBuildNumber" description="Use ivy get the next build number">
<ivy:buildnumber
resolver="url-chain"
organisation="${ivy.organisation}"
module="${ivy.module}"
revision="${version.base}"/>
<echoproperties prefix="ivy.new."/>
</target>
Is there a way to do so in gradle? if not how can I access ivy tasks from gradle's ant?
In my build.gradle I calling to the ant
ant.importBuild 'build.xml'

I don't think there is support in Gradle, but you can try to use the Ant task.
https://docs.gradle.org/current/userguide/ant.html#sec:import_ant_build
Another way to do this is to use some sort of plugin, or customized task for managing the version.
Plugin: https://github.com/researchgate/gradle-release
Custom task: https://www.tikalk.com/devops/increment-version-numbers-in-gradle/

Yes, you can access ivy tasks from the ant script by importing ant's build.xml file to gradle's build.gradle file. Following is the syntax to do so.
ant.importBuild 'build.xml'
Please refer : https://docs.gradle.org/current/userguide/ant.html#sec:import_ant_build

I recommend you to use ResearchGate release plugin
https://github.com/researchgate/gradle-release
It has a pretty documentation. Easy to read.
Also, check out how I used it in my personal project.
https://github.com/vatolinrp/bitcoin-esb/blob/master/build.gradle
It would be a nice example for you.

After a long work, I managed to do that.
In my build.gradle I added this following code
ant.importBuild 'build.xml'
task getNextBuild(dependsOn : ivyBuildNumber) {
doLast{
def nextVersion = ant.properties['ivy.new.revision']
println nextVersion
}
}
I imported my ant build file, and created a task that calls the ivy buildnumber task.
There is my build.xml
<project xmlns:ivy="antlib:org.apache.ivy.ant">
<target name="ivyBuildNumber">
<path id="ivy.classpath" path="lib/ivy.jar" />
<typedef resource="org/apache/ivy/ant/antlib.xml" uri="antlib:org.apache.ivy.ant" classpathref="ivy.classpath" />
<ivy:buildnumber
organisation="daniel"
module="hello"/>
<echoproperties prefix="ivy.new."/>
</target>
</project>
Because my IDE (Intellij), didn't have ivy.jar in the content,
I imported the ivy.jar from my root dir (lib/ivy.jar)

For this exact behavior, Ivy buildnumber task can be invoked using pure Gradle without importing the Ant build:
configurations {
antTasks // define a new configuration
}
repositories {
mavenCentral()
}
dependencies {
antTasks("org.apache.ivy:ivy:2.4.0") // add Ivy library to it
}
ext {
// define the Ivy task, using the extra configuration as classpath extension
ant.taskdef(name: "ivyBuildNumber",
classname: "org.apache.ivy.ant.IvyBuildNumber",
classpath: configurations.antTasks.asPath)
ant.ivyBuildNumber(organisation: "daniel", module: "hello")
nextVersion = ant.properties["ivy.new.revision"]
}
task demo {
doLast {
println nextVersion
}
}
In general, Gradle doesn't have any bundled equivalent to Maven Release Plugin, so one has to rely on plugins. One solid plugin is gradle-release by ResearchGate, the other is axion by Allegro Tech. The former is classic Maven-style versioning, the latter takes SCM itself as the only source of truth, eliminating the versioning in the build files. But neither of these plugins does provide the exact requested behavior.
My personal take on the versioning problem was initially to use some plugins. Since I use Bamboo as CI server at work, literally everything I did with release plugins using Gradle crashed on CI server sooner or later. It might have worked for some weeks, but every server update brought some problems. I ended up using SCM-less approach with a simple convention: use branch name as base version, concatenate it with build number (both values are provided by the CI server):
ext {
branch = System.getProperty("branch", "develop")
buildNumber = System.getProperty("buildNumber", "latest")
isRelease = System.getProperty("isRelease", "false").toBoolean()
artifactVersion = "${branch}${(isRelease ? ".$buildNumber" : "-SNAPSHOT")}"
}
CI server then can be set up for executing the following command
./gradlew -DisRelease=true -Dbranch=${git.branch} -DbuildNumber=${build.number} mavenPublish
when 'Release' button is pushed. For example, build 12 of the 3.0 branch will produce version 3.0.12 in the binary repository.
The advantages are:
+ the version comes for free, assuming the branches are named accordingly
+ the auto-incremented build number also comes for free
+ one can easily publish custom revisions
+ no plugins means no problems with Gradle version updates
+ this approach is dead simple and always works
The downsides are:
- additional script tasks are required for tags
- some build numbers will be skipped, obviously (e.g. next version after 3.5.76 can be 3.5.84)

Related

Gradle set name for jar created with spring-boot's assemble

I want to create an executable jar with gradle (kotlin-dsl) and I want to give it a custom name. For the executable jar I'm using the spring boot plugin and ./gradlew :app1:assemble:
plugins {
id("myproject.java-application-conventions")
id("org.springframework.boot") version "2.2.2.RELEASE"
}
dependencies {
implementation(project(":lib"))
}
application {
mainClass.set("org.myproject.app.Main")
}
init created two more files, buildSrc/build.gradle.kts:
plugins {
`kotlin-dsl`
}
repositories {
gradlePluginPortal()
mavenCentral()
}
and buildSrc/src/main/kotlin/myproject.java-application-conventions.gradle.kts:
plugins {
id("lomboker.java-common-conventions")
application
}
With ./gradlew :app1:assemble I can create an executable jar but I don't see how I can set its name.
This question deals with naming jars but I don't know how to apply any answers to my problem.
Adding a jar block to my gradle file does not work: Expression 'jar' cannot be invoked as a function. it is interpreted as sun.tools.jar.resources.jar. So I try tasks.jar instead.
For
tasks.jar {
archiveBaseName.set("myapp")
archiveVersion.set("version")
}
./gradlew :app1:jar while building successful creates no jar (it wouldn't be executable anyway) and ./gradlew :app1:assemble ignores the properties and just creates ./app1/build/libs/app1.jar.
Since I'm not using jar but assemble I guess I should use a tasks.assemble block. But that doesn't recognize archiveBaseName or archiveVersion and I don't know what the API is.
This is the page: https://plugins.gradle.org/plugin/org.springframework.boot but I find no API.
assemble is a lifecycle task which means that it doesn’t create anything. Its role is to trigger other tasks that it depends upon and that do have some output. You can see those tasks by running your build with --console=plain.
The task that creates the Spring Boot fat jar is named bootJar. As you can see from its javadoc, it’s a customization of Gradle’s Jar and can be configured in the same way:
tasks.bootJar {
archiveBaseName.set("myapp")
archiveVersion.set("version")
}

Use Gradle to upload archives to GitLab Maven repository

I use Gradle and Gradle Maven plugin to upload archives to Maven Central. This works fine. I want to upload the same archives also to the GitLab Maven repository. Upload to this repo requires authentication with special HTTP header values. But I don't know how to do that with the Gradle Maven plugin. The GitLab documentation describes a Maven based build process using pom.xml and settings.xml. What I currently have is this:
Files created with Gradle:
build/libs
├── wms-1.2.0.jar
├── wms-1.2.0.jar.asc
├── wms-1.2.0-javadoc.jar
├── wms-1.2.0-javadoc.jar.asc
├── wms-1.2.0-sources.jar
└── wms-1.2.0-sources.jar.asc
build/poms
└── pom-default.xml
Files according to the GitLab documentation:
pom.xml
settings.xml
When I execute
mvn deploy -s settings.xml
then pom-default.xml must be "mixed into" pom.xml and build/libs/* must be used as archive location. How can I do this?
Please note that the maven-publish plugin “is now the preferred option for publishing [Maven] artifacts” with Gradle (see also the note at the top of the page you linked). Doing what you need with the maven plugin would be more cumbersome as it’s both more intricate and not as well documented, IMHO. Hence, I hope you won’t mind when I answer your question with the maven-publish plugin in mind.
As for the authentication with special HTTP header values, you should be able to solve this as follows (via):
publishing {
repositories {
maven {
url "http://repo.mycompany.com/maven2"
credentials(HttpHeaderCredentials) {
name = "Private-Token"
value = "REPLACE_WITH_YOUR_PERSONAL_ACCESS_TOKEN"
}
authentication {
header(HttpHeaderAuthentication)
}
}
}
}
I you really want to use the old maven plugin then I’d suggest to start researching from this section of the documentation on how to solve the authentication issue.
BTW: I have mainly answered your question on how to authenticate with GitLab here. If you should have trouble with configuring the publication, then I’d recommend to post this as a separate question with more details on your setup and on maybe what you’ve tried already.
Edited to add: if you need to use different header credentials depending on certain command line options, you could change the credentials configuration above to something like the following:
credentials(HttpHeaderCredentials) {
if (project.hasProperty('jobToken')) {
name = "Job-Token"
value = project.property('jobToken')
} else {
name = "Private-Token"
value = "REPLACE_WITH_YOUR_PERSONAL_ACCESS_TOKEN"
}
}
In this example, you could run ./gradlew -PjobToken=REPLACE_WITH_YOUR_JOB_TOKEN … in GitLab CI jobs while leaving out the -PjobToken=… part when working locally.

Combining/Resolving Two Repository Types in Gradle

In my Gradle project, I need to define two types of repositories: a flat directory and a Maven repository (a local Nexus server).
I can get both working separately, but can't get them to play nicely together. Ideally, I would have Gradle look at the local directory first, then at the Maven repository.
Current Setup
I have defined the repositories in my build.gradle like this:
repositories {
flatDir dirs: "${rootProject.projectDir}/libs"
flatDir dirs: "${rootProject.projectDir}/test.libs"
maven {
credentials {
username nexus_username
password nexus_password
}
url "http://nexus-server/nexus/content/groups/public"
}
}
In the libs (and test.libs) directory, the jar file names may or may not have versioning (but when using a flatDir repository, I believe that is irrelevant):
libs\activation.jar
libs\imap.jar
....
libs\<closed_source_framework>.jar
....
libs\gson-2.2.4.jar
libs\stax-utils.jar
.....
The reason I can't use our local Nexus server for everything is because of <closed_source_framework>.jar; most of the dependancies in the libs folder come packaged with that distribution, and I can't reliably get the version information to pull them from Nexus.
Now, one of the other teams is publishing their jars to the Nexus server and I'd like to be able to pull their jars from Nexus, so I have (re)defined my dependencies in my build.gradle:
dependencies {
// Grab other-team jar files from Nexus server
compile "other-team-group:other-team-jar-1:version"
compile "other-team-group:other-team-jar-2:version"
compile "other-team-group:other-team-jar-3:version"
// Grab everything else from 'flatDir'
compile name: 'activation'
compile name: 'imap'
...
compile name: 'gson-2.2.4'
compile name: 'stax-utils'
.....
}
The Problem
So now comes my problem. I had expected Gradle would search the repositories in the order specified in my build.gradle; meaning that it would look to the local libs folder first and then go to Nexus if it can't find it locally. What I'm seeing instead is that Gradle is looking at the Nexus server for the jar files already in the local libs folder. Obviously, this is slowing down my build (I have ~30 dependencies defined).
Some Info
Output from gradle properties command, to show repository information:
.....
repositories: [org.gradle.api.internal.artifacts.repositories.DefaultFlatDirArtifactRepository_Decorated#18814b1b, org.gradle.api.internal.artifacts.repositories.DefaultMavenArtifactRepository_Decorated#6dff028]
.....
Output from gradle --info compileJava, to show that Gradle is doing a lookup to Nexus:
.....
// Successfully find the other team jar files in Nexus, this is okay
Download http://nexus-server/nexus/content/groups/public/other-team-group/other-team-jar-1/version/other-team-jar-1-version.pom
Download http://nexus-server/nexus/content/groups/public/other-team-group/other-team-jar-2/version/other-team-jar-2-version.pom
Download http://nexus-server/nexus/content/groups/public/other-team-group/other-team-jar-3/version/other-team-jar-3-version.pom
.....
// Continues looking in Nexus for jar files that should be found in local libs folder
Resource missing. [HTTP GET: http://nexus-server/nexus/content/groups/public//activation//activation-.pom]
Resource missing. [HTTP HEAD: http://nexus-server/nexus/content/groups/public//activation//activation-.jar]
Resource missing. [HTTP GET: http://nexus-server/nexus/content/groups/public///imap//imap-.pom]
Resource missing. [HTTP HEAD: http://nexus-server/nexus/content/groups/public//imap//imap-.jar]
.....
Bottom Line
How can I get Gradle to stop looking at the Maven repository for jar files that I know it will only find locally?
I also posted this question over on the Gradle forums. I have copy/pasted the solution below.
Gradle will prefer an artifact with an pom/ivy descriptor over an
artifact without. I think this is why gradle continues searching after
it finds a match in the flatDir repository. This may or may not solve
your problem, but you could use a FileCollectionDependency instead of
a ModuleDependency.
Eg:
ext {
libs = "${rootProject.projectDir}/libs"
testLibs = "${rootProject.projectDir}/test.libs"
}
dependencies {
compile files("${libs}/activation.jar", "${libs}/imap.jar")
compile files("${testLibs}/gson-2.2.4.jar")
...
}

In Gradle, associating task with a dependency configuration

How can a task be associated to a specific dependency configuration?
If I look the 23.5. Dependency management (gradle java plugin official doc) section part, it states that, for example, compileTestJava task use testCompile configuration.
I just wanted to know how I could achieve that.
gradle is creating these configurations automatically;
if you define a sourceSet, a bunch of things gets created (by convention):
sourceSets {
thing
}
will define configurations: thingCompile, thingRuntime
tasks: compileThingJava, processThingResources, thingClasses
you might want to look at: gradle tasks --all and gradle dependencies
if you want to add dependencies to these configurations
the most preferable to use the generated ones
you may of course create your own configuration and extend from that: configurations { thingCompile.extendsFrom(myConfig) }

Use Ivy API to obtain latest version of a dependency?

We have a simple Ivy repository we host off of an in-house server (Apache httpd serving up JARs and their XML Ivy descriptors).
I now have a need to programmatically determine what the latest version of a dependency is in our repo. Thus if we have two versions of Mockito, our repo might look like:
mockito/ ==> organisation
mockito-all ==> module
1.9.4/ ==> revision #
mockito-all-1.9.4.jar
mockito-all-1.9.4-ivy.xml
1.9.5/
mockito-all-1.9.5.jar
mockito-all-1.9.5-ivy.xml
It would be nice if, from Java, I can use Ivy to determine that "1.9.5" is the latest version of the mockito/mockito-all module that we have.
This would likely not be an Ant task, and instead would likely be some custom Java code using the classes that exist inside ivy.jar.
Any ideas? Thanks in advance!
I believe you can use latest.integration revision value to specify the absolute latest version needed. For example, specify your Ivy dependency like so:
<dependency org="mockito" name="mockito-all" rev="latest.integration" />
You can also specify latest.milestone or latest.release if you don't want the "edge" version. Here is a good explanation on the rev value: http://ant.apache.org/ivy/history/latest-milestone/ivyfile/dependency.html
So I found your question looking to do the same thing and after some research found that in Ivy 2.4, such a thing exists.
http://ant.apache.org/ivy/history/latest-milestone/use/checkdepsupdate.html
Here is a sample step:
<target name="ivy.outdated" description="Check ivy for outdated jars">
<ivy:resolve/>
<ivy:checkdepsupdate showTransitive="false" revisionToCheck="latest.release"/>
</target>

Categories