forked from sds/overcommit
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[FEATURE] Pre-commit hook: check your yard documentation coverage (sd…
…s#584) * [FEATURE] Pre-commit hook: check your yard documentation coverage * Fixes for rubocop Fix some issues detected by Rubocop: CheckYardCoverage hook: run was too big and lines too long * Fix for rubocop Removing empty, following Rubocop orders * [FIX] Fix command The earlier command createded documentation files in ./doc. The current command does not. * [FIX] Bad stats extraction
- Loading branch information
1 parent
f06fc8a
commit f6ecd43
Showing
4 changed files
with
197 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
|
||
module Overcommit::Hook::PreCommit | ||
# Class to check yard documentation coverage. | ||
# | ||
# Use option "min_coverage_percentage" in your CheckYardCoverage configuration | ||
# to set your desired documentation coverage percentage. | ||
# | ||
class CheckYardCoverage < Base | ||
def run | ||
# Run a no-stats yard command to get the coverage | ||
args = flags + applicable_files | ||
result = execute(command, args: args) | ||
|
||
warnings_and_stats_text, undocumented_objects_text = | ||
result.stdout.split('Undocumented Objects:') | ||
|
||
warnings_and_stats = warnings_and_stats_text.strip.split("\n") | ||
|
||
# Stats are the last 7 lines before the undocumented objects | ||
stats = warnings_and_stats.slice(-7, 7) | ||
|
||
# If no stats present (shouldn't happen), warn the user and end | ||
if stats.class != Array || stats.length != 7 | ||
return [:warn, 'Impossible to read the yard stats. Please, check your yard installation.'] | ||
end | ||
|
||
# Check the yard coverage | ||
yard_coverage = check_yard_coverage(stats) | ||
if yard_coverage == :warn | ||
return [ | ||
:warn, | ||
'Impossible to read yard doc coverage. Please, check your yard installation.' | ||
] | ||
end | ||
return :pass if yard_coverage == :pass | ||
|
||
error_messages(yard_coverage, undocumented_objects_text) | ||
end | ||
|
||
private | ||
|
||
# Check the yard coverage | ||
# | ||
# Return a :pass if the coverage is enough, :warn if it couldn't be read, | ||
# otherwise, it has been read successfully. | ||
# | ||
def check_yard_coverage(stat_lines) | ||
if config['min_coverage_percentage'] | ||
match = stat_lines.last.match(/^\s*([\d.]+)%\s+documented\s*$/) | ||
unless match | ||
return :warn | ||
end | ||
|
||
yard_coverage = match.captures[0].to_f | ||
if yard_coverage >= config['min_coverage_percentage'].to_f | ||
return :pass | ||
end | ||
|
||
yard_coverage | ||
end | ||
end | ||
|
||
# Create the error messages | ||
def error_messages(yard_coverage, error_text) | ||
first_message = "You have a #{yard_coverage}% yard documentation coverage. "\ | ||
"#{config['min_coverage_percentage']}% is the minimum required." | ||
|
||
# Add the undocumented objects text as error messages | ||
messages = [Overcommit::Hook::Message.new(:error, nil, nil, first_message)] | ||
|
||
errors = error_text.strip.split("\n") | ||
errors.each do |undocumented_object| | ||
undocumented_object_message, file_info = undocumented_object.split(/:?\s+/) | ||
file_info_match = file_info.match(/^\(([^:]+):(\d+)\)/) | ||
|
||
# In case any compacted error does not follow the format, ignore it | ||
if file_info_match | ||
file = file_info_match.captures[0] | ||
line = file_info_match.captures[1] | ||
messages << Overcommit::Hook::Message.new( | ||
:error, file, line, "#{file}:#{line}: #{undocumented_object_message}" | ||
) | ||
end | ||
end | ||
messages | ||
end | ||
end | ||
end |
97 changes: 97 additions & 0 deletions
97
spec/overcommit/hook/pre_commit/check_yard_coverage_spec.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
require 'spec_helper' | ||
|
||
describe Overcommit::Hook::PreCommit::CheckYardCoverage do | ||
let(:config) { Overcommit::ConfigurationLoader.default_configuration } | ||
let(:context) { double('context') } | ||
subject { described_class.new(config, context) } | ||
|
||
before do | ||
subject.stub(:applicable_files).and_return(%w[file1.rb file2.rb]) | ||
end | ||
|
||
context 'when yard exits successfully' do | ||
before do | ||
result = double('result') | ||
result.stub(:stdout).and_return( | ||
<<-HEREDOC | ||
Files: 72 | ||
Modules: 12 ( 0 undocumented) | ||
Classes: 63 ( 0 undocumented) | ||
Constants: 91 ( 0 undocumented) | ||
Attributes: 11 ( 0 undocumented) | ||
Methods: 264 ( 0 undocumented) | ||
100.0% documented | ||
HEREDOC | ||
) | ||
subject.stub(:execute).and_return(result) | ||
end | ||
|
||
it { should pass } | ||
end | ||
|
||
context 'when somehow yard exits a non-stats output' do | ||
before do | ||
result = double('result') | ||
result.stub(:stdout).and_return( | ||
<<-HEREDOC | ||
WHATEVER OUTPUT THAT IS NOT YARD STATS ONE | ||
HEREDOC | ||
) | ||
subject.stub(:execute).and_return(result) | ||
end | ||
|
||
it { should warn } | ||
end | ||
|
||
context 'when somehow yard coverage is not a valid value' do | ||
before do | ||
result = double('result') | ||
result.stub(:stdout).and_return( | ||
<<-HEREDOC | ||
Files: 72 | ||
Modules: 12 ( 0 undocumented) | ||
Classes: 63 ( 0 undocumented) | ||
Constants: 91 ( 0 undocumented) | ||
Attributes: 11 ( 0 undocumented) | ||
Methods: 264 ( 0 undocumented) | ||
AAAAAA documented | ||
HEREDOC | ||
) | ||
subject.stub(:execute).and_return(result) | ||
end | ||
|
||
it { should warn } | ||
end | ||
|
||
context 'when yard exits unsucessfully' do | ||
let(:result) { double('result') } | ||
|
||
before do | ||
result.stub(:success?).and_return(false) | ||
subject.stub(:execute).and_return(result) | ||
end | ||
|
||
context 'and it reports an error' do | ||
before do | ||
result.stub(:stdout).and_return( | ||
<<-HEREDOC | ||
Files: 72 | ||
Modules: 12 ( 3 undocumented) | ||
Classes: 63 ( 15 undocumented) | ||
Constants: 91 ( 79 undocumented) | ||
Attributes: 11 ( 0 undocumented) | ||
Methods: 264 ( 55 undocumented) | ||
65.53% documented | ||
Undocumented Objects: | ||
ApplicationCable (app/channels/application_cable/channel.rb:1) | ||
ApplicationCable::Channel (app/channels/application_cable/channel.rb:2) | ||
ApplicationCable::Connection (app/channels/application_cable/connection.rb:2) | ||
HEREDOC | ||
) | ||
end | ||
|
||
it { should fail_hook } | ||
end | ||
end | ||
end |