slack-notifier 1.5.1 → 2.0.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.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/lib/slack-notifier.rb +35 -60
  3. data/lib/slack-notifier/config.rb +37 -0
  4. data/lib/slack-notifier/payload_middleware.rb +21 -0
  5. data/lib/slack-notifier/payload_middleware/base.rb +35 -0
  6. data/lib/slack-notifier/payload_middleware/format_attachments.rb +37 -0
  7. data/lib/slack-notifier/payload_middleware/format_message.rb +19 -0
  8. data/lib/slack-notifier/payload_middleware/stack.rb +35 -0
  9. data/lib/slack-notifier/util/escape.rb +15 -0
  10. data/lib/slack-notifier/util/http_client.rb +53 -0
  11. data/lib/slack-notifier/util/link_formatter.rb +63 -0
  12. data/lib/slack-notifier/version.rb +2 -1
  13. data/spec/end_to_end_spec.rb +84 -0
  14. data/spec/integration/ping_integration_test.rb +12 -5
  15. data/spec/lib/slack-notifier/config_spec.rb +71 -0
  16. data/spec/lib/slack-notifier/payload_middleware/base_spec.rb +75 -0
  17. data/spec/lib/slack-notifier/payload_middleware/format_attachments_spec.rb +35 -0
  18. data/spec/lib/slack-notifier/payload_middleware/format_message_spec.rb +26 -0
  19. data/spec/lib/slack-notifier/payload_middleware/stack_spec.rb +93 -0
  20. data/spec/lib/slack-notifier/payload_middleware_spec.rb +32 -0
  21. data/spec/lib/slack-notifier/util/http_client_spec.rb +34 -0
  22. data/spec/lib/slack-notifier/{link_formatter_spec.rb → util/link_formatter_spec.rb} +30 -19
  23. data/spec/lib/slack-notifier_spec.rb +62 -128
  24. data/spec/spec_helper.rb +20 -5
  25. metadata +30 -9
  26. data/lib/slack-notifier/default_http_client.rb +0 -51
  27. data/lib/slack-notifier/link_formatter.rb +0 -62
  28. data/spec/lib/slack-notifier/default_http_client_spec.rb +0 -37
@@ -1,5 +1,6 @@
1
+ # frozen_string_literal: true
1
2
  module Slack
2
3
  class Notifier
3
- VERSION = "1.5.1"
4
+ VERSION = "2.0.0".freeze # rubocop:disable Style/RedundantFreeze
4
5
  end
5
6
  end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+ require "spec_helper"
