lazylead 0.5.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +49 -1
  3. data/.simplecov +1 -1
  4. data/Guardfile +1 -1
  5. data/Rakefile +4 -3
  6. data/bin/lazylead +9 -5
  7. data/lazylead.gemspec +20 -15
  8. data/lib/lazylead/cc.rb +21 -20
  9. data/lib/lazylead/cli/app.rb +13 -5
  10. data/lib/lazylead/confluence.rb +8 -1
  11. data/lib/lazylead/email.rb +0 -20
  12. data/lib/lazylead/exchange.rb +16 -28
  13. data/lib/lazylead/log.rb +2 -1
  14. data/lib/lazylead/model.rb +31 -16
  15. data/lib/lazylead/opts.rb +65 -2
  16. data/lib/lazylead/postman.rb +18 -16
  17. data/lib/lazylead/salt.rb +1 -0
  18. data/lib/lazylead/smtp.rb +3 -1
  19. data/lib/lazylead/system/jira.rb +31 -6
  20. data/lib/lazylead/task/accuracy/accuracy.rb +8 -10
  21. data/lib/lazylead/task/accuracy/attachment.rb +0 -4
  22. data/lib/lazylead/task/accuracy/logs.rb +8 -4
  23. data/lib/lazylead/task/accuracy/onlyll.rb +148 -0
  24. data/lib/lazylead/task/accuracy/records.rb +1 -1
  25. data/lib/lazylead/task/accuracy/servers.rb +16 -7
  26. data/lib/lazylead/task/accuracy/stacktrace.rb +50 -10
  27. data/lib/lazylead/task/accuracy/testcase.rb +23 -6
  28. data/lib/lazylead/task/assignment.rb +96 -0
  29. data/lib/lazylead/task/fix_version.rb +6 -0
  30. data/lib/lazylead/task/propagate_down.rb +1 -1
  31. data/lib/lazylead/task/svn/diff.rb +77 -0
  32. data/lib/lazylead/task/svn/grep.rb +139 -0
  33. data/lib/lazylead/task/svn/touch.rb +99 -0
  34. data/lib/lazylead/version.rb +1 -1
  35. data/lib/messages/illegal_assignee_change.erb +123 -0
  36. data/lib/messages/illegal_fixversion_change.erb +8 -0
  37. data/lib/messages/only_ll.erb +107 -0
  38. data/lib/messages/svn_diff.erb +110 -0
  39. data/lib/messages/{svn_log.erb → svn_diff_attachment.erb} +19 -9
  40. data/lib/messages/svn_grep.erb +114 -0
  41. data/test/lazylead/cc_test.rb +1 -0
  42. data/test/lazylead/model_test.rb +20 -0
  43. data/test/lazylead/opts_test.rb +47 -0
  44. data/test/lazylead/postman_test.rb +8 -5
  45. data/test/lazylead/smoke_test.rb +13 -0
  46. data/test/lazylead/system/jira_test.rb +6 -7
  47. data/test/lazylead/task/accuracy/logs_test.rb +62 -2
  48. data/test/lazylead/task/accuracy/onlyll_test.rb +138 -0
  49. data/test/lazylead/task/accuracy/servers_test.rb +2 -2
  50. data/test/lazylead/task/accuracy/stacktrace_test.rb +227 -0
  51. data/test/lazylead/task/accuracy/testcase_test.rb +49 -0
  52. data/test/lazylead/task/assignment_test.rb +53 -0
  53. data/test/lazylead/task/fix_version_test.rb +1 -0
  54. data/test/lazylead/task/propagate_down_test.rb +4 -3
  55. data/test/lazylead/task/savepoint_test.rb +7 -4
  56. data/test/lazylead/task/svn/diff_test.rb +97 -0
  57. data/test/lazylead/task/svn/grep_test.rb +103 -0
  58. data/test/lazylead/task/{touch_test.rb → svn/touch_test.rb} +7 -34
  59. data/test/test.rb +7 -6
  60. data/upgrades/sqlite/999.testdata.sql +3 -1
  61. metadata +120 -34
  62. data/lib/lazylead/task/touch.rb +0 -119
@@ -64,7 +64,7 @@
64
64
  padding: 36px
65
65
  }
66
66
 
