jirametrics 2.10 → 2.13
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/aging_work_in_progress_chart.rb +105 -41
- data/lib/jirametrics/aging_work_table.rb +56 -13
- data/lib/jirametrics/atlassian_document_format.rb +156 -0
- data/lib/jirametrics/board.rb +38 -10
- data/lib/jirametrics/board_config.rb +1 -0
- data/lib/jirametrics/board_movement_calculator.rb +155 -0
- data/lib/jirametrics/change_item.rb +38 -16
- data/lib/jirametrics/chart_base.rb +7 -5
- data/lib/jirametrics/css_variable.rb +1 -1
- data/lib/jirametrics/cycletime_config.rb +1 -1
- data/lib/jirametrics/daily_view.rb +274 -0
- data/lib/jirametrics/downloader.rb +61 -21
- data/lib/jirametrics/estimate_accuracy_chart.rb +34 -10
- data/lib/jirametrics/estimation_configuration.rb +25 -0
- data/lib/jirametrics/examples/standard_project.rb +2 -0
- data/lib/jirametrics/exporter.rb +2 -2
- data/lib/jirametrics/file_config.rb +1 -1
- data/lib/jirametrics/flow_efficiency_scatterplot.rb +1 -1
- data/lib/jirametrics/html/aging_work_in_progress_chart.erb +22 -5
- data/lib/jirametrics/html/aging_work_table.erb +7 -3
- data/lib/jirametrics/html/index.css +82 -2
- data/lib/jirametrics/html/index.erb +25 -1
- data/lib/jirametrics/html_report_config.rb +2 -0
- data/lib/jirametrics/issue.rb +69 -28
- data/lib/jirametrics/issue_collection.rb +33 -0
- data/lib/jirametrics/jira_gateway.rb +8 -1
- data/lib/jirametrics/project_config.rb +24 -7
- data/lib/jirametrics/settings.json +2 -1
- data/lib/jirametrics/sprint.rb +1 -0
- data/lib/jirametrics/sprint_burndown.rb +35 -33
- data/lib/jirametrics/sprint_issue_change_data.rb +3 -3
- data/lib/jirametrics/status.rb +3 -0
- data/lib/jirametrics/status_collection.rb +7 -0
- data/lib/jirametrics/user.rb +12 -0
- data/lib/jirametrics.rb +5 -0
- metadata +8 -2
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class IssueCollection < Array
|
|
4
|
+
attr_reader :hidden
|
|
5
|
+
|
|
6
|
+
def self.[] *issues
|
|
7
|
+
collection = new
|
|
8
|
+
issues.each { |i| collection << i }
|
|
9
|
+
collection
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
super
|
|
14
|
+
@hidden = []
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def reject! &block
|
|
18
|
+
select(&block).each do |issue|
|
|
19
|
+
@hidden << issue
|
|
20
|
+
end
|
|
21
|
+
super
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def find_by_key key:, include_hidden: false
|
|
25
|
+
block = ->(issue) { issue.key == key }
|
|
26
|
+
issue = find(&block)
|
|
27
|
+
issue = hidden.find(&block) if issue.nil? && include_hidden
|
|
28
|
+
issue
|
|
29
|
+
end
|
|
30
|
+
def clone
|
|
31
|
+
raise 'baboom'
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -26,7 +26,10 @@ class JiraGateway
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
def call_command command
|
|
29
|
-
|
|
29
|
+
log_entry = " #{command.gsub(/\s+/, ' ')}"
|
|
30
|
+
log_entry = log_entry.gsub(@jira_api_token, '[API_TOKEN]') if @jira_api_token
|
|
31
|
+
@file_system.log log_entry
|
|
32
|
+
|
|
30
33
|
result = `#{command}`
|
|
31
34
|
@file_system.log result unless $CHILD_STATUS.success?
|
|
32
35
|
return result if $CHILD_STATUS.success?
|
|
@@ -74,4 +77,8 @@ class JiraGateway
|
|
|
74
77
|
|
|
75
78
|
true
|
|
76
79
|
end
|
|
80
|
+
|
|
81
|
+
def cloud?
|
|
82
|
+
@jira_url.downcase.end_with? '.atlassian.net'
|
|
83
|
+
end
|
|
77
84
|
end
|
|
@@ -6,7 +6,7 @@ require 'jirametrics/status_collection'
|
|
|
6
6
|
class ProjectConfig
|
|
7
7
|
attr_reader :target_path, :jira_config, :all_boards, :possible_statuses,
|
|
8
8
|
:download_config, :file_configs, :exporter, :data_version, :name, :board_configs,
|
|
9
|
-
:settings, :aggregate_config, :discarded_changes_data
|
|
9
|
+
:settings, :aggregate_config, :discarded_changes_data, :users
|
|
10
10
|
attr_accessor :time_range, :jira_url, :id
|
|
11
11
|
|
|
12
12
|
def initialize exporter:, jira_config:, block:, target_path: '.', name: '', id: nil
|
|
@@ -40,6 +40,7 @@ class ProjectConfig
|
|
|
40
40
|
@id = guess_project_id
|
|
41
41
|
load_project_metadata
|
|
42
42
|
load_sprints
|
|
43
|
+
load_users
|
|
43
44
|
end
|
|
44
45
|
|
|
45
46
|
def run load_only: false
|
|
@@ -151,6 +152,8 @@ class ProjectConfig
|
|
|
151
152
|
end
|
|
152
153
|
|
|
153
154
|
def status_category_mapping status:, category:
|
|
155
|
+
return if @exporter.downloading?
|
|
156
|
+
|
|
154
157
|
status, status_id = possible_statuses.parse_name_id status
|
|
155
158
|
category, category_id = possible_statuses.parse_name_id category
|
|
156
159
|
|
|
@@ -323,6 +326,15 @@ class ProjectConfig
|
|
|
323
326
|
raise
|
|
324
327
|
end
|
|
325
328
|
|
|
329
|
+
def load_users
|
|
330
|
+
@users = []
|
|
331
|
+
filename = File.join @target_path, "#{get_file_prefix}_users.json"
|
|
332
|
+
return unless File.exist? filename
|
|
333
|
+
|
|
334
|
+
json = file_system.load_json(filename)
|
|
335
|
+
json.each { |user_data| @users << User.new(raw: user_data) }
|
|
336
|
+
end
|
|
337
|
+
|
|
326
338
|
def to_time string, end_of_day: false
|
|
327
339
|
time = end_of_day ? '23:59:59' : '00:00:00'
|
|
328
340
|
string = "#{string}T#{time}#{exporter.timezone_offset}" if string.match?(/^\d{4}-\d{2}-\d{2}$/)
|
|
@@ -356,7 +368,7 @@ class ProjectConfig
|
|
|
356
368
|
|
|
357
369
|
# To be used by the aggregate_config only. Not intended to be part of the public API
|
|
358
370
|
def add_issues issues_list
|
|
359
|
-
@issues =
|
|
371
|
+
@issues = IssueCollection.new if @issues.nil?
|
|
360
372
|
@all_boards = {}
|
|
361
373
|
|
|
362
374
|
issues_list.each do |issue|
|
|
@@ -373,7 +385,7 @@ class ProjectConfig
|
|
|
373
385
|
'declaration but none are here. Check your config.'
|
|
374
386
|
end
|
|
375
387
|
|
|
376
|
-
return @issues =
|
|
388
|
+
return @issues = IssueCollection.new if @exporter.downloading?
|
|
377
389
|
raise 'No data found. Must do a download before an export' unless data_downloaded?
|
|
378
390
|
|
|
379
391
|
load_data if all_boards.empty?
|
|
@@ -385,7 +397,7 @@ class ProjectConfig
|
|
|
385
397
|
issues = load_issues_from_issues_directory path: issues_path, timezone_offset: timezone_offset
|
|
386
398
|
else
|
|
387
399
|
file_system.log "Can't find directory #{issues_path}. Has a download been done?", also_write_to_stderr: true
|
|
388
|
-
return
|
|
400
|
+
return IssueCollection.new
|
|
389
401
|
end
|
|
390
402
|
|
|
391
403
|
# Attach related issues
|
|
@@ -397,7 +409,8 @@ class ProjectConfig
|
|
|
397
409
|
|
|
398
410
|
# We'll have some issues that are in the list that weren't part of the initial query. Once we've
|
|
399
411
|
# attached them in the appropriate places, remove any that aren't part of that initial set.
|
|
400
|
-
|
|
412
|
+
issues.reject! { |i| !i.in_initial_query? } # rubocop:disable Style/InverseMethods
|
|
413
|
+
@issues = issues
|
|
401
414
|
end
|
|
402
415
|
|
|
403
416
|
@issues
|
|
@@ -438,7 +451,7 @@ class ProjectConfig
|
|
|
438
451
|
end
|
|
439
452
|
|
|
440
453
|
def load_issues_from_issues_directory path:, timezone_offset:
|
|
441
|
-
issues =
|
|
454
|
+
issues = IssueCollection.new
|
|
442
455
|
default_board = nil
|
|
443
456
|
|
|
444
457
|
group_filenames_and_board_ids(path: path).each do |filename, board_ids|
|
|
@@ -450,6 +463,10 @@ class ProjectConfig
|
|
|
450
463
|
end
|
|
451
464
|
|
|
452
465
|
boards.each do |board|
|
|
466
|
+
if board.cycletime.nil?
|
|
467
|
+
raise "The board declaration for board #{board.id} must come before the " \
|
|
468
|
+
"first usage of 'issues' in the configuration"
|
|
469
|
+
end
|
|
453
470
|
issues << Issue.new(raw: content, timezone_offset: timezone_offset, board: board)
|
|
454
471
|
end
|
|
455
472
|
end
|
|
@@ -462,7 +479,7 @@ class ProjectConfig
|
|
|
462
479
|
# board ids appropriately.
|
|
463
480
|
def group_filenames_and_board_ids path:
|
|
464
481
|
hash = {}
|
|
465
|
-
|
|
482
|
+
file_system.foreach(path) do |filename|
|
|
466
483
|
# Matches either FAKE-123.json or FAKE-123-456.json
|
|
467
484
|
if /^(?<key>[^-]+-\d+)(?<_>-(?<board_id>\d+))?\.json$/ =~ filename
|
|
468
485
|
(hash[key] ||= []) << [filename, board_id&.to_i || :unknown]
|
data/lib/jirametrics/sprint.rb
CHANGED
|
@@ -121,11 +121,13 @@ class SprintBurndown < ChartBase
|
|
|
121
121
|
|
|
122
122
|
# select all the changes that are relevant for the sprint. If this issue never appears in this sprint then return [].
|
|
123
123
|
def changes_for_one_issue issue:, sprint:
|
|
124
|
-
|
|
124
|
+
estimate = 0.0
|
|
125
125
|
ever_in_sprint = false
|
|
126
126
|
currently_in_sprint = false
|
|
127
127
|
change_data = []
|
|
128
128
|
|
|
129
|
+
estimate_display_name = current_board.estimation_configuration.display_name
|
|
130
|
+
|
|
129
131
|
issue_completed_time = issue.board.cycletime.started_stopped_times(issue).last
|
|
130
132
|
completed_has_been_tracked = false
|
|
131
133
|
|
|
@@ -140,26 +142,26 @@ class SprintBurndown < ChartBase
|
|
|
140
142
|
if currently_in_sprint == false && in_change_item
|
|
141
143
|
action = :enter_sprint
|
|
142
144
|
ever_in_sprint = true
|
|
143
|
-
value =
|
|
145
|
+
value = estimate
|
|
144
146
|
elsif currently_in_sprint && in_change_item == false
|
|
145
147
|
action = :leave_sprint
|
|
146
|
-
value = -
|
|
148
|
+
value = -estimate
|
|
147
149
|
end
|
|
148
150
|
currently_in_sprint = in_change_item
|
|
149
|
-
elsif change.
|
|
151
|
+
elsif change.field == estimate_display_name && (issue_completed_time.nil? || change.time < issue_completed_time)
|
|
150
152
|
action = :story_points
|
|
151
|
-
|
|
152
|
-
value =
|
|
153
|
+
estimate = change.value.to_f
|
|
154
|
+
value = estimate - change.old_value.to_f
|
|
153
155
|
elsif completed_has_been_tracked == false && change.time == issue_completed_time
|
|
154
156
|
completed_has_been_tracked = true
|
|
155
157
|
action = :issue_stopped
|
|
156
|
-
value = -
|
|
158
|
+
value = -estimate
|
|
157
159
|
end
|
|
158
160
|
|
|
159
161
|
next unless action
|
|
160
162
|
|
|
161
163
|
change_data << SprintIssueChangeData.new(
|
|
162
|
-
time: change.time, issue: issue, action: action, value: value,
|
|
164
|
+
time: change.time, issue: issue, action: action, value: value, estimate: estimate
|
|
163
165
|
)
|
|
164
166
|
end
|
|
165
167
|
|
|
@@ -176,7 +178,7 @@ class SprintBurndown < ChartBase
|
|
|
176
178
|
summary_stats = SprintSummaryStats.new
|
|
177
179
|
summary_stats.completed = 0.0
|
|
178
180
|
|
|
179
|
-
|
|
181
|
+
estimate = 0.0
|
|
180
182
|
start_data_written = false
|
|
181
183
|
data_set = []
|
|
182
184
|
|
|
@@ -185,11 +187,11 @@ class SprintBurndown < ChartBase
|
|
|
185
187
|
change_data_for_sprint.each do |change_data|
|
|
186
188
|
if start_data_written == false && change_data.time >= sprint.start_time
|
|
187
189
|
data_set << {
|
|
188
|
-
y:
|
|
190
|
+
y: estimate,
|
|
189
191
|
x: chart_format(sprint.start_time),
|
|
190
|
-
title: "Sprint started with #{
|
|
192
|
+
title: "Sprint started with #{estimate} points"
|
|
191
193
|
}
|
|
192
|
-
summary_stats.started =
|
|
194
|
+
summary_stats.started = estimate
|
|
193
195
|
start_data_written = true
|
|
194
196
|
end
|
|
195
197
|
|
|
@@ -198,12 +200,12 @@ class SprintBurndown < ChartBase
|
|
|
198
200
|
case change_data.action
|
|
199
201
|
when :enter_sprint
|
|
200
202
|
issues_currently_in_sprint << change_data.issue.key
|
|
201
|
-
|
|
203
|
+
estimate += change_data.estimate
|
|
202
204
|
when :leave_sprint
|
|
203
205
|
issues_currently_in_sprint.delete change_data.issue.key
|
|
204
|
-
|
|
206
|
+
estimate -= change_data.estimate
|
|
205
207
|
when :story_points
|
|
206
|
-
|
|
208
|
+
estimate += change_data.value if issues_currently_in_sprint.include? change_data.issue.key
|
|
207
209
|
end
|
|
208
210
|
|
|
209
211
|
next unless change_data.time >= sprint.start_time
|
|
@@ -213,26 +215,26 @@ class SprintBurndown < ChartBase
|
|
|
213
215
|
when :story_points
|
|
214
216
|
next unless issues_currently_in_sprint.include? change_data.issue.key
|
|
215
217
|
|
|
216
|
-
|
|
217
|
-
message = "Story points changed from #{
|
|
218
|
+
old_estimate = change_data.estimate - change_data.value
|
|
219
|
+
message = "Story points changed from #{old_estimate} points to #{change_data.estimate} points"
|
|
218
220
|
summary_stats.points_values_changed = true
|
|
219
221
|
when :enter_sprint
|
|
220
|
-
message = "Added to sprint with #{change_data.
|
|
221
|
-
summary_stats.added += change_data.
|
|
222
|
+
message = "Added to sprint with #{change_data.estimate || 'no'} points"
|
|
223
|
+
summary_stats.added += change_data.estimate
|
|
222
224
|
when :issue_stopped
|
|
223
|
-
|
|
224
|
-
message = "Completed with #{change_data.
|
|
225
|
+
estimate -= change_data.estimate
|
|
226
|
+
message = "Completed with #{change_data.estimate || 'no'} points"
|
|
225
227
|
issues_currently_in_sprint.delete change_data.issue.key
|
|
226
|
-
summary_stats.completed += change_data.
|
|
228
|
+
summary_stats.completed += change_data.estimate
|
|
227
229
|
when :leave_sprint
|
|
228
|
-
message = "Removed from sprint with #{change_data.
|
|
229
|
-
summary_stats.removed += change_data.
|
|
230
|
+
message = "Removed from sprint with #{change_data.estimate || 'no'} points"
|
|
231
|
+
summary_stats.removed += change_data.estimate
|
|
230
232
|
else
|
|
231
233
|
raise "Unexpected action: #{change_data.action}"
|
|
232
234
|
end
|
|
233
235
|
|
|
234
236
|
data_set << {
|
|
235
|
-
y:
|
|
237
|
+
y: estimate,
|
|
236
238
|
x: chart_format(change_data.time),
|
|
237
239
|
title: "#{change_data.issue.key} #{message}"
|
|
238
240
|
}
|
|
@@ -241,27 +243,27 @@ class SprintBurndown < ChartBase
|
|
|
241
243
|
unless start_data_written
|
|
242
244
|
# There was nothing that triggered us to write the sprint started block so do it now.
|
|
243
245
|
data_set << {
|
|
244
|
-
y:
|
|
246
|
+
y: estimate,
|
|
245
247
|
x: chart_format(sprint.start_time),
|
|
246
|
-
title: "Sprint started with #{
|
|
248
|
+
title: "Sprint started with #{estimate} points"
|
|
247
249
|
}
|
|
248
|
-
summary_stats.started =
|
|
250
|
+
summary_stats.started = estimate
|
|
249
251
|
end
|
|
250
252
|
|
|
251
253
|
if sprint.completed_time
|
|
252
254
|
data_set << {
|
|
253
|
-
y:
|
|
255
|
+
y: estimate,
|
|
254
256
|
x: chart_format(sprint.completed_time),
|
|
255
|
-
title: "Sprint ended with #{
|
|
257
|
+
title: "Sprint ended with #{estimate} points unfinished"
|
|
256
258
|
}
|
|
257
|
-
summary_stats.remaining =
|
|
259
|
+
summary_stats.remaining = estimate
|
|
258
260
|
end
|
|
259
261
|
|
|
260
262
|
unless sprint.completed_at?(time_range.end)
|
|
261
263
|
data_set << {
|
|
262
|
-
y:
|
|
264
|
+
y: estimate,
|
|
263
265
|
x: chart_format(time_range.end),
|
|
264
|
-
title: "Sprint still active. #{
|
|
266
|
+
title: "Sprint still active. #{estimate} points still in progress."
|
|
265
267
|
}
|
|
266
268
|
end
|
|
267
269
|
|
|
@@ -4,14 +4,14 @@ require 'jirametrics/value_equality'
|
|
|
4
4
|
|
|
5
5
|
class SprintIssueChangeData
|
|
6
6
|
include ValueEquality
|
|
7
|
-
attr_reader :time, :action, :value, :issue, :
|
|
7
|
+
attr_reader :time, :action, :value, :issue, :estimate
|
|
8
8
|
|
|
9
|
-
def initialize time:, action:, value:, issue:,
|
|
9
|
+
def initialize time:, action:, value:, issue:, estimate:
|
|
10
10
|
@time = time
|
|
11
11
|
@action = action
|
|
12
12
|
@value = value
|
|
13
13
|
@issue = issue
|
|
14
|
-
@
|
|
14
|
+
@estimate = estimate
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def inspect
|
data/lib/jirametrics/status.rb
CHANGED
|
@@ -36,7 +36,10 @@ class Status
|
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
def self.from_raw raw
|
|
39
|
+
raise "raw cannot be nil" if raw.nil?
|
|
40
|
+
|
|
39
41
|
category_config = raw['statusCategory']
|
|
42
|
+
raise "statusCategory can't be nil in #{category_config.inspect}" if category_config.nil?
|
|
40
43
|
|
|
41
44
|
Status.new(
|
|
42
45
|
name: raw['name'],
|
|
@@ -16,6 +16,13 @@ class StatusCollection
|
|
|
16
16
|
@list.find { |status| status.id == id }
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
+
def find_by_id! id
|
|
20
|
+
status = @list.find { |status| status.id == id }
|
|
21
|
+
raise "Can't find any status for id #{id} in #{self}" unless status
|
|
22
|
+
|
|
23
|
+
status
|
|
24
|
+
end
|
|
25
|
+
|
|
19
26
|
def find_all_by_name identifier
|
|
20
27
|
name, id = parse_name_id identifier
|
|
21
28
|
|
data/lib/jirametrics.rb
CHANGED
|
@@ -69,6 +69,7 @@ class JiraMetrics < Thor
|
|
|
69
69
|
require 'jirametrics/daily_wip_chart'
|
|
70
70
|
require 'jirametrics/groupable_issue_chart'
|
|
71
71
|
require 'jirametrics/css_variable'
|
|
72
|
+
require 'jirametrics/issue_collection'
|
|
72
73
|
|
|
73
74
|
require 'jirametrics/aggregate_config'
|
|
74
75
|
require 'jirametrics/expedited_chart'
|
|
@@ -112,7 +113,11 @@ class JiraMetrics < Thor
|
|
|
112
113
|
require 'jirametrics/download_config'
|
|
113
114
|
require 'jirametrics/columns_config'
|
|
114
115
|
require 'jirametrics/hierarchy_table'
|
|
116
|
+
require 'jirametrics/estimation_configuration'
|
|
115
117
|
require 'jirametrics/board'
|
|
118
|
+
require 'jirametrics/daily_view'
|
|
119
|
+
require 'jirametrics/user'
|
|
120
|
+
require 'jirametrics/atlassian_document_format'
|
|
116
121
|
load config_file
|
|
117
122
|
end
|
|
118
123
|
end
|
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: '2.
|
|
4
|
+
version: '2.13'
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mike Bowler
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2025-
|
|
10
|
+
date: 2025-07-25 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: random-word
|
|
@@ -65,10 +65,12 @@ files:
|
|
|
65
65
|
- lib/jirametrics/aging_work_in_progress_chart.rb
|
|
66
66
|
- lib/jirametrics/aging_work_table.rb
|
|
67
67
|
- lib/jirametrics/anonymizer.rb
|
|
68
|
+
- lib/jirametrics/atlassian_document_format.rb
|
|
68
69
|
- lib/jirametrics/blocked_stalled_change.rb
|
|
69
70
|
- lib/jirametrics/board.rb
|
|
70
71
|
- lib/jirametrics/board_column.rb
|
|
71
72
|
- lib/jirametrics/board_config.rb
|
|
73
|
+
- lib/jirametrics/board_movement_calculator.rb
|
|
72
74
|
- lib/jirametrics/change_item.rb
|
|
73
75
|
- lib/jirametrics/chart_base.rb
|
|
74
76
|
- lib/jirametrics/columns_config.rb
|
|
@@ -76,6 +78,7 @@ files:
|
|
|
76
78
|
- lib/jirametrics/cycletime_config.rb
|
|
77
79
|
- lib/jirametrics/cycletime_histogram.rb
|
|
78
80
|
- lib/jirametrics/cycletime_scatterplot.rb
|
|
81
|
+
- lib/jirametrics/daily_view.rb
|
|
79
82
|
- lib/jirametrics/daily_wip_by_age_chart.rb
|
|
80
83
|
- lib/jirametrics/daily_wip_by_blocked_stalled_chart.rb
|
|
81
84
|
- lib/jirametrics/daily_wip_by_parent_chart.rb
|
|
@@ -85,6 +88,7 @@ files:
|
|
|
85
88
|
- lib/jirametrics/download_config.rb
|
|
86
89
|
- lib/jirametrics/downloader.rb
|
|
87
90
|
- lib/jirametrics/estimate_accuracy_chart.rb
|
|
91
|
+
- lib/jirametrics/estimation_configuration.rb
|
|
88
92
|
- lib/jirametrics/examples/aggregated_project.rb
|
|
89
93
|
- lib/jirametrics/examples/standard_project.rb
|
|
90
94
|
- lib/jirametrics/expedited_chart.rb
|
|
@@ -113,6 +117,7 @@ files:
|
|
|
113
117
|
- lib/jirametrics/html/throughput_chart.erb
|
|
114
118
|
- lib/jirametrics/html_report_config.rb
|
|
115
119
|
- lib/jirametrics/issue.rb
|
|
120
|
+
- lib/jirametrics/issue_collection.rb
|
|
116
121
|
- lib/jirametrics/issue_link.rb
|
|
117
122
|
- lib/jirametrics/jira_gateway.rb
|
|
118
123
|
- lib/jirametrics/project_config.rb
|
|
@@ -127,6 +132,7 @@ files:
|
|
|
127
132
|
- lib/jirametrics/throughput_chart.rb
|
|
128
133
|
- lib/jirametrics/tree_organizer.rb
|
|
129
134
|
- lib/jirametrics/trend_line_calculator.rb
|
|
135
|
+
- lib/jirametrics/user.rb
|
|
130
136
|
- lib/jirametrics/value_equality.rb
|
|
131
137
|
homepage: https://jirametrics.org
|
|
132
138
|
licenses:
|