teams_connector 0.1.4 → 0.1.6

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: 46a69bacfa1eb6a6b46616d436ff4b8c7890db602ce30c7f082e004e53e161c3
4
- data.tar.gz: e98ac0f36a4fc64a1ec41f100ce6b062dc4b1ff4579a2094e2b6d49530b2b5f3
3
+ metadata.gz: ec351030eb8a9eb02df72d9807fec0ebb3040bb08fa2046182de96ccc01f0523
4
+ data.tar.gz: 54c5be1eeccab5fc6f0b34f0a226c896d1f96c9902d662c1c99cf88844216f4a
5
5
  SHA512:
6
- metadata.gz: f5183b39ff855da474a6417861020f44b2933a4e93fbc497207eab427802e88a33d41511ca30c90390741baf85f39a72b30804ddf78a302f1247e49bfb3edd69
7
- data.tar.gz: b68b7311f4ba4f7fd2b37c99bdc960fef80d0c7528fdad6a06002820df60131c0f4b5ae1eb2f5f08a9d57e54c5a7673ee96add2d9aca7219c76301ccc5d27f14
6
+ metadata.gz: b2e9831c57a4961021faae608a4e2ee0b1752ad4b2ca05adc974a8ac44421ae30175217bfc3705b0810918aef694b4ac1e1323a0ad7945b79bdb313c061b77c3
7
+ data.tar.gz: c6935973c88bbdf258dbbcda1f5341209eca6ce53738579f95d3da64cbe8cbc28e7c4a499f7e21f14109a6c53d3eadc8c44f4ce5ef9359809f92c0aa6d1d5e0b
@@ -15,21 +15,18 @@ on:
15
15
 
16
16
  jobs:
17
17
  test:
18
-
19
18
  runs-on: ubuntu-latest
19
+ name: Ruby ${{ matrix.ruby-version }}
20
20
  strategy:
21
21
  matrix:
22
- ruby-version: ['2.6', '2.7', '3.0']
22
+ ruby-version: ['2.6', '2.7', '3.0', '3.2']
23
23
 
24
24
  steps:
25
- - uses: actions/checkout@v2
26
- - name: Set up Ruby
27
- # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
28
- # change this to (see https://github.com/ruby/setup-ruby#versioning):
29
- # uses: ruby/setup-ruby@v1
30
- uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
31
- with:
32
- ruby-version: ${{ matrix.ruby-version }}
33
- bundler-cache: true # runs 'bundle install' and caches installed gems automatically
34
- - name: Run tests
35
- run: bundle exec rake
25
+ - uses: actions/checkout@v3
26
+ - name: Set up Ruby
27
+ uses: ruby/setup-ruby@v1
28
+ with:
29
+ ruby-version: ${{ matrix.ruby-version }}
30
+ bundler-cache: true
31
+ - name: Run the default task
32
+ run: bundle exec rake
data/.rubocop.yml ADDED
@@ -0,0 +1,19 @@
1
+ AllCops:
2
+ NewCops: enable
3
+ TargetRubyVersion: 2.6
4
+
5
+ Layout/LineLength:
6
+ Exclude:
7
+ - spec/**/*
8
+
9
+ Metrics/BlockLength:
10
+ Exclude:
11
+ - spec/**/*
12
+ - '*.gemspec'
13
+
14
+ Style/CaseEquality:
15
+ Exclude:
16
+ - lib/teams_connector/matchers/have_sent_notification_to.rb
17
+
18
+ Style/Documentation:
19
+ Enabled: false
data/CHANGES.md CHANGED
@@ -1,19 +1,28 @@
1
1
  # Teams Connector Changelog
2
2
 
