diff --git a/bin/overcommit b/bin/overcommit index eda07c13..21ce4723 100755 --- a/bin/overcommit +++ b/bin/overcommit @@ -5,4 +5,4 @@ require 'overcommit/cli' logger = Overcommit::Logger.new(STDOUT) -Overcommit::CLI.new(ARGV, logger).run +Overcommit::CLI.new(ARGV, STDIN, logger).run diff --git a/lib/overcommit/cli.rb b/lib/overcommit/cli.rb index 35dda583..7c6cc213 100644 --- a/lib/overcommit/cli.rb +++ b/lib/overcommit/cli.rb @@ -4,8 +4,9 @@ module Overcommit # Responsible for parsing command-line options and executing appropriate # application logic based on those options. class CLI # rubocop:disable ClassLength - def initialize(arguments, logger) + def initialize(arguments, input, logger) @arguments = arguments + @input = input @log = logger @options = {} end @@ -177,7 +178,8 @@ def sign_plugins config = Overcommit::ConfigurationLoader.load_repo_config context = Overcommit::HookContext.create(@options[:hook_to_sign], config, - @arguments) + @arguments, + @input) Overcommit::HookLoader::PluginHookLoader.new(config, context, log).update_signatures @@ -186,7 +188,7 @@ def sign_plugins def run_all config = Overcommit::ConfigurationLoader.load_repo_config - context = Overcommit::HookContext.create('run-all', config, @arguments) + context = Overcommit::HookContext.create('run-all', config, @arguments, @input) config.apply_environment!(context, ENV) printer = Overcommit::Printer.new(log, context) diff --git a/lib/overcommit/hook/pre_push/base.rb b/lib/overcommit/hook/pre_push/base.rb new file mode 100644 index 00000000..934ce58d --- /dev/null +++ b/lib/overcommit/hook/pre_push/base.rb @@ -0,0 +1,10 @@ +require 'forwardable' + +module Overcommit::Hook::PrePush + # Functionality common to all pre-push hooks. + class Base < Overcommit::Hook::Base + extend Forwardable + + def_delegators :@context, :remote_name, :remote_url, :pushed_commits + end +end diff --git a/lib/overcommit/hook_context.rb b/lib/overcommit/hook_context.rb index a7ce5721..567ac153 100644 --- a/lib/overcommit/hook_context.rb +++ b/lib/overcommit/hook_context.rb @@ -1,12 +1,12 @@ # Utility module which manages the creation of {HookContext}s. module Overcommit::HookContext - def self.create(hook_type, config, args) + def self.create(hook_type, config, args, input) hook_type_class = Overcommit::Utils.camel_case(hook_type) underscored_hook_type = Overcommit::Utils.snake_case(hook_type) require "overcommit/hook_context/#{underscored_hook_type}" - Overcommit::HookContext.const_get(hook_type_class).new(config, args) + Overcommit::HookContext.const_get(hook_type_class).new(config, args, input) rescue LoadError, NameError => error # Could happen when a symlink was created for a hook type Overcommit does # not yet support. diff --git a/lib/overcommit/hook_context/base.rb b/lib/overcommit/hook_context/base.rb index f234ac09..86d31d8a 100644 --- a/lib/overcommit/hook_context/base.rb +++ b/lib/overcommit/hook_context/base.rb @@ -13,9 +13,10 @@ module Overcommit::HookContext class Base # @param config [Overcommit::Configuration] # @param args [Array] - def initialize(config, args) + def initialize(config, args, input) @config = config @args = args + @input = input end # Returns the camel-cased type of this hook (e.g. PreCommit) @@ -65,5 +66,10 @@ def modified_files def modified_lines(_file) Set.new end + + # Returns an array of lines passed to the hook via STDIN. + def input_lines + @input_lines ||= @input.read.split("\n") + end end end diff --git a/lib/overcommit/hook_context/pre_push.rb b/lib/overcommit/hook_context/pre_push.rb new file mode 100644 index 00000000..b0ac8c17 --- /dev/null +++ b/lib/overcommit/hook_context/pre_push.rb @@ -0,0 +1,26 @@ +module Overcommit::HookContext + # Contains helpers related to contextual information used by pre-push hooks. + class PrePush < Base + attr_accessor :args + + def remote_name + @args[0] + end + + def remote_url + @args[1] + end + + def pushed_commits + input_lines.map do |line| + PushedCommit.new(*line.split(' ')) + end + end + + PushedCommit = Struct.new(:local_ref, :local_sha1, :remote_ref, :remote_sha1) do + def to_s + "#{local_ref} #{local_sha1} #{remote_ref} #{remote_sha1}" + end + end + end +end diff --git a/spec/overcommit/cli_spec.rb b/spec/overcommit/cli_spec.rb index 7db27e13..9aa27031 100644 --- a/spec/overcommit/cli_spec.rb +++ b/spec/overcommit/cli_spec.rb @@ -5,7 +5,8 @@ describe Overcommit::CLI do describe '#run' do let(:logger) { Overcommit::Logger.silent } - let(:cli) { described_class.new(arguments, logger) } + let(:input) { double('input') } + let(:cli) { described_class.new(arguments, input, logger) } subject { cli.run } before do diff --git a/spec/overcommit/hook_context/base_spec.rb b/spec/overcommit/hook_context/base_spec.rb index 73db4d5c..97695f90 100644 --- a/spec/overcommit/hook_context/base_spec.rb +++ b/spec/overcommit/hook_context/base_spec.rb @@ -3,7 +3,8 @@ describe Overcommit::HookContext::Base do let(:config) { double('config') } let(:args) { [] } - let(:context) { described_class.new(config, args) } + let(:input) { double('input') } + let(:context) { described_class.new(config, args, input) } describe '#hook_class_name' do subject { context.hook_class_name } @@ -12,4 +13,14 @@ subject.should == 'Base' end end + + describe '#input_lines' do + subject { context.input_lines } + + before do + input.stub(:read).and_return("line 1\nline 2\n") + end + + it { should == ['line 1', 'line 2'] } + end end diff --git a/spec/overcommit/hook_context/commit_msg_spec.rb b/spec/overcommit/hook_context/commit_msg_spec.rb index 73e28282..782de26b 100644 --- a/spec/overcommit/hook_context/commit_msg_spec.rb +++ b/spec/overcommit/hook_context/commit_msg_spec.rb @@ -4,7 +4,8 @@ describe Overcommit::HookContext::CommitMsg do let(:config) { double('config') } let(:args) { [commit_message_file] } - let(:context) { described_class.new(config, args) } + let(:input) { double('input') } + let(:context) { described_class.new(config, args, input) } let(:commit_msg) do [ '# Please enter the commit message for your changes.', diff --git a/spec/overcommit/hook_context/post_checkout_spec.rb b/spec/overcommit/hook_context/post_checkout_spec.rb index 1c4f5f6d..45f4bf96 100644 --- a/spec/overcommit/hook_context/post_checkout_spec.rb +++ b/spec/overcommit/hook_context/post_checkout_spec.rb @@ -4,10 +4,11 @@ describe Overcommit::HookContext::PostCheckout do let(:config) { double('config') } let(:args) { [previous_head, new_head, branch_flag] } + let(:input) { double('input') } let(:previous_head) { random_hash } let(:new_head) { random_hash } let(:branch_flag) { '1' } - let(:context) { described_class.new(config, args) } + let(:context) { described_class.new(config, args, input) } describe '#previous_head' do subject { context.previous_head } diff --git a/spec/overcommit/hook_context/post_commit_spec.rb b/spec/overcommit/hook_context/post_commit_spec.rb index d80a71d2..fe0eafe4 100644 --- a/spec/overcommit/hook_context/post_commit_spec.rb +++ b/spec/overcommit/hook_context/post_commit_spec.rb @@ -4,7 +4,8 @@ describe Overcommit::HookContext::PostCommit do let(:config) { double('config') } let(:args) { [] } - let(:context) { described_class.new(config, args) } + let(:input) { double('input') } + let(:context) { described_class.new(config, args, input) } describe '#modified_files' do subject { context.modified_files } diff --git a/spec/overcommit/hook_context/post_merge_spec.rb b/spec/overcommit/hook_context/post_merge_spec.rb index df8cca5e..6fdb8a6c 100644 --- a/spec/overcommit/hook_context/post_merge_spec.rb +++ b/spec/overcommit/hook_context/post_merge_spec.rb @@ -4,7 +4,8 @@ describe Overcommit::HookContext::PostMerge do let(:config) { double('config') } let(:args) { [] } - let(:context) { described_class.new(config, args) } + let(:input) { double('input') } + let(:context) { described_class.new(config, args, input) } describe '#squash?' do subject { context.squash? } diff --git a/spec/overcommit/hook_context/post_rewrite_spec.rb b/spec/overcommit/hook_context/post_rewrite_spec.rb index e0fd84a2..20da4f48 100644 --- a/spec/overcommit/hook_context/post_rewrite_spec.rb +++ b/spec/overcommit/hook_context/post_rewrite_spec.rb @@ -3,7 +3,8 @@ describe Overcommit::HookContext::PostRewrite do let(:config) { double('config') } - let(:context) { described_class.new(config, args) } + let(:input) { double('input') } + let(:context) { described_class.new(config, args, input) } describe '#amend?' do subject { context.amend? } diff --git a/spec/overcommit/hook_context/pre_commit_spec.rb b/spec/overcommit/hook_context/pre_commit_spec.rb index 40fa4c3f..cdf3f8ba 100644 --- a/spec/overcommit/hook_context/pre_commit_spec.rb +++ b/spec/overcommit/hook_context/pre_commit_spec.rb @@ -4,7 +4,8 @@ describe Overcommit::HookContext::PreCommit do let(:config) { double('config') } let(:args) { [] } - let(:context) { described_class.new(config, args) } + let(:input) { double('input') } + let(:context) { described_class.new(config, args, input) } describe '#setup_environment' do subject { context.setup_environment } diff --git a/spec/overcommit/hook_context/pre_push_spec.rb b/spec/overcommit/hook_context/pre_push_spec.rb new file mode 100644 index 00000000..2c3b43b7 --- /dev/null +++ b/spec/overcommit/hook_context/pre_push_spec.rb @@ -0,0 +1,46 @@ +require 'spec_helper' +require 'overcommit/hook_context/pre_push' + +describe Overcommit::HookContext::PrePush do + let(:config) { double('config') } + let(:args) { [remote_name, remote_url] } + let(:input) { double('input') } + let(:remote_name) { 'origin' } + let(:remote_url) { 'git@github.com:brigade/overcommit.git' } + let(:context) { described_class.new(config, args, input) } + + describe '#remote_name' do + subject { context.remote_name } + + it { should == remote_name } + end + + describe '#remote_url' do + subject { context.remote_url } + + it { should == remote_url } + end + + describe '#pushed_commits' do + subject(:pushed_commits) { context.pushed_commits } + + let(:local_ref) { 'refs/heads/master' } + let(:local_sha1) { random_hash } + let(:remote_ref) { 'refs/heads/master' } + let(:remote_sha1) { random_hash } + + before do + input.stub(:read).and_return("#{local_ref} #{local_sha1} #{remote_ref} #{remote_sha1}\n") + end + + it 'should parse commit info from the input' do + pushed_commits.length.should == 1 + pushed_commits.each do |pushed_commit| + pushed_commit.local_ref.should == local_ref + pushed_commit.local_sha1.should == local_sha1 + pushed_commit.remote_ref.should == remote_ref + pushed_commit.remote_sha1.should == remote_sha1 + end + end + end +end diff --git a/spec/overcommit/hook_context/run_all_spec.rb b/spec/overcommit/hook_context/run_all_spec.rb index a0a9fea0..bef45038 100644 --- a/spec/overcommit/hook_context/run_all_spec.rb +++ b/spec/overcommit/hook_context/run_all_spec.rb @@ -4,7 +4,8 @@ describe Overcommit::HookContext::RunAll do let(:config) { double('config') } let(:args) { [] } - let(:context) { described_class.new(config, args) } + let(:input) { double('input') } + let(:context) { described_class.new(config, args, input) } describe '#modified_files' do subject { context.modified_files } diff --git a/spec/overcommit/utils_spec.rb b/spec/overcommit/utils_spec.rb index b3786ca5..8d3777c8 100644 --- a/spec/overcommit/utils_spec.rb +++ b/spec/overcommit/utils_spec.rb @@ -108,13 +108,17 @@ describe '.supported_hook_types' do subject { described_class.supported_hook_types } - it { should =~ %w[commit-msg pre-commit post-checkout post-commit post-merge post-rewrite] } + # rubocop:disable Metrics/LineLength + it { should =~ %w[commit-msg pre-commit post-checkout post-commit post-merge post-rewrite pre-push] } + # rubocop:enable Metrics/LineLength end describe '.supported_hook_type_classes' do subject { described_class.supported_hook_type_classes } - it { should =~ %w[CommitMsg PreCommit PostCheckout PostCommit PostMerge PostRewrite] } + # rubocop:disable Metrics/LineLength + it { should =~ %w[CommitMsg PreCommit PostCheckout PostCommit PostMerge PostRewrite PrePush] } + # rubocop:enable Metrics/LineLength end describe '.execute' do diff --git a/template-dir/hooks/overcommit-hook b/template-dir/hooks/overcommit-hook index 61b9de27..3949832a 100755 --- a/template-dir/hooks/overcommit-hook +++ b/template-dir/hooks/overcommit-hook @@ -45,7 +45,7 @@ begin config = Overcommit::ConfigurationLoader.load_repo_config - context = Overcommit::HookContext.create(hook_type, config, ARGV) + context = Overcommit::HookContext.create(hook_type, config, ARGV, STDIN) config.apply_environment!(context, ENV) printer = Overcommit::Printer.new(logger, context) diff --git a/template-dir/hooks/pre-push b/template-dir/hooks/pre-push new file mode 120000 index 00000000..d4cfaf72 --- /dev/null +++ b/template-dir/hooks/pre-push @@ -0,0 +1 @@ +overcommit-hook \ No newline at end of file