-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathjira.rb
197 lines (158 loc) · 5.77 KB
/
jira.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
require 'open-uri'
require 'hpricot'
require 'tempfile'
require 'rexml/document'
##
# JIRA plugin
#
# checks JIRA for new issues and posts them to the room
#
# in your config.yml you can either specify a single URL or a list of URLs, e.g.
#
# jira_url: http://your_jira_url
# # OR
# jira_url:
# - http://your_jira_url
# - http://your_jira_url2
#
class Jira < CampfireBot::Plugin
at_interval 3.minutes, :check_jira
on_command 'checkjira', :checkjira_command
on_command 'jira', :checkjira_command
def initialize
# log "initializing... "
@data_file = File.join(BOT_ROOT, 'tmp', "jira-#{BOT_ENVIRONMENT}.yml")
@cached_ids = YAML::load(File.read(@data_file)) rescue {}
@last_checked = @cached_ids[:last_checked] || 10.minutes.ago
@log = Logging.logger["CampfireBot::Plugin::Jira"]
end
# respond to checkjira command-- same as interval except we answer with 'no issues found' if there are no issues
def checkjira_command(msg)
begin
msg.speak "no new issues since I last checked #{@lastlast} ago" if !check_jira(msg)
rescue
msg.speak "sorry, we had trouble connecting to JIRA."
end
end
def check_jira(msg)
saw_an_issue = false
old_cache = Marshal::load(Marshal.dump(@cached_ids)) # since ruby doesn't have deep copy
@lastlast = time_ago_in_words(@last_checked)
@last_checked = Time.now
tix = fetch_jira_url
raise if tix.nil?
tix.each do |ticket|
if seen?(ticket, old_cache)
saw_an_issue = true
@cached_ids = update_cache(ticket, @cached_ids)
messagetext = "#{ticket[:type]} - #{ticket[:title]} - #{ticket[:link]} - reported by #{ticket[:reporter]} - #{ticket[:priority]}"
msg.speak(messagetext)
msg.play("vuvuzela") if ticket[:priority] == "Blocker"
@log.info messagetext
end
end
flush_cache(@cached_ids)
@log.info "no new issues." if !saw_an_issue
saw_an_issue
end
protected
# fetch jira url and return a list of ticket Hashes
def fetch_jira_url()
jiraconfig = bot.config['jira_url']
if jiraconfig.is_a?(Array)
searchurls = jiraconfig
else
searchurls = [jiraconfig]
end
tix = []
searchurls.each do |searchurl|
begin
@log.info "checking jira for new issues... #{searchurl}"
xmldata = open(searchurl).read
doc = REXML::Document.new(xmldata)
raise Exception.new("response had no content") if doc.nil?
doc.elements.inject('rss/channel/item', tix) do |tix, element|
tix.push(parse_ticket_info(element))
end
rescue Exception => e
@log.error "error connecting to jira: #{e.message}"
# @log.error "#{e.backtrace}"
end
end
return tix
end
# extract ticket hash from individual xml element
def parse_ticket_info(xml_element)
id = xml_element.elements['key'].text rescue ""
id, spacekey = split_spacekey_and_id(id) rescue ""
link = xml_element.elements['link'].text rescue ""
title = xml_element.elements['title'].text rescue ""
reporter = xml_element.elements['reporter'].text rescue ""
type = xml_element.elements['type'].text rescue ""
priority = xml_element.elements['priority'].text rescue ""
return {
:spacekey => spacekey,
:id => id,
:link => link,
:title => title,
:reporter => reporter,
:type => type,
:priority => priority
}
end
# extract the spacekey and id from the ticket id
def split_spacekey_and_id(key)
spacekey = key.scan(/^([A-Z]+)/).to_s
id = key.scan(/([0-9]+)$/)[0].to_s.to_i
return id, spacekey
end
# has this ticket been seen before this run?
def seen?(ticket, old_cache)
!old_cache.key?(ticket[:spacekey]) or old_cache[ticket[:spacekey]] < ticket[:id]
end
# only update the cached highest ID if it is in fact the highest ID
def update_cache(ticket, cache)
cache[ticket[:spacekey]] = ticket[:id] if seen?(ticket, cache)
cache
end
# write the cache to disk
def flush_cache(cache)
cache[:last_checked] = @last_checked
File.open(@data_file, 'w') do |out|
YAML.dump(cache, out)
end
end
#
# time/utility functions
#
def time_ago_in_words(from_time, include_seconds = false)
distance_of_time_in_words(from_time, Time.now, include_seconds)
end
def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false)
from_time = from_time.to_time if from_time.respond_to?(:to_time)
to_time = to_time.to_time if to_time.respond_to?(:to_time)
distance_in_minutes = (((to_time - from_time).abs)/60).round
distance_in_seconds = ((to_time - from_time).abs).round
case distance_in_minutes
when 0..1
return (distance_in_minutes == 0) ? 'less than a minute' : '1 minute' unless include_seconds
case distance_in_seconds
when 0..4 then 'less than 5 seconds'
when 5..9 then 'less than 10 seconds'
when 10..19 then 'less than 20 seconds'
when 20..39 then 'half a minute'
when 40..59 then 'less than a minute'
else '1 minute'
end
when 2..44 then "#{distance_in_minutes} minutes"
when 45..89 then 'about 1 hour'
when 90..1439 then "about #{(distance_in_minutes.to_f / 60.0).round} hours"
when 1440..2879 then '1 day'
when 2880..43199 then "#{(distance_in_minutes / 1440).round} days"
when 43200..86399 then 'about 1 month'
when 86400..525599 then "#{(distance_in_minutes / 43200).round} months"
when 525600..1051199 then 'about 1 year'
else "over #{(distance_in_minutes / 525600).round} years"
end
end
end