apadmi_grout 1.0.0 → 2.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -1
- data/lib/apadmi/grout/actions/find_tickets_to_move_action/find_tickets_to_move_action.rb +24 -0
- data/lib/apadmi/grout/actions/find_tickets_to_move_action/find_tickets_to_move_ado_action.rb +91 -0
- data/lib/apadmi/grout/actions/find_tickets_to_move_action/find_tickets_to_move_jira_action.rb +114 -0
- data/lib/apadmi/grout/actions/generate_release_notes_action/generate_release_notes_action.rb +48 -0
- data/lib/apadmi/grout/actions/generate_release_notes_action/issue_classifier.rb +51 -0
- data/lib/apadmi/grout/{release_notes/actions → actions}/issues_from_changelog_action.rb +11 -8
- data/lib/apadmi/grout/actions/move_tickets_action.rb +34 -0
- data/lib/apadmi/grout/di.rb +54 -9
- data/lib/apadmi/grout/models/ado_config.rb +10 -0
- data/lib/apadmi/grout/models/find_tickets_options.rb +44 -0
- data/lib/apadmi/grout/models/flag_messages.rb +25 -0
- data/lib/apadmi/grout/models/issue.rb +49 -0
- data/lib/apadmi/grout/{jira/models → models}/pull_request.rb +0 -0
- data/lib/apadmi/grout/models/release_notes_config.rb +47 -0
- data/lib/apadmi/grout/{release_notes/models → models}/release_notes_templates.rb +6 -6
- data/lib/apadmi/grout/service/board_service/ado_board_service.rb +199 -0
- data/lib/apadmi/grout/service/board_service/board_service.rb +59 -0
- data/lib/apadmi/grout/{jira/wrapper/jira_wrapper.rb → service/board_service/jira_board_service.rb} +68 -107
- data/lib/apadmi/grout/utils/filename_utils.rb +40 -0
- data/lib/apadmi/grout/utils/git_utils.rb +57 -0
- data/lib/apadmi/grout/utils/network_service.rb +88 -0
- data/lib/apadmi/grout/version.rb +1 -1
- data/lib/apadmi_grout.rb +3 -18
- metadata +23 -13
- data/lib/apadmi/grout/jira/actions/find_tickets_to_move_action.rb +0 -76
- data/lib/apadmi/grout/jira/actions/move_jira_tickets_action.rb +0 -58
- data/lib/apadmi/grout/jira/models/flag_messages.rb +0 -8
- data/lib/apadmi/grout/jira/models/version.rb +0 -23
- data/lib/apadmi/grout/release_notes/actions/generate_release_notes_action.rb +0 -39
- data/lib/apadmi/grout/release_notes/models/release_notes_config.rb +0 -74
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8da866b98ba10eeb0dd9a8a664bd926e8c657cb918bf8a73474d1e3aacd941c4
|
4
|
+
data.tar.gz: '0759b30f1bcbe228e7c1a22eecc52bad02f8174d31584d130936a9d3203d35ef'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd158cbb2bda541b4fbb80137200c60793d86d1257705aec7ffe5450f1fd66a6d8dc13f6e1135ca5c2db28a8049a92db4e1d76b678b0aa745314cdd7bdd92fed
|
7
|
+
data.tar.gz: f0a7a913306577749fcba0a68ce1311e073ce4f21ac0e15d50f87527f7a65a8c27e0f3136e871d7d0b5ab457da99369bc9c99a91007f361f4cb102c435e3751f
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,15 @@
|
|
1
1
|
# Core Changelog
|
2
2
|
|
3
|
-
## [
|
3
|
+
## [2.0.0] - 2022-05-25
|
4
|
+
* Almost total refactor to support having different board providers (other than jira)
|
5
|
+
* Implement ADO support for all existing actions
|
6
|
+
|
7
|
+
## [1.2.0] - 2022-05-17
|
8
|
+
* Filter out issues missing from git changelogs when finding tickets to move.
|
9
|
+
|
10
|
+
## [1.1.0] - 2022-05-12
|
11
|
+
* Support allowing tickets that aren't assigned to a sprint to be moved.
|
12
|
+
* Created utilities for getting the git root and number of commits
|
4
13
|
|
5
14
|
## [1.0.0] - 2022-05-09 - Initial release
|
6
15
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Apadmi
|
4
|
+
module Grout
|
5
|
+
# Generic action for finding tickets to move
|
6
|
+
class FindTicketsToMoveAction
|
7
|
+
# @param _component [String] Only include tickets tagged with this component
|
8
|
+
# @param _status [String] The status of tickets to be moved (Usually "Awaiting QA Release")
|
9
|
+
# @param _excluded_ticket_keys [Array<String>] ticket keys to be excluded from consideration
|
10
|
+
# @param _custom_flag_messages [Apadmi::Grout::FlagMessages]
|
11
|
+
# @param _options [Apadmi::Grout::JiraFindTicketsOptions|Apadmi::Grout::AdoFindTicketsOptions]
|
12
|
+
# @return [Array<Apadmi::Grout::Issue>] the issues ready to move
|
13
|
+
def run(
|
14
|
+
_component,
|
15
|
+
_status,
|
16
|
+
_excluded_ticket_keys,
|
17
|
+
_custom_flag_messages = nil,
|
18
|
+
_options = nil
|
19
|
+
)
|
20
|
+
raise "Unimplemented :("
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Apadmi
|
4
|
+
module Grout
|
5
|
+
# ATTENTION: Any changes to the logic here should be reflected in the docs (find-tickets.md)
|
6
|
+
|
7
|
+
# Finds and returns a list of all the issues that are ready to be moved
|
8
|
+
# Any tickets found that have the given status but *don't* appear ready to be moved will
|
9
|
+
# be flagged.
|
10
|
+
class FindTicketsToMoveAdoAction < FindTicketsToMoveAction
|
11
|
+
# @param [Apadmi::Grout::AdoBoardService]
|
12
|
+
# @param [String]
|
13
|
+
# @param [Apadmi::Grout::GitUtils]
|
14
|
+
# @param [Apadmi::Grout::IssuesFromChangelogAction]
|
15
|
+
# @param [Apadmi::Grout::DefaultLogger] // or your own logger!
|
16
|
+
def initialize(ado_board_service, ticket_prefix, git_utils, issues_from_chnglg, logger)
|
17
|
+
@ado_board_service = ado_board_service
|
18
|
+
@ticket_prefix = ticket_prefix
|
19
|
+
@git_utils = git_utils
|
20
|
+
@issues_from_changelog_action = issues_from_chnglg
|
21
|
+
@logger = logger
|
22
|
+
end
|
23
|
+
|
24
|
+
# @param component [String] Only include tickets tagged with this component
|
25
|
+
# @param status [String] The status of tickets to be moved (Usually "Awaiting QA Release")
|
26
|
+
# @param excluded_ticket_keys [Array<String>] ticket keys to be excluded from consideration
|
27
|
+
# @param custom_flag_messages [Apadmi::Grout::FlagMessages]
|
28
|
+
# @param options [Apadmi::Grout::JiraFindTicketsOptions]
|
29
|
+
# @return [Array<Apadmi::Grout::Issue>] the issues ready to move
|
30
|
+
def run(
|
31
|
+
component,
|
32
|
+
status,
|
33
|
+
excluded_ticket_keys,
|
34
|
+
custom_flag_messages = nil,
|
35
|
+
options = nil
|
36
|
+
)
|
37
|
+
custom_flag_messages ||= Apadmi::Grout::FlagMessages.default(status)
|
38
|
+
options ||= Apadmi::Grout::AdoFindTicketsOptions.new(required_tags: [],
|
39
|
+
not_tags: [])
|
40
|
+
|
41
|
+
issues = @ado_board_service.search_unblocked_issues(
|
42
|
+
component, status, [], options
|
43
|
+
).reject { |issue| excluded_ticket_keys.include? issue.key }
|
44
|
+
|
45
|
+
issue_keys = issues.map(&:key)
|
46
|
+
@logger.message("Found issues to consider #{issue_keys.join(", ")}")
|
47
|
+
|
48
|
+
# Get the issues in the git changelog, filtered for the issues being considered
|
49
|
+
changelog_ids = @issues_from_changelog_action.issue_ids_from_changelog(
|
50
|
+
@git_utils.merge_changelog(issue_keys)
|
51
|
+
).map { |id| id.delete_prefix(@ticket_prefix) }
|
52
|
+
|
53
|
+
@git_utils.fetch_all
|
54
|
+
# issues that have been merged, but aren't in this build.
|
55
|
+
# This is a valid state (e.g. merged into a release branch but not develop)
|
56
|
+
invert_changelog_ids = @issues_from_changelog_action.issue_ids_from_changelog(
|
57
|
+
@git_utils.invert_changelog(issue_keys)
|
58
|
+
).map { |id| id.delete_prefix(@ticket_prefix) }
|
59
|
+
|
60
|
+
final_list = issues.filter do |issue|
|
61
|
+
# Flag the ticket if it doesn't include in either changelog since
|
62
|
+
# this means the ticket is likely in an incorrect state
|
63
|
+
decide_should_include(changelog_ids, custom_flag_messages, invert_changelog_ids, issue)
|
64
|
+
end
|
65
|
+
|
66
|
+
@logger.message("Final list: #{final_list.map(&:key).join(", ")}")
|
67
|
+
final_list
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def decide_should_include(changelog_ids, custom_flag_messages, invert_changelog_ids, issue)
|
73
|
+
if !changelog_ids.include?(issue.key) && !invert_changelog_ids.include?(issue.key)
|
74
|
+
@ado_board_service.flag_ticket(
|
75
|
+
issue.key,
|
76
|
+
custom_flag_messages.no_prs_flag_msg
|
77
|
+
)
|
78
|
+
@logger.message("Not including #{issue.key} since it's not in the changelog at all")
|
79
|
+
return false
|
80
|
+
end
|
81
|
+
|
82
|
+
if !changelog_ids.include?(issue.key) && invert_changelog_ids.include?(issue.key)
|
83
|
+
@logger.message("Not including #{issue.key} since it's merged but not in this build")
|
84
|
+
return false
|
85
|
+
end
|
86
|
+
|
87
|
+
true
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Apadmi
|
4
|
+
module Grout
|
5
|
+
module PrStatus
|
6
|
+
MERGED = 1
|
7
|
+
UNMERGED_BUT_INCLUDED = 2
|
8
|
+
UN_INCLUDED = 3
|
9
|
+
end
|
10
|
+
|
11
|
+
# ATTENTION: Any changes to the logic here should be reflected in the docs (find-tickets.md)
|
12
|
+
|
13
|
+
# Finds and returns a list of all the issues that are ready to be moved
|
14
|
+
# Any tickets found that have the given status but *don't* appear ready to be moved will
|
15
|
+
# be flagged.
|
16
|
+
class FindTicketsToMoveJiraAction < FindTicketsToMoveAction
|
17
|
+
# @param [Apadmi::Grout::JiraBoardService]
|
18
|
+
# @param [Apadmi::Grout::GitUtils]
|
19
|
+
# @param [Apadmi::Grout::IssuesFromChangelogAction]
|
20
|
+
# @param [Apadmi::Grout::DefaultLogger] // or your own logger!
|
21
|
+
def initialize(jira_board_service, git_utils, issues_from_chnglg, logger)
|
22
|
+
@jira_board_service = jira_board_service
|
23
|
+
@git_utils = git_utils
|
24
|
+
@issues_from_changelog_action = issues_from_chnglg
|
25
|
+
@logger = logger
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param component [String] Only include tickets tagged with this component
|
29
|
+
# @param status [String] The status of tickets to be moved (Usually "Awaiting QA Release")
|
30
|
+
# @param excluded_ticket_keys [Array<String>] ticket keys to be excluded from consideration
|
31
|
+
# @param custom_flag_messages [Apadmi::Grout::FlagMessages]
|
32
|
+
# @param options [Apadmi::Grout::JiraFindTicketsOptions]
|
33
|
+
# @return [Array<Apadmi::Grout::Issue>] the issues ready to move
|
34
|
+
def run(
|
35
|
+
component,
|
36
|
+
status,
|
37
|
+
excluded_ticket_keys,
|
38
|
+
custom_flag_messages = nil,
|
39
|
+
options = nil
|
40
|
+
)
|
41
|
+
custom_flag_messages ||= Apadmi::Grout::FlagMessages.default(status)
|
42
|
+
options ||= Apadmi::Grout::JiraFindTicketsOptions.new(include_no_sprint_tickets: false)
|
43
|
+
|
44
|
+
issues = @jira_board_service.search_unblocked_issues(
|
45
|
+
component, status, [], options
|
46
|
+
).reject do |issue|
|
47
|
+
excluded_ticket_keys.include? issue.key
|
48
|
+
end
|
49
|
+
|
50
|
+
issue_keys = issues.map(&:key)
|
51
|
+
@logger.message("Found issues to consider #{issue_keys.join(", ")}")
|
52
|
+
|
53
|
+
# Get the issues in the git changelog, filtered for the issues being considered
|
54
|
+
changelog_ids = @issues_from_changelog_action.issue_ids_from_changelog(
|
55
|
+
@git_utils.merge_changelog(issue_keys)
|
56
|
+
)
|
57
|
+
|
58
|
+
final_list = issues.filter do |issue|
|
59
|
+
# Decide whether to include this ticket based on PRs
|
60
|
+
status = process_prs(issue, custom_flag_messages)
|
61
|
+
decide_should_include(issue, status, changelog_ids)
|
62
|
+
end
|
63
|
+
|
64
|
+
@logger.message("Final list: #{final_list.map(&:key).join(", ")}")
|
65
|
+
final_list
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
# @param issue [Apadmi::Grout::Issue]
|
71
|
+
# @param pr_status [Int] status of whether or not we can move
|
72
|
+
# @param changelog_ids [Array<String>] the ticket ids pulled from git
|
73
|
+
def decide_should_include(issue, pr_status, changelog_ids)
|
74
|
+
# For merged PRs, check if the ticket appears in the changelog.
|
75
|
+
# If it doesn't then it's likely it was merged AFTER this release build was triggered and shouldn't be moved
|
76
|
+
# by this build
|
77
|
+
if pr_status == PrStatus::MERGED
|
78
|
+
is_in_changelog = changelog_ids.include?(issue.key)
|
79
|
+
@logger.message("NOTE: Not including #{issue.key} since it's not in the git changelog.") unless is_in_changelog
|
80
|
+
return is_in_changelog
|
81
|
+
end
|
82
|
+
|
83
|
+
pr_status != PrStatus::UN_INCLUDED
|
84
|
+
end
|
85
|
+
|
86
|
+
# @param issue [Apadmi::Grout::Issue]
|
87
|
+
# @param custom_flag_messages [FlagMessages]
|
88
|
+
# @return [Int] status of whether or not we can move
|
89
|
+
def process_prs(issue, custom_flag_messages)
|
90
|
+
prs = @jira_board_service.get_ticket_prs(issue)
|
91
|
+
|
92
|
+
if prs.empty?
|
93
|
+
@logger.message("#{issue.key} has no PRs. Flagging it: STILL MOVABLE")
|
94
|
+
@jira_board_service.flag_ticket(issue.key, custom_flag_messages.no_prs_flag_msg)
|
95
|
+
return PrStatus::UNMERGED_BUT_INCLUDED
|
96
|
+
elsif prs.all?(&:open)
|
97
|
+
@logger.message("#{issue.key} has only open PRs. Flagging it: NOT MOVABLE")
|
98
|
+
@jira_board_service.flag_ticket(issue.key, custom_flag_messages.open_prs_flag_msg)
|
99
|
+
return PrStatus::UN_INCLUDED
|
100
|
+
elsif prs.all?(&:declined)
|
101
|
+
@logger.message("#{issue.key} has only declined PRs. Flagging it: NOT MOVABLE")
|
102
|
+
@jira_board_service.flag_ticket(issue.key, custom_flag_messages.declined_prs_flag_msg)
|
103
|
+
return PrStatus::UN_INCLUDED
|
104
|
+
elsif prs.none?(&:merged)
|
105
|
+
@logger.message("#{issue.key} has no merged PRs. Flagging it: NOT MOVABLE")
|
106
|
+
@jira_board_service.flag_ticket(issue.key, custom_flag_messages.no_merged_prs_flag_msg)
|
107
|
+
return PrStatus::UN_INCLUDED
|
108
|
+
end
|
109
|
+
|
110
|
+
PrStatus::MERGED # At least one merged PR
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "mustache"
|
4
|
+
|
5
|
+
module Apadmi
|
6
|
+
module Grout
|
7
|
+
# Finds and returns a list of all the issues who's ids exist in the given changelog
|
8
|
+
class GenerateReleaseNotesAction
|
9
|
+
# @param classifier [Apadmi::Grout::IssueClassifier]
|
10
|
+
def initialize(classifier)
|
11
|
+
@classifier = classifier
|
12
|
+
end
|
13
|
+
|
14
|
+
# @param config [Apadmi::Grout::ReleaseNotesConfig]
|
15
|
+
def run(config)
|
16
|
+
moved = @classifier.classify(config.moved_issues)
|
17
|
+
release = @classifier.classify(config.release_issues)
|
18
|
+
|
19
|
+
CustomMustache.render(
|
20
|
+
config.templates.document_template,
|
21
|
+
config: config,
|
22
|
+
rendered_moved_issues: render_classified_issues(config.templates.list_template, moved),
|
23
|
+
rendered_release_issues: render_classified_issues(config.templates.list_template, release)
|
24
|
+
).strip
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def render_classified_issues(template, classified_issues)
|
30
|
+
return if classified_issues.empty
|
31
|
+
|
32
|
+
CustomMustache.render(
|
33
|
+
template,
|
34
|
+
classified_issues: classified_issues
|
35
|
+
)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Custom mustache class which doesn't escape HTML, since we're generating markdown
|
40
|
+
class CustomMustache < Mustache
|
41
|
+
# rubocop:disable Naming/MethodName
|
42
|
+
def escapeHTML(txt)
|
43
|
+
txt
|
44
|
+
end
|
45
|
+
# rubocop:enable Naming/MethodName
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Apadmi
|
4
|
+
module Grout
|
5
|
+
# Generic issue classifier
|
6
|
+
class IssueClassifier
|
7
|
+
# @param types [Array<String>] List of types to match on
|
8
|
+
# @param issues [Array<Apadmi::Grout::Issue>]
|
9
|
+
# @return [Array<Apadmi::Grout::Issue>]
|
10
|
+
def filter_issues_by_type(types, issues)
|
11
|
+
issues.find_all { |issue| types.include?(issue.issue_type) }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Jira specific issue classifier
|
16
|
+
class JiraIssueClassifier < IssueClassifier
|
17
|
+
# @param issues [Array<Apadmi::Grout::Issue>]
|
18
|
+
def classify(issues)
|
19
|
+
tasks = filter_issues_by_type(%w[Task], issues)
|
20
|
+
features = filter_issues_by_type(%w[Story], issues)
|
21
|
+
improvements = filter_issues_by_type(%w[Improvement Rework Debt], issues)
|
22
|
+
defects = filter_issues_by_type(%w[Bug], issues)
|
23
|
+
ClassifiedIssues.new(
|
24
|
+
tasks,
|
25
|
+
features,
|
26
|
+
improvements,
|
27
|
+
defects,
|
28
|
+
issues - tasks - features - improvements - defects
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Ado specific issue classifier
|
34
|
+
class AdoIssueClassifier < IssueClassifier
|
35
|
+
# @param issues [Array<Apadmi::Grout::Issue>]
|
36
|
+
def classify(issues)
|
37
|
+
tasks = filter_issues_by_type(%w[Task], issues)
|
38
|
+
features = filter_issues_by_type(["User Story", "Feature"], issues)
|
39
|
+
improvements = filter_issues_by_type(["Improvement", "Tech Debt"], issues)
|
40
|
+
defects = filter_issues_by_type(%w[Bug], issues)
|
41
|
+
ClassifiedIssues.new(
|
42
|
+
tasks,
|
43
|
+
features,
|
44
|
+
improvements,
|
45
|
+
defects,
|
46
|
+
issues - tasks - features - improvements - defects
|
47
|
+
)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -4,28 +4,31 @@ module Apadmi
|
|
4
4
|
module Grout
|
5
5
|
# Finds and returns a list of all the issues who's ids exist in the given changelog
|
6
6
|
class IssuesFromChangelogAction
|
7
|
-
# @param [Apadmi::Grout::
|
7
|
+
# @param board_service [Apadmi::Grout::BoardService]
|
8
|
+
# @param ticket_prefix [String] The prefix for the ticket numbers in git e.g "PPT-"
|
8
9
|
# @param [Apadmi::Grout::DefaultLogger] // or your own logger!
|
9
|
-
def initialize(
|
10
|
-
@
|
10
|
+
def initialize(board_service, ticket_prefix, logger)
|
11
|
+
@board_service = board_service
|
11
12
|
@logger = logger
|
13
|
+
@ticket_prefix = ticket_prefix
|
12
14
|
end
|
13
15
|
|
14
16
|
# @param changelog [String] raw git changelog
|
15
|
-
# @return [Array<
|
17
|
+
# @return [Array<Apadmi::Grout::Issue>] list of issues from changelog
|
16
18
|
def run(changelog)
|
17
19
|
ids = issue_ids_from_changelog(changelog)
|
18
20
|
|
19
21
|
@logger.message("Found issue ids: #{ids.join(", ")}")
|
20
|
-
@
|
22
|
+
@board_service.find_issues_by_keys(ids)
|
21
23
|
end
|
22
24
|
|
23
|
-
private
|
24
|
-
|
25
25
|
# @param changelog [String] raw git changelog
|
26
26
|
# @return [Array<String>] list of issue ids from changelog
|
27
27
|
def issue_ids_from_changelog(changelog)
|
28
|
-
|
28
|
+
# Changelog often has the pull request number in it, this can mess up the parsing so strip it out if we can
|
29
|
+
changelog = changelog.gsub(/\(pull request.*\)/, "")
|
30
|
+
|
31
|
+
changelog.scan(/(#{@ticket_prefix}\d+)/).flatten.uniq
|
29
32
|
end
|
30
33
|
end
|
31
34
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Apadmi
|
4
|
+
module Grout
|
5
|
+
# Moves all given tickets to a given status and assigns fix versions
|
6
|
+
class MoveTicketsAction
|
7
|
+
# @param [Apadmi::Grout::BoardService]
|
8
|
+
# @param [Apadmi::Grout::DefaultLogger] // or your own logger!
|
9
|
+
def initialize(board_service, logger)
|
10
|
+
@board_service = board_service
|
11
|
+
@logger = logger
|
12
|
+
end
|
13
|
+
|
14
|
+
# @param [Array<String>] version_strings
|
15
|
+
# @param [Array<Apadmi::Grout::Issue>] issues
|
16
|
+
# @param [String] new_status
|
17
|
+
def run(version_strings, issues, new_status)
|
18
|
+
if issues.empty?
|
19
|
+
@logger.error("No issues found, aborting")
|
20
|
+
return
|
21
|
+
end
|
22
|
+
|
23
|
+
@logger.message("Transitioning issues: #{issues.map(&:key).join(", ")}")
|
24
|
+
|
25
|
+
issues.each do |issue|
|
26
|
+
@board_service.transition_issue(issue, new_status)
|
27
|
+
@board_service.assign_fixversions(issue.key, version_strings)
|
28
|
+
end
|
29
|
+
|
30
|
+
@logger.success("Issues transitioned successfully :D")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/apadmi/grout/di.rb
CHANGED
@@ -3,22 +3,67 @@
|
|
3
3
|
module Apadmi
|
4
4
|
module Grout
|
5
5
|
# Convenience class for initializing and accessing the various actions
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
DependencyInjector = Struct.new(
|
7
|
+
:board_service,
|
8
|
+
:move_tickets_action,
|
9
|
+
:find_tickets_to_move_action,
|
10
|
+
:issues_from_changelog_action,
|
11
|
+
:generate_release_notes_action,
|
12
|
+
keyword_init: true
|
13
|
+
) do
|
9
14
|
# @param [String] username
|
10
15
|
# @param [String] token
|
11
16
|
# @param [String] base_url
|
12
17
|
# @param [String] context_path
|
13
18
|
# @param [String] project
|
14
19
|
# @param [Logger] logger
|
15
|
-
def
|
16
|
-
|
20
|
+
def self.init_for_jira(
|
21
|
+
username,
|
22
|
+
token,
|
23
|
+
base_url,
|
24
|
+
context_path,
|
25
|
+
project,
|
26
|
+
logger = Apadmi::Grout::DefaultLogger.new
|
27
|
+
)
|
28
|
+
network_service = Apadmi::Grout::NetworkService.new(username, token, base_url)
|
29
|
+
jira_board_service = Apadmi::Grout::JiraBoardService.new(username, token, base_url, context_path, project, network_service)
|
30
|
+
git_utils = Apadmi::Grout::GitUtils
|
31
|
+
issues_from_changelog_action = Apadmi::Grout::IssuesFromChangelogAction.new(jira_board_service, "#{project}-", logger)
|
32
|
+
|
33
|
+
DependencyInjector.new(
|
34
|
+
board_service: jira_board_service,
|
35
|
+
move_tickets_action: Apadmi::Grout::MoveTicketsAction.new(jira_board_service, logger),
|
36
|
+
issues_from_changelog_action: issues_from_changelog_action,
|
37
|
+
find_tickets_to_move_action: Apadmi::Grout::FindTicketsToMoveJiraAction.new(jira_board_service, git_utils, issues_from_changelog_action, logger),
|
38
|
+
generate_release_notes_action: Apadmi::Grout::GenerateReleaseNotesAction.new(Apadmi::Grout::JiraIssueClassifier.new)
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
# @param [String] personal_access_token
|
43
|
+
# @param [String] base_url
|
44
|
+
# @param [Logger] logger
|
45
|
+
def self.init_for_ado(
|
46
|
+
personal_access_token,
|
47
|
+
base_url,
|
48
|
+
logger = Apadmi::Grout::DefaultLogger.new,
|
49
|
+
ado_config = Apadmi::Grout::AdoConfig.new(
|
50
|
+
flag_tag: "FLAGGED"
|
51
|
+
)
|
52
|
+
)
|
53
|
+
ticket_prefix = "#"
|
54
|
+
network_service = Apadmi::Grout::NetworkService.new("", personal_access_token, base_url)
|
55
|
+
ado_board_service = Apadmi::Grout::AdoBoardService.new(network_service, ado_config, logger)
|
56
|
+
git_utils = Apadmi::Grout::GitUtils
|
57
|
+
issues_from_changelog_action = Apadmi::Grout::IssuesFromChangelogAction.new(ado_board_service, ticket_prefix, logger)
|
17
58
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
59
|
+
DependencyInjector.new(
|
60
|
+
board_service: ado_board_service,
|
61
|
+
move_tickets_action: Apadmi::Grout::MoveTicketsAction.new(ado_board_service, logger),
|
62
|
+
issues_from_changelog_action: issues_from_changelog_action,
|
63
|
+
find_tickets_to_move_action: Apadmi::Grout::FindTicketsToMoveAdoAction.new(ado_board_service, ticket_prefix, git_utils, issues_from_changelog_action,
|
64
|
+
logger),
|
65
|
+
generate_release_notes_action: Apadmi::Grout::GenerateReleaseNotesAction.new(Apadmi::Grout::AdoIssueClassifier.new)
|
66
|
+
)
|
22
67
|
end
|
23
68
|
end
|
24
69
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Apadmi
|
4
|
+
module Grout
|
5
|
+
# Generic find tickets options
|
6
|
+
class FindTicketsOptions; end
|
7
|
+
|
8
|
+
# Jira specific find tickets options
|
9
|
+
class JiraFindTicketsOptions < FindTicketsOptions
|
10
|
+
attr_reader :include_no_sprint_tickets
|
11
|
+
|
12
|
+
# @param include_no_sprint_tickets [String] whether or not to include tickets with no sprint assigned
|
13
|
+
def initialize(include_no_sprint_tickets: false)
|
14
|
+
@include_no_sprint_tickets = include_no_sprint_tickets
|
15
|
+
end
|
16
|
+
|
17
|
+
def ==(other)
|
18
|
+
other.class == self.class && other.state == state
|
19
|
+
end
|
20
|
+
|
21
|
+
def state
|
22
|
+
[@include_no_sprint_tickets]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Ado specific find tickets options
|
27
|
+
class AdoFindTicketsOptions < FindTicketsOptions
|
28
|
+
attr_reader :required_tags, :not_tags
|
29
|
+
|
30
|
+
def initialize(required_tags: [], not_tags: [])
|
31
|
+
@required_tags = required_tags
|
32
|
+
@not_tags = not_tags
|
33
|
+
end
|
34
|
+
|
35
|
+
def ==(other)
|
36
|
+
other.class == self.class && other.state == state
|
37
|
+
end
|
38
|
+
|
39
|
+
def state
|
40
|
+
[@required_tags, @not_tags]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Apadmi
|
4
|
+
module Grout
|
5
|
+
FlagMessages = Struct.new(
|
6
|
+
:no_prs_flag_msg,
|
7
|
+
:open_prs_flag_msg,
|
8
|
+
:declined_prs_flag_msg,
|
9
|
+
:no_merged_prs_flag_msg
|
10
|
+
) do
|
11
|
+
# Get default flag messages
|
12
|
+
# @param status [String] status ticket will be moving to
|
13
|
+
# @return [Apadmi::Grout::FlagMessages]
|
14
|
+
def self.default(status)
|
15
|
+
FlagMessages.new(
|
16
|
+
"REASON FOR FLAG: Check this ticket - it was put in #{status} but has no PRs connected to it. CI still moved it. " \
|
17
|
+
"(WARNING: this may cause the `fix_versions` to be incorrect)",
|
18
|
+
"REASON FOR FLAG: Check this ticket - it was put in #{status} but has no MERGED PRs and at least one OPEN PR",
|
19
|
+
"REASON FOR FLAG: Check this ticket - it was put in #{status} but has only DECLINED PRs",
|
20
|
+
"REASON FOR FLAG: Check this ticket - it was put in #{status} but has no MERGED PRs"
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Apadmi
|
4
|
+
module Grout
|
5
|
+
# A generic issue type wrapping up the underlying JIRA & ADO object
|
6
|
+
# @param key [String] Unique key identifying the issue
|
7
|
+
# @param summary [String] The issue title
|
8
|
+
# @param status [String] The current status on the board
|
9
|
+
# @param issue_type [String] Raw string representing issue type e.g "In Progress"
|
10
|
+
# @param url [String] url to the issue
|
11
|
+
# @param raw_object [JIRA::Resource::Issue|Hash] The underlying raw object from the platform
|
12
|
+
Issue = Struct.new(:key, :summary, :status, :issue_type, :url, :raw_object) do
|
13
|
+
# @return [Apadmi::Grout::Issue]
|
14
|
+
def self.from_ado_hash(hash)
|
15
|
+
Issue.new(
|
16
|
+
hash["id"].to_s,
|
17
|
+
hash["fields"]["System.Title"],
|
18
|
+
hash["fields"]["System.State"],
|
19
|
+
hash["fields"]["System.WorkItemType"],
|
20
|
+
hash["url"],
|
21
|
+
hash
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [Array<Apadmi::Grout::Issue>]
|
26
|
+
def self.from_ado_hashes(hashes)
|
27
|
+
hashes.map { |h| Issue.from_ado_hash(h) }
|
28
|
+
end
|
29
|
+
|
30
|
+
# @param issue [JIRA::Resource::Issue]
|
31
|
+
# @return [Apadmi::Grout::Issue]
|
32
|
+
def self.from_jira_issue(issue, base_url)
|
33
|
+
Issue.new(
|
34
|
+
issue.key,
|
35
|
+
issue.summary,
|
36
|
+
issue.status.name,
|
37
|
+
issue.issuetype.name,
|
38
|
+
"#{base_url}/browse/#{issue.key}",
|
39
|
+
issue
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
# @return [Array<Apadmi::Grout::Issue>]
|
44
|
+
def self.from_jira_issues(issues, base_url)
|
45
|
+
issues.map { |i| Issue.from_jira_issue(i, base_url) }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
File without changes
|