airbrakeV4rails5 4.3.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +1716 -0
  3. data/Gemfile +3 -0
  4. data/Guardfile +6 -0
  5. data/INSTALL +20 -0
  6. data/LICENSE +61 -0
  7. data/README.md +148 -0
  8. data/README_FOR_HEROKU_ADDON.md +102 -0
  9. data/Rakefile +179 -0
  10. data/TESTED_AGAINST +7 -0
  11. data/airbrake.gemspec +41 -0
  12. data/bin/airbrake +12 -0
  13. data/features/metal.feature +34 -0
  14. data/features/rack.feature +60 -0
  15. data/features/rails.feature +324 -0
  16. data/features/rake.feature +33 -0
  17. data/features/sinatra.feature +126 -0
  18. data/features/step_definitions/file_steps.rb +14 -0
  19. data/features/step_definitions/rack_steps.rb +27 -0
  20. data/features/step_definitions/rails_application_steps.rb +267 -0
  21. data/features/step_definitions/rake_steps.rb +22 -0
  22. data/features/support/airbrake_shim.rb.template +11 -0
  23. data/features/support/aruba.rb +5 -0
  24. data/features/support/env.rb +39 -0
  25. data/features/support/matchers.rb +35 -0
  26. data/features/support/rails.rb +156 -0
  27. data/features/support/rake/Rakefile +77 -0
  28. data/features/user_informer.feature +57 -0
  29. data/generators/airbrake/airbrake_generator.rb +94 -0
  30. data/generators/airbrake/lib/insert_commands.rb +34 -0
  31. data/generators/airbrake/lib/rake_commands.rb +24 -0
  32. data/generators/airbrake/templates/airbrake_tasks.rake +25 -0
  33. data/generators/airbrake/templates/capistrano_hook.rb +6 -0
  34. data/generators/airbrake/templates/initializer.rb +4 -0
  35. data/install.rb +1 -0
  36. data/lib/airbrake.rb +191 -0
  37. data/lib/airbrake/backtrace.rb +103 -0
  38. data/lib/airbrake/capistrano.rb +103 -0
  39. data/lib/airbrake/capistrano3.rb +3 -0
  40. data/lib/airbrake/cli/client.rb +76 -0
  41. data/lib/airbrake/cli/options.rb +45 -0
  42. data/lib/airbrake/cli/printer.rb +33 -0
  43. data/lib/airbrake/cli/project.rb +17 -0
  44. data/lib/airbrake/cli/project_factory.rb +33 -0
  45. data/lib/airbrake/cli/runner.rb +49 -0
  46. data/lib/airbrake/cli/validator.rb +8 -0
  47. data/lib/airbrake/configuration.rb +366 -0
  48. data/lib/airbrake/jobs/send_job.rb +7 -0
  49. data/lib/airbrake/notice.rb +411 -0
  50. data/lib/airbrake/rack.rb +64 -0
  51. data/lib/airbrake/rails.rb +45 -0
  52. data/lib/airbrake/rails/action_controller_catcher.rb +32 -0
  53. data/lib/airbrake/rails/controller_methods.rb +146 -0
  54. data/lib/airbrake/rails/error_lookup.rb +35 -0
  55. data/lib/airbrake/rails/middleware.rb +63 -0
  56. data/lib/airbrake/rails3_tasks.rb +126 -0
  57. data/lib/airbrake/railtie.rb +44 -0
  58. data/lib/airbrake/rake_handler.rb +75 -0
  59. data/lib/airbrake/response.rb +29 -0
  60. data/lib/airbrake/sender.rb +213 -0
  61. data/lib/airbrake/shared_tasks.rb +59 -0
  62. data/lib/airbrake/sidekiq.rb +8 -0
  63. data/lib/airbrake/sinatra.rb +40 -0
  64. data/lib/airbrake/tasks.rb +81 -0
  65. data/lib/airbrake/tasks/airbrake.cap +28 -0
  66. data/lib/airbrake/user_informer.rb +36 -0
  67. data/lib/airbrake/utils/params_cleaner.rb +141 -0
  68. data/lib/airbrake/utils/rack_filters.rb +45 -0
  69. data/lib/airbrake/version.rb +3 -0
  70. data/lib/airbrake_tasks.rb +62 -0
  71. data/lib/rails/generators/airbrake/airbrake_generator.rb +155 -0
  72. data/lib/templates/rescue.erb +91 -0
  73. data/rails/init.rb +1 -0
  74. data/resources/README.md +34 -0
  75. data/resources/airbrake_2_4.xsd +89 -0
  76. data/resources/airbrake_3_0.json +52 -0
  77. data/resources/ca-bundle.crt +3376 -0
  78. data/script/integration_test.rb +35 -0
  79. data/test/airbrake_tasks_test.rb +161 -0
  80. data/test/backtrace_test.rb +215 -0
  81. data/test/capistrano_test.rb +44 -0
  82. data/test/configuration_test.rb +303 -0
  83. data/test/controller_methods_test.rb +230 -0
  84. data/test/helper.rb +233 -0
  85. data/test/integration.rb +13 -0
  86. data/test/integration/catcher_test.rb +371 -0
  87. data/test/logger_test.rb +79 -0
  88. data/test/notice_test.rb +494 -0
  89. data/test/notifier_test.rb +288 -0
  90. data/test/params_cleaner_test.rb +204 -0
  91. data/test/rack_test.rb +62 -0
  92. data/test/rails_initializer_test.rb +36 -0
  93. data/test/recursion_test.rb +10 -0
  94. data/test/response_test.rb +18 -0
  95. data/test/sender_test.rb +335 -0
  96. data/test/support/response_shim.xml +4 -0
  97. data/test/user_informer_test.rb +29 -0
  98. metadata +469 -0
