Skip to content

Commit fe1df2d

Browse files
committed
CHANGELOG
1 parent a59ff46 commit fe1df2d

File tree

2 files changed

+91
-5
lines changed

2 files changed

+91
-5
lines changed

CHANGELOG.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,17 @@
33
## [Unreleased]
44

55
- Ruby is now installed before bundler. Previously, Bundler was used to detect the Ruby version by calling
6-
`bundle platform --ruby`. Now that the Ruby version is detected directly from the `Gemfile.lock`, the
7-
order of installation can be changed such that Ruby is installed before Bundler.
6+
`bundle platform --ruby`. Now that the Ruby version is detected directly from the `Gemfile.lock`, the
7+
order of installation can be changed such that Ruby is installed before Bundler.
8+
9+
This change should be a refactor (no observed change in build behavior), but involved substantial
10+
internal changes. If your app can build with `https://github.com/heroku/heroku-buildpack-ruby#v335`
11+
but not with this version, please open a support ticket https://help.heroku.com/. (https://github.com/heroku/heroku-buildpack-ruby/pull/1684)
12+
- The `PATH` order on Heroku CI relying on `bin/test` interface has changed for applications using the `heroku/ruby`
13+
buildpack. It now starts with: `/app/bin:/app/vendor/bundle/bin:/app/vendor/bundle/ruby/3.3.0/bin` which matches
14+
the behavior of regular `git push heroku` and customers who specify tests via `app.json`.
15+
(https://github.com/heroku/heroku-buildpack-ruby/pull/1684)
816

9-
This change should be a refactor (no observed change in build behavior), but involved substantial
10-
internal changes. If your app can build with `https://github.com/heroku/heroku-buildpack-ruby#v335`
11-
but not with this version, please open a support ticket https://help.heroku.com/. (https://github.com/heroku/heroku-buildpack-ruby/pull/1684)
1217

1318
## [v337] - 2025-12-18
1419

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
## Ruby applications using Heroku CI have a different PATH load order
2+
3+
The `PATH` order on Heroku CI relying on `bin/test` interface has changed for applications using the `heroku/ruby` buildpack.
4+
5+
It now starts with:
6+
7+
- `/app/bin:/app/vendor/bundle/bin:/app/vendor/bundle/ruby/<major>.<minor>.0/bin`
8+
9+
> Note `<major>.<minor>` is for the Ruby version so Ruby 3.3.10 would show `/app/vendor/bundle/ruby/3.3.0/bin` on the path .
10+
11+
This matches the behavior of regular `$ git push heroku` deploys and applications specifying a test command via `app.json`.
12+
13+
Previously it started with:
14+
15+
- `/app/bin:vendor/bundle/ruby/<major>.<minor>.0/bin:<bootstrap ruby>/bin:/app/vendor/bundle/ruby/<major>.<minor>.0/bin:/app/vendor/bundle/bin`
16+
17+
This discrepancy between has resulted in zero reported issues or tickets, so the fix is not expected to be disruptive. However, it's still a change, and if your application is affected it helps to understand each of the parts of those path to help with debugging.
18+
19+
## Heroku CI `bin/test`
20+
21+
Only applications that do not specify a test command in their `app.json` will trigger calling `bin/test` of the
22+
buildpack. This `bin/test` runs a Ruby script to determine what test command should be called (such as `bin/rake test`).
23+
Applications relying on this behavior will now get a different `PATH` order.
24+
25+
## What is the `PATH`?
26+
27+
When you type in `$ rspec` the operating system will look for the executable `rspec` by breaking the `PATH` environment variable into parts with a colon (`:`) separator in order from back to front. That means that it will now look for the `rspec` executable in this order:
28+
29+
- `/app/bin/rspec`
30+
- `/app/vendor/bundle/bin/rspec`
31+
- `/app/vendor/bundle/ruby/<major>.<minor>.0/bin/rspec`
32+
33+
By changing the contents or the ordering of the `PATH` you'll possibly change which executable is run. You can see the executable order by using the `which` tool.
34+
35+
```
36+
$ heroku run bash
37+
~ $ which -a rake
38+
/app/bin/rake
39+
/app/vendor/bundle/bin/rake
40+
/app/vendor/bundle/ruby/3.3.0/bin/rake
41+
```
42+
43+
The `-a` flag tells `which` to list all found executables, not just the first. But when you run `$ rake` it will effectively be the same as calling the full path `$ /app/bin/rake` directly.
44+
45+
## Path parts
46+
47+
The following describes the parts that `heroku/ruby` places on the `PATH` both before and after the change.
48+
49+
### App binstubs `/app/bin`
50+
51+
This is the local `./bin` "binstubs" directory that all recent Rails applications have.
52+
In addition, the Ruby buildpack also places a symlink to the `ruby` executable we install there, as
53+
well as other default gems.
54+
55+
This path is first for the current and prior `PATH`.
56+
57+
### Bundler binstubs `/app/vendor/bundle/bin`
58+
59+
The location of binstubs installed by `bundle install`. So if you have `rake` in your `Gemfile` you would get a `/app/vendor/bundle/bin/rake` executable file. Notably, these executables load `bundler/setup`, so if you call `$ /app/vendor/bundle/bin/rake` it's similar to calling `$ bundle exec /app/vendor/bundle/bin/rake`.
60+
61+
Unlike on a local machine, the difference between activating `$ rspec` and `$ bundle exec rspec` is very small, because Heroku cleans unused gem versions. The only time there are multiple versions of a gem on the system is due to default gems or multiple Ruby installations (due to conflicting "bootstrap" Ruby).
62+
63+
This is now second on the `PATH`, previously it was last (as installed by `heroku/ruby`).
64+
65+
> Note that this is bundler version dependent Bundler 2.6 places files here Bundler 2.7+ does not
66+
67+
### RubyGems binstubs`/app/vendor/bundle/ruby/<major>.<minor>.0/bin`
68+
69+
The location of binstubs installed by RubyGems (`gem`). When you `bundle install`, it also installs "binstubs" to this directory. These executables do NOT load bundler, so on Ruby 3.3.10 `$ bundle exec /app/vendor/bundle/ruby/3.3.0/bin/rake` and `$ /app/vendor/bundle/ruby/3.3.0/bin` would possibly produce different results on a system where there are many versions of a default gem installed.
70+
71+
This is now third on the `PATH`, previously it was second as a relative path and again later as an absolute path.
72+
73+
When a relative path is on the `PATH` as the application changes working directories it changes the effective value of the path. For example, `Dir.chdir("tmp")` would trigger path lookups in `tmp/vendor/bundle/ruby/3.3.0/bin` (for Ruby 3.3.10). It's unlikely this affected many people, but the difference is worth noting.
74+
75+
### Bootstrap Ruby `<bootstrap ruby>/bin`
76+
77+
The Ruby buildpack uses a "bootstrap" version of Ruby to execute itself.
78+
79+
Because `/app/bin` is on the path first, the correct version of Ruby will always be used (since that is where we symlink Ruby). However, if you were trying to call a default gem binstub, it's possible that prior to this change, you could have activated the "bootstrap" Ruby's copy instead of the Ruby version you requested.
80+
81+
This is no longer on the path as the implementation was refactored, so it's no longer needed. Previously, it was on the path by necessity of the implementation of `bin/test`.

0 commit comments

Comments
 (0)