lazylead 0.7.1 → 0.8.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/.docs/duedate_expired.md +1 -1
  3. data/.rubocop.yml +19 -3
  4. data/Gemfile +1 -1
  5. data/Rakefile +1 -1
  6. data/bin/lazylead +1 -1
  7. data/lazylead.gemspec +17 -16
  8. data/lib/lazylead.rb +2 -2
  9. data/lib/lazylead/allocated.rb +1 -1
  10. data/lib/lazylead/cc.rb +17 -23
  11. data/lib/lazylead/cli/app.rb +1 -1
  12. data/lib/lazylead/confluence.rb +1 -1
  13. data/lib/lazylead/email.rb +1 -1
  14. data/lib/lazylead/exchange.rb +1 -1
  15. data/lib/lazylead/home.rb +1 -1
  16. data/lib/lazylead/log.rb +1 -1
  17. data/lib/lazylead/model.rb +6 -8
  18. data/lib/lazylead/opts.rb +6 -3
  19. data/lib/lazylead/postman.rb +1 -1
  20. data/{Guardfile → lib/lazylead/requires.rb} +13 -8
  21. data/lib/lazylead/salt.rb +1 -1
  22. data/lib/lazylead/schedule.rb +1 -1
  23. data/lib/lazylead/smtp.rb +1 -1
  24. data/lib/lazylead/system/empty.rb +1 -1
  25. data/lib/lazylead/system/fake.rb +1 -1
  26. data/lib/lazylead/system/jira.rb +20 -18
  27. data/lib/lazylead/system/synced.rb +1 -1
  28. data/lib/lazylead/task/accuracy/accuracy.rb +37 -29
  29. data/lib/lazylead/task/accuracy/affected_build.rb +1 -1
  30. data/lib/lazylead/task/accuracy/attachment.rb +1 -1
  31. data/lib/lazylead/task/accuracy/environment.rb +1 -1
  32. data/lib/lazylead/task/accuracy/logs.rb +5 -2
  33. data/lib/lazylead/task/accuracy/onlyll.rb +6 -8
  34. data/lib/lazylead/task/accuracy/records.rb +1 -1
  35. data/lib/lazylead/task/accuracy/requirement.rb +1 -1
  36. data/lib/lazylead/task/accuracy/screenshots.rb +60 -0
  37. data/lib/lazylead/task/accuracy/servers.rb +1 -1
  38. data/lib/lazylead/task/accuracy/stacktrace.rb +1 -1
  39. data/lib/lazylead/task/accuracy/testcase.rb +3 -3
  40. data/lib/lazylead/task/accuracy/wiki.rb +1 -1
  41. data/lib/lazylead/task/{alert.rb → alert/alert.rb} +6 -6
  42. data/lib/lazylead/task/alert/alertif.rb +75 -0
  43. data/lib/lazylead/task/alert/changed_to.rb +58 -0
  44. data/lib/lazylead/task/assignment.rb +1 -1
  45. data/lib/lazylead/task/confluence_ref.rb +1 -1
  46. data/lib/lazylead/task/echo.rb +1 -1
  47. data/lib/lazylead/task/fix_version.rb +1 -1
  48. data/lib/lazylead/task/loading.rb +94 -0
  49. data/lib/lazylead/task/missing_comment.rb +1 -1
  50. data/lib/lazylead/task/propagate_down.rb +3 -3
  51. data/lib/lazylead/task/savepoint.rb +1 -1
  52. data/lib/lazylead/task/svn/diff.rb +29 -7
  53. data/lib/lazylead/task/svn/grep.rb +1 -1
  54. data/lib/lazylead/task/svn/touch.rb +1 -1
  55. data/lib/lazylead/version.rb +2 -2
  56. data/lib/messages/accuracy.erb +1 -1
  57. data/lib/messages/alertif.erb +134 -0
  58. data/lib/messages/created_recently.erb +110 -0
  59. data/lib/messages/loading.erb +117 -0
  60. data/readme.md +26 -18
  61. data/test/lazylead/allocated_test.rb +1 -1
  62. data/test/lazylead/cc_test.rb +1 -1
  63. data/test/lazylead/cli/app_test.rb +2 -2
  64. data/test/lazylead/confluence_test.rb +1 -1
  65. data/test/lazylead/exchange_test.rb +1 -1
  66. data/test/lazylead/model_test.rb +1 -1
  67. data/test/lazylead/opts_test.rb +1 -1
  68. data/test/lazylead/postman_test.rb +1 -1
  69. data/test/lazylead/salt_test.rb +1 -1
  70. data/test/lazylead/smoke_test.rb +1 -1
  71. data/test/lazylead/smtp_test.rb +1 -1
  72. data/test/lazylead/system/jira_test.rb +10 -1
  73. data/test/lazylead/task/accuracy/accuracy_test.rb +1 -1
  74. data/test/lazylead/task/accuracy/affected_build_test.rb +1 -1
  75. data/test/lazylead/task/accuracy/attachment_test.rb +1 -1
  76. data/test/lazylead/task/accuracy/environment_test.rb +1 -1
  77. data/test/lazylead/task/accuracy/logs_test.rb +13 -1
  78. data/test/lazylead/task/accuracy/onlyll_test.rb +1 -1
  79. data/test/lazylead/task/accuracy/records_test.rb +1 -1
  80. data/test/lazylead/task/accuracy/score_test.rb +40 -2
  81. data/test/lazylead/task/accuracy/screenshots_test.rb +126 -0
  82. data/test/lazylead/task/accuracy/servers_test.rb +1 -1
  83. data/test/lazylead/task/accuracy/stacktrace_test.rb +1 -1
  84. data/test/lazylead/task/accuracy/testcase_test.rb +28 -1
  85. data/test/lazylead/task/accuracy/wiki_test.rb +1 -1
  86. data/test/lazylead/task/alert/alertif_test.rb +54 -0
  87. data/test/lazylead/task/{assignee_alert_test.rb → alert/assignee_alert_test.rb} +10 -10
  88. data/test/lazylead/task/alert/changed_to_test.rb +42 -0
  89. data/test/lazylead/task/assignment_test.rb +1 -1
  90. data/test/lazylead/task/confluence_ref_test.rb +1 -1
  91. data/test/lazylead/task/created_recently_test.rb +53 -0
  92. data/test/lazylead/task/duedate_test.rb +2 -2
  93. data/test/lazylead/task/echo_test.rb +1 -1
  94. data/test/lazylead/task/fix_version_test.rb +1 -1
  95. data/test/lazylead/task/loading_test.rb +54 -0
  96. data/test/lazylead/task/missing_comment_test.rb +1 -1
  97. data/test/lazylead/task/propagate_down_test.rb +1 -1
  98. data/test/lazylead/task/savepoint_test.rb +1 -1
  99. data/test/lazylead/task/svn/diff_test.rb +8 -4
  100. data/test/lazylead/task/svn/grep_test.rb +1 -1
  101. data/test/lazylead/task/svn/touch_test.rb +1 -1
  102. data/test/lazylead/version_test.rb +1 -1
  103. data/test/sqlite_test.rb +1 -1
  104. data/test/test.rb +13 -1
  105. data/upgrades/sqlite/001-install-main-lazylead-tables.sql +1 -1
  106. data/upgrades/sqlite/999.testdata.sql +1 -1
  107. metadata +64 -33