@@ -0,0 +1,22 @@
1
+ Given /I've prepared the Rakefile/ do
2
+ rakefile = File.join(PROJECT_ROOT, 'features', 'support', 'rake', 'Rakefile')
3
+ target = File.join(TEMP_DIR, 'Rakefile')
4
+ FileUtils.cp(rakefile, target)
5
+ end
6
+
7
+ When /I run rake with (.+)/ do |command|
8
+ command = "rake #{command.gsub(' ','_')}"
9
+ step %{I run `#{command}`}
10
+ end
11
+
12
+ Then "Airbrake should not catch the exception" do
13
+ step %{I should not see "[airbrake]"}
14
+ end
15
+
16
+ Then "Airbrake should catch the exception" do
17
+ step %{I should see "[airbrake]"}
18
+ end
19
+
20
+ Then /^command "(.*?)" should be reported$/ do |command_name|
21
+ step %{the output should contain "[airbrake] rake #{command_name}"}
22
+ end
@@ -0,0 +1,11 @@
1
+ require 'sham_rack'
2
+
3
+ ShamRack.at("api.airbrake.io") do |env|
4
+ response = <<-end_xml
5
+ <notice>
6
+ <id>b6817316-9c45-ed26-45eb-780dbb86aadb</id>
7
+ <url>http://airbrake.io/locate/b6817316-9c45-ed26-45eb-780dbb86aadb</url>
8
+ </notice>
9
+ end_xml
10
+ ["200 OK", { "Content-type" => "text/xml" }, [response]]
11
+ end
@@ -0,0 +1,5 @@
1
+ Before do
2
+ @aruba_timeout_seconds = 30
3
+ @aruba_io_wait_seconds = 5
4
+ @dirs = ["tmp"]
5
+ end
@@ -0,0 +1,39 @@
1
+ require 'active_support'
2
+ require 'nokogiri'
3
+ require 'rspec'
4
+ require 'aruba/cucumber'
5
+ require 'pry'
6
+
7
+ PROJECT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..')).freeze
8
+ TEMP_DIR = File.join(PROJECT_ROOT, 'tmp').freeze
9
+ LOCAL_RAILS_ROOT = File.join(TEMP_DIR, 'rails_root').freeze
10
+ RACK_FILE = File.join(TEMP_DIR, 'rack_app.rb').freeze
11
+ LAST_NOTICE = File.join(PROJECT_ROOT, 'resources', 'notice.xml')
12
+ ORIGINAL_RACK_FILTERS = File.join(PROJECT_ROOT, 'lib', 'airbrake', 'utils', 'rack_filters.rb')
13
+
14
+ Before do
15
+ FileUtils.rm_rf(LOCAL_RAILS_ROOT)
16
+
17
+ reload_rack_filters
18
+ end
19
+
20
+ When /^I reset Bundler environment variable$/ do
21
+ BUNDLE_ENV_VARS.each do |key|
22
+ ENV[key] = nil
23
+ end
24
+ end
25
+
26
+ def prepend_path(path)
27
+ ENV['PATH'] = path + ":" + ENV['PATH']
28
+ end
29
+
30
+ def reload_rack_filters
31
+ original_filters = File.read(ORIGINAL_RACK_FILTERS)
32
+
33
+ Dir.mkdir(TEMP_DIR) unless Dir.exist?(TEMP_DIR)
34
+
35
+ File.write(File.join(TEMP_DIR, "rack_filters.rb"),
36
+ original_filters.lines.to_a[1..-2].join("\n"))
37
+
38
+ require File.join(TEMP_DIR, "rack_filters.rb")
39
+ end
@@ -0,0 +1,35 @@
1
+ RSpec::Matchers.define :have_content do |xpath, content|
2
+ match do |document|
3
+ @elements = document.search(xpath)
4
+
5
+ if @elements.empty?
6
+ false
7
+ else
8
+ element_with_content = document.at("#{xpath}[contains(.,'#{content}')]")
9
+
10
+ if element_with_content.nil?
11
+ @found = @elements.collect { |element| element.content }
12
+
13
+ false
14
+ else
15
+ true
16
+ end
17
+ end
18
+ end
19
+
20
+ failure_message_for_should do |document|
21
+ if @elements.empty?
22
+ "In XML:\n#{document}\nNo element at #{xpath}"
23
+ else
24
+ "In XML:\n#{document}\nGot content #{@found.inspect} at #{xpath} instead of #{content.inspect}"
25
+ end
26
+ end
27
+
28
+ failure_message_for_should_not do |document|
29
+ unless @elements.empty?
30
+ "In XML:\n#{document}\nExpcted no content #{content.inspect} at #{xpath}"
31
+ end
32
+ end
33
+ end
34
+
35
+ World(RSpec::Matchers)
@@ -0,0 +1,156 @@
1
+ BUNDLE_ENV_VARS = %w(RUBYOPT BUNDLE_PATH BUNDLE_BIN_PATH BUNDLE_GEMFILE)
2
+ ORIGINAL_BUNDLE_VARS = Hash[ENV.select{ |key,value| BUNDLE_ENV_VARS.include?(key) }]
3
+
4
+ ENV['RAILS_ENV'] = 'test'
5
+
6
+ Before do
7
+ ENV['BUNDLE_GEMFILE'] = File.join(Dir.pwd, ENV['BUNDLE_GEMFILE']) unless ENV['BUNDLE_GEMFILE'].start_with?(Dir.pwd)
8
+ @framework_version = nil
9
+ end
10
+
11
+ After do |s|
12
+ ORIGINAL_BUNDLE_VARS.each_pair do |key, value|
13
+ ENV[key] = value
14
+ end
15
+ Cucumber.wants_to_quit = true if s.failed?
16
+ end
17
+
18
+ module RailsHelpers
19
+ def rails_root_exists?
20
+ File.exists?(environment_path)
21
+ end
22
+
23
+ def application_controller_filename
24
+ controller_filename = File.join(rails_root, 'app', 'controllers', "application_controller.rb")
25
+ end
26
+
27
+ def rails_3_or_4?
28
+ rails_version =~ /\A[34]/
29
+ end
30
+
31
+ def rails_root
32
+ LOCAL_RAILS_ROOT
33
+ end
34
+
35
+ def rails_uses_rack?
36
+ rails_3_or_4? || rails_version =~ /^2\.3/
37
+ end
38
+
39
+ def rails_version
40
+ @rails_version ||= begin
41
+ if ENV["RAILS_VERSION"]
42
+ ENV["RAILS_VERSION"]
43
+ elsif bundler_manages_gems?
44
+ rails_version = open(gemfile_path).read.match(/gem.*rails["'].*["'](.+)["']/)[1]
45
+ else
46
+ environment_file = File.join(rails_root, 'config', 'environment.rb')
47
+ rails_version = `grep RAILS_GEM_VERSION #{environment_file}`.match(/[\d.]+/)[0]
48
+ end
49
+ end
50
+ end
51
+
52
+ def bundler_manages_gems?
53
+ File.exists?(gemfile_path)
54
+ end
55
+
56
+ def gemfile_path
57
+ gemfile = File.join(rails_root, 'Gemfile')
58
+ end
59
+
60
+ def rails_manages_gems?
61
+ rails_version =~ /\A2\.[123]/
62
+ end
63
+
64
+ def rails_supports_initializers?
65
+ rails_3_or_4? || rails_version =~ /\A2\./
66
+ end
67
+
68
+ def rails_finds_generators_in_gems?
69
+ rails_3_or_4? || rails_version =~ /\A2\./
70
+ end
71
+
72
+ def version_string
73
+ ENV['RAILS_VERSION'] || `tail -n 1 SUPPORTED_RAILS_VERSIONS` # use latest version if ENV["RAILS_VERSION"] is undefined
74
+ end
75
+
76
+ def environment_path
77
+ File.join(rails_root, 'config', 'environment.rb')
78
+ end
79
+
80
+ def rakefile_path
81
+ File.join(rails_root, 'Rakefile')
82
+ end
83
+
84
+ def config_gem(gem_name, version = nil)
85
+ run = "Rails::Initializer.run do |config|"
86
+ insert = " config.gem '#{gem_name}'"
87
+ insert += ", :version => '#{version}'" if version
88
+ content = File.read(environment_path)
89
+ content = "require 'thread'\n#{content}"
90
+ if content.sub!(run, "#{run}\n#{insert}")
91
+ File.open(environment_path, 'wb') { |file| file.write(content) }
92
+ else
93
+ raise "Couldn't find #{run.inspect} in #{environment_path}"
94
+ end
95
+ end
96
+
97
+ def config_gem_dependencies
98
+ insert = <<-END
99
+ if Gem::VERSION >= "1.3.6"
100
+ module Rails
101
+ class GemDependency
102
+ def requirement
103
+ r = super
104
+ (r == Gem::Requirement.default) ? nil : r
105
+ end
106
+ end
107
+ end
108
+ end
109
+ END
110
+ run = "Rails::Initializer.run do |config|"
111
+ content = File.read(environment_path)
112
+ if content.sub!(run, "#{insert}\n#{run}")
113
+ File.open(environment_path, 'wb') { |file| file.write(content) }
114
+ else
115
+ raise "Couldn't find #{run.inspect} in #{environment_path}"
116
+ end
117
+ end
118
+
119
+ def require_thread
120
+ content = File.read(rakefile_path)
121
+ content = "require 'thread'\n#{content}"
122
+ File.open(rakefile_path, 'wb') { |file| file.write(content) }
123
+ end
124
+
125
+ def perform_request(uri, environment = 'production')
126
+ request_script = <<-SCRIPT
127
+ require File.expand_path('../config/environment', __FILE__)
128
+
129
+ env = Rack::MockRequest.env_for(#{uri.inspect})
130
+ response = RailsRoot::Application.call(env)
131
+
132
+ response = response.last if response.last.is_a?(ActionDispatch::Response)
133
+
134
+ if response.is_a?(Array)
135
+ puts "Status: " + response.first.to_s
136
+ puts "Headers: " + response.second.to_s
137
+ if response.last.respond_to?(:each)
138
+ # making it work even with Rack::BodyProxy
139
+ body = ""
140
+ response.last.each do |chunk|
141
+ body << chunk
142
+ end
143
+ response.pop
144
+ response << body
145
+ end
146
+ puts "Body: " + response.last.to_s
147
+ else
148
+ puts response.body
149
+ end
150
+ SCRIPT
151
+ File.open(File.join(rails_root, 'request.rb'), 'w') { |file| file.write(request_script) }
152
+ end
153
+
154
+ end
155
+
156
+ World(RailsHelpers)
@@ -0,0 +1,77 @@
1
+ # A test harness for RakeHandler
2
+ #
3
+ require 'rake'
4
+ require 'rubygems'
5
+ require 'airbrake'
6
+ require 'airbrake/rake_handler'
7
+
8
+ class IgnoredException < StandardError; end
9
+
10
+ Airbrake.configure do |c|
11
+ c.ignore_rake_only = ["IgnoredException"]
12
+ end
13
+
14
+ # Should catch exception
15
+ task :airbrake do
16
+ Airbrake.configuration.rescue_rake_exceptions = true
17
+ stub_tty_output(true)
18
+ raise_exception
19
+ end
20
+
21
+ # Should not catch exception
22
+ task :airbrake_disabled do
23
+ Airbrake.configuration.rescue_rake_exceptions = false
24
+ stub_tty_output(true)
25
+ raise_exception
26
+ end
27
+
28
+ # Should ignore the exception
29
+ task :airbrake_ignored do
30
+ Airbrake.configuration.rescue_rake_exceptions = true
31
+ stub_tty_output(true)
32
+ raise_exception(IgnoredException)
33
+ end
34
+
35
+ # Should not catch exception as tty_output is true
36
+ task :airbrake_autodetect_from_terminal do
37
+ Airbrake.configuration.rescue_rake_exceptions = nil
38
+ stub_tty_output(true)
39
+ raise_exception
40
+ end
41
+
42
+ # Should catch exception as tty_output is false
43
+ task :airbrake_autodetect_not_from_terminal do
44
+ Airbrake.configuration.rescue_rake_exceptions = nil
45
+ stub_tty_output(false)
46
+ raise_exception
47
+ end
48
+
49
+ task :airbrake_not_yet_configured do
50
+ Airbrake.configuration.rescue_rake_exceptions = true
51
+ stub_tty_output(true)
52
+ stub_empty_sender
53
+ raise_exception
54
+ end
55
+
56
+ module Airbrake
57
+ def self.send_notice(notice)
58
+ $stderr.puts "[airbrake] #{notice.component}"
59
+ end
60
+ end
61
+
62
+ def stub_empty_sender
63
+ Airbrake.sender = nil
64
+ end
65
+
66
+ def stub_tty_output(value)
67
+ Rake.application.instance_eval do
68
+ @tty_output_stub = value
69
+ def tty_output?
70
+ @tty_output_stub
71
+ end
72
+ end
73
+ end
74
+
75
+ def raise_exception(exception_class = StandardError)
76
+ raise exception_class.new('TEST')
77
+ end
@@ -0,0 +1,57 @@
1
+ Feature: Inform the user of the airbrake notice that was just created
2
+
3
+ Background:
4
+ Given I successfully run `rails new rails_root -O --skip-gemfile`
5
+ And I cd to "rails_root"
6
+ And I configure the Airbrake shim
7
+
8
+ Scenario: Rescue an exception in a controller
9
+ When I run `rails generate airbrake -k myapikey`
10
+ And I define a response for "TestController#index":
11
+ """
12
+ raise RuntimeError, "some message"
13
+ """
14
+ And the response page for a "500" error is
15
+ """
16
+ <!-- AIRBRAKE ERROR -->
17
+ """
18
+ And I route "/test/index" to "test#index"
19
+ And I perform a request to "http://example.com:123/test/index?param=value" in the "production" environment
20
+ Then I should see "Airbrake Error b6817316-9c45-ed26-45eb-780dbb86aadb"
21
+
22
+ Scenario: Rescue an exception in a controller with a custom error string
23
+ When I configure the notifier to use the following configuration lines:
24
+ """
25
+ config.api_key = "myapikey"
26
+ config.user_information = 'Error #{{ error_id }}'
27
+ """
28
+ And I run `rails generate airbrake -k myapikey`
29
+ And I define a response for "TestController#index":
30
+ """
31
+ raise RuntimeError, "some message"
32
+ """
33
+ And the response page for a "500" error is
34
+ """
35
+ <!-- AIRBRAKE ERROR -->
36
+ """
37
+ And I route "/test/index" to "test#index"
38
+ And I perform a request to "http://example.com:123/test/index?param=value" in the "production" environment
39
+ Then I should see "Error #b6817316-9c45-ed26-45eb-780dbb86aadb"
40
+
41
+ Scenario: Don't inform the user
42
+ When I configure the notifier to use the following configuration lines:
43
+ """
44
+ config.user_information = false
45
+ """
46
+ And I run `rails generate airbrake -k myapikey`
47
+ And I define a response for "TestController#index":
48
+ """
49
+ raise RuntimeError, "some message"
50
+ """
51
+ And the response page for a "500" error is
52
+ """
53
+ <!-- AIRBRAKE ERROR -->
54
+ """
55
+ And I route "/test/index" to "test#index"
56
+ And I perform a request to "http://example.com:123/test/index?param=value" in the "production" environment
57
+ Then I should not see "Airbrake Error b6817316-9c45-ed26-45eb-780dbb86aadb"
@@ -0,0 +1,94 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/lib/insert_commands.rb")
2
+ require File.expand_path(File.dirname(__FILE__) + "/lib/rake_commands.rb")
3
+
4
+ class AirbrakeGenerator < Rails::Generator::Base
5
+ def add_options!(opt)
6
+ opt.on('-k', '--api-key=key', String, "Your Airbrake API key") { |v| options[:api_key] = v}
7
+ opt.on('-h', '--heroku', "Use the Heroku addon to provide your Airbrake API key") { |v| options[:heroku] = v}
8
+ opt.on('-a', '--app=myapp', String, "Your Heroku app name (only required if deploying to >1 Heroku app)") { |v| options[:app] = v}
9
+ end
10
+
11
+ def manifest
12
+ if !api_key_configured? && !options[:api_key] && !options[:heroku]
13
+ puts "Must pass --api-key or --heroku or create config/initializers/airbrake.rb"
14
+ exit
15
+ end
16
+ if plugin_is_present?
17
+ puts "You must first remove the airbrake plugin. Please run: script/plugin remove airbrake"
18
+ exit
19
+ end
20
+ record do |m|
21
+ m.directory 'lib/tasks'
22
+ m.file 'airbrake_tasks.rake', 'lib/tasks/airbrake_tasks.rake'
23
+ if ['config/deploy.rb', 'Capfile'].all? { |file| File.exists?(file) }
24
+ m.append_to 'config/deploy.rb', capistrano_hook
25
+ end
26
+ if api_key_expression
27
+ if use_initializer?
28
+ m.template 'initializer.rb', 'config/initializers/airbrake.rb',
29
+ :assigns => {:api_key => api_key_expression}
30
+ else
31
+ m.template 'initializer.rb', 'config/airbrake.rb',
32
+ :assigns => {:api_key => api_key_expression}
33
+ m.append_to 'config/environment.rb', "require 'config/airbrake'"
34
+ end
35
+ end
36
+ determine_api_key if heroku?
37
+ m.rake "airbrake:test", :generate_only => true
38
+ end
39
+ end
40
+
41
+ def api_key_expression
42
+ s = if options[:api_key]
43
+ "'#{options[:api_key]}'"
44
+ elsif options[:heroku]
45
+ "ENV['HOPTOAD_API_KEY']"
46
+ end
47
+ end
48
+
49
+ def determine_api_key
50
+ puts "Attempting to determine your API Key from Heroku..."
51
+ ENV['HOPTOAD_API_KEY'] = heroku_api_key
52
+ if ENV['HOPTOAD_API_KEY'] =~ /\S/
53
+ puts "... Done."
54
+ puts "Heroku's Airbrake API Key is '#{ENV['HOPTOAD_API_KEY']}'"
55
+ else
56
+ puts "... Failed."
57
+ puts "WARNING: We were unable to detect the Airbrake API Key from your Heroku environment."
58
+ puts "Your Heroku application environment may not be configured correctly."
59
+ exit 1
60
+ end
61
+ end
62
+
63
+ def heroku_var(var,app_name = nil)
64
+ app = app_name ? "--app #{app_name}" : ''
65
+ `heroku config #{app} | grep -E "#{var.upcase}" | awk '{ print $3; }'`.strip
66
+ end
67
+
68
+ def heroku_api_key
69
+ heroku_var("(hoptoad|airbrake)_api_key",options[:app]).split.find {|x| x =~ /\S/ }
70
+ end
71
+
72
+ def heroku?
73
+ options[:heroku] ||
74
+ system("grep HOPTOAD_API_KEY config/initializers/airbrake.rb") ||
75
+ system("grep HOPTOAD_API_KEY config/environment.rb")
76
+ end
77
+
78
+ def use_initializer?
79
+ ::Rails::VERSION::MAJOR > 1
80
+ end
81
+
82
+ def api_key_configured?
83
+ File.exists?('config/initializers/airbrake.rb') ||
84
+ system("grep Airbrake config/environment.rb")
85
+ end
86
+
87
+ def capistrano_hook
88
+ IO.read(source_path('capistrano_hook.rb'))
89
+ end
90
+
91
+ def plugin_is_present?
92
+ File.exists?('vendor/plugins/airbrake')
93
+ end
94
+ end