lazylead 0.10.5 → 0.11.3

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: 85f4a0cb192b81550bc11f25d2b284e51ba3437726f72bcf5b1d13d5b8e1560f
4
+ data.tar.gz: 2740b477357205bb40195e72b4fbd503a30c5c0ae8a729b4bbae4a2b27e7d6e4
5
5
  SHA512:
6
- metadata.gz: 58f54eb88f268b67c48ac5867502637767fb0cb27cbfaf0b6b3edd0b0119774c0fde9d78408b4e81243b279eec1fc9a18c970dfd37bc344f0654fd653ed59709
7
- data.tar.gz: 131a15331350d5869187b2e8f8546715434138fc66b0d711a6a882a5292bc5937ac44e060f2a6a233dcbd098cef8e568af592ecd85d0c1b8c3f4965ddd8ac9c4
6
+ metadata.gz: ce207ea7736acab2e0221ef5f09c6f887e1b6d761167f5fa878553f7de0132856d79d647464e90bba21b619d9a33df869af6b4d0016ea00836628acc53a8ba47
7
+ data.tar.gz: 3a9568ea019e7167a80dfb88d1d202f7de64996d4e9dd2091dd08f0cc5a76b3d46195d7ef0ba5232baa0cf92cbaa0f61f36e3138f8a452bb2277d8c7b34d11a8
@@ -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.3"
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.3!
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.2"
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,12 +91,13 @@ 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.21.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
+ s.add_development_dependency "ruby-prof", "1.4.3"
99
100
  s.add_development_dependency "sqlint", "0.2.0"
100
101
  s.add_development_dependency "tempfile", "0.1.1"
101
- s.add_development_dependency "xcop", "0.6.2"
102
+ s.add_development_dependency "xcop", "0.6.3"
102
103
  end
@@ -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
@@ -64,7 +64,8 @@ module Lazylead
64
64
  def jira_defaults
65
65
  {
66
66
  max_results: fetch("max_results", 50),
67
- fields: jira_fields
67
+ fields: jira_fields,
68
+ limit: to_h["limit"]
68
69
  }
69
70
  end
70
71
 
@@ -142,5 +143,16 @@ module Lazylead
142
143
  def construct(field, delim: ",")
143
144
  slice(field, delim).map(&:constantize).map(&:new)
144
145
  end
146
+
147
+ # Get the value by key
148
+ # @param key
149
+ # The key to fetch value. The key might be a plain text or symbol
150
+ # @param default
151
+ # The default/alternative value if key not found
152
+ # @return The value by key or alternative/default value.
153
+ def find(key, default = nil)
154
+ return default if key.nil?
155
+ to_h[key.to_s] || to_h[key.to_sym] || default
156
+ end
145
157
  end
146
158
  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::Retry.new(
54
+ ORM::Verbose.new(task, @log),
55
+ @log
56
+ ).exec
54
57
  end
55
58
  end
56
59
  end
@@ -0,0 +1,23 @@
1
+ ## Enable profiler
2
+ ```ruby
3
+ require 'ruby-prof'
4
+ alloc = RubyProf.profile(:track_allocations => true) do
5
+ # code
6
+ end
7
+ printer = RubyProf::MultiPrinter.new(alloc)
8
+ printer.print(:path => ".", :profile => "alloc")
9
+ ```
10
+
11
+ ## Jira allocation memory
12
+ Fields: `assignee,summary,priority,duedate,reporter`
13
+
14
+ | Tickets | Bytes | KB | MB |
15
+ | ------------- | :-------: | :-------: | :-------: |
16
+ | 1 | 40 | 0.03 | 0,00003 |
17
+ | 157 | 6280 | 6.13 | 0.59 |
18
+ | 4315 | 172600 | 168.55 | 0.16 |
19
+ | 10379 | 415160 | 405.42 | 0.39 |
20
+ |~10000 | ~400000 | ~390.625 | ~0.38 |
21
+
22
+ ## GitHub allocation memory
23
+ TBD
@@ -57,17 +57,18 @@ 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 = []
63
64
  total = jira.Issue.jql(jql, max_results: 0)
64
65
  @log.debug "Found #{total} ticket(s) in '#{jql}'"
65
66
  loop do
