lazylead 0.10.4 → 0.11.2

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: 59ec5b9c923e07aa0f71bf625df793b8a3451d5e6910d9a77e0785e8922cc55e
4
- data.tar.gz: 81725aa788eb3a69cce4563cbbf9f087e7ea7fe777edc48b4d17691702765039
3
+ metadata.gz: 4a9f540303ac3a6fd834b5d67f63e44fa6a5f7ff3a6fdc7b94886d5313399868
4
+ data.tar.gz: d0c5dc8e810eeaff607d277c7be3a03976c8dad3df99a9aa30ad39dd97fd5934
5
5
  SHA512:
6
- metadata.gz: eed91c6f6228e9c344cca171f7838c17cd38fa4ea83965b08cac8465840430713cae5a37bfc10a49b549bb405b2cea58577b4bfecab427662a1d0be58add495d
7
- data.tar.gz: 0a9ca2d4ea7aa062f623bb342951ae7c0a07dfba16333571d36653886a3da456d6c745aef13510bfb71787ca826c7b908625c7eea8dfaf254734adb10a3ca2fe
6
+ metadata.gz: 05c9ec86d37fb1a0c187db82aecd82df5bbe4f6913064dd67b453662404a87be8328e0a5ff1cab5cf4c7c778b995ef076cebaa4ec8e29ad456f9bfc74a2b0867
7
+ data.tar.gz: f12ed09c28b76276d27de41b7f23b2ebcba36fbd038a4e5154da87f3b1ca1625dd326c987314e91a64f63bf6f3e22d674646c005b5730b66d0edd1087516a169
@@ -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.4"
35
+ s.version = "0.11.2"
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.4!
48
+ s.post_install_message = "Thanks for installing Lazylead v0.11.2!
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"
@@ -66,6 +66,7 @@ tasks instead of solving technical problems."
66
66
  s.add_runtime_dependency "logging", "2.3.0"
67
67
  s.add_runtime_dependency "mail", "2.7.1"
68
68
  s.add_runtime_dependency "memory_profiler", "1.0.0"
69
+ s.add_runtime_dependency "nokogiri", "1.11.3"
69
70
  s.add_runtime_dependency "openssl", "2.1.2"
70
71
  s.add_runtime_dependency "railties", "6.1.3"
71
72
  s.add_runtime_dependency "require_all", "3.0.0"
@@ -79,7 +80,7 @@ tasks instead of solving technical problems."
79
80
  s.add_runtime_dependency "tzinfo-data", "1.2021.1"
80
81
  s.add_runtime_dependency "vcs4sql", "0.1.1"
81
82
  s.add_runtime_dependency "viewpoint", "1.1.1"
82
- s.add_development_dependency "codecov", "0.5.2"
83
+ s.add_development_dependency "codecov", "0.6.0"
83
84
  s.add_development_dependency "guard", "2.18.0"
84
85
  s.add_development_dependency "guard-minitest", "2.4.6"
85
86
  s.add_development_dependency "minitest", "5.14.4"
@@ -90,12 +91,12 @@ tasks instead of solving technical problems."
90
91
  s.add_development_dependency "rake", "13.0.6"
91
92
  s.add_development_dependency "random-port", "0.5.1"
92
93
  s.add_development_dependency "rdoc", "6.3.2"
93
- s.add_development_dependency "rubocop", "1.18.4"
94
+ s.add_development_dependency "rubocop", "1.21.0"
94
95
  s.add_development_dependency "rubocop-minitest", "0.15.0"
95
- s.add_development_dependency "rubocop-performance", "1.11.4"
96
+ s.add_development_dependency "rubocop-performance", "1.11.5"
96
97
  s.add_development_dependency "rubocop-rake", "0.6.0"
97
98
  s.add_development_dependency "rubocop-rspec", "2.4.0"
98
99
  s.add_development_dependency "sqlint", "0.2.0"
99
100
  s.add_development_dependency "tempfile", "0.1.1"
100
- s.add_development_dependency "xcop", "0.6.2"
101
+ s.add_development_dependency "xcop", "0.6.3"
101
102
  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::Verbose.new(
54
+ ORM::Retry.new(task, @log),
55
+ @log
56
+ ).exec
54
57
  end
