Use Ivy API to obtain latest version of a dependency? - java

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>

Related

Using fabric8 API to check kubernetes cron jobs

I'm trying to create a java test to check the status of cron jobs on a kubernetes, however I'm having trouble with the fabric8 imports.
I've tried
import io.fabric8.kubernetes.api.model.batch.Job;
import io.fabric8.kubernetes.api.model.batch.JobList;
However this throws an error. For some reason, java cannot resolve the 'batch' symbol. This tells me there is probably something missing in my ivy.xml dependencies.
I have the following dependencies already in my ivy.xml
<dependency org="io.fabric8" name="kubernetes-client" rev="3.1.12"/>
<dependency org="io.fabric8" name="kubernetes-api" rev="2.0.9"/>
<dependency org="io.fabric8" name="kubernetes-model" rev="3.1.12"/>
Am I missing a dependency? Or is there another problem?
The problem was the dependencies were out of date.
The dependency for JobList wasn't added until several versions later. Apparently, nobody on our team has updated those dependencies in our ivy file for almost a year.
In other words, to avoid issues like this, one should always keep there dependencies up to date.

How to get the next build number in Gradle

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)

How to get jar library name and version from String library name?

I have many jar files in my directory:
some-lib-2.0.jar
some-lib-2.1-SNAPSHOT.jar
some-lib-3.RELEASE.jar
some-lib-R8.jar
some-lib-core-1.jar
some-lib-2.patch2.jar
some-lib-2-alpha-4.jar
some-lib.jar
some-lib2-4.0.jar
How can I get library name and version from file name?
Is regex ((?:(?!-\d)\S)+)-(\S*\d\S*(?:-SNAPSHOT)?).jar$ valid for extract name and version?
The version number in the JAR file name is merely a convention and a default for Maven-built JARs. It may have been overridden, and it is not always reliable reading the version number from just the file name.
A more reliable way for reading version number from JAR is to look inside the JAR file. Here you have a couple of options depending on how the JAR was built:
look at META-INF/maven/.../pom.properies and pom.xml and read the version from that - this should be present for Maven-built binaries
sometimes version number if present in META-INF/MANIFEST.MF under Specification-Version or Implementation-Version properties
If this fails, then fall back to reading version number from the JAR name since there is no other information available.
Naming policy could differ across different libraries, so you aren't able to extract name/version from package name using one rule, for details you should check project docs.
In case of Maven you are able to configure the final name of built artifact with finalName pom.xml configuration option. Maven docs provide nice introduction into pom structure. Below is the example from docs:
<build>
...
<finalName>${artifactId}-${version}</finalName>
...
</build>

can I use 2 ivy files?

I'm creating a build environment for third party developers. I want to provide them with an ivy.xml which a 3rd party shouldn't change and also a ivy-custom.xml which they should change.
<target name="resolve" depends="download-ivy">
<ivy:resolve file="ivy.xml"/>
<ivy:resolve file="ivy-custom.xml"/>
</target>
This doesn't seem to work, though. The ivy-custom.xml seems to usurp the original ivy.xml. Does anyone know of a way to do this? Thanks.
You may consider split it into 2 separate modules. The first one is with dependency of your ivy.xml and publish it into your maven repository. (said org="com.abc", name="your-module", version 1.0)
Then you may let your 3rd party developers use ivy-custom.xml that also resolve "your-module" as one of the dependency.
<dependency org="com.abc" name="your-module" rev="1.0" transitive="true"/>
This assume your developer have access to your repository.

How do you configure Apache Ivy to remove orphan artifacts?

Let's say I have an ivy.xml that contains the following:
<dependency org="checkstyle" name="checkstyle" rev="4.3" />
And then I want to upgrade to Checkstyle 4.4, so I change my ivy.xml to contain:
<dependency org="checkstyle" name="checkstyle" rev="4.4" />
After a retrieve with the first configuration, I have the file checkstyle-4.3.jar. After the second configuration, I also have the file checkstyle-4.4.jar, and the file checkstyle-4.3.jar still exists.
Is there a way to have Ivy realize that the old file is an orphan, and remove it from the lib directory? The idea is that I don't want my developers' disk space usage to drastically increase every time I upgrade a tool.
Ideally I'd also want it removed from the local repository as well. I do realize that the intent of the local repository is that it is shared among projects, so it would not make sense to remove anything, as it would not know if the artifact was still in use in other projects. But there must be some kind of prune procedure...
I've been using Ivy 2.0.0, so I don't know if this applies to the version you're using.
The Ivy retrieve task has a sync attribute. Set this to true and unused/unknown files in your retrieved directory (lib in your case) will be removed. Keep in mind this will mean any manually copied artifacts in this directory which Ivy doesn't specifically resolve will be removed.
Also, note that if you use the sync option but Ivy resolves no dependencies (empty or missing ivy.xml, for example), the retrieve directory will be deleted.

Categories