On the Bamboo development team we recently spent some time investigating how a wrong artifact ended up in one of our dogfooding servers. Apart from the awesomeness of dogfooding, it highlighted the perils of maven and its implications on continuous integration (CI). The mystery: A WAR deployed to our dogfooding server contained the wrong version of a library The contents of the library installed differed from the corresponding artifact in our internal maven repository, despite having the same groupId, artifactId and version (GAV) We traced the rogue artifact back to a Bamboo build, which never deployed to our maven repository! So how did it happen? Maven does not check remote repositories for stable versions of artifacts already in its local repository A stable version of an artifact was being mvn install ed. Changes were still made to this line of development even though it had a stable version Maven repositories on a build agent are not cleaned out between builds Problem When developing locally, we often use mvn clean install to build the project we’re working on. The install phase of the default maven lifecycle will place the freshly-built artifacts of the project being built into your local repository (~/.m2). This can be a problem in CI because the same build agents are used to build different plans, and these plans may then pick up locally-installed artifacts from a previous build. To illustrate the problem, suppose we have project A with a dependency on project B <-- Somewhere in the pom of project A --> <dependency> <groupId>projectB</groupId> <artifactId>projectB</artifactId> <version>1.0-SNAPSHOT</version> </dependency> Project A and B have separate plans which build and deploy artifacts, e.g. say PROJACI does mvn clean install, PROJADEPLOY does mvn clean deploy, and so on with PROJBCI, PROJBDEPLOY. Suppose that we only had one build agent, and the sequence of events ran like this: PROJBDEPLOY -> PROJBCI (as a result of a new commit) -> PROJACI -> PROJADEPLOY Using install, PROJACI would pick up the version of project B that was built in PROJBCI, as opposed to whatever is in the canonical remote maven repository (PROJBDEPLOY). This can lead to strange and mysterious problems where the canonical maven repository says one thing, but your build that depends on a SNAPSHOT artifact says another. Thankfully, an internally developed Bamboo plugin removes SNAPSHOT artifacts in the local repository to maintain consistent disk usage across our build agents, but it also has the useful side effect of preventing such problems since we will now always resolve SNAPSHOTs from the remote maven repository. Unfortunately, if you are constantly installing a stable version, and not a SNAPSHOT you will still run into this. When using a SNAPSHOT, maven will attempt to retrieve the latest version based on timestamp. Maven assumes that non-snapshot versions are immutable, so if a stable version of an artifact exists in its local repository, maven will not go to the canonical remote repository to check for a newer version and retrieve it. So suppose we have project A depending [...]