data/lib/lazylead/salt.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # The MIT License
4
4
  #
5
- # Copyright (c) 2019-2020 Yurii Dubinka
5
+ # Copyright (c) 2019-2021 Yurii Dubinka
6
6
  #
7
7
  # Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  # of this software and associated documentation files (the "Software"),
@@ -2,7 +2,7 @@
2
2
 
3
3
  # The MIT License
4
4
  #
5
- # Copyright (c) 2019-2020 Yurii Dubinka
5
+ # Copyright (c) 2019-2021 Yurii Dubinka
6
6
  #
7
7
  # Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  # of this software and associated documentation files (the "Software"),
data/lib/lazylead/smtp.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # The MIT License
4
4
  #
5
- # Copyright (c) 2019-2020 Yurii Dubinka
5
+ # Copyright (c) 2019-2021 Yurii Dubinka
6
6
  #
7
7
  # Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  # of this software and associated documentation files (the "Software"),
@@ -2,7 +2,7 @@
2
2
 
3
3
  # The MIT License
4
4
  #
5
- # Copyright (c) 2019-2020 Yurii Dubinka
5
+ # Copyright (c) 2019-2021 Yurii Dubinka
6
6
  #
7
7
  # Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  # of this software and associated documentation files (the "Software"),
@@ -2,7 +2,7 @@
2
2
 
