lazylead 0.10.5 → 0.11.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: ef86e7fdc0c41c8f9d7220a580e6afd1c7f9e09e396c14142df99a407eec0d1c
4
- data.tar.gz: aa452077f1e99ac82c6add4b7dd9ac057d0715f1feea02ed2d6d6e744e322991
3
+ metadata.gz: 25f9021629329ee9ec02db8d6d8d51a0daaffcfccdc6e63627e12644f5775aab
4
+ data.tar.gz: 5560dc06b0b2c67ce56ff918ebe3eeb1b28d0bf22457c3c539f0229cf7db8690
5
5
  SHA512:
6
- metadata.gz: 58f54eb88f268b67c48ac5867502637767fb0cb27cbfaf0b6b3edd0b0119774c0fde9d78408b4e81243b279eec1fc9a18c970dfd37bc344f0654fd653ed59709
7
- data.tar.gz: 131a15331350d5869187b2e8f8546715434138fc66b0d711a6a882a5292bc5937ac44e060f2a6a233dcbd098cef8e568af592ecd85d0c1b8c3f4965ddd8ac9c4
6
+ metadata.gz: 1240d3399f5d17087f3e844dbebe1c838f152dac9ac11635dcb4697ba5ec9c391b69dc7ccf140966e8a83fa95f12607bb46e32f50b768187335f1c43ed9b1aed
7
+ data.tar.gz: 92da12e36cba95581298efc6a3899af2f24e61d0be558b40e919fa8a5a98f871dbb565c5f1e8b7d1ad5cc53768deec7e5cc0edec94a1510cc4663e8c0abf53b8
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ def check_message_format
4
+ regex = /^#\d+:\s\w+/
5
+ message_file = ARGV[0]
6
+ message = File.read(message_file)
7
+ unless regex.match(message)
8
+ puts "Your message is not formatted correctly"
9
+ puts "Message should have following format: '#issue_id: Commit message'"
10
+ exit 1
11
+ end
12
+ end
13
+ check_message_format
data/.rultor.yml CHANGED
@@ -25,6 +25,7 @@ release:
25
25
  curl -s -X POST --url "https://circleci.com/api/v2/project/gh/dgroup/lazylead/envvar" -H @../circleci.header -H "accept: application/json" -H "content-type: application/json" -d "{ \"name\": \"DOCKER_RELEASE_TAGS\", \"value\": \"${tag}\" }" -o /dev/null
26
26
  curl -s -X POST --url https://circleci.com/api/v2/project/gh/dgroup/lazylead/pipeline -H @../circleci.header -H 'accept: application/json' -H 'content-type: application/json' -H 'x-attribution-login: dgroup' -o /dev/null
27
27
  merge:
28
+ squash: true
28
29
  script: |-
29
30
  bundle install
30
31
  bundle exec rake test rubocop sqlint xcop
data/Rakefile CHANGED
@@ -28,6 +28,7 @@ require "date"
28
28
  require "rdoc"
29
29
  require "colorize"
30
30
  require "rake/clean"
31
+ require "concurrent"
31
32
 
32
33
  # @todo #/DEV Investigate the possibility of using migrations from active_record
33
34
  # - Rake tasks https://gist.github.com/schickling/6762581
@@ -45,11 +46,18 @@ def version
45
46
  Gem::Specification.load(Dir["*.gemspec"].first).version
46
47
  end
47
48
 
48
- task default: %i[clean rubocop test sqlint xcop copyright docker]
49
+ task default: %i[init_hooks clean rubocop test sqlint xcop copyright docker]
50
+
51
+ task :init_hooks do
52
+ next if File.file?(".git/hooks/commit-msg")
53
+ FileUtils.copy(".githooks/commit-msg", ".git/hooks/commit-msg")
54
+ FileUtils.chmod("+x", ".git/hooks/commit-msg")
55
+ end
49
56
 
50
57
  require "rake/testtask"
51
58
  desc "Run all unit tests"
52
59
  Rake::TestTask.new(:test) do |t|
60
+ ENV["MT_CPU"] = Concurrent.processor_count.to_s
53
61
  t.libs << "test"
54
62
  t.libs << "lib"
55
63
  t.test_files = FileList["test/**/*_test.rb"]
data/lazylead.gemspec CHANGED
@@ -32,7 +32,7 @@ Gem::Specification.new do |s|
32
32
  s.rubygems_version = "2.2"
33
33
  s.required_ruby_version = ">=2.6.5"
34
34
  s.name = "lazylead"
35
- s.version = "0.10.5"
35
+ s.version = "0.11.0"
36
36
  s.license = "MIT"
37
37
  s.summary = "Eliminate the annoying work within bug-trackers."
38
38
  s.description = "Ticketing systems (Github, Jira, etc.) are strongly
@@ -45,7 +45,7 @@ tasks instead of solving technical problems."
45
45
  s.authors = ["Yurii Dubinka"]
46
46
  s.email = "yurii.dubinka@gmail.com"
47
47
  s.homepage = "http://github.com/dgroup/lazylead"
