lazylead 0.4.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.docs/accuracy.md +4 -4
  3. data/.docs/duedate_expired.md +3 -3
  4. data/.docs/propagate_down.md +3 -3
  5. data/.gitattributes +1 -0
  6. data/.github/dependabot.yml +6 -0
  7. data/Rakefile +2 -0
  8. data/bin/lazylead +1 -1
  9. data/lazylead.gemspec +3 -2
  10. data/lib/lazylead/exchange.rb +15 -9
  11. data/lib/lazylead/model.rb +37 -3
  12. data/lib/lazylead/opts.rb +13 -1
  13. data/lib/lazylead/postman.rb +1 -2
  14. data/lib/lazylead/schedule.rb +16 -15
  15. data/lib/lazylead/system/jira.rb +43 -0
  16. data/lib/lazylead/task/accuracy/accuracy.rb +13 -8
  17. data/lib/lazylead/task/accuracy/affected_build.rb +2 -6
  18. data/lib/lazylead/task/accuracy/attachment.rb +44 -0
  19. data/lib/lazylead/task/accuracy/environment.rb +39 -0
  20. data/lib/lazylead/task/accuracy/logs.rb +40 -0
  21. data/lib/lazylead/task/accuracy/records.rb +45 -0
  22. data/lib/lazylead/task/accuracy/requirement.rb +9 -0
  23. data/lib/lazylead/task/accuracy/servers.rb +50 -0
  24. data/lib/lazylead/task/accuracy/stacktrace.rb +63 -0
  25. data/lib/lazylead/task/accuracy/testcase.rb +75 -0
  26. data/lib/lazylead/task/accuracy/wiki.rb +41 -0
  27. data/lib/lazylead/task/echo.rb +18 -0
  28. data/lib/lazylead/task/fix_version.rb +9 -2
  29. data/lib/lazylead/task/touch.rb +28 -11
  30. data/lib/lazylead/version.rb +1 -1
  31. data/lib/messages/svn_log.erb +117 -0
  32. data/lib/messages/svn_touch.erb +1 -1
  33. data/license.txt +1 -1
  34. data/readme.md +5 -5
  35. data/test/lazylead/cli/app_test.rb +11 -11
  36. data/test/lazylead/opts_test.rb +4 -0
  37. data/test/lazylead/system/jira_test.rb +38 -0
  38. data/test/lazylead/task/accuracy/accuracy_test.rb +1 -1
  39. data/test/lazylead/task/accuracy/affected_build_test.rb +2 -2
  40. data/test/lazylead/task/accuracy/attachment_test.rb +50 -0
  41. data/test/lazylead/task/accuracy/environment_test.rb +42 -0
  42. data/test/lazylead/task/accuracy/logs_test.rb +78 -0
  43. data/test/lazylead/task/accuracy/records_test.rb +60 -0
  44. data/test/lazylead/task/accuracy/score_test.rb +46 -0
  45. data/test/lazylead/task/accuracy/servers_test.rb +66 -0
  46. data/test/lazylead/task/accuracy/stacktrace_test.rb +113 -0
  47. data/test/lazylead/task/accuracy/testcase_test.rb +205 -0
  48. data/test/lazylead/task/accuracy/wiki_test.rb +40 -0
  49. data/test/lazylead/task/touch_test.rb +48 -23
  50. data/test/test.rb +25 -0
  51. data/upgrades/sqlite/001-install-main-lazylead-tables.sql +1 -5
  52. data/upgrades/sqlite/999.testdata.sql +12 -17
  53. metadata +45 -4
  54. data/.travis.yml +0 -16
@@ -22,22 +22,18 @@
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 "../../log"
26
- require_relative "../../email"
27
- require_relative "../../version"
28
- require_relative "../../postman"
29
25
  require_relative "requirement"
30
26
 
31
27
  module Lazylead
32
28
  # A requirement that Jira field "Affects Version/s" provided by the reporter.
33
- class RequirementAffectedBuild < Requirement
29
+ class AffectedBuild < Requirement
34
30
  def initialize(score = 0.5)
35
31
  super "Affected build", score, "Affects Version/s"
36
32
  end
37
33
 
38
34
  # @return true if an issue has non-empty "Affects Version/s" field