3
3
  # The MIT License
4
4
  #
5
- # Copyright (c) 2019-2020 Yurii Dubinka
5
+ # Copyright (c) 2019-2021 Yurii Dubinka
6
6
  #
7
7
  # Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  # of this software and associated documentation files (the "Software"),
@@ -2,7 +2,7 @@
2
2
 
3
3
  # The MIT License
4
4
  #
5
- # Copyright (c) 2019-2020 Yurii Dubinka
5
+ # Copyright (c) 2019-2021 Yurii Dubinka
6
6
  #
7
7
  # Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  # of this software and associated documentation files (the "Software"),
@@ -26,10 +26,15 @@ require "jira-ruby"
26
26
  require "forwardable"
27
27
  require_relative "../salt"
28
28
  require_relative "../opts"
29
+ require_relative "../log"
29
30
 
30
31
  module Lazylead
31
32
  # Jira system for manipulation with issues.
32
33
  #
34
+ # Jira official documentation:
35
+ # - https://docs.atlassian.com/jira-software/REST/7.3.1/#agile/1.0/issue-getIssue
36
+ # - https://developer.atlassian.com/server/jira/platform/rest-apis/
37
+ #
33
38
  # Author:: Yurii Dubinka (yurii.dubinka@gmail.com)
34
39
  # Copyright:: Copyright (c) 2019-2020 Yurii Dubinka
35
40
  # License:: MIT
@@ -82,22 +87,7 @@ module Lazylead
82
87
  @opts[:auth_type] = :basic if @opts[:auth_type].nil?
83
88
  @opts["username"] = @salt.decrypt(@opts["username"]) if @salt.specified?
84
89
  @opts["password"] = @salt.decrypt(@opts["password"]) if @salt.specified?
85
- cp("site", :site)
86
- cp("username", :username)
87
- cp("password", :password)
88
- cp("context_path", :context_path)
89
- @client = JIRA::Client.new(@opts)
90
- end
91
-
92
- # Copy the required/mandatory parameter(s) for Jira client which can't
93
- # be specified/defined at database level.
94
- #
95
- # @todo #/DEV Jira.cp - find a way how to avoid this method.
96
- # Potentially, hash with indifferent access might be used.
97
- # http://jocellyn.cz/2014/05/03/hash-with-indifferent-access.html
98
- # key.kind_of?(Symbol) ? key.to_s : key
99
- def cp(act, exp)
100
- @opts[exp] = @opts[act] if @opts.key? act
90
+ @client = JIRA::Client.new(@opts.symbolize_keys)
101
91
  end
102
92
  end
103
93
 
@@ -313,7 +303,19 @@ module Lazylead
313
303
 
314
304
  # Check that comment has expected text
315
305
  def include?(text)
