hipbot 0.1.0 → 0.2.0
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/.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
|
[](http://travis-ci.org/pewniak747/hipbot)
|
4
4
|
[](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
|