jirametrics 1.0.0
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 +7 -0
- data/bin/jirametrics +4 -0
- data/lib/jirametrics/aggregate_config.rb +89 -0
- data/lib/jirametrics/aging_work_bar_chart.rb +235 -0
- data/lib/jirametrics/aging_work_in_progress_chart.rb +148 -0
- data/lib/jirametrics/aging_work_table.rb +149 -0
- data/lib/jirametrics/anonymizer.rb +186 -0
- data/lib/jirametrics/blocked_stalled_change.rb +43 -0
- data/lib/jirametrics/board.rb +85 -0
- data/lib/jirametrics/board_column.rb +14 -0
- data/lib/jirametrics/board_config.rb +31 -0
- data/lib/jirametrics/change_item.rb +80 -0
- data/lib/jirametrics/chart_base.rb +239 -0
- data/lib/jirametrics/columns_config.rb +42 -0
- data/lib/jirametrics/cycletime_config.rb +69 -0
- data/lib/jirametrics/cycletime_histogram.rb +74 -0
- data/lib/jirametrics/cycletime_scatterplot.rb +128 -0
- data/lib/jirametrics/daily_wip_by_age_chart.rb +88 -0
- data/lib/jirametrics/daily_wip_by_blocked_stalled_chart.rb +77 -0
- data/lib/jirametrics/daily_wip_chart.rb +123 -0
- data/lib/jirametrics/data_quality_report.rb +278 -0
- data/lib/jirametrics/dependency_chart.rb +217 -0
- data/lib/jirametrics/discard_changes_before.rb +37 -0
- data/lib/jirametrics/download_config.rb +41 -0
- data/lib/jirametrics/downloader.rb +337 -0
- data/lib/jirametrics/examples/aggregated_project.rb +36 -0
- data/lib/jirametrics/examples/standard_project.rb +111 -0
- data/lib/jirametrics/expedited_chart.rb +169 -0
- data/lib/jirametrics/experimental/generator.rb +209 -0
- data/lib/jirametrics/experimental/info.rb +77 -0
- data/lib/jirametrics/exporter.rb +127 -0
- data/lib/jirametrics/file_config.rb +119 -0
- data/lib/jirametrics/fix_version.rb +21 -0
- data/lib/jirametrics/groupable_issue_chart.rb +44 -0
- data/lib/jirametrics/grouping_rules.rb +13 -0
- data/lib/jirametrics/hierarchy_table.rb +31 -0
- data/lib/jirametrics/html/aging_work_bar_chart.erb +72 -0
- data/lib/jirametrics/html/aging_work_in_progress_chart.erb +52 -0
- data/lib/jirametrics/html/aging_work_table.erb +60 -0
- data/lib/jirametrics/html/collapsible_issues_panel.erb +32 -0
- data/lib/jirametrics/html/cycletime_histogram.erb +41 -0
- data/lib/jirametrics/html/cycletime_scatterplot.erb +103 -0
- data/lib/jirametrics/html/daily_wip_chart.erb +63 -0
- data/lib/jirametrics/html/data_quality_report.erb +126 -0
- data/lib/jirametrics/html/expedited_chart.erb +67 -0
- data/lib/jirametrics/html/hierarchy_table.erb +29 -0
- data/lib/jirametrics/html/index.erb +66 -0
- data/lib/jirametrics/html/sprint_burndown.erb +116 -0
- data/lib/jirametrics/html/story_point_accuracy_chart.erb +57 -0
- data/lib/jirametrics/html/throughput_chart.erb +65 -0
- data/lib/jirametrics/html_report_config.rb +217 -0
- data/lib/jirametrics/issue.rb +521 -0
- data/lib/jirametrics/issue_link.rb +60 -0
- data/lib/jirametrics/json_file_loader.rb +9 -0
- data/lib/jirametrics/project_config.rb +442 -0
- data/lib/jirametrics/rules.rb +34 -0
- data/lib/jirametrics/self_or_issue_dispatcher.rb +15 -0
- data/lib/jirametrics/sprint.rb +43 -0
- data/lib/jirametrics/sprint_burndown.rb +335 -0
- data/lib/jirametrics/sprint_issue_change_data.rb +31 -0
- data/lib/jirametrics/status.rb +26 -0
- data/lib/jirametrics/status_collection.rb +67 -0
- data/lib/jirametrics/story_point_accuracy_chart.rb +139 -0
- data/lib/jirametrics/throughput_chart.rb +91 -0
- data/lib/jirametrics/tree_organizer.rb +96 -0
- data/lib/jirametrics/trend_line_calculator.rb +74 -0
- data/lib/jirametrics.rb +85 -0
- metadata +167 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<meta charset="UTF-8">
|
4
|
+
<script src="https://cdn.jsdelivr.net/npm/moment@2.29.1/moment.js"></script>
|
5
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
6
|
+
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment@^1"></script>
|
7
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-annotation/1.2.2/chartjs-plugin-annotation.min.js" integrity="sha512-HycvvBSFvDEVyJ0tjE2rPmymkt6XqsP/Zo96XgLRjXwn6SecQqsn+6V/7KYev66OshZZ9+f9AttCGmYqmzytiw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
8
|
+
<script type="text/javascript">
|
9
|
+
function expand_collapse(link_id, issues_id) {
|
10
|
+
link_text = document.getElementById(link_id).textContent
|
11
|
+
if( link_text == 'Show details') {
|
12
|
+
document.getElementById(link_id).textContent = 'Hide details'
|
13
|
+
document.getElementById(issues_id).style.display = 'block'
|
14
|
+
}
|
15
|
+
else {
|
16
|
+
document.getElementById(link_id).textContent = 'Show details'
|
17
|
+
document.getElementById(issues_id).style.display = 'none'
|
18
|
+
}
|
19
|
+
}
|
20
|
+
</script>
|
21
|
+
<style>
|
22
|
+
h1 {
|
23
|
+
border: 1px solid black;
|
24
|
+
background: lightgray;
|
25
|
+
padding-left: 0.2em;
|
26
|
+
}
|
27
|
+
dl, dd, dt {
|
28
|
+
padding: 0;
|
29
|
+
margin: 0;
|
30
|
+
}
|
31
|
+
dd {
|
32
|
+
margin-bottom: 0.4em;
|
33
|
+
}
|
34
|
+
span.highlight {
|
35
|
+
background: #FDD5B1;
|
36
|
+
}
|
37
|
+
a.issue_key {
|
38
|
+
white-space: nowrap;
|
39
|
+
}
|
40
|
+
table.standard thead tr th {
|
41
|
+
border-bottom: 1px solid gray;
|
42
|
+
position: sticky;
|
43
|
+
top: 0;
|
44
|
+
background: white;
|
45
|
+
}
|
46
|
+
table.standard tbody tr td {
|
47
|
+
padding-left: 0.5em;
|
48
|
+
padding-right: 0.5em;
|
49
|
+
vertical-align: top;
|
50
|
+
}
|
51
|
+
table.standard tbody tr:nth-child(odd){
|
52
|
+
background-color: #eee;
|
53
|
+
}
|
54
|
+
.quality_note_bullet {
|
55
|
+
color: red;
|
56
|
+
}
|
57
|
+
</style>
|
58
|
+
</head>
|
59
|
+
<body>
|
60
|
+
<div>
|
61
|
+
Page generated <%= (timezone_offset.nil? ? DateTime.now : DateTime.now.new_offset(timezone_offset)).strftime('%Y-%b-%d at %I:%M:%S%P') %>
|
62
|
+
</div>
|
63
|
+
<%= "\n" + @sections.collect { |text, type| text if type == :header }.compact.join("\n\n") %>
|
64
|
+
<%= "\n" + @sections.collect { |text, type| text if type == :body }.compact.join("\n\n") %>
|
65
|
+
</body>
|
66
|
+
</html>
|
@@ -0,0 +1,116 @@
|
|
1
|
+
<h2>Burndown by <%= y_axis_title %></h2>
|
2
|
+
|
3
|
+
<div>
|
4
|
+
<canvas id="<%= chart_id %>" width="<%= canvas_width %>" height="<%= canvas_height %>"></canvas>
|
5
|
+
</div>
|
6
|
+
<script>
|
7
|
+
new Chart(document.getElementById('<%= chart_id %>').getContext('2d'), {
|
8
|
+
type: 'scatter',
|
9
|
+
data: {
|
10
|
+
datasets: <%= JSON.generate(data_sets) %>
|
11
|
+
},
|
12
|
+
options: {
|
13
|
+
title: {
|
14
|
+
display: true,
|
15
|
+
text: "Sprint Burndown"
|
16
|
+
},
|
17
|
+
responsive: <%= canvas_responsive? %>, // If responsive is true then it fills the screen
|
18
|
+
scales: {
|
19
|
+
x: {
|
20
|
+
type: "time",
|
21
|
+
time: {
|
22
|
+
format: 'YYYY-MM-DD'
|
23
|
+
},
|
24
|
+
scaleLabel: {
|
25
|
+
display: true,
|
26
|
+
labelString: 'Date'
|
27
|
+
},
|
28
|
+
min: "<%= date_range.begin.to_s %>",
|
29
|
+
max: "<%= (date_range.end + 1).to_s %>"
|
30
|
+
|
31
|
+
},
|
32
|
+
y: {
|
33
|
+
scaleLabel: {
|
34
|
+
display: true,
|
35
|
+
labelString: 'Items remaining'
|
36
|
+
},
|
37
|
+
title: {
|
38
|
+
display: true,
|
39
|
+
text: "<%= y_axis_title %>"
|
40
|
+
},
|
41
|
+
min: 0.0
|
42
|
+
}
|
43
|
+
},
|
44
|
+
plugins: {
|
45
|
+
tooltip: {
|
46
|
+
callbacks: {
|
47
|
+
label: function(context) {
|
48
|
+
return context.dataset.data[context.dataIndex].title
|
49
|
+
}
|
50
|
+
}
|
51
|
+
},
|
52
|
+
annotation: {
|
53
|
+
annotations: {
|
54
|
+
<% holidays().each_with_index do |range, index| %>
|
55
|
+
holiday<%= index %>: {
|
56
|
+
drawTime: 'beforeDraw',
|
57
|
+
type: 'box',
|
58
|
+
xMin: '<%= range.begin %>T00:00:00',
|
59
|
+
xMax: '<%= range.end %>T23:59:59',
|
60
|
+
backgroundColor: '#F0F0F0',
|
61
|
+
borderColor: '#F0F0F0'
|
62
|
+
},
|
63
|
+
<% end %>
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
67
|
+
}
|
68
|
+
});
|
69
|
+
</script>
|
70
|
+
|
71
|
+
<%
|
72
|
+
link_id = next_id
|
73
|
+
issues_id = next_id
|
74
|
+
%>
|
75
|
+
[<a id='<%= link_id %>' href="#" onclick='expand_collapse("<%= link_id %>", "<%= issues_id %>"); return false;'>Show details</a>]
|
76
|
+
<div id="<%= issues_id %>" style="display: none;">
|
77
|
+
<table class='standard' style="margin-left: 1em;">
|
78
|
+
<thead>
|
79
|
+
<th>Sprint</th>
|
80
|
+
<th>State</th>
|
81
|
+
<th>Started</th>
|
82
|
+
<th>Completed</th>
|
83
|
+
<th>Added</th>
|
84
|
+
<th>Removed</th>
|
85
|
+
<th>Remaining</th>
|
86
|
+
<th>Note</th>
|
87
|
+
</thead>
|
88
|
+
<tbody>
|
89
|
+
<% @summary_stats.keys.sort_by(&:start_time).each do |sprint| %>
|
90
|
+
<tr>
|
91
|
+
<td><%= sprint.name %></td>
|
92
|
+
<td><%= sprint.raw['state'] %></td>
|
93
|
+
<% stats = @summary_stats[sprint] %>
|
94
|
+
<td><%= stats.started %></td>
|
95
|
+
<td><%= stats.completed %></td>
|
96
|
+
<td><%= stats.added %></td>
|
97
|
+
<td><%= stats.removed %></td>
|
98
|
+
<td><%= stats.remaining %></td>
|
99
|
+
<td>
|
100
|
+
<% if stats.points_values_changed %>
|
101
|
+
Points values changed mid-sprint. Numbers may not add up
|
102
|
+
<% end %>
|
103
|
+
</td>
|
104
|
+
</tr>
|
105
|
+
<% end %>
|
106
|
+
</tbody>
|
107
|
+
</table>
|
108
|
+
|
109
|
+
<p>Legend:
|
110
|
+
<ul>
|
111
|
+
<% legend.each do |line| %>
|
112
|
+
<li><%= line %></li>
|
113
|
+
<% end %>
|
114
|
+
</ul>
|
115
|
+
</p>
|
116
|
+
</div>
|
@@ -0,0 +1,57 @@
|
|
1
|
+
<div>
|
2
|
+
<canvas id="<%= chart_id %>" width="<%= canvas_width %>" height="<%= canvas_height %>"></canvas>
|
3
|
+
</div>
|
4
|
+
<script>
|
5
|
+
new Chart(document.getElementById('<%= chart_id %>').getContext('2d'), {
|
6
|
+
type: 'bubble',
|
7
|
+
data: {
|
8
|
+
datasets: <%= JSON.generate(data_sets) %>
|
9
|
+
},
|
10
|
+
options: {
|
11
|
+
title: {
|
12
|
+
display: true,
|
13
|
+
text: "Sprint Burndown"
|
14
|
+
},
|
15
|
+
responsive: <%= canvas_responsive? %>, // If responsive is true then it fills the screen
|
16
|
+
scales: {
|
17
|
+
x: {
|
18
|
+
type: "linear",
|
19
|
+
scaleLabel: {
|
20
|
+
display: true,
|
21
|
+
labelString: 'Date'
|
22
|
+
},
|
23
|
+
title: {
|
24
|
+
display: true,
|
25
|
+
text: "Cycletime (days)"
|
26
|
+
},
|
27
|
+
min: 0
|
28
|
+
|
29
|
+
},
|
30
|
+
y: {
|
31
|
+
type: "<%= @y_axis_type %>",
|
32
|
+
<% if @y_axis_sort_order %>
|
33
|
+
labels: ["","<%= @y_axis_sort_order.reverse.join('","')%>",""],
|
34
|
+
<% end %>
|
35
|
+
scaleLabel: {
|
36
|
+
display: true,
|
37
|
+
labelString: 'Items remaining'
|
38
|
+
},
|
39
|
+
title: {
|
40
|
+
display: true,
|
41
|
+
text: "<%= @y_axis_label %>"
|
42
|
+
},
|
43
|
+
min: 0.0
|
44
|
+
}
|
45
|
+
},
|
46
|
+
plugins: {
|
47
|
+
tooltip: {
|
48
|
+
callbacks: {
|
49
|
+
label: function(context) {
|
50
|
+
return context.dataset.data[context.dataIndex].title
|
51
|
+
}
|
52
|
+
}
|
53
|
+
},
|
54
|
+
}
|
55
|
+
}
|
56
|
+
});
|
57
|
+
</script>
|
@@ -0,0 +1,65 @@
|
|
1
|
+
|
2
|
+
<div>
|
3
|
+
<canvas id="<%= chart_id %>" width="<%= canvas_width %>" height="<%= canvas_height %>"></canvas>
|
4
|
+
</div>
|
5
|
+
<script>
|
6
|
+
new Chart(document.getElementById('<%= chart_id %>').getContext('2d'), {
|
7
|
+
type: 'scatter',
|
8
|
+
data: {
|
9
|
+
datasets: <%= JSON.generate(data_sets) %>
|
10
|
+
},
|
11
|
+
options: {
|
12
|
+
title: {
|
13
|
+
display: true,
|
14
|
+
text: "Throughput Chart"
|
15
|
+
},
|
16
|
+
responsive: <%= canvas_responsive? %>, // If responsive is true then it fills the screen
|
17
|
+
scales: {
|
18
|
+
x: {
|
19
|
+
type: "time",
|
20
|
+
time: {
|
21
|
+
format: 'YYYY-MM-DD'
|
22
|
+
},
|
23
|
+
scaleLabel: {
|
24
|
+
display: true,
|
25
|
+
labelString: 'Date Completed'
|
26
|
+
}
|
27
|
+
},
|
28
|
+
y: {
|
29
|
+
scaleLabel: {
|
30
|
+
display: true,
|
31
|
+
},
|
32
|
+
title: {
|
33
|
+
display: true,
|
34
|
+
text: 'Count of items'
|
35
|
+
},
|
36
|
+
min: 0
|
37
|
+
},
|
38
|
+
},
|
39
|
+
plugins: {
|
40
|
+
tooltip: {
|
41
|
+
callbacks: {
|
42
|
+
label: function(context) {
|
43
|
+
return context.dataset.data[context.dataIndex].title
|
44
|
+
}
|
45
|
+
}
|
46
|
+
},
|
47
|
+
annotation: {
|
48
|
+
annotations: {
|
49
|
+
<% holidays.each_with_index do |range, index| %>
|
50
|
+
holiday<%= index %>: {
|
51
|
+
drawTime: 'beforeDraw',
|
52
|
+
type: 'box',
|
53
|
+
xMin: '<%= range.begin %>T00:00:00',
|
54
|
+
xMax: '<%= range.end %>T23:59:59',
|
55
|
+
backgroundColor: '#F0F0F0',
|
56
|
+
borderColor: '#F0F0F0'
|
57
|
+
},
|
58
|
+
<% end %>
|
59
|
+
}
|
60
|
+
}
|
61
|
+
}
|
62
|
+
}
|
63
|
+
});
|
64
|
+
</script>
|
65
|
+
|
@@ -0,0 +1,217 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'erb'
|
4
|
+
require 'jirametrics/self_or_issue_dispatcher'
|
5
|
+
|
6
|
+
class HtmlReportConfig
|
7
|
+
include SelfOrIssueDispatcher
|
8
|
+
include DiscardChangesBefore
|
9
|
+
|
10
|
+
attr_reader :file_config, :sections
|
11
|
+
|
12
|
+
def initialize file_config:, block:
|
13
|
+
@file_config = file_config
|
14
|
+
@block = block
|
15
|
+
# @cycletimes = []
|
16
|
+
@sections = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def cycletime label = nil, &block
|
20
|
+
# TODO: This is about to become deprecated
|
21
|
+
|
22
|
+
@file_config.project_config.all_boards.each do |_id, board|
|
23
|
+
raise 'Multiple cycletimes not supported yet' if board.cycletime
|
24
|
+
|
25
|
+
board.cycletime = CycleTimeConfig.new(parent_config: self, label: label, block: block)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def run
|
30
|
+
instance_eval(&@block)
|
31
|
+
|
32
|
+
# The quality report has to be generated last because otherwise cycletime won't have been
|
33
|
+
# set. Then we have to rotate it to the first position so it's at the top of the report.
|
34
|
+
execute_chart DataQualityReport.new(@original_issue_times || {})
|
35
|
+
@sections.rotate!(-1)
|
36
|
+
|
37
|
+
File.open @file_config.output_filename, 'w' do |file|
|
38
|
+
html_directory = "#{Pathname.new(File.realpath(__FILE__)).dirname}/html"
|
39
|
+
erb = ERB.new File.read("#{html_directory}/index.erb")
|
40
|
+
file.puts erb.result(binding)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def board_id id = nil
|
45
|
+
@board_id = id unless id.nil?
|
46
|
+
@board_id
|
47
|
+
end
|
48
|
+
|
49
|
+
def timezone_offset
|
50
|
+
@file_config.project_config.exporter.timezone_offset
|
51
|
+
end
|
52
|
+
|
53
|
+
def aging_work_in_progress_chart board_id: nil, &block
|
54
|
+
if board_id.nil?
|
55
|
+
ids = issues.collect { |i| i.board.id }.uniq.sort
|
56
|
+
else
|
57
|
+
ids = [board_id]
|
58
|
+
end
|
59
|
+
|
60
|
+
ids.each do |id|
|
61
|
+
execute_chart(AgingWorkInProgressChart.new(block)) do |chart|
|
62
|
+
chart.board_id = id
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def aging_work_bar_chart &block
|
68
|
+
execute_chart AgingWorkBarChart.new(block)
|
69
|
+
end
|
70
|
+
|
71
|
+
def aging_work_table priority_name = nil, &block
|
72
|
+
if priority_name
|
73
|
+
deprecated message: 'priority name should no longer be passed into the chart. Specify it in the ' \
|
74
|
+
'board declaration. See https://github.com/mikebowler/jira-export/wiki/Deprecated',
|
75
|
+
date: '2022-12-26'
|
76
|
+
end
|
77
|
+
execute_chart AgingWorkTable.new(block)
|
78
|
+
end
|
79
|
+
|
80
|
+
def cycletime_scatterplot &block
|
81
|
+
execute_chart CycletimeScatterplot.new block
|
82
|
+
end
|
83
|
+
|
84
|
+
def total_wip_over_time_chart &block
|
85
|
+
puts 'Deprecated(total_wip_over_time_chart). Use daily_wip_by_age_chart instead.'
|
86
|
+
execute_chart DailyWipByAgeChart.new block
|
87
|
+
end
|
88
|
+
|
89
|
+
def daily_wip_chart &block
|
90
|
+
execute_chart DailyWipChart.new(block)
|
91
|
+
end
|
92
|
+
|
93
|
+
def daily_wip_by_age_chart &block
|
94
|
+
execute_chart DailyWipByAgeChart.new block
|
95
|
+
end
|
96
|
+
|
97
|
+
def daily_wip_by_type &block
|
98
|
+
execute_chart DailyWipChart.new block
|
99
|
+
end
|
100
|
+
|
101
|
+
def daily_wip_by_blocked_stalled_chart
|
102
|
+
execute_chart DailyWipByBlockedStalledChart.new
|
103
|
+
end
|
104
|
+
|
105
|
+
def throughput_chart &block
|
106
|
+
execute_chart ThroughputChart.new(block)
|
107
|
+
end
|
108
|
+
|
109
|
+
def blocked_stalled_chart
|
110
|
+
puts 'Deprecated(blocked_stalled_chart). Use daily_wip_by_blocked_stalled_chart instead.'
|
111
|
+
execute_chart DailyWipByBlockedStalledChart.new
|
112
|
+
end
|
113
|
+
|
114
|
+
def expedited_chart priority_name = nil
|
115
|
+
if priority_name
|
116
|
+
deprecated message: 'priority name should no longer be passed into the chart. Specify it in the ' \
|
117
|
+
'board declaration. See https://github.com/mikebowler/jira-export/wiki/Deprecated',
|
118
|
+
date: '2022-12-26'
|
119
|
+
end
|
120
|
+
execute_chart ExpeditedChart.new
|
121
|
+
end
|
122
|
+
|
123
|
+
def cycletime_histogram &block
|
124
|
+
execute_chart CycletimeHistogram.new block
|
125
|
+
end
|
126
|
+
|
127
|
+
def random_color
|
128
|
+
"\##{Random.bytes(3).unpack1('H*')}"
|
129
|
+
end
|
130
|
+
|
131
|
+
def html string, type: :body
|
132
|
+
raise "Unexpected type: #{type}" unless [:body, :header].include? type
|
133
|
+
|
134
|
+
@sections << [string, type]
|
135
|
+
end
|
136
|
+
|
137
|
+
def sprint_burndown options = :points_and_counts
|
138
|
+
execute_chart SprintBurndown.new do |chart|
|
139
|
+
chart.options = options
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def story_point_accuracy_chart &block
|
144
|
+
execute_chart StoryPointAccuracyChart.new block
|
145
|
+
end
|
146
|
+
|
147
|
+
def hierarchy_table &block
|
148
|
+
execute_chart HierarchyTable.new block
|
149
|
+
end
|
150
|
+
|
151
|
+
def discard_changes_before_hook issues_cutoff_times
|
152
|
+
# raise 'Cycletime must be defined before using discard_changes_before' unless @cycletime
|
153
|
+
|
154
|
+
@original_issue_times = {}
|
155
|
+
issues_cutoff_times.each do |issue, cutoff_time|
|
156
|
+
started = issue.board.cycletime.started_time(issue)
|
157
|
+
if started && started <= cutoff_time
|
158
|
+
# We only need to log this if data was discarded
|
159
|
+
@original_issue_times[issue] = { cutoff_time: cutoff_time, started_time: started }
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def discarded_changes_report
|
165
|
+
puts 'Deprecated(discarded_changes_report) No need to specify this anymore as this information is ' \
|
166
|
+
'now included in the data quality checks.'
|
167
|
+
end
|
168
|
+
|
169
|
+
def dependency_chart &block
|
170
|
+
execute_chart DependencyChart.new block
|
171
|
+
end
|
172
|
+
|
173
|
+
def execute_chart chart, &after_init_block
|
174
|
+
project_config = @file_config.project_config
|
175
|
+
|
176
|
+
chart.issues = issues
|
177
|
+
chart.time_range = project_config.time_range
|
178
|
+
chart.timezone_offset = timezone_offset
|
179
|
+
chart.settings = project_config.settings
|
180
|
+
|
181
|
+
chart.all_boards = project_config.all_boards
|
182
|
+
chart.board_id = find_board_id if chart.respond_to? :board_id=
|
183
|
+
chart.holiday_dates = project_config.exporter.holiday_dates
|
184
|
+
|
185
|
+
time_range = @file_config.project_config.time_range
|
186
|
+
chart.date_range = time_range.begin.to_date..time_range.end.to_date
|
187
|
+
chart.aggregated_project = project_config.aggregated_project?
|
188
|
+
|
189
|
+
after_init_block&.call chart
|
190
|
+
|
191
|
+
html chart.run
|
192
|
+
end
|
193
|
+
|
194
|
+
def find_board_id
|
195
|
+
@board_id || @file_config.project_config.guess_board_id
|
196
|
+
end
|
197
|
+
|
198
|
+
def issues
|
199
|
+
@file_config.issues
|
200
|
+
end
|
201
|
+
|
202
|
+
def find_board id
|
203
|
+
@file_config.project_config.all_boards[id]
|
204
|
+
end
|
205
|
+
|
206
|
+
def project_name
|
207
|
+
@file_config.project_config.name
|
208
|
+
end
|
209
|
+
|
210
|
+
def boards
|
211
|
+
@file_config.project_config.board_configs.collect(&:id).collect { |id| find_board id }
|
212
|
+
end
|
213
|
+
|
214
|
+
def find_project_by_name name
|
215
|
+
@file_config.project_config.exporter.project_configs.find { |p| p.name == name }
|
216
|
+
end
|
217
|
+
end
|