package App::GitHooks::Hook::PreCommit;

use strict;
use warnings;

# Inherit from the base Hook class.
use base 'App::GitHooks::Hook';

# External dependencies.
use Carp;
use Data::Dumper;
use Data::Validate::Type;
use Path::Tiny qw();

# Internal dependencies.
use App::GitHooks::Constants qw( :HOOK_EXIT_CODES :PLUGIN_RETURN_CODES );

=head1 NAME

App::GitHooks::Hook::PreCommit - Handler for pre-commit hook.

=head1 VERSION

Version 1.9.0


our $VERSION = '1.9.0';

=head1 METHODS

=head2 run()

Run the hook handler and return an exit status to pass to git.

	my $exit_status = App::GitHooks::Hook::PreCommit->run(
		app => $app,


=over 4

=item * app I<(mandatory)>

An App::GitHooks object.



sub run
	my ( $class, %args ) = @_;
	my $app = delete( $args{'app'} );
	croak 'Unknown argument(s): ' . join( ', ', keys %args )
		if scalar( keys %args ) != 0;

	# Check parameters.
	croak "The 'app' argument is mandatory"
		if !Data::Validate::Type::is_instance( $app, class => 'App::GitHooks' );

	# Remove the file that we use to indicate that pre-commit checks have been
	# run for the set of staged files, in case it exists.
	unlink( '.git/COMMIT-MSG-CHECKS' );

	# If the terminal isn't interactive, we won't have a human available to fix the
	# problems so we just let the commit go as is.
	my $config = $app->get_config();
	my $force_interactive = $config->get( 'testing', 'force_interactive' );
		if !$app->get_terminal()->is_interactive() && !$force_interactive;

	# Run the checks on the staged changes.
	my $checks_pass = run_all_tests( $app );

	# If the checks passed, write a file for the prepare-commit-msg hook to know
	# that we've already run the checks and there's no need to do it a second time.
	# This is what allows it to detect when --no-verify was used.
	if ( $checks_pass )
		Path::Tiny::path( '.git', 'COMMIT-MSG-CHECKS' )
			->spew( $checks_pass );

	# Indicate if we should allow continuing to the commit message or not.
	return $checks_pass

=head2 run_all_tests()

Run all the tests available for the pre-commit hook and return whether issues
were detected.

	my $tests_success = run_all_tests( $app );

This is a two step operation:

=over 4

=item 1. We load all the plugins that support "pre-commit", and run them to
analyze the overall pre-commit operation.

=item 2. Each staged file is loaded and we run plugins that support
"pre-commit-file" on each one.



sub run_all_tests
	my ( $app ) = @_;

	# Find all the plugins that support the pre-commit hook.
	my $plugins = $app->get_hook_plugins( 'pre-commit' );

	# Run the plugins.
	my $tests_success = 1;
	my $has_warnings = 0;
	foreach my $plugin ( @$plugins )
		my $check_result = $plugin->run_pre_commit(
			app => $app,

		$tests_success = 0
			if $check_result == $PLUGIN_RETURN_FAILED;

		$has_warnings = 1
			if $check_result == $PLUGIN_RETURN_WARNED;

	# Check the changed files individually with plugins that support
	# "pre-commit-file".
		my ( $file_checks, $file_warnings ) = $app
		$tests_success = 0
			if !$file_checks;
		$has_warnings = 1
			if $file_warnings;

	# If warnings were found, notify users.
	if ( $has_warnings )
		# If we have a user, stop and ask if we should continue with the commit.
		# uncoverable branch true
		if ( $app->get_terminal()->is_interactive() )
			print "Some warnings were found. Press <Enter> to continue committing or Ctrl-C to abort the commit.\n";
			my $input = <STDIN>; ## no critic (InputOutput::ProhibitExplicitStdin)
			print "\n";
		# If we don't have a user, just warn and continue.
			print "Some warnings were found, please review.\n";

	return $tests_success;

=head1 BUGS

Please report any bugs or feature requests through the web interface at
I will be notified, and then you'll automatically be notified of progress on
your bug as I make changes.

=head1 SUPPORT

You can find documentation for this module with the perldoc command.

	perldoc App::GitHooks::Hook::PreCommit

You can also look for information at:


=item * GitHub's request tracker


=item * AnnoCPAN: Annotated CPAN documentation


=item * CPAN Ratings


=item * MetaCPAN



=head1 AUTHOR

L<Guillaume Aubert|>,
C<< <aubertg at> >>.


Copyright 2013-2017 Guillaume Aubert.

This code is free software; you can redistribute it and/or modify it under the
same terms as Perl 5 itself.

This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the LICENSE file for more details.