55
58
  end
56
59
  end
@@ -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,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?
54
+ opts
55
+ end
56
+
57
+ # Initialize accuracy rules and configuration for tickets verification.
58
+ def init_rules(opts)
59
+ Requires.new(__dir__).load
60
+ opts[:rules] = opts.construct("rules")
61
+ opts[:total] = opts[:rules].sum(&:score)
62
+ opts[:memes] = Memes.new(opts["memes"])
55
63
  end
56
64
  end
57
65
  end
@@ -93,7 +101,7 @@ module Lazylead
93
101
  comment << "|#{r.desc}|#{r.passed(@issue) ? '(/)' : '(-)'}|#{r.field}|"
94
102
  end
95
103
  comment << docs_link
96
- comment << ""
104
+ comment << reaction
97
105
  comment << "Posted by [lazylead v#{Lazylead::VERSION}|https://bit.ly/2NjdndS]."
98
106
  comment.join("\r\n")
99
107
  end
@@ -144,5 +152,26 @@ module Lazylead
144
152
  return @issue.reporter.id if first.nil?
145
153
  first["author"]["key"]
146
154
  end
155
+
156
+ # Add reaction meme to the ticket comment based on score.
157
+ # The meme details are represented as array, where each element is a separate line in future
158
+ # comment in jira.
159
+ #
160
+ # @todo #339/DEV Seems jira doesn't support the rendering of external images by url, thus so far
161
+ # we might have several options:
162
+ # - attach meme to ticket and make rendering using [^attach.jpg!thumbnail] option
163
+ # - have a link to meme (like it implemented now)
164
+ # The 1st option with attachment might generate multiple events in jira and spam ticket
165
+ # watchers, thus, some research & UX testing needed how to make it better.
166
+ def reaction
167
+ return [] if @opts[:memes].nil? && !@opts[:memes].enabled?
168
+ url = @opts[:memes].find(@accuracy)
169
+ return [] if url.blank?
170
+ [
171
+ "",
172
+ "Our reaction when we got the ticket with triage accuracy #{@accuracy}% is [here|#{url}].",
173
+ ""
174
+ ]
175
+ end
147
176
  end
148
177
  end
@@ -0,0 +1,48 @@
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 "requirement"
26
+
27
+ module Lazylead
28
+ # Check that ticket has specified label.
29
+ class HasLabel < Lazylead::Requirement
30
+ #
31
+ # @param label which should be present in ticket.
32
+ #
33
+ def initialize(label, desc: "Has label", score: 0.5)
34
+ super(desc, score, "Labels")
35
+ @label = label
36
+ end
37
+
38
+ def passed(issue)
39
+ return false if issue.labels.empty?
40
+ issue.labels.any? { |l| match?(l) }
41
+ end
42
+
43
+ # Ensure that particular label matches expected label.
44
+ def match?(label)
45
+ @label.eql? label
46
+ end
47
+ end
48
+ 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]
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.4"
26
+ VERSION = "0.11.2"
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
@@ -143,7 +143,7 @@ module Lazylead
143
143
  end
144
144
 
145
145
  test "description is correct" do
146
- assert_words %w[DATACMNS-1639\ moved\ entity\ instantiators],
146
+ assert_words ["DATACMNS-1639 moved entity instantiators"],
147
147
  NoAuthJira.new("https://jira.spring.io")
148
148
  .issues("key=DATAJDBC-480")
149
149
  .first
@@ -151,7 +151,7 @@ module Lazylead
151
151
  end
152
152
 
153
153
  test "component is correct" do
154
- assert_equal %w[Stream\ Module],
154
+ assert_equal ["Stream Module"],
155
155
  NoAuthJira.new("https://jira.spring.io")
156
156
  .issues("key=XD-3766")
157
157
  .first
