Class: DevMetrics::MetricsCalc

Inherits:
Object
  • Object
show all
Defined in:
lib/dev_metrics/metrics_calc.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(prs, period, excluded_accounts:, rollback_branch_prefixes:) ⇒ MetricsCalc

Returns a new instance of MetricsCalc.



7
8
9
10
11
12
# File 'lib/dev_metrics/metrics_calc.rb', line 7

def initialize(prs, period, excluded_accounts:, rollback_branch_prefixes:)
  @prs = prs
  @period = period
  @excluded_accounts = excluded_accounts || []
  @rollback_branch_prefixes = rollback_branch_prefixes
end

Instance Attribute Details

#periodObject (readonly)

Returns the value of attribute period.



5
6
7
# File 'lib/dev_metrics/metrics_calc.rb', line 5

def period
  @period
end

Instance Method Details

#assignee_countsHash

Returns a hash with assignee names as keys and their counts as values.

Returns:

  • (Hash)

    Assignee counts.



134
135
136
# File 'lib/dev_metrics/metrics_calc.rb', line 134

def assignee_counts
  @prs.flat_map(&:assignees).compact.tally
end

#average_changed_fileFloat

Returns the average number of changed files per PR.

Returns:

  • (Float)

    Average number of changed files.



66
67
68
69
70
# File 'lib/dev_metrics/metrics_calc.rb', line 66

def average_changed_file
  return 0 if @prs.empty?
  files = @prs.map(&:changed_files)
  (files.sum.to_f / files.size).round(2)
end

#average_changed_line_sizeFloat

Returns the average PR size (additions + deletions).

Returns:

  • (Float)

    Average PR size.



57
58
59
60
61
# File 'lib/dev_metrics/metrics_calc.rb', line 57

def average_changed_line_size
  return 0 if @prs.empty?
  sizes = @prs.map { |pr| pr.additions + pr.deletions }
  (sizes.sum.to_f / sizes.size).round(2)
end

#average_commits_countFloat

Returns the average number of commits per PR.

Returns:

  • (Float)

    Average number of commits.



91
92
93
94
95
# File 'lib/dev_metrics/metrics_calc.rb', line 91

def average_commits_count
  return 0 if @prs.empty?
  counts = @prs.map(&:commits_count)
  (counts.sum.to_f / counts.size).round(2)
end

#average_pr_ageFloat

Returns the average PR age in days (from creation to close, or now if open).

Returns:

  • (Float)

    Average PR age in days.



148
149
150
151
152
153
154
155
156
# File 'lib/dev_metrics/metrics_calc.rb', line 148

def average_pr_age
  return 0 if @prs.empty?
  ages = @prs.map do |pr|
    closed = pr.closed_at || Time.now
    created = pr.created_at
    created && closed ? (closed - created) / 86400.0 : 0
  end
  (ages.sum / ages.size).round(2)
end

#average_review_requests_countFloat

Returns the average number of review requests per PR.

Returns:

  • (Float)

    Average number of review requests.



109
110
111
112
113
# File 'lib/dev_metrics/metrics_calc.rb', line 109

def average_review_requests_count
  return 0 if @prs.empty?
  counts = @prs.map(&:review_requests_count)
  (counts.sum.to_f / counts.size).round(2)
end

#average_reviews_countFloat

Returns the average number of reviews per PR.

Returns:

  • (Float)

    Average number of reviews.



100
101
102
103
104
# File 'lib/dev_metrics/metrics_calc.rb', line 100

def average_reviews_count
  return 0 if @prs.empty?
  counts = @prs.map(&:reviews_count)
  (counts.sum.to_f / counts.size).round(2)
end

#closed_unmerged_pr_countInteger

Returns the number of closed but unmerged PRs.

Returns:

  • (Integer)

    Number of closed but unmerged PRs.



201
202
203
# File 'lib/dev_metrics/metrics_calc.rb', line 201

def closed_unmerged_pr_count
  @prs.count { |pr| pr.closed_at && pr.merged_at.nil? }
end

#draft_pr_countInteger

Returns the number of draft PRs.

Returns:

  • (Integer)

    Number of draft PRs.



187
188
189
# File 'lib/dev_metrics/metrics_calc.rb', line 187

def draft_pr_count
  @prs.count(&:draft?)
end

#draft_pr_rateFloat

Returns the percentage of PRs that are drafts.

Returns:

  • (Float)

    Percentage of draft PRs.



118
119
120
121
122
# File 'lib/dev_metrics/metrics_calc.rb', line 118

