Skip to content

Commit

Permalink
[FEATURE] Pre-commit hook: check your yard documentation coverage (sd…
Browse files Browse the repository at this point in the history
…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
diegojromerolopez authored and sds committed Jul 17, 2018
1 parent f06fc8a commit f6ecd43
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,7 @@ issue](https://github.com/brigade/overcommit/issues/238) for more details.
* [BundleOutdated](lib/overcommit/hook/pre_commit/bundle_outdated.rb)
* [`*`CaseConflicts](lib/overcommit/hook/pre_commit/case_conflicts.rb)
* [ChamberSecurity](lib/overcommit/hook/pre_commit/chamber_security.rb)
* [CheckYardCoverage](lib/overcommit/hook/pre_commit/check_yard_coverage.rb)
* [CoffeeLint](lib/overcommit/hook/pre_commit/coffee_lint.rb)
* [Credo](lib/overcommit/hook/pre_commit/credo.rb)
* [CssLint](lib/overcommit/hook/pre_commit/css_lint.rb)
Expand Down
11 changes: 11 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,17 @@ PreCommit:
install_command: 'gem install chamber'
include: *chamber_settings_files

CheckYardCoverage:
enabled: false
description: 'Checking for yard coverage'
command: ['yard', 'stats', '--list-undoc', '--compact']
flags: ['--private', '--protected']
required_executable: 'yard'
install_command: 'gem install yard'
min_coverage_percentage: 100
include:
- '/**/*.rb'

CoffeeLint:
enabled: false
description: 'Analyze with coffeelint'
Expand Down
88 changes: 88 additions & 0 deletions lib/overcommit/hook/pre_commit/check_yard_coverage.rb
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 spec/overcommit/hook/pre_commit/check_yard_coverage_spec.rb
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

0 comments on commit f6ecd43

Please sign in to comment.