slack_message 3.0.0 → 3.1.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.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +1 -1
- data/CHANGELOG.md +14 -0
- data/README.md +28 -26
- data/docs/01_configuration.md +12 -12
- data/docs/02_posting_a_message.md +7 -3
- data/docs/03_message_dsl.md +150 -46
- data/docs/04_editing_messages.md +6 -7
- data/docs/05_deleting_messages.md +7 -7
- data/docs/06_notifying_users.md +1 -1
- data/docs/_config.yml +6 -0
- data/docs/index.md +47 -1
- data/lib/slack_message/api.rb +13 -32
- data/lib/slack_message/dsl.rb +15 -0
- data/lib/slack_message/error_handling.rb +124 -0
- data/lib/slack_message/rspec.rb +39 -17
- data/lib/slack_message.rb +1 -0
- data/slack_message.gemspec +1 -1
- data/spec/slack_message_spec.rb +73 -9
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2b4cc88c84b2a958d75262b0d1fea97de8b7b694555159e4962a4a9fa16c55f6
|
4
|
+
data.tar.gz: 750afd5d7321952cc9dbf344d6db3659f85d916f988ca7ac3e56ec615cde4b34
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7eb4393b8e51b899a65abe790f4e217522441274bc6cc418ea21e43257716d218ad87fbddfce2fd7521f4305840312967249f4faf20261f5f7b665ec01d55896
|
7
|
+
data.tar.gz: ce790defaa92aeea75683771a85ef827386a1275524ac6006139aa3db58e387797ae5f8b8623e6896f07c5af0e6fd881b2878bac1cadf1be398333ab20066a2c
|
data/.github/workflows/main.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [3.1.0] - TBD
|
4
|
+
- Methods from the calling context can now be called within a section block.
|
5
|
+
|
6
|
+
## [3.0.2] - 2022-04-16
|
7
|
+
- Fix tests on ruby 3.0.
|
8
|
+
- More adjustments and additions to docs.
|
9
|
+
- Add warnings when overriding notification text and context block.
|
10
|
+
|
11
|
+
## [3.0.1] - 2021-12-22
|
12
|
+
- Major overhaul of error handling and expansion on which errors trigger
|
13
|
+
friendly messages for users.
|
14
|
+
- More additions to the docs, and working github pages integration.
|
15
|
+
- It's my birthday!
|
16
|
+
|
3
17
|
## [3.0.0] - 2021-12-19
|
4
18
|
- Return a more structured object from successful message sends.
|
5
19
|
- Add the ability to edit or delete a message.
|
data/README.md
CHANGED
@@ -12,13 +12,18 @@ SlackMessage.post_to('#general') do
|
|
12
12
|
text "We did it @here! :thumbsup:"
|
13
13
|
end
|
14
14
|
```
|
15
|
+
|
16
|
+
### The Docs
|
15
17
|
|
16
|
-
|
18
|
+
You'll find much more information about how to use SlackMessage by visiting
|
19
|
+
[the docs](https://jmmastey.github.io/slack_message).
|
20
|
+
|
17
21
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
+
### A Rich DSL Focused on Maintainability
|
23
|
+
|
24
|
+
SlackMessage is able to build all kinds of rich messages for you. It focuses on
|
25
|
+
writing code that looks similar to the output messages themselves, with as
|
26
|
+
little repetition and cruft as possible.
|
22
27
|
|
23
28
|
```ruby
|
24
29
|
SlackMessage.post_to('#general') do
|
@@ -48,12 +53,7 @@ SlackMessage.post_to('#general') do
|
|
48
53
|
end
|
49
54
|
```
|
50
55
|
|
51
|
-
###
|
52
|
-
|
53
|
-
You'll find much more information about how to use SlackMessage by visiting
|
54
|
-
[the docs](https://jmmastey.github.io/slack_message).
|
55
|
-
|
56
|
-
#### Opinionated Stances
|
56
|
+
### Opinionated Stances
|
57
57
|
|
58
58
|
This gem is intended to stay simple. Other Slack gems have lots of config
|
59
59
|
options and abilities, which makes them powerful, but makes them a pain to use.
|
@@ -61,6 +61,8 @@ options and abilities, which makes them powerful, but makes them a pain to use.
|
|
61
61
|
Accordingly, SlackMessage is developed with some strong opinions in mind:
|
62
62
|
|
63
63
|
* SlackMessage has no dependencies. Your lockfile is enough of a mess already.
|
64
|
+
* A DSL that focuses on code that is easy to write, read, and maintain. Only
|
65
|
+
features that can be implemented with that in mind are included.
|
64
66
|
* The code to build a message should look a lot like the message itself. Code
|
65
67
|
that is simple to read and understand is a priority.
|
66
68
|
* Webhooks are passé. Only Slack Apps are supported now.
|
@@ -71,28 +73,28 @@ Accordingly, SlackMessage is developed with some strong opinions in mind:
|
|
71
73
|
to look it up as an email address.
|
72
74
|
* A few little hacks on the block syntax, such as adding a `blank_line` (which
|
73
75
|
doesn't exist in the API), or leading spaces.
|
74
|
-
* Configuration is kept
|
75
|
-
possible should occur just once via configuration and not on every call.
|
76
|
+
* Configuration is kept simple, with helpers for frequently reused bots.
|
76
77
|
|
77
|
-
Some
|
78
|
+
Some changes that are still planned or desired, but not yet added:
|
78
79
|
|
79
80
|
* any interactive elements at all: https://api.slack.com/interactivity/handling
|
80
81
|
* multiple recipients: https://api.slack.com/methods/conversations.open
|
81
|
-
* more
|
82
|
-
*
|
83
|
-
* more mrkdwn syntax, like quotes or code blocks
|
84
|
-
* more and better organized testing capability
|
82
|
+
* more mrkdwn syntax, like quotes or code blocks https://api.slack.com/reference/surfaces/formatting#line-breaks
|
83
|
+
* more and better organized testing capability (for scheduled messages, editing, deleting)
|
85
84
|
* posting ephemeral messages: https://api.slack.com/methods/chat.postEphemeral
|
86
|
-
*
|
85
|
+
* easier way to dump / load message responses
|
86
|
+
* updated docs w/ links to BlockBuilder
|
87
87
|
|
88
|
-
Contributing
|
89
|
-
------------
|
88
|
+
### Contributing
|
90
89
|
|
91
|
-
Contributions are very welcome. Fork, fix, submit pull. Since simplicity of API
|
90
|
+
Contributions are very welcome. Fork, fix, submit pull. Since simplicity of API
|
91
|
+
is a strong priority, so opening an issue to discuss possible interface changes
|
92
|
+
would be wise.
|
92
93
|
|
93
|
-
Contribution is expected to conform to the [Contributor
|
94
|
+
Contribution is expected to conform to the [Contributor
|
95
|
+
Covenant](https://github.com/jmmastey/slack_message/blob/master/CODE_OF_CONDUCT.md).
|
94
96
|
|
95
|
-
License
|
96
|
-
------------
|
97
|
+
### License
|
97
98
|
|
98
|
-
This software is released under the [MIT
|
99
|
+
This software is released under the [MIT
|
100
|
+
License](https://github.com/jmmastey/slack_message/blob/master/MIT-LICENSE).
|
data/docs/01_configuration.md
CHANGED
@@ -95,18 +95,18 @@ end
|
|
95
95
|
You will now see warnings detailing all params sent to the API.
|
96
96
|
|
97
97
|
```ruby
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
98
|
+
{
|
99
|
+
:channel=>"#general",
|
100
|
+
:username=>"Builds",
|
101
|
+
:blocks=>[
|
102
|
+
{:type=>"section", :text=>{
|
103
|
+
:type=>"mrkdwn",
|
104
|
+
:text=>"Build Stability is Looking Ruff :dog:"
|
105
|
+
}}
|
106
|
+
],
|
107
|
+
:text=>"Build Issues",
|
108
|
+
:post_at=>1639421171,
|
109
|
+
}
|
110
110
|
```
|
111
111
|
|
112
112
|
Note this includes data that is not included in `SlackMessage.build`.
|
@@ -101,7 +101,7 @@ end
|
|
101
101
|
|
102
102
|
### Scheduling a Message
|
103
103
|
|
104
|
-
To schedule a message, simply provide
|
104
|
+
To schedule a message, simply provide an `at` parameter to your post. Provide
|
105
105
|
either a time object that responds to `to_i`, or an integer that represents a
|
106
106
|
[unix timestamp](https://en.wikipedia.org/wiki/Unix_time) for the time at which
|
107
107
|
you want your message posted.
|
@@ -121,8 +121,12 @@ nor can they be scheduled more than 120 days into the future.
|
|
121
121
|
|
122
122
|
### Best Practices
|
123
123
|
|
124
|
-
|
125
|
-
|
124
|
+
From experience, building messages with maintainability in mind is key. Adding
|
125
|
+
lots of flow control and indirection will undermine your ability to understand
|
126
|
+
and change messages later.
|
127
|
+
|
128
|
+
For simple messages, using implicit sections is perfectly fine. However, if you
|
129
|
+
intend to create several sections, it's usually better to just declare them.
|
126
130
|
|
127
131
|
See the [API documentation for
|
128
132
|
chat.postMessage](https://api.slack.com/methods/chat.postMessage) or
|
data/docs/03_message_dsl.md
CHANGED
@@ -1,10 +1,15 @@
|
|
1
|
-
|
1
|
+
## The Message DSL
|
2
2
|
|
3
|
-
A pretty good number of the elements available in BlockKit are usable in
|
3
|
+
A pretty good number of the elements available in BlockKit are usable in
|
4
|
+
SlackMessage. There are also a few elements that haven't been implemented in
|
5
|
+
the official API, but are too useful to be missing.
|
4
6
|
|
5
|
-
|
7
|
+
### Basic Text
|
6
8
|
|
7
|
-
While BlockKit officially requires that any elements are contained within a
|
9
|
+
While BlockKit officially requires that any elements are contained within a
|
10
|
+
section element, that requirement is relaxed in SlackMessage. If you don't
|
11
|
+
specify a section, one will silently be created to encapsulate your code.
|
12
|
+
That's the secret behind the most basic messages in these docs.
|
8
13
|
|
9
14
|
```ruby
|
10
15
|
SlackMessage.build do
|
@@ -108,7 +113,51 @@ end
|
|
108
113
|
Note that between the two newlines in the above example is a unicode emspace,
|
109
114
|
which the API will respect as a line worth rendering.
|
110
115
|
|
111
|
-
|
116
|
+
### Explicitly Declared Sections
|
117
|
+
|
118
|
+
Adding more sections is trivial. Simply declare each section and it will be
|
119
|
+
separated in the rendered message. This can often occur when looping.
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
SlackMessage.build do
|
123
|
+
pet_types.each do |type, breeds|
|
124
|
+
section do
|
125
|
+
text "*#{type}:* #{breeds.join(", ")}"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
```
|
130
|
+
|
131
|
+
It can also be useful to add a visual divider (similar to an `hr` in HTML)
|
132
|
+
between sections. To add one of these, use the `divider` helper. You can also
|
133
|
+
add a divider at the end of all the sections, but it often looks silly.
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
SlackMessage.build do
|
137
|
+
section do
|
138
|
+
text "*Topsiders:* Emily, Elsie, Derick"
|
139
|
+
end
|
140
|
+
|
141
|
+
divider
|
142
|
+
|
143
|
+
section do
|
144
|
+
text "*Undergrounders:* Kristina, Lauren, Different Emily"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# => [
|
149
|
+
# {:type=>"section", :text=>{:type=>"mrkdwn", :text=>"*Topsiders:* Emily, Elsie, Derick"}},
|
150
|
+
# {:type=>"divider"},
|
151
|
+
# {:type=>"section", :text=>{:type=>"mrkdwn", :text=>"*Undergrounders:* Kristina, Lauren, Different Emily"}}
|
152
|
+
# ]
|
153
|
+
```
|
154
|
+
|
155
|
+
Note that a divider can only occur between sections, not within a single
|
156
|
+
section. Because of how implicit sections are built, it may look like this
|
157
|
+
works for simple messages. But, you may have troubles when you start adding
|
158
|
+
more complicated elements to your messages.
|
159
|
+
|
160
|
+
### Buttons
|
112
161
|
|
113
162
|
BlockKit allows you to specify a button to the right of a section / block. That
|
114
163
|
button will be aligned outside the normal space for a section, and is meant to
|
@@ -132,10 +181,10 @@ end
|
|
132
181
|
Slack allows three styles for buttons: `default`, `primary`, and `danger`.
|
133
182
|
These correspond to gray, green and red buttons respectively. If not specified,
|
134
183
|
SlackMessage will use the `primary` style for buttons. I get that this could be
|
135
|
-
confusing when there is a default
|
136
|
-
is way more common.
|
184
|
+
confusing when there is a style specifically named default, but in my
|
185
|
+
experience, a colorful button is way more common.
|
137
186
|
|
138
|
-
You can override
|
187
|
+
You can override button style by specifying the style with your link button.
|
139
188
|
|
140
189
|
```ruby
|
141
190
|
SlackMessage.build do
|
@@ -152,62 +201,114 @@ end
|
|
152
201
|
# :style=>:danger}}]
|
153
202
|
```
|
154
203
|
|
155
|
-
|
204
|
+
### Ordered and Unordered Lists
|
156
205
|
|
157
|
-
-
|
206
|
+
The Slack API doesn't have native support for HTML-style ordered and unordered
|
207
|
+
lists, but there are convenience methods in SlackMessage to render a close
|
208
|
+
approximation.
|
158
209
|
|
159
|
-
|
210
|
+
```ruby
|
211
|
+
SlackMessage.build do
|
212
|
+
section do
|
213
|
+
text '*Pet Goodness Tiers*'
|
214
|
+
|
215
|
+
ol([
|
216
|
+
'tiny pigs',
|
217
|
+
'reptiles',
|
218
|
+
'dogs',
|
219
|
+
'cats',
|
220
|
+
])
|
221
|
+
end
|
160
222
|
|
161
|
-
|
162
|
-
|
223
|
+
section do
|
224
|
+
text '_voted by_'
|
225
|
+
ul(['Joe', 'Emily', 'Sophia', 'Matt'])
|
226
|
+
end
|
227
|
+
end
|
228
|
+
```
|
229
|
+
|
230
|
+
Because Slack automatically collapses leading whitespace, indention of lists is
|
231
|
+
handled using unicode emspaces. Bullets for unordered lists are also unicode
|
232
|
+
characters to avoid being read as markdown.
|
233
|
+
|
234
|
+
### List Items (e.g. HTML dt & dd)
|
235
|
+
|
236
|
+
When trying to represent title / value lists, you can use the "list item" block
|
237
|
+
type to pass a set of values. Slack does not allow you to customize how many
|
238
|
+
items are shown per line, so you'll just have to work with it.
|
163
239
|
|
164
240
|
```ruby
|
165
241
|
SlackMessage.build do
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
242
|
+
text 'Import results are available!'
|
243
|
+
|
244
|
+
list_item 'Import Date', Date.today.to_s
|
245
|
+
list_item 'Items Imported', 55_000
|
246
|
+
list_item 'Errors', 23
|
247
|
+
list_item 'Bad Values', errors.map(&:to_s)
|
171
248
|
end
|
172
249
|
```
|
173
250
|
|
174
|
-
|
175
|
-
|
176
|
-
|
251
|
+
### Images and Accessory Images
|
252
|
+
|
253
|
+
There are two main types of images in Slack: the
|
254
|
+
[image](https://imgur.com/XEUap1r) and the [accessory
|
255
|
+
image](https://imgur.com/zuhjBDq). In short, `accessory_image` is part of a
|
256
|
+
section itself and is shown alongside an existing block, while `image` is shown
|
257
|
+
as its own top-level element.
|
258
|
+
|
259
|
+
Accordingly, an accessory image should be used within a section. An accessory
|
260
|
+
image can accept alt-text, which is also a best practice, for usability
|
261
|
+
reasons.
|
177
262
|
|
178
263
|
```ruby
|
179
264
|
SlackMessage.build do
|
180
265
|
section do
|
181
|
-
text
|
266
|
+
text 'Looks like the coffee machine is empty.'
|
267
|
+
accessory_image 'https://your.com/empty_coffee_logo.jpg', alt_text: 'logo of a forlorn coffee cup'
|
182
268
|
end
|
269
|
+
end
|
270
|
+
```
|
183
271
|
|
184
|
-
|
272
|
+
Only one accessory image can be used per section, and declaring more will issue
|
273
|
+
a warning and simply override the previous accessory image.
|
185
274
|
|
275
|
+
By contrast, `image` can be used many times, and will create a new top-level
|
276
|
+
section for each call. Image accepts alt-text, but also a title, which will
|
277
|
+
be displayed above the image (along with an icon to collapse the image).
|
278
|
+
|
279
|
+
```ruby
|
280
|
+
SlackMessage.build do
|
186
281
|
section do
|
187
|
-
text
|
282
|
+
text 'Most Recent Tiny Pig Images'
|
188
283
|
end
|
189
|
-
end
|
190
284
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
# ]
|
285
|
+
image 'https://your.com/employee_pets/best/pig_1.jpg', alt_text: 'a tiny pig eating ice cream', title: 'Spider Pig'
|
286
|
+
image 'https://your.com/employee_pets/best/pig_2.jpg', alt_text: 'a tiny pig smiling mischeviously', title: 'Porkeypine'
|
287
|
+
image 'https://your.com/employee_pets/best/pig_3.jpg', alt_text: 'a tiny pig with wellies and an umbrella', title: 'Albert Sweinstein'
|
288
|
+
end
|
196
289
|
```
|
197
290
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
complicated elements to your messages.
|
291
|
+
Sectionless messages can also use `accessory_image`, but this can get confusing
|
292
|
+
since they could potentially be interspersed with top-level images, so I
|
293
|
+
wouldn't recommend it.
|
202
294
|
|
203
|
-
|
204
|
-
|
295
|
+
```ruby
|
296
|
+
# the difference between these two image styles is confusing, and the call
|
297
|
+
# to `image` closed the current section and started a new one.
|
298
|
+
SlackMessage.build do
|
299
|
+
text 'Looks like the coffee machine is empty.'
|
300
|
+
accessory_image 'https://your.com/empty_coffee_logo.jpg'
|
301
|
+
|
302
|
+
text '*Most Recent Coffee Maker Surveillance Photo*'
|
303
|
+
image 'https://your.com/surveillance/coffee/current.jpg'
|
304
|
+
end
|
305
|
+
```
|
205
306
|
|
206
307
|
### Footers (Context)
|
207
308
|
|
208
309
|
Slack allows you to add a small additional piece of text to your message, which
|
209
|
-
will be rendered in italics and small text. It can support both links and
|
210
|
-
and is useful for providing minor details for your message.
|
310
|
+
will be rendered in italics and small text. It can support both links and
|
311
|
+
emoji, and is useful for providing minor details for your message.
|
211
312
|
|
212
313
|
```ruby
|
213
314
|
SlackMessage.build do
|
@@ -225,15 +326,16 @@ end
|
|
225
326
|
# }]
|
226
327
|
```
|
227
328
|
|
228
|
-
Context does not belong to a section, and
|
229
|
-
|
329
|
+
Context does not belong to a section, and only one can be added to your entire
|
330
|
+
slack message. Specifying another `context` will issue a warning and overwrite
|
331
|
+
any previous call.
|
230
332
|
|
231
333
|
### Bot Customization
|
232
334
|
|
233
335
|
By default - and with scheduled messages - Slack will use the name and icon of
|
234
|
-
the Slack app whose API key you configured. As seen before, it's
|
235
|
-
|
236
|
-
|
336
|
+
the Slack app whose API key you configured. As seen before, it's possible to
|
337
|
+
override those default names and icons in configuration. However, it can also
|
338
|
+
be customized per-message.
|
237
339
|
|
238
340
|
```ruby
|
239
341
|
SlackMessage.build do
|
@@ -247,9 +349,9 @@ end
|
|
247
349
|
```
|
248
350
|
|
249
351
|
Notice that the bot details aren't shown in the output of the `build` command.
|
250
|
-
To view the
|
352
|
+
To view the change to the message payload from these calls, use `debug` mode.
|
251
353
|
|
252
|
-
The `bot_icon` can be specified as either an emoji (`:
|
354
|
+
The `bot_icon` can be specified as either an emoji (`:shipit:`), or a URL
|
253
355
|
pointing to an image (`http://mysite.com/shipit.png`). Any other value seems to
|
254
356
|
cause an error.
|
255
357
|
|
@@ -276,7 +378,9 @@ end
|
|
276
378
|
```
|
277
379
|
|
278
380
|
Again notice that notification text is not set within the blocks themselves, so
|
279
|
-
you will need to enable debugging to see how it changes what is sent to the
|
381
|
+
you will need to enable debugging to see how it changes what is sent to the
|
382
|
+
API. Only one custom notification is allowed, so further calls will issue a
|
383
|
+
warning and replace the previous notification text.
|
280
384
|
|
281
385
|
---
|
282
386
|
|
data/docs/04_editing_messages.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
## Updating a Previous Message
|
2
2
|
|
3
3
|
After you've posted a message, you may want to edit it later. Interactive bots,
|
4
4
|
for instance, may want to repeatedly update a message.
|
@@ -52,12 +52,11 @@ class SomeWorker < ApplicationWorker
|
|
52
52
|
end
|
53
53
|
```
|
54
54
|
|
55
|
-
|
55
|
+
### Storing Response Objects for Later
|
56
56
|
|
57
|
-
Since updates are likely to occur after you
|
58
|
-
|
59
|
-
|
60
|
-
for later.
|
57
|
+
Since updates are likely to occur long after you post the original message, you
|
58
|
+
may want to persist a reference to the message until you need to update it
|
59
|
+
later. As one option, you could serialize the response object for later.
|
61
60
|
|
62
61
|
```ruby
|
63
62
|
# initially
|
@@ -74,7 +73,7 @@ SlackMessage.update(message) do
|
|
74
73
|
end
|
75
74
|
```
|
76
75
|
|
77
|
-
|
76
|
+
### Updating Scheduled Messages
|
78
77
|
|
79
78
|
Sadly, there's currently no way to edit a scheduled message. You'll receive an
|
80
79
|
error if you attempt to call `update` on a scheduled message.
|
@@ -1,26 +1,26 @@
|
|
1
|
-
|
1
|
+
## Deleting Messages
|
2
2
|
|
3
3
|
Deleting a message is much like editing a message, only simpler. Just like when
|
4
4
|
you edit a message, you'll need a reference to the message you posted.
|
5
5
|
|
6
|
-
*Important Note: It's not possible to delete a message sent directly to a user.
|
7
|
-
It's also not possible to delete a scheduled message once it's already posted.
|
8
|
-
Don't send anything you don't want your boss to read.*
|
9
|
-
|
10
6
|
```ruby
|
11
7
|
message = SlackMessage.post_to('#general') do
|
12
8
|
text "Testing: #{SLACK_SECRET_KEY}"
|
13
9
|
end
|
14
10
|
```
|
15
11
|
|
16
|
-
|
12
|
+
Then you can simply call the `delete` method to make up for your mistakes.
|
17
13
|
|
18
14
|
```ruby
|
19
15
|
SlackMessage.delete(message)
|
20
16
|
```
|
21
17
|
|
18
|
+
*Important Note: It's not possible to delete a message sent directly to a user.
|
19
|
+
It's also not possible to delete a scheduled message once it's already posted.
|
20
|
+
Don't send anything you don't want your boss to read.*
|
21
|
+
|
22
22
|
As with editing a message, it's possible to persist messages to redis / your
|
23
|
-
database
|
23
|
+
database to be removed at a later date.
|
24
24
|
|
25
25
|
```ruby
|
26
26
|
# initially
|
data/docs/06_notifying_users.md
CHANGED
data/docs/_config.yml
ADDED
data/docs/index.md
CHANGED
@@ -1,7 +1,53 @@
|
|
1
|
-
* [Configuration](https://jmmastey.github.io/slack_message/01_configuration)
|
1
|
+
* [Getting Started / Configuration](https://jmmastey.github.io/slack_message/01_configuration)
|
2
2
|
* [Posting a Message](https://jmmastey.github.io/slack_message/02_posting_a_message)
|
3
3
|
* [The SlackMessage DSL](https://jmmastey.github.io/slack_message/03_message_dsl)
|
4
4
|
* [Editing Messages](https://jmmastey.github.io/slack_message/04_editing_messages)
|
5
5
|
* [Deleting Messages](https://jmmastey.github.io/slack_message/05_deleting_messages)
|
6
6
|
* [Mentions / Notifying Users](https://jmmastey.github.io/slack_message/06_notifying_users)
|
7
7
|
* [Testing](https://jmmastey.github.io/slack_message/07_testing)
|
8
|
+
|
9
|
+
SlackMessage is a gem that makes it easy to send messages to Slack from your
|
10
|
+
application. _Really_ easy.
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
SlackMessage.post_to('#general') do
|
14
|
+
text "We did it @here! :thumbsup:"
|
15
|
+
end
|
16
|
+
```
|
17
|
+
|
18
|
+
And not just simple messages. You can compose complicated messages quickly in a
|
19
|
+
DSL that's focused on usability and maintainability. It can be tough to
|
20
|
+
maintain code in other similar gems, but not here.
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
SlackMessage.post_to('hello@joemastey.com') do
|
24
|
+
section do
|
25
|
+
text "A job has generated some output for you to review."
|
26
|
+
text 'And More' * 10
|
27
|
+
link_button "See Results", "https://google.com"
|
28
|
+
end
|
29
|
+
|
30
|
+
section do
|
31
|
+
text ":unlock-new: New Data Summary"
|
32
|
+
|
33
|
+
list_item "Date", "09/05/2021"
|
34
|
+
list_item "Total Imported", 45_004
|
35
|
+
list_item "Total Errors", 5
|
36
|
+
end
|
37
|
+
|
38
|
+
divider
|
39
|
+
|
40
|
+
section do
|
41
|
+
text "See more here: #{link('result', 'https://google.com')}"
|
42
|
+
end
|
43
|
+
|
44
|
+
context "Kicked off by <hello@joemastey.com> at **9:05am**"
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
It has no dependencies and minimal configuration needs, so you can get up and
|
49
|
+
running quickly.
|
50
|
+
|
51
|
+
---
|
52
|
+
|
53
|
+
Next: [Get Started](https://jmmastey.github.io/slack_message/01_configuration)
|
data/lib/slack_message/api.rb
CHANGED
@@ -10,6 +10,10 @@ module SlackMessage::Api
|
|
10
10
|
raise ArgumentError, "Tried to find profile by invalid email address '#{email}'"
|
11
11
|
end
|
12
12
|
|
13
|
+
if SlackMessage::Configuration.debugging?
|
14
|
+
warn [email, profile].inspect
|
15
|
+
end
|
16
|
+
|
13
17
|
response = look_up_user_by_email(email, profile)
|
14
18
|
|
15
19
|
if response.code != "200"
|
@@ -24,14 +28,7 @@ module SlackMessage::Api
|
|
24
28
|
raise SlackMessage::ApiError, "Unable to parse JSON response from Slack API\n#{response.body}"
|
25
29
|
end
|
26
30
|
|
27
|
-
|
28
|
-
raise SlackMessage::ApiError, "Received an error because your authentication token isn't properly configured."
|
29
|
-
elsif payload.include?("error") && payload["error"] == "users_not_found"
|
30
|
-
raise SlackMessage::ApiError, "Couldn't find a user with the email '#{email}'."
|
31
|
-
elsif payload.include?("error")
|
32
|
-
raise SlackMessage::ApiError, "Received error response from Slack during user lookup:\n#{response.body}"
|
33
|
-
end
|
34
|
-
|
31
|
+
SlackMessage::ErrorHandling.raise_user_lookup_errors(response, target, profile)
|
35
32
|
payload["user"]["id"]
|
36
33
|
end
|
37
34
|
|
@@ -69,26 +66,8 @@ module SlackMessage::Api
|
|
69
66
|
end
|
70
67
|
|
71
68
|
response = post_message(profile, params)
|
72
|
-
body = JSON.parse(response.body)
|
73
|
-
error = body.fetch("error", "")
|
74
|
-
|
75
|
-
# TODO: if a scheduled message w/ a short timer is "time_in_past", warn the user?
|
76
|
-
|
77
|
-
# let's try to be helpful about error messages
|
78
|
-
if ["token_revoked", "token_expired", "invalid_auth", "not_authed"].include?(error)
|
79
|
-
raise SlackMessage::ApiError, "Couldn't send slack message because the API key for profile '#{profile[:handle]}' is wrong."
|
80
|
-
elsif ["no_permission", "ekm_access_denied"].include?(error)
|
81
|
-
raise SlackMessage::ApiError, "Couldn't send slack message because the API key for profile '#{profile[:handle]}' isn't allowed to post messages."
|
82
|
-
elsif error == "channel_not_found"
|
83
|
-
raise SlackMessage::ApiError, "Tried to send Slack message to non-existent channel or user '#{target}'"
|
84
|
-
elsif error == "invalid_arguments"
|
85
|
-
raise SlackMessage::ApiError, "Tried to send Slack message with invalid payload."
|
86
|
-
elsif response.code == "302"
|
87
|
-
raise SlackMessage::ApiError, "Got 302 response while posting to Slack. Check your API key for profile '#{profile[:handle]}'."
|
88
|
-
elsif response.code != "200"
|
89
|
-
raise SlackMessage::ApiError, "Got an error back from the Slack API (HTTP #{response.code}):\n#{response.body}"
|
90
|
-
end
|
91
69
|
|
70
|
+
SlackMessage::ErrorHandling.raise_post_response_errors(response, params, profile)
|
92
71
|
SlackMessage::Response.new(response, profile[:handle])
|
93
72
|
end
|
94
73
|
|
@@ -97,7 +76,7 @@ module SlackMessage::Api
|
|
97
76
|
channel: message.channel,
|
98
77
|
ts: message.timestamp,
|
99
78
|
blocks: payload.render,
|
100
|
-
text: payload.custom_notification
|
79
|
+
text: payload.custom_notification
|
101
80
|
}
|
102
81
|
|
103
82
|
if params[:blocks].length == 0
|
@@ -112,8 +91,7 @@ module SlackMessage::Api
|
|
112
91
|
body = JSON.parse(response.body)
|
113
92
|
error = body.fetch("error", "")
|
114
93
|
|
115
|
-
|
116
|
-
|
94
|
+
SlackMessage::ErrorHandling.raise_post_response_errors(response, message, profile)
|
117
95
|
SlackMessage::Response.new(response, profile[:handle])
|
118
96
|
end
|
119
97
|
|
@@ -130,10 +108,13 @@ module SlackMessage::Api
|
|
130
108
|
}
|
131
109
|
end
|
132
110
|
|
133
|
-
|
111
|
+
if SlackMessage::Configuration.debugging?
|
112
|
+
warn params.inspect
|
113
|
+
end
|
134
114
|
|
135
|
-
|
115
|
+
response = delete_message(profile, params)
|
136
116
|
|
117
|
+
SlackMessage::ErrorHandling.raise_delete_response_errors(response, message, profile)
|
137
118
|
response
|
138
119
|
end
|
139
120
|
|
data/lib/slack_message/dsl.rb
CHANGED
@@ -63,6 +63,13 @@ class SlackMessage::Dsl
|
|
63
63
|
|
64
64
|
text = self.enrich_text(text)
|
65
65
|
|
66
|
+
|
67
|
+
previous_context = @body.find { |element| element[:type] && element[:type] == "context" }
|
68
|
+
if previous_context
|
69
|
+
previous_text = previous_context[:elements].first[:text]
|
70
|
+
warn "WARNING: Overriding previous context in section: #{previous_text}"
|
71
|
+
end
|
72
|
+
|
66
73
|
@body.push({ type: "context", elements: [{
|
67
74
|
type: "mrkdwn", text: text
|
68
75
|
}]})
|
@@ -94,6 +101,10 @@ class SlackMessage::Dsl
|
|
94
101
|
end
|
95
102
|
|
96
103
|
def notification_text(msg)
|
104
|
+
if @custom_notification
|
105
|
+
warn "WARNING: Overriding previous custom notification text: #{@custom_notification}"
|
106
|
+
end
|
107
|
+
|
97
108
|
@custom_notification = msg
|
98
109
|
end
|
99
110
|
|
@@ -261,6 +272,10 @@ class SlackMessage::Dsl
|
|
261
272
|
|
262
273
|
body
|
263
274
|
end
|
275
|
+
|
276
|
+
def method_missing(meth, *args, &blk)
|
277
|
+
@parent.send meth, *args, &blk
|
278
|
+
end
|
264
279
|
end
|
265
280
|
|
266
281
|
class List
|
@@ -0,0 +1,124 @@
|
|
1
|
+
class SlackMessage::ErrorHandling
|
2
|
+
PERMISSIONS_ERRORS = ["token_revoked", "token_expired", "invalid_auth", "not_authed",
|
3
|
+
"team_access_not_granted", "no_permission", "missing_scope",
|
4
|
+
"not_allowed_token_type", "ekm_access_denied"]
|
5
|
+
|
6
|
+
def self.raise_post_response_errors(response, params, profile)
|
7
|
+
body = JSON.parse(response.body)
|
8
|
+
error = body.fetch("error", "")
|
9
|
+
|
10
|
+
if ["invalid_blocks", "invalid_blocks_format"].include?(error)
|
11
|
+
raise SlackMessage::ApiError, "Couldn't send Slack message because the serialized message had an invalid format"
|
12
|
+
elsif error == "channel_not_found"
|
13
|
+
raise SlackMessage::ApiError, "Tried to send Slack message to non-existent channel or user '#{params[:channel]}'"
|
14
|
+
|
15
|
+
# scheduling messages
|
16
|
+
elsif error == "invalid_time"
|
17
|
+
raise SlackMessage::ApiError, "Couldn't schedule Slack message because you requested an invalid time '#{params[:post_at]}'"
|
18
|
+
elsif error == "time_in_past"
|
19
|
+
raise SlackMessage::ApiError, "Couldn't schedule Slack message because you requested a time in the past (or too close to now) '#{params[:post_at]}'"
|
20
|
+
elsif error == "time_too_far"
|
21
|
+
raise SlackMessage::ApiError, "Couldn't schedule Slack message because you requested a time more than 120 days in the future '#{params[:post_at]}'"
|
22
|
+
|
23
|
+
|
24
|
+
elsif PERMISSIONS_ERRORS.include?(error)
|
25
|
+
raise SlackMessage::ApiError, "Couldn't send Slack message because the API key for profile '#{profile[:handle]}' is wrong, or the app has insufficient permissions (#{error})"
|
26
|
+
elsif error == "message_too_long"
|
27
|
+
raise SlackMessage::ApiError, "Tried to send Slack message, but the message was too long"
|
28
|
+
elsif error == "invalid_arguments"
|
29
|
+
raise SlackMessage::ApiError, "Tried to send Slack message with invalid payload"
|
30
|
+
elsif ["rate_limited", "ratelimited"].include?(error)
|
31
|
+
raise SlackMessage::ApiError, "Couldn't send Slack message because you've reached your rate limit"
|
32
|
+
elsif response.code == "302"
|
33
|
+
raise SlackMessage::ApiError, "Got 302 response while posting to Slack. Check your API key for profile '#{profile[:handle]}'"
|
34
|
+
elsif response.code != "200"
|
35
|
+
raise SlackMessage::ApiError, "Got an error back from the Slack API (HTTP #{response.code}):\n#{response.body}"
|
36
|
+
elsif !(error.nil? || error == "")
|
37
|
+
raise SlackMessage::ApiError, "Received error response from Slack during message posting:\n#{response.body}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.raise_update_response_errors(response, message, profile)
|
42
|
+
body = JSON.parse(response.body)
|
43
|
+
error = body.fetch("error", "")
|
44
|
+
|
45
|
+
if ["invalid_blocks", "invalid_blocks_format"].include?(error)
|
46
|
+
raise SlackMessage::ApiError, "Couldn't update Slack message because the serialized message had an invalid format"
|
47
|
+
elsif error == "channel_not_found"
|
48
|
+
raise SlackMessage::ApiError, "Tried to update Slack message to non-existent channel or user '#{message.channel}'"
|
49
|
+
|
50
|
+
elsif error == "message_not_found"
|
51
|
+
raise SlackMessage::ApiError, "Tried to update Slack message, but the message wasn't found (timestamp '#{message.timestamp}' for channel '#{message.channel}'"
|
52
|
+
elsif error == "cant_update_message"
|
53
|
+
raise SlackMessage::ApiError, "Couldn't update message because the message type isn't able to be updated, or #{profile[:handle]} isn't allowed to update it"
|
54
|
+
elsif error == "edit_window_closed"
|
55
|
+
raise SlackMessage::ApiError, "Couldn't update message because it's too old"
|
56
|
+
|
57
|
+
|
58
|
+
elsif PERMISSIONS_ERRORS.include?(error)
|
59
|
+
raise SlackMessage::ApiError, "Couldn't update Slack message because the API key for profile '#{profile[:handle]}' is wrong, or the app has insufficient permissions (#{error})"
|
60
|
+
elsif error == "message_too_long"
|
61
|
+
raise SlackMessage::ApiError, "Tried to update Slack message, but the message was too long"
|
62
|
+
elsif error == "invalid_arguments"
|
63
|
+
raise SlackMessage::ApiError, "Tried to update Slack message with invalid payload"
|
64
|
+
elsif ["rate_limited", "ratelimited"].include?(error)
|
65
|
+
raise SlackMessage::ApiError, "Couldn't update Slack message because you've reached your rate limit"
|
66
|
+
elsif response.code == "302"
|
67
|
+
raise SlackMessage::ApiError, "Got 302 response while updating a message. Check your API key for profile '#{profile[:handle]}'"
|
68
|
+
elsif response.code != "200"
|
69
|
+
raise SlackMessage::ApiError, "Got an error back from the Slack API (HTTP #{response.code}):\n#{response.body}"
|
70
|
+
elsif !(error.nil? || error == "")
|
71
|
+
raise SlackMessage::ApiError, "Received error response from Slack during message update:\n#{response.body}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.raise_delete_response_errors(response, message, profile)
|
76
|
+
body = JSON.parse(response.body)
|
77
|
+
error = body.fetch("error", "")
|
78
|
+
|
79
|
+
if error == "channel_not_found"
|
80
|
+
raise SlackMessage::ApiError, "Tried to delete Slack message in non-existent channel '#{message.channel}'"
|
81
|
+
|
82
|
+
elsif error == "invalid_scheduled_message_id"
|
83
|
+
raise SlackMessage::ApiError, "Can't delete message because the ID was invalid, or the message has already posted (#{message.scheduled_message_id})"
|
84
|
+
elsif error == "message_not_found"
|
85
|
+
raise SlackMessage::ApiError, "Tried to delete Slack message, but the message wasn't found (timestamp '#{message.timestamp}' for channel '#{message.channel}')"
|
86
|
+
elsif error == "cant_delete_message"
|
87
|
+
raise SlackMessage::ApiError, "Can't delete message because '#{profile[:handle]}' doesn't have permission to"
|
88
|
+
elsif error == "compliance_exports_prevent_deletion"
|
89
|
+
raise SlackMessage::ApiError, "Can't delete message because team compliance settings prevent it"
|
90
|
+
|
91
|
+
|
92
|
+
elsif PERMISSIONS_ERRORS.include?(error)
|
93
|
+
raise SlackMessage::ApiError, "Couldn't delete Slack message because the API key for profile '#{profile[:handle]}' is wrong, or the app has insufficient permissions (#{error})"
|
94
|
+
elsif ["rate_limited", "ratelimited"].include?(error)
|
95
|
+
raise SlackMessage::ApiError, "Couldn't delete Slack message because you've reached your rate limit"
|
96
|
+
elsif response.code == "302"
|
97
|
+
raise SlackMessage::ApiError, "Got 302 response while deleting a message. Check your API key for profile '#{profile[:handle]}'"
|
98
|
+
elsif response.code != "200"
|
99
|
+
raise SlackMessage::ApiError, "Got an error back from the Slack API (HTTP #{response.code}):\n#{response.body}"
|
100
|
+
elsif !(error.nil? || error == "")
|
101
|
+
raise SlackMessage::ApiError, "Received error response from Slack during message delete:\n#{response.body}"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.raise_user_lookup_response_errors(payload)
|
106
|
+
error = payload["error"]
|
107
|
+
|
108
|
+
if error == "users_not_found"
|
109
|
+
raise SlackMessage::ApiError, "Couldn't find a user with the email '#{email}'"
|
110
|
+
|
111
|
+
|
112
|
+
elsif PERMISSIONS_ERRORS.include?(error)
|
113
|
+
raise SlackMessage::ApiError, "Couldn't look up users because the API key for profile '#{profile[:handle]}' is wrong, or the app has insufficient permissions (#{error})"
|
114
|
+
elsif error
|
115
|
+
raise SlackMessage::ApiError, "Received error response from Slack during user lookup:\n#{response.body}"
|
116
|
+
elsif response.code == "302"
|
117
|
+
raise SlackMessage::ApiError, "Got 302 response during user lookup. Check your API key for profile '#{profile[:handle]}'"
|
118
|
+
elsif response.code != "200"
|
119
|
+
raise SlackMessage::ApiError, "Got an error back from the Slack API (HTTP #{response.code}):\n#{response.body}"
|
120
|
+
elsif !(error.nil? || error == "")
|
121
|
+
raise SlackMessage::ApiError, "Received error response from Slack during user lookup:\n#{response.body}"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
data/lib/slack_message/rspec.rb
CHANGED
@@ -14,12 +14,15 @@ require 'rspec/mocks'
|
|
14
14
|
# it can be cleaned up properly.
|
15
15
|
#
|
16
16
|
|
17
|
-
# TODO:
|
17
|
+
# TODO: test helpers for scheduled messages, editing and deleting, and
|
18
|
+
# notification text. And realistically, overhaul all this.
|
18
19
|
|
19
20
|
module SlackMessage::RSpec
|
20
21
|
extend RSpec::Matchers::DSL
|
21
22
|
|
22
23
|
@@listeners = []
|
24
|
+
@@custom_response = {}
|
25
|
+
@@response_code = '200'
|
23
26
|
|
24
27
|
def self.register_expectation_listener(expectation_instance)
|
25
28
|
@@listeners << expectation_instance
|
@@ -29,6 +32,11 @@ module SlackMessage::RSpec
|
|
29
32
|
@@listeners.delete(expectation_instance)
|
30
33
|
end
|
31
34
|
|
35
|
+
def self.reset_custom_responses
|
36
|
+
@@custom_response = {}
|
37
|
+
@@response_code = '200'
|
38
|
+
end
|
39
|
+
|
32
40
|
FauxResponse = Struct.new(:code, :body)
|
33
41
|
|
34
42
|
def self.included(_)
|
@@ -38,22 +46,24 @@ module SlackMessage::RSpec
|
|
38
46
|
listener.record_call(params.merge(profile: profile))
|
39
47
|
end
|
40
48
|
|
41
|
-
response = {
|
42
|
-
"
|
43
|
-
"
|
44
|
-
"
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
49
|
+
response = {
|
50
|
+
"ok" => true,
|
51
|
+
"channel" => "C12345678",
|
52
|
+
"ts" => "1635863996.002300",
|
53
|
+
"message" => { "type"=>"message", "subtype"=>"bot_message",
|
54
|
+
"text"=>"foo",
|
55
|
+
"ts"=>"1635863996.002300",
|
56
|
+
"username"=>"SlackMessage",
|
57
|
+
"icons"=>{"emoji"=>":successkid:"},
|
58
|
+
"bot_id"=>"B1234567890",
|
59
|
+
"blocks"=> [{"type"=>"section",
|
60
|
+
"block_id"=>"hAh7",
|
61
|
+
"text"=>{"type"=>"mrkdwn", "text"=>"foo", "verbatim"=>false}}
|
62
|
+
]
|
63
|
+
}
|
64
|
+
}.merge(@@custom_response).to_json
|
65
|
+
|
66
|
+
return FauxResponse.new(@@response_code, response)
|
57
67
|
end
|
58
68
|
|
59
69
|
SlackMessage::Api.undef_method(:look_up_user_by_email)
|
@@ -63,6 +73,18 @@ module SlackMessage::RSpec
|
|
63
73
|
end
|
64
74
|
end
|
65
75
|
|
76
|
+
def self.respond_with(response = {}, code: '200')
|
77
|
+
raise ArgumentError, "custom response must be a hash" unless response.is_a? Hash
|
78
|
+
|
79
|
+
@@custom_response = response
|
80
|
+
@@response_code = code
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.reset_mock_response
|
84
|
+
@@custom_response = {}
|
85
|
+
@@response_code = '200'
|
86
|
+
end
|
87
|
+
|
66
88
|
# w/ channel
|
67
89
|
matcher :post_slack_message_to do |expected|
|
68
90
|
match do |actual|
|
data/lib/slack_message.rb
CHANGED
data/slack_message.gemspec
CHANGED
data/spec/slack_message_spec.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
RSpec.describe SlackMessage do
|
4
|
+
|
4
5
|
describe "DSL" do
|
5
6
|
describe "#build" do
|
7
|
+
def outer_method
|
8
|
+
"foo"
|
9
|
+
end
|
10
|
+
|
6
11
|
it "renders some JSON" do
|
7
12
|
SlackMessage.configure do |config|
|
8
13
|
config.clear_profiles!
|
@@ -12,11 +17,17 @@ RSpec.describe SlackMessage do
|
|
12
17
|
expected_output = [
|
13
18
|
{ type: "section",
|
14
19
|
text: { text: "foo", type: "mrkdwn" }
|
15
|
-
}
|
20
|
+
},
|
21
|
+
{ type: "section",
|
22
|
+
text: { text: "foo", type: "mrkdwn" }
|
23
|
+
},
|
16
24
|
]
|
17
25
|
|
18
26
|
output = SlackMessage.build do
|
19
|
-
text
|
27
|
+
text outer_method()
|
28
|
+
section do
|
29
|
+
text outer_method()
|
30
|
+
end
|
20
31
|
end
|
21
32
|
|
22
33
|
expect(output).to eq(expected_output)
|
@@ -49,6 +60,13 @@ RSpec.describe SlackMessage do
|
|
49
60
|
end
|
50
61
|
end
|
51
62
|
|
63
|
+
fit do
|
64
|
+
SlackMessage.build do
|
65
|
+
notification_text 'one'
|
66
|
+
notification_text 'two'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
52
70
|
it "can assert expectations against posts" do
|
53
71
|
expect {
|
54
72
|
SlackMessage.post_to('#lieutenant') { text "foo" }
|
@@ -111,10 +129,6 @@ RSpec.describe SlackMessage do
|
|
111
129
|
}.to post_slack_message_with_icon_matching(/thisperson/)
|
112
130
|
end
|
113
131
|
|
114
|
-
it "lets you assert notification text" do
|
115
|
-
# TODO :|
|
116
|
-
end
|
117
|
-
|
118
132
|
it "can assert more generally too tbh" do
|
119
133
|
expect {
|
120
134
|
SlackMessage.post_to('#general') { text "foo" }
|
@@ -123,8 +137,6 @@ RSpec.describe SlackMessage do
|
|
123
137
|
end
|
124
138
|
|
125
139
|
describe "API convenience" do
|
126
|
-
let(:profile) { SlackMessage::Configuration.profile(:default) }
|
127
|
-
|
128
140
|
before do
|
129
141
|
SlackMessage.configure do |config|
|
130
142
|
config.clear_profiles!
|
@@ -158,5 +170,57 @@ RSpec.describe SlackMessage do
|
|
158
170
|
end
|
159
171
|
end
|
160
172
|
|
161
|
-
|
173
|
+
describe "error handling" do
|
174
|
+
before do
|
175
|
+
SlackMessage.configure do |config|
|
176
|
+
config.clear_profiles!
|
177
|
+
config.add_profile(name: 'default profile', api_token: 'abc123')
|
178
|
+
config.add_profile(:schmoebot, name: 'Schmoe', api_token: 'abc123', icon: ':schmoebot:', default_channel: '#schmoes')
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
after do
|
183
|
+
SlackMessage::RSpec.reset_mock_response
|
184
|
+
end
|
185
|
+
|
186
|
+
it "raises nice error messages when API methods return errors" do
|
187
|
+
SlackMessage::RSpec.respond_with({'error' => 'nuffin'})
|
188
|
+
|
189
|
+
expect {
|
190
|
+
SlackMessage.post_to('#general') { text 'nuh uh' }
|
191
|
+
}.to raise_error(SlackMessage::ApiError)
|
192
|
+
|
193
|
+
expect {
|
194
|
+
SlackMessage.post_as(:schmoebot) { text 'nuh uh' }
|
195
|
+
}.to raise_error(SlackMessage::ApiError)
|
196
|
+
end
|
197
|
+
|
198
|
+
it "raises for redirects" do
|
199
|
+
SlackMessage::RSpec.respond_with(code: '302')
|
200
|
+
|
201
|
+
expect {
|
202
|
+
SlackMessage.post_to('#general') { text 'nuh uh' }
|
203
|
+
}.to raise_error(SlackMessage::ApiError)
|
204
|
+
end
|
205
|
+
|
206
|
+
it "raises errors w/ updates too" do
|
207
|
+
message = SlackMessage.post_to('#general') { text 'nuh uh' }
|
208
|
+
|
209
|
+
SlackMessage::RSpec.respond_with({'error' => 'bad choice'})
|
210
|
+
|
211
|
+
expect {
|
212
|
+
SlackMessage.update(message) { text 'nuh uh' }
|
213
|
+
}.to raise_error(SlackMessage::ApiError)
|
214
|
+
end
|
215
|
+
|
216
|
+
it "even raises errors during deletes" do
|
217
|
+
message = SlackMessage.post_to('#general') { text 'nuh uh' }
|
218
|
+
|
219
|
+
SlackMessage::RSpec.respond_with({'error' => 'bad choice'})
|
220
|
+
|
221
|
+
expect {
|
222
|
+
SlackMessage.delete(message) { text 'nuh uh' }
|
223
|
+
}.to raise_error(SlackMessage::ApiError)
|
224
|
+
end
|
225
|
+
end
|
162
226
|
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: 3.
|
4
|
+
version: 3.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joe Mastey
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-04-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -73,11 +73,13 @@ files:
|
|
73
73
|
- docs/05_deleting_messages.md
|
74
74
|
- docs/06_notifying_users.md
|
75
75
|
- docs/07_testing.md
|
76
|
+
- docs/_config.yml
|
76
77
|
- docs/index.md
|
77
78
|
- lib/slack_message.rb
|
78
79
|
- lib/slack_message/api.rb
|
79
80
|
- lib/slack_message/configuration.rb
|
80
81
|
- lib/slack_message/dsl.rb
|
82
|
+
- lib/slack_message/error_handling.rb
|
81
83
|
- lib/slack_message/response.rb
|
82
84
|
- lib/slack_message/rspec.rb
|
83
85
|
- slack_message.gemspec
|