redmine_airbrake_backend 1.0.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/app/controllers/airbrake_controller.rb +39 -34
- data/app/controllers/airbrake_notice_controller.rb +11 -13
- data/app/controllers/airbrake_report_controller.rb +5 -11
- data/app/helpers/airbrake_helper.rb +21 -10
- data/app/views/airbrake/issue_description/default.erb +15 -14
- data/lib/redmine_airbrake_backend/backtrace_element.rb +1 -1
- data/lib/redmine_airbrake_backend/error.rb +5 -27
- data/lib/redmine_airbrake_backend/ios_report.rb +25 -17
- data/lib/redmine_airbrake_backend/notice.rb +64 -0
- data/lib/redmine_airbrake_backend/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5926fca2b10cfdf572494c9891adc633b583bbdb
|
4
|
+
data.tar.gz: 0dc91282b47937a48254ff1e3da0fbd4b555c0be
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 58cfc22082b4c0098a5c756d915401fe334a3346c55541038b21fcd500978f5646ab7627234b5eb882f00561df2bbc28569de2b3c2976d1708c31857a59036ad
|
7
|
+
data.tar.gz: 71de8ff6c61f7894afbafb4a763cef7402651beaac638f0756839a140fdc877c0ba7f6cc0466b5f39883b39460472ddd1531d968a37599b2aaaf772bd5c589ff
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'tempfile'
|
2
|
-
require 'redmine_airbrake_backend/
|
2
|
+
require 'redmine_airbrake_backend/notice'
|
3
3
|
|
4
4
|
|
5
5
|
# Controller with airbrake related stuff
|
@@ -11,7 +11,6 @@ class AirbrakeController < ::ApplicationController
|
|
11
11
|
prepend_before_action :load_records
|
12
12
|
prepend_before_action :parse_key
|
13
13
|
prepend_before_action :find_project
|
14
|
-
before_action :set_environment
|
15
14
|
before_action :authorize
|
16
15
|
|
17
16
|
after_action :cleanup_tempfiles
|
@@ -25,14 +24,11 @@ class AirbrakeController < ::ApplicationController
|
|
25
24
|
end
|
26
25
|
|
27
26
|
def parse_key
|
28
|
-
@key = JSON.parse(params[:key]).symbolize_keys
|
27
|
+
@key = JSON.parse(params[:key]).symbolize_keys rescue nil
|
29
28
|
|
30
29
|
# API key
|
31
30
|
invalid_request!('No or invalid API key') if @key.blank? || @key[:key].blank?
|
32
31
|
params[:key] = @key[:key]
|
33
|
-
|
34
|
-
# Type
|
35
|
-
@type = @key[:type] || (params[:context][:language].split('/', 2).first.downcase rescue nil)
|
36
32
|
end
|
37
33
|
|
38
34
|
def load_records
|
@@ -56,10 +52,6 @@ class AirbrakeController < ::ApplicationController
|
|
56
52
|
@repository = @project.repositories.find_by(identifier: (@key[:repository] || ''))
|
57
53
|
end
|
58
54
|
|
59
|
-
def set_environment
|
60
|
-
@environment ||= params[:context][:environment].presence rescue nil
|
61
|
-
end
|
62
|
-
|
63
55
|
def invalid_request!(message)
|
64
56
|
raise InvalidRequest.new(message)
|
65
57
|
end
|
@@ -112,39 +104,52 @@ class AirbrakeController < ::ApplicationController
|
|
112
104
|
custom_field(:occurrences_field)
|
113
105
|
end
|
114
106
|
|
107
|
+
def create_issue!
|
108
|
+
return if @notice.blank?
|
109
|
+
return if @notice.errors.blank?
|
110
|
+
|
111
|
+
@issue = find_or_initialize_issue(@notice)
|
112
|
+
|
113
|
+
set_issue_custom_field_values(@issue, @notice)
|
114
|
+
|
115
|
+
reopen_issue(@issue, @notice) if @issue.persisted? && @issue.status.is_closed? && reopen_issue?(@notice)
|
116
|
+
|
117
|
+
@issue = nil unless @issue.save
|
118
|
+
end
|
119
|
+
|
115
120
|
# Load or initialize issue by project, tracker and airbrake hash
|
116
|
-
def find_or_initialize_issue(
|
117
|
-
issue_ids = CustomValue.where(customized_type: Issue.name, custom_field_id: notice_hash_field.id, value:
|
121
|
+
def find_or_initialize_issue(notice)
|
122
|
+
issue_ids = CustomValue.where(customized_type: Issue.name, custom_field_id: notice_hash_field.id, value: notice.id).pluck(:customized_id)
|
118
123
|
|
119
124
|
issue = Issue.find_by(id: issue_ids, project_id: @project.id, tracker_id: @tracker.id)
|
120
125
|
|
121
126
|
return issue if issue.present?
|
122
127
|
|
123
|
-
initialize_issue(
|
128
|
+
initialize_issue(notice)
|
124
129
|
end
|
125
130
|
|
126
|
-
def initialize_issue(
|
131
|
+
def initialize_issue(notice)
|
127
132
|
issue = Issue.new(
|
128
|
-
subject:
|
133
|
+
subject: notice.subject,
|
129
134
|
project: @project,
|
130
135
|
tracker: @tracker,
|
131
136
|
author: User.current,
|
132
137
|
category: @category,
|
133
138
|
priority: @priority,
|
134
|
-
description: render_description(
|
139
|
+
description: render_description(notice),
|
135
140
|
assigned_to: @assignee
|
136
141
|
)
|
137
142
|
|
138
|
-
add_attachments_to_issue(issue,
|
143
|
+
add_attachments_to_issue(issue, notice)
|
139
144
|
|
140
145
|
issue
|
141
146
|
end
|
142
147
|
|
143
|
-
def set_issue_custom_field_values(issue,
|
148
|
+
def set_issue_custom_field_values(issue, notice)
|
144
149
|
custom_field_values = {}
|
145
150
|
|
146
151
|
# Error ID
|
147
|
-
custom_field_values[notice_hash_field.id] =
|
152
|
+
custom_field_values[notice_hash_field.id] = notice.id if issue.new_record?
|
148
153
|
|
149
154
|
# Update occurrences
|
150
155
|
if occurrences_field.present?
|
@@ -155,12 +160,12 @@ class AirbrakeController < ::ApplicationController
|
|
155
160
|
issue.custom_field_values = custom_field_values
|
156
161
|
end
|
157
162
|
|
158
|
-
def add_attachments_to_issue(issue,
|
159
|
-
return if
|
163
|
+
def add_attachments_to_issue(issue, notice)
|
164
|
+
return if notice.attachments.blank?
|
160
165
|
|
161
166
|
@tempfiles ||= []
|
162
167
|
|
163
|
-
|
168
|
+
notice.attachments.each do |data|
|
164
169
|
filename = data[:filename].presence || Redmine::Utils.random_hex(16)
|
165
170
|
|
166
171
|
file = Tempfile.new(filename)
|
@@ -173,37 +178,37 @@ class AirbrakeController < ::ApplicationController
|
|
173
178
|
end
|
174
179
|
end
|
175
180
|
|
176
|
-
def reopen_issue?
|
181
|
+
def reopen_issue?(notice)
|
177
182
|
reopen_regexp = project_setting(:reopen_regexp)
|
178
183
|
|
179
184
|
return false if reopen_regexp.blank?
|
180
|
-
return false if
|
185
|
+
return false if notice.environment_name.blank?
|
181
186
|
|
182
|
-
!!(
|
187
|
+
!!(notice.environment_name =~ /#{reopen_regexp}/i)
|
183
188
|
end
|
184
189
|
|
185
190
|
def issue_reopen_repeat_description?
|
186
191
|
!!project_setting(:reopen_repeat_description)
|
187
192
|
end
|
188
193
|
|
189
|
-
def reopen_issue(issue,
|
190
|
-
return if
|
194
|
+
def reopen_issue(issue, notice)
|
195
|
+
return if notice.environment_name.blank?
|
191
196
|
|
192
|
-
desc = "*Issue reopened after occurring again in _#{
|
193
|
-
desc << "\n\n#{render_description(
|
197
|
+
desc = "*Issue reopened after occurring again in _#{notice.environment_name}_ environment.*"
|
198
|
+
desc << "\n\n#{render_description(notice)}" if issue_reopen_repeat_description?
|
194
199
|
|
195
200
|
issue.status = issue.tracker.default_status
|
196
201
|
|
197
202
|
issue.init_journal(User.current, desc)
|
198
203
|
|
199
|
-
add_attachments_to_issue(issue,
|
204
|
+
add_attachments_to_issue(issue, notice)
|
200
205
|
end
|
201
206
|
|
202
|
-
def render_description(
|
203
|
-
locals = {
|
207
|
+
def render_description(notice)
|
208
|
+
locals = { notice: notice }
|
204
209
|
|
205
|
-
if template_exists?("airbrake/issue_description/#{
|
206
|
-
render_to_string("airbrake/issue_description/#{
|
210
|
+
if template_exists?("airbrake/issue_description/#{notice.type}")
|
211
|
+
render_to_string("airbrake/issue_description/#{notice.type}", layout: false, locals: locals)
|
207
212
|
else
|
208
213
|
render_to_string('airbrake/issue_description/default', layout: false, locals: locals)
|
209
214
|
end
|
@@ -2,26 +2,24 @@
|
|
2
2
|
class AirbrakeNoticeController < ::AirbrakeController
|
3
3
|
accept_api_auth :notices
|
4
4
|
|
5
|
+
before_action :parse_notice
|
6
|
+
|
5
7
|
# Handle airbrake notices
|
6
8
|
def notices
|
7
|
-
|
9
|
+
create_issue!
|
8
10
|
|
9
11
|
render_airbrake_response
|
10
12
|
end
|
11
13
|
|
12
14
|
private
|
13
15
|
|
14
|
-
def
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
reopen_issue(issue, error) if issue.persisted? && issue.status.is_closed? && reopen_issue?
|
23
|
-
|
24
|
-
@issue ||= issue if issue.save
|
25
|
-
end
|
16
|
+
def parse_notice
|
17
|
+
@notice = RedmineAirbrakeBackend::Notice.new(
|
18
|
+
errors: params[:errors].map { |e| RedmineAirbrakeBackend::Error.new(e) },
|
19
|
+
params: params[:params],
|
20
|
+
session: params[:session],
|
21
|
+
context: params[:context],
|
22
|
+
environment: params[:environment]
|
23
|
+
)
|
26
24
|
end
|
27
25
|
end
|
@@ -5,24 +5,18 @@ require 'redmine_airbrake_backend/ios_report'
|
|
5
5
|
class AirbrakeReportController < ::AirbrakeController
|
6
6
|
accept_api_auth :ios_reports
|
7
7
|
|
8
|
+
before_action :parse_report
|
9
|
+
|
8
10
|
# Handle airbrake iOS reports
|
9
11
|
def ios_reports
|
10
|
-
create_issue
|
12
|
+
create_issue!
|
11
13
|
|
12
14
|
render_airbrake_response
|
13
15
|
end
|
14
16
|
|
15
17
|
private
|
16
18
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
@issue = find_or_initialize_issue(error)
|
21
|
-
|
22
|
-
set_issue_custom_field_values(@issue, error)
|
23
|
-
|
24
|
-
reopen_issue(@issue, error) if @issue.persisted? && @issue.status.is_closed? && reopen_issue?
|
25
|
-
|
26
|
-
@issue = nil unless @issue.save
|
19
|
+
def parse_report
|
20
|
+
@notice = RedmineAirbrakeBackend::IosReport.new(params)
|
27
21
|
end
|
28
22
|
end
|
@@ -1,7 +1,17 @@
|
|
1
1
|
module AirbrakeHelper
|
2
|
+
# Error title
|
3
|
+
def airbrake_error_title(error)
|
4
|
+
if error.type.blank?
|
5
|
+
error.message
|
6
|
+
else
|
7
|
+
"#{error.type}: #{error.message}"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
2
11
|
# Wiki markup for a table
|
3
|
-
def
|
12
|
+
def airbrake_format_table(data)
|
4
13
|
lines = []
|
14
|
+
|
5
15
|
data.each do |key, value|
|
6
16
|
next if value.blank?
|
7
17
|
|
@@ -11,19 +21,20 @@ module AirbrakeHelper
|
|
11
21
|
lines << "|@#{key}@|@#{value.map { |k, v| "#{k}: #{v}"}.join(', ')}@|"
|
12
22
|
end
|
13
23
|
end
|
24
|
+
|
14
25
|
lines.join("\n")
|
15
26
|
end
|
16
27
|
|
17
28
|
# Wiki markup for a list item
|
18
|
-
def
|
29
|
+
def airbrake_format_list_item(name, value)
|
19
30
|
return '' if value.blank?
|
20
31
|
|
21
32
|
"* *#{name}:* #{value}"
|
22
33
|
end
|
23
34
|
|
24
35
|
# Wiki markup for backtrace element with link to repository if possible
|
25
|
-
def
|
26
|
-
repository =
|
36
|
+
def airbrake_format_backtrace_element(element)
|
37
|
+
repository = airbrake_repository_for_backtrace_element(element)
|
27
38
|
|
28
39
|
if repository.blank?
|
29
40
|
if element.line.blank?
|
@@ -32,7 +43,7 @@ module AirbrakeHelper
|
|
32
43
|
markup = "@#{element.file}:#{element.line}@"
|
33
44
|
end
|
34
45
|
else
|
35
|
-
filename =
|
46
|
+
filename = airbrake_filename_for_backtrace_element(element)
|
36
47
|
|
37
48
|
if repository.identifier.blank?
|
38
49
|
markup = "source:\"#{filename}#L#{element.line}\""
|
@@ -46,15 +57,15 @@ module AirbrakeHelper
|
|
46
57
|
|
47
58
|
private
|
48
59
|
|
49
|
-
def
|
60
|
+
def airbrake_repository_for_backtrace_element(element)
|
50
61
|
return nil unless element.file.start_with?('[PROJECT_ROOT]')
|
51
62
|
|
52
|
-
filename =
|
63
|
+
filename = airbrake_filename_for_backtrace_element(element)
|
53
64
|
|
54
|
-
|
65
|
+
airbrake_repositories_for_backtrace.find { |r| r.entry(filename) }
|
55
66
|
end
|
56
67
|
|
57
|
-
def
|
68
|
+
def airbrake_repositories_for_backtrace
|
58
69
|
return @_bactrace_repositories unless @_bactrace_repositories.nil?
|
59
70
|
|
60
71
|
if @repository.present?
|
@@ -66,7 +77,7 @@ module AirbrakeHelper
|
|
66
77
|
@_bactrace_repositories
|
67
78
|
end
|
68
79
|
|
69
|
-
def
|
80
|
+
def airbrake_filename_for_backtrace_element(element)
|
70
81
|
return nil if element.file.blank?
|
71
82
|
|
72
83
|
element.file[14..-1]
|
@@ -1,44 +1,45 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
<% notice.errors.each do |error| %>
|
2
|
+
h1. <%= airbrake_error_title(error) %>
|
3
3
|
|
4
4
|
<% if error.backtrace.present? %>
|
5
5
|
h2. Stacktrace:
|
6
6
|
|
7
|
-
p((. <%= raw error.backtrace.map { |e|
|
7
|
+
p((. <%= raw error.backtrace.map { |e| airbrake_format_backtrace_element(e) }.join("\n") %>
|
8
8
|
<% end %>
|
9
9
|
|
10
|
+
<% end %>
|
10
11
|
|
11
|
-
<% if
|
12
|
+
<% if notice.application.present? %>
|
12
13
|
h2. Application:
|
13
14
|
|
14
|
-
<%=
|
15
|
-
<%=
|
15
|
+
<%= airbrake_format_list_item('Name', notice.application[:name]) %>
|
16
|
+
<%= airbrake_format_list_item('Version', notice.application[:version]) %>
|
16
17
|
<% end %>
|
17
18
|
|
18
19
|
|
19
|
-
<% if params
|
20
|
+
<% if notice.params.present? %>
|
20
21
|
h2. Parameters:
|
21
22
|
|
22
|
-
<%=
|
23
|
+
<%= airbrake_format_table(notice.params) %>
|
23
24
|
<% end %>
|
24
25
|
|
25
26
|
|
26
|
-
<% if
|
27
|
+
<% if notice.session.present? %>
|
27
28
|
h2. Session
|
28
29
|
|
29
|
-
<%=
|
30
|
+
<%= airbrake_format_table(notice.session) %>
|
30
31
|
<% end %>
|
31
32
|
|
32
33
|
|
33
|
-
<% if
|
34
|
+
<% if notice.context.present? %>
|
34
35
|
h2. Context
|
35
36
|
|
36
|
-
<%=
|
37
|
+
<%= airbrake_format_table(notice.context) %>
|
37
38
|
<% end %>
|
38
39
|
|
39
40
|
|
40
|
-
<% if
|
41
|
+
<% if notice.environment.present? %>
|
41
42
|
h2. Environment
|
42
43
|
|
43
|
-
<%=
|
44
|
+
<%= airbrake_format_table(notice.environment) %>
|
44
45
|
<% end %>
|
@@ -5,30 +5,20 @@ require 'redmine_airbrake_backend/backtrace_element'
|
|
5
5
|
module RedmineAirbrakeBackend
|
6
6
|
# Error received by airbrake
|
7
7
|
class Error
|
8
|
-
attr_reader :type, :message, :backtrace
|
9
|
-
attr_reader :id, :subject, :application, :attachments
|
8
|
+
attr_reader :id, :type, :message, :backtrace
|
10
9
|
|
11
|
-
def initialize(
|
10
|
+
def initialize(options)
|
12
11
|
# Type
|
13
|
-
@type =
|
12
|
+
@type = options[:type]
|
14
13
|
|
15
14
|
# Message
|
16
|
-
@message =
|
15
|
+
@message = options[:message]
|
17
16
|
|
18
17
|
# Backtrace
|
19
|
-
@backtrace =
|
18
|
+
@backtrace = options[:backtrace].map { |b| BacktraceElement.new(b) }
|
20
19
|
|
21
20
|
# Error ID
|
22
21
|
@id = generate_id
|
23
|
-
|
24
|
-
# Subject
|
25
|
-
@subject = generate_subject
|
26
|
-
|
27
|
-
# Attachments
|
28
|
-
@attachments = (data[:attachments].presence || []).compact
|
29
|
-
|
30
|
-
# Application
|
31
|
-
@application = data[:application].presence
|
32
22
|
end
|
33
23
|
|
34
24
|
private
|
@@ -41,17 +31,5 @@ module RedmineAirbrakeBackend
|
|
41
31
|
|
42
32
|
Digest::MD5.hexdigest(h.compact.join("\n"))
|
43
33
|
end
|
44
|
-
|
45
|
-
def generate_subject
|
46
|
-
s = ''
|
47
|
-
|
48
|
-
if @type.blank? || @message.starts_with?("#{@type}:")
|
49
|
-
s = "[#{@id[0..7]}] #{@message}"
|
50
|
-
else
|
51
|
-
s = "[#{@id[0..7]}] #{@type}: #{@message}"
|
52
|
-
end
|
53
|
-
|
54
|
-
s[0..254].strip
|
55
|
-
end
|
56
34
|
end
|
57
35
|
end
|
@@ -1,21 +1,26 @@
|
|
1
|
-
require 'redmine_airbrake_backend/
|
1
|
+
require 'redmine_airbrake_backend/notice'
|
2
2
|
|
3
3
|
|
4
4
|
module RedmineAirbrakeBackend
|
5
5
|
# iOS Report received by airbrake
|
6
|
-
class IosReport <
|
7
|
-
def initialize(
|
8
|
-
|
6
|
+
class IosReport < Notice
|
7
|
+
def initialize(options)
|
8
|
+
error, application, attachments = self.class.parse(options[:report])
|
9
|
+
|
10
|
+
super({
|
11
|
+
errors: [Error.new(error)],
|
12
|
+
context: options[:context],
|
13
|
+
application: application,
|
14
|
+
attachments: attachments
|
15
|
+
})
|
9
16
|
end
|
10
17
|
|
11
18
|
private
|
12
19
|
|
13
20
|
def self.parse(data)
|
14
|
-
error
|
15
|
-
|
16
|
-
|
17
|
-
attachments: [],
|
18
|
-
}
|
21
|
+
error = { backtrace: [] }
|
22
|
+
application = {}
|
23
|
+
attachments = []
|
19
24
|
|
20
25
|
header_finished = false
|
21
26
|
next_line_is_message = false
|
@@ -25,8 +30,8 @@ module RedmineAirbrakeBackend
|
|
25
30
|
data.split("\n").each do |line|
|
26
31
|
header_finished = true if line =~ /^(Application Specific Information|Last Exception Backtrace|Thread \d+( Crashed)?):$/
|
27
32
|
|
28
|
-
unless
|
29
|
-
ii = parse_header_line(line, error)
|
33
|
+
unless header_finished
|
34
|
+
ii = parse_header_line(line, error, application)
|
30
35
|
indicent_identifier ||= ii if ii
|
31
36
|
end
|
32
37
|
|
@@ -38,7 +43,10 @@ module RedmineAirbrakeBackend
|
|
38
43
|
|
39
44
|
crashed_thread = false if line =~ /^Thread \d+:$/
|
40
45
|
|
41
|
-
|
46
|
+
if crashed_thread
|
47
|
+
backtrace = parse_backtrace_element(line)
|
48
|
+
error[:backtrace] << backtrace if backtrace
|
49
|
+
end
|
42
50
|
|
43
51
|
crashed_thread = true if error[:backtrace].compact.blank? && line =~ /^(Last Exception Backtrace|Thread \d+ Crashed):$/
|
44
52
|
|
@@ -47,15 +55,15 @@ module RedmineAirbrakeBackend
|
|
47
55
|
|
48
56
|
return nil if error.blank?
|
49
57
|
|
50
|
-
|
58
|
+
attachments << {
|
51
59
|
filename: "#{indicent_identifier}.crash",
|
52
60
|
data: data
|
53
61
|
} if indicent_identifier.present?
|
54
62
|
|
55
|
-
error
|
63
|
+
[error, application, attachments]
|
56
64
|
end
|
57
65
|
|
58
|
-
def self.parse_header_line(line, error)
|
66
|
+
def self.parse_header_line(line, error, application)
|
59
67
|
key, value = line.split(':', 2).map { |s| s.strip }
|
60
68
|
|
61
69
|
return nil if key.blank? || value.blank?
|
@@ -68,9 +76,9 @@ module RedmineAirbrakeBackend
|
|
68
76
|
when 'Incident Identifier'
|
69
77
|
return value
|
70
78
|
when 'Identifier'
|
71
|
-
|
79
|
+
application[:name] = value
|
72
80
|
when 'Version'
|
73
|
-
|
81
|
+
application[:version] = value
|
74
82
|
end
|
75
83
|
|
76
84
|
nil
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'redmine_airbrake_backend/error'
|
2
|
+
|
3
|
+
|
4
|
+
module RedmineAirbrakeBackend
|
5
|
+
# Notice received by airbrake
|
6
|
+
class Notice
|
7
|
+
attr_reader :id, :subject, :type, :environment_name
|
8
|
+
attr_reader :errors, :params, :session, :context, :environment, :application, :attachments
|
9
|
+
|
10
|
+
def initialize(options)
|
11
|
+
# Errors
|
12
|
+
@errors = options[:errors].compact
|
13
|
+
|
14
|
+
# Params
|
15
|
+
@params = options[:params]
|
16
|
+
|
17
|
+
# Session
|
18
|
+
@session = options[:session]
|
19
|
+
|
20
|
+
# Context
|
21
|
+
@context = options[:context].reject { |k, v| ['notifier'].include?(k) }
|
22
|
+
|
23
|
+
# Environment
|
24
|
+
@environment = options[:environment]
|
25
|
+
|
26
|
+
# Application
|
27
|
+
@application = options[:application]
|
28
|
+
|
29
|
+
# Attachments
|
30
|
+
@attachments = (options[:attachments].presence || []).compact
|
31
|
+
|
32
|
+
# Environment name
|
33
|
+
@environment_name = options[:context][:environment].presence rescue nil
|
34
|
+
|
35
|
+
# Type
|
36
|
+
@type = options[:type] || (options[:context][:language].split('/', 2).first.downcase rescue nil)
|
37
|
+
|
38
|
+
# Error ID
|
39
|
+
@id = generate_id
|
40
|
+
|
41
|
+
# Subject
|
42
|
+
@subject = generate_subject
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def generate_id
|
48
|
+
Digest::MD5.hexdigest(@errors.map(&:id).join("\n"))
|
49
|
+
end
|
50
|
+
|
51
|
+
def generate_subject
|
52
|
+
error = @errors.first
|
53
|
+
s = ''
|
54
|
+
|
55
|
+
if error.type.blank? || error.message.starts_with?("#{error.type}:")
|
56
|
+
s = "[#{@id[0..7]}] #{error.message}"
|
57
|
+
else
|
58
|
+
s = "[#{@id[0..7]}] #{error.type}: #{error.message}"
|
59
|
+
end
|
60
|
+
|
61
|
+
s[0..254].strip
|
62
|
+
end
|
63
|
+
end
|
64
|
+
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.1.0
|
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-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -85,6 +85,7 @@ files:
|
|
85
85
|
- lib/redmine_airbrake_backend/engine.rb
|
86
86
|
- lib/redmine_airbrake_backend/error.rb
|
87
87
|
- lib/redmine_airbrake_backend/ios_report.rb
|
88
|
+
- lib/redmine_airbrake_backend/notice.rb
|
88
89
|
- lib/redmine_airbrake_backend/patches/issue_category.rb
|
89
90
|
- lib/redmine_airbrake_backend/patches/issue_priority.rb
|
90
91
|
- lib/redmine_airbrake_backend/patches/project.rb
|