apadmi_grout 1.1.0 → 2.1.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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/lib/apadmi/grout/actions/find_tickets_to_move_action/find_tickets_to_move_action.rb +24 -0
  4. data/lib/apadmi/grout/actions/find_tickets_to_move_action/find_tickets_to_move_ado_action.rb +91 -0
  5. data/lib/apadmi/grout/actions/find_tickets_to_move_action/find_tickets_to_move_jira_action.rb +114 -0
  6. data/lib/apadmi/grout/actions/generate_release_notes_action/generate_release_notes_action.rb +48 -0
  7. data/lib/apadmi/grout/actions/generate_release_notes_action/issue_classifier.rb +51 -0
  8. data/lib/apadmi/grout/{release_notes/actions → actions}/issues_from_changelog_action.rb +11 -8
  9. data/lib/apadmi/grout/actions/move_tickets_action.rb +34 -0
  10. data/lib/apadmi/grout/di.rb +59 -9
  11. data/lib/apadmi/grout/{jira/models/find_tickets_options.rb → models/ado_config.rb} +2 -2
  12. data/lib/apadmi/grout/models/bitrise.rb +38 -0
  13. data/lib/apadmi/grout/models/find_tickets_options.rb +44 -0
  14. data/lib/apadmi/grout/{jira/models → models}/flag_messages.rb +2 -1
  15. data/lib/apadmi/grout/models/issue.rb +49 -0
  16. data/lib/apadmi/grout/{jira/models → models}/pull_request.rb +0 -0
  17. data/lib/apadmi/grout/models/release_notes_config.rb +47 -0
  18. data/lib/apadmi/grout/{release_notes/models → models}/release_notes_templates.rb +6 -6
  19. data/lib/apadmi/grout/service/bitrise_service/bitrise_service.rb +103 -0
  20. data/lib/apadmi/grout/service/board_service/ado_board_service.rb +199 -0
  21. data/lib/apadmi/grout/service/board_service/board_service.rb +59 -0
  22. data/lib/apadmi/grout/{jira/wrapper/jira_wrapper.rb → service/board_service/jira_board_service.rb} +65 -107
  23. data/lib/apadmi/grout/utils/git_utils.rb +36 -0
  24. data/lib/apadmi/grout/utils/network_service.rb +123 -0
  25. data/lib/apadmi/grout/version.rb +1 -1
  26. data/lib/apadmi_grout.rb +3 -21
  27. metadata +23 -14
  28. data/lib/apadmi/grout/jira/actions/find_tickets_to_move_action.rb +0 -80
  29. data/lib/apadmi/grout/jira/actions/move_jira_tickets_action.rb +0 -58
  30. data/lib/apadmi/grout/jira/models/version.rb +0 -23
  31. data/lib/apadmi/grout/release_notes/actions/generate_release_notes_action.rb +0 -39
  32. data/lib/apadmi/grout/release_notes/models/release_notes_config.rb +0 -74
@@ -1,23 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Build tools
4
3
  require "jira-ruby"
5
- require "faraday"
6
4
 
7
5
  module Apadmi
8
6
  module Grout
9
7
  # Provides a layer of abstraction on top of the Jira api
10
- class JiraWrapper
11
- APPLICATION_JSON = "application/json"
12
- CONTENT_TYPE = "Content-Type"
13
- private_constant :CONTENT_TYPE, :APPLICATION_JSON
14
-
8
+ class JiraBoardService < BoardService
15
9
  # @param [String] username
16
10
  # @param [String] token
17
11
  # @param [String] base_url
18
12
  # @param [String] context_path
19
13
  # @param [String] project
20
- def initialize(username, token, base_url, context_path, project)
14
+ # @param [Apadmi::Grout::NetworkService] network_service
15
+ def initialize(username, token, base_url, context_path, project, network_service)
21
16
  @options = {
22
17
  username: username,
23
18
  password: token,
@@ -26,29 +21,27 @@ module Apadmi
26
21
  auth_type: :basic
27
22
  }
28
23
  @project = project
