slack-notifier 1.5.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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