jira-auto-tool 0.1.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 (139) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +291 -0
  4. data/CHANGELOG.md +5 -0
  5. data/CODE_OF_CONDUCT.md +132 -0
  6. data/Guardfile +105 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +159 -0
  9. data/Rakefile +20 -0
  10. data/bin/jira-auto-tool +57 -0
  11. data/bin/jira-auto-tool.bat +2 -0
  12. data/bin/setup +8 -0
  13. data/bin/setup-dev-win.bat +3 -0
  14. data/cucumber.yml +7 -0
  15. data/features/align_sprint_time_in_dates.feature +33 -0
  16. data/features/assign_tickets_to_team_sprints.feature +73 -0
  17. data/features/cache_boards.feature +24 -0
  18. data/features/control_http_request_rate_limit.feature +17 -0
  19. data/features/create_sprints_using_existing_ones_as_reference.feature +79 -0
  20. data/features/list_boards.feature +12 -0
  21. data/features/list_project_fields.feature +89 -0
  22. data/features/list_sprint_prefixes.feature +77 -0
  23. data/features/quarterly_add_sprints_using_existing_ones_as_a_reference.feature +71 -0
  24. data/features/quarterly_create_sprints_until_specific_date.feature +75 -0
  25. data/features/quarterly_rename_sprints.feature +179 -0
  26. data/features/rename_sprints.feature +203 -0
  27. data/features/self_documented_command_line.feature +15 -0
  28. data/features/sprint_filtering.feature +111 -0
  29. data/features/step_definitions/execution_context_steps.rb +33 -0
  30. data/features/step_definitions/jira_board_steps.rb +102 -0
  31. data/features/step_definitions/jira_ticket_steps.rb +63 -0
  32. data/features/support/10.setup_cucumber.rb +10 -0
  33. data/features/support/env.rb +25 -0
  34. data/features/support/hooks.rb +25 -0
  35. data/features/support/setup_rspec.rb +14 -0
  36. data/features/support/setup_simplecov.rb +5 -0
  37. data/features/update_sprint_end_date_and_shift_following_ones.feature +52 -0
  38. data/lib/jira/auto/tool/board/cache.rb +67 -0
  39. data/lib/jira/auto/tool/board/unavailable_board.rb +36 -0
  40. data/lib/jira/auto/tool/board.rb +105 -0
  41. data/lib/jira/auto/tool/board_controller/options.rb +32 -0
  42. data/lib/jira/auto/tool/board_controller.rb +88 -0
  43. data/lib/jira/auto/tool/common_options.rb +37 -0
  44. data/lib/jira/auto/tool/config/options.rb +19 -0
  45. data/lib/jira/auto/tool/config.rb +64 -0
  46. data/lib/jira/auto/tool/fetch_custom_field_options.rb +47 -0
  47. data/lib/jira/auto/tool/field.rb +59 -0
  48. data/lib/jira/auto/tool/field_controller.rb +50 -0
  49. data/lib/jira/auto/tool/field_option.rb +35 -0
  50. data/lib/jira/auto/tool/get_createmeta_for_project.rb +24 -0
  51. data/lib/jira/auto/tool/helpers/environment_based_value.rb +96 -0
  52. data/lib/jira/auto/tool/helpers/option_parser.rb +16 -0
  53. data/lib/jira/auto/tool/helpers/overridable_time.rb +18 -0
  54. data/lib/jira/auto/tool/helpers/pagination.rb +50 -0
  55. data/lib/jira/auto/tool/jira_http_options.rb +20 -0
  56. data/lib/jira/auto/tool/next_sprint_creator.rb +60 -0
  57. data/lib/jira/auto/tool/performer/options.rb +76 -0
  58. data/lib/jira/auto/tool/performer/planning_increment_sprint_creator.rb +42 -0
  59. data/lib/jira/auto/tool/performer/prefix_sprint_updater.rb +42 -0
  60. data/lib/jira/auto/tool/performer/quarterly_sprint_renamer/next_name_generator.rb +60 -0
  61. data/lib/jira/auto/tool/performer/quarterly_sprint_renamer.rb +19 -0
  62. data/lib/jira/auto/tool/performer/sprint_end_date_updater.rb +55 -0
  63. data/lib/jira/auto/tool/performer/sprint_renamer/keep_same_name_generator.rb +19 -0
  64. data/lib/jira/auto/tool/performer/sprint_renamer/next_name_generator.rb +47 -0
  65. data/lib/jira/auto/tool/performer/sprint_renamer.rb +55 -0
  66. data/lib/jira/auto/tool/performer/sprint_time_in_dates_aligner.rb +52 -0
  67. data/lib/jira/auto/tool/project/options.rb +22 -0
  68. data/lib/jira/auto/tool/project/ticket_fields.rb +70 -0
  69. data/lib/jira/auto/tool/project.rb +40 -0
  70. data/lib/jira/auto/tool/rate_limited_jira_client.rb +50 -0
  71. data/lib/jira/auto/tool/request_builder/field_context_fetcher.rb +78 -0
  72. data/lib/jira/auto/tool/request_builder/field_option_fetcher.rb +54 -0
  73. data/lib/jira/auto/tool/request_builder/get.rb +29 -0
  74. data/lib/jira/auto/tool/request_builder/sprint_creator.rb +112 -0
  75. data/lib/jira/auto/tool/request_builder/sprint_state_updater.rb +60 -0
  76. data/lib/jira/auto/tool/request_builder.rb +89 -0
  77. data/lib/jira/auto/tool/setup_logging.rb +35 -0
  78. data/lib/jira/auto/tool/sprint/name.rb +105 -0
  79. data/lib/jira/auto/tool/sprint/prefix.rb +66 -0
  80. data/lib/jira/auto/tool/sprint.rb +183 -0
  81. data/lib/jira/auto/tool/sprint_controller/options.rb +61 -0
  82. data/lib/jira/auto/tool/sprint_controller.rb +152 -0
  83. data/lib/jira/auto/tool/sprint_state_controller.rb +58 -0
  84. data/lib/jira/auto/tool/team.rb +23 -0
  85. data/lib/jira/auto/tool/team_sprint_prefix_mapper/options.rb +27 -0
  86. data/lib/jira/auto/tool/team_sprint_prefix_mapper.rb +62 -0
  87. data/lib/jira/auto/tool/team_sprint_ticket_dispatcher.rb +76 -0
  88. data/lib/jira/auto/tool/ticket.rb +110 -0
  89. data/lib/jira/auto/tool/until_date.rb +68 -0
  90. data/lib/jira/auto/tool/version.rb +9 -0
  91. data/lib/jira/auto/tool.rb +216 -0
  92. data/sig/jira/sprint/tool.rbs +8 -0
  93. data/spec/jira/auto/tool/board/cache_spec.rb +179 -0
  94. data/spec/jira/auto/tool/board/unavailable_board_spec.rb +34 -0
  95. data/spec/jira/auto/tool/board_controller/options_spec.rb +52 -0
  96. data/spec/jira/auto/tool/board_controller_spec.rb +154 -0
  97. data/spec/jira/auto/tool/board_spec.rb +163 -0
  98. data/spec/jira/auto/tool/common_options_spec.rb +49 -0
  99. data/spec/jira/auto/tool/config_spec.rb +108 -0
  100. data/spec/jira/auto/tool/field_controller_spec.rb +121 -0
  101. data/spec/jira/auto/tool/field_option_spec.rb +42 -0
  102. data/spec/jira/auto/tool/field_spec.rb +99 -0
  103. data/spec/jira/auto/tool/helpers/environment_based_value_spec.rb +21 -0
  104. data/spec/jira/auto/tool/helpers/option_parser_spec.rb +21 -0
  105. data/spec/jira/auto/tool/helpers/overridable_time_spec.rb +43 -0
  106. data/spec/jira/auto/tool/helpers/pagination_spec.rb +72 -0
  107. data/spec/jira/auto/tool/jira_http_options_spec.rb +32 -0
  108. data/spec/jira/auto/tool/next_sprint_creator_spec.rb +85 -0
  109. data/spec/jira/auto/tool/performer/option_spec.rb +55 -0
  110. data/spec/jira/auto/tool/performer/planning_increment_sprint_creator_spec.rb +62 -0
  111. data/spec/jira/auto/tool/performer/prefix_sprint_updater_spec.rb +35 -0
  112. data/spec/jira/auto/tool/performer/quarterly_sprint_renamer/next_name_generator_spec.rb +175 -0
  113. data/spec/jira/auto/tool/performer/quarterly_sprint_renamer_spec.rb +239 -0
  114. data/spec/jira/auto/tool/performer/sprint_end_date_updater_spec.rb +90 -0
  115. data/spec/jira/auto/tool/performer/sprint_renamer/keep_same_name_generator_spec.rb +12 -0
  116. data/spec/jira/auto/tool/performer/sprint_renamer/next_name_generator_spec.rb +129 -0
  117. data/spec/jira/auto/tool/performer/sprint_renamer_spec.rb +240 -0
  118. data/spec/jira/auto/tool/performer/sprint_time_in_dates_aligner_spec.rb +132 -0
  119. data/spec/jira/auto/tool/project/ticket_fields_spec.rb +390 -0
  120. data/spec/jira/auto/tool/project_spec.rb +31 -0
  121. data/spec/jira/auto/tool/rate_limited_jira_client_spec.rb +82 -0
  122. data/spec/jira/auto/tool/request_builder/field_context_fetcher_spec.rb +54 -0
  123. data/spec/jira/auto/tool/request_builder/field_option_fetcher_spec.rb +64 -0
  124. data/spec/jira/auto/tool/request_builder/get_spec.rb +40 -0
  125. data/spec/jira/auto/tool/request_builder/sprint_creator_spec.rb +179 -0
  126. data/spec/jira/auto/tool/request_builder/sprint_state_updater_spec.rb +31 -0
  127. data/spec/jira/auto/tool/request_builder_spec.rb +73 -0
  128. data/spec/jira/auto/tool/sprint/name_spec.rb +101 -0
  129. data/spec/jira/auto/tool/sprint/prefix_spec.rb +207 -0
  130. data/spec/jira/auto/tool/sprint_controller_spec.rb +406 -0
  131. data/spec/jira/auto/tool/sprint_spec.rb +309 -0
  132. data/spec/jira/auto/tool/team_spec.rb +21 -0
  133. data/spec/jira/auto/tool/team_sprint_prefix_mapper_spec.rb +97 -0
  134. data/spec/jira/auto/tool/team_sprint_ticket_dispatcher_spec.rb +232 -0
  135. data/spec/jira/auto/tool/ticket_spec.rb +116 -0
  136. data/spec/jira/auto/tool/until_date_spec.rb +80 -0
  137. data/spec/jira/auto/tool_spec.rb +458 -0
  138. data/spec/spec_helper.rb +42 -0
  139. metadata +368 -0
