views:

82

answers:

4

One of the most common and annoying problems I encounter with Maven is the building process failing/passing depending on who, when and on which machine is executing the process.

More formally - in ideal world I would expect the build process to be repeatable. As a programmer I would say that I expect the build process to be like a pure function of source code and resources being build input and "an environment" - I would expect it to return the same result any time and anywhere I "evaluate" it using "fixed environment" and I expect (rather wish) that everyone in the team has the same "fixed environment".

In real world either "an environment" changes over time or varies between developer machines, possibly because it includes some dependencies one neither expects nor realizes.

What I am trying to achieve asking this question is finding/defining an algorithm/procedure or check list for troubleshooting not repeatable Maven build processes. Let assume we have two separate machines A and B with the same OS and that we are building exactly the same version of our application on them, but they give different results (for example one is successful and one fails). Where/how one should look for differences between these two "environments".

These are some steps I usually use:

  1. compare effective POMs obtained via mvn help:effective-pom
  2. compare mvn executable versions + other involved tools (for example jdk)
  3. compare environment settings (obtained under Windows using command line's set command)
  4. compare settings.xml files from user's home directories
  5. compare classpaths generated using mvn dependency:build-classpath
  6. delete repository or even both repositories

Any ideas what else can give valuable informations? Maybe there is a better way I am simply missing...

A: 

I've seen a lot of Maven builds slip up on different machines because of different versions of Maven or Java and associated bugs or features. I've even seen builds fail and pass on the same machine when e.g. built on the commandline vs. built in an IDE.

If commandline tools are called, you may find these are either platform- or machine-dependant. I've seen this most notably in package tasks which create .dmg files on Mac or .msi on Windows machines, and the packaging must be run on these OSs to created specific files.

File encoding of both resources and source files has caused me problems in the past. Checking that the project.build.sourceEncoding property is set seems like useful info. Rather counter-intuitively, this seems to be used when copying or filtering resources, but ignored when dealing with the source files, IIRC.

Alison
A: 

Track what you do and be able to track what developers do:

  1. Create a build machine (for release builds), documenting each and every piece of software installed, and each and every configuration option chosen
  2. Private build machines must be set up the same way to ensure maximum liklihood of a build working
  3. When a private build fails, list the software & configurations and diff them against the release configuration. Differences are assumed unsupported and must be corrected to reach maximum liklihood of a successful build
atk
koppernickus
Sorry - thought you were looking for process not how to diff. It depends on how you track the information. you could track them in a text file and run 'diff'... You could track them in a database and have each change as a different database entry... you could have a file under source control, and use the source control's diff mechanism... you could use tripwire...
atk
+1  A: 

Let's make toast American style: you burn, I'll scrape. --W. Edwards Deming.

Instead of looking for an algorithm to troubleshoot your non repeatable builds, fix the root cause, make them repeatable by following good practices (Maven builds are 100% repeatable if you use it right):

  • use the same version of Maven on all machines of a given project (distribute a packaged version)
  • use the same version of the JDK (at least the same version for a given project)
  • lock down plugins versions in your poms for build reproducibility
  • enforce the above rules using the Maven Enforcer Plugin
  • use a corporate repository (and only the corporate repository)
  • avoid making builds non portable by adding non user specific things in ~/.m2/settings.xml
  • put everything under version control (the effective pom should be identical on all machines)
  • run clean builds on a build machine (the reference)

I've used Maven in organizations with hundreds of developers without experiencing the problems you're describing. Actually, and I'm sorry to say that, the problems you are facing are not Maven's fault, they're just the result of poor development practices (I don't mean to be rude but that's true).

Pascal Thivent
Pascal, we already have/use all of that. Despite that problems occur from time to time and we have to deal with them. Of course most often the root cause is not Maven fault but our mistakes, often errors in POM files.
koppernickus
@Pascal, I've suggested having the md5 of the settings file be an option for the enforcer plugin. That should fix many problems.
sal
@sal That's a nice suggestion (not sure how to deal with user-specific stuff like passwords though). But, to be honest, I don't really understand the problem with the `settings.xml`: isn't it just common sense to avoid putting stuff in it, since it's not shared?
Pascal Thivent
@Pascal, maybe your coworkers have more self control when it comes to tweaking things. I'm amazed at what mine will tweak for little to no gain.
sal
+1  A: 

Not really an answer per se, but we delete the entire local repo on the build machine every week.

The build machine is also restricted to a small set of local and proxy repos that the developers can not edit.

At first we had lots of builds that just stop working after the repo is deleted. Now its a monthly problem. Its trending to a every other month problem.

This has promoted a number of good practices in locking down version numbers, plugin versions, using profiles for local builds, using excludes when needed and adding 3rd party jars to the right places.

sal