48
- s.post_install_message = "Thanks for installing Lazylead v0.10.5!
48
+ s.post_install_message = "Thanks for installing Lazylead v0.11.0!
49
49
  Read our blog posts: https://lazylead.org
50
50
  Stay in touch with the community in Telegram: https://t.me/lazylead
51
51
  Follow us on Twitter: https://twitter.com/lazylead
@@ -58,7 +58,7 @@ tasks instead of solving technical problems."
58
58
  s.add_runtime_dependency "activerecord", "6.1.3"
59
59
  s.add_runtime_dependency "backtrace", "0.3"
60
60
  s.add_runtime_dependency "colorize", "0.8.1"
61
- s.add_runtime_dependency "faraday", "1.7.0"
61
+ s.add_runtime_dependency "faraday", "1.7.1"
62
62
  s.add_runtime_dependency "get_process_mem", "0.2.7"
63
63
  s.add_runtime_dependency "inifile", "3.0.0"
64
64
  s.add_runtime_dependency "jira-ruby", "2.1.5"
@@ -80,7 +80,7 @@ tasks instead of solving technical problems."
80
80
  s.add_runtime_dependency "tzinfo-data", "1.2021.1"
81
81
  s.add_runtime_dependency "vcs4sql", "0.1.1"
82
82
  s.add_runtime_dependency "viewpoint", "1.1.1"
83
- s.add_development_dependency "codecov", "0.5.2"
83
+ s.add_development_dependency "codecov", "0.6.0"
84
84
  s.add_development_dependency "guard", "2.18.0"
85
85
  s.add_development_dependency "guard-minitest", "2.4.6"
86
86
  s.add_development_dependency "minitest", "5.14.4"
@@ -91,9 +91,9 @@ tasks instead of solving technical problems."
91
91
  s.add_development_dependency "rake", "13.0.6"
92
92
  s.add_development_dependency "random-port", "0.5.1"
93
93
  s.add_development_dependency "rdoc", "6.3.2"
94
- s.add_development_dependency "rubocop", "1.19.0"
94
+ s.add_development_dependency "rubocop", "1.20.0"
95
95
  s.add_development_dependency "rubocop-minitest", "0.15.0"
96
- s.add_development_dependency "rubocop-performance", "1.11.4"
96
+ s.add_development_dependency "rubocop-performance", "1.11.5"
97
97
  s.add_development_dependency "rubocop-rake", "0.6.0"
98
98
  s.add_development_dependency "rubocop-rspec", "2.4.0"
99
99
  s.add_development_dependency "sqlint", "0.2.0"
@@ -70,7 +70,7 @@ module Lazylead
70
70
  ActiveRecord::Base.establish_connection(
71
71
  adapter: "sqlite3",
72
72
  database: @db,
73
- pool: opts[:max_connections]
73
+ pool: opts[:max_connections] || ENV["MT_CPU"]
74
74
  )
75
75
  @log.debug "Database connection established"
76
76
  end
@@ -170,10 +170,9 @@ module Lazylead
170
170
 
171
171
  # A task with extended logging
172
172
  # @see Lazylead::ORM::Task
173
- class VerboseTask
173
+ class Verbose
174
174
  extend Forwardable
175
- def_delegators :@orig, :id, :name, :team, :to_s, :inspect, :props, :type,
176
- :unit
175
+ def_delegators :@orig, :id, :name, :team, :to_s, :inspect, :props, :type, :unit
177
176
 
178
177
  def initialize(orig, log = Log.new)
179
178
  @orig = orig
@@ -203,6 +202,28 @@ module Lazylead
203
202
  # rubocop:enable Metrics/AbcSize
204
203
  end
205
204
 
205
+ # A task which support retry in case of failure.
206
+ # @see Lazylead::ORM::Task
207
+ class Retry
208
+ extend Forwardable
209
+ def_delegators :@orig, :id, :name, :team, :to_s, :inspect, :props, :type, :unit
210
+
211
+ def initialize(orig, log = Log.new)
212
+ @orig = orig
213
+ @log = log
214
+ end
215
+
216
+ def exec
217
+ retries ||= 0
218
+ @orig.exec
219
+ @orig
220
+ rescue StandardError
221
+ sleep(props.fetch("attempt_wait", 0).to_f) if props.key? "attempt_wait"
222
+ retry if (retries += 1) < props.fetch("attempt", 0).to_i
223
+ @orig
224
+ end
225
+ end
226
+
206
227
  # Ticketing systems to monitor.
207
228
  class System < ActiveRecord::Base
208
229
  include ORM
data/lib/lazylead/opts.rb CHANGED
@@ -142,5 +142,16 @@ module Lazylead
142
142
  def construct(field, delim: ",")
143
143
  slice(field, delim).map(&:constantize).map(&:new)
144
144
  end
145
+
146
+ # Get the value by key
147
+ # @param key
148
+ # The key to fetch value. The key might be a plain text or symbol
149
+ # @param default
150
+ # The default/alternative value if key not found
151
+ # @return The value by key or alternative/default value.
152
+ def find(key, default = nil)
153
+ return default if key.nil?
154
+ to_h[key.to_s] || to_h[key.to_sym] || default
155
+ end
145
156
  end