4
+
5
+ RSpec.describe Slack::Notifier do
6
+ {
7
+ { text: "hello" } =>
8
+ { payload: { text: "hello" } },
9
+
10
+ { text: "[hello](http://example.com/world)" } =>
11
+ { payload: { text: "<http://example.com/world|hello>" } },
12
+
13
+ { text: '<a href="http://example.com">example</a>' } =>
14
+ { payload: { text: "<http://example.com|example>" } },
15
+
16
+ { text: "hello/こんにちは from notifier test" } =>
17
+ { payload: { text: "hello/こんにちは from notifier test" } },
18
+
19
+ { text: "Hello World, enjoy [](http://example.com)." } =>
20
+ { payload: { text: "Hello World, enjoy <http://example.com>." } },
21
+
22
+ { text: "Hello World, enjoy [this](http://example.com)[this2](http://example2.com)" } =>
23
+ { payload: { text: "Hello World, enjoy <http://example.com|this><http://example2.com|this2>" } },
24
+
25
+ { text: "[John](mailto:john@example.com)" } =>
26
+ { payload: { text: "<mailto:john@example.com|John>" } },
27
+
28
+ { text: '<a href="mailto:john@example.com">John</a>' } =>
29
+ { payload: { text: "<mailto:john@example.com|John>" } },
30
+
31
+ { text: "hello", channel: "hodor" } =>
32
+ { payload: { text: "hello", channel: "hodor" } },
33
+
34
+ { text: "the message", channel: "foo", attachments: [{ color: "#000",
35
+ text: "attachment message",
36
+ fallback: "fallback message" }] } =>
37
+ { payload: { text: "the message",
38
+ channel: "foo",
39
+ attachments: [{ color: "#000",
40
+ text: "attachment message",
41
+ fallback: "fallback message" }] } },
42
+
43
+ { attachments: [{ color: "#000",
44
+ text: "attachment message",
45
+ fallback: "fallback message" }] } =>
46
+ { payload: { attachments: [{ color: "#000",
47
+ text: "attachment message",
48
+ fallback: "fallback message" }] } },
49
+
50
+ { attachments: { color: "#000",
51
+ text: "attachment message [hodor](http://winterfell.com)",
52
+ fallback: "fallback message" } } =>
53
+ { payload: { attachments: { color: "#000",
54
+ text: "attachment message <http://winterfell.com|hodor>",
55
+ fallback: "fallback message" } } },
56
+
57
+ { text: "hello", http_options: { timeout: 5 } } =>
58
+ { http_options: { timeout: 5 }, payload: { text: "hello" } }
59
+ }.each do |args, payload|
60
+ it "sends correct payload for #post(#{args})" do
61
+ http_client = class_double("Slack::Notifier::Util::HTTPClient", post: nil)
62
+ notifier = Slack::Notifier.new "http://example.com", http_client: http_client
63
+ payload[:payload] = payload[:payload].to_json
64
+
65
+ expect(http_client).to receive(:post)
66
+ .with(URI.parse("http://example.com"), payload)
67
+
68
+ notifier.post(args)
69
+ end
70
+ end
71
+
72
+ it "applies options given to middleware" do
73
+ client = class_double("Slack::Notifier::Util::HTTPClient", post: nil)
74
+ notifier = Slack::Notifier.new "http://example.com" do
75
+ http_client client
76
+ middleware format_message: { formats: [] }
77
+ end
78
+
79
+ expect(client).to receive(:post)
80
+ .with(URI.parse("http://example.com"), payload: { text: "Hello [world](http://example.com)!" }.to_json)
81
+
82
+ notifier.post text: "Hello [world](http://example.com)!"
83
+ end
84
+ end
@@ -1,7 +1,14 @@
1
+ # frozen_string_literal: true
1
2
  # encoding: utf-8
2
- require_relative '../../lib/slack-notifier'
3
+ require_relative "../../lib/slack-notifier"
3
4
 