@@ -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,54 @@
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/has_label"
27
+
28
+ module Lazylead
29
+ class HasLabelTest < Lazylead::Test
30
+ test "label is present" do
31
+ assert HasLabel.new("Invalid_Reopen").passed(
32
+ OpenStruct.new(
33
+ labels: %w[Invalid_Reopen 10%]
34
+ )
35
+ )
36
+ end
37
+
38
+ test "label is absent" do
39
+ refute HasLabel.new("Invalid_Reopen").passed(
40
+ OpenStruct.new(
41
+ labels: %w[E2E top_priority 10%]
42
+ )
43
+ )
44
+ end
45
+
46
+ test "labels are absent in ticket" do
47
+ refute HasLabel.new("Invalid_Reopen").passed(
48
+ OpenStruct.new(
49
+ labels: []
50
+ )
51
+ )
52
+ end
53
+ end
54
+ 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(
@@ -55,7 +55,7 @@ module Lazylead
55
55
  )
56
56
  )
57
57
  assert_email "[SVN] Important files have been changed!",
58
- %w[3 dgroup /189.md Add\ description\ for\ 189\ issue]
58
+ ["3", "dgroup", "/189.md", "Add description for 189 issue"]
59
59
  end
60
60
  end
61
61
  end
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.4
4
+ version: 0.11.2
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-09 00:00:00.000000000 Z
11
+ date: 2021-09-15 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
@@ -164,6 +164,20 @@ dependencies:
164
164
  - - '='
165
165
  - !ruby/object:Gem::Version
166
166
  version: 1.0.0
167
+ - !ruby/object:Gem::Dependency
168
+ name: nokogiri
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - '='
172
+ - !ruby/object:Gem::Version
173
+ version: 1.11.3
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - '='
179
+ - !ruby/object:Gem::Version
180
+ version: 1.11.3
167
181
  - !ruby/object:Gem::Dependency
168
182
  name: openssl
169
183
  requirement: !ruby/object:Gem::Requirement
@@ -352,14 +366,14 @@ dependencies:
352
366
  requirements:
353
367
  - - '='
354
368
  - !ruby/object:Gem::Version
355
- version: 0.5.2
369
+ version: 0.6.0
356
370
  type: :development
357
371
  prerelease: false
358
372
  version_requirements: !ruby/object:Gem::Requirement
359
373
  requirements:
360
374
  - - '='
361
375
  - !ruby/object:Gem::Version
362
- version: 0.5.2
376
+ version: 0.6.0
363
377
  - !ruby/object:Gem::Dependency
364
378
  name: guard
365
379
  requirement: !ruby/object:Gem::Requirement
@@ -506,14 +520,14 @@ dependencies:
506
520
  requirements:
507
521
  - - '='
508
522
  - !ruby/object:Gem::Version
509
- version: 1.18.4
523
+ version: 1.21.0
510
524
  type: :development
511
525
  prerelease: false
512
526
  version_requirements: !ruby/object:Gem::Requirement
513
527
  requirements:
514
528
  - - '='
515
529
  - !ruby/object:Gem::Version
516
- version: 1.18.4
530
+ version: 1.21.0
517
531
  - !ruby/object:Gem::Dependency
518
532
  name: rubocop-minitest
519
533
  requirement: !ruby/object:Gem::Requirement
@@ -534,14 +548,14 @@ dependencies:
534
548
  requirements:
535
549
  - - '='
536
550
  - !ruby/object:Gem::Version
537
- version: 1.11.4
551
+ version: 1.11.5
538
552
  type: :development
539
553
  prerelease: false
540
554
  version_requirements: !ruby/object:Gem::Requirement
541
555
  requirements:
542
556
  - - '='
543
557
  - !ruby/object:Gem::Version
544
- version: 1.11.4
558
+ version: 1.11.5
545
559
  - !ruby/object:Gem::Dependency
546
560
  name: rubocop-rake
547
561
  requirement: !ruby/object:Gem::Requirement
@@ -604,14 +618,14 @@ dependencies:
604
618
  requirements:
605
619
  - - '='
606
620
  - !ruby/object:Gem::Version
607
- version: 0.6.2
621
+ version: 0.6.3
608
622
  type: :development
609
623
  prerelease: false
610
624
  version_requirements: !ruby/object:Gem::Requirement
611
625
  requirements:
612
626
  - - '='
613
627
  - !ruby/object:Gem::Version
614
- version: 0.6.2
628
+ version: 0.6.3
615
629
  description: |-
