Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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