316
- @comment.attrs["body"].include? text
306
+ to_s.include? text
307
+ end
308
+
309
+ def to_s
310
+ @comment.attrs["body"]
311
+ end
312
+
313
+ def lines
314
+ to_s.split("\n").reject(&:blank?)
315
+ end
316
+
317
+ def author
318
+ @comment.attrs["author"]["displayName"]
317
319
  end
318
320
  end
319
321
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  # The MIT License
4
4
  #
5
- # Copyright (c) 2019-2020 Yurii Dubinka
5
+ # Copyright (c) 2019-2021 Yurii Dubinka
6
6
  #
7
7
  # Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  # of this software and associated documentation files (the "Software"),
@@ -2,7 +2,7 @@
2
2
 
3
3
  # The MIT License
4
4
  #
5
- # Copyright (c) 2019-2020 Yurii Dubinka
5
+ # Copyright (c) 2019-2021 Yurii Dubinka
6
6
  #
7
7
  # Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  # of this software and associated documentation files (the "Software"),
@@ -27,6 +27,7 @@ require_relative "../../opts"
27
27
  require_relative "../../email"
28
28
  require_relative "../../version"
29
29
  require_relative "../../postman"
30
+ require_relative "../../requires"
30
31
 
31
32
  module Lazylead
32
33
  module Task
@@ -43,55 +44,52 @@ module Lazylead
43
44
  end
44
45
 
45
46
  def run(sys, postman, opts)
46
- Dir[File.join(__dir__, "*.rb")].sort.each { |f| require f }
47
- rules = opts.slice("rules", ",")
48
- .map(&:constantize)
49
- .map(&:new)
50
- raised = sys.issues(opts["jql"], opts.jira_defaults)
51
- .map { |i| Score.new(i, opts, rules) }
52
- .each(&:evaluate)
53
- .each(&:post)
54
- postman.send opts.merge(tickets: raised) unless raised.empty?
47
+ Requires.new(__dir__).load
48
+ opts[:rules] = opts.construct("rules")
49
+ 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?
55
55
  end
56
56
  end
57
57
  end
58
58
 
59
59
  # The ticket score based on fields content.
60
60
  class Score
61
- attr_reader :issue, :total, :score, :accuracy
61
+ attr_reader :issue, :score, :accuracy
62
62
 
63
- def initialize(issue, opts, rules)
63
+ def initialize(issue, opts)
64
64
  @issue = issue
65
- @link = opts["docs"]
66
65
  @opts = opts
67
- @rules = rules
68
66
  end
69
67
 
70
68
  # Estimate the ticket score and accuracy.
71
69
  # Accuracy is a percentage between current score and maximum possible value.
72
70
  def evaluate(digits = 2)
73
- @total = @rules.sum(&:score)
74
- @score = @rules.select { |r| r.passed(@issue) }.sum(&:score)
75
- @accuracy = (score / @total * 100).round(digits)
71
+ @score = @opts[:rules].select { |r| r.passed(@issue) }.sum(&:score)
72
+ @accuracy = (score / @opts[:total] * 100).round(digits)
73
+ self
76
74
  end
77
75
 
78
76
  # Post the comment with score and accuracy to the ticket.
79
77
  def post
80
78
  return if @opts.key? "silent"
81
79
  @issue.post comment
82
- @issue.add_label "LL.accuracy", "#{grade(@accuracy)}%"
80
+ @issue.add_label "LL.accuracy", "#{grade(@accuracy)}%", "#{@accuracy}%"
83
81
  end
84
82
 
85
83
  # The jira comment in markdown format
86
84
  def comment
87
85
  comment = [
88
- "Hi [~#{@issue.reporter.id}],",
86
+ "Hi [~#{reporter}],",
89
87
  "",
90
88
  "The triage accuracy is '{color:#{color}}#{@score}{color}'" \
91
89
  " (~{color:#{color}}#{@accuracy}%{color}), here are the reasons why:",
92
90
  "|| Ticket requirement || Status || Field ||"
93
91
  ]
94
- @rules.each do |r|
92
+ @opts[:rules].each do |r|
95
93
  comment << "|#{r.desc}|#{r.passed(@issue) ? '(/)' : '(-)'}|#{r.field}|"
96
94
  end
97
95
  comment << docs_link
@@ -103,11 +101,11 @@ module Lazylead
103
101
 
104
102
  # Link to ticket formatting rules
105
103
  def docs_link
106
- if @link.nil? || @link.blank?
104
+ if @opts["docs"].nil? || @opts["docs"].blank?
107
105
  ""
108
106
  else
109
107
  "The requirements/examples of ticket formatting rules you may find " \
110
- "[here|#{@link}]."
108
+ "[here|#{@opts['docs']}]."
111
109
  end
112
110
  end
113
111
 
@@ -120,13 +118,11 @@ module Lazylead
120
118
  end
121
119
 
122
120
  def colors
123
- @colors ||= begin
124
- JSON.parse(@opts["colors"])
125
- .to_h
126
- .to_a
127
- .each { |e| e[0] = e[0].to_i }
128
- .sort_by { |e| e[0] }
129
- end
121
+ @colors ||= JSON.parse(@opts["colors"])
122
+ .to_h
123
+ .to_a
124
+ .each { |e| e[0] = e[0].to_i }
125
+ .sort_by { |e| e[0] }
130
126
  end
131
127
 
132
128
  # Calculate grade for accuracy
@@ -137,5 +133,17 @@ module Lazylead
137
133
  def grade(value)
138
134
  (value / 10).floor * 10
139
135
  end
136
+
137
+ # Detect the ticket reporter.
138
+ #
139
+ # If ticket created by some automatic/admin user account then reporter is the first non-system
140
+ # user account who modified the ticket.
141
+ def reporter
142
+ return @issue.reporter.id unless @opts.key? "system-users"
143
+ sys = @opts.slice("system-users", ",")
144
+ return @issue.reporter.id if sys.empty? || sys.none? { |susr| @issue.reporter.id.eql? susr }
145
+ @issue.history
146
+ .find { |h| sys.none? { |susr| susr.eql? h["author"]["key"] } }["author"]["key"]
147
+ end
140
148
  end
141
149
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  # The MIT License
4
4
  #
5
- # Copyright (c) 2019-2020 Yurii Dubinka
5
+ # Copyright (c) 2019-2021 Yurii Dubinka
6
6
  #
7
7
  # Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  # of this software and associated documentation files (the "Software"),
@@ -2,7 +2,7 @@
2
2
 
3
3
  # The MIT License
4
4
  #
5
- # Copyright (c) 2019-2020 Yurii Dubinka
5
+ # Copyright (c) 2019-2021 Yurii Dubinka
6
6
  #
7
7
  # Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  # of this software and associated documentation files (the "Software"),
@@ -2,7 +2,7 @@
2
2
 
3
3
  # The MIT License
4
4
  #
5
- # Copyright (c) 2019-2020 Yurii Dubinka
5
+ # Copyright (c) 2019-2021 Yurii Dubinka
6
6
  #
7
7
  # Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  # of this software and associated documentation files (the "Software"),
@@ -2,7 +2,7 @@
2
2
 
3
3
  # The MIT License
4
4
  #
5
- # Copyright (c) 2019-2020 Yurii Dubinka
5
+ # Copyright (c) 2019-2021 Yurii Dubinka
6
6
  #
7
7
  # Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  # of this software and associated documentation files (the "Software"),
@@ -38,7 +38,10 @@ module Lazylead
38
38
  name = attachment.attrs["filename"].downcase
39
39
  return false unless attachment.attrs["size"].to_i > 5120
40
40
  return true if File.extname(name).start_with? ".log", ".txt", ".out"
41
- @files.any? { |l| name.end_with? l }
41
+ return true if @files.any? { |l| name.end_with? l }
42
+ %w[.zip .7z .gz tar.gz].any? do |l|
43
+ name.end_with?(l) && name.split(/(?:[^a-zA-Z0-9](?<![^\x00-\x7F]))+/).include?("logs")
44
+ end
42
45
  end