24
+ @network_service = network_service
29
25
  @jira_client = JIRA::Client.new(@options)
30
26
  end
31
27
 
32
- # @return returns the ticket prefix for the given project
33
- def issue_id_prefix
34
- @project
35
- end
36
-
37
28
  # @param [String[]] keys
38
- # @return [Array<JIRA::Resource::Issue>]
29
+ # @return [Array<Apadmi::Grout::Issue>]
39
30
  def find_issues_by_keys(keys)
40
31
  return [] if keys.length <= 0
41
32
 
42
33
  jql_search = "project = '#{@project}' AND issue IN (#{keys.join(", ")})"
43
- @jira_client.Issue.jql(jql_search, { max_results: 1000 }).uniq
34
+ issues = @jira_client.Issue.jql(jql_search, { max_results: 1000 }).uniq
35
+ convert(issues)
44
36
  end
45
37
 
46
38
  # @param [String] component
47
39
  # @param [String] status
48
40
  # @param [String[]] ticket_types
49
- # @param [Boolean] allow_no_sprint
50
- # @return [Array<JIRA::Resource::Issue>]
51
- def search_unblocked_issues(component, status, ticket_types = [], allow_no_sprint: false)
41
+ # @param [Apadmi::Grout::JiraFindTicketsOptions] options
42
+ # @return [Array<Apadmi::Grout::Issue>]
43
+ def search_unblocked_issues(component, status, ticket_types = [], options = nil)
44
+ allow_no_sprint = options&.include_no_sprint_tickets || false
52
45
  component_filter = (" AND component = '#{component}' " unless component.empty?) || ""
53
46
  status_filter = (" AND status = '#{status}' " unless status.empty?) || ""
54
47
  type_filter = ("AND (#{ticket_types.map { |type| "type = #{type}" }.join("OR ")})" unless ticket_types.empty?) || ""
@@ -61,20 +54,31 @@ module Apadmi
61
54
  AND Flagged is EMPTY
62
55
  }
63
56
 
64
- @jira_client.Issue.jql(jql_search, { max_results: 1000 }).uniq
57
+ issues = @jira_client.Issue.jql(jql_search, { max_results: 1000 }).uniq
58
+ convert(issues)
59
+ end
60
+
61
+ # @param [Apadmi::Grout::Issue] issue
62
+ # @param [String] state_name
63
+ def transition_issue(issue, state_name)
64
+ transitions = @jira_client.Transition.all(issue: issue.raw_object)
65
+ transition = transitions.find { |elem| elem.name.downcase == state_name.downcase }
66
+
67
+ trans = issue.raw_object.transitions.build
68
+ trans.save!("transition" => { "id" => transition.id })
65
69
  end
66
70
 
67
71
  # @param [String] key
68
72
  # @param [String] comment
69
73
  def flag_ticket(key, comment)
70
74
  payload = "{\"flag\":true,\"issueKeys\":[\"#{key}\"],\"commentVisibility\":\"\",\"comment\":\"#{comment}\"}"
71
- do_post("#{@options[:site]}/rest/greenhopper/1.0/xboard/issue/flag/flag.json", payload)
75
+ @network_service.do_post("/rest/greenhopper/1.0/xboard/issue/flag/flag.json", payload)
72
76
  end
73
77
 
74
78
  # @param [String] key
75
79
  def un_flag_ticket(key)
76
80
  payload = "{\"flag\":false,\"issueKeys\":[\"#{key}\"],\"commentVisibility\":\"\",\"comment\":\"Unflagged by CI\"}"
77
- do_post("#{@options[:site]}/rest/greenhopper/1.0/xboard/issue/flag/flag.json", payload)
81
+ @network_service.do_post("/rest/greenhopper/1.0/xboard/issue/flag/flag.json", payload)
78
82
  end
79
83
 
80
84
  # @param [String] key
@@ -89,7 +93,7 @@ module Apadmi
89
93
  # @param [String] comment
90
94
  def add_comment(key, comment)
91
95
  payload = "{\"issueKeys\":[\"#{key}\"],\"commentVisibility\":\"\",\"comment\":\"#{comment}\"}"
