slack_message 2.2.0 → 2.3.1

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.
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