apollographql / federation-jvm

JVM support for Apollo Federation

Home Page:https://www.apollographql.com/docs/federation/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Move build system to Gradle?

martinbonnin opened this issue · comments

Any thoughts about moving to Gradle for the build system? One immediate reason for doing so would be to use in-memory GPG keys in CI and automating the release process. It might be doable with Maven too but it looks more complicated (need to store a cryped keystore in the repo or restore it from env variables which both do not sound really fun things to do).

Overall, Gradle looks more flexible and more in-line with tools we use for other projects like apollo-android but maybe there are reasons to stick with Maven?

Any thoughts about moving to Gradle for the build system?

I'm not strongly against Gradle, although I would note we have a lot of plugins and checks in our Parent POM, e.g. Spotless and several Maven Enforcer rules.

If we move, we should make sure we have equivalent checks and functionality in Gradle. It looks like there's a port of Maven Enforcer to Gradle, but looking at the feature-parity chart, it's missing some rather important rules. (It also just appears to be one contributor who contributes sporadically.)

One of the useful ones in our case is RequireUpperBoundDeps. This is a rule that checks that the dependency version resolved by Maven is the same as the max version among all transitive dependency declarations. This is useful for ensuring that Maven and Gradle have the same behavior during dependency version mediation/resolution (and also for ensuring that dependency exclusions don't accidentally exclude a higher version).

One immediate reason for doing so would be to use in-memory GPG keys in CI and automating the release process. It might be doable with Maven too but it looks more complicated (need to store a cryped keystore in the repo or restore it from env variables which both do not sound really fun things to do).

From https://www.cloudbees.com/blog/continuous-deployment-maven-central-apache-maven it looks we can use the pgp-maven-plugin to pass them in through environment variables.

Overall, Gradle looks more flexible and more in-line with tools we use for other projects like apollo-android but maybe there are reasons to stick with Maven?

It's mainly the reasons above. If we can keep the same checks and functionality I'm definitely down to move to Gradle, but from a cursory glance it doesn't look like it's there. (Also while Gradle is certainly more flexible, there's a question of whether we need that level of flexibility here, or whether declarative configs and plugins are sufficient.)

It may be the case that Gradle natively has some of this functionality built-in though. I'm down to pair on explaining the current plugins in pom.xmls so we can get a better idea of what migrating to Gradle would entail.

TBH, I like the way Gradle manages dependencies way better and I think it should make the Maven Enforcer plugin obsolete. Let's dig into that this week 👍

I do think the dependency resolution strategy that Gradle uses is much better than Maven, although I don't think that means we should ignore the UX of Maven users.

To clarify, what I'm getting after is some basic reproducibility across build systems. If we were to migrate to Gradle, the following may happen:

  1. We'd like to make a release.
  2. We run tests, and they pass, so we think everything is fine.
  3. We make the release.
  4. The library fails for most Maven users, because different dependency versions get chosen for Maven users compared to Gradle users, e.g. with runtime errors like NoSuchMethodException.

The rule RequireUpperBoundDeps ensures that, when recursing into the library for dependency resolution, the same resolved versions for that library are seen regardless of whether you're using Gradle or Maven (the "upper bound" version).

There's alternatives here potentially, e.g.:

  1. Publish a BOM with all dependencies used by the library, and ask users to use that. This essentially overrides default resolution strategies of the user's build system, although I'm not sure how hard it is to generate a BOM with the upper bound versions of all dependencies in Gradle.
  2. Run end-to-end tests in both Maven and Gradle following the instructions we recommend to users, although that sounds like it could be a pain to maintain.

There's also some other plugins we'll have to find alternatives for (e.g. maven-dependency-plugin for detecting unused or undeclared dependencies), but we can dig more into that this week.

Plugins only run against the project they are configured against (either directly or by importing parent POMs). Maven enforcer rules in this repo have 0 effect on the clients of this library. This library should also have a minimal set of dependencies (basically just graphql-java).