92
- do_post("#{@options[:site]}/rest/greenhopper/1.0/xboard/issue/flag/flag.json", payload)
96
+ @network_service.do_post("/rest/greenhopper/1.0/xboard/issue/flag/flag.json", payload)
93
97
  end
94
98
 
95
99
  # @param [String] key
@@ -104,14 +108,14 @@ module Apadmi
104
108
  # @param [String] key
105
109
  # @param [String] comment_id
106
110
  def remove_comment(key, comment_id)
107
- do_delete("#{@options[:site]}/rest/api/2/issue/#{key}/comment/#{comment_id}")
111
+ @network_service.do_delete("/rest/api/2/issue/#{key}/comment/#{comment_id}")
108
112
  end
109
113
 
110
114
  # @param [String] component_key
111
- # @return [Array<JIRA::Resource::Issue>]
115
+ # @return [Array<Apadmi::Grout::Issue>]
112
116
  def get_tickets_by_component(component_key)
113
117
  jql_search = "project = '#{@project}' AND component IN ('#{component_key}')"
114
- @jira_client.Issue.jql(jql_search, { max_results: 1000 }).uniq
118
+ convert(@jira_client.Issue.jql(jql_search, { max_results: 1000 }).uniq)
115
119
  end
116
120
 
117
121
  # @param [String] key
@@ -120,33 +124,18 @@ module Apadmi
120
124
  @jira_client.Transition.all(issue: issue)
121
125
  end
122
126
 
123
- # @param [String] ticket
124
- # @param [String] state_name
125
- def transition_ticket(ticket, state_name)
126
- issue = @jira_client.Issue.find(ticket)
127
- transition_issue(issue, state_name)
128
- end
129
-
130
- # @param [JIRA::Resource::Issue] issue
131
- # @param [String] state_name
132
- def transition_issue(issue, state_name)
133
- transitions = @jira_client.Transition.all(issue: issue)
134
- transition = transitions.find { |elem| elem.name == state_name }
135
-
136
- trans = issue.transitions.build
137
- trans.save!("transition" => { "id" => transition.id })
138
- end
139
-
140
127
  # @param [String] key
128
+ # @return [String]
141
129
  def get_ticket_status(key)
142
130
  issue = @jira_client.Issue.find(key)
143
- issue.status
131
+ issue.status.name
144
132
  end
145
133
 
146
- # @param [JIRA::Resource::Issue] issue
134
+ # @param [Apadmi::Grout::Issue] issue
147
135
  # @return [Array<PullRequest>]
148
136
  def get_ticket_prs(issue)
149
- response = do_get("#{@options[:site]}/rest/dev-status/latest/issue/details?issueId=#{issue.id}&applicationType=bitbucket&dataType=pullrequest")
137
+ query_string = "issueId=#{issue.raw_object.id}&applicationType=bitbucket&dataType=pullrequest"
138
+ response = @network_service.do_get("/rest/dev-status/latest/issue/details?#{query_string}")
150
139
 
151
140
  return [] if JSON.parse(response.body)["detail"].empty?
152
141
 
@@ -157,11 +146,11 @@ module Apadmi
157
146
 
158
147
  # @param [String] keys
159
148
  # @param [String] component
160
- # @return [Array<JIRA::Resource::Issue>]
149
+ # @return [Array<Apadmi::Grout::Issue>]
161
150
  def get_ticket_subtask(keys, component = nil)
162
151
  jql_search = "project = '#{@project}' AND parent IN #{keys.to_s.gsub("[", "(").gsub("]", ")")}"\
163
152
  + (component.nil? ? "" : " AND component IN ('#{component}')")
164
- @jira_client.Issue.jql(jql_search, { max_results: 1000 }).uniq
153
+ convert(@jira_client.Issue.jql(jql_search, { max_results: 1000 }).uniq)
165
154
  end
166
155
 
167
156
  # @param [String] release_date
@@ -182,7 +171,7 @@ module Apadmi
182
171
  def delete_version(version_id, move_version_id)
