apadmi_grout 1.2.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- 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/{jira/actions/find_tickets_to_move_action.rb → actions/find_tickets_to_move_action/find_tickets_to_move_jira_action.rb} +16 -17
- 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 -6
- data/lib/apadmi/grout/actions/move_tickets_action.rb +34 -0
- data/lib/apadmi/grout/di.rb +53 -9
- data/lib/apadmi/grout/{jira/models/find_tickets_options.rb → models/ado_config.rb} +2 -2
- data/lib/apadmi/grout/models/find_tickets_options.rb +44 -0
- data/lib/apadmi/grout/{jira/models → models}/flag_messages.rb +0 -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} +65 -107
- data/lib/apadmi/grout/utils/git_utils.rb +18 -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 -21
- metadata +20 -13
- data/lib/apadmi/grout/jira/actions/move_jira_tickets_action.rb +0 -58
- 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,5 +1,9 @@
|
|
1
1
|
# Core Changelog
|
2
2
|
|
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
|
+
|
3
7
|
## [1.2.0] - 2022-05-17
|
4
8
|
* Filter out issues missing from git changelogs when finding tickets to move.
|
5
9
|
|
@@ -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
|
@@ -13,13 +13,13 @@ module Apadmi
|
|
13
13
|
# Finds and returns a list of all the issues that are ready to be moved
|
14
14
|
# Any tickets found that have the given status but *don't* appear ready to be moved will
|
15
15
|
# be flagged.
|
16
|
-
class FindTicketsToMoveAction
|
17
|
-
# @param [Apadmi::Grout::
|
16
|
+
class FindTicketsToMoveJiraAction < FindTicketsToMoveAction
|
17
|
+
# @param [Apadmi::Grout::JiraBoardService]
|
18
18
|
# @param [Apadmi::Grout::GitUtils]
|
19
19
|
# @param [Apadmi::Grout::IssuesFromChangelogAction]
|
20
20
|
# @param [Apadmi::Grout::DefaultLogger] // or your own logger!
|
21
|
-
def initialize(
|
22
|
-
@
|
21
|
+
def initialize(jira_board_service, git_utils, issues_from_chnglg, logger)
|
22
|
+
@jira_board_service = jira_board_service
|
23
23
|
@git_utils = git_utils
|
24
24
|
@issues_from_changelog_action = issues_from_chnglg
|
25
25
|
@logger = logger
|
@@ -29,8 +29,8 @@ module Apadmi
|
|
29
29
|
# @param status [String] The status of tickets to be moved (Usually "Awaiting QA Release")
|
30
30
|
# @param excluded_ticket_keys [Array<String>] ticket keys to be excluded from consideration
|
31
31
|
# @param custom_flag_messages [Apadmi::Grout::FlagMessages]
|
32
|
-
# @param options [Apadmi::Grout::
|
33
|
-
# @return [Array<
|
32
|
+
# @param options [Apadmi::Grout::JiraFindTicketsOptions]
|
33
|
+
# @return [Array<Apadmi::Grout::Issue>] the issues ready to move
|
34
34
|
def run(
|
35
35
|
component,
|
36
36
|
status,
|
@@ -39,11 +39,10 @@ module Apadmi
|
|
39
39
|
options = nil
|
40
40
|
)
|
41
41
|
custom_flag_messages ||= Apadmi::Grout::FlagMessages.default(status)
|
42
|
-
options ||= Apadmi::Grout::
|
42
|
+
options ||= Apadmi::Grout::JiraFindTicketsOptions.new(include_no_sprint_tickets: false)
|
43
43
|
|
44
|
-
issues = @
|
45
|
-
component, status, [],
|
46
|
-
allow_no_sprint: options.include_no_sprint_tickets
|
44
|
+
issues = @jira_board_service.search_unblocked_issues(
|
45
|
+
component, status, [], options
|
47
46
|
).reject do |issue|
|
48
47
|
excluded_ticket_keys.include? issue.key
|
49
48
|
end
|
@@ -68,7 +67,7 @@ module Apadmi
|
|
68
67
|
|
69
68
|
private
|
70
69
|
|
71
|
-
# @param issue [
|
70
|
+
# @param issue [Apadmi::Grout::Issue]
|
72
71
|
# @param pr_status [Int] status of whether or not we can move
|
73
72
|
# @param changelog_ids [Array<String>] the ticket ids pulled from git
|
74
73
|
def decide_should_include(issue, pr_status, changelog_ids)
|
@@ -84,27 +83,27 @@ module Apadmi
|
|
84
83
|
pr_status != PrStatus::UN_INCLUDED
|
85
84
|
end
|
86
85
|
|
87
|
-
# @param issue [
|
86
|
+
# @param issue [Apadmi::Grout::Issue]
|
88
87
|
# @param custom_flag_messages [FlagMessages]
|
89
88
|
# @return [Int] status of whether or not we can move
|
90
89
|
def process_prs(issue, custom_flag_messages)
|
91
|
-
prs = @
|
90
|
+
prs = @jira_board_service.get_ticket_prs(issue)
|
92
91
|
|
93
92
|
if prs.empty?
|
94
93
|
@logger.message("#{issue.key} has no PRs. Flagging it: STILL MOVABLE")
|
95
|
-
@
|
94
|
+
@jira_board_service.flag_ticket(issue.key, custom_flag_messages.no_prs_flag_msg)
|
96
95
|
return PrStatus::UNMERGED_BUT_INCLUDED
|
97
96
|
elsif prs.all?(&:open)
|
98
97
|
@logger.message("#{issue.key} has only open PRs. Flagging it: NOT MOVABLE")
|
99
|
-
@
|
98
|
+
@jira_board_service.flag_ticket(issue.key, custom_flag_messages.open_prs_flag_msg)
|
100
99
|
return PrStatus::UN_INCLUDED
|
101
100
|
elsif prs.all?(&:declined)
|
102
101
|
@logger.message("#{issue.key} has only declined PRs. Flagging it: NOT MOVABLE")
|
103
|
-
@
|
102
|
+
@jira_board_service.flag_ticket(issue.key, custom_flag_messages.declined_prs_flag_msg)
|
104
103
|
return PrStatus::UN_INCLUDED
|
105
104
|
elsif prs.none?(&:merged)
|
106
105
|
@logger.message("#{issue.key} has no merged PRs. Flagging it: NOT MOVABLE")
|
107
|
-
@
|
106
|
+
@jira_board_service.flag_ticket(issue.key, custom_flag_messages.no_merged_prs_flag_msg)
|
108
107
|
return PrStatus::UN_INCLUDED
|
109
108
|
end
|
110
109
|
|
@@ -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,26 +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
25
|
# @param changelog [String] raw git changelog
|
24
26
|
# @return [Array<String>] list of issue ids from changelog
|
25
27
|
def issue_ids_from_changelog(changelog)
|
26
|
-
|
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
|
27
32
|
end
|
28
33
|
end
|
29
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,23 +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
|
17
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)
|
18
56
|
git_utils = Apadmi::Grout::GitUtils
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
57
|
+
issues_from_changelog_action = Apadmi::Grout::IssuesFromChangelogAction.new(ado_board_service, ticket_prefix, logger)
|
58
|
+
|
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
|
+
)
|
23
67
|
end
|
24
68
|
end
|
25
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
|
File without changes
|
@@ -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
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Apadmi
|
4
|
+
module Grout
|
5
|
+
# @param tasks [Array<Apadmi::Grout::Issue>]
|
6
|
+
# @param features [Array<Apadmi::Grout::Issue>] aka stories
|
7
|
+
# @param improvements [Array<Apadmi::Grout::Issue>]
|
8
|
+
# @param defects [Array<Apadmi::Grout::Issue>] aka bugs
|
9
|
+
# @param others [Array<Apadmi::Grout::Issue>] any other non-standard issue types
|
10
|
+
ClassifiedIssues = Struct.new(
|
11
|
+
:tasks,
|
12
|
+
:features,
|
13
|
+
:improvements,
|
14
|
+
:defects,
|
15
|
+
:others
|
16
|
+
) do
|
17
|
+
# @return returns true if all categories are empty
|
18
|
+
def empty
|
19
|
+
tasks.empty? && features.empty? &&
|
20
|
+
improvements.empty? && defects.empty? && others.empty?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# @param title [String] The title of the document
|
25
|
+
# @param app_version [String] The app version pertaining to this release
|
26
|
+
# @param min_os_version [String] The min supported os version of this release
|
27
|
+
# @param date [String] Today's date
|
28
|
+
# @param moved_issues [Array<Apadmi::Grout::Issue>] Issues moved to a new state by this build job
|
29
|
+
# @param release_issues [Array<Apadmi::Grout::Issue>] Issues considered part of this release
|
30
|
+
# @param commit_hash [String] Commit hash from which release was built
|
31
|
+
# @param ci_build_number [String] CI build number which built the release
|
32
|
+
# @param ci_build_url [String] Link to CI build job
|
33
|
+
# @param templates [Apadmi::Grout::Templates] Mustache templates to use to generate the document
|
34
|
+
ReleaseNotesConfig = Struct.new(
|
35
|
+
:title,
|
36
|
+
:app_version,
|
37
|
+
:min_os_version,
|
38
|
+
:date,
|
39
|
+
:moved_issues,
|
40
|
+
:release_issues,
|
41
|
+
:commit_hash,
|
42
|
+
:ci_build_number,
|
43
|
+
:ci_build_url,
|
44
|
+
:templates
|
45
|
+
)
|
46
|
+
end
|
47
|
+
end
|