lazylead 0.4.3 → 0.6.1

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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/.docs/accuracy.md +2 -2
  3. data/.docs/duedate_expired.md +3 -3
  4. data/.docs/propagate_down.md +3 -3
  5. data/.gitattributes +1 -0
  6. data/Rakefile +6 -3
  7. data/bin/lazylead +7 -5
  8. data/lazylead.gemspec +4 -3
  9. data/lib/lazylead/cli/app.rb +11 -3
  10. data/lib/lazylead/exchange.rb +15 -9
  11. data/lib/lazylead/log.rb +2 -1
  12. data/lib/lazylead/model.rb +42 -1
  13. data/lib/lazylead/opts.rb +13 -0
  14. data/lib/lazylead/postman.rb +13 -7
  15. data/lib/lazylead/schedule.rb +16 -15
  16. data/lib/lazylead/smtp.rb +3 -1
  17. data/lib/lazylead/system/jira.rb +65 -4
  18. data/lib/lazylead/task/accuracy/accuracy.rb +13 -8
  19. data/lib/lazylead/task/accuracy/affected_build.rb +2 -6
  20. data/lib/lazylead/task/accuracy/attachment.rb +44 -0
  21. data/lib/lazylead/task/accuracy/environment.rb +39 -0
  22. data/lib/lazylead/task/accuracy/logs.rb +42 -0
  23. data/lib/lazylead/task/accuracy/records.rb +45 -0
  24. data/lib/lazylead/task/accuracy/requirement.rb +9 -0
  25. data/lib/lazylead/task/accuracy/servers.rb +50 -0
  26. data/lib/lazylead/task/accuracy/stacktrace.rb +103 -0
  27. data/lib/lazylead/task/accuracy/testcase.rb +92 -0
  28. data/lib/lazylead/task/accuracy/wiki.rb +41 -0
  29. data/lib/lazylead/task/assignment.rb +96 -0
  30. data/lib/lazylead/task/echo.rb +18 -0
  31. data/lib/lazylead/task/fix_version.rb +13 -2
  32. data/lib/lazylead/task/svn/diff.rb +85 -0
  33. data/lib/lazylead/task/svn/grep.rb +111 -0
  34. data/lib/lazylead/task/svn/touch.rb +101 -0
  35. data/lib/lazylead/version.rb +1 -1
  36. data/lib/messages/illegal_assignee_change.erb +123 -0
  37. data/lib/messages/illegal_fixversion_change.erb +2 -0
  38. data/lib/messages/svn_diff.erb +110 -0
  39. data/lib/messages/svn_diff_attachment.erb +117 -0
  40. data/lib/messages/svn_grep.erb +114 -0
  41. data/license.txt +1 -1
  42. data/readme.md +5 -5
  43. data/test/lazylead/cli/app_test.rb +11 -11
  44. data/test/lazylead/model_test.rb +10 -0
  45. data/test/lazylead/system/jira_test.rb +41 -4
  46. data/test/lazylead/task/accuracy/accuracy_test.rb +1 -1
  47. data/test/lazylead/task/accuracy/affected_build_test.rb +2 -2
  48. data/test/lazylead/task/accuracy/attachment_test.rb +50 -0
  49. data/test/lazylead/task/accuracy/environment_test.rb +42 -0
  50. data/test/lazylead/task/accuracy/logs_test.rb +138 -0
  51. data/test/lazylead/task/accuracy/records_test.rb +60 -0
  52. data/test/lazylead/task/accuracy/score_test.rb +46 -0
  53. data/test/lazylead/task/accuracy/servers_test.rb +66 -0
  54. data/test/lazylead/task/accuracy/stacktrace_test.rb +340 -0
  55. data/test/lazylead/task/accuracy/testcase_test.rb +254 -0
  56. data/test/lazylead/task/accuracy/wiki_test.rb +40 -0
  57. data/test/lazylead/task/assignment_test.rb +53 -0
  58. data/test/lazylead/task/svn/diff_test.rb +97 -0
  59. data/test/lazylead/task/svn/grep_test.rb +61 -0
  60. data/test/lazylead/task/{touch_test.rb → svn/touch_test.rb} +8 -8
  61. data/test/test.rb +16 -0
  62. data/upgrades/sqlite/001-install-main-lazylead-tables.sql +1 -5
  63. data/upgrades/sqlite/999.testdata.sql +13 -17
  64. metadata +72 -20
  65. data/.travis.yml +0 -16
  66. data/lib/lazylead/task/touch.rb +0 -104
