happygiraffe-svenbot 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,7 @@
1
+ h1. svenbot
2
+
3
+ Svenbot is a very simple Jabber bot. It listens to commits through a subversion hook and sends out messages to anybody who has registered an interest in such things.
4
+
5
+ h3. TODO
6
+
7
+ * Only send out notifications to available people.
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
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/ruby
2
+ #
3
+ # Send a message to the bot.
4
+
5
+ require 'socket'
6
+ require 'svenbot/repo'
7
+
8
+ repo = Svenbot::Repo.new(ARGV[0])
9
+ rev = ARGV[1]
10
+
11
+ sock = UNIXSocket.open "#{repo.meta_dir}/sock"
12
+ sock.send rev, 0
13
+ sock.close
@@ -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
@@ -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
@@ -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