Mange-git-remote-monitor 0.1.1 → 0.1.2
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.
- data/HISTORY.markdown +26 -0
- data/Rakefile +4 -1
- data/TODO +10 -9
- data/VERSION.yml +1 -1
- data/bin/git-remote-monitor +62 -12
- data/lib/git_remote_monitor.rb +6 -2
- data/lib/git_remote_monitor/git_wrapper.rb +32 -1
- data/lib/git_remote_monitor/monitor.rb +17 -7
- data/lib/git_remote_monitor/notifier.rb +11 -32
- data/lib/git_remote_monitor/notifiers.rb +52 -0
- data/lib/git_remote_monitor/notifiers/base.rb +38 -0
- data/lib/git_remote_monitor/notifiers/meow.rb +72 -0
- data/lib/git_remote_monitor/status.rb +58 -0
- data/spec/git_remote_monitor/git_wrapper_spec.rb +116 -14
- data/spec/git_remote_monitor/monitor_spec.rb +138 -0
- data/spec/git_remote_monitor/notifier_spec.rb +46 -0
- data/spec/git_remote_monitor/notifiers/base_spec.rb +49 -0
- data/spec/git_remote_monitor/notifiers/meow_spec.rb +113 -0
- data/spec/git_remote_monitor/notifiers_spec.rb +54 -0
- data/spec/git_remote_monitor/status_spec.rb +57 -0
- data/spec/git_remote_monitor_spec.rb +37 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +28 -4
- metadata +18 -3
- data/HISTORY +0 -15
data/HISTORY.markdown
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
VERSION 0.1.2
|
2
|
+
=============
|
3
|
+
Major refactoring for upcoming beta. A few bug fixes, too.
|
4
|
+
|
5
|
+
* Added note type to Meow for more client customization.
|
6
|
+
* Refactored the notification system into a plug-in based system.
|
7
|
+
It will be much easier to test and extend this, and getting it to work with new notification systems on
|
8
|
+
other platforms is going to be a piece of cake from now on.
|
9
|
+
* New options for executable: --list-plugins, --version
|
10
|
+
* You can now specify a DIR for the monitor executable
|
11
|
+
* BUG: Human-readable error when trying to fetch in a repo without remotes
|
12
|
+
* BUG: Error out when entering a directory which is not part of a repository
|
13
|
+
|
14
|
+
VERSION 0.1.1
|
15
|
+
=============
|
16
|
+
Quick patch release to fix serious error in the gem creation.
|
17
|
+
|
18
|
+
* BUG: Only the executable was built into the gem
|
19
|
+
* BUG: The executable did not try to load the lib when running gem executable
|
20
|
+
|
21
|
+
VERSION 0.1.0
|
22
|
+
=============
|
23
|
+
* Basic support for notifications
|
24
|
+
* Basic fetch wrapper to git
|
25
|
+
* Basic monitor, waiting 20 seconds between each fetch
|
26
|
+
* Simple comparing remotes with local possible
|
data/Rakefile
CHANGED
@@ -26,12 +26,15 @@ end
|
|
26
26
|
|
27
27
|
Spec::Rake::SpecTask.new do |t|
|
28
28
|
t.libs << 'lib'
|
29
|
+
t.spec_files = FileList['spec/**/*.rb']
|
29
30
|
t.verbose = false
|
30
31
|
t.rcov = false
|
31
32
|
end
|
32
33
|
|
33
34
|
Spec::Rake::SpecTask.new('rcov') do |t|
|
34
35
|
t.libs << 'lib'
|
36
|
+
t.spec_files = FileList['spec/**/*.rb']
|
37
|
+
t.rcov_opts = ['--exclude', 'spec,rcov']
|
35
38
|
t.verbose = false
|
36
39
|
t.rcov = true
|
37
40
|
end
|
@@ -44,4 +47,4 @@ Rake::RDocTask.new do |rdoc|
|
|
44
47
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
45
48
|
end
|
46
49
|
|
47
|
-
task :default => :
|
50
|
+
task :default => :spec
|
data/TODO
CHANGED
@@ -2,22 +2,23 @@ TODO
|
|
2
2
|
====
|
3
3
|
|
4
4
|
Before beta:
|
5
|
-
*
|
6
|
-
|
7
|
-
* Command line arguments
|
8
|
-
* Specify a project name
|
9
|
-
* Specify path
|
10
|
-
* Specify fetch interval
|
5
|
+
* Command line arguments
|
6
|
+
* Specify a project name
|
11
7
|
* Daemonize the program
|
12
8
|
* Look at real Git libraries; might be better than calling the system
|
13
|
-
|
9
|
+
|
14
10
|
Before 1.0:
|
15
11
|
* Read/Save configuration with git-config(1)
|
16
12
|
* Make it easy to quit the daemons (git-remote-monitor --kill-all, or similar)
|
17
|
-
|
13
|
+
|
18
14
|
Before 1.1:
|
19
15
|
* Extend to more notification systems than Meow (Growl on Mac OS X)
|
20
16
|
* knotify
|
21
17
|
* Whatever Gnome uses
|
22
18
|
* Windows possible?
|
23
|
-
*
|
19
|
+
* Email?
|
20
|
+
* HTTP request to a URL?
|
21
|
+
* Run generic command?
|
22
|
+
* XMPP? Too crazy?
|
23
|
+
* Let notification plugins have configuration settings
|
24
|
+
* Project name/Notifier plugin structure. Have a wildcard project for default settings.
|
data/VERSION.yml
CHANGED
data/bin/git-remote-monitor
CHANGED
@@ -26,9 +26,9 @@
|
|
26
26
|
#
|
27
27
|
|
28
28
|
# Add ../lib/ as a load path in case we are doing development
|
29
|
-
$LOAD_PATH
|
29
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
30
30
|
|
31
|
-
REQUIRED_GEMS = ['rubygems'
|
31
|
+
REQUIRED_GEMS = ['rubygems']
|
32
32
|
begin
|
33
33
|
REQUIRED_GEMS.each { |g| require g }
|
34
34
|
rescue LoadError => e
|
@@ -45,19 +45,27 @@ require 'rdoc/usage'
|
|
45
45
|
|
46
46
|
$usage = %Q{
|
47
47
|
= Synopsis
|
48
|
-
Monitors the current branch
|
49
|
-
notified about
|
48
|
+
Monitors the HEAD's (current branch) remote for changes at a fixed interval. Changes will be fetched
|
49
|
+
and you will be notified about them in any notification system you specify.
|
50
50
|
|
51
51
|
= Usage
|
52
|
-
git remote-monitor [OPTIONS]
|
52
|
+
git remote-monitor [OPTIONS] [DIR]
|
53
|
+
|
54
|
+
When no DIR is specified, current working directory will be used.
|
53
55
|
|
54
56
|
== Options
|
55
57
|
-h, --help:
|
56
58
|
displays this usage information
|
57
59
|
|
60
|
+
-V, --version:
|
61
|
+
displays version information
|
62
|
+
|
58
63
|
-i TIME, --interval=TIME:
|
59
64
|
time, in seconds, between each fetch. Defaults to 60 seconds.
|
60
65
|
|
66
|
+
-p, --list-plugins:
|
67
|
+
list all notification plugins and show which ones are active on your system, then quit.
|
68
|
+
|
61
69
|
== Daemon
|
62
70
|
Since this utility is in an early stage, no daemon capabilities have yet been added. It is recommended that
|
63
71
|
you start the command in the background (append a single & to the end of the command line) so you can keep
|
@@ -71,7 +79,7 @@ using your term to other things while the program is running.
|
|
71
79
|
# RubyGems will call this from a wrapper, and #usage is hardcoded to look
|
72
80
|
# at the top-level file instead of the current one. I have changed this
|
73
81
|
# code to instead just parse a string.
|
74
|
-
def
|
82
|
+
def usage_information
|
75
83
|
markup = SM::SimpleMarkup.new
|
76
84
|
flow_convertor = SM::ToFlow.new
|
77
85
|
|
@@ -80,8 +88,33 @@ def usage_and_exit!
|
|
80
88
|
options = RI::Options.instance
|
81
89
|
formatter = options.formatter.new(options, "")
|
82
90
|
formatter.display_flow(flow)
|
91
|
+
end
|
92
|
+
|
93
|
+
def version_information
|
94
|
+
require 'yaml'
|
95
|
+
version = YAML::load_file(File.join(GitRemoteMonitor.root, 'VERSION.yml'))
|
96
|
+
stability = (version[:minor] % 2 == 0) ? "stable" : "unstable"
|
97
|
+
puts "#{File.basename($0)} version #{version[:major]}.#{version[:minor]}.#{version[:patch]} (#{stability})"
|
98
|
+
puts "Run in ruby #{RUBY_VERSION} (#{RUBY_PLATFORM}) released #{RUBY_RELEASE_DATE}, patchlevel #{RUBY_PATCHLEVEL}"
|
99
|
+
end
|
100
|
+
|
101
|
+
def list_plugins
|
102
|
+
loaded = GitRemoteMonitor::Notifiers.notifier_plugins
|
103
|
+
available = GitRemoteMonitor::Notifiers.available_notifiers
|
104
|
+
preferred = GitRemoteMonitor::Notifiers.preferred_notifier
|
83
105
|
|
84
|
-
|
106
|
+
puts "Plugins currently in this version of git-remote-monitor:"
|
107
|
+
loaded.each do |plugin|
|
108
|
+
status = if plugin == preferred
|
109
|
+
" (Available, Active)"
|
110
|
+
elsif available.include?(plugin)
|
111
|
+
" (Available)"
|
112
|
+
else
|
113
|
+
""
|
114
|
+
end
|
115
|
+
plugin_name = plugin.to_s.sub(/^.*::/, '')
|
116
|
+
puts "\t* #{plugin_name}#{status}"
|
117
|
+
end
|
85
118
|
end
|
86
119
|
|
87
120
|
#
|
@@ -89,14 +122,23 @@ end
|
|
89
122
|
#
|
90
123
|
def parse_command_line_arguments!
|
91
124
|
opts = GetoptLong.new(
|
92
|
-
[ '--help',
|
93
|
-
[ '--
|
125
|
+
[ '--help', '-h', GetoptLong::NO_ARGUMENT ],
|
126
|
+
[ '--version', '-V', GetoptLong::NO_ARGUMENT ],
|
127
|
+
[ '--list-plugins', '-p', GetoptLong::NO_ARGUMENT ],
|
128
|
+
[ '--interval', '-i', GetoptLong::REQUIRED_ARGUMENT]
|
94
129
|
)
|
95
130
|
|
96
131
|
opts.each do |opt, arg|
|
97
132
|
case opt
|
98
133
|
when '--help'
|
99
|
-
|
134
|
+
usage_information
|
135
|
+
exit(0)
|
136
|
+
when '--version'
|
137
|
+
version_information
|
138
|
+
exit(0)
|
139
|
+
when '--list-plugins'
|
140
|
+
list_plugins
|
141
|
+
exit(0)
|
100
142
|
when '--interval'
|
101
143
|
interval = arg.to_i
|
102
144
|
unless interval > 10
|
@@ -106,17 +148,25 @@ def parse_command_line_arguments!
|
|
106
148
|
$interval = interval
|
107
149
|
end
|
108
150
|
end
|
151
|
+
|
152
|
+
# ARGV now contains all non-params. Check for only one extra param, max. This is the DIR.
|
153
|
+
if $ARGV.size > 1
|
154
|
+
$stderr.puts "Only one directory may be specified!"
|
155
|
+
Kernel.exit(1)
|
156
|
+
elsif $ARGV.size == 1
|
157
|
+
$dir = $ARGV.first
|
158
|
+
end
|
109
159
|
end
|
110
160
|
|
111
161
|
# Default values for the command line options
|
112
162
|
$interval = 60
|
163
|
+
$dir = Dir.pwd
|
113
164
|
|
114
165
|
begin
|
115
166
|
parse_command_line_arguments!
|
116
167
|
|
117
168
|
notifier = GitRemoteMonitor::Notifier.new
|
118
|
-
|
119
|
-
monitor = GitRemoteMonitor::Monitor.new(Dir.pwd, $interval, notifier)
|
169
|
+
monitor = GitRemoteMonitor::Monitor.new($dir, $interval, notifier)
|
120
170
|
|
121
171
|
monitor.start_monitoring!
|
122
172
|
rescue => e
|
data/lib/git_remote_monitor.rb
CHANGED
@@ -20,9 +20,13 @@
|
|
20
20
|
# THE SOFTWARE.
|
21
21
|
|
22
22
|
module GitRemoteMonitor
|
23
|
-
|
23
|
+
|
24
|
+
def self.root
|
25
|
+
File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
26
|
+
end
|
27
|
+
|
24
28
|
end
|
25
29
|
|
26
|
-
|
30
|
+
%w(git_wrapper notifiers monitor status notifier).each do |file|
|
27
31
|
require File.join(File.dirname(__FILE__), 'git_remote_monitor', file)
|
28
32
|
end
|
@@ -62,11 +62,31 @@ class GitRemoteMonitor::GitWrapper
|
|
62
62
|
# The method will return true if a fetch was made or false if nothing was fetched.
|
63
63
|
#
|
64
64
|
def fetch!
|
65
|
+
raise "This repository have no remotes to fetch from!" unless has_remotes?
|
65
66
|
# If the output was empty, no actual fetch was done
|
66
67
|
return !call_fetch.strip.empty?
|
67
68
|
end
|
68
69
|
|
69
|
-
|
70
|
+
#
|
71
|
+
# Returns number of defined remotes or nil if no remotes are defined. Useful for
|
72
|
+
# if statements before doing fetches and whatnot.
|
73
|
+
#
|
74
|
+
# Works on current working dir, like most of the methods here.
|
75
|
+
#
|
76
|
+
def has_remotes?
|
77
|
+
remotes = call_remotes_list.strip.split("\n").size
|
78
|
+
return nil if remotes == 0
|
79
|
+
remotes
|
80
|
+
end
|
81
|
+
|
82
|
+
#
|
83
|
+
# Returns true if current working dir is inside a git repository. False otherwise.
|
84
|
+
#
|
85
|
+
def in_repo?
|
86
|
+
call_repo_discovery
|
87
|
+
end
|
88
|
+
|
89
|
+
protected
|
70
90
|
# Do the actual system call for "git fetch", returning output
|
71
91
|
def call_fetch
|
72
92
|
output = `git fetch 2>&1`
|
@@ -97,5 +117,16 @@ class GitRemoteMonitor::GitWrapper
|
|
97
117
|
def call_get_remote(local_name)
|
98
118
|
`git config branch.#{local_name}.remote`
|
99
119
|
end
|
120
|
+
|
121
|
+
def call_remotes_list
|
122
|
+
`git branch -r --no-color`
|
123
|
+
end
|
124
|
+
|
125
|
+
# Runs a simple plumbing command to quickly see if there is a repository in current working dir.
|
126
|
+
# Returns true or false depending on success in calling the command.
|
127
|
+
def call_repo_discovery
|
128
|
+
`git show-ref`
|
129
|
+
$?.success?
|
130
|
+
end
|
100
131
|
end
|
101
132
|
end
|
@@ -24,37 +24,47 @@
|
|
24
24
|
# instance about the changes later on.
|
25
25
|
#
|
26
26
|
class GitRemoteMonitor::Monitor
|
27
|
+
attr_reader :name, :directory
|
28
|
+
|
27
29
|
def initialize(directory, interval, notifier, name = nil)
|
28
30
|
@directory = directory
|
29
31
|
@name = name || File.basename(directory)
|
30
32
|
@interval = interval.to_i
|
31
33
|
@notifier = notifier
|
32
34
|
|
33
|
-
move_to_directory!(@directory)
|
35
|
+
self.class.move_to_directory!(@directory)
|
34
36
|
end
|
35
37
|
|
36
38
|
def start_monitoring!
|
37
|
-
|
39
|
+
loop do
|
38
40
|
notify! if GitRemoteMonitor::GitWrapper.fetch!
|
39
41
|
sleep @interval
|
42
|
+
break unless should_loop_monitoring?
|
40
43
|
end
|
41
44
|
end
|
42
45
|
|
43
46
|
protected
|
44
|
-
|
47
|
+
|
48
|
+
# This method is added only for easier testing. Might be usable in the future, though.
|
49
|
+
def should_loop_monitoring?
|
50
|
+
true
|
51
|
+
end
|
52
|
+
|
45
53
|
def notify!
|
46
54
|
# Find out the status
|
47
55
|
local = GitRemoteMonitor::GitWrapper.local_branch
|
48
56
|
remote = GitRemoteMonitor::GitWrapper.remote_branch
|
49
57
|
my_commits, their_commits = GitRemoteMonitor::GitWrapper.get_tracking_info(local, remote)
|
50
|
-
@notifier.notify_commits(
|
51
|
-
end
|
52
|
-
|
53
|
-
def move_to_directory!(directory)
|
58
|
+
@notifier.notify_commits(self, local, my_commits, their_commits)
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.move_to_directory!(directory)
|
54
62
|
unless File.exist?(directory) and File.directory?(directory)
|
55
63
|
raise "#{directory} not found or not a directory"
|
56
64
|
end
|
57
65
|
Dir.chdir(directory)
|
66
|
+
raise "#{File.expand_path(directory)} is not part of a git repository" unless GitRemoteMonitor::GitWrapper.in_repo?
|
58
67
|
end
|
68
|
+
|
59
69
|
|
60
70
|
end
|
@@ -19,42 +19,21 @@
|
|
19
19
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
20
|
# THE SOFTWARE.
|
21
21
|
|
22
|
+
#
|
23
|
+
# In its current form, this class is not much more than simple glue between the monitor and the
|
24
|
+
# whole notification system. Its primary use right now is to separate the logic properly. It
|
25
|
+
# will hopefully be refactored quite a bit in the future.
|
26
|
+
#
|
22
27
|
class GitRemoteMonitor::Notifier
|
23
28
|
|
24
|
-
def initialize
|
25
|
-
|
26
|
-
# For now, just use meow. REMEMBER: Remove 'meow' from the bin/ script when
|
27
|
-
# this requirement changes here!
|
28
|
-
|
29
|
-
require 'meow'
|
30
|
-
@notifier = ::Meow.new('git-remote-monitor')
|
29
|
+
def initialize
|
30
|
+
@notifier = GitRemoteMonitor::Notifiers.preferred_notifier.new
|
31
31
|
end
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
end
|
33
|
+
# FIXME: This method should probably be refactored later on. We shouldn't need this many arguments.
|
34
|
+
def notify_commits(monitor, branch_name, local_commits, remote_commits)
|
35
|
+
status = GitRemoteMonitor::Status.new(monitor, branch_name, local_commits, remote_commits)
|
36
|
+
@notifier.send_notification!(status)
|
38
37
|
end
|
39
38
|
|
40
|
-
protected
|
41
|
-
def get_message(local_commits, remote_commits)
|
42
|
-
# If there aren't any commits on the remote, we just ignore
|
43
|
-
# this difference. It's because we don't want to notify the user
|
44
|
-
# that they are x commits before the remote.
|
45
|
-
unless remote_commits == 0
|
46
|
-
|
47
|
-
# Now, we can have this scenarios:
|
48
|
-
# 1. The branch has not diverged; user has no commits, but remote has.
|
49
|
-
# 2. The branch has diverged; both the user and the remote has commits
|
50
|
-
message = if local_commits > 0
|
51
|
-
"Diverged! Remote has #{remote_commits} new commits, and you have #{local_commits} commits to push."
|
52
|
-
else
|
53
|
-
"Remote got updated! Now #{remote_commits} commits in front of you."
|
54
|
-
end
|
55
|
-
return message
|
56
|
-
end
|
57
|
-
nil
|
58
|
-
end
|
59
|
-
|
60
39
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# The MIT License
|
2
|
+
# Copyright © 2009 Magnus Bergmark
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
12
|
+
# all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
# THE SOFTWARE.
|
21
|
+
|
22
|
+
#
|
23
|
+
# This class is a mediator between the monitor and the actual notifier plugins.
|
24
|
+
# It will give you information about which plugin the monitor should use and also
|
25
|
+
# have the capability to tell you about the available plugins and all the defined
|
26
|
+
# ones.
|
27
|
+
#
|
28
|
+
class GitRemoteMonitor::Notifiers
|
29
|
+
class << self
|
30
|
+
|
31
|
+
# Returns the first plugin that is available; does not load any unneccessary stuff
|
32
|
+
# from plugins that will not be used.
|
33
|
+
def preferred_notifier
|
34
|
+
@preferred_notifier ||= notifier_plugins.find { |plugin| plugin.available? }
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns an array of all plugins that are available for use; will load a lot of gems
|
38
|
+
# and libraries which you may not want to use.
|
39
|
+
def available_notifiers
|
40
|
+
@available_notifiers ||= notifier_plugins.find_all { |plugin| plugin.available? }
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns an array of all defined plugins as classes.
|
44
|
+
def notifier_plugins
|
45
|
+
[Meow]
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
require 'git_remote_monitor/notifiers/base'
|
52
|
+
require 'git_remote_monitor/notifiers/meow'
|