lita 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 08671280114ef4f96291a7b7f296e7b616f40647
4
- data.tar.gz: dc0372bef9351ea61ae833568d07302f586896fa
3
+ metadata.gz: 73a99962e90c5ed2aa41e8d8a728abdd0a707051
4
+ data.tar.gz: 1b9026e1e1d32e693d67d13a40fe1fa412982930
5
5
  SHA512:
6
- metadata.gz: e6c6c3f23fa4657320607973ef740765863539a1b5fe4fb281c92b8bddd8c6f6285be942b691b04ab9f0a0f1ea54a8aafbb81615bf88bfc79df4d02c4fa4bf4e
7
- data.tar.gz: b655f0ff87524fb958f83398ffa5adae67b955eca3b281c3eab915dbda71517e034d2016fb05ed3f3685dc68f5497ce02c2a97fbd9c29ba6e09793154d0863e8
6
+ metadata.gz: 5abc300962d3cdfbe95a1d2882acc8c79cdd4b259819badc7d396ca8b2a83aed37176a4c8c92721926810706bb3cd9a27cbf4d3cf2613aa3f166d53e5420e34b
7
+ data.tar.gz: b48afb57c7cb94f560ebb4ff0a7a88ba390759720020c8085868d6a748e541c338317bbb0837902183f61a95c1a4ca9e7c50677ce3478511bee80204bc97723a
data/README.md CHANGED
@@ -27,8 +27,8 @@ Lita draws much inspiration from GitHub's fantastic [Hubot](http://hubot.github.
27
27
 
28
28
  * It's written in Ruby.
29
29
  * It exposes the full power of Redis rather than using it to serialize JSON.