39
35
  def passed(issue)
40
- !issue.fields["versions"].nil? && !issue.fields["versions"].empty?
36
+ non_blank? issue, "versions"
41
37
  end
42
38
  end
43
39
  end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The MIT License
4
+ #
5
+ # Copyright (c) 2019-2020 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 an attachment.
29
+ class Attachment < Lazylead::Requirement
30
+ def initialize(desc, score, field)
31
+ super(desc, score, field)
32
+ end
33
+
34
+ def passed(issue)
35
+ issue.attachments.any?(&method(:matching))
36
+ end
37
+
38
+ # Check a single attachment from ticket.
39
+ # Potential extension point for custom verification logic.
40
+ def matching(attachment)
41
+ !attachment.nil?
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The MIT License
4
+ #
5
+ # Copyright (c) 2019-2020 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
+ # A requirement that Jira field "Environment" provided by the reporter.
29
+ class Environment < Requirement
30
+ def initialize(score = 0.5)
31
+ super "Environment details (URL, patches)", score, "Environment"
32
+ end
33
+
34
+ # @return true if an issue has non-empty "Environment" field
35
+ def passed(issue)
36
+ non_blank? issue, "environment"
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The MIT License
4
+ #
5
+ # Copyright (c) 2019-2020 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 "attachment"
26
+
27
+ module Lazylead
28
+ # Check that ticket has log file(s) in attachment.
29
+ class Logs < Lazylead::Attachment
30
+ def initialize
31
+ super("Log files", 2, "Attachments")
32
+ end
33
+
34
+ # Ensure that ticket has a '*.log' file more '10KB'
35
+ def matching(attachment)
36
+ attachment.attrs["size"].to_i > 10_240 &&
37
+ File.extname(attachment.attrs["filename"]).downcase.start_with?(".log")
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The MIT License
4
+ #
5
+ # Copyright (c) 2019-2020 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 "attachment"
26
+
27
+ module Lazylead
28
+ # Check that ticket has video record(s) with reproducing results.
29
+ class Records < Lazylead::Attachment
30
+ def initialize(ext = [])
31
+ super("Recorded internal reproducing results", 5, "Attachments")
32
+ @ext = ext
33
+ return unless @ext.empty?
34
+ @ext = %w[.webm .mkv .flv .flv .vob .ogv .ogg .drc .gif .gifv .mng .avi
35
+ .mts .m2ts .ts .mov .qt .wmv .yuv .rm .rmvb .viv .asf .amv .mp4
36
+ .m4p .m4v .mpg .mp2 .mpeg .mpe .mpv .mpg .mpeg .m2v .m4v .svi
37
+ .3gp .3g2 .mxf .roq .nsv .flv .f4v .f4p .f4a .f4b]
38
+ end
39
+
40
+ # Ensure that ticket has an attachment with video-file extension
41
+ def matching(attach)
42
+ @ext.any? { |e| e.eql? File.extname(attach.attrs["filename"]).downcase }
43
+ end
44
+ end
45
+ end
@@ -36,5 +36,14 @@ module Lazylead
36
36
  def passed(_)
37
37
  true
38
38
  end
39
+
40
+ def blank?(issue, field)
41
+ return false if issue.nil?
42
+ issue.fields[field].nil? || issue.fields[field].blank?
43
+ end
44
+
45
+ def non_blank?(issue, field)
46
+ !blank? issue, field
47
+ end
39
48
  end
40
49
  end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The MIT License
