Skip to content

Commit 8f96762

Browse files
diegojromerolopezsds
authored andcommitted
[FEATURE] Pre-commit hook: check for structural similarities with flay (#585)
* [FEATURE] New pre-commit hook: flay * [FIX] Run flay for each file Run flay separately for each because flay does not allow multiple files passed as parameters * [FIX] undefined method positive? for Fixnum * Fix for Rubocop Rubocop doesn't lik length > 0 * [FIX] Remove extra empty line in flay_spec.rb
1 parent f6ecd43 commit 8f96762

File tree

4 files changed

+105
-0
lines changed

4 files changed

+105
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,7 @@ issue](https://github.com/brigade/overcommit/issues/238) for more details.
497497
* [ExecutePermissions](lib/overcommit/hook/pre_commit/execute_permissions.rb)
498498
* [Fasterer](lib/overcommit/hook/pre_commit/fasterer.rb)
499499
* [FixMe](lib/overcommit/hook/pre_commit/fix_me.rb)
500+
* [Flay](lib/overcommit/hook/pre_commit/flay.rb)
500501
* [Foodcritic](lib/overcommit/hook/pre_commit/foodcritic.rb)
501502
* [ForbiddenBranches](lib/overcommit/hook/pre_commit/forbidden_branches.rb)
502503
* [GoLint](lib/overcommit/hook/pre_commit/go_lint.rb)

config/default.yml

+10
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,16 @@ PreCommit:
294294
flags: ['-IEHnw']
295295
keywords: ['BROKEN', 'BUG', 'ERROR', 'FIXME', 'HACK', 'NOTE', 'OPTIMIZE', 'REVIEW', 'TODO', 'WTF', 'XXX']
296296

297+
Flay:
298+
enabled: false
299+
description: 'Analyze ruby code for structural similarities with Flay'
300+
required_executable: 'flay'
301+
install_command: 'gem install flay'
302+
mass_threshold: 16
303+
fuzzy: 1
304+
liberal: false
305+
include: '**/*.rb'
306+
297307
Foodcritic:
298308
enabled: false
299309
description: 'Analyze with Foodcritic'
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
module Overcommit::Hook::PreCommit
2+
# Runs `flay` against any modified files.
3+
#
4+
# @see https://github.com/seattlerb/flay
5+
class Flay < Base
6+
# Flay prints two kinds of messages:
7+
#
8+
# 1) IDENTICAL code found in :defn (mass*2 = MASS)
9+
# file_path_1.rb:LINE_1
10+
# file_path_2.rb:LINE_2
11+
#
12+
# 2) Similar code found in :defn (mass = MASS)
13+
# file_path_1.rb:LINE_1
14+
# file_path_2.rb:LINE_2
15+
#
16+
17+
def run
18+
command = ['flay', '--mass', @config['mass_threshold'].to_s, '--fuzzy', @config['fuzzy'].to_s]
19+
# Use a more liberal detection method
20+
command += ['--liberal'] if @config['liberal']
21+
messages = []
22+
# Run the command for each file
23+
applicable_files.each do |file|
24+
result = execute(command, args: [file])
25+
results = result.stdout.split("\n\n")
26+
results.shift
27+
unless results.empty?
28+
error_message = results.join("\n").gsub(/^\d+\)\s*/, '')
29+
message = Overcommit::Hook::Message.new(:error, nil, nil, error_message)
30+
messages << message
31+
end
32+
end
33+
messages
34+
end
35+
end
36+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
require 'spec_helper'
2+
3+
describe Overcommit::Hook::PreCommit::Flay do
4+
let(:config) { Overcommit::ConfigurationLoader.default_configuration }
5+
let(:context) { double('context') }
6+
let(:applicable_files) { %w[file1.rb] }
7+
subject { described_class.new(config, context) }
8+
9+
before do
10+
subject.stub(:applicable_files).and_return(applicable_files)
11+
end
12+
13+
around do |example|
14+
repo do
15+
example.run
16+
end
17+
end
18+
19+
before do
20+
command = %w[flay --mass 16 --fuzzy 1]
21+
subject.stub(:execute).with(command, args: applicable_files).and_return(result)
22+
end
23+
24+
context 'flay discovered two issues' do
25+
let(:result) do
26+
double(
27+
success?: false,
28+
stdout: <<-MSG
29+
Total score (lower is better) = 268
30+
31+
1) IDENTICAL code found in :defn (mass*2 = 148)
32+
app/whatever11.rb:105
33+
app/whatever12.rb:76
34+
35+
2) Similar code found in :defn (mass = 120)
36+
app/whatever21.rb:105
37+
app/whatever22.rb:76
38+
39+
MSG
40+
)
41+
end
42+
43+
it { should fail_hook }
44+
end
45+
46+
context 'flay discovered no issues' do
47+
let(:result) do
48+
double(
49+
success?: false,
50+
stdout: <<-MSG
51+
Total score (lower is better) = 0
52+
MSG
53+
)
54+
end
55+
56+
it { should pass }
57+
end
58+
end

0 commit comments

Comments
 (0)