-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathsvn.rb
169 lines (133 loc) · 5.16 KB
/
svn.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
require 'open-uri'
require 'hpricot'
require 'tempfile'
class Svn < CampfireBot::Plugin
at_interval 20.minutes, :check_svn
on_command 'svn', :checksvn_command
def initialize
# log "initializing... "
@data_file = File.join(BOT_ROOT, 'tmp', "svn-#{BOT_ENVIRONMENT}-#{bot.config['room']}.yml")
@cached_revisions = YAML::load(File.read(@data_file)) rescue {}
@last_checked ||= 10.minutes.ago
@urls = bot.config['svn_urls']
@log = Logging.logger["CampfireBot::Plugin::Svn"]
end
# respond to checkjira command-- same as interval except we answer with 'no issues found' if
def checksvn_command(msg)
msg.speak "no new commits since I last checked #{@lastlast} ago" if !check_svn(msg)
end
def check_svn(msg)
saw_a_commit = false
old_cache = Marshal::load(Marshal.dump(@cached_revisions)) # since ruby doesn't have deep copy
@lastlast = time_ago_in_words(@last_checked)
commits = fetch_svn_urls
commits.each do |commit|
# p commit
if new?(commit, old_cache)
saw_a_commit = true
@cached_revisions = update_cache(commit, @cached_revisions)
flush_cache(@cached_revisions)
messagetext = "#{commit[:author]} committed revision #{commit[:revision]} #{time_ago_in_words(commit[:date])} ago on #{commit[:url]}:\n"
messagetext += "\n#{commit[:message]}\n"
messagetext += "----\n"
commit[:paths].each do |path|
messagetext += path[:action] + " " + path[:path] + "\n"
end
msg.paste(messagetext)
@log.info messagetext
end
end
@last_checked = Time.now
@log.info "no new commits." if !saw_a_commit
saw_a_commit
end
protected
# fetch jira url and return a list of commit Hashes
def fetch_svn_urls()
urls = bot.config['svn_urls']
svn_username = bot.config['svn_username']
svn_password = bot.config['svn_password']
commits = []
urls.each do |url|
begin
@log.info "checking #{url} for new commits..."
xmldata = `svn log --xml -v --limit 15 #{url} --username #{svn_username} --password #{svn_password}`
doc = REXML::Document.new(xmldata)
doc.elements.inject('log/logentry', commits) do |commits, element|
commits.push({:url => url}.merge(parse_entry_info(element)))
end
rescue Exception => e
@log.error "error connecting to svn: #{e.message}"
end
end
return commits
end
# extract commit hash from indivrevisionual xml element
def parse_entry_info(xml_element)
revision = xml_element.attributes['revision']
author = xml_element.elements['author'].text
date = DateTime.parse(xml_element.elements['date'].text)
message = xml_element.elements['msg'].text
paths = xml_element.elements.collect('paths/path') do |e|
{
:action => e.attributes['action'],
:path => e.text
}
end
return {
:revision => revision,
:author => author,
:message => message,
:date => date,
:paths => paths
}
end
# has this commit been seen before this run?
def new?(commit, old_cache)
!old_cache.key?(commit[:url]) or old_cache[commit[:url]] < commit[:revision].to_i
end
# only update the cached highest revision if it is in fact the highest revision
def update_cache(commit, cache)
cache[commit[:url]] = commit[:revision].to_i if new?(commit, cache)
cache
end
# write the cache to disk
def flush_cache(cache)
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