@@ -0,0 +1,175 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rspec"
4
+
5
+ require "jira/auto/tool/performer/quarterly_sprint_renamer/next_name_generator"
6
+
7
+ RSpec.describe Jira::Auto::Tool::Performer::QuarterlySprintRenamer::NextNameGenerator do
8
+ def parsed_name(sprint_name)
9
+ Jira::Auto::Tool::Sprint::Name.parse(sprint_name)
10
+ end
11
+
12
+ describe "#new_name_of_sprint_next_to_first_renamed_sprint" do
13
+ subject(:new_name) { next_name_generator.new_name_of_sprint_next_to_first_renamed_sprint }
14
+
15
+ let(:next_name_generator) do
16
+ described_class.new(original_name_of_first_renamed_sprint, name_of_first_renamed_sprint)
17
+ end
18
+
19
+ context "when pulling sprint into previous planning interval" do
20
+ let(:original_name_of_first_renamed_sprint) { "prefix_23.2.1" }
21
+ let(:name_of_first_renamed_sprint) { "prefix_23.1.6" }
22
+
23
+ it("returns the original sprint name") { expect(new_name).to eq(parsed_name("prefix_23.2.1")) }
24
+ end
25
+
26
+ context "when renaming inside planning interval" do
27
+ let(:original_name_of_first_renamed_sprint) { "prefix_23.2.1" }
28
+ let(:name_of_first_renamed_sprint) { "prefix_23.2.4" }
29
+
30
+ it { expect(new_name).to eq(parsed_name("prefix_23.2.5")) }
31
+ end
32
+
33
+ context "when pushing sprint into next planning interval" do
34
+ let(:original_name_of_first_renamed_sprint) { "prefix_23.1.5" }
35
+ let(:name_of_first_renamed_sprint) { "prefix_23.2.2" }
36
+
37
+ it("returns the original sprint parsed name") { expect(new_name).to eq(parsed_name("prefix_23.2.3")) }
38
+ end
39
+ end
40
+
41
+ describe "#pulling_sprint_into_previous_planning_interval?" do
42
+ let(:next_name_generator) do
43
+ described_class.new(original_name_of_first_renamed_sprint, name_of_first_renamed_sprint)
44
+ end
45
+
46
+ context "when sprint goes to the preceding planning interval" do
47
+ let(:original_name_of_first_renamed_sprint) { "prefix_26.1.1" }
48
+ let(:name_of_first_renamed_sprint) { "prefix_25.2.1" }
49
+
50
+ it { expect(next_name_generator).to be_pulling_sprint_into_previous_planning_interval }
51
+ end
52
+
53
+ context "when sprint is renamed backward inside the current planning interval" do
54
+ let(:original_name_of_first_renamed_sprint) { "prefix_26.1.4" }
55
+ let(:name_of_first_renamed_sprint) { "prefix_26.1.1" }
56
+
57
+ it { expect(next_name_generator).not_to be_pulling_sprint_into_previous_planning_interval }
58
+ end
59
+
60
+ context "when sprint is renamed forward inside the current planning interval" do
61
+ let(:original_name_of_first_renamed_sprint) { "prefix_26.1.1" }
62
+ let(:name_of_first_renamed_sprint) { "prefix_26.1.4" }
63
+
64
+ it { expect(next_name_generator).not_to be_pulling_sprint_into_previous_planning_interval }
65
+ end
66
+
67
+ context "when sprint goes to the following planning interval" do
68
+ let(:original_name_of_first_renamed_sprint) { "prefix_25.1.5" }
69
+ let(:name_of_first_renamed_sprint) { "prefix_25.2.1" }
70
+
71
+ it { expect(next_name_generator).not_to be_pulling_sprint_into_previous_planning_interval }
72
+ end
73
+ end
74
+
75
+ describe "#next_name_in_planning_interval" do
76
+ let(:name_generator) { described_class.new(original_name_of_first_renamed_sprint, name_of_first_renamed_sprint) }
77
+ let(:next_names) { 4.times.collect { name_generator.next_name_in_planning_interval } }
78
+
79
+ context "when pulling to the previous planning interval" do
80
+ let(:original_name_of_first_renamed_sprint) { "prefix_25.2.1" }
81
+ let(:name_of_first_renamed_sprint) { "prefix_25.1.8" }
82
+
83
+ it "generates a new name consecutive to the previous one in the planning interval" do
84
+ expect(next_names).to eq(%w[prefix_25.2.1 prefix_25.2.2 prefix_25.2.3 prefix_25.2.4])
85
+ end
86
+ end
87
+
88
+ context "when renaming in the same planning interval" do
89
+ let(:original_name_of_first_renamed_sprint) { "prefix_25.1.5" }
90
+ let(:name_of_first_renamed_sprint) { "prefix_25.1.20" }
91
+
92
+ it "generates a new name consecutive to the previous one in the planning interval" do
93
+ expect(next_names).to eq(%w[prefix_25.1.21 prefix_25.1.22 prefix_25.1.23 prefix_25.1.24])
94
+ end
95
+ end
96
+
97
+ context "when pushing to the next planning interval" do
98
+ let(:original_name_of_first_renamed_sprint) { "prefix_25.1.5" }
99
+ let(:name_of_first_renamed_sprint) { "prefix_25.2.1" }
100
+
101
+ it "generates a new name consecutive to the previous one in the planning interval" do
102
+ expect(next_names).to eq(%w[prefix_25.2.2 prefix_25.2.3 prefix_25.2.4 prefix_25.2.5])
103
+ end
104
+ end
105
+ end
106
+
107
+ describe "#name_for" do
108
+ let(:name_generator) { described_class.new(original_name_of_first_renamed_sprint, name_of_first_renamed_sprint) }
109
+ let(:original_name_of_first_renamed_sprint) { "prefix_25.2.1" }
110
+ let(:name_of_first_renamed_sprint) { "prefix_25.1.8" }
111
+
112
+ context "when sprint name inside the planning interval" do
113
+ before do
114
+ allow(name_generator).to receive_messages(next_name_in_planning_interval: "next_name_in_planning_interval")
115
+ end
116
+
117
+ it { expect(name_generator.name_for("prefix_25.2.2")).to eq("next_name_in_planning_interval") }
118
+ end
119
+
120
+ context "when sprint name outside planning interval from first sprint to rename" do
121
+ let(:original_name_of_first_renamed_sprint) { "prefix_25.1.5" }
122
+ let(:name_of_first_renamed_sprint) { "prefix_25.1.20" }
123
+
124
+ it "the name stays unchanged" do
125
+ expect(name_generator.name_for("prefix_25.3.2")).to eq("prefix_25.3.2")
126
+ end
127
+ end
128
+ end
129
+
130
+ describe "#outside_planning_interval_of_sprint_next_to_first_renamed_sprint?" do
131
+ let(:name_generator) { described_class.new(original_name, new_name) }
132
+
133
+ def outside?(sprint_name)
134
+ name_generator.outside_planning_interval_of_sprint_next_to_first_renamed_sprint?(sprint_name)
135
+ end
136
+
137
+ context "when pulling sprint into previous planning interval" do
138
+ let(:original_name) { "prefix_25.2.1" }
139
+ let(:new_name) { "prefix_25.1.6" }
140
+
141
+ it { expect(outside?("prefix_25.1.3")).to be_truthy }
142
+ it { expect(outside?("prefix_25.2.1")).not_to be_truthy }
143
+ it { expect(outside?("prefix_25.2.3")).not_to be_truthy }
144
+ it { expect(outside?("prefix_25.3.1")).to be_truthy }
145
+ it { expect(outside?("prefix_25.3.2")).to be_truthy }
146
+ it { expect(outside?("prefix_25.4.2")).to be_truthy }
147
+ it { expect(outside?("prefix_26.1.1")).to be_truthy }
148
+ end
149
+
150
+ context "when sprint renamed inside planning interval" do
151
+ let(:original_name) { "prefix_25.2.5" }
152
+ let(:new_name) { "prefix_25.2.16" }
153
+
154
+ it { expect(outside?("prefix_25.1.5")).to be_truthy }
155
+ it { expect(outside?("prefix_25.2.1")).to be_falsy }
156
+ it { expect(outside?("prefix_25.2.20")).to be_falsy }
157
+ it { expect(outside?("prefix_25.3.2")).to be_truthy }
158
+ it { expect(outside?("prefix_25.4.2")).to be_truthy }
159
+ it { expect(outside?("prefix_26.1.1")).to be_truthy }
160
+ end
161
+
162
+ context "when pushing sprint into next planning interval" do
163
+ let(:original_name) { "prefix_25.1.5" }
164
+ let(:new_name) { "prefix_25.2.1" }
165
+
166
+ it { expect(outside?("prefix_25.1.5")).to be_truthy }
167
+ it { expect(outside?("prefix_25.2.1")).to be_falsy }
168
+ it { expect(outside?("prefix_25.2.3")).to be_falsy }
169
+ it { expect(outside?("prefix_25.3.1")).to be_truthy }
170
+ it { expect(outside?("prefix_25.3.2")).to be_truthy }
171
+ it { expect(outside?("prefix_25.4.2")).to be_truthy }
172
+ it { expect(outside?("prefix_26.1.1")).to be_truthy }
173
+ end
174
+ end
175
+ end
@@ -0,0 +1,239 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rspec"
4
+ require "jira/auto/tool/performer/quarterly_sprint_renamer"
5
+
6
+ RSpec.describe Jira::Auto::Tool::Performer::QuarterlySprintRenamer do
7
+ let(:sprint_renamer) { described_class.new(tool, from_string, to_string) }
8
+ let(:tool) { instance_double(Jira::Auto::Tool) }
9
+ let(:from_string) { "25.1.5" }
10
+ let(:to_string) { "25.2.1" }
11
+
12
+ describe "#from_string_regex" do
13
+ it { expect(sprint_renamer.from_string_regex).to eq(/25\.1\.5/) }
14
+ end
15
+
16
+ describe "#to_string" do
17
+ it { expect(sprint_renamer.to_string).to eq("25.2.1") }
18
+ end
19
+
20
+ describe "#acton_sprints_for_sprint_prefix" do
21
+ def create_sprint(name)
22
+ instance_double(Jira::Auto::Tool::Sprint, name: name, rename_to: nil)
23
+ end
24
+
25
+ let(:one_sprint) { create_sprint("a sprint name") }
26
+ let(:another_sprint) { create_sprint("another sprint name") }
27
+
28
+ let(:sprints) { [one_sprint, another_sprint] }
29
+
30
+ let(:prefix) { instance_double(Jira::Auto::Tool::Sprint::Prefix, name: "Food_Delivery", sprints: sprints) }
31
+
32
+ before do
33
+ allow(sprint_renamer).to receive_messages(calculate_sprint_new_names: ["a new name", "another new name"])
34
+ end
35
+
36
+ it "renames each sprint" do
37
+ sprint_renamer.act_on_sprints_for_sprint_prefix(prefix)
38
+
39
+ expect(sprints).to all have_received(:rename_to)
40
+ end
41
+ end
42
+
43
+ describe "#calculate_sprint_new_names" do
44
+ let(:sprint_names) do
45
+ %w[
46
+ Food_Delivery_25.1.2
47
+ Food_Delivery_25.1.3
48
+ Food_Delivery_25.1.4
49
+ Food_Delivery_25.1.5
50
+ Food_Delivery_25.2.1
51
+ Food_Delivery_25.2.2
52
+ Food_Delivery_25.2.3
53
+ Food_Delivery_25.2.4
54
+ Food_Delivery_25.2.5
55
+ ]
56
+ end
57
+
58
+ context "when pulling a sprint into the previous planning interval" do
59
+ let(:from_string) { "25.2.1" }
60
+ let(:to_string) { "25.1.6" }
61
+
62
+ let(:expected_new_sprint_names) do
63
+ %w[
64
+ Food_Delivery_25.1.2
65
+ Food_Delivery_25.1.3
66
+ Food_Delivery_25.1.4
67
+ Food_Delivery_25.1.5
68
+ Food_Delivery_25.1.6
69
+ Food_Delivery_25.2.1
70
+ Food_Delivery_25.2.2
71
+ Food_Delivery_25.2.3
72
+ Food_Delivery_25.2.4
73
+ ]
74
+ end
75
+
76
+ it { expect(sprint_renamer.calculate_sprint_new_names(sprint_names)).to eq(expected_new_sprint_names) }
77
+ end
78
+
79
+ context "when renaming sprint forward inside planning interval" do
80
+ let(:from_string) { "25.2.1" }
81
+ let(:to_string) { "25.2.10" }
82
+
83
+ let(:expected_new_sprint_names) do
84
+ %w[
85
+ Food_Delivery_25.1.2
86
+ Food_Delivery_25.1.3
87
+ Food_Delivery_25.1.4
88
+ Food_Delivery_25.1.5
89
+ Food_Delivery_25.2.10
90
+ Food_Delivery_25.2.11
91
+ Food_Delivery_25.2.12
92
+ Food_Delivery_25.2.13
93
+ Food_Delivery_25.2.14
94
+ ]
95
+ end
96
+
97
+ it do
98
+ expect(sprint_renamer.calculate_sprint_new_names(["Food_Delivery_25.1.5"]))
99
+ .to eq(["Food_Delivery_25.1.5"])
100
+ end
101
+
102
+ it { expect(sprint_renamer.calculate_sprint_new_names(sprint_names)).to eq(expected_new_sprint_names) }
103
+ end
104
+
105
+ context "when renaming sprint backward inside planning interval" do
106
+ let(:from_string) { "25.2.10" }
107
+ let(:to_string) { "25.2.1" }
108
+
109
+ let(:sprint_names) do
110
+ %w[
111
+ Food_Delivery_25.1.2
112
+ Food_Delivery_25.1.3
113
+ Food_Delivery_25.1.4
114
+ Food_Delivery_25.1.5
115
+ Food_Delivery_25.2.10
116
+ Food_Delivery_25.2.11
117
+ Food_Delivery_25.2.12
118
+ Food_Delivery_25.2.13
119
+ Food_Delivery_25.2.14
120
+ ]
121
+ end
122
+
123
+ let(:expected_new_sprint_names) do
124
+ %w[
125
+ Food_Delivery_25.1.2
126
+ Food_Delivery_25.1.3
127
+ Food_Delivery_25.1.4
128
+ Food_Delivery_25.1.5
129
+ Food_Delivery_25.2.1
130
+ Food_Delivery_25.2.2
131
+ Food_Delivery_25.2.3
132
+ Food_Delivery_25.2.4
133
+ Food_Delivery_25.2.5
134
+ ]
135
+ end
136
+
137
+ it do
138
+ expect(sprint_renamer.calculate_sprint_new_names(["Food_Delivery_25.1.5"]))
139
+ .to eq(["Food_Delivery_25.1.5"])
140
+ end
141
+
142
+ it { expect(sprint_renamer.calculate_sprint_new_names(sprint_names)).to eq(expected_new_sprint_names) }
143
+ end
144
+
145
+ context "when pushing a sprint to the next planning interval" do
146
+ let(:expected_new_sprint_names) do
147
+ %w[
148
+ Food_Delivery_25.1.2
149
+ Food_Delivery_25.1.3
150
+ Food_Delivery_25.1.4
151
+ Food_Delivery_25.2.1
152
+ Food_Delivery_25.2.2
153
+ Food_Delivery_25.2.3
154
+ Food_Delivery_25.2.4
155
+ Food_Delivery_25.2.5
156
+ Food_Delivery_25.2.6
157
+ ]
158
+ end
159
+
160
+ it { expect(sprint_renamer.calculate_sprint_new_names(["Food_Delivery_25.1.5"])).to eq(["Food_Delivery_25.2.1"]) }
161
+
162
+ it { expect(sprint_renamer.calculate_sprint_new_names(sprint_names)).to eq(expected_new_sprint_names) }
163
+ end
164
+
165
+ context "when sprints exist beyond the immediate planning interval of the sprint" do
166
+ let(:from_string) { "25.2.1" }
167
+ let(:to_string) { "25.1.6" }
168
+
169
+ let(:sprint_names) do
170
+ %w[
171
+ Food_Delivery_25.1.5
172
+ Food_Delivery_25.2.1
173
+ Food_Delivery_25.2.2
174
+ Food_Delivery_25.3.1
175
+ Food_Delivery_25.3.2
176
+ Food_Delivery_25.3.3
177
+ ]
178
+ end
179
+
180
+ let(:expected_new_sprint_names) do
181
+ %w[
182
+ Food_Delivery_25.1.5
183
+ Food_Delivery_25.1.6
184
+ Food_Delivery_25.2.1
185
+ Food_Delivery_25.3.1
186
+ Food_Delivery_25.3.2
187
+ Food_Delivery_25.3.3
188
+ ]
189
+ end
190
+
191
+ it "does not rename those sprints" do
192
+ expect(sprint_renamer.calculate_sprint_new_names(sprint_names)).to eq(expected_new_sprint_names)
193
+ end
194
+ end
195
+
196
+ context "when multiple sprints are matching the first sprint to rename" do
197
+ let(:from_string) { "25.2.1" }
198
+ let(:to_string) { "25.1.6" }
199
+
200
+ let(:sprint_names) do
201
+ %w[
202
+ Food_Delivery_25.1.5
203
+ Food_Delivery_25.2.1
204
+ Food_Delivery_25.2.1
205
+ Food_Delivery_25.2.1
206
+ Food_Delivery_25.2.1
207
+ ]
208
+ end
209
+
210
+ let(:expected_new_sprint_names) do
211
+ %w[
212
+ Food_Delivery_25.1.5
213
+ Food_Delivery_25.1.6
214
+ Food_Delivery_25.2.1
215
+ Food_Delivery_25.2.2
216
+ Food_Delivery_25.2.3
217
+ ]
218
+ end
219
+
220
+ it "does rename those sprints in sequence" do
221
+ expect(sprint_renamer.calculate_sprint_new_names(sprint_names)).to eq(expected_new_sprint_names)
222
+ end
223
+ end
224
+ end
225
+
226
+ describe "#first_sprint_to_act_on?" do
227
+ let(:sprint_renamer) { described_class.new(nil, "25.1.5", "25.2.1") }
228
+
229
+ def first_to_rename?(sprint_name)
230
+ sprint_renamer.first_sprint_to_act_on?(sprint_name)
231
+ end
232
+
233
+ it { expect(first_to_rename?("prefix_25.1.4")).not_to be_truthy }
234
+ it { expect(first_to_rename?("prefix_25.1.5")).to be_truthy }
235
+ it { expect(first_to_rename?("prefix_24.1.5")).not_to be_truthy }
236
+ it { expect(first_to_rename?("prefix_25.2.1")).not_to be_truthy }
237
+ it { expect(first_to_rename?("prefix_26.1.6")).not_to be_truthy }
238
+ end
239
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rspec"
4
+
5
+ require "jira/auto/tool/performer/sprint_end_date_updater"
6
+
7
+ module Jira
8
+ module Auto
9
+ class Tool
10
+ class Performer
11
+ class SprintEndDateUpdater
12
+ RSpec.describe SprintEndDateUpdater do
13
+ let(:updater) { described_class.new(tool, "25.2.2", new_end_date_string) }
14
+ let(:tool) { instance_double(Tool) }
15
+ let(:new_end_date_string) { "2025-02-14 15:38" }
16
+ let(:new_end_date) { get_date(new_end_date_string) }
17
+
18
+ def get_date(date_string)
19
+ Time.parse(date_string)
20
+ end
21
+
22
+ describe "#update_sprint_end_date" do
23
+ let(:sprint) { instance_double(Sprint, :end_date= => nil, :save => nil, :length_in_days => 10) }
24
+
25
+ it do
26
+ updater.update_sprint_end_date(sprint)
27
+
28
+ expect(sprint).to have_received(:end_date=).with(new_end_date)
29
+ expect(sprint).to have_received(:save)
30
+ end
31
+ end
32
+
33
+ describe "#shift_sprint_to_new_start_date" do
34
+ let(:sprint) { instance_double(Sprint, length_in_days: 10, save: nil) }
35
+
36
+ let(:new_start_date) { get_date("2025-03-21 15:38") }
37
+
38
+ it "keeps the the sprint length unchanged" do
39
+ allow(sprint).to receive(:start_date=).with(new_start_date)
40
+ allow(sprint).to receive(:end_date=).with(get_date("2025-03-31 15:38"))
41
+
42
+ updater.shift_sprint_to_new_start_date(sprint, new_start_date)
43
+
44
+ expect(sprint).to have_received(:save)
45
+ end
46
+ end
47
+
48
+ # rubocop:disable RSpec/MultipleMemoizedHelpers
49
+ describe "#act_on_sprints_for_sprint_prefix" do
50
+ def get_sprint(name, attributes)
51
+ instance_double(Sprint, name: name, to_s: name, **attributes)
52
+ end
53
+
54
+ let(:a_sprint_that_should_not_change) { get_sprint "Food_Delivery_25.2.1", end_date: nil }
55
+
56
+ let(:a_that_should_get_a_new_end_date) do
57
+ get_sprint "Food_Delivery_25.2.2", end_date: get_date("2025-03-21 15:38")
58
+ end
59
+
60
+ let(:a_sprint_that_should_get_shifted_with_a_new_start_date) do
61
+ get_sprint "Food_Delivery_25.2.3", end_date: get_date("2025-03-31 15:38")
62
+ end
63
+
64
+ let(:sprints) do
65
+ [a_sprint_that_should_not_change,
66
+ a_that_should_get_a_new_end_date,
67
+ a_sprint_that_should_get_shifted_with_a_new_start_date]
68
+ end
69
+
70
+ let(:sprint_prefix) { instance_double(Sprint::Prefix, sprints: sprints) }
71
+
72
+ it "the prefix sprints as per expectations" do
73
+ expect(updater).to receive(:do_nothing).with(a_sprint_that_should_not_change, nil)
74
+ expect(updater).to receive(:update_sprint_end_date).with(a_that_should_get_a_new_end_date)
75
+
76
+ expect(updater).to receive(:shift_sprint_to_new_start_date).with(
77
+ a_sprint_that_should_get_shifted_with_a_new_start_date,
78
+ get_date("2025-03-21 15:38")
79
+ )
80
+
81
+ updater.act_on_sprints_for_sprint_prefix(sprint_prefix)
82
+ end
83
+ end
84
+ # rubocop:enable RSpec/MultipleMemoizedHelpers
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rspec"
4
+
5
+ require "jira/auto/tool/performer/sprint_renamer/keep_same_name_generator"
6
+
7
+ RSpec.describe Jira::Auto::Tool::Performer::SprintRenamer::KeepSameNameGenerator do
8
+ let(:keep_same_name_generator) { described_class.new }
9
+ let(:sprint_name) { "random sprint name #{rand}" }
10
+
11
+ it { expect(keep_same_name_generator.name_for(sprint_name)).to eq(sprint_name) }
12
+ end
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rspec"
4
+
5
+ require "jira/auto/tool/performer/sprint_renamer/next_name_generator"
6
+
7
+ RSpec.describe Jira::Auto::Tool::Performer::SprintRenamer::NextNameGenerator do
8
+ def parsed_name(sprint_name)
9
+ Jira::Auto::Tool::Sprint::Name.parse(sprint_name)
10
+ end
11
+
12
+ describe "#new_name_of_sprint_next_to_first_renamed_sprint" do
13
+ subject(:new_name) { next_name_generator.new_name_of_sprint_next_to_first_renamed_sprint }
14
+
15
+ let(:next_name_generator) do
16
+ described_class.new(original_name_of_first_renamed_sprint, name_of_first_renamed_sprint)
17
+ end
18
+
19
+ context "when pulling sprint into previous planning interval" do
20
+ let(:original_name_of_first_renamed_sprint) { "prefix_23.2.1" }
21
+ let(:name_of_first_renamed_sprint) { "prefix_23.1.6" }
22
+
23
+ it("returns the original sprint name") { expect(new_name).to eq(parsed_name("prefix_23.1.7")) }
24
+ end
25
+
26
+ context "when renaming inside planning interval" do
27
+ let(:original_name_of_first_renamed_sprint) { "prefix_23.2.1" }
28
+ let(:name_of_first_renamed_sprint) { "prefix_23.2.4" }
29
+
30
+ it { expect(new_name).to eq(parsed_name("prefix_23.2.5")) }
31
+ end
32
+
33
+ context "when pushing sprint into next planning interval" do
34
+ let(:original_name_of_first_renamed_sprint) { "prefix_23.1.5" }
35
+ let(:name_of_first_renamed_sprint) { "prefix_23.2.2" }
36
+
37
+ it("returns the original sprint parsed name") { expect(new_name).to eq(parsed_name("prefix_23.2.3")) }
38
+ end
39
+ end
40
+
41
+ describe "#pulling_sprint_into_previous_planning_interval?" do
42
+ let(:next_name_generator) do
43
+ described_class.new(original_name_of_first_renamed_sprint, name_of_first_renamed_sprint)
44
+ end
45
+
46
+ context "when sprint goes to the preceding planning interval" do
47
+ let(:original_name_of_first_renamed_sprint) { "prefix_26.1.1" }
48
+ let(:name_of_first_renamed_sprint) { "prefix_25.2.1" }
49
+
50
+ it { expect(next_name_generator).to be_pulling_sprint_into_previous_planning_interval }
51
+ end
52
+
53
+ context "when sprint is renamed backward inside the current preceding planning interval" do
54
+ let(:original_name_of_first_renamed_sprint) { "prefix_26.1.4" }
55
+ let(:name_of_first_renamed_sprint) { "prefix_26.1.1" }
56
+
57
+ it { expect(next_name_generator).not_to be_pulling_sprint_into_previous_planning_interval }
58
+ end
59
+
60
+ context "when sprint is renamed forward inside the current planning interval" do
61
+ let(:original_name_of_first_renamed_sprint) { "prefix_26.1.1" }
62
+ let(:name_of_first_renamed_sprint) { "prefix_26.1.4" }
63
+
64
+ it { expect(next_name_generator).not_to be_pulling_sprint_into_previous_planning_interval }
65
+ end
66
+
67
+ context "when sprint goes to the following planning interval" do
68
+ let(:original_name_of_first_renamed_sprint) { "prefix_25.1.5" }
69
+ let(:name_of_first_renamed_sprint) { "prefix_25.2.1" }
70
+
71
+ it { expect(next_name_generator).not_to be_pulling_sprint_into_previous_planning_interval }
72
+ end
73
+ end
74
+
75
+ describe "#next_name_in_planning_interval" do
76
+ let(:name_generator) { described_class.new(original_name_of_first_renamed_sprint, name_of_first_renamed_sprint) }
77
+ let(:next_names) { 4.times.collect { name_generator.next_name_in_planning_interval } }
78
+
79
+ context "when pulling to the previous planning interval" do
80
+ let(:original_name_of_first_renamed_sprint) { "prefix_25.2.1" }
81
+ let(:name_of_first_renamed_sprint) { "prefix_25.1.8" }
82
+
83
+ it "generates a new name consecutive to the previous one in the planning interval" do
84
+ expect(next_names).to eq(%w[prefix_25.1.9 prefix_25.1.10 prefix_25.1.11 prefix_25.1.12])
85
+ end
86
+ end
87
+
88
+ context "when renaming in the same planning interval" do
89
+ let(:original_name_of_first_renamed_sprint) { "prefix_25.1.5" }
90
+ let(:name_of_first_renamed_sprint) { "prefix_25.1.20" }
91
+
92
+ it "generates a new name consecutive to the previous one in the planning interval" do
93
+ expect(next_names).to eq(%w[prefix_25.1.21 prefix_25.1.22 prefix_25.1.23 prefix_25.1.24])
94
+ end
95
+ end
96
+
97
+ context "when pushing to the next planning interval" do
98
+ let(:original_name_of_first_renamed_sprint) { "prefix_25.1.5" }
99
+ let(:name_of_first_renamed_sprint) { "prefix_25.2.1" }
100
+
101
+ it "generates a new name consecutive to the previous one in the planning interval" do
102
+ expect(next_names).to eq(%w[prefix_25.2.2 prefix_25.2.3 prefix_25.2.4 prefix_25.2.5])
103
+ end
104
+ end
105
+ end
106
+
107
+ describe "#name_for" do
108
+ let(:name_generator) { described_class.new(original_name_of_first_renamed_sprint, name_of_first_renamed_sprint) }
109
+ let(:original_name_of_first_renamed_sprint) { "prefix_25.2.1" }
110
+ let(:name_of_first_renamed_sprint) { "prefix_25.1.8" }
111
+
112
+ context "when sprint name inside the planning interval" do
113
+ before do
114
+ allow(name_generator).to receive_messages(next_name_in_planning_interval: "next_name_in_planning_interval")
115
+ end
116
+
117
+ it { expect(name_generator.name_for("prefix_25.2.2")).to eq("next_name_in_planning_interval") }
118
+ end
119
+
120
+ context "when sprint name outside planning interval" do
121
+ let(:original_name_of_first_renamed_sprint) { "prefix_25.1.5" }
122
+ let(:name_of_first_renamed_sprint) { "prefix_25.2.20" }
123
+
124
+ it "generates a new name consecutive to the previous one in the planning interval" do
125
+ expect(name_generator.name_for("prefix_25.3.2")).to eq("prefix_25.2.21")
126
+ end
127
+ end
128
+ end
129
+ end