apadmi_grout 1.0.0 → 2.0.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 +10 -1
  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 +54 -9
  11. data/lib/apadmi/grout/models/ado_config.rb +10 -0
  12. data/lib/apadmi/grout/models/find_tickets_options.rb +44 -0
  13. data/lib/apadmi/grout/models/flag_messages.rb +25 -0
  14. data/lib/apadmi/grout/models/issue.rb +49 -0
  15. data/lib/apadmi/grout/{jira/models → models}/pull_request.rb +0 -0
  16. data/lib/apadmi/grout/models/release_notes_config.rb +47 -0
  17. data/lib/apadmi/grout/{release_notes/models → models}/release_notes_templates.rb +6 -6
  18. data/lib/apadmi/grout/service/board_service/ado_board_service.rb +199 -0
  19. data/lib/apadmi/grout/service/board_service/board_service.rb +59 -0
  20. data/lib/apadmi/grout/{jira/wrapper/jira_wrapper.rb → service/board_service/jira_board_service.rb} +68 -107
  21. data/lib/apadmi/grout/utils/filename_utils.rb +40 -0
  22. data/lib/apadmi/grout/utils/git_utils.rb +57 -0
  23. data/lib/apadmi/grout/utils/network_service.rb +88 -0
  24. data/lib/apadmi/grout/version.rb +1 -1
  25. data/lib/apadmi_grout.rb +3 -18
  26. metadata +23 -13
  27. data/lib/apadmi/grout/jira/actions/find_tickets_to_move_action.rb +0 -76
  28. data/lib/apadmi/grout/jira/actions/move_jira_tickets_action.rb +0 -58
  29. data/lib/apadmi/grout/jira/models/flag_messages.rb +0 -8
  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
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Apadmi
4
+ module Grout
5
+ # @param tasks [Array<Apadmi::Grout::Issue>]
6
+ # @param features [Array<Apadmi::Grout::Issue>] aka stories
7
+ # @param improvements [Array<Apadmi::Grout::Issue>]
8
+ # @param defects [Array<Apadmi::Grout::Issue>] aka bugs
9
+ # @param others [Array<Apadmi::Grout::Issue>] any other non-standard issue types
10
+ ClassifiedIssues = Struct.new(
11
+ :tasks,
12
+ :features,
13
+ :improvements,
14
+ :defects,
15
+ :others
16
+ ) do
17
+ # @return returns true if all categories are empty
18
+ def empty
19
+ tasks.empty? && features.empty? &&
20
+ improvements.empty? && defects.empty? && others.empty?
21
+ end
22
+ end
23
+
24
+ # @param title [String] The title of the document
25
+ # @param app_version [String] The app version pertaining to this release
26
+ # @param min_os_version [String] The min supported os version of this release
27
+ # @param date [String] Today's date
28
+ # @param moved_issues [Array<Apadmi::Grout::Issue>] Issues moved to a new state by this build job
29
+ # @param release_issues [Array<Apadmi::Grout::Issue>] Issues considered part of this release
30
+ # @param commit_hash [String] Commit hash from which release was built
31
+ # @param ci_build_number [String] CI build number which built the release
32
+ # @param ci_build_url [String] Link to CI build job
33
+ # @param templates [Apadmi::Grout::Templates] Mustache templates to use to generate the document
34
+ ReleaseNotesConfig = Struct.new(
35
+ :title,
36
+ :app_version,
37
+ :min_os_version,
38
+ :date,
39
+ :moved_issues,
40
+ :release_issues,
41
+ :commit_hash,
42
+ :ci_build_number,
43
+ :ci_build_url,
44
+ :templates
45
+ )
46
+ end
47
+ end
@@ -9,7 +9,7 @@ module Apadmi
9
9
 
10
10
  ### Version
11
11
  {{config.app_version}}
12
- {{config.hello}}
12
+
13
13
  ### Release date
14
14
  {{config.date}}
15
15
 