183
172
  payload = "{\"moveFixIssuesTo\": #{move_version_id}, \"moveAffectedIssuesTo\": #{move_version_id}, "\
184
173
  "\"customFieldReplacementList\": []}"
185
- do_post("#{@options[:site]}/rest/api/2/version/#{version_id}/removeAndSwap", payload)
174
+ @network_service.do_post("/rest/api/2/version/#{version_id}/removeAndSwap", payload)
186
175
  end
187
176
 
188
177
  # @return [Array<JIRA::Resource::Version>]
@@ -190,75 +179,44 @@ module Apadmi
190
179
  @jira_client.Project.find(@project).versions
191
180
  end
192
181
 
193
- # @param [String] ticket
194
- # @param [Array<JIRA::Resource::Version>] versions
195
- def assign_fixversions(ticket, versions)
182
+ # @param [String] key
183
+ # @param [Array<String>] version_strings
184
+ def assign_fixversions(key, version_strings)
185
+ versions = create_or_get_versions(version_strings)
196
186
  fixversions = versions.map { |v| "{\"id\": \"#{v.id}\"}" }.join(", ")
197
187
  payload = "{\"fields\" : {\"fixVersions\": [#{fixversions}] }}"
198
- do_put("#{@options[:site]}/rest/api/2/issue/#{ticket}", payload)
199
- end
200
-
201
- # @param [String] ticket
202
- # @return [Array<Version>]
203
- def get_ticket_fixversions(ticket)
204
- response = do_get("#{@options[:site]}/rest/api/2/issue/#{ticket}")
205
- JSON.parse(response.body)["fields"]["fixVersions"].map do |version|
206
- Version.new(version)
207
- end
208
- end
209
-
210
- # @param [Faraday::Response] response
211
- def throw_if_error(response)
212
- raise "Network call failed #{response.status} #{response.body}" unless (200..210).include?(response.status)
188
+ @network_service.do_put("/rest/api/2/issue/#{key}", payload)
213
189
  end
214
190
 
215
- # @param [String] uri
216
- # @return [Faraday::Response]
217
- def do_get(uri)
218
- conn = setup_con
219
- response = conn.get(uri, CONTENT_TYPE => APPLICATION_JSON)
220
- throw_if_error(response)
221
- response
222
- end
223
-
224
- # @param [String] uri
225
- # @param [String] payload
226
- # @return [Faraday::Response]
227
- def do_put(uri, payload)
228
- conn = setup_con
229
- response = conn.put(uri, payload, CONTENT_TYPE => APPLICATION_JSON)
230
- throw_if_error(response)
231
- response
191
+ # @param [String] key
192
+ # @return [Array<String>]
193
+ def get_ticket_fixversions(key)
194
+ response = @network_service.do_get("/rest/api/2/issue/#{key}")
195
+ JSON.parse(response.body)["fields"]["fixVersions"].map { |v| v["name"] } || []
232
196
  end
233
197
 
234
- # @param [String] uri
235
- # @param [String] payload
236
- # @return [Faraday::Response]
237
- def do_post(uri, payload)
238
- conn = setup_con
239
- response = conn.post(uri, payload, CONTENT_TYPE => APPLICATION_JSON)
240
- throw_if_error(response)
241
- response
242
- end
198
+ private
243
199
 
244
- # @param [String] uri
245
- # @return [Faraday::Response]
246
- def do_delete(uri)
247
- conn = setup_con
248
- response = conn.delete(uri, CONTENT_TYPE => APPLICATION_JSON)
249
- throw_if_error(response)
250
- response
200
+ # @param [Array<String>] version_strings
201
+ # @return [Array<JIRA::Resource::Version>]
202
+ def create_or_get_versions(version_strings)
203
+ all = all_versions
204
+ version_strings.map do |version|
205
+ existing_version = all.find { |v| v.name == version }
206
+ if !existing_version.nil?
207
+ existing_version
208
+ else
209
+ date = Time.now.strftime("%Y-%m-%d")
210
+ create_version(date, version)
211
+ end
212
+ end
251
213
  end