4
- notifier = Slack::Notifier.new ENV['SLACK_WEBHOOK_URL'], username: 'notifier'
5
- puts "testing with ruby #{RUBY_VERSION}"
6
- notifier.ping "hello/こんにちは from notifier test script on ruby: #{RUBY_VERSION}\225"
7
- notifier.ping attachments: [{color:"#1BF5AF",fallback:"fallback",text:"attachment"}]
5
+ ruby = if defined?(JRUBY_VERSION)
6
+ "jruby #{JRUBY_VERSION}"
7
+ else
8
+ "ruby #{RUBY_VERSION}"
9
+ end
10
+ puts "testing with #{ruby}"
11
+
12
+ notifier = Slack::Notifier.new ENV["SLACK_WEBHOOK_URL"], username: "notifier"
13
+ notifier.ping "hello/こんにちは from notifier test script on #{ruby}\225"
14
+ notifier.ping attachments: [{ color: "#1BF5AF", fallback: "fallback", text: "attachment" }]
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Slack::Notifier::Config do
4
+ describe "#http_client" do
5
+ it "is Util::HTTPClient if not set" do
6
+ subject = described_class.new
7
+ expect(subject.http_client).to eq Slack::Notifier::Util::HTTPClient
8
+ end
9
+
10
+ it "sets a new client class if given one" do
11
+ new_client = class_double("Slack::Notifier::Util::HTTPClient", post: nil)
12
+ subject = described_class.new
13
+ subject.http_client new_client
14
+ expect(subject.http_client).to eq new_client
15
+ end
16
+
17
+ it "raises an ArgumentError if given class does not respond to ::post" do
18
+ subject = described_class.new
19
+ expect do
20
+ subject.http_client :nope
21
+ end.to raise_error ArgumentError
22
+ end
23
+ end
24
+
25
+ describe "#defaults" do
26
+ it "is an empty hash by default" do
27
+ subject = described_class.new
28
+ expect(subject.defaults).to eq({})
29
+ end
30
+
31
+ it "sets a hash to default if given" do
32
+ subject = described_class.new
33
+ subject.defaults foo: :bar
34
+ expect(subject.defaults).to eq foo: :bar
35
+ end
36
+
37
+ it "raises ArgumentError if not given a hash" do
38
+ subject = described_class.new
39
+ expect do
40
+ subject.defaults :nope
41
+ end.to raise_error ArgumentError
42
+ end
43
+ end
44
+
45
+ describe "#middleware" do
46
+ it "is [:format_message, :format_attachments] if not set" do
47
+ subject = described_class.new
48
+
49
+ expect(subject.middleware).to eq [:format_message, :format_attachments]
50
+ end
51
+
52
+ it "takes an array or a splat of args" do
53
+ subject = described_class.new
54
+
55
+ subject.middleware :layer, :two
56
+ expect(subject.middleware).to eq [:layer, :two]
57
+
58
+ subject.middleware [:one, :layer]
59
+ expect(subject.middleware).to eq [:one, :layer]
60
+ end
61
+
62
+ it "allows passing options to middleware stack" do
63
+ subject = described_class.new
64
+ subject.middleware one: { opts: :for_one },
65
+ two: { opts: :for_two }
66
+
67
+ expect(subject.middleware).to eq one: { opts: :for_one },
68
+ two: { opts: :for_two }
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+ RSpec.describe Slack::Notifier::PayloadMiddleware::Base do
3
+ before(:each) do
4
+ @registry_backup = Slack::Notifier::PayloadMiddleware.registry.dup
5
+ Slack::Notifier::PayloadMiddleware.send(:remove_instance_variable, :@registry)
6
+ end
7
+
8
+ after(:each) do
9
+ # cleanup middleware registry
10
+ Slack::Notifier::PayloadMiddleware.registry
11
+ Slack::Notifier::PayloadMiddleware.send(:remove_instance_variable, :@registry)
12
+
13
+ # cleanup object constants
14
+ Object.send(:remove_const, :Subject) if Object.constants.include?(:Subject)
15
+ Slack::Notifier::PayloadMiddleware.send(:instance_variable_set, :@registry, @registry_backup)
16
+ end
17
+
18
+ describe "::middleware_name" do
19
+ it "registers class w/ given name" do
20
+ class Subject < Slack::Notifier::PayloadMiddleware::Base
21
+ end
22
+
23
+ expect(Slack::Notifier::PayloadMiddleware)
24
+ .to receive(:register).with(Subject, :subject)
25
+
26
+ class Subject
27
+ middleware_name :subject
28
+ end
29
+ end
30
+
31
+ it "uses symbolized name to register" do
32
+ class Subject < Slack::Notifier::PayloadMiddleware::Base
33
+ end
34
+
35
+ expect(Slack::Notifier::PayloadMiddleware)
36
+ .to receive(:register).with(Subject, :subject)
37
+
38
+ class Subject
39
+ middleware_name "subject"
40
+ end
41
+ end
42
+ end
43
+
44
+ describe "::options" do
45
+ it "allows setting default options for a middleware" do
46
+ class Subject < Slack::Notifier::PayloadMiddleware::Base
47
+ options foo: :bar
48
+ end
49
+
50
+ subject = Subject.new(:notifier)
51
+ expect(subject.options).to eq foo: :bar
52
+
53
+ subject = Subject.new(:notifier, foo: :baz)
54
+ expect(subject.options).to eq foo: :baz
55
+ end
56
+ end
57
+
58
+ describe "#initialize" do
59
+ it "sets given notifier as notifier" do
60
+ expect(described_class.new(:notifier).notifier).to eq :notifier
61
+ end
62
+
63
+ it "sets given options as opts" do
64
+ expect(described_class.new(:notifier, opts: :options).options).to eq opts: :options
65
+ end
66
+ end
67
+
68
+ describe "#call" do
69
+ it "raises NoMethodError (expects subclass to define)" do
70
+ expect do
71
+ described_class.new(:notifier).call
72
+ end.to raise_exception NoMethodError
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+ RSpec.describe Slack::Notifier::PayloadMiddleware::FormatAttachments do
3
+ it "passes the text of attachments through linkformatter with options[:formats]" do
4
+ subject = described_class.new(:notifier, formats: [:html])
5
+ expect(Slack::Notifier::Util::LinkFormatter).to receive(:format)
6
+ .with("hello", formats: [:html])
7
+ subject.call(attachments: [{ text: "hello" }])
8
+ end
9
+
10
+ it "searches through string or symbol keys" do
11
+ subject = described_class.new(:notifier)
12
+ expect(Slack::Notifier::Util::LinkFormatter).to receive(:format)
13
+ .with("hello", formats: [:html, :markdown])
14
+ subject.call("attachments" => [{ "text" => "hello" }])
15
+
16
+ subject = described_class.new(:notifier)
17
+ expect(Slack::Notifier::Util::LinkFormatter).to receive(:format)
18
+ .with("hello", formats: [:html, :markdown])
19
+ subject.call(attachments: [{ text: "hello" }])
20
+ end
21
+
22
+ it "can handle a single attachment" do
23
+ subject = described_class.new(:notifier)
24
+ expect(Slack::Notifier::Util::LinkFormatter).to receive(:format)
25
+ .with("hello", formats: [:html, :markdown])
26
+ subject.call(attachments: { text: "hello" })
27
+ end
28
+
29
+ it "returns the payload unmodified if not :attachments key" do
30
+ payload = { foo: :bar }
31
+ subject = described_class.new(:notifier)
32
+
33
+ expect(subject.call(payload)).to eq payload
34
+ end
35
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ RSpec.describe Slack::Notifier::PayloadMiddleware::FormatMessage do
3
+ it "passes the text through linkformatter with options[:formats]" do
4
+ subject = described_class.new(:notifier, formats: [:html])
5
+ expect(Slack::Notifier::Util::LinkFormatter).to receive(:format)
6
+ .with("hello", formats: [:html])
7
+ subject.call(text: "hello")
8
+
9
+ subject = described_class.new(:notifier)
10
+ expect(Slack::Notifier::Util::LinkFormatter).to receive(:format)
11
+ .with("hello", formats: [:html, :markdown])
12
+ subject.call(text: "hello")
13
+
14
+ subject = described_class.new(:notifier, formats: [:markdown])
15
+ expect(Slack::Notifier::Util::LinkFormatter).to receive(:format)
16
+ .with("hello", formats: [:markdown])
17
+ subject.call(text: "hello")
18
+ end
19
+
20
+ it "returns the payload unmodified if not :text key" do
21
+ payload = { foo: :bar }
22
+ subject = described_class.new(:notifier)
23
+
24
+ expect(subject.call(payload)).to eq payload
25
+ end
26
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+ RSpec.describe Slack::Notifier::PayloadMiddleware::Stack do
3
+ let(:return_one) do
4
+ double(call: 1)
5
+ end
6
+
7
+ let(:return_two) do
8
+ double(call: 2)
9
+ end
10
+
11
+ let(:return_three) do
12
+ double(call: 3)
13
+ end
14
+
15
+ before(:each) do
16
+ # setup our middleware in the registry
17
+ @registry_backup = Slack::Notifier::PayloadMiddleware.registry.dup
18
+ Slack::Notifier::PayloadMiddleware.send(:remove_instance_variable, :@registry)
19
+
20
+ Slack::Notifier::PayloadMiddleware.register return_one, :return_one
21
+ Slack::Notifier::PayloadMiddleware.register return_two, :return_two
22
+ Slack::Notifier::PayloadMiddleware.register return_three, :return_three
23
+ end
24
+
25
+ after(:each) do
26
+ # cleanup middleware registry
27
+ Slack::Notifier::PayloadMiddleware.send(:remove_instance_variable, :@registry)
28
+ Slack::Notifier::PayloadMiddleware.send(:instance_variable_set, :@registry, @registry_backup)
29
+ end
30
+
31
+ describe "::initialize" do
32
+ it "sets notifier to given notifier" do
33
+ expect(described_class.new(:notifier).notifier).to eq :notifier
34
+ end
35
+
36
+ it "has empty stack" do
37
+ expect(described_class.new(:notifier).stack).to match_array []
38
+ end
39
+ end
40
+
41
+ describe "#set" do
42
+ it "initializes each middleware w/ the notifier instance" do
43
+ expect(return_one).to receive(:new).with(:notifier)
44
+ expect(return_two).to receive(:new).with(:notifier)
45
+
46
+ described_class.new(:notifier).set(:return_one, :return_two)
47
+ end
48
+
49
+ it "creates the stack in an array" do
50
+ allow(return_one).to receive(:new).and_return(return_one)
51
+ allow(return_two).to receive(:new).and_return(return_two)
52
+
53
+ subject = described_class.new(:notifier)
54
+ subject.set(:return_one, :return_two)
55
+
56
+ expect(subject.stack).to be_a Array
57
+ expect(subject.stack.first.call).to eq 1
58
+ expect(subject.stack.last.call).to eq 2
59
+ end
60
+
61
+ it "creates a stack from hashes passing them as opts" do
62
+ expect(return_one).to receive(:new).with(:notifier, opts: :for_one)
63
+ expect(return_two).to receive(:new).with(:notifier, opts: :for_two)
64
+
65
+ subject = described_class.new(:notifier)
66
+ subject.set return_one: { opts: :for_one },
67
+ return_two: { opts: :for_two }
68
+ end
69
+
70
+ it "raises if a middleware is missing" do
71
+ expect do
72
+ described_class.new(:notifier).set(:missing)
73
+ end.to raise_exception KeyError
74
+ end
75
+ end
76
+
77
+ describe "#call" do
78
+ it "calls the middleware in order, passing return of each to the next" do
79
+ allow(return_one).to receive(:new).and_return(return_one)
80
+ allow(return_two).to receive(:new).and_return(return_two)
81
+ allow(return_three).to receive(:new).and_return(return_three)
82
+
83
+ subject = described_class.new(:notifier)
84
+ subject.set(:return_one, :return_three, :return_two)
85
+
86
+ expect(return_one).to receive(:call).with(5)
87
+ expect(return_three).to receive(:call).with(1)
88
+ expect(return_two).to receive(:call).with(3)
89
+
90
+ expect(subject.call(5)).to eq 2
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ RSpec.describe Slack::Notifier::PayloadMiddleware do
3
+ before(:each) do
4
+ @registry_backup = described_class.registry.dup
5
+ Slack::Notifier::PayloadMiddleware.send(:remove_instance_variable, :@registry)
6
+ end
7
+
8
+ after(:each) do
9
+ described_class.send(:remove_instance_variable, :@registry)
10
+ described_class.send(:instance_variable_set, :@registry, @registry_backup)
11
+ end
12
+
13
+ describe "::registry" do
14
+ it "returns a hash if nothing set" do
15
+ expect(described_class.registry).to eq({})
16
+ end
17
+
18
+ it "returns memoized version if already set" do
19
+ described_class.instance_variable_set(:@registry, "hodor")
20
+ expect(described_class.registry).to eq "hodor"
21
+ end
22
+ end
23
+
24
+ describe "::register" do
25
+ it "adds given class to key in registry" do
26
+ MyClass = Struct.new(:myclass)
27
+ described_class.register MyClass, :my_class
28
+
29
+ expect(described_class.registry[:my_class]).to eq MyClass
30
+ end
31
+ end
32
+ end