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 +4 -4
- data/.rubocop.yml +1 -1
- data/README.md +11 -9
- data/Rakefile +2 -2
- data/exe/ruby-quality-report +107 -11
- data/lib/quality_report/version.rb +1 -1
- data/lib/quality_report.rb +1 -1
- data/screenshot-1@2x.webp +0 -0
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eb26bd22c7b99d601f0eca7648de96e15dc06ac06b405c887cca9c92e96d353f
|
4
|
+
data.tar.gz: 03bc3e1613cc9bdb6b84d123164ec213051054d5f05b9627ab57394ca9df721f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|

|
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
|
-
|
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
|
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
|
-
- [
|
73
|
-
- [
|
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
data/exe/ruby-quality-report
CHANGED
@@ -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
|
-
|
48
|
-
|
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
|
-
|
52
|
-
|
53
|
-
|
54
|
-
{ value: stats[:
|
55
|
-
{ value: stats[:
|
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
|
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
|
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:)
|
data/lib/quality_report.rb
CHANGED
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
|
+
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-
|
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
|