honeybadger 1.10.3 → 1.11.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Appraisals +10 -0
- data/CHANGELOG.md +17 -10
- data/Gemfile.lock +1 -1
- data/features/rails.feature +6 -4
- data/features/step_definitions/rails_steps.rb +8 -0
- data/features/support/rails.rb +5 -0
- data/gemfiles/rack.gemfile.lock +1 -1
- data/gemfiles/rails2.3.gemfile.lock +1 -1
- data/gemfiles/rails3.0.gemfile.lock +1 -1
- data/gemfiles/rails3.1.gemfile.lock +1 -1
- data/gemfiles/rails3.2.gemfile.lock +1 -1
- data/gemfiles/rails4.gemfile.lock +1 -1
- data/gemfiles/rails4_cap3.gemfile +13 -0
- data/gemfiles/rails4_cap3.gemfile.lock +204 -0
- data/gemfiles/rake.gemfile.lock +1 -1
- data/gemfiles/sinatra.gemfile.lock +1 -1
- data/honeybadger.gemspec +7 -4
- data/lib/honeybadger.rb +14 -1
- data/lib/honeybadger/capistrano.rb +4 -45
- data/lib/honeybadger/capistrano/legacy.rb +45 -0
- data/lib/honeybadger/capistrano/tasks.rake +67 -0
- data/lib/honeybadger/configuration.rb +2 -2
- data/lib/honeybadger/monitor/worker.rb +1 -1
- data/lib/honeybadger/notice.rb +10 -1
- data/lib/honeybadger/rack.rb +1 -0
- data/lib/honeybadger/rails.rb +8 -0
- data/lib/honeybadger/railtie.rb +1 -7
- data/lib/honeybadger/stats.rb +1 -1
- data/lib/honeybadger/templates/{feedback_form.html.erb → feedback_form.erb} +12 -9
- data/lib/honeybadger/user_feedback.rb +47 -17
- data/lib/honeybadger_tasks.rb +3 -3
- data/lib/rails/generators/honeybadger/honeybadger_generator.rb +1 -2
- data/spec/honeybadger/capistrano_spec.rb +26 -23
- data/spec/honeybadger/configuration_spec.rb +25 -21
- data/spec/honeybadger/notice_spec.rb +30 -37
- data/spec/honeybadger/notifier_spec.rb +60 -4
- data/spec/honeybadger/rack_spec.rb +1 -0
- data/spec/honeybadger/user_feedback_spec.rb +29 -4
- data/spec/honeybadger_tasks_spec.rb +13 -4
- metadata +9 -6
- data/spec/honeybadger/stats_spec.rb +0 -57
data/lib/honeybadger_tasks.rb
CHANGED
@@ -17,12 +17,12 @@ module HoneybadgerTasks
|
|
17
17
|
def self.deploy(opts = {})
|
18
18
|
api_key = opts.delete(:api_key) || Honeybadger.configuration.api_key
|
19
19
|
unless api_key =~ /\S/
|
20
|
-
puts "I don't seem to be configured with an API key. Please check your configuration."
|
20
|
+
$stderr.puts "I don't seem to be configured with an API key. Please check your configuration."
|
21
21
|
return false
|
22
22
|
end
|
23
23
|
|
24
24
|
unless opts[:environment] =~ /\S/
|
25
|
-
puts "I don't know to which environment you are deploying (use the TO=production option)."
|
25
|
+
$stderr.puts "I don't know to which environment you are deploying (use the TO=production option)."
|
26
26
|
return false
|
27
27
|
end
|
28
28
|
|
@@ -60,7 +60,7 @@ module HoneybadgerTasks
|
|
60
60
|
puts "Succesfully recorded deployment"
|
61
61
|
return true
|
62
62
|
else
|
63
|
-
puts response.body
|
63
|
+
$stderr.puts "Error recording deployment: #{response.class} -- #{response.body || 'no response'}"
|
64
64
|
return false
|
65
65
|
end
|
66
66
|
end
|
@@ -36,9 +36,8 @@ class HoneybadgerGenerator < Rails::Generators::Base
|
|
36
36
|
|
37
37
|
def append_capistrano_hook
|
38
38
|
if File.exists?('config/deploy.rb') && File.exists?('Capfile')
|
39
|
-
append_file('
|
39
|
+
append_file('Capfile', <<-HOOK)
|
40
40
|
|
41
|
-
require './config/boot'
|
42
41
|
require 'honeybadger/capistrano'
|
43
42
|
HOOK
|
44
43
|
end
|
@@ -1,33 +1,36 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'capistrano'
|
2
3
|
|
3
|
-
|
4
|
-
|
4
|
+
if defined?(Capistrano::Configuration.instance)
|
5
|
+
describe 'Honeybadger::Capistrano' do
|
6
|
+
require 'capistrano/configuration'
|
7
|
+
require 'honeybadger/capistrano'
|
5
8
|
|
6
|
-
|
7
|
-
before(:each) do
|
8
|
-
reset_config
|
9
|
+
before { reset_config }
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
before(:each) do
|
12
|
+
@configuration = Capistrano::Configuration.new
|
13
|
+
Honeybadger::Capistrano.load_into(@configuration)
|
14
|
+
@configuration.dry_run = true
|
15
|
+
end
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
-
|
17
|
+
it "defines honeybadger:deploy task" do
|
18
|
+
expect(@configuration.find_task('honeybadger:deploy')).not_to be_nil
|
19
|
+
end
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
it "logs when calling honeybadger:deploy task" do
|
22
|
+
@configuration.set(:current_revision, '084505b1c0e0bcf1526e673bb6ac99fbcb18aecc')
|
23
|
+
@configuration.set(:repository, 'repository')
|
24
|
+
@configuration.set(:current_release, '/home/deploy/rails_app/honeybadger')
|
25
|
+
io = StringIO.new
|
26
|
+
logger = Capistrano::Logger.new(:output => io)
|
27
|
+
logger.level = Capistrano::Logger::MAX_LEVEL
|
26
28
|
|
27
|
-
|
28
|
-
|
29
|
+
@configuration.logger = logger
|
30
|
+
@configuration.find_and_execute_task('honeybadger:deploy')
|
29
31
|
|
30
|
-
|
31
|
-
|
32
|
+
expect(io.string).to include '** Notifying Honeybadger of Deploy'
|
33
|
+
expect(io.string).to include '** Honeybadger Notification Complete'
|
34
|
+
end
|
32
35
|
end
|
33
36
|
end
|
@@ -3,6 +3,7 @@ require 'socket'
|
|
3
3
|
|
4
4
|
describe Honeybadger::Configuration do
|
5
5
|
it "provides default values" do
|
6
|
+
assert_config_default :api_key, nil
|
6
7
|
assert_config_default :proxy_host, nil
|
7
8
|
assert_config_default :proxy_port, nil
|
8
9
|
assert_config_default :proxy_user, nil
|
@@ -206,29 +207,32 @@ describe Honeybadger::Configuration do
|
|
206
207
|
expect(config.public?).to be_true
|
207
208
|
end
|
208
209
|
|
209
|
-
|
210
|
-
config
|
211
|
-
config.features = {}
|
212
|
-
expect(config.public?).to be_false
|
213
|
-
end
|
210
|
+
describe "#metrics?" do
|
211
|
+
let(:config) { Honeybadger::Configuration.new }
|
214
212
|
|
215
|
-
|
216
|
-
|
217
|
-
config.environment_name = 'production'
|
218
|
-
expect(config.metrics?).to be_true
|
219
|
-
end
|
213
|
+
context "when public" do
|
214
|
+
before { config.stub(:public?).and_return(true) }
|
220
215
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
config.metrics = false
|
225
|
-
expect(config.metrics?).to be_false
|
226
|
-
end
|
216
|
+
it "sends metrics by default" do
|
217
|
+
expect(config.metrics?).to be_true
|
218
|
+
end
|
227
219
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
220
|
+
context "when disabled" do
|
221
|
+
before { config.metrics = false }
|
222
|
+
|
223
|
+
it "does not send metrics" do
|
224
|
+
expect(config.metrics?).to be_false
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
context "when not public" do
|
230
|
+
before { config.stub(:public?).and_return(false) }
|
231
|
+
|
232
|
+
it "does not send metrics" do
|
233
|
+
expect(config.metrics?).to be_false
|
234
|
+
end
|
235
|
+
end
|
232
236
|
end
|
233
237
|
|
234
238
|
it "uses the assigned logger if set" do
|
@@ -237,7 +241,7 @@ describe Honeybadger::Configuration do
|
|
237
241
|
expect(config.logger).to eq "CUSTOM LOGGER"
|
238
242
|
end
|
239
243
|
|
240
|
-
it
|
244
|
+
it "gives a new instance if non defined" do
|
241
245
|
Honeybadger.configuration = nil
|
242
246
|
expect(Honeybadger.configuration).to be_a Honeybadger::Configuration
|
243
247
|
end
|
@@ -14,15 +14,6 @@ describe Honeybadger::Notice do
|
|
14
14
|
Honeybadger::Notice.new(configuration.merge(args))
|
15
15
|
end
|
16
16
|
|
17
|
-
def stub_request(attrs = {})
|
18
|
-
double('request', { :parameters => { 'one' => 'two' },
|
19
|
-
:protocol => 'http',
|
20
|
-
:host => 'some.host',
|
21
|
-
:request_uri => '/some/uri',
|
22
|
-
:session => { :to_hash => { 'a' => 'b' } },
|
23
|
-
:env => { 'three' => 'four' } }.update(attrs))
|
24
|
-
end
|
25
|
-
|
26
17
|
context '#deliver' do
|
27
18
|
context 'sender is configured' do
|
28
19
|
it "delivers to sender" do
|
@@ -313,53 +304,55 @@ describe Honeybadger::Notice do
|
|
313
304
|
assert_filters_hash(:session_data)
|
314
305
|
end
|
315
306
|
|
316
|
-
|
317
|
-
let(:params_filters) { [] }
|
318
|
-
let(:notice) { build_notice(:params_filters => params_filters, :url => url) }
|
319
|
-
|
320
|
-
context 'filtered params in query' do
|
321
|
-
let(:params_filters) { [:bar] }
|
322
|
-
let(:url) { 'https://www.honeybadger.io/?foo=1&bar=2&baz=3' }
|
307
|
+
context 'filtered parameters in query string' do
|
308
|
+
let(:params_filters) { [:foo, :bar] }
|
323
309
|
|
310
|
+
describe '#url' do
|
311
|
+
let(:notice) { build_notice(:params_filters => params_filters, :url => 'https://www.honeybadger.io/?foo=1&bar=2&baz=3') }
|
324
312
|
it 'filters query' do
|
325
|
-
expect(notice.url).to eq 'https://www.honeybadger.io/?foo=
|
313
|
+
expect(notice.url).to eq 'https://www.honeybadger.io/?foo=[FILTERED]&bar=[FILTERED]&baz=3'
|
326
314
|
end
|
327
315
|
end
|
328
316
|
|
329
|
-
|
330
|
-
let(:
|
317
|
+
describe '#cgi_data' do
|
318
|
+
let(:cgi_data) { { 'QUERY_STRING' => 'foo=1&bar=2&baz=3', 'ORIGINAL_FULLPATH' => '/?foo=1&bar=2&baz=3' } }
|
319
|
+
let(:notice) { build_notice(:params_filters => params_filters, :cgi_data => cgi_data) }
|
320
|
+
|
321
|
+
subject { notice.cgi_data }
|
331
322
|
|
332
|
-
it '
|
333
|
-
expect(
|
323
|
+
it 'filters QUERY_STRING key' do
|
324
|
+
expect(subject['QUERY_STRING']).to eq 'foo=[FILTERED]&bar=[FILTERED]&baz=3'
|
334
325
|
end
|
326
|
+
|
327
|
+
it 'filters ORIGINAL_FULLPATH key' do
|
328
|
+
expect(subject['ORIGINAL_FULLPATH']).to eq '/?foo=[FILTERED]&bar=[FILTERED]&baz=3'
|
329
|
+
end
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
describe '#filter_url' do
|
334
|
+
let(:notice) { build_notice(:params_filters => [], :url => url) }
|
335
|
+
subject { notice.send(:filter_url, url) }
|
336
|
+
|
337
|
+
context 'malformed query' do
|
338
|
+
let(:url) { 'https://www.honeybadger.io/?foobar12' }
|
339
|
+
it { should eq url }
|
335
340
|
end
|
336
341
|
|
337
342
|
context 'no query' do
|
338
343
|
let(:url) { 'https://www.honeybadger.io' }
|
339
|
-
|
340
|
-
it 'keeps original URL' do
|
341
|
-
expect(notice.url).to eq url
|
342
|
-
end
|
344
|
+
it { should eq url }
|
343
345
|
end
|
344
346
|
|
345
347
|
context 'malformed url' do
|
346
348
|
let(:url) { 'http s ! honeybadger' }
|
347
|
-
|
348
|
-
|
349
|
-
expect { URI.parse(url) }.to raise_error
|
350
|
-
end
|
351
|
-
|
352
|
-
it 'keeps original URL' do
|
353
|
-
expect(notice.url).to eq url
|
354
|
-
end
|
349
|
+
before { expect { URI.parse(url) }.to raise_error }
|
350
|
+
it { should eq url }
|
355
351
|
end
|
356
352
|
|
357
353
|
context 'complex url' do
|
358
354
|
let(:url) { 'https://foo:bar@www.honeybadger.io:123/asdf/?foo=1&bar=2&baz=3' }
|
359
|
-
|
360
|
-
it 'keeps original URL' do
|
361
|
-
expect(notice.url).to eq url
|
362
|
-
end
|
355
|
+
it { should eq url }
|
363
356
|
end
|
364
357
|
end
|
365
358
|
|
@@ -7,10 +7,6 @@ describe 'Honeybadger' do
|
|
7
7
|
class ContinuedException < Exception
|
8
8
|
end
|
9
9
|
|
10
|
-
before(:each) do
|
11
|
-
reset_config
|
12
|
-
end
|
13
|
-
|
14
10
|
def assert_sends(notice, notice_args)
|
15
11
|
Honeybadger::Notice.should_receive(:new).with(hash_including(notice_args))
|
16
12
|
Honeybadger.sender.should_receive(:send_to_honeybadger).with(notice)
|
@@ -24,6 +20,66 @@ describe 'Honeybadger' do
|
|
24
20
|
Honeybadger.configure { |config| config.environment_name = 'development' }
|
25
21
|
end
|
26
22
|
|
23
|
+
before(:each) { reset_config }
|
24
|
+
|
25
|
+
describe "#ping" do
|
26
|
+
let(:config) { Honeybadger::Configuration.new }
|
27
|
+
let(:sender) { double() }
|
28
|
+
|
29
|
+
let(:invoke_subject) { Honeybadger.ping(config) }
|
30
|
+
subject { invoke_subject }
|
31
|
+
|
32
|
+
before do
|
33
|
+
config.framework = 'Rails 4.1.0'
|
34
|
+
config.environment_name = 'production'
|
35
|
+
config.hostname = 'twix'
|
36
|
+
stub_const('Honeybadger::VERSION', '1.11.0')
|
37
|
+
|
38
|
+
Honeybadger.stub(:sender).and_return(sender)
|
39
|
+
end
|
40
|
+
|
41
|
+
context "configuration is public" do
|
42
|
+
before { config.stub(:public?).and_return(true) }
|
43
|
+
|
44
|
+
it "pings the sender" do
|
45
|
+
sender.should_receive(:ping).with(hash_including(:version => '1.11.0', :framework => 'Rails 4.1.0', :environment => 'production', :hostname => 'twix'))
|
46
|
+
invoke_subject
|
47
|
+
end
|
48
|
+
|
49
|
+
context "result is truthy" do
|
50
|
+
before { sender.should_receive(:ping).and_return(result) }
|
51
|
+
|
52
|
+
context "result does not contain features" do
|
53
|
+
let(:result) { {} }
|
54
|
+
it { should be_nil }
|
55
|
+
specify { expect { subject }.not_to change(config, :features) }
|
56
|
+
end
|
57
|
+
|
58
|
+
context "result contains features" do
|
59
|
+
let(:result) { {'features' => {'notices' => true, 'metrics' => true}} }
|
60
|
+
it { should eq result['features'] }
|
61
|
+
specify { expect { subject }.to change(config, :features).to(result['features']) }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "result is falsey" do
|
66
|
+
before { sender.should_receive(:ping) }
|
67
|
+
it { should be_nil }
|
68
|
+
specify { expect { invoke_subject }.not_to change(config, :features) }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "configuration is not public" do
|
73
|
+
before { config.stub(:public?).and_return(false) }
|
74
|
+
it { should be_nil }
|
75
|
+
|
76
|
+
it "doesn't attempt to ping sender" do
|
77
|
+
sender.should_not_receive(:ping)
|
78
|
+
invoke_subject
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
27
83
|
it "yields and save a configuration when configuring" do
|
28
84
|
yielded_configuration = nil
|
29
85
|
Honeybadger.configure do |config|
|
@@ -12,11 +12,12 @@ describe Honeybadger::UserFeedback do
|
|
12
12
|
let(:response) { Net::HTTP.get_response(URI.parse("http://example.com/")) }
|
13
13
|
|
14
14
|
before do
|
15
|
+
reset_config
|
15
16
|
ShamRack.mount(informer_app, "example.com")
|
16
17
|
end
|
17
18
|
|
18
19
|
context "feedback feature is disabled by ping" do
|
19
|
-
it
|
20
|
+
it "does not modify the output" do
|
20
21
|
expect(response.body).to eq '<!-- HONEYBADGER FEEDBACK -->'
|
21
22
|
end
|
22
23
|
end
|
@@ -29,25 +30,49 @@ describe Honeybadger::UserFeedback do
|
|
29
30
|
context "there is a honeybadger id" do
|
30
31
|
let(:honeybadger_id) { 1 }
|
31
32
|
|
32
|
-
it
|
33
|
+
it "modifies output" do
|
33
34
|
rendered_length = informer_app.render_form(1).size
|
34
35
|
expect(response.body).to match(/honeybadger_feedback_token/)
|
35
36
|
expect(response["Content-Length"].to_i).to eq rendered_length
|
36
37
|
end
|
37
38
|
|
39
|
+
context "a project root is configured" do
|
40
|
+
let(:tmp_dir) { File.expand_path('../../../tmp', __FILE__) }
|
41
|
+
let(:template_dir) { File.join(tmp_dir, 'lib', 'honeybadger', 'templates') }
|
42
|
+
let(:template_file) { File.join(template_dir, 'feedback_form.erb') }
|
43
|
+
|
44
|
+
before do
|
45
|
+
FileUtils.mkdir_p(template_dir)
|
46
|
+
FileUtils.rm_f(template_file)
|
47
|
+
Honeybadger.configure(true) do |config|
|
48
|
+
config.project_root = tmp_dir
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "custom template is implemented" do
|
53
|
+
before do
|
54
|
+
File.open(template_file, 'w') { |f| f.write 'custom feedback form' }
|
55
|
+
end
|
56
|
+
|
57
|
+
it "renders with custom template" do
|
58
|
+
expect(response.body).to match(/custom feedback form/)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
38
63
|
context "feedback feature is disabled by customer" do
|
39
64
|
before do
|
40
65
|
Honeybadger.configuration.feedback = false
|
41
66
|
end
|
42
67
|
|
43
|
-
it
|
68
|
+
it "does not modify the output" do
|
44
69
|
expect(response.body).to eq '<!-- HONEYBADGER FEEDBACK -->'
|
45
70
|
end
|
46
71
|
end
|
47
72
|
end
|
48
73
|
|
49
74
|
context "there is no honeybadger id" do
|
50
|
-
it
|
75
|
+
it "does not modify the output" do
|
51
76
|
expect(response.body).to eq '<!-- HONEYBADGER FEEDBACK -->'
|
52
77
|
end
|
53
78
|
end
|
@@ -17,14 +17,17 @@ describe HoneybadgerTasks do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
context "being quiet" do
|
20
|
-
before
|
20
|
+
before do
|
21
|
+
HoneybadgerTasks.stub(:puts)
|
22
|
+
$stderr.stub(:puts)
|
23
|
+
end
|
21
24
|
|
22
25
|
context "in a configured project" do
|
23
26
|
before(:each) { Honeybadger.configure { |config| config.api_key = "1234123412341234" } }
|
24
27
|
|
25
28
|
context "on deploy({})" do
|
26
29
|
it "complains about missing rails env" do
|
27
|
-
|
30
|
+
$stderr.should_receive(:puts).with(/which environment/i)
|
28
31
|
HoneybadgerTasks.deploy({})
|
29
32
|
end
|
30
33
|
|
@@ -95,11 +98,17 @@ describe HoneybadgerTasks do
|
|
95
98
|
end
|
96
99
|
|
97
100
|
it "puts the response body on failure" do
|
98
|
-
|
101
|
+
$stderr.should_receive(:puts).with(/body/)
|
99
102
|
@http_proxy.should_receive(:request).with(anything).and_return(unsuccessful_response('body'))
|
100
103
|
HoneybadgerTasks.deploy(@options)
|
101
104
|
end
|
102
105
|
|
106
|
+
it "puts the response class on failure" do
|
107
|
+
$stderr.should_receive(:puts).with(/Net::HTTPClientError/)
|
108
|
+
@http_proxy.should_receive(:request).with(anything).and_return(unsuccessful_response)
|
109
|
+
HoneybadgerTasks.deploy(@options)
|
110
|
+
end
|
111
|
+
|
103
112
|
it "returns false on failure" do
|
104
113
|
@http_proxy.should_receive(:request).with(anything).and_return(unsuccessful_response('body'))
|
105
114
|
output = HoneybadgerTasks.deploy(@options)
|
@@ -148,7 +157,7 @@ describe HoneybadgerTasks do
|
|
148
157
|
|
149
158
|
context "on deploy(:environment => 'staging')" do
|
150
159
|
it "complains about missing api key" do
|
151
|
-
|
160
|
+
$stderr.should_receive(:puts).with(/api key/i)
|
152
161
|
HoneybadgerTasks.deploy(:environment => "staging")
|
153
162
|
end
|
154
163
|
|