slack_message 2.2.0 → 2.3.1

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
  SHA256:
3
- metadata.gz: 368533ab7e4dae44ffbef5ccf8afef048def96d964a6af64c294c23ba617dfa3
4
- data.tar.gz: f9397472bbc5c5db81dd1c9d7715e5015f4ec455948e7a29afbb11ef8c8a3d01
3
+ metadata.gz: 25b5670dec5c6c5d2ba870180aa636f192cce3c9d899936337f553bc18108b7d
4
+ data.tar.gz: 47bd6ff799803ce186cdd01057dfa47a852422c715a2d1c550a6d41fc484ba18
5
5
  SHA512:
6
- metadata.gz: 5cce143a95d508694221f1c667428f850ce7aa537e73f61c1869498b68a5751afe2ac386215b96702a1a27bcad3758c474ba09870a1cd7a31a7c33a17ebd4d53
7
- data.tar.gz: 7f81e1876f231899588b174c87c4a0a3ca3bcbc4057216092311b300cff7d23d6541083b5e481e811795042538e2e6713b1a9f5eb5f6eba345e79960335cad91
6
+ metadata.gz: 022ca4f2ffb28a3976be37d7104fd59e3ed296d406bf90176b4745c36880a159306112eb444ca1a1151720ad1cdb6a08e2b2779ad1ff2151e837fbee925c5808
7
+ data.tar.gz: a3f3d4c889e7c4036c2063f0ef038c54f515779526c6d4a9b0858e5e812bf2ba6667e08298b63988a074f82066c8d7eb9494b3d02d6c4785ff291cbfc7824f75
@@ -0,0 +1,27 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ test:
11
+ strategy:
12
+ matrix:
13
+ os: [ubuntu-latest, macos-latest]
14
+ ruby-version: [3.0, 2.7, 2.6, 2.5]
15
+ runs-on: ${{ matrix.os }}
16
+
17
+ steps:
18
+ - uses: actions/checkout@v2
19
+ - name: Set up Ruby ${{ matrix.ruby-version }}
20
+ uses: ruby/setup-ruby@v1
21
+ with:
22
+ ruby-version: ${{ matrix.ruby-version }}
23
+ bundler-cache: true
24
+ - name: Install dependencies
25
+ run: bundle install
26
+ - name: Run tests
27
+ run: bundle exec rspec
data/.gitignore CHANGED
@@ -1 +1,2 @@
1
+ Gemfile.lock
1
2
  slack_message*.gem
data/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.3.1] - 2021-11-30
4
+ - Adjust that minimum version by changing some syntax to older styles. Given
5
+ support for ruby 2.4 ended almost 2 years ago, going to go ahead and leave
6
+ it behind.
7
+ - Remove lockfile from repo
8
+
9
+ ## [2.3.0] - 2021-11-30
10
+ - Formally require minimum version of ruby. It wouldn't have worked anyway,
11
+ but worth actually specifying.
12
+
13
+ ## [2.2.2] - 2021-11-30
14
+ - Add github workflow for automatic CI runs. Stolen from another project.
15
+
16
+ ## [2.2.1] - 2021-11-20
17
+ - Trying to fetch user ID for a string that isn't email-like raises an error.
18
+ - In tests, fetching user IDs is mocked out to prevent network requests.
19
+ - Tightened up and clarified README.
20
+ - Some internal cleanup and restructuring of modules.
21
+
3
22
  ## [2.2.0] - 2021-11-20
4
23
  - When sending text, it is now possible to mention users and have their user
5
24
  IDs automatically converted using `<email@email.com>` within text nodes.
data/README.md CHANGED
@@ -15,19 +15,21 @@ end
15
15
 
16
16
  To install, just add `slack_message` to your bundle and you're ready to go.
17
17
 
18
- Opinionated Stances
19
- ------------
18
+ #### Opinionated Stances
20
19
 
21
20
  Slack's API has a lot of options available to you! But this gem takes some
22
- opinionated stances on how to make use of that API. For instance:
21
+ opinionated stances about usage to try to minimize the pain of integrating
22
+ with it. For example:
23
23
 
24
- * No dependencies. Your lockfile is enough of a mess already.
24
+ * SlackMessage has no dependencies. Your lockfile is enough of a mess already.
25
+ * The code to build a message should look a lot like the message itself. Code
26
+ that is simple to read and understand is a priority.
25
27
  * Webhooks are passé. Only Slack Apps are supported now.
26
28
  * Unless you request otherwise, text is always rendered using `mrkdwn`. If you
27
29
  want plaintext, you'll need to ask for it. Same for the `emoji` flag.