43
46
  end
44
47
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  # The MIT License
4
4
  #
5
- # Copyright (c) 2019-2020 Yurii Dubinka
5
+ # Copyright (c) 2019-2021 Yurii Dubinka
6
6
  #
7
7
  # Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  # of this software and associated documentation files (the "Software"),
@@ -94,13 +94,11 @@ module Lazylead
94
94
 
95
95
  # Detect the percentage grid for tickets, by default its 0%, 10%, 20%, etc.
96
96
  def grid
97
- @grid ||= begin
98
- if @opts.key? "grid"
99
- @opts.slice("grid", ",")
100
- else
101
- %w[0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%]
102
- end
103
- end
97
+ @grid ||= if @opts.key? "grid"
98
+ @opts.slice("grid", ",")
99
+ else
100
+ %w[0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%]
101
+ end
104
102
  end
105
103
 
106
104
  # Remove score labels from the ticket.
@@ -2,7 +2,7 @@
2
2
 
3
3
  # The MIT License
4
4
  #
5
- # Copyright (c) 2019-2020 Yurii Dubinka
5
+ # Copyright (c) 2019-2021 Yurii Dubinka
6
6
  #
7
7
  # Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  # of this software and associated documentation files (the "Software"),
@@ -2,7 +2,7 @@
2
2
 
3
3
  # The MIT License
4
4
  #
5
- # Copyright (c) 2019-2020 Yurii Dubinka
5
+ # Copyright (c) 2019-2021 Yurii Dubinka
6
6
  #
7
7
  # Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  # of this software and associated documentation files (the "Software"),
@@ -0,0 +1,60 @@
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
+ #
29
+ # Check that ticket has screenshot(s).
30
+ # The screenshots should
31
+ # 1. present as attachments
32
+ # 2. has extension .jpg .jpeg .exif .tiff .tff .bmp .png .svg
33
+ # 3. mentioned in description with !<name>.<extension>|thumbnail! (read more https://bit.ly/3rusNgW)
34
+ #
35
+ class Screenshots < Lazylead::Requirement
36
+ # @param minimum The number of expected screenshots
37
+ def initialize(minimum: 1, score: 2, ext: %w[.jpg .jpeg .exif .tiff .tff .bmp .png .svg])
38
+ super "Screenshots", score, "Description,Attachments"
39
+ @minimum = minimum
40
+ @ext = ext
41
+ end
42
+
43
+ def passed(issue)
44
+ return false if issue.attachments.nil? || blank?(issue, "description")
45
+ references = issue.description
46
+ .to_enum(:scan, /!.+!/)
47
+ .map { Regexp.last_match }
48
+ .map(&:to_s)
49
+ return false if references.size < @minimum
50
+ references.all? { |ref| pictures(issue).any? { |file| ref.include? file } }
51
+ end
52
+
53
+ # Detect all pictures in ticket attachments and returns an array with file names.
54
+ def pictures(issue)
55
+ @pictures ||= issue.attachments
56
+ .select { |a| @ext.include? File.extname(a.filename).downcase }
57
+ .map(&:filename)
58
+ end
59
+ end
60
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  # The MIT License
4
4
  #
5
- # Copyright (c) 2019-2020 Yurii Dubinka
5
+ # Copyright (c) 2019-2021 Yurii Dubinka
6
6
  #
7
7
  # Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  # of this software and associated documentation files (the "Software"),
@@ -2,7 +2,7 @@
2
2
 
3
3
  # The MIT License
4
4
  #
5
- # Copyright (c) 2019-2020 Yurii Dubinka
5
+ # Copyright (c) 2019-2021 Yurii Dubinka
6
6
  #
7
7
  # Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  # of this software and associated documentation files (the "Software"),