happygiraffe-svenbot 0.0.1
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/LICENSE +23 -0
- data/Manifest +19 -0
- data/README.textile +7 -0
- data/Rakefile +17 -0
- data/bin/svenbot +58 -0
- data/bin/svenbot-notify +13 -0
- data/lib/svenbot/bot.rb +66 -0
- data/lib/svenbot/commit.rb +44 -0
- data/lib/svenbot/message.rb +21 -0
- data/lib/svenbot/repo.rb +23 -0
- data/lib/svenbot/user.rb +26 -0
- data/lib/svenbot/user_manager.rb +80 -0
- data/svenbot.gemspec +36 -0
- data/test/svenbot/bot_test.rb +97 -0
- data/test/svenbot/commit_test.rb +17 -0
- data/test/svenbot/message_test.rb +19 -0
- data/test/svenbot/repo_test.rb +18 -0
- data/test/svenbot/user_manager_test.rb +89 -0
- data/test/svenbot/user_test.rb +32 -0
- metadata +99 -0
data/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Copyright (C) 2008 by Dominic Mitchell
|
|
2
|
+
|
|
3
|
+
Redistribution and use in source and binary forms, with or without
|
|
4
|
+
modification, are permitted provided that the following conditions
|
|
5
|
+
are met:
|
|
6
|
+
|
|
7
|
+
1. Redistributions of source code must retain the above copyright
|
|
8
|
+
notice, this list of conditions and the following disclaimer.
|
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright
|
|
10
|
+
notice, this list of conditions and the following disclaimer in the
|
|
11
|
+
documentation and/or other materials provided with the distribution.
|
|
12
|
+
|
|
13
|
+
THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
14
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
15
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
16
|
+
ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
17
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
18
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
19
|
+
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
20
|
+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
21
|
+
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
22
|
+
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
23
|
+
SUCH DAMAGE.
|
data/Manifest
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
bin/svenbot
|
|
2
|
+
bin/svenbot-notify
|
|
3
|
+
lib/svenbot/bot.rb
|
|
4
|
+
lib/svenbot/commit.rb
|
|
5
|
+
lib/svenbot/message.rb
|
|
6
|
+
lib/svenbot/repo.rb
|
|
7
|
+
lib/svenbot/user.rb
|
|
8
|
+
lib/svenbot/user_manager.rb
|
|
9
|
+
LICENSE
|
|
10
|
+
Rakefile
|
|
11
|
+
README.textile
|
|
12
|
+
svenbot.gemspec
|
|
13
|
+
test/svenbot/bot_test.rb
|
|
14
|
+
test/svenbot/commit_test.rb
|
|
15
|
+
test/svenbot/message_test.rb
|
|
16
|
+
test/svenbot/repo_test.rb
|
|
17
|
+
test/svenbot/user_manager_test.rb
|
|
18
|
+
test/svenbot/user_test.rb
|
|
19
|
+
Manifest
|
data/README.textile
ADDED
data/Rakefile
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'rake'
|
|
3
|
+
require 'rake/clean'
|
|
4
|
+
require 'rake/rdoctask'
|
|
5
|
+
|
|
6
|
+
gem 'echoe'
|
|
7
|
+
require 'echoe'
|
|
8
|
+
|
|
9
|
+
Echoe.new("svenbot", "0.0.1") do |p|
|
|
10
|
+
p.author = 'Dominic Mitchell'
|
|
11
|
+
p.email = 'dom@happygiraffe.net'
|
|
12
|
+
p.url = 'http://github.com/happygiraffe/svenbot'
|
|
13
|
+
p.description = 'A jabber bot for subversion commits.'
|
|
14
|
+
p.need_zip = true
|
|
15
|
+
p.ignore_pattern = /^(pkg|doc|nbproject)|\.git/
|
|
16
|
+
p.retain_gemspec = true
|
|
17
|
+
end
|
data/bin/svenbot
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/ruby
|
|
2
|
+
#
|
|
3
|
+
# Fire up a new svenbot.
|
|
4
|
+
|
|
5
|
+
require 'svenbot/bot'
|
|
6
|
+
require 'svenbot/commit'
|
|
7
|
+
require 'svenbot/repo'
|
|
8
|
+
require 'yaml'
|
|
9
|
+
|
|
10
|
+
gem 'xmpp4r-simple'
|
|
11
|
+
require 'xmpp4r-simple'
|
|
12
|
+
|
|
13
|
+
Jabber::debug = true if ENV['JABBER_DEBUG']
|
|
14
|
+
|
|
15
|
+
repo = Svenbot::Repo.new(ARGV[0])
|
|
16
|
+
if !File.directory?(repo.dir)
|
|
17
|
+
warn "repo '#{repo.dir}' does not exist"
|
|
18
|
+
exit 1
|
|
19
|
+
end
|
|
20
|
+
repo.make_meta_dir
|
|
21
|
+
|
|
22
|
+
bot = Svenbot::Bot.new(repo)
|
|
23
|
+
|
|
24
|
+
commits = []
|
|
25
|
+
Thread.new do
|
|
26
|
+
sock_path = "#{repo.meta_dir}/sock"
|
|
27
|
+
# XXX Check for currently running svnbot
|
|
28
|
+
File.delete(sock_path) if File.exist?(sock_path)
|
|
29
|
+
sock = UNIXServer.new sock_path
|
|
30
|
+
loop do
|
|
31
|
+
s1 = sock.accept
|
|
32
|
+
msg = s1.recvfrom(256)[0]
|
|
33
|
+
# XXX A thread safe queue would be good.
|
|
34
|
+
commits << Svenbot::Commit.from(repo, msg)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
config = YAML.load_file("#{repo.meta_dir}/config.yml")
|
|
39
|
+
|
|
40
|
+
xmpp = Jabber::Simple.new(config[:connect_jid], config[:connect_password])
|
|
41
|
+
loop do
|
|
42
|
+
xmpp.received_messages do |msg|
|
|
43
|
+
case msg.body
|
|
44
|
+
when /^quit\b/
|
|
45
|
+
xmpp.deliver(msg.from, "bye bye")
|
|
46
|
+
xmpp.disconnect
|
|
47
|
+
exit
|
|
48
|
+
else
|
|
49
|
+
result = bot.dispatch_cmd(msg)
|
|
50
|
+
xmpp.deliver(result.to, result)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
while !commits.empty?
|
|
54
|
+
bot.commit_messages(commits.shift).each do |msg|
|
|
55
|
+
xmpp.deliver(msg.to, msg)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
data/bin/svenbot-notify
ADDED
data/lib/svenbot/bot.rb
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require 'svenbot/message'
|
|
2
|
+
require 'svenbot/user_manager'
|
|
3
|
+
|
|
4
|
+
module Svenbot
|
|
5
|
+
class Bot
|
|
6
|
+
include Message
|
|
7
|
+
|
|
8
|
+
def initialize(repo)
|
|
9
|
+
@repo = repo
|
|
10
|
+
@user_manager = UserManager.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def dispatch_cmd(msg)
|
|
14
|
+
cmd, args = msg.body.split(' ', 2)
|
|
15
|
+
method = "cmd_#{cmd}".to_sym
|
|
16
|
+
if self.class.method_defined? method
|
|
17
|
+
return self.send(method, msg.from, args)
|
|
18
|
+
else
|
|
19
|
+
return html_message("unknown command '#{cmd}'").set_to(msg.from)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def cmd_help(jid, unused)
|
|
24
|
+
commands = self.class.public_instance_methods.grep(/^cmd_/).
|
|
25
|
+
collect { |m| m.sub( /^cmd_/, '' ) }.sort.join(', ')
|
|
26
|
+
return html_message("available commands: #{commands}").set_to(jid)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def cmd_register(jid, path)
|
|
30
|
+
@user_manager.register jid, path
|
|
31
|
+
paths = @user_manager.paths_for jid
|
|
32
|
+
msg = "You will get commits for: #{paths.join(', ')}"
|
|
33
|
+
return html_message(msg).set_to(jid)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# Return a list of paths you are interested in commits for.
|
|
38
|
+
def cmd_list(jid, unused)
|
|
39
|
+
paths = @user_manager.paths_for(jid)
|
|
40
|
+
if paths.empty?
|
|
41
|
+
msg = 'You are not listening to any commits'
|
|
42
|
+
else
|
|
43
|
+
msg = "You are listening for commits to: #{paths.join(', ')}"
|
|
44
|
+
end
|
|
45
|
+
return html_message(msg).set_to(jid)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Remove messages about commits to a certain +path+. If not specified,
|
|
49
|
+
# +path+ defaults to "/".
|
|
50
|
+
def cmd_unregister(jid, path)
|
|
51
|
+
@user_manager.unregister jid, path
|
|
52
|
+
msg = "You will no longer get commits for: #{path}"
|
|
53
|
+
return html_message(msg).set_to(jid)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Return a list of messages to send out for +commit+.
|
|
57
|
+
def commit_messages(commit)
|
|
58
|
+
msg = "#{commit.user} committed #{commit.id}: #{commit.message}"
|
|
59
|
+
@user_manager.users_for(commit.path_prefix).collect do |jid|
|
|
60
|
+
html_message(msg).set_to(jid)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module Svenbot
|
|
2
|
+
# Representation of a commit message
|
|
3
|
+
class Commit
|
|
4
|
+
# Identifier for this commit
|
|
5
|
+
attr_reader :id
|
|
6
|
+
# Who made this commit?
|
|
7
|
+
attr_reader :user
|
|
8
|
+
# What part of the repository did this affect?
|
|
9
|
+
attr_reader :path_prefix
|
|
10
|
+
# Why was this commit made?
|
|
11
|
+
attr_reader :message
|
|
12
|
+
|
|
13
|
+
# Create a new commit.
|
|
14
|
+
def initialize(id, user, path_prefix, message)
|
|
15
|
+
@id = id
|
|
16
|
+
@user = user
|
|
17
|
+
@path_prefix = path_prefix
|
|
18
|
+
@message = message
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Populate a new commit object from a repository
|
|
22
|
+
def self.from(repo, id)
|
|
23
|
+
user = `svnlook author '#{repo.dir}' -r '#{id}'`.chomp
|
|
24
|
+
message = `svnlook log '#{repo.dir}' -r '#{id}'`.chomp
|
|
25
|
+
paths = `svnlook changed '#{repo.dir}' -r '#{id}'`.split(/\n/)
|
|
26
|
+
paths.collect! { |p| p.sub(/^..../, '').chomp }
|
|
27
|
+
return Commit.new(id, user, pick_prefix(paths), message)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
# Work out the common prefix of these paths.
|
|
33
|
+
# http://newsgroups.derkeiler.com/Archive/Comp/comp.lang.ruby/2007-08/msg00370.html
|
|
34
|
+
def self.pick_prefix(paths)
|
|
35
|
+
# A list of indexes of differing characters in a & b.
|
|
36
|
+
s = []
|
|
37
|
+
a, b = paths.max.split(//), paths.min.split(//)
|
|
38
|
+
# Note the index of each character that differs.
|
|
39
|
+
a.each_with_index{ |val,i| s << i if val != b[i] }
|
|
40
|
+
# Extract from the first char to the first differing char.
|
|
41
|
+
return (0...s[0]).collect { |j| a[j] }.join
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
|
|
3
|
+
gem 'xmpp4r'
|
|
4
|
+
require 'xmpp4r/message'
|
|
5
|
+
require 'xmpp4r/xhtml/html'
|
|
6
|
+
|
|
7
|
+
module Svenbot
|
|
8
|
+
# A factory for messages.
|
|
9
|
+
module Message
|
|
10
|
+
# Create a Jabber::Message with both HTML and text body. Pass in a
|
|
11
|
+
# string of HTML.
|
|
12
|
+
def html_message(contents)
|
|
13
|
+
msg = Jabber::Message.new
|
|
14
|
+
msg.type = :chat
|
|
15
|
+
html = Jabber::XHTML::HTML.new(contents)
|
|
16
|
+
msg.add(html)
|
|
17
|
+
msg.body = html.to_text
|
|
18
|
+
return msg
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/svenbot/repo.rb
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Svenbot
|
|
2
|
+
# A subversion repository on the filesystem.
|
|
3
|
+
class Repo
|
|
4
|
+
# The directory the repository lives in.
|
|
5
|
+
attr_reader :dir
|
|
6
|
+
|
|
7
|
+
# Create a new Repo.
|
|
8
|
+
def initialize(dir)
|
|
9
|
+
@dir = dir
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Return a directory within the repository for use by svenbot. Defaults
|
|
13
|
+
# to a subdirectory "svenbot".
|
|
14
|
+
def meta_dir
|
|
15
|
+
return "#{dir}/svenbot"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Create the meta directory if needed.
|
|
19
|
+
def make_meta_dir
|
|
20
|
+
Dir.mkdir(meta_dir) unless File.directory?(meta_dir)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
data/lib/svenbot/user.rb
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Svenbot
|
|
2
|
+
# A user who wishes to receive notifications about commits.
|
|
3
|
+
class User
|
|
4
|
+
# The jabber ID of the user.
|
|
5
|
+
attr_accessor :jid
|
|
6
|
+
# A list of paths that the user wishes to be notified about.
|
|
7
|
+
attr_accessor :paths
|
|
8
|
+
|
|
9
|
+
# Create a new user +jid+ with no paths to monitor.
|
|
10
|
+
def initialize(jid)
|
|
11
|
+
@jid = jid
|
|
12
|
+
@paths = []
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Add a path to the list monitored.
|
|
16
|
+
def <<(path)
|
|
17
|
+
@paths << path
|
|
18
|
+
return self
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Remove a path from the list monitored.
|
|
22
|
+
def delete(path)
|
|
23
|
+
@paths.delete path
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
require 'set'
|
|
2
|
+
require 'svenbot/user'
|
|
3
|
+
|
|
4
|
+
module Svenbot
|
|
5
|
+
# Keep state tracking who is interested in what commits. Users can register
|
|
6
|
+
# or unregister for paths. Commits to those paths will result in a message
|
|
7
|
+
# being emitted.
|
|
8
|
+
class UserManager
|
|
9
|
+
# A hash of registered users.
|
|
10
|
+
attr_reader :users
|
|
11
|
+
# A hash of paths we are interested in, and which users map to them.
|
|
12
|
+
attr_reader :paths
|
|
13
|
+
|
|
14
|
+
# Create a new UserManager instance
|
|
15
|
+
def initialize
|
|
16
|
+
@users = {}
|
|
17
|
+
@paths = {}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Register +jid+ as interested in commits to +path+. If path isn't
|
|
21
|
+
# specified, default to "everything" (i.e. "/")
|
|
22
|
+
def register(jid, path)
|
|
23
|
+
user = get_user(jid)
|
|
24
|
+
user << path
|
|
25
|
+
add_path_for_user path, user
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Remove messages about commits to a certain +path+.
|
|
29
|
+
def unregister(jid, path)
|
|
30
|
+
user = @users.delete jid
|
|
31
|
+
remove_path_for_user path, user if user
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Return a sorted list of paths that +jid+ has registered.
|
|
35
|
+
def paths_for(jid)
|
|
36
|
+
get_user(jid).paths.sort
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Return a sorted list of jids that have registered an interest in +path+
|
|
40
|
+
def users_for(path)
|
|
41
|
+
interested = Set.new
|
|
42
|
+
while path != "/"
|
|
43
|
+
interested.merge users_for_path(path)
|
|
44
|
+
path = File.dirname path
|
|
45
|
+
end
|
|
46
|
+
# Be nice to get rid of this special case.
|
|
47
|
+
interested.merge users_for_path(path)
|
|
48
|
+
# Return jids, as User is an impl detail
|
|
49
|
+
return interested.collect { |u| u.jid }.sort
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
# Return an existing user or create a new one.
|
|
55
|
+
def get_user(jid)
|
|
56
|
+
@users[jid] ||= User.new(jid)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Fill in the reverse mapping so we know which paths are of interest to
|
|
60
|
+
# which users.
|
|
61
|
+
def add_path_for_user(path, user)
|
|
62
|
+
@paths[path] ||= Set.new
|
|
63
|
+
@paths[path] << user
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Remove user from a given path. If there are no further users listening
|
|
67
|
+
# for a given path, remove the whole path.
|
|
68
|
+
def remove_path_for_user(path, user)
|
|
69
|
+
if @paths[path]
|
|
70
|
+
@paths[path].delete user
|
|
71
|
+
@paths.delete path if @paths[path].empty?
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Return a list of users for a given path.
|
|
76
|
+
def users_for_path(path)
|
|
77
|
+
@paths[path] || Set.new
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
data/svenbot.gemspec
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |s|
|
|
4
|
+
s.name = %q{svenbot}
|
|
5
|
+
s.version = "0.0.1"
|
|
6
|
+
|
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
|
8
|
+
s.authors = ["Dominic Mitchell"]
|
|
9
|
+
s.date = %q{2008-12-24}
|
|
10
|
+
s.description = %q{A jabber bot for subversion commits.}
|
|
11
|
+
s.email = %q{dom@happygiraffe.net}
|
|
12
|
+
s.executables = ["svenbot", "svenbot-notify"]
|
|
13
|
+
s.extra_rdoc_files = ["bin/svenbot", "bin/svenbot-notify", "lib/svenbot/bot.rb", "lib/svenbot/commit.rb", "lib/svenbot/message.rb", "lib/svenbot/repo.rb", "lib/svenbot/user.rb", "lib/svenbot/user_manager.rb", "LICENSE", "README.textile"]
|
|
14
|
+
s.files = ["bin/svenbot", "bin/svenbot-notify", "lib/svenbot/bot.rb", "lib/svenbot/commit.rb", "lib/svenbot/message.rb", "lib/svenbot/repo.rb", "lib/svenbot/user.rb", "lib/svenbot/user_manager.rb", "LICENSE", "Rakefile", "README.textile", "svenbot.gemspec", "test/svenbot/bot_test.rb", "test/svenbot/commit_test.rb", "test/svenbot/message_test.rb", "test/svenbot/repo_test.rb", "test/svenbot/user_manager_test.rb", "test/svenbot/user_test.rb", "Manifest"]
|
|
15
|
+
s.has_rdoc = true
|
|
16
|
+
s.homepage = %q{http://github.com/happygiraffe/svenbot}
|
|
17
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Svenbot", "--main", "README.textile"]
|
|
18
|
+
s.require_paths = ["lib"]
|
|
19
|
+
s.rubyforge_project = %q{svenbot}
|
|
20
|
+
s.rubygems_version = %q{1.3.1}
|
|
21
|
+
s.summary = %q{A jabber bot for subversion commits.}
|
|
22
|
+
s.test_files = ["test/svenbot/bot_test.rb", "test/svenbot/commit_test.rb", "test/svenbot/message_test.rb", "test/svenbot/repo_test.rb", "test/svenbot/user_manager_test.rb", "test/svenbot/user_test.rb"]
|
|
23
|
+
|
|
24
|
+
if s.respond_to? :specification_version then
|
|
25
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
|
26
|
+
s.specification_version = 2
|
|
27
|
+
|
|
28
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
|
29
|
+
s.add_development_dependency(%q<echoe>, [">= 0"])
|
|
30
|
+
else
|
|
31
|
+
s.add_dependency(%q<echoe>, [">= 0"])
|
|
32
|
+
end
|
|
33
|
+
else
|
|
34
|
+
s.add_dependency(%q<echoe>, [">= 0"])
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# To change this template, choose Tools | Templates
|
|
2
|
+
# and open the template in the editor.
|
|
3
|
+
|
|
4
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','lib')
|
|
5
|
+
|
|
6
|
+
require 'test/unit'
|
|
7
|
+
require 'svenbot/bot'
|
|
8
|
+
require 'svenbot/message'
|
|
9
|
+
require 'svenbot/repo'
|
|
10
|
+
require 'tmpdir'
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
module Svenbot
|
|
15
|
+
class BotTest < Test::Unit::TestCase
|
|
16
|
+
include Message
|
|
17
|
+
|
|
18
|
+
attr_reader :bot
|
|
19
|
+
|
|
20
|
+
# Sample data
|
|
21
|
+
A_JID = 'me@example.com'
|
|
22
|
+
# More sample data
|
|
23
|
+
ANOTHER_JID = 'you@example.com'
|
|
24
|
+
|
|
25
|
+
def setup
|
|
26
|
+
@bot = Bot.new(Repo.new("#{Dir.tmpdir}/repo"))
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def assert_message(expected_to, expected_body, msg)
|
|
30
|
+
assert_equal expected_to, msg.to.to_s
|
|
31
|
+
assert_equal expected_body, msg.body
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def test_register_message
|
|
35
|
+
msg = bot.cmd_register A_JID, '/proj1'
|
|
36
|
+
assert_message A_JID, 'You will get commits for: /proj1', msg
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def test_register_message_for_two_projects
|
|
40
|
+
msg = bot.cmd_register A_JID, '/proj1'
|
|
41
|
+
msg = bot.cmd_register A_JID, '/proj2'
|
|
42
|
+
assert_message A_JID, 'You will get commits for: /proj1, /proj2', msg
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def test_unregister_message
|
|
46
|
+
msg = bot.cmd_register A_JID, '/proj1'
|
|
47
|
+
msg = bot.cmd_unregister A_JID, '/proj1'
|
|
48
|
+
assert_message A_JID, 'You will no longer get commits for: /proj1', msg
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def test_list
|
|
52
|
+
msg = bot.cmd_register A_JID, '/proj1'
|
|
53
|
+
msg = bot.cmd_register A_JID, '/proj2'
|
|
54
|
+
msg = bot.cmd_list A_JID, nil
|
|
55
|
+
assert_message A_JID, 'You are listening for commits to: /proj1, /proj2', msg
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def test_list_none
|
|
59
|
+
msg = bot.cmd_list A_JID, nil
|
|
60
|
+
assert_message A_JID, 'You are not listening to any commits', msg
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def test_commit_messages
|
|
64
|
+
bot.cmd_register(A_JID, '/proj1')
|
|
65
|
+
c = Commit.new('12345', 'arthur', '/proj1', 'fix bug 42')
|
|
66
|
+
msgs = bot.commit_messages c
|
|
67
|
+
assert_equal 1, msgs.size
|
|
68
|
+
assert_message A_JID, 'arthur committed 12345: fix bug 42', msgs[0]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def test_commit_messages_understand_prefix
|
|
72
|
+
bot.cmd_register(A_JID, '/')
|
|
73
|
+
c = Commit.new('12345', 'arthur', '/proj1/README', 'fix bug 42')
|
|
74
|
+
msgs = bot.commit_messages c
|
|
75
|
+
assert_equal 1, msgs.size
|
|
76
|
+
assert_message A_JID, 'arthur committed 12345: fix bug 42', msgs[0]
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def test_help
|
|
80
|
+
msg = bot.cmd_help(A_JID, nil)
|
|
81
|
+
assert_message A_JID, 'available commands: help, list, register, unregister', msg
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def test_dispatch_cmd
|
|
85
|
+
in_msg = html_message('help').set_from(A_JID)
|
|
86
|
+
out_msg = bot.dispatch_cmd(in_msg)
|
|
87
|
+
assert_message A_JID, 'available commands: help, list, register, unregister', out_msg
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def test_dispatch_cmd_unknown
|
|
91
|
+
in_msg = html_message('aardvark').set_from(A_JID)
|
|
92
|
+
out_msg = bot.dispatch_cmd(in_msg)
|
|
93
|
+
assert_message A_JID, "unknown command 'aardvark'", out_msg
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','lib')
|
|
2
|
+
|
|
3
|
+
require 'test/unit'
|
|
4
|
+
require 'svenbot/commit'
|
|
5
|
+
|
|
6
|
+
module Svenbot
|
|
7
|
+
class CommitTest < Test::Unit::TestCase
|
|
8
|
+
|
|
9
|
+
def test_commit_fields
|
|
10
|
+
commit = Commit.new '12345', 'dom', '/proj1', 'I made this!'
|
|
11
|
+
assert_equal 'dom', commit.user
|
|
12
|
+
assert_equal '12345', commit.id
|
|
13
|
+
assert_equal '/proj1', commit.path_prefix
|
|
14
|
+
assert_equal 'I made this!', commit.message
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','lib')
|
|
2
|
+
|
|
3
|
+
require 'test/unit'
|
|
4
|
+
require 'svenbot/message'
|
|
5
|
+
|
|
6
|
+
module Svenbot
|
|
7
|
+
class MessageTest < Test::Unit::TestCase
|
|
8
|
+
include Message
|
|
9
|
+
|
|
10
|
+
def test_html_message
|
|
11
|
+
msg = html_message("hello <em>world</em>")
|
|
12
|
+
assert_equal :chat, msg.type
|
|
13
|
+
assert_equal "hello world", msg.body
|
|
14
|
+
assert_equal "<html xmlns='http://jabber.org/protocol/xhtml-im'><body " +
|
|
15
|
+
"xmlns='http://www.w3.org/1999/xhtml'>hello <em>world</em></body></html>",
|
|
16
|
+
msg.first_element('html').to_s
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# To change this template, choose Tools | Templates
|
|
2
|
+
# and open the template in the editor.
|
|
3
|
+
|
|
4
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','lib')
|
|
5
|
+
|
|
6
|
+
require 'test/unit'
|
|
7
|
+
require 'svenbot/repo'
|
|
8
|
+
|
|
9
|
+
module Svenbot
|
|
10
|
+
class RepoTest < Test::Unit::TestCase
|
|
11
|
+
def test_dir
|
|
12
|
+
assert_equal('/tmp/repo', Repo.new('/tmp/repo').dir)
|
|
13
|
+
end
|
|
14
|
+
def test_meta_dir
|
|
15
|
+
assert_equal('/tmp/repo/svenbot', Repo.new('/tmp/repo').meta_dir)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','lib')
|
|
2
|
+
|
|
3
|
+
require 'test/unit'
|
|
4
|
+
require 'svenbot/commit'
|
|
5
|
+
require 'svenbot/user_manager'
|
|
6
|
+
|
|
7
|
+
module Svenbot
|
|
8
|
+
class UserManagerTest < Test::Unit::TestCase
|
|
9
|
+
attr_reader :um
|
|
10
|
+
# Sample data
|
|
11
|
+
A_JID = 'me@example.com'
|
|
12
|
+
# More sample data
|
|
13
|
+
ANOTHER_JID = 'you@example.com'
|
|
14
|
+
|
|
15
|
+
def setup
|
|
16
|
+
@um = UserManager.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_register_user
|
|
20
|
+
um.register A_JID, '/'
|
|
21
|
+
|
|
22
|
+
assert_equal 1, um.users.size
|
|
23
|
+
assert_equal ['/'], um.users[A_JID].paths
|
|
24
|
+
|
|
25
|
+
assert_equal 1, um.paths.size
|
|
26
|
+
assert_equal [A_JID], um.paths['/'].collect { |u| u.jid }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def test_register_two_users_same_path
|
|
30
|
+
um.register A_JID, '/proj'
|
|
31
|
+
um.register ANOTHER_JID, '/proj'
|
|
32
|
+
|
|
33
|
+
assert_equal 2, um.users.size
|
|
34
|
+
assert_equal ['/proj'], um.users[A_JID].paths
|
|
35
|
+
assert_equal ['/proj'], um.users[ANOTHER_JID].paths
|
|
36
|
+
|
|
37
|
+
assert_equal 1, um.paths.size
|
|
38
|
+
assert_equal [A_JID, ANOTHER_JID], jids_for_path(um, '/proj').sort
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def test_register_two_paths
|
|
42
|
+
um.register A_JID, '/proj1'
|
|
43
|
+
um.register A_JID, '/proj2'
|
|
44
|
+
|
|
45
|
+
assert_equal 1, um.users.size
|
|
46
|
+
assert_equal ['/proj1', '/proj2'], um.users[A_JID].paths
|
|
47
|
+
|
|
48
|
+
assert_equal 2, um.paths.size
|
|
49
|
+
assert_equal [A_JID], jids_for_path(um, '/proj1')
|
|
50
|
+
assert_equal [A_JID], jids_for_path(um, '/proj2')
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def test_unregister
|
|
54
|
+
um.register A_JID, '/proj1'
|
|
55
|
+
um.unregister A_JID, '/proj1'
|
|
56
|
+
|
|
57
|
+
assert_equal 0, um.users.size
|
|
58
|
+
assert_equal 0, um.paths.size
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def test_users_for_path
|
|
62
|
+
um.register(A_JID, '/proj1')
|
|
63
|
+
assert_equal [A_JID], um.users_for('/proj1')
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def test_users_for_path_understands_prefixes
|
|
67
|
+
um.register(A_JID, '/')
|
|
68
|
+
assert_equal [A_JID], um.users_for('/proj1')
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def test_users_for_path_with_multiple_users
|
|
72
|
+
um.register(A_JID, '/proj1')
|
|
73
|
+
um.register(ANOTHER_JID, '/proj1')
|
|
74
|
+
assert_equal [A_JID, ANOTHER_JID], um.users_for('/proj1')
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def test_paths_for
|
|
78
|
+
um.register A_JID, '/proj1'
|
|
79
|
+
um.register A_JID, '/proj2'
|
|
80
|
+
assert_equal %w[ /proj1 /proj2 ], um.paths_for(A_JID).sort
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
def jids_for_path(bot, path)
|
|
86
|
+
bot.paths[path].collect { |u| u.jid }
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','lib')
|
|
2
|
+
|
|
3
|
+
require 'test/unit'
|
|
4
|
+
require 'svenbot/user'
|
|
5
|
+
|
|
6
|
+
module Svenbot
|
|
7
|
+
class UserTest < Test::Unit::TestCase
|
|
8
|
+
attr_reader :user
|
|
9
|
+
|
|
10
|
+
def setup
|
|
11
|
+
@user = User.new 'user@example.com'
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_initialize
|
|
15
|
+
assert_equal 'user@example.com', user.jid
|
|
16
|
+
assert_equal [], user.paths
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_add
|
|
20
|
+
# Should return itself
|
|
21
|
+
assert_equal user, user << '/project'
|
|
22
|
+
# Should have added to paths
|
|
23
|
+
assert_equal ['/project'], user.paths
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_delete
|
|
27
|
+
user.paths = %w( /foo /bar )
|
|
28
|
+
user.delete '/bar'
|
|
29
|
+
assert_equal ['/foo'], user.paths
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: happygiraffe-svenbot
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Dominic Mitchell
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
|
|
12
|
+
date: 2008-12-24 00:00:00 -08:00
|
|
13
|
+
default_executable:
|
|
14
|
+
dependencies:
|
|
15
|
+
- !ruby/object:Gem::Dependency
|
|
16
|
+
name: echoe
|
|
17
|
+
version_requirement:
|
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
19
|
+
requirements:
|
|
20
|
+
- - ">="
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: "0"
|
|
23
|
+
version:
|
|
24
|
+
description: A jabber bot for subversion commits.
|
|
25
|
+
email: dom@happygiraffe.net
|
|
26
|
+
executables:
|
|
27
|
+
- svenbot
|
|
28
|
+
- svenbot-notify
|
|
29
|
+
extensions: []
|
|
30
|
+
|
|
31
|
+
extra_rdoc_files:
|
|
32
|
+
- bin/svenbot
|
|
33
|
+
- bin/svenbot-notify
|
|
34
|
+
- lib/svenbot/bot.rb
|
|
35
|
+
- lib/svenbot/commit.rb
|
|
36
|
+
- lib/svenbot/message.rb
|
|
37
|
+
- lib/svenbot/repo.rb
|
|
38
|
+
- lib/svenbot/user.rb
|
|
39
|
+
- lib/svenbot/user_manager.rb
|
|
40
|
+
- LICENSE
|
|
41
|
+
- README.textile
|
|
42
|
+
files:
|
|
43
|
+
- bin/svenbot
|
|
44
|
+
- bin/svenbot-notify
|
|
45
|
+
- lib/svenbot/bot.rb
|
|
46
|
+
- lib/svenbot/commit.rb
|
|
47
|
+
- lib/svenbot/message.rb
|
|
48
|
+
- lib/svenbot/repo.rb
|
|
49
|
+
- lib/svenbot/user.rb
|
|
50
|
+
- lib/svenbot/user_manager.rb
|
|
51
|
+
- LICENSE
|
|
52
|
+
- Rakefile
|
|
53
|
+
- README.textile
|
|
54
|
+
- svenbot.gemspec
|
|
55
|
+
- test/svenbot/bot_test.rb
|
|
56
|
+
- test/svenbot/commit_test.rb
|
|
57
|
+
- test/svenbot/message_test.rb
|
|
58
|
+
- test/svenbot/repo_test.rb
|
|
59
|
+
- test/svenbot/user_manager_test.rb
|
|
60
|
+
- test/svenbot/user_test.rb
|
|
61
|
+
- Manifest
|
|
62
|
+
has_rdoc: true
|
|
63
|
+
homepage: http://github.com/happygiraffe/svenbot
|
|
64
|
+
post_install_message:
|
|
65
|
+
rdoc_options:
|
|
66
|
+
- --line-numbers
|
|
67
|
+
- --inline-source
|
|
68
|
+
- --title
|
|
69
|
+
- Svenbot
|
|
70
|
+
- --main
|
|
71
|
+
- README.textile
|
|
72
|
+
require_paths:
|
|
73
|
+
- lib
|
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
75
|
+
requirements:
|
|
76
|
+
- - ">="
|
|
77
|
+
- !ruby/object:Gem::Version
|
|
78
|
+
version: "0"
|
|
79
|
+
version:
|
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
81
|
+
requirements:
|
|
82
|
+
- - ">="
|
|
83
|
+
- !ruby/object:Gem::Version
|
|
84
|
+
version: "1.2"
|
|
85
|
+
version:
|
|
86
|
+
requirements: []
|
|
87
|
+
|
|
88
|
+
rubyforge_project: svenbot
|
|
89
|
+
rubygems_version: 1.2.0
|
|
90
|
+
signing_key:
|
|
91
|
+
specification_version: 2
|
|
92
|
+
summary: A jabber bot for subversion commits.
|
|
93
|
+
test_files:
|
|
94
|
+
- test/svenbot/bot_test.rb
|
|
95
|
+
- test/svenbot/commit_test.rb
|
|
96
|
+
- test/svenbot/message_test.rb
|
|
97
|
+
- test/svenbot/repo_test.rb
|
|
98
|
+
- test/svenbot/user_manager_test.rb
|
|
99
|
+
- test/svenbot/user_test.rb
|