hubeye 0.0.4 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +17 -0
- data/VERSION.rb +2 -2
- data/bin/hubeye +1 -1
- data/lib/client/hubeye_client.rb +9 -4
- data/lib/log/logger.rb +3 -8
- data/lib/notification/notification.rb +6 -6
- data/lib/server/hubeye_server.rb +207 -227
- data/test/runner.rb +2 -2
- metadata +6 -6
- data/README.md.html +0 -212
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
$:.unshift 'lib'
|
2
|
+
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/clean'
|
5
|
+
|
6
|
+
task :default => [:test]
|
7
|
+
|
8
|
+
desc 'Run tests (default)'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.test_files = FileList['test/runner.rb']
|
11
|
+
end
|
12
|
+
|
13
|
+
desc 'Display current version'
|
14
|
+
task :version do
|
15
|
+
require_relative 'VERSION'
|
16
|
+
puts Hubeye::VERSION * '.'
|
17
|
+
end
|
data/VERSION.rb
CHANGED
data/bin/hubeye
CHANGED
data/lib/client/hubeye_client.rb
CHANGED
@@ -36,12 +36,11 @@ class HubeyeClient
|
|
36
36
|
def read_welcome
|
37
37
|
# Wait just a bit, to see if the server sends any initial message.
|
38
38
|
begin
|
39
|
-
sleep(
|
39
|
+
sleep(1) # Wait a second
|
40
40
|
msg = @s.readpartial(4096) # Read whatever is ready
|
41
41
|
STDOUT.puts msg.chop # And display it
|
42
42
|
# If nothing was ready to read, just ignore the exception.
|
43
|
-
rescue SystemCallError
|
44
|
-
rescue NoMethodError
|
43
|
+
rescue SystemCallError, NoMethodError
|
45
44
|
STDOUT.puts "The server's not running!"
|
46
45
|
end
|
47
46
|
end
|
@@ -64,7 +63,13 @@ class HubeyeClient
|
|
64
63
|
# The server may send more than one line, so use readpartial
|
65
64
|
# to read whatever it sends (as long as it all arrives in one chunk).
|
66
65
|
|
67
|
-
|
66
|
+
if local =~ /load repo/
|
67
|
+
puts "Loading..."
|
68
|
+
sleep 1
|
69
|
+
else
|
70
|
+
sleep 0.5
|
71
|
+
end
|
72
|
+
|
68
73
|
begin
|
69
74
|
response = @s.readpartial(4096)
|
70
75
|
rescue EOFError
|
data/lib/log/logger.rb
CHANGED
@@ -14,12 +14,11 @@ class Logger
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
|
18
|
-
#
|
19
|
-
#process is not daemonized). Always log to the logfile.
|
17
|
+
# If {include_terminal: true}, log to the terminal too (make sure that the
|
18
|
+
# process is not daemonized). Always log to the logfile.
|
20
19
|
|
21
20
|
def self.log_change(repo_name, commit_msg, committer, options={})
|
22
|
-
opts = {:
|
21
|
+
opts = {:include_terminal => false}.merge options
|
23
22
|
change_msg = <<-MSG
|
24
23
|
===============================
|
25
24
|
Repository: #{repo_name.downcase.strip} has changed (#{Time.now.strftime("%m/%d/%Y at %I:%M%p")})
|
@@ -27,10 +26,6 @@ class Logger
|
|
27
26
|
Committer : #{committer}
|
28
27
|
===============================
|
29
28
|
MSG
|
30
|
-
if opts[:include_socket]
|
31
|
-
socket.puts(change_msg)
|
32
|
-
end
|
33
|
-
|
34
29
|
if opts[:include_terminal]
|
35
30
|
puts change_msg
|
36
31
|
end
|
@@ -8,10 +8,10 @@ module Notification
|
|
8
8
|
elsif RUBY_PLATFORM =~ /linux/
|
9
9
|
libnotify = system('locate libnotify-bin > /dev/null')
|
10
10
|
|
11
|
-
if libnotify &&
|
11
|
+
if libnotify && LibCheck.autotest
|
12
12
|
require_relative "gnomenotify"
|
13
13
|
return "libnotify"
|
14
|
-
elsif
|
14
|
+
elsif LibCheck.autotest_notification
|
15
15
|
require_relative "growl"
|
16
16
|
return "growl"
|
17
17
|
else
|
@@ -20,9 +20,9 @@ module Notification
|
|
20
20
|
|
21
21
|
elsif RUBY_PLATFORM =~ /darwin/i
|
22
22
|
|
23
|
-
if
|
24
|
-
|
25
|
-
|
23
|
+
if LibCheck.autotest_notification
|
24
|
+
require_relative "growl"
|
25
|
+
return "growl"
|
26
26
|
else
|
27
27
|
return
|
28
28
|
end
|
@@ -32,7 +32,7 @@ module Notification
|
|
32
32
|
|
33
33
|
end
|
34
34
|
|
35
|
-
class
|
35
|
+
class LibCheck
|
36
36
|
|
37
37
|
class << self
|
38
38
|
def autotest
|
data/lib/server/hubeye_server.rb
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
module Server
|
2
2
|
# standard lib.
|
3
3
|
require 'socket'
|
4
|
-
require 'open-uri'
|
5
4
|
require 'yaml'
|
6
5
|
|
7
6
|
# vendor
|
8
7
|
begin
|
9
|
-
require '
|
8
|
+
require 'octopi'
|
10
9
|
rescue LoadError
|
11
10
|
if require 'rubygems'
|
12
11
|
retry
|
13
12
|
else
|
14
|
-
abort '
|
13
|
+
abort 'Octopi is needed to run hubeye. Gem install octopi'
|
15
14
|
end
|
16
15
|
end
|
16
|
+
include Octopi
|
17
17
|
|
18
18
|
# hubeye
|
19
19
|
require "config/parser"
|
@@ -32,28 +32,27 @@ module Server
|
|
32
32
|
#
|
33
33
|
# Option overview:
|
34
34
|
#
|
35
|
-
# CONFIG[:oncearound]:
|
35
|
+
# CONFIG[:oncearound]: 60 (seconds) is the default amount of time for looking
|
36
36
|
# for changes in every single repository. If tracking lots of repos,
|
37
37
|
# it might be a good idea to increase the value, or hubeye will cry
|
38
38
|
# due to overwork, fatigue and general anhedonia.
|
39
39
|
#
|
40
|
-
# hubeyerc format
|
40
|
+
# hubeyerc format => oncearound: 1000
|
41
41
|
#
|
42
|
-
# CONFIG[:username] is the username used when not specified
|
42
|
+
# CONFIG[:username] is the username used when not specified.
|
43
|
+
# hubeyerc format => username: 'hansolo'
|
43
44
|
# when set to 'hansolo'
|
44
45
|
# >rails
|
45
46
|
# would track https://www.github.com/hansolo/rails
|
46
47
|
# but a full URI path won't use CONFIG[:username]
|
47
48
|
# >rails/rails
|
48
49
|
# would track https://www.github.com/rails/rails
|
49
|
-
#
|
50
|
-
# hubeyerc format: username: hansolo
|
51
50
|
::Hubeye::Config::Parser.new(CONFIG_FILE) do |c|
|
52
|
-
CONFIG[:username] = c.username || ''
|
51
|
+
CONFIG[:username] = c.username || 'john_doe'
|
53
52
|
CONFIG[:oncearound] = c.oncearound || 60
|
54
53
|
CONFIG[:load_repos] = c.load_repos || []
|
55
54
|
CONFIG[:load_hooks] = c.load_hooks || []
|
56
|
-
CONFIG[:default_track] = c.default_track ||
|
55
|
+
CONFIG[:default_track] = c.default_track || nil
|
57
56
|
# returns true or false if defined in hubeyerc
|
58
57
|
CONFIG[:notification_wanted] = case c.notification_wanted
|
59
58
|
when false
|
@@ -66,7 +65,8 @@ module Server
|
|
66
65
|
end
|
67
66
|
end
|
68
67
|
|
69
|
-
CONFIG[:desktop_notification] = (CONFIG[:notification_wanted] ?
|
68
|
+
CONFIG[:desktop_notification] = (CONFIG[:notification_wanted] ?
|
69
|
+
Notification::Finder.find_notify : nil)
|
70
70
|
|
71
71
|
class InputError < StandardError; end
|
72
72
|
|
@@ -79,7 +79,6 @@ module Server
|
|
79
79
|
get_input(@socket)
|
80
80
|
puts @input if @debug
|
81
81
|
parse_input()
|
82
|
-
get_github_doc("/#{@username}/#{@repo_name}")
|
83
82
|
parse_doc()
|
84
83
|
@username = CONFIG[:username]
|
85
84
|
end
|
@@ -95,14 +94,18 @@ module Server
|
|
95
94
|
def setup_env(options={})
|
96
95
|
@daemonized = options[:daemon]
|
97
96
|
@sockets = [@server] # An array of sockets we'll monitor
|
98
|
-
if CONFIG[:default_track].
|
99
|
-
|
97
|
+
if CONFIG[:default_track].nil?
|
98
|
+
# will be array of 2-element arrays that contain the
|
99
|
+
# tracked repo name [0] and hash of latest sha and latest commit object
|
100
|
+
# for that repo [1]
|
101
|
+
# Example:
|
102
|
+
# [ ['luke-gru/hubeye', {:sha1 => 90j93r0rf389, :commit => <#Commit Object>}], [..., ...] ]
|
100
103
|
@hubeye_tracker = []
|
101
104
|
else
|
102
105
|
# default tracking arrays (hubeyerc configurations)
|
103
106
|
@hubeye_tracker = CONFIG[:default_track]
|
104
|
-
@ary_commits_repos = insert_default_tracking_messages
|
105
107
|
end
|
108
|
+
setup_hubeye_singleton_methods
|
106
109
|
|
107
110
|
if CONFIG[:load_hooks].empty?
|
108
111
|
# do nothing (the hooks hash is only assigned when needed)
|
@@ -125,89 +128,148 @@ module Server
|
|
125
128
|
@remote_connection = false
|
126
129
|
end
|
127
130
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
131
|
+
class ::Array
|
132
|
+
include Octopi
|
133
|
+
class NotTrackerElementError < TypeError ; end
|
134
|
+
|
135
|
+
def extract_old_and_new
|
136
|
+
if length != 2
|
137
|
+
raise NotTrackerElementError.new "#{self} is not a @hubeye_tracker element"
|
138
|
+
else
|
139
|
+
tracked_repo, tracked_sha = self[0], self[1][:sha1]
|
140
|
+
username, repo_name = tracked_repo.split '/'
|
141
|
+
begin
|
142
|
+
gh_user = User.find(username)
|
143
|
+
rescue Octopi::NotFound
|
144
|
+
# fall back to using default username if not found
|
145
|
+
gh_user = @username
|
146
|
+
end
|
147
|
+
begin
|
148
|
+
repo = gh_user.repository repo_name
|
149
|
+
rescue Octopi::NotFound
|
150
|
+
raise
|
151
|
+
end
|
152
|
+
end
|
153
|
+
[tracked_sha, repo]
|
136
154
|
end
|
137
|
-
track_default
|
138
155
|
end
|
139
|
-
private :insert_default_tracking_messages
|
140
156
|
|
157
|
+
def setup_hubeye_singleton_methods
|
158
|
+
def_try_append_or_replace!
|
159
|
+
def_eyeing
|
160
|
+
def_rm_repo
|
161
|
+
end
|
141
162
|
|
142
|
-
def
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
doc.xpath('//div[@class = "message"]/pre').each do |node|
|
154
|
-
commit_msg = node.text
|
155
|
-
if @ary_commits_repos.include?(commit_msg)
|
156
|
-
CONFIG[:oncearound].times do
|
157
|
-
sleep 1
|
158
|
-
@remote_connection = client_ready(@sockets) ? true : false
|
159
|
-
break if @remote_connection
|
160
|
-
end
|
163
|
+
def def_try_append_or_replace!
|
164
|
+
@hubeye_tracker.singleton_class.class_eval do
|
165
|
+
define_method :try_append_or_replace! do |repo_name, new_commit_obj|
|
166
|
+
status = {:replace => nil, :add => nil, :same => true}
|
167
|
+
match = nil
|
168
|
+
map! do |e|
|
169
|
+
if e[0] == repo_name
|
170
|
+
match = true
|
171
|
+
if e[1][:sha1] == new_commit_obj.id
|
172
|
+
e
|
161
173
|
else
|
162
|
-
|
174
|
+
e[1][:sha1] = new_commit_obj.id
|
175
|
+
e[1][:commit] = new_commit_obj
|
176
|
+
status = status.merge :replace => true, :same => false
|
177
|
+
end
|
178
|
+
else
|
179
|
+
e
|
180
|
+
end
|
181
|
+
end # end of map!
|
182
|
+
if match
|
183
|
+
return status
|
184
|
+
else
|
185
|
+
self << [repo_name, {:sha1 => new_commit_obj.id,
|
186
|
+
:commit => new_commit_obj}]
|
187
|
+
return status.merge :add => true, :same => false
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
163
192
|
|
164
|
-
|
165
|
-
|
193
|
+
def def_eyeing
|
194
|
+
@hubeye_tracker.singleton_class.class_eval do
|
195
|
+
define_method :eyeing do
|
196
|
+
(ary = []).tap do
|
197
|
+
each do |e|
|
198
|
+
ary << e[0]
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def def_rm_repo
|
206
|
+
@hubeye_tracker.singleton_class.class_eval do
|
207
|
+
define_method :rm_repo do |repo_name|
|
208
|
+
match = nil
|
209
|
+
reject! do |e|
|
210
|
+
e[0] == repo_name ? match = true : nil
|
211
|
+
end
|
212
|
+
match
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
166
216
|
|
167
|
-
doc.xpath('//div[@class = "actor"]/div[@class = "name"]').each do |node|
|
168
|
-
committer = node.text
|
169
|
-
end
|
170
217
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
change_msg = "Repo #{repo} has changed\nNew commit: #{commit_msg} => #{committer}"
|
175
|
-
case CONFIG[:desktop_notification]
|
176
|
-
when "libnotify"
|
177
|
-
Autotest::GnomeNotify.notify("Hubeye", change_msg)
|
178
|
-
Logger.log_change(repo, commit_msg, committer)
|
179
|
-
when "growl"
|
180
|
-
Autotest::Growl.growl("Hubeye", change_msg)
|
181
|
-
Logger.log_change(repo, commit_msg, committer)
|
182
|
-
when nil
|
183
|
-
|
184
|
-
if @daemonized
|
185
|
-
Logger.log_change(repo, commit_msg, committer)
|
186
|
-
else
|
187
|
-
Logger.log_change(repo, commit_msg, committer, :include_terminal => true)
|
188
|
-
end
|
218
|
+
def not_connected
|
219
|
+
# if no client is connected, but the commits array contains repos
|
220
|
+
if @sockets.size == 1 and !@hubeye_tracker.empty?
|
189
221
|
|
222
|
+
while @remote_connection == false
|
223
|
+
sleep_amt = CONFIG[:oncearound] / @hubeye_tracker.length
|
224
|
+
@hubeye_tracker.each do |ary|
|
225
|
+
# this method does api calls, takes a couple of seconds to
|
226
|
+
# complete right now (TODO: see what's taking so long)
|
227
|
+
start_time = Time.now
|
228
|
+
old_sha, new_repo = ary.extract_old_and_new
|
229
|
+
api_time = (Time.now - start_time).to_i
|
230
|
+
new_commit = new_repo.commits.first
|
231
|
+
if new_commit.id == old_sha
|
232
|
+
(sleep_amt - api_time).times do
|
233
|
+
sleep 1
|
234
|
+
@remote_connection = client_ready(@sockets) ? true : false
|
235
|
+
break if @remote_connection
|
236
|
+
end
|
237
|
+
else
|
238
|
+
# There was a change to a tracked repository.
|
239
|
+
full_repo_name = ary[0]
|
240
|
+
commit_msg = new_commit.message
|
241
|
+
committer = new_commit.author['name']
|
242
|
+
# notify of change to repository
|
243
|
+
# if they have a Desktop notification
|
244
|
+
# library installed
|
245
|
+
change_msg = "Repo #{full_repo_name} has changed\nNew commit: " +
|
246
|
+
"#{commit_msg}\n=> #{committer}"
|
247
|
+
case CONFIG[:desktop_notification]
|
248
|
+
when "libnotify"
|
249
|
+
Autotest::GnomeNotify.notify("Hubeye", change_msg)
|
250
|
+
Logger.log_change(full_repo_name, commit_msg, committer)
|
251
|
+
when "growl"
|
252
|
+
Autotest::Growl.growl("Hubeye", change_msg)
|
253
|
+
Logger.log_change(full_repo_name, commit_msg, committer)
|
254
|
+
when nil
|
255
|
+
if @daemonized
|
256
|
+
Logger.log_change(full_repo_name, commit_msg, committer)
|
257
|
+
else
|
258
|
+
Logger.log_change(full_repo_name, commit_msg, committer, :include_terminal => true)
|
190
259
|
end
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
260
|
+
end
|
261
|
+
# execute any hooks for that repository
|
262
|
+
unless @hook_cmds.nil? || @hook_cmds.empty?
|
263
|
+
if @hook_cmds[full_repo_name]
|
264
|
+
hook_cmds = @hook_cmds[full_repo_name].dup
|
265
|
+
dir = (hook_cmds.include?('/') ? hook_cmds.shift : nil)
|
266
|
+
|
267
|
+
# execute() takes [commands], {options} where
|
268
|
+
# options = :directory and :repo
|
269
|
+
Hooks::Command.execute(hook_cmds, :directory => dir, :repo => repo)
|
201
270
|
end
|
202
|
-
|
203
|
-
@ary_commits_repos << repo
|
204
|
-
@ary_commits_repos << commit_msg
|
205
|
-
# delete the repo and old commit that appear first in the array
|
206
|
-
index_old_HEAD = @ary_commits_repos.index(repo)
|
207
|
-
@ary_commits_repos.delete_at(index_old_HEAD)
|
208
|
-
# and again to get rid of the commit message
|
209
|
-
@ary_commits_repos.delete_at(index_old_HEAD)
|
210
271
|
end
|
272
|
+
@hubeye_tracker.try_append_or_replace!(full_repo_name, new_commit)
|
211
273
|
end
|
212
274
|
end
|
213
275
|
redo unless @remote_connection
|
@@ -232,10 +294,11 @@ module Server
|
|
232
294
|
@socket = client # From here on in referred to as @socket
|
233
295
|
sockets << @socket # Add it to the set of sockets
|
234
296
|
# Inform the client of connection
|
297
|
+
basic_inform = "Hubeye running on #{Socket.gethostname} as #{@username}"
|
235
298
|
if !@hubeye_tracker.empty?
|
236
|
-
@socket.puts "
|
299
|
+
@socket.puts "#{basic_inform}\nTracking:#{@hubeye_tracker.eyeing.join ', '}"
|
237
300
|
else
|
238
|
-
@socket.puts
|
301
|
+
@socket.puts basic_inform
|
239
302
|
end
|
240
303
|
|
241
304
|
if !@daemonized
|
@@ -298,11 +361,8 @@ module Server
|
|
298
361
|
@socket.puts("Bye!") # Say goodbye
|
299
362
|
Logger.log "Closing connection to #{@socket.peeraddr[2]}"
|
300
363
|
@remote_connection = false
|
301
|
-
if !@
|
302
|
-
Logger.log "Tracking: "
|
303
|
-
@ary_commits_repos.each do |repo|
|
304
|
-
Logger.log repo if @ary_commits_repos.index(repo).even?
|
305
|
-
end
|
364
|
+
if !@hubeye_tracker.empty?
|
365
|
+
Logger.log "Tracking: #{@hubeye_tracker.eyeing.join ', '}"
|
306
366
|
end
|
307
367
|
Logger.log "" # to look pretty when multiple connections per loop
|
308
368
|
@sockets.delete(@socket) # Stop monitoring the socket
|
@@ -328,7 +388,7 @@ module Server
|
|
328
388
|
else
|
329
389
|
return
|
330
390
|
end
|
331
|
-
shutdown
|
391
|
+
shutdown
|
332
392
|
end
|
333
393
|
|
334
394
|
|
@@ -341,14 +401,13 @@ module Server
|
|
341
401
|
|
342
402
|
def parse_hook
|
343
403
|
if %r{hook add} =~ @input
|
344
|
-
hook_add
|
404
|
+
hook_add
|
345
405
|
else
|
346
406
|
return
|
347
407
|
end
|
348
408
|
end
|
349
409
|
|
350
410
|
|
351
|
-
##
|
352
411
|
# @hook_cmds:
|
353
412
|
# repo is the key, value is array of directory and commands. First element
|
354
413
|
# of array is the local directory for that remote repo, rest are commands
|
@@ -390,7 +449,7 @@ module Server
|
|
390
449
|
elsif @input =~ %r{\A\s*save repo(s?) as (.+)\Z}
|
391
450
|
if !@hubeye_tracker.empty?
|
392
451
|
File.open("#{ENV['HOME']}/.hubeye/repos/#{$2}.yml", "w") do |f_out|
|
393
|
-
::YAML.dump(@hubeye_tracker, f_out)
|
452
|
+
::YAML.dump(@hubeye_tracker.eyeing, f_out)
|
394
453
|
end
|
395
454
|
@socket.puts("Saved repo#{$1} as #{$2}")
|
396
455
|
else
|
@@ -452,20 +511,15 @@ module Server
|
|
452
511
|
end
|
453
512
|
# newrepos is an array of repos to be tracked
|
454
513
|
newrepos.each do |e|
|
455
|
-
# append the repo and the
|
456
|
-
#
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
@
|
462
|
-
# and append the repo to the hubeye_tracker array
|
463
|
-
@hubeye_tracker << e
|
514
|
+
# append the repo name and the commit hash to the hubeye tracker
|
515
|
+
# array, then inform the client of the newest commit message
|
516
|
+
username, repo = e.split '/'
|
517
|
+
gh_user = User.find(username)
|
518
|
+
gh_repo = gh_user.repository repo
|
519
|
+
new_commit = gh_repo.commits.first
|
520
|
+
@hubeye_tracker.try_append_or_replace!(e, new_commit)
|
464
521
|
end
|
465
|
-
@
|
466
|
-
@hubeye_tracker.uniq!
|
467
|
-
|
468
|
-
@socket.puts "Loaded #{$2}.\nTracking:\n#{show_repos_pretty()}"
|
522
|
+
@socket.puts "Loaded #{$2}.\nTracking:\n#{@hubeye_tracker.eyeing.join ', '}"
|
469
523
|
else
|
470
524
|
# no repo file with that name
|
471
525
|
@socket.puts("No file to load from")
|
@@ -522,46 +576,18 @@ module Server
|
|
522
576
|
end # end of input#each
|
523
577
|
# flatten the newrepos array because it contains arrays
|
524
578
|
newrepos.flatten!
|
525
|
-
newrepos.each do |
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
579
|
+
newrepos.each do |e|
|
580
|
+
username, repo = e.split '/'
|
581
|
+
gh_user = User.find(username)
|
582
|
+
gh_repo = gh_user.repository repo
|
583
|
+
new_commit = gh_repo.commits.first
|
584
|
+
@hubeye_tracker.try_append_or_replace!(e, new_commit)
|
530
585
|
end
|
531
|
-
@ary_commits_repos.uniq!
|
532
|
-
@hubeye_tracker.uniq!
|
533
586
|
else
|
534
587
|
raise ArgumentError.new "#{input} must be array-like"
|
535
588
|
end
|
536
589
|
end
|
537
590
|
|
538
|
-
|
539
|
-
# helper method to get commit message for a
|
540
|
-
# single repo
|
541
|
-
def get_commit_msg(remote_repo)
|
542
|
-
begin
|
543
|
-
@doc = Nokogiri::HTML(open("https://github.com#{'/' + remote_repo}"))
|
544
|
-
rescue
|
545
|
-
return nil
|
546
|
-
end
|
547
|
-
# returns the commit message
|
548
|
-
commit_msg = parse_msg(@doc)
|
549
|
-
end
|
550
|
-
|
551
|
-
|
552
|
-
def show_repos_pretty
|
553
|
-
pretty_repos = ""
|
554
|
-
@ary_commits_repos.each do |e|
|
555
|
-
if @ary_commits_repos.index(e).even?
|
556
|
-
pretty_repos += e + "\n"
|
557
|
-
else
|
558
|
-
pretty_repos += " " + e + "\n"
|
559
|
-
end
|
560
|
-
end
|
561
|
-
pretty_repos
|
562
|
-
end
|
563
|
-
|
564
|
-
|
565
591
|
def hook_list
|
566
592
|
if @input =~ %r{hook list}
|
567
593
|
unless @hook_cmds.nil? || @hook_cmds.empty?
|
@@ -597,7 +623,7 @@ remote: #{remote}
|
|
597
623
|
# they're tracking
|
598
624
|
def tracking_list
|
599
625
|
if @input =~ /\Atracking\s*\Z/
|
600
|
-
list =
|
626
|
+
list = @hubeye_tracker.eyeing.join ', '
|
601
627
|
@socket.puts(list)
|
602
628
|
throw(:next)
|
603
629
|
else
|
@@ -648,24 +674,13 @@ remote: #{remote}
|
|
648
674
|
else
|
649
675
|
@username, @repo_name = "#{@username}/#{$1}".split('/')
|
650
676
|
end
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
end
|
659
|
-
@hubeye_tracker.delete("#{@username}/#{@repo_name}")
|
660
|
-
@socket.puts("Stopped watching repository #{@username}/#{@repo_name}")
|
661
|
-
sleep 0.5
|
662
|
-
throw(:next)
|
663
|
-
else
|
664
|
-
@socket.puts("Repository #{@username}/#{@repo_name} not currently being watched")
|
665
|
-
throw(:next)
|
666
|
-
end
|
667
|
-
rescue
|
668
|
-
@socket.puts($!)
|
677
|
+
rm = @hubeye_tracker.rm_repo("#{@username}/#{@repo_name}")
|
678
|
+
if rm
|
679
|
+
@socket.puts("Stopped watching repository #{@username}/#{@repo_name}")
|
680
|
+
sleep 0.5
|
681
|
+
throw(:next)
|
682
|
+
else
|
683
|
+
@socket.puts("Repository #{@username}/#{@repo_name} not currently being watched")
|
669
684
|
throw(:next)
|
670
685
|
end
|
671
686
|
else
|
@@ -690,84 +705,49 @@ remote: #{remote}
|
|
690
705
|
@repo_name = @input
|
691
706
|
end
|
692
707
|
|
693
|
-
|
694
|
-
def get_github_doc(full_repo_path)
|
695
|
-
begin
|
696
|
-
# if adding a repo with another username
|
697
|
-
@doc = Nokogiri::HTML(open("https://github.com#{full_repo_path}"))
|
698
|
-
rescue OpenURI::HTTPError
|
699
|
-
@socket.puts("Not a Github repository!")
|
700
|
-
throw(:next)
|
701
|
-
rescue URI::InvalidURIError
|
702
|
-
@socket.puts("Not a valid URI")
|
703
|
-
throw(:next)
|
704
|
-
end
|
705
|
-
end
|
706
|
-
|
707
|
-
|
708
708
|
def parse_doc
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
709
|
+
@full_repo_name = "#{@username}/#{@repo_name}"
|
710
|
+
begin
|
711
|
+
gh_user = User.find(@username)
|
712
|
+
gh_repo = gh_user.repository @repo_name
|
713
|
+
rescue ArgumentError, Octopi::NotFound
|
714
|
+
#Octopi library's User.find ArgumentError
|
715
|
+
@socket.puts "Not a Github repository name"
|
716
|
+
throw :next
|
717
|
+
end
|
718
|
+
new_commit = gh_repo.commits.first
|
719
|
+
change_status = @hubeye_tracker.try_append_or_replace!(@full_repo_name, new_commit)
|
720
|
+
# get commit info
|
721
|
+
commit_msg = new_commit.message
|
722
|
+
committer = new_commit.author['name']
|
723
|
+
url = "https://www.github.com#{new_commit.url[0..-30]}"
|
724
|
+
msg = "#{commit_msg}\n=> #{committer}"
|
714
725
|
# new repo to track
|
715
|
-
|
716
|
-
if !@ary_commits_repos.include?(full_repo_name)
|
717
|
-
@ary_commits_repos << full_repo_name
|
718
|
-
@hubeye_tracker << full_repo_name
|
719
|
-
@ary_commits_repos << @commit_msg
|
720
|
-
# get commit info
|
721
|
-
@info = parse_info()
|
722
|
-
@msg = "#{@commit_msg} => #{@committer}".gsub(/\(author\)/, '')
|
726
|
+
if change_status[:add]
|
723
727
|
# log the fact that the user added a repo to be tracked
|
724
|
-
Logger.log("Added to tracker: #{@
|
728
|
+
Logger.log("Added to tracker: #{@full_repo_name} (#{NOW})")
|
725
729
|
# show the user, via the client, the info and commit msg for the commit
|
726
|
-
@socket.puts("#{
|
730
|
+
@socket.puts("#{msg}\n#{url}")
|
727
731
|
|
728
732
|
# new commit to tracked repo
|
729
|
-
elsif
|
733
|
+
elsif change_status[:replace]
|
734
|
+
change_msg = "New commit on #{@full_repo_name}\n"
|
735
|
+
change_msg << "#{msg}\n#{url}"
|
736
|
+
@socket.puts(change_msg)
|
730
737
|
begin
|
731
|
-
index_of_msg = @ary_commits_repos.index(@username + "/" + @repo_name) + 1
|
732
|
-
@ary_commits_repos.delete_at(index_of_msg)
|
733
|
-
@ary_commits_repos.insert(index_of_msg - 1, @commit_msg)
|
734
|
-
|
735
738
|
# log to the logfile and tell the client
|
736
739
|
if @daemonized
|
737
|
-
Logger.log_change(@
|
738
|
-
:include_socket => true)
|
740
|
+
Logger.log_change(@full_repo_name, commit_msg, committer)
|
739
741
|
else
|
740
|
-
Logger.log_change(@
|
741
|
-
:
|
742
|
+
Logger.log_change(@full_repo_name, commit_msg, committer,
|
743
|
+
:include_terminal => true)
|
742
744
|
end
|
743
745
|
rescue
|
744
|
-
|
746
|
+
throw :next
|
745
747
|
end
|
746
748
|
else
|
747
749
|
# no change to the tracked repo
|
748
|
-
@socket.puts("Repository #{@
|
749
|
-
end
|
750
|
-
end
|
751
|
-
|
752
|
-
|
753
|
-
def parse_msg(html_doc)
|
754
|
-
# get commit msg
|
755
|
-
html_doc.xpath('//div[@class = "message"]/pre').each do |node|
|
756
|
-
return commit_msg = node.text
|
757
|
-
end
|
758
|
-
end
|
759
|
-
|
760
|
-
|
761
|
-
def parse_committer
|
762
|
-
@doc.xpath('//div[@class = "actor"]/div[@class = "name"]').each do |node|
|
763
|
-
return committer = node.text
|
764
|
-
end
|
765
|
-
end
|
766
|
-
|
767
|
-
|
768
|
-
def parse_info
|
769
|
-
@doc.xpath('//div[@class = "machine"]').each do |node|
|
770
|
-
return info = node.text.gsub(/\n/, '').gsub(/tree/, "\ntree").gsub(/parent.*?(\w)/, "\nparent \\1").strip!
|
750
|
+
@socket.puts("Repository #{@full_repo_name} has not changed")
|
771
751
|
end
|
772
752
|
end
|
773
753
|
|
@@ -776,7 +756,7 @@ end # of Server module
|
|
776
756
|
class HubeyeServer
|
777
757
|
include Server
|
778
758
|
|
779
|
-
def initialize(debug=
|
759
|
+
def initialize(debug=true)
|
780
760
|
@debug = debug
|
781
761
|
end
|
782
762
|
|
data/test/runner.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
# environment file
|
4
|
-
require File.join(File.dirname(__FILE__), "
|
4
|
+
require File.join(File.expand_path(File.dirname(__FILE__) + '/..'), "lib/environment")
|
5
5
|
|
6
6
|
# test/unit
|
7
7
|
require 'test/unit'
|
8
8
|
|
9
9
|
# test files
|
10
10
|
require_relative 'environment'
|
11
|
-
require File.join(File.dirname(__FILE__), "
|
11
|
+
require File.join(File.expand_path(File.dirname(__FILE__) + '/..'), "lib/notification/notification")
|
12
12
|
require_relative "notification"
|
13
13
|
require Environment::LIBDIR + '/config/parser'
|
14
14
|
require_relative "config_parser"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hubeye
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-10-04 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
16
|
-
requirement: &
|
15
|
+
name: octopi
|
16
|
+
requirement: &86576300 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *86576300
|
25
25
|
description: Github repository commit watcher -- keep your eye on new commits from
|
26
26
|
multiple repos through an interactive CLI
|
27
27
|
email: luke.gru@gmail.com
|
@@ -42,7 +42,7 @@ files:
|
|
42
42
|
- lib/environment.rb
|
43
43
|
- lib/helpers/time.rb
|
44
44
|
- bin/hubeye
|
45
|
-
-
|
45
|
+
- Rakefile
|
46
46
|
- README.md
|
47
47
|
- VERSION.rb
|
48
48
|
- LICENSE
|
data/README.md.html
DELETED
@@ -1,212 +0,0 @@
|
|
1
|
-
<h1>Hubeye</h1>
|
2
|
-
|
3
|
-
<p><br />
|
4
|
-
Keep track of repositories on Github, get notified when they change and<br />
|
5
|
-
(optionally) run local system commands when new commits come in to Github.<br />
|
6
|
-
<br /></p>
|
7
|
-
|
8
|
-
<p>Hubeye is composed of a client and server. Once the server is run,<br />
|
9
|
-
you can connect to it via the client. Once connected, you'll be<br />
|
10
|
-
prompted by a '>'. Type the name of a Github repository.</p>
|
11
|
-
|
12
|
-
<p>Example: (what the user enters is preceded by the prompt)</p>
|
13
|
-
|
14
|
-
<pre><code>>hubeye
|
15
|
-
commit 77b82b54044c16751228
|
16
|
-
tree 8ce18af1461b5c741003
|
17
|
-
parent ea63fe317fe58dff1c95
|
18
|
-
log tracking info for repos on client quit => luke-gru
|
19
|
-
</code></pre>
|
20
|
-
|
21
|
-
<p>What you see is the latest commit reference, tree reference and parent<br />
|
22
|
-
commit reference on Github for that repository. Note that the user did<br />
|
23
|
-
not type a username. This is because the user defined a username in his<br />
|
24
|
-
~/.hubeye/hubeyerc file.</p>
|
25
|
-
|
26
|
-
<h2>Starting Hubeye</h2>
|
27
|
-
|
28
|
-
<p>To start the server:</p>
|
29
|
-
|
30
|
-
<pre><code>>hubeye -s
|
31
|
-
</code></pre>
|
32
|
-
|
33
|
-
<p>or just</p>
|
34
|
-
|
35
|
-
<pre><code>>hubeye
|
36
|
-
</code></pre>
|
37
|
-
|
38
|
-
<p>This starts the server as a daemonized process. To run the server in<br />
|
39
|
-
your terminal (on <b>t</b>op):</p>
|
40
|
-
|
41
|
-
<pre><code>>hubeye -st
|
42
|
-
</code></pre>
|
43
|
-
|
44
|
-
<p>Hubeye runs on port 2000 be default. Change the port like this:</p>
|
45
|
-
|
46
|
-
<pre><code>>hubeye -sp 9001
|
47
|
-
</code></pre>
|
48
|
-
|
49
|
-
<p>To connect with the client:</p>
|
50
|
-
|
51
|
-
<pre><code>>hubeye -c
|
52
|
-
</code></pre>
|
53
|
-
|
54
|
-
<p>For more options:</p>
|
55
|
-
|
56
|
-
<pre><code>>hubeye -h
|
57
|
-
</code></pre>
|
58
|
-
|
59
|
-
<h3>~/.hubeye/hubeyerc</h3>
|
60
|
-
|
61
|
-
<pre><code>username: luke-gru
|
62
|
-
</code></pre>
|
63
|
-
|
64
|
-
<p>This allows the user to type a repository name only, and to receive<br />
|
65
|
-
information regarding that <i>username</i>'s repository. The username<br />
|
66
|
-
should be a valid Github username.</p>
|
67
|
-
|
68
|
-
<h3>Keeping track of repositories</h3>
|
69
|
-
|
70
|
-
<p>Hubeye doesn't actually track any repositories unless you disconnect<br />
|
71
|
-
from the server and leave the server running. This can be done by:</p>
|
72
|
-
|
73
|
-
<pre><code>>quit
|
74
|
-
Bye!
|
75
|
-
</code></pre>
|
76
|
-
|
77
|
-
<p>If Hubeye has any repos to watch (track), it will watch Github for changes.<br />
|
78
|
-
It can keep track of as many repos as you want; just keep typing<br />
|
79
|
-
them in. If Hubeye finds a change to a repo, it will notify you of the<br />
|
80
|
-
changes using your Desktop notification system (libnotify, growl). It will<br />
|
81
|
-
also log the changes to your $HOME/.hubeye/log file. If the server is run<br />
|
82
|
-
in a terminal (-t option), the changes will also be logged to the terminal.<br
|
83
|
-
/></p>
|
84
|
-
|
85
|
-
<p>To track your own repository, start the client in the root directory<br />
|
86
|
-
of your local git repo:</p>
|
87
|
-
|
88
|
-
<pre><code>>.
|
89
|
-
</code></pre>
|
90
|
-
|
91
|
-
<p>This only works if a <i>username</i> is added to the hubeyerc, and if the<br />
|
92
|
-
Github repository name is the same as the local root directory name.<br />
|
93
|
-
ie: '.' put in '/home/luke/code/hubeye' would track https://www.github.com/
|
94
|
-
luke-gru/hubeye<br />
|
95
|
-
if <i>username</i> was set to luke-gru.<br /></p>
|
96
|
-
|
97
|
-
<p>You can add another user's repo like this:</p>
|
98
|
-
|
99
|
-
<pre><code>>rails/rails
|
100
|
-
</code></pre>
|
101
|
-
|
102
|
-
<p>This adds https://github.com/rails/rails to the watch list.<br />
|
103
|
-
Hubeye does not remove a repo from the watch list unless explicitly<br />
|
104
|
-
told to do so:</p>
|
105
|
-
|
106
|
-
<pre><code>>rm luke-gru/hubeye
|
107
|
-
</code></pre>
|
108
|
-
|
109
|
-
<p>To see a list of all repos (with recent commit messages) in the watch (track) list:</p>
|
110
|
-
|
111
|
-
<pre><code>>tracking
|
112
|
-
</code></pre>
|
113
|
-
|
114
|
-
<h3>Desktop Notification</h3>
|
115
|
-
|
116
|
-
<p><i>On Linux: install libnotify-bin. On Mac: install growl (if not already installed).<br />
|
117
|
-
The autotest gem is needed for Desktop notification to work in both
|
118
|
-
cases.</i><br /></p>
|
119
|
-
|
120
|
-
<h3>Shutting down and persistence between sessions</h3>
|
121
|
-
|
122
|
-
<pre><code>>shutdown
|
123
|
-
</code></pre>
|
124
|
-
|
125
|
-
<p>Next time you start up the server, the watch list will be empty<br />
|
126
|
-
(and so will the log file). In order to have a default watch list:</p>
|
127
|
-
|
128
|
-
<p><i>~/.hubeye/hubeyerc</i></p>
|
129
|
-
|
130
|
-
<pre><code>track: rails/rails, dchelimsky/rspec
|
131
|
-
</code></pre>
|
132
|
-
|
133
|
-
<p>These will be watched automatically when starting up the server.<br /></p>
|
134
|
-
|
135
|
-
<p>A way to interactively save all currently tracked repositories:</p>
|
136
|
-
|
137
|
-
<pre><code>>save repos as my_work_repos
|
138
|
-
</code></pre>
|
139
|
-
|
140
|
-
<p>And then load any time (even after a shutdown; next session, next week, etc...)</p>
|
141
|
-
|
142
|
-
<pre><code>>load repos my_work_repos
|
143
|
-
</code></pre>
|
144
|
-
|
145
|
-
<h3>Working with hooks</h3>
|
146
|
-
|
147
|
-
<pre><code>>hook add rails/rails dir: /path/to/local/rails cmd: git pull origin master
|
148
|
-
</code></pre>
|
149
|
-
|
150
|
-
<p>When <b>https://www.github.com/rails/rails</b> changes, a process will start,
|
151
|
-
<br />
|
152
|
-
change to the selected directory and execute the command. The <i>(dir: /my/dir)
|
153
|
-
<br />
|
154
|
-
</i> part is optional, and when ignored won't change directories. In this
|
155
|
-
case,
|
156
|
-
<br />
|
157
|
-
the directory will be where the hubeye server was originally
|
158
|
-
started from.<br /></p>
|
159
|
-
|
160
|
-
<p>To see all currently loaded hooks:</p>
|
161
|
-
|
162
|
-
<pre><code>>hook list
|
163
|
-
</code></pre>
|
164
|
-
|
165
|
-
<p>To save all hooks for next sessions (after a server shutdown)</p>
|
166
|
-
|
167
|
-
<pre><code>>save hooks as weekend_projects_hooks
|
168
|
-
</code></pre>
|
169
|
-
|
170
|
-
<p>Then, next weekend:</p>
|
171
|
-
|
172
|
-
<pre><code>>load hooks weekend_projects_hooks
|
173
|
-
</code></pre>
|
174
|
-
|
175
|
-
<p>These hooks, of course, will only really do anything if the repositories they
|
176
|
-
<br />
|
177
|
-
are hooked to are currently being watched. This is not done automatically.</p>
|
178
|
-
|
179
|
-
<h3>All ~/.hubeyerc configurations</h3>
|
180
|
-
|
181
|
-
<p>When the server is started, the options are set here.</p>
|
182
|
-
|
183
|
-
<pre><code>username: luke-gru
|
184
|
-
track: username/reponame, username2/reponame2, myreponame
|
185
|
-
oncearound = 90
|
186
|
-
load hooks: myhook1, myworkhooks
|
187
|
-
load repos: workprojects, funprojects
|
188
|
-
desktop notification: on/off
|
189
|
-
</code></pre>
|
190
|
-
|
191
|
-
<p><i>username</i>: username used for Github URLS when the full path is not
|
192
|
-
given<br />
|
193
|
-
inside of the client.<br /></p>
|
194
|
-
|
195
|
-
<p><i>track</i>: default repositories to watch for changes upon server start<br /></p>
|
196
|
-
|
197
|
-
<p><i>oncearound</i>: number of seconds before completing a check of every repo in<br />
|
198
|
-
the watch list for changes<br /></p>
|
199
|
-
|
200
|
-
<p><i>load hooks</i>: load hooks on server start. To see how to save hooks in the
|
201
|
-
<br />
|
202
|
-
client, see the <i>Working with hooks</i> section<br /></p>
|
203
|
-
|
204
|
-
<p><i>load repos</i>: load repos on server start. To see how to save repos in the
|
205
|
-
<br />
|
206
|
-
client, see the <i>Shutting down and persistence between sessions</i> section.
|
207
|
-
<br /></p>
|
208
|
-
|
209
|
-
<p><i>desktop notification</i>: whether to notify of repo changes using libnotify
|
210
|
-
<br />
|
211
|
-
or growl. This is set to <i>on</i> by default. However, if no notification<br />
|
212
|
-
system is found, it is ignored.</p>
|