-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Run Bundler v1 native helpers with explicit version #3196
Conversation
end | ||
|
||
def self.helper_path(bundler_version: "v1") | ||
"ruby #{File.join(native_helpers_root, bundler_version, 'run.rb')}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jurre running without bundle exec
worked and removed the need for an empty Gemfile
🎉
@@ -8,6 +8,10 @@ if [ -z "$install_dir" ]; then | |||
exit 1 | |||
fi | |||
|
|||
if [ ! -d "$install_dir" ]; then | |||
mkdir -p "$install_dir" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
creates the nested v1
in /opt/bundler
def self.helper_path | ||
"bundle exec ruby #{File.join(native_helpers_root, 'run.rb')}" | ||
def self.run_bundler_subprocess(function:, args:, bundler_version:) | ||
bundler_env_version = bundler_version.tr("v", "") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels a bit funky, might be easier to do the version detection here instead
@jurre @brrygrdn got specs passing with just running the native helpers with a re-set ENV and setting |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for breaking this change out, it's very easy to follow the restructuring 👍🏻
I only have a couple of questions
V2 = "2" | ||
|
||
# TODO: Add support for bundler v2 | ||
# return "v2" if lockfile.content.match?(/BUNDLED WITH\s+2/m) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👌🏻
|
||
def self.helper_path(bundler_version:) | ||
native_helper_version = "v#{bundler_version}" | ||
"ruby #{File.join(native_helpers_root, native_helper_version, 'run.rb')}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to confirm, we've removed bundle exec intentionally in addition to clearing the env?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 intentionally removing as bundle exec
needs to be run in a folder with a Gemfile
source (or point to one with a env var) that has resolved dependencies, we currently don't rely on any dependencies in the native helpers so this just got in the way of running the native helpers with a custom bundler version. Bundler refuses to run BUNDLER_VERSION=1 cmd
if the Gemfile.lock
that we're pointing to has been resolved with BUNDLED WITH 2.x
and vice versa.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Previously, when we executed bundle exec cmd
it inherited all existing ENV
values so ended up pointing to ./bundler/Gemfile
as we ran the specs with bundle exec rspec spec
and inherited the same BUNDLER_VERSION
ENV
var which I couldn't re-set without setting unsetenv_others: true
.
Similarly, when run from the updater it would inherit the BUNDLED WITH
from the updaters Gemfile.lock
: https://github.com/dependabot/dependabot-updater/blob/main/bin/run#L21
start = Time.now | ||
stdin_data = JSON.dump(function: function, args: args) | ||
cmd = allow_unsafe_shell_command ? command : escape_command(command) | ||
env_cmd = [env, cmd].compact | ||
if ENV["DEBUG_FUNCTION"] == function | ||
escaped_stdin_data = stdin_data.gsub("\"", "\\\"") | ||
puts "$ cd #{Dir.pwd} && echo \"#{escaped_stdin_data}\" | #{env_cmd.join(' ')}" | ||
env_keys = env ? env.map { |k, v| "#{k}=#{v}" } : "" | ||
puts "$ cd #{Dir.pwd} && echo \"#{escaped_stdin_data}\" | #{env_keys} #{cmd}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't fully follow the switch from #{env_cmd.join(' ')}
to #{env_keys} #{cmd}
here, as it looks like we still pass env_cmd
on line 89.
My read is that this purely to improve presentation in the logs, but I just wanted to check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This path should only be used when you pass DEBUG_FUNCTION=somefunc
as env var when running specs/dry-run and puts out the command that's being executed by ruby so you can cd into the temp dir and run the same thing in bash. The previous way of concatenating env
and cmd
didn't work when actually passing in a env
hash.
The env_cmd arg still works for Open3
but now the bash version flattens the env
hash to ENV_KEY=value ./func
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I attempted to clarify this a bit with the above comment and moving env_cmd
down to where it's used
ec8f2ed
to
e339e4c
Compare
fc98076
to
5e3da4c
Compare
5e3da4c
to
1612bcd
Compare
if ENV["DEBUG_FUNCTION"] == function | ||
escaped_stdin_data = stdin_data.gsub("\"", "\\\"") | ||
puts "$ cd #{Dir.pwd} && echo \"#{escaped_stdin_data}\" | #{env_cmd.join(' ')}" | ||
puts helper_subprocess_bash_command(stdin_data: stdin_data, command: cmd, env: env) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@brrygrdn moved this into it's own method
Example output, if you run DEBUG_FUNCTION=parsed_gemspec bundle exec rspec spec/dependabot/bundler/file_parser_spec.rb:685
you'll see this in console:
$ cd /Users/feelepxyz/code/dependabot-core/bundler/tmp/dependabot_20210302-86366-1xt144c && \
echo "{\"function\":\"parsed_gemspec\",\"args\":{\"gemspec_name\":\"example.gemspec\",\"lockfile_name\":null,\"dir\":\"/Users/feelepxyz/code/dependabot-core/bundler/tmp/dependabot_20210302-86366-1xt144c\"}}" \
| BUNDLER_VERSION=1 \
BUNDLE_GEMFILE=/Users/feelepxyz/code/dependabot-core/bundler/lib/dependabot/bundler/../../../helpers/v1/Gemfile \
bundle exec ruby /Users/feelepxyz/code/dependabot-core/bundler/lib/dependabot/bundler/../../../helpers/v1/run.rb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, thanks for clarifying this 🙇🏻
This runs existing bundler 1 native helpers by explicitly setting a `BUNDLER_VERSION` env var as well as pointing the `BUNDLE_GEMFILE` to the `Gemfile` in `helpers/v1` which has been bundled with: `BUNDLER_VERSION=1 bundle install` setting `BUNDLED WITH` to the matching installed v1 version.
1612bcd
to
b088744
Compare
"RUBYLIB" => nil, | ||
"RUBYOPT" => nil, | ||
"GEM_PATH" => nil, | ||
"GEM_HOME" => nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is kinda funky but seems to work, verified that these env vars are not set in the container so get set by bundler/ruby when running core with bundle exec rspec/updater run
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple of copy edits, otherwise this looks 💯
I don't feel bad unsetting specific ruby/bundler envvars given the circumstances. It's well called out and doesn't feel brittle in the sense those are pretty fixed points in the ecosystem.
bundler/helpers/v1/Gemfile
Outdated
# gemspec so we've added it here for backwards compatability during bundler 2 | ||
# rollout. | ||
# | ||
# NOTE: If we don't require it and a customers `.gemspec` uses File without |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# NOTE: If we don't require it and a customers `.gemspec` uses File without | |
# NOTE: If we don't require it and a customers `.gemspec` uses Find without |
bundler/helpers/v1/Gemfile
Outdated
@@ -0,0 +1,16 @@ | |||
# frozen_string_literal: true | |||
|
|||
# TODO: Look into removing this. "file" used to get required from common's |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# TODO: Look into removing this. "file" used to get required from common's | |
# TODO: Look into removing this. "find" used to get required from common's |
"RUBYLIB" => nil, | ||
"RUBYOPT" => nil, | ||
"GEM_PATH" => nil, | ||
"GEM_HOME" => nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like a fair workaround, it feels like the cost of doing business since we're running bundler to run core to run bundler ♻️ 😅
if ENV["DEBUG_FUNCTION"] == function | ||
escaped_stdin_data = stdin_data.gsub("\"", "\\\"") | ||
puts "$ cd #{Dir.pwd} && echo \"#{escaped_stdin_data}\" | #{env_cmd.join(' ')}" | ||
puts helper_subprocess_bash_command(stdin_data: stdin_data, command: cmd, env: env) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, thanks for clarifying this 🙇🏻
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚀
This runs existing bundler 1 native helpers by explicitly setting a
BUNDLER_VERSION
env var as well as pointing theBUNDLE_GEMFILE
tobundler/helpers/v1/Gemfile
which has been installed withBUNDLER_VERSION=1 bundle install
settingBUNDLED WITH
to the latest installed v1 version.I've verified this setup works with bundler 2 installed in the core container and installing core's gems with v2 and running helpers with v1, I've got the native helper tests working with a setup that extends on this PR: https://github.com/dependabot/dependabot-core/pull/3211/files
A follow on ship from this would be running native helper specs with bundler 1 followed by actually installing bundler 2 and installing core's gems with it.
This also moves the native helpers to
v1
folder making room for av2
folder.Release plan