active_notifier 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -0
- data/.travis.yml +13 -0
- data/README.md +40 -66
- data/active_notifier.gemspec +1 -0
- data/lib/active_notifier/adapters/abstract_adapter.rb +3 -2
- data/lib/active_notifier/adapters/dingtalk_adapter.rb +3 -2
- data/lib/active_notifier/configurable.rb +4 -3
- data/lib/active_notifier/core.rb +65 -42
- data/lib/active_notifier/templates/default.markdown.erb +1 -1
- data/lib/active_notifier/templates/default.text.erb +1 -0
- data/lib/active_notifier/version.rb +1 -1
- metadata +19 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 11d89dfa1aff8c314539b8ff79b5cbb72ed89f98e2fdce3c324a7e8ee097c789
|
4
|
+
data.tar.gz: b8edd79f2f6244a442a2d4bfb603ef0f4e6504971d6c9b4a33b66330f87a60e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 53025b951b32263b901f958d9200fa0eae7c954960a39299a1d249686fdeac091bedeee457256c379a4bd44e09274a02e1c2d613e8b1003c918501cee18be66d
|
7
|
+
data.tar.gz: 2d83333750347d2ec943ac14a273111de68ccb02226898ffea26c4e22792efc460859b1c17306c8cd0c521c9d74ffe3a2399ff098a8338120aed489c4d3dda2d
|
data/.rubocop.yml
CHANGED
data/.travis.yml
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.5.1
|
4
|
+
cache: bundler
|
5
|
+
script:
|
6
|
+
- bundle exec rspec
|
7
|
+
- bundle exec rubocop
|
8
|
+
deploy:
|
9
|
+
provider: rubygems
|
10
|
+
api_key:
|
11
|
+
secure: Kuaq/l0/f+pasOQRFpiF43o5bOqlhP3wbStxSYVAZye8YuGCMZ7wnzhNlD8cU57nc1e2tsONv78OT8qUKr8uNTeDU1RpRzAq8FEAiIHYHe2Rw/JUibE2c7GJchvpoQNCSCZZJbr6NZ5EcK6yx/mOoiZgWlAcvLWb2SdkIwDsRkucl6UEE6DP87ddkjBsE9TYAKV+Q+U76JHr20E0ANjoyTq4K6htdLuOqY2GwwhosQzZw/ixHNS+9GMCDJNJAJg5VYbv8AgCNgzkOPmPydfca1GWHSVul1QLvxC5EC7Sv8gt+uAcfxErf860hwoymenobhCMNPPmRZk65I+a2PC2O0Ni8xWriT8zsOJC15kFEGvmWFT5Vhix1fOCglB2C0CCanbfId+NjGu9AzfuT2cn7ySKbl3f2A7U3Kaopqge38z4xg0uYudfh9TkcZteUM8bq/S3Ioh3Z7NrynMfWcaFxArMkFoiAyCcJhXmQg/WXFKJjDXIC5AEWaEfv1xnBh/UZPIaqB5KC7MU2VRoesebr3EQl3rLU1AS+ga5m50lqnTIMRyH6clxvwojgfg51hkFRc16svTXshDvCq+u+ZfQUghO93jkeVHXernbiZFyzPFosBUwTxk75o5OaSKs6l6O52OIGa+mp6YqlCPXw5AGfQLBdS7qcuFokAKNesJQnts=
|
12
|
+
on:
|
13
|
+
tags: true
|
data/README.md
CHANGED
@@ -2,6 +2,10 @@
|
|
2
2
|
|
3
3
|
Notify message through webhooks.
|
4
4
|
|
5
|
+
[![Gem Version](https://badge.fury.io/rb/active_notifier.svg)](https://badge.fury.io/rb/active_notifier)
|
6
|
+
[![Build Status](https://travis-ci.org/pinewong/active_notifier.svg)](https://travis-ci.org/pinewong/active_notifier)
|
7
|
+
[![Test Coverage](https://codecov.io/github/pinewong/active_notifier/coverage.svg?branch=master)](https://codecov.io/github/pinewong/active_notifier?branch=master)
|
8
|
+
|
5
9
|
## Installation
|
6
10
|
|
7
11
|
Add this line to your application's Gemfile:
|
@@ -18,118 +22,88 @@ Or install it yourself as:
|
|
18
22
|
|
19
23
|
$ gem install active_notifier
|
20
24
|
|
21
|
-
## Usage
|
25
|
+
## Basic Usage
|
22
26
|
|
23
|
-
|
27
|
+
Just notify the message through a webhook token, ActiveNotifier use Dingtalk by default, the webhook token
|
28
|
+
need be a accessible dingtalk webhook token.
|
24
29
|
|
25
30
|
```ruby
|
26
|
-
|
27
|
-
ActiveNotifier.exec(:default)
|
28
|
-
# This will notifier message, use options:
|
29
|
-
# token: config.channel_tokens[:default],
|
30
|
-
# template: "#{config.template_home}/default.*.erb"
|
31
|
-
|
32
|
-
ActiveNotifier.exec(:default, template: "orders/create")
|
33
|
-
# Use specific template file but not get by channel
|
34
|
-
# This will notifier message, use options:
|
35
|
-
# token: config.channel_tokens[:default],
|
36
|
-
# template: "#{config.template_home}/orders/create.*.erb"
|
37
|
-
|
38
|
-
ActiveNotifier.exec(:default, token: "special_token", data: { title: "Title", message: "Message" })
|
39
|
-
# Use specific token but not get by channel
|
40
|
-
# This will notifier message, use options:
|
41
|
-
# token: "special_token",
|
42
|
-
# template: "#{config.template_home}/default.*.erb"
|
43
|
-
# And the Hash data will inject to template, and get a dynamic message after parse template
|
31
|
+
ActiveNotifier.exec(token: "your-webhook-token", message: "your-message")
|
44
32
|
```
|
45
33
|
|
46
|
-
|
34
|
+
Is it too much trouble to set the token and message always? You can save commonly used ones and access them via better ways.
|
35
|
+
For token, ActiveNotifier use channel_tokens to store it, and for message, we can use the ERB template and locals data, like the familiar ActiveView does.
|
47
36
|
|
48
|
-
Set token and template home for Rails application
|
49
37
|
|
50
38
|
```ruby
|
51
39
|
ActiveNotifier.configure do |config|
|
52
|
-
config.channel_tokens = {
|
40
|
+
config.channel_tokens = { my_channel: "xxx" }
|
53
41
|
config.template_home = Rails.root.join("app", "views", "active_notifier")
|
54
42
|
end
|
55
43
|
```
|
56
44
|
|
57
|
-
|
58
|
-
|
59
|
-
> app/views/active_notifier/default.markdown.erb
|
60
|
-
|
61
|
-
```erb
|
62
|
-
## #{data[:title]}
|
63
|
-
> #{data[:message]}
|
45
|
+
```shell
|
46
|
+
echo "## #{data[:title]\n> #{data[:body]}}" > app/views/active_notifier/my_channel.markdown.erb
|
64
47
|
```
|
65
48
|
|
66
|
-
Notify message
|
67
|
-
|
68
49
|
```ruby
|
69
|
-
ActiveNotifier.exec(:
|
50
|
+
ActiveNotifier.exec(token_channel: :my_channel, template: :my_channel, data: { title: "Message Title", body: "Message Body" })
|
70
51
|
```
|
71
52
|
|
72
|
-
|
73
|
-
|
74
|
-
Message type will dynamic set according by valid template files, when we
|
75
|
-
set a template named `order.text.erb`
|
53
|
+
Also when token_channel and template is the same, we can simplify it by using the first optional argument channel
|
76
54
|
|
77
55
|
```ruby
|
78
|
-
ActiveNotifier.
|
79
|
-
config.channel_tokens = { order: "xxx" }
|
80
|
-
config.template_home = Rails.root.join("app", "views", "active_notifier")
|
56
|
+
ActiveNotifier.exec(:my_channel, data: { title: "Message Title", body: "Message Body" })
|
81
57
|
```
|
82
58
|
|
83
|
-
|
59
|
+
## Advanced knowledge
|
84
60
|
|
85
|
-
|
86
|
-
title: #{data[:title]}
|
87
|
-
message: #{data[:message]}
|
88
|
-
```
|
61
|
+
### Send message with dynamic type
|
89
62
|
|
90
|
-
|
91
|
-
|
63
|
+
Message type will dynamic set according to a valid template, imagine we have two template files named `order.text.erb` and `order.markdown.erb`,
|
64
|
+
now we want use the text type of template, we need add a type option
|
92
65
|
|
93
66
|
```ruby
|
94
|
-
ActiveNotifier.exec(:
|
67
|
+
ActiveNotifier.exec(:order, data: { title: "Message Title", body: "Message Body" }, type: :text)
|
95
68
|
```
|
96
69
|
|
97
|
-
|
98
|
-
are exist, we still can make it OK which no need for type option, just
|
99
|
-
set the priority type
|
70
|
+
But if there is only one type of template, the type option is optional
|
100
71
|
|
101
|
-
|
72
|
+
```ruby
|
73
|
+
# Now we have only template file `product.text.erb` for product channel
|
102
74
|
|
103
|
-
|
104
|
-
title: #{data[:title]}
|
105
|
-
message: #{data[:message]}
|
75
|
+
ActiveNotifier.exec(:product, data: { title: "Message Title", body: "Message Body" }) # Needn't type option
|
106
76
|
```
|
107
77
|
|
108
|
-
|
78
|
+
And also we can configure priority type for ActiveNotifier
|
109
79
|
|
110
|
-
```
|
111
|
-
|
112
|
-
|
80
|
+
```ruby
|
81
|
+
ActiveNotifier.configure do |config|
|
82
|
+
# default is :markdown
|
83
|
+
config.priority_type = :text
|
84
|
+
end
|
113
85
|
```
|
114
86
|
|
115
87
|
```ruby
|
116
|
-
#
|
117
|
-
ActiveNotifer.config.priority_type = :text
|
88
|
+
# Now even we have template files `book.text.erb` and `book.markdown.erb` for book channel
|
118
89
|
|
119
|
-
#
|
120
|
-
ActiveNotifier.exec(:default, data: { title: "Title", message: "Message" }) # => Notifer message OK by text type template
|
90
|
+
ActiveNotifier.exec(:book, data: { title: "Message Title", body: "Message Body" }) # Needn't type option, and will choose the text type
|
121
91
|
```
|
122
92
|
|
123
|
-
### Set a short constant
|
93
|
+
### Set a short constant
|
94
|
+
|
95
|
+
ActiveSupport hook `after_initialize` will set this by default
|
124
96
|
|
125
97
|
```ruby
|
126
98
|
ActiveNotifer.config.const_name = :Notifier
|
127
99
|
Notifer.exec(...)
|
128
100
|
```
|
129
101
|
|
130
|
-
|
102
|
+
## Help and Docs
|
131
103
|
|
132
|
-
|
104
|
+
* [More Examples](https://github.com/pinewong/active_notifier/blob/master/spec/active_notifier_spec.rb)
|
105
|
+
* [RDoc](https://www.rubydoc.info/github/pinewong/active_notifier)
|
106
|
+
* [Gem RDoc](http://www.rubydoc.info/gems/active_notifier/0.3.0)
|
133
107
|
|
134
108
|
## Development
|
135
109
|
|
data/active_notifier.gemspec
CHANGED
@@ -34,6 +34,7 @@ Gem::Specification.new do |spec|
|
|
34
34
|
|
35
35
|
spec.add_development_dependency "bundler", "~> 1.16"
|
36
36
|
spec.add_development_dependency "byebug"
|
37
|
+
spec.add_development_dependency "codecov", ">= 0.1.10"
|
37
38
|
spec.add_development_dependency "rake", "~> 10.0"
|
38
39
|
spec.add_development_dependency "rspec", "~> 3.7"
|
39
40
|
spec.add_development_dependency "rubocop", "~> 0.58.1"
|
@@ -7,15 +7,16 @@ module ActiveNotifier
|
|
7
7
|
end
|
8
8
|
|
9
9
|
# Notify message
|
10
|
+
#
|
10
11
|
# @abstract Implement through setting a real adapter, like :dingtalk
|
11
12
|
# @param token [String] Channel webhook token
|
12
13
|
# @param type [Symbol] Message type
|
13
14
|
# @param message [String] Message body
|
14
|
-
# @param options [Hash]
|
15
|
-
# some adapters require some another options
|
15
|
+
# @param options [Hash] Adapter message options, some adapters require some another options
|
16
16
|
# @raise [AdapterOptionsInvalidError]
|
17
17
|
# @raise [AdapterTypeInvalidError]
|
18
18
|
# @raise [MessageBlankError]
|
19
|
+
# @see ActiveNotitifier::exec for usage
|
19
20
|
def notify(token, type, message, **options)
|
20
21
|
adapter.notify(token, type, message, **options)
|
21
22
|
end
|
@@ -2,14 +2,15 @@ module ActiveNotifier
|
|
2
2
|
class DingtalkAdapter
|
3
3
|
VALID_TYPES = %i[markdown].freeze
|
4
4
|
|
5
|
+
# (see AbstractAdapter#notify)
|
5
6
|
def notify(token, type, message, **options)
|
6
7
|
webhook = "#{ActiveNotifier.config.adapters_with_base_url.fetch(:dingtalk)}#{token}"
|
7
8
|
unless VALID_TYPES.include?(type)
|
8
|
-
error_message = "
|
9
|
+
error_message = "The Dingtalk adapter only support types: #{VALID_TYPES.join(', ')}"
|
9
10
|
raise ActiveNotifier::AdapterTypeInvalidError, error_message
|
10
11
|
end
|
11
12
|
raise ActiveNotifier::MessageBlankError, "message can't be blank, please check template file" if message.empty?
|
12
|
-
title = options[:title]
|
13
|
+
title = options[:title]&.to_s
|
13
14
|
raise ActiveNotifier::AdapterOptionsInvalidError, "Dingtalk adapter require other options: title" if title.empty?
|
14
15
|
|
15
16
|
body = {
|
@@ -3,15 +3,16 @@ module ActiveNotifier
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
module ClassMethods
|
6
|
-
# Configure for ActiveNotifier
|
7
|
-
#
|
8
|
-
# @raise [ConfigureError]
|
6
|
+
# Configure for ActiveNotifier.
|
7
|
+
#
|
9
8
|
# @example
|
10
9
|
# ActiveNotifier.configure do |config|
|
11
10
|
# config.const_name = :Message
|
12
11
|
# config.adapter = :slack
|
13
12
|
# # ...
|
14
13
|
# end
|
14
|
+
# @yield [config] Give a Configuration instance for settings
|
15
|
+
# @raise [ConfigureError]
|
15
16
|
def configure
|
16
17
|
yield config
|
17
18
|
end
|
data/lib/active_notifier/core.rb
CHANGED
@@ -3,59 +3,77 @@ module ActiveNotifier
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
module ClassMethods
|
6
|
-
# Message execute
|
7
|
-
#
|
8
|
-
# @
|
9
|
-
#
|
10
|
-
# @
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
6
|
+
# Message execute.
|
7
|
+
#
|
8
|
+
# @example Command Usage
|
9
|
+
# ActiveNotifier.exec(token: "your-webhook-token", message: "your-message")
|
10
|
+
# @example Common Usage
|
11
|
+
# # Configure it
|
12
|
+
# ActiveNotifier.configure do |config|
|
13
|
+
# config.channel_tokens = { my_channel: "xxx" }
|
14
|
+
# config.template_home = Rails.root.join("app", "views", "active_notifier")
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# # Add template
|
18
|
+
# echo "## #{data[:title]\n> #{data[:body]}}" > app/views/active_notifier/my_channel.markdown.erb
|
19
|
+
#
|
20
|
+
# # Execute it
|
21
|
+
# ActiveNotifier.exec(:my_channel, data: { title: "Message Title", body: "Message Body" })
|
22
|
+
# @param channel [#to_sym] (nil) Message channel, it will set template and token_channel together
|
23
|
+
# @param options [#to_h] ({})
|
24
|
+
# @option options [#to_s] :token (nil) Message webhook token,
|
25
|
+
# @option options [#to_s] :message (nil) Message
|
26
|
+
# @option options [#to_sym] :token_channel (nil) Message webhook token channel,
|
27
|
+
# will use `channel` when this value is blank
|
28
|
+
# @option options [#to_sym] :template (nil) Message template, will use `channel` when this value is blank
|
29
|
+
# @option options [#to_sym] :adapter (ActiveNotifier.config.adapter) Message adapter
|
30
|
+
# @option options [#to_sym] :type (nil) Message type, it will use a specific template file, for example,
|
31
|
+
# when type is :text and template is :order, then ActiveNotifier will choose `order.text.erb` for template file
|
32
|
+
# @option options [#to_h] :data ({}) Message variable data for template, it can used in erb template file
|
33
|
+
# @option options [Anything] Other options will used in adapter message execute, like Dingtalk require title
|
34
|
+
# for message, we can pass it here: `ActiveNotifer.exec(:default, title: "dingtalk title")`
|
20
35
|
# @raise [TemplateNotFoundError]
|
21
36
|
# @raise [UndefinedTokenError]
|
22
37
|
# @raise [AdapterOptionsInvalidError]
|
23
38
|
# @raise [AdapterTypeInvalidError]
|
24
39
|
# @raise [MessageBlankError]
|
25
|
-
# @
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
adapter
|
41
|
-
|
42
|
-
adapter.notify(token, type, message, adapter_options)
|
40
|
+
# @see Get more see README
|
41
|
+
def exec(channel = nil, **options)
|
42
|
+
channel = channel&.to_sym
|
43
|
+
token = options[:token]&.to_s
|
44
|
+
message = options[:message]&.to_s
|
45
|
+
token_channel = options[:token_channel]&.to_sym
|
46
|
+
template = options[:template]&.to_sym
|
47
|
+
adapter = options[:adapter]&.to_sym
|
48
|
+
type = options[:type]&.to_sym
|
49
|
+
data = options[:data].to_h
|
50
|
+
token = fetch_token(token, token_channel, channel)
|
51
|
+
template ||= channel
|
52
|
+
type ||= get_type_by_template(template)
|
53
|
+
message ||= get_message(template, type, data)
|
54
|
+
adapter_options = options.except(:token, :message, :token_channel, :template, :adapter, :type, :data)
|
55
|
+
adapter ||= ActiveNotifier.config.adapter.to_sym
|
56
|
+
ActiveNotifier.adapt(adapter).notify(token, type, message, adapter_options)
|
43
57
|
end
|
44
58
|
|
45
59
|
private
|
46
60
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
61
|
+
# @param token [String, nil]
|
62
|
+
# @param token_channel [Symbol, nil]
|
63
|
+
# @param channel [Symbol, nil]
|
64
|
+
# @return [String]
|
65
|
+
def fetch_token(token, token_channel, channel)
|
66
|
+
token = token ||
|
67
|
+
token_channel && ActiveNotifier.config.channel_tokens[token_channel]&.to_s ||
|
68
|
+
channel && ActiveNotifier.config.channel_tokens[channel]&.to_s
|
69
|
+
raise ActiveNotifier::UndefinedTokenError unless token
|
70
|
+
token
|
56
71
|
end
|
57
72
|
|
58
|
-
|
73
|
+
# @param template [Symbol, nil]
|
74
|
+
# @return [Symbol, nil]
|
75
|
+
def get_type_by_template(template)
|
76
|
+
return unless template
|
59
77
|
template_paths = Dir["#{ActiveNotifier.config.template_home}/#{template}.*.erb"]
|
60
78
|
raise ActiveNotifier::TemplateNotFoundError if template_paths.empty?
|
61
79
|
types = template_paths.map do |template_path|
|
@@ -68,7 +86,12 @@ module ActiveNotifier
|
|
68
86
|
end
|
69
87
|
end
|
70
88
|
|
89
|
+
# @param template [Symbol, nil]
|
90
|
+
# @param type [Symbol]
|
91
|
+
# @param data [Hash]
|
92
|
+
# @return [String, nil]
|
71
93
|
def get_message(template, type, data)
|
94
|
+
return unless template
|
72
95
|
template_data = File.read("#{ActiveNotifier.config.template_home}/#{template}.#{type}.erb")
|
73
96
|
ERB.new(template_data).result_with_hash(data: data)
|
74
97
|
rescue Errno::ENOENT => e
|
@@ -1 +1 @@
|
|
1
|
-
<%= data %>
|
1
|
+
> <%= data %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= data %>
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_notifier
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pine Wong
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-07-
|
11
|
+
date: 2018-07-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: codecov
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.1.10
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.1.10
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: rake
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -151,6 +165,7 @@ extra_rdoc_files: []
|
|
151
165
|
files:
|
152
166
|
- ".gitignore"
|
153
167
|
- ".rubocop.yml"
|
168
|
+
- ".travis.yml"
|
154
169
|
- CODE_OF_CONDUCT.md
|
155
170
|
- Gemfile
|
156
171
|
- README.md
|
@@ -166,6 +181,7 @@ files:
|
|
166
181
|
- lib/active_notifier/core.rb
|
167
182
|
- lib/active_notifier/errors.rb
|
168
183
|
- lib/active_notifier/templates/default.markdown.erb
|
184
|
+
- lib/active_notifier/templates/default.text.erb
|
169
185
|
- lib/active_notifier/version.rb
|
170
186
|
homepage: https://github.com/pinewong/active_notifier
|
171
187
|
licenses: []
|
@@ -186,7 +202,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
186
202
|
version: '0'
|
187
203
|
requirements: []
|
188
204
|
rubyforge_project:
|
189
|
-
rubygems_version: 2.7.
|
205
|
+
rubygems_version: 2.7.7
|
190
206
|
signing_key:
|
191
207
|
specification_version: 4
|
192
208
|
summary: Notify message through webhooks.
|