jirametrics 2.0.1 → 2.1.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/aging_work_bar_chart.rb +17 -9
- data/lib/jirametrics/aging_work_in_progress_chart.rb +8 -6
- data/lib/jirametrics/aging_work_table.rb +8 -15
- data/lib/jirametrics/anonymizer.rb +6 -5
- data/lib/jirametrics/chart_base.rb +19 -17
- data/lib/jirametrics/css_variable.rb +33 -0
- data/lib/jirametrics/cycletime_scatterplot.rb +9 -7
- data/lib/jirametrics/daily_wip_by_age_chart.rb +9 -9
- data/lib/jirametrics/daily_wip_by_blocked_stalled_chart.rb +22 -14
- data/lib/jirametrics/daily_wip_chart.rb +2 -2
- data/lib/jirametrics/dependency_chart.rb +18 -14
- data/lib/jirametrics/downloader.rb +6 -7
- data/lib/jirametrics/examples/aggregated_project.rb +3 -1
- data/lib/jirametrics/examples/standard_project.rb +10 -4
- data/lib/jirametrics/expedited_chart.rb +5 -2
- data/lib/jirametrics/exporter.rb +26 -20
- data/lib/jirametrics/grouping_rules.rb +7 -1
- data/lib/jirametrics/html/aging_work_bar_chart.erb +12 -6
- data/lib/jirametrics/html/aging_work_in_progress_chart.erb +8 -2
- data/lib/jirametrics/html/aging_work_table.erb +1 -1
- data/lib/jirametrics/html/cycletime_histogram.erb +9 -3
- data/lib/jirametrics/html/cycletime_scatterplot.erb +10 -4
- data/lib/jirametrics/html/daily_wip_chart.erb +10 -5
- data/lib/jirametrics/html/expedited_chart.erb +11 -5
- data/lib/jirametrics/html/hierarchy_table.erb +1 -1
- data/lib/jirametrics/html/index.css +174 -0
- data/lib/jirametrics/html/index.erb +8 -36
- data/lib/jirametrics/html/sprint_burndown.erb +11 -6
- data/lib/jirametrics/html/story_point_accuracy_chart.erb +9 -4
- data/lib/jirametrics/html/throughput_chart.erb +11 -5
- data/lib/jirametrics/html_report_config.rb +17 -2
- data/lib/jirametrics/issue.rb +3 -2
- data/lib/jirametrics/jira_gateway.rb +1 -1
- data/lib/jirametrics/project_config.rb +13 -18
- data/lib/jirametrics/settings.json +7 -0
- data/lib/jirametrics/sprint_burndown.rb +2 -2
- data/lib/jirametrics/status_collection.rb +1 -1
- data/lib/jirametrics/story_point_accuracy_chart.rb +8 -4
- data/lib/jirametrics/throughput_chart.rb +4 -1
- data/lib/jirametrics.rb +1 -0
- metadata +6 -3
@@ -1,5 +1,5 @@
|
|
1
1
|
|
2
|
-
<div>
|
2
|
+
<div class="chart">
|
3
3
|
<canvas id="<%= chart_id %>" width="<%= canvas_width %>" height="<%= canvas_height %>"></canvas>
|
4
4
|
</div>
|
5
5
|
<script>
|
@@ -23,7 +23,10 @@ new Chart(document.getElementById('<%= chart_id %>').getContext('2d'), {
|
|
23
23
|
scaleLabel: {
|
24
24
|
display: true,
|
25
25
|
labelString: 'Date Completed'
|
26
|
-
}
|
26
|
+
},
|
27
|
+
grid: {
|
28
|
+
color: <%= CssVariable['--grid-line-color'].to_json %>
|
29
|
+
},
|
27
30
|
},
|
28
31
|
y: {
|
29
32
|
scaleLabel: {
|
@@ -33,7 +36,10 @@ new Chart(document.getElementById('<%= chart_id %>').getContext('2d'), {
|
|
33
36
|
display: true,
|
34
37
|
text: 'Count of items'
|
35
38
|
},
|
36
|
-
min: 0
|
39
|
+
min: 0,
|
40
|
+
grid: {
|
41
|
+
color: <%= CssVariable['--grid-line-color'].to_json %>
|
42
|
+
},
|
37
43
|
},
|
38
44
|
},
|
39
45
|
plugins: {
|
@@ -52,8 +58,8 @@ new Chart(document.getElementById('<%= chart_id %>').getContext('2d'), {
|
|
52
58
|
type: 'box',
|
53
59
|
xMin: '<%= range.begin %>T00:00:00',
|
54
60
|
xMax: '<%= range.end %>T23:59:59',
|
55
|
-
backgroundColor: '
|
56
|
-
borderColor: '
|
61
|
+
backgroundColor: <%= CssVariable.new('--non-working-days-color').to_json %>,
|
62
|
+
borderColor: <%= CssVariable.new('--non-working-days-color').to_json %>
|
57
63
|
},
|
58
64
|
<% end %>
|
59
65
|
}
|
@@ -36,11 +36,21 @@ class HtmlReportConfig
|
|
36
36
|
|
37
37
|
File.open @file_config.output_filename, 'w' do |file|
|
38
38
|
html_directory = "#{Pathname.new(File.realpath(__FILE__)).dirname}/html"
|
39
|
-
|
39
|
+
css = load_css html_directory: html_directory
|
40
|
+
erb = ERB.new File.read(File.join(html_directory, 'index.erb'))
|
40
41
|
file.puts erb.result(binding)
|
41
42
|
end
|
42
43
|
end
|
43
44
|
|
45
|
+
def load_css html_directory:
|
46
|
+
base_css = File.read(File.join(html_directory, 'index.css'))
|
47
|
+
extra_css_filename = settings['include_css']
|
48
|
+
return base_css unless extra_css_filename && File.exist?(extra_css_filename)
|
49
|
+
|
50
|
+
@file_config.project_config.exporter.file_system.log("including css from file: #{extra_css_filename}")
|
51
|
+
base_css << "\n\n" << File.read(extra_css_filename)
|
52
|
+
end
|
53
|
+
|
44
54
|
def board_id id = nil
|
45
55
|
@board_id = id unless id.nil?
|
46
56
|
@board_id
|
@@ -145,13 +155,18 @@ class HtmlReportConfig
|
|
145
155
|
execute_chart DependencyChart.new block
|
146
156
|
end
|
147
157
|
|
158
|
+
# have an explicit method here so that index.erb can call 'settings' just as any other erb can.
|
159
|
+
def settings
|
160
|
+
@file_config.project_config.settings
|
161
|
+
end
|
162
|
+
|
148
163
|
def execute_chart chart, &after_init_block
|
149
164
|
project_config = @file_config.project_config
|
150
165
|
|
151
166
|
chart.issues = issues
|
152
167
|
chart.time_range = project_config.time_range
|
153
168
|
chart.timezone_offset = timezone_offset
|
154
|
-
chart.settings =
|
169
|
+
chart.settings = settings
|
155
170
|
|
156
171
|
chart.all_boards = project_config.all_boards
|
157
172
|
chart.board_id = find_board_id if chart.respond_to? :board_id=
|
data/lib/jirametrics/issue.rb
CHANGED
@@ -30,7 +30,8 @@ class Issue
|
|
30
30
|
fabricate_change(field_name: 'status'),
|
31
31
|
fabricate_change(field_name: 'priority')
|
32
32
|
].compact + @changes
|
33
|
-
rescue
|
33
|
+
rescue # rubocop:disable Style/RescueStandardError
|
34
|
+
# All we're doing is adding information to the existing exception and letting it propogate up
|
34
35
|
raise "Unable to initialize #{raw['key']}"
|
35
36
|
end
|
36
37
|
|
@@ -252,7 +253,7 @@ class Issue
|
|
252
253
|
end
|
253
254
|
|
254
255
|
blocked_link_texts = settings['blocked_link_text']
|
255
|
-
stalled_threshold = settings['
|
256
|
+
stalled_threshold = settings['stalled_threshold_days']
|
256
257
|
|
257
258
|
blocking_issue_keys = []
|
258
259
|
|
@@ -29,7 +29,7 @@ class JiraGateway
|
|
29
29
|
|
30
30
|
def load_jira_config jira_config
|
31
31
|
@jira_url = jira_config['url']
|
32
|
-
raise
|
32
|
+
raise 'Must specify URL in config' if @jira_url.nil?
|
33
33
|
|
34
34
|
@jira_email = jira_config['email']
|
35
35
|
@jira_api_token = jira_config['api_token']
|
@@ -8,7 +8,7 @@ class ProjectConfig
|
|
8
8
|
|
9
9
|
attr_reader :target_path, :jira_config, :all_boards, :possible_statuses,
|
10
10
|
:download_config, :file_configs, :exporter, :data_version, :name, :board_configs,
|
11
|
-
:settings
|
11
|
+
:settings
|
12
12
|
attr_accessor :time_range, :jira_url, :id
|
13
13
|
|
14
14
|
def initialize exporter:, jira_config:, block:, target_path: '.', name: '', id: nil
|
@@ -22,22 +22,12 @@ class ProjectConfig
|
|
22
22
|
@name = name
|
23
23
|
@board_configs = []
|
24
24
|
@all_boards = {}
|
25
|
-
@settings =
|
26
|
-
'stalled_threshold' => 5,
|
27
|
-
'blocked_statuses' => [],
|
28
|
-
'stalled_statuses' => [],
|
29
|
-
'blocked_link_text' => [],
|
30
|
-
|
31
|
-
'colors' => {
|
32
|
-
'stalled' => 'orange',
|
33
|
-
'blocked' => '#FF7400'
|
34
|
-
}
|
35
|
-
}
|
25
|
+
@settings = load_settings
|
36
26
|
@id = id
|
37
27
|
end
|
38
28
|
|
39
29
|
def evaluate_next_level
|
40
|
-
instance_eval(&@block)
|
30
|
+
instance_eval(&@block) if @block
|
41
31
|
end
|
42
32
|
|
43
33
|
def run
|
@@ -58,6 +48,10 @@ class ProjectConfig
|
|
58
48
|
end
|
59
49
|
end
|
60
50
|
|
51
|
+
def load_settings
|
52
|
+
JSON.parse(File.read(File.join(__dir__, 'settings.json')))
|
53
|
+
end
|
54
|
+
|
61
55
|
def guess_project_id
|
62
56
|
return @id if @id
|
63
57
|
|
@@ -243,7 +237,7 @@ class ProjectConfig
|
|
243
237
|
|
244
238
|
start = json['date_start'] || json['time_start'] # date_start is the current format. Time is the old.
|
245
239
|
stop = json['date_end'] || json['time_end']
|
246
|
-
@time_range = to_time(start)..to_time(stop)
|
240
|
+
@time_range = to_time(start)..to_time(stop, end_of_day: true)
|
247
241
|
|
248
242
|
@jira_url = json['jira_url']
|
249
243
|
rescue Errno::ENOENT
|
@@ -251,8 +245,9 @@ class ProjectConfig
|
|
251
245
|
raise
|
252
246
|
end
|
253
247
|
|
254
|
-
def to_time string
|
255
|
-
|
248
|
+
def to_time string, end_of_day: false
|
249
|
+
time = end_of_day ? '23:59:59' : '00:00:00'
|
250
|
+
string = "#{string}T#{time}#{@timezone_offset}" if string.match?(/^\d{4}-\d{2}-\d{2}$/)
|
256
251
|
Time.parse string
|
257
252
|
end
|
258
253
|
|
@@ -436,8 +431,8 @@ class ProjectConfig
|
|
436
431
|
else
|
437
432
|
message << "days of data from #{issue.changes.first.time.to_date} to #{cutoff_time.to_date}"
|
438
433
|
end
|
439
|
-
|
434
|
+
exporter.file_system.log message
|
440
435
|
end
|
441
|
-
|
436
|
+
exporter.file_system.log "Discarded data from #{issues_cutoff_times.count} issues out of a total #{issues.size}"
|
442
437
|
end
|
443
438
|
end
|
@@ -57,7 +57,7 @@ class SprintBurndown < ChartBase
|
|
57
57
|
result = +''
|
58
58
|
result << '<h1>Sprint Burndowns</h1>'
|
59
59
|
|
60
|
-
possible_colours =
|
60
|
+
possible_colours = (1..5).collect { |i| CssVariable["--sprint-burndown-sprint-color-#{i}"] }
|
61
61
|
charts_to_generate = []
|
62
62
|
charts_to_generate << [:data_set_by_story_points, 'Story Points'] if @use_story_points
|
63
63
|
charts_to_generate << [:data_set_by_story_counts, 'Story Count'] if @use_story_counts
|
@@ -65,7 +65,7 @@ class SprintBurndown < ChartBase
|
|
65
65
|
@summary_stats.clear
|
66
66
|
data_sets = []
|
67
67
|
sprints.each_with_index do |sprint, index|
|
68
|
-
color = possible_colours[index %
|
68
|
+
color = possible_colours[index % possible_colours.size]
|
69
69
|
label = sprint.name
|
70
70
|
data = send(data_method, sprint: sprint, change_data_for_sprint: change_data_by_sprint[sprint])
|
71
71
|
data_sets << {
|
@@ -32,7 +32,7 @@ class StatusCollection
|
|
32
32
|
next
|
33
33
|
else
|
34
34
|
all_status_names = @list.collect { |s| "#{s.name.inspect}:#{s.id.inspect}" }.uniq.sort.join(', ')
|
35
|
-
raise "Status not found: #{name_or_id}. Possible statuses are: #{all_status_names}"
|
35
|
+
raise "Status not found: \"#{name_or_id}\". Possible statuses are: #{all_status_names}"
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
@@ -11,7 +11,8 @@ class StoryPointAccuracyChart < ChartBase
|
|
11
11
|
estimates can change over time, we're graphing the estimate at the time that the story started.
|
12
12
|
</p>
|
13
13
|
<p>
|
14
|
-
The completed dots indicate cycletimes. The aging dots (
|
14
|
+
The completed dots indicate cycletimes. The aging dots (click on the legend to turn them on)
|
15
|
+
show the current
|
15
16
|
age of items, which will give you a hint as to where they might end up. If they're already
|
16
17
|
far to the right then you know you have a problem.
|
17
18
|
</p>
|
@@ -56,9 +57,12 @@ class StoryPointAccuracyChart < ChartBase
|
|
56
57
|
end
|
57
58
|
|
58
59
|
[
|
59
|
-
[completed_hash, 'Completed', '
|
60
|
-
[aging_hash, 'Still in progress', '
|
61
|
-
].filter_map do |hash, label,
|
60
|
+
[completed_hash, 'Completed', 'completed', false],
|
61
|
+
[aging_hash, 'Still in progress', 'active', true]
|
62
|
+
].filter_map do |hash, label, completed_or_active, starts_hidden|
|
63
|
+
fill_color = CssVariable["--estimate-accuracy-chart-#{completed_or_active}-fill-color"]
|
64
|
+
border_color = CssVariable["--estimate-accuracy-chart-#{completed_or_active}-border-color"]
|
65
|
+
|
62
66
|
# We sort so that the smaller circles are in front of the bigger circles.
|
63
67
|
data = hash.sort(&hash_sorter).collect do |key, values|
|
64
68
|
estimate, cycle_time = *key
|
@@ -25,7 +25,10 @@ class ThroughputChart < ChartBase
|
|
25
25
|
data_sets = []
|
26
26
|
if rules_to_issues.size > 1
|
27
27
|
data_sets << weekly_throughput_dataset(
|
28
|
-
completed_issues: completed_issues,
|
28
|
+
completed_issues: completed_issues,
|
29
|
+
label: 'Totals',
|
30
|
+
color: CssVariable['--throughput_chart_total_line_color'],
|
31
|
+
dashed: true
|
29
32
|
)
|
30
33
|
end
|
31
34
|
|
data/lib/jirametrics.rb
CHANGED
@@ -51,6 +51,7 @@ class JiraMetrics < Thor
|
|
51
51
|
require 'jirametrics/daily_wip_chart'
|
52
52
|
require 'jirametrics/groupable_issue_chart'
|
53
53
|
require 'jirametrics/discard_changes_before'
|
54
|
+
require 'jirametrics/css_variable'
|
54
55
|
|
55
56
|
require 'jirametrics/aggregate_config'
|
56
57
|
require 'jirametrics/expedited_chart'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jirametrics
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Bowler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-05-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: random-word
|
@@ -74,6 +74,7 @@ files:
|
|
74
74
|
- lib/jirametrics/change_item.rb
|
75
75
|
- lib/jirametrics/chart_base.rb
|
76
76
|
- lib/jirametrics/columns_config.rb
|
77
|
+
- lib/jirametrics/css_variable.rb
|
77
78
|
- lib/jirametrics/cycletime_config.rb
|
78
79
|
- lib/jirametrics/cycletime_histogram.rb
|
79
80
|
- lib/jirametrics/cycletime_scatterplot.rb
|
@@ -107,6 +108,7 @@ files:
|
|
107
108
|
- lib/jirametrics/html/data_quality_report.erb
|
108
109
|
- lib/jirametrics/html/expedited_chart.erb
|
109
110
|
- lib/jirametrics/html/hierarchy_table.erb
|
111
|
+
- lib/jirametrics/html/index.css
|
110
112
|
- lib/jirametrics/html/index.erb
|
111
113
|
- lib/jirametrics/html/sprint_burndown.erb
|
112
114
|
- lib/jirametrics/html/story_point_accuracy_chart.erb
|
@@ -118,6 +120,7 @@ files:
|
|
118
120
|
- lib/jirametrics/project_config.rb
|
119
121
|
- lib/jirametrics/rules.rb
|
120
122
|
- lib/jirametrics/self_or_issue_dispatcher.rb
|
123
|
+
- lib/jirametrics/settings.json
|
121
124
|
- lib/jirametrics/sprint.rb
|
122
125
|
- lib/jirametrics/sprint_burndown.rb
|
123
126
|
- lib/jirametrics/sprint_issue_change_data.rb
|
@@ -151,7 +154,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
151
154
|
- !ruby/object:Gem::Version
|
152
155
|
version: '0'
|
153
156
|
requirements: []
|
154
|
-
rubygems_version: 3.5.
|
157
|
+
rubygems_version: 3.5.10
|
155
158
|
signing_key:
|
156
159
|
specification_version: 4
|
157
160
|
summary: Extract Jira metrics
|