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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/lib/jirametrics/aging_work_bar_chart.rb +17 -9
  3. data/lib/jirametrics/aging_work_in_progress_chart.rb +8 -6
  4. data/lib/jirametrics/aging_work_table.rb +8 -15
  5. data/lib/jirametrics/anonymizer.rb +6 -5
  6. data/lib/jirametrics/chart_base.rb +19 -17
  7. data/lib/jirametrics/css_variable.rb +33 -0
  8. data/lib/jirametrics/cycletime_scatterplot.rb +9 -7
  9. data/lib/jirametrics/daily_wip_by_age_chart.rb +9 -9
  10. data/lib/jirametrics/daily_wip_by_blocked_stalled_chart.rb +22 -14
  11. data/lib/jirametrics/daily_wip_chart.rb +2 -2
  12. data/lib/jirametrics/dependency_chart.rb +18 -14
  13. data/lib/jirametrics/downloader.rb +6 -7
  14. data/lib/jirametrics/examples/aggregated_project.rb +3 -1
  15. data/lib/jirametrics/examples/standard_project.rb +10 -4
  16. data/lib/jirametrics/expedited_chart.rb +5 -2
  17. data/lib/jirametrics/exporter.rb +26 -20
  18. data/lib/jirametrics/grouping_rules.rb +7 -1
  19. data/lib/jirametrics/html/aging_work_bar_chart.erb +12 -6
  20. data/lib/jirametrics/html/aging_work_in_progress_chart.erb +8 -2
  21. data/lib/jirametrics/html/aging_work_table.erb +1 -1
  22. data/lib/jirametrics/html/cycletime_histogram.erb +9 -3
  23. data/lib/jirametrics/html/cycletime_scatterplot.erb +10 -4
  24. data/lib/jirametrics/html/daily_wip_chart.erb +10 -5
  25. data/lib/jirametrics/html/expedited_chart.erb +11 -5
  26. data/lib/jirametrics/html/hierarchy_table.erb +1 -1
  27. data/lib/jirametrics/html/index.css +174 -0
  28. data/lib/jirametrics/html/index.erb +8 -36
  29. data/lib/jirametrics/html/sprint_burndown.erb +11 -6
  30. data/lib/jirametrics/html/story_point_accuracy_chart.erb +9 -4
  31. data/lib/jirametrics/html/throughput_chart.erb +11 -5
  32. data/lib/jirametrics/html_report_config.rb +17 -2
  33. data/lib/jirametrics/issue.rb +3 -2
  34. data/lib/jirametrics/jira_gateway.rb +1 -1
  35. data/lib/jirametrics/project_config.rb +13 -18
  36. data/lib/jirametrics/settings.json +7 -0
  37. data/lib/jirametrics/sprint_burndown.rb +2 -2
  38. data/lib/jirametrics/status_collection.rb +1 -1
  39. data/lib/jirametrics/story_point_accuracy_chart.rb +8 -4
  40. data/lib/jirametrics/throughput_chart.rb +4 -1
  41. data/lib/jirametrics.rb +1 -0
  42. 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: '#F0F0F0',
56
- borderColor: '#F0F0F0'
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
- erb = ERB.new File.read("#{html_directory}/index.erb")
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 = project_config.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=
@@ -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 => e
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['stalled_threshold']
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 "Must specify URL in config" if @jira_url.nil?
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, :id
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
- string = "#{string}T00:00:00#{@timezone_offset}" if string.match?(/^\d{4}-\d{2}\d{2}$/)
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
- puts message
434
+ exporter.file_system.log message
440
435
  end
441
- puts "Discarded data from #{issues_cutoff_times.count} issues out of a total #{issues.size}"
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
@@ -0,0 +1,7 @@
1
+ {
2
+ "stalled_threshold_days": 5,
3
+ "stalled_statuses": [],
4
+
5
+ "blocked_link_text": [],
6
+ "blocked_statuses": []
7
+ }
@@ -57,7 +57,7 @@ class SprintBurndown < ChartBase
57
57
  result = +''
58
58
  result << '<h1>Sprint Burndowns</h1>'
59
59
 
60
- possible_colours = %w[blue orange green red brown]
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 % 5]
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 (if you turn them on) show the current
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', '#66FF99', 'green', false],
60
- [aging_hash, 'Still in progress', '#FFCCCB', 'red', true]
61
- ].filter_map do |hash, label, fill_color, border_color, starts_hidden|
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, label: 'Totals', color: 'gray', dashed: true
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.0.1
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-04-23 00:00:00.000000000 Z
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.7
157
+ rubygems_version: 3.5.10
155
158
  signing_key:
156
159
  specification_version: 4
157
160
  summary: Extract Jira metrics