party_foul 0.5.0 → 0.6.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/README.md +34 -28
- data/lib/generators/party_foul/templates/party_foul.rb +8 -11
- data/lib/party_foul.rb +22 -41
- data/lib/party_foul/exception_handler.rb +7 -3
- data/lib/party_foul/issue_renderers.rb +5 -0
- data/lib/party_foul/{issue_renderer.rb → issue_renderers/base.rb} +40 -45
- data/lib/party_foul/issue_renderers/rack.rb +41 -15
- data/lib/party_foul/issue_renderers/rackless.rb +26 -0
- data/lib/party_foul/issue_renderers/rails.rb +24 -20
- data/lib/party_foul/middleware.rb +2 -2
- data/lib/party_foul/processors.rb +1 -3
- data/lib/party_foul/processors/base.rb +11 -0
- data/lib/party_foul/processors/sync.rb +3 -1
- data/lib/party_foul/rackless_exception_handler.rb +17 -0
- data/lib/party_foul/version.rb +1 -1
- data/test/party_foul/configure_test.rb +2 -2
- data/test/party_foul/exception_handler_test.rb +7 -7
- data/test/party_foul/issue_renderers/base_test.rb +91 -0
- data/test/party_foul/issue_renderers/rack_test.rb +2 -2
- data/test/party_foul/issue_renderers/rackless_test.rb +29 -0
- data/test/party_foul/issue_renderers/rails_test.rb +13 -2
- data/test/party_foul/middleware_test.rb +1 -1
- data/test/party_foul/rackless_exception_handler_test.rb +25 -0
- data/test/test_helper.rb +7 -4
- data/test/tmp/config/initializers/party_foul.rb +8 -11
- metadata +31 -7
- data/test/party_foul/issue_renderer_test.rb +0 -139
data/README.md
CHANGED
@@ -16,10 +16,10 @@ following:
|
|
16
16
|
unique title, session information, and stack trace. The issue is
|
17
17
|
tagged as a `bug`. A new comment is added with relevant data on the
|
18
18
|
application state.
|
19
|
-
3. If an open issue is found the
|
19
|
+
3. If an open issue is found the occurence count and time stamp is
|
20
20
|
updated. A new comment is added with relevant data on the
|
21
21
|
application state.
|
22
|
-
4. If a closed issue is found the
|
22
|
+
4. If a closed issue is found the occurence count and time stamp is
|
23
23
|
updated. The issue is reopened and a `regression` tag is
|
24
24
|
added. A new comment is added with relevant data on the
|
25
25
|
application state.
|
@@ -64,32 +64,29 @@ You need to initialize `PartyFoul`, use the following:
|
|
64
64
|
|
65
65
|
```ruby
|
66
66
|
PartyFoul.configure do |config|
|
67
|
-
#
|
67
|
+
# The collection of exceptions PartyFoul should not be allowed to handle
|
68
68
|
# The constants here *must* be represented as strings
|
69
|
-
config.
|
70
|
-
|
71
|
-
# The names of the HTTP headers to not report
|
72
|
-
config.filtered_http_headers = ['Cookie']
|
69
|
+
config.blacklisted_exceptions = ['ActiveRecord::RecordNotFound', 'ActionController::RoutingError']
|
73
70
|
|
74
71
|
# The OAuth token for the account that is opening the issues on Github
|
75
|
-
config.oauth_token
|
72
|
+
config.oauth_token = 'abcdefgh1234567890'
|
76
73
|
|
77
74
|
# The API endpoint for Github. Unless you are hosting a private
|
78
75
|
# instance of Enterprise Github you do not need to include this
|
79
|
-
config.endpoint
|
76
|
+
config.endpoint = 'https://api.github.com'
|
80
77
|
|
81
78
|
# The Web URL for Github. Unless you are hosting a private
|
82
79
|
# instance of Enterprise Github you do not need to include this
|
83
|
-
config.web_url
|
80
|
+
config.web_url = 'https://github.com'
|
84
81
|
|
85
82
|
# The organization or user that owns the target repository
|
86
|
-
config.owner
|
83
|
+
config.owner = 'owner_name'
|
87
84
|
|
88
85
|
# The repository for this application
|
89
|
-
config.repo
|
86
|
+
config.repo = 'repo_name'
|
90
87
|
|
91
88
|
# The branch for your deployed code
|
92
|
-
# config.branch
|
89
|
+
# config.branch = 'master'
|
93
90
|
end
|
94
91
|
```
|
95
92
|
|
@@ -98,8 +95,8 @@ You can generate an OAuth token from via the
|
|
98
95
|
with cURL:
|
99
96
|
|
100
97
|
```bash
|
101
|
-
curl -
|
102
|
-
https
|
98
|
+
curl -u <github_login> -i -d "{ \"scopes\": [\"repo\"] }" \
|
99
|
+
https://api.github.com/authorizations
|
103
100
|
```
|
104
101
|
|
105
102
|
Add as the very last middleware in your production `Rack` stack.
|
@@ -128,25 +125,34 @@ end
|
|
128
125
|
|
129
126
|
```
|
130
127
|
|
131
|
-
###
|
128
|
+
### Using PartyFoul with Sidekiq
|
129
|
+
|
130
|
+
In order to use PartyFoul for exception handling with Sidekiq you will need to create an initializer with some middleware configuration. The following example is based on using [Sidekiq with another exception notifiier server](https://github.com/bugsnag/bugsnag-ruby/blob/master/lib/bugsnag/sidekiq.rb).
|
132
131
|
|
133
|
-
|
134
|
-
comments are. If you want to override these templates you simply need to
|
135
|
-
add them as an option in your initializer:
|
132
|
+
File: config/initializers/partyfoul_sidekiq.rb
|
136
133
|
|
137
134
|
```ruby
|
138
|
-
PartyFoul
|
139
|
-
|
140
|
-
|
135
|
+
module PartyFoul
|
136
|
+
class Sidekiq
|
137
|
+
def call(worker, msg, queue)
|
138
|
+
begin
|
139
|
+
yield
|
140
|
+
rescue => ex
|
141
|
+
PartyFoul::RacklessExceptionHandler.handle(ex, {class: worker.class.name, method: queue, params: msg})
|
142
|
+
raise
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
::Sidekiq.configure_server do |config|
|
149
|
+
config.server_middleware do |chain|
|
150
|
+
chain.add ::PartyFoul::Sidekiq
|
151
|
+
end
|
141
152
|
end
|
142
153
|
```
|
143
154
|
|
144
|
-
|
145
|
-
templates are evaluated with the value of the corresponding named
|
146
|
-
instance method on the instance of `PartyFoul::IssueRenderer`. If you
|
147
|
-
want to add additional values for replacement you should open that class
|
148
|
-
to add the methods. Depending upon the data point you may want o make
|
149
|
-
the change in one of the [different issue renderer adapters](https://github.com/dockyard/party_foul/tree/master/lib/party_foul/issue_renderers).
|
155
|
+
This will pass the worker class name and queue as well as all worker-related parameters off to PartyFoul before passing on the exception.
|
150
156
|
|
151
157
|
## Authors ##
|
152
158
|
|
@@ -1,28 +1,25 @@
|
|
1
1
|
PartyFoul.configure do |config|
|
2
|
-
#
|
2
|
+
# The collection of exceptions PartyFoul should not be allowed to handle
|
3
3
|
# The constants here *must* be represented as strings
|
4
|
-
config.
|
5
|
-
|
6
|
-
# The names of the HTTP headers to not report
|
7
|
-
config.filtered_http_headers = ['Cookie']
|
4
|
+
config.blacklisted_exceptions = ['ActiveRecord::RecordNotFound', 'ActionController::RoutingError']
|
8
5
|
|
9
6
|
# The OAuth token for the account that is opening the issues on Github
|
10
|
-
config.oauth_token
|
7
|
+
config.oauth_token = '<%= @oauth_token %>'
|
11
8
|
|
12
9
|
# The API endpoint for Github. Unless you are hosting a private
|
13
10
|
# instance of Enterprise Github you do not need to include this
|
14
|
-
config.endpoint
|
11
|
+
config.endpoint = '<%= @endpoint %>'
|
15
12
|
|
16
13
|
# The Web URL for Github. Unless you are hosting a private
|
17
14
|
# instance of Enterprise Github you do not need to include this
|
18
|
-
config.web_url
|
15
|
+
config.web_url = '<%= @web_url %>'
|
19
16
|
|
20
17
|
# The organization or user that owns the target repository
|
21
|
-
config.owner
|
18
|
+
config.owner = '<%= @owner %>'
|
22
19
|
|
23
20
|
# The repository for this application
|
24
|
-
config.repo
|
21
|
+
config.repo = '<%= @repo %>'
|
25
22
|
|
26
23
|
# The branch for your deployed code
|
27
|
-
# config.branch
|
24
|
+
# config.branch = 'master'
|
28
25
|
end
|
data/lib/party_foul.rb
CHANGED
@@ -2,9 +2,11 @@ require 'github_api'
|
|
2
2
|
|
3
3
|
module PartyFoul
|
4
4
|
class << self
|
5
|
-
attr_accessor :github, :oauth_token, :endpoint, :owner, :repo,
|
6
|
-
|
7
|
-
|
5
|
+
attr_accessor :github, :oauth_token, :endpoint, :owner, :repo, :blacklisted_exceptions, :processor, :web_url, :branch, :whitelisted_rack_variables
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.whitelisted_rack_variables
|
9
|
+
@whitelisted_rack_variables ||= %w{GATEWAY_INTERFACE PATH_INFO REMOTE_ADDR REMOTE_HOST REQUEST_METHOD REQUEST_URI SERVER_NAME SERVER_PORT SERVER_PROTOCOL SERVER_SOFTWARE HTTP_HOST HTTP_CONNECTION HTTP_CACHE_CONTROL HTTP_ACCEPT HTTP_USER_AGENT HTTP_ACCEPT_ENCODING HTTP_ACCEPT_LANGUAGE HTTP_ACCEPT_CHARSET rack.version rack.input rack.errors rack.multithread rack.multiprocess rack.run_once rack.url_scheme HTTP_VERSION REQUEST_PATH ORIGINAL_FULLPATH action_dispatch.routes action_dispatch.parameter_filter action_dispatch.secret_token action_dispatch.show_exceptions action_dispatch.show_detailed_exceptions action_dispatch.logger action_dispatch.backtrace_cleaner action_dispatch.request_id action_dispatch.remote_ip rack.session rack.session.options rack.request.cookie_hash rack.request.cookie_string action_dispatch.cookies action_dispatch.request.unsigned_session_cookie action_dispatch.request.path_parameters action_controller.instance action_dispatch.request.request_parameters rack.request.query_string rack.request.query_hash action_dispatch.request.query_parameters action_dispatch.request.parameters action_dispatch.request.formats}
|
8
10
|
end
|
9
11
|
|
10
12
|
# The git branch that is used for linking in the stack trace
|
@@ -22,38 +24,20 @@ module PartyFoul
|
|
22
24
|
@web_url ||= 'https://github.com'
|
23
25
|
end
|
24
26
|
|
25
|
-
# The
|
27
|
+
# The api endpoint for Github. This is only interesting for Enterprise
|
28
|
+
# users
|
26
29
|
#
|
27
|
-
# @return [String]
|
28
|
-
def self.
|
29
|
-
@
|
30
|
-
<<-TEMPLATE
|
31
|
-
<table>
|
32
|
-
<tr><th>Exception</th><td>:exception</td></tr>
|
33
|
-
<tr><th>Count</th><td>1</td></tr>
|
34
|
-
<tr><th>Last Occurance</th><td>:occurred_at</td></tr>
|
35
|
-
</table>
|
36
|
-
|
37
|
-
## Stack Trace
|
38
|
-
<pre>:stack_trace</pre>
|
39
|
-
Fingerprint: `:fingerprint`
|
40
|
-
TEMPLATE
|
30
|
+
# @return [String] Defaults to 'https://api.github.com' if not set
|
31
|
+
def self.endpoint
|
32
|
+
@endpoint ||= 'https://api.github.com'
|
41
33
|
end
|
42
34
|
|
43
|
-
# The
|
35
|
+
# The processor to be used when handling the exception. Defaults to a
|
36
|
+
# synchrons processor
|
44
37
|
#
|
45
|
-
# @return [
|
46
|
-
def self.
|
47
|
-
@
|
48
|
-
<<-TEMPLATE
|
49
|
-
<table>
|
50
|
-
<tr><th>Occurred at</th><td>:occurred_at</td></tr>
|
51
|
-
<tr><th>Params</th><td>:params</td></tr>
|
52
|
-
<tr><th>IP Address</th><td>:ip_address</td></tr>
|
53
|
-
<tr><th>Session</th><td>:session</td></tr>
|
54
|
-
<tr><th>HTTP Headers</th><td>:http_headers</td></tr>
|
55
|
-
</table>
|
56
|
-
TEMPLATE
|
38
|
+
# @return [Class] Defaults to 'PartyFoul::Processors:Sync
|
39
|
+
def self.processor
|
40
|
+
@processor ||= PartyFoul::Processors::Sync
|
57
41
|
end
|
58
42
|
|
59
43
|
# The collection of exceptions that should not be captured. Members of
|
@@ -67,8 +51,8 @@ Fingerprint: `:fingerprint`
|
|
67
51
|
# [ActiveRecord::RecordNotFound]
|
68
52
|
#
|
69
53
|
# @return [Array]
|
70
|
-
def self.
|
71
|
-
@
|
54
|
+
def self.blacklisted_exceptions
|
55
|
+
@blacklisted_exceptions || []
|
72
56
|
end
|
73
57
|
|
74
58
|
# The url of the repository. Built using the {.web_url}, {.owner}, and {.repo}
|
@@ -87,20 +71,17 @@ Fingerprint: `:fingerprint`
|
|
87
71
|
# config.oauth_token = ENV['oauth_token']
|
88
72
|
# end
|
89
73
|
#
|
74
|
+
# Will also setup for Github api connections
|
75
|
+
#
|
90
76
|
# @param [Block]
|
91
77
|
def self.configure(&block)
|
92
78
|
yield self
|
93
|
-
self.
|
94
|
-
_self = self
|
95
|
-
self.github ||= Github.new do |config|
|
96
|
-
%w{endpoint oauth_token}.each do |option|
|
97
|
-
config.send("#{option}=", _self.send(option)) if !_self.send(option).nil?
|
98
|
-
end
|
99
|
-
end
|
79
|
+
self.github ||= Github.new oauth_token: oauth_token, endpoint: endpoint
|
100
80
|
end
|
101
81
|
end
|
102
82
|
|
103
83
|
require 'party_foul/exception_handler'
|
104
|
-
require 'party_foul/
|
84
|
+
require 'party_foul/rackless_exception_handler'
|
85
|
+
require 'party_foul/issue_renderers'
|
105
86
|
require 'party_foul/middleware'
|
106
87
|
require 'party_foul/processors'
|
@@ -7,7 +7,7 @@ class PartyFoul::ExceptionHandler
|
|
7
7
|
#
|
8
8
|
# @param [Exception, Hash]
|
9
9
|
def self.handle(exception, env)
|
10
|
-
PartyFoul.processor.handle(exception, env)
|
10
|
+
PartyFoul.processor.handle(exception, clean_env(env))
|
11
11
|
end
|
12
12
|
|
13
13
|
# Makes an attempt to determine what framework is being used and will use the proper
|
@@ -16,9 +16,9 @@ class PartyFoul::ExceptionHandler
|
|
16
16
|
# @param [Exception, Hash]
|
17
17
|
def initialize(exception, env)
|
18
18
|
renderer_klass = if defined?(Rails)
|
19
|
-
PartyFoul::
|
19
|
+
PartyFoul::IssueRenderers::Rails
|
20
20
|
else
|
21
|
-
PartyFoul::
|
21
|
+
PartyFoul::IssueRenderers::Rack
|
22
22
|
end
|
23
23
|
|
24
24
|
self.rendered_issue = renderer_klass.new(exception, env)
|
@@ -69,6 +69,10 @@ class PartyFoul::ExceptionHandler
|
|
69
69
|
|
70
70
|
private
|
71
71
|
|
72
|
+
def self.clean_env(env)
|
73
|
+
env.select { |key, value| PartyFoul.whitelisted_rack_variables.include?(key) }
|
74
|
+
end
|
75
|
+
|
72
76
|
def fingerprint
|
73
77
|
rendered_issue.fingerprint
|
74
78
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class PartyFoul::
|
1
|
+
class PartyFoul::IssueRenderers::Base
|
2
2
|
attr_accessor :exception, :env, :sha
|
3
3
|
|
4
4
|
# A new renderer instance for Githug issues
|
@@ -16,18 +16,27 @@ class PartyFoul::IssueRenderer
|
|
16
16
|
raise NotImplementedError
|
17
17
|
end
|
18
18
|
|
19
|
-
#
|
20
|
-
#
|
19
|
+
# Renders the issue body
|
20
|
+
#
|
21
|
+
# Customize by overriding {#body_options}
|
21
22
|
#
|
22
23
|
# @return [String]
|
23
24
|
def body
|
24
|
-
|
25
|
+
<<-BODY
|
26
|
+
#{build_table_from_hash(body_options)}
|
27
|
+
|
28
|
+
## Stack Trace
|
29
|
+
<pre>#{stack_trace}</pre>
|
30
|
+
Fingerprint: `#{fingerprint}`
|
31
|
+
BODY
|
25
32
|
end
|
26
33
|
|
27
|
-
#
|
28
|
-
#
|
34
|
+
# Renderes the issue comment
|
35
|
+
#
|
36
|
+
# Customize by overriding {#comment_options}
|
37
|
+
#
|
29
38
|
def comment
|
30
|
-
|
39
|
+
build_table_from_hash(comment_options)
|
31
40
|
end
|
32
41
|
|
33
42
|
# Compiles the stack trace for use in the issue body. Lines in the
|
@@ -67,21 +76,13 @@ class PartyFoul::IssueRenderer
|
|
67
76
|
begin
|
68
77
|
current_count = old_body.match(/<th>Count<\/th><td>(\d+)<\/td>/)[1].to_i
|
69
78
|
old_body.sub!("<th>Count</th><td>#{current_count}</td>", "<th>Count</th><td>#{current_count + 1}</td>")
|
70
|
-
old_body.sub!(/<th>Last
|
79
|
+
old_body.sub!(/<th>Last Occurrence<\/th><td>.+<\/td>/, "<th>Last Occurrence</th><td>#{occurred_at}</td>")
|
71
80
|
old_body
|
72
81
|
rescue
|
73
82
|
self.body
|
74
83
|
end
|
75
84
|
end
|
76
85
|
|
77
|
-
# The params hash at the time the exception occurred. This method is
|
78
|
-
# overriden for each framework adapter. It should return a hash.
|
79
|
-
#
|
80
|
-
# @return [NotImplementedError]
|
81
|
-
def params
|
82
|
-
raise NotImplementedError
|
83
|
-
end
|
84
|
-
|
85
86
|
# The timestamp when the exception occurred.
|
86
87
|
#
|
87
88
|
# @return [String]
|
@@ -89,48 +90,45 @@ class PartyFoul::IssueRenderer
|
|
89
90
|
Time.now.strftime('%B %d, %Y %H:%M:%S %z')
|
90
91
|
end
|
91
92
|
|
92
|
-
#
|
93
|
+
# The hash used for building the table in issue body
|
93
94
|
#
|
94
|
-
# @return [
|
95
|
-
def
|
96
|
-
|
95
|
+
# @return [Hash]
|
96
|
+
def body_options(count = 0)
|
97
|
+
{ Exception: exception, 'Last Occurrence' => occurred_at, Count: count + 1 }
|
97
98
|
end
|
98
99
|
|
99
|
-
# The
|
100
|
+
# The hash used for building the table in the comment body
|
100
101
|
#
|
101
102
|
# @return [Hash]
|
102
|
-
def
|
103
|
-
|
103
|
+
def comment_options
|
104
|
+
{ 'Occurred At' => occurred_at }
|
104
105
|
end
|
105
106
|
|
106
|
-
|
107
|
-
#
|
107
|
+
|
108
|
+
# Builds an HTML table from hash
|
108
109
|
#
|
109
|
-
# @return [
|
110
|
-
def
|
111
|
-
|
112
|
-
hash[key.split('HTTP_').last.split('_').map(&:capitalize).join('-')] = env[key]
|
113
|
-
hash
|
114
|
-
end
|
110
|
+
# @return [String]
|
111
|
+
def build_table_from_hash(hash)
|
112
|
+
"<table>#{rows_for_table_from_hash(hash)}</table>"
|
115
113
|
end
|
116
114
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
115
|
+
# Builds the rows of an HTML table from hash.
|
116
|
+
# Keys as Headers cells and Values as Data cells
|
117
|
+
# If the Value is a Hash it will be rendered as a table
|
118
|
+
#
|
119
|
+
# @return [String]
|
120
|
+
def rows_for_table_from_hash(hash)
|
121
|
+
hash.inject('') do |rows, row|
|
122
|
+
key, value = row
|
123
|
+
if row[1].kind_of?(Hash)
|
124
|
+
value = build_table_from_hash(row[1])
|
124
125
|
end
|
126
|
+
rows << "<tr><th>#{key}</th><td>#{value}</td></tr>"
|
125
127
|
end
|
126
128
|
end
|
127
129
|
|
128
130
|
private
|
129
131
|
|
130
|
-
def hash_as_table(value)
|
131
|
-
"<table>#{value.map {|key, value| "<tr><th>#{key}</th><td>#{value}</td></tr>"}.join}</table>"
|
132
|
-
end
|
133
|
-
|
134
132
|
def app_root
|
135
133
|
Dir.pwd
|
136
134
|
end
|
@@ -139,6 +137,3 @@ class PartyFoul::IssueRenderer
|
|
139
137
|
backtrace_line.match(/#{app_root}\/((.+?):(\d+))/)
|
140
138
|
end
|
141
139
|
end
|
142
|
-
|
143
|
-
require 'party_foul/issue_renderers/rack'
|
144
|
-
require 'party_foul/issue_renderers/rails'
|
@@ -1,19 +1,45 @@
|
|
1
|
-
|
1
|
+
class PartyFoul::IssueRenderers::Rack < PartyFoul::IssueRenderers::Base
|
2
|
+
# Title for the issue comprised of (exception) "message"
|
3
|
+
#
|
4
|
+
# @return [String]
|
5
|
+
def title
|
6
|
+
%{(#{exception.class}) "#{exception.message}"}
|
7
|
+
end
|
8
|
+
|
9
|
+
def comment_options
|
10
|
+
super.merge(URL: url, Params: params, Session: session, 'IP Address' => ip_address, 'HTTP Headers' => http_headers)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Rack params
|
14
|
+
#
|
15
|
+
# @return [Hash]
|
16
|
+
def params
|
17
|
+
env['QUERY_STRING']
|
18
|
+
end
|
2
19
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
20
|
+
# IP address of the client who triggered the exception
|
21
|
+
#
|
22
|
+
# @return [String]
|
23
|
+
def ip_address
|
24
|
+
env['REMOTE_ADDR']
|
25
|
+
end
|
26
|
+
|
27
|
+
def url
|
28
|
+
"[#{env['REQUEST_METHOD']}] #{env['REQUEST_URI']}"
|
29
|
+
end
|
30
|
+
|
31
|
+
# The session hash for the client at the time of the exception
|
32
|
+
#
|
33
|
+
# @return [Hash]
|
34
|
+
def session
|
35
|
+
env['rack.session']
|
36
|
+
end
|
11
37
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
38
|
+
# HTTP Headers hash from the request. Headers can be filtered out by
|
39
|
+
# adding matching key names to {PartyFoul.blacklisted_headers}
|
40
|
+
#
|
41
|
+
# @return [Hash]
|
42
|
+
def http_headers
|
43
|
+
{ Version: env['HTTP_VERSION'], 'User Agent' => env['HTTP_USER_AGENT'], 'Accept Encoding' => env['HTTP_ACCEPT_ENCODING'], Accept: env['HTTP_ACCEPT'] }
|
18
44
|
end
|
19
45
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'party_foul/issue_renderers/base'
|
2
|
+
|
3
|
+
class PartyFoul::IssueRenderers::Rackless < PartyFoul::IssueRenderers::Base
|
4
|
+
# env in a rackless environment is expected to contain three keys:
|
5
|
+
# class: name of the class that raised the exception
|
6
|
+
# method: name of the method that raised the exception
|
7
|
+
# params: parameters passed to the method that raised the exception
|
8
|
+
|
9
|
+
# Rails params hash. Filtered parms are respected.
|
10
|
+
#
|
11
|
+
# @return [Hash]
|
12
|
+
def params
|
13
|
+
env[:params]
|
14
|
+
end
|
15
|
+
|
16
|
+
# Title for the issue comprised of Controller#action (exception) "message"
|
17
|
+
#
|
18
|
+
# @return [String]
|
19
|
+
def title
|
20
|
+
%{#{env[:class]}##{env[:method]} (#{exception.class}) "#{exception.message}"}
|
21
|
+
end
|
22
|
+
|
23
|
+
def comment_options
|
24
|
+
super.merge(Params: params)
|
25
|
+
end
|
26
|
+
end
|
@@ -1,26 +1,30 @@
|
|
1
|
-
|
1
|
+
class PartyFoul::IssueRenderers::Rails < PartyFoul::IssueRenderers::Rack
|
2
|
+
# Title for the issue comprised of Controller#action (exception) "message"
|
3
|
+
#
|
4
|
+
# @return [String]
|
5
|
+
def title
|
6
|
+
%{#{env['action_controller.instance'].class}##{env['action_dispatch.request.path_parameters']['action']} (#{exception.class}) "#{exception.message}"}
|
7
|
+
end
|
2
8
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
parameter_filter.filter(env['action_dispatch.request.path_parameters'])
|
11
|
-
end
|
9
|
+
# Rails params hash. Filtered parms are respected.
|
10
|
+
#
|
11
|
+
# @return [Hash]
|
12
|
+
def params
|
13
|
+
parameter_filter = ActionDispatch::Http::ParameterFilter.new(env["action_dispatch.parameter_filter"])
|
14
|
+
parameter_filter.filter(env['action_dispatch.request.path_parameters'])
|
15
|
+
end
|
12
16
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
# Rails session hash. Filtered parms are respected.
|
18
|
+
#
|
19
|
+
# @return [Hash]
|
20
|
+
def session
|
21
|
+
parameter_filter = ActionDispatch::Http::ParameterFilter.new(env['action_dispatch.parameter_filter'])
|
22
|
+
parameter_filter.filter(env['rack.session'])
|
23
|
+
end
|
19
24
|
|
20
|
-
|
25
|
+
private
|
21
26
|
|
22
|
-
|
23
|
-
|
24
|
-
end
|
27
|
+
def app_root
|
28
|
+
Rails.root
|
25
29
|
end
|
26
30
|
end
|
@@ -16,8 +16,8 @@ module PartyFoul
|
|
16
16
|
private
|
17
17
|
|
18
18
|
def allow_handling?(captured_exception)
|
19
|
-
!PartyFoul.
|
20
|
-
names =
|
19
|
+
!PartyFoul.blacklisted_exceptions.find do |blacklisted_exception|
|
20
|
+
names = blacklisted_exception.split('::')
|
21
21
|
names.shift if names.empty? || names.first.empty?
|
22
22
|
|
23
23
|
constant = Object
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class PartyFoul::Processors::Base
|
2
|
+
# Passes the exception and rack env data to the ExceptionHandler and
|
3
|
+
# runs everything synchronously. This base class method must be
|
4
|
+
# overriden by any inheriting class.
|
5
|
+
#
|
6
|
+
# @param [Exception, Hash]
|
7
|
+
# @return [NotImplementedError]
|
8
|
+
def self.handle(exception, env)
|
9
|
+
raise NotImplementedError
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class PartyFoul::RacklessExceptionHandler < PartyFoul::ExceptionHandler
|
2
|
+
# This handler will pass the exception and working environment from Rack off to a processor.
|
3
|
+
# The default PartyFoul processor will work synchronously. Processor adapters can be written
|
4
|
+
# to push this logic to a background job if desired.
|
5
|
+
#
|
6
|
+
# @param [Exception, Hash]
|
7
|
+
def self.handle(exception, env)
|
8
|
+
self.new(exception, clean_env(env)).run
|
9
|
+
end
|
10
|
+
|
11
|
+
# Uses the Rackless IssueRenderer for a rackless environment
|
12
|
+
#
|
13
|
+
# @param [Exception, Hash]
|
14
|
+
def initialize(exception, env)
|
15
|
+
self.rendered_issue = PartyFoul::IssueRenderers::Rackless.new(exception, env)
|
16
|
+
end
|
17
|
+
end
|
data/lib/party_foul/version.rb
CHANGED
@@ -8,7 +8,7 @@ describe 'Party Foul Confg' do
|
|
8
8
|
|
9
9
|
it 'sets the proper config variables' do
|
10
10
|
PartyFoul.configure do |config|
|
11
|
-
config.
|
11
|
+
config.blacklisted_exceptions = ['StandardError']
|
12
12
|
config.oauth_token = 'test_token'
|
13
13
|
config.web_url = 'http://example.com'
|
14
14
|
config.endpoint = 'http://api.example.com'
|
@@ -17,7 +17,7 @@ describe 'Party Foul Confg' do
|
|
17
17
|
config.branch = 'master'
|
18
18
|
end
|
19
19
|
|
20
|
-
PartyFoul.
|
20
|
+
PartyFoul.blacklisted_exceptions.must_equal ['StandardError']
|
21
21
|
PartyFoul.github.must_be_instance_of Github::Client
|
22
22
|
PartyFoul.github.oauth_token.must_equal 'test_token'
|
23
23
|
PartyFoul.github.endpoint.must_equal 'http://api.example.com'
|
@@ -16,14 +16,14 @@ describe 'Party Foul Exception Handler' do
|
|
16
16
|
PartyFoul.github.issues.stubs(:edit)
|
17
17
|
PartyFoul.github.issues.stubs(:comments).returns(mock('Comments'))
|
18
18
|
PartyFoul.github.issues.comments.stubs(:create)
|
19
|
-
PartyFoul::
|
20
|
-
PartyFoul::
|
19
|
+
PartyFoul::IssueRenderers::Rails.any_instance.stubs(:title).returns('Test Title')
|
20
|
+
PartyFoul::IssueRenderers::Rails.any_instance.stubs(:fingerprint).returns('test_fingerprint')
|
21
21
|
end
|
22
22
|
|
23
23
|
context 'when error is new' do
|
24
24
|
it 'will open a new error on Github' do
|
25
|
-
PartyFoul::
|
26
|
-
PartyFoul::
|
25
|
+
PartyFoul::IssueRenderers::Rails.any_instance.stubs(:body).returns('Test Body')
|
26
|
+
PartyFoul::IssueRenderers::Rails.any_instance.stubs(:comment).returns('Test Comment')
|
27
27
|
PartyFoul.github.search.stubs(:issues).with(owner: 'test_owner', repo: 'test_repo', keyword: 'test_fingerprint', state: 'open').returns(Hashie::Mash.new(issues: []))
|
28
28
|
PartyFoul.github.search.stubs(:issues).with(owner: 'test_owner', repo: 'test_repo', keyword: 'test_fingerprint', state: 'closed').returns(Hashie::Mash.new(issues: []))
|
29
29
|
PartyFoul.github.issues.expects(:create).with('test_owner', 'test_repo', title: 'Test Title', body: 'Test Body', :labels => ['bug']).returns(Hashie::Mash.new('number' => 1))
|
@@ -35,8 +35,8 @@ describe 'Party Foul Exception Handler' do
|
|
35
35
|
|
36
36
|
context 'when error is not new' do
|
37
37
|
before do
|
38
|
-
PartyFoul::
|
39
|
-
PartyFoul::
|
38
|
+
PartyFoul::IssueRenderers::Rails.any_instance.stubs(:update_body).returns('New Body')
|
39
|
+
PartyFoul::IssueRenderers::Rails.any_instance.stubs(:comment).returns('Test Comment')
|
40
40
|
end
|
41
41
|
|
42
42
|
context 'and open' do
|
@@ -63,7 +63,7 @@ describe 'Party Foul Exception Handler' do
|
|
63
63
|
|
64
64
|
context 'when issue is marked as "wontfix"' do
|
65
65
|
it 'does nothing' do
|
66
|
-
PartyFoul::
|
66
|
+
PartyFoul::IssueRenderers::Rails.any_instance.stubs(:body).returns('Test Body')
|
67
67
|
PartyFoul.github.search.stubs(:issues).with(owner: 'test_owner', repo: 'test_repo', keyword: 'test_fingerprint', state: 'open').returns(Hashie::Mash.new(issues: []))
|
68
68
|
PartyFoul.github.search.stubs(:issues).with(owner: 'test_owner', repo: 'test_repo', keyword: 'test_fingerprint', state: 'closed').returns(Hashie::Mash.new(issues: [{title: 'Test Title', body: 'Test Body', state: 'closed', number: 1, 'labels' => ['wontfix']}]))
|
69
69
|
PartyFoul.github.issues.expects(:create).never
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'active_support/core_ext/object/blank'
|
3
|
+
require 'action_dispatch/http/parameter_filter'
|
4
|
+
|
5
|
+
describe 'Party Foul Issue Renderer Base' do
|
6
|
+
before do
|
7
|
+
Time.stubs(:now).returns(Time.new(1970, 1, 1, 0, 0, 0, '-05:00'))
|
8
|
+
end
|
9
|
+
|
10
|
+
after do
|
11
|
+
clean_up_party
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#body' do
|
15
|
+
describe 'updating issue body' do
|
16
|
+
before do
|
17
|
+
@rendered_issue = PartyFoul::IssueRenderers::Base.new(nil, nil)
|
18
|
+
@rendered_issue.stubs(:exception).returns('Test Exception')
|
19
|
+
@rendered_issue.stubs(:fingerprint).returns('abcdefg1234567890')
|
20
|
+
@rendered_issue.stubs(:stack_trace)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'updates count and timestamp' do
|
24
|
+
body = <<-BODY
|
25
|
+
<table>
|
26
|
+
<tr><th>Exception</th><td>Test Exception</td></tr>
|
27
|
+
<tr><th>Count</th><td>1</td></tr>
|
28
|
+
<tr><th>Last Occurrence</th><td>January 01, 1970 00:00:00 -0500</td></tr>
|
29
|
+
</table>
|
30
|
+
|
31
|
+
## Stack Trace
|
32
|
+
<pre></pre>
|
33
|
+
Fingerprint: `abcdefg1234567890`
|
34
|
+
BODY
|
35
|
+
|
36
|
+
Time.stubs(:now).returns(Time.new(1985, 10, 25, 1, 22, 0, '-05:00'))
|
37
|
+
|
38
|
+
expected_body = <<-BODY
|
39
|
+
<table>
|
40
|
+
<tr><th>Exception</th><td>Test Exception</td></tr>
|
41
|
+
<tr><th>Count</th><td>2</td></tr>
|
42
|
+
<tr><th>Last Occurrence</th><td>October 25, 1985 01:22:00 -0500</td></tr>
|
43
|
+
</table>
|
44
|
+
|
45
|
+
## Stack Trace
|
46
|
+
<pre></pre>
|
47
|
+
Fingerprint: `abcdefg1234567890`
|
48
|
+
BODY
|
49
|
+
|
50
|
+
@rendered_issue.update_body(body).must_equal expected_body
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe 'empty body' do
|
55
|
+
before do
|
56
|
+
@rendered_issue = PartyFoul::IssueRenderers::Base.new(nil, nil)
|
57
|
+
@rendered_issue.stubs(:exception).returns('Test Exception')
|
58
|
+
@rendered_issue.stubs(:fingerprint).returns('abcdefg1234567890')
|
59
|
+
@rendered_issue.stubs(:stack_trace)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'resets body' do
|
63
|
+
expected_body = <<-BODY
|
64
|
+
<table><tr><th>Exception</th><td>Test Exception</td></tr><tr><th>Last Occurrence</th><td>January 01, 1970 00:00:00 -0500</td></tr><tr><th>Count</th><td>1</td></tr></table>
|
65
|
+
|
66
|
+
## Stack Trace
|
67
|
+
<pre></pre>
|
68
|
+
Fingerprint: `abcdefg1234567890`
|
69
|
+
BODY
|
70
|
+
@rendered_issue.update_body(nil).must_equal expected_body
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#build_table_from_hash' do
|
76
|
+
it 'builds an HTML table from a hash' do
|
77
|
+
rendered_issue = PartyFoul::IssueRenderers::Base.new(nil, nil)
|
78
|
+
hash = { 'Value 1' => 'abc', 'Value 2' => { 'Value A' => 123, 'Value B' => 456 } }
|
79
|
+
expected = '<table><tr><th>Value 1</th><td>abc</td></tr><tr><th>Value 2</th><td><table><tr><th>Value A</th><td>123</td></tr><tr><th>Value B</th><td>456</td></tr></table></td></tr></table>'
|
80
|
+
rendered_issue.build_table_from_hash(hash).must_equal expected
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '#fingerprint' do
|
85
|
+
it 'SHA1s the title' do
|
86
|
+
rendered_issue = PartyFoul::IssueRenderers::Base.new(nil, nil)
|
87
|
+
rendered_issue.stubs(:title).returns('abcdefg1234567890')
|
88
|
+
rendered_issue.fingerprint.must_equal Digest::SHA1.hexdigest(rendered_issue.title)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -3,7 +3,7 @@ require 'test_helper'
|
|
3
3
|
describe 'Rack Issue Renderer' do
|
4
4
|
describe '#params' do
|
5
5
|
before do
|
6
|
-
@rendered_issue = PartyFoul::
|
6
|
+
@rendered_issue = PartyFoul::IssueRenderers::Rack.new(nil, {'QUERY_STRING' => { 'status' => 'ok' } })
|
7
7
|
end
|
8
8
|
|
9
9
|
it 'returns ok' do
|
@@ -17,7 +17,7 @@ describe 'Rack Issue Renderer' do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
it 'constructs the title with the class and instance method' do
|
20
|
-
@rendered_issue = PartyFoul::
|
20
|
+
@rendered_issue = PartyFoul::IssueRenderers::Rack.new(@exception, {})
|
21
21
|
@rendered_issue.title.must_equal %{(Exception) "message"}
|
22
22
|
end
|
23
23
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe 'Rackless Issue Renderer' do
|
4
|
+
before do
|
5
|
+
@env = { :params => { :val1 => '1', :val2 => '2' }, :class => 'Worker', :method => 'perform' }
|
6
|
+
end
|
7
|
+
|
8
|
+
describe '#params' do
|
9
|
+
before do
|
10
|
+
@rendered_issue = PartyFoul::IssueRenderers::Rackless.new(nil, @env)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'returns the parameters' do
|
14
|
+
@rendered_issue.params[:val1].must_equal '1'
|
15
|
+
@rendered_issue.params[:val2].must_equal '2'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#title' do
|
20
|
+
before do
|
21
|
+
@exception = Exception.new('message')
|
22
|
+
@rendered_issue = PartyFoul::IssueRenderers::Rackless.new(@exception, @env)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'constructs the title with the controller and action' do
|
26
|
+
@rendered_issue.title.must_equal %{Worker#perform (Exception) "message"}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -3,7 +3,7 @@ require 'test_helper'
|
|
3
3
|
describe 'Rails Issue Renderer' do
|
4
4
|
describe '#params' do
|
5
5
|
before do
|
6
|
-
@rendered_issue = PartyFoul::
|
6
|
+
@rendered_issue = PartyFoul::IssueRenderers::Rails.new(nil, {'action_dispatch.parameter_filter' => ['password'], 'action_dispatch.request.path_parameters' => { 'status' => 'ok', 'password' => 'test' }, 'QUERY_STRING' => { 'status' => 'fail' } })
|
7
7
|
end
|
8
8
|
|
9
9
|
it 'returns ok' do
|
@@ -12,6 +12,17 @@ describe 'Rails Issue Renderer' do
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
+
describe '#session' do
|
16
|
+
before do
|
17
|
+
@rendered_issue = PartyFoul::IssueRenderers::Rails.new(nil, {'action_dispatch.parameter_filter' => ['password'], 'rack.session' => { 'status' => 'ok', 'password' => 'test' }, 'QUERY_STRING' => { 'status' => 'fail' } })
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'returns ok' do
|
21
|
+
@rendered_issue.session['status'].must_equal 'ok'
|
22
|
+
@rendered_issue.session['password'].must_equal '[FILTERED]'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
15
26
|
describe '#title' do
|
16
27
|
before do
|
17
28
|
@exception = Exception.new('message')
|
@@ -21,7 +32,7 @@ describe 'Rails Issue Renderer' do
|
|
21
32
|
'action_dispatch.request.path_parameters' => { 'controller' => 'landing', 'action' => 'index' },
|
22
33
|
'action_controller.instance' => controller_instance
|
23
34
|
}
|
24
|
-
@rendered_issue = PartyFoul::
|
35
|
+
@rendered_issue = PartyFoul::IssueRenderers::Rails.new(@exception, env)
|
25
36
|
end
|
26
37
|
|
27
38
|
it 'constructs the title with the controller and action' do
|
@@ -33,7 +33,7 @@ describe 'Party Foul Middleware' do
|
|
33
33
|
|
34
34
|
context 'filtering based upon exception' do
|
35
35
|
before do
|
36
|
-
PartyFoul.
|
36
|
+
PartyFoul.blacklisted_exceptions = ['StandardError']
|
37
37
|
self.stubs(:error_to_raise).returns(StandardError)
|
38
38
|
end
|
39
39
|
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe 'Party Foul Rackless Exception Handler' do
|
4
|
+
before do
|
5
|
+
PartyFoul.configure do |config|
|
6
|
+
config.oauth_token = 'abcdefg1234567890'
|
7
|
+
config.owner = 'test_owner'
|
8
|
+
config.repo = 'test_repo'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#handle' do
|
13
|
+
it 'will call run on itself' do
|
14
|
+
PartyFoul::RacklessExceptionHandler.any_instance.expects(:run)
|
15
|
+
PartyFoul::RacklessExceptionHandler.handle(nil, {})
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#initialize' do
|
20
|
+
it 'should use PartyFoul::IssueRenderers::Rackless for rendering issues' do
|
21
|
+
issue_renderer = PartyFoul::RacklessExceptionHandler.new(nil, {}).rendered_issue
|
22
|
+
assert_kind_of(PartyFoul::IssueRenderers::Rackless, issue_renderer)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -1,13 +1,16 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
|
1
3
|
if defined?(M)
|
2
4
|
require 'minitest/spec'
|
3
5
|
else
|
4
6
|
require 'minitest/autorun'
|
5
7
|
end
|
6
|
-
|
7
|
-
require 'mocha/setup'
|
8
|
-
unless ENV['CI']
|
8
|
+
begin
|
9
9
|
require 'debugger'
|
10
|
+
rescue LoadError
|
10
11
|
end
|
12
|
+
require 'rack/test'
|
13
|
+
require 'mocha/setup'
|
11
14
|
require 'party_foul'
|
12
15
|
|
13
16
|
class MiniTest::Spec
|
@@ -21,7 +24,7 @@ module MiniTest::Expectations
|
|
21
24
|
end
|
22
25
|
|
23
26
|
def clean_up_party
|
24
|
-
%w{github oauth_token endpoint owner repo
|
27
|
+
%w{github oauth_token endpoint owner repo blacklisted_exceptions processor web_url branch}.each do |attr|
|
25
28
|
PartyFoul.send("#{attr}=", nil)
|
26
29
|
end
|
27
30
|
end
|
@@ -1,28 +1,25 @@
|
|
1
1
|
PartyFoul.configure do |config|
|
2
|
-
#
|
2
|
+
# The collection of exceptions PartyFoul should not be allowed to handle
|
3
3
|
# The constants here *must* be represented as strings
|
4
|
-
config.
|
5
|
-
|
6
|
-
# The names of the HTTP headers to not report
|
7
|
-
config.filtered_http_headers = ['Cookie']
|
4
|
+
config.blacklisted_exceptions = ['ActiveRecord::RecordNotFound', 'ActionController::RoutingError']
|
8
5
|
|
9
6
|
# The OAuth token for the account that is opening the issues on Github
|
10
|
-
config.oauth_token
|
7
|
+
config.oauth_token = 'test_token'
|
11
8
|
|
12
9
|
# The API endpoint for Github. Unless you are hosting a private
|
13
10
|
# instance of Enterprise Github you do not need to include this
|
14
|
-
config.endpoint
|
11
|
+
config.endpoint = 'http://api.example.com'
|
15
12
|
|
16
13
|
# The Web URL for Github. Unless you are hosting a private
|
17
14
|
# instance of Enterprise Github you do not need to include this
|
18
|
-
config.web_url
|
15
|
+
config.web_url = 'http://example.com'
|
19
16
|
|
20
17
|
# The organization or user that owns the target repository
|
21
|
-
config.owner
|
18
|
+
config.owner = 'test_owner'
|
22
19
|
|
23
20
|
# The repository for this application
|
24
|
-
config.repo
|
21
|
+
config.repo = 'test_repo'
|
25
22
|
|
26
23
|
# The branch for your deployed code
|
27
|
-
# config.branch
|
24
|
+
# config.branch = 'master'
|
28
25
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: party_foul
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2013-
|
13
|
+
date: 2013-02-04 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: github_api
|
@@ -28,6 +28,22 @@ dependencies:
|
|
28
28
|
- - ~>
|
29
29
|
- !ruby/object:Gem::Version
|
30
30
|
version: 0.8.8
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: io-console
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ~>
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: 0.3.0
|
39
|
+
type: :runtime
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 0.3.0
|
31
47
|
- !ruby/object:Gem::Dependency
|
32
48
|
name: actionpack
|
33
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -167,12 +183,16 @@ files:
|
|
167
183
|
- lib/generators/party_foul/install_generator.rb
|
168
184
|
- lib/generators/party_foul/templates/party_foul.rb
|
169
185
|
- lib/party_foul/exception_handler.rb
|
170
|
-
- lib/party_foul/
|
186
|
+
- lib/party_foul/issue_renderers/base.rb
|
171
187
|
- lib/party_foul/issue_renderers/rack.rb
|
188
|
+
- lib/party_foul/issue_renderers/rackless.rb
|
172
189
|
- lib/party_foul/issue_renderers/rails.rb
|
190
|
+
- lib/party_foul/issue_renderers.rb
|
173
191
|
- lib/party_foul/middleware.rb
|
192
|
+
- lib/party_foul/processors/base.rb
|
174
193
|
- lib/party_foul/processors/sync.rb
|
175
194
|
- lib/party_foul/processors.rb
|
195
|
+
- lib/party_foul/rackless_exception_handler.rb
|
176
196
|
- lib/party_foul/version.rb
|
177
197
|
- lib/party_foul.rb
|
178
198
|
- Rakefile
|
@@ -180,10 +200,12 @@ files:
|
|
180
200
|
- test/generator_test.rb
|
181
201
|
- test/party_foul/configure_test.rb
|
182
202
|
- test/party_foul/exception_handler_test.rb
|
183
|
-
- test/party_foul/
|
203
|
+
- test/party_foul/issue_renderers/base_test.rb
|
184
204
|
- test/party_foul/issue_renderers/rack_test.rb
|
205
|
+
- test/party_foul/issue_renderers/rackless_test.rb
|
185
206
|
- test/party_foul/issue_renderers/rails_test.rb
|
186
207
|
- test/party_foul/middleware_test.rb
|
208
|
+
- test/party_foul/rackless_exception_handler_test.rb
|
187
209
|
- test/test_helper.rb
|
188
210
|
- test/tmp/config/initializers/party_foul.rb
|
189
211
|
homepage: https://github.com/dockyard/party_foul
|
@@ -200,7 +222,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
200
222
|
version: '0'
|
201
223
|
segments:
|
202
224
|
- 0
|
203
|
-
hash: -
|
225
|
+
hash: -845978866647605957
|
204
226
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
205
227
|
none: false
|
206
228
|
requirements:
|
@@ -209,7 +231,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
209
231
|
version: '0'
|
210
232
|
segments:
|
211
233
|
- 0
|
212
|
-
hash: -
|
234
|
+
hash: -845978866647605957
|
213
235
|
requirements: []
|
214
236
|
rubyforge_project:
|
215
237
|
rubygems_version: 1.8.23
|
@@ -220,9 +242,11 @@ test_files:
|
|
220
242
|
- test/generator_test.rb
|
221
243
|
- test/party_foul/configure_test.rb
|
222
244
|
- test/party_foul/exception_handler_test.rb
|
223
|
-
- test/party_foul/
|
245
|
+
- test/party_foul/issue_renderers/base_test.rb
|
224
246
|
- test/party_foul/issue_renderers/rack_test.rb
|
247
|
+
- test/party_foul/issue_renderers/rackless_test.rb
|
225
248
|
- test/party_foul/issue_renderers/rails_test.rb
|
226
249
|
- test/party_foul/middleware_test.rb
|
250
|
+
- test/party_foul/rackless_exception_handler_test.rb
|
227
251
|
- test/test_helper.rb
|
228
252
|
- test/tmp/config/initializers/party_foul.rb
|
@@ -1,139 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
require 'active_support/core_ext/object/blank'
|
3
|
-
require 'action_dispatch/http/parameter_filter'
|
4
|
-
|
5
|
-
describe 'Party Foul Issue Renderer' do
|
6
|
-
before do
|
7
|
-
Time.stubs(:now).returns(Time.new(1970, 1, 1, 0, 0, 0, '-05:00'))
|
8
|
-
end
|
9
|
-
|
10
|
-
after do
|
11
|
-
clean_up_party
|
12
|
-
end
|
13
|
-
|
14
|
-
describe '#body' do
|
15
|
-
describe 'updating issue body' do
|
16
|
-
before do
|
17
|
-
@rendered_issue = PartyFoul::IssueRenderer.new(nil, nil)
|
18
|
-
@rendered_issue.stubs(:exception).returns('Test Exception')
|
19
|
-
@rendered_issue.stubs(:fingerprint).returns('abcdefg1234567890')
|
20
|
-
@rendered_issue.stubs(:stack_trace)
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'updates count and timestamp' do
|
24
|
-
body = <<-BODY
|
25
|
-
<table>
|
26
|
-
<tr><th>Exception</th><td>Test Exception</td></tr>
|
27
|
-
<tr><th>Count</th><td>1</td></tr>
|
28
|
-
<tr><th>Last Occurance</th><td>January 01, 1970 00:00:00 -0500</td></tr>
|
29
|
-
</table>
|
30
|
-
|
31
|
-
## Stack Trace
|
32
|
-
<pre></pre>
|
33
|
-
Fingerprint: `abcdefg1234567890`
|
34
|
-
BODY
|
35
|
-
|
36
|
-
Time.stubs(:now).returns(Time.new(1985, 10, 25, 1, 22, 0, '-05:00'))
|
37
|
-
|
38
|
-
expected_body = <<-BODY
|
39
|
-
<table>
|
40
|
-
<tr><th>Exception</th><td>Test Exception</td></tr>
|
41
|
-
<tr><th>Count</th><td>2</td></tr>
|
42
|
-
<tr><th>Last Occurance</th><td>October 25, 1985 01:22:00 -0500</td></tr>
|
43
|
-
</table>
|
44
|
-
|
45
|
-
## Stack Trace
|
46
|
-
<pre></pre>
|
47
|
-
Fingerprint: `abcdefg1234567890`
|
48
|
-
BODY
|
49
|
-
|
50
|
-
@rendered_issue.update_body(body).must_equal expected_body
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
describe 'empty body' do
|
55
|
-
before do
|
56
|
-
@rendered_issue = PartyFoul::IssueRenderer.new(nil, nil)
|
57
|
-
@rendered_issue.stubs(:exception).returns('Test Exception')
|
58
|
-
@rendered_issue.stubs(:fingerprint).returns('abcdefg1234567890')
|
59
|
-
@rendered_issue.stubs(:stack_trace)
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'resets body' do
|
63
|
-
expected_body = <<-BODY
|
64
|
-
<table>
|
65
|
-
<tr><th>Exception</th><td>Test Exception</td></tr>
|
66
|
-
<tr><th>Count</th><td>1</td></tr>
|
67
|
-
<tr><th>Last Occurance</th><td>January 01, 1970 00:00:00 -0500</td></tr>
|
68
|
-
</table>
|
69
|
-
|
70
|
-
## Stack Trace
|
71
|
-
<pre></pre>
|
72
|
-
Fingerprint: `abcdefg1234567890`
|
73
|
-
BODY
|
74
|
-
@rendered_issue.update_body(nil).must_equal expected_body
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
describe '#issue_comment' do
|
80
|
-
before do
|
81
|
-
env = {
|
82
|
-
'REQUEST_URI' => 'http://example.com/',
|
83
|
-
'HTTP_USER_AGENT' => 'test_user_agent',
|
84
|
-
'REMOTE_ADDR' => '127.0.0.1',
|
85
|
-
'HTTP_HOST' => 'localhost:3000',
|
86
|
-
'rack.session' => { :id => 1 }
|
87
|
-
}
|
88
|
-
@rendered_issue = PartyFoul::IssueRenderer.new(nil, env)
|
89
|
-
@rendered_issue.stubs(:params).returns({})
|
90
|
-
end
|
91
|
-
|
92
|
-
it 'renders a new comment' do
|
93
|
-
expected_comment = <<-COMMENT
|
94
|
-
<table>
|
95
|
-
<tr><th>Occurred at</th><td>January 01, 1970 00:00:00 -0500</td></tr>
|
96
|
-
<tr><th>Params</th><td><table></table></td></tr>
|
97
|
-
<tr><th>IP Address</th><td>127.0.0.1</td></tr>
|
98
|
-
<tr><th>Session</th><td><table><tr><th>id</th><td>1</td></tr></table></td></tr>
|
99
|
-
<tr><th>HTTP Headers</th><td><table><tr><th>Host</th><td>localhost:3000</td></tr><tr><th>User-Agent</th><td>test_user_agent</td></tr></table></td></tr>
|
100
|
-
</table>
|
101
|
-
COMMENT
|
102
|
-
|
103
|
-
@rendered_issue.comment.must_equal expected_comment
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
describe '#compile_template' do
|
108
|
-
it 'it parses the tags and inserts proper data' do
|
109
|
-
template = '<span>:data1</span><div>:data2</div>'
|
110
|
-
@rendered_issue = PartyFoul::IssueRenderer.new(nil, nil)
|
111
|
-
@rendered_issue.stubs(:data1).returns('123')
|
112
|
-
@rendered_issue.stubs(:data2).returns('abc')
|
113
|
-
@rendered_issue.compile_template(template).must_equal '<span>123</span><div>abc</div>'
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
describe '#http_headers' do
|
118
|
-
before do
|
119
|
-
PartyFoul.filtered_http_headers = ['Cookie']
|
120
|
-
env = {
|
121
|
-
'HTTP_USER_AGENT' => 'test_user_agent',
|
122
|
-
'HTTP_COOKIE' => 'test_cookie',
|
123
|
-
}
|
124
|
-
@rendered_issue = PartyFoul::IssueRenderer.new(nil, env)
|
125
|
-
end
|
126
|
-
|
127
|
-
it 'ignored Cookie' do
|
128
|
-
@rendered_issue.http_headers.must_equal('User-Agent' => 'test_user_agent')
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
describe '#fingerprint' do
|
133
|
-
it 'SHA1s the title' do
|
134
|
-
rendered_issue = PartyFoul::IssueRenderer.new(nil, nil)
|
135
|
-
rendered_issue.stubs(:title).returns('abcdefg1234567890')
|
136
|
-
rendered_issue.fingerprint.must_equal Digest::SHA1.hexdigest(rendered_issue.title)
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|