Skip to content

Commit

Permalink
Merge pull request #2676 from newrelic/bootstrap
Browse files Browse the repository at this point in the history
lib/bootstrap.rb -> lib/boot/strap.rb
  • Loading branch information
fallwith authored Jun 3, 2024
2 parents 11c2f7e + 38be29a commit 675f5a6
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 41 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# New Relic Ruby Agent Release Notes

## dev

- **Bugfix: Incompatibility with Bootstrap**

Version <dev> fixes an incompatibility between the agent and the [Bootstrap](https://github.com/twbs/bootstrap-rubygem) gem caused by agent v9.10.0's introduction of a `lib/bootstrap.rb` file. Thank you to [@dorner](https://github.com/dorner) for reporting the bug and identifying the 'bootstrap' name collision as the root cause. [BUG#2675](https://github.com/newrelic/newrelic-ruby-agent/issues/2675) [PR#2676](https://github.com/newrelic/newrelic-ruby-agent/pull/2676)

## v9.10.0

Version 9.10.0 introduces instrumentation for DynamoDB, adds a new feature to automatically apply nonces from the Rails content security policy, fixes a bug that would cause an expected error to negatively impact a transaction's Apdex, and fixes the agent's autostart logic so that by default `rails runner` and `rails db` commands will not cause the agent to start.
Expand Down
22 changes: 9 additions & 13 deletions lib/bootstrap.rb → lib/boot/strap.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
# - Next, use the "RUBYOPT" environment variable to require ("-r") this
# file (note that the ".rb" extension is dropped):
# ```
# export RUBYOPT="-r /newrelic/lib/bootstrap"
# export RUBYOPT="-r /newrelic/lib/boot/strap"
# ```
# - Add your New Relic license key as an environment variable.
# ```
Expand All @@ -50,7 +50,7 @@ def require(*_groups)
end

def require_newrelic
lib = File.dirname(__FILE__)
lib = File.expand_path('../..', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
Kernel.require NR_AGENT_GEM
end
Expand All @@ -65,40 +65,36 @@ def self.patch
check_for_rubyopt
check_for_bundler
Bundler::Runtime.prepend(NRBundlerPatch)
rescue StandardError => e
Kernel.warn "New Relic entrypoint at #{__FILE__} encountered an issue:\n #{e.message}"
end

private

def self.check_for_require
warn_and_exit "#{__FILE__} is meant to be required, not invoked directly" if $PROGRAM_NAME == __FILE__
raise "#{__FILE__} is meant to be required, not invoked directly" if $PROGRAM_NAME == __FILE__
end

def self.check_for_rubyopt
unless ENV[RUBYOPT].to_s.match?("-r #{__FILE__.rpartition('.').first}")
warn_and_exit "#{__FILE__} is meant to be required via the RUBYOPT env var"
raise "#{__FILE__} is meant to be required via the RUBYOPT env var"
end
end

def self.check_for_bundler
require_bundler

warn_and_exit 'Required Ruby Bundler class Bundler::Runtime not defined!' unless defined?(Bundler::Runtime)
raise 'Required Ruby Bundler class Bundler::Runtime not defined!' unless defined?(Bundler::Runtime)

unless Bundler::Runtime.method_defined?(:require)
warn_and_exit "The active Ruby Bundler instance doesn't offer Bundler::Runtime#require"
raise "The active Ruby Bundler instance doesn't offer Bundler::Runtime#require"
end
end

def self.require_bundler
require BUNDLER
rescue LoadError => e
warn_and_exit "Required Ruby library '#{BUNDLER}' could not be required - #{e}"
end

def self.warn_and_exit(msg)
warn "New Relic entrypoint at #{__FILE__} encountered an issue:\n\t#{msg}"

exit 1
raise "Required Ruby library '#{BUNDLER}' could not be required - #{e}"
end
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
# frozen_string_literal: true

require_relative '../test_helper'
require_relative '../../test_helper'

class NewRelicBootstrapTest < Minitest::Test
class PhonyBundler
Expand Down Expand Up @@ -34,13 +34,10 @@ def test_check_for_require
opn = $PROGRAM_NAME

$PROGRAM_NAME = bootstrap_file
msg = ''
NRBundlerPatcher.stub :warn_and_exit, proc { |m| msg = m } do

assert_raises(RuntimeError, 'meant to be required, not invoked') do
NRBundlerPatcher.check_for_require
end

assert_match(/meant to be required, not invoked/, msg,
'Expected check_for_require to complain when bootstrap is invoked directly')
ensure
$PROGRAM_NAME = opn
end
Expand All @@ -61,13 +58,9 @@ def test_check_for_bundler_class_not_defined
NRBundlerPatcher.stub :require_bundler, nil do
Bundler.send(:remove_const, :Runtime)

msg = ''
NRBundlerPatcher.stub :warn_and_exit, proc { |m| msg = m; Bundler.send(:const_set, :Runtime, oruntime) } do
assert_raises(RuntimeError, 'class Bundler::Runtime not defined!') do
NRBundlerPatcher.check_for_bundler
end

assert_match(/class Bundler::Runtime not defined!/, msg,
'Expected check_for_bundler to complain if Bundler::Runtime is not defined')
end
ensure
Bundler.send(:const_set, :Runtime, oruntime)
Expand All @@ -78,13 +71,9 @@ def test_check_for_bundler_method_not_defined

NRBundlerPatcher.stub :require_bundler, nil do
Bundler::Runtime.stub :method_defined?, false, [:require] do
msg = ''
NRBundlerPatcher.stub :warn_and_exit, proc { |m| msg = m } do
assert_raises(RuntimeError, "doesn't offer Bundler::Runtime#require") do
NRBundlerPatcher.check_for_bundler
end

assert_match(/doesn't offer Bundler::Runtime#require/, msg,
'Expected check_for_bundler to complain if Bundler::Runtime#require is not defined')
end
end
end
Expand All @@ -93,26 +82,26 @@ def test_require_bundler
skip_unless_minitest5_or_above

NRBundlerPatcher.stub :require, proc { |_gem| raise LoadError }, ['bundler'] do
msg = ''
NRBundlerPatcher.stub :warn_and_exit, proc { |m| msg = m } do
assert_raises(RuntimeError, 'could not be required') do
NRBundlerPatcher.check_for_bundler
end

assert_match(/could not be required/, msg,
'Expected require_bundler to complain if Bundler could not be required')
end
end

private

# Load the bootstrap file and anticipate the `warn` and `exit` calls
# with assertions
# Load the bootstrap file and anticipate the `warn` call
def require_bootstrap
assert_raises SystemExit do
assert_output(/New Relic entrypoint/) do
require_relative '../../lib/bootstrap'
end
msg = ''
loaded = nil
Kernel.stub :warn, proc { |m| msg = m } do
loaded = require_relative '../../../lib/boot/strap'
end

return unless loaded

assert_match(/New Relic entrypoint/, msg,
'Expected the initial requiring of boot/strap to generate a warning')
end

# Have the patcher patch our phony Bundler instead of the real one
Expand All @@ -129,6 +118,6 @@ def monkeypatch_phony_bundler
end

def bootstrap_file
@bootstrap_file ||= File.expand_path('../../../lib/bootstrap.rb', __FILE__)
@bootstrap_file ||= File.expand_path('../../../../lib/boot/strap.rb', __FILE__)
end
end

0 comments on commit 675f5a6

Please sign in to comment.