jirametrics 2.0.1 → 2.2.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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/lib/jirametrics/aggregate_config.rb +1 -1
  3. data/lib/jirametrics/aging_work_bar_chart.rb +18 -13
  4. data/lib/jirametrics/aging_work_in_progress_chart.rb +8 -6
  5. data/lib/jirametrics/aging_work_table.rb +21 -16
  6. data/lib/jirametrics/anonymizer.rb +6 -5
  7. data/lib/jirametrics/chart_base.rb +35 -19
  8. data/lib/jirametrics/css_variable.rb +33 -0
  9. data/lib/jirametrics/cycletime_scatterplot.rb +8 -9
  10. data/lib/jirametrics/daily_wip_by_age_chart.rb +43 -17
  11. data/lib/jirametrics/daily_wip_by_blocked_stalled_chart.rb +32 -17
  12. data/lib/jirametrics/daily_wip_by_parent_chart.rb +42 -0
  13. data/lib/jirametrics/daily_wip_chart.rb +67 -6
  14. data/lib/jirametrics/data_quality_report.rb +1 -1
  15. data/lib/jirametrics/dependency_chart.rb +18 -14
  16. data/lib/jirametrics/downloader.rb +13 -11
  17. data/lib/jirametrics/examples/aggregated_project.rb +17 -20
  18. data/lib/jirametrics/examples/standard_project.rb +10 -18
  19. data/lib/jirametrics/expedited_chart.rb +17 -15
  20. data/lib/jirametrics/exporter.rb +26 -20
  21. data/lib/jirametrics/grouping_rules.rb +7 -1
  22. data/lib/jirametrics/html/aging_work_bar_chart.erb +12 -6
  23. data/lib/jirametrics/html/aging_work_in_progress_chart.erb +8 -2
  24. data/lib/jirametrics/html/aging_work_table.erb +11 -19
  25. data/lib/jirametrics/html/cycletime_histogram.erb +9 -3
  26. data/lib/jirametrics/html/cycletime_scatterplot.erb +10 -4
  27. data/lib/jirametrics/html/daily_wip_chart.erb +18 -5
  28. data/lib/jirametrics/html/expedited_chart.erb +11 -5
  29. data/lib/jirametrics/html/hierarchy_table.erb +1 -1
  30. data/lib/jirametrics/html/index.css +186 -0
  31. data/lib/jirametrics/html/index.erb +8 -36
  32. data/lib/jirametrics/html/sprint_burndown.erb +11 -6
  33. data/lib/jirametrics/html/story_point_accuracy_chart.erb +9 -4
  34. data/lib/jirametrics/html/throughput_chart.erb +11 -5
  35. data/lib/jirametrics/html_report_config.rb +28 -3
  36. data/lib/jirametrics/issue.rb +5 -3
  37. data/lib/jirametrics/jira_gateway.rb +5 -2
  38. data/lib/jirametrics/project_config.rb +14 -19
  39. data/lib/jirametrics/settings.json +7 -0
  40. data/lib/jirametrics/sprint_burndown.rb +10 -4
  41. data/lib/jirametrics/status_collection.rb +1 -1
  42. data/lib/jirametrics/story_point_accuracy_chart.rb +20 -10
  43. data/lib/jirametrics/throughput_chart.rb +10 -2
  44. data/lib/jirametrics.rb +2 -0
  45. metadata +7 -3
@@ -13,7 +13,10 @@ class JiraGateway
13
13
 
14
14
  def call_url relative_url:
15
15
  command = make_curl_command url: "#{@jira_url}#{relative_url}"
16
- JSON.parse call_command command
16
+ result = call_command command
17
+ JSON.parse result
18
+ rescue => e # rubocop:disable Style/RescueStandardError
19
+ puts "Error #{e.inspect} when parsing result: #{result.inspect}"
17
20
  end
18
21
 
19
22
  def call_command command
@@ -29,7 +32,7 @@ class JiraGateway
29
32
 
30
33
  def load_jira_config jira_config
31
34
  @jira_url = jira_config['url']
