Cross-Project Versioning for Eclipse Plugins - java

i have multiple Elipse plugin projects that depend on each other. Several questions concerning that:
1) If i change the version number of one plugin, is it somehow possible to automatically update the plugin.xml files of the dependent plugins to reflect the version number change?
2) The same for Maven pom's: can i somehow automatically update the pom's when i change version numbers?
3) If i want to keep plugin.xml and pom.xml version numbers consistent, is there an automatic way to do so?
4) and last: If i have multiple projects that should have the same version numbers, can i somehow sync the version numbers?

Using the Maven Release Plugin - and especially the update-versions goal - may solve at least some of the issues you have addressed.
From the documentation at http://maven.apache.org/:
In some situations you may want an easy way to update the version numbers in each POM of a multi-module project. The update-versions goal is designed to accomplish this.
To update the version numbers in your POMs, run:
mvn release:update-versions
You will be prompted for the version number for each module of the project. If you prefer that each module version be the same as the parent POM, you can use the option autoVersionSubmodules.
mvn release:update-versions -DautoVersionSubmodules=true
In this case you will only be prompted for the desired version number once.

As pointed out by khmarbaise, there is Tycho, which is a maven plugin that works as bridge between maven and eclipse plugins.
Those two links provide the information needed to achieve what i asked in my question:
https://docs.sonatype.org/display/M2ECLIPSE/Staging+and+releasing+new+M2Eclipse+release
http://software.2206966.n2.nabble.com/Incrementing-updating-release-version-of-plugins-while-generating-p2-site-td5929658.html
It seems like you need to use the command
mvn -Dtycho.mode=maven org.eclipse.tycho:tycho-versions-plugin:set-version -DnewVersion=<version>
which should set all versions of the parent pom, the modules, and the plugin.xml 's to the given version.lik

Related

How to make maven use separate target folders for every version of program?

As example, i have program with version 0.0.1. Maven must create separate folder for it - "target/0.0.1/" instead of "target/". It must be done for version "0.0.2", "0.0.3", etc.
I use Eclipse & it's Maven:
Version: Oxygen.3a Release (4.7.3a)
Build id: 20180405-1200
JDK 1.8.0_172
Maven doesn't work that way, and trying to do something like that will lead to a path of suffering. Options I see include
Creating a separate assembly (and output Jar) for each version (see Maven Assembly Plugin)
Create a multi-project reactor with a separate output configuration for every project. Keep common code in one project that you link as dependency from the others. Possibly use the maven-shade-plugin to re-link the packages in your common project into the individual output projects
As you can see, both of these approaches are pretty hacky and require advanced Maven skills. It would be much easier to have parameterized builds where you pass in the output version. But that would make sense on a CI server like Jenkins.

Issues excluding transitive dependency of project reference from eclipse class path