146
157
  end
@@ -48,9 +48,12 @@ module Lazylead
48
48
  @trigger.method(task.type).call(task.unit) do
49
49
  ActiveRecord::Base.connection_pool.with_connection do
50
50
  if task.props.key? "no_logs"
51
- task.exec
51
+ ORM::Retry.new(task, @log).exec
52
52
  else
53
- ORM::VerboseTask.new(task, @log).exec
53
+ ORM::Verbose.new(
54
+ ORM::Retry.new(task, @log),
55
+ @log
56
+ ).exec
54
57
  end
55
58
  end
56
59
  end
@@ -57,6 +57,7 @@ module Lazylead
57
57
  # :max_results => maximum number of tickets per one iteration.
58
58
  # :fields => ticket fields to be fetched like assignee, summary, etc.
59
59
  def issues(jql, opts = { max_results: 50, fields: nil, expand: nil })
60
+ opts = Opts.new(opts)
60
61
  raw do |jira|
61
62
  start = 0
62
63
  tickets = []
@@ -66,8 +67,8 @@ module Lazylead
66
67
  tickets.concat(jira.Issue.jql(jql, opts.merge(start_at: start))
67
68
  .map { |i| Lazylead::Issue.new(i, jira) })
68
69
  @log.debug "Fetched #{tickets.size}"
69
- start += opts.fetch(:max_results, 50).to_i
70
- break if start > total
70
+ start += opts.find(:max_results, 50)
71
+ break if (start > total) || (start >= opts.find(:limit, total))
71
72
  end
72
73
  tickets
73
74
  end
@@ -326,7 +327,7 @@ module Lazylead
326
327
  # or dashboards.
327
328
  class NoAuthJira
328
329
  extend Forwardable
329
- def_delegators :@jira, :issues, :raw
330
+ def_delegators :@jira, :issues, :raw, :max_results, :limit
330
331
 
331
332
  def initialize(url, path = "", log = Log.new)
