hatless-hoptoad_notifier 2.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. data/CHANGELOG +149 -0
  2. data/INSTALL +25 -0
  3. data/MIT-LICENSE +22 -0
  4. data/README.rdoc +382 -0
  5. data/Rakefile +217 -0
  6. data/SUPPORTED_RAILS_VERSIONS +9 -0
  7. data/TESTING.rdoc +8 -0
  8. data/generators/hoptoad/hoptoad_generator.rb +54 -0
  9. data/generators/hoptoad/lib/insert_commands.rb +34 -0
  10. data/generators/hoptoad/lib/rake_commands.rb +24 -0
  11. data/generators/hoptoad/templates/capistrano_hook.rb +6 -0
  12. data/generators/hoptoad/templates/hoptoad_notifier_tasks.rake +25 -0
  13. data/generators/hoptoad/templates/initializer.rb +6 -0
  14. data/lib/hoptoad_notifier/backtrace.rb +99 -0
  15. data/lib/hoptoad_notifier/capistrano.rb +20 -0
  16. data/lib/hoptoad_notifier/configuration.rb +232 -0
  17. data/lib/hoptoad_notifier/notice.rb +318 -0
  18. data/lib/hoptoad_notifier/rack.rb +40 -0
  19. data/lib/hoptoad_notifier/rails/action_controller_catcher.rb +29 -0
  20. data/lib/hoptoad_notifier/rails/controller_methods.rb +58 -0
  21. data/lib/hoptoad_notifier/rails/error_lookup.rb +33 -0
  22. data/lib/hoptoad_notifier/rails.rb +37 -0
  23. data/lib/hoptoad_notifier/rails3_tasks.rb +90 -0
  24. data/lib/hoptoad_notifier/railtie.rb +23 -0
  25. data/lib/hoptoad_notifier/sender.rb +63 -0
  26. data/lib/hoptoad_notifier/tasks.rb +97 -0
  27. data/lib/hoptoad_notifier/version.rb +3 -0
  28. data/lib/hoptoad_notifier.rb +148 -0
  29. data/lib/hoptoad_tasks.rb +40 -0
  30. data/lib/rails/generators/hoptoad/hoptoad_generator.rb +64 -0
  31. data/lib/templates/rescue.erb +91 -0
  32. data/rails/init.rb +1 -0
  33. data/script/integration_test.rb +38 -0
  34. data/test/backtrace_test.rb +118 -0
  35. data/test/catcher_test.rb +324 -0
  36. data/test/configuration_test.rb +208 -0
  37. data/test/helper.rb +239 -0
  38. data/test/hoptoad_tasks_test.rb +138 -0
  39. data/test/logger_test.rb +85 -0
  40. data/test/notice_test.rb +443 -0
  41. data/test/notifier_test.rb +222 -0
  42. data/test/rack_test.rb +58 -0
  43. data/test/rails_initializer_test.rb +36 -0
  44. data/test/sender_test.rb +123 -0
  45. metadata +204 -0
data/Rakefile ADDED
@@ -0,0 +1,217 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'rake/gempackagetask'
5
+ require 'cucumber/rake/task'
6
+
7
+ desc 'Default: run unit tests.'
8
+ task :default => [:test, :cucumber]
9
+
10
+ desc 'Test the hoptoad_notifier gem.'
11
+ Rake::TestTask.new(:test) do |t|
12
+ t.libs << 'lib'
13
+ t.pattern = 'test/**/*_test.rb'
14
+ t.verbose = true
15
+ end
16
+
17
+ desc 'Run ginger tests'
18
+ task :ginger do
19
+ $LOAD_PATH << File.join(*%w[vendor ginger lib])
20
+ ARGV.clear
21
+ ARGV << 'test'
22
+ load File.join(*%w[vendor ginger bin ginger])
23
+ end
24
+
25
+ namespace :changeling do
26
+ desc "Bumps the version by a minor or patch version, depending on what was passed in."
27
+ task :bump, :part do |t, args|
28
+ # Thanks, Jeweler!
29
+ if HoptoadNotifier::VERSION =~ /^(\d+)\.(\d+)\.(\d+)(?:\.(.*?))?$/
30
+ major = $1.to_i
31
+ minor = $2.to_i
32
+ patch = $3.to_i
33
+ build = $4
34
+ else
35
+ abort
36
+ end
37
+
38
+ case args[:part]
39
+ when /minor/
40
+ minor += 1
41
+ patch = 0
42
+ when /patch/
43
+ patch += 1
44
+ else
45
+ abort
46
+ end
47
+
48
+ version = [major, minor, patch, build].compact.join('.')
49
+
50
+ File.open(File.join("lib", "hoptoad_notifier", "version.rb"), "w") do |f|
51
+ f.write <<EOF
52
+ module HoptoadNotifier
53
+ VERSION = "#{version}".freeze
54
+ end
55
+ EOF
56
+ end
57
+ end
58
+
59
+ desc "Writes out the new CHANGELOG and prepares the release"
60
+ task :change do
61
+ load 'lib/hoptoad_notifier/version.rb'
62
+ file = "CHANGELOG"
63
+ old = File.read(file)
64
+ version = HoptoadNotifier::VERSION
65
+ message = "Bumping to version #{version}"
66
+
67
+ File.open(file, "w") do |f|
68
+ f.write <<EOF
69
+ Version #{version} - #{Date.today}
70
+ ===============================================================================
71
+
72
+ #{`git log $(git tag | tail -1)..HEAD | git shortlog`}
73
+ #{old}
74
+ EOF
75
+ end
76
+
77
+ exec ["#{ENV["EDITOR"]} #{file}",
78
+ "git commit -aqm '#{message}'",
79
+ "git tag -a -m '#{message}' v#{version}",
80
+ "echo '\n\n\033[32mMarked v#{version} /' `git show-ref -s refs/heads/master` 'for release. Run: rake changeling:push\033[0m\n\n'"].join(' && ')
81
+ end
82
+
83
+ desc "Bump by a minor version (1.2.3 => 1.3.0)"
84
+ task :minor do |t|
85
+ Rake::Task['changeling:bump'].invoke(t.name)
86
+ Rake::Task['changeling:change'].invoke
87
+ end
88
+
89
+ desc "Bump by a patch version, (1.2.3 => 1.2.4)"
90
+ task :patch do |t|
91
+ Rake::Task['changeling:bump'].invoke(t.name)
92
+ Rake::Task['changeling:change'].invoke
93
+ end
94
+
95
+ desc "Push the latest version and tags"
96
+ task :push do |t|
97
+ system("git push origin master")
98
+ system("git push origin $(git tag | tail -1)")
99
+ end
100
+ end
101
+
102
+ begin
103
+ require 'yard'
104
+ YARD::Rake::YardocTask.new do |t|
105
+ t.files = ['lib/**/*.rb', 'TESTING.rdoc']
106
+ end
107
+ rescue LoadError
108
+ end
109
+
110
+ GEM_ROOT = File.dirname(__FILE__).freeze
111
+ VERSION_FILE = File.join(GEM_ROOT, 'lib', 'hoptoad_notifier', 'version')
112
+
113
+ require VERSION_FILE
114
+
115
+ gemspec = Gem::Specification.new do |s|
116
+ s.name = %q{hoptoad_notifier}
117
+ s.version = HoptoadNotifier::VERSION
118
+ s.summary = %q{Send your application errors to our hosted service and reclaim your inbox.}
119
+
120
+ s.files = FileList['[A-Z]*', 'generators/**/*.*', 'lib/**/*.rb',
121
+ 'test/**/*.rb', 'rails/**/*.rb', 'script/*',
122
+ 'lib/templates/*.erb']
123
+ s.require_path = 'lib'
124
+ s.test_files = Dir[*['test/**/*_test.rb']]
125
+
126
+ s.has_rdoc = true
127
+ s.extra_rdoc_files = ["README.rdoc"]
128
+ s.rdoc_options = ['--line-numbers', "--main", "README.rdoc"]
129
+
130
+ s.add_runtime_dependency("activesupport")
131
+ s.add_development_dependency("activerecord")
132
+ s.add_development_dependency("actionpack")
133
+ s.add_development_dependency("jferris-mocha")
134
+ s.add_development_dependency("nokogiri")
135
+ s.add_development_dependency("shoulda")
136
+
137
+ s.authors = ["thoughtbot, inc"]
138
+ s.email = %q{support@hoptoadapp.com}
139
+ s.homepage = "http://www.hoptoadapp.com"
140
+
141
+ s.platform = Gem::Platform::RUBY
142
+ end
143
+
144
+ Rake::GemPackageTask.new gemspec do |pkg|
145
+ pkg.need_tar = true
146
+ pkg.need_zip = true
147
+ end
148
+
149
+ desc "Clean files generated by rake tasks"
150
+ task :clobber => [:clobber_rdoc, :clobber_package]
151
+
152
+ desc "Generate a gemspec file"
153
+ task :gemspec do
154
+ File.open("#{gemspec.name}.gemspec", 'w') do |f|
155
+ f.write gemspec.to_ruby
156
+ end
157
+ end
158
+
159
+ LOCAL_GEM_ROOT = File.join(GEM_ROOT, 'tmp', 'local_gems').freeze
160
+ RAILS_VERSIONS = IO.read('SUPPORTED_RAILS_VERSIONS').strip.split("\n")
161
+ LOCAL_GEMS = [['sham_rack', nil], ['capistrano', nil], ['sqlite3-ruby', nil], ['sinatra', nil]] +
162
+ RAILS_VERSIONS.collect { |version| ['rails', version] }
163
+
164
+ task :vendor_test_gems do
165
+ old_gem_path = ENV['GEM_PATH']
166
+ old_gem_home = ENV['GEM_HOME']
167
+ ENV['GEM_PATH'] = LOCAL_GEM_ROOT
168
+ ENV['GEM_HOME'] = LOCAL_GEM_ROOT
169
+ LOCAL_GEMS.each do |gem_name, version|
170
+ gem_file_pattern = [gem_name, version || '*'].compact.join('-')
171
+ version_option = version ? "-v #{version}" : ''
172
+ pattern = File.join(LOCAL_GEM_ROOT, 'gems', "#{gem_file_pattern}")
173
+ existing = Dir.glob(pattern).first
174
+ unless existing
175
+ command = "gem install -i #{LOCAL_GEM_ROOT} --no-ri --no-rdoc --backtrace #{version_option} #{gem_name}"
176
+ puts "Vendoring #{gem_file_pattern}..."
177
+ unless system("#{command} 2>&1")
178
+ puts "Command failed: #{command}"
179
+ exit(1)
180
+ end
181
+ end
182
+ end
183
+ ENV['GEM_PATH'] = old_gem_path
184
+ ENV['GEM_HOME'] = old_gem_home
185
+ end
186
+
187
+ Cucumber::Rake::Task.new(:cucumber) do |t|
188
+ t.fork = true
189
+ t.cucumber_opts = ['--format', (ENV['CUCUMBER_FORMAT'] || 'progress')]
190
+ end
191
+
192
+ task :cucumber => [:gemspec, :vendor_test_gems]
193
+
194
+ def define_rails_cucumber_tasks(additional_cucumber_args = '')
195
+ namespace :rails do
196
+ RAILS_VERSIONS.each do |version|
197
+ desc "Test integration of the gem with Rails #{version}"
198
+ task version => [:gemspec, :vendor_test_gems] do
199
+ puts "Testing Rails #{version}"
200
+ ENV['RAILS_VERSION'] = version
201
+ system("cucumber --format #{ENV['CUCUMBER_FORMAT'] || 'progress'} #{additional_cucumber_args} features/rails.feature")
202
+ end
203
+ end
204
+
205
+ desc "Test integration of the gem with all Rails versions"
206
+ task :all => RAILS_VERSIONS
207
+ end
208
+ end
209
+
210
+ namespace :cucumber do
211
+ namespace :wip do
212
+ define_rails_cucumber_tasks('--tags @wip')
213
+ end
214
+
215
+ define_rails_cucumber_tasks
216
+ end
217
+
@@ -0,0 +1,9 @@
1
+ 1.2.6
2
+ 2.0.2
3
+ 2.1.0
4
+ 2.1.2
5
+ 2.2.2
6
+ 2.3.2
7
+ 2.3.4
8
+ 2.3.5
9
+ 3.0.0.beta4
data/TESTING.rdoc ADDED
@@ -0,0 +1,8 @@
1
+ = For Maintainers:
2
+
3
+ When developing the Hoptoad Notifier, be sure to use the integration test
4
+ against an existing project on staging before pushing to master.
5
+
6
+ +./script/integration_test.rb <test project's api key> <staging server hostname>+
7
+
8
+ +./script/integration_test.rb <test project's api key> <staging server hostname> secure+
@@ -0,0 +1,54 @@
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 HoptoadGenerator < Rails::Generator::Base
5
+ def add_options!(opt)
6
+ opt.on('-k', '--api-key=key', String, "Your Hoptoad API key") {|v| options[:api_key] = v}
7
+ end
8
+
9
+ def manifest
10
+ if !api_key_configured? && !options[:api_key]
11
+ puts "Must pass --api-key or create config/initializers/hoptoad.rb"
12
+ exit
13
+ end
14
+ if plugin_is_present?
15
+ puts "You must first remove the hoptoad_notifier plugin. Please run: script/plugin remove hoptoad_notifier"
16
+ exit
17
+ end
18
+ record do |m|
19
+ m.directory 'lib/tasks'
20
+ m.file 'hoptoad_notifier_tasks.rake', 'lib/tasks/hoptoad_notifier_tasks.rake'
21
+ if ['config/deploy.rb', 'Capfile'].all? { |file| File.exists?(file) }
22
+ m.append_to 'config/deploy.rb', capistrano_hook
23
+ end
24
+ if options[:api_key]
25
+ if use_initializer?
26
+ m.template 'initializer.rb', 'config/initializers/hoptoad.rb',
27
+ :assigns => {:api_key => options[:api_key]}
28
+ else
29
+ m.template 'initializer.rb', 'config/hoptoad.rb',
30
+ :assigns => {:api_key => options[:api_key]}
31
+ m.append_to 'config/environment.rb', "require 'config/hoptoad'"
32
+ end
33
+ end
34
+ m.rake "hoptoad:test", :generate_only => true
35
+ end
36
+ end
37
+
38
+ def use_initializer?
39
+ Rails::VERSION::MAJOR > 1
40
+ end
41
+
42
+ def api_key_configured?
43
+ File.exists?('config/initializers/hoptoad.rb') ||
44
+ system("grep HoptoadNotifier config/environment.rb")
45
+ end
46
+
47
+ def capistrano_hook
48
+ IO.read(source_path('capistrano_hook.rb'))
49
+ end
50
+
51
+ def plugin_is_present?
52
+ File.exists?('vendor/plugins/hoptoad_notifier')
53
+ end
54
+ end
@@ -0,0 +1,34 @@
1
+ # Mostly pinched from http://github.com/ryanb/nifty-generators/tree/master
2
+
3
+ Rails::Generator::Commands::Base.class_eval do
4
+ def file_contains?(relative_destination, line)
5
+ File.read(destination_path(relative_destination)).include?(line)
6
+ end
7
+ end
8
+
9
+ Rails::Generator::Commands::Create.class_eval do
10
+ def append_to(file, line)
11
+ logger.insert "#{line} appended to #{file}"
12
+ unless options[:pretend] || file_contains?(file, line)
13
+ File.open(file, "a") do |file|
14
+ file.puts
15
+ file.puts line
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ Rails::Generator::Commands::Destroy.class_eval do
22
+ def append_to(file, line)
23
+ logger.remove "#{line} removed from #{file}"
24
+ unless options[:pretend]
25
+ gsub_file file, "\n#{line}", ''
26
+ end
27
+ end
28
+ end
29
+
30
+ Rails::Generator::Commands::List.class_eval do
31
+ def append_to(file, line)
32
+ logger.insert "#{line} appended to #{file}"
33
+ end
34
+ end
@@ -0,0 +1,24 @@
1
+ Rails::Generator::Commands::Create.class_eval do
2
+ def rake(cmd, opts = {})
3
+ logger.rake "rake #{cmd}"
4
+ unless system("rake #{cmd}")
5
+ logger.rake "#{cmd} failed. Rolling back"
6
+ command(:destroy).invoke!
7
+ end
8
+ end
9
+ end
10
+
11
+ Rails::Generator::Commands::Destroy.class_eval do
12
+ def rake(cmd, opts = {})
13
+ unless opts[:generate_only]
14
+ logger.rake "rake #{cmd}"
15
+ system "rake #{cmd}"
16
+ end
17
+ end
18
+ end
19
+
20
+ Rails::Generator::Commands::List.class_eval do
21
+ def rake(cmd, opts = {})
22
+ logger.rake "rake #{cmd}"
23
+ end
24
+ end
@@ -0,0 +1,6 @@
1
+
2
+ Dir[File.join(File.dirname(__FILE__), '..', 'vendor', 'gems', 'hoptoad_notifier-*')].each do |vendored_notifier|
3
+ $: << File.join(vendored_notifier, 'lib')
4
+ end
5
+
6
+ require 'hoptoad_notifier/capistrano'
@@ -0,0 +1,25 @@
1
+ # Don't load anything when running the gems:* tasks.
2
+ # Otherwise, hoptoad_notifier will be considered a framework gem.
3
+ # https://thoughtbot.lighthouseapp.com/projects/14221/tickets/629
4
+ unless ARGV.any? {|a| a =~ /^gems/}
5
+
6
+ Dir[File.join(RAILS_ROOT, 'vendor', 'gems', 'hoptoad_notifier-*')].each do |vendored_notifier|
7
+ $: << File.join(vendored_notifier, 'lib')
8
+ end
9
+
10
+ begin
11
+ require 'hoptoad_notifier/tasks'
12
+ rescue LoadError => exception
13
+ namespace :hoptoad do
14
+ %w(deploy test log_stdout).each do |task_name|
15
+ desc "Missing dependency for hoptoad:#{task_name}"
16
+ task task_name do
17
+ $stderr.puts "Failed to run hoptoad:#{task_name} because of missing dependency."
18
+ $stderr.puts "You probably need to run `rake gems:install` to install the hoptoad_notifier gem"
19
+ abort exception.inspect
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ end
@@ -0,0 +1,6 @@
1
+ <% if Rails::VERSION::MAJOR < 3 && Rails::VERSION::MINOR < 2 -%>
2
+ require 'hoptoad_notifier/rails'
3
+ <% end -%>
4
+ HoptoadNotifier.configure do |config|
5
+ config.api_key = '<%= api_key %>'
6
+ end
@@ -0,0 +1,99 @@
1
+ module HoptoadNotifier
2
+ # Front end to parsing the backtrace for each notice
3
+ class Backtrace
4
+
5
+ # Handles backtrace parsing line by line
6
+ class Line
7
+
8
+ INPUT_FORMAT = %r{^([^:]+):(\d+)(?::in `([^']+)')?$}.freeze
9
+
10
+ # The file portion of the line (such as app/models/user.rb)
11
+ attr_reader :file
12
+
13
+ # The line number portion of the line
14
+ attr_reader :number
15
+
16
+ # The method of the line (such as index)
17
+ attr_reader :method
18
+
19
+ # Parses a single line of a given backtrace
20
+ # @param [String] unparsed_line The raw line from +caller+ or some backtrace
21
+ # @return [Line] The parsed backtrace line
22
+ def self.parse(unparsed_line)
23
+ _, file, number, method = unparsed_line.match(INPUT_FORMAT).to_a
24
+ new(file, number, method)
25
+ end
26
+
27
+ def initialize(file, number, method)
28
+ self.file = file
29
+ self.number = number
30
+ self.method = method
31
+ end
32
+
33
+ # Reconstructs the line in a readable fashion
34
+ def to_s
35
+ "#{file}:#{number}:in `#{method}'"
36
+ end
37
+
38
+ def ==(other)
39
+ to_s == other.to_s
40
+ end
41
+
42
+ def inspect
43
+ "<Line:#{to_s}>"
44
+ end
45
+
46
+ private
47
+
48
+ attr_writer :file, :number, :method
49
+ end
50
+
51
+ # holder for an Array of Backtrace::Line instances
52
+ attr_reader :lines
53
+
54
+ def self.parse(ruby_backtrace, opts = {})
55
+ ruby_lines = split_multiline_backtrace(ruby_backtrace)
56
+
57
+ filters = opts[:filters] || []
58
+ filtered_lines = ruby_lines.to_a.map do |line|
59
+ filters.inject(line) do |line, proc|
60
+ proc.call(line)
61
+ end
62
+ end.compact
63
+
64
+ lines = filtered_lines.collect do |unparsed_line|
65
+ Line.parse(unparsed_line)
66
+ end
67
+
68
+ instance = new(lines)
69
+ end
70
+
71
+ def initialize(lines)
72
+ self.lines = lines
73
+ end
74
+
75
+ def inspect
76
+ "<Backtrace: " + lines.collect { |line| line.inspect }.join(", ") + ">"
77
+ end
78
+
79
+ def ==(other)
80
+ if other.respond_to?(:lines)
81
+ lines == other.lines
82
+ else
83
+ false
84
+ end
85
+ end
86
+
87
+ private
88
+
89
+ attr_writer :lines
90
+
91
+ def self.split_multiline_backtrace(backtrace)
92
+ if backtrace.to_a.size == 1
93
+ backtrace.to_a.first.split(/\n\s*/)
94
+ else
95
+ backtrace
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,20 @@
1
+ # Defines deploy:notify_hoptoad which will send information about the deploy to Hoptoad.
2
+
3
+ Capistrano::Configuration.instance(:must_exist).load do
4
+ after "deploy", "deploy:notify_hoptoad"
5
+ after "deploy:migrations", "deploy:notify_hoptoad"
6
+
7
+ namespace :deploy do
8
+ desc "Notify Hoptoad of the deployment"
9
+ task :notify_hoptoad, :except => { :no_release => true } do
10
+ rails_env = fetch(:hoptoad_env, fetch(:rails_env, "production"))
11
+ local_user = ENV['USER'] || ENV['USERNAME']
12
+ executable = RUBY_PLATFORM.downcase.include?('mswin') ? 'rake.bat' : 'rake'
13
+ notify_command = "#{executable} hoptoad:deploy TO=#{rails_env} REVISION=#{current_revision} REPO=#{repository} USER=#{local_user}"
14
+ notify_command << " API_KEY=#{ENV['API_KEY']}" if ENV['API_KEY']
15
+ puts "Notifying Hoptoad of Deploy (#{notify_command})"
16
+ `#{notify_command}`
17
+ puts "Hoptoad Notification Complete."
18
+ end
19
+ end
20
+ end