nautilfer 0.3.1 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f026890d209390f607032ea3ac7f6c30375600b711f2377c3df67b68bbd050e7
4
- data.tar.gz: 943ed91b71baaa172ba03f7e861ccf41f65ecdd18ecdeec511cf4d26f0592ad2
3
+ metadata.gz: 0345f886d7a3add841aab8d2ba2557232461dea43a39cbe383aef7841a380dbe
4
+ data.tar.gz: 03d7133181c366fcbe8b38eb3c25e029c61bc65ab4f7c6657b122c8ee118e97e
5
5
  SHA512:
6
- metadata.gz: 580405d5b98669d458560cc4a84abb99501eaed169eebfad4a0a27ff2496055125534379dbc5c144ddd76a30f96d3d17a73605493ccea3a8404d77a36ebcd37e
7
- data.tar.gz: 46500be06ccc88b586feddc3cad131bbe5ea9701be8df3a4ff67f9ad73d7b12dab6c1b8eeea9ee1bc51a654586f1dddd17aca9378aa8d7ab7e5de781889ff744
6
+ metadata.gz: cd254576c3fa630717153bf93008f2534b27ac2384e87f37034fca3212f3bdb94f8c00b5bb0de0cff69bdbccd5d46711bd360dfeb2b4ae5ea8828a7a7c643e39
7
+ data.tar.gz: ffe47507667a0bc83389db74d1599e61b8b276a6c8ca09fc67a680e3c458fe07beb460c95c598d8a97eaf5840575f1c81dc55bf0b2bf91af3bdc4f3dfd4a6c82
data/AGENTS.md CHANGED
@@ -4,3 +4,4 @@
4
4
  - Every change must include appropriate updates to the test suite (add or modify specs as needed).
5
5
  - Update the README if necessary to reflect your changes.
6
6
  - All instructions in this file are written in English and should be followed as written.
7
+ - `Gemfile.lock` is intentionally omitted from the repository; do not add or commit it.
data/README.md CHANGED
@@ -50,27 +50,17 @@ To use nautilfer, first require it.
50
50
  require 'nautilfer'
51
51
  ```
52
52
 
53
- Then, you can easily parse and extract information from a web page like this:
53
+ Instantiate Nautilfer with the adapter you want to use:
54
54
 
55
55
  ```ruby
56
- Nautilfer.to_teams(message: "## TEST\nhello", endpoint: "#{workflow_endpoint}")
57
- ```
58
-
59
- Or instantiate Nautilfer directly when you want to reuse the same endpoint:
60
-
61
- ```ruby
62
- notifier = Nautilfer.new(endpoint: "#{workflow_endpoint}", adapter: :teams)
56
+ notifier = Nautilfer.new(endpoint: "#{workflow_endpoint}", adapter: Nautilfer::Adapters::Teams.new)
63
57
  notifier.notify("## TEST\nhello")
64
58
  ```
65
59
 
66
60
  To notify a Slack channel via Incoming Webhook:
67
61
 
68
62
  ```ruby
69
- Nautilfer.to_slack(message: "Deployment completed", endpoint: "#{slack_webhook_url}")
70
- ```
71
-
72
- ```ruby
73
- slack_notifier = Nautilfer.new(endpoint: "#{slack_webhook_url}", adapter: :slack)
63
+ slack_notifier = Nautilfer.new(endpoint: "#{slack_webhook_url}", adapter: Nautilfer::Adapters::Slack.new)
74
64
  slack_notifier.notify("Deployment completed")
75
65
  ```
76
66
 
@@ -81,28 +71,30 @@ Use the environment controls to avoid sending notifications in non-production en
81
71
  Enable notifications only in specific environments:
82
72
 
83
73
  ```ruby