I have several gradle projects in my eclipse workspace. For the sake of simplicity I'm only really interested in 2 of them, let's just use A and B for this.
So the problem I'm having is that Project A has an included dependency on JBoss, which pulls in javax validation-api 1.0.0.GA, and Project B has a dependency on javax validation-api 1.1.0.Final. Since Gradle itself resolves the conflict by using the newer library first, B is happy when built by gradle. But Eclipse itself includes errors which are very distracting while editing.
The correct version of the validation-api jar ends up in B's class path but the problem is that the Gradle IDE plugin changes the project(':A') dependency to a project reference, and Eclipse seems to give the project reference precedence over the external jar. So the old jar is preferred by extension.
I tried adding { exclude module: 'validation-api' } in B's build.gradle for the dependency on A which works according to the output of 'gradle dependencies', however since Eclipse just gets as far as making it a project reference, it won't exclude the jar and the problem remains.
Also per this question I tried adding { transitive = false } and the same thing happens. I don't think even the hack posed there would work for me since the .classpath contains a single reference to the Gradle container so there's nothing to remove.
I've managed to get around this by explicitly including a reference to the correct version of the jar from my gradle cache and then moving it above the Gradle Classpath Container so that eclipse sees that version first.
My question is: Is there a better/more generic way to do this? Preferably one that I can commit to source control without breaking other people's builds or requiring them to manually modify paths or properties somewhere? There is another project with what appears to be a similar issue so something I can fix in the build.gradle file would be awesome.
Worst case scenario, I could probably switch to IntelliJ if that behaves itself better than the Eclipse-Gradle integration?
These kind of transitive dependency issues are long-standing problem with Gradle Eclipse integration (both in STS tooling and also commandline generated .classpath metadata from Gradle's Eclipse plugin. The problem is the way that Eclipse computes transitive classpaths.
Only recently we found a reasonable solution to this problem. Actually there are now two solutions, one better than the other but depending on your situation you might want to use either of them.
The first solution is a bug fix that changes the classpath order of project dependencies so that they are no longer 'preferred' over jar dependencies PR-74. To get this fix you may need to install gradle tooling from a snapshot update site because the fix went in after 3.6.3.
This solution doesn't fix the real problem (you still have the 'wrong' stuff on the classpath) but just makes it less likely to cause real problem in your projects.
The second solution is to enable use of the 'Custom Tooling API model' PR-55 introduced in STS 3.6.3. This is a bit experimental and only works for recent version of Gradle, at least 1.12 but probably better to use 2.x. It also only works for projects that have 'Dependency management' enabled (if not enabled you are using the .classpath generated by Gradle's eclipse plugin which has the same 'broken' classpath issues as the STS tooling).
The 'custom tooling model' is really the better solution in principle as it fixes the way gradle classpath get mapped to eclipse projects so that project dependencies are no longer exported and each project gets its own classpath considering dependencies conflict resolution.
To enable this go to "Window >> Preferences >> Gradle" and enable checkbox "Use Custom Tooling Model".

What is an OSGI version qualifier

I need to confirm what I suspect as I cannot find any documentation on it, so this would appear a silly question, and since I am a learner at eclipse PDE.
Initially,
I had a parent project pom of an eclipse plugin project with
<version>1.1.0-SNAPSHOT</version>
with two child projects, with both their poms referring to the parent pom as version 1.1.0-SNAPSHOT.
I was able to build the projects successfully and had a site which I use to install the plugin into eclipse.
Then, I wanted my personal temp version called 1.1.1-mine. So I modified the three poms to
1.1.1-mine
I also updated the META-INF/MANIFEST.MF and feature.xml from
0.13.0.qualifier
to
0.13.1.qualifier
However, the build encountered the following error.
[ERROR] Failed to execute goal org.eclipse.tycho:tycho-packaging-plugin:0.15.0:validate-version (default-validate-version) on project org.sonatype.m2e.subclipse: OSGi version 1.1.1.qualifier in META-INF/MANIFEST.MF does not match Maven version 1.1.1-mine in pom.xml
Does qualifier have to be a maven version keyword? Because, the build proceeded without error after I changed mine to SNAPSHOT in the poms.
If not, what did I do wrong?
What can I do to allow me to have version 1.1.1-mine?
In a nutshell, OSGi .qualifier means the same thing as -SNAPSHOT.
Since OSGi doesn't allow for more than 3 numbers in a version (+ qualifier), creating a -mine version is a bit tricky.
According to the FAQ, you can tell Tycho a string that it should be use to replace qualifier with:
mvn -DforceContextQualifier=mine
Note that this disables all the goodness you get from SNAPSHOT versions (namely that you can deploy the bundle several times).

What is the Maven way for automatic project versions when doing continuous delivery?

I have a web application where we deploy to production whenever a feature is ready, sometimes that can be a couple of times a day, sometimes it can be a couple of weeks between releases.
Currently, we don't increment our version numbers for our project, and everything has been sitting at version 0.0.1-SNAPSHOT for well over a year.
I am wondering what is the Maven way for doing continuous delivery for a web apps. It seems overkill to bump up the version number on every commit, and never bumping the version number like we are doing now, also seems wrong.
What is the recommend best practice for this type of Maven usage?
The problem is actually a two-fold one:
Advancing project version number in individual pom.xml file (and there can be many).
Updating version number in all dependent components to use latest ones of each other.
I recommend the following presentation that discusses the practical realities of doing continuous delivery with Maven:
You tube presentation on CD with Maven
Slides
The key takeaway is each build is a potential release, so don't use snapshots.
This is my summary based on the video linked by Mark O'Connor's answer.
The solution requires a DVCS like git and a CI server like Jenkins.
Don't use snapshot builds in the Continuous Delivery pipeline and don't use the maven release plugin.
Snapshot versions such as 1.0-SNAPSHOT are turned into real versions such as 1.0.buildNumber where the buildNumber is the Jenkins job number.
Algorithm steps:
Jenkins clones the git repo with the source code, and say the source code has version 1.0-SNAPSHOT
Jenkins creates a git branch called 1.0.JENKINS-JOB-NUMBER so the snapshot version is turned into a real version 1.0.124
Jenkins invokes the maven versions plugin to change the version number in the pom.xml files from 1.0-SNAPSHOT to 1.0.JENKINS-JOB-NUMBER
Jenkins invokes mvn install
If the mvn install is a success then Jenkins will commit the branch 1.0.JENKINS-JOB-NUMBER and a real non-snapshot version is created with a proper tag in git to reproduce later. If the mvn install fails then Jenkins will just delete the newly created branch and fail the build.
I highly recommend the video linked from Mark's answer.
Starting from Maven 3.2.1 continuous delivery friendly versions are supported out of the box : https://issues.apache.org/jira/browse/MNG-5576
You can use 3 predefined variables in version:
${changelist}
${revision}
${sha1}
So what you basically do is :
Set your version to e.g. 1.0.0-${revision}. (You can use mvn versions:set to do it quickly and correctly in multi-module project.)
Put a property <revision>SNAPSHOT</revision> for local development.
In your CI environment run mvn clean install -Drevision=${BUILD_NUMBER} or something like this or even mvn clean verify -Drevision=${BUILD_NUMBER}.
You can use for example https://wiki.jenkins-ci.org/display/JENKINS/Version+Number+Plugin to generate interesting build numbers.
Once you find out that the build is stable (e.g. pass acceptance tests) you can push the version to Nexus or other repository. Any unstable builds just go to trash.
There are some great discussions and proposals how to deal with the maven version number and continuous delivery (CD) (I will add them after my part of the answer).
So first my opinion on SNAPSHOT versions. In maven a SNAPSHOT shows that this is currently under development to the specific version before the SNAPSHOT suffix. Because of this, tools like Nexus or the maven-release-plugin has a special treatment for SNAPSHOTS. For Nexus they are stored in a separate repository and its allowed to update multiple artefacts with the same SNAPSHOT release version. So a SNAPSHOT can change without you knowing about it (because you never increment any number in your pom). Because of this I do not recommend to use SNAPSHOT dependencies in a project especially in a CD world since the build is not reliable any more.
SNAPSHOT as project version would be a problem when your project is used by other ones, because of the above reasons.
An other problem of SNAPSHOT for me is that is not really traceable or reproducibly any more. When I see a version 0.0.1-SNAPSHOT in production I need to do some searching to find out when it was build from which revision it was build. When I find a releases of this software on a filesystem I need to have a look at the pom.properties or MANIFEST file to see if this is old garbage or maybe the latest and greatest version.
To avoid the manual change of the version number (especially when you build multiple builds a day) let the Build Server change the number for you. So for development I would go with a
<major>.<minor>-SNAPSHOT
version but when building a new release the Build Server could replace the SNAPSHOT with something more unique and traceable.
For example one of this:
<major>.<minor>-b<buildNumber>
<major>.<minor>-r<scmNumber>
So the major and minor number can be used for marketing issues or to just show that a new great milestone is reached and can be changed manually when ever you want it. And the buildNumber (number from your Continuous Integration server) or the scmNumber (Revision of SUbversion or GIT) make each release unique and traceable. When using the buildNumber or Subversion revision the project versions are even sortable (not with GIT numbers). With the buildNumber or the scmNumber is also kinda easy to see what changes are in this release.
An other example is the versioning of stackoverflow which use
<year>.<month>.<day>.<buildNumber>
And here the missing links:
Versioning in a Pipeline
Continuous Delivery and Maven
DON'T DO THIS!
<Major>.<minor>-<build>
will bite you in the backside because Maven treats anything after a hyphen as LEXICAL. This means version 1 will be lexically higher than 10.
This is bad as if you're asking for the latest version of something in maven, then the above point wins.
The solution is to use a decimal point instead of a hyphen preceding the build number.
DO THIS!
<Major>.<minor>.<build>
It's okay to have SNAPSHOT versions locally, but as part of a build, it's better to use
mvn versions:set -DnewVersion=${major}.${minor}.${build.number}
There are ways to derive the major/minor version from the pom, eg using help:evaluate and pipe to a environment variable before invoking versions:set. This is dirty, but I really scratched my head (and others in my team) to make it simpler, and (at the time) Maven wasn't mature enough to handle this. I believe Maven 2.3.1 might have something that go some way in helping this, so this info may no longer be relevant.
It's okay for a bunch of developers to release on the same major.minor version - but it's always good to be mindful that minor changes are non-breaking and major version changes have some breaking API change, or deprecation of functionality/behaviour.
From a Continuous Delivery perspective every build is potentially releasable, therefore every check-in should create a build.
At my work for web apps we currently use this versioning pattern:
<jenkins build num>-<git-short-hash>
Example: 247-262e37b9.
This is nice because it it gives you a version that is always unique and traceable back to the jenkins build and git revision that produced it.
In Maven 3.2.1+ they finally killed the warnings for using a ${property} as a version so that makes it really easy to build these. Simply change all your poms to use <version>${revision}</version> and build with -Drevision=whatever. The only issue with that is that in your released poms the version will stay at ${revision} in the actual pom file which can cause all sorts of weird issues. To solve this I wrote a simple maven plugin (https://github.com/jeffskj/cd-versions-maven-plugin) which does the variable replacement in the file.
As a starting point you may have a look at Maven: The Complete Reference. Project Versions.
Then there is a good post on versioning strategy.

When should we move to Maven 3?

Our project badly needs to move to Flexmojos4 to get a fix, but this requires Maven 3. Our project makes extensive use of Maven and we really love it, but have configured it very heavily. Between a dozen modules we probably have 50+ pages of XML configuration.
We also use Eclipse and make heavy use of the M2Eclipse plug-in. We also use the following Maven plug-ins:
Resources
BuildNumber
SQL
Hibernate3
Flexmojos
Assembly
Jetty
Cargo
JAR/WAR
and several others. Reading this blog makes me feel like Eclipse Indigo is when it'll all work together. When should we invest the time to make the move?
In fact "the move" should actually consist of simply upgrading the maven installation / m2eclipse only. Maven 3 is almost completely backward-compatible with Maven 2.
Check the compatibility notes to make sure you are not breaking something that will need a lot to fix.
(...) Makes me feel like Eclipse Indigo is when it'll all work together. When should we invest the time to make the move?
No, you can use Maven 3 and Eclipse 3.5 / 3.6 now (I don't even remember when I started to use Maven 3).
First, Maven 3 is backward compatible (see Maven 3 - Worth it?) so, as I commented in Should I upgrade to Maven 3?:
why don't you just try it? There is nothing to "upgrade", just install Maven 3 along your Maven 2 install, change your PATH settings and try it on an existing POM.
Second, m2eclipse 0.10 uses Maven 3 as embedded version for a long time (for dependency resolution even if you declare an "external" install) and is thus already Maven 3 ready. Just add the final version of Maven 3.0 as external install and there you go.
To sum up: Maven 3 is totally usable, I almost had nothing to change in my poms (only a few things to fix them thanks to the better reporting of Maven 3), it just works inside Eclipse and it builds faster. Just try it.
PS: I use the script attached to MNG-2730 to switch between the maven versions I have on my machine, if required.

Categories