332
333
  @jira = Jira.new(
@@ -22,6 +22,7 @@
22
22
  # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
23
23
  # OR OTHER DEALINGS IN THE SOFTWARE.
24
24
 
25
+ require_relative "memes"
25
26
  require_relative "../../log"
26
27
  require_relative "../../opts"
27
28
  require_relative "../../email"
@@ -44,15 +45,21 @@ module Lazylead
44
45
  end
45
46
 
46
47
  def run(sys, postman, opts)
47
- Requires.new(__dir__).load
48
- opts[:rules] = opts.construct("rules")
49
- opts[:total] = opts[:rules].sum(&:score)
48
+ init_rules(opts)
50
49
  opts[:tickets] = sys.issues(opts["jql"], opts.jira_defaults.merge(expand: "changelog"))
51
50
  .map { |i| Score.new(i, opts) }
52
51
  .each(&:evaluate)
53
52
  .each(&:post)
54
53
  postman.send(opts) unless opts[:tickets].empty?
55
54
  end
55
+
56
+ # Initialize accuracy rules and configuration for tickets verification.
57
+ def init_rules(opts)
58
+ Requires.new(__dir__).load
59
+ opts[:rules] = opts.construct("rules")
60
+ opts[:total] = opts[:rules].sum(&:score)
61
+ opts[:memes] = Memes.new(opts["memes"])
62
+ end
56
63
  end
57
64
  end
58
65
 
@@ -93,7 +100,7 @@ module Lazylead
93
100
  comment << "|#{r.desc}|#{r.passed(@issue) ? '(/)' : '(-)'}|#{r.field}|"
94
101
  end
95
102
  comment << docs_link
96
- comment << ""
103
+ comment << reaction
97
104
  comment << "Posted by [lazylead v#{Lazylead::VERSION}|https://bit.ly/2NjdndS]."
98
105
  comment.join("\r\n")
99
106
  end
@@ -144,5 +151,26 @@ module Lazylead
144
151
  return @issue.reporter.id if first.nil?
145
152
  first["author"]["key"]
146
153
  end
154
+
155
+ # Add reaction meme to the ticket comment based on score.
156
+ # The meme details are represented as array, where each element is a separate line in future
157
+ # comment in jira.
158
+ #
159
+ # @todo #339/DEV Seems jira doesn't support the rendering of external images by url, thus so far
160
+ # we might have several options:
161
+ # - attach meme to ticket and make rendering using [^attach.jpg!thumbnail] option
162
+ # - have a link to meme (like it implemented now)
163
+ # The 1st option with attachment might generate multiple events in jira and spam ticket
164
+ # watchers, thus, some research & UX testing needed how to make it better.
165
+ def reaction
166
+ return [] if @opts[:memes].nil? && !@opts[:memes].enabled?
167
+ url = @opts[:memes].find(@accuracy)
168
+ return [] if url.blank?
169
+ [
170
+ "",
171
+ "Our reaction when we got the ticket with triage accuracy #{@accuracy}% is [here|#{url}].",
172
+ ""
173
+ ]
174
+ end
147
175
  end
148
176
  end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The MIT License
4
+ #
5
+ # Copyright (c) 2019-2021 Yurii Dubinka
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"),
9
+ # to deal in the Software without restriction, including without limitation
10
+ # the rights to use, copy, modify, merge, publish, distribute, sublicense,
11
+ # and/or sell copies of the Software, and to permit persons to whom
12
+ # the Software is furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included
15
+ # in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22
+ # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
23
+ # OR OTHER DEALINGS IN THE SOFTWARE.
24
+
25
+ require "json"
26
+ require_relative "../../log"
27
+ require_relative "../../opts"
28
+
29
+ module Lazylead
30
+ # Meme generator based on tickets accuracy.
31
+ # For each range of scores there might be several available memes to be chosen randomly.
32
+ # If no meme found for score, empty url should be provided.
33
+ #
34
+ # @todo #339/DEV Prepare the meme list and attach them to the github, section .docs/accuracy/memes
35
+ # As url they will be required for configuration of the each task.
36
+ class Memes
37
+ def initialize(memes, log: Log.new)
38
+ @log = log
39
+ @memes = memes
40
+ end
41
+
42
+ def enabled?
43
+ !@memes.nil? && !range.empty?
44
+ end
45
+
46
+ # Detect meme url based on accuracy score.
47
+ # @param score
48
+ # Accuracy score in percentage
49
+ def find(score)
50
+ r = range.find { |m| score >= m[0] && score <= m[1] }
51
+ return "" if r.nil?
52
+ r.last.sample
53
+ end
54
+
55
+ # Parse json-based memes configuration.
56
+ # Expected format is
57
+ # "memes": {
58
+ # "0-9.9": "https://meme.com?id=awful1.gif,https://meme.com?id=awful2.gif",
59
+ # "70-89.9": "https://meme.com?id=nice.gif",
60
+ # "90-100": "https://meme.com?id=wow.gif"
61
+ # }
62
+ def range
63
+ @range ||= if @memes.nil?
64
+ []
65
+ else
66
+ rng = JSON.parse(@memes).to_h
67
+ return [] if rng.empty?
68
+ rng.map do |k, v|
69
+ next unless k.include? "-"
70
+ row = k.split("-").map(&:to_f)
71
+ row << v.split(",")
72
+ row
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -39,7 +39,9 @@ module Lazylead
39
39
 
40
40
  # Ensure that ticket has an attachment with video-file extension
41
41
  def matches?(attach)
42
- @ext.any? { |e| e.eql? File.extname(attach.attrs["filename"]).downcase }
42
+ return true if @ext.any? { |e| e.eql? File.extname(attach.attrs["filename"]).downcase }
43
+ return false if attach.attrs["mimeType"].nil?
44
+ @ext.any? { |e| attach.attrs["mimeType"].include? e[1..] }
43
45
  end
44
46
  end
45
47
  end
@@ -28,7 +28,7 @@ module Lazylead
28
28
  # Check that ticket has a web link to external system with design.
29
29
  class WikiUrl < Lazylead::Wiki
30
30
  def initialize(url)
31
- super
31
+ super()
32
32
  @url = url
33
33
  end
34
34
 
@@ -23,5 +23,5 @@
23
23
  # OR OTHER DEALINGS IN THE SOFTWARE.
24
24
 
25
25
  module Lazylead
26
- VERSION = "0.10.5"
26
+ VERSION = "0.11.0"
27
27
  end
@@ -66,6 +66,7 @@
66
66
 
67
67
  td {
68
68
  padding: 2px;
69
+ vertical-align: top;
69
70
  }
70
71
 
71
72
  .commit * {
@@ -26,6 +26,7 @@ require_relative "../test"
26
26
  require_relative "../../lib/lazylead/log"
27
27
  require_relative "../../lib/lazylead/salt"
28
28
  require_relative "../../lib/lazylead/home"
29
+ require_relative "../../lib/lazylead/opts"
29
30
  require_relative "../../lib/lazylead/exchange"
30
31
  require_relative "../../lib/lazylead/system/jira"
31
32
 
@@ -37,11 +38,13 @@ module Lazylead
37
38
  "exchange_password",
38
39
  "exchange_to"
39
40
  Exchange.new(Log.new, NoSalt.new).send(
40
- to: ENV["exchange_to"],
41
- tickets: NoAuthJira.new("https://jira.spring.io")
42
- .issues("key = DATAJDBC-480"),
43
- "subject" => "[DD] PDTN!",
44
- "template" => "lib/messages/due_date_expired.erb"
41
+ Opts.new(
42
+ to: ENV["exchange_to"],
43
+ tickets: NoAuthJira.new("https://jira.spring.io")
44
+ .issues("key = DATAJDBC-480"),
45
+ "subject" => "[DD] PDTN!",
46
+ "template" => "lib/messages/due_date_expired.erb"
47
+ )
45
48
  )
46
49
  end
47
50
 
@@ -58,11 +61,13 @@ module Lazylead
58
61
  "exchange_user" => ENV["enc_exchange_usr"],
59
62
  "exchange_password" => ENV["enc_exchange_psw"]
60
63
  ).send(
61
- to: ENV["exchange_to"],
62
- tickets: NoAuthJira.new("https://jira.spring.io")
63
- .issues("key = DATAJDBC-480"),
64
- "subject" => "[DD] Enc PDTN!",
65
- "template" => "lib/messages/due_date_expired.erb"
64
+ Opts.new(
65
+ to: ENV["exchange_to"],
66
+ tickets: NoAuthJira.new("https://jira.spring.io")
67
+ .issues("key = DATAJDBC-480"),
68
+ "subject" => "[DD] Enc PDTN!",
69
+ "template" => "lib/messages/due_date_expired.erb"
70
+ )
66
71
  )
67
72
  end
68
73
 
@@ -78,10 +83,12 @@ module Lazylead
78
83
  "exchange_user" => ENV["enc_exchange_usr"],
79
84
  "exchange_password" => ENV["enc_exchange_psw"]
80
85
  ).send(
81
- to: ENV["exchange_to"],
82
- "attachments" => "readme.md",
83
- "subject" => "[LL] Attachments",
84
- "template" => "lib/messages/savepoint.erb"
86
+ Opts.new(
87
+ to: ENV["exchange_to"],
88
+ "attachments" => "readme.md",
89
+ "subject" => "[LL] Attachments",
90
+ "template" => "lib/messages/savepoint.erb"
91
+ )
85
92
  )