30
- * Is easy to develop and test plugins for with the provied [RSpec](https://github.com/rspec/rspec) extras. Lita strongly encourages thorough testing of plugins.
31
- * It uses uses the Ruby ecosystem's standard tools (RubyGems and Bundler) for plugin installation and loading.
30
+ * It's easy to develop and test plugins for with the provied [RSpec](https://github.com/rspec/rspec) extras. Lita strongly encourages thorough testing of plugins.
31
+ * It uses the Ruby ecosystem's standard tools (RubyGems and Bundler) for plugin installation and loading.
32
32
  * It's thoroughly documented.
33
33
 
34
34
  ## Is it any good?
@@ -115,6 +115,14 @@ Lita: auth remove joe committers
115
115
 
116
116
  The first command adds a user whose ID or name is "joe" to the authorization group "committers." If the group doesn't yet exist, it is created. The second command removes joe from the group. Handlers can specify that a route (a method that matches an incoming message) requires that the user sending the message be in a certain authorization group. See the section on writing handlers for more details.
117
117
 
118
+ To list all the authorization groups and the names of the users in them, send Lita this command:
119
+
120
+ ```
121
+ Lita: auth list
122
+ ```
123
+
124
+ You can optionally suffix the command with the name of a group if you're only interested in the memebers of one group.
125
+
118
126
  ## Online help
119
127
 
120
128
  Message Lita `help` for a list of commands it knows about. You can also message it `help FOO` to list only commands beginning with FOO.
@@ -208,6 +216,8 @@ Additionally, handlers have access to these top-level methods:
208
216
  * `redis` - A `Redis::Namespace` object which provides each handler with its own isolated Redis store, suitable for many data persistence and manipulation tasks.
209
217
  * `http` - A `Faraday::Connection` object for making HTTP requests. Takes an optional hash of options and optional block which are passed on to [Faraday](https://github.com/lostisland/faraday).
210
218
 
219
+ If a handler method crashes, the backtrace will be output to Lita's log with the `:error` level, but it will not crash the robot itself.
220
+
211
221
  ### HTTP routes
212
222
 
213
223
  In addition to chat routes, handlers can also define HTTP routes for the built-in web server. This is done with the class-level `http` method. `http` returns a `Lita::HTTPRoute` object, which has methods for the most common HTTP methods. These methods take two arguments: the path for the route, and the name of the method that it will invoke as a symbol. The callback method takes two arguments: a `Rack::Request` and a `Rack::Response`. For example:
@@ -382,11 +392,12 @@ There are a few things worth mentioning when deploying an instance of Lita to He
382
392
 
383
393
  1. Your Procfile should contain one process: `web: bundle exec lita`.
384
394
 
385
- 1. To use the Redis To Go add-on, configure Lita's redis connection like this:
395
+ 1. To use the Redis To Go add-on and the HTTP port set by Heroku, configure Lita like this:
386
396
 
387
397
  ``` ruby
388
398
  Lita.configure do |config|
389
399
  config.redis.url = ENV["REDISTOGO_URL"]
400
+ config.http.port = ENV["PORT"]
390
401
  end
391
402
  ```
392
403
 
@@ -396,6 +407,10 @@ There are a few things worth mentioning when deploying an instance of Lita to He
396
407
 
397
408
  Complete documentation for all of Lita's classes and methods can be found at [rdoc.info](http://rdoc.info/gems/lita/frames).
398
409
 
410
+ ## Try it out
411
+
412
+ You can chat with an instance of Lita on the Freenode IRC network in the channel `#litabot`. The bot's name is also *Litabot*.
413
+
399
414
  ## History
400
415
 
401
416
  For a history of releases, see the [Releases](https://github.com/jimmycuadra/lita/releases) page.
@@ -41,6 +41,23 @@ module Lita
41
41
  Array(Lita.config.robot.admins).include?(user.id)
42
42
  end
43
43
 
44
+ # Returns a list of all authorization groups.
45
+ # @return [Array<Symbol>] The names of all authorization groups.
46
+ def groups
47
+ redis.keys("*").map(&:to_sym)
48
+ end
49
+
50
+ # Returns a hash of authorization group names and the users in them.
51
+ # @return [Hash] A map of +Symbol+ group names to +Lita::User+ objects.
52
+ def groups_with_users
53
+ groups.inject({}) do |list, group|
54
+ list[group] = redis.smembers(group).map do |user_id|
55
+ User.find_by_id(user_id)
56
+ end
57
+ list
58
+ end
59
+ end
60
+
44
61
  private
45
62
 
46
63
  # Ensures that group names are stored consistently in Redis.
data/lib/lita/handler.rb CHANGED
@@ -56,10 +56,18 @@ module Lita
56
56
  Lita.logger.debug <<-LOG.chomp
57
57
  Dispatching message to #{self}##{route.method_name}.
58
58
  LOG
59
- new(robot).public_send(route.method_name, Response.new(
60
- message,
61
- matches: message.match(route.pattern)
62
- ))
59
+ begin
60
+ new(robot).public_send(route.method_name, Response.new(
61
+ message,
62
+ matches: message.match(route.pattern)
63
+ ))
64
+ rescue Exception => e
65
+ Lita.logger.error <<-ERROR.chomp
66
+ #{name} crashed. The exception was:
67
+ #{e.message}
68
+ #{e.backtrace.join("\n")}
69
+ ERROR
70
+ end
63
71
  end
64
72
  end
65
73
  end
@@ -8,6 +8,12 @@ module Lita
8
8
  route(/^auth\s+remove/, :remove, command: true, help: {
9
9
  "auth remove USER GROUP" => "Remove USER from authorization group GROUP. Requires admin privileges."
10
10
  })
11
+ route(/^auth\s+list/, :list, command: true, help: {
12
+ "auth list [GROUP]" => <<-HELP
13
+ List authorization groups and the users in them. If GROUP is supplied, only \
14
+ lists that group."
15
+ HELP
16
+ })
11
17
 
12
18
  # Adds a user to an authorization group.
13
19
  # @param response [Lita::Response] The response object.
@@ -45,8 +51,40 @@ module Lita
45
51
  end
46
52
  end
47
53
 
54
+ # Lists all authorization groups (or only the specified group) and the
55
+ # names of their members.
56
+ # @param response [Lita::Response] The response object.
57
+ # @return [void]
58
+ def list(response)
59
+ requested_group = response.args[1]
60
+ output = get_groups_list(requested_group)
61
+ if output.empty?
62
+ if requested_group
63
+ response.reply(
64
+ "There is no authorization group named #{requested_group}."
65
+ )
66
+ else
67
+ response.reply("There are no authorization groups yet.")
68
+ end
69
+ else
70
+ response.reply(output.join("\n"))
71
+ end
72
+ end
73
+
48
74
  private
49
75
 
76
+ def get_groups_list(requested_group)
77
+ groups_with_users = Lita::Authorization.groups_with_users
78
+ if requested_group
79
+ requested_group = requested_group.downcase.strip.to_sym
80
+ groups_with_users.select! { |group, _| group == requested_group }
81
+ end
82
+ groups_with_users.map do |group, users|
83
+ user_names = users.map { |u| u.name }.join(", ")
84
+ "#{group}: #{user_names}"
85
+ end
86
+ end
87
+
50
88
  # Validates that incoming messages have the right format and a valid user.
51
89
  # Also assigns the user and group to instance variables for the main
52
90
  # methods to use later.
data/lib/lita/rspec.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  begin
2
2
  require "rspec"
3
+ require "rspec/expectations"
4
+ require "rspec/mocks"
3
5
  rescue LoadError
4
6
  abort "Lita::RSpec requires both RSpec::Mocks and RSpec::Expectations."
5
7
  end
data/lib/lita/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Lita
2
2
  # The current version of Lita.
3
- VERSION = "2.0.0"
3
+ VERSION = "2.1.0"
4
4
  end
data/lita.gemspec CHANGED
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
29
29
  spec.add_runtime_dependency "thor", "~> 0.18.1"
30
30
 
31
31
  spec.add_development_dependency "rake"
32
- spec.add_development_dependency "rspec", ">= 2.14.0rc1"
32
+ spec.add_development_dependency "rspec", "~> 2.14"
33
33
  spec.add_development_dependency "simplecov"
34
34
  spec.add_development_dependency "coveralls"
35
35
  spec.add_development_dependency "pry"
@@ -73,4 +73,42 @@ describe Lita::Authorization, lita: true do
73
73
  expect(described_class.user_is_admin?(user)).to be_false
74
74
  end
75
75
  end
76
+
77
+ describe ".groups" do
78
+ before do
79
+ %i{foo bar baz}.each do |group|
80
+ described_class.add_user_to_group(requesting_user, user, group)
81
+ end
82
+ end
83
+
84
+ it "returns a list of all authorization groups" do
85
+ expect(described_class.groups).to match_array(%i{foo bar baz})
86
+ end
87
+ end
88
+
89
+ describe ".groups_with_users" do
90
+ before do
91
+ %i{foo bar baz}.each do |group|
92
+ described_class.add_user_to_group(requesting_user, user, group)
93
+ described_class.add_user_to_group(
94
+ requesting_user,
95
+ requesting_user,
96
+ group
97
+ )
98
+ end
99
+ allow(Lita::User).to receive(:find_by_id).with("1").and_return(
100
+ requesting_user
101
+ )
102
+ allow(Lita::User).to receive(:find_by_id).with("2").and_return(user)
103
+ end
104
+
105
+ it "returns a hash of all authorization groups and their members" do
106
+ groups = %i{foo bar baz}
107
+ groups_with_users = described_class.groups_with_users
108
+ expect(groups_with_users.keys).to match_array(groups)
109
+ groups.each do |group|
110
+ expect(groups_with_users[group]).to match_array([user, requesting_user])
111
+ end
112
+ end
113
+ end
76
114
  end
@@ -1,6 +1,6 @@
1
1
  require "spec_helper"
2
2
 
3
- describe Lita::Handler do
3
+ describe Lita::Handler, lita: true do
4
4
  let(:robot) { double("Lita::Robot", name: "Lita") }
5
5
  let(:user) { double("Lita::User") }
6
6
 
@@ -15,6 +15,7 @@ describe Lita::Handler do
15
15
  route(/\w{3}/, :foo)
16
16
  route(/\w{4}/, :blah, command: true)
17
17
  route(/secret/, :secret, restrict_to: :admins)
18
+ route(/danger/, :danger)
18
19
 
19
20
  http.get "web", :web
20
21
 
@@ -30,6 +31,10 @@ describe Lita::Handler do
30
31
  def web(request, response)
31
32
  end
32
33
 
34
+ def danger(response)
35
+ raise "The developer of this handler's got a bug in their code!"
36
+ end
37
+
33
38
  def self.name
34
39
  "Lita::Handlers::Test"
35
40
  end
@@ -85,6 +90,14 @@ describe Lita::Handler do
85
90
  expect_any_instance_of(handler_class).not_to receive(:secret)
86
91
  handler_class.dispatch(robot, message)
87
92
  end
93
+
94
+ it "logs exceptions but doesn't crash the bot" do
95
+ allow(message).to receive(:body).and_return("#{robot.name}: danger")
96
+ expect(Lita.logger).to receive(:error).with(
97
+ %r{Lita::Handlers::Test crashed}
98
+ )
99
+ expect { handler_class.dispatch(robot, message) }.not_to raise_error
100
+ end
88
101
  end
89
102
 
90
103
  describe ".namespace" do
@@ -13,6 +13,8 @@ describe Lita::Handlers::Authorization, lita_handler: true do
13
13
  it { routes_command("auth add foo@bar.com baz").to(:add) }
14
14
  it { routes_command("auth remove foo bar").to(:remove) }
15
15
  it { routes_command("auth remove foo@bar.com baz").to(:remove) }
16
+ it { routes_command("auth list").to(:list) }
17
+ it { routes_command("auth list foo").to(:list) }
16
18
 
17
19
  describe "#add" do
18
20
  it "replies with the proper format if the require commands are missing" do
@@ -73,4 +75,44 @@ describe Lita::Handlers::Authorization, lita_handler: true do
73
75
  expect(replies.last).to match(/Only administrators can remove/)
74
76
  end
75
77
  end
78
+
79
+ describe "#list" do
80
+ context "when there are populated groups" do
81
+ let(:groups) { %i{foo bar} }
82
+ let(:user1) { Lita::User.create(3, name: "Bongo") }
83
+ let(:user2) { Lita::User.create(4, name: "Carl") }
84
+
85
+ before do
86
+ groups.each do |group|
87
+ Lita::Authorization.add_user_to_group(user, user1, group)
88
+ Lita::Authorization.add_user_to_group(user, user2, group)
89
+ end
90
+ end
91
+
92
+ it "lists all authorization groups and their members" do
93
+ send_command("auth list")
94
+ groups.each do |group|
95
+ expect(replies.last).to include(
96
+ "#{group}: #{user1.name}, #{user2.name}"
97
+ )
98
+ end
99
+ end
100
+
101
+ it "lists only the requested group" do
102
+ send_command("auth list foo")
103
+ expect(replies.last).to include("foo")
104
+ expect(replies.last).not_to include("bar")
105
+ end
106
+ end
107
+
108
+ it "replies that there are no groups" do
109
+ send_command("auth list")
110
+ expect(replies.last).to include("no authorization groups yet")
111
+ end
112
+
113
+ it "replies that the specified group doesn't exist" do
114
+ send_command("auth list nothing")
115
+ expect(replies.last).to include("no authorization group named nothing")
116
+ end
117
+ end
76
118
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lita
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jimmy Cuadra
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-06 00:00:00.000000000 Z
11
+ date: 2013-07-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -126,16 +126,16 @@ dependencies:
126
126
  name: rspec
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - '>='
129
+ - - ~>
130
130
  - !ruby/object:Gem::Version
131
- version: 2.14.0rc1
131
+ version: '2.14'
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - '>='
136
+ - - ~>
137
137
  - !ruby/object:Gem::Version
138
- version: 2.14.0rc1
138
+ version: '2.14'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: simplecov
141
141
  requirement: !ruby/object:Gem::Requirement