Our project uses Gradle (whose dependency system is compatible with Maven IIUC). When depending on external projects, we try to depend on stable versions. Sometimes we have to depend on a development version. And sometimes we have to fork the repository of a dependency and depend on that (in general we try to upstream our changes as soon as possible).

How can we ensure that every of our developers get a consistent build environment?

  • We could use Mercurial subrepositories (which are similar to Git submodules and allow to "embed" specific revisions of external repositories into our repository). The disadvantage is that every developer has to build all the non-released versions of the dependencies.

  • We could set up an internal artifact server and build all the forked dependencies centrally.

    • We could leave the version of the dependency unchanged in the forked repository. Then we have to somehow ensure that changes in the repository get picked up by all developers to have a consistent environment across all machines.
    • We could give every "significant" revision in the forked repository a special version and change our project to depend on these versions. This has the disadvantage that we can't just use the branch we use to upstream our changes (since the version should be unchanged when creating a pull request).

Thoughts? Are there better ways to solve this problem?


We could use Mercurial subrepositories

This also has the risk of becoming a "hidden" dependency: all the builds pass so nobody thinks of removing the subrepository once the original project has been released. More likely to happen if you have a large number of dependent projects.

We could set up an internal artifact server

This is what every team that I've worked with has done, and it's just one of the reasons to use an artifact server. IMO, any team that has more than one developer and more than one project will benefit from a local repository, especially when paired with a build server.

The question of how you should version forked artifacts is trickier, and comes down to whether this is a temporary situation or whether you're planning to maintain a long-term fork.

If you're just looking to get development builds, and the project uses "snapshot" versioning, then you should almost certainly keep the project's version (and group/artifact IDs). Eventually there will be a release version and you can stop storing the snapshot in the local repository.

If, on the other hand, you're making a long-term fork where you'll cherry-pick updates from the source project, you should not only give it its own version but also its own group and artifact IDs. So instead of com.example:someartifact:1.2.3, uses com.mycompany:example-someartifact:1.2.3. Beware, however, that this introduces the possibility of classpath conflicts.

Are there better ways to solve this problem?

It's not a better way, but if the upstream project maintains its own public build repository, you could pull your artifacts from it. Even in this case I think a local repository server that proxies the remote is a better idea than putting lots of explicit repository references in your settings file.

  • Generally we try to keep forks temporary and try to upstream our changes as soon as possible (or, as soon as someone gets around to go through the review process...), so we'd most likely not want to change the group and artifact IDs. In this case (and also in general) I could imagine that making sure everyone is getting the most recent SNAPSHOT version could create problems if someone didn't sync his maven repository. @kdgregory Did you ever run into these kind of problems? Dec 11 '17 at 16:11
  • If you use a continuous integration pipeline that deploys snapshots to a central repository, that largely overcomes the "latest snapshot" issue. It's still a problem, since Maven doesn't check for updated snapshots by default (finding the docs for this is surprisingly difficult), but the -U command-line argument should ensure that you get the latest.
    – kdgregory
    Dec 12 '17 at 0:54
  • The biggest problem that I've run into (and am running into right now) is when different projects rely on different versions, especially in-development versions. For example, did you know that mixing SLF4J 1.7.22 and 1.7.5 would cause a runtime ClassNotFoundException? Neither did I until this week ;-) The problem gets worse when you're dealing with long-lived snapshots.
    – kdgregory
    Dec 12 '17 at 0:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.