84
- Nautilfer.to_teams(
85
- message: "Release deployed",
74
+ notifier = Nautilfer.new(
86
75
  endpoint: "#{workflow_endpoint}",
76
+ adapter: Nautilfer::Adapters::Teams.new,
87
77
  environment: 'production',
88
78
  enabled_environments: ['production']
89
79
  )
80
+ notifier.notify("Release deployed")
90
81
  ```
91
82
 
92
83
  Or disable notifications for certain environments:
93
84
 
94
85
  ```ruby
95
- Nautilfer.to_slack(
96
- message: "Smoke tests running",
86
+ slack_notifier = Nautilfer.new(
97
87
  endpoint: "#{slack_webhook_url}",
88
+ adapter: Nautilfer::Adapters::Slack.new,
98
89
  environment: 'test',
99
90
  disabled_environments: ['test', 'development']
100
91
  )
92
+ slack_notifier.notify("Smoke tests running")
101
93
  ```
102
94
 
103
95
  ### Configure defaults once
104
96
 
105
- Persist your environment preferences by configuring defaults up front. New instances and helper calls will reuse these values unless you override them per call.
97
+ Persist your environment preferences by configuring defaults up front. New instances will reuse these values unless you override them per call.
106
98
 
107
99
  ```ruby
108
100
  Nautilfer.configure do |config|
@@ -113,20 +105,24 @@ end
113
105
 
114
106
  notifier = Nautilfer.new(endpoint: "#{workflow_endpoint}", adapter: :teams)
115
107
  notifier.notify("Deployment finished")
116
-
117
- # Helpers will also reuse the configured defaults
118
- Nautilfer.to_slack(message: "Deployment finished", endpoint: "#{slack_webhook_url}")
119
108
  ```
120
109
 
121
110
  ## Chatwork Notification Integration
122
111
 
123
- To enable Chatwork notifications, configure the API token and room ID:
112
+ To enable Chatwork notifications using the unified adapter interface, initialize `Nautilfer` with the Chatwork adapter and tar
113
+ get a room-specific endpoint:
124
114
 
125
115
  ```ruby
126
- notifier = Nautilfer::ChatworkNotifier.new('your_api_token', 'your_room_id')
116
+ endpoint = "https://api.chatwork.com/v2/rooms/#{room_id}/messages"
117
+ notifier = Nautilfer.new(
118
+ endpoint: endpoint,
119
+ adapter: Nautilfer::Adapters::Chatwork.new(api_token: ENV['CHATWORK_API_TOKEN'])
120
+ )
127
121
  notifier.notify('This is a test message from Nautilfer!')
128
122
  ```
129
123
 
124
+ You can also pass `adapter: :chatwork` when `CHATWORK_API_TOKEN` is set in your environment.
125
+
130
126
  ## Features
131
127
  - More features coming soon!
132
128
 
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Nautilfer
4
+ module Adapters
5
+ class Base
6
+ def headers
7
+ { 'Content-Type' => 'application/json' }
8
+ end
9
+
10
+ def payload(_message)
11
+ raise NotImplementedError, "Adapters must implement #payload"
12
+ end
13
+
14
+ def body(payload)
15
+ payload.to_json
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+ require 'uri'
5
+
6
+ class Nautilfer
7
+ module Adapters
8
+ class Chatwork < Base
9
+ API_ENDPOINT = "https://api.chatwork.com/v2"
10
+
11
+ def initialize(api_token:)
12
+ @api_token = api_token
13
+ end
14
+
15
+ def headers
16
+ {
17
+ 'X-ChatWorkToken' => api_token,
18
+ 'Content-Type' => 'application/x-www-form-urlencoded'
19
+ }
20
+ end
21
+
22
+ def payload(message)
23
+ { body: message }
24
+ end
25
+
26
+ def body(payload)
27
+ URI.encode_www_form(payload)
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :api_token
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ class Nautilfer
6
+ module Adapters
7
+ class Slack < Base
8
+ def payload(message)
9
+ {
10
+ "text": message
11
+ }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ class Nautilfer
6
+ module Adapters
7
+ class Teams < Base
8
+ def payload(message)
9
+ {
10
+ "attachments": [
11
+ {
12
+ "contentType": "application/vnd.microsoft.card.adaptive",
13
+ "content": {
14
+ "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
15
+ "type": "AdaptiveCard",
16
+ "version": "1.2",
17
+ "body": [
18
+ {
19
+ "type": "TextBlock",
20
+ "text": message,
21
+ "wrap": true,
22
+ "markdown": true
23
+ }
24
+ ]
25
+ }
26
+ }
27
+ ]
28
+ }
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Nautilfer
4
- VERSION = "0.3.1"
4
+ VERSION = "0.4.0"
5
5
  end
data/lib/nautilfer.rb CHANGED
@@ -1,6 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "nautilfer/version"
4
+ require_relative "nautilfer/adapters/base"
5
+ require_relative "nautilfer/adapters/teams"
6
+ require_relative "nautilfer/adapters/slack"
7
+ require_relative "nautilfer/adapters/chatwork"
4
8
  require "json/add/core"
5
9
  require "net/http"
6
10
  require "uri"
@@ -29,11 +33,11 @@ class Nautilfer
29
33
  @configuration = Configuration.new
30
34
  end
31
35
 
32
- def initialize(endpoint:, adapter: :teams, environment: nil, enabled_environments: nil, disabled_environments: nil)
36
+ def initialize(endpoint:, adapter: Adapters::Teams.new, environment: nil, enabled_environments: nil, disabled_environments: nil)
33
37
  config = self.class.configuration
34
38
 
35
39
  @endpoint = URI.parse(endpoint)
36
- @adapter = adapter
40
+ @adapter = resolve_adapter(adapter)
37
41
  @environment = environment || config.environment || ENV['NAUTILFER_ENV'] || ENV['RAILS_ENV'] || ENV['RACK_ENV']
38
42
  @enabled_environments = normalize_env_list(enabled_environments, config.enabled_environments)
39
43
  @disabled_environments = normalize_env_list(disabled_environments, config.disabled_environments)
@@ -46,29 +50,42 @@ class Nautilfer
46
50
  perform_request(payload, headers)
47
51
  end
48
52
 
49
- def self.to_teams(message:, endpoint:, environment: nil, enabled_environments: nil, disabled_environments: nil)
50
- new(
51
- endpoint: endpoint,
52
- adapter: :teams,
53
- environment: environment,
54
- enabled_environments: enabled_environments,
55
- disabled_environments: disabled_environments
56
- ).notify(message)
53
+ private
54
+
55
+ attr_reader :endpoint, :adapter, :environment, :enabled_environments, :disabled_environments
56
+
57
+ def resolve_adapter(adapter)
58
+ resolved_adapter =
59
+ case adapter
60
+ when Symbol
61
+ adapter_from_symbol(adapter)
62
+ when Class
63
+ adapter.new
64
+ else
65
+ adapter
66
+ end
67
+
68
+ validate_adapter!(resolved_adapter)
57
69
  end
58
70
 
59
- def self.to_slack(message:, endpoint:, environment: nil, enabled_environments: nil, disabled_environments: nil)
60
- new(
61
- endpoint: endpoint,
62
- adapter: :slack,
63
- environment: environment,
64
- enabled_environments: enabled_environments,
65
- disabled_environments: disabled_environments
66
- ).notify(message)
71
+ def adapter_from_symbol(adapter)
72
+ case adapter
73
+ when :teams
74
+ Adapters::Teams.new
75
+ when :slack
76
+ Adapters::Slack.new
77
+ when :chatwork
78
+ Adapters::Chatwork.new(api_token: ENV.fetch('CHATWORK_API_TOKEN') { raise Error, 'CHATWORK_API_TOKEN is required for chatwork adapter' })
79
+ else
80
+ raise Error, "Unsupported adapter: #{adapter}"
81
+ end
67
82
  end
68
83
 
69
- private
84
+ def validate_adapter!(adapter)
85
+ return adapter if adapter.respond_to?(:payload) && adapter.respond_to?(:headers) && adapter.respond_to?(:body)
70
86
 
71
- attr_reader :endpoint, :adapter, :environment, :enabled_environments, :disabled_environments
87
+ raise Error, "Unsupported adapter: #{adapter.inspect}"
88
+ end
72
89
 
73
90
  def normalize_env_list(custom_value, configured_value)
74
91
  Array(custom_value.nil? ? configured_value : custom_value).compact
@@ -82,18 +99,7 @@ class Nautilfer
82
99
  end
83
100
 
84
101
  def build_payload(message)
85
- case adapter
86
- when :teams
87
- [teams_payload(message), default_headers]
88
- when :slack
89
- [slack_payload(message), default_headers]
90
- else
91
- raise Error, "Unsupported adapter: #{adapter}"
92
- end
93
- end
94
-
95
- def default_headers
96
- { 'Content-Type' => 'application/json' }
102
+ [adapter.payload(message), adapter.headers]
97
103
  end
98
104
 
99
105
  def perform_request(payload, headers)
@@ -101,37 +107,8 @@ class Nautilfer
101
107
  http.use_ssl = endpoint.scheme == 'https'
102
108
  http.start do |connection|
103
109
  request = Net::HTTP::Post.new(endpoint.request_uri, headers)
104
- request.body = payload.to_json
110
+ request.body = adapter.body(payload)
105
111
  connection.request(request)
106
112
  end
107
113
  end
108
-
109
- def teams_payload(message)
110
- {
111
- "attachments": [
112
- {
113
- "contentType": "application/vnd.microsoft.card.adaptive",
114
- "content": {
115
- "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
116
- "type": "AdaptiveCard",
117
- "version": "1.2",
118
- "body": [
119
- {
120
- "type": "TextBlock",
121
- "text": message,
122
- "wrap": true,
123
- "markdown": true
124
- }
125
- ]
126
- }
127
- }
128
- ]
129
- }
130
- end
131
-
132
- def slack_payload(message)
133
- {
134
- "text": message
135
- }
136
- end
137
114
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nautilfer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yusuke Abe
@@ -28,7 +28,10 @@ files:
28
28
  - Rakefile
29
29
  - compose.yml
30
30
  - lib/nautilfer.rb
31
- - lib/nautilfer/chatwork_notifier.rb
31
+ - lib/nautilfer/adapters/base.rb
32
+ - lib/nautilfer/adapters/chatwork.rb
33
+ - lib/nautilfer/adapters/slack.rb
34
+ - lib/nautilfer/adapters/teams.rb
32
35
  - lib/nautilfer/version.rb
33
36
  homepage: https://github.com/slidict/nautilfer
34
37
  licenses:
@@ -1,29 +0,0 @@
1
- require 'net/http'
2
- require 'uri'
3
- require 'json'
4
-
5
- class Nautilfer
6
- class ChatworkNotifier
7
- CHATWORK_API_ENDPOINT = "https://api.chatwork.com/v2"
8
-
9
- def initialize(api_token, room_id)
10
- @api_token = api_token
11
- @room_id = room_id
12
- end
13
-
14
- def notify(message)
15
- uri = URI("#{CHATWORK_API_ENDPOINT}/rooms/#{@room_id}/messages")
16
- request = Net::HTTP::Post.new(uri)
17
- request['X-ChatWorkToken'] = @api_token
18
- request.set_form_data(body: message)
19
-
20
- response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
21
- http.request(request)
22
- end
23
-
24
- raise "Failed to send notification: #{response.body}" unless response.is_a?(Net::HTTPSuccess)
25
-
26
- JSON.parse(response.body)
27
- end
28
- end
29
- end