jirametrics 2.30.1pre1 → 2.30.1pre2
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/lib/jirametrics/download_config.rb +1 -5
- data/lib/jirametrics/downloader_for_cloud.rb +40 -1
- data/lib/jirametrics/downloader_for_data_center.rb +9 -1
- data/lib/jirametrics/github_gateway.rb +28 -9
- data/lib/jirametrics/jira_gateway.rb +6 -1
- data/lib/jirametrics/worklog_helper.rb +34 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 06c3a3f5e8296c0acf9dfeb03bf42e7773ae59676c45af1fa9c5c9e40ee00fa1
|
|
4
|
+
data.tar.gz: 30fc6cfdd1857336ad9ac6a73166803c319197ca2b29ddbb055453742d02532b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 17b036d6a1f1b8ef6282e001e8befe9c64744cc3b8f529175068762ca1771a1ede57ab3b3dc86744c086e29480d00a1c75636e6784df656f23f1be826b03fc54
|
|
7
|
+
data.tar.gz: 8f5d9af1c3ab342d93a1d43a0d6c8df3342889412e3e7a7398febf9d1775b831885e85f3b7b4d5841a5e7bbb4f3f2717c245672246cefc1506771b1e016fc0d4
|
|
@@ -30,7 +30,7 @@ class DownloadConfig
|
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
def github_repo *repos
|
|
33
|
-
github_repos.concat(repos
|
|
33
|
+
github_repos.concat(repos)
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
def start_date today:
|
|
@@ -42,8 +42,4 @@ class DownloadConfig
|
|
|
42
42
|
|
|
43
43
|
private
|
|
44
44
|
|
|
45
|
-
def normalize_github_repo repo
|
|
46
|
-
match = repo.match(%r{github\.com/([^/]+/[^/]+?)/?$})
|
|
47
|
-
match ? match[1] : repo
|
|
48
|
-
end
|
|
49
45
|
end
|
|
@@ -101,6 +101,7 @@ class DownloaderForCloud < Downloader
|
|
|
101
101
|
)
|
|
102
102
|
|
|
103
103
|
attach_changelog_to_issues issue_datas: issue_datas, issue_jsons: response['issues']
|
|
104
|
+
attach_worklogs_to_issues issue_datas: issue_datas, issue_jsons: response['issues']
|
|
104
105
|
|
|
105
106
|
response['issues'].each do |issue_json|
|
|
106
107
|
issue_json['exporter'] = {
|
|
@@ -129,6 +130,44 @@ class DownloaderForCloud < Downloader
|
|
|
129
130
|
issue_datas
|
|
130
131
|
end
|
|
131
132
|
|
|
133
|
+
def attach_worklogs_to_issues issue_datas:, issue_jsons:
|
|
134
|
+
max_results = 100
|
|
135
|
+
|
|
136
|
+
issue_jsons.each do |issue_json|
|
|
137
|
+
worklog = issue_json['fields']['worklog']
|
|
138
|
+
next unless worklog
|
|
139
|
+
|
|
140
|
+
total = worklog['total'].to_i
|
|
141
|
+
all_worklogs = worklog['worklogs'] || []
|
|
142
|
+
next if all_worklogs.size >= total
|
|
143
|
+
|
|
144
|
+
key = issue_json['key']
|
|
145
|
+
start_at = all_worklogs.size
|
|
146
|
+
|
|
147
|
+
loop do
|
|
148
|
+
response = @jira_gateway.call_url(
|
|
149
|
+
relative_url: "/rest/api/3/issue/#{CGI.escape(key)}/worklog?startAt=#{start_at}&maxResults=#{max_results}"
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
worklogs = response['worklogs'] || []
|
|
153
|
+
all_worklogs.concat(worklogs)
|
|
154
|
+
|
|
155
|
+
break if all_worklogs.size >= response['total'].to_i
|
|
156
|
+
|
|
157
|
+
start_at += worklogs.size
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
issue_json['fields']['worklog'] = {
|
|
161
|
+
'startAt' => 0,
|
|
162
|
+
'maxResults' => all_worklogs.size,
|
|
163
|
+
'total' => all_worklogs.size,
|
|
164
|
+
'worklogs' => all_worklogs
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
log " Enhanced #{key} with #{all_worklogs.size} worklogs"
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
132
171
|
def attach_changelog_to_issues issue_datas:, issue_jsons:
|
|
133
172
|
max_results = 10_000 # The max jira accepts is 10K
|
|
134
173
|
payload = {
|
|
@@ -190,7 +229,7 @@ class DownloaderForCloud < Downloader
|
|
|
190
229
|
unless stale.empty?
|
|
191
230
|
log_start ' Downloading more issues ' unless in_related_phase
|
|
192
231
|
stale.each_slice(100) do |slice|
|
|
193
|
-
slice = bulk_fetch_issues(issue_datas: slice, board: board, in_initial_query:
|
|
232
|
+
slice = bulk_fetch_issues(issue_datas: slice, board: board, in_initial_query: !in_related_phase)
|
|
194
233
|
progress_dot
|
|
195
234
|
slice.each do |data|
|
|
196
235
|
next unless data.issue
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative 'worklog_helper'
|
|
4
|
+
|
|
3
5
|
class DownloaderForDataCenter < Downloader
|
|
6
|
+
include WorklogHelper
|
|
7
|
+
|
|
4
8
|
def jira_instance_type
|
|
5
9
|
'Jira DataCenter'
|
|
6
10
|
end
|
|
@@ -49,8 +53,12 @@ class DownloaderForDataCenter < Downloader
|
|
|
49
53
|
}
|
|
50
54
|
identify_other_issues_to_be_downloaded raw_issue: issue_json, board: board
|
|
51
55
|
file = "#{issue_json['key']}-#{board.id}.json"
|
|
56
|
+
issue_path = File.join(path, file)
|
|
57
|
+
|
|
58
|
+
@file_system.save_json(json: issue_json, filename: issue_path)
|
|
52
59
|
|
|
53
|
-
|
|
60
|
+
# Fetch complete worklog data for this issue
|
|
61
|
+
enhance_issue_with_worklogs(issue_key: issue_json['key'], issue_path: issue_path)
|
|
54
62
|
end
|
|
55
63
|
|
|
56
64
|
total = json['total'].to_i
|
|
@@ -99,17 +99,36 @@ class GithubGateway
|
|
|
99
99
|
Regexp.new("\\b(?:#{keys_pattern})-\\d+(?![A-Za-z0-9])")
|
|
100
100
|
end
|
|
101
101
|
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
TRANSIENT_HTTP_ERRORS = [429, 500, 502, 503, 504].freeze
|
|
103
|
+
MAX_RETRIES = 3
|
|
104
104
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
105
|
+
def run_command args
|
|
106
|
+
attempts = 0
|
|
107
|
+
loop do
|
|
108
|
+
attempts += 1
|
|
109
|
+
stdout, stderr, status = Open3.capture3('gh', *args)
|
|
110
|
+
|
|
111
|
+
# This extra check seems to only matter on Windows. On the mac, auth failures don't pass status.success?
|
|
112
|
+
if stderr.include?('SAML enforcement')
|
|
113
|
+
raise "GitHub CLI is not authorized to access #{@repo}. " \
|
|
114
|
+
'Run: gh auth refresh -h github.com -s read:org'
|
|
115
|
+
end
|
|
110
116
|
|
|
111
|
-
|
|
117
|
+
unless status.success?
|
|
118
|
+
if attempts < MAX_RETRIES && TRANSIENT_HTTP_ERRORS.any? { |code| stderr.include?("HTTP #{code}") }
|
|
119
|
+
delay = 2**attempts
|
|
120
|
+
@file_system.log " GitHub returned transient error for #{@repo}: #{stderr.strip}. Retrying in #{delay}s (attempt #{attempts}/#{MAX_RETRIES})...", also_write_to_stderr: true
|
|
121
|
+
sleep delay
|
|
122
|
+
next
|
|
123
|
+
end
|
|
124
|
+
raise "GitHub CLI command failed for #{@repo}: #{stderr}"
|
|
125
|
+
end
|
|
112
126
|
|
|
113
|
-
|
|
127
|
+
result = JSON.parse(stdout)
|
|
128
|
+
if result.nil? || (result.is_a?(Array) && result.empty?)
|
|
129
|
+
@file_system.warning "No data was found in GitHub for #{@repo}. Is that what you expected?"
|
|
130
|
+
end
|
|
131
|
+
return result
|
|
132
|
+
end
|
|
114
133
|
end
|
|
115
134
|
end
|
|
@@ -40,7 +40,7 @@ class JiraGateway
|
|
|
40
40
|
return parse_response(command: command, result: stdout)
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
-
if RETRYABLE_EXIT_CODES.include?(status.exitstatus) && retries < MAX_RETRIES
|
|
43
|
+
if RETRYABLE_EXIT_CODES.include?(status.exitstatus) && retries < MAX_RETRIES && !stderr.include?('503')
|
|
44
44
|
retries += 1
|
|
45
45
|
@file_system.log "Transient network error (exit #{status.exitstatus}), retrying in #{RETRY_DELAY_SECONDS}s (attempt #{retries}/#{MAX_RETRIES})..."
|
|
46
46
|
sleep_between_retries
|
|
@@ -53,6 +53,11 @@ class JiraGateway
|
|
|
53
53
|
if stderr.include?('401')
|
|
54
54
|
raise 'The request was not authorized. Verify that your authentication token hasn\'t expired'
|
|
55
55
|
end
|
|
56
|
+
if stderr.include?('503')
|
|
57
|
+
raise 'Jira returned 503 (Service Unavailable). This may be a temporary outage, or your ' \
|
|
58
|
+
'Jira account may have been deactivated due to inactivity. Check your Jira subscription ' \
|
|
59
|
+
'and try again later.'
|
|
60
|
+
end
|
|
56
61
|
raise "Failed call with exit status #{status.exitstatus}. " \
|
|
57
62
|
"See #{@file_system.logfile_name} for details"
|
|
58
63
|
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module WorklogHelper
|
|
4
|
+
def enhance_issue_with_worklogs issue_key:, issue_path:
|
|
5
|
+
all_worklogs = []
|
|
6
|
+
start_at = 0
|
|
7
|
+
max_results = 100
|
|
8
|
+
|
|
9
|
+
loop do
|
|
10
|
+
url = "/rest/api/2/issue/#{CGI.escape(issue_key)}/worklog?startAt=#{start_at}&maxResults=#{max_results}"
|
|
11
|
+
response = @jira_gateway.call_url(relative_url: url)
|
|
12
|
+
|
|
13
|
+
worklogs = response['worklogs'] || []
|
|
14
|
+
all_worklogs.concat(worklogs)
|
|
15
|
+
|
|
16
|
+
total = response['total'].to_i
|
|
17
|
+
break if start_at + worklogs.size >= total
|
|
18
|
+
|
|
19
|
+
start_at += max_results
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Reload the saved issue and update worklogs
|
|
23
|
+
issue_json = @file_system.load_json(issue_path)
|
|
24
|
+
issue_json['worklog'] = {
|
|
25
|
+
'startAt' => 0,
|
|
26
|
+
'maxResults' => all_worklogs.size,
|
|
27
|
+
'total' => all_worklogs.size,
|
|
28
|
+
'worklogs' => all_worklogs
|
|
29
|
+
}
|
|
30
|
+
@file_system.save_json(json: issue_json, filename: issue_path)
|
|
31
|
+
|
|
32
|
+
log " Enhanced #{issue_key} with #{all_worklogs.size} worklogs" if all_worklogs.any?
|
|
33
|
+
end
|
|
34
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jirametrics
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.30.
|
|
4
|
+
version: 2.30.1pre2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mike Bowler
|
|
@@ -188,6 +188,7 @@ files:
|
|
|
188
188
|
- lib/jirametrics/user.rb
|
|
189
189
|
- lib/jirametrics/value_equality.rb
|
|
190
190
|
- lib/jirametrics/wip_by_column_chart.rb
|
|
191
|
+
- lib/jirametrics/worklog_helper.rb
|
|
191
192
|
homepage: https://jirametrics.org
|
|
192
193
|
licenses:
|
|
193
194
|
- Apache-2.0
|
|
@@ -210,7 +211,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
210
211
|
- !ruby/object:Gem::Version
|
|
211
212
|
version: '0'
|
|
212
213
|
requirements: []
|
|
213
|
-
rubygems_version: 4.0.
|
|
214
|
+
rubygems_version: 4.0.13
|
|
214
215
|
specification_version: 4
|
|
215
216
|
summary: Extract Jira metrics
|
|
216
217
|
test_files: []
|