def draft_pr_rate
  return 0 if @prs.empty?
  draft_count = @prs.count(&:draft?)
  ((draft_count.to_f / @prs.size) * 100).round(2)
end

#failure_rateString, Float

Returns the failure rate (percentage of rollback PRs).

Returns:

  • (String, Float)

    Percentage of rollback PRs or “-” if no PRs.



49
50
51
52
# File 'lib/dev_metrics/metrics_calc.rb', line 49

def failure_rate
  return "-" if @prs.empty?
  ((rollback_prs_length.to_f / @prs.count) * 100).round(2)
end

#label_countsHash

Returns a hash with label names as keys and their counts as values.

Returns:

  • (Hash)

    Label counts.



127
128
129
# File 'lib/dev_metrics/metrics_calc.rb', line 127

def label_counts
  @prs.flat_map(&:labels).compact.tally
end

#lead_timeString

Returns the average lead time for PRs (from creation to merge) as a formatted string.

Returns:

  • (String)

    Average lead time formatted as “Xd HH:MM:SS”.



33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/dev_metrics/metrics_calc.rb', line 33

def lead_time
  return "0d 00:00:00" if @prs.empty?

  times = @prs.map do |pr|
    merged_at = pr.merged_at
    created_at = pr.created_at
    merged_at && created_at ? merged_at - created_at : 0
  end

  average_time = times.sum.fdiv(times.size)
  format_time(average_time)
end

#max_pr_ageFloat

Returns the maximum PR age in days.

Returns:

  • (Float)

    Maximum PR age in days.



161
162
163
164
165
166
167
168
169
# File 'lib/dev_metrics/metrics_calc.rb', line 161

def max_pr_age
  return 0 if @prs.empty?
  ages = @prs.map do |pr|
    closed = pr.closed_at || Time.now
    created = pr.created_at
    created && closed ? (closed - created) / 86400.0 : 0
  end
  ages.max.round(2)
end

#max_pr_sizeInteger

Returns the maximum PR size (additions + deletions).

Returns:

  • (Integer)

    Maximum PR size.



75
76
77
78
# File 'lib/dev_metrics/metrics_calc.rb', line 75

def max_pr_size
  return 0 if @prs.empty?
  @prs.map { |pr| pr.additions + pr.deletions }.max
end

#merged_pr_countInteger

Returns the number of merged PRs.

Returns:

  • (Integer)

    Number of merged PRs.



194
195
196
# File 'lib/dev_metrics/metrics_calc.rb', line 194

def merged_pr_count
  @prs.count { |pr| !pr.merged_at.nil? }
end

#milestone_countsHash

Returns a hash with milestone titles as keys and their counts as values.

Returns:

  • (Hash)

    Milestone counts.



141
142
143
# File 'lib/dev_metrics/metrics_calc.rb', line 141

def milestone_counts
  @prs.map(&:milestone).compact.tally
end

#min_pr_ageFloat

Returns the minimum PR age in days.

Returns:

  • (Float)

    Minimum PR age in days.



174
175
176
177
178
179
180
181
182
# File 'lib/dev_metrics/metrics_calc.rb', line 174

def min_pr_age
  return 0 if @prs.empty?
  ages = @prs.map do |pr|
    closed = pr.closed_at || Time.now
    created = pr.created_at
    created && closed ? (closed - created) / 86400.0 : 0
  end
  ages.min.round(2)
end

#min_pr_sizeInteger

Returns the minimum PR size (additions + deletions).

Returns:

  • (Integer)

    Minimum PR size.



83
84
85
86
# File 'lib/dev_metrics/metrics_calc.rb', line 83

def min_pr_size
  return 0 if @prs.empty?
  @prs.map { |pr| pr.additions + pr.deletions }.min
end

#prs_lengthInteger

Returns the number of PRs excluding those created by bot accounts.

Returns:

  • (Integer)

    Number of PRs excluding bots.



17
18
19
# File 'lib/dev_metrics/metrics_calc.rb', line 17

def prs_length
  (@prs, @excluded_accounts).length
end

#rollback_prs_lengthInteger

Returns the number of rollback PRs (branch name matches fix patterns).

Returns:

  • (Integer)

    Number of rollback PRs.



24
25
26
27
28
# File 'lib/dev_metrics/metrics_calc.rb', line 24

def rollback_prs_length
  return 0 if @rollback_branch_prefixes.nil? || @rollback_branch_prefixes.empty?
  regex = /^#{@rollback_branch_prefixes.join('|')}/
  @prs.count { |pr| pr.head_ref_name&.match?(regex) }
end