4
+ #
5
+ # Copyright (c) 2019-2020 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 expected links to failed entities on dedicated
29
+ # servers.
30
+ class Servers < Lazylead::Requirement
31
+ #
32
+ # @param envs regexp expressions to match servers in description.
33
+ #
34
+ def initialize(score: 2, envs: [], desc: "Internal reproducing results")
35
+ super desc, score, "Description/Environment"
36
+ @envs = envs
37
+ end
38
+
39
+ def passed(issue)
40
+ return true if @envs.empty?
41
+ lines = issue["environment"].to_s + "\n" + issue.description
42
+ lines.split("\n")
43
+ .reject(&:blank?)
44
+ .map(&:strip)
45
+ .flat_map { |l| l.split(" ").map(&:strip) }
46
+ .select { |w| w.start_with?("http://", "https://") }
47
+ .any? { |u| @envs.any? { |e| u.match? e } }
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The MIT License
4
+ #
5
+ # Copyright (c) 2019-2020 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
+ # Java stacktrace or Oracle errors in {noformat} section
29
+ class Stacktrace < Lazylead::Requirement
30
+ def initialize(score = 3)
31
+ super "Stacktrace/errors in *\\{noformat\\}* for JIRA indexing", score,
32
+ "Description"
33
+ end
34
+
35
+ def passed(issue)
36
+ return false if issue.description.nil?
37
+ !frames(issue.description).select { |f| oracle?(f) || java?(f) }.empty?
38
+ end
39
+
40
+ # Detect all {noformat} frames in description field
41
+ def frames(description)
42
+ description.enum_for(:scan, /(?={noformat})/)
43
+ .map { Regexp.last_match.offset(0).first }
44
+ .each_slice(2).map do |f|
45
+ description[f.first, f.last - f.first + "{noformat}".size]
46
+ end
47
+ end
48
+
49
+ # @return true if frame has few lines with java stack frames
50
+ def java?(frame)
51
+ allowed = ["at ", "Caused by:"]
52
+ frame.split("\n")
53
+ .map(&:strip)
54
+ .count { |l| allowed.any? { |a| l.start_with? a } } > 3
55
+ end
56
+
57
+ # @return true if frame has Oracle error
58
+ # @see https://docs.oracle.com/pls/db92/db92.error_search
59
+ def oracle?(frame)
60
+ frame.match?(/\WORA-\d{5}:/)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The MIT License
4
+ #
5
+ # Copyright (c) 2019-2020 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 the 'Description' field that ticket has mandatory details like
29
+ # - test case (TC)
30
+ # - actual result (AR)
31
+ # - expected result (ER)
32
+ class Testcase < Lazylead::Requirement
33
+ def initialize(score = 4)
34
+ super "Test case with AR/ER", score, "Description"
35
+ end
36
+
37
+ def passed(issue)
38
+ return false if issue.description.nil?
39
+ @tc = @ar = @er = -1
40
+ issue.description.split("\n").reject(&:blank?).each_with_index do |l, i|
41
+ line = l.gsub(/[^a-zA-Z(:|=)]/, "").downcase
42
+ detect_tc line, i
43
+ detect_ar line, i
44
+ detect_er line, i
45
+ break if with_tc_ar_er?
46
+ end
47
+ with_tc_ar_er?
48
+ end
49
+
50
+ # @return true if description has test case, AR and ER
51
+ def with_tc_ar_er?
52
+ (@tc.zero? || @tc.positive?) && @ar.positive? && @er.positive?
53
+ end
54
+
55
+ # Detect index of line with test case
56
+ def detect_tc(line, index)
57
+ return unless @tc.negative?
58
+ @tc = index if %w[testcase: tc: teststeps: teststeps steps:].any? do |e|
59
+ e.eql? line
60
+ end
61
+ end
62
+
63
+ # Detect index of line with actual result
64
+ def detect_ar(line, index)
65
+ return unless @ar.negative? && index > @tc
66
+ @ar = index if %w[ar: actualresult: ar=].any? { |e| line.start_with? e }
67
+ end
68
+
69
+ # Detect index of line with expected result
70
+ def detect_er(line, index)
71
+ return unless @er.negative? && index > @tc
72
+ @er = index if %w[er: expectedresult: er=].any? { |e| line.start_with? e }
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The MIT License
4
+ #
5
+ # Copyright (c) 2019-2020 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 a remote link to external system with relationship
29
+ # type = "Wiki Page".
30
+ class Wiki < Lazylead::Requirement
31
+ def initialize(score = 2, relationship = "Wiki Page")
32
+ super "Reference to design specification", score, "Ticket Links (Wiki)"
33
+ @relationship = relationship
34
+ end
35
+
36
+ def passed(issue)
37
+ return false if issue.remote_links.nil? || issue.remote_links.empty?
38
+ issue.remote_links.any? { |l| @relationship.eql? l.attrs["relationship"] }
39
+ end
40
+ end
41
+ end