@@ -0,0 +1,117 @@
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) changed since <code><%= since_rev %></code> rev in <a href="<%= svn_url %>"><%= svn_url %></a>:</p>
88
+ <% stdout.split("------------------------------------------------------------------------").reject(&:blank?).reverse.each do |commit| %>
89
+ <div class="commit">
90
+ <% commit.split("\n").reject(&:blank?).each_with_index do |line, index| %>
91
+ <% if index.zero? %>
92
+ <% 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>
97
+ </p>
98
+ <% else %>
99
+ <% if line.start_with?("+++") || line.start_with?("---") %>
100
+ <p style="background: gainsboro;"><%= 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
+ <% end %>
110
+ </div>
111
+ <br/>
112
+ <% end %>
113
+ <p>Posted by
114
+ <a href="https://github.com/dgroup/lazylead">lazylead v<%= version %></a>.
115
+ </p>
116
+ </body>
117
+ </html>
@@ -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.lines[2..-1].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>
@@ -1,6 +1,6 @@
1
1
  The MIT License
2
2
 
3
- Copyright (c) 2019-2020 Yurii Dubinka
3
+ Copyright (c) 2019-2021 Yurii Dubinka
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"),
data/readme.md CHANGED
@@ -113,7 +113,7 @@ For simplicity, we are using [docker-compose](https://docs.docker.com/compose/):
113
113
  ll > docker-compose -f .github/tasks.yml up
114
114
  Creating lazylead ... done
115
115
  Attaching to lazylead
116
- lazylead | [2020-08-09T06:17:32] DEBUG [main] Version: 0.4.0
116
+ lazylead | [2020-08-09T06:17:32] DEBUG [main] Version: 0.5.0
117
117
  lazylead | [2020-08-09T06:17:32] DEBUG [main] Memory footprint at start is 52MB
118
118
  lazylead | [2020-08-09T06:17:32] DEBUG [main] Database: '/lazylead/db/ll.db', sql migration dir: '/lazylead/upgrades/sqlite'
119
119
  lazylead | [2020-08-09T06:17:32] DEBUG [main] Migration applied to /lazylead/db/ll.db from /lazylead/upgrades/sqlite
@@ -135,16 +135,16 @@ For simplicity, we are using [docker-compose](https://docs.docker.com/compose/):
135
135
  values (1, 'Dream team with lazylead', '{}');
136
136
  insert into systems(id, properties)
137
137
  values (1,'{"type":"Lazylead::Jira", "username":"${jira_user}", "password":"${jira_password}", "site":"${jira_url}", "context_path":""}');
138
- insert into tasks (name, cron, enabled, id, system, team_id, action, properties)
138
+ insert into tasks (name, schedule, enabled, id, system, team_id, action, properties)
139
139
  values ('Expired due dates',
140
- '0 8 * * 1-5',
140
+ 'cron:0 8 * * 1-5',
141
141
  'true',
142
142
  1, 1, 1,
143
143
  'Lazylead::Task::AssigneeAlert',
144
144
  '{"sql":"filter=555", "cc":"<youremail.com>", "subject":"[LL] Expired due dates", "template":"lib/messages/due_date_expired.erb", "postman":"Lazylead::Exchange"}');
145
145
 
146
146
  ```
147
- Yes, for task scheduling we are using [cron](https://crontab.guru).
147
+ Yes, for task scheduling we are using [cron](https://crontab.guru) here, but you may use other scheduling types from [rufus-scheduler](https://github.com/jmettraux/rufus-scheduler).
148
148
 
149
149
  4. Once you changed `./ll.db`, please restart the container using `docker-compose -f .github/tasks.yml restart`
150
150
  ```bash
@@ -154,7 +154,7 @@ For simplicity, we are using [docker-compose](https://docs.docker.com/compose/):
154
154
  check the logs and stop container if needed
155
155
  ```bash
156
156
  ll > docker logs lazylead
157
- lazylead | [2020-08-09T06:17:32] DEBUG [main] Version: 0.4.0
157
+ lazylead | [2020-08-09T06:17:32] DEBUG [main] Version: 0.5.0
158
158
  lazylead | [2020-08-09T06:17:32] DEBUG [main] Memory footprint at start is 52MB
159
159
  lazylead | [2020-08-09T06:17:32] DEBUG [main] Database: '/lazylead/db/ll.db', sql migration dir: '/lazylead/upgrades/sqlite'
160
160
  lazylead | [2020-08-09T06:17:32] DEBUG [main] Migration applied to /lazylead/db/ll.db from /lazylead/upgrades/sqlite
@@ -39,14 +39,14 @@ module Lazylead
39
39
  assert_tables "test/resources/#{no_ext(__FILE__)}.#{__method__}.db",
40
40
  systems: %w[id properties],
41
41
  teams: %w[id name properties],
42
- tasks: %w[id name cron system action team_id enabled properties]
42
+ tasks: %w[id name schedule system action team_id enabled properties]
43
43
  assert_fk "test/resources/#{no_ext(__FILE__)}.#{__method__}.db",
44
44
  %w[tasks team_id teams id],
45
45
  %w[tasks system systems id]
46
46
  end
47
47
 
48
48
  test "activesupport is activated for access to domain entities" do
49
- CLI::App.new(Log.new, Schedule.new(cling: false)).run(
49
+ CLI::App.new(Log.new, NoSchedule.new).run(
50
50
  home: ".",
51
51
  sqlite: "test/resources/#{no_ext(__FILE__)}.#{__method__}.db",
52
52
  vcs4sql: "upgrades/sqlite",
@@ -57,16 +57,16 @@ module Lazylead
57
57
  "Required team record wasn't found in the database"
58
58
  end
59
59
 
60
- # @todo #10/DEV Think about using "timecop" >v0.9.1 gem in order to make
61
- # E2E application skeleton https://stackoverflow.com/questions/59955571.
62
- # The depedency for gemspec should be after *thin* in .gemspec
63
- # ..
64
- # s.add_runtime_dependency "thin", "1.7.2"
65
- # s.add_runtime_dependency "timecop", "0.9.1"
66
- # ..
67
- # More https://github.com/travisjeffery/timecop
68
60
  test "scheduled task was triggered successfully" do
69
- skip "Not implemented yet"
61
+ CLI::App.new(Log.new, Schedule.new(cling: false)).run(
62
+ home: ".",
63
+ sqlite: "test/resources/#{no_ext(__FILE__)}.#{__method__}.db",
64
+ vcs4sql: "upgrades/sqlite",
65
+ testdata: true
66
+ )
67
+ sleep 0.4
68
+ assert (Time.now - 5.seconds) < Time.parse(File.open("test/resources/echo.txt").first),
69
+ "Scheduled task wasn't executed few seconds ago"
70
70
  end
71
71
  end
72
72
  end
@@ -72,5 +72,15 @@ 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
75
85
  end
76
86
  end
@@ -142,11 +142,48 @@ 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,
145
+ test "description is correct" do
146
+ assert_words %w[DATACMNS-1639\ moved\ entity\ instantiators],
147
147
  NoAuthJira.new("https://jira.spring.io")
148
- .issues("key in (DATAJDBC-480, DATAJDBC-500)", max_results: "1")
149
- .size
148
+ .issues("key=DATAJDBC-480")
149
+ .first
150
+ .description
151
+ end
152
+
153
+ test "component is correct" do
154
+ assert_equal %w[Stream\ Module],
155
+ NoAuthJira.new("https://jira.spring.io")
156
+ .issues("key=XD-3766")
157
+ .first
158
+ .components
159
+ end
160
+
161
+ test "field found" do
162
+ assert_includes NoAuthJira.new("https://jira.spring.io")
163
+ .issues("key=DATAJDBC-480")
164
+ .first["description"],
165
+ "DATACMNS-1639 moved "
166
+ end
167
+
168
+ test "field not found" do
169
+ assert NoAuthJira.new("https://jira.spring.io")
170
+ .issues("key=DATAJDBC-480")
171
+ .first["absent field"]
172
+ .blank?
173
+ end
174
+
175
+ test "labels found" do
176
+ assert_includes NoAuthJira.new("https://jira.spring.io")
177
+ .issues("key=XD-3766")
178
+ .first
179
+ .labels,
180
+ "Spring"
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
150
187
  end
151
188
  end
152
189
  end
@@ -40,7 +40,7 @@ module Lazylead
40
40
  Opts.new(
41
41
  "from" => "ll@fake.com",
42
42
  "to" => "lead@fake.com",
43
- "rules" => "Lazylead::RequirementAffectedBuild",
43
+ "rules" => "Lazylead::AffectedBuild",
44
44
  "silent" => "true",
45
45
  "colors" => {
46
46
  "0" => "#FF4F33",
@@ -28,13 +28,13 @@ require_relative "../../../../lib/lazylead/task/accuracy/affected_build"
28
28
  module Lazylead
29
29
  class AffectedBuildTest < Lazylead::Test
30
30
  test "affected version absent" do
31
- refute RequirementAffectedBuild.new.passed(
31
+ refute AffectedBuild.new.passed(
32
32
  OpenStruct.new(fields: { "versions" => [] })
33
33
  )
34
34
  end
35
35
 
36
36
  test "affected version provided" do
37
- assert RequirementAffectedBuild.new.passed(
37
+ assert AffectedBuild.new.passed(
38
38
  OpenStruct.new(fields: { "versions" => ["0.4.0"] })
39
39
  )
40
40
  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 "../../../test"
26
+ require_relative "../../../../lib/lazylead/log"
27
+ require_relative "../../../../lib/lazylead/system/jira"
28
+ require_relative "../../../../lib/lazylead/task/accuracy/attachment"
29
+
30
+ module Lazylead
31
+ class AttachmentTest < Lazylead::Test
32
+ class Txt < Attachment
33
+ def initialize
34
+ super "", 0, ""
35
+ end
36
+
37
+ def matching(attach)
38
+ "ConfigServerLogWithException.txt".eql? attach.attrs["filename"]
39
+ end
40
+ end
41
+
42
+ test "attachment is present" do
43
+ assert Txt.new.passed(
44
+ NoAuthJira.new("https://jira.spring.io")
45
+ .issues("key=XD-3761", fields: ["attachment"])
46
+ .first
47
+ )
48
+ end
49
+ end
50
+ end