67
- .commit {
67
+ .commit, .table-of-contents {
68
68
  min-width: 100%;
69
69
  border-radius: 3.5px;
70
70
  overflow: hidden;
@@ -74,26 +74,36 @@
74
74
  border: 1px solid #BCC6CC;
75
75
  }
76
76
 
77
- .commit * {
77
+ .commit *, .table-of-contents * {
78
78
  padding-left: 4px;
79
79
  font-size: 8px;
80
80
  line-height: 15px;
81
81
  }
82
+
83
+ .table-of-contents {
84
+ border: none;
85
+ }
82
86
  </style>
83
87
  <title>SVN log</title>
84
88
  </head>
85
89
  <body>
86
90
  <p>Hi,</p>
87
- <p>The following file(s) changed since <code><%= since_rev %></code> rev in <a href="<%= svn_url %>"><%= svn_url %></a>:</p>
91
+ <p>Commit(s) since <code><%= since_rev %></code> revision in <a href="<%= svn_url %>"><%= svn_url %></a>:</p>
92
+ <div id="table-of-contents" class="table-of-contents">
93
+ <ul>
94
+ <% stdout.split("------------------------------------------------------------------------").reject(&:blank?).reverse.each do |commit| %>
95
+ <% details = commit.split("\n").reject(&:blank?).first.split("|").map(&:strip).reject(&:blank?) %>
96
+ <li><a href="#<%= details[0] %>"><%= details[0] %></a> by <%= details[1] %> at <%= details[2] %></li>
97
+ <% end %>
98
+ </ul>
99
+ </div>
88
100
  <% stdout.split("------------------------------------------------------------------------").reject(&:blank?).reverse.each do |commit| %>
89
101
  <div class="commit">
90
102
  <% commit.split("\n").reject(&:blank?).each_with_index do |line, index| %>
91
103
  <% if index.zero? %>
92
104
  <% details = line.split("|").map(&:strip).reject(&:blank?) %>
93
- <p style="background: gainsboro;">
94
- <a href="<%= commit_url %><%= details[0][1 .. -1] %>"><%= details[0] %></a>
95
- by <a href="<%= user %><%= details[1] %>"><%= details[1] %></a>
96
- at <span style="color: #275a90;"><%= details[2] %></span>
105
+ <p style="background: gainsboro;" id="<%= details[0] %>"><a href="<%= commit_url %><%= details[0][1..-1] %>"><%= details[0] %></a> by <a href="<%= user %><%= details[1] %>"><%= details[1] %></a> at <span style="color: #275a90;"><%= details[2] %></span>
106
+ <a href="#table-of-contents">&#8593;</a>
97
107
  </p>
98
108
  <% else %>
99
109
  <% if line.start_with?("+++") || line.start_with?("---") %>
@@ -103,12 +113,12 @@
103
113
  <% elsif line.start_with?("-") %>
104
114
  <p style="<%= "background: lightsalmon;" %>"><%= line.gsub(/[<>]/, '<' => '&lt;', '>' => '&gt;') %></p>
105
115
  <% else %>
106
- <p style="background: gainsboro;"><%= line.gsub(/[<>]/,'<' => '&lt;', '>' => '&gt;') %></p>
116
+ <p style="background: gainsboro;"><%= line.gsub(/[<>]/, '<' => '&lt;', '>' => '&gt;') %></p>
107
117
  <% end %>
108
118
  <% end %>
109
119
  <% end %>
110
120
  </div>
111
- <br/><br/><br/>
121
+ <br/>
112
122
  <% end %>
113
123
  <p>Posted by
114
124
  <a href="https://github.com/dgroup/lazylead">lazylead v<%= version %></a>.
@@ -0,0 +1,114 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <style>
5
+ /* CSS styles taken from https://github.com/yegor256/tacit */
6
+ pre, code, kbd, samp, var, output {
7
+ font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
8
+ font-size: 14.4px
9
+ }
10
+
11
+ pre code {
12
+ background: none;
13
+ border: 0;
14
+ line-height: 29.7px;
15
+ padding: 0
16
+ }
17
+
18
+ code, kbd {
19
+ background: #daf1e0;
20
+ border-radius: 3.6px;
21
+ color: #2a6f3b;
22
+ display: inline-block;
23
+ line-height: 18px;
24
+ padding: 3.6px 6.3px 2.7px
25
+ }
26
+
27
+ a {
28
+ color: #275a90;
29
+ text-decoration: none
30
+ }
31
+
32
+ a:hover {
33
+ text-decoration: underline
34
+ }
35
+
36
+ * {
37
+ border: 0;
38
+ border-collapse: separate;
39
+ border-spacing: 0;
40
+ box-sizing: border-box;
41
+ margin: 0;
42
+ max-width: 100%;
43
+ padding: 0;
44
+ vertical-align: baseline;
45
+ font-family: system-ui, "Helvetica Neue", Helvetica, Arial, sans-serif;
46
+ font-size: 13px;
47
+ font-stretch: normal;
48
+ font-style: normal;
49
+ font-weight: 400;
50
+ line-height: 29.7px
51
+ }
52
+
53
+ html, body {
54
+ width: 100%
55
+ }
56
+
57
+ html {
58
+ height: 100%
59
+ }
60
+
61
+ body {
62
+ background: #fff;
63
+ color: #1a1919;
64
+ padding: 36px
65
+ }
66
+
67
+ .commit {
68
+ min-width: 100%;
69
+ border-radius: 3.5px;
70
+ overflow: hidden;
71
+ display: inline-block;
72
+ line-height: 15px;
73
+ font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
74
+ border: 1px solid #BCC6CC;
75
+ }
76
+
77
+ .commit * {
78
+ padding-left: 4px;
79
+ font-size: 8px;
80
+ line-height: 15px;
81
+ }
82
+ </style>
83
+ <title>SVN log</title>
84
+ </head>
85
+ <body>
86
+ <p>Hi,</p>
87
+ <p>The following file(s) contain text <code><%= text %></code> in
88
+ <a href="<%= svn_url %>"><%= svn_url %></a>:</p>
89
+ <% entries.each do |commit| %>
90
+ <div class="commit">
91
+ <p style="background: gainsboro;">
92
+ <a href="<%= commit_url %><%= commit.rev %>"><%= commit.msg %></a>
93
+ by <a href="<%= user %><%= commit.author %>"><%= commit.author %></a>
94
+ at <span style="color: #275a90;"><%= commit.time %></span>
95
+ </p>
96
+ <% commit.diff(text.split(",")).each do |line| %>
97
+ <% if line.start_with?("+++") || line.start_with?("---") %>
98
+ <p style="background: gainsboro;"><%= line.gsub(/[<>]/, '<' => '&lt;', '>' => '&gt;') %></p>
99
+ <% elsif text.split(",").any? { |t| line.include? t } %>
100
+ <p style="background: #F9F103;"><%= line.gsub(/[<>]/, '<' => '&lt;', '>' => '&gt;') %></p>
101
+ <% elsif line.start_with?("+") %>
102
+ <p style="<%= "background: darkseagreen;" %>"><%= line.gsub(/[<>]/, '<' => '&lt;', '>' => '&gt;') %></p>
103
+ <% elsif line.start_with?("-") %>
104
+ <p style="<%= "background: lightsalmon;" %>"><%= line.gsub(/[<>]/, '<' => '&lt;', '>' => '&gt;') %></p>
105
+ <% else %>
106
+ <p style="background: gainsboro;"><%= line.gsub(/[<>]/, '<' => '&lt;', '>' => '&gt;') %></p>
107
+ <% end %>
108
+ <% end %>
109
+ </div>
110
+ <% end %>
111
+ <p>Posted by<a href="https://github.com/dgroup/lazylead">lazylead
112
+ v<%= version %></a>.</p>
113
+ </body>
114
+ </html>
@@ -49,6 +49,7 @@ module Lazylead
49
49
  assert Lazylead::CC.new.undefined? "type" => " "
50
50
  end
51
51
  end
52
+
52
53
  class PlainCcTest < Lazylead::Test
53
54
  test "cc has valid email" do
54
55
  assert_equal "a@fake.com", Lazylead::PlainCC.new("a@fake.com").cc.first
@@ -72,5 +72,25 @@ module Lazylead
72
72
  )
73
73
  assert_equal "value", ORM::Task.find(171).props["envkey"]
74
74
  end
75
+
76
+ test "task properties are parsed despite on wrong config" do
77
+ CLI::App.new(Log.new, NoSchedule.new).run(
78
+ home: ".",
79
+ sqlite: "test/resources/#{no_ext(__FILE__)}.#{__method__}.db",
80
+ vcs4sql: "upgrades/sqlite",
81
+ testdata: true
82
+ )
83
+ refute ORM::Task.find(260).to_h?
84
+ end
85
+
86
+ test "second ticketing system is found" do
87
+ CLI::App.new(Log.new, NoSchedule.new).run(
88
+ home: ".",
89
+ sqlite: "test/resources/#{no_ext(__FILE__)}.#{__method__}.db",
90
+ vcs4sql: "upgrades/sqlite",
91
+ testdata: true
92
+ )
93
+ assert_kind_of Jira, ORM::Task.find(270).second_sys
94
+ end
75
95
  end
76
96
  end
@@ -66,5 +66,52 @@ module Lazylead
66
66
  test "except keys" do
67
67
  assert_equal 1, Opts.new("one" => "1", "two" => "2").except("one").size
68
68
  end
69
+
70
+ test "attachment is blank" do
71
+ assert_empty Opts.new("attachments" => "").msg_attachments
72
+ end
73
+
74
+ test "attachment is nil" do
75
+ assert_empty Opts.new("attachments" => nil).msg_attachments
76
+ end
77
+
78
+ test "attachment is absent" do
79
+ assert_empty Opts.new({}).msg_attachments
80
+ end
81
+
82
+ test "attachment is present" do
83
+ assert_equal %w[readme.md],
84
+ Opts.new("attachments" => "readme.md").msg_attachments
85
+ end
86
+
87
+ test "attachments are present" do
88
+ assert_equal %w[readme.md license.txt],
89
+ Opts.new("attachments" => "readme.md,license.txt")
90
+ .msg_attachments
91
+ end
92
+
93
+ test "attachments are present as symbol" do
94
+ assert_equal %w[readme.md license.txt],
95
+ Opts.new(attachments: " readme.md , license.txt ")
96
+ .msg_attachments
97
+ end
98
+
99
+ test "attachments is present as array" do
100
+ assert_equal %w[readme.md license.txt],
101
+ Opts.new(attachments: %w[readme.md license.txt])
102
+ .msg_attachments
103
+ end
104
+
105
+ test "value has numeric value" do
106
+ assert Opts.new("key" => "1").numeric? "key"
107
+ end
108
+
109
+ test "text value is not a numeric" do
110
+ refute Opts.new("key" => "val").numeric? "key"
111
+ end
112
+
113
+ test "nil is not a numeric" do
114
+ refute Opts.new("key" => nil).numeric? "key"
115
+ end
69
116
  end
70
117
  end
@@ -24,6 +24,7 @@
24
24
 
25
25
  require_relative "../test"
26
26
  require_relative "../../lib/lazylead/log"
27
+ require_relative "../../lib/lazylead/opts"
27
28
  require_relative "../../lib/lazylead/salt"
28
29
  require_relative "../../lib/lazylead/smtp"
29
30
  require_relative "../../lib/lazylead/postman"
@@ -46,11 +47,13 @@ module Lazylead
46
47
  smtp_pass: ENV["LL_SMTP_PASS"]
47
48
  ).enable
