redmine_airbrake_backend 1.0.0 → 1.0.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -1
- data/README.md +1 -0
- data/app/controllers/airbrake_controller.rb +25 -7
- data/app/controllers/airbrake_notice_controller.rb +7 -10
- data/app/controllers/airbrake_report_controller.rb +9 -10
- data/app/helpers/airbrake_helper.rb +1 -1
- data/app/views/airbrake/issue_description/default.erb +1 -1
- data/lib/redmine_airbrake_backend/error.rb +1 -1
- data/lib/redmine_airbrake_backend/ios_report.rb +48 -36
- data/lib/redmine_airbrake_backend/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7fced1efea4d537b27f9a4a741aaf307a22718bf
|
4
|
+
data.tar.gz: dcbedce9d1f9abdcd109ae1cec7c15b4f33702c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5431defd44ddd91e10b3b052a93ca98afea49629a45612f2e7d15242baa3e76d4d4b69268084d71dddfad80559d48a461fdaacff36734f940c2ab7caec32a3c9
|
7
|
+
data.tar.gz: c4195a878a5fd1fba3e90eddfa1ffb44e314122d587c854bcd594ecccc986a93b6089a4e43521e39773a6232347c81d1f0990bcbbe769f3958c5036edc473c95
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
##
|
3
|
+
## 1.0.1 (2016-01-25)
|
4
|
+
### Fixes
|
5
|
+
- Add space to comma separated key-value list in description tables
|
6
|
+
- Exclude notifier information from context table
|
7
|
+
|
8
|
+
## 1.0.0 (2016-01-23)
|
4
9
|
### Changes
|
5
10
|
- Add support for new v3 JSON notices
|
6
11
|
- Add support for new v3 JSON iOS reports
|
data/README.md
CHANGED
@@ -33,6 +33,7 @@ Please see http://www.redmine.org/projects/redmine/wiki/Plugins for installation
|
|
33
33
|
4. Check if the custom fields are assigned to the trackers you want to use with airbrake
|
34
34
|
5. Enable the project module (Airbrake) in your project settings (don't forget to add at least the Airbrake notice ID custom field to your project if it is not a global field)
|
35
35
|
6. Configure additional defaults under the settings tab per project (Airbrake)
|
36
|
+
6. Check if the user used for airbrake has a role with the _Airbrake_ permission
|
36
37
|
|
37
38
|
## Client configuration
|
38
39
|
|
@@ -8,6 +8,7 @@ class AirbrakeController < ::ApplicationController
|
|
8
8
|
|
9
9
|
skip_before_action :verify_authenticity_token
|
10
10
|
|
11
|
+
prepend_before_action :load_records
|
11
12
|
prepend_before_action :parse_key
|
12
13
|
prepend_before_action :find_project
|
13
14
|
before_action :set_environment
|
@@ -27,15 +28,20 @@ class AirbrakeController < ::ApplicationController
|
|
27
28
|
@key = JSON.parse(params[:key]).symbolize_keys #rescue nil
|
28
29
|
|
29
30
|
# API key
|
30
|
-
|
31
|
+
invalid_request!('No or invalid API key') if @key.blank? || @key[:key].blank?
|
31
32
|
params[:key] = @key[:key]
|
32
33
|
|
34
|
+
# Type
|
35
|
+
@type = @key[:type] || (params[:context][:language].split('/', 2).first.downcase rescue nil)
|
36
|
+
end
|
37
|
+
|
38
|
+
def load_records
|
33
39
|
# Tracker
|
34
40
|
@tracker = record_for(@project.trackers, :tracker)
|
35
|
-
|
41
|
+
invalid_request!('No or invalid tracker') if @tracker.blank?
|
36
42
|
|
37
43
|
# Notice ID field
|
38
|
-
|
44
|
+
invalid_request!('Custom field for notice hash not available on selected tracker') if @tracker.custom_fields.find_by(id: notice_hash_field.id).blank?
|
39
45
|
|
40
46
|
# Category
|
41
47
|
@category = record_for(@project.issue_categories, :category)
|
@@ -48,13 +54,14 @@ class AirbrakeController < ::ApplicationController
|
|
48
54
|
|
49
55
|
# Repository
|
50
56
|
@repository = @project.repositories.find_by(identifier: (@key[:repository] || ''))
|
51
|
-
|
52
|
-
# Type
|
53
|
-
@type = @key[:type] || (params[:context][:language].split('/', 2).first.downcase rescue nil)
|
54
57
|
end
|
55
58
|
|
56
59
|
def set_environment
|
57
|
-
@environment
|
60
|
+
@environment ||= params[:context][:environment].presence rescue nil
|
61
|
+
end
|
62
|
+
|
63
|
+
def invalid_request!(message)
|
64
|
+
raise InvalidRequest.new(message)
|
58
65
|
end
|
59
66
|
|
60
67
|
def render_bad_request(error)
|
@@ -63,6 +70,17 @@ class AirbrakeController < ::ApplicationController
|
|
63
70
|
render text: error.message, status: :bad_request
|
64
71
|
end
|
65
72
|
|
73
|
+
def render_airbrake_response
|
74
|
+
if @issue.present?
|
75
|
+
render json: {
|
76
|
+
id: (CustomValue.find_by(customized_type: Issue.name, customized_id: @issue.id, custom_field_id: notice_hash_field.id).value rescue nil),
|
77
|
+
url: issue_url(@issue)
|
78
|
+
}
|
79
|
+
else
|
80
|
+
render json: {}
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
66
84
|
def record_for(on, key, fields = [:id, :name])
|
67
85
|
fields.each do |field|
|
68
86
|
val = on.find_by(field => @key[key])
|
@@ -4,8 +4,14 @@ class AirbrakeNoticeController < ::AirbrakeController
|
|
4
4
|
|
5
5
|
# Handle airbrake notices
|
6
6
|
def notices
|
7
|
-
|
7
|
+
create_issues
|
8
8
|
|
9
|
+
render_airbrake_response
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def create_issues
|
9
15
|
params[:errors].each do |e|
|
10
16
|
error = RedmineAirbrakeBackend::Error.new(e)
|
11
17
|
|
@@ -17,14 +23,5 @@ class AirbrakeNoticeController < ::AirbrakeController
|
|
17
23
|
|
18
24
|
@issue ||= issue if issue.save
|
19
25
|
end
|
20
|
-
|
21
|
-
if @issue.present?
|
22
|
-
render json: {
|
23
|
-
id: (CustomValue.find_by(customized_type: Issue.name, customized_id: @issue.id, custom_field_id: notice_hash_field.id).value rescue nil),
|
24
|
-
url: issue_url(@issue)
|
25
|
-
}
|
26
|
-
else
|
27
|
-
render json: {}
|
28
|
-
end
|
29
26
|
end
|
30
27
|
end
|
@@ -7,6 +7,14 @@ class AirbrakeReportController < ::AirbrakeController
|
|
7
7
|
|
8
8
|
# Handle airbrake iOS reports
|
9
9
|
def ios_reports
|
10
|
+
create_issue
|
11
|
+
|
12
|
+
render_airbrake_response
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def create_issue
|
10
18
|
error = RedmineAirbrakeBackend::IosReport.new(params[:report])
|
11
19
|
|
12
20
|
@issue = find_or_initialize_issue(error)
|
@@ -15,15 +23,6 @@ class AirbrakeReportController < ::AirbrakeController
|
|
15
23
|
|
16
24
|
reopen_issue(@issue, error) if @issue.persisted? && @issue.status.is_closed? && reopen_issue?
|
17
25
|
|
18
|
-
unless @issue.save
|
19
|
-
render json: {}
|
20
|
-
|
21
|
-
return
|
22
|
-
end
|
23
|
-
|
24
|
-
render json: {
|
25
|
-
id: (CustomValue.find_by(customized_type: Issue.name, customized_id: @issue.id, custom_field_id: notice_hash_field.id).value rescue nil),
|
26
|
-
url: issue_url(@issue)
|
27
|
-
}
|
26
|
+
@issue = nil unless @issue.save
|
28
27
|
end
|
29
28
|
end
|
@@ -8,7 +8,7 @@ module AirbrakeHelper
|
|
8
8
|
if value.is_a?(String)
|
9
9
|
lines << "|@#{key}@|@#{value}@|"
|
10
10
|
elsif value.is_a?(Hash)
|
11
|
-
lines << "|@#{key}@|@#{value.map { |k, v| "#{k}: #{v}"}.join(',')}@|"
|
11
|
+
lines << "|@#{key}@|@#{value.map { |k, v| "#{k}: #{v}"}.join(', ')}@|"
|
12
12
|
end
|
13
13
|
end
|
14
14
|
lines.join("\n")
|
@@ -25,7 +25,7 @@ module RedmineAirbrakeBackend
|
|
25
25
|
@subject = generate_subject
|
26
26
|
|
27
27
|
# Attachments
|
28
|
-
@attachments = data[:attachments].presence || []
|
28
|
+
@attachments = (data[:attachments].presence || []).compact
|
29
29
|
|
30
30
|
# Application
|
31
31
|
@application = data[:application].presence
|
@@ -25,51 +25,19 @@ module RedmineAirbrakeBackend
|
|
25
25
|
data.split("\n").each do |line|
|
26
26
|
header_finished = true if line =~ /^(Application Specific Information|Last Exception Backtrace|Thread \d+( Crashed)?):$/
|
27
27
|
|
28
|
-
unless header_finished
|
29
|
-
key, value = line.split(':', 2).map { |s| s.strip }
|
30
|
-
|
31
|
-
next if key.blank? || value.blank?
|
32
|
-
|
33
|
-
case key
|
34
|
-
when 'Exception Type'
|
35
|
-
error[:type] = value
|
36
|
-
when 'Exception Codes'
|
37
|
-
error[:message] = value
|
38
|
-
when 'Incident Identifier'
|
39
|
-
indicent_identifier = value
|
40
|
-
when 'Identifier'
|
41
|
-
error[:application][:name] = value
|
42
|
-
when 'Version'
|
43
|
-
error[:application][:version] = value
|
44
|
-
end
|
45
|
-
end
|
28
|
+
indicent_identifier = parse_header_line(line, error) unless header_finished
|
46
29
|
|
47
30
|
if next_line_is_message
|
48
31
|
next_line_is_message = false
|
49
32
|
|
50
|
-
error
|
51
|
-
|
52
|
-
if line =~ /^\*\*\* Terminating app due to uncaught exception '([^']+)', reason: '\*\*\* (.*)'$/
|
53
|
-
error[:type] = Regexp.last_match(1)
|
54
|
-
error[:message] = Regexp.last_match(2)
|
55
|
-
else
|
56
|
-
error[:message] = line
|
57
|
-
end
|
33
|
+
parse_message(line, error)
|
58
34
|
end
|
59
35
|
|
60
36
|
crashed_thread = false if line =~ /^Thread \d+:$/
|
61
37
|
|
62
|
-
if crashed_thread
|
63
|
-
if line =~ /^(\d+)\s+([^\s]+)\s+(0x[0-9a-f]+)\s+(.+) \+ (\d+)$/
|
64
|
-
error[:backtrace] << {
|
65
|
-
file: Regexp.last_match(2),
|
66
|
-
function: Regexp.last_match(4),
|
67
|
-
line: Regexp.last_match(5)
|
68
|
-
}
|
69
|
-
end
|
70
|
-
end
|
38
|
+
error[:backtrace] << parse_backtrace_element(line) if crashed_thread
|
71
39
|
|
72
|
-
crashed_thread = true if error[:backtrace].blank? && line =~ /^(Last Exception Backtrace|Thread \d+ Crashed):$/
|
40
|
+
crashed_thread = true if error[:backtrace].compact.blank? && line =~ /^(Last Exception Backtrace|Thread \d+ Crashed):$/
|
73
41
|
|
74
42
|
next_line_is_message = true if line =~ /^Application Specific Information:$/
|
75
43
|
end
|
@@ -83,5 +51,49 @@ module RedmineAirbrakeBackend
|
|
83
51
|
|
84
52
|
error
|
85
53
|
end
|
54
|
+
|
55
|
+
def self.parse_header_line(line, error)
|
56
|
+
key, value = line.split(':', 2).map { |s| s.strip }
|
57
|
+
|
58
|
+
next if key.blank? || value.blank?
|
59
|
+
|
60
|
+
case key
|
61
|
+
when 'Exception Type'
|
62
|
+
error[:type] = value
|
63
|
+
when 'Exception Codes'
|
64
|
+
error[:message] = value
|
65
|
+
when 'Incident Identifier'
|
66
|
+
return value
|
67
|
+
when 'Identifier'
|
68
|
+
error[:application][:name] = value
|
69
|
+
when 'Version'
|
70
|
+
error[:application][:version] = value
|
71
|
+
end
|
72
|
+
|
73
|
+
nil
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.parse_message(line, error)
|
77
|
+
error[:message] = line
|
78
|
+
|
79
|
+
if line =~ /^\*\*\* Terminating app due to uncaught exception '([^']+)', reason: '\*\*\* (.*)'$/
|
80
|
+
error[:type] = Regexp.last_match(1)
|
81
|
+
error[:message] = Regexp.last_match(2)
|
82
|
+
else
|
83
|
+
error[:message] = line
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.parse_backtrace_element(line)
|
88
|
+
if line =~ /^(\d+)\s+([^\s]+)\s+(0x[0-9a-f]+)\s+(.+) \+ (\d+)$/
|
89
|
+
{
|
90
|
+
file: Regexp.last_match(2),
|
91
|
+
function: Regexp.last_match(4),
|
92
|
+
line: Regexp.last_match(5)
|
93
|
+
}
|
94
|
+
else
|
95
|
+
nil
|
96
|
+
end
|
97
|
+
end
|
86
98
|
end
|
87
99
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redmine_airbrake_backend
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Florian Schwab
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-01-
|
11
|
+
date: 2016-01-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|