66
- tickets.concat(jira.Issue.jql(jql, opts.merge(start_at: start))
67
+ tickets.concat(jira.Issue.jql(jql, range(start, opts))
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).to_i
71
+ break if (start > total) || (start >= opts.find(:limit, total).to_i)
71
72
  end
72
73
  tickets
73
74
  end
@@ -82,6 +83,26 @@ module Lazylead
82
83
 
83
84
  private
84
85
 
86
+ # Detect tickets range in remote search result.
87
+ #
88
+ # In jira you may navigate through the search result using following parameters:
89
+ # https://docs.atlassian.com/jira-software/REST/7.3.1/#agile/1.0/epic-getIssuesForEpic
90
+ # :start_at
91
+ # The starting index of the returned issues. Base index: 0. See the 'Pagination' section at
92
+ # the top of this page for more details.
93
+ # :max_results
94
+ # The maximum number of issues to return per page. Default: 50. See the 'Pagination' section
95
+ # at the top of this page for more details. Note, the total number of issues returned is
96
+ # limited by the property 'jira.search.views.default.max' in your JIRA instance. If you
97
+ # exceed this limit, your results will be truncated.
98
+ def range(start, opts)
99
+ limit = opts.find(:limit, 0).to_i
100
+ max_results = opts.find(:max_results, 50).to_i
101
+ opts[:start_at] = start
102
+ opts[:max_results] = [limit, max_results].min if limit.positive?
103
+ opts
104
+ end
105
+
85
106
  def client
86
107
  return @client if defined? @client
87
108
  @opts[:auth_type] = :basic if @opts[:auth_type].nil?
@@ -326,7 +347,7 @@ module Lazylead
326
347
  # or dashboards.
327
348
  class NoAuthJira
328
349
  extend Forwardable
329
- def_delegators :@jira, :issues, :raw
350
+ def_delegators :@jira, :issues, :raw, :max_results, :limit
330
351
 
331
352
  def initialize(url, path = "", log = Log.new)
332
353
  @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,14 +45,26 @@ module Lazylead
44
45
  end
45
46
 
46
47
  def run(sys, postman, opts)
48
+ init_rules(opts)
49
+ tasks = sys.issues(opts["jql"], opts.jira_defaults.merge(expand: "changelog"))
50
+ .map { |i| Score.new(i, opts) }
51
+ .each do |s|
52
+ s.evaluate
53
+ s.post
54
+ end
55
+ unless tasks.empty? && tasks.size <= opts.fetch(:limit, 300).to_i
56
+ opts[:tickets] = tasks
57
+ postman.send(opts)
58
+ end
59
+ opts
60
+ end
61
+
62
+ # Initialize accuracy rules and configuration for tickets verification.
63
+ def init_rules(opts)
47
64
  Requires.new(__dir__).load
48
65
  opts[:rules] = opts.construct("rules")
49
66
  opts[:total] = opts[:rules].sum(&:score)
50
- opts[:tickets] = sys.issues(opts["jql"], opts.jira_defaults.merge(expand: "changelog"))
51
- .map { |i| Score.new(i, opts) }
52
- .each(&:evaluate)
53
- .each(&:post)
54
- postman.send(opts) unless opts[:tickets].empty?
67
+ opts[:memes] = Memes.new(opts["memes"])
55
68
  end
56
69
  end
57
70
  end
@@ -93,7 +106,7 @@ module Lazylead
93
106
  comment << "|#{r.desc}|#{r.passed(@issue) ? '(/)' : '(-)'}|#{r.field}|"
94
107
  end
95
108
  comment << docs_link
96
- comment << ""
109
+ comment << reaction
97
110
  comment << "Posted by [lazylead v#{Lazylead::VERSION}|https://bit.ly/2NjdndS]."
98
111
  comment.join("\r\n")
99
112
  end
@@ -144,5 +157,26 @@ module Lazylead
144
157
  return @issue.reporter.id if first.nil?
145
158
  first["author"]["key"]
146
159
  end
160
+
161
+ # Add reaction meme to the ticket comment based on score.
162
+ # The meme details are represented as array, where each element is a separate line in future
163
+ # comment in jira.
164
+ #
165
+ # @todo #339/DEV Seems jira doesn't support the rendering of external images by url, thus so far
166
+ # we might have several options:
167
+ # - attach meme to ticket and make rendering using [^attach.jpg!thumbnail] option
168
+ # - have a link to meme (like it implemented now)
169
+ # The 1st option with attachment might generate multiple events in jira and spam ticket
170
+ # watchers, thus, some research & UX testing needed how to make it better.
171
+ def reaction
172
+ return [] if @opts[:memes].nil? && !@opts[:memes].enabled?
173
+ url = @opts[:memes].find(@accuracy)
174
+ return [] if url.blank?
175
+ [
176
+ "",
177
+ "Our reaction when we got the ticket with triage accuracy #{@accuracy}% is [here|#{url}].",
178
+ ""
179
+ ]
180
+ end
147
181
  end
148
182
  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
@@ -34,12 +34,14 @@ module Lazylead
34
34
  @ext = %w[.webm .mkv .flv .flv .vob .ogv .ogg .drc .gif .gifv .mng .avi
35
35
  .mts .m2ts .ts .mov .qt .wmv .yuv .rm .rmvb .viv .asf .amv .mp4
36
36
  .m4p .m4v .mpg .mp2 .mpeg .mpe .mpv .mpg .mpeg .m2v .m4v .svi
37
- .3gp .3g2 .mxf .roq .nsv .flv .f4v .f4p .f4a .f4b .gif]
37
+ .3gp .3g2 .mxf .roq .nsv .flv .f4v .f4p .f4a .f4b .wrf]
38
38
  end
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"].end_with? "/#{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
 