48
49
  Postman.new.send(
49
- "to" => ENV["LL_SMTP_TO"],
50
- "from" => ENV["LL_SMTP_FROM"],
51
- "attachments" => ["readme.md"],
52
- "subject" => "[LL] Attachments",
53
- "template" => "lib/messages/savepoint.erb"
50
+ Opts.new(
51
+ "to" => ENV["LL_SMTP_TO"],
52
+ "from" => ENV["LL_SMTP_FROM"],
53
+ "attachments" => ["readme.md"],
54
+ "subject" => "[LL] Attachments",
55
+ "template" => "lib/messages/savepoint.erb"
56
+ )
54
57
  )
55
58
  end
56
59
  end
@@ -22,6 +22,8 @@
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 "inifile"
26
+ require "tempfile"
25
27
  require_relative "../test"
26
28
 
27
29
  module Lazylead
@@ -34,5 +36,16 @@ module Lazylead
34
36
  test "ENV has no key" do
35
37
  refute env? "c"
36
38
  end
39
+ test "ini file found" do
40
+ Tempfile.create do |f|
41
+ f << "EnvTest=value"
42
+ f.flush
43
+ IniFile.new(filename: f).each { |_, k, v| ENV[k] = v }
44
+ assert_equal "value", ENV["EnvTest"]
45
+ end
46
+ end
47
+ test "ini file not found" do
48
+ assert_empty IniFile.new(filename: "absent.ini").to_h
49
+ end
37
50
  end
