bender-bot 0.5.6 → 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.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/bender/bot.rb +54 -52
- data/lib/bender/helpers.rb +25 -35
- data/lib/bender/main.rb +90 -166
- data/lib/bender/metadata.rb +0 -1
- data/lib/bender/mjolnir.rb +0 -7
- metadata +2 -36
- data/lib/bender/web.rb +0 -36
- data/web/app/bender.js +0 -5
- data/web/app/style/bender.css +0 -0
- data/web/public/favicon.ico +0 -0
- data/web/views/app.erb +0 -1
- data/web/views/layout.erb +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0c7feb7ff451b53acb7ea0171573c05e0658a217
|
4
|
+
data.tar.gz: f337922a2e8310c05de4ad7ab7e44bb743a22a6a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 15069ef3e4408d5166023b7031bbbf7e810350687c77738fff83c3cbe8430717a1eb6f7f0095a0c8e47e29e7ae8b92a62059845e89b2d66dbe5416585c07e853
|
7
|
+
data.tar.gz: 6782aa69d9109eb06b92299f9246a552e80eef81f8cb5f80660ccb12c48fd6fac80d19d27116e362598d04e3af8509db59c48dcf877a7b17176a0a45d37dc3e6
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.6.0
|
data/lib/bender/bot.rb
CHANGED
@@ -15,11 +15,11 @@ Bot = Robut # alias
|
|
15
15
|
|
16
16
|
|
17
17
|
module Bot
|
18
|
-
def self.run!
|
19
|
-
hipchat = HipChat::Client.new(
|
18
|
+
def self.run! config, logger
|
19
|
+
hipchat = HipChat::Client.new(config[:hipchat_token])
|
20
20
|
BenderBot.class_variable_set :@@hipchat, hipchat
|
21
21
|
BenderBot.class_variable_set :@@rooms, hipchat.rooms
|
22
|
-
BenderBot.class_variable_set :@@
|
22
|
+
BenderBot.class_variable_set :@@config, config
|
23
23
|
BenderBot.class_variable_set :@@logger, logger
|
24
24
|
Bot::Plugin.plugins = [ BenderBot ]
|
25
25
|
conn = Bot::Connection.new
|
@@ -36,39 +36,41 @@ class BenderBot
|
|
36
36
|
|
37
37
|
JARO = FuzzyStringMatch::JaroWinkler.create :native
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
39
|
+
def self.set_commands
|
40
|
+
BenderBot.const_set :COMMANDS, {
|
41
|
+
help: {
|
42
|
+
desc: 'Display this help text',
|
43
|
+
},
|
44
|
+
list: {
|
45
|
+
cmd: '',
|
46
|
+
desc: 'List open incidents'
|
47
|
+
},
|
48
|
+
show: {
|
49
|
+
cmd: '',
|
50
|
+
fmt: 'INCIDENT_NUMBER',
|
51
|
+
desc: 'Display incident details'
|
52
|
+
},
|
53
|
+
resolve: {
|
54
|
+
fmt: 'INCIDENT_NUMBER',
|
55
|
+
desc: 'Resolve an incident',
|
56
|
+
},
|
57
|
+
close: {
|
58
|
+
fmt: 'INCIDENT_NUMBER',
|
59
|
+
desc: 'Close an incident',
|
60
|
+
},
|
61
|
+
open: {
|
62
|
+
fmt: "SEVERITY=#{SEVERITIES.keys.sort_by(&:to_i).join(',')} SUMMARY_TEXT",
|
63
|
+
desc: 'Open a new incident',
|
64
|
+
},
|
65
|
+
summary: {
|
66
|
+
desc: 'Summarize incidents from past 24 hours (open or closed)'
|
67
|
+
},
|
68
|
+
comment: {
|
69
|
+
fmt: 'INCIDENT_NUMBER COMMENT_TEXT',
|
70
|
+
desc: 'Add a comment to an incident'
|
71
|
+
}
|
70
72
|
}
|
71
|
-
|
73
|
+
end
|
72
74
|
|
73
75
|
|
74
76
|
|
@@ -104,7 +106,7 @@ class BenderBot
|
|
104
106
|
@this_room = @@rooms.select { |r| r.xmpp_jid == jid }.first
|
105
107
|
@@hipchat[@this_room.name].get_room # test
|
106
108
|
rescue
|
107
|
-
@@hipchat = HipChat::Client.new(@@
|
109
|
+
@@hipchat = HipChat::Client.new(@@config[:hipchat_token])
|
108
110
|
@@rooms = @@hipchat.rooms
|
109
111
|
@this_room = @@rooms.select { |r| r.xmpp_jid == jid }.first
|
110
112
|
end
|
@@ -252,7 +254,7 @@ class BenderBot
|
|
252
254
|
else
|
253
255
|
incident = select_incident $1
|
254
256
|
if incident
|
255
|
-
reply_html
|
257
|
+
reply_html(*resolve_incident(incident))
|
256
258
|
else
|
257
259
|
reply_html 'Sorry, no such incident!', :red
|
258
260
|
end
|
@@ -265,7 +267,7 @@ class BenderBot
|
|
265
267
|
else
|
266
268
|
incident = select_incident $1
|
267
269
|
if incident
|
268
|
-
reply_html
|
270
|
+
reply_html(*close_incident(incident))
|
269
271
|
else
|
270
272
|
reply_html 'Sorry, no such incident!', :red
|
271
273
|
end
|
@@ -279,8 +281,8 @@ class BenderBot
|
|
279
281
|
user = user_where name: sender
|
280
282
|
data = {
|
281
283
|
fields: {
|
282
|
-
project: { key:
|
283
|
-
issuetype: { name:
|
284
|
+
project: { key: config[:jira_project] },
|
285
|
+
issuetype: { name: config[:jira_type] },
|
284
286
|
reporter: { name: user[:nick] },
|
285
287
|
summary: $3,
|
286
288
|
SHOW_FIELDS.key('Severity') => {
|
@@ -289,7 +291,7 @@ class BenderBot
|
|
289
291
|
}
|
290
292
|
}
|
291
293
|
|
292
|
-
reply_html
|
294
|
+
reply_html(*file_incident(data))
|
293
295
|
end
|
294
296
|
|
295
297
|
|
@@ -302,7 +304,7 @@ class BenderBot
|
|
302
304
|
if !user
|
303
305
|
reply_html "Couldn't find the associated user in JIRA", :red
|
304
306
|
elsif incident
|
305
|
-
reply_html
|
307
|
+
reply_html(*comment_on_incident(incident, comment, user))
|
306
308
|
else
|
307
309
|
reply_html 'Sorry, no such incident!', :red
|
308
310
|
end
|
@@ -323,7 +325,7 @@ private
|
|
323
325
|
|
324
326
|
def log ; @@logger end
|
325
327
|
|
326
|
-
def
|
328
|
+
def config ; @@config end
|
327
329
|
|
328
330
|
def user_where fields, threshold=0.85
|
329
331
|
field, value = fields.to_a.shift
|
@@ -335,7 +337,7 @@ private
|
|
335
337
|
|
336
338
|
user = distance < threshold ? nil : suggested_user
|
337
339
|
|
338
|
-
log.
|
340
|
+
log.debug \
|
339
341
|
action: 'user_where',
|
340
342
|
fields: fields,
|
341
343
|
threshold: threshold,
|
@@ -359,11 +361,11 @@ private
|
|
359
361
|
|
360
362
|
def file_incident data
|
361
363
|
req_path = '/rest/api/2/issue'
|
362
|
-
uri = URI(
|
364
|
+
uri = URI(config[:jira_site] + req_path)
|
363
365
|
http = Net::HTTP.new uri.hostname, uri.port
|
364
366
|
|
365
367
|
req = Net::HTTP::Post.new uri
|
366
|
-
req.basic_auth
|
368
|
+
req.basic_auth config[:jira_user], config[:jira_pass]
|
367
369
|
req['Content-Type'] = 'application/json'
|
368
370
|
req['Accept'] = 'application/json'
|
369
371
|
req.body = data.to_json
|
@@ -397,11 +399,11 @@ private
|
|
397
399
|
req_path = '/rest/api/2/issue/%s/transitions?expand=transitions.fields' % [
|
398
400
|
incident['key']
|
399
401
|
]
|
400
|
-
uri = URI(
|
402
|
+
uri = URI(config[:jira_site] + req_path)
|
401
403
|
http = Net::HTTP.new uri.hostname, uri.port
|
402
404
|
|
403
405
|
req = Net::HTTP::Post.new uri
|
404
|
-
req.basic_auth
|
406
|
+
req.basic_auth config[:jira_user], config[:jira_pass]
|
405
407
|
req['Content-Type'] = 'application/json'
|
406
408
|
req['Accept'] = 'application/json'
|
407
409
|
|
@@ -439,11 +441,11 @@ private
|
|
439
441
|
req_path = '/rest/api/2/issue/%s/transitions?expand=transitions.fields' % [
|
440
442
|
incident['key']
|
441
443
|
]
|
442
|
-
uri = URI(
|
444
|
+
uri = URI(config[:jira_site] + req_path)
|
443
445
|
http = Net::HTTP.new uri.hostname, uri.port
|
444
446
|
|
445
447
|
req = Net::HTTP::Post.new uri
|
446
|
-
req.basic_auth
|
448
|
+
req.basic_auth config[:jira_user], config[:jira_pass]
|
447
449
|
req['Content-Type'] = 'application/json'
|
448
450
|
req['Accept'] = 'application/json'
|
449
451
|
|
@@ -470,11 +472,11 @@ private
|
|
470
472
|
|
471
473
|
def comment_on_incident incident, comment, user
|
472
474
|
req_path = '/rest/api/2/issue/%s/comment' % incident['key']
|
473
|
-
uri = URI(
|
475
|
+
uri = URI(config[:jira_site] + req_path)
|
474
476
|
http = Net::HTTP.new uri.hostname, uri.port
|
475
477
|
|
476
478
|
req = Net::HTTP::Post.new uri
|
477
|
-
req.basic_auth
|
479
|
+
req.basic_auth config[:jira_user], config[:jira_pass]
|
478
480
|
req['Content-Type'] = 'application/json'
|
479
481
|
req['Accept'] = 'application/json'
|
480
482
|
req.body = { body: '_[~%s]_ says: %s' % [ user[:nick], comment ] }.to_json
|
data/lib/bender/helpers.rb
CHANGED
@@ -1,37 +1,27 @@
|
|
1
1
|
module Helpers
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
'customfield_11251' => 'Impact Started',
|
24
|
-
'customfield_11252' => 'Impact Ended',
|
25
|
-
'customfield_11253' => 'Reported By',
|
26
|
-
'customfield_11254' => 'Services Affected',
|
27
|
-
'customfield_11255' => 'Cause',
|
28
|
-
'status' => 'Status',
|
29
|
-
'created' => 'Created',
|
30
|
-
'updated' => 'Updated'
|
2
|
+
DEFAULT_CONFIG = {
|
3
|
+
hipchat_token: nil,
|
4
|
+
hipchat_v2_token: nil,
|
5
|
+
primary_room_id: nil,
|
6
|
+
jid: nil,
|
7
|
+
password: nil,
|
8
|
+
nick: nil,
|
9
|
+
mention: nil,
|
10
|
+
rooms: nil,
|
11
|
+
database: nil,
|
12
|
+
jira_user: nil,
|
13
|
+
jira_pass: nil,
|
14
|
+
jira_site: nil,
|
15
|
+
jira_project: nil,
|
16
|
+
jira_group: nil,
|
17
|
+
jira_type: nil,
|
18
|
+
user_refresh: 300,
|
19
|
+
issue_refresh: 5,
|
20
|
+
group_refresh: 60,
|
21
|
+
room_base_name: nil,
|
22
|
+
order: false
|
31
23
|
}
|
32
24
|
|
33
|
-
SEVERITY_FIELD = SHOW_FIELDS.key('Severity')
|
34
|
-
|
35
25
|
QUOTES = [
|
36
26
|
'Bite my shiny metal ass!',
|
37
27
|
'This is the worst kind of discrimination there is: the kind against me!',
|
@@ -55,16 +45,16 @@ module Helpers
|
|
55
45
|
def refresh_incidents bot=self
|
56
46
|
req_path = '/rest/api/2/search'
|
57
47
|
req_params = QueryParams.encode \
|
58
|
-
jql: "project = #{
|
48
|
+
jql: "project = #{config[:jira_project]} ORDER BY created ASC, priority DESC",
|
59
49
|
fields: SHOW_FIELDS.keys.join(','),
|
60
50
|
startAt: 0,
|
61
51
|
maxResults: 1_000_000
|
62
52
|
|
63
|
-
uri = URI(
|
53
|
+
uri = URI(config[:jira_site] + req_path + '?' + req_params)
|
64
54
|
http = Net::HTTP.new uri.hostname, uri.port
|
65
55
|
|
66
56
|
req = Net::HTTP::Get.new uri
|
67
|
-
req.basic_auth
|
57
|
+
req.basic_auth config[:jira_user], config[:jira_pass]
|
68
58
|
req['Content-Type'] = 'application/json'
|
69
59
|
req['Accept'] = 'application/json'
|
70
60
|
|
@@ -129,7 +119,7 @@ module Helpers
|
|
129
119
|
|
130
120
|
|
131
121
|
def incident_url incident
|
132
|
-
|
122
|
+
config[:jira_site] + '/browse/' + incident['key']
|
133
123
|
end
|
134
124
|
|
135
125
|
def incident_link incident
|
data/lib/bender/main.rb
CHANGED
@@ -8,7 +8,6 @@ require 'queryparams'
|
|
8
8
|
require_relative 'metadata'
|
9
9
|
require_relative 'mjolnir'
|
10
10
|
require_relative 'helpers'
|
11
|
-
require_relative 'web'
|
12
11
|
require_relative 'bot'
|
13
12
|
|
14
13
|
Thread.abort_on_exception = true
|
@@ -31,130 +30,71 @@ module Bender
|
|
31
30
|
|
32
31
|
|
33
32
|
|
34
|
-
desc '
|
35
|
-
option :
|
36
|
-
type: :string,
|
37
|
-
aliases: %w[ -b ],
|
38
|
-
desc: 'Set Sinatra interface',
|
39
|
-
default: '0.0.0.0'
|
40
|
-
option :port, \
|
41
|
-
type: :numeric,
|
42
|
-
aliases: %w[ -o ],
|
43
|
-
desc: 'Set Sinatra port',
|
44
|
-
default: 4567
|
45
|
-
option :environment, \
|
46
|
-
type: :string,
|
47
|
-
aliases: %w[ -e ],
|
48
|
-
desc: 'Set Sinatra environment',
|
49
|
-
default: 'development'
|
50
|
-
option :hipchat_token, \
|
51
|
-
type: :string,
|
52
|
-
aliases: %w[ -t ],
|
53
|
-
desc: 'Set HipChat v1 API token',
|
54
|
-
required: true
|
55
|
-
option :hipchat_v2_token, \
|
33
|
+
desc 'start', 'Start Bender HipChat bot and Web server'
|
34
|
+
option :config, \
|
56
35
|
type: :string,
|
57
36
|
aliases: %w[ -c ],
|
58
|
-
desc: 'Set
|
59
|
-
required: true
|
60
|
-
option :primary_room_id, \
|
61
|
-
type: :string,
|
62
|
-
aliases: %w[ -i ],
|
63
|
-
desc: 'Set HipChat primary room ID',
|
64
|
-
required: true
|
65
|
-
option :jid, \
|
66
|
-
type: :string,
|
67
|
-
aliases: %w[ -j ],
|
68
|
-
desc: 'Set HipChat JID',
|
69
|
-
required: true
|
70
|
-
option :password, \
|
71
|
-
type: :string,
|
72
|
-
aliases: %w[ -p ],
|
73
|
-
desc: 'Set HipChat password',
|
74
|
-
required: true
|
75
|
-
option :nick, \
|
76
|
-
type: :string,
|
77
|
-
aliases: %w[ -n ],
|
78
|
-
desc: 'Set HipChat nick name',
|
79
|
-
required: true
|
80
|
-
option :mention, \
|
81
|
-
type: :string,
|
82
|
-
aliases: %w[ -m ],
|
83
|
-
desc: 'Set HipChat mention name',
|
84
|
-
required: true
|
85
|
-
option :rooms, \
|
86
|
-
type: :string,
|
87
|
-
aliases: %w[ -r ],
|
88
|
-
desc: 'Set HipChat rooms (comma-separated)',
|
89
|
-
required: true
|
90
|
-
option :database, \
|
91
|
-
type: :string,
|
92
|
-
aliases: %w[ -d ],
|
93
|
-
desc: 'Set path to application database',
|
94
|
-
required: true
|
95
|
-
option :jira_user, \
|
96
|
-
type: :string,
|
97
|
-
aliases: %w[ -U ],
|
98
|
-
desc: 'Set JIRA username',
|
99
|
-
required: true
|
100
|
-
option :jira_pass, \
|
101
|
-
type: :string,
|
102
|
-
aliases: %w[ -P ],
|
103
|
-
desc: 'Set JIRA password',
|
37
|
+
desc: 'Set path to config file',
|
104
38
|
required: true
|
105
|
-
option :jira_site, \
|
106
|
-
type: :string,
|
107
|
-
aliases: %w[ -S ],
|
108
|
-
desc: 'Set JIRA site',
|
109
|
-
required: true
|
110
|
-
option :jira_project, \
|
111
|
-
type: :string,
|
112
|
-
aliases: %w[ -J ],
|
113
|
-
desc: 'Set JIRA project',
|
114
|
-
required: true
|
115
|
-
option :jira_group, \
|
116
|
-
type: :string,
|
117
|
-
aliases: %w[ -G ],
|
118
|
-
desc: 'Set JIRA group for write mode',
|
119
|
-
required: true
|
120
|
-
option :jira_type, \
|
121
|
-
type: :string,
|
122
|
-
aliases: %w[ -T ],
|
123
|
-
desc: 'Set JIRA issue type',
|
124
|
-
required: true
|
125
|
-
option :user_refresh, \
|
126
|
-
type: :numeric,
|
127
|
-
aliases: %w[ -R ],
|
128
|
-
desc: 'Set JIRA user refresh rate',
|
129
|
-
default: 300
|
130
|
-
option :issue_refresh, \
|
131
|
-
type: :numeric,
|
132
|
-
aliases: %w[ -S ],
|
133
|
-
desc: 'Set JIRA issue refresh rate',
|
134
|
-
default: 5
|
135
|
-
option :group_refresh, \
|
136
|
-
type: :numeric,
|
137
|
-
aliases: %w[ -T ],
|
138
|
-
desc: 'Set JIRA group refresh rate',
|
139
|
-
default: 60
|
140
|
-
option :order, \
|
141
|
-
type: :boolean,
|
142
|
-
aliases: %w[ -O ],
|
143
|
-
desc: 'Reverse order of HipChat API loading (hack)',
|
144
|
-
default: false
|
145
|
-
option :room_base_name, \
|
146
|
-
type: :string,
|
147
|
-
aliases: %w[ -N ],
|
148
|
-
desc: 'Base name for the primary room',
|
149
|
-
default: 'Production Indicent'
|
150
39
|
include_common_options
|
151
40
|
def start
|
41
|
+
raw_config = JSON.parse File.read(options.config), symbolize_names: true
|
42
|
+
@config = DEFAULT_CONFIG.merge! raw_config
|
43
|
+
|
44
|
+
BenderBot.const_set :RESOLVED_TRANSITIONS, %w[ 51 ]
|
45
|
+
Bender.const_set :RESOLVED_TRANSITIONS, BenderBot::RESOLVED_TRANSITIONS
|
46
|
+
Helpers.const_set :RESOLVED_TRANSITIONS, BenderBot::RESOLVED_TRANSITIONS
|
47
|
+
|
48
|
+
BenderBot.const_set :RESOLVED_STATE, /resolve/i
|
49
|
+
Bender.const_set :RESOLVED_STATE, BenderBot::RESOLVED_STATE
|
50
|
+
Helpers.const_set :RESOLVED_STATE, BenderBot::RESOLVED_STATE
|
51
|
+
|
52
|
+
BenderBot.const_set :CLOSED_TRANSITIONS, %w[ 61 71 ]
|
53
|
+
Bender.const_set :CLOSED_TRANSITIONS, BenderBot::CLOSED_TRANSITIONS
|
54
|
+
Helpers.const_set :CLOSED_TRANSITIONS, BenderBot::CLOSED_TRANSITIONS
|
55
|
+
|
56
|
+
BenderBot.const_set :CLOSED_STATE, /close/i
|
57
|
+
Bender.const_set :CLOSED_STATE, BenderBot::CLOSED_STATE
|
58
|
+
Helpers.const_set :CLOSED_STATE, BenderBot::CLOSED_STATE
|
59
|
+
|
60
|
+
BenderBot.const_set :SEVERITIES, {
|
61
|
+
1 => '10480',
|
62
|
+
2 => '10481',
|
63
|
+
3 => '10482',
|
64
|
+
4 => '10483',
|
65
|
+
5 => '10484'
|
66
|
+
}
|
67
|
+
Bender.const_set :SEVERITIES, BenderBot::SEVERITIES
|
68
|
+
Helpers.const_set :SEVERITIES, BenderBot::SEVERITIES
|
69
|
+
|
70
|
+
BenderBot.const_set :SHOW_FIELDS, {
|
71
|
+
'summary' => 'Summary',
|
72
|
+
'description' => 'Description',
|
73
|
+
'customfield_11250' => 'Severity',
|
74
|
+
'customfield_11251' => 'Impact Started',
|
75
|
+
'customfield_11252' => 'Impact Ended',
|
76
|
+
'customfield_11253' => 'Reported By',
|
77
|
+
'customfield_11254' => 'Services Affected',
|
78
|
+
'customfield_11255' => 'Cause',
|
79
|
+
'status' => 'Status',
|
80
|
+
'created' => 'Created',
|
81
|
+
'updated' => 'Updated'
|
82
|
+
}
|
83
|
+
Bender.const_set :SHOW_FIELDS, BenderBot::SHOW_FIELDS
|
84
|
+
Helpers.const_set :SHOW_FIELDS, BenderBot::SHOW_FIELDS
|
85
|
+
|
86
|
+
BenderBot.const_set :SEVERITY_FIELD, SHOW_FIELDS.key('Severity')
|
87
|
+
Bender.const_set :SEVERITY_FIELD, BenderBot::SEVERITY_FIELD
|
88
|
+
Helpers.const_set :SEVERITY_FIELD, BenderBot::SEVERITY_FIELD
|
89
|
+
|
90
|
+
BenderBot.set_commands
|
91
|
+
|
152
92
|
bot = start_bot
|
153
93
|
ts = []
|
154
94
|
ts << periodically_refresh_group(bot)
|
155
95
|
ts << periodically_refresh_users(bot)
|
156
96
|
ts << periodically_refresh_incidents(bot)
|
157
|
-
|
97
|
+
|
158
98
|
ts.map(&:join)
|
159
99
|
end
|
160
100
|
|
@@ -162,21 +102,24 @@ module Bender
|
|
162
102
|
|
163
103
|
private
|
164
104
|
|
165
|
-
def
|
166
|
-
Bot::Connection.configure do |config|
|
167
|
-
config.jid = options.jid
|
168
|
-
config.password = options.password
|
169
|
-
config.nick = options.mention
|
170
|
-
config.mention_name = options.nick
|
171
|
-
config.rooms = options.rooms.split(',')
|
172
|
-
|
173
|
-
Bot::Storage::YamlStore.file = options.database
|
174
|
-
config.store = Bot::Storage::YamlStore
|
105
|
+
def config ; @config end
|
175
106
|
|
176
|
-
|
107
|
+
def start_bot
|
108
|
+
Bot::Connection.configure do |conn|
|
109
|
+
conn.jid = config[:jid]
|
110
|
+
conn.password = config[:password]
|
111
|
+
conn.nick = config[:mention]
|
112
|
+
conn.mention_name = config[:nick]
|
113
|
+
conn.rooms = config[:rooms].is_a?(Array) ? \
|
114
|
+
config[:rooms] : config[:rooms].split(',')
|
115
|
+
|
116
|
+
Bot::Storage::YamlStore.file = config[:database]
|
117
|
+
conn.store = Bot::Storage::YamlStore
|
118
|
+
|
119
|
+
conn.logger = log
|
177
120
|
end
|
178
121
|
|
179
|
-
Bot.run!
|
122
|
+
Bot.run! config, log
|
180
123
|
end
|
181
124
|
|
182
125
|
|
@@ -205,7 +148,7 @@ module Bender
|
|
205
148
|
|
206
149
|
@open = nil unless defined? @open
|
207
150
|
|
208
|
-
log.
|
151
|
+
log.debug \
|
209
152
|
primary_room_name: bot.store['primary_room_name'],
|
210
153
|
primary_room_topic: bot.store['primary_room_topic'],
|
211
154
|
new_room_name: new_room['name'],
|
@@ -216,7 +159,7 @@ module Bender
|
|
216
159
|
|
217
160
|
if open_incidents.empty?
|
218
161
|
if @open.nil? || @open > 0
|
219
|
-
new_room['name'] = '[NONE] %s' %
|
162
|
+
new_room['name'] = '[NONE] %s' % config[:room_base_name]
|
220
163
|
new_room['topic'] = 'Good news everyone! No high-severity incidents at the moment'
|
221
164
|
apply_room_name_and_topic new_room
|
222
165
|
end
|
@@ -230,7 +173,7 @@ module Bender
|
|
230
173
|
end
|
231
174
|
|
232
175
|
unless @open == open_incidents.size
|
233
|
-
new_room['name'] = '[IN PROGRESS] %s' %
|
176
|
+
new_room['name'] = '[IN PROGRESS] %s' % config[:room_base_name]
|
234
177
|
tha_news = open_incidents.size == 1 ? "There's a high-severity incident" : "There are #{open_incidents.size} high-severity incidents"
|
235
178
|
new_room['topic'] = "Terrible news everyone! #{tha_news}"
|
236
179
|
apply_room_name_and_topic new_room
|
@@ -247,10 +190,10 @@ module Bender
|
|
247
190
|
def apply_room_name_and_topic room
|
248
191
|
uri = URI room['links']['self']
|
249
192
|
|
250
|
-
|
193
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
251
194
|
req = Net::HTTP::Put.new uri
|
252
195
|
req['Content-Type'] = 'application/json'
|
253
|
-
req['Authorization'] = 'Bearer %s' %
|
196
|
+
req['Authorization'] = 'Bearer %s' % config[:hipchat_v2_token]
|
254
197
|
req.body = {
|
255
198
|
name: room['name'],
|
256
199
|
topic: room['topic'],
|
@@ -267,24 +210,24 @@ module Bender
|
|
267
210
|
|
268
211
|
def periodically_refresh_incidents bot
|
269
212
|
Thread.new do
|
270
|
-
if
|
213
|
+
if config[:order]
|
271
214
|
hipchat_v1 = HipChat::Client.new \
|
272
|
-
|
215
|
+
config[:hipchat_token], api_version: 'v1'
|
273
216
|
hipchat_v2 = HipChat::Client.new \
|
274
|
-
|
217
|
+
config[:hipchat_v2_token], api_version: 'v2'
|
275
218
|
else
|
276
219
|
hipchat_v2 = HipChat::Client.new \
|
277
|
-
|
220
|
+
config[:hipchat_v2_token], api_version: 'v2'
|
278
221
|
hipchat_v1 = HipChat::Client.new \
|
279
|
-
|
222
|
+
config[:hipchat_token], api_version: 'v1'
|
280
223
|
end
|
281
224
|
|
282
|
-
room_id =
|
225
|
+
room_id = config[:primary_room_id]
|
283
226
|
|
284
227
|
loop do
|
285
228
|
is = refresh_incidents bot
|
286
229
|
set_room_name_and_topic room_id, is, hipchat_v2, bot
|
287
|
-
sleep
|
230
|
+
sleep config[:issue_refresh]
|
288
231
|
end
|
289
232
|
end
|
290
233
|
end
|
@@ -293,15 +236,15 @@ module Bender
|
|
293
236
|
def periodically_refresh_users bot
|
294
237
|
req_path = '/rest/api/2/user/assignable/search'
|
295
238
|
req_params = QueryParams.encode \
|
296
|
-
project:
|
239
|
+
project: config[:jira_project],
|
297
240
|
startAt: 0,
|
298
241
|
maxResults: 1_000_000
|
299
242
|
|
300
|
-
uri = URI(
|
243
|
+
uri = URI(config[:jira_site] + req_path + '?' + req_params)
|
301
244
|
http = Net::HTTP.new uri.hostname, uri.port
|
302
245
|
|
303
246
|
req = Net::HTTP::Get.new uri
|
304
|
-
req.basic_auth
|
247
|
+
req.basic_auth config[:jira_user], config[:jira_pass]
|
305
248
|
req['Content-Type'] = 'application/json'
|
306
249
|
req['Accept'] = 'application/json'
|
307
250
|
|
@@ -329,7 +272,7 @@ module Bender
|
|
329
272
|
|
330
273
|
bot.store['users'] = users
|
331
274
|
|
332
|
-
sleep
|
275
|
+
sleep config[:user_refresh]
|
333
276
|
end
|
334
277
|
end
|
335
278
|
end
|
@@ -338,14 +281,14 @@ module Bender
|
|
338
281
|
def periodically_refresh_group bot
|
339
282
|
req_path = '/rest/api/2/group'
|
340
283
|
req_params = QueryParams.encode \
|
341
|
-
groupname:
|
284
|
+
groupname: config[:jira_group],
|
342
285
|
expand: 'users'
|
343
286
|
|
344
|
-
uri = URI(
|
287
|
+
uri = URI(config[:jira_site] + req_path + '?' + req_params)
|
345
288
|
http = Net::HTTP.new uri.hostname, uri.port
|
346
289
|
|
347
290
|
req = Net::HTTP::Get.new uri
|
348
|
-
req.basic_auth
|
291
|
+
req.basic_auth config[:jira_user], config[:jira_pass]
|
349
292
|
req['Content-Type'] = 'application/json'
|
350
293
|
req['Accept'] = 'application/json'
|
351
294
|
|
@@ -364,29 +307,10 @@ module Bender
|
|
364
307
|
|
365
308
|
user_names = data['users']['items'].map { |u| u['displayName'] }
|
366
309
|
bot.store['group'] = user_names
|
367
|
-
sleep
|
310
|
+
sleep config[:group_refresh]
|
368
311
|
end
|
369
312
|
end
|
370
313
|
end
|
371
314
|
|
372
|
-
|
373
|
-
def serve_web bot
|
374
|
-
Web.set :environment, options.environment
|
375
|
-
Web.set :port, options.port
|
376
|
-
Web.set :bind, options.bind
|
377
|
-
Web.set :store, options.database
|
378
|
-
|
379
|
-
if log.level >= ::Logger::DEBUG
|
380
|
-
Web.set :raise_errors, true
|
381
|
-
Web.set :dump_errors, true
|
382
|
-
Web.set :show_exceptions, true
|
383
|
-
Web.set :logging, ::Logger::DEBUG
|
384
|
-
end
|
385
|
-
|
386
|
-
Web.set :bot, bot
|
387
|
-
Web.run!
|
388
|
-
end
|
389
|
-
|
390
|
-
|
391
315
|
end
|
392
316
|
end
|
data/lib/bender/metadata.rb
CHANGED
data/lib/bender/mjolnir.rb
CHANGED
@@ -18,12 +18,6 @@ class Mjolnir < Thor
|
|
18
18
|
aliases: %w[ -V ],
|
19
19
|
desc: 'Enable DEBUG-level logging',
|
20
20
|
default: ENV['BENDER_DEBUG'] || false
|
21
|
-
},
|
22
|
-
trace: {
|
23
|
-
type: :boolean,
|
24
|
-
aliases: %w[ -VV ],
|
25
|
-
desc: 'Enable TRACE-level logging',
|
26
|
-
default: ENV['BENDER_TRACE'] || false
|
27
21
|
}
|
28
22
|
}
|
29
23
|
|
@@ -42,7 +36,6 @@ class Mjolnir < Thor
|
|
42
36
|
return @logger if defined? @logger
|
43
37
|
level = :info
|
44
38
|
level = :debug if options.debug?
|
45
|
-
level = :trace if options.trace?
|
46
39
|
device = options.log || $stderr
|
47
40
|
pretty = device.tty? rescue false
|
48
41
|
@logger = Slog.new \
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bender-bot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sean Clemmer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-02-
|
11
|
+
date: 2016-02-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -38,20 +38,6 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: sinatra
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '1.4'
|
48
|
-
type: :runtime
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '1.4'
|
55
41
|
- !ruby/object:Gem::Dependency
|
56
42
|
name: sclemmer-robut
|
57
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -122,20 +108,6 @@ dependencies:
|
|
122
108
|
- - '='
|
123
109
|
- !ruby/object:Gem::Version
|
124
110
|
version: 1.0.4
|
125
|
-
- !ruby/object:Gem::Dependency
|
126
|
-
name: thin
|
127
|
-
requirement: !ruby/object:Gem::Requirement
|
128
|
-
requirements:
|
129
|
-
- - '='
|
130
|
-
- !ruby/object:Gem::Version
|
131
|
-
version: 1.6.3
|
132
|
-
type: :runtime
|
133
|
-
prerelease: false
|
134
|
-
version_requirements: !ruby/object:Gem::Requirement
|
135
|
-
requirements:
|
136
|
-
- - '='
|
137
|
-
- !ruby/object:Gem::Version
|
138
|
-
version: 1.6.3
|
139
111
|
- !ruby/object:Gem::Dependency
|
140
112
|
name: json
|
141
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -181,12 +153,6 @@ files:
|
|
181
153
|
- lib/bender/main.rb
|
182
154
|
- lib/bender/metadata.rb
|
183
155
|
- lib/bender/mjolnir.rb
|
184
|
-
- lib/bender/web.rb
|
185
|
-
- web/app/bender.js
|
186
|
-
- web/app/style/bender.css
|
187
|
-
- web/public/favicon.ico
|
188
|
-
- web/views/app.erb
|
189
|
-
- web/views/layout.erb
|
190
156
|
homepage: https://github.com/sczizzo/bender
|
191
157
|
licenses:
|
192
158
|
- ISC
|
data/lib/bender/web.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
require 'pathname'
|
2
|
-
require 'thread'
|
3
|
-
require 'json'
|
4
|
-
|
5
|
-
require 'sinatra/base'
|
6
|
-
|
7
|
-
require_relative 'metadata'
|
8
|
-
|
9
|
-
Thread.abort_on_exception = true
|
10
|
-
|
11
|
-
|
12
|
-
module Bender
|
13
|
-
class Web < Sinatra::Application
|
14
|
-
set :root, File.join(Bender::ROOT, 'web')
|
15
|
-
|
16
|
-
get '/v' do
|
17
|
-
content_type :text
|
18
|
-
VERSION
|
19
|
-
end
|
20
|
-
|
21
|
-
get '/' do
|
22
|
-
erb :app
|
23
|
-
end
|
24
|
-
|
25
|
-
get '/favicon.ico' do
|
26
|
-
send_file File.join(settings.root, 'favicon.ico'), \
|
27
|
-
disposition: 'inline'
|
28
|
-
end
|
29
|
-
|
30
|
-
get %r|/app/(.*)| do |fn|
|
31
|
-
send_file File.join(settings.root, 'app', fn), \
|
32
|
-
disposition: 'inline'
|
33
|
-
end
|
34
|
-
|
35
|
-
end
|
36
|
-
end
|
data/web/app/bender.js
DELETED
data/web/app/style/bender.css
DELETED
File without changes
|
data/web/public/favicon.ico
DELETED
Binary file
|
data/web/views/app.erb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
Heyo!
|
data/web/views/layout.erb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html lang="en">
|
3
|
-
<head>
|
4
|
-
<title>Bender</title>
|
5
|
-
<meta charset="utf-8" />
|
6
|
-
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
7
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
8
|
-
<meta name="description" content="Weave." />
|
9
|
-
<meta name="author" content="Sean Clemmer" />
|
10
|
-
<link rel="icon" href="/favicon.ico" />
|
11
|
-
<link href="//maxcdn.bootstrapcdn.com/bootswatch/3.3.4/superhero/bootstrap.min.css" rel="stylesheet" />
|
12
|
-
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet" />
|
13
|
-
<link href="/app/style/bender.css" rel="stylesheet" />
|
14
|
-
</head>
|
15
|
-
<body>
|
16
|
-
<%= yield %>
|
17
|
-
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
18
|
-
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
|
19
|
-
<script src="/app/bender.js"></script>
|
20
|
-
</body>
|
21
|
-
</html>
|