openrewrite / rewrite

Automated mass refactoring of source code.
https://docs.openrewrite.org
Apache License 2.0
2.19k stars 329 forks source link

Introduce dependency locking and automated daily lock updates #1484

Open yeikel opened 2 years ago

yeikel commented 2 years ago

There are pros and cons of using dependency ranges, but one of the main cons is that it makes builds not reproducible

It is also possible that a new upgrade will break our tests and we will only know when it happens

I think that like in https://github.com/openrewrite/rewrite/issues/1479, we should pin all our dependencies and use #1483 to keep ourselves up to date

jkschneider commented 2 years ago

Dependabot is not reliable for Gradle at this point. I would prefer we stick with dynamic versions and use Gradle's dependency locking mechanism. I would be happy with a github action workflow that attempts to update lock files daily, and if tests pass commits the result.

shanman190 commented 2 years ago

Unless @yeikel wants to submit a PR, I'll submit one later this evening for Gradle dependency locking and rich version constraints (as shown via the attached issue).

yeikel commented 2 years ago

Unless @yeikel wants to submit a PR, I'll submit one later this evening for Gradle dependency locking and rich version constraints (as shown via the attached issue).

Feel free to do so and thank you

shanman190 commented 2 years ago

Spoke with @sambsnyd a bit on this one and it's a bit more complicated that described here.

In short, right now dependency upgrades are provided for free. In particular, this makes updates to the recipe libraries and the build plugins quite easy by not requiring much thought other than triggering the desired downstream build. By introducing dependency locking, this would mean that transitives would also need to have locks updated as part of a rolling release cycle (ex. openrewrite/rewrite -> openrewrite/rewrite-gradle-plugin). By implementing this naively, additional work for openrewrite transitive repositories would need to be incurred as part of the development and release processes.

sambsnyd commented 2 years ago

Great summary Shannon, you've saved me the effort of having to write it. :)

I'd be happy to have a lock file checked in and automatically updated upon successful CI build. There are many reasons reproducible builds are desirable.

Automatically taking the latest version of most dependencies really streamlines the release process. And more than once I've wasted time debugging, not realizing there was a lock file pinning dependencies.

Is there an option to have a lock file that doesn't lock by default? Less of a "lock", more of a ledger or record. If anyone knows how to configure that behavior I'd be interested to hear about it

shanman190 commented 2 years ago

Would a guard along the lines of the below work you think, @sambsnyd? This would allow you to enable locks when you desire a reproducible build (ie. Patch releases) or newcomers trying to build the project achieving a stable build. Then being able to stay up to date in the general case.

I would think we would enable dependency lock updating during all release builds that are not patch releases, where instead we would be using the lock state from that release. Then during the nightly builds as well.

if (hasProperty("dependency-lock") || gradle.startParameter.isWriteDependencyLocks) {
  // Enable dependency locking
}
jkschneider commented 2 years ago

In particular, this makes updates to the recipe libraries and the build plugins quite easy

I was thinking we would exclude org.openrewrite and build plugins from locks. We don't need to lock transitives, because even though in theory they can be dynamically versioned, in the vast majority of cases they simply aren't.

I would think we would enable dependency lock updating during all release builds that are not patch releases

This does improve the situation, but folks have also expressed frustration with dynamic versions causing problems on snapshot builds too as they attempt to contribute up to rewrite's main branch (e.g. whenever Jackson releases there is an hour or two period of unresolvability).