jirametrics 2.17 → 2.17.1
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/anonymizer.rb +8 -6
- data/lib/jirametrics/change_item.rb +2 -2
- data/lib/jirametrics/downloader.rb +0 -26
- data/lib/jirametrics/downloader_for_cloud.rb +66 -2
- data/lib/jirametrics/downloader_for_data_center.rb +24 -2
- data/lib/jirametrics/exporter.rb +3 -3
- data/lib/jirametrics/issue.rb +5 -1
- data/lib/jirametrics/jira_gateway.rb +18 -10
- data/lib/jirametrics.rb +2 -2
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4e9534fd6ca22944557cfe40c63ebf5c30ff111458ec52dd3e35617246315ce8
|
4
|
+
data.tar.gz: 2feb93d3ae826f133902664751f3cee4e54de3512daaaa882ae78fed47605e65
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 84942ea82c68aa66325299e5db0e5f5a4fe4af95eb909d1fde004435b53898c60ee7dde2251fec0e075f4b2db7ba2f1eade384795370f3b90d7230926e79d2b9
|
7
|
+
data.tar.gz: 9015a7c5ef2b60726dca272a0b5b07de9f62d76e076038e4c8d45cbae13facf37f7e8f45dac82639c72615bbee549de756d3fb4792d21345fb4d3dc3fb17a32e
|
@@ -2,11 +2,12 @@
|
|
2
2
|
|
3
3
|
require 'random-word'
|
4
4
|
|
5
|
-
class Anonymizer
|
5
|
+
class Anonymizer < ChartBase
|
6
6
|
# needed for testing
|
7
7
|
attr_reader :project_config, :issues
|
8
8
|
|
9
9
|
def initialize project_config:, date_adjustment: -200
|
10
|
+
super()
|
10
11
|
@project_config = project_config
|
11
12
|
@issues = @project_config.issues
|
12
13
|
@all_boards = @project_config.all_boards
|
@@ -130,18 +131,19 @@ class Anonymizer
|
|
130
131
|
end
|
131
132
|
end
|
132
133
|
|
133
|
-
def shift_all_dates
|
134
|
-
|
134
|
+
def shift_all_dates date_adjustment: @date_adjustment
|
135
|
+
adjustment_in_seconds = 60 * 60 * 24 * date_adjustment
|
136
|
+
@file_system.log "Shifting all dates by #{label_days date_adjustment}"
|
135
137
|
@issues.each do |issue|
|
136
138
|
issue.changes.each do |change|
|
137
|
-
change.time = change.time +
|
139
|
+
change.time = change.time + adjustment_in_seconds
|
138
140
|
end
|
139
141
|
|
140
|
-
issue.raw['fields']['updated'] = (issue.updated +
|
142
|
+
issue.raw['fields']['updated'] = (issue.updated + adjustment_in_seconds).to_s
|
141
143
|
end
|
142
144
|
|
143
145
|
range = @project_config.time_range
|
144
|
-
@project_config.time_range = (range.begin +
|
146
|
+
@project_config.time_range = (range.begin + date_adjustment)..(range.end + date_adjustment)
|
145
147
|
end
|
146
148
|
|
147
149
|
def random_name
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class ChangeItem
|
4
|
-
attr_reader :field, :value_id, :old_value_id, :raw, :
|
5
|
-
attr_accessor :value, :old_value
|
4
|
+
attr_reader :field, :value_id, :old_value_id, :raw, :author_raw
|
5
|
+
attr_accessor :value, :old_value, :time
|
6
6
|
|
7
7
|
def initialize raw:, author_raw:, time:, artificial: false
|
8
8
|
@raw = raw
|
@@ -350,32 +350,6 @@ class Downloader
|
|
350
350
|
)
|
351
351
|
end
|
352
352
|
|
353
|
-
def bulk_fetch_issues issue_datas:, board:, in_initial_query:
|
354
|
-
log " Downloading #{issue_datas.size} issues", both: true
|
355
|
-
payload = {
|
356
|
-
'expand' => [
|
357
|
-
'changelog'
|
358
|
-
],
|
359
|
-
'fields' => ['*all'],
|
360
|
-
'issueIdsOrKeys' => issue_datas.collect(&:key)
|
361
|
-
}
|
362
|
-
response = @jira_gateway.post_request(
|
363
|
-
relative_url: issue_bulk_fetch_api,
|
364
|
-
payload: JSON.generate(payload)
|
365
|
-
)
|
366
|
-
response['issues'].each do |issue_json|
|
367
|
-
issue_json['exporter'] = {
|
368
|
-
'in_initial_query' => in_initial_query
|
369
|
-
}
|
370
|
-
issue = Issue.new(raw: issue_json, board: board)
|
371
|
-
data = issue_datas.find { |d| d.key == issue.key }
|
372
|
-
data.up_to_date = true
|
373
|
-
data.last_modified = issue.updated
|
374
|
-
data.issue = issue
|
375
|
-
end
|
376
|
-
issue_datas
|
377
|
-
end
|
378
|
-
|
379
353
|
def delete_issues_from_cache_that_are_not_in_server issue_data_hash:, path:
|
380
354
|
# The gotcha with deleted issues is that they just stop being returned in queries
|
381
355
|
# and we have no way to know that they should be removed from our local cache.
|
@@ -44,7 +44,71 @@ class DownloaderForCloud < Downloader
|
|
44
44
|
hash
|
45
45
|
end
|
46
46
|
|
47
|
-
def
|
48
|
-
|
47
|
+
def bulk_fetch_issues issue_datas:, board:, in_initial_query:
|
48
|
+
# We used to use the expand option to pull in the changelog directly. Unfortunately
|
49
|
+
# that only returns the "recent" changes, not all of them. So now we get the issue
|
50
|
+
# without changes and then make a second call for that changes. Then we insert it
|
51
|
+
# into the raw issue as if it had been there all along.
|
52
|
+
log " Downloading #{issue_datas.size} issues", both: true
|
53
|
+
payload = {
|
54
|
+
'fields' => ['*all'],
|
55
|
+
'issueIdsOrKeys' => issue_datas.collect(&:key)
|
56
|
+
}
|
57
|
+
response = @jira_gateway.post_request(
|
58
|
+
relative_url: '/rest/api/3/issue/bulkfetch',
|
59
|
+
payload: JSON.generate(payload)
|
60
|
+
)
|
61
|
+
|
62
|
+
attach_changelog_to_issues issue_datas: issue_datas, issue_jsons: response['issues']
|
63
|
+
|
64
|
+
response['issues'].each do |issue_json|
|
65
|
+
issue_json['exporter'] = {
|
66
|
+
'in_initial_query' => in_initial_query
|
67
|
+
}
|
68
|
+
issue = Issue.new(raw: issue_json, board: board)
|
69
|
+
data = issue_datas.find { |d| d.key == issue.key }
|
70
|
+
data.up_to_date = true
|
71
|
+
data.last_modified = issue.updated
|
72
|
+
data.issue = issue
|
73
|
+
end
|
74
|
+
|
75
|
+
issue_datas
|
76
|
+
end
|
77
|
+
|
78
|
+
def attach_changelog_to_issues issue_datas:, issue_jsons:
|
79
|
+
max_results = 10_000 # The max jira accepts is 10K
|
80
|
+
payload = {
|
81
|
+
'issueIdsOrKeys' => issue_datas.collect(&:key),
|
82
|
+
'maxResults' => max_results
|
83
|
+
}
|
84
|
+
loop do
|
85
|
+
response = @jira_gateway.post_request(
|
86
|
+
relative_url: '/rest/api/3/changelog/bulkfetch',
|
87
|
+
payload: JSON.generate(payload)
|
88
|
+
)
|
89
|
+
|
90
|
+
response['issueChangeLogs'].each do |issue_change_log|
|
91
|
+
issue_id = issue_change_log['issueId']
|
92
|
+
json = issue_jsons.find { |json| json['id'] == issue_id }
|
93
|
+
|
94
|
+
unless json['changelog']
|
95
|
+
# If this is our first time in, there won't be a changelog section
|
96
|
+
json['changelog'] = {
|
97
|
+
'startAt' => 0,
|
98
|
+
'maxResults' => max_results,
|
99
|
+
'total' => 0,
|
100
|
+
'histories' => []
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
new_changes = issue_change_log['changeHistories']
|
105
|
+
json['changelog']['total'] += new_changes.size
|
106
|
+
json['changelog']['histories'] += new_changes
|
107
|
+
end
|
108
|
+
|
109
|
+
next_page_token = response['nextPageToken']
|
110
|
+
payload['nextPageToken'] = next_page_token
|
111
|
+
break if next_page_token.nil?
|
112
|
+
end
|
49
113
|
end
|
50
114
|
end
|
@@ -40,7 +40,29 @@ class DownloaderForDataCenter < Downloader
|
|
40
40
|
hash
|
41
41
|
end
|
42
42
|
|
43
|
-
def
|
44
|
-
|
43
|
+
def bulk_fetch_issues issue_datas:, board:, in_initial_query:
|
44
|
+
log " Downloading #{issue_datas.size} issues", both: true
|
45
|
+
payload = {
|
46
|
+
'expand' => [
|
47
|
+
'changelog'
|
48
|
+
],
|
49
|
+
'fields' => ['*all'],
|
50
|
+
'issueIdsOrKeys' => issue_datas.collect(&:key)
|
51
|
+
}
|
52
|
+
response = @jira_gateway.post_request(
|
53
|
+
relative_url: '/rest/api/2/issue/bulkfetch',
|
54
|
+
payload: JSON.generate(payload)
|
55
|
+
)
|
56
|
+
response['issues'].each do |issue_json|
|
57
|
+
issue_json['exporter'] = {
|
58
|
+
'in_initial_query' => in_initial_query
|
59
|
+
}
|
60
|
+
issue = Issue.new(raw: issue_json, board: board)
|
61
|
+
data = issue_datas.find { |d| d.key == issue.key }
|
62
|
+
data.up_to_date = true
|
63
|
+
data.last_modified = issue.updated
|
64
|
+
data.issue = issue
|
65
|
+
end
|
66
|
+
issue_datas
|
45
67
|
end
|
46
68
|
end
|
data/lib/jirametrics/exporter.rb
CHANGED
@@ -65,14 +65,14 @@ class Exporter
|
|
65
65
|
puts "Full output from downloader in #{file_system.logfile_name}"
|
66
66
|
end
|
67
67
|
|
68
|
-
def info
|
68
|
+
def info key, name_filter:
|
69
69
|
selected = []
|
70
70
|
each_project_config(name_filter: name_filter) do |project|
|
71
71
|
project.evaluate_next_level
|
72
72
|
|
73
73
|
project.run load_only: true
|
74
74
|
project.issues.each do |issue|
|
75
|
-
selected << [project, issue] if
|
75
|
+
selected << [project, issue] if key == issue.key
|
76
76
|
end
|
77
77
|
rescue => e # rubocop:disable Style/RescueStandardError
|
78
78
|
# This happens when we're attempting to load an aggregated project because it hasn't been
|
@@ -81,7 +81,7 @@ class Exporter
|
|
81
81
|
end
|
82
82
|
|
83
83
|
if selected.empty?
|
84
|
-
file_system.log "No issues found to match #{
|
84
|
+
file_system.log "No issues found to match #{key.inspect}"
|
85
85
|
else
|
86
86
|
selected.each do |project, issue|
|
87
87
|
file_system.log "\nProject #{project.name}", also_write_to_stderr: true
|
data/lib/jirametrics/issue.rb
CHANGED
@@ -212,7 +212,11 @@ class Issue
|
|
212
212
|
end
|
213
213
|
|
214
214
|
def parse_time text
|
215
|
-
|
215
|
+
if text.is_a? String
|
216
|
+
Time.parse(text).getlocal(@timezone_offset)
|
217
|
+
else
|
218
|
+
Time.at(text / 1000).getlocal(@timezone_offset)
|
219
|
+
end
|
216
220
|
end
|
217
221
|
|
218
222
|
def created
|
@@ -7,7 +7,7 @@ require 'open3'
|
|
7
7
|
|
8
8
|
class JiraGateway
|
9
9
|
attr_accessor :ignore_ssl_errors
|
10
|
-
attr_reader :jira_url, :settings
|
10
|
+
attr_reader :jira_url, :settings, :file_system
|
11
11
|
|
12
12
|
def initialize file_system:, jira_config:, settings:
|
13
13
|
@file_system = file_system
|
@@ -18,15 +18,23 @@ class JiraGateway
|
|
18
18
|
|
19
19
|
def post_request relative_url:, payload:
|
20
20
|
command = make_curl_command url: "#{@jira_url}#{relative_url}", method: 'POST'
|
21
|
+
log_entry = " #{command.gsub(/\s+/, ' ')}"
|
22
|
+
log_entry = sanitize_message log_entry
|
23
|
+
@file_system.log log_entry
|
24
|
+
|
21
25
|
stdout, stderr, status = Open3.capture3(command, stdin_data: payload)
|
22
|
-
|
23
|
-
|
24
|
-
|
26
|
+
unless status.success?
|
27
|
+
@file_system.log "Failed call with exit status #{status.exitstatus}!"
|
28
|
+
@file_system.log "Returned (stdout): #{stdout.inspect}"
|
29
|
+
@file_system.log "Returned (stderr): #{stderr.inspect}"
|
30
|
+
raise "Failed call with exit status #{status.exitstatus}. " \
|
31
|
+
"See #{@file_system.logfile_name} for details"
|
32
|
+
end
|
25
33
|
|
26
|
-
@file_system.log
|
27
|
-
|
28
|
-
|
29
|
-
|
34
|
+
@file_system.log "Returned (stderr): #{stderr}" unless stderr == ''
|
35
|
+
raise 'no response from curl on stdout' if stdout == ''
|
36
|
+
|
37
|
+
parse_response(command: command, result: stdout)
|
30
38
|
end
|
31
39
|
|
32
40
|
def call_url relative_url:
|
@@ -53,12 +61,12 @@ class JiraGateway
|
|
53
61
|
token = @jira_api_token || @jira_personal_access_token
|
54
62
|
raise 'Neither Jira API Token or personal access token has been set' unless token
|
55
63
|
|
56
|
-
message.gsub(
|
64
|
+
message.gsub(token, '[API_TOKEN]')
|
57
65
|
end
|
58
66
|
|
59
67
|
def call_command command
|
60
68
|
log_entry = " #{command.gsub(/\s+/, ' ')}"
|
61
|
-
log_entry = sanitize_message log_entry
|
69
|
+
log_entry = sanitize_message log_entry
|
62
70
|
@file_system.log log_entry
|
63
71
|
|
64
72
|
result = `#{command}`
|
data/lib/jirametrics.rb
CHANGED
@@ -47,9 +47,9 @@ class JiraMetrics < Thor
|
|
47
47
|
|
48
48
|
option :config
|
49
49
|
desc 'info', 'Dump information about one issue'
|
50
|
-
def info
|
50
|
+
def info key
|
51
51
|
load_config options[:config]
|
52
|
-
Exporter.instance.info(
|
52
|
+
Exporter.instance.info(key, name_filter: options[:name] || '*')
|
53
53
|
end
|
54
54
|
|
55
55
|
no_commands do
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jirametrics
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.17.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Bowler
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: random-word
|
@@ -159,7 +159,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
159
159
|
- !ruby/object:Gem::Version
|
160
160
|
version: '0'
|
161
161
|
requirements: []
|
162
|
-
rubygems_version: 3.
|
162
|
+
rubygems_version: 3.7.2
|
163
163
|
specification_version: 4
|
164
164
|
summary: Extract Jira metrics
|
165
165
|
test_files: []
|