86
93
  end
87
94
  end
@@ -113,5 +113,21 @@ module Lazylead
113
113
  test "nil is not a numeric" do
114
114
  refute Opts.new("key" => nil).numeric? "key"
115
115
  end
116
+
117
+ test "find by text key" do
118
+ assert_equal "val", Opts.new("key" => "val").find("key")
119
+ end
120
+
121
+ test "find by symbol key" do
122
+ assert_equal "val", Opts.new(key: "val").find(:key)
123
+ end
124
+
125
+ test "find by symbol key but with text key" do
126
+ assert_equal "val", Opts.new("key" => "val").find(:key)
127
+ end
128
+
129
+ test "find default" do
130
+ assert_equal "val", Opts.new.find(:key, "val")
131
+ end
116
132
  end
117
133
  end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The MIT License
4
+ #
5
+ # Copyright (c) 2019-2021 Yurii Dubinka
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"),
9
+ # to deal in the Software without restriction, including without limitation
10
+ # the rights to use, copy, modify, merge, publish, distribute, sublicense,
11
+ # and/or sell copies of the Software, and to permit persons to whom
12
+ # the Software is furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included
15
+ # in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22
+ # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
23
+ # OR OTHER DEALINGS IN THE SOFTWARE.
24
+
25
+ require_relative "../test"
26
+ require_relative "../../lib/lazylead/log"
27
+ require_relative "../../lib/lazylead/model"
28
+
29
+ module Lazylead
30
+ # Fake lazylead task for unit testing purposes.
31
+ class FakeTask
32
+ attr_reader :attempts
33
+
34
+ # Ctor.
35
+ # @param proc
36
+ # The logic to be executed in task.
37
+ # The logic may successfully finished or fail due to the exception.
38
+ # @param opts
39
+ # The task properties defined in the database by the user.
40
+ # @see Task#props
41
+ def initialize(proc, opts)
42
+ @proc = proc
43
+ @opts = opts
44
+ @attempts = 0
45
+ end
46
+
47
+ # Execute the fake task logic and count the attempt.
48
+ def exec
49
+ @attempts += 1
50
+ @proc.call
51
+ end
52
+
53
+ # The task properties.
54
+ def props
55
+ @opts
56
+ end
57
+ end
58
+
59
+ class RetryTest < Lazylead::Test
60
+ test "retry 3 times if error" do
61
+ assert_equal 3,
62
+ ORM::Retry.new(
63
+ FakeTask.new(
64
+ proc { raise "shit happens, you know..." },
65
+ "attempt" => "3"
66
+ )
67
+ ).exec.attempts
68
+ end
69
+
70
+ test "no retry if task successful" do
71
+ assert_equal 1, ORM::Retry.new(FakeTask.new(proc { "ok" }, "attempt" => "3")).exec.attempts
72
+ end
73
+
74
+ test "retry and sleep if error" do
75
+ assert_equal 2,
76
+ ORM::Retry.new(
77
+ FakeTask.new(
78
+ proc { raise "network issue" },
79
+ "attempt" => "2",
80
+ "attempt_wait" => "0.01" # => 0.01 second
81
+ )
82
+ ).exec.attempts
83
+ end
84
+ end
85
+ end
@@ -181,9 +181,10 @@ module Lazylead
181
181
  end
182
182
 
183
183
  test "bulk search in few iterations" do
184
- assert NoAuthJira.new("https://jira.spring.io")
185
- .issues("key>DATAJDBC-500")
186
- .size >= 118
184
+ assert_equal 3,
185
+ NoAuthJira.new("https://jira.spring.io")
186
+ .issues("key>DATAJDBC-500 and key < DATAJDBC-504", max_results: 1)
187
+ .size
187
188
  end