252
214
 
253
- # @return [Faraday::Connection]
254
- def setup_con
255
- auth_str = "#{@options[:username]}:#{@options[:password]}"
256
- conn = Faraday.new # create a new Connection with base URL
257
- conn.headers["Authorization"] = "Basic #{Base64.strict_encode64(auth_str)}"
258
- conn
215
+ # @param [Array<JIRA::Resource::Issue>]
216
+ # @return [Array<Apadmi::Grout::Issue>]
217
+ def convert(issues)
218
+ Apadmi::Grout::Issue.from_jira_issues(issues, @options[:site])
259
219
  end
260
-
261
- private :setup_con, :do_delete, :do_get, :do_post, :do_put
262
220
  end
263
221
  end
264
222
  end
@@ -15,6 +15,14 @@ module Apadmi
15
15
  stdout.strip
16
16
  end
17
17
 
18
+ # Gets the commit hash of the current HEAD
19
+ def self.commit_hash
20
+ stdout, stderr, = Open3.capture3("git rev-parse HEAD")
21
+ raise "Failed to get hash: #{stderr}" unless stderr.strip.empty?
22
+
23
+ stdout.strip
24
+ end
25
+
18
26
  # Gets the number of commits accessible from HEAD treating the history as a graph.
19
27
  # See more details here: https://git-scm.com/docs/git-rev-list
20
28
  # @return [String] The number of commits
@@ -24,6 +32,34 @@ module Apadmi
24
32
 
25
33
  stdout.strip
26
34
  end
35
+
36
+ # Runs a git fetch all
37
+ def self.fetch_all
38
+ stdout, stderr, = Open3.capture3("git fetch --all")
39
+ raise "Failed to fetch #{stderr}" unless stderr.strip.empty?
40
+
41
+ stdout.strip
42
+ end
43
+
44
+ # Gets all the merges accessible from the current HEAD which matches at least one of the given grep conditions
45
+ # @param grep_conditions [Array<String>] values to be passed in as grep cases (https://git-scm.com/docs/git-log)
46
+ def self.merge_changelog(grep_conditions)
47
+ command = "git log HEAD --merges --format=%s#{grep_conditions.map { |c| " --grep #{c}" }.join(" ")}"
48
+ stdout, stderr, = Open3.capture3(command)
49
+ raise "Failed to get changelog: #{stderr}" unless stderr.strip.empty?
50
+
51
+ stdout
52
+ end
53
+
54
+ # Gets all the merges that are NOT accessible from HEAD which matches at least one of the given grep conditions
55
+ # @param grep_conditions [Array<String>] values to be passed in as grep cases (https://git-scm.com/docs/git-log)
56
+ def self.invert_changelog(grep_conditions)
57
+ command = "git log --all ^HEAD --merges --format=%s#{grep_conditions.map { |c| " --grep #{c}" }.join(" ")}"
58
+ stdout, stderr, = Open3.capture3(command)
59
+ raise "Failed to get changelog: #{stderr}" unless stderr.strip.empty?
60
+
61
+ stdout
62
+ end
27
63
  end
28
64
  end
29
65
  end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "faraday"
