Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PhpCsFixer Pre-Commit hook #580

Merged
merged 3 commits into from
Jul 17, 2018
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
9 changes: 9 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,15 @@ PreCommit:
flags: ['--standard=PSR2', '--report=csv']
include: '**/*.php'

PhpCsFixer:
enabled: false
description: 'Fix non compliant PHP files'
required_executable: 'php-cs-fixer'
command: 'vendor/bin/php-cs-fixer'
flags: ['fix', '-v', '--path-mode=intersection']
install_command: 'composer global require friendsofphp/php-cs-fixer'
include: '**/*.php'

PhpStan:
description: 'Analyze with phpstan'
enabled: false
Expand Down
55 changes: 55 additions & 0 deletions lib/overcommit/hook/pre_commit/php_cs_fixer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
module Overcommit::Hook::PreCommit
# Runs `php-cs-fixer` against any modified PHP files.
class PhpCsFixer < Base
MESSAGE_REGEX = /\s+\d+\)\s+(?<file>.*\.php)(?<violated_rules>\s+\(\w+(?:,\s+)?\))?/

def run
messages = []
feedback = ''

# Exit status for all of the runs. Should be zero!
exit_status_sum = 0

applicable_files.each do |file|
result = execute(command, args: [file])
output = result.stdout.chomp
exit_status_sum += result.status

if result.status
messages = output.lstrip.split("\n")
end
end

unless messages.empty?
feedback = parse_messages(messages)
end

:pass if exit_status_sum == 0
:pass if feedback.empty?

feedback
end

def parse_messages(messages)
output = []

messages.map do |message|
message.scan(MESSAGE_REGEX).map do |file, violated_rules|
type = :error
unless violated_rules.nil?
type = :warning
end
text = if type == :error
"Cannot process #{file}: Syntax error"
else
"#{file} has been fixed"
end

output << Overcommit::Hook::Message.new(type, file, 0, text)
end
end

output
end
end
end
84 changes: 84 additions & 0 deletions spec/overcommit/hook/pre_commit/phpcs_fixer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
require 'spec_helper'

describe Overcommit::Hook::PreCommit::PhpCsFixer 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[sample.php])
end

context 'when phpcs fixer exits successfully with fixed file' do
before do
# rubocop:disable Metrics/LineLength
sample_output = [
'Loaded config default.',
'Using cache file ".php_cs.cache".',
'F',
'Legend: ?-unknown, I-invalid file syntax, file ignored, S-Skipped, .-no changes, F-fixed, E-error',
' 1) foo/fixable.php (braces)',
'',
'Fixed all files in 0.001 seconds, 10.000 MB memory used',
'',
].join("\n")
# rubocop:enable Metrics/LineLength

result = double('result')
result.stub(:status).and_return(0)
result.stub(:success?).and_return(true)
result.stub(:stdout).and_return(sample_output)
subject.stub(:execute).and_return(result)
end

it { should warn }
end

context 'when phpcs fixer exits successfully with no file to fix' do
before do
# rubocop:disable Metrics/LineLength
sample_output = [
'Loaded config default.',
'Using cache file ".php_cs.cache".',
'S',
'Legend: ?-unknown, I-invalid file syntax, file ignored, S-Skipped, .-no changes, F-fixed, E-error',
'',
].join("\n")
# rubocop:enable Metrics/LineLength

result = double('result')
result.stub(:status).and_return(0)
result.stub(:success?).and_return(true)
result.stub(:stdout).and_return(sample_output)
subject.stub(:execute).and_return(result)
end

it { should pass }
end

context 'when phpcs exits unsuccessfully' do
before do
# rubocop:disable Metrics/LineLength
sample_output = [
'Loaded config default.',
'Using cache file ".php_cs.cache".',
'I',
'Legend: ?-unknown, I-invalid file syntax, file ignored, S-Skipped, .-no changes, F-fixed, E-error',
'Fixed all files in 0.001 seconds, 10.000 MB memory used',
'',
'Files that were not fixed due to errors reported during linting before fixing:',
' 1) /home/damien/Code/Rezdy/php/foo/broken.php',
'',
].join("\n")
# rubocop:enable Metrics/LineLength

result = double('result')
result.stub(:status).and_return(1)
result.stub(:success?).and_return(false)
result.stub(:stdout).and_return(sample_output)
result.stub(:stderr).and_return(sample_output)
subject.stub(:execute).and_return(result)
end
it { should fail_hook }
end
end