errornot_notifier 0.1.0
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.
- data/INSTALL +25 -0
- data/MIT-LICENSE +22 -0
- data/README.rdoc +289 -0
- data/Rakefile +124 -0
- data/SUPPORTED_RAILS_VERSIONS +8 -0
- data/TESTING.rdoc +8 -0
- data/generators/hoptoad/hoptoad_generator.rb +55 -0
- data/generators/hoptoad/lib/insert_commands.rb +34 -0
- data/generators/hoptoad/lib/rake_commands.rb +24 -0
- data/generators/hoptoad/templates/capistrano_hook.rb +6 -0
- data/generators/hoptoad/templates/hoptoad_notifier_tasks.rake +5 -0
- data/generators/hoptoad/templates/initializer.rb +7 -0
- data/lib/hoptoad_notifier/backtrace.rb +99 -0
- data/lib/hoptoad_notifier/capistrano.rb +20 -0
- data/lib/hoptoad_notifier/configuration.rb +232 -0
- data/lib/hoptoad_notifier/notice.rb +287 -0
- data/lib/hoptoad_notifier/rack.rb +40 -0
- data/lib/hoptoad_notifier/rails/action_controller_catcher.rb +29 -0
- data/lib/hoptoad_notifier/rails/controller_methods.rb +59 -0
- data/lib/hoptoad_notifier/rails/error_lookup.rb +33 -0
- data/lib/hoptoad_notifier/rails.rb +37 -0
- data/lib/hoptoad_notifier/sender.rb +85 -0
- data/lib/hoptoad_notifier/tasks.rb +97 -0
- data/lib/hoptoad_notifier/version.rb +3 -0
- data/lib/hoptoad_notifier.rb +146 -0
- data/lib/hoptoad_tasks.rb +37 -0
- data/lib/templates/rescue.erb +91 -0
- data/rails/init.rb +1 -0
- data/script/integration_test.rb +38 -0
- data/test/backtrace_test.rb +118 -0
- data/test/catcher_test.rb +300 -0
- data/test/configuration_test.rb +208 -0
- data/test/helper.rb +232 -0
- data/test/hoptoad_tasks_test.rb +138 -0
- data/test/logger_test.rb +85 -0
- data/test/notice_test.rb +395 -0
- data/test/notifier_test.rb +222 -0
- data/test/rack_test.rb +58 -0
- data/test/rails_initializer_test.rb +36 -0
- data/test/sender_test.rb +123 -0
- metadata +164 -0
@@ -0,0 +1,59 @@
|
|
1
|
+
module HoptoadNotifier
|
2
|
+
module Rails
|
3
|
+
module ControllerMethods
|
4
|
+
private
|
5
|
+
|
6
|
+
# This method should be used for sending manual notifications while you are still
|
7
|
+
# inside the controller. Otherwise it works like HoptoadNotifier.notify.
|
8
|
+
def notify_hoptoad(hash_or_exception)
|
9
|
+
unless consider_all_requests_local || local_request?
|
10
|
+
HoptoadNotifier.notify(hash_or_exception, hoptoad_request_data)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def hoptoad_ignore_user_agent? #:nodoc:
|
15
|
+
# Rails 1.2.6 doesn't have request.user_agent, so check for it here
|
16
|
+
user_agent = request.respond_to?(:user_agent) ? request.user_agent : request.env["HTTP_USER_AGENT"]
|
17
|
+
HoptoadNotifier.configuration.ignore_user_agent.flatten.any? { |ua| ua === user_agent }
|
18
|
+
end
|
19
|
+
|
20
|
+
def hoptoad_request_data
|
21
|
+
{ :parameters => hoptoad_filter_if_filtering(params.to_hash),
|
22
|
+
:session_data => hoptoad_session_data,
|
23
|
+
:controller => params[:controller],
|
24
|
+
:action => params[:action],
|
25
|
+
:url => hoptoad_request_url,
|
26
|
+
:cgi_data => hoptoad_filter_if_filtering(request.env),
|
27
|
+
:environment_vars => hoptoad_filter_if_filtering(ENV) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def hoptoad_filter_if_filtering(hash)
|
31
|
+
if respond_to?(:filter_parameters)
|
32
|
+
filter_parameters(hash) rescue hash
|
33
|
+
else
|
34
|
+
hash
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def hoptoad_session_data
|
39
|
+
if session.respond_to?(:to_hash)
|
40
|
+
session.to_hash
|
41
|
+
else
|
42
|
+
session.data
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def hoptoad_request_url
|
47
|
+
url = "#{request.protocol}#{request.host}"
|
48
|
+
|
49
|
+
unless [80, 443].include?(request.port)
|
50
|
+
url << ":#{request.port}"
|
51
|
+
end
|
52
|
+
|
53
|
+
url << request.request_uri
|
54
|
+
url
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module HoptoadNotifier
|
2
|
+
module Rails
|
3
|
+
module ErrorLookup
|
4
|
+
|
5
|
+
# Sets up an alias chain to catch exceptions when Rails does
|
6
|
+
def self.included(base) #:nodoc:
|
7
|
+
base.send(:alias_method, :rescue_action_locally_without_hoptoad, :rescue_action_locally)
|
8
|
+
base.send(:alias_method, :rescue_action_locally, :rescue_action_locally_with_hoptoad)
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def rescue_action_locally_with_hoptoad(exception)
|
14
|
+
result = rescue_action_locally_without_hoptoad(exception)
|
15
|
+
|
16
|
+
if HoptoadNotifier.configuration.development_lookup
|
17
|
+
path = File.join(File.dirname(__FILE__), '..', '..', 'templates', 'rescue.erb')
|
18
|
+
notice = HoptoadNotifier.build_lookup_hash_for(exception, hoptoad_request_data)
|
19
|
+
|
20
|
+
result << @template.render(
|
21
|
+
:file => path,
|
22
|
+
:use_full_path => false,
|
23
|
+
:locals => { :host => HoptoadNotifier.configuration.host,
|
24
|
+
:api_key => HoptoadNotifier.configuration.api_key,
|
25
|
+
:notice => notice })
|
26
|
+
end
|
27
|
+
|
28
|
+
result
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'hoptoad_notifier'
|
2
|
+
require 'hoptoad_notifier/rails/controller_methods'
|
3
|
+
require 'hoptoad_notifier/rails/action_controller_catcher'
|
4
|
+
require 'hoptoad_notifier/rails/error_lookup'
|
5
|
+
|
6
|
+
module HoptoadNotifier
|
7
|
+
module Rails
|
8
|
+
def self.initialize
|
9
|
+
if defined?(ActionController::Base)
|
10
|
+
ActionController::Base.send(:include, HoptoadNotifier::Rails::ActionControllerCatcher)
|
11
|
+
ActionController::Base.send(:include, HoptoadNotifier::Rails::ErrorLookup)
|
12
|
+
ActionController::Base.send(:include, HoptoadNotifier::Rails::ControllerMethods)
|
13
|
+
end
|
14
|
+
|
15
|
+
rails_logger = if defined?(::Rails.logger)
|
16
|
+
::Rails.logger
|
17
|
+
elsif defined?(RAILS_DEFAULT_LOGGER)
|
18
|
+
RAILS_DEFAULT_LOGGER
|
19
|
+
end
|
20
|
+
|
21
|
+
if defined?(::Rails.configuration) && ::Rails.configuration.respond_to?(:middleware)
|
22
|
+
::Rails.configuration.middleware.insert_after 'ActionController::Failsafe',
|
23
|
+
HoptoadNotifier::Rack
|
24
|
+
end
|
25
|
+
|
26
|
+
HoptoadNotifier.configure(true) do |config|
|
27
|
+
config.logger = rails_logger
|
28
|
+
config.environment_name = RAILS_ENV if defined?(RAILS_ENV)
|
29
|
+
config.project_root = RAILS_ROOT if defined?(RAILS_ROOT)
|
30
|
+
config.framework = "Rails: #{::Rails::VERSION::STRING}" if defined?(::Rails::VERSION)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
HoptoadNotifier::Rails.initialize
|
37
|
+
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module HoptoadNotifier
|
2
|
+
# Sends out the notice to Hoptoad
|
3
|
+
class Sender
|
4
|
+
|
5
|
+
NOTICES_URI = '/errors'.freeze
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
[:proxy_host, :proxy_port, :proxy_user, :proxy_pass, :protocol,
|
9
|
+
:host, :port, :secure, :http_open_timeout, :http_read_timeout].each do |option|
|
10
|
+
instance_variable_set("@#{option}", options[option])
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Methode extract from RestClient
|
15
|
+
# maybe need some test
|
16
|
+
def process_payload(p=nil, parent_key=nil)
|
17
|
+
unless p.is_a?(Hash)
|
18
|
+
p
|
19
|
+
else
|
20
|
+
p.keys.map do |k|
|
21
|
+
key = parent_key ? "#{parent_key}[#{k}]" : k
|
22
|
+
if p[k].is_a? Hash
|
23
|
+
process_payload(p[k], key)
|
24
|
+
else
|
25
|
+
value = URI.escape(p[k].to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
|
26
|
+
"#{key}=#{value}"
|
27
|
+
end
|
28
|
+
end.join("&")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
# Sends the notice data off to Hoptoad for processing.
|
34
|
+
#
|
35
|
+
# @param [String] data The XML notice to be sent off
|
36
|
+
def send_to_hoptoad(data)
|
37
|
+
logger.debug { "Sending request to #{url.to_s}:\n#{data}" } if logger
|
38
|
+
|
39
|
+
http =
|
40
|
+
Net::HTTP::Proxy(proxy_host, proxy_port, proxy_user, proxy_pass).
|
41
|
+
new(url.host, url.port)
|
42
|
+
|
43
|
+
http.read_timeout = http_read_timeout
|
44
|
+
http.open_timeout = http_open_timeout
|
45
|
+
http.use_ssl = secure
|
46
|
+
|
47
|
+
response = begin
|
48
|
+
# TODO see how use http.post or convert all to restclient
|
49
|
+
#RestClient.post(url.to_s, data)
|
50
|
+
data = process_payload(data)
|
51
|
+
http.post(url.path, data, HEADERS)
|
52
|
+
rescue TimeoutError => e
|
53
|
+
log :error, "Timeout while contacting the Hoptoad server."
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
|
57
|
+
case response
|
58
|
+
when Net::HTTPSuccess then
|
59
|
+
log :info, "Success: #{response.class}", response
|
60
|
+
else
|
61
|
+
log :error, "Failure: #{response.class}", response
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
attr_reader :proxy_host, :proxy_port, :proxy_user, :proxy_pass, :protocol,
|
68
|
+
:host, :port, :secure, :http_open_timeout, :http_read_timeout
|
69
|
+
|
70
|
+
def url
|
71
|
+
URI.parse("#{protocol}://#{host}:#{port}").merge(NOTICES_URI)
|
72
|
+
end
|
73
|
+
|
74
|
+
def log(level, message, response = nil)
|
75
|
+
logger.send level, LOG_PREFIX + message if logger
|
76
|
+
HoptoadNotifier.report_environment_info
|
77
|
+
HoptoadNotifier.report_response_body(response.body) if response && response.respond_to?(:body)
|
78
|
+
end
|
79
|
+
|
80
|
+
def logger
|
81
|
+
HoptoadNotifier.logger
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'hoptoad_notifier'
|
2
|
+
|
3
|
+
namespace :hoptoad do
|
4
|
+
desc "Notify Hoptoad of a new deploy."
|
5
|
+
task :deploy => :environment do
|
6
|
+
require 'hoptoad_tasks'
|
7
|
+
HoptoadTasks.deploy(:rails_env => ENV['TO'],
|
8
|
+
:scm_revision => ENV['REVISION'],
|
9
|
+
:scm_repository => ENV['REPO'],
|
10
|
+
:local_username => ENV['USER'],
|
11
|
+
:api_key => ENV['API_KEY'])
|
12
|
+
end
|
13
|
+
|
14
|
+
task :log_stdout do
|
15
|
+
require 'logger'
|
16
|
+
RAILS_DEFAULT_LOGGER = Logger.new(STDOUT)
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "Verify your gem installation by sending a test exception to the hoptoad service"
|
20
|
+
task :test => ['hoptoad:log_stdout', :environment] do
|
21
|
+
RAILS_DEFAULT_LOGGER.level = Logger::DEBUG
|
22
|
+
|
23
|
+
require 'action_controller/test_process'
|
24
|
+
|
25
|
+
Dir["app/controllers/application*.rb"].each { |file| require(file) }
|
26
|
+
|
27
|
+
class HoptoadTestingException < RuntimeError; end
|
28
|
+
|
29
|
+
unless HoptoadNotifier.configuration.api_key
|
30
|
+
puts "Hoptoad needs an API key configured! Check the README to see how to add it."
|
31
|
+
exit
|
32
|
+
end
|
33
|
+
|
34
|
+
HoptoadNotifier.configuration.development_environments = []
|
35
|
+
|
36
|
+
catcher = HoptoadNotifier::Rails::ActionControllerCatcher
|
37
|
+
in_controller = ApplicationController.included_modules.include?(catcher)
|
38
|
+
in_base = ActionController::Base.included_modules.include?(catcher)
|
39
|
+
if !in_controller || !in_base
|
40
|
+
puts "Rails initialization did not occur"
|
41
|
+
exit
|
42
|
+
end
|
43
|
+
|
44
|
+
puts "Configuration:"
|
45
|
+
HoptoadNotifier.configuration.to_hash.each do |key, value|
|
46
|
+
puts sprintf("%25s: %s", key.to_s, value.inspect.slice(0, 55))
|
47
|
+
end
|
48
|
+
|
49
|
+
unless defined?(ApplicationController)
|
50
|
+
puts "No ApplicationController found"
|
51
|
+
exit
|
52
|
+
end
|
53
|
+
|
54
|
+
puts 'Setting up the Controller.'
|
55
|
+
class ApplicationController
|
56
|
+
# This is to bypass any filters that may prevent access to the action.
|
57
|
+
prepend_before_filter :test_hoptoad
|
58
|
+
def test_hoptoad
|
59
|
+
puts "Raising '#{exception_class.name}' to simulate application failure."
|
60
|
+
raise exception_class.new, 'Testing hoptoad via "rake hoptoad:test". If you can see this, it works.'
|
61
|
+
end
|
62
|
+
|
63
|
+
def rescue_action(exception)
|
64
|
+
rescue_action_in_public exception
|
65
|
+
end
|
66
|
+
|
67
|
+
# Ensure we actually have an action to go to.
|
68
|
+
def verify; end
|
69
|
+
|
70
|
+
def consider_all_requests_local
|
71
|
+
false
|
72
|
+
end
|
73
|
+
|
74
|
+
def local_request?
|
75
|
+
false
|
76
|
+
end
|
77
|
+
|
78
|
+
def exception_class
|
79
|
+
exception_name = ENV['EXCEPTION'] || "HoptoadTestingException"
|
80
|
+
Object.const_get(exception_name)
|
81
|
+
rescue
|
82
|
+
Object.const_set(exception_name, Class.new(Exception))
|
83
|
+
end
|
84
|
+
|
85
|
+
def logger
|
86
|
+
nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
class HoptoadVerificationController < ApplicationController; end
|
90
|
+
|
91
|
+
puts 'Processing request.'
|
92
|
+
request = ActionController::TestRequest.new
|
93
|
+
response = ActionController::TestResponse.new
|
94
|
+
HoptoadVerificationController.new.process(request, response)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
require 'rubygems'
|
4
|
+
require 'active_support'
|
5
|
+
require 'hoptoad_notifier/version'
|
6
|
+
require 'hoptoad_notifier/configuration'
|
7
|
+
require 'hoptoad_notifier/notice'
|
8
|
+
require 'hoptoad_notifier/sender'
|
9
|
+
require 'hoptoad_notifier/backtrace'
|
10
|
+
require 'hoptoad_notifier/rack'
|
11
|
+
|
12
|
+
# Gem for applications to automatically post errors to the Hoptoad of their choice.
|
13
|
+
module HoptoadNotifier
|
14
|
+
|
15
|
+
API_VERSION = "1.0"
|
16
|
+
LOG_PREFIX = "** [ErrorNot Logger] "
|
17
|
+
|
18
|
+
HEADERS = {
|
19
|
+
'Content-type' => 'application/x-www-form-urlencoded',
|
20
|
+
'Accept' => 'text/json'
|
21
|
+
}
|
22
|
+
|
23
|
+
class << self
|
24
|
+
# The sender object is responsible for delivering formatted data to the Hoptoad server.
|
25
|
+
# Must respond to #send_to_hoptoad. See HoptoadNotifier::Sender.
|
26
|
+
attr_accessor :sender
|
27
|
+
|
28
|
+
# A Hoptoad configuration object. Must act like a hash and return sensible
|
29
|
+
# values for all Hoptoad configuration options. See HoptoadNotifier::Configuration.
|
30
|
+
attr_accessor :configuration
|
31
|
+
|
32
|
+
# Tell the log that the Notifier is good to go
|
33
|
+
def report_ready
|
34
|
+
write_verbose_log("Notifier #{VERSION} ready to catch errors")
|
35
|
+
end
|
36
|
+
|
37
|
+
# Prints out the environment info to the log for debugging help
|
38
|
+
def report_environment_info
|
39
|
+
write_verbose_log("Environment Info: #{environment_info}")
|
40
|
+
end
|
41
|
+
|
42
|
+
# Prints out the response body from Hoptoad for debugging help
|
43
|
+
def report_response_body(response)
|
44
|
+
write_verbose_log("Response from Hoptoad: \n#{response}")
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns the Ruby version, Rails version, and current Rails environment
|
48
|
+
def environment_info
|
49
|
+
info = "[Ruby: #{RUBY_VERSION}]"
|
50
|
+
info << " [#{configuration.framework}]"
|
51
|
+
info << " [Env: #{configuration.environment_name}]"
|
52
|
+
end
|
53
|
+
|
54
|
+
# Writes out the given message to the #logger
|
55
|
+
def write_verbose_log(message)
|
56
|
+
logger.info LOG_PREFIX + message if logger
|
57
|
+
end
|
58
|
+
|
59
|
+
# Look for the Rails logger currently defined
|
60
|
+
def logger
|
61
|
+
self.configuration.logger
|
62
|
+
end
|
63
|
+
|
64
|
+
# Call this method to modify defaults in your initializers.
|
65
|
+
#
|
66
|
+
# @example
|
67
|
+
# HoptoadNotifier.configure do |config|
|
68
|
+
# config.api_key = '1234567890abcdef'
|
69
|
+
# config.secure = false
|
70
|
+
# end
|
71
|
+
def configure(silent = false)
|
72
|
+
self.configuration ||= Configuration.new
|
73
|
+
yield(configuration)
|
74
|
+
self.sender = Sender.new(configuration)
|
75
|
+
report_ready unless silent
|
76
|
+
end
|
77
|
+
|
78
|
+
# Sends an exception manually using this method, even when you are not in a controller.
|
79
|
+
#
|
80
|
+
# @param [Exception] exception The exception you want to notify Hoptoad about.
|
81
|
+
# @param [Hash] opts Data that will be sent to Hoptoad.
|
82
|
+
#
|
83
|
+
# @option opts [String] :api_key The API key for this project. The API key is a unique identifier that Hoptoad uses for identification.
|
84
|
+
# @option opts [String] :error_message The error returned by the exception (or the message you want to log).
|
85
|
+
# @option opts [String] :backtrace A backtrace, usually obtained with +caller+.
|
86
|
+
# @option opts [String] :request The controller's request object.
|
87
|
+
# @option opts [String] :session The contents of the user's session.
|
88
|
+
# @option opts [String] :environment ENV merged with the contents of the request's environment.
|
89
|
+
def notify(exception, opts = {})
|
90
|
+
send_notice(build_notice_for(exception, opts))
|
91
|
+
end
|
92
|
+
|
93
|
+
# Sends the notice unless it is one of the default ignored exceptions
|
94
|
+
# @see HoptoadNotifier.notify
|
95
|
+
def notify_or_ignore(exception, opts = {})
|
96
|
+
notice = build_notice_for(exception, opts)
|
97
|
+
send_notice(notice) unless notice.ignore?
|
98
|
+
end
|
99
|
+
|
100
|
+
def build_lookup_hash_for(exception, options = {})
|
101
|
+
notice = build_notice_for(exception, options)
|
102
|
+
|
103
|
+
result = {}
|
104
|
+
result[:action] = notice.action rescue nil
|
105
|
+
result[:component] = notice.component rescue nil
|
106
|
+
result[:error_class] = notice.error_class if notice.error_class
|
107
|
+
result[:environment_name] = 'production'
|
108
|
+
|
109
|
+
unless notice.backtrace.lines.empty?
|
110
|
+
result[:file] = notice.backtrace.lines.first.file
|
111
|
+
result[:line_number] = notice.backtrace.lines.first.number
|
112
|
+
end
|
113
|
+
|
114
|
+
result
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def send_notice(notice)
|
120
|
+
if configuration.public?
|
121
|
+
sender.send_to_hoptoad(notice.to_xml)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def build_notice_for(exception, opts = {})
|
126
|
+
exception = unwrap_exception(exception)
|
127
|
+
if exception.respond_to?(:to_hash)
|
128
|
+
opts = opts.merge(exception)
|
129
|
+
else
|
130
|
+
opts = opts.merge(:exception => exception)
|
131
|
+
end
|
132
|
+
Notice.new(configuration.merge(opts))
|
133
|
+
end
|
134
|
+
|
135
|
+
def unwrap_exception(exception)
|
136
|
+
if exception.respond_to?(:original_exception)
|
137
|
+
exception.original_exception
|
138
|
+
elsif exception.respond_to?(:continued_exception)
|
139
|
+
exception.continued_exception
|
140
|
+
else
|
141
|
+
exception
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'uri'
|
3
|
+
require 'active_support'
|
4
|
+
|
5
|
+
# Capistrano tasks for notifying Hoptoad of deploys
|
6
|
+
module HoptoadTasks
|
7
|
+
|
8
|
+
# Alerts Hoptoad of a deploy.
|
9
|
+
#
|
10
|
+
# @param [Hash] opts Data about the deploy that is set to Hoptoad
|
11
|
+
#
|
12
|
+
# @option opts [String] :rails_env Environment of the deploy (production, staging)
|
13
|
+
# @option opts [String] :scm_revision The given revision/sha that is being deployed
|
14
|
+
# @option opts [String] :scm_repository Address of your repository to help with code lookups
|
15
|
+
# @option opts [String] :local_username Who is deploying
|
16
|
+
def self.deploy(opts = {})
|
17
|
+
if HoptoadNotifier.configuration.api_key.blank?
|
18
|
+
puts "I don't seem to be configured with an API key. Please check your configuration."
|
19
|
+
return false
|
20
|
+
end
|
21
|
+
|
22
|
+
if opts[:rails_env].blank?
|
23
|
+
puts "I don't know to which Rails environment you are deploying (use the TO=production option)."
|
24
|
+
return false
|
25
|
+
end
|
26
|
+
|
27
|
+
params = {'api_key' => opts.delete(:api_key) ||
|
28
|
+
HoptoadNotifier.configuration.api_key}
|
29
|
+
opts.each {|k,v| params["deploy[#{k}]"] = v }
|
30
|
+
|
31
|
+
url = URI.parse("http://#{HoptoadNotifier.configuration.host || 'hoptoadapp.com'}/deploys.txt")
|
32
|
+
response = Net::HTTP.post_form(url, params)
|
33
|
+
puts response.body
|
34
|
+
return Net::HTTPSuccess === response
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
@@ -0,0 +1,91 @@
|
|
1
|
+
<script type="text/javascript">
|
2
|
+
var Hoptoad = {
|
3
|
+
host : <%= host.to_json %>,
|
4
|
+
api_key : <%= api_key.to_json %>,
|
5
|
+
notice : <%= notice.to_json %>,
|
6
|
+
message : 'This error exists in production!',
|
7
|
+
|
8
|
+
initialize: function() {
|
9
|
+
if (this.initialized) {
|
10
|
+
return;
|
11
|
+
} else {
|
12
|
+
this.initialized = true;
|
13
|
+
}
|
14
|
+
|
15
|
+
var data = [];
|
16
|
+
|
17
|
+
for (var key in this.notice) {
|
18
|
+
data[data.length] = 'notice[' + key + ']=' + this.notice[key];
|
19
|
+
}
|
20
|
+
|
21
|
+
data[data.length] = 'notice[api_key]=' + this.api_key;
|
22
|
+
data[data.length] = 'callback=Hoptoad.onSuccess';
|
23
|
+
data[data.length] = '_=' + (new Date()).getTime();
|
24
|
+
|
25
|
+
var head = document.getElementsByTagName('head')[0];
|
26
|
+
var done = false;
|
27
|
+
|
28
|
+
var
|
29
|
+
script = document.createElement('script');
|
30
|
+
script.src = 'http://' + this.host + '/notices_api/v1/notices/exist?' +
|
31
|
+
data.join('&');
|
32
|
+
script.type = 'text/javascript';
|
33
|
+
script.onload = script.onreadystatechange = function(){
|
34
|
+
if (!done && (!this.readyState ||
|
35
|
+
this.readyState == 'loaded' || this.readyState == 'complete')) {
|
36
|
+
|
37
|
+
done = true;
|
38
|
+
|
39
|
+
// Handle memory leak in IE. (via jQuery)
|
40
|
+
script.onload = script.onreadystatechange = null;
|
41
|
+
head.removeChild(script);
|
42
|
+
}
|
43
|
+
};
|
44
|
+
|
45
|
+
head.appendChild(script);
|
46
|
+
},
|
47
|
+
|
48
|
+
onSuccess: function(error) {
|
49
|
+
var body = document.getElementsByTagName('body')[0];
|
50
|
+
var text = document.createTextNode(this.message);
|
51
|
+
var element = document.createElement('a');
|
52
|
+
|
53
|
+
element.id = 'hoptoad';
|
54
|
+
element.href = 'http://' + error.subdomain + '.' + this.host +
|
55
|
+
'/projects/' + error.project_id + '/errors/' + error.id;
|
56
|
+
element.appendChild(text);
|
57
|
+
|
58
|
+
body.insertBefore(element, body.firstChild);
|
59
|
+
|
60
|
+
var h1 = document.getElementsByTagName('h1')[0];
|
61
|
+
var pre = document.getElementsByTagName('pre')[0];
|
62
|
+
var wrapper = document.createElement('div');
|
63
|
+
|
64
|
+
wrapper.id = 'wrapper';
|
65
|
+
wrapper.appendChild(h1);
|
66
|
+
wrapper.appendChild(pre);
|
67
|
+
|
68
|
+
body.insertBefore(wrapper, body.children[1]);
|
69
|
+
}
|
70
|
+
};
|
71
|
+
|
72
|
+
window.onload = function() {
|
73
|
+
Hoptoad.initialize.apply(Hoptoad);
|
74
|
+
};
|
75
|
+
</script>
|
76
|
+
|
77
|
+
<style type="text/css">
|
78
|
+
#hoptoad {
|
79
|
+
background: #FFF url(http://hoptoadapp.com/images/fell-off-the-toad.gif) no-repeat top right;
|
80
|
+
color: #F00;
|
81
|
+
padding: 45px 101px 45px 12px;
|
82
|
+
font-size: 14px;
|
83
|
+
font-weight: bold;
|
84
|
+
display: block;
|
85
|
+
float: right;
|
86
|
+
}
|
87
|
+
|
88
|
+
#wrapper {
|
89
|
+
padding-right: 360px;
|
90
|
+
}
|
91
|
+
</style>
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'hoptoad_notifier/rails'
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
RAILS_ENV = "production"
|
7
|
+
RAILS_ROOT = FileUtils.pwd
|
8
|
+
RAILS_DEFAULT_LOGGER = Logger.new(STDOUT)
|
9
|
+
|
10
|
+
$: << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
11
|
+
require 'hoptoad_notifier'
|
12
|
+
require 'rails/init'
|
13
|
+
|
14
|
+
fail "Please supply an API Key as the first argument" if ARGV.empty?
|
15
|
+
|
16
|
+
host = ARGV[1]
|
17
|
+
host ||= "hoptoadapp.com"
|
18
|
+
|
19
|
+
secure = (ARGV[2] == "secure")
|
20
|
+
|
21
|
+
exception = begin
|
22
|
+
raise "Testing hoptoad notifier with secure = #{secure}. If you can see this, it works."
|
23
|
+
rescue => foo
|
24
|
+
foo
|
25
|
+
end
|
26
|
+
|
27
|
+
HoptoadNotifier.configure do |config|
|
28
|
+
config.secure = secure
|
29
|
+
config.host = host
|
30
|
+
config.api_key = ARGV.first
|
31
|
+
end
|
32
|
+
puts "Configuration:"
|
33
|
+
HoptoadNotifier.configuration.to_hash.each do |key, value|
|
34
|
+
puts sprintf("%25s: %s", key.to_s, value.inspect.slice(0, 55))
|
35
|
+
end
|
36
|
+
puts "Sending #{secure ? "" : "in"}secure notification to project with key #{ARGV.first}"
|
37
|
+
HoptoadNotifier.notify(exception)
|
38
|
+
|