chat_notifier 0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 11bbd1390ca03c1f99d0ff66a5e3a361f259f40704575db73ae255e67e48b94b
4
+ data.tar.gz: 24781a89995cf1384962fb46b5a60d8ed5095e442af92162a85e5e82489007ee
5
+ SHA512:
6
+ metadata.gz: a2584238466e94fc1efba40198f83761464f6bf399b9e99b8b640eb21a074a13699fe18bb42a4c1be049e1d0ccdb5950d721ce1342c04f1bfbc277f4195be189
7
+ data.tar.gz: f6e4ac759352ba03f7a21a283f3e43eb4202f0fad8ddd7125b1024713fe96bdac3b283a9bc3f5555495005c96bc92b5438307f55cf1b318556b79674c7143f32
data/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## 0.1.0
9
+
10
+ ### Added
11
+
12
+ - Initial code
data/LICENSE.txt ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2023 SOFware LLC
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # ChatNotifier
2
+
3
+ Notify a chat room with data from your test run.
4
+
5
+ ## Installation
6
+
7
+ ```
8
+ gem "chat_notifier", git: "https://github.com/SOFware/chat_notifier.git"
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ Add to your `spec_helper.rb` or `rails_helper.rb`:
14
+
15
+ ```
16
+ require "chat_notifier/rspec_formatter"
17
+ ```
18
+
19
+ ### Debug your Slack setup
20
+
21
+ Create rake task to test the connection to your Slack channel
22
+
23
+ ```ruby
24
+ namespace :chat_notifier do
25
+ task debug: :environment do
26
+ unless ENV["SLACK_WEBHOOK_URL"]
27
+ puts "You MUST set the environment variables for:\nSLACK_WEBHOOK_URL"
28
+ return
29
+ end
30
+ ENV["DEBUG"] = "1"
31
+ ENV["CURRENT_REPOSITORY_URL"] = "https://example.com"
32
+ ENV["TEST_RUN_ID"] = "9999"
33
+ require "chat_notifier"
34
+
35
+ failure = ChatNotifier::DebugExceptionLocation.new(location: "fake/path.rb")
36
+ summary = ChatNotifier::DebugSummary.new(failed_examples: [failure])
37
+
38
+ ChatNotifier.debug!(ENV, summary:)
39
+ end
40
+ end
41
+ ```
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ChatNotifier
4
+ class Chatter
5
+ class Debug < Slack
6
+ Chatter.register self
7
+
8
+ class << self
9
+ def handles?(settings)
10
+ !settings.keys.grep(/DEBUG/).empty?
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ChatNotifier
4
+ class Chatter
5
+ class Slack < self
6
+ Chatter.register self
7
+
8
+ class << self
9
+ def handles?(settings)
10
+ !settings.keys.grep(/SLACK/).empty?
11
+ end
12
+ end
13
+
14
+ def webhook_url
15
+ settings.fetch("SLACK_WEBHOOK_URL", nil)
16
+ end
17
+
18
+ def channel
19
+ settings.fetch("SLACK_NOTIFY_CHANNEL", nil)
20
+ end
21
+
22
+ def payload(data)
23
+ super(Configuration.for(data, self).to_h)
24
+ end
25
+
26
+ class Configuration
27
+ def self.for(messenger, communicator)
28
+ if messenger.failure?
29
+ FailureConfiguration
30
+ else
31
+ self
32
+ end.new(messenger, communicator).to_h
33
+ end
34
+
35
+ def initialize(messenger, communicator)
36
+ @messenger = messenger
37
+ @communicator = communicator
38
+ end
39
+ attr_reader :messenger, :communicator
40
+
41
+ def icon_emoji = ":green_circle:"
42
+
43
+ def to_h
44
+ {
45
+ channel: communicator.channel,
46
+ icon_emoji: icon_emoji
47
+ }.merge(messenger.to_h)
48
+ end
49
+
50
+ class FailureConfiguration < self
51
+ def icon_emoji = ":red_circle:"
52
+ end
53
+
54
+ private_constant :FailureConfiguration
55
+ end
56
+ private_constant :Configuration
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "uri"
5
+ require "json"
6
+
7
+ module ChatNotifier
8
+ # All behavior for interacting with a notification platform
9
+ class Chatter
10
+ def initialize(settings:, repository:, environment:)
11
+ @settings = settings
12
+ @repository = repository
13
+ @environment = environment
14
+ end
15
+
16
+ attr :settings, :repository, :environment
17
+
18
+ class << self
19
+ def handlers
20
+ @handlers ||= []
21
+ end
22
+
23
+ def handles?
24
+ false
25
+ end
26
+
27
+ def register(klass)
28
+ handlers << klass
29
+ end
30
+
31
+ def handling(settings, repository:, environment:)
32
+ handlers.select { |handler| handler.handles?(settings) }.map do |klass|
33
+ klass.new(
34
+ settings: settings,
35
+ repository: repository,
36
+ environment: environment
37
+ )
38
+ end
39
+ end
40
+ end
41
+
42
+ def webhook_url
43
+ end
44
+
45
+ def body
46
+ end
47
+
48
+ def post(messenger)
49
+ uri = URI(webhook_url)
50
+
51
+ Net::HTTP.post(uri, payload(messenger))
52
+ end
53
+
54
+ def conditional_post(messenger)
55
+ return if messenger.success? && !verbose?
56
+
57
+ post(messenger)
58
+ end
59
+
60
+ def verbose?
61
+ !!settings.fetch("NOTIFIER_VERBOSE", false)
62
+ end
63
+
64
+ def payload(data)
65
+ data.to_json
66
+ end
67
+ end
68
+ end
69
+
70
+ require_relative "chatter/slack"
71
+ require_relative "chatter/debug"
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+
5
+ module ChatNotifier
6
+ class Messenger
7
+ extend Forwardable
8
+
9
+ class << self
10
+ def for(summary, repository:, environment:, app:)
11
+ if summary.failed_examples.empty?
12
+ self
13
+ else
14
+ Failure
15
+ end.new(
16
+ summary:,
17
+ app:,
18
+ repository:,
19
+ environment:
20
+ )
21
+ end
22
+
23
+ def debug=(val)
24
+ prepend Debug if val
25
+ end
26
+ end
27
+
28
+ module Debug
29
+ def message = "This is only a test…"
30
+ end
31
+
32
+ def initialize(summary:, app:, repository:, environment:)
33
+ @summary = summary
34
+ @app = app
35
+ @repository = repository
36
+ @environment = environment
37
+ end
38
+
39
+ attr :summary, :app, :repository, :environment
40
+
41
+ def failures = summary.failed_examples
42
+
43
+ def_delegator :failures, :count
44
+ def_delegators :app, :branch, :sha
45
+ def_delegator :environment, :ruby_version
46
+
47
+ def message
48
+ "#{message_prefix} #{identifier} is OK on branch #{repository.link(branch)}"
49
+ end
50
+
51
+ def lede = message
52
+
53
+ def body = ""
54
+
55
+ def identifier
56
+ "#{app} #{ruby_version} #{sha}"
57
+ end
58
+
59
+ def message_prefix = ":thumbsup:"
60
+
61
+ def success? = true
62
+
63
+ def failure? = !success?
64
+
65
+ def to_h
66
+ {
67
+ text: message
68
+ }
69
+ end
70
+
71
+ def to_hash = to_h
72
+
73
+ class Failure < self
74
+ def count = "#{failures.size} times!"
75
+
76
+ def message_prefix = ":boom:"
77
+
78
+ def success? = false
79
+
80
+ def failure? = !success?
81
+
82
+ def lede
83
+ <<~LEDE.chomp
84
+ #{message_prefix} #{identifier} has failed #{count} in #{branch}
85
+
86
+ #{environment.test_run_url}
87
+ LEDE
88
+ end
89
+
90
+ def message
91
+ <<~MESSAGE.chomp
92
+ #{lede}
93
+
94
+ #{body}
95
+ MESSAGE
96
+ end
97
+
98
+ def body
99
+ failures.flat_map(&:location).join("\n")
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ChatNotifier
4
+ class Repository
5
+ class Debug < self
6
+ def url
7
+ "http://example.com"
8
+ end
9
+
10
+ def link(sha)
11
+ "#{url}/tree/#{sha}"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ChatNotifier
4
+ class Repository
5
+ class Github < self
6
+ def url
7
+ settings.fetch("CURRENT_REPOSITORY_URL", nil)
8
+ end
9
+
10
+ def link(sha)
11
+ "#{url}/tree/#{sha}"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ChatNotifier
4
+ # All information about the location of the source code
5
+ class Repository
6
+ def initialize(settings:)
7
+ @settings = settings
8
+ end
9
+
10
+ attr_reader :settings
11
+
12
+ def self.for(settings)
13
+ if settings["DEBUG"]
14
+ Debug
15
+ else
16
+ Github
17
+ end.new(settings: settings)
18
+ end
19
+
20
+ def link(_sha)
21
+ end
22
+ end
23
+ end
24
+
25
+ require_relative "repository/github"
26
+ require_relative "repository/debug"
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rspec/core/formatters"
4
+ RSpec::Support.require_rspec_core "formatters/base_formatter"
5
+
6
+ require "chat_notifier"
7
+
8
+ module ChatNotifier
9
+ # Formatter for RSpec tests to receive the summary of a test
10
+ # run after the suite has finished.
11
+ class RspecFormatter < RSpec::Core::Formatters::BaseFormatter
12
+ RSpec::Core::Formatters.register self, :dump_summary
13
+
14
+ def dump_summary(summary)
15
+ ChatNotifier.call(summary:)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ChatNotifier
4
+ class TestEnvironment
5
+ class Debug < self
6
+ def url
7
+ "http://example.com"
8
+ end
9
+
10
+ def test_run_url
11
+ "#{url}/test-run/9999999"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ChatNotifier
4
+ class TestEnvironment
5
+ class Github < self
6
+ def test_run_url
7
+ "#{url}/actions/runs/#{run_id}"
8
+ end
9
+
10
+ def run_id
11
+ settings.fetch("TEST_RUN_ID")
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ChatNotifier
4
+ # All information about the place where the test was run
5
+ class TestEnvironment
6
+ def initialize(settings:)
7
+ @settings = settings
8
+ end
9
+
10
+ attr_reader :settings
11
+
12
+ def self.for(settings)
13
+ if settings["DEBUG"]
14
+ Debug
15
+ else
16
+ Github
17
+ end.new(settings: settings)
18
+ end
19
+
20
+ def ruby_version
21
+ "Ruby #{::RUBY_VERSION}"
22
+ end
23
+
24
+ def url
25
+ settings.fetch("CURRENT_REPOSITORY_URL")
26
+ end
27
+
28
+ def test_run_url
29
+ end
30
+ end
31
+ end
32
+
33
+ require_relative "test_environment/github"
34
+ require_relative "test_environment/debug"
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ChatNotifier
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "chat_notifier/version"
4
+
5
+ require_relative "chat_notifier/messenger"
6
+ require_relative "chat_notifier/repository"
7
+ require_relative "chat_notifier/test_environment"
8
+ require_relative "chat_notifier/chatter"
9
+
10
+ module ChatNotifier
11
+ DebugExceptionLocation = Data.define(:location)
12
+ DebugSummary = Data.define(:failed_examples)
13
+
14
+ class << self
15
+ # In order to test this locally see `rake chat_notifier:debug`
16
+ def debug!(env, summary:, notifier: :Debug)
17
+ repository = Repository.for(env)
18
+ environment = TestEnvironment.for(env)
19
+
20
+ chatter = Chatter.const_get(notifier).new(
21
+ settings: env,
22
+ repository: repository,
23
+ environment: environment
24
+ )
25
+ messenger = Messenger.for(
26
+ summary,
27
+ app: Rails.application.class.module_parent,
28
+ repository: repository,
29
+ environment: environment
30
+ )
31
+
32
+ chatter.post(messenger)
33
+ end
34
+
35
+ def call(summary:)
36
+ repository = Repository.for(ENV)
37
+ environment = TestEnvironment.for(ENV)
38
+ chatter = Chatter.handling(
39
+ ENV,
40
+ repository:,
41
+ environment:
42
+ )
43
+
44
+ messenger = Messenger.for(
45
+ summary,
46
+ app: Rails.application.class.module_parent,
47
+ repository:,
48
+ environment:
49
+ )
50
+
51
+ chatter.each do |box|
52
+ box.conditional_post(messenger)
53
+ end
54
+ end
55
+ end
56
+ end
metadata ADDED
@@ -0,0 +1,60 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chat_notifier
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jim Gay
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-04-19 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Send test results to chat
14
+ email:
15
+ - jim@saturnflyer.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - CHANGELOG.md
21
+ - LICENSE.txt
22
+ - README.md
23
+ - lib/chat_notifier.rb
24
+ - lib/chat_notifier/chatter.rb
25
+ - lib/chat_notifier/chatter/debug.rb
26
+ - lib/chat_notifier/chatter/slack.rb
27
+ - lib/chat_notifier/messenger.rb
28
+ - lib/chat_notifier/repository.rb
29
+ - lib/chat_notifier/repository/debug.rb
30
+ - lib/chat_notifier/repository/github.rb
31
+ - lib/chat_notifier/rspec_formatter.rb
32
+ - lib/chat_notifier/test_environment.rb
33
+ - lib/chat_notifier/test_environment/debug.rb
34
+ - lib/chat_notifier/test_environment/github.rb
35
+ - lib/chat_notifier/version.rb
36
+ homepage:
37
+ licenses: []
38
+ metadata:
39
+ source_code_uri: https://github.com/SOFware/chat_notifier.git
40
+ changelog_uri: https://github.com/SOFWare/chat_notifier/blob/master/CHANGELOG.md
41
+ post_install_message:
42
+ rdoc_options: []
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 3.2.0
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ requirements: []
56
+ rubygems_version: 3.4.6
57
+ signing_key:
58
+ specification_version: 4
59
+ summary: Notify chat of test results
60
+ test_files: []