4
+
5
+ module Apadmi
6
+ module Grout
7
+ # Utility class for running REST network calls
8
+ class NetworkService
9
+ attr_reader :base_url
10
+
11
+ APPLICATION_JSON = "application/json"
12
+ PATCH_CONTENT_TYPE = "application/json-patch+json"
13
+ FORM_CONTENT_TYPE = "application/x-www-form-urlencoded"
14
+ CONTENT_TYPE = "Content-Type"
15
+ private_constant :CONTENT_TYPE, :APPLICATION_JSON
16
+
17
+ # @param username [String]
18
+ # @param password [String]
19
+ # @param base_url [String]
20
+ # Params are encoded for use in Basic Auth https://datatracker.ietf.org/doc/html/rfc7617
21
+ def self.init_for_basic_auth(username, password, base_url, timeout = 30)
22
+ auth_str = "#{username}:#{password}"
23
+ auth_header = "Basic #{Base64.strict_encode64(auth_str)}"
24
+ NetworkService.new(auth_header, base_url, timeout)
25
+ end
26
+
27
+ # @param auth_header [String]
28
+ # @param base_url [String]
29
+ def initialize(auth_header, base_url, timeout = 30)
30
+ @base_url = base_url
31
+ @auth_header = auth_header
32
+ @timeout = timeout
33
+ end
34
+
35
+ # @param [String] path
36
+ # @return [Faraday::Response]
37
+ def do_get(path)
38
+ conn = setup_con
39
+ response = conn.get("#{@base_url}#{path}", CONTENT_TYPE => APPLICATION_JSON)
40
+ throw_if_error(response)
41
+ response
42
+ end
43
+
44
+ # @param [String] path
45
+ # @param [String] payload
46
+ # @return [Faraday::Response]
47
+ def do_put(path, payload)
48
+ conn = setup_con
49
+ response = conn.put("#{@base_url}#{path}", payload, CONTENT_TYPE => APPLICATION_JSON)
50
+ throw_if_error(response)
51
+ response
52
+ end
53
+
54
+ # @param [String] path
55
+ # @param [String] payload
56
+ # @return [Faraday::Response]
57
+ def do_post(path, payload)
58
+ conn = setup_con
59
+ response = conn.post("#{@base_url}#{path}", payload, CONTENT_TYPE => APPLICATION_JSON)
60
+ throw_if_error(response)
61
+ response
62
+ end
63
+
64
+ def do_form_encoded_post(path, payload)
65
+ conn = setup_con
66
+ response = conn.post("#{@base_url}#{path}") do |req|
67
+ req.headers[CONTENT_TYPE] = FORM_CONTENT_TYPE
68
+ req.body = URI.encode_www_form(payload)
69
+ end
70
+ throw_if_error(response)
71
+ response
72
+ end
73
+
74
+ def do_file_post(path, file_path, type)
75
+ conn = Faraday.new do |f|
76
+ f.request :multipart
77
+ f.adapter :net_http
78
+ end
79
+ conn.options.timeout = @timeout
80
+ conn.headers["Authorization"] = @auth_header
81
+
82
+ payload = { file: Faraday::UploadIO.new(file_path, type) }
83
+ response = conn.post("#{@base_url}#{path}", payload)
84
+ throw_if_error(response)
85
+ response
86
+ end
87
+
88
+ # @param [String] path
89
+ # @param [String] payload
90
+ # @return [Faraday::Response]
91
+ def do_patch(path, payload)
92
+ conn = setup_con
93
+ response = conn.patch("#{@base_url}#{path}", payload, CONTENT_TYPE => PATCH_CONTENT_TYPE)
94
+ throw_if_error(response)
95
+ response
96
+ end
97
+
98
+ # @param [String] path
99
+ # @return [Faraday::Response]
100
+ def do_delete(path)
101
+ conn = setup_con
102
+ response = conn.delete("#{@base_url}#{path}", CONTENT_TYPE => APPLICATION_JSON)
103
+ throw_if_error(response)
104
+ response
105
+ end
106
+
107
+ private
108
+
109
+ # @return [Faraday::Connection]
110
+ def setup_con
111
+ conn = Faraday.new # create a new Connection with base URL
112
+ conn.headers["Authorization"] = @auth_header
113
+ conn.options.timeout = @timeout
114
+ conn
115
+ end
116
+
117
+ # @param [Faraday::Response] response
118
+ def throw_if_error(response)
119
+ raise "Network call failed #{response.status} #{response.body}" unless (200..210).include?(response.status)
120
+ end
121
+ end
122
+ end
123
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Apadmi
4
4
  module Grout
5
- VERSION = "1.1.0"
5
+ VERSION = "2.1.0"
6
6
  end
7
7
  end
