HornsAndHooves-slackiq 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4d33511bc1da33236ea8a6b3c03b4d1e2a26305fbc55d9d8db48cd71644c713c
4
- data.tar.gz: da45ca5736a952f4f75bced5cfc5c1f3f4858ad7d1a0edb383558785458308c2
3
+ metadata.gz: 5cf82d00d5319230c303822b593bc4350c99f18cc5bd7539247c2622cc35b021
4
+ data.tar.gz: 40f830f297f3469d0b32bd104c6a3eeaa1cb71c0da5e8b31a8813af7bcfd5294
5
5
  SHA512:
6
- metadata.gz: ebe7cbb7a607f79063c21f549ce0a2680ab8c3d96f0da08b00c65110a37aa3eb17228ac21ffc133933d53bb037e3f94b3afd718122e43462e5bd5251b01fdede
7
- data.tar.gz: a1907bad4728a9f07d581901a2e3e57b60e8ddd1079a9d631cc84c5e503db42d90dbfde4936b937261ee878062274d276b4ed6b9e5105cea3cc34502238f7df4
6
+ metadata.gz: a07bc1b7e428c2ceac87a093118307b549dd2cae23ce12872a80f4347459951dabef1af998853f8ac54a7abdafe109805dc20a0a7703b4b4883029dc030a554d
7
+ data.tar.gz: 5281494bd6f24caf781621d41960f9db72655a676684b9212ed51dc721695bd8f704236f8e6c8f090febda3a7a78795198af537fa869a3daf159d6bff3d2798d
@@ -1,6 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
- lib = File.expand_path("../lib", __FILE__)
3
+ lib = File.expand_path("lib", __dir__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
  require "slackiq/version"
6
6
 
@@ -20,7 +20,6 @@ Gem::Specification.new do |s|
20
20
  s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
21
  s.require_paths = ["lib"]
22
22
 
23
- s.add_dependency "httparty"
24
23
  s.add_development_dependency "bundler"
25
24
  s.add_development_dependency "rake"
26
25
  s.add_development_dependency "rspec"
@@ -1,156 +1,195 @@
1
1
  require "slackiq/version"
2
2
 
3
3
  require "net/http"
4
+ require "uri"
4
5
  require "json"
5
- require "httparty"
6
+ require "date"
6
7
 
7
- require "slackiq/time_helper"
8
+ class Slackiq
8
9
 
9
- require "active_support" # For Hash#except
10
+ attr_reader :options
10
11
 
11
- module Slackiq
12
-
13
- class << self
14
-
15
- # Configure all of the webhook URLs you're going to use
16
- # @author Jason Lew
17
- def configure(webhook_urls={})
18
- raise "Argument must be a Hash" unless webhook_urls.class == Hash
19
- @@webhook_urls = webhook_urls
20
- end
21
-
22
- # Send a notification to Slack with Sidekiq info about the batch
23
- # @author Jason Lew
24
- def notify(options={})
25
- url = @@webhook_urls[options[:webhook_name]]
26
- title = options[:title]
27
- # description = options[:description]
28
- status = options[:status]
29
-
30
- if (bid = options[:bid]) && status.nil?
31
- raise <<~EOT.chomp unless defined?(Sidekiq::Batch::Status)
32
- Sidekiq::Batch::Status is not defined. \
33
- Are you sure Sidekiq Pro is set up correctly?
34
- EOT
35
- status = Sidekiq::Batch::Status.new(bid)
36
- end
37
-
38
- color = options[:color] || color_for(status)
39
-
40
- extra_fields = options.except(:webhook_name, :title, :description, :status)
12
+ # @param options [Hash]
13
+ def self.notify(options)
14
+ raise "Need to run Slackiq.configure first" if @webhook_urls.nil?
15
+ new(options.merge(webhook_urls: @webhook_urls)).execute
16
+ end
41
17
 
42
- fields = []
18
+ # @param options [Hash]
19
+ def self.configure(webhook_urls={})
20
+ @webhook_urls = webhook_urls
21
+ end
43
22
 
44
- if status
45
- created_at = status.created_at
23
+ # @param options [Hash]
24
+ def initialize(options)
25
+ @options = options
26
+ end
46
27
 
47
- if created_at
48
- time_now = Time.now
49
- duration = Slackiq::TimeHelper.elapsed_time_humanized(created_at, time_now)
50
- time_now_title = (status.complete? ? "Completed" : "Now")
51
- end
28
+ # Send a notification to Slack with Sidekiq info about the batch
29
+ def execute
30
+ time_now = Time.now
52
31
 
53
- total_jobs = status.total
54
- failures = status.failures
55
- jobs_run = total_jobs - status.pending
56
-
57
- completion_percentage = (jobs_run/total_jobs.to_f)*100
58
- failure_percentage = (failures/total_jobs.to_f)*100 if total_jobs && failures
59
-
60
- # Round to two decimal places
61
- decimal_places = 2
62
- completion_percentage = completion_percentage.round(decimal_places)
63
- failure_percentage = failure_percentage.round(decimal_places)
64
-
65
- description = status.description
66
-
67
- fields += [
68
- {
69
- title: "Created",
70
- value: Slackiq::TimeHelper.format(created_at),
71
- short: true
72
- },
73
- {
74
- title: time_now_title,
75
- value: Slackiq::TimeHelper.format(time_now),
76
- short: true
77
- },
78
- {
79
- title: "Duration",
80
- value: duration,
81
- short: true
82
- },
83
- {
84
- title: "Total Jobs",
85
- value: total_jobs,
86
- short: true
87
- },
88
- {
89
- title: "Jobs Run",
90
- value: jobs_run,
91
- short: true
92
- },
93
- {
94
- title: "Completion %",
95
- value: "#{completion_percentage}%",
96
- short: true
97
- },
98
- {
99
- title: "Failures",
100
- value: status.failures,
101
- short: true
102
- },
103
- {
104
- title: "Failure %",
105
- value: "#{failure_percentage}%",
106
- short: true
107
- },
108
- ]
109
- end
32
+ title = options[:title]
33
+ status = options[:status]
110
34
 
111
- # Add extra fields
112
- fields += extra_fields.map do |title, value|
113
- {
114
- title: title,
115
- value: value,
116
- short: false
117
- }
118
- end
35
+ if (bid = options[:bid]) && status.nil?
36
+ raise <<~EOT.chomp unless defined?(Sidekiq::Batch::Status)
37
+ Sidekiq::Batch::Status is not defined. \
38
+ Are you sure Sidekiq Pro is set up correctly?
39
+ EOT
40
+ status = Sidekiq::Batch::Status.new(bid)
41
+ end
119
42
 
120
- attachments = [
121
- {
122
- fallback: title,
123
- color: color,
124
- title: title,
125
- text: description,
126
- fields: fields,
127
- }
43
+ return if status.nil?
44
+
45
+ color = options[:color] || color_for(status)
46
+
47
+ duration = elapsed_time_humanized(status.created_at, time_now)
48
+ time_title = status.complete? ? "Completed" : "Now"
49
+ jobs_run = status.total - status.pending
50
+
51
+ completion_percentage = percentage(jobs_run / status.total.to_f)
52
+ failure_percentage = percentage(status.failures / status.total.to_f)
53
+
54
+ fields = [
55
+ {
56
+ title: title,
57
+ value: status.description,
58
+ short: false
59
+ },
60
+ {
61
+ title: "Batch ID",
62
+ value: status.bid,
63
+ short: false
64
+ },
65
+ {
66
+ title: "Created",
67
+ value: time_format(status.created_at),
68
+ short: true
69
+ },
70
+ {
71
+ title: time_title,
72
+ value: time_format(time_now),
73
+ short: true
74
+ },
75
+ {
76
+ title: "Duration",
77
+ value: duration,
78
+ short: true
79
+ },
80
+ {
81
+ title: "Total Jobs",
82
+ value: status.total,
83
+ short: true
84
+ },
85
+ {
86
+ title: "Jobs Run",
87
+ value: jobs_run,
88
+ short: true
89
+ },
90
+ {
91
+ title: "Completion %",
92
+ value: completion_percentage,
93
+ short: true
94
+ },
95
+ {
96
+ title: "Failures",
97
+ value: status.failures,
98
+ short: true
99
+ },
100
+ {
101
+ title: "Failure %",
102
+ value: failure_percentage,
103
+ short: true
104
+ }
105
+ ]
106
+
107
+ body = {
108
+ attachments: [
109
+ fields: fields,
110
+ color: color
128
111
  ]
112
+ }
113
+ http_post(body)
114
+ end
129
115
 
130
- body = { attachments: attachments }.to_json
116
+ # @param data [Hash]
117
+ private def http_post(data)
118
+ url = options[:webhook_urls].fetch(options[:webhook_name])
119
+ uri = URI.parse(url)
120
+ http = Net::HTTP.new(uri.host, uri.port)
121
+ http.use_ssl = true if uri.port == 443
122
+
123
+ header = {"Content-Type": "application/json"}
124
+ request = Net::HTTP::Post.new(uri.request_uri, header)
125
+ request.body = data.to_json
126
+ http.request(request)
127
+ end
131
128
 
132
- HTTParty.post(url, body: body)
133
- end
129
+ # @param number [Numeric]
130
+ # @param precision [Integer]
131
+ # @param multiply100 [Boolean]
132
+ private def percentage(number, precision: 2, multiply100: true)
133
+ number = number * 100 if multiply100
134
+ rounded = number.to_f.round(precision)
135
+ format = number == rounded.to_i ? "%.f" : "%.#{precision}f"
136
+ (format % rounded) + "%"
137
+ end
134
138
 
135
- # Send a notification without Sidekiq batch info
136
- # @author Jason Lew
137
- def message(text, options)
138
- url = @@webhook_urls[options[:webhook_name]]
139
- body = { text: text }.to_json
140
- HTTParty.post(url, body: body)
139
+ # @param status [Sidekiq::Batch::Status]
140
+ private def color_for(status)
141
+ colors = {
142
+ red: "f00000",
143
+ yellow: "ffc000",
144
+ green: "009800"
145
+ }
146
+
147
+ if status.total == 0
148
+ colors[:yellow]
149
+ elsif status.failures > 0
150
+ colors[:red]
151
+ elsif status.failures == 0
152
+ colors[:green]
153
+ else
154
+ colors[:yellow]
141
155
  end
156
+ end
157
+
158
+ # @param t0 [DateTime]
159
+ # @param t1 [DateTime]
160
+ private def elapsed_time_humanized(t0, t1, precision: 2)
161
+ time_humanize(
162
+ elapsed_seconds(t0, t1, precision: precision),
163
+ precision: precision
164
+ )
165
+ end
142
166
 
143
- private
144
- def color_for(status)
145
- if status.total == 0
146
- "#FBBD08" # yellow
147
- elsif status.failures > 0
148
- "#FF0000" # red
149
- elsif status.failures == 0
150
- "#1C9513" # green
151
- else
152
- "#FBBD08" # yellow
167
+ # @param t0 [DateTime]
168
+ # @param t1 [DateTime]
169
+ private def elapsed_seconds(t0, t1, precision: 2)
170
+ dt0 = t0.to_datetime
171
+ dt1 = t1.to_datetime
172
+ ((dt1 - dt0) * 24 * 60 * 60).to_f.round(precision)
173
+ end
174
+
175
+ # http://stackoverflow.com/questions/4136248/how-to-generate-a-human-readable-time-range-using-ruby-on-rails
176
+ # @param secs [Integer]
177
+ private def time_humanize(secs, precision: 2)
178
+ [[60, :s], [60, :m], [24, :h], [1000, :d]].map do |count, name|
179
+ if secs > 0
180
+ secs, n = secs.divmod(count)
181
+ if name == :s
182
+ num = n.to_f == n.to_i ? n.to_i : n.to_f
183
+ "%.#{precision}f#{name}" % num
184
+ else
185
+ "#{n.to_i}#{name}"
186
+ end
153
187
  end
154
- end
188
+ end.compact.reverse.join(" ")
189
+ end
190
+
191
+ # @param time [DateTime]
192
+ private def time_format(time)
193
+ time.strftime("%D @ %I:%M:%S %P")
155
194
  end
156
195
  end
@@ -1,3 +1,3 @@
1
- module Slackiq
2
- VERSION = "1.2.1"
1
+ class Slackiq
2
+ VERSION = "1.3.0".freeze
3
3
  end
metadata CHANGED
@@ -1,30 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: HornsAndHooves-slackiq
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - HornsAndHooves
8
8
  - Peter Maneykowski
9
- autorequire:
9
+ autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2020-04-03 00:00:00.000000000 Z
12
+ date: 2020-07-12 00:00:00.000000000 Z
13
13
  dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: httparty
16
- requirement: !ruby/object:Gem::Requirement
17
- requirements:
18
- - - ">="
19
- - !ruby/object:Gem::Version
20
- version: '0'
21
- type: :runtime
22
- prerelease: false
23
- version_requirements: !ruby/object:Gem::Requirement
24
- requirements:
25
- - - ">="
26
- - !ruby/object:Gem::Version
27
- version: '0'
28
14
  - !ruby/object:Gem::Dependency
29
15
  name: bundler
30
16
  requirement: !ruby/object:Gem::Requirement
@@ -86,13 +72,12 @@ files:
86
72
  - bin/console
87
73
  - bin/setup
88
74
  - lib/slackiq.rb
89
- - lib/slackiq/time_helper.rb
90
75
  - lib/slackiq/version.rb
91
76
  homepage: https://github.com/HornsAndHooves/slackiq
92
77
  licenses:
93
78
  - MIT
94
79
  metadata: {}
95
- post_install_message:
80
+ post_install_message:
96
81
  rdoc_options: []
97
82
  require_paths:
98
83
  - lib
@@ -108,7 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
108
93
  version: '0'
109
94
  requirements: []
110
95
  rubygems_version: 3.0.6
111
- signing_key:
96
+ signing_key:
112
97
  specification_version: 4
113
98
  summary: 'HornsAndHooves: Slack and Sidekiq Pro integration'
114
99
  test_files: []
@@ -1,37 +0,0 @@
1
- require "date"
2
-
3
- module Slackiq
4
- module TimeHelper
5
-
6
- class << self
7
-
8
- def elapsed_time_humanized(t0, t1)
9
- humanize(elapsed_seconds(t0, t1))
10
- end
11
-
12
- def elapsed_seconds(t0, t1)
13
- dt0 = t0.to_datetime
14
- dt1 = t1.to_datetime
15
- ((dt1-dt0)*24*60*60).to_f.round(2)
16
- end
17
-
18
- # http://stackoverflow.com/questions/4136248/how-to-generate-a-human-readable-time-range-using-ruby-on-rails
19
- def humanize(secs)
20
- [[60, :s], [60, :m], [24, :h], [1000, :d]].map{ |count, name|
21
- if secs > 0
22
- secs, n = secs.divmod(count)
23
- if name == :s
24
- "%.2f#{name}" % [n.to_f]
25
- else
26
- "#{n.to_i}#{name}"
27
- end
28
- end
29
- }.compact.reverse.join(" ")
30
- end
31
-
32
- def format(time)
33
- time.strftime("%D @ %r").gsub("PM", "pm").gsub("AM", "am")
34
- end
35
- end
36
- end
37
- end