188
189
 
189
190
  test "connected based on string properties" do
@@ -202,5 +203,12 @@ module Lazylead
202
203
  .first
203
204
  .sprint("customfield_10480")
204
205
  end
206
+
207
+ test "bulk search in few iterations with limit" do
208
+ assert_equal 3,
209
+ NoAuthJira.new("https://jira.spring.io")
210
+ .issues("key > DATAJDBC-500", max_results: 1, "limit" => 3)
211
+ .size
212
+ end
205
213
  end
206
214
  end
@@ -48,6 +48,11 @@ module Lazylead
48
48
  "57" => "#19DD1E",
49
49
  "90" => "#0FA81A"
50
50
  }.to_json.to_s,
51
+ "memes" => {
52
+ "0-9.9" => "https://meme.com?id=awful1.gif,https://meme.com?id=awful2.gif",
53
+ "70-89.9" => "https://meme.com?id=nice.gif",
54
+ "90-100" => "https://meme.com?id=wow.gif"
55
+ }.to_json.to_s,
51
56
  "docs" => "https://github.com/dgroup/lazylead/blob/master/.github/ISSUE_TEMPLATE/bug_report.md",
52
57
  "jql" => "key in (DATAJDBC-490, DATAJDBC-492, DATAJDBC-493)",
53
58
  "max_results" => 200,
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The MIT License
4
+ #
5
+ # Copyright (c) 2019-2021 Yurii Dubinka
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"),
9
+ # to deal in the Software without restriction, including without limitation
10
+ # the rights to use, copy, modify, merge, publish, distribute, sublicense,
11
+ # and/or sell copies of the Software, and to permit persons to whom
12
+ # the Software is furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included
15
+ # in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22
+ # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
23
+ # OR OTHER DEALINGS IN THE SOFTWARE.
24
+
25
+ require_relative "../../../test"
26
+ require_relative "../../../../lib/lazylead/task/accuracy/memes"
27
+
28
+ module Lazylead
29
+ class MemesTest < Lazylead::Test
30
+ test "detect range" do
31
+ assert_array(
32
+ [
33
+ [0.0, 9.9, %w[https://meme.com?id=awful1.gif https://meme.com?id=awful2.gif]],
34
+ [70.0, 89.9, ["https://meme.com?id=nice.gif"]],
35
+ [90.0, 100.0, ["https://meme.com?id=wow.gif"]]
36
+ ],
37
+ Lazylead::Memes.new(
38
+ {
39
+ "0-9.9" => "https://meme.com?id=awful1.gif,https://meme.com?id=awful2.gif",
40
+ "70-89.9" => "https://meme.com?id=nice.gif",
41
+ "90-100" => "https://meme.com?id=wow.gif"
42
+ }.to_json.to_s
43
+ ).range
44
+ )
45
+ end
46
+
47
+ test "find by score" do
48
+ assert_equal "https://meme.com?id=nice.gif",
49
+ Lazylead::Memes.new(
50
+ {
51
+ "0-9.9" => "https://meme.com?id=awful1.gif,https://meme.com?id=awful2.gif",
52
+ "70-89.9" => "https://meme.com?id=nice.gif",
53
+ "90-100" => "https://meme.com?id=wow.gif"
54
+ }.to_json.to_s
55
+ ).find(80)
56
+ end
57
+
58
+ test "not found" do
59
+ assert_blank Lazylead::Memes.new(
60
+ {
61
+ "0-9.9" => "https://meme.com?id=awful1.gif,https://meme.com?id=awful2.gif",
62
+ "70-89.9" => "https://meme.com?id=nice.gif"
63
+ }.to_json.to_s
64
+ ).find(40)
65
+ end
66
+
67
+ test "positive_assert_array" do
68
+ assert_array [[1, 2, %w[a b]]],
69
+ [[1, 2, %w[a b]]]
70
+ end
71
+
72
+ test "negative_assert_array" do
73
+ refute array? [[1, 2, %w[a b]]],
74
+ [[1, 2, %w[c d]]]
75
+ end
76
+ end
77
+ end
@@ -24,6 +24,7 @@
24
24
 
25
25
  require_relative "../../../test"
26
26
  require_relative "../../../../lib/lazylead/task/accuracy/records"
27
+ require_relative "../../../../lib/lazylead/system/jira"
27
28
 
28
29
  module Lazylead
29
30
  class RecordsTest < Lazylead::Test
@@ -56,5 +57,20 @@ module Lazylead
56
57
  )
57
58
  )
58
59
  end
60
+
61
+ test "mime type has .gif despite on ext" do
62
+ assert Records.new.passed(
63
+ OpenStruct.new(
64
+ attachments: [
65
+ OpenStruct.new(
66
+ attrs: {
67
+ "filename" => "snapshot.png",
68
+ "mimeType" => "image/gif"
69
+ }
70
+ )
71
+ ]
72
+ )
73
+ )
74
+ end
59
75
  end
60
76
  end
@@ -66,6 +66,13 @@ module Lazylead
66
66
  "57" => "#19DD1E",