616
630
  Ticketing systems (Github, Jira, etc.) are strongly
617
631
  integrated into our processes and everyone understands their necessity. As soon
@@ -645,6 +659,7 @@ files:
645
659
  - ".docs/duedate_expired.md"
646
660
  - ".docs/propagate_down.md"
647
661
  - ".gitattributes"
662
+ - ".githooks/commit-msg"
648
663
  - ".github/CODE_OF_CONDUCT.md"
649
664
  - ".github/CONTRIBUTING.md"
650
665
  - ".github/ISSUE_TEMPLATE.md"
@@ -693,8 +708,10 @@ files:
693
708
  - lib/lazylead/task/accuracy/affected_build.rb
694
709
  - lib/lazylead/task/accuracy/attachment.rb
695
710
  - lib/lazylead/task/accuracy/environment.rb
711
+ - lib/lazylead/task/accuracy/has_label.rb
696
712
  - lib/lazylead/task/accuracy/logs.rb
697
713
  - lib/lazylead/task/accuracy/logs_link.rb
714
+ - lib/lazylead/task/accuracy/memes.rb
698
715
  - lib/lazylead/task/accuracy/onlyll.rb
699
716
  - lib/lazylead/task/accuracy/records.rb
700
717
  - lib/lazylead/task/accuracy/records_link.rb
@@ -748,6 +765,7 @@ files:
748
765
  - test/lazylead/model_test.rb
749
766
  - test/lazylead/opts_test.rb
750
767
  - test/lazylead/postman_test.rb
768
+ - test/lazylead/retry_test.rb
751
769
  - test/lazylead/salt_test.rb
752
770
  - test/lazylead/smoke_test.rb
753
771
  - test/lazylead/smtp_test.rb
@@ -756,8 +774,10 @@ files:
756
774
  - test/lazylead/task/accuracy/affected_build_test.rb
757
775
  - test/lazylead/task/accuracy/attachment_test.rb
758
776
  - test/lazylead/task/accuracy/environment_test.rb
777
+ - test/lazylead/task/accuracy/has_label_test.rb
759
778
  - test/lazylead/task/accuracy/logs_link_test.rb
760
779
  - test/lazylead/task/accuracy/logs_test.rb
780
+ - test/lazylead/task/accuracy/memes_test.rb
761
781
  - test/lazylead/task/accuracy/onlyll_test.rb
762
782
  - test/lazylead/task/accuracy/records_llink_test.rb
763
783
  - test/lazylead/task/accuracy/records_test.rb
@@ -795,7 +815,7 @@ licenses:
795
815
  - MIT
796
816
  metadata: {}
797
817
  post_install_message: |-
798
- Thanks for installing Lazylead v0.10.4!
818
+ Thanks for installing Lazylead v0.11.2!
799
819
  Read our blog posts: https://lazylead.org
800
820
  Stay in touch with the community in Telegram: https://t.me/lazylead
801
821
  Follow us on Twitter: https://twitter.com/lazylead
@@ -828,6 +848,7 @@ test_files:
828
848
  - test/lazylead/model_test.rb
829
849
  - test/lazylead/opts_test.rb
830
850
  - test/lazylead/postman_test.rb
851
+ - test/lazylead/retry_test.rb
831
852
  - test/lazylead/salt_test.rb
832
853
  - test/lazylead/smoke_test.rb
833
854
  - test/lazylead/smtp_test.rb
@@ -836,8 +857,10 @@ test_files:
836
857
  - test/lazylead/task/accuracy/affected_build_test.rb
837
858
  - test/lazylead/task/accuracy/attachment_test.rb
838
859
  - test/lazylead/task/accuracy/environment_test.rb
860
+ - test/lazylead/task/accuracy/has_label_test.rb
839
861
  - test/lazylead/task/accuracy/logs_link_test.rb
840
862
  - test/lazylead/task/accuracy/logs_test.rb
863
+ - test/lazylead/task/accuracy/memes_test.rb
841
864
  - test/lazylead/task/accuracy/onlyll_test.rb
842
865
  - test/lazylead/task/accuracy/records_llink_test.rb
843
866
  - test/lazylead/task/accuracy/records_test.rb