Multi-project (not multi-module) developer workflow

We (like I’m sure many) have a number of projects – some gradle, some maven. For example, I work on our companies commons library (a maven project) and an application (a gradle project) that depends on the commons library. Most of the developers on the application dont work on the commons library. Most of the developers that work on the commons library don’t work on this particular application.

If I’m working on a feature in application that relies on some changes to commons that I’m making – I don’t want to keep pushing new point releases to our company artifact server just to get my gradle application project to see them. In the maven world this is the case where I’m using a commons SNAPSHOT, installing to mavenLocal() and then doing the equivalent of --update-dependencies in gradle to have it get the new SNAPSHOT. Then when im done I push my commons changes, it builds on our CI and pushes a new version to the artifact server.

Some of this works today, I can put mavenLocal() in my repository list in gradle and it will pick up my local SNAPSHOTs that I install. The problem is when developer Bob makes a change to commons and pushes the to the CI server. Now the “current” SNAPSHOT is only on the artifact server and my mavenLocal() is stale. It appears that when gradle (with --update-dependencies) see the matching dependency in mavenLocal() it doesn’t bother checking our artifact server.

If I comment out mavenLocal() then run an -update-dependencies then it resolves fine from the remote repo.

  1. Surely others have a similar problem? How are you handling it? Never installing locally?
  2. even without mavenLocal() – lets say I have two gralde projects in this situation? What is the gradle way to do this?

Same problem was mentioned here: Multi-Module Maven Local & Remote Development Workflow Problem
Spring’s Chris Beams also opened a similar issue (at least an answer to #2) here:

I have read all of the other posts I could find, and cannot determine a suitable workaround. Any help is appreciated.

We do have something similar at work.

We have several ivy repositories, one local to each developer, and several on a server.
Dependency resolution stops when it finds a matching artifact on a declared repository.

If you declare first your ‘server’ repository, Gradle should see the published snapshot there, and stop. It shouldn’t also check your local repository.
It’s what we experience.
Maybe mavenLocal() behaves differently though

Sure that makes sense. However, in my case I think that means that the remote repo will always be used to satisfy the commons SNAPSHOT dependency. If I am working locally on some changes to commons that I want to use in application (i.e. im building a common component in order to support a feature in application) then I want to do local development and install into mavenLocal so that this will take precedence over the SNAPSHOT in the remote repository.

This general need of working locally, having that take precedence, then pushing that and having the remote take precedence seems like a very normal thing to me.

If I could configure commons to resolve using the “latest” version from any repository, that would solve my problem. But because commons is SNAPSHOT and a gradle changing dependency it only consults the repos in order.

As I’ve dug around some more I think maybe people are using dynamic versions for some of this? Because apparently dynamic versions always consult all repos. However, I really want to be able to constrain the dynamic version in some way. Something like “always get the latest 3.5.0-SNAPSHOT by timestamp across all repos”. That would solve my problem exactly. If I just say latest.integration as a dynamic version – then I think it will be fine if 3.5.0-SNAPSHOT is the only and newest commons dependency, but will fail if we have a few projects, each working with different branches of commons (i.e. a 3.4.0-SNAPSHOT vs a 3.5.0-SNAPSHOT).

For now I am just commenting out mavenLocal() normally, and when I do need to use local commons development, I uncomment it and refresh, causing it to pickup my local one. But the fact that I can’t find any clear idioms to do this is freaking me out – how is no one else having these problems? maven or not

When in a situation like yours, we publish locally using different names for our artifact than the current snapshot name. We don’t care as they stay local.
Then we force them during dependency resolution (force=true).
To be sure Gradle always takes the expected dependencies, I always print them (using the ‘dependencies’ task)