apadmi_grout 1.1.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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