3
- 0.1.4
4
- ---
3
+ ## 0.1.6
4
+ - Enable Github actions for ruby 3
5
+ - Enable Rubocop linting
6
+ - Bump compatibility to sidekiq 7
7
+ - More stringent RuboCop tests
8
+ - Enable RubyGems MFA required
9
+
10
+ ## 0.1.5
11
+ - RSpec Matchers for testing, thanks to [rspec-rails](https://github.com/rspec/rspec-rails) for their ActionCable `have_broadcasted_to` matcher as reference
12
+ - README update for testing
13
+ - Sometimes use testing mode internally
14
+ - Fixed code smells
15
+
16
+ ## 0.1.4
5
17
  - Add rudimentary testing method
6
18
 
7
- 0.1.3
8
- ---
19
+ ## 0.1.3
9
20
  - Allow sending a notification to multiple channels at the same time
10
21
 
11
- 0.1.2
12
- ---
22
+ ## 0.1.2
13
23
  - Use `TeamsConnector::Configuration#load_from_rails_credentials` to load encrypted channel URLs in your Rails environment
14
24
 
15
- 0.1.1
16
- ---
25
+ ## 0.1.1
17
26
  - Adaptive Card Notification
18
27
  - Send a more complex Adaptive Card instead of the basic Message Card
19
28
  - Builder
@@ -28,7 +37,6 @@
28
37
  - Change constructor from numbered to named parameters
29
38
  - Pretty print JSON to STDOUT with #pretty_print
30
39
 
31
- 0.1.0
32
- ---
40
+ ## 0.1.0
33
41
  - Initial commit of the Teams Connector gem
34
42
  - Send messages as cards defined by JSON templates to configured Microsoft Teams channels
data/Gemfile CHANGED
@@ -1,6 +1,14 @@
1
- source "https://rubygems.org"
1
+ # frozen_string_literal: true
2
2
 
3
- git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
3
+ source 'https://rubygems.org'
4
4
 
5
5
  # Specify your gem's dependencies in teams_connector.gemspec
6
6
  gemspec
7
+
8
+ gem 'bundler', '>= 1.17'
9
+ gem 'rake', '>= 10.0'
10
+ gem 'rspec', '>= 3.0'
11
+ gem 'rubocop'
12
+ gem 'sidekiq', '< 8'
13
+ gem 'simplecov'
14
+ gem 'webmock'
data/README.md CHANGED
@@ -81,11 +81,11 @@ The default templates will be still available so you can mix and match.
81
81
 
82
82
  #### Default templates
83
83
 
84
- Template name | Description
85
- -----|-------
86
- :adaptive_card | A card with the body of an adaptive card for more complex scenarios
87
- :facts_card | A card with title, subtitle and a list of facts
88
- :test_card | A simple text message without any configurable content for testing
84
+ | Template name | Description |
85
+ |----------------|---------------------------------------------------------------------|
86
+ | :adaptive_card | A card with the body of an adaptive card for more complex scenarios |
87
+ | :facts_card | A card with title, subtitle and a list of facts |
88
+ | :test_card | A simple text message without any configurable content for testing |
89
89
 
90
90
  #### Custom Templates
91
91
 
@@ -112,18 +112,63 @@ TeamsConnector::Notification::AdaptiveCard.new(content: builder).deliver_later
112
112
  ## Testing
113
113
 
114
114
  To test TeamsConnector integration in your application you can use the `:testing` method.
115
- Instead of performing real HTTP requests, an array in `TeamsConnector.testing.requests` is filled in chronological order.
115
+ Instead of performing real HTTP requests, an array in `TeamsConnector.testing.requests` is filled with your notifications in chronological order.
116
116
 
117
117
  The request elements have the following structure:
118
118
  ```ruby
119
119
  {
120
120
  channel: :default,
121
121
  template: :facts_card,
122
- content: "rendered content",
122
+ content: '{"rendered content": "in JSON format"}',
123
123
  time: Time.now
124
124
  }
125
125
  ```
126
126
 
127
+ ### RSpec Matcher
128
+ TeamsConnector provides the `sent_notification_to?(channel = nil, template = nil)` matcher for RSpec.
129
+ It is available by adding `require "teams_connector/rspec"` to your `spec_helper.rb`.
130
+ The matcher supports filtering notifications by channel and template. If one is not given, it does not filter the notifications by it.
131
+ There exists the alias `send_notification_to` and `have_sent_notification_to` for `sent_notification_to?`.
132
+
133
+ ```ruby
134
+ it "has sent exactly one notification to the channel" do
135
+ expect { notification.deliver_later }.to sent_notification_to?(:channel)
136
+ end
137
+ ```
138
+
139
+ #### Expecting number of notifications
140
+ By default `sent_notification_to?` expects exactly one matching notification.
141
+ You can change the expected amount by chaining `exactly`, `at_least` or `at_most`.
142
+
143
+ Example:
144
+ ```ruby
145
+ it "has sent less than 10 notifications to the channel" do
146
+ expect { notification.deliver_later }.to sent_notification_to?(:channel).at_most(10)
147
+ end
148
+ ```
149
+
150
+ You can also use `once`, `twice` and `thrice` as an alias for `exactly(1..3)`.
151
+ For more readable expectations `times` can be chained.
152
+
153
+ #### Expecting templates
154
+ The template argument in the matcher does filter the notifications.
155
+ If you expect a template instead, you can chain with `with_template(:template)`.
156
+
157
+ #### Expecting content
158
+ To expect specific content, you can chain with `with(data = nil, &block)`.
159
+ Data supports other RSpec matchers like `hash_including`.
160
+ The block is called for every notification with the notification content hash and the raw notification itself.
161
+
162
+ Example:
163
+ ```ruby
164
+ expect {
165
+ notification(:default, :test_card).deliver_later
166
+ }.to sent_notification_to?(:default).with { |content, notification|
167
+ expect(notification[:channel]).to eq :default
168
+ expect(notification[:template]).to eq :test_card
169
+ expect(content["sections"]).to include(hash_including("activityTitle", "activitySubtitle", "facts", "markdown" => true))
170
+ }
171
+ ```
127
172
  ## Development
128
173
 
129
174
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/Rakefile CHANGED
@@ -1,6 +1,12 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
3
5
 
4
6
  RSpec::Core::RakeTask.new(:spec)
5
7
 
6
- task :default => :spec
8
+ require 'rubocop/rake_task'
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
data/bin/console CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
- require "bundler/setup"
4
- require "teams_connector"
4
+ require 'bundler/setup'
5
+ require 'teams_connector'
5
6
 
6
7
  # You can add fixtures and/or initialization code here to make experimenting
7
8
  # with your gem easier. You can also use a different console, if you like.
@@ -11,26 +12,26 @@ require "teams_connector"
11
12
  # Pry.start
12
13
 
13
14
  TeamsConnector.configure do |config|
14
- if File.exist?("channels.yml")
15
+ if File.exist?('channels.yml')
15
16
  # NOTE(Keune): The channels available in the console can be set in the file channels.yml. It contains a simple
16
17
  # mapping of channel identifiers to webhook URLs. The channel identifier is loaded as a symbol.
17
18
  #
18
19
  # Example: default: "<INSERT YOUR WEBHOOK URL HERE>"
19
- puts "Load channels specified by file"
20
+ puts 'Load channels specified by file'
20
21
 
21
- require "yaml"
22
- channels = YAML.load_file "channels.yml"
22
+ require 'yaml'
23
+ channels = YAML.load_file 'channels.yml'
23
24
  channels.each do |k, v|
24
25
  config.channel k.to_sym, v
25
26
  end
26
27
  else
27
28
  # NOTE(Keune): Specify the channels you want to have available in the console
28
- config.channel :default, "<INSERT YOUR WEBHOOK URL HERE>"
29
+ config.channel :default, '<INSERT YOUR WEBHOOK URL HERE>'
29
30
  end
30
31
  config.default = :default
31
32
  config.always_use_default = true
32
33
  config.method = :direct
33
34
  end
34
35
 
35
- require "irb"
36
+ require 'irb'
36
37
  IRB.start(__FILE__)
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ # NOTE(Keune): This core extension is taken directly from rails to support a single usage of #present?
4
+ # See rails/activesupport/lib/active_support/core_ext/object/blank.rb
5
+ class Object
6
+ # An object is blank if it's false, empty, or a whitespace string.
7
+ # For example, +nil+, '', ' ', [], {}, and +false+ are all blank.
8
+ #
9
+ # This simplifies
10
+ #
11
+ # !address || address.empty?
12
+ #
13
+ # to
14
+ #
15
+ # address.blank?
16
+ #
17
+ # @return [true, false]
18
+ def blank?
19
+ respond_to?(:empty?) ? !!empty? : false
20
+ end
21
+
22
+ # An object is present if it's not blank.
23
+ #
24
+ # @return [true, false]
25
+ def present?
26
+ !blank?
27
+ end
28
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module TeamsConnector
2
4
  class Builder
3
5
  attr_accessor :type, :content
@@ -15,8 +17,8 @@ module TeamsConnector
15
17
  @content = text
16
18
  end
17
19
 
18
- def self.container
19
- TeamsConnector::Builder.new { |entry| entry.container { |items| yield items } }
20
+ def self.container(&block)
21
+ TeamsConnector::Builder.new { |entry| entry.container(&block) }
20
22
  end
21
23
 
22
24
  def container
@@ -25,8 +27,8 @@ module TeamsConnector
25
27
  yield @content
26
28
  end
27
29
 
28
- def self.facts
29
- TeamsConnector::Builder.new { |entry| entry.facts { |facts| yield facts } }
30
+ def self.facts(&block)
31
+ TeamsConnector::Builder.new { |entry| entry.facts(&block) }
30
32
  end
31
33
 
32
34
  def facts
@@ -38,23 +40,37 @@ module TeamsConnector
38
40
  def result
39
41
  case @type
40
42
  when :container
41
- {
42
- type: "Container",
43
- items: @content.map { |element| element.result }
44
- }
43
+ result_container
45
44
  when :facts
46
- {
47
- type: "FactSet",
48
- facts: @content.map { |fact| { title: fact[0], value: fact[1] } }
49
- }
45
+ result_facts
50
46
  when :text
51
- {
52
- type: "TextBlock",
53
- text: @content
54
- }
47
+ result_text
55
48
  else
56
49
  raise TypeError, "The type #{@type} is not supported by the TeamsConnector::Builder"
57
50
  end
58
51
  end
52
+
53
+ private
54
+
55
+ def result_container
56
+ {
57
+ type: 'Container',
58
+ items: @content.map(&:result)
59
+ }
60
+ end
61
+
62
+ def result_facts
63
+ {
64
+ type: 'FactSet',
65
+ facts: @content.map { |fact| { title: fact[0], value: fact[1] } }
66
+ }
67
+ end
68
+
69
+ def result_text
70
+ {
71
+ type: 'TextBlock',
72
+ text: @content
73
+ }
74
+ end
59
75
  end
60
76
  end
@@ -1,8 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module TeamsConnector
2
4
  class Configuration
3
- DEFAULT_TEMPLATE_DIR = %w[templates teams_connector]
5
+ DEFAULT_TEMPLATE_DIR = %w[templates teams_connector].freeze
4
6
 
5
- attr_accessor :default, :channels, :always_use_default, :method, :template_dir, :color
7
+ attr_reader :default, :method
8
+ attr_accessor :channels, :always_use_default, :template_dir, :color
6
9
 
7
10
  def initialize
8
11
  @default = nil
@@ -10,28 +13,28 @@ module TeamsConnector
10
13
  @always_use_default = false
11
14
  @method = :direct
12
15
  @template_dir = DEFAULT_TEMPLATE_DIR
13
- @color = "3f95b5"
16
+ @color = '3f95b5'
14
17
  end
15
18
 
16
19
  def default=(channel)
17
20
  raise ArgumentError, "Desired default channel '#{channel}' is not configured" unless @channels.key?(channel)
21
+
18
22
  @default = channel
19
23
  end
20
24
 
21
25
  def method=(method)
22
- raise ArgumentError, "Method '#{method.to_s}' is not supported" unless [:direct, :sidekiq, :testing].include? method
23
- raise ArgumentError, "Sidekiq is not available" if method == :sidekiq && !defined? Sidekiq
26
+ raise ArgumentError, "Method '#{method}' is not supported" unless %i[direct sidekiq testing].include? method
27
+ raise ArgumentError, 'Sidekiq is not available' if method == :sidekiq && !defined? Sidekiq
28
+
24
29
  @method = method
25
30
  end
26
31
 
27
32
  def channel(name, url)
28
- @channels[name] = url;
33
+ @channels[name] = url
29
34
  end
30
35
 
31
36
  def load_from_rails_credentials
32
- unless defined? Rails
33
- raise RuntimeError, "This method is only available in Ruby on Rails."
34
- end
37
+ raise 'This method is only available in Ruby on Rails.' unless defined? Rails
35
38
 
36
39
  webhook_urls = Rails.application.credentials.teams_connector!
37
40
  webhook_urls.each do |entry|
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TeamsConnector
4
+ module Matchers
5
+ module ExpectedNumber
6
+ def exactly(count)
7
+ set_expected_number(:exactly, count)
8
+ self
9
+ end
10
+
11
+ def at_least(count)
12
+ set_expected_number(:at_least, count)
13
+ self
14
+ end
15
+
16
+ def at_most(count)
17
+ set_expected_number(:at_most, count)
18
+ self
19
+ end
20
+
21
+ def times
22
+ self
23
+ end
24
+
25
+ def once
26
+ exactly(:once)
27
+ end
28
+
29
+ def twice
30
+ exactly(:twice)
31
+ end
32
+
33
+ def thrice
34
+ exactly(:thrice)
35
+ end
36
+
37
+ private
38
+
39
+ def set_expected_number(relativity, count)
40
+ @expectation_type = relativity
41
+ @expected_number =
42
+ case count
43
+ when :once then 1
44
+ when :twice then 2
45
+ when :thrice then 3
46
+ else Integer(count)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'expected_number'
4
+ require_relative 'with'
5
+
6
+ module TeamsConnector
7
+ module Matchers
8
+ class HaveSentNotificationTo
9
+ include RSpec::Matchers::Composable
10
+ include TeamsConnector::Matchers::ExpectedNumber
11
+ include TeamsConnector::Matchers::With
12
+
13
+ class RelativityNotSupported < StandardError; end
14
+
15
+ def initialize(channel, template)
16
+ @filter = {
17
+ channel: channel,
18
+ template: template
19
+ }
20
+ @block = proc {}
21
+ @data = nil
22
+ @template_data = nil
23
+ set_expected_number(:exactly, 1)
24
+ end
25
+
26
+ def failure_message
27
+ msg = "expected to send #{base_message}"
28
+ if @unmatching_ntfcts.any?
29
+ msg += "\nSent notifications"
30
+ msg += " to #{@filter[:channel]}" if @filter[:channel]
31
+ msg += " of #{@filter[:template]}" if @filter[:template]
32
+ msg += ':'
33
+ @unmatching_ntfcts.each { |data| msg += "\n #{data}" }
34
+ end
35
+
36
+ msg
37
+ end
38
+
39
+ def failure_message_when_negated
40
+ "expected not to send #{base_message}"
41
+ end
42
+
43
+ def matches?(expectation)
44
+ matching_notifications = in_block_notifications(expectation).select do |msg|
45
+ @filter.map { |k, v| msg[k] == v unless v.nil? }.compact.all?
46
+ end
47
+
48
+ check(matching_notifications)
49
+ end
50
+
51
+ def supports_block_expectations?
52
+ true
53
+ end
54
+
55
+ private
56
+
57
+ def check(notifications)
58
+ @matching_ntfcts, @unmatching_ntfcts = notifications.partition do |ntfct|
59
+ check_partition(ntfct)
60
+ end
61
+
62
+ @matching_count = @matching_ntfcts.size
63
+
64
+ check_result
65
+ end
66
+
67
+ def check_partition(ntfct)
68
+ result = true
69
+
70
+ result &= ntfct[:template] == @template_data unless @template_data.nil?
71
+
72
+ decoded = JSON.parse(ntfct[:content])
73
+ if @data.nil? || @data === decoded
74
+ @block.call(decoded, ntfct)
75
+ result & true
76
+ else
77
+ false
78
+ end
79
+ end
80
+
81
+ def check_result
82
+ case @expectation_type
83
+ when :exactly then @expected_number == @matching_count
84
+ when :at_most then @expected_number >= @matching_count
85
+ when :at_least then @expected_number <= @matching_count
86
+ else
87
+ raise RelativityNotSupported
88
+ end
89
+ end
90
+
91
+ def in_block_notifications(expectation)
92
+ if expectation.is_a? Proc
93
+ original_count = TeamsConnector.testing.requests.size
94
+ expectation.call
95
+ TeamsConnector.testing.requests.drop(original_count)
96
+ else
97
+ expectation
98
+ end
99
+ end
100
+
101
+ def base_message
102
+ msg = String("#{message_expectation_modifier} #{@expected_number} notifications")
103
+ msg += " to #{@filter[:channel]}" if @filter[:channel]
104
+ msg += " of #{@filter[:template]}" if @filter[:template]
105
+ msg += " with template #{@template_data}" if @template_data
106
+ msg += " with content #{data_description(@data)}" if @data
107
+ msg + ", but sent #{@matching_count}"
108
+ end
109
+
110
+ def message_expectation_modifier
111
+ case @expectation_type
112
+ when :exactly then 'exactly'
113
+ when :at_most then 'at most'
114
+ when :at_least then 'at least'
115
+ else
116
+ raise RelativityNotSupported
117
+ end
118
+ end
119
+
120
+ def data_description(data)
121
+ if RSpec::Support.is_a_matcher?(data) && data.respond_to?(:description)
122
+ data.description
123
+ else
124
+ data
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TeamsConnector
4
+ module Matchers
5
+ module With
6
+ def with(data = nil, &block)
7
+ @data = data
8
+ @block = block if block
9
+ self
10
+ end
11
+
12
+ def with_template(template = nil)
13
+ @template_data = template
14
+ self
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'teams_connector/matchers/have_sent_notification_to'
4
+
5
+ module TeamsConnector
6
+ module Matchers
7
+ def sent_notification_to?(channel = nil, template = nil)
8
+ HaveSentNotificationTo.new(channel, template)
9
+ end
10
+
11
+ alias have_sent_notification_to sent_notification_to?
12
+ alias send_notification_to have_sent_notification_to
13
+ end
14
+ end
@@ -1,15 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module TeamsConnector
2
- class Notification::AdaptiveCard < Notification
3
- attr_accessor :content
4
+ class Notification
5
+ class AdaptiveCard < Notification
6
+ attr_accessor :content
4
7
 
5
- def initialize(template: :adaptive_card, content: {}, channel: TeamsConnector.configuration.default)
6
- super(template: template, channel: channel)
7
- if content.instance_of? TeamsConnector::Builder
8
- @content = {
9
- card: [content.result]
10
- }
11
- else
12
- @content = content
8
+ def initialize(template: :adaptive_card, content: {}, channel: TeamsConnector.configuration.default)
9
+ super(template: template, channels: channel)
10
+ @content =
11
+ if content.instance_of? TeamsConnector::Builder
12
+ {
13
+ card: [content.result]
14
+ }
15
+ else
16
+ content
17
+ end
13
18
  end
14
19
  end
15
20
  end
@@ -1,11 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module TeamsConnector
2
- class Notification::Message < Notification
3
- attr_accessor :summary, :content
4
+ class Notification
5
+ class Message < Notification
6
+ attr_accessor :summary, :content
4
7
 
5
- def initialize(template, summary, content = {}, channel = TeamsConnector.configuration.default)
6
- super(template: template, channels: channel)
7
- @summary = summary
8
- @content = content
8
+ def initialize(template, summary, content = {}, channel = TeamsConnector.configuration.default)
9
+ super(template: template, channels: channel)
10
+ @summary = summary
11
+ @content = content
12
+ end
9
13
  end
10
14
  end
11
15
  end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'erb'
2
4
  require 'json'
3
5
  require 'net/http'
4
- require 'teams_connector/post_worker' if defined? Sidekiq
6
+ require 'teams_connector/post_job' if defined? Sidekiq
5
7
 
6
8
  module TeamsConnector
7
9
  class Notification
@@ -22,17 +24,7 @@ module TeamsConnector
22
24
 
23
25
  channels = TeamsConnector.configuration.always_use_default ? [TeamsConnector.configuration.default] : @channels
24
26
  channels.each do |channel|
25
- url = TeamsConnector.configuration.channels[channel]
26
- raise ArgumentError, "The Teams channel '#{channel}' is not available in the configuration." if url.nil?
27
-
28
- if TeamsConnector.configuration.method == :sidekiq
29
- TeamsConnector::PostWorker.perform_async(url, content)
30
- elsif TeamsConnector.configuration.method == :testing
31
- TeamsConnector.testing.perform_request channel, @template, content
32
- else
33
- response = Net::HTTP.post(URI(url), content, { "Content-Type": "application/json" })
34
- response.value
35
- end
27
+ deliver_channel(channel, content)
36
28
  end
37
29
  end
38
30
 
@@ -48,11 +40,26 @@ module TeamsConnector
48
40
 
49
41
  private
50
42
 
51
- def find_template
52
- path = File.join(TeamsConnector::project_root, *TeamsConnector.configuration.template_dir, "#{@template.to_s}.json.erb")
53
- unless File.exist? path
54
- path = File.join(TeamsConnector::gem_root, *TeamsConnector::Configuration::DEFAULT_TEMPLATE_DIR, "#{@template.to_s}.json.erb")
43
+ def deliver_channel(channel, content)
44
+ url = TeamsConnector.configuration.channels[channel]
45
+ raise ArgumentError, "The Teams channel '#{channel}' is not available in the configuration." if url.nil?
46
+
47
+ case TeamsConnector.configuration.method
48
+ when :sidekiq then TeamsConnector::PostJob.perform_async(url, content)
49
+ when :testing then TeamsConnector.testing.perform_request channel, @template, content
50
+ else
51
+ response = Net::HTTP.post(URI(url), content, { 'Content-Type' => 'application/json' })
52
+ response.value
55
53
  end
54
+ end
55
+
56
+ def find_template
57
+ path = File.join(TeamsConnector.project_root, *TeamsConnector.configuration.template_dir, "#{@template}.json.erb")
58
+ return path if File.exist? path
59
+
60
+ path = File.join(TeamsConnector.gem_root,
61
+ *TeamsConnector::Configuration::DEFAULT_TEMPLATE_DIR,
62
+ "#{@template}.json.erb")
56
63
  raise ArgumentError, "The template '#{@template}' is not available." unless File.exist? path
57
64
 
58
65
  path
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'sidekiq/job'
5
+
6
+ module TeamsConnector
7
+ class PostJob
8
+ # === Includes ===
9
+ include Sidekiq::Job
10
+
11
+ def perform(url, content)
12
+ response = Net::HTTP.post(URI(url), content, { 'Content-Type' => 'application/json' })
13
+ response.value
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'teams_connector/matchers'
4
+
5
+ RSpec.configure do |config|
6
+ config.include TeamsConnector::Matchers
7
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module TeamsConnector
2
4
  class Testing
3
5
  attr_reader :requests
@@ -7,7 +9,7 @@ module TeamsConnector
7
9
  end
8
10
 
9
11
  def perform_request(channel, template, content)
10
- @requests.push({channel: channel, content: content, template: template, time: Time.now})
12
+ @requests.push({ channel: channel, content: content, template: template, time: Time.now })
11
13
  end
12
14
  end
13
15
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module TeamsConnector
2
- VERSION = "0.1.4"
4
+ VERSION = '0.1.6'
3
5
  end
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'core_ext/object'
1
4
  require 'teams_connector/configuration'
2
5
  require 'teams_connector/version'
3
6
  require 'teams_connector/notification'
@@ -7,7 +10,7 @@ require 'teams_connector/builder'
7
10
 
8
11
  module TeamsConnector
9
12
  class << self
10
- attr_accessor :configuration, :testing
13
+ attr_writer :configuration, :testing
11
14
  end
12
15
 
13
16
  def self.configuration
@@ -33,19 +36,18 @@ module TeamsConnector
33
36
  end
34
37
 
35
38
  def self.project_root
36
- if defined?(Rails)
37
- return Rails.root
38
- end
39
-
40
- if defined?(Bundler)
41
- return Bundler.root
42
- end
39
+ return Rails.root if defined?(Rails)
40
+ return Bundler.root if defined?(Bundler)
43
41
 
44
42
  Dir.pwd
45
43
  end
46
44
 
47
45
  def self.gem_root
48
- spec = Gem::Specification.find_by_name("teams_connector")
49
- spec.gem_dir rescue project_root
46
+ spec = Gem::Specification.find_by_name('teams_connector')
47
+ begin
48
+ spec.gem_dir
49
+ rescue NoMethodError
50
+ project_root
51
+ end
50
52
  end
51
53
  end
@@ -1,42 +1,30 @@
1
+ # frozen_string_literal: true
1
2
 
2
- lib = File.expand_path("../lib", __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "teams_connector/version"
3
+ require_relative 'lib/teams_connector/version'
5
4
 
6
5
  Gem::Specification.new do |spec|
7
- spec.name = "teams_connector"
6
+ spec.name = 'teams_connector'
8
7
  spec.version = TeamsConnector::VERSION
9
- spec.authors = ["Lucas Keune"]
10
- spec.email = ["lucas.keune@qurasoft.de"]
8
+ spec.required_ruby_version = '>= 2.6'
9
+ spec.authors = ['Lucas Keune']
10
+ spec.email = ['lucas.keune@qurasoft.de']
11
11
 
12
- spec.summary = %q{Simple connector to send messages and cards to Microsoft Teams channels}
13
- spec.description = %q{Send templated messages or adaptive cards to Microsoft Teams channels}
14
- spec.homepage = "https://github.com/Qurasoft/teams_connector"
15
- spec.license = "MIT"
12
+ spec.summary = 'Simple connector to send messages and cards to Microsoft Teams channels'
13
+ spec.description = 'Send templated messages or adaptive cards to Microsoft Teams channels'
14
+ spec.homepage = 'https://github.com/Qurasoft/teams_connector'
15
+ spec.license = 'MIT'
16
16
 
17
- # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
- # to allow pushing to a single host or delete this section to allow pushing to any host.
19
- if spec.respond_to?(:metadata)
20
- spec.metadata["homepage_uri"] = spec.homepage
21
- spec.metadata["source_code_uri"] = "https://github.com/Qurasoft/teams_connector"
22
- spec.metadata["changelog_uri"] = "https://github.com/Qurasoft/teams_connector/blob/main/CHANGES.md"
23
- else
24
- raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
25
- end
17
+ spec.metadata['homepage_uri'] = spec.homepage
18
+ spec.metadata['source_code_uri'] = 'https://github.com/Qurasoft/teams_connector'
19
+ spec.metadata['changelog_uri'] = 'https://github.com/Qurasoft/teams_connector/blob/main/CHANGES.md'
20
+ spec.metadata['rubygems_mfa_required'] = 'true'
26
21
 
27
22
  # Specify which files should be added to the gem when it is released.
28
23
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
29
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
24
+ spec.files = Dir.chdir(__dir__) do
30
25
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
31
26
  end
32
- spec.bindir = "exe"
33
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
34
- spec.require_paths = ["lib"]
35
-
36
- spec.add_development_dependency "bundler", ">= 1.17"
37
- spec.add_development_dependency "rake", ">= 10.0"
38
- spec.add_development_dependency "rspec", ">= 3.0"
39
- spec.add_development_dependency "webmock"
40
- spec.add_development_dependency "sidekiq"
41
- spec.add_development_dependency "simplecov"
27
+ spec.bindir = 'bin'
28
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
29
+ spec.require_paths = ['lib']
42
30
  end
metadata CHANGED
@@ -1,103 +1,22 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: teams_connector
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lucas Keune
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-02 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '1.17'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '1.17'
27
- - !ruby/object:Gem::Dependency
28
- name: rake
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '10.0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '10.0'
41
- - !ruby/object:Gem::Dependency
42
- name: rspec
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '3.0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '3.0'
55
- - !ruby/object:Gem::Dependency
56
- name: webmock
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: sidekiq
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: simplecov
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
11
+ date: 2023-12-01 00:00:00.000000000 Z
12
+ dependencies: []
97
13
  description: Send templated messages or adaptive cards to Microsoft Teams channels
98
14
  email:
99
15
  - lucas.keune@qurasoft.de
100
- executables: []
16
+ executables:
17
+ - ".gitignore"
18
+ - console
19
+ - setup
101
20
  extensions: []
102
21
  extra_rdoc_files: []
103
22
  files:
@@ -105,6 +24,7 @@ files:
105
24
  - ".github/workflows/ruby.yml"
106
25
  - ".gitignore"
107
26
  - ".rspec"
27
+ - ".rubocop.yml"
108
28
  - ".travis.yml"
109
29
  - CHANGES.md
110
30
  - Gemfile
@@ -114,13 +34,19 @@ files:
114
34
  - bin/.gitignore
115
35
  - bin/console
116
36
  - bin/setup
37
+ - lib/core_ext/object.rb
117
38
  - lib/teams_connector.rb
118
39
  - lib/teams_connector/builder.rb
119
40
  - lib/teams_connector/configuration.rb
41
+ - lib/teams_connector/matchers.rb
42
+ - lib/teams_connector/matchers/expected_number.rb
43
+ - lib/teams_connector/matchers/have_sent_notification_to.rb
44
+ - lib/teams_connector/matchers/with.rb
120
45
  - lib/teams_connector/notification.rb
121
46
  - lib/teams_connector/notification/adaptive_card.rb
122
47
  - lib/teams_connector/notification/message.rb
123
- - lib/teams_connector/post_worker.rb
48
+ - lib/teams_connector/post_job.rb
49
+ - lib/teams_connector/rspec.rb
124
50
  - lib/teams_connector/testing.rb
125
51
  - lib/teams_connector/version.rb
126
52
  - teams_connector.gemspec
@@ -134,6 +60,7 @@ metadata:
134
60
  homepage_uri: https://github.com/Qurasoft/teams_connector
135
61
  source_code_uri: https://github.com/Qurasoft/teams_connector
136
62
  changelog_uri: https://github.com/Qurasoft/teams_connector/blob/main/CHANGES.md
63
+ rubygems_mfa_required: 'true'
137
64
  post_install_message:
138
65
  rdoc_options: []
139
66
  require_paths:
@@ -142,14 +69,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
142
69
  requirements:
143
70
  - - ">="
144
71
  - !ruby/object:Gem::Version
145
- version: '0'
72
+ version: '2.6'
146
73
  required_rubygems_version: !ruby/object:Gem::Requirement
147
74
  requirements:
148
75
  - - ">="
149
76
  - !ruby/object:Gem::Version
150
77
  version: '0'
151
78
  requirements: []
152
- rubygems_version: 3.0.9
79
+ rubygems_version: 3.4.21
153
80
  signing_key:
154
81
  specification_version: 4
155
82
  summary: Simple connector to send messages and cards to Microsoft Teams channels
@@ -1,14 +0,0 @@
1
- require 'net/http'
2
- require 'sidekiq/worker'
3
-
4
- module TeamsConnector
5
- class PostWorker
6
- # === Includes ===
7
- include Sidekiq::Worker
8
-
9
- def perform(url, content)
10
- response = Net::HTTP.post(URI(url), content, { "Content-Type": "application/json" })
11
- response.value
12
- end
13
- end
14
- end