38
51
  end
@@ -142,13 +142,6 @@ module Lazylead
142
142
  assert_equal "Hi there!", issue.comment[:body]
143
143
  end
144
144
 
145
- test "search by limit in 1 issue" do
146
- assert_equal 1,
147
- NoAuthJira.new("https://jira.spring.io")
148
- .issues("key in (DATAJDBC-480, DATAJDBC-500)", max_results: "1")
149
- .size
150
- end
151
-
152
145
  test "description is correct" do
153
146
  assert_words %w[DATACMNS-1639\ moved\ entity\ instantiators],
154
147
  NoAuthJira.new("https://jira.spring.io")
@@ -186,5 +179,11 @@ module Lazylead
186
179
  .labels,
187
180
  "Spring"
188
181
  end
182
+
183
+ test "bulk search in few iterations" do
184
+ assert NoAuthJira.new("https://jira.spring.io")
185
+ .issues("key>DATAJDBC-500")
186
+ .size >= 118
187
+ end
189
188
  end
190
189
  end
@@ -63,12 +63,72 @@ module Lazylead
63
63
  )
64
64
  end
65
65
 
66
- test "log file size less than 10KB" do
66
+ test "log file size less than 5KB" do
67
67
  refute Logs.new.passed(
68
68
  OpenStruct.new(
69
69
  attachments: [
70
70
  OpenStruct.new(
71
- attrs: { "size" => 10_000, "filename" => "catalina.log" }
71
+ attrs: { "size" => 5000, "filename" => "catalina.log" }
72
+ )
73
+ ]
74
+ )
75
+ )
76
+ end
77
+
78
+ test "rotated log file is present" do
79
+ assert Logs.new.passed(
80
+ OpenStruct.new(
81
+ attachments: [
82
+ OpenStruct.new(
83
+ attrs: { "size" => 10_241, "filename" => "catalina.log111" }
84
+ )
85
+ ]
86
+ )
87
+ )
88
+ end
89
+
90
+ test "log txt file is present" do
91
+ assert Logs.new.passed(
92
+ OpenStruct.new(
93
+ attachments: [
94
+ OpenStruct.new(
95
+ attrs: { "size" => 10_241, "filename" => "catalina.txt" }
96
+ )
97
+ ]
98
+ )
99
+ )
100
+ end
101
+
102
+ test "zip log file is present" do
103
+ assert Logs.new.passed(
104
+ OpenStruct.new(
105
+ attachments: [
106
+ OpenStruct.new(
107
+ attrs: { "size" => 10_241, "filename" => "catalina.log.zip" }
108
+ )
109
+ ]
110
+ )
111
+ )
112
+ end
113
+
114
+ test "gz log file is present" do
115
+ assert Logs.new.passed(
116
+ OpenStruct.new(
117
+ attachments: [
118
+ OpenStruct.new(
119
+ attrs: { "size" => 10_241, "filename" => "catalina.log.gz" }
120
+ )
121
+ ]
122
+ )
123
+ )
124
+ end
125
+
126
+ test "tar gz log file is present" do
127
+ assert Logs.new.passed(
128
+ OpenStruct.new(
129
+ attachments: [
130
+ OpenStruct.new(
131
+ attrs: { "size" => 10_241, "filename" => "catalina.log.tar.gz" }
72
132
  )
73
133
  ]
74
134
  )
@@ -0,0 +1,138 @@
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 "../../../test"
26
+ require_relative "../../../../lib/lazylead/opts"
27
+ require_relative "../../../../lib/lazylead/smtp"
28
+ require_relative "../../../../lib/lazylead/postman"
29
+ require_relative "../../../../lib/lazylead/system/jira"
30
+ require_relative "../../../../lib/lazylead/task/accuracy/onlyll"
31
+
32
+ module Lazylead
33
+ class OnlyLLTest < Lazylead::Test
34
+ # In current tests the grid label is 'PullRequest'.
35
+ # The default grid labels are 0%, 10%, 20%, etc., the reason why
36
+ # 'PullRequest' label is used here as we don't have 0%, 10%, etc.
37
+ # on https://jira.spring.io.
38
+ test "grid label found" do
39
+ assert Labels.new(
40
+ NoAuthJira.new("https://jira.spring.io").issues("key=XD-3725").first,
41
+ Opts.new("grid" => "PullRequest, ,")
42
+ ).exists?
43
+ end
44
+
45
+ test "grid label set by ll" do
46
+ assert Labels.new(
47
+ NoAuthJira.new("https://jira.spring.io")
48
+ .issues("key=XD-3725", expand: "changelog")
49
+ .first,
50
+ Opts.new("grid" => "PullRequest", "author" => "grussell")
51
+ ).valid?
52
+ end
53
+
54
+ test "email notification" do
55
+ Lazylead::Smtp.new.enable
56
+ Lazylead::Task::OnlyLL.new.run(
57
+ NoAuthJira.new("https://jira.spring.io"),
58
+ Postman.new,
59
+ Opts.new(
60
+ "from" => "ll@fake.com",
61
+ "to" => "lead@fake.com",
62
+ "grid" => "PullRequest",
63
+ "author" => "LL",
64
+ "jql" => "key=XD-3725",
65
+ "max_results" => 200,
66
+ "subject" => "[LL] Only",
67
+ "fields" => "priority,summary,reporter,labels",
68
+ "template" => "lib/messages/only_ll.erb"
69
+ )
70
+ )
71
+ assert_email "[LL] Only",
72
+ %w[XD-3725 Blocker EmbeddedHeadersMessageConverter]
73
+ end
74
+
75
+ test "detect score" do
76
+ assert_equal "PullRequest",
77
+ Labels.new(
78
+ NoAuthJira.new("https://jira.spring.io")
79
+ .issues("key=XD-3725", expand: "changelog")
80
+ .first,
81
+ Opts.new(
82
+ "grid" => "PullRequest",
83
+ "author" => "grussell"
84
+ )
85
+ ).score
86
+ end
87
+
88
+ test "multiple scores in the same ticket" do
89
+ assert_equal "10%",
90
+ Labels.new(
91
+ Struct.new(:key) do
92
+ def history
93
+ [{ "id" => "287906", "author" => { "self" => "https://jira.spring.io/rest/api/2/user?username=sy", "name" => "sy", "key" => "sy", "emailAddress" => "san at pivotal dot io", "avatarUrls" => { "48x48" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=48", "24x24" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=24", "16x16" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=16", "32x32" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=32" }, "displayName" => "sy an", "active" => true, "timeZone" => "America/Los_Angeles" }, "created" => "2015-12-17T18:12:35.853+0000", "items" => [{ "field" => "Fix Version", "fieldtype" => "jira", "from" => nil, "fromString" => nil, "to" => "15424", "toString" => "1.3.1" }] }, { "id" => "287913", "author" => { "self" => "https://jira.spring.io/rest/api/2/user?username=ll", "name" => "ll", "key" => "ll", "emailAddress" => "ll at pivotal dot io", "avatarUrls" => { "48x48" => "https://www.gravatar.com/avatar/0037f772e271b0d90bd62361768cb820?d=mm&s=48", "24x24" => "https://www.gravatar.com/avatar/0037f772e271b0d90bd62361768cb820?d=mm&s=24", "16x16" => "https://www.gravatar.com/avatar/0037f772e271b0d90bd62361768cb820?d=mm&s=16", "32x32" => "https://www.gravatar.com/avatar/0037f772e271b0d90bd62361768cb820?d=mm&s=32" }, "displayName" => "Y LL", "active" => true, "timeZone" => "America/New_York" }, "created" => "2015-12-17T18:14:34.085+0000", "items" => [{ "field" => "assignee", "fieldtype" => "jira", "from" => nil, "fromString" => nil, "to" => "ll", "toString" => "Y LL" }] }, { "id" => "287915", "author" => { "self" => "https://jira.spring.io/rest/api/2/user?username=sy", "name" => "sy", "key" => "sy", "emailAddress" => "san at pivotal dot io", "avatarUrls" => { "48x48" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=48", "24x24" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=24", "16x16" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=16", "32x32" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=32" }, "displayName" => "sy an", "active" => true, "timeZone" => "America/Los_Angeles" }, "created" => "2015-12-17T18:19:36.118+0000", "items" => [{ "field" => "Sprint", "fieldtype" => "custom", "from" => nil, "fromString" => nil, "to" => "106", "toString" => "Sprint 64" }] }, { "id" => "287916", "author" => { "self" => "https://jira.spring.io/rest/api/2/user?username=sy", "name" => "sy", "key" => "sy", "emailAddress" => "san at pivotal dot io", "avatarUrls" => { "48x48" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=48", "24x24" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=24", "16x16" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=16", "32x32" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=32" }, "displayName" => "sy an", "active" => true, "timeZone" => "America/Los_Angeles" }, "created" => "2015-12-17T18:19:36.162+0000", "items" => [{ "field" => "Rank", "fieldtype" => "custom", "from" => "", "fromString" => "", "to" => "", "toString" => "Ranked higher" }] }, { "id" => "287921", "author" => { "self" => "https://jira.spring.io/rest/api/2/user?username=ll", "name" => "ll", "key" => "ll", "emailAddress" => "ll at pivotal dot io", "avatarUrls" => { "48x48" => "https://www.gravatar.com/avatar/0037f772e271b0d90bd62361768cb820?d=mm&s=48", "24x24" => "https://www.gravatar.com/avatar/0037f772e271b0d90bd62361768cb820?d=mm&s=24", "16x16" => "https://www.gravatar.com/avatar/0037f772e271b0d90bd62361768cb820?d=mm&s=16", "32x32" => "https://www.gravatar.com/avatar/0037f772e271b0d90bd62361768cb820?d=mm&s=32" }, "displayName" => "Y LL", "active" => true, "timeZone" => "America/New_York" }, "created" => "2015-12-17T18:30:47.508+0000", "items" => [{ "field" => "status", "fieldtype" => "jira", "from" => "10000", "fromString" => "To Do", "to" => "3", "toString" => "In Progress" }] }, { "id" => "287922", "author" => { "self" => "https://jira.spring.io/rest/api/2/user?username=ll", "name" => "ll", "key" => "ll", "emailAddress" => "ll at pivotal dot io", "avatarUrls" => { "48x48" => "https://www.gravatar.com/avatar/0037f772e271b0d90bd62361768cb820?d=mm&s=48", "24x24" => "https://www.gravatar.com/avatar/0037f772e271b0d90bd62361768cb820?d=mm&s=24", "16x16" => "https://www.gravatar.com/avatar/0037f772e271b0d90bd62361768cb820?d=mm&s=16", "32x32" => "https://www.gravatar.com/avatar/0037f772e271b0d90bd62361768cb820?d=mm&s=32" }, "displayName" => "Y LL", "active" => true, "timeZone" => "America/New_York" }, "created" => "2015-12-17T18:31:54.137+0000", "items" => [{ "field" => "Pull Request URL", "fieldtype" => "custom", "from" => nil, "fromString" => nil, "to" => nil, "toString" => "https://github.com/spring-projects/spring-xd/pull/1872" }, { "field" => "labels", "fieldtype" => "jira", "from" => nil, "fromString" => "", "to" => nil, "toString" => "10% 20%" }] }, { "id" => "288214", "author" => { "self" => "https://jira.spring.io/rest/api/2/user?username=sy", "name" => "sy", "key" => "sy", "emailAddress" => "san at pivotal dot io", "avatarUrls" => { "48x48" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=48", "24x24" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=24", "16x16" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=16", "32x32" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=32" }, "displayName" => "sy an", "active" => true, "timeZone" => "America/Los_Angeles" }, "created" => "2015-12-25T00:16:09.649+0000", "items" => [{ "field" => "status", "fieldtype" => "jira", "from" => "3", "fromString" => "In Progress", "to" => "10006", "toString" => "In PR" }] }, { "id" => "288215", "author" => { "self" => "https://jira.spring.io/rest/api/2/user?username=sy", "name" => "sy", "key" => "sy", "emailAddress" => "san at pivotal dot io", "avatarUrls" => { "48x48" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=48", "24x24" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=24", "16x16" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=16", "32x32" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=32" }, "displayName" => "sy an", "active" => true, "timeZone" => "America/Los_Angeles" }, "created" => "2015-12-25T00:16:17.499+0000", "items" => [{ "field" => "Actual Story Points", "fieldtype" => "custom", "from" => nil, "fromString" => nil, "to" => nil, "toString" => "1" }, { "field" => "resolution", "fieldtype" => "jira", "from" => nil, "fromString" => nil, "to" => "8", "toString" => "Complete" }, { "field" => "status", "fieldtype" => "jira", "from" => "10006", "fromString" => "In PR", "to" => "10001", "toString" => "Done" }] }]
94
+ end
95
+ end.new("XD-3725"),
96
+ Opts.new("grid" => "10%,20%,30%", "author" => "ll")
97
+ ).score
98
+ end
99
+
100
+ test "sort of percents" do
101
+ assert_equal %w[10% 20% 30%], %w[30% 10% 20%].sort
102
+ end
103
+
104
+ test "ensure that violators found" do
105
+ assert_equal "Aron set 40%",
106
+ Labels.new(
107
+ Struct.new(:key) do
108
+ def history
109
+ [
110
+ { "author" => { "name" => "sy", "key" => "sy", "displayName" => "S N" }, "items" => [{ "field" => "Fix Version", "fieldtype" => "jira", "from" => nil, "fromString" => nil, "to" => "15424", "toString" => "1.3.1" }] },
111
+ { "author" => { "name" => "ll", "key" => "ll", "displayName" => "L L" }, "items" => [{ "field" => "assignee", "fieldtype" => "jira", "from" => nil, "fromString" => nil, "to" => "ll", "toString" => "ll" }] },
112
+ { "author" => { "name" => "sy", "key" => "sy", "displayName" => "S N" }, "items" => [{ "field" => "Sprint", "fieldtype" => "custom", "from" => nil, "fromString" => nil, "to" => "106", "toString" => "Sprint 64" }] },
113
+ { "author" => { "name" => "sy", "key" => "sy", "displayName" => "S N" }, "items" => [{ "field" => "Rank", "fieldtype" => "custom", "from" => "", "fromString" => "", "to" => "", "toString" => "Ranked higher" }] },
114
+ { "author" => { "name" => "ll", "key" => "ll", "displayName" => "L L" }, "items" => [{ "field" => "status", "fieldtype" => "jira", "from" => "10000", "fromString" => "To Do", "to" => "3", "toString" => "In Progress" }] },
115
+ { "author" => { "name" => "ll", "key" => "ll", "displayName" => "L L" }, "items" => [{ "field" => "assignee", "fieldtype" => "jira", "from" => nil, "fromString" => nil, "to" => "ll", "toString" => "ll" }, { "field" => "labels", "fieldtype" => "jira", "from" => nil, "fromString" => "", "to" => nil, "toString" => "20%" }] },
116
+ { "author" => { "name" => "sy", "key" => "sy", "displayName" => "S N" }, "items" => [{ "field" => "Actual Story Points", "fieldtype" => "custom", "from" => nil, "fromString" => nil, "to" => nil, "toString" => "1" }, { "field" => "resolution", "fieldtype" => "jira", "from" => nil, "fromString" => nil, "to" => "8", "toString" => "Complete" }, { "field" => "status", "fieldtype" => "jira", "from" => "10006", "fromString" => "In PR", "to" => "10001", "toString" => "Done" }] },
117
+ { "author" => { "name" => "ap", "key" => "ap", "displayName" => "Aron" }, "items" => [{ "field" => "labels", "fieldtype" => "jira", "from" => nil, "fromString" => "", "to" => nil, "toString" => "abc 40%" }] },
118
+ { "author" => { "name" => "sy", "key" => "sy", "displayName" => "S N" }, "items" => [{ "field" => "status", "fieldtype" => "jira", "from" => "3", "fromString" => "In Progress", "to" => "10006", "toString" => "In PR" }] }
119
+ ]
120
+ end
121
+ end.new("XD-3725"),
122
+ Opts.new("grid" => "10%,20%,30%,40%", "author" => "ll")
123
+ ).violators.first
124
+ end
125
+
126
+ test "violators should consider already existing LL grid labels" do
127
+ assert_equal "Aron set 40%",
128
+ Labels.new(
129
+ Struct.new(:key) do
130
+ def history
131
+ [{ "author" => { "name" => "ap", "key" => "ap", "displayName" => "Aron" }, "items" => [{ "field" => "labels", "fromString" => "0%", "toString" => "0% abc 40%" }] }]
132
+ end
133
+ end.new("XD-3725"),
134
+ Opts.new("grid" => "10%,20%,30%,40%", "author" => "ll")
135
+ ).violators.first
136
+ end
137
+ end
138
+ end