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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -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/actions/find_tickets_to_move_action/find_tickets_to_move_jira_action.rb +114 -0
- 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 -8
- data/lib/apadmi/grout/actions/move_tickets_action.rb +34 -0
- data/lib/apadmi/grout/di.rb +59 -9
- data/lib/apadmi/grout/{jira/models/find_tickets_options.rb → models/ado_config.rb} +2 -2
- data/lib/apadmi/grout/models/bitrise.rb +38 -0
- data/lib/apadmi/grout/models/find_tickets_options.rb +44 -0
- data/lib/apadmi/grout/{jira/models → models}/flag_messages.rb +2 -1
- 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/bitrise_service/bitrise_service.rb +103 -0
- 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 +36 -0
- data/lib/apadmi/grout/utils/network_service.rb +123 -0
- data/lib/apadmi/grout/version.rb +1 -1
- data/lib/apadmi_grout.rb +3 -21
- metadata +23 -14
- data/lib/apadmi/grout/jira/actions/find_tickets_to_move_action.rb +0 -80
- 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
data/lib/apadmi/grout/{jira/wrapper/jira_wrapper.rb → service/board_service/jira_board_service.rb}
RENAMED
@@ -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
|
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
|
-
|
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<
|
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 [
|
50
|
-
# @return [Array<
|
51
|
-
def search_unblocked_issues(component, status, ticket_types = [],
|
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("
|
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("
|
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("
|
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("
|
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<
|
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 [
|
134
|
+
# @param [Apadmi::Grout::Issue] issue
|
147
135
|
# @return [Array<PullRequest>]
|
148
136
|
def get_ticket_prs(issue)
|
149
|
-
|
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<
|
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("
|
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]
|
194
|
-
# @param [Array<
|
195
|
-
def assign_fixversions(
|
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("
|
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]
|
216
|
-
# @return [
|
217
|
-
def
|
218
|
-
|
219
|
-
response
|
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
|
-
|
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]
|
245
|
-
# @return [
|
246
|
-
def
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
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
|
-
# @
|
254
|
-
|
255
|
-
|
256
|
-
|
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
|
data/lib/apadmi/grout/version.rb
CHANGED
data/lib/apadmi_grout.rb
CHANGED
@@ -1,23 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
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:
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- Apadmi
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
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/
|
68
|
-
- lib/apadmi/grout/
|
69
|
-
- lib/apadmi/grout/
|
70
|
-
- lib/apadmi/grout/
|
71
|
-
- lib/apadmi/grout/
|
72
|
-
- lib/apadmi/grout/
|
73
|
-
- lib/apadmi/grout/
|
74
|
-
- lib/apadmi/grout/
|
75
|
-
- lib/apadmi/grout/
|
76
|
-
- lib/apadmi/grout/
|
77
|
-
- lib/apadmi/grout/
|
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
|