lita-announce 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 23650169379196bfa169ae3a9cd0f7001ad15afd
4
+ data.tar.gz: 1be5ebe6151241ddf78f63a47580b22158be9d5b
5
+ SHA512:
6
+ metadata.gz: 1eb346cffc8598e74d029ccf8a5fc34181d72461957513887cb8a0e430b807cb0755faadc009cc5f314188b2e4c22e042a1719140c8337a4b02f958189eaaf2e
7
+ data.tar.gz: aa2dc780020dfc97944cf70caad48faabdb2edb1ae7196c3c8add13a76dd41a3854ad74dbebe936dc5adaf6fe1afc84bb3c9102c1e9007ee582339d8864d6c4c
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,16 @@
1
+ # Use Travis's cointainer based infrastructure
2
+ sudo: false
3
+
4
+ rvm:
5
+ - 2.3.1
6
+
7
+ bundler_args: --jobs 7
8
+
9
+ services:
10
+ - redis-server
11
+
12
+ branches:
13
+ only:
14
+ - master
15
+
16
+ script: bundle exec rake
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # lita-announce
2
+
3
+ Quick and easy way to share content with multiple channels.
4
+
5
+ ## Installation
6
+
7
+ Add lita-announce to your Lita instance's Gemfile:
8
+
9
+ ``` ruby
10
+ gem "lita-announce"
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ @lita announce to <channels> <content>
16
+ @lita announce to <groups> <content>
17
+ @lita announce list-groups
18
+ @lita announce add-group <name> <channels>
19
+ @lita announce mod-group <name> <channels>
20
+ @lita announce del-group <name>
21
+
22
+ ### Managing Groups
23
+
24
+ #### list-groups
25
+
26
+ @lita announce list-groups
27
+ Group1: #channel1, #channel2, #channel3
28
+ Group2: #channel1, #channel4
29
+
30
+ #### add-group
31
+ Each group must have a unique name that contains only letters, numbers, and underscores.
32
+
33
+ @lita announce add-group devs foo-dev,bar-dev,baz-dev
34
+
35
+ #### mod-group
36
+ Modify the list of channels in a group. Must provide the full list.
37
+
38
+ @lita announce mod-group devs foo-dev,bar-dev,baz-dev,super-dev
39
+
40
+ #### del-group
41
+ Delete a group.
42
+
43
+ @lita announce del-group devs
44
+
45
+ ### Making Announcements
46
+
47
+ #### Send a message to multiple channels
48
+
49
+ @lita announce to general,random Hey everyone! All hands is starting in five minutes! Join us in #all-hands-meeting. :smile:
50
+
51
+ ### Share a message with a pre-configured group of channels
52
+
53
+ @lita announce add-group devs foo-dev,bar-dev,baz-dev
54
+
55
+ @lita announce to group:devs Don't forget to turn in your TPS reports!
56
+
57
+ ### Share a link with several pre-configured groups of channels
58
+
59
+ @lita announce add-group devs foo-dev,bar-dev,baz-dev
60
+ @lita announce add-group foo-announcements foo-dev,foo-announce,foo-discuss
61
+
62
+ @lita announce to group:foo-announcements,group:devs Hey everyone! Thanks for your combined effort to get foo out the door!
63
+
64
+ And don't worry! Messages will only get send to channels once, even if they are part of multiple groups!
65
+
66
+ ### Share a link with a combination of groups and channels
67
+
68
+ @lita announce add-group devs foo-dev,bar-dev,baz-dev
69
+
70
+ @lita announce to group:devs,general Hey everyone! Make sure that you get your TPS reports in on time this week.
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require "chefstyle"
2
+ require "bundler/gem_tasks"
3
+ require "rspec/core/rake_task"
4
+ require "rubocop/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new
7
+
8
+ desc " Run ChefStyle"
9
+ RuboCop::RakeTask.new(:chefstyle) do |task|
10
+ task.options << "--display-cop-names"
11
+ end
12
+
13
+ task default: [:spec, :chefstyle]
data/dev/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "lita"
4
+ gem "lita-slack"
5
+ gem "lita-announce", path: "../"
@@ -0,0 +1,7 @@
1
+ Lita.configure do |config|
2
+ config.robot.log_level = :debug
3
+ config.robot.adapter = :slack
4
+ config.robot.admins = ["1"]
5
+
6
+ config.adapters.slack.token = ENV["SLACK_TOKEN"]
7
+ end
@@ -0,0 +1,12 @@
1
+ require "lita"
2
+
3
+ Lita.load_locales Dir[File.expand_path(
4
+ File.join("..", "..", "locales", "*.yml"), __FILE__
5
+ )]
6
+
7
+ require "lita/handlers/announce"
8
+
9
+ Lita::Handlers::Announce.template_root File.expand_path(
10
+ File.join("..", "..", "templates"),
11
+ __FILE__
12
+ )
@@ -0,0 +1,188 @@
1
+ #
2
+ # Copyright:: Copyright 2016 Chef Software, Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ #     http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require "json"
19
+ require "time"
20
+
21
+ module Lita
22
+ module Handlers
23
+ class Announce < Handler
24
+
25
+ config :announcements_to_keep, default: 10
26
+
27
+ route(
28
+ /^announce\s+list-groups/i,
29
+ :handle_list_groups,
30
+ command: true,
31
+ help: {
32
+ "announce list-groups" => "list-groups",
33
+ }
34
+ )
35
+
36
+ route(
37
+ /^announce\s+add-group\s+(.+)/i,
38
+ :handle_mod_group,
39
+ command: true,
40
+ help: {
41
+ "announce add-group" => "add-group <name> <channels>",
42
+ }
43
+ )
44
+
45
+ route(
46
+ /^announce\s+mod-group\s+(.+)/i,
47
+ :handle_mod_group,
48
+ command: true,
49
+ help: {
50
+ "announce mod-group" => "mod-group <name> <channels>",
51
+ }
52
+ )
53
+
54
+ route(
55
+ /^announce\s+del-group\s+(.+)/i,
56
+ :handle_del_group,
57
+ command: true,
58
+ help: {
59
+ "announce del-group" => "del-group <name>",
60
+ }
61
+ )
62
+
63
+ route(
64
+ /^announce\s+to\s+(.+)/i,
65
+ :handle_announce,
66
+ command: true,
67
+ help: {
68
+ "announce" => "announce to <groups and channels> <message>",
69
+ }
70
+ )
71
+
72
+ def handle_list_groups(response)
73
+ results = []
74
+ redis.scan_each do |key|
75
+ if key =~ /^group:(\w+)$/
76
+ channels = JSON.parse(redis.get(key))["channels"]
77
+ results << "*#{$1}*: #{channels.map { |c| "\##{c}" }.join(", ")}"
78
+ end
79
+ end
80
+ response.reply(results.join("\n"))
81
+ end
82
+
83
+ def handle_mod_group(response)
84
+ group = response.args[1]
85
+ channels = response.args[2]
86
+
87
+ unless group =~ /^\w+$/
88
+ response.reply(":failed: '#{group}' is not a valid name. Please use only letters, numbers, and underscores.")
89
+ return
90
+ end
91
+
92
+ unless response.args[3].nil?
93
+ response.reply(":failed: Please provide channels as a comma-separated list with no spaces.")
94
+ return
95
+ end
96
+
97
+ channel_array = channels.split(",").map { |c| c.gsub(/^\#/, "") }
98
+
99
+ all_channels_exist = true
100
+ channel_array.each do |c|
101
+ if Lita::Room.fuzzy_find(c).nil?
102
+ response.reply(":failed: Can not create '#{group}': the \##{c} channel does not exist.")
103
+ all_channels_exist = false
104
+ end
105
+ end
106
+ return unless all_channels_exist
107
+
108
+ redis.set("group:#{group}", { channels: channel_array }.to_json)
109
+ response.reply(":successful: Announcement group '#{group}' updated! Will send messages to #{channel_array.map { |c| "\##{c}" }.join(", ")}")
110
+ end
111
+
112
+ def handle_del_group(response)
113
+ group = response.args[1]
114
+
115
+ if redis.get("group:#{group}").nil?
116
+ response.reply(":failed: Can not delete '#{group}': does not exist.")
117
+ return
118
+ end
119
+
120
+ redis.del("group:#{group}")
121
+ response.reply(":successful: Announcement group '#{group}' deleted.")
122
+ end
123
+
124
+ def handle_announce(response)
125
+ channels = parse_channels(response.args[1])
126
+ message = response.args[2..-1].join(" ")
127
+
128
+ return if channels.nil?
129
+
130
+ payload = {
131
+ author: response.user.name,
132
+ channels: channels.uniq,
133
+ text: message,
134
+ timestamp: DateTime.now.to_time.to_i,
135
+ }
136
+
137
+ save_announcement(payload)
138
+ make_announcement_to_channels(payload)
139
+ end
140
+
141
+ def parse_channels(targets)
142
+ channels = []
143
+ targets.split(",").each do |target|
144
+ c = parse_target(target)
145
+
146
+ if c.nil?
147
+ response.reply(":failed: Could not send message: the group '#{target}' could not be found.")
148
+ return nil
149
+ else
150
+ channels.concat(c)
151
+ end
152
+ end
153
+ channels
154
+ end
155
+
156
+ def save_announcement(payload)
157
+ redis.lpush("announcements", payload.to_json)
158
+ redis.ltrim("announcements", 0, config.announcements_to_keep - 1)
159
+ end
160
+
161
+ def make_announcement_to_channels(payload)
162
+ payload[:channels].each do |c|
163
+ channel = Lita::Source.new(room: Lita::Room.fuzzy_find(c))
164
+ robot.send_message(channel, "#{payload[:text]} - #{payload[:author]}")
165
+ end
166
+ end
167
+
168
+ def parse_target(target)
169
+ if target =~ /^group:(\w+)$/
170
+ group = redis.get(target)
171
+ return nil if group.nil?
172
+ JSON.parse(group)["channels"]
173
+ else
174
+ [target]
175
+ end
176
+ end
177
+
178
+ def attachment_for(payload)
179
+ options = {
180
+
181
+ }
182
+ Lita::Adapters::Slack::Attachment.new(payload[:message], options)
183
+ end
184
+
185
+ Lita.register_handler(self)
186
+ end
187
+ end
188
+ end
@@ -0,0 +1,25 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "lita-announce"
3
+ spec.version = "0.1.0"
4
+ spec.authors = ["Tom Duffield"]
5
+ spec.email = ["tom@chef.io"]
6
+ spec.description = "Lita plugin to make announcements across multiple channels."
7
+ spec.summary = "Lita plugin to make announcements across multiple channels."
8
+ spec.homepage = "http://github.com/tduffield/lita-announce"
9
+ spec.license = "Apache 2.0"
10
+ spec.metadata = { "lita_plugin_type" => "handler" }
11
+
12
+ spec.files = `git ls-files`.split($/)
13
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
14
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
15
+ spec.require_paths = ["lib"]
16
+
17
+ spec.add_runtime_dependency "lita", ">= 4.7"
18
+ spec.add_runtime_dependency "json", "~> 2.0.0"
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.3"
21
+ spec.add_development_dependency "pry-byebug"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rack-test"
24
+ spec.add_development_dependency "rspec", ">= 3.0.0"
25
+ end
data/locales/en.yml ADDED
@@ -0,0 +1,4 @@
1
+ en:
2
+ lita:
3
+ handlers:
4
+ announce:
@@ -0,0 +1,179 @@
1
+ require "spec_helper"
2
+
3
+ describe Lita::Handlers::Announce, lita_handler: true do
4
+
5
+ it { is_expected.to route_command("announce list-groups").to(:handle_list_groups) }
6
+ it { is_expected.to route_command("announce add-group name channels").to(:handle_mod_group) }
7
+ it { is_expected.to route_command("announce mod-group name channels").to(:handle_mod_group) }
8
+ it { is_expected.to route_command("announce del-group name").to(:handle_del_group) }
9
+ it { is_expected.to route_command("announce to channel message").to(:handle_announce) }
10
+ it { is_expected.to route_command("announce to group:group1 message").to(:handle_announce) }
11
+ it { is_expected.to route_command("announce to channel1,channel2 message").to(:handle_announce) }
12
+ it { is_expected.to route_command("announce to group:group1,group:group2 messae").to(:handle_announce) }
13
+ it { is_expected.to route_command("announce to group:group1,channel1,group:group2 message").to(:handle_announce) }
14
+
15
+ let(:network_group) { %w{abc fox cbs nbc} }
16
+ let(:premium_group) { %w{hbo showtime cinemax} }
17
+ let(:my_favorites) { %w{discover hbo science cbs} }
18
+ let(:all_channels) { [premium_group, network_group, my_favorites].flatten.uniq }
19
+
20
+ before do
21
+ all_channels.each { |c| Lita::Room.create_or_update(c) }
22
+ allow(robot.chat_service).to receive(:send_attachment) # This is provided by lita-slack
23
+ end
24
+
25
+ describe "list-groups" do
26
+ before { subject.redis.set("group:network", { channels: network_group }.to_json) }
27
+
28
+ it "returns a list of groups" do
29
+ send_command("announce list-groups")
30
+ expect(replies.last).to eql("\*network\*: #{network_group.map { |c| "##{c}" }.join(", ")}")
31
+ end
32
+ end
33
+
34
+ shared_examples_for "group channel modification validation" do
35
+ it "adds group to redis" do
36
+ send_command(command)
37
+ expect(subject.redis.get("group:premium")).to eql({ channels: premium_group }.to_json)
38
+ expect(replies.last).to eql(":successful: Announcement group 'premium' updated! Will send messages to #{premium_group.map { |c| "##{c}" }.join(", ")}")
39
+ end
40
+
41
+ context "when group name is invalid" do
42
+ let(:group) { "premium:movies" }
43
+
44
+ it "returns an error message" do
45
+ send_command(command)
46
+ expect(replies.last).to eql(":failed: '#{group}' is not a valid name. Please use only letters, numbers, and underscores.")
47
+ end
48
+ end
49
+
50
+ context "when a channel provided does not exist" do
51
+ let(:channels) { premium_group.push("skinemax").join(",") }
52
+
53
+ it "returns an error message" do
54
+ send_command(command)
55
+ expect(replies.last).to eql(":failed: Can not create '#{group}': the #skinemax channel does not exist.")
56
+ end
57
+ end
58
+
59
+ context "when the channel list is formatted incorrectly" do
60
+ let(:channels) { premium_group.join(" ") }
61
+
62
+ it "returns an error message" do
63
+ send_command(command)
64
+ expect(replies.last).to eql(":failed: Please provide channels as a comma-separated list with no spaces.")
65
+ end
66
+ end
67
+ end
68
+
69
+ describe "add-group" do
70
+ let(:group) { "premium" }
71
+ let(:channels) { premium_group.join(",") }
72
+ let(:command) { "announce add-group #{group} #{channels}" }
73
+
74
+ it_behaves_like "group channel modification validation"
75
+ end
76
+
77
+ describe "mod-group" do
78
+ let(:group) { "premium" }
79
+ let(:channels) { premium_group.push("starz").join(",") }
80
+ let(:command) { "announce mod-group #{group} #{channels}" }
81
+
82
+ before do
83
+ subject.redis.set("group:premium", { channels: premium_group }.to_json)
84
+ Lita::Room.create_or_update("starz")
85
+ end
86
+
87
+ it_behaves_like "group channel modification validation"
88
+ end
89
+
90
+ describe "del-group" do
91
+ let(:group) { "premium" }
92
+ let(:command) { "announce del-group #{group}" }
93
+
94
+ before { subject.redis.set("group:premium", { channels: premium_group }.to_json) }
95
+
96
+ it "deletes group from redis" do
97
+ send_command(command)
98
+ expect(subject.redis.get("group:#{group}")).to be_nil
99
+ expect(replies.last).to eql(":successful: Announcement group '#{group}' deleted.")
100
+ end
101
+
102
+ context "when group does not exist" do
103
+ let(:group) { "static-only" }
104
+
105
+ it "returns error message" do
106
+ send_command(command)
107
+ expect(replies.last).to eql(":failed: Can not delete '#{group}': does not exist.")
108
+ end
109
+ end
110
+ end
111
+
112
+ describe "making an announcement" do
113
+ let(:message) { "Everyone just watches Netflix anyways" }
114
+ let(:command) { "announce to #{targets} #{message}" }
115
+ let(:payload) do
116
+ {
117
+ author: user.name,
118
+ channels: expected_channels.uniq,
119
+ text: message,
120
+ timestamp: DateTime.now.to_time.to_i,
121
+ }
122
+ end
123
+
124
+ before do
125
+ subject.redis.set("group:premium", { channels: premium_group }.to_json)
126
+ subject.redis.set("group:network", { channels: network_group }.to_json)
127
+ subject.redis.set("group:my_favorites", { channels: my_favorites }.to_json)
128
+ end
129
+
130
+ shared_examples_for "an announcement" do
131
+ let(:expected_message) { "#{payload[:text]} - #{payload[:author]}" }
132
+ it "writes the message to redis" do
133
+ send_command(command)
134
+ expect(subject.redis.lpop("announcements")).to eql(payload.to_json)
135
+ end
136
+
137
+ it "sends message" do
138
+ send_command(command)
139
+ expect(replies.length).to eql(payload[:channels].length)
140
+ expect(replies.last).to eql(expected_message)
141
+ end
142
+ end
143
+
144
+ context "to a single channel" do
145
+ let(:targets) { "cbs" }
146
+ let(:expected_channels) { %w{cbs} }
147
+
148
+ it_behaves_like "an announcement"
149
+ end
150
+
151
+ context "to multiple channels" do
152
+ let(:targets) { "cbs,hbo" }
153
+ let(:expected_channels) { %w{cbs hbo} }
154
+
155
+ it_behaves_like "an announcement"
156
+ end
157
+
158
+ context "to a single group" do
159
+ let(:targets) { "group:premium" }
160
+ let(:expected_channels) { premium_group }
161
+
162
+ it_behaves_like "an announcement"
163
+ end
164
+
165
+ context "to multiple groups" do
166
+ let(:targets) { "group:premium,group:network,group:my_favorites" }
167
+ let(:expected_channels) { all_channels }
168
+
169
+ it_behaves_like "an announcement"
170
+ end
171
+
172
+ context "to a combination of groups and channels" do
173
+ let(:targets) { "group:premium,fox,cbs" }
174
+ let(:expected_channels) { premium_group.concat(%w{fox cbs}) }
175
+
176
+ it_behaves_like "an announcement"
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,6 @@
1
+ require "lita-announce"
2
+ require "lita/rspec"
3
+
4
+ # A compatibility mode is provided for older plugins upgrading from Lita 3. Since this plugin
5
+ # was generated with Lita 4, the compatibility mode should be left disabled.
6
+ Lita.version_3_compatibility_mode = false
File without changes
metadata ADDED
@@ -0,0 +1,159 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lita-announce
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Tom Duffield
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-12-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: lita
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4.7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '4.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: json
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry-byebug
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rack-test
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 3.0.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: 3.0.0
111
+ description: Lita plugin to make announcements across multiple channels.
112
+ email:
113
+ - tom@chef.io
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".gitignore"
119
+ - ".travis.yml"
120
+ - Gemfile
121
+ - README.md
122
+ - Rakefile
123
+ - dev/Gemfile
124
+ - dev/lita_config.rb
125
+ - lib/lita-announce.rb
126
+ - lib/lita/handlers/announce.rb
127
+ - lita-announce.gemspec
128
+ - locales/en.yml
129
+ - spec/lita/handlers/announce_spec.rb
130
+ - spec/spec_helper.rb
131
+ - templates/.gitkeep
132
+ homepage: http://github.com/tduffield/lita-announce
133
+ licenses:
134
+ - Apache 2.0
135
+ metadata:
136
+ lita_plugin_type: handler
137
+ post_install_message:
138
+ rdoc_options: []
139
+ require_paths:
140
+ - lib
141
+ required_ruby_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ required_rubygems_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ requirements: []
152
+ rubyforge_project:
153
+ rubygems_version: 2.6.8
154
+ signing_key:
155
+ specification_version: 4
156
+ summary: Lita plugin to make announcements across multiple channels.
157
+ test_files:
158
+ - spec/lita/handlers/announce_spec.rb
159
+ - spec/spec_helper.rb