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.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +291 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/Guardfile +105 -0
- data/LICENSE.txt +21 -0
- data/README.md +159 -0
- data/Rakefile +20 -0
- data/bin/jira-auto-tool +57 -0
- data/bin/jira-auto-tool.bat +2 -0
- data/bin/setup +8 -0
- data/bin/setup-dev-win.bat +3 -0
- data/cucumber.yml +7 -0
- data/features/align_sprint_time_in_dates.feature +33 -0
- data/features/assign_tickets_to_team_sprints.feature +73 -0
- data/features/cache_boards.feature +24 -0
- data/features/control_http_request_rate_limit.feature +17 -0
- data/features/create_sprints_using_existing_ones_as_reference.feature +79 -0
- data/features/list_boards.feature +12 -0
- data/features/list_project_fields.feature +89 -0
- data/features/list_sprint_prefixes.feature +77 -0
- data/features/quarterly_add_sprints_using_existing_ones_as_a_reference.feature +71 -0
- data/features/quarterly_create_sprints_until_specific_date.feature +75 -0
- data/features/quarterly_rename_sprints.feature +179 -0
- data/features/rename_sprints.feature +203 -0
- data/features/self_documented_command_line.feature +15 -0
- data/features/sprint_filtering.feature +111 -0
- data/features/step_definitions/execution_context_steps.rb +33 -0
- data/features/step_definitions/jira_board_steps.rb +102 -0
- data/features/step_definitions/jira_ticket_steps.rb +63 -0
- data/features/support/10.setup_cucumber.rb +10 -0
- data/features/support/env.rb +25 -0
- data/features/support/hooks.rb +25 -0
- data/features/support/setup_rspec.rb +14 -0
- data/features/support/setup_simplecov.rb +5 -0
- data/features/update_sprint_end_date_and_shift_following_ones.feature +52 -0
- data/lib/jira/auto/tool/board/cache.rb +67 -0
- data/lib/jira/auto/tool/board/unavailable_board.rb +36 -0
- data/lib/jira/auto/tool/board.rb +105 -0
- data/lib/jira/auto/tool/board_controller/options.rb +32 -0
- data/lib/jira/auto/tool/board_controller.rb +88 -0
- data/lib/jira/auto/tool/common_options.rb +37 -0
- data/lib/jira/auto/tool/config/options.rb +19 -0
- data/lib/jira/auto/tool/config.rb +64 -0
- data/lib/jira/auto/tool/fetch_custom_field_options.rb +47 -0
- data/lib/jira/auto/tool/field.rb +59 -0
- data/lib/jira/auto/tool/field_controller.rb +50 -0
- data/lib/jira/auto/tool/field_option.rb +35 -0
- data/lib/jira/auto/tool/get_createmeta_for_project.rb +24 -0
- data/lib/jira/auto/tool/helpers/environment_based_value.rb +96 -0
- data/lib/jira/auto/tool/helpers/option_parser.rb +16 -0
- data/lib/jira/auto/tool/helpers/overridable_time.rb +18 -0
- data/lib/jira/auto/tool/helpers/pagination.rb +50 -0
- data/lib/jira/auto/tool/jira_http_options.rb +20 -0
- data/lib/jira/auto/tool/next_sprint_creator.rb +60 -0
- data/lib/jira/auto/tool/performer/options.rb +76 -0
- data/lib/jira/auto/tool/performer/planning_increment_sprint_creator.rb +42 -0
- data/lib/jira/auto/tool/performer/prefix_sprint_updater.rb +42 -0
- data/lib/jira/auto/tool/performer/quarterly_sprint_renamer/next_name_generator.rb +60 -0
- data/lib/jira/auto/tool/performer/quarterly_sprint_renamer.rb +19 -0
- data/lib/jira/auto/tool/performer/sprint_end_date_updater.rb +55 -0
- data/lib/jira/auto/tool/performer/sprint_renamer/keep_same_name_generator.rb +19 -0
- data/lib/jira/auto/tool/performer/sprint_renamer/next_name_generator.rb +47 -0
- data/lib/jira/auto/tool/performer/sprint_renamer.rb +55 -0
- data/lib/jira/auto/tool/performer/sprint_time_in_dates_aligner.rb +52 -0
- data/lib/jira/auto/tool/project/options.rb +22 -0
- data/lib/jira/auto/tool/project/ticket_fields.rb +70 -0
- data/lib/jira/auto/tool/project.rb +40 -0
- data/lib/jira/auto/tool/rate_limited_jira_client.rb +50 -0
- data/lib/jira/auto/tool/request_builder/field_context_fetcher.rb +78 -0
- data/lib/jira/auto/tool/request_builder/field_option_fetcher.rb +54 -0
- data/lib/jira/auto/tool/request_builder/get.rb +29 -0
- data/lib/jira/auto/tool/request_builder/sprint_creator.rb +112 -0
- data/lib/jira/auto/tool/request_builder/sprint_state_updater.rb +60 -0
- data/lib/jira/auto/tool/request_builder.rb +89 -0
- data/lib/jira/auto/tool/setup_logging.rb +35 -0
- data/lib/jira/auto/tool/sprint/name.rb +105 -0
- data/lib/jira/auto/tool/sprint/prefix.rb +66 -0
- data/lib/jira/auto/tool/sprint.rb +183 -0
- data/lib/jira/auto/tool/sprint_controller/options.rb +61 -0
- data/lib/jira/auto/tool/sprint_controller.rb +152 -0
- data/lib/jira/auto/tool/sprint_state_controller.rb +58 -0
- data/lib/jira/auto/tool/team.rb +23 -0
- data/lib/jira/auto/tool/team_sprint_prefix_mapper/options.rb +27 -0
- data/lib/jira/auto/tool/team_sprint_prefix_mapper.rb +62 -0
- data/lib/jira/auto/tool/team_sprint_ticket_dispatcher.rb +76 -0
- data/lib/jira/auto/tool/ticket.rb +110 -0
- data/lib/jira/auto/tool/until_date.rb +68 -0
- data/lib/jira/auto/tool/version.rb +9 -0
- data/lib/jira/auto/tool.rb +216 -0
- data/sig/jira/sprint/tool.rbs +8 -0
- data/spec/jira/auto/tool/board/cache_spec.rb +179 -0
- data/spec/jira/auto/tool/board/unavailable_board_spec.rb +34 -0
- data/spec/jira/auto/tool/board_controller/options_spec.rb +52 -0
- data/spec/jira/auto/tool/board_controller_spec.rb +154 -0
- data/spec/jira/auto/tool/board_spec.rb +163 -0
- data/spec/jira/auto/tool/common_options_spec.rb +49 -0
- data/spec/jira/auto/tool/config_spec.rb +108 -0
- data/spec/jira/auto/tool/field_controller_spec.rb +121 -0
- data/spec/jira/auto/tool/field_option_spec.rb +42 -0
- data/spec/jira/auto/tool/field_spec.rb +99 -0
- data/spec/jira/auto/tool/helpers/environment_based_value_spec.rb +21 -0
- data/spec/jira/auto/tool/helpers/option_parser_spec.rb +21 -0
- data/spec/jira/auto/tool/helpers/overridable_time_spec.rb +43 -0
- data/spec/jira/auto/tool/helpers/pagination_spec.rb +72 -0
- data/spec/jira/auto/tool/jira_http_options_spec.rb +32 -0
- data/spec/jira/auto/tool/next_sprint_creator_spec.rb +85 -0
- data/spec/jira/auto/tool/performer/option_spec.rb +55 -0
- data/spec/jira/auto/tool/performer/planning_increment_sprint_creator_spec.rb +62 -0
- data/spec/jira/auto/tool/performer/prefix_sprint_updater_spec.rb +35 -0
- data/spec/jira/auto/tool/performer/quarterly_sprint_renamer/next_name_generator_spec.rb +175 -0
- data/spec/jira/auto/tool/performer/quarterly_sprint_renamer_spec.rb +239 -0
- data/spec/jira/auto/tool/performer/sprint_end_date_updater_spec.rb +90 -0
- data/spec/jira/auto/tool/performer/sprint_renamer/keep_same_name_generator_spec.rb +12 -0
- data/spec/jira/auto/tool/performer/sprint_renamer/next_name_generator_spec.rb +129 -0
- data/spec/jira/auto/tool/performer/sprint_renamer_spec.rb +240 -0
- data/spec/jira/auto/tool/performer/sprint_time_in_dates_aligner_spec.rb +132 -0
- data/spec/jira/auto/tool/project/ticket_fields_spec.rb +390 -0
- data/spec/jira/auto/tool/project_spec.rb +31 -0
- data/spec/jira/auto/tool/rate_limited_jira_client_spec.rb +82 -0
- data/spec/jira/auto/tool/request_builder/field_context_fetcher_spec.rb +54 -0
- data/spec/jira/auto/tool/request_builder/field_option_fetcher_spec.rb +64 -0
- data/spec/jira/auto/tool/request_builder/get_spec.rb +40 -0
- data/spec/jira/auto/tool/request_builder/sprint_creator_spec.rb +179 -0
- data/spec/jira/auto/tool/request_builder/sprint_state_updater_spec.rb +31 -0
- data/spec/jira/auto/tool/request_builder_spec.rb +73 -0
- data/spec/jira/auto/tool/sprint/name_spec.rb +101 -0
- data/spec/jira/auto/tool/sprint/prefix_spec.rb +207 -0
- data/spec/jira/auto/tool/sprint_controller_spec.rb +406 -0
- data/spec/jira/auto/tool/sprint_spec.rb +309 -0
- data/spec/jira/auto/tool/team_spec.rb +21 -0
- data/spec/jira/auto/tool/team_sprint_prefix_mapper_spec.rb +97 -0
- data/spec/jira/auto/tool/team_sprint_ticket_dispatcher_spec.rb +232 -0
- data/spec/jira/auto/tool/ticket_spec.rb +116 -0
- data/spec/jira/auto/tool/until_date_spec.rb +80 -0
- data/spec/jira/auto/tool_spec.rb +458 -0
- data/spec/spec_helper.rb +42 -0
- metadata +368 -0
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "delegate"
|
4
|
+
require "jira-ruby"
|
5
|
+
|
6
|
+
require_relative "sprint_state_controller"
|
7
|
+
require_relative "sprint/name"
|
8
|
+
|
9
|
+
module Jira
|
10
|
+
module Auto
|
11
|
+
class Tool
|
12
|
+
class NextSprintCreator
|
13
|
+
def self.create_sprint_following(sprint)
|
14
|
+
new(sprint).create
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :sprint
|
18
|
+
|
19
|
+
def initialize(sprint)
|
20
|
+
log.debug { "Creating next sprint for #{sprint}" }
|
21
|
+
@sprint = sprint
|
22
|
+
end
|
23
|
+
|
24
|
+
def next_sprint_length_in_days
|
25
|
+
sprint.length_in_days
|
26
|
+
end
|
27
|
+
|
28
|
+
def create
|
29
|
+
RequestBuilder::SprintCreator.create_sprint(sprint.tool, sprint.origin_board_id, {
|
30
|
+
name: next_sprint_name,
|
31
|
+
start_date: next_sprint_start_date.utc.to_s,
|
32
|
+
length_in_days: next_sprint_length_in_days
|
33
|
+
})
|
34
|
+
end
|
35
|
+
|
36
|
+
INDEX_FIRST_SPRINT_IN_QUARTER = 1
|
37
|
+
|
38
|
+
def next_sprint_name
|
39
|
+
index_in_quarter =
|
40
|
+
if same_quarter?
|
41
|
+
sprint.index_in_quarter + 1
|
42
|
+
else
|
43
|
+
INDEX_FIRST_SPRINT_IN_QUARTER
|
44
|
+
end
|
45
|
+
|
46
|
+
Sprint::Name.new(sprint.name_prefix, next_sprint_start_date.year, next_sprint_start_date.quarter,
|
47
|
+
index_in_quarter).to_s
|
48
|
+
end
|
49
|
+
|
50
|
+
def same_quarter?
|
51
|
+
sprint.start_date.quarter == next_sprint_start_date.quarter
|
52
|
+
end
|
53
|
+
|
54
|
+
def next_sprint_start_date
|
55
|
+
sprint.end_date
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "optparse/time"
|
4
|
+
require "jira/auto/tool/helpers/option_parser"
|
5
|
+
require "jira/auto/tool/performer/quarterly_sprint_renamer"
|
6
|
+
require "jira/auto/tool/performer/sprint_renamer"
|
7
|
+
require "jira/auto/tool/performer/sprint_time_in_dates_aligner"
|
8
|
+
require "jira/auto/tool/performer/sprint_end_date_updater"
|
9
|
+
require "jira/auto/tool/performer/planning_increment_sprint_creator"
|
10
|
+
|
11
|
+
module Jira
|
12
|
+
module Auto
|
13
|
+
class Tool
|
14
|
+
class Performer
|
15
|
+
module Options
|
16
|
+
def self.add(tool, parser)
|
17
|
+
parser.section_header "Sprint"
|
18
|
+
add_sprint_add(parser, tool)
|
19
|
+
add_sprint_align_time_in_dates(parser, tool)
|
20
|
+
add_quarterly_sprint_rename(parser, tool)
|
21
|
+
add_sprint_rename(parser, tool)
|
22
|
+
add_sprint_update_end_date(parser, tool)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.add_quarterly_sprint_rename(parser, tool)
|
26
|
+
parser.on("--quarterly-sprint-rename=FROM_STRING,TO_STRING", "--qsr", Array,
|
27
|
+
"Rename sprints starting with FROM_STRING to TO_STRING. The following sprints in the same " \
|
28
|
+
"planning increment will also be renamed. ") do |from_string, to_string|
|
29
|
+
QuarterlySprintRenamer.new(tool, from_string, to_string).run
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
SR_SHORT_OPTION_NAME = "--sr"
|
34
|
+
def self.add_sprint_rename(parser, tool)
|
35
|
+
parser.on("--sprint-rename=FROM_STRING,TO_STRING", SR_SHORT_OPTION_NAME, Array,
|
36
|
+
"Rename sprints starting with FROM_STRING to TO_STRING. The following sprints in the same " \
|
37
|
+
"prefix are also all going to be renamed " \
|
38
|
+
"irrespective of their original planning interval " \
|
39
|
+
"(e.g., #{SR_SHORT_OPTION_NAME}=25.3.6,25.4.1).") do |from_string, to_string|
|
40
|
+
SprintRenamer.new(tool, from_string, to_string).run
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.add_sprint_update_end_date(parser, tool)
|
45
|
+
parser.on("--sprint-update-end-date=REGEX,NEW_END_DATE", "--sued", Array,
|
46
|
+
"Update the end of the sprint matching REGEX to NEW_END_DATE. " \
|
47
|
+
"The following sprints are shifted " \
|
48
|
+
"while keeping their original length planning increment will " \
|
49
|
+
"also be renamed. ") do |sprint_name_regex, new_end_date|
|
50
|
+
SprintEndDateUpdater.new(tool, sprint_name_regex, new_end_date).run
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
SATID_SHORT_OPTION_NAME = "--satid"
|
55
|
+
def self.add_sprint_align_time_in_dates(parser, tool)
|
56
|
+
parser.on("--sprint-align-time-in-dates=TIME", SATID_SHORT_OPTION_NAME, Time,
|
57
|
+
"Update the start and end dates of sprints to all have the specified time " \
|
58
|
+
"(e.g., #{SATID_SHORT_OPTION_NAME}=\"14:15 UTC\").") do |time|
|
59
|
+
SprintTimeInDatesAligner.new(tool, time).run
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
SA_SHORT_OPTION_NAME = "--sa"
|
64
|
+
def self.add_sprint_add(parser, tool)
|
65
|
+
parser.on("--sprint-add=YY.PI.START,COUNT", SA_SHORT_OPTION_NAME, Array,
|
66
|
+
"Add COUNT sprints for each sprint prefix/team sprints using " \
|
67
|
+
"the specified YY.PI.START (e.g., #{SA_SHORT_OPTION_NAME}=25.3.1) and " \
|
68
|
+
"the existing sprints as templates.") do |sprint_suffix, iteration_count|
|
69
|
+
PlanningIncrementSprintCreator.new(tool, sprint_suffix, Integer(iteration_count)).run
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "jira/auto/tool/performer/prefix_sprint_updater"
|
4
|
+
|
5
|
+
module Jira
|
6
|
+
module Auto
|
7
|
+
class Tool
|
8
|
+
class Performer
|
9
|
+
class PlanningIncrementSprintCreator < PrefixSprintUpdater
|
10
|
+
attr_reader :sprint_suffix, :iteration_count
|
11
|
+
|
12
|
+
def initialize(tool, sprint_suffix, iteration_count)
|
13
|
+
super(tool)
|
14
|
+
|
15
|
+
@sprint_suffix = sprint_suffix
|
16
|
+
@iteration_count = iteration_count
|
17
|
+
end
|
18
|
+
|
19
|
+
def act_on_sprints_for_sprint_prefix(sprint_prefix)
|
20
|
+
last_sprint = sprint_prefix.last_sprint
|
21
|
+
parsed_new_name = Sprint::Name.new_with(sprint_prefix.name, sprint_suffix)
|
22
|
+
|
23
|
+
iteration_count.times do |_iteration|
|
24
|
+
last_sprint = create_sprint_for(last_sprint, parsed_new_name.to_s)
|
25
|
+
|
26
|
+
sprint_prefix << last_sprint
|
27
|
+
|
28
|
+
parsed_new_name = parsed_new_name.next_in_planning_interval
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def create_sprint_for(last_sprint, new_name)
|
33
|
+
RequestBuilder::SprintCreator.create_sprint(
|
34
|
+
tool, last_sprint.origin_board_id,
|
35
|
+
name: new_name, start_date: last_sprint.end_date, length_in_days: last_sprint.length_in_days
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "jira/auto/tool"
|
4
|
+
|
5
|
+
module Jira
|
6
|
+
module Auto
|
7
|
+
class Tool
|
8
|
+
class Performer
|
9
|
+
class PrefixSprintUpdater
|
10
|
+
attr_reader :tool
|
11
|
+
|
12
|
+
def initialize(tool)
|
13
|
+
@tool = tool
|
14
|
+
end
|
15
|
+
|
16
|
+
def sprint_prefixes
|
17
|
+
tool.unclosed_sprint_prefixes
|
18
|
+
end
|
19
|
+
|
20
|
+
def run
|
21
|
+
sprint_prefixes.each do |sprint_prefix|
|
22
|
+
@first_sprint_already_identified = false
|
23
|
+
act_on_sprints_for_sprint_prefix(sprint_prefix)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def act_on_sprints_for_sprint_prefix(sprint_prefix)
|
28
|
+
raise NotImplementedError
|
29
|
+
end
|
30
|
+
|
31
|
+
def first_sprint_to_act_on?(sprint_name)
|
32
|
+
if @first_sprint_already_identified
|
33
|
+
false
|
34
|
+
else
|
35
|
+
@first_sprint_already_identified = (sprint_name =~ from_string_regex)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "jira/auto/tool/performer/quarterly_sprint_renamer"
|
4
|
+
|
5
|
+
module Jira
|
6
|
+
module Auto
|
7
|
+
class Tool
|
8
|
+
class Performer
|
9
|
+
class QuarterlySprintRenamer
|
10
|
+
class NextNameGenerator
|
11
|
+
attr_reader :original_name_of_first_renamed_sprint, :name_of_first_renamed_sprint
|
12
|
+
|
13
|
+
def initialize(original_name_of_first_renamed_sprint, name_of_first_renamed_sprint)
|
14
|
+
@original_name_of_first_renamed_sprint = Sprint::Name.parse(original_name_of_first_renamed_sprint)
|
15
|
+
@name_of_first_renamed_sprint = Sprint::Name.parse(name_of_first_renamed_sprint)
|
16
|
+
end
|
17
|
+
|
18
|
+
def name_for(sprint_name)
|
19
|
+
if outside_planning_interval_of_sprint_next_to_first_renamed_sprint?(sprint_name)
|
20
|
+
sprint_name
|
21
|
+
else
|
22
|
+
next_name_in_planning_interval
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def new_name_of_sprint_next_to_first_renamed_sprint
|
27
|
+
@new_name_of_sprint_next_to_first_renamed_sprint ||=
|
28
|
+
if pulling_sprint_into_previous_planning_interval?
|
29
|
+
original_name_of_first_renamed_sprint
|
30
|
+
else
|
31
|
+
name_of_first_renamed_sprint.next_in_planning_interval
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def next_name_in_planning_interval
|
36
|
+
@next_name_in_planning_interval ||= new_name_of_sprint_next_to_first_renamed_sprint
|
37
|
+
|
38
|
+
next_name = @next_name_in_planning_interval.to_s
|
39
|
+
|
40
|
+
@next_name_in_planning_interval = @next_name_in_planning_interval.next_in_planning_interval
|
41
|
+
|
42
|
+
next_name
|
43
|
+
end
|
44
|
+
|
45
|
+
def pulling_sprint_into_previous_planning_interval?
|
46
|
+
(name_of_first_renamed_sprint.planning_interval <=>
|
47
|
+
original_name_of_first_renamed_sprint.planning_interval)
|
48
|
+
.negative?
|
49
|
+
end
|
50
|
+
|
51
|
+
def outside_planning_interval_of_sprint_next_to_first_renamed_sprint?(sprint_name)
|
52
|
+
new_name_of_sprint_next_to_first_renamed_sprint.planning_interval !=
|
53
|
+
Sprint::Name.parse(sprint_name).planning_interval
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "sprint_renamer"
|
4
|
+
|
5
|
+
module Jira
|
6
|
+
module Auto
|
7
|
+
class Tool
|
8
|
+
class Performer
|
9
|
+
class QuarterlySprintRenamer < SprintRenamer
|
10
|
+
require_relative "quarterly_sprint_renamer/next_name_generator"
|
11
|
+
|
12
|
+
def next_sprint_name_generator_class
|
13
|
+
QuarterlySprintRenamer::NextNameGenerator
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "prefix_sprint_updater"
|
4
|
+
|
5
|
+
module Jira
|
6
|
+
module Auto
|
7
|
+
class Tool
|
8
|
+
class Performer
|
9
|
+
class SprintEndDateUpdater < PrefixSprintUpdater
|
10
|
+
attr_reader :from_string_regex, :new_end_date
|
11
|
+
|
12
|
+
def initialize(tool, from_string, new_end_date)
|
13
|
+
super(tool)
|
14
|
+
|
15
|
+
@from_string_regex = Regexp.new(Regexp.escape(from_string))
|
16
|
+
@new_end_date = Time.parse(new_end_date)
|
17
|
+
end
|
18
|
+
|
19
|
+
def act_on_sprints_for_sprint_prefix(sprint_prefix)
|
20
|
+
prefix_sprints = sprint_prefix.sprints
|
21
|
+
update_action = :do_nothing
|
22
|
+
new_start_date = nil
|
23
|
+
|
24
|
+
prefix_sprints.each do |sprint|
|
25
|
+
if first_sprint_to_act_on?(sprint.name)
|
26
|
+
update_sprint_end_date(sprint)
|
27
|
+
update_action = :shift_sprint_to_new_start_date
|
28
|
+
else
|
29
|
+
send(update_action, sprint, new_start_date)
|
30
|
+
end
|
31
|
+
|
32
|
+
new_start_date = sprint.end_date
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def do_nothing(_sprint, _new_start_date) end
|
37
|
+
|
38
|
+
def update_sprint_end_date(sprint)
|
39
|
+
sprint.end_date = new_end_date
|
40
|
+
sprint.save
|
41
|
+
end
|
42
|
+
|
43
|
+
def shift_sprint_to_new_start_date(sprint, new_start_date)
|
44
|
+
length_in_days = sprint.length_in_days
|
45
|
+
|
46
|
+
sprint.start_date = new_start_date
|
47
|
+
sprint.end_date = new_start_date + length_in_days.days
|
48
|
+
|
49
|
+
sprint.save
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "jira/auto/tool/performer/sprint_renamer"
|
4
|
+
|
5
|
+
module Jira
|
6
|
+
module Auto
|
7
|
+
class Tool
|
8
|
+
class Performer
|
9
|
+
class SprintRenamer
|
10
|
+
class KeepSameNameGenerator
|
11
|
+
def name_for(sprint_name)
|
12
|
+
sprint_name
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "jira/auto/tool/performer/sprint_renamer"
|
4
|
+
|
5
|
+
module Jira
|
6
|
+
module Auto
|
7
|
+
class Tool
|
8
|
+
class Performer
|
9
|
+
class SprintRenamer
|
10
|
+
class NextNameGenerator
|
11
|
+
attr_reader :original_name_of_first_renamed_sprint, :name_of_first_renamed_sprint
|
12
|
+
|
13
|
+
def initialize(original_name_of_first_renamed_sprint, name_of_first_renamed_sprint)
|
14
|
+
@original_name_of_first_renamed_sprint = Sprint::Name.parse(original_name_of_first_renamed_sprint)
|
15
|
+
@name_of_first_renamed_sprint = Sprint::Name.parse(name_of_first_renamed_sprint)
|
16
|
+
end
|
17
|
+
|
18
|
+
def name_for(_sprint_name)
|
19
|
+
next_name_in_planning_interval
|
20
|
+
end
|
21
|
+
|
22
|
+
def new_name_of_sprint_next_to_first_renamed_sprint
|
23
|
+
@new_name_of_sprint_next_to_first_renamed_sprint ||=
|
24
|
+
name_of_first_renamed_sprint.next_in_planning_interval
|
25
|
+
end
|
26
|
+
|
27
|
+
def next_name_in_planning_interval
|
28
|
+
@next_name_in_planning_interval ||= new_name_of_sprint_next_to_first_renamed_sprint
|
29
|
+
|
30
|
+
next_name = @next_name_in_planning_interval.to_s
|
31
|
+
|
32
|
+
@next_name_in_planning_interval = @next_name_in_planning_interval.next_in_planning_interval
|
33
|
+
|
34
|
+
next_name
|
35
|
+
end
|
36
|
+
|
37
|
+
def pulling_sprint_into_previous_planning_interval?
|
38
|
+
(name_of_first_renamed_sprint.planning_interval <=>
|
39
|
+
original_name_of_first_renamed_sprint.planning_interval)
|
40
|
+
.negative?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "prefix_sprint_updater"
|
4
|
+
|
5
|
+
module Jira
|
6
|
+
module Auto
|
7
|
+
class Tool
|
8
|
+
class Performer
|
9
|
+
class SprintRenamer < PrefixSprintUpdater
|
10
|
+
require_relative "sprint_renamer/keep_same_name_generator"
|
11
|
+
require_relative "sprint_renamer/next_name_generator"
|
12
|
+
|
13
|
+
attr_reader :from_string_regex, :to_string
|
14
|
+
|
15
|
+
def initialize(tool, from_string, to_string)
|
16
|
+
super(tool)
|
17
|
+
|
18
|
+
@from_string_regex = Regexp.new(Regexp.escape(from_string))
|
19
|
+
@to_string = to_string
|
20
|
+
end
|
21
|
+
|
22
|
+
def act_on_sprints_for_sprint_prefix(sprint_prefix)
|
23
|
+
prefix_sprints = sprint_prefix.sprints
|
24
|
+
|
25
|
+
new_sprint_names = calculate_sprint_new_names(prefix_sprints.collect(&:name))
|
26
|
+
|
27
|
+
prefix_sprints.zip(new_sprint_names).each do |sprint, new_sprint_name|
|
28
|
+
sprint.rename_to(new_sprint_name)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def calculate_sprint_new_names(sprint_names)
|
33
|
+
name_generator = Performer::SprintRenamer::KeepSameNameGenerator.new
|
34
|
+
|
35
|
+
sprint_names.collect do |sprint_name|
|
36
|
+
if first_sprint_to_act_on?(sprint_name)
|
37
|
+
sprint_new_name = sprint_name.sub(from_string_regex, to_string)
|
38
|
+
|
39
|
+
name_generator = next_sprint_name_generator_class.new(sprint_name, sprint_new_name)
|
40
|
+
|
41
|
+
sprint_new_name
|
42
|
+
else
|
43
|
+
name_generator.name_for(sprint_name)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def next_sprint_name_generator_class
|
49
|
+
NextNameGenerator
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "jira/auto/tool"
|
4
|
+
|
5
|
+
module Jira
|
6
|
+
module Auto
|
7
|
+
class Tool
|
8
|
+
class Performer
|
9
|
+
class SprintTimeInDatesAligner
|
10
|
+
attr_reader :tool, :sprint_time_in_dates
|
11
|
+
|
12
|
+
def initialize(tool, sprint_time_in_dates)
|
13
|
+
@tool = tool
|
14
|
+
@sprint_time_in_dates =
|
15
|
+
if sprint_time_in_dates.is_a?(String)
|
16
|
+
Time.parse(sprint_time_in_dates)
|
17
|
+
else
|
18
|
+
sprint_time_in_dates
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def run
|
23
|
+
update_sprint_dates_with_expected_time
|
24
|
+
end
|
25
|
+
|
26
|
+
def update_sprint_dates_with_expected_time
|
27
|
+
tool.unclosed_sprints.each { |sprint| update_sprint_dates_for(sprint) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def update_sprint_dates_for(sprint)
|
31
|
+
return if sprint.closed? || !(sprint.start_date? || sprint.end_date?)
|
32
|
+
|
33
|
+
sprint.start_date = date_with_expected_time(sprint.start_date) if sprint.start_date?
|
34
|
+
sprint.end_date = date_with_expected_time(sprint.end_date) if sprint.end_date?
|
35
|
+
|
36
|
+
sprint.save
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def date_with_expected_time(original_date)
|
42
|
+
original_date = Time.parse(original_date) if original_date.is_a?(String)
|
43
|
+
|
44
|
+
original_date.change(
|
45
|
+
hour: sprint_time_in_dates.hour, min: sprint_time_in_dates.min, sec: sprint_time_in_dates.sec
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "jira/auto/tool/project"
|
4
|
+
|
5
|
+
module Jira
|
6
|
+
module Auto
|
7
|
+
class Tool
|
8
|
+
class Project
|
9
|
+
class Options
|
10
|
+
def self.add(tool, parser)
|
11
|
+
parser.section_header "Project"
|
12
|
+
|
13
|
+
parser.on("--project-field-list",
|
14
|
+
"Display the fields pertaining to the ticket types of a project") do
|
15
|
+
tool.project.list_ticket_fields
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jira
|
4
|
+
module Auto
|
5
|
+
class Tool
|
6
|
+
class Project
|
7
|
+
class TicketFields
|
8
|
+
attr_reader :tool, :project
|
9
|
+
|
10
|
+
def initialize(tool, project)
|
11
|
+
@tool = tool
|
12
|
+
@project = project
|
13
|
+
end
|
14
|
+
|
15
|
+
def list
|
16
|
+
table = Terminal::Table.new(
|
17
|
+
title: "Project #{project.key} Ticket Fields",
|
18
|
+
headings: table_row_header,
|
19
|
+
rows: table_rows
|
20
|
+
)
|
21
|
+
|
22
|
+
puts table
|
23
|
+
end
|
24
|
+
|
25
|
+
def table_row_header
|
26
|
+
["Ticket Type", "Field Key", "Field Name", "Field Type", "Allowed Values"]
|
27
|
+
end
|
28
|
+
|
29
|
+
def table_rows
|
30
|
+
rows = []
|
31
|
+
|
32
|
+
each_issue_type_field do |issue_type_name, field|
|
33
|
+
rows << [issue_type_name, field["key"], field["name"], field["schema"]["type"], allowed_values(field)]
|
34
|
+
end
|
35
|
+
|
36
|
+
rows.sort
|
37
|
+
end
|
38
|
+
|
39
|
+
def each_issue_type_field
|
40
|
+
tool.jira_client.Createmeta.all({ projectKeys: project.key, "expand" => "projects.issuetypes.fields" })
|
41
|
+
.each do |createmeta|
|
42
|
+
createmeta.attrs["issuetypes"].each do |issue_type|
|
43
|
+
issue_type_name = issue_type["name"]
|
44
|
+
issue_type["fields"].each_value do |field|
|
45
|
+
yield(issue_type_name, field)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def allowed_values(field)
|
54
|
+
field_allowed_values = field["allowedValues"]
|
55
|
+
|
56
|
+
if field_allowed_values
|
57
|
+
field_allowed_values.collect do |allowed_value|
|
58
|
+
value = allowed_value["value"] || allowed_value["name"]
|
59
|
+
|
60
|
+
"#{value} (#{allowed_value["id"]})"
|
61
|
+
end
|
62
|
+
else
|
63
|
+
"n/a"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "terminal-table"
|
4
|
+
require "jira/auto/tool/field_controller"
|
5
|
+
require "jira/auto/tool/project/ticket_fields"
|
6
|
+
|
7
|
+
module Jira
|
8
|
+
module Auto
|
9
|
+
class Tool
|
10
|
+
class Project
|
11
|
+
def self.find(tool, project_key)
|
12
|
+
new(tool, tool.jira_client.Project.find(project_key))
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(tool, jira_project)
|
16
|
+
@tool = tool
|
17
|
+
@jira_project = jira_project
|
18
|
+
end
|
19
|
+
|
20
|
+
def key
|
21
|
+
jira_project.key
|
22
|
+
end
|
23
|
+
|
24
|
+
def list_ticket_fields
|
25
|
+
ticket_fields.list
|
26
|
+
end
|
27
|
+
|
28
|
+
def ticket_fields
|
29
|
+
TicketFields.new(tool, self)
|
30
|
+
|
31
|
+
# FieldController.new(jira_client).ticket_fields
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
attr_reader :tool, :jira_project
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|