data/lib/apadmi_grout.rb CHANGED
@@ -1,23 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "apadmi/grout/version"
4
- require_relative "apadmi/grout/di"
5
-
6
- require_relative "apadmi/grout/release_notes/actions/issues_from_changelog_action"
7
- require_relative "apadmi/grout/release_notes/actions/generate_release_notes_action"
8
- require_relative "apadmi/grout/release_notes/models/release_notes_config"
9
- require_relative "apadmi/grout/release_notes/models/release_notes_templates"
10
-
11
- require_relative "apadmi/grout/jira/actions/move_jira_tickets_action"
12
- require_relative "apadmi/grout/jira/actions/find_tickets_to_move_action"
13
-
14
- require_relative "apadmi/grout/jira/wrapper/jira_wrapper"
15
-
16
- require_relative "apadmi/grout/jira/models/pull_request"
17
- require_relative "apadmi/grout/jira/models/version"
18
- require_relative "apadmi/grout/jira/models/flag_messages"
19
- require_relative "apadmi/grout/jira/models/find_tickets_options"
20
-
21
- require_relative "apadmi/grout/utils/logger"
22
- require_relative "apadmi/grout/utils/git_utils"
23
- require_relative "apadmi/grout/utils/filename_utils"
3
+ Dir[File.expand_path("apadmi/grout/**/*.rb", File.dirname(__FILE__))].sort.each do |current|
4
+ require current
5
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apadmi_grout
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
- - Sam
7
+ - Apadmi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-05-12 00:00:00.000000000 Z
11
+ date: 2022-07-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -63,21 +63,30 @@ files:
63
63
  - CODE_OF_CONDUCT.md
64
64
  - LICENSE
65
65
  - README.md
66
+ - lib/apadmi/grout/actions/find_tickets_to_move_action/find_tickets_to_move_action.rb
67
+ - lib/apadmi/grout/actions/find_tickets_to_move_action/find_tickets_to_move_ado_action.rb
68
+ - lib/apadmi/grout/actions/find_tickets_to_move_action/find_tickets_to_move_jira_action.rb
69
+ - lib/apadmi/grout/actions/generate_release_notes_action/generate_release_notes_action.rb
70
+ - lib/apadmi/grout/actions/generate_release_notes_action/issue_classifier.rb
71
+ - lib/apadmi/grout/actions/issues_from_changelog_action.rb
72
+ - lib/apadmi/grout/actions/move_tickets_action.rb
66
73
  - lib/apadmi/grout/di.rb
67
- - lib/apadmi/grout/jira/actions/find_tickets_to_move_action.rb
68
- - lib/apadmi/grout/jira/actions/move_jira_tickets_action.rb
69
- - lib/apadmi/grout/jira/models/find_tickets_options.rb
70
- - lib/apadmi/grout/jira/models/flag_messages.rb
71
- - lib/apadmi/grout/jira/models/pull_request.rb
72
- - lib/apadmi/grout/jira/models/version.rb
73
- - lib/apadmi/grout/jira/wrapper/jira_wrapper.rb
74
- - lib/apadmi/grout/release_notes/actions/generate_release_notes_action.rb
75
- - lib/apadmi/grout/release_notes/actions/issues_from_changelog_action.rb
76
- - lib/apadmi/grout/release_notes/models/release_notes_config.rb
77
- - lib/apadmi/grout/release_notes/models/release_notes_templates.rb
74
+ - lib/apadmi/grout/models/ado_config.rb
75
+ - lib/apadmi/grout/models/bitrise.rb
76
+ - lib/apadmi/grout/models/find_tickets_options.rb
77
+ - lib/apadmi/grout/models/flag_messages.rb
78
+ - lib/apadmi/grout/models/issue.rb
79
+ - lib/apadmi/grout/models/pull_request.rb
80
+ - lib/apadmi/grout/models/release_notes_config.rb
81
+ - lib/apadmi/grout/models/release_notes_templates.rb
82
+ - lib/apadmi/grout/service/bitrise_service/bitrise_service.rb
83
+ - lib/apadmi/grout/service/board_service/ado_board_service.rb
84
+ - lib/apadmi/grout/service/board_service/board_service.rb
85
+ - lib/apadmi/grout/service/board_service/jira_board_service.rb
78
86
  - lib/apadmi/grout/utils/filename_utils.rb
