heroku-buildpack-ruby icon indicating copy to clipboard operation
heroku-buildpack-ruby copied to clipboard

Natively support windows Gemfile.lock

Open schneems opened this issue 4 years ago • 1 comments

Rubygems supports different platforms

On rubygems.org a library can be released with a native dependency. Native dependencies can target different infrastructures, for instance Puma releases a version for jruby (targeting java) and one for everyone else:

  • A version targeting java: https://rubygems.org/gems/puma/versions/5.3.2-java
  • A version tareting non-java systems: https://rubygems.org/gems/puma/versions/5.3.2

Note the version is the same

It's possible to target other platforms than just java (such as windows, or linux, or mac). A good example is nokogiri:

  • https://rubygems.org/gems/nokogiri/versions/1.11.5-x86_64-linux
  • https://rubygems.org/gems/nokogiri/versions/1.11.5-x86_64-darwin
  • https://rubygems.org/gems/nokogiri/versions/1.11.5-x86-mingw32
  • https://rubygems.org/gems/nokogiri/versions/1.11.5-x86-linux

In this case a binary is pre-built and shipped as a gem instead of requiring compilation at install time.

Behavior before bundler 2.2

Prior to Bundler 2.2 when a ruby app ran bundle install on a windows and then on a linux machine it MAY resolve to different versions. Some gem authors may accidentally forget to release a platform specific version of their gem for a specific version. Imagine a world where nokogiri didn't release a "linux" version for 1.11.5 but released a windows version. Things might work locally but when you deploy it won't be able to resolve that same dependency to that same version. As a result bundler doesn't just lock to the version but also the platform.

The fix for this failure case on Heroku is very heavy handed, it's to delete the Gemfile.lock:

https://github.com/heroku/heroku-buildpack-ruby/blob/fe4db44101a9482c09cadd6e5b5ebf112e278f79/lib/language_pack/ruby.rb#L819-L829

This allows gems to resolve, but since they're not locked they could resolve to wildly different versions and have wildly different behavior.

Bundler 2.2 introduces platform targeting

When you use bundler 2.2 you must declare all platforms where the application will be used (which itself causes issues see: https://devcenter.heroku.com/articles/bundler-version#known-upgrade-issues and https://github.com/rubygems/rubygems/issues/4269). Basically if you want to dev on windows and deploy to linux you can now:

bundle lock --add-platform x86_64-linux

Now dependencies will only resolve in a way that they can deploy to all platforms that are "locked". It's my belief that if this feature works as advertised and there are not major bugs that it allows us to skip deleting the Gemfile.lock on windows generated apps.

Todo

  • We need to decide what we want to do for bundler 1.x users to warn, error, or preserve existing behavior. (I'm leaning preserve existing behavior and warn)
  • We need to validate that my above assumptions work as stated with manual testing
  • Consider impact and a possible targeted rollout. We could just merge it into main and see what happens (some people deploy to prod off of main, so it effectively acts as a staging/slow-rollout/canary for Ruby) or we could do some forensics and analysis etc.

schneems avatar May 21 '21 22:05 schneems

This came up in ticket 1264615 (internal link)

schneems avatar Jul 17 '23 22:07 schneems

Deployed https://devcenter.heroku.com/changelog-items/2912

schneems avatar Jun 26 '24 17:06 schneems