jirametrics 2.0.1 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
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