apadmi_grout 3.0.0 → 3.0.1.pre1
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 +4 -1
- data/lib/apadmi/grout/actions/generate_release_notes_action/issue_classifier.rb +16 -10
- data/lib/apadmi/grout/actions/issues_from_changelog_action.rb +35 -1
- data/lib/apadmi/grout/models/issue.rb +13 -1
- data/lib/apadmi/grout/models/release_notes_config.rb +8 -2
- data/lib/apadmi/grout/models/release_notes_templates.rb +9 -1
- data/lib/apadmi/grout/service/board_service/jira_board_service.rb +15 -0
- data/lib/apadmi/grout/version.rb +1 -1
- metadata +5 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2b4dc32ad592cfe4759341af5327f80f0f1eb5b067b9eab72ff9b428fc82cc3b
|
|
4
|
+
data.tar.gz: 6e1b769f878a99adf7ad362f2690023584f3dad7b829175c769ba95f5b92a1c3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f4c50f009c0421f1eb6d00549cca5665a6717e2f26ab1542898107a476b9ae48706269eaca656602a5ac2aeca2e17719e0647327fb6235fde122c2c464d0e61a
|
|
7
|
+
data.tar.gz: 578bd2ed0f11d462294072be19de710f54f88720c3aad2b38c4dbf5ad4a5b9ee0e8fba0dac49c8ac59bc52f3a05025d43aebebf8553a47a921d67e94dabe5f5e
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# Core Changelog
|
|
2
2
|
|
|
3
|
-
## [3.0.
|
|
3
|
+
## [3.0.1.pre1] - TBD
|
|
4
|
+
* Bump dependencies to support Ruby 4
|
|
5
|
+
|
|
6
|
+
## [3.0.0] - 2026-04-22
|
|
4
7
|
* Support blank fields in release notes template
|
|
5
8
|
* Rename "Release Date" to "Build Date" to more accurately reflect the field in default release notes template
|
|
6
9
|
* Add utilities for writing and reading confluence files
|
|
@@ -16,16 +16,19 @@ module Apadmi
|
|
|
16
16
|
class JiraIssueClassifier < IssueClassifier
|
|
17
17
|
# @param issues [Array<Apadmi::Grout::Issue>]
|
|
18
18
|
def classify(issues)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
unclassified = issues.find_all { |issue| issue.issue_type == Apadmi::Grout::Issue::UNCLASSIFIED_ISSUE_TYPE }
|
|
20
|
+
classified = issues - unclassified
|
|
21
|
+
tasks = filter_issues_by_type(%w[Task], classified)
|
|
22
|
+
features = filter_issues_by_type(%w[Story], classified)
|
|
23
|
+
improvements = filter_issues_by_type(%w[Improvement Rework Debt], classified)
|
|
24
|
+
defects = filter_issues_by_type(%w[Bug], classified)
|
|
23
25
|
ClassifiedIssues.new(
|
|
24
26
|
tasks,
|
|
25
27
|
features,
|
|
26
28
|
improvements,
|
|
27
29
|
defects,
|
|
28
|
-
|
|
30
|
+
classified - tasks - features - improvements - defects,
|
|
31
|
+
unclassified
|
|
29
32
|
)
|
|
30
33
|
end
|
|
31
34
|
end
|
|
@@ -34,16 +37,19 @@ module Apadmi
|
|
|
34
37
|
class AdoIssueClassifier < IssueClassifier
|
|
35
38
|
# @param issues [Array<Apadmi::Grout::Issue>]
|
|
36
39
|
def classify(issues)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
unclassified = issues.find_all { |issue| issue.issue_type == Apadmi::Grout::Issue::UNCLASSIFIED_ISSUE_TYPE }
|
|
41
|
+
classified = issues - unclassified
|
|
42
|
+
tasks = filter_issues_by_type(%w[Task], classified)
|
|
43
|
+
features = filter_issues_by_type(["User Story", "Feature"], classified)
|
|
44
|
+
improvements = filter_issues_by_type(["Improvement", "Tech Debt"], classified)
|
|
45
|
+
defects = filter_issues_by_type(%w[Bug], classified)
|
|
41
46
|
ClassifiedIssues.new(
|
|
42
47
|
tasks,
|
|
43
48
|
features,
|
|
44
49
|
improvements,
|
|
45
50
|
defects,
|
|
46
|
-
|
|
51
|
+
classified - tasks - features - improvements - defects,
|
|
52
|
+
unclassified
|
|
47
53
|
)
|
|
48
54
|
end
|
|
49
55
|
end
|
|
@@ -19,9 +19,43 @@ module Apadmi
|
|
|
19
19
|
ids = issue_ids_from_changelog(changelog)
|
|
20
20
|
|
|
21
21
|
@logger.message("Found issue ids: #{ids.join(", ")}")
|
|
22
|
-
@board_service.find_issues_by_keys(ids)
|
|
22
|
+
found_issues = @board_service.find_issues_by_keys(ids)
|
|
23
|
+
|
|
24
|
+
# ADO strips the '#' prefix from returned Issue#key (e.g. '#16' → '16'),
|
|
25
|
+
# so check both forms when detecting missing tickets.
|
|
26
|
+
found_keys_normalised = found_issues.to_set { |i| i.key.to_s }
|
|
27
|
+
missing_ids = ids.reject do |id|
|
|
28
|
+
normalised = id.delete_prefix(@ticket_prefix.to_s)
|
|
29
|
+
found_keys_normalised.include?(id) || found_keys_normalised.include?(normalised)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
return found_issues if missing_ids.empty?
|
|
33
|
+
|
|
34
|
+
commit_lines = commit_line_for_ids(changelog)
|
|
35
|
+
fallback_issues = missing_ids.map do |id|
|
|
36
|
+
Apadmi::Grout::Issue.unclassified(id, commit_lines[id] || id)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
found_issues + fallback_issues
|
|
23
40
|
end
|
|
24
41
|
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
# @param changelog [String] raw git changelog
|
|
45
|
+
# @return [Hash{String => String}] mapping ticket ID to cleaned first commit line containing it
|
|
46
|
+
def commit_line_for_ids(changelog)
|
|
47
|
+
cleaned_changelog = changelog.gsub(/\(pull request.*\)/, "")
|
|
48
|
+
result = {}
|
|
49
|
+
cleaned_changelog.each_line do |line|
|
|
50
|
+
line.scan(/(#{@ticket_prefix}\d+)/).flatten.each do |id|
|
|
51
|
+
result[id] ||= line.strip.delete_prefix("- ").strip
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
result
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
public
|
|
58
|
+
|
|
25
59
|
# @param changelog [String] raw git changelog
|
|
26
60
|
# @return [Array<String>] list of issue ids from changelog
|
|
27
61
|
def issue_ids_from_changelog(changelog)
|
|
@@ -8,8 +8,17 @@ module Apadmi
|
|
|
8
8
|
# @param status [String] The current status on the board
|
|
9
9
|
# @param issue_type [String] Raw string representing issue type e.g "In Progress"
|
|
10
10
|
# @param url [String] url to the issue
|
|
11
|
-
# @param raw_object [JIRA::Resource::Issue
|
|
11
|
+
# @param raw_object [JIRA::Resource::Issue, Hash, nil] The underlying raw object from the platform.
|
|
12
|
+
# nil for unclassified fallback issues created from commit messages when the ticket was not found.
|
|
12
13
|
Issue = Struct.new(:key, :summary, :status, :issue_type, :url, :raw_object) do
|
|
14
|
+
# Creates a fallback issue from a commit message when the ticket ID could not be found in the board.
|
|
15
|
+
# @param key [String] the ticket ID as extracted from the commit (e.g. "PPT-999")
|
|
16
|
+
# @param summary [String] the first line of the commit message
|
|
17
|
+
# @return [Apadmi::Grout::Issue]
|
|
18
|
+
def self.unclassified(key, summary)
|
|
19
|
+
Issue.new(key, summary, "Unknown", Issue::UNCLASSIFIED_ISSUE_TYPE, "", nil)
|
|
20
|
+
end
|
|
21
|
+
|
|
13
22
|
# @return [Apadmi::Grout::Issue]
|
|
14
23
|
def self.from_ado_hash(hash)
|
|
15
24
|
Issue.new(
|
|
@@ -45,5 +54,8 @@ module Apadmi
|
|
|
45
54
|
issues.map { |i| Issue.from_jira_issue(i, base_url) }
|
|
46
55
|
end
|
|
47
56
|
end
|
|
57
|
+
|
|
58
|
+
# Issue type string used for fallback issues created from commit messages when the ticket was not found in the board.
|
|
59
|
+
Issue::UNCLASSIFIED_ISSUE_TYPE = "Unclassified"
|
|
48
60
|
end
|
|
49
61
|
end
|
|
@@ -7,17 +7,23 @@ module Apadmi
|
|
|
7
7
|
# @param improvements [Array<Apadmi::Grout::Issue>]
|
|
8
8
|
# @param defects [Array<Apadmi::Grout::Issue>] aka bugs
|
|
9
9
|
# @param others [Array<Apadmi::Grout::Issue>] any other non-standard issue types
|
|
10
|
+
# @param unclassified [Array<Apadmi::Grout::Issue>] commits whose ticket IDs could not be found in Jira/ADO
|
|
10
11
|
ClassifiedIssues = Struct.new(
|
|
11
12
|
:tasks,
|
|
12
13
|
:features,
|
|
13
14
|
:improvements,
|
|
14
15
|
:defects,
|
|
15
|
-
:others
|
|
16
|
+
:others,
|
|
17
|
+
:unclassified
|
|
16
18
|
) do
|
|
19
|
+
def initialize(tasks, features, improvements, defects, others, unclassified = [])
|
|
20
|
+
super
|
|
21
|
+
end
|
|
22
|
+
|
|
17
23
|
# @return returns true if all categories are empty
|
|
18
24
|
def empty?
|
|
19
25
|
tasks.empty? && features.empty? &&
|
|
20
|
-
improvements.empty? && defects.empty? && others.empty?
|
|
26
|
+
improvements.empty? && defects.empty? && others.empty? && unclassified.empty?
|
|
21
27
|
end
|
|
22
28
|
end
|
|
23
29
|
|
|
@@ -72,7 +72,15 @@ Commit Hash: {{config.commit_hash}}
|
|
|
72
72
|
* [{{issue_type}} - {{ key }} - {{ summary }}]({{ url }})
|
|
73
73
|
{{/ classified_issues.others}}
|
|
74
74
|
|
|
75
|
-
{{/ classified_issues.others.first}}}
|
|
75
|
+
{{/ classified_issues.others.first}}{{# classified_issues.unclassified.first}}
|
|
76
|
+
### Unclassified
|
|
77
|
+
{{# classified_issues.unclassified}}
|
|
78
|
+
* {{ key }} - {{ summary }}
|
|
79
|
+
{{/ classified_issues.unclassified}}
|
|
80
|
+
|
|
81
|
+
_Note: These commits reference ticket IDs that could not be found in the board._
|
|
82
|
+
|
|
83
|
+
{{/ classified_issues.unclassified.first}}}
|
|
76
84
|
end
|
|
77
85
|
end
|
|
78
86
|
|
|
@@ -57,6 +57,11 @@ module Apadmi
|
|
|
57
57
|
# @param [Apadmi::Grout::Issue] issue
|
|
58
58
|
# @param [String] state_name
|
|
59
59
|
def transition_issue(issue, state_name)
|
|
60
|
+
if issue.raw_object.nil?
|
|
61
|
+
warn "Skipping transition for unclassified fallback issue #{issue.key}"
|
|
62
|
+
return
|
|
63
|
+
end
|
|
64
|
+
|
|
60
65
|
transitions = @jira_client.Transition.all(issue: issue.raw_object)
|
|
61
66
|
transition = transitions.find { |elem| elem.name.downcase == state_name.downcase }
|
|
62
67
|
|
|
@@ -132,6 +137,11 @@ module Apadmi
|
|
|
132
137
|
# @param [Apadmi::Grout::Issue] issue
|
|
133
138
|
# @return [Array<PullRequest>]
|
|
134
139
|
def get_ticket_prs(issue)
|
|
140
|
+
if issue.raw_object.nil?
|
|
141
|
+
warn "Skipping PR lookup for unclassified fallback issue #{issue.key}"
|
|
142
|
+
return []
|
|
143
|
+
end
|
|
144
|
+
|
|
135
145
|
query_string = "issueId=#{issue.raw_object.id}&applicationType=bitbucket&dataType=pullrequest"
|
|
136
146
|
response = @network_service.do_get("/rest/dev-status/latest/issue/details?#{query_string}")
|
|
137
147
|
|
|
@@ -206,6 +216,11 @@ module Apadmi
|
|
|
206
216
|
versions = create_or_get_versions(version_names)
|
|
207
217
|
|
|
208
218
|
issues.each do |issue|
|
|
219
|
+
if issue.raw_object.nil?
|
|
220
|
+
warn "Skipping fix version assignment for unclassified fallback issue #{issue.key}"
|
|
221
|
+
next
|
|
222
|
+
end
|
|
223
|
+
|
|
209
224
|
existing_ids = issue.raw_object.fixVersions.map(&:id)
|
|
210
225
|
missing = versions.reject { |v| existing_ids.include?(v.id) }
|
|
211
226
|
next if missing.empty?
|
data/lib/apadmi/grout/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: apadmi_grout
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.0.
|
|
4
|
+
version: 3.0.1.pre1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Apadmi
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: faraday
|
|
@@ -30,14 +29,14 @@ dependencies:
|
|
|
30
29
|
requirements:
|
|
31
30
|
- - "~>"
|
|
32
31
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: 3.
|
|
32
|
+
version: '3.1'
|
|
34
33
|
type: :runtime
|
|
35
34
|
prerelease: false
|
|
36
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
36
|
requirements:
|
|
38
37
|
- - "~>"
|
|
39
38
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: 3.
|
|
39
|
+
version: '3.1'
|
|
41
40
|
- !ruby/object:Gem::Dependency
|
|
42
41
|
name: mustache
|
|
43
42
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -121,7 +120,6 @@ metadata:
|
|
|
121
120
|
documentation_uri: https://apadmi-grout.web.app/
|
|
122
121
|
source_code_uri: https://bitbucket.org/apadmi/apadmi-grout-ruby/
|
|
123
122
|
changelog_uri: https://bitbucket.org/apadmi/apadmi-grout-ruby/
|
|
124
|
-
post_install_message:
|
|
125
123
|
rdoc_options: []
|
|
126
124
|
require_paths:
|
|
127
125
|
- lib
|
|
@@ -136,8 +134,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
136
134
|
- !ruby/object:Gem::Version
|
|
137
135
|
version: '0'
|
|
138
136
|
requirements: []
|
|
139
|
-
rubygems_version:
|
|
140
|
-
signing_key:
|
|
137
|
+
rubygems_version: 4.0.6
|
|
141
138
|
specification_version: 4
|
|
142
139
|
summary: Apadmi build tool utils for use through Fastlane on Android and iOS.
|
|
143
140
|
test_files: []
|