party_foul 0.3.0 → 0.4.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 +37 -37
- data/lib/generators/party_foul/install_generator.rb +3 -2
- data/lib/generators/party_foul/templates/party_foul.rb +5 -1
- data/lib/party_foul/exception_handler.rb +15 -104
- data/lib/party_foul/issue_renderer.rb +96 -0
- data/lib/party_foul/issue_renderers/rack.rb +13 -0
- data/lib/party_foul/issue_renderers/rails.rb +20 -0
- data/lib/party_foul/{sync_adapter.rb → processors/sync.rb} +1 -1
- data/lib/party_foul/processors.rb +4 -0
- data/lib/party_foul/version.rb +1 -1
- data/lib/party_foul.rb +14 -3
- data/test/generator_test.rb +10 -7
- data/test/party_foul/configure_test.rb +4 -2
- data/test/party_foul/exception_handler_test.rb +48 -139
- data/test/party_foul/issue_renderer_test.rb +139 -0
- data/test/party_foul/issue_renderers/rack_test.rb +24 -0
- data/test/party_foul/issue_renderers/rails_test.rb +31 -0
- data/test/party_foul/middleware_test.rb +6 -73
- data/test/test_helper.rb +1 -1
- data/test/tmp/config/initializers/party_foul.rb +7 -3
- metadata +15 -5
data/README.md
CHANGED
@@ -8,23 +8,23 @@ Rails exceptions automatically opened as issues on Github
|
|
8
8
|
|
9
9
|
## About ##
|
10
10
|
|
11
|
-
`PartyFoul`
|
11
|
+
`PartyFoul` captures exceptions in your application and does the
|
12
12
|
following:
|
13
13
|
|
14
|
-
1.
|
15
|
-
2. If no matching issue is found an new issue
|
16
|
-
unique title, session information, and stack trace. The issue
|
17
|
-
tagged as a `bug`. A new comment
|
14
|
+
1. Attempt to find a matching issue in your Github repo
|
15
|
+
2. If no matching issue is found an new issue is created with a
|
16
|
+
unique title, session information, and stack trace. The issue is
|
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 occurance count and time stamp
|
20
|
-
updated. A new comment
|
19
|
+
3. If an open issue is found the occurance count and time stamp is
|
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 occurance count and time stamp
|
23
|
-
updated. The issue
|
24
|
-
added. A new comment
|
22
|
+
4. If a closed issue is found the occurance count and time stamp is
|
23
|
+
updated. The issue is reopened and a `regression` tag is
|
24
|
+
added. A new comment is added with relevant data on the
|
25
25
|
application state.
|
26
26
|
5. If the issue is marked as `wontfix` the issue is not updated nor is
|
27
|
-
a new issue created. No comments
|
27
|
+
a new issue created. No comments are added.
|
28
28
|
|
29
29
|
## Installation ##
|
30
30
|
|
@@ -32,7 +32,7 @@ application state.
|
|
32
32
|
a collaborator on your repository. Use this new account's credentials
|
33
33
|
for the installation below. If you use your own account you will
|
34
34
|
not receive emails when issues are created, updated, reopened, etc...
|
35
|
-
because all of the work
|
35
|
+
because all of the work is done as your account.
|
36
36
|
|
37
37
|
In your Gemfile add the following:
|
38
38
|
|
@@ -47,8 +47,8 @@ If you are using Rails you can run the install generator.
|
|
47
47
|
rails g party_foul:install
|
48
48
|
```
|
49
49
|
|
50
|
-
This
|
51
|
-
|
50
|
+
This prompts you for the Github credentials of the account that is
|
51
|
+
opening the issues. The OAuth token for that account is stored
|
52
52
|
in `config/initializers/party_foul.rb`. You may want to remove the token
|
53
53
|
string and store in an environment variable. It is best not to store the
|
54
54
|
token in version control.
|
@@ -60,30 +60,33 @@ config.middleware.use('PartyFoul::Middleware')
|
|
60
60
|
```
|
61
61
|
### Other ###
|
62
62
|
|
63
|
-
You
|
64
|
-
so:
|
63
|
+
You need to initialize `PartyFoul`, use the following:
|
65
64
|
|
66
65
|
```ruby
|
67
66
|
PartyFoul.configure do |config|
|
68
67
|
# the collection of exceptions to be ignored by PartyFoul
|
69
68
|
# The constants here *must* be represented as strings
|
70
|
-
config.ignored_exceptions
|
69
|
+
config.ignored_exceptions = ['ActiveRecord::RecordNotFound', 'ActionController::RoutingError']
|
71
70
|
|
72
71
|
# The names of the HTTP headers to not report
|
73
72
|
config.filtered_http_headers = ['Cookie']
|
74
73
|
|
75
|
-
# The OAuth token for the account that
|
76
|
-
config.oauth_token
|
74
|
+
# The OAuth token for the account that is opening the issues on Github
|
75
|
+
config.oauth_token = 'abcdefgh1234567890'
|
77
76
|
|
78
77
|
# The API endpoint for Github. Unless you are hosting a private
|
79
78
|
# instance of Enterprise Github you do not need to include this
|
80
|
-
config.endpoint
|
79
|
+
config.endpoint = 'https://api.github.com'
|
80
|
+
|
81
|
+
# The Web URL for Github. Unless you are hosting a private
|
82
|
+
# instance of Enterprise Github you do not need to include this
|
83
|
+
config.web_url = 'https://github.com'
|
81
84
|
|
82
85
|
# The organization or user that owns the target repository
|
83
|
-
config.owner
|
86
|
+
config.owner = 'owner_name'
|
84
87
|
|
85
88
|
# The repository for this application
|
86
|
-
config.repo
|
89
|
+
config.repo = 'repo_name'
|
87
90
|
end
|
88
91
|
```
|
89
92
|
|
@@ -100,20 +103,20 @@ Add as the very last middleware in your production `Rack` stack.
|
|
100
103
|
|
101
104
|
## Customization ##
|
102
105
|
|
103
|
-
###
|
106
|
+
### Background Processing ###
|
104
107
|
|
105
108
|
You can specify the adapter with which the exceptions should be
|
106
109
|
handled. By default, PartyFoul includes the
|
107
110
|
[`PartyFoul::SyncAdapter`](https://github.com/dockyard/party_foul/tree/master/lib/party_foul/sync_adapter.rb)
|
108
|
-
which
|
111
|
+
which handles the exception synchronously. To use your own adapter,
|
109
112
|
include the following in your `PartyFoul.configure` block:
|
110
113
|
|
111
114
|
```ruby
|
112
115
|
PartyFoul.configure do |config|
|
113
|
-
config.adapter =
|
116
|
+
config.adapter = PartyFoul::Processors::MyBackgroundProcessor
|
114
117
|
end
|
115
118
|
|
116
|
-
class
|
119
|
+
class PartyFoul::Processors::MyBackgroundProcessor
|
117
120
|
def self.handle(exception, env)
|
118
121
|
# Enqueue the exception, then in your worker, call
|
119
122
|
# PartyFoul::ExceptionHandler.new(exception, env).run
|
@@ -122,7 +125,7 @@ end
|
|
122
125
|
|
123
126
|
```
|
124
127
|
|
125
|
-
|
128
|
+
### Changing How Issues Are Reported ###
|
126
129
|
|
127
130
|
`PartyFoul` comes with default templates for what the body of issues and
|
128
131
|
comments are. If you want to override these templates you simply need to
|
@@ -130,20 +133,17 @@ add them as an option in your initializer:
|
|
130
133
|
|
131
134
|
```ruby
|
132
135
|
PartyFoul.configure do |config|
|
133
|
-
config.issue_body
|
134
|
-
:
|
135
|
-
|
136
|
-
|
137
|
-
config.comment_body = <<-TEMPLATE
|
138
|
-
:occurred_at
|
139
|
-
TEMPLATE
|
136
|
+
config.issue_body = ':issue_title'
|
137
|
+
config.comment_body = ':occurred_at'
|
138
|
+
end
|
140
139
|
```
|
141
140
|
|
142
141
|
In this over-simplistic example the words that start with `:` in the
|
143
|
-
templates
|
144
|
-
instance method on the instance of `PartyFoul::
|
142
|
+
templates are evaluated with the value of the corresponding named
|
143
|
+
instance method on the instance of `PartyFoul::IssueRenderer`. If you
|
145
144
|
want to add additional values for replacement you should open that class
|
146
|
-
to add the methods.
|
145
|
+
to add the methods. Depending upon the data point you may want o make
|
146
|
+
the change in one of the [different issue renderer adapters](https://github.com/dockyard/party_foul/tree/master/lib/party_foul/issue_renderers).
|
147
147
|
|
148
148
|
## Authors ##
|
149
149
|
|
@@ -11,11 +11,12 @@ module PartyFoul
|
|
11
11
|
password = STDIN.noecho { ask 'Github password:' }
|
12
12
|
@owner = ask_with_default "\nRepository owner:", login
|
13
13
|
@repo = ask 'Repository name:'
|
14
|
-
@endpoint = ask_with_default 'Endpoint:', 'https://api.github.com'
|
14
|
+
@endpoint = ask_with_default 'Api Endpoint:', 'https://api.github.com'
|
15
|
+
@web_url = ask_with_default 'Web URL:', 'https://github.com'
|
15
16
|
|
16
17
|
begin
|
17
18
|
github = Github.new :login => login, :password => password, :endpoint => @endpoint
|
18
|
-
@oauth_token = github.oauth.create(
|
19
|
+
@oauth_token = github.oauth.create(scopes: ['repo'], note: "PartyFoul #{@owner}/#{@repo}", note_url: "#{@web_url}/#{@owner}/#{@repo}").token
|
19
20
|
template 'party_foul.rb', 'config/initializers/party_foul.rb'
|
20
21
|
rescue Github::Error::Unauthorized
|
21
22
|
say 'There was an error retrieving your Github OAuth token'
|
@@ -6,13 +6,17 @@ PartyFoul.configure do |config|
|
|
6
6
|
# The names of the HTTP headers to not report
|
7
7
|
config.filtered_http_headers = ['Cookie']
|
8
8
|
|
9
|
-
# The OAuth token for the account that
|
9
|
+
# The OAuth token for the account that is opening the issues on Github
|
10
10
|
config.oauth_token = '<%= @oauth_token %>'
|
11
11
|
|
12
12
|
# The API endpoint for Github. Unless you are hosting a private
|
13
13
|
# instance of Enterprise Github you do not need to include this
|
14
14
|
config.endpoint = '<%= @endpoint %>'
|
15
15
|
|
16
|
+
# The Web URL for Github. Unless you are hosting a private
|
17
|
+
# instance of Enterprise Github you do not need to include this
|
18
|
+
config.web_url = '<%= @web_url %>'
|
19
|
+
|
16
20
|
# The organization or user that owns the target repository
|
17
21
|
config.owner = '<%= @owner %>'
|
18
22
|
|
@@ -1,13 +1,18 @@
|
|
1
1
|
class PartyFoul::ExceptionHandler
|
2
|
-
attr_accessor :
|
2
|
+
attr_accessor :rendered_issue
|
3
3
|
|
4
4
|
def self.handle(exception, env)
|
5
|
-
PartyFoul.
|
5
|
+
PartyFoul.processor.handle(exception, env)
|
6
6
|
end
|
7
7
|
|
8
8
|
def initialize(exception, env)
|
9
|
-
|
10
|
-
|
9
|
+
renderer_klass = if defined?(Rails)
|
10
|
+
PartyFoul::RailsIssueRenderer
|
11
|
+
else
|
12
|
+
PartyFoul::RackIssueRenderer
|
13
|
+
end
|
14
|
+
|
15
|
+
self.rendered_issue = renderer_klass.new(exception, env)
|
11
16
|
end
|
12
17
|
|
13
18
|
def run
|
@@ -26,121 +31,27 @@ class PartyFoul::ExceptionHandler
|
|
26
31
|
issue
|
27
32
|
end
|
28
33
|
|
29
|
-
def stack_trace
|
30
|
-
exception.backtrace.map do |line|
|
31
|
-
if matches = extract_file_name_and_line_number(line)
|
32
|
-
"<a href='../tree/master/#{matches[2]}#L#{matches[3]}'>#{line}</a>"
|
33
|
-
else
|
34
|
-
line
|
35
|
-
end
|
36
|
-
end.join("\n")
|
37
|
-
end
|
38
|
-
|
39
34
|
def create_issue
|
40
|
-
issue = PartyFoul.github.issues.create(PartyFoul.owner, PartyFoul.repo, title:
|
41
|
-
PartyFoul.github.issues.comments.create(PartyFoul.owner, PartyFoul.repo, issue['number'], body:
|
35
|
+
issue = PartyFoul.github.issues.create(PartyFoul.owner, PartyFoul.repo, title: rendered_issue.title, body: rendered_issue.body, labels: ['bug'])
|
36
|
+
PartyFoul.github.issues.comments.create(PartyFoul.owner, PartyFoul.repo, issue['number'], body: rendered_issue.comment)
|
42
37
|
end
|
43
38
|
|
44
39
|
def update_issue(issue)
|
45
40
|
unless issue.key?('labels') && issue['labels'].include?('wontfix')
|
46
|
-
params = {body: update_body(issue['body']), state: 'open'}
|
41
|
+
params = {body: rendered_issue.update_body(issue['body']), state: 'open'}
|
47
42
|
|
48
43
|
if issue['state'] == 'closed'
|
49
44
|
params[:labels] = ['bug', 'regression']
|
50
45
|
end
|
51
46
|
|
52
47
|
PartyFoul.github.issues.edit(PartyFoul.owner, PartyFoul.repo, issue['number'], params)
|
53
|
-
PartyFoul.github.issues.comments.create(PartyFoul.owner, PartyFoul.repo, issue['number'], body:
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def issue_title
|
58
|
-
line = exception.backtrace.select {|p| p =~ /#{app_root}/ }.first
|
59
|
-
name_and_number = extract_file_name_and_line_number(line)[1]
|
60
|
-
"#{exception} - #{name_and_number}"
|
61
|
-
end
|
62
|
-
|
63
|
-
def fingerprint
|
64
|
-
Digest::SHA1.hexdigest(issue_title)
|
65
|
-
end
|
66
|
-
|
67
|
-
def update_body(body)
|
68
|
-
begin
|
69
|
-
current_count = body.match(/<th>Count<\/th><td>(\d+)<\/td>/)[1].to_i
|
70
|
-
body.sub!("<th>Count</th><td>#{current_count}</td>", "<th>Count</th><td>#{current_count + 1}</td>")
|
71
|
-
body.sub!(/<th>Last Occurance<\/th><td>.+<\/td>/, "<th>Last Occurance</th><td>#{occurred_at}</td>")
|
72
|
-
body
|
73
|
-
rescue
|
74
|
-
issue_body
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def params
|
79
|
-
if env["action_dispatch.parameter_filter"]
|
80
|
-
parameter_filter = ActionDispatch::Http::ParameterFilter.new(env["action_dispatch.parameter_filter"])
|
81
|
-
parameter_filter.filter(env['action_dispatch.request.path_parameters'])
|
82
|
-
else
|
83
|
-
env['QUERY_STRING']
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def issue_body
|
88
|
-
compile_template(PartyFoul.issue_template)
|
89
|
-
end
|
90
|
-
|
91
|
-
def comment_body
|
92
|
-
compile_template(PartyFoul.comment_template)
|
93
|
-
end
|
94
|
-
|
95
|
-
def compile_template(template)
|
96
|
-
template.gsub(/:\w+/) do |method|
|
97
|
-
value = self.send(method.split(':').last)
|
98
|
-
if value.kind_of?(Hash)
|
99
|
-
hash_as_table(value)
|
100
|
-
else
|
101
|
-
value
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
def hash_as_table(value)
|
107
|
-
"<table>#{value.map {|key, value| "<tr><th>#{key}</th><td>#{value}</td></tr>"}.join}</table>"
|
108
|
-
end
|
109
|
-
|
110
|
-
def occurred_at
|
111
|
-
Time.now.strftime('%B %d, %Y %H:%M:%S %z')
|
112
|
-
end
|
113
|
-
|
114
|
-
def ip_address
|
115
|
-
env['REMOTE_ADDR']
|
116
|
-
end
|
117
|
-
|
118
|
-
def session
|
119
|
-
env['rack.session']
|
120
|
-
end
|
121
|
-
|
122
|
-
def http_headers
|
123
|
-
env.keys.select { |key| key =~ /^HTTP_(\w+)/ && !(PartyFoul.filtered_http_headers || []).include?($1.split('_').map(&:capitalize).join('-')) }.sort.inject({}) do |hash, key|
|
124
|
-
hash[key.split('HTTP_').last.split('_').map(&:capitalize).join('-')] = env[key]
|
125
|
-
hash
|
48
|
+
PartyFoul.github.issues.comments.create(PartyFoul.owner, PartyFoul.repo, issue['number'], body: rendered_issue.comment)
|
126
49
|
end
|
127
50
|
end
|
128
51
|
|
129
52
|
private
|
130
53
|
|
131
|
-
def
|
132
|
-
|
133
|
-
Rails.root
|
134
|
-
else
|
135
|
-
Dir.pwd
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
def file_and_line_regex
|
140
|
-
/#{app_root}\/((.+?):(\d+))/
|
141
|
-
end
|
142
|
-
|
143
|
-
def extract_file_name_and_line_number(backtrace_line)
|
144
|
-
backtrace_line.match(file_and_line_regex)
|
54
|
+
def fingerprint
|
55
|
+
rendered_issue.fingerprint
|
145
56
|
end
|
146
57
|
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
class PartyFoul::IssueRenderer
|
2
|
+
attr_accessor :exception, :env
|
3
|
+
|
4
|
+
def initialize(exception, env)
|
5
|
+
self.exception = exception
|
6
|
+
self.env = env
|
7
|
+
end
|
8
|
+
|
9
|
+
def title
|
10
|
+
raise NotImplementedError
|
11
|
+
end
|
12
|
+
|
13
|
+
def body
|
14
|
+
compile_template(PartyFoul.issue_template)
|
15
|
+
end
|
16
|
+
|
17
|
+
def comment
|
18
|
+
compile_template(PartyFoul.comment_template)
|
19
|
+
end
|
20
|
+
|
21
|
+
def stack_trace
|
22
|
+
exception.backtrace.map do |line|
|
23
|
+
if matches = extract_file_name_and_line_number(line)
|
24
|
+
"<a href='#{PartyFoul.repo_url}/tree/master/#{matches[2]}#L#{matches[3]}'>#{line}</a>"
|
25
|
+
else
|
26
|
+
line
|
27
|
+
end
|
28
|
+
end.join("\n")
|
29
|
+
end
|
30
|
+
|
31
|
+
def fingerprint
|
32
|
+
Digest::SHA1.hexdigest(title)
|
33
|
+
end
|
34
|
+
|
35
|
+
def update_body(old_body)
|
36
|
+
begin
|
37
|
+
current_count = old_body.match(/<th>Count<\/th><td>(\d+)<\/td>/)[1].to_i
|
38
|
+
old_body.sub!("<th>Count</th><td>#{current_count}</td>", "<th>Count</th><td>#{current_count + 1}</td>")
|
39
|
+
old_body.sub!(/<th>Last Occurance<\/th><td>.+<\/td>/, "<th>Last Occurance</th><td>#{occurred_at}</td>")
|
40
|
+
old_body
|
41
|
+
rescue
|
42
|
+
self.body
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def params
|
47
|
+
raise NotImplementedError
|
48
|
+
end
|
49
|
+
|
50
|
+
def occurred_at
|
51
|
+
Time.now.strftime('%B %d, %Y %H:%M:%S %z')
|
52
|
+
end
|
53
|
+
|
54
|
+
def ip_address
|
55
|
+
env['REMOTE_ADDR']
|
56
|
+
end
|
57
|
+
|
58
|
+
def session
|
59
|
+
env['rack.session']
|
60
|
+
end
|
61
|
+
|
62
|
+
def http_headers
|
63
|
+
env.keys.select { |key| key =~ /^HTTP_(\w+)/ && !(PartyFoul.filtered_http_headers || []).include?($1.split('_').map(&:capitalize).join('-')) }.sort.inject({}) do |hash, key|
|
64
|
+
hash[key.split('HTTP_').last.split('_').map(&:capitalize).join('-')] = env[key]
|
65
|
+
hash
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def compile_template(template)
|
70
|
+
template.gsub(/:\w+/) do |method|
|
71
|
+
value = self.send(method.split(':').last)
|
72
|
+
if value.kind_of?(Hash)
|
73
|
+
hash_as_table(value)
|
74
|
+
else
|
75
|
+
value
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def hash_as_table(value)
|
83
|
+
"<table>#{value.map {|key, value| "<tr><th>#{key}</th><td>#{value}</td></tr>"}.join}</table>"
|
84
|
+
end
|
85
|
+
|
86
|
+
def app_root
|
87
|
+
Dir.pwd
|
88
|
+
end
|
89
|
+
|
90
|
+
def extract_file_name_and_line_number(backtrace_line)
|
91
|
+
backtrace_line.match(/#{app_root}\/((.+?):(\d+))/)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
require 'party_foul/issue_renderers/rack'
|
96
|
+
require 'party_foul/issue_renderers/rails'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'party_foul/issue_renderer'
|
2
|
+
|
3
|
+
module PartyFoul
|
4
|
+
class RailsIssueRenderer < IssueRenderer
|
5
|
+
def params
|
6
|
+
parameter_filter = ActionDispatch::Http::ParameterFilter.new(env["action_dispatch.parameter_filter"])
|
7
|
+
parameter_filter.filter(env['action_dispatch.request.path_parameters'])
|
8
|
+
end
|
9
|
+
|
10
|
+
def title
|
11
|
+
%{#{env['action_controller.instance'].class}##{env['action_dispatch.request.path_parameters']['action']} (#{exception.class}) "#{exception.message}"}
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def app_root
|
17
|
+
Rails.root
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/party_foul/version.rb
CHANGED
data/lib/party_foul.rb
CHANGED
@@ -2,7 +2,13 @@ require 'github_api'
|
|
2
2
|
|
3
3
|
module PartyFoul
|
4
4
|
class << self
|
5
|
-
attr_accessor :github, :oauth_token, :endpoint, :owner, :repo,
|
5
|
+
attr_accessor :github, :oauth_token, :endpoint, :owner, :repo,
|
6
|
+
:ignored_exceptions, :processor, :issue_template,
|
7
|
+
:comment_template, :filtered_http_headers, :web_url
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.web_url
|
11
|
+
@web_url ||= 'https://github.com'
|
6
12
|
end
|
7
13
|
|
8
14
|
def self.issue_template
|
@@ -37,9 +43,13 @@ Fingerprint: `:fingerprint`
|
|
37
43
|
@ignored_exceptions || []
|
38
44
|
end
|
39
45
|
|
46
|
+
def self.repo_url
|
47
|
+
"#{web_url}/#{owner}/#{repo}"
|
48
|
+
end
|
49
|
+
|
40
50
|
def self.configure(&block)
|
41
51
|
yield self
|
42
|
-
self.
|
52
|
+
self.processor ||= PartyFoul::Processors::Sync
|
43
53
|
_self = self
|
44
54
|
self.github ||= Github.new do |config|
|
45
55
|
%w{endpoint oauth_token}.each do |option|
|
@@ -50,5 +60,6 @@ Fingerprint: `:fingerprint`
|
|
50
60
|
end
|
51
61
|
|
52
62
|
require 'party_foul/exception_handler'
|
63
|
+
require 'party_foul/issue_renderer'
|
53
64
|
require 'party_foul/middleware'
|
54
|
-
require 'party_foul/
|
65
|
+
require 'party_foul/processors'
|
data/test/generator_test.rb
CHANGED
@@ -6,20 +6,23 @@ class PartyFoul::GeneratorTest < Rails::Generators::TestCase
|
|
6
6
|
destination File.expand_path('../tmp', __FILE__)
|
7
7
|
tests PartyFoul::InstallGenerator
|
8
8
|
test 'it copies the initializer' do
|
9
|
+
owner = 'test_owner'
|
10
|
+
repo = 'test_repo'
|
9
11
|
oauth = mock('Oauth')
|
10
12
|
oauth.stubs(:create)
|
11
|
-
oauth.expects(:create).with(
|
13
|
+
oauth.expects(:create).with(scopes: ['repo'], note: 'PartyFoul test_owner/test_repo', note_url: 'http://example.com/test_owner/test_repo').returns(Hashie::Mash.new(token: 'test_token'))
|
12
14
|
github = mock('Github')
|
13
15
|
github.stubs(:oauth).returns(oauth)
|
14
|
-
Github.stubs(:new).with(:login => 'test_login', :password => 'test_password', :endpoint => '
|
15
|
-
$stdin.stubs(:gets).returns('test_login').then.returns('test_password').then.returns(
|
16
|
+
Github.stubs(:new).with(:login => 'test_login', :password => 'test_password', :endpoint => 'http://api.example.com').returns(github)
|
17
|
+
$stdin.stubs(:gets).returns('test_login').then.returns('test_password').then.returns(owner).then.returns(repo).then.returns('http://api.example.com').then.returns('http://example.com').then.returns('')
|
16
18
|
run_generator
|
17
19
|
|
18
20
|
assert_file 'config/initializers/party_foul.rb' do |initializer|
|
19
|
-
assert_match(/config
|
20
|
-
assert_match(/config
|
21
|
-
assert_match(/config
|
22
|
-
assert_match(/config
|
21
|
+
assert_match(/config\.endpoint\s+=\s'http:\/\/api\.example\.com'/, initializer)
|
22
|
+
assert_match(/config\.web_url\s+=\s'http:\/\/example\.com'/, initializer)
|
23
|
+
assert_match(/config\.owner\s+=\s'test_owner'/, initializer)
|
24
|
+
assert_match(/config\.repo\s+=\s'test_repo'/, initializer)
|
25
|
+
assert_match(/config\.oauth_token\s+=\s'test_token'/, initializer)
|
23
26
|
end
|
24
27
|
end
|
25
28
|
end
|
@@ -10,7 +10,8 @@ describe 'Party Foul Confg' do
|
|
10
10
|
PartyFoul.configure do |config|
|
11
11
|
config.ignored_exceptions = ['StandardError']
|
12
12
|
config.oauth_token = 'test_token'
|
13
|
-
config.
|
13
|
+
config.web_url = 'http://example.com'
|
14
|
+
config.endpoint = 'http://api.example.com'
|
14
15
|
config.owner = 'test_owner'
|
15
16
|
config.repo = 'test_repo'
|
16
17
|
end
|
@@ -18,8 +19,9 @@ describe 'Party Foul Confg' do
|
|
18
19
|
PartyFoul.ignored_exceptions.must_equal ['StandardError']
|
19
20
|
PartyFoul.github.must_be_instance_of Github::Client
|
20
21
|
PartyFoul.github.oauth_token.must_equal 'test_token'
|
21
|
-
PartyFoul.github.endpoint.must_equal '
|
22
|
+
PartyFoul.github.endpoint.must_equal 'http://api.example.com'
|
22
23
|
PartyFoul.owner.must_equal 'test_owner'
|
23
24
|
PartyFoul.repo.must_equal 'test_repo'
|
25
|
+
PartyFoul.repo_url.must_equal 'http://example.com/test_owner/test_repo'
|
24
26
|
end
|
25
27
|
end
|
@@ -1,161 +1,70 @@
|
|
1
1
|
require 'test_helper'
|
2
|
-
require 'active_support/core_ext/object/blank'
|
3
|
-
require 'action_dispatch/http/parameter_filter'
|
4
2
|
|
5
3
|
describe 'Party Foul Exception Handler' do
|
6
4
|
before do
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
clean_up_party
|
12
|
-
end
|
13
|
-
|
14
|
-
describe '#body' do
|
15
|
-
describe 'updating issue body' do
|
16
|
-
before do
|
17
|
-
@handler = PartyFoul::ExceptionHandler.new(nil, nil)
|
18
|
-
@handler.stubs(:exception).returns('Test Exception')
|
19
|
-
@handler.stubs(:fingerprint).returns('abcdefg1234567890')
|
20
|
-
@handler.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
|
-
@handler.update_body(body).must_equal expected_body
|
51
|
-
end
|
5
|
+
PartyFoul.configure do |config|
|
6
|
+
config.oauth_token = 'abcdefg1234567890'
|
7
|
+
config.owner = 'test_owner'
|
8
|
+
config.repo = 'test_repo'
|
52
9
|
end
|
53
10
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
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
|
-
@handler.update_body(nil).must_equal expected_body
|
75
|
-
end
|
76
|
-
end
|
11
|
+
PartyFoul.github.stubs(:issues).returns(mock('Issues'))
|
12
|
+
PartyFoul.github.stubs(:search).returns(mock('Search'))
|
13
|
+
PartyFoul.github.issues.stubs(:create)
|
14
|
+
PartyFoul.github.issues.stubs(:edit)
|
15
|
+
PartyFoul.github.issues.stubs(:comments).returns(mock('Comments'))
|
16
|
+
PartyFoul.github.issues.comments.stubs(:create)
|
17
|
+
PartyFoul::RailsIssueRenderer.any_instance.stubs(:title).returns('Test Title')
|
18
|
+
PartyFoul::RailsIssueRenderer.any_instance.stubs(:fingerprint).returns('test_fingerprint')
|
77
19
|
end
|
78
20
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
context 'without Rails' do
|
92
|
-
before do
|
93
|
-
@handler = PartyFoul::ExceptionHandler.new(nil, {'QUERY_STRING' => { 'status' => 'ok' } })
|
94
|
-
end
|
95
|
-
|
96
|
-
it 'returns ok' do
|
97
|
-
@handler.params['status'].must_equal 'ok'
|
98
|
-
end
|
21
|
+
context 'when error is new' do
|
22
|
+
it 'will open a new error on Github' do
|
23
|
+
PartyFoul::RailsIssueRenderer.any_instance.stubs(:body).returns('Test Body')
|
24
|
+
PartyFoul::RailsIssueRenderer.any_instance.stubs(:comment).returns('Test Comment')
|
25
|
+
PartyFoul.github.search.stubs(:issues).with(owner: 'test_owner', repo: 'test_repo', keyword: 'test_fingerprint', state: 'open').returns(Hashie::Mash.new(issues: []))
|
26
|
+
PartyFoul.github.search.stubs(:issues).with(owner: 'test_owner', repo: 'test_repo', keyword: 'test_fingerprint', state: 'closed').returns(Hashie::Mash.new(issues: []))
|
27
|
+
PartyFoul.github.issues.expects(:create).with('test_owner', 'test_repo', title: 'Test Title', body: 'Test Body', :labels => ['bug']).returns(Hashie::Mash.new('number' => 1))
|
28
|
+
PartyFoul.github.issues.comments.expects(:create).with('test_owner', 'test_repo', 1, body: 'Test Comment')
|
29
|
+
PartyFoul::ExceptionHandler.new(nil, {}).run
|
99
30
|
end
|
100
31
|
end
|
101
32
|
|
102
|
-
|
33
|
+
context 'when error is not new' do
|
103
34
|
before do
|
104
|
-
|
105
|
-
|
106
|
-
'HTTP_USER_AGENT' => 'test_user_agent',
|
107
|
-
'REMOTE_ADDR' => '127.0.0.1',
|
108
|
-
'HTTP_HOST' => 'localhost:3000',
|
109
|
-
'QUERY_STRING' => { :controller => 'landing', :action => 'index' },
|
110
|
-
'rack.session' => { :id => 1 }
|
111
|
-
}
|
112
|
-
@handler = PartyFoul::ExceptionHandler.new(nil, env)
|
35
|
+
PartyFoul::RailsIssueRenderer.any_instance.stubs(:update_body).returns('New Body')
|
36
|
+
PartyFoul::RailsIssueRenderer.any_instance.stubs(:comment).returns('Test Comment')
|
113
37
|
end
|
114
38
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
<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>
|
123
|
-
</table>
|
124
|
-
COMMENT
|
125
|
-
|
126
|
-
@handler.comment_body.must_equal expected_comment
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
describe '#compile_template' do
|
131
|
-
it 'it parses the tags and inserts proper data' do
|
132
|
-
template = '<span>:data1</span><div>:data2</div>'
|
133
|
-
@handler = PartyFoul::ExceptionHandler.new(nil, nil)
|
134
|
-
@handler.stubs(:data1).returns('123')
|
135
|
-
@handler.stubs(:data2).returns('abc')
|
136
|
-
@handler.compile_template(template).must_equal '<span>123</span><div>abc</div>'
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
describe '#http_headers' do
|
141
|
-
before do
|
142
|
-
PartyFoul.filtered_http_headers = ['Cookie']
|
143
|
-
env = {
|
144
|
-
'HTTP_USER_AGENT' => 'test_user_agent',
|
145
|
-
'HTTP_COOKIE' => 'test_cookie',
|
146
|
-
}
|
147
|
-
@handler = PartyFoul::ExceptionHandler.new(nil, env)
|
39
|
+
context 'and open' do
|
40
|
+
it 'will update the issue' do
|
41
|
+
PartyFoul.github.search.stubs(:issues).with(owner: 'test_owner', repo: 'test_repo', keyword: 'test_fingerprint', state: 'open').returns(Hashie::Mash.new(issues: [{title: 'Test Title', body: 'Test Body', state: 'open', number: 1}]))
|
42
|
+
PartyFoul.github.issues.expects(:edit).with('test_owner', 'test_repo', 1, body: 'New Body', state: 'open')
|
43
|
+
PartyFoul.github.issues.comments.expects(:create).with('test_owner', 'test_repo', 1, body: 'Test Comment')
|
44
|
+
PartyFoul::ExceptionHandler.new(nil, {}).run
|
45
|
+
end
|
148
46
|
end
|
149
47
|
|
150
|
-
|
151
|
-
|
48
|
+
context 'and closed' do
|
49
|
+
it 'will update the count on the body and re-open the issue' do
|
50
|
+
PartyFoul.github.search.stubs(:issues).with(owner: 'test_owner', repo: 'test_repo', keyword: 'test_fingerprint', state: 'open').returns(Hashie::Mash.new(issues: []))
|
51
|
+
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}]))
|
52
|
+
PartyFoul.github.issues.expects(:edit).with('test_owner', 'test_repo', 1, body: 'New Body', state: 'open', labels: ['bug', 'regression'])
|
53
|
+
PartyFoul.github.issues.comments.expects(:create).with('test_owner', 'test_repo', 1, body: 'Test Comment')
|
54
|
+
PartyFoul::ExceptionHandler.new(nil, {}).run
|
55
|
+
end
|
152
56
|
end
|
153
57
|
end
|
154
58
|
|
155
|
-
|
156
|
-
it '
|
157
|
-
|
158
|
-
PartyFoul
|
59
|
+
context 'when issue is marked as "wontfix"' do
|
60
|
+
it 'does nothing' do
|
61
|
+
PartyFoul::RailsIssueRenderer.any_instance.stubs(:body).returns('Test Body')
|
62
|
+
PartyFoul.github.search.stubs(:issues).with(owner: 'test_owner', repo: 'test_repo', keyword: 'test_fingerprint', state: 'open').returns(Hashie::Mash.new(issues: []))
|
63
|
+
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']}]))
|
64
|
+
PartyFoul.github.issues.expects(:create).never
|
65
|
+
PartyFoul.github.issues.expects(:edit).never
|
66
|
+
PartyFoul.github.issues.comments.expects(:create).never
|
67
|
+
PartyFoul::ExceptionHandler.new(nil, {}).run
|
159
68
|
end
|
160
69
|
end
|
161
70
|
end
|
@@ -0,0 +1,139 @@
|
|
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
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe 'Rack Issue Renderer' do
|
4
|
+
describe '#params' do
|
5
|
+
before do
|
6
|
+
@rendered_issue = PartyFoul::RackIssueRenderer.new(nil, {'QUERY_STRING' => { 'status' => 'ok' } })
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'returns ok' do
|
10
|
+
@rendered_issue.params['status'].must_equal 'ok'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#title' do
|
15
|
+
before do
|
16
|
+
@exception = Exception.new('message')
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'constructs the title with the class and instance method' do
|
20
|
+
@rendered_issue = PartyFoul::RackIssueRenderer.new(@exception, {})
|
21
|
+
@rendered_issue.title.must_equal %{(Exception) "message"}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe 'Rails Issue Renderer' do
|
4
|
+
describe '#params' do
|
5
|
+
before do
|
6
|
+
@rendered_issue = PartyFoul::RailsIssueRenderer.new(nil, {'action_dispatch.parameter_filter' => ['password'], 'action_dispatch.request.path_parameters' => { 'status' => 'ok', 'password' => 'test' }, 'QUERY_STRING' => { 'status' => 'fail' } })
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'returns ok' do
|
10
|
+
@rendered_issue.params['status'].must_equal 'ok'
|
11
|
+
@rendered_issue.params['password'].must_equal '[FILTERED]'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#title' do
|
16
|
+
before do
|
17
|
+
@exception = Exception.new('message')
|
18
|
+
controller_instance = mock('Controller')
|
19
|
+
controller_instance.stubs(:class).returns('LandingController')
|
20
|
+
env = {
|
21
|
+
'action_dispatch.request.path_parameters' => { 'controller' => 'landing', 'action' => 'index' },
|
22
|
+
'action_controller.instance' => controller_instance
|
23
|
+
}
|
24
|
+
@rendered_issue = PartyFoul::RailsIssueRenderer.new(@exception, env)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'constructs the title with the controller and action' do
|
28
|
+
@rendered_issue.title.must_equal %{LandingController#index (Exception) "message"}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -21,74 +21,10 @@ describe 'Party Foul Middleware' do
|
|
21
21
|
}
|
22
22
|
end
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
config.repo = 'test_repo'
|
29
|
-
end
|
30
|
-
PartyFoul.github.stubs(:issues).returns(mock('Issues'))
|
31
|
-
PartyFoul.github.stubs(:search).returns(mock('Search'))
|
32
|
-
PartyFoul.github.issues.stubs(:create)
|
33
|
-
PartyFoul.github.issues.stubs(:edit)
|
34
|
-
PartyFoul.github.issues.stubs(:comments).returns(mock('Comments'))
|
35
|
-
PartyFoul.github.issues.comments.stubs(:create)
|
36
|
-
PartyFoul::ExceptionHandler.any_instance.stubs(:issue_title).returns('Test Title')
|
37
|
-
PartyFoul::ExceptionHandler.any_instance.stubs(:fingerprint).returns('test_fingerprint')
|
38
|
-
end
|
39
|
-
|
40
|
-
context 'when error is new' do
|
41
|
-
it 'will open a new error on Github' do
|
42
|
-
PartyFoul::ExceptionHandler.any_instance.stubs(:issue_body).returns('Test Body')
|
43
|
-
PartyFoul::ExceptionHandler.any_instance.stubs(:comment_body).returns('Test Comment')
|
44
|
-
PartyFoul.github.search.stubs(:issues).with(owner: 'test_owner', repo: 'test_repo', keyword: 'test_fingerprint', state: 'open').returns(Hashie::Mash.new(issues: []))
|
45
|
-
PartyFoul.github.search.stubs(:issues).with(owner: 'test_owner', repo: 'test_repo', keyword: 'test_fingerprint', state: 'closed').returns(Hashie::Mash.new(issues: []))
|
46
|
-
PartyFoul.github.issues.expects(:create).with('test_owner', 'test_repo', title: 'Test Title', body: 'Test Body', :labels => ['bug']).returns(Hashie::Mash.new('number' => 1))
|
47
|
-
PartyFoul.github.issues.comments.expects(:create).with('test_owner', 'test_repo', 1, body: 'Test Comment')
|
48
|
-
lambda {
|
49
|
-
get '/'
|
50
|
-
}.must_raise(Exception)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
context 'when error is not new' do
|
55
|
-
before do
|
56
|
-
PartyFoul::ExceptionHandler.any_instance.stubs(:update_body).returns('New Body')
|
57
|
-
PartyFoul::ExceptionHandler.any_instance.stubs(:comment_body).returns('Test Comment')
|
58
|
-
end
|
59
|
-
|
60
|
-
context 'and open' do
|
61
|
-
it 'will update the issue' do
|
62
|
-
PartyFoul.github.search.stubs(:issues).with(owner: 'test_owner', repo: 'test_repo', keyword: 'test_fingerprint', state: 'open').returns(Hashie::Mash.new(issues: [{title: 'Test Title', body: 'Test Body', state: 'open', number: 1}]))
|
63
|
-
PartyFoul.github.issues.expects(:edit).with('test_owner', 'test_repo', 1, body: 'New Body', state: 'open')
|
64
|
-
PartyFoul.github.issues.comments.expects(:create).with('test_owner', 'test_repo', 1, body: 'Test Comment')
|
65
|
-
lambda {
|
66
|
-
get '/'
|
67
|
-
}.must_raise(Exception)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
context 'and closed' do
|
72
|
-
it 'will update the count on the body and re-open the issue' do
|
73
|
-
PartyFoul.github.search.stubs(:issues).with(owner: 'test_owner', repo: 'test_repo', keyword: 'test_fingerprint', state: 'open').returns(Hashie::Mash.new(issues: []))
|
74
|
-
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}]))
|
75
|
-
PartyFoul.github.issues.expects(:edit).with('test_owner', 'test_repo', 1, body: 'New Body', state: 'open', labels: ['bug', 'regression'])
|
76
|
-
PartyFoul.github.issues.comments.expects(:create).with('test_owner', 'test_repo', 1, body: 'Test Comment')
|
77
|
-
lambda {
|
78
|
-
get '/'
|
79
|
-
}.must_raise(Exception)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
context 'when issue is marked as "wontfix"' do
|
85
|
-
it 'does nothing' do
|
86
|
-
PartyFoul::ExceptionHandler.any_instance.stubs(:issue_body).returns('Test Body')
|
87
|
-
PartyFoul.github.search.stubs(:issues).with(owner: 'test_owner', repo: 'test_repo', keyword: 'test_fingerprint', state: 'open').returns(Hashie::Mash.new(issues: []))
|
88
|
-
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']}]))
|
89
|
-
PartyFoul.github.issues.expects(:create).never
|
90
|
-
PartyFoul.github.issues.expects(:edit).never
|
91
|
-
PartyFoul.github.issues.comments.expects(:create).never
|
24
|
+
context 'handling an exception' do
|
25
|
+
it 'does not handle exception' do
|
26
|
+
PartyFoul::ExceptionHandler.stubs(:handle)
|
27
|
+
PartyFoul::ExceptionHandler.expects(:handle)
|
92
28
|
lambda {
|
93
29
|
get '/'
|
94
30
|
}.must_raise(Exception)
|
@@ -102,11 +38,8 @@ describe 'Party Foul Middleware' do
|
|
102
38
|
end
|
103
39
|
|
104
40
|
it 'does not handle exception' do
|
105
|
-
PartyFoul::ExceptionHandler.
|
106
|
-
PartyFoul.
|
107
|
-
PartyFoul.github.search.stubs(:issues).with(owner: 'test_owner', repo: 'test_repo', keyword: 'test_fingerprint', state: 'closed').returns(Hashie::Mash.new(issues: []))
|
108
|
-
PartyFoul.github.issues.expects(:create).never
|
109
|
-
PartyFoul.github.issues.comments.expects(:create).never
|
41
|
+
PartyFoul::ExceptionHandler.stubs(:handle)
|
42
|
+
PartyFoul::ExceptionHandler.expects(:handle).never
|
110
43
|
lambda {
|
111
44
|
get '/'
|
112
45
|
}.must_raise(StandardError)
|
data/test/test_helper.rb
CHANGED
@@ -21,7 +21,7 @@ module MiniTest::Expectations
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def clean_up_party
|
24
|
-
%w{github oauth_token endpoint owner repo ignored_exceptions
|
24
|
+
%w{github oauth_token endpoint owner repo ignored_exceptions processor issue_template comment_template filtered_http_headers web_url}.each do |attr|
|
25
25
|
PartyFoul.send("#{attr}=", nil)
|
26
26
|
end
|
27
27
|
end
|
@@ -6,15 +6,19 @@ PartyFoul.configure do |config|
|
|
6
6
|
# The names of the HTTP headers to not report
|
7
7
|
config.filtered_http_headers = ['Cookie']
|
8
8
|
|
9
|
-
# The OAuth token for the account that
|
9
|
+
# The OAuth token for the account that is opening the issues on Github
|
10
10
|
config.oauth_token = 'test_token'
|
11
11
|
|
12
12
|
# The API endpoint for Github. Unless you are hosting a private
|
13
13
|
# instance of Enterprise Github you do not need to include this
|
14
|
-
config.endpoint = '
|
14
|
+
config.endpoint = 'http://api.example.com'
|
15
|
+
|
16
|
+
# The Web URL for Github. Unless you are hosting a private
|
17
|
+
# instance of Enterprise Github you do not need to include this
|
18
|
+
config.web_url = 'http://example.com'
|
15
19
|
|
16
20
|
# The organization or user that owns the target repository
|
17
|
-
config.owner = '
|
21
|
+
config.owner = 'test_owner'
|
18
22
|
|
19
23
|
# The repository for this application
|
20
24
|
config.repo = 'test_repo'
|
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.4.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-01-
|
13
|
+
date: 2013-01-27 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: github_api
|
@@ -167,8 +167,12 @@ files:
|
|
167
167
|
- lib/generators/party_foul/install_generator.rb
|
168
168
|
- lib/generators/party_foul/templates/party_foul.rb
|
169
169
|
- lib/party_foul/exception_handler.rb
|
170
|
+
- lib/party_foul/issue_renderer.rb
|
171
|
+
- lib/party_foul/issue_renderers/rack.rb
|
172
|
+
- lib/party_foul/issue_renderers/rails.rb
|
170
173
|
- lib/party_foul/middleware.rb
|
171
|
-
- lib/party_foul/
|
174
|
+
- lib/party_foul/processors/sync.rb
|
175
|
+
- lib/party_foul/processors.rb
|
172
176
|
- lib/party_foul/version.rb
|
173
177
|
- lib/party_foul.rb
|
174
178
|
- Rakefile
|
@@ -176,6 +180,9 @@ files:
|
|
176
180
|
- test/generator_test.rb
|
177
181
|
- test/party_foul/configure_test.rb
|
178
182
|
- test/party_foul/exception_handler_test.rb
|
183
|
+
- test/party_foul/issue_renderer_test.rb
|
184
|
+
- test/party_foul/issue_renderers/rack_test.rb
|
185
|
+
- test/party_foul/issue_renderers/rails_test.rb
|
179
186
|
- test/party_foul/middleware_test.rb
|
180
187
|
- test/test_helper.rb
|
181
188
|
- test/tmp/config/initializers/party_foul.rb
|
@@ -193,7 +200,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
193
200
|
version: '0'
|
194
201
|
segments:
|
195
202
|
- 0
|
196
|
-
hash:
|
203
|
+
hash: -3123915090860232817
|
197
204
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
198
205
|
none: false
|
199
206
|
requirements:
|
@@ -202,7 +209,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
202
209
|
version: '0'
|
203
210
|
segments:
|
204
211
|
- 0
|
205
|
-
hash:
|
212
|
+
hash: -3123915090860232817
|
206
213
|
requirements: []
|
207
214
|
rubyforge_project:
|
208
215
|
rubygems_version: 1.8.23
|
@@ -213,6 +220,9 @@ test_files:
|
|
213
220
|
- test/generator_test.rb
|
214
221
|
- test/party_foul/configure_test.rb
|
215
222
|
- test/party_foul/exception_handler_test.rb
|
223
|
+
- test/party_foul/issue_renderer_test.rb
|
224
|
+
- test/party_foul/issue_renderers/rack_test.rb
|
225
|
+
- test/party_foul/issue_renderers/rails_test.rb
|
216
226
|
- test/party_foul/middleware_test.rb
|
217
227
|
- test/test_helper.rb
|
218
228
|
- test/tmp/config/initializers/party_foul.rb
|