From db91fefddd1c1e5f07206c61a1035304186fe999 Mon Sep 17 00:00:00 2001 From: Damien Biasotto Date: Thu, 17 May 2018 14:36:26 +1000 Subject: [PATCH 1/3] Add php-cs-fixer hook --- config/default.yml | 9 +++ .../hook/pre_commit/php_cs_fixer.rb | 55 +++++++++++++ .../hook/pre_commit/phpcs_fixer_spec.rb | 80 +++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 lib/overcommit/hook/pre_commit/php_cs_fixer.rb create mode 100644 spec/overcommit/hook/pre_commit/phpcs_fixer_spec.rb diff --git a/config/default.yml b/config/default.yml index 34cb6cd6..26b85bb1 100644 --- a/config/default.yml +++ b/config/default.yml @@ -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: 'php-cs-fixer' + flags: ['-v'] + install_command: 'composer require --dev friendsofphp/php-cs-fixer' + include: '**/*.php' + PhpStan: description: 'Analyze with phpstan' enabled: false diff --git a/lib/overcommit/hook/pre_commit/php_cs_fixer.rb b/lib/overcommit/hook/pre_commit/php_cs_fixer.rb new file mode 100644 index 00000000..a06caf09 --- /dev/null +++ b/lib/overcommit/hook/pre_commit/php_cs_fixer.rb @@ -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+(?.*\.php)(?\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 diff --git a/spec/overcommit/hook/pre_commit/phpcs_fixer_spec.rb b/spec/overcommit/hook/pre_commit/phpcs_fixer_spec.rb new file mode 100644 index 00000000..775f886f --- /dev/null +++ b/spec/overcommit/hook/pre_commit/phpcs_fixer_spec.rb @@ -0,0 +1,80 @@ +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 + 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") + 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 + 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") + 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 From 740fb916c84c3e3d67735643894de0ee2b9e4252 Mon Sep 17 00:00:00 2001 From: Damien Biasotto Date: Thu, 17 May 2018 14:50:50 +1000 Subject: [PATCH 2/3] Fixing command. --- config/default.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/default.yml b/config/default.yml index 26b85bb1..128398dc 100644 --- a/config/default.yml +++ b/config/default.yml @@ -503,9 +503,9 @@ PreCommit: enabled: false description: 'Fix non compliant PHP files' required_executable: 'php-cs-fixer' - command: 'php-cs-fixer' - flags: ['-v'] - install_command: 'composer require --dev friendsofphp/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: From a2464488b3c5f999ef041779d1aa4c44f2b4f7ac Mon Sep 17 00:00:00 2001 From: Damien Biasotto Date: Thu, 17 May 2018 16:18:56 +1000 Subject: [PATCH 3/3] Fix rubocop violations. --- spec/overcommit/hook/pre_commit/phpcs_fixer_spec.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/spec/overcommit/hook/pre_commit/phpcs_fixer_spec.rb b/spec/overcommit/hook/pre_commit/phpcs_fixer_spec.rb index 775f886f..86fe8bc7 100644 --- a/spec/overcommit/hook/pre_commit/phpcs_fixer_spec.rb +++ b/spec/overcommit/hook/pre_commit/phpcs_fixer_spec.rb @@ -11,6 +11,7 @@ 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".', @@ -21,6 +22,8 @@ '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) @@ -31,9 +34,9 @@ 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".', @@ -41,6 +44,8 @@ '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) @@ -76,5 +81,4 @@ end it { should fail_hook } end - end