28
30
  * As many API semantics as possible are hidden. For instance, if you post to
29
- something that looks like an email address, `slack_message` is going to try to
30
- look it up as an email address.
31
+ something that looks like an email address, `slack_message` is going to try
32
+ to look it up as an email address.
31
33
  * A few little hacks on the block syntax, such as adding a `blank_line` (which
32
34
  doesn't exist in the API), or leading spaces.
33
35
  * Configuration is kept as simple as possible. But, as much heavy lifting as
@@ -173,9 +175,7 @@ It's just as easy to send messages directly to users. SlackMessage will look for
173
175
  targets that are email-addressish, and look them up for you automatically:
174
176
 
175
177
  ```ruby
176
- user_email = 'hello@joemastey.com'
177
-
178
- SlackMessage.post_to(user_email) do
178
+ SlackMessage.post_to('hello@joemastey.com') do
179
179
  text "You specifically did it! :thumbsup:"
180
180
  end
181
181
  ```
@@ -207,15 +207,13 @@ SlackMessage.post_to('#general') do
207
207
  text "See more here: #{link('result', 'https://google.com')}"
208
208
  end
209
209
 
210
- text ":rocketship: hello@joemastey.com"
210
+ text ":rocketship: <hello@joemastey.com>"
211
211
 
212
212
  context ":custom_slack_emoji: An example footer *with some markdown*."
213
213
  end
214
214
  ```
215
215
 
216
216
  SlackMessage will compose this into Block Kit syntax and send it on its way!
217
- For now you'll need to read a bit of the source code to get the entire API. Sorry,
218
- working on it.
219
217
 
220
218
  If you've defined multiple profiles in configuration, you can specify which to
221
219
  use for your message by specifying its name:
@@ -223,6 +221,7 @@ use for your message by specifying its name:
223
221
  ```ruby
224
222
  SlackMessage.post_to('#general', as: :sidekiq_bot) do
225
223
  text ":octagonal_sign: A job has failed permanently and needs to be rescued."
224
+
226
225
  link_button "Sidekiq Dashboard", sidekiq_dashboard_url, style: :danger
227
226
  end
228
227
  ```
@@ -261,16 +260,16 @@ SlackMessage.post_to('#general') do
261
260
  end
262
261
  ```
263
262
 
264
- Emails that are not wrapped in tags will be rendered as normal clickable email
265
- addresses. Additionally, Slack will automatically convert a number of channel
266
- names and tags you're probably already used to:
263
+ Emails that are not wrapped in tags will be rendered as normal email addresses.
264
+ Additionally, Slack will automatically convert a number of channel names and
265
+ tags you're probably already used to:
267
266
 
268
267
  ```ruby
269
268
  SlackMessage.post_to('#general') do
270
269
  bot_name "CoffeeBot"
271
270
  bot_icon ":coffee:"
272
271
 
273
- text "@here there's no coffee left!"
272
+ text "@here There's no coffee left! Let #general know when you fix it."
274
273
  end
275
274
  ```
276
275
 
@@ -303,8 +302,8 @@ RSpec.configure do |config|
303
302
  end
304
303
  ```
305
304
 
306
- This will stop API calls for posting messages, and will allow you access to
307
- some custom matchers:
305
+ This will prevent API calls from leaking in your tests, and will allow you
306
+ access to some custom matchers:
308
307
 
309
308
  ```ruby
310
309
  expect {
@@ -340,12 +339,12 @@ of very complicated regexes.
340
339
  What it Doesn't Do
341
340
  ------------
342
341
 
343
- This gem is intended to stay fairly simple. Other gems have lots of config
344
- options and abilities, which is wonderful, but overall complicates usage. If
345
- you want to add a feature, open an issue on Github first to see if it's likely
346
- to be merged. This gem was built out of an existing need that _didn't_ include
347
- most of the block API, but I'd be inclined to merge features that sustainably
348
- expand the DSL to include more useful features.
342
+ This gem is intended to stay simple. Other Slack gems have lots of config
343
+ options and abilities, which makes them powerful, but makes them a pain to use.
344
+ If you want to add a feature, open an issue on Github first to see if it's
345
+ likely to be merged. This gem was built out of an existing need that _didn't_
346
+ include all of the block API, but I'd be inclined to merge features that
347
+ sustainably expand the DSL to include more useful features.
349
348
 
350
349
  Some behaviors that are still planned but not yet added:
351
350
 
@@ -357,6 +356,7 @@ Some behaviors that are still planned but not yet added:
357
356
  * multiple recipients
358
357
  * more interesting return types for your message
359
358
  * richer text formatting (for instance, `ul` is currently a hack)
359
+ * more and better organized testing capability
360
360
 
361
361
  Contributing
362
362
  ------------
@@ -2,18 +2,16 @@ require 'net/http'
2
2
  require 'net/https'
3
3
  require 'json'
4
4
 
5
- class SlackMessage::Api
6
- def self.user_id_for(email, profile)
7
- uri = URI("https://slack.com/api/users.lookupByEmail?email=#{email}")
8
- request = Net::HTTP::Get.new(uri).tap do |req|
9
- req['Authorization'] = "Bearer #{profile[:api_token]}"
10
- req['Content-type'] = "application/json; charset=utf-8"
11
- end
5
+ module SlackMessage::Api
6
+ extend self
12
7
 
13
- response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
14
- http.request(request)
8
+ def user_id_for(email, profile)
9
+ unless email =~ SlackMessage::EMAIL_PATTERN
10
+ raise ArgumentError, "Tried to find profile by invalid email address '#{email}'"
15
11
  end
16
12
 
13
+ response = look_up_user_by_email(email, profile)
14
+
17
15
  if response.code != "200"
18
16
  raise SlackMessage::ApiError, "Got an error back from the Slack API (HTTP #{response.code}):\n#{response.body}"
19
17
  elsif response.body == ""
@@ -37,7 +35,7 @@ class SlackMessage::Api
37
35
  payload["user"]["id"]
38
36
  end
39
37
 
40
- def self.post(payload, target, profile)
38
+ def post(payload, target, profile)
41
39
  params = {
42
40
  channel: target,
43
41
  username: payload.custom_bot_name || profile[:name],
@@ -80,8 +78,23 @@ class SlackMessage::Api
80
78
  response
81
79
  end
82
80
 
83
- # mostly test harness
84
- def self.post_message(profile, params)
81
+ private
82
+
83
+ # mostly for test harnesses
84
+
85
+ def look_up_user_by_email(email, profile)
86
+ uri = URI("https://slack.com/api/users.lookupByEmail?email=#{email}")
87
+ request = Net::HTTP::Get.new(uri).tap do |req|
88
+ req['Authorization'] = "Bearer #{profile[:api_token]}"
89
+ req['Content-type'] = "application/json; charset=utf-8"
90
+ end
91
+
92
+ Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
93
+ http.request(request)
94
+ end
95
+ end
96
+
97
+ def post_message(profile, params)
85
98
  uri = URI("https://slack.com/api/chat.postMessage")
86
99
  request = Net::HTTP::Post.new(uri).tap do |req|
87
100
  req['Authorization'] = "Bearer #{profile[:api_token]}"
@@ -93,6 +106,4 @@ class SlackMessage::Api
93
106
  http.request(request)
94
107
  end
95
108
  end
96
-
97
- private_class_method :post_message
98
109
  end
@@ -2,7 +2,7 @@ class SlackMessage::Dsl
2
2
  attr_reader :body, :default_section, :custom_bot_name, :custom_bot_icon, :profile
3
3
  attr_accessor :custom_notification
4
4
 
5
- EMSPACE = " " # unicode emspace
5
+ EMSPACE = " " # unicode emspace, Slack won't compress this
6
6
 
7
7
  def initialize(block, profile)
8
8
  # Delegate missing methods to caller scope. Thanks 2008:
@@ -108,17 +108,17 @@ class SlackMessage::Dsl
108
108
  @caller_self.send meth, *args, &blk
109
109
  end
110
110
 
111
- EMAIL_TAG_PATTERN = /<[^@ \t\r\n\<]+@[^@ \t\r\n]+\.[^@ \t\r\n]+>/
112
-
113
111
  # replace emails w/ real user IDs
114
112
  def enrich_text(text_body)
115
- text_body.scan(EMAIL_TAG_PATTERN).each do |email_tag|
116
- raw_email = email_tag.gsub(/[><]/, '')
117
- user_id = SlackMessage::Api::user_id_for(raw_email, profile)
118
-
119
- text_body.gsub!(email_tag, "<@#{user_id}>") if user_id
120
- rescue SlackMessage::ApiError => e
121
- # swallow errors for not-found users
113
+ text_body.scan(SlackMessage::EMAIL_TAG_PATTERN).each do |email_tag|
114
+ begin
115
+ raw_email = email_tag.gsub(/[><]/, '')
116
+ user_id = SlackMessage::Api::user_id_for(raw_email, profile)
117
+
118
+ text_body.gsub!(email_tag, "<@#{user_id}>") if user_id
119
+ rescue SlackMessage::ApiError => e
120
+ # swallow errors for not-found users
121
+ end
122
122
  end
123
123
 
124
124
  text_body
@@ -30,7 +30,7 @@ module SlackMessage::RSpec
30
30
  FauxResponse = Struct.new(:code, :body)
31
31
 
32
32
  def self.included(_)
33
- SlackMessage::Api.singleton_class.undef_method(:post_message)
33
+ SlackMessage::Api.undef_method(:post_message)
34
34
  SlackMessage::Api.define_singleton_method(:post_message) do |profile, params|
35
35
  @@listeners.each do |listener|
36
36
  listener.record_call(params.merge(profile: profile))
@@ -53,6 +53,12 @@ module SlackMessage::RSpec
53
53
 
54
54
  return FauxResponse.new('200', response.to_json)
55
55
  end
56
+
57
+ SlackMessage::Api.undef_method(:look_up_user_by_email)
58
+ SlackMessage::Api.define_singleton_method(:look_up_user_by_email) do |email, profile|
59
+ response = {"ok"=>true, "user"=>{"id"=>"U5432CBA"}}
60
+ return FauxResponse.new('200', response.to_json)
61
+ end
56
62
  end
57
63
 
58
64
  # w/ channel
@@ -200,11 +206,11 @@ module SlackMessage::RSpec
200
206
  SlackMessage::RSpec.unregister_expectation_listener(self)
201
207
 
202
208
  @captured_calls
203
- .filter { |call| !@channel || call[:channel] == @channel }
204
- .filter { |call| !@profile || [call[:profile][:handle], call[:username]].include?(@profile) }
205
- .filter { |call| !@content || call.fetch(:blocks).to_s =~ @content }
206
- .filter { |call| !@icon || call.fetch(:icon_emoji, call.fetch(:icon_url, '')) == @icon }
207
- .filter { |call| !@icon_matching || call.fetch(:icon_emoji, call.fetch(:icon_url, '')) =~ @icon_matching }
209
+ .select { |call| !@channel || call[:channel] == @channel }
210
+ .select { |call| !@profile || [call[:profile][:handle], call[:username]].include?(@profile) }
211
+ .select { |call| !@content || call.fetch(:blocks).to_s =~ @content }
212
+ .select { |call| !@icon || call.fetch(:icon_emoji, call.fetch(:icon_url, '')) == @icon }
213
+ .select { |call| !@icon_matching || call.fetch(:icon_emoji, call.fetch(:icon_url, '')) =~ @icon_matching }
208
214
  .any?
209
215
  end
210
216
 
data/lib/slack_message.rb CHANGED
@@ -3,6 +3,9 @@ module SlackMessage
3
3
  require 'slack_message/api'
4
4
  require 'slack_message/configuration'
5
5
 
6
+ EMAIL_TAG_PATTERN = /<[^@ \t\r\n\<]+@[^@ \t\r\n]+\.[^@ \t\r\n]+>/
7
+ EMAIL_PATTERN = /^\S{1,}@\S{2,}\.\S{2,}$/
8
+
6
9
  class ApiError < RuntimeError; end
7
10
 
8
11
  def self.configuration
@@ -25,7 +28,7 @@ module SlackMessage
25
28
  instance.instance_eval(&block)
26
29
  end
27
30
 
28
- target = Api::user_id_for(target, profile) if target =~ /^\S{1,}@\S{2,}\.\S{2,}$/
31
+ target = Api::user_id_for(target, profile) if target =~ EMAIL_PATTERN
29
32
 
30
33
  Api.post(payload, target, profile)
31
34
  end
@@ -41,7 +44,7 @@ module SlackMessage
41
44
  end
42
45
 
43
46
  target = profile[:default_channel]
44
- target = Api::user_id_for(target, profile) if target =~ /^\S{1,}@\S{2,}\.\S{2,}$/
47
+ target = Api::user_id_for(target, profile) if target =~ EMAIL_PATTERN
45
48
 
46
49
  Api.post(payload, target, profile)
47
50
  end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |gem|
2
2
  gem.name = 'slack_message'
3
- gem.version = "2.2.0"
3
+ gem.version = "2.3.1"
4
4
  gem.summary = "A nice DSL for composing rich messages in Slack"
5
5
  gem.authors = ["Joe Mastey"]
6
6
  gem.email = 'hello@joemastey.com'
@@ -18,6 +18,8 @@ Gem::Specification.new do |gem|
18
18
  "source_code_uri" => "http://github.com/jmmastey/slack_message",
19
19
  }
20
20
 
21
+ gem.required_ruby_version = '>= 2.5.0'
22
+
21
23
  gem.add_development_dependency "rspec", "3.10.0"
22
24
  gem.add_development_dependency "pry", "0.14.1"
23
25
  gem.add_development_dependency "rb-readline", "0.5.5"
@@ -132,15 +132,6 @@ RSpec.describe SlackMessage do
132
132
  end
133
133
  end
134
134
 
135
- it "can grab user IDs" do
136
- allow(Net::HTTP).to receive(:start).and_return(
137
- double(code: "200", body: '{ "user": { "id": "ABC123" }}')
138
- )
139
-
140
- result = SlackMessage::Api.user_id_for("hello@joemastey.com", profile)
141
- expect(result).to eq("ABC123")
142
- end
143
-
144
135
  it "converts user IDs within text when tagged properly" do
145
136
  allow(SlackMessage::Api).to receive(:user_id_for).and_return('ABC123')
146
137
 
@@ -151,13 +142,19 @@ RSpec.describe SlackMessage do
151
142
  expect {
152
143
  SlackMessage.post_to('#general') { text("Not Tagged: hello@joemastey.com ") }
153
144
  }.to post_to_slack.with_content_matching(/hello@joemastey.com/)
145
+ end
154
146
 
155
-
156
- allow(SlackMessage::Api).to receive(:user_id_for).and_raise(SlackMessage::ApiError)
147
+ it "is graceful about those failures" do
148
+ allow(SlackMessage::Api).to receive(:user_id_for).with('nuffin@nuffin.nuffin', any_args).and_raise(SlackMessage::ApiError)
149
+ allow(SlackMessage::Api).to receive(:user_id_for).with('hello@joemastey.com', any_args).and_return('ABC123')
157
150
 
158
151
  expect {
159
152
  SlackMessage.post_to('#general') { text("Not User: <nuffin@nuffin.nuffin>") }
160
153
  }.to post_to_slack.with_content_matching(/\<nuffin@nuffin.nuffin\>/)
154
+
155
+ expect {
156
+ SlackMessage.post_to('#general') { text("Not User: <nuffin@nuffin.nuffin>, User: <hello@joemastey.com>") }
157
+ }.to post_to_slack.with_content_matching(/ABC123/)
161
158
  end
162
159
  end
163
160
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slack_message
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 2.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joe Mastey
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-20 00:00:00.000000000 Z
11
+ date: 2021-11-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -58,12 +58,12 @@ executables: []
58
58
  extensions: []
59
59
  extra_rdoc_files: []
60
60
  files:
61
+ - ".github/workflows/main.yml"
61
62
  - ".gitignore"
62
63
  - ".ruby-version"
63
64
  - CHANGELOG.md
64
65
  - CODE_OF_CONDUCT.md
65
66
  - Gemfile
66
- - Gemfile.lock
67
67
  - MIT-LICENSE
68
68
  - README.md
69
69
  - lib/slack_message.rb
@@ -89,7 +89,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
89
89
  requirements:
90
90
  - - ">="
91
91
  - !ruby/object:Gem::Version
92
- version: '0'
92
+ version: 2.5.0
93
93
  required_rubygems_version: !ruby/object:Gem::Requirement
94
94
  requirements:
95
95
  - - ">="
data/Gemfile.lock DELETED
@@ -1,40 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- slack_message (2.2.0)
5
-
6
- GEM
7
- remote: https://rubygems.org/
8
- specs:
9
- coderay (1.1.3)
10
- diff-lcs (1.4.4)
11
- method_source (1.0.0)
12
- pry (0.14.1)
13
- coderay (~> 1.1)
14
- method_source (~> 1.0)
15
- rb-readline (0.5.5)
16
- rspec (3.10.0)
17
- rspec-core (~> 3.10.0)
18
- rspec-expectations (~> 3.10.0)
19
- rspec-mocks (~> 3.10.0)
20
- rspec-core (3.10.1)
21
- rspec-support (~> 3.10.0)
22
- rspec-expectations (3.10.1)
23
- diff-lcs (>= 1.2.0, < 2.0)
24
- rspec-support (~> 3.10.0)
25
- rspec-mocks (3.10.2)
26
- diff-lcs (>= 1.2.0, < 2.0)
27
- rspec-support (~> 3.10.0)
28
- rspec-support (3.10.2)
29
-
30
- PLATFORMS
31
- ruby
32
-
33
- DEPENDENCIES
34
- pry (= 0.14.1)
35
- rb-readline (= 0.5.5)
36
- rspec (= 3.10.0)
37
- slack_message!
38
-
39
- BUNDLED WITH
40
- 2.1.4