bender-bot 0.2.4 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 702cbc0ab493486d62b7c9db41dfc1191a5c9868
4
- data.tar.gz: 3e6535a990ed42e03aa8d6b93c4a24bd83643791
3
+ metadata.gz: 50e516ad8b6f747483302fc79ab811a8cccf2368
4
+ data.tar.gz: bd931995c92e814c96bbcea6f305534c2941cede
5
5
  SHA512:
6
- metadata.gz: 10f0310b8a034da123d18f08da7b22698b57acc31520c66a2e9d9306d64c028f161e3f0a77b123fca96b50ff56ece5e9434a924f0481d2bc34859d971b80225e
7
- data.tar.gz: c8b49ba2fa7bb1f1b715fbbb04dea79ed361657a2483d7fc4f8a8fbe2a61694a28c6992ad0cffd7edc19e0fc81a6e03b09b1abd6ed8dd08300d91826a2cd63b2
6
+ metadata.gz: b43003dffdf9a21bb11877116e287e04b80a84618a3d2743b7a83a030025d7c0303d6842a5d478c048c49680e9a0955576de7497ae0275e08baa26540701abe5
7
+ data.tar.gz: 23de30730b6a02d26c1e71603966bb6811ef7ef4a7037c978f4dc69e75e6d3afe4abccafdd8d4eae6c9afd0d40eae674d3a47f470e52a8cffc56d14e1d9c07e9
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.4
1
+ 0.3.0
data/lib/bender/bot.rb CHANGED
@@ -8,6 +8,8 @@ require 'robut/storage/yaml_store'
8
8
  require 'fuzzystringmatch'
9
9
  require 'queryparams'
10
10
 
11
+ require_relative 'helpers'
12
+
11
13
  Bot = Robut # alias
12
14
 
13
15
 
@@ -29,59 +31,10 @@ end
29
31
 
30
32
  class BenderBot
31
33
  include Bot::Plugin
34
+ include Helpers
32
35
 
33
36
  JARO = FuzzyStringMatch::JaroWinkler.create :native
34
37
 