32
- raise "Must specify URL in config" if @jira_url.nil?
35
+ raise 'Must specify URL in config' if @jira_url.nil?
33
36
 
34
37
  @jira_email = jira_config['email']
35
38
  @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, :aggregate_config
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
 
@@ -121,7 +115,7 @@ class ProjectConfig
121
115
  board_id = $1.to_i
122
116
  load_board board_id: board_id, filename: "#{@target_path}#{file}"
123
117
  end
124
- raise "No boards found in #{@target_path.inspect}" if @all_boards.empty?
118
+ raise "No boards found for #{@file_prefix} in #{@target_path.inspect}" if @all_boards.empty?
125
119
  end
126
120
 
127
121
  def load_board board_id:, filename:
@@ -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
+ }
@@ -22,7 +22,13 @@ class SprintBurndown < ChartBase
22
22
 
23
23
  @summary_stats = {}
24
24
  header_text 'Sprint burndown'
25
- description_text ''
25
+ description_text <<-TEXT
26
+ <div class="p">
27
+ Burndowns for all sprints in this time period. The different colours are only to
28
+ differentiate one sprint from another as they may overlap time periods.
29
+ </div>
30
+ #{describe_non_working_days}
31
+ TEXT
26
32
  end
27
33
 
28
34
  def options= arg
@@ -55,9 +61,9 @@ class SprintBurndown < ChartBase
55
61
  end
56
62
 
57
63
  result = +''
58
- result << '<h1>Sprint Burndowns</h1>'
64
+ result << render_top_text(binding)
59
65
 
60
- possible_colours = %w[blue orange green red brown]
66
+ possible_colours = (1..5).collect { |i| CssVariable["--sprint-burndown-sprint-color-#{i}"] }
61
67
  charts_to_generate = []
62
68
  charts_to_generate << [:data_set_by_story_points, 'Story Points'] if @use_story_points
63
69
  charts_to_generate << [:data_set_by_story_counts, 'Story Count'] if @use_story_counts
@@ -65,7 +71,7 @@ class SprintBurndown < ChartBase
65
71
  @summary_stats.clear
66
72
  data_sets = []
67
73
  sprints.each_with_index do |sprint, index|
68
- color = possible_colours[index % 5]
74
+ color = possible_colours[index % possible_colours.size]
69
75
  label = sprint.name
70
76
  data = send(data_method, sprint: sprint, change_data_for_sprint: change_data_by_sprint[sprint])
71
77
  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
 
@@ -6,15 +6,20 @@ class StoryPointAccuracyChart < ChartBase
6
6
 
7
7
  header_text 'Estimate Accuracy'
8
8
  description_text <<-HTML
9
- <p>
9
+ <div class="p">
10
10
  This chart graphs estimates against actual recorded cycle times. Since
11
11
  estimates can change over time, we're graphing the estimate at the time that the story started.
12
- </p>
13
- <p>
14
- The completed dots indicate cycletimes. The aging dots (if you turn them on) show the current
15
- age of items, which will give you a hint as to where they might end up. If they're already
16
- far to the right then you know you have a problem.
17
- </p>
12
+ </div>
13
+ <div class="p">
14
+ The #{color_block '--estimate-accuracy-chart-completed-fill-color'} completed dots indicate
15
+ cycletimes.
16
+ <% if @has_aging_data %>
17
+ The #{color_block '--estimate-accuracy-chart-active-fill-color'} aging dots
18
+ (click on the legend to turn them on) show the current
19
+ age of items, which will give you a hint as to where they might end up. If they're already
20
+ far to the right then you know you have a problem.
21
+ <% end %>
22
+ </div>
18
23
  HTML
19
24
 
20
25
  @y_axis_label = 'Story Point Estimates'
@@ -55,10 +60,15 @@ class StoryPointAccuracyChart < ChartBase
55
60
  (hash[key] ||= []) << issue
56
61
  end
57
62
 
