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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d8923ffd455567fa6a2c5d5472f4a789774ce6ef908338deee9dc8d52b63de33
4
- data.tar.gz: 65e30d6c06c05f0ab2f132336a994dbee4fff7c0384311b4eb91ee3e05010875
3
+ metadata.gz: 2b4dc32ad592cfe4759341af5327f80f0f1eb5b067b9eab72ff9b428fc82cc3b
4
+ data.tar.gz: 6e1b769f878a99adf7ad362f2690023584f3dad7b829175c769ba95f5b92a1c3
5
5
  SHA512:
6
- metadata.gz: 886dad14e21540cd5f8bbfdc74f8b33e78321eeae62a5d89b0d9ecdb568b15f8ffb928291ce443a68e7c55c349f39a2c6fce69ec902f694711adbdc6df62df0c
7
- data.tar.gz: 1db680639fc0621edaeb1346a51be1b1bb9d90dae3772969dcd4edd1e531a22ad81c630034fd83c98753a687c70e330d09ef382b29fcc7e160a62812ad4a6f70
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.0] - TBD
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
- 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)
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
- issues - tasks - features - improvements - defects
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
- 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)
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
- issues - tasks - features - improvements - defects
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|Hash] The underlying raw object from the platform
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?
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Apadmi
4
4
  module Grout
5
- VERSION = "3.0.0"
5
+ VERSION = "3.0.1.pre1"
6
6
  end
7
7
  end
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.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: 2026-04-22 00:00:00.000000000 Z
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.0.0
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.0.0
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: 3.5.22
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: []