@@ -51,7 +51,7 @@ module Lazylead
51
51
  private
52
52
 
53
53
  def less_mb(path, megabytes)
54
- (File.size(path).to_f / 2**20).round(2) < megabytes.to_i
54
+ (File.size(path).to_f / (2**20)).round(2) < megabytes.to_i
55
55
  end
56
56
  end
57
57
  end
@@ -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.3"
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,
@@ -69,5 +74,28 @@ module Lazylead
69
74
  assert_kind_of Lazylead::Task::Accuracy,
70
75
  ORM::Task.find(195).action.constantize.new
71
76
  end
77
+
78
+ test "one ticket found" do
79
+ Lazylead::Smtp.new.enable
80
+ assert_equal 1,
81
+ Task::Accuracy.new.run(
82
+ NoAuthJira.new("https://jira.spring.io"),
83
+ Postman.new,
84
+ Opts.new(
85
+ "from" => "ll@fake.com",
86
+ "to" => "lead@fake.com",
87
+ "rules" => "Lazylead::AffectedBuild",
88
+ "silent" => "true",
89
+ "colors" => {
90
+ "0" => "#FF4F33",
91
+ "57" => "#19DD1E"
92
+ }.to_json.to_s,
93
+ "jql" => "key > DATAJDBC-490",
94
+ "limit" => "1",
95
+ "subject" => "[LL] Raised tickets",
96
+ "template" => "lib/messages/accuracy.erb"
97
+ )
98
+ )[:tickets].size
99
+ end
72
100
  end
73
101
  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_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,35 @@ 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
75
+
76
+ test "mime type is xlsx" do
77
+ refute Records.new.passed(
78
+ OpenStruct.new(
79
+ attachments: [
80
+ OpenStruct.new(
81
+ attrs: {
82
+ "filename" => "snapshot.xlsx",
83
+ "mimeType" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
84
+ }
85
+ )
86
+ ]
87
+ )
88
+ )
89
+ end
59
90
  end
60
91
  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.3
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-19 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.2
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.2
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.21.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.21.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
@@ -584,6 +584,20 @@ dependencies:
584
584
  - - '='
585
585
  - !ruby/object:Gem::Version
586
586
  version: 2.4.0
587
+ - !ruby/object:Gem::Dependency
588
+ name: ruby-prof
589
+ requirement: !ruby/object:Gem::Requirement
590
+ requirements:
591
+ - - '='
592
+ - !ruby/object:Gem::Version
593
+ version: 1.4.3
594
+ type: :development
595
+ prerelease: false
596
+ version_requirements: !ruby/object:Gem::Requirement
597
+ requirements:
598
+ - - '='
599
+ - !ruby/object:Gem::Version
600
+ version: 1.4.3
587
601
  - !ruby/object:Gem::Dependency
588
602
  name: sqlint
589
603
  requirement: !ruby/object:Gem::Requirement
@@ -618,14 +632,14 @@ dependencies:
618
632
  requirements:
619
633
  - - '='
620
634
  - !ruby/object:Gem::Version