35
- RESOLVED_TRANSITIONS = %w[ 51 ]
36
-
37
- RESOLVED_STATE = /resolve/i
38
-
39
- CLOSED_TRANSITIONS = %w[ 61 71 ]
40
-
41
- CLOSED_STATE = /close/i
42
-
43
- SEVERITIES = {
44
- 1 => '10480',
45
- 2 => '10481',
46
- 3 => '10482',
47
- 4 => '10483',
48
- 5 => '10484'
49
- }
50
-
51
- SHOW_FIELDS = {
52
- 'summary' => 'Summary',
53
- 'description' => 'Description',
54
- 'customfield_11250' => 'Severity',
55
- 'customfield_11251' => 'Impact Started',
56
- 'customfield_11252' => 'Impact Ended',
57
- 'customfield_11253' => 'Reported By',
58
- 'customfield_11254' => 'Services Affected',
59
- 'customfield_11255' => 'Cause',
60
- 'status' => 'Status',
61
- 'created' => 'Created',
62
- 'updated' => 'Updated'
63
- }
64
-
65
-
66
- QUOTES = [
67
- 'Bite my shiny metal ass!',
68
- 'This is the worst kind of discrimination there is: the kind against me!',
69
- 'I guess if you want children beaten, you have to do it yourself.',
70
- "Hahahahaha! Oh wait you're serious. Let me laugh even harder.",
71
- "You know what cheers me up? Other people's misfortune.",
72
- 'Anything less than immortality is a complete waste of time.',
73
- "Blackmail is such an ugly word. I prefer extortion. The 'x' makes it sound cool.",
74
- 'Have you tried turning off the TV, sitting down with your children, and hitting them?',
75
- "You're a pimple on society’s ass and you'll never amount to anything!",
76
- 'Shut up baby, I know it!',
77
- "I'm so embarrassed. I wish everyone else was dead!",
78
- "Afterlife? If I thought I had to live another life, I'd kill myself right now!",
79
- "I'm back baby!",
80
- "LET'S GO ALREADYYYYYY!",
81
- "I don't have emotions and sometimes that makes me very sad",
82
- "Life is hilariously cruel"
83
- ]
84
-
85
38
  COMMANDS = {
86
39
  help: {
87
40
  desc: 'Display this help text',
@@ -134,7 +87,14 @@ class BenderBot
134
87
 
135
88
 
136
89
  def handle room, sender, message
137
- @room_name = @@rooms.select { |r| r.xmpp_jid == room }.first.name
90
+ begin
91
+ @room_name = @@rooms.select { |r| r.xmpp_jid == room }.first.name
92
+ @@hipchat[@room_name].get_room # test
93
+ rescue
94
+ @@hipchat = HipChat::Client.new(@@options.hipchat_token)
95
+ @@rooms = @@hipchat.rooms
96
+ @room_name = @@rooms.select { |r| r.xmpp_jid == room }.first.name
97
+ end
138
98
  @room = room
139
99
  @sender = sender
140
100
  @message = message
@@ -142,13 +102,6 @@ class BenderBot
142
102
  severity_field = SHOW_FIELDS.key 'Severity'
143
103
  severities = Hash.new { |h,k| h[k] = [] }
144
104
 
145
- if message =~ /\/inc\s+(\w+)?\s*/
146
- unless COMMANDS.include? $1.to_sym
147
- reply_html 'Invalid usage', :red
148
- reply_with_help
149
- return
150
- end
151
- end
152
105
 
153
106
  case message
154
107
 
@@ -175,7 +128,7 @@ class BenderBot
175
128
 
176
129
  is = store['incidents'].reverse.map do |i|
177
130
  status = normalize_value i['fields']['status']
178
- unless status =~ /done|complete|closed/i
131
+ unless status =~ /resolved|closed/i
179
132
  '%s (%s - %s) [%s]: %s' % [
180
133
  incident_link(i),
181
134
  short_severity(i['fields'][severity_field]['value']),
@@ -230,7 +183,7 @@ class BenderBot
230
183
  end
231
184
 
232
185
  if severities.empty?
233
- reply_html 'No recent incidents! Woohoo!', :green
186
+ reply_html 'Good news everyone! No open incidents at the moment', :green
234
187
 
235
188
  else
236
189
  is = severities.keys.sort.map do |sev|
@@ -313,6 +266,11 @@ class BenderBot
313
266
  else
314
267
  reply_html 'Sorry, no such incident!', :red
315
268
  end
269
+
270
+
271
+ when /^\s*\/inc/i
272
+ reply_html 'Invalid usage', :red
273
+ reply_with_help
316
274
  end
317
275
 
318
276
 
@@ -346,31 +304,6 @@ private
346
304
 
347
305
 
348
306
 
349
- def refresh_incidents
350
- req_path = '/rest/api/2/search'
351
- req_params = QueryParams.encode \
352
- jql: "project = #{options.jira_project} ORDER BY created ASC, priority DESC",
353
- fields: SHOW_FIELDS.keys.join(','),
354
- startAt: 0,
355
- maxResults: 1_000_000
356
-
357
- uri = URI(options.jira_site + req_path + '?' + req_params)
358
- http = Net::HTTP.new uri.hostname, uri.port
359
-
360
- req = Net::HTTP::Get.new uri
361
- req.basic_auth options.jira_user, options.jira_pass
362
- req['Content-Type'] = 'application/json'
363
- req['Accept'] = 'application/json'
364
-
365
- resp = http.request req
366
- issues = JSON.parse(resp.body)['issues']
367
-
368
- store['incidents'] = issues.map! do |i|
369
- i['num'] = i['key'].split('-', 2).last ; i
370
- end
371
- end
372
-
373
-
374
307
  def file_incident data
375
308
  req_path = '/rest/api/2/issue'
376
309
  uri = URI(options.jira_site + req_path)
@@ -499,62 +432,4 @@ private
499
432
  end
500
433
  end
501
434
 
502
-
503
- def normalize_value val
504
- case val
505
- when Hash
506
- val['name'] || val['value'] || val
507
- when Array
508
- val.map { |v| v['value'] }.join(', ')
509
- when /^\d{4}\-\d{2}\-\d{2}/
510
- '%s (%s)' % [ val, normalize_date(val) ]
511
- else
512
- val
513
- end
514
- end
515
-
516
-
517
- def normalize_date val
518
- Time.parse(val).utc.iso8601(0).sub(/Z$/, 'UTC')
519
- end
520
-
521
-
522
- def friendly_date val
523
- Time.parse(val).strftime('%Y-%m-%d %H:%M %Z')
524
- end
525
-
526
-
527
- def recent_incident? i
528
- it = Time.parse(i['fields']['created'])
529
- Time.now - it < one_day
530
- end
531
-
532
-
533
- def one_day
534
- 24 * 60 * 60 # seconds/day
535
- end
536
-
537
-
538
- def select_incident num, refresh=true
539
- refresh_incidents if refresh
540
- store['incidents'].select { |i| i['num'] == num }.first
541
- end
542
-
543
-
544
- def short_severity s
545
- s.split(' - ', 2).first
546
- end
547
-
548
-
549
- def incident_url incident
550
- options.jira_site + '/browse/' + incident['key']
551
- end
552
-
553
- def incident_link incident
554
- '<a href="%s">%s</a>' % [
555
- incident_url(incident),
556
- incident['key']
557
- ]
558
- end
559
-
560
435
  end
@@ -0,0 +1,136 @@
1
+ module Helpers
2
+
3
+ RESOLVED_TRANSITIONS = %w[ 51 ]
4
+
5
+ RESOLVED_STATE = /resolve/i
6
+
7
+ CLOSED_TRANSITIONS = %w[ 61 71 ]
8
+
9
+ CLOSED_STATE = /close/i
10
+
11
+ SEVERITIES = {
12
+ 1 => '10480',
13
+ 2 => '10481',
14
+ 3 => '10482',
15
+ 4 => '10483',
16
+ 5 => '10484'
17
+ }
18
+
19
+ SHOW_FIELDS = {
20
+ 'summary' => 'Summary',
21
+ 'description' => 'Description',
22
+ 'customfield_11250' => 'Severity',
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'
31
+ }
32
+
33
+
34
+ QUOTES = [
35
+ 'Bite my shiny metal ass!',
36
+ 'This is the worst kind of discrimination there is: the kind against me!',
37
+ 'I guess if you want children beaten, you have to do it yourself.',
38
+ "Hahahahaha! Oh wait you're serious. Let me laugh even harder.",
39
+ "You know what cheers me up? Other people's misfortune.",
40
+ 'Anything less than immortality is a complete waste of time.',
41
+ "Blackmail is such an ugly word. I prefer extortion. The 'x' makes it sound cool.",
42
+ 'Have you tried turning off the TV, sitting down with your children, and hitting them?',
43
+ "You're a pimple on society’s ass and you'll never amount to anything!",
44
+ 'Shut up baby, I know it!',
45
+ "I'm so embarrassed. I wish everyone else was dead!",
46
+ "Afterlife? If I thought I had to live another life, I'd kill myself right now!",
47
+ "I'm back baby!",
48
+ "LET'S GO ALREADYYYYYY!",
49
+ "I don't have emotions and sometimes that makes me very sad",
50
+ "Life is hilariously cruel"
51
+ ]
52
+
53
+
54
+ def refresh_incidents bot=self
55
+ req_path = '/rest/api/2/search'
56
+ req_params = QueryParams.encode \
57
+ jql: "project = #{options.jira_project} ORDER BY created ASC, priority DESC",
58
+ fields: SHOW_FIELDS.keys.join(','),
59
+ startAt: 0,
60
+ maxResults: 1_000_000
61
+
62
+ uri = URI(options.jira_site + req_path + '?' + req_params)
63
+ http = Net::HTTP.new uri.hostname, uri.port
64
+
65
+ req = Net::HTTP::Get.new uri
66
+ req.basic_auth options.jira_user, options.jira_pass
67
+ req['Content-Type'] = 'application/json'
68
+ req['Accept'] = 'application/json'
69
+
70
+ resp = http.request req
71
+ issues = JSON.parse(resp.body)['issues']
72
+
73
+ bot.store['incidents'] = issues.map! do |i|
74
+ i['num'] = i['key'].split('-', 2).last ; i
75
+ end
76
+ end
77
+
78
+
79
+ def normalize_value val
80
+ case val
81
+ when Hash
82
+ val['name'] || val['value'] || val
83
+ when Array
84
+ val.map { |v| v['value'] }.join(', ')
85
+ when /^\d{4}\-\d{2}\-\d{2}/
86
+ '%s (%s)' % [ val, normalize_date(val) ]
87
+ else
88
+ val
89
+ end
90
+ end
91
+
92
+
93
+ def normalize_date val
94
+ Time.parse(val).utc.iso8601(0).sub(/Z$/, 'UTC')
95
+ end
96
+
97
+
98
+ def friendly_date val
99
+ Time.parse(val).strftime('%Y-%m-%d %H:%M %Z')
100
+ end
101
+
102
+
103
+ def recent_incident? i
104
+ it = Time.parse(i['fields']['created'])
105
+ Time.now - it < one_day
106
+ end
107
+
108
+
109
+ def one_day
110
+ 24 * 60 * 60 # seconds/day
111
+ end
112
+
113
+
114
+ def select_incident num, refresh=true
115
+ refresh_incidents if refresh
116
+ store['incidents'].select { |i| i['num'] == num }.first
117
+ end
118
+
119
+
120
+ def short_severity s
121
+ s.split(' - ', 2).first
122
+ end
123
+
124
+
125
+ def incident_url incident
126
+ options.jira_site + '/browse/' + incident['key']
127
+ end
128
+
129
+ def incident_link incident
130
+ '<a href="%s">%s</a>' % [
131
+ incident_url(incident),
132
+ incident['key']
133
+ ]
134
+ end
135
+
136
+ end
data/lib/bender/main.rb CHANGED
@@ -6,12 +6,16 @@ require 'queryparams'
6
6
 
7
7
  require_relative 'metadata'
8
8
  require_relative 'mjolnir'
9
+ require_relative 'helpers'
9
10
  require_relative 'web'
10
11
  require_relative 'bot'
11
12
 
13
+ Thread.abort_on_exception = true
14
+
12
15
 
13
16
  module Bender
14
17
  class Main < Mjolnir
18
+ include Helpers
15
19
 
16
20
  desc 'version', 'Echo the application version'
17
21
  def version
@@ -47,6 +51,16 @@ module Bender
47
51
  aliases: %w[ -t ],
48
52
  desc: 'Set HipChat v1 API token',
49
53
  required: true
54
+ option :hipchat_v2_token, \
55
+ type: :string,
56
+ aliases: %w[ -c ],
57
+ desc: 'Set HipChat v2 API token',
58
+ required: true
59
+ option :primary_room_id, \
60
+ type: :string,
61
+ aliases: %w[ -i ],
62
+ desc: 'Set HipChat primary room ID',
63
+ required: true
50
64
  option :jid, \
51
65
  type: :string,
52
66
  aliases: %w[ -j ],
@@ -77,11 +91,6 @@ module Bender
77
91
  aliases: %w[ -d ],
78
92
  desc: 'Set path to application database',
79
93
  required: true
80
- option :rooms, \
81
- type: :string,
82
- aliases: %w[ -r ],
83
- desc: 'Set HipChat rooms (comma-separated)',
84
- required: true
85
94
  option :jira_user, \
86
95
  type: :string,
87
96
  aliases: %w[ -U ],
@@ -107,15 +116,21 @@ module Bender
107
116
  aliases: %w[ -T ],
108
117
  desc: 'Set JIRA issue type',
109
118
  required: true
110
- option :refresh, \
119
+ option :user_refresh, \
111
120
  type: :numeric,
112
121
  aliases: %w[ -R ],
113
- desc: 'Set JIRA refresh rate',
122
+ desc: 'Set JIRA user refresh rate',
114
123
  default: 300
124
+ option :issue_refresh, \
125
+ type: :numeric,
126
+ aliases: %w[ -S ],
127
+ desc: 'Set JIRA issue refresh rate',
128
+ default: 5
115
129
  include_common_options
116
130
  def start
117
131
  bot = start_bot
118
- refresh_users bot
132
+ periodically_refresh_users bot
133
+ periodically_refresh_incidents bot
119
134
  serve_web bot
120
135
  end
121
136
 
@@ -141,7 +156,78 @@ module Bender
141
156
  end
142
157
 
143
158
 
144
- def refresh_users bot
159
+ def set_room_name_and_topic room_id, incidents, hipchat, bot
160
+ room = hipchat[room_id]
161
+ new_room = room.get_room
162
+
163
+ open_incidents = incidents.select do |i|
164
+ status = normalize_value i['fields']['status']
165
+ !(status =~ /resolved|closed/i)
166
+ end
167
+
168
+ @room_name ||= bot.store['primary_room_name'] || new_room['name']
169
+ @room_topic ||= bot.store['primary_room_topic'] || new_room['topic']
170
+
171
+ @open = false unless defined? @open
172
+
173
+ log.info \
174
+ primary_room_name: bot.store['primary_room_name'],
175
+ primary_room_topic: bot.store['primary_room_topic'],
176
+ new_room_name: new_room['name'],
177
+ new_room_topic: new_room['topic'],
178
+ room_name: @room_name,
179
+ room_topic: @room_topic,
180
+ open: @open
181
+
182
+ if open_incidents.empty?
183
+ if @open
184
+ new_room['name'] = @room_name
185
+ new_room['topic'] = @room_topic
186
+ room.update_room(new_room)
187
+ end
188
+
189
+ @open = false
190
+
191
+ else
192
+ unless @open
193
+ @room_name = new_room['name']
194
+ @room_topic = new_room['topic']
195
+ bot.store['primary_room_name'] = @room_name
196
+ bot.store['primary_room_topic'] = @room_topic
197
+ new_room['name'] = 'DANGER WILL ROBINSON'
198
+ new_room['topic'] = '%d open incicents!' % open_incidents.size
199
+ room.update_room(new_room)
200
+ end
201
+
202
+ @open = true
203
+ end
204
+ end
205
+
206
+
207
+ def periodically_refresh_incidents bot
208
+ Thread.new do
209
+ hipchat_v2 = HipChat::Client.new \
210
+ options.hipchat_v2_token, api_version: 'v2'
211
+
212
+ hipchat_v1 = HipChat::Client.new \
213
+ options.hipchat_token, api_version: 'v1'
214
+
215
+ room_id = options.primary_room_id
216
+
217
+ loop do
218
+ is = refresh_incidents bot
219
+ begin
220
+ set_room_name_and_topic room_id, is, hipchat_v2, bot
221
+ sleep options.issue_refresh
222
+ rescue NoMethodError
223
+ sleep 1
224
+ end
225
+ end
226
+ end
227
+ end
228
+
229
+
230
+ def periodically_refresh_users bot
145
231
  req_path = '/rest/api/2/user/assignable/search'
146
232
  req_params = QueryParams.encode \
147
233
  project: options.jira_project,
@@ -169,7 +255,7 @@ module Bender
169
255
 
170
256
  bot.store['users'] = users
171
257
 
172
- sleep options.refresh
258
+ sleep options.user_refresh
173
259
  end
174
260
  end
175
261
  end
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.2.4
4
+ version: 0.3.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: 2015-08-26 00:00:00.000000000 Z
11
+ date: 2015-08-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -177,6 +177,7 @@ files:
177
177
  - bin/bender
178
178
  - lib/bender.rb
179
179
  - lib/bender/bot.rb
180
+ - lib/bender/helpers.rb
180
181
  - lib/bender/main.rb
181
182
  - lib/bender/metadata.rb
182
183
  - lib/bender/mjolnir.rb