79
87
  - lib/apadmi/grout/utils/git_utils.rb
80
88
  - lib/apadmi/grout/utils/logger.rb
89
+ - lib/apadmi/grout/utils/network_service.rb
81
90
  - lib/apadmi/grout/version.rb
82
91
  - lib/apadmi_grout.rb
83
92
  homepage: https://bitbucket.org/apadmi/apadmi-grout-ruby/
@@ -1,80 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Apadmi
4
- module Grout
5
- # Finds and returns a list of all the issues that are ready to be moved
6
- # Any tickets found that have the given status but *don't* appear ready to be moved will
7
- # be flagged.
8
- class FindTicketsToMoveAction
9
- # @param [Apadmi::Grout::JiraWrapper]
10
- # @param [Apadmi::Grout::DefaultLogger] // or your own logger!
11
- def initialize(jira_wrapper, logger)
12
- @jira_wrapper = jira_wrapper
13
- @logger = logger
14
- end
15
-
16
- # @param component [String] Only include tickets tagged with this component
17
- # @param status [String] The status of tickets to be moved (Usually "Awaiting QA Release")
18
- # @param excluded_ticket_keys [Array<String>] ticket keys to be excluded from consideration
19
- # @param custom_flag_messages [Apadmi::Grout::FlagMessages]
20
- # @param options [Apadmi::Grout::FindTicketsOptions]
21
- # @return [Array<JIRA::Resource::Issue>] the issues ready to move
22
- def run(
23
- component,
24
- status,
25
- excluded_ticket_keys,
26
- custom_flag_messages = nil,
27
- options = nil
28
- )
29
- custom_flag_messages ||= Apadmi::Grout::FlagMessages.default(status)
30
- options ||= Apadmi::Grout::FindTicketsOptions.new(include_no_sprint_tickets: false)
31
-
32
- issues = @jira_wrapper.search_unblocked_issues(
33
- component,
34
- status,
35
- [],
36
- allow_no_sprint: options.include_no_sprint_tickets
37
- ).reject do |issue|
38
- excluded_ticket_keys.include? issue.key
39
- end
40
-
41
- @logger.message("Found issues to consider #{issues.map(&:key).join(", ")}")
42
- final_list = issues.filter do |issue|
43
- # Decide whether to include this ticket based on PRs
44
- process_prs(issue, custom_flag_messages)
45
- end
46
- @logger.message("Final list: #{final_list.map(&:key).join(", ")}")
47
- final_list
48
- end
49
-
50
- private
51
-
52
- # @param issue [JIRA::Resource::Issue]
53
- # @param custom_flag_messages [FlagMessages]
54
- # @return [Boolean] whether or not this ticket can be moved
55
- def process_prs(issue, custom_flag_messages)
56
- prs = @jira_wrapper.get_ticket_prs(issue)
57
-
58
- if prs.empty?
59
- @logger.message("#{issue.key} has no PRs. Flagging it: STILL MOVABLE")
60
- @jira_wrapper.flag_ticket(issue.key, custom_flag_messages.no_prs_flag_msg)
61
- return true
62
- elsif prs.all?(&:open)
63
- @logger.message("#{issue.key} has only open PRs. Flagging it: NOT MOVABLE")
64
- @jira_wrapper.flag_ticket(issue.key, custom_flag_messages.open_prs_flag_msg)
65
- return false
66
- elsif prs.all?(&:declined)
67
- @logger.message("#{issue.key} has only declined PRs. Flagging it: NOT MOVABLE")
68
- @jira_wrapper.flag_ticket(issue.key, custom_flag_messages.declined_prs_flag_msg)
69
- return false
70
- elsif prs.none?(&:merged)
71
- @logger.message("#{issue.key} has no merged PRs. Flagging it: NOT MOVABLE")
72
- @jira_wrapper.flag_ticket(issue.key, custom_flag_messages.no_merged_prs_flag_msg)
73
- return false
74
- end
75
-
76
- true # At least one merged PR, so it's included
77
- end
78
- end
79
- end
80
- end