621
- version: 0.6.2
635
+ version: 0.6.3
622
636
  type: :development
623
637
  prerelease: false
624
638
  version_requirements: !ruby/object:Gem::Requirement
625
639
  requirements:
626
640
  - - '='
627
641
  - !ruby/object:Gem::Version
628
- version: 0.6.2
642
+ version: 0.6.3
629
643
  description: |-
630
644
  Ticketing systems (Github, Jira, etc.) are strongly
631
645
  integrated into our processes and everyone understands their necessity. As soon
@@ -659,6 +673,7 @@ files:
659
673
  - ".docs/duedate_expired.md"
660
674
  - ".docs/propagate_down.md"
661
675
  - ".gitattributes"
676
+ - ".githooks/commit-msg"
662
677
  - ".github/CODE_OF_CONDUCT.md"
663
678
  - ".github/CONTRIBUTING.md"
664
679
  - ".github/ISSUE_TEMPLATE.md"
@@ -699,6 +714,7 @@ files:
699
714
  - lib/lazylead/salt.rb
700
715
  - lib/lazylead/schedule.rb
701
716
  - lib/lazylead/smtp.rb
717
+ - lib/lazylead/system/allocations.md
702
718
  - lib/lazylead/system/empty.rb
703
719
  - lib/lazylead/system/fake.rb
704
720
  - lib/lazylead/system/jira.rb
@@ -710,6 +726,7 @@ files:
710
726
  - lib/lazylead/task/accuracy/has_label.rb
711
727
  - lib/lazylead/task/accuracy/logs.rb
712
728
  - lib/lazylead/task/accuracy/logs_link.rb
729
+ - lib/lazylead/task/accuracy/memes.rb
713
730
  - lib/lazylead/task/accuracy/onlyll.rb
714
731
  - lib/lazylead/task/accuracy/records.rb
715
732
  - lib/lazylead/task/accuracy/records_link.rb
@@ -763,6 +780,7 @@ files:
763
780
  - test/lazylead/model_test.rb
764
781
  - test/lazylead/opts_test.rb
765
782
  - test/lazylead/postman_test.rb
783
+ - test/lazylead/retry_test.rb
766
784
  - test/lazylead/salt_test.rb
767
785
  - test/lazylead/smoke_test.rb
768
786
  - test/lazylead/smtp_test.rb
@@ -774,6 +792,7 @@ files:
774
792
  - test/lazylead/task/accuracy/has_label_test.rb
775
793
  - test/lazylead/task/accuracy/logs_link_test.rb
776
794
  - test/lazylead/task/accuracy/logs_test.rb
795
+ - test/lazylead/task/accuracy/memes_test.rb
777
796
  - test/lazylead/task/accuracy/onlyll_test.rb
778
797
  - test/lazylead/task/accuracy/records_llink_test.rb
779
798
  - test/lazylead/task/accuracy/records_test.rb
@@ -811,7 +830,7 @@ licenses:
811
830
  - MIT
812
831
  metadata: {}
813
832
  post_install_message: |-
814
- Thanks for installing Lazylead v0.10.5!
833
+ Thanks for installing Lazylead v0.11.3!
815
834
  Read our blog posts: https://lazylead.org
816
835
  Stay in touch with the community in Telegram: https://t.me/lazylead
817
836
  Follow us on Twitter: https://twitter.com/lazylead
@@ -844,6 +863,7 @@ test_files:
844
863
  - test/lazylead/model_test.rb
845
864
  - test/lazylead/opts_test.rb
846
865
  - test/lazylead/postman_test.rb
866
+ - test/lazylead/retry_test.rb
847
867
  - test/lazylead/salt_test.rb
848
868
  - test/lazylead/smoke_test.rb
849
869
  - test/lazylead/smtp_test.rb
@@ -855,6 +875,7 @@ test_files:
855
875
  - test/lazylead/task/accuracy/has_label_test.rb
856
876
  - test/lazylead/task/accuracy/logs_link_test.rb
857
877
  - test/lazylead/task/accuracy/logs_test.rb
878
+ - test/lazylead/task/accuracy/memes_test.rb
858
879
  - test/lazylead/task/accuracy/onlyll_test.rb
859
880
  - test/lazylead/task/accuracy/records_llink_test.rb
860
881
  - test/lazylead/task/accuracy/records_test.rb