63
+ @has_aging_data = !aging_hash.empty?
64
+
58
65
  [
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|
66
+ [completed_hash, 'Completed', 'completed', false],
67
+ [aging_hash, 'Still in progress', 'active', true]
68
+ ].filter_map do |hash, label, completed_or_active, starts_hidden|
69
+ fill_color = CssVariable["--estimate-accuracy-chart-#{completed_or_active}-fill-color"]
70
+ border_color = CssVariable["--estimate-accuracy-chart-#{completed_or_active}-border-color"]
71
+
62
72
  # We sort so that the smaller circles are in front of the bigger circles.
63
73
  data = hash.sort(&hash_sorter).collect do |key, values|
64
74
  estimate, cycle_time = *key
@@ -9,7 +9,12 @@ class ThroughputChart < ChartBase
9
9
  super()
10
10
 
11
11
  header_text 'Throughput Chart'
12
- description_text 'This chart shows how many items we completed per unit of time'
12
+ description_text <<-TEXT
13
+ <div class="p">
14
+ This chart shows how many items we completed per week
15
+ </div>
16
+ #{describe_non_working_days}
17
+ TEXT
13
18
 
14
19
  init_configuration_block(block) do
15
20
  grouping_rules do |issue, rule|
@@ -25,7 +30,10 @@ class ThroughputChart < ChartBase
25
30
  data_sets = []
26
31
  if rules_to_issues.size > 1
27
32
  data_sets << weekly_throughput_dataset(
28
- completed_issues: completed_issues, label: 'Totals', color: 'gray', dashed: true
33
+ completed_issues: completed_issues,
34
+ label: 'Totals',
35
+ color: CssVariable['--throughput_chart_total_line_color'],
36
+ dashed: true
29
37
  )
30
38
  end
31
39
 
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'
@@ -65,6 +66,7 @@ class JiraMetrics < Thor
65
66
  require 'jirametrics/sprint'
66
67
  require 'jirametrics/issue'
67
68
  require 'jirametrics/daily_wip_by_age_chart'
69
+ require 'jirametrics/daily_wip_by_parent_chart'
68
70
  require 'jirametrics/aging_work_in_progress_chart'
69
71
  require 'jirametrics/cycletime_scatterplot'
70
72
  require 'jirametrics/sprint_issue_change_data'
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.2.0
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-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: random-word
@@ -74,11 +74,13 @@ 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
80
81
  - lib/jirametrics/daily_wip_by_age_chart.rb
81
82
  - lib/jirametrics/daily_wip_by_blocked_stalled_chart.rb
83
+ - lib/jirametrics/daily_wip_by_parent_chart.rb
82
84
  - lib/jirametrics/daily_wip_chart.rb
83
85
  - lib/jirametrics/data_quality_report.rb
84
86
  - lib/jirametrics/dependency_chart.rb
@@ -107,6 +109,7 @@ files:
107
109
  - lib/jirametrics/html/data_quality_report.erb
108
110
  - lib/jirametrics/html/expedited_chart.erb
109
111
  - lib/jirametrics/html/hierarchy_table.erb
112
+ - lib/jirametrics/html/index.css
110
113
  - lib/jirametrics/html/index.erb
111
114
  - lib/jirametrics/html/sprint_burndown.erb
112
115
  - lib/jirametrics/html/story_point_accuracy_chart.erb
@@ -118,6 +121,7 @@ files:
118
121
  - lib/jirametrics/project_config.rb
119
122
  - lib/jirametrics/rules.rb
120
123
  - lib/jirametrics/self_or_issue_dispatcher.rb
124
+ - lib/jirametrics/settings.json
121
125
  - lib/jirametrics/sprint.rb
122
126
  - lib/jirametrics/sprint_burndown.rb
123
127
  - lib/jirametrics/sprint_issue_change_data.rb
@@ -151,7 +155,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
151
155
  - !ruby/object:Gem::Version
152
156
  version: '0'
153
157
  requirements: []
154
- rubygems_version: 3.5.7
158
+ rubygems_version: 3.5.10
155
159
  signing_key:
156
160
  specification_version: 4
157
161
  summary: Extract Jira metrics