hipbot 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +2 -0
- data/.travis.yml +1 -0
- data/Gemfile +2 -1
- data/Gemfile.lock +46 -25
- data/Guardfile +5 -0
- data/README.md +85 -17
- data/hipbot.gemspec +6 -5
- data/lib/hipbot.rb +4 -1
- data/lib/hipbot/adapters/hipchat/connection.rb +71 -66
- data/lib/hipbot/adapters/hipchat/hipchat.rb +1 -10
- data/lib/hipbot/adapters/telnet/telnet.rb +1 -3
- data/lib/hipbot/bot.rb +51 -34
- data/lib/hipbot/collection.rb +2 -4
- data/lib/hipbot/configuration.rb +2 -4
- data/lib/hipbot/helpers.rb +40 -0
- data/lib/hipbot/logger.rb +15 -0
- data/lib/hipbot/message.rb +1 -1
- data/lib/hipbot/patches/hipchat_client.rb +1 -1
- data/lib/hipbot/plugin.rb +11 -0
- data/lib/hipbot/reactable.rb +60 -0
- data/lib/hipbot/reaction.rb +6 -1
- data/lib/hipbot/response.rb +9 -8
- data/lib/hipbot/room.rb +3 -3
- data/lib/hipbot/user.rb +1 -1
- data/lib/hipbot/version.rb +1 -1
- data/spec/integration/hipbot_spec.rb +40 -1
- data/spec/spec_helper.rb +2 -0
- data/spec/unit/hipbot_spec.rb +54 -3
- metadata +35 -14
- data/lib/hipbot/http_response.rb +0 -15
data/.rspec
ADDED
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,51 +1,72 @@
|
|
1
1
|
GEM
|
2
2
|
remote: https://rubygems.org/
|
3
3
|
specs:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
addressable (2.3.
|
4
|
+
activesupport (3.2.12)
|
5
|
+
i18n (~> 0.6)
|
6
|
+
multi_json (~> 1.0)
|
7
|
+
addressable (2.3.3)
|
8
|
+
coderay (1.0.9)
|
8
9
|
cookiejar (0.3.0)
|
9
|
-
daemons (1.1.
|
10
|
-
diff-lcs (1.
|
11
|
-
em-http-request (1.0.
|
10
|
+
daemons (1.1.9)
|
11
|
+
diff-lcs (1.2.2)
|
12
|
+
em-http-request (1.0.3)
|
12
13
|
addressable (>= 2.2.3)
|
13
14
|
cookiejar
|
14
15
|
em-socksify
|
15
16
|
eventmachine (>= 1.0.0.beta.4)
|
16
17
|
http_parser.rb (>= 0.5.3)
|
17
|
-
em-socksify (0.2.
|
18
|
+
em-socksify (0.2.1)
|
18
19
|
eventmachine (>= 1.0.0.beta.4)
|
19
|
-
eventmachine (1.0.
|
20
|
+
eventmachine (1.0.3)
|
21
|
+
formatador (0.2.4)
|
22
|
+
guard (1.7.0)
|
23
|
+
formatador (>= 0.2.4)
|
24
|
+
listen (>= 0.6.0)
|
25
|
+
lumberjack (>= 1.0.2)
|
26
|
+
pry (>= 0.9.10)
|
27
|
+
thor (>= 0.14.6)
|
28
|
+
guard-rspec (2.5.2)
|
29
|
+
guard (>= 1.1)
|
30
|
+
rspec (~> 2.11)
|
20
31
|
http_parser.rb (0.5.3)
|
21
|
-
httparty (0.
|
32
|
+
httparty (0.10.2)
|
22
33
|
multi_json (~> 1.0)
|
23
|
-
multi_xml
|
24
|
-
i18n (0.6.
|
34
|
+
multi_xml (>= 0.5.2)
|
35
|
+
i18n (0.6.4)
|
36
|
+
listen (0.7.3)
|
37
|
+
lumberjack (1.0.3)
|
25
38
|
metaclass (0.0.1)
|
26
|
-
|
39
|
+
method_source (0.8.1)
|
40
|
+
mocha (0.13.3)
|
27
41
|
metaclass (~> 0.0.1)
|
28
|
-
multi_json (1.
|
29
|
-
multi_xml (0.5.
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
rspec
|
36
|
-
|
37
|
-
|
38
|
-
|
42
|
+
multi_json (1.7.2)
|
43
|
+
multi_xml (0.5.3)
|
44
|
+
pry (0.9.12)
|
45
|
+
coderay (~> 1.0.5)
|
46
|
+
method_source (~> 0.8)
|
47
|
+
slop (~> 3.4)
|
48
|
+
rake (10.0.4)
|
49
|
+
rspec (2.13.0)
|
50
|
+
rspec-core (~> 2.13.0)
|
51
|
+
rspec-expectations (~> 2.13.0)
|
52
|
+
rspec-mocks (~> 2.13.0)
|
53
|
+
rspec-core (2.13.1)
|
54
|
+
rspec-expectations (2.13.0)
|
55
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
56
|
+
rspec-mocks (2.13.0)
|
57
|
+
slop (3.4.4)
|
58
|
+
thor (0.18.1)
|
39
59
|
xmpp4r (0.5)
|
40
60
|
|
41
61
|
PLATFORMS
|
42
62
|
ruby
|
43
63
|
|
44
64
|
DEPENDENCIES
|
45
|
-
|
65
|
+
activesupport
|
46
66
|
daemons
|
47
67
|
em-http-request
|
48
68
|
eventmachine
|
69
|
+
guard-rspec
|
49
70
|
httparty
|
50
71
|
i18n
|
51
72
|
mocha
|
data/Guardfile
ADDED
data/README.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
[![Build Status](https://secure.travis-ci.org/pewniak747/hipbot.png?branch=master)](http://travis-ci.org/pewniak747/hipbot)
|
4
4
|
[![Code Climate](https://codeclimate.com/github/pewniak747/hipbot.png)](https://codeclimate.com/github/pewniak747/hipbot)
|
5
5
|
|
6
|
-
Hipbot is a bot for HipChat, written in ruby & eventmachine.
|
6
|
+
Hipbot is a XMPP bot for HipChat, written in ruby & eventmachine.
|
7
7
|
|
8
8
|
## Usage
|
9
9
|
|
@@ -15,21 +15,44 @@ gem install hipbot
|
|
15
15
|
|
16
16
|
### Customize
|
17
17
|
|
18
|
-
|
18
|
+
Create `bot.rb` file, subclass `Hipbot::Bot` and customize the responses.
|
19
19
|
|
20
20
|
``` ruby
|
21
21
|
require 'hipbot'
|
22
22
|
|
23
23
|
class MyCompanyBot < Hipbot::Bot
|
24
24
|
configure do |c|
|
25
|
-
c.name
|
26
|
-
c.jid
|
27
|
-
c.password
|
25
|
+
c.name = 'robot' # required
|
26
|
+
c.jid = 'changeme@chat.hipchat.com' # required
|
27
|
+
c.password = 'secret' # required
|
28
|
+
c.teams = { vip: ['John', 'Mike'] }
|
29
|
+
c.rooms = { project_rooms: ['Project 1', 'Project 2'] }
|
30
|
+
c.plugins = [ PluginClass ]
|
28
31
|
end
|
29
32
|
|
30
|
-
on /^hello
|
33
|
+
on /^hello/ do
|
31
34
|
reply('hello!')
|
32
35
|
end
|
36
|
+
|
37
|
+
on /^restart/, from: :vip do
|
38
|
+
# ...
|
39
|
+
reply('restarting...')
|
40
|
+
end
|
41
|
+
|
42
|
+
on /^deploy/, room: :project_rooms do
|
43
|
+
# ...
|
44
|
+
reply('deploying...')
|
45
|
+
end
|
46
|
+
|
47
|
+
default do
|
48
|
+
reply('I don\'t understand you!')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class PluginClass < Hipbot::Plugin
|
53
|
+
on /^plugin/ do
|
54
|
+
reply('this is from plugin!')
|
55
|
+
end
|
33
56
|
end
|
34
57
|
|
35
58
|
MyCompanyBot.start!
|
@@ -38,7 +61,7 @@ MyCompanyBot.start!
|
|
38
61
|
You can create a response by providing simple regexp:
|
39
62
|
|
40
63
|
``` ruby
|
41
|
-
on /^hello
|
64
|
+
on /^hello/ do
|
42
65
|
reply('hello!')
|
43
66
|
end
|
44
67
|
```
|
@@ -59,10 +82,15 @@ on /my name is (.*)/, /I am (.*)/ do |name|
|
|
59
82
|
end
|
60
83
|
```
|
61
84
|
|
62
|
-
Use :from to only match messages from certain users
|
85
|
+
Use :from to only match messages from certain users or user groups defined in configuration
|
63
86
|
|
64
87
|
``` ruby
|
65
|
-
|
88
|
+
configure do |c|
|
89
|
+
# ...
|
90
|
+
c.teams = { vip: ['John', 'Mike'] }
|
91
|
+
end
|
92
|
+
|
93
|
+
on /status report/, from: ['Tom', 'Dave', :vip] do
|
66
94
|
reply('all clear')
|
67
95
|
end
|
68
96
|
```
|
@@ -70,7 +98,12 @@ end
|
|
70
98
|
Use :room to only match messages in certain hipchat rooms
|
71
99
|
|
72
100
|
``` ruby
|
73
|
-
|
101
|
+
configure do |c|
|
102
|
+
# ...
|
103
|
+
c.rooms = { project_rooms: ['Project 1', 'Project 2'] }
|
104
|
+
end
|
105
|
+
|
106
|
+
on /hello/, room: ['Public Room', :project_rooms] do
|
74
107
|
reply('hello!')
|
75
108
|
end
|
76
109
|
```
|
@@ -78,7 +111,7 @@ end
|
|
78
111
|
Use :global to react to messages that are not sent directly to @robot
|
79
112
|
|
80
113
|
``` ruby
|
81
|
-
on /hey I just met you/, :
|
114
|
+
on /hey I just met you/, global: true do
|
82
115
|
reply('and this is crazy...')
|
83
116
|
end
|
84
117
|
```
|
@@ -103,7 +136,7 @@ end
|
|
103
136
|
|
104
137
|
``` ruby
|
105
138
|
on /ping site/ do
|
106
|
-
get 'http://example.com', :
|
139
|
+
get 'http://example.com', ping: "1" # issues http://example.com?ping=1
|
107
140
|
end
|
108
141
|
```
|
109
142
|
|
@@ -125,8 +158,8 @@ end
|
|
125
158
|
|
126
159
|
class Bot < Hipbot::Bot
|
127
160
|
configure do |c|
|
161
|
+
# ...
|
128
162
|
c.helpers = HipbotHelpers
|
129
|
-
# rest of configuration
|
130
163
|
end
|
131
164
|
|
132
165
|
on /what's the project called\?/ do
|
@@ -135,6 +168,42 @@ class Bot < Hipbot::Bot
|
|
135
168
|
end
|
136
169
|
```
|
137
170
|
|
171
|
+
#### Plugins
|
172
|
+
|
173
|
+
To define a plugin, subclass `Hipbot::Plugin` and add responses like in bot:
|
174
|
+
|
175
|
+
``` ruby
|
176
|
+
class GreeterPlugin < Hipbot::Plugin
|
177
|
+
on /^hello/ do
|
178
|
+
reply('hello there!')
|
179
|
+
end
|
180
|
+
end
|
181
|
+
```
|
182
|
+
|
183
|
+
You can gain access to plugin data inside reaction with `plugin` helper:
|
184
|
+
|
185
|
+
``` ruby
|
186
|
+
class GreeterPlugin < Hipbot::Plugin
|
187
|
+
attr_accessor :language
|
188
|
+
def initialize(language)
|
189
|
+
self.language = language
|
190
|
+
end
|
191
|
+
|
192
|
+
on /^hello/ do
|
193
|
+
case plugin.language
|
194
|
+
when :en
|
195
|
+
reply("hello!")
|
196
|
+
when :pl
|
197
|
+
reply("cześć!")
|
198
|
+
when :jp
|
199
|
+
reply("おはよう!")
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
```
|
204
|
+
|
205
|
+
For a collection of open-source plugins, see https://github.com/netguru/hipbot-plugins
|
206
|
+
|
138
207
|
### Run
|
139
208
|
|
140
209
|
Run hipbot as daemon by saying:
|
@@ -162,11 +231,10 @@ heroku ps:scale worker=1
|
|
162
231
|
|
163
232
|
## TODO:
|
164
233
|
|
165
|
-
* add plugins support
|
166
|
-
* add extended logging
|
167
|
-
|
168
234
|
### Done:
|
169
235
|
|
236
|
+
* ~~add extended logging~~
|
237
|
+
* ~~add plugins support~~
|
170
238
|
* ~~rewrite SimpleMUCClient~~
|
171
239
|
* ~~handle private messages callbacks~~
|
172
240
|
* ~~handle auto joining on room invite~~
|
@@ -176,4 +244,4 @@ heroku ps:scale worker=1
|
|
176
244
|
* ~~allow injecting custom module to response object, adding arbitrary methods~~
|
177
245
|
* ~~handle reconnecting after disconnect/failure~~
|
178
246
|
* ~~add support for multiple regexps for one response~~
|
179
|
-
* ~~add support for responses in particular room (`on //, :
|
247
|
+
* ~~add support for responses in particular room (`on //, room: ['public'] do ...`)~~
|
data/hipbot.gemspec
CHANGED
@@ -15,11 +15,12 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
gem.version = Hipbot::VERSION
|
17
17
|
gem.add_runtime_dependency "daemons", ["~> 1.1.8"]
|
18
|
-
gem.add_runtime_dependency "
|
18
|
+
gem.add_runtime_dependency "activesupport", ["~> 3.2.12"]
|
19
19
|
gem.add_runtime_dependency "i18n", ["~> 0.6.0"]
|
20
|
-
gem.add_runtime_dependency "eventmachine", ["~> 0.
|
21
|
-
gem.add_runtime_dependency "em-http-request", ["~> 0.3
|
20
|
+
gem.add_runtime_dependency "eventmachine", ["~> 1.0.3"]
|
21
|
+
gem.add_runtime_dependency "em-http-request", ["~> 1.0.3"]
|
22
22
|
gem.add_runtime_dependency "xmpp4r", ["~> 0.5"]
|
23
|
-
gem.add_development_dependency "rspec", ['~> 2.
|
24
|
-
gem.add_development_dependency "
|
23
|
+
gem.add_development_dependency "rspec", ['~> 2.13.0']
|
24
|
+
gem.add_development_dependency "guard-rspec", ['~> 2.5.1']
|
25
|
+
gem.add_development_dependency "mocha", ['~> 0.13.3']
|
25
26
|
end
|
data/lib/hipbot.rb
CHANGED
@@ -8,14 +8,17 @@ require 'xmpp4r/muc'
|
|
8
8
|
require 'hipbot/patches/hipchat_client'
|
9
9
|
require 'hipbot/patches/encoding'
|
10
10
|
|
11
|
+
require 'hipbot/logger'
|
11
12
|
require 'hipbot/adapters/hipchat/hipchat'
|
12
13
|
require 'hipbot/adapters/hipchat/connection'
|
13
14
|
require 'hipbot/adapters/telnet/telnet'
|
14
15
|
require 'hipbot/adapters/telnet/connection'
|
16
|
+
require 'hipbot/reactable'
|
15
17
|
require 'hipbot/bot'
|
18
|
+
require 'hipbot/plugin'
|
16
19
|
require 'hipbot/configuration'
|
17
20
|
require 'hipbot/collection'
|
18
|
-
require 'hipbot/
|
21
|
+
require 'hipbot/helpers'
|
19
22
|
require 'hipbot/message'
|
20
23
|
require 'hipbot/reaction'
|
21
24
|
require 'hipbot/response'
|
@@ -6,8 +6,7 @@ module Hipbot
|
|
6
6
|
@bot = bot
|
7
7
|
@bot.connection = self
|
8
8
|
|
9
|
-
|
10
|
-
setup_timers
|
9
|
+
setup_error_handler && setup_bot && setup_timers
|
11
10
|
end
|
12
11
|
|
13
12
|
def restart!
|
@@ -34,23 +33,21 @@ module Hipbot
|
|
34
33
|
private
|
35
34
|
|
36
35
|
def setup_bot
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
36
|
+
initialize_client do
|
37
|
+
initialize_rooms
|
38
|
+
initialize_users
|
39
|
+
initialize_callbacks
|
40
|
+
join_rooms
|
41
|
+
set_presence('Hello humans!')
|
42
|
+
end
|
44
43
|
end
|
45
44
|
|
46
45
|
def initialize_client
|
47
|
-
::Jabber.debug = true
|
48
46
|
@client = ::Jabber::MUC::HipchatClient.new(@bot.jid + '/' + @bot.name)
|
49
|
-
@client.connect(@bot.password)
|
47
|
+
yield if @client.connect(@bot.password)
|
50
48
|
end
|
51
49
|
|
52
50
|
def initialize_rooms
|
53
|
-
Room.bot = @bot
|
54
51
|
@client.get_rooms.each do |r|
|
55
52
|
Room.create(r[:item].jid, r[:item].iname, topic: r[:details]['topic'])
|
56
53
|
end
|
@@ -58,13 +55,12 @@ module Hipbot
|
|
58
55
|
end
|
59
56
|
|
60
57
|
def initialize_users
|
61
|
-
User.bot = @bot
|
62
58
|
@client.get_users.each do |v|
|
63
59
|
params = {
|
64
|
-
|
60
|
+
email: v[:vcard]['EMAIL/USERID'],
|
65
61
|
mention: v[:item].attributes['mention_name'],
|
66
|
-
|
67
|
-
|
62
|
+
title: v[:vcard]['TITLE'],
|
63
|
+
photo: v[:vcard]['PHOTO'],
|
68
64
|
}
|
69
65
|
User.create(v[:item].jid, v[:item].iname, params)
|
70
66
|
end
|
@@ -72,84 +68,93 @@ module Hipbot
|
|
72
68
|
end
|
73
69
|
|
74
70
|
def join_rooms
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
Room.each do |room_jid, _|
|
80
|
-
@client.join(room_jid)
|
71
|
+
with_rooms do |rooms|
|
72
|
+
rooms.each do |r|
|
73
|
+
@client.join(r.id)
|
74
|
+
end
|
81
75
|
end
|
82
|
-
true
|
83
76
|
end
|
84
77
|
|
85
78
|
def exit_all_rooms
|
86
|
-
|
87
|
-
|
79
|
+
with_rooms do |rooms|
|
80
|
+
rooms.each do |r|
|
81
|
+
@client.exit(r.id, 'bye bye!')
|
82
|
+
end
|
88
83
|
end
|
89
84
|
end
|
90
85
|
|
91
86
|
def initialize_callbacks
|
92
|
-
@client.on_message
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
Jabber::debuglog "[#{Time.now}] <#{room.name}> #{user_name}: #{message.body}"
|
99
|
-
begin
|
100
|
-
@bot.react(user, room, message.body)
|
101
|
-
rescue => e
|
102
|
-
Jabber::debuglog e.inspect
|
103
|
-
e.backtrace.each do |line|
|
104
|
-
Jabber::debuglog line
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
87
|
+
@client.on_message{ |*args| message_callback *args }
|
88
|
+
@client.on_private_message{ |*args| private_message_callback *args }
|
89
|
+
@client.on_invite{ |*args| invite_callback *args }
|
90
|
+
@client.on_presence{ |*args| presence_callback *args }
|
91
|
+
@client.activate_callbacks
|
92
|
+
end
|
108
93
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
if message.body.
|
113
|
-
|
114
|
-
# elsif message.inactive?
|
115
|
-
# elsif message.composing?
|
116
|
-
# elsif message.gone?
|
117
|
-
# elsif message.paused?
|
118
|
-
# end
|
119
|
-
else
|
120
|
-
@bot.react(user, nil, message.body)
|
121
|
-
end
|
94
|
+
def message_callback room_jid, user_name, message
|
95
|
+
with_sender(room_jid, user_name) do |room, user|
|
96
|
+
room.params.topic = message.subject if message.subject.present?
|
97
|
+
return if user_name == @bot.name || message.body.blank?
|
98
|
+
@bot.react(user, room, message.body)
|
122
99
|
end
|
100
|
+
end
|
123
101
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
102
|
+
def invite_callback room_jid, user_name, room_name, topic
|
103
|
+
Room.create(room_jid, room_name, topic: topic)
|
104
|
+
@client.join(room_jid)
|
105
|
+
end
|
128
106
|
|
129
|
-
|
130
|
-
|
131
|
-
next if room.blank? || user_name.blank?
|
132
|
-
user = User[user_name]
|
107
|
+
def presence_callback room_jid, user_name, pres
|
108
|
+
with_sender(room_jid, user_name) do |room, user|
|
133
109
|
if pres == 'unavailable'
|
134
110
|
if user_name == @bot.name
|
135
111
|
room.delete
|
136
112
|
elsif user.present?
|
137
113
|
room.user_ids.delete(user.id)
|
138
114
|
end
|
139
|
-
elsif pres.blank? &&
|
115
|
+
elsif pres.blank? && room.user_ids.exclude?(user.id)
|
140
116
|
room.user_ids << user.id
|
141
117
|
end
|
142
118
|
end
|
119
|
+
end
|
143
120
|
|
144
|
-
|
121
|
+
def private_message_callback user_jid, message
|
122
|
+
with_user(user_jid) do |user|
|
123
|
+
@bot.react(user, nil, message.body) if user.name != @bot.name
|
124
|
+
end if message.body.present?
|
125
|
+
end
|
126
|
+
|
127
|
+
def with_rooms
|
128
|
+
return Jabber::debuglog 'No rooms found' if Room.empty?
|
129
|
+
yield Room
|
130
|
+
end
|
131
|
+
|
132
|
+
def with_sender room_id, user_id
|
133
|
+
room = Room[room_id]
|
134
|
+
with_user(user_id) do |user|
|
135
|
+
yield room, user
|
136
|
+
end if room.present?
|
137
|
+
end
|
138
|
+
|
139
|
+
def with_user user_id
|
140
|
+
user = User[user_id]
|
141
|
+
yield user if user
|
145
142
|
end
|
146
143
|
|
147
144
|
def setup_timers
|
148
|
-
::EM::add_periodic_timer(60)
|
145
|
+
::EM::add_periodic_timer(60) do
|
149
146
|
@client.keep_alive(@bot.password) if @client.present?
|
150
|
-
|
147
|
+
end
|
151
148
|
end
|
152
149
|
|
150
|
+
def setup_error_handler
|
151
|
+
::EM.error_handler do |e|
|
152
|
+
Jabber::debuglog e.inspect
|
153
|
+
e.backtrace.each do |line|
|
154
|
+
Jabber::debuglog line
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
153
158
|
end
|
154
159
|
end
|
155
160
|
end
|