quality_report 1.2.2 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a54ad55acc9cb09976954e805eb8c7136d5f81e76ca0d23b732739b629b43b77
4
- data.tar.gz: 4ba83e201032c764ef7077187d267f9fba8f29c682e4087b893eb0ab92ecfae6
3
+ metadata.gz: c36b81a22b99492d9995e4446769315fe3a01df58e39ed71a3a1050bc05f1791
4
+ data.tar.gz: ebc3e1150b528d795fd72e926a462a93aca6311f4a232a3d94c04416bc0a7a7e
5
5
  SHA512:
6
- metadata.gz: 295733e297b006cca1f68d5689f44422060f689aa44f10ecca0903fa4acca34fbd098df986edbceae908aa90b228e3e076eda2c5e324a8542015d2688e9118c4
7
- data.tar.gz: acfe8e8f47c38ec7fe118a6ead137b11083ac7288b94882cf1b9980c1ae8b797ec4fc124dc470374591ba3871c471039fb9894481e2bfc4c91b34d5ff94cc160
6
+ metadata.gz: 1e9379b163149edcab1180868a320b7b5529f6c73b5a8c90cc2ffe3292fa818ccc1a48a1cfef9fb6a319fd9dbdf348fc9e6f66749d9b82e4886f2f4a42a50d4d
7
+ data.tar.gz: f9911d996413da6cf9264b34749e318d01a1c64e85925c76dae7da609966495341e7fc9d5956866b32c477cc7adbf9f0fbbe50bd0422773242b69e16a122003f
data/README.md CHANGED
@@ -1,12 +1,82 @@
1
1
  # Ruby Quality Report
2
2
 
3
+ ## Installation
4
+
5
+ ```sh
6
+ gem install quality-report
7
+ ```
8
+
3
9
  ## Usage
4
10
 
5
11
  ```sh
6
12
  ruby-quality-report
7
13
  ```
8
14
 
9
- This outputs a CSV report to stdout.
15
+ After a bit of a wait, it outputs a report in table form:
16
+
17
+ ![Screenshot](screenshot-1@2x.webp)
18
+
19
+ This is showing, for each author, the percentage of problematic lines of code. Lower is better.
20
+
21
+
22
+ ### For improved relevance, it has two filters.
23
+
24
+ It excludes:
25
+
26
+ - authors with fewer than 200 lines of code
27
+ - authors with no commits in the previous 60 days
28
+
29
+
30
+ ### In Rails Projects
31
+
32
+ This works great in Rails projects. It examines code recursively starting in the current directory. In my testing,
33
+ I like the results best when run from `/app`. This is how I generated the report, above.
34
+
35
+
36
+ ## How it works
37
+
38
+ It runs a subset of [Rubocop Metrics cops](https://docs.rubocop.org/rubocop/cops_metrics.html) on `*.rb` files that flag single lines or methods:
39
+
40
+ - [ABC Size](https://docs.rubocop.org/rubocop/cops_metrics.html#metricsabcsize)
41
+ - [Block Length](https://docs.rubocop.org/rubocop/cops_metrics.html#metricsblocklength)
42
+ - [Block Nesting](https://docs.rubocop.org/rubocop/cops_metrics.html#metricsblocknesting)
43
+ - [Cyclomatic Complexity](https://docs.rubocop.org/rubocop/cops_metrics.html#metricscyclomaticcomplexity)
44
+ - [Method Length](https://docs.rubocop.org/rubocop/cops_metrics.html#metricsmethodlength)
45
+ - [Perceived Complexity](https://docs.rubocop.org/rubocop/cops_metrics.html#metricsperceivedcomplexity)
46
+
47
+ It then calculates the percentage of warnings per line written, per author. Each failing check is another warning.
48
+
49
+
50
+ ## Intent
51
+
52
+ This is a team management tool to:
53
+
54
+ - understand the quality of the code your team is producing
55
+ - identify programmers who'd benefit from mentorship and education
56
+
57
+ ## Foundational Research
58
+
59
+ Diving a little deeper, I've seen the phenomenon of micro-economies of bug-creation and bug-fixing develop within teams. Some developers appear to be extremely productive. They write a lot of code. But they also introduce a lot of bugs. The productivity is illusory.
60
+
61
+ This code quality report doesn't track **bugs** per se. But it does report **quality and complexity**. Researchers have found a strong correlation between complexity and bug rate [1]. This link is reflected, _e.g.,_ in international safety standards that mandate low software complexity to reduce failures [2].
62
+
63
+ Complex code introduces bugs in a second, more subtle way. This is because code complexity is the killer of understandability. Studies have found that developers devote 64% of their time to understanding code, while only 5% is spent on actually modifying it [3].
64
+
65
+ 1. De Silva, Dilshan, et al. The Relationship between Code Complexity and Software Quality: An Empirical Study. 2023, https://www.researchgate.net/publication/370761578_The_Relationship_between_Code_Complexity_and_Software_Quality_An_Empirical_Study.
66
+ 2. See e.g., ISO 26262-1:2018(En), Road Vehicles — Functional Safety — Part 1: Vocabulary. https://www.iso.org/obp/ui/en/#iso:std:iso:26262:-1:ed-2:v1:en. Accessed 29 Sept. 2024.
67
+ 3. Feitelson, Dror G. “From Code Complexity Metrics to Program Comprehension.” Communications of the ACM, vol. 66, no. 5, May 2023, pp. 52–61. DOI.org (Crossref), https://doi.org/10.1145/3546576.
68
+
69
+
70
+ ## Roadmap
71
+
72
+ - [ ] Colorize the output to separate high, medium, and low warning percentages.
73
+ - [ ] Fix the numerical alignment.
74
+ - [ ] Add a `--csv` option.
75
+ - [ ] Make the filters configurable.
76
+ - [ ] Speed up the scan.
77
+ - [ ] Add a progress bar.
78
+ - [ ] Refactor from script-style coding to a more standard Ruby project.
79
+
10
80
 
11
81
  ## Contributing
12
82
 
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'tty-table'
5
+ require 'pastel'
5
6
 
6
7
  #
7
8
  # ruby-quality-report
@@ -10,6 +11,9 @@ require 'tty-table'
10
11
  # of lines of code written by each author that have been flagged as
11
12
  # having too high of a complexity.
12
13
  #
14
+ #
15
+
16
+ SIXTY_DAYS_IN_SECONDS = 60 * 24 * 60 * 60
13
17
 
14
18
  def create_combined_stats(part_stats, whole_stats)
15
19
  part_data = make_data_set(part_stats)
@@ -17,13 +21,9 @@ def create_combined_stats(part_stats, whole_stats)
17
21
 
18
22
  whole_data.map do |label, whole_count|
19
23
  part_count = part_data[label] || 0
24
+ percent = float_to_percent(part_count.to_f / whole_count)
20
25
 
21
- {
22
- label:,
23
- part_count:,
24
- whole_count:,
25
- percent: float_to_percent(part_count.to_f / whole_count)
26
- }
26
+ { label:, part_count:, whole_count:, percent: }
27
27
  end
28
28
  end
29
29
 
@@ -44,21 +44,47 @@ def generate_csv(combined_stats)
44
44
  end
45
45
 
46
46
  def generate_table(combined_stats)
47
- table = TTY::Table.new(header: ['Author', 'Percent Flagged', 'Flagged Lines', 'All Lines'])
47
+ table = TTY::Table.new(header: %W[Author Percent\nFlagged Flagged\nLines All\nLines])
48
+ table_data = generate_data(combined_stats).reject { should_skip?(_1) }
49
+
50
+ table_data.each do |stats|
51
+ table << [
52
+ { value: stats[:label], alignment: :left },
53
+ { value: "#{stats[:percent]}%", alignment: :right },
54
+ { value: stats[:part_count], alignment: :right },
55
+ { value: stats[:whole_count], alignment: :right }
56
+ ]
57
+ end
48
58
 
49
- generate_data(combined_stats).each do |stats|
50
- next if should_skip?(stats)
59
+ render_table(table, table_data)
60
+ end
51
61
 
52
- table << [stats[:label], "#{stats[:percent]}%", stats[:part_count], stats[:whole_count]]
62
+ def render_table(table, table_data)
63
+ pastel = Pastel.new
64
+
65
+ table.render(:unicode, alignment: :center, padding: [0, 1], multiline: true) do |renderer|
66
+ renderer.border.style = :dim
67
+ renderer.filter = lambda { |val, row_index, _col_index|
68
+ if row_index <= 0
69
+ # Header row
70
+ val
71
+ else
72
+ case table_data[row_index - 1][:percent]
73
+ when 0...40
74
+ val
75
+ when 40...50
76
+ pastel.bold.yellow(val)
77
+ else
78
+ pastel.bold.red(val)
79
+ end
80
+ end
81
+ }
53
82
  end
54
-
55
- table.render(:unicode)
56
83
  end
57
84
 
58
85
  def generate_data(combined_stats)
59
86
  combined_stats
60
87
  .sort_by { |s| s[:percent] }
61
- .reverse
62
88
  end
63
89
 
64
90
  def should_skip?(stats)
@@ -78,7 +104,7 @@ def no_commits_in_last_60_days?(stats)
78
104
 
79
105
  # Convert Unix timestamp to Time object
80
106
  last_commit_time = Time.at(last_commit.to_i)
81
- sixty_days_ago = Time.now - (60 * 24 * 60 * 60) # 60 days in seconds
107
+ sixty_days_ago = Time.now - SIXTY_DAYS_IN_SECONDS
82
108
 
83
109
  last_commit_time < sixty_days_ago
84
110
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module QualityReport
4
- VERSION = '1.2.2'
4
+ VERSION = '1.4.0'
5
5
  end
Binary file
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quality_report
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robb Shecter
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-11-08 00:00:00.000000000 Z
11
+ date: 2024-11-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -75,6 +75,7 @@ files:
75
75
  - exe/ruby-quality-report
76
76
  - lib/quality_report.rb
77
77
  - lib/quality_report/version.rb
78
+ - screenshot-1@2x.webp
78
79
  - sig/quality_report.rbs
79
80
  homepage: https://github.com/dogweather/ruby-quality-report
80
81
  licenses: