quality_report 1.4.0 → 1.6.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c36b81a22b99492d9995e4446769315fe3a01df58e39ed71a3a1050bc05f1791
4
- data.tar.gz: ebc3e1150b528d795fd72e926a462a93aca6311f4a232a3d94c04416bc0a7a7e
3
+ metadata.gz: eb26bd22c7b99d601f0eca7648de96e15dc06ac06b405c887cca9c92e96d353f
4
+ data.tar.gz: 03bc3e1613cc9bdb6b84d123164ec213051054d5f05b9627ab57394ca9df721f
5
5
  SHA512:
6
- metadata.gz: 1e9379b163149edcab1180868a320b7b5529f6c73b5a8c90cc2ffe3292fa818ccc1a48a1cfef9fb6a319fd9dbdf348fc9e6f66749d9b82e4886f2f4a42a50d4d
7
- data.tar.gz: f9911d996413da6cf9264b34749e318d01a1c64e85925c76dae7da609966495341e7fc9d5956866b32c477cc7adbf9f0fbbe50bd0422773242b69e16a122003f
6
+ metadata.gz: 4a35e38922d52d49f34d6e4269e76aa1e43820f7c3d22ab569aa92667397cf3a1b9b0bfeed46fbc188bf3fcf9911166c6ec8372f074c033272e378b21a9e3383
7
+ data.tar.gz: d841f2ecc4afc0bbefeacc3500be6132e976d82da5705759151527d8be64b03cfdb96083e2819eff1590d725d1f34e59b644c349bb6c08ef09146bf4e893211a
data/.rubocop.yml CHANGED
@@ -1,2 +1,2 @@
1
1
  AllCops:
2
- TargetRubyVersion: 3.1
2
+ TargetRubyVersion: 3.1
data/README.md CHANGED
@@ -3,11 +3,13 @@
3
3
  ## Installation
4
4
 
5
5
  ```sh
6
- gem install quality-report
6
+ gem install quality_report
7
7
  ```
8
8
 
9
9
  ## Usage
10
10
 
11
+ Change to a project directory that contains `*.rb` files. Then:
12
+
11
13
  ```sh
12
14
  ruby-quality-report
13
15
  ```
@@ -16,7 +18,7 @@ After a bit of a wait, it outputs a report in table form:
16
18
 
17
19
  ![Screenshot](screenshot-1@2x.webp)
18
20
 
19
- This is showing, for each author, the percentage of problematic lines of code. Lower is better.
21
+ This is showing, for each author, the percentage of problematic lines of code in the repo. Lower is better.
20
22
 
21
23
 
22
24
  ### For improved relevance, it has two filters.
@@ -44,7 +46,7 @@ It runs a subset of [Rubocop Metrics cops](https://docs.rubocop.org/rubocop/cops
44
46
  - [Method Length](https://docs.rubocop.org/rubocop/cops_metrics.html#metricsmethodlength)
45
47
  - [Perceived Complexity](https://docs.rubocop.org/rubocop/cops_metrics.html#metricsperceivedcomplexity)
46
48
 
47
- It then calculates the percentage of warnings per line written, per author. Each failing check is another warning.
49
+ Then, using git, it calculates the percentage of warnings per line written, per author. Each failing check is another warning.
48
50
 
49
51
 
50
52
  ## Intent
@@ -56,7 +58,7 @@ This is a team management tool to:
56
58
 
57
59
  ## Foundational Research
58
60
 
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.
61
+ 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 create a lot of commits. But they also create a lot of bugs. Their productivity is illusory.
60
62
 
61
63
  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
64
 
@@ -69,13 +71,13 @@ Complex code introduces bugs in a second, more subtle way. This is because code
69
71
 
70
72
  ## Roadmap
71
73
 
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.
74
+ - [x] Colorize the output to separate high, medium, and low warning percentages.
75
+ - [x] Fix the numerical alignment.
77
76
  - [ ] Add a progress bar.
77
+ - [ ] Speed up the scan.
78
78
  - [ ] Refactor from script-style coding to a more standard Ruby project.
79
+ - [ ] Make the filters configurable.
80
+ - [ ] Add a `--csv` option.
79
81
 
80
82
 
81
83
  ## Contributing
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bundler/gem_tasks"
4
- require "rspec/core/rake_task"
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
5
 
6
6
  RSpec::Core::RakeTask.new(:spec)
7
7
 
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'json'
5
+ require 'tty-option'
4
6
  require 'tty-table'
5
7
  require 'pastel'
6
8
 
@@ -43,17 +45,27 @@ def generate_csv(combined_stats)
43
45
  .join("\n")
44
46
  end
45
47
 
46
- def generate_table(combined_stats)
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) }
48
+ def generate_table(combined_stats, colspec: {}, skip: '')
49
+ default_headings = ['Author', 'Percent Flagged', 'Flagged Lines', 'All lines']
50
+ static_heading = colspec.keys&.first # Handle just one column for now
51
+ all_headings = (default_headings + [static_heading]).compact
52
+
53
+ table = TTY::Table.new(header: all_headings)
54
+ table_data = generate_data(combined_stats).reject { should_skip?(_1) }
55
+ static_values = colspec[static_heading] || {}
49
56
 
50
57
  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 }
58
+ next if skip.include?(stats[:label])
59
+
60
+ new_row = [
61
+ { value: stats[:label], alignment: :left },
62
+ { value: "#{stats[:percent]}%", alignment: :right },
63
+ { value: int_to_accounting(stats[:part_count]), alignment: :right },
64
+ { value: int_to_accounting(stats[:whole_count]), alignment: :right }
56
65
  ]
66
+ new_row << { value: static_values[stats[:label]], alignment: :left } if static_heading
67
+
68
+ table << new_row
57
69
  end
58
70
 
59
71
  render_table(table, table_data)
@@ -109,15 +121,99 @@ def no_commits_in_last_60_days?(stats)
109
121
  last_commit_time < sixty_days_ago
110
122
  end
111
123
 
124
+ ###
125
+ # Converts a float to an integer percentage
126
+ #
112
127
  def float_to_percent(a_float)
113
- (Float(a_float) * 100).round(1)
128
+ (Float(a_float) * 100).round
129
+ end
130
+
131
+ ##
132
+ # Converts an integer to a string with commas separating thousands.
133
+ #
134
+ # An alternative implementation is:
135
+ # an_int.to_s.gsub(/(\d)(?=(\d{3})+(?!\d))/, '\\1,')
136
+ #
137
+ def int_to_accounting(an_int)
138
+ an_int.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
139
+ end
140
+
141
+ #
142
+ # CLI Argument Parser
143
+ #
144
+ class Command
145
+ include TTY::Option
146
+
147
+ usage do
148
+ program 'ruby-quality-report'
149
+ no_command
150
+ header 'Ruby Quality Report'
151
+ desc <<~DESC
152
+ Generates a report of the percentage of flagged lines of code written by each author. For improved relevance, it excludes:
153
+
154
+ - authors with fewer than 200 lines of code
155
+ - authors with no commits in the previous 60 days
156
+
157
+ It runs a suite of Rubocop metrics on *.rb files recursively starting in the current directory. Then, using git, it calculates the percentage of warnings per line written, per author. Each failing check is another warning.
158
+ DESC
159
+
160
+ example <<~EXAMPLE1
161
+ Append a column showing office location. The order of the keys in the JSON does not matter:
162
+ $ ruby-quality-report -c '{"Location": {"Amy": "NYC", "Bob": "Remote"}}'
163
+ EXAMPLE1
164
+
165
+ example <<~EXAMPLE2
166
+ Skip one author:
167
+ $ ruby-quality-report --skip Cathy
168
+ EXAMPLE2
169
+ end
170
+
171
+ option :add_column do
172
+ long '--add-column JSON'
173
+ short '-c JSON'
174
+ desc 'Add a static column to the report. This is a simple way to add known information. See the examples.'
175
+ end
176
+
177
+ flag :skip do
178
+ long '--skip AUTHOR'
179
+ short '-s AUTHOR'
180
+ desc 'Filter out a git author'
181
+ end
182
+
183
+ flag :help do
184
+ short '-h'
185
+ long '--help'
186
+ desc 'Print this help'
187
+ end
188
+
189
+ def run
190
+ if params[:help]
191
+ print help
192
+ exit 1
193
+ elsif params.errors.any?
194
+ puts params.errors.summary
195
+ exit 1
196
+ end
197
+ end
114
198
  end
115
199
 
116
200
  #
117
201
  # Execution begins here
118
202
  #
203
+
204
+ command = Command.new
205
+ command.parse
206
+ command.run
207
+
208
+ add_column_param = command.params[:add_column]
209
+ colspec = add_column_param ? JSON.parse(add_column_param) : {}
210
+ puts "Adding column: #{colspec.keys.first}" unless colspec.empty?
211
+
212
+ skip = command.params[:skip] || ''
213
+ puts "Skipping author: #{skip}" if skip != ''
214
+
119
215
  PART_STATS = `ruby-author-warnings | frequency-list`.freeze
120
- WHOLE_STATS = `ruby-line-authors | frequency-list`.freeze
216
+ WHOLE_STATS = `ruby-line-authors | frequency-list`.freeze
121
217
  COMBINED_STATS = create_combined_stats(PART_STATS, WHOLE_STATS)
122
218
 
123
- puts generate_table(COMBINED_STATS)
219
+ puts generate_table(COMBINED_STATS, colspec:, skip:)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module QualityReport
4
- VERSION = '1.4.0'
4
+ VERSION = '1.6.0'
5
5
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "quality_report/version"
3
+ require_relative 'quality_report/version'
4
4
 
5
5
  module QualityReport
6
6
  class Error < StandardError; end
data/screenshot-1@2x.webp CHANGED
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.4.0
4
+ version: 1.6.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-09 00:00:00.000000000 Z
11
+ date: 2024-11-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.68'
27
+ - !ruby/object:Gem::Dependency
28
+ name: tty-option
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.3.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.3.0
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: tty-table
29
43
  requirement: !ruby/object:Gem::Requirement