67
67
  "90" => "#0FA81A"
68
68
  }.to_json.to_s,
69
+ memes: Memes.new(
70
+ {
71
+ "0-9.9" => "https://meme.com?id=awful1.gif,https://meme.com?id=awful2.gif",
72
+ "70-89.9" => "https://meme.com?id=nice.gif",
73
+ "90-100" => "https://meme.com?id=wow.gif"
74
+ }.to_json.to_s
75
+ ),
69
76
  "docs" => "https://github.com/dgroup/lazylead/blob/master/.github/ISSUE_TEMPLATE/bug_report.md"
70
77
  )
71
78
  ).evaluate.comment
@@ -27,6 +27,8 @@ require_relative "../../../../lib/lazylead/task/accuracy/screenshots"
27
27
  require_relative "../../../../lib/lazylead/system/jira"
28
28
 
29
29
  module Lazylead
30
+ # @todo #/DEV Rename the tests name as some of them are too huge.
31
+ # The maximum name size should be 56 symbols as it gives fancy format for test output in terminal
30
32
  class ScreenshotsTest < Lazylead::Test
31
33
  test "issue has two .png files with reference in description" do
32
34
  assert Screenshots.new.passed(
@@ -50,5 +50,9 @@ module Lazylead
50
50
  )
51
51
  )
52
52
  end
53
+
54
+ test "wiki score" do
55
+ greater_then WikiUrl.new("https://wiki.com/page=").score, 0
56
+ end
53
57
  end
54
58
  end
@@ -33,8 +33,7 @@ require_relative "../../../../lib/lazylead/task/svn/svn"
33
33
  module Lazylead
34
34
  class GrepTest < Lazylead::Test
35
35
  test "changes with text" do
36
- skip "No svn credentials provided" unless env? "svn_log_user",
37
- "svn_log_password"
36
+ skip "No svn credentials provided" unless env? "svn_log_user", "svn_log_password"
38
37
  skip "No internet connection to riouxsvn.com" unless ping? "riouxsvn.com"
39
38
  Lazylead::Smtp.new.enable
40
39
  Task::Svn::Grep.new.run(
data/test/test.rb CHANGED
@@ -51,6 +51,15 @@ module Lazylead
51
51
  include Minitest::Hooks
52
52
 
53
53
  make_my_diffs_pretty!
54
+ parallelize(workers: ENV["MT_CPU"].to_i)
55
+
56
+ parallelize_setup do |worker|
57
+ SimpleCov.command_name "#{SimpleCov.command_name}-#{worker}"
58
+ end
59
+
60
+ parallelize_teardown do |_worker|
61
+ SimpleCov.result
62
+ end
54
63
 
55
64
  def around
56
65
  Timeout.timeout(
@@ -147,5 +156,43 @@ module Lazylead
147
156
  require "net/ping"
148
157
  Net::Ping::External.new(host).ping?
149
158
  end
159
+
160
+ # Ensure that actual array contain at least expected array.
161
+ # @param exp
162
+ # The array with expected values
163
+ # @param act
164
+ # The array with actual values
165
+ def assert_array(exp, act)
166
+ assert_equal exp.size, act.size, "Size mismatch between arrays"
167
+ assert array?(exp, act), "No match between '#{exp}' and '#{act}'"
168
+ end
169
+
170
+ # Compare that actual array contain(not equal!) at least expected array.
171
+ # @return true
172
+ # If array <exp> contain array <act>
173
+ # rubocop:disable Metrics/PerceivedComplexity
174
+ # rubocop:disable Metrics/CyclomaticComplexity
175
+ def array?(exp, act)
176
+ rows = []
177
+ exp.each do |row|
178
+ rows << if row.respond_to? :each
179
+ act.any? do |arow|
180
+ next unless arow.respond_to? :[]
181
+ row.each_with_index.map { |c, i| c.eql? arow[i] }.all? { |c| c }
182
+ end
183
+ else
184
+ act.any? { |arow| row.eql? arow }
185
+ end
186
+ end
187
+ rows.all? { |r| r }
188
+ end
189
+ # rubocop:enable Metrics/PerceivedComplexity
190
+ # rubocop:enable Metrics/CyclomaticComplexity
191
+
192
+ # Ensure that text is blank.
193
+ def assert_blank(text)
194
+ assert_respond_to text, :blank?, "Text has no method :blank?"
195
+ assert text.blank?, "Text isn't blank"
196
+ end
150
197
  end
151
198
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lazylead
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.5
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yurii Dubinka
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-16 00:00:00.000000000 Z
11
+ date: 2021-09-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - '='
60
60
  - !ruby/object:Gem::Version
61
- version: 1.7.0
61
+ version: 1.7.1
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - '='
67
67
  - !ruby/object:Gem::Version
68
- version: 1.7.0
68
+ version: 1.7.1
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: get_process_mem
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -366,14 +366,14 @@ dependencies:
366
366
  requirements:
367
367
  - - '='
368
368
  - !ruby/object:Gem::Version
369
- version: 0.5.2
369
+ version: 0.6.0
370
370
  type: :development
371
371
  prerelease: false
372
372
  version_requirements: !ruby/object:Gem::Requirement
373
373
  requirements:
374
374
  - - '='
375
375
  - !ruby/object:Gem::Version
376
- version: 0.5.2
376
+ version: 0.6.0
377
377
  - !ruby/object:Gem::Dependency
378
378
  name: guard
379
379
  requirement: !ruby/object:Gem::Requirement
@@ -520,14 +520,14 @@ dependencies:
520
520
  requirements:
521
521
  - - '='
522
522
  - !ruby/object:Gem::Version
523
- version: 1.19.0
523
+ version: 1.20.0
524
524
  type: :development
525
525
  prerelease: false
526
526
  version_requirements: !ruby/object:Gem::Requirement
527
527
  requirements:
528
528
  - - '='
529
529
  - !ruby/object:Gem::Version
530
- version: 1.19.0
530
+ version: 1.20.0
531
531
  - !ruby/object:Gem::Dependency
532
532
  name: rubocop-minitest
533
533
  requirement: !ruby/object:Gem::Requirement
@@ -548,14 +548,14 @@ dependencies:
548
548
  requirements:
549
549
  - - '='
550
550
  - !ruby/object:Gem::Version
551
- version: 1.11.4
551
+ version: 1.11.5
552
552
  type: :development
553
553
  prerelease: false
554
554
  version_requirements: !ruby/object:Gem::Requirement
555
555
  requirements:
556
556
  - - '='
557
557
  - !ruby/object:Gem::Version
558
- version: 1.11.4
558
+ version: 1.11.5
559
559
  - !ruby/object:Gem::Dependency
560
560
  name: rubocop-rake
561
561
  requirement: !ruby/object:Gem::Requirement
@@ -659,6 +659,7 @@ files:
659
659
  - ".docs/duedate_expired.md"
660
660
  - ".docs/propagate_down.md"
661
661
  - ".gitattributes"
662
+ - ".githooks/commit-msg"
662
663
  - ".github/CODE_OF_CONDUCT.md"
663
664
  - ".github/CONTRIBUTING.md"
664
665
  - ".github/ISSUE_TEMPLATE.md"
@@ -710,6 +711,7 @@ files:
710
711
  - lib/lazylead/task/accuracy/has_label.rb
711
712
  - lib/lazylead/task/accuracy/logs.rb
712
713
  - lib/lazylead/task/accuracy/logs_link.rb
714
+ - lib/lazylead/task/accuracy/memes.rb
713
715
  - lib/lazylead/task/accuracy/onlyll.rb
714
716
  - lib/lazylead/task/accuracy/records.rb
715
717
  - lib/lazylead/task/accuracy/records_link.rb
@@ -763,6 +765,7 @@ files:
763
765
  - test/lazylead/model_test.rb
764
766
  - test/lazylead/opts_test.rb
765
767
  - test/lazylead/postman_test.rb
768
+ - test/lazylead/retry_test.rb
766
769
  - test/lazylead/salt_test.rb
767
770
  - test/lazylead/smoke_test.rb
768
771
  - test/lazylead/smtp_test.rb
@@ -774,6 +777,7 @@ files:
774
777
  - test/lazylead/task/accuracy/has_label_test.rb
775
778
  - test/lazylead/task/accuracy/logs_link_test.rb
776
779
  - test/lazylead/task/accuracy/logs_test.rb
780
+ - test/lazylead/task/accuracy/memes_test.rb
777
781
  - test/lazylead/task/accuracy/onlyll_test.rb
778
782
  - test/lazylead/task/accuracy/records_llink_test.rb
779
783
  - test/lazylead/task/accuracy/records_test.rb
@@ -811,7 +815,7 @@ licenses:
811
815
  - MIT
812
816
  metadata: {}
813
817
  post_install_message: |-
814
- Thanks for installing Lazylead v0.10.5!
818
+ Thanks for installing Lazylead v0.11.0!
815
819
  Read our blog posts: https://lazylead.org
816
820
  Stay in touch with the community in Telegram: https://t.me/lazylead
817
821
  Follow us on Twitter: https://twitter.com/lazylead
@@ -844,6 +848,7 @@ test_files:
844
848
  - test/lazylead/model_test.rb
845
849
  - test/lazylead/opts_test.rb
846
850
  - test/lazylead/postman_test.rb
851
+ - test/lazylead/retry_test.rb
847
852
  - test/lazylead/salt_test.rb
848
853
  - test/lazylead/smoke_test.rb
849
854
  - test/lazylead/smtp_test.rb
@@ -855,6 +860,7 @@ test_files:
855
860
  - test/lazylead/task/accuracy/has_label_test.rb
856
861
  - test/lazylead/task/accuracy/logs_link_test.rb
857
862
  - test/lazylead/task/accuracy/logs_test.rb
863
+ - test/lazylead/task/accuracy/memes_test.rb
858
864
  - test/lazylead/task/accuracy/onlyll_test.rb
859
865
  - test/lazylead/task/accuracy/records_llink_test.rb
860
866
  - test/lazylead/task/accuracy/records_test.rb