@@ -30,35 +30,35 @@ Commit Hash: {{config.commit_hash}}
30
30
  %{### New functionality
31
31
  {{# classified_issues.features.first}}
32
32
  {{# classified_issues.features}}
33
- * [{{ key }} - {{ summary }}]({{ base_url }}{{ key }})
33
+ * [{{ key }} - {{ summary }}]({{ url }})
34
34
  {{/ classified_issues.features}}
35
35
 
36
36
  {{/ classified_issues.features.first}}
37
37
  {{# classified_issues.improvements.first}}
38
38
  ### Improvements
39
39
  {{# classified_issues.improvements}}
40
- * [{{ key }} - {{ summary }}]({{ base_url }}{{ key }})
40
+ * [{{ key }} - {{ summary }}]({{ url }})
41
41
  {{/ classified_issues.improvements}}
42
42
 
43
43
  {{/ classified_issues.improvements.first}}
44
44
  {{# classified_issues.tasks.first}}
45
45
  ### Completed Tasks
46
46
  {{# classified_issues.tasks}}
47
- * [{{ key }} - {{ summary }}]({{ base_url }}{{ key }})
47
+ * [{{ key }} - {{ summary }}]({{ url }})
48
48
  {{/ classified_issues.tasks}}
49
49
 
50
50
  {{/ classified_issues.tasks.first}}
51
51
  {{# classified_issues.defects.first}}
52
52
  ### Fixed defects
53
53
  {{# classified_issues.defects}}
54
- * [{{ key }} - {{ summary }}]({{ base_url }}{{ key }})
54
+ * [{{ key }} - {{ summary }}]({{ url }})
55
55
  {{/ classified_issues.defects}}
56
56
 
57
57
  {{/ classified_issues.defects.first}}
58
58
  {{# classified_issues.others.first}}
59
59
  ### Other issue types
60
60
  {{# classified_issues.others}}
61
- * [{{ key }} - {{ summary }}]({{ base_url }}{{ key }})
61
+ * [{{issue_type}} - {{ key }} - {{ summary }}]({{ url }})
62
62
  {{/ classified_issues.others}}
63
63
 
64
64
  {{/ classified_issues.others.first}}}
@@ -0,0 +1,199 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "./board_service"
4
+
5
+ module Apadmi
6
+ module Grout
7
+ # Provides a layer of abstraction on top of the ADO api
8
+ class AdoBoardService < BoardService
9
+ API_VERSION_PARAM = "api-version=6.0"
10
+
11
+ # @param [Apadmi::Grout::NetworkService] network_service
12
+ # @param [Apadmi::Grout::AdoConfig] ado_config
13
+ # @param [Logger] logger
14
+ def initialize(network_service, ado_config, logger)
15
+ @network_service = network_service
16
+ @ado_config = ado_config
17
+ @logger = logger
18
+ end
19
+
20
+ # @param [String[]] keys
21
+ # @return [Array<Apadmi::Grout::Issue>]
22
+ def find_issues_by_keys(keys)
23
+ return [] if keys.length <= 0
24
+
25
+ keys = keys.map { |k| sanitise_key(k) } # Allows supporting raw keys, and keys prefixed with a hash which is common ADO practice
26
+
27
+ res = @network_service.do_get("/wit/workitems?ids=#{keys.join(",")}&api-version=7.1-preview.2")
28
+ parsed = JSON.parse(res.body)
29
+ items = parsed["value"]
30
+
31
+ return if items.nil? || items.empty?
32
+
33
+ items.map { |i| Apadmi::Grout::Issue.from_ado_hash(i) }
34
+ end
35
+
36
+ # @param component [String] Included to be consistent with JIRA, this will boil down to a tag in ADO
37
+ # @param status [String]
38
+ # @param ticket_types [String[]]
39
+ # @param options [Apadmi::Grout::AdoFindTicketsOptions] Additional options to filter by
40
+
41
+ # @return [Array<Apadmi::Grout::Issue>]
42
+ def search_unblocked_issues(component, status, ticket_types = [], options = nil)
43
+ tags = (options&.required_tags || []).push(*component).filter { |it| !it.blank? }
44
+ not_tags = (options&.not_tags || []).filter { |it| !it.blank? }
45
+
46
+ raise "Tags can either be required or not required, not both" unless (tags & not_tags).empty?
47
+
48
+ tags_filter = tags.map { |tag| " AND [System.Tags] CONTAINS '#{tag}' " }.join(" ")
49
+ not_tags_filter = not_tags.map { |tag| " AND [System.Tags] NOT CONTAINS '#{tag}'" }.join(" ")
50
+
51
+ status_filter = ("AND [System.State]='#{status}' " unless status.blank?) || ""
52
+ type_filter = ("AND [System.WorkItemType] IN (#{ticket_types.map { |t| "'#{t}'" }.join(", ")})" unless ticket_types.empty?) || ""
53
+ wiql = %(
54
+ Select [System.Id]
55
+ From WorkItems
56
+ Where [System.Id] >= 1
57
+ #{status_filter}
58
+ #{tags_filter}
59
+ #{not_tags_filter}
60
+ #{type_filter}
61
+ )
62
+
63
+ get_issues_by_wiql(wiql)
64
+ end
65
+
66
+ # @param [String] key
67
+ # @param [String] comment
68
+ def flag_ticket(key, comment)
69
+ key = sanitise_key(key)
70
+
71
+ add_tag(key, @ado_config.flag_tag)
72
+ add_comment(key, comment) unless comment.blank?
73
+ end
74
+
75
+ # @param [String] key
76
+ def un_flag_ticket(key)
77
+ key = sanitise_key(key)
78
+
79
+ remove_tag(key, @ado_config.flag_tag)
80
+ end
81
+
82
+ # @param [String] key
83
+ # @param [String] comment
84
+ def add_comment(key, comment)
85
+ key = sanitise_key(key)
86
+
87
+ payload = {
88
+ "text" => comment
89
+ }
90
+ @network_service.do_post("/wit/workitems/#{key}/comments?#{API_VERSION_PARAM}-preview.3", payload.to_json)
91
+ end
92
+
93
+ # @param [String] key
94
+ # @param [String] tag
95
+ def add_tag(key, tag)
96
+ payload = [{
97
+ "op" => "add",
98
+ "path" => "/fields/System.Tags",
99
+ "value" => tag
100
+ }]
101
+ @network_service.do_patch("/wit/workitems/#{key}?#{API_VERSION_PARAM}", payload.to_json)
102
+ end
103
+
104
+ # @param [String] key
105
+ # @param [String] tag
106
+ def remove_tag(key, tag)
107
+ current_tags = get_work_item(key)["fields"]["System.Tags"].split("; ")
108
+ new_tags = current_tags.filter { |t| t != tag }
109
+
110
+ payload = [{
111
+ "op" => "replace",
112
+ "path" => "/fields/System.Tags",
113
+ "value" => new_tags.join("; ")
114
+ }]
115
+ @network_service.do_patch("/wit/workitems/#{key}?#{API_VERSION_PARAM}", payload.to_json)
116
+ end
117
+
118
+ # @param [String] key
119
+ def flagged?(key)
120
+ current_tags = get_work_item(key)["fields"]["System.Tags"].split("; ")
121
+ current_tags.include?(@ado_config.flag_tag)
122
+ end
123
+
124
+ # @param [String] key
125
+ # @return [RawWorkItemHash]
126
+ def get_work_item(key)
127
+ key = sanitise_key(key)
128
+
129
+ res = @network_service.do_get("/wit/workitems/#{key}?#{API_VERSION_PARAM}")
130
+ JSON.parse(res.body)
131
+ end
132
+
133
+ # @param [String] key
134
+ # @param [Array<String>] versions
135
+ def assign_fixversions(key, versions)
136
+ key = sanitise_key(key)
137
+
138
+ payload = [{
139
+ "op" => "replace",
140
+ "path" => "/fields/Microsoft.VSTS.Build.IntegrationBuild",
141
+ "value" => versions.join("; ")
142
+ }]
143
+ @network_service.do_patch("/wit/workitems/#{key}?#{API_VERSION_PARAM}", payload.to_json)
144
+ end
145
+
146
+ # @param [String] key
147
+ # @return [Array<String>] fix versions
148
+ def get_ticket_fixversions(key)
149
+ key = sanitise_key(key)
150
+
151
+ get_work_item(key)["fields"]["Microsoft.VSTS.Build.IntegrationBuild"].split("; ")
152
+ end
153
+
154
+ # @param [Apadmi::Grout::Issue] issue
155
+ # @param [String] state_name
156
+ def transition_issue(issue, state_name)
157
+ key = sanitise_key(issue.key)
158
+
159
+ payload = [{
160
+ "op" => "add",
161
+ "path" => "/fields/System.State",
162
+ "value" => state_name
163
+ }]
164
+ @network_service.do_patch("/wit/workitems/#{key}?#{API_VERSION_PARAM}", payload.to_json)
165
+ end
166
+
167
+ # @param [String] key
168
+ # @return [String]
169
+ def get_ticket_status(key)
170
+ key = sanitise_key(key)
171
+
172
+ get_work_item(key)["fields"]["System.State"]
173
+ end
174
+
175
+ private
176
+
177
+ def sanitise_key(key)
178
+ key = key.to_s.strip.delete_prefix "#"
179
+ raise "Invalid key" if key.blank?
180
+
181
+ key
182
+ end
183
+
184
+ # @param wiql_query [String]
185
+ # @return [Array<Apadmi::Grout::Issue>]
186
+ def get_issues_by_wiql(wiql_query)
187
+ @logger.message("Executing wiql")
188
+ @logger.message(wiql_query)
189
+
190
+ payload = { "query" => wiql_query }
191
+ res = @network_service.do_post("/wit/wiql?#{API_VERSION_PARAM}", payload.to_json)
192
+ parsed = JSON.parse(res.body)
193
+ items = parsed["workItems"] || []
194
+ ids = items.map { |item| item["id"] } || []
195
+ find_issues_by_keys(ids)
196
+ end
197
+ end
198
+ end
199
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Apadmi
4
+ module Grout
5
+ # A generic board service to be implemented by whatever
6
+ # board providers we have e.g. JIRA and ADO
7
+ class BoardService
8
+ # @param [String[]] keys
9
+ # @return [Array<Apadmi::Grout::Issue>]
10
+ def find_issues_by_keys(_keys)
11
+ raise "Unimplemented :("
12
+ end
13
+
14
+ # @param [String] _component
15
+ # @param [String] _status
16
+ # @param [String[]] _ticket_types
17
+ # @param [Apadmi::Grout::JiraFindTicketsOptions|Apadmi::Grout::JiraFindTicketsOptions] _options
18
+ # @return [Array<Apadmi::Grout::Issue>]
19
+ def search_unblocked_issues(_component, _status, _ticket_types = [], _options = nil)
20
+ raise "Unimplemented :("
21
+ end
22
+
23
+ # @param [String] _key
24
+ # @param [String] _comment
25
+ def flag_ticket(_key, _comment)
26
+ raise "Unimplemented :("
27
+ end
28
+
29
+ # @param [String] _key
30
+ def un_flag_ticket(_key)
31
+ raise "Unimplemented :("
32
+ end
33
+
34
+ # @param [String] _key
35
+ # @return bool
36
+ def flagged?(_key)
37
+ raise "Unimplemented :("
38
+ end
39
+
40
+ # @param [String] _key
41
+ # @param [Array<String>] _version_strings
42
+ def assign_fixversions(_key, _version_strings)
43
+ raise "Unimplemented :("
44
+ end
45
+
46
+ # @param [String] _key
47
+ # @return [Array<String>]
48
+ def get_ticket_fixversions(_key)
49
+ raise "Unimplemented :("
50
+ end
51
+
52
+ # @param [Apadmi::Grout::Issue] _issue
53
+ # @param [String] _state_name
54
+ def transition_issue(_issue, _state_name)
55
+ raise "Unimplemented :("
56
+ end
57
+ end
58
+ end
59
+ end
@@ -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,52 +21,64 @@ 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
- # @return [Array<JIRA::Resource::Issue>]
50
- 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
51
45
  component_filter = (" AND component = '#{component}' " unless component.empty?) || ""
52
46
  status_filter = (" AND status = '#{status}' " unless status.empty?) || ""
53
47
  type_filter = ("AND (#{ticket_types.map { |type| "type = #{type}" }.join("OR ")})" unless ticket_types.empty?) || ""
48
+ empty_sprint_condition = ("OR sprint is EMPTY" if allow_no_sprint) || ""
54
49
 
55
50
  jql_search = %{
56
51
  project = '#{@project}'
57
52
  #{status_filter} #{component_filter} #{type_filter}
58
- AND sprint in openSprints() AND (labels not in(Blocked) or labels is EMPTY) AND Flagged is EMPTY
53
+ AND (sprint in openSprints() #{empty_sprint_condition}) AND (labels not in(Blocked) or labels is EMPTY)
54
+ AND Flagged is EMPTY
59
55
  }
60
56
 
61
- @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 })
62
69
  end
63
70
 
64
71
  # @param [String] key
65
72
  # @param [String] comment
66
73
  def flag_ticket(key, comment)
67
74
  payload = "{\"flag\":true,\"issueKeys\":[\"#{key}\"],\"commentVisibility\":\"\",\"comment\":\"#{comment}\"}"
68
- 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)
69
76
  end
70
77
 
71
78
  # @param [String] key
72
79
  def un_flag_ticket(key)
73
80
  payload = "{\"flag\":false,\"issueKeys\":[\"#{key}\"],\"commentVisibility\":\"\",\"comment\":\"Unflagged by CI\"}"
74
- 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)
75
82
  end
76
83
 
77
84
  # @param [String] key
@@ -86,7 +93,7 @@ module Apadmi
86
93
  # @param [String] comment
87
94
  def add_comment(key, comment)
88
95
  payload = "{\"issueKeys\":[\"#{key}\"],\"commentVisibility\":\"\",\"comment\":\"#{comment}\"}"
89
- 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)
90
97
  end
91
98
 
92
99
  # @param [String] key
@@ -101,14 +108,14 @@ module Apadmi
101
108
  # @param [String] key
102
109
  # @param [String] comment_id
103
110
  def remove_comment(key, comment_id)
104
- 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}")
105
112
  end
106
113
 
107
114
  # @param [String] component_key
108
- # @return [Array<JIRA::Resource::Issue>]
115
+ # @return [Array<Apadmi::Grout::Issue>]
109
116
  def get_tickets_by_component(component_key)
110
117
  jql_search = "project = '#{@project}' AND component IN ('#{component_key}')"
111
- @jira_client.Issue.jql(jql_search, { max_results: 1000 }).uniq
118
+ convert(@jira_client.Issue.jql(jql_search, { max_results: 1000 }).uniq)
112
119
  end
113
120
 
114
121
  # @param [String] key
@@ -117,33 +124,18 @@ module Apadmi
117
124
  @jira_client.Transition.all(issue: issue)
118
125
  end
119
126
 
120
- # @param [String] ticket
121
- # @param [String] state_name
122
- def transition_ticket(ticket, state_name)
123
- issue = @jira_client.Issue.find(ticket)
124
- transition_issue(issue, state_name)
125
- end
126
-
127
- # @param [JIRA::Resource::Issue] issue
128
- # @param [String] state_name
129
- def transition_issue(issue, state_name)
130
- transitions = @jira_client.Transition.all(issue: issue)
131
- transition = transitions.find { |elem| elem.name == state_name }
132
-
133
- trans = issue.transitions.build
134
- trans.save!("transition" => { "id" => transition.id })
135
- end
136
-
137
127
  # @param [String] key
128
+ # @return [String]
138
129
  def get_ticket_status(key)
139
130
  issue = @jira_client.Issue.find(key)
140
- issue.status
131
+ issue.status.name
141
132
  end
142
133
 
143
- # @param [JIRA::Resource::Issue] issue
134
+ # @param [Apadmi::Grout::Issue] issue
144
135
  # @return [Array<PullRequest>]
145
136
  def get_ticket_prs(issue)
146
- 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}")
147
139
 
148
140
  return [] if JSON.parse(response.body)["detail"].empty?
149
141
 
@@ -154,11 +146,11 @@ module Apadmi
154
146
 
155
147
  # @param [String] keys
156
148
  # @param [String] component
157
- # @return [Array<JIRA::Resource::Issue>]
149
+ # @return [Array<Apadmi::Grout::Issue>]
158
150
  def get_ticket_subtask(keys, component = nil)
159
151
  jql_search = "project = '#{@project}' AND parent IN #{keys.to_s.gsub("[", "(").gsub("]", ")")}"\
160
152
  + (component.nil? ? "" : " AND component IN ('#{component}')")
161
- @jira_client.Issue.jql(jql_search, { max_results: 1000 }).uniq
153
+ convert(@jira_client.Issue.jql(jql_search, { max_results: 1000 }).uniq)
162
154
  end
163
155
 
164
156
  # @param [String] release_date
@@ -179,7 +171,7 @@ module Apadmi
179
171
  def delete_version(version_id, move_version_id)
180
172
  payload = "{\"moveFixIssuesTo\": #{move_version_id}, \"moveAffectedIssuesTo\": #{move_version_id}, "\
181
173
  "\"customFieldReplacementList\": []}"
182
- 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)
183
175
  end
184
176
 
185
177
  # @return [Array<JIRA::Resource::Version>]
@@ -187,75 +179,44 @@ module Apadmi
187
179
  @jira_client.Project.find(@project).versions
188
180
  end
189
181
 
190
- # @param [String] ticket
191
- # @param [Array<JIRA::Resource::Version>] versions
192
- 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)
193
186
  fixversions = versions.map { |v| "{\"id\": \"#{v.id}\"}" }.join(", ")
194
187
  payload = "{\"fields\" : {\"fixVersions\": [#{fixversions}] }}"
195
- do_put("#{@options[:site]}/rest/api/2/issue/#{ticket}", payload)
196
- end
197
-
198
- # @param [String] ticket
199
- # @return [Array<Version>]
200
- def get_ticket_fixversions(ticket)
201
- response = do_get("#{@options[:site]}/rest/api/2/issue/#{ticket}")
202
- JSON.parse(response.body)["fields"]["fixVersions"].map do |version|
203
- Version.new(version)
204
- end
205
- end
206
-
207
- # @param [Faraday::Response] response
208
- def throw_if_error(response)
209
- 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)
210
189
  end
211
190
 
212
- # @param [String] uri
213
- # @return [Faraday::Response]
214
- def do_get(uri)
215
- conn = setup_con
216
- response = conn.get(uri, CONTENT_TYPE => APPLICATION_JSON)
217
- throw_if_error(response)
218
- response
219
- end
220
-
221
- # @param [String] uri
222
- # @param [String] payload
223
- # @return [Faraday::Response]
224
- def do_put(uri, payload)
225
- conn = setup_con
226
- response = conn.put(uri, payload, CONTENT_TYPE => APPLICATION_JSON)
227
- throw_if_error(response)
228
- 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"] } || []
229
196
  end
230
197
 
231
- # @param [String] uri
232
- # @param [String] payload
233
- # @return [Faraday::Response]
234
- def do_post(uri, payload)
235
- conn = setup_con
236
- response = conn.post(uri, payload, CONTENT_TYPE => APPLICATION_JSON)
237
- throw_if_error(response)
238
- response
239
- end
198
+ private
240
199
 
241
- # @param [String] uri
242
- # @return [Faraday::Response]
243
- def do_delete(uri)
244
- conn = setup_con
245
- response = conn.delete(uri, CONTENT_TYPE => APPLICATION_JSON)
246
- throw_if_error(response)
247
- 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
248
213
  end
249
214
 
250
- # @return [Faraday::Connection]
251
- def setup_con
252
- auth_str = "#{@options[:username]}:#{@options[:password]}"
253
- conn = Faraday.new # create a new Connection with base URL
254
- conn.headers["Authorization"] = "Basic #{Base64.strict_encode64(auth_str)}"
255
- 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])
256
219
  end
257
-
258
- private :setup_con, :do_delete, :do_get, :do_post, :do_put
259
220
  end
260
221
  end
261
222
  end