diff --git a/config/default.yml b/config/default.yml index 02777c7e..f678f35f 100644 --- a/config/default.yml +++ b/config/default.yml @@ -337,6 +337,14 @@ PreCommit: flags: ['-IEHnw'] keywords: ['FContext','FDescribe','FIt','FMeasure','FSpecify','FWhen'] + GoFmt: + enabled: true + description: 'Fix with go fmt' + required_executable: 'go' + command: ['go', 'fmt'] + parallelize: false + include: '**/*.go' + GoLint: enabled: false description: 'Analyze with golint' diff --git a/lib/overcommit/hook/pre_commit/go_fmt.rb b/lib/overcommit/hook/pre_commit/go_fmt.rb new file mode 100644 index 00000000..0f46a18e --- /dev/null +++ b/lib/overcommit/hook/pre_commit/go_fmt.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Overcommit::Hook::PreCommit + # Runs go fmt for all modified Go files + class GoFmt < Base + def run + errors = [] + applicable_files.each do |file| + result = execute(command, args: [file]) + errors << (result.stdout + result.stderr) unless result.success? + end + return :pass if errors.empty? + + [:fail, errors.join("\n")] + end + end +end diff --git a/spec/overcommit/hook/pre_commit/go_fmt_spec.rb b/spec/overcommit/hook/pre_commit/go_fmt_spec.rb new file mode 100644 index 00000000..496ca097 --- /dev/null +++ b/spec/overcommit/hook/pre_commit/go_fmt_spec.rb @@ -0,0 +1,99 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Overcommit::Hook::PreCommit::GoFmt do + let(:config) { Overcommit::ConfigurationLoader.default_configuration } + let(:context) { double('context') } + subject { described_class.new(config, context) } + + let(:files) do + %w[ + pkg1/file1.go + pkg1/file2.go + pkg2/file1.go + file1.go + ] + end + before do + subject.stub(:applicable_files).and_return(files) + end + + context 'when go fmt exits successfully' do + let(:result) { double('result') } + + before do + result.stub(success?: true, stderr: '', stdout: '') + subject.stub(:execute).and_return(result) + end + + it 'executes go fmt for each file' do + files.each do |file| + expect(subject).to receive(:execute).with(subject.command, args: [file]).once + end + subject.run + end + + it 'passes' do + expect(subject).to pass + end + end + + context 'when go fmt exits unsucessfully' do + let(:result) { double('result') } + + before do + result.stub(:success?).and_return(false) + subject.stub(:execute).and_return(result) + end + + context 'when go fmt returns an error to stdout' do + let(:error_message) { 'some go fmt error' } + + before do + result.stub(:stdout).and_return(error_message) + result.stub(:stderr).and_return('') + end + + it 'executes go fmt for each file' do + files.each do |file| + expect(subject).to receive(:execute).with(subject.command, args: [file]).once + end + subject.run + end + + it 'fails' do + expect(subject).to fail_hook + end + + it 'returns errors' do + message = subject.run.last + expect(message).to eq Array.new(files.count, error_message).join("\n") + end + end + + context 'when fo fmt returns an error to stderr' do + let(:error_message) { 'go: command not found' } + before do + result.stub(:stdout).and_return('') + result.stub(:stderr).and_return(error_message) + end + + it 'executes go fmt for each file' do + files.each do |file| + expect(subject).to receive(:execute).with(subject.command, args: [file]).once + end + subject.run + end + + it 'fails' do + expect(subject).to fail_hook + end + + it 'returns valid message' do + message = subject.run.last + expect(message).to eq Array.new(files.count, error_message).join("\n") + end + end + end +end