App-GitHooks
view release on metacpan or search on metacpan
lib/App/GitHooks/Hook/CommitMsg.pm view on Meta::CPAN
App::GitHooks::Hook::CommitMsg - Handle the commit-msg hook.
=head1 VERSION
Version 1.9.0
=cut
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::CommitMsg->run(
app => $app,
);
Arguments:
=over 4
=item * app I<(mandatory)>
An App::GitHooks object.
=back
=cut
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' );
# Reassigns standard input back to the keyboard.
# Note: this will silently fail in some non-interactive shells where /dev/tty
# can't be referenced, which is fine since there will be no user typing anyway.
my $console = $^O eq 'MSWin32'
? 'CON:'
: '/dev/tty';
open( STDIN, '<', $console ); ## no critic (InputOutput::RequireCheckedOpen)
# 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' );
return $HOOK_EXIT_SUCCESS
if !$app->get_terminal()->is_interactive() && !$force_interactive;
# Analyze the commit message and prompt the user to fix it if needed until it
# passes the checks.
my $has_errors = 0;
while ( 1 )
{
# Retrieve the commit message.
my $command_line_arguments = $app->get_command_line_arguments();
my $commit_message_file = $command_line_arguments->[0];
my $commit_message = App::GitHooks::CommitMessage->new(
message => Path::Tiny::path( $commit_message_file )->slurp_utf8() // '',
app => $app,
);
# If the commit message is empty, don't bother running any checks - git will
# abort the commit.
last
if $commit_message->is_empty();
# Find all the tests we will need to run.
my $plugins = $app->get_hook_plugins( $app->get_hook_name() );
$has_errors = 0;
foreach my $plugin ( @$plugins )
{
my $return_code = $plugin->run_commit_msg(
app => $app,
commit_message => $commit_message,
);
$has_errors = 1
if $return_code == $PLUGIN_RETURN_FAILED;
}
# If errors were found, let the user try to fix the commit message,
# otherwise finish and let git complete.
if ( $has_errors )
{
print "Press <Enter> to edit the commit message or Ctrl-C to abort the commit.\n";
if ( $app->get_terminal()->is_interactive() )
{
my $input = <STDIN>; ## no critic (InputOutput::ProhibitExplicitStdin)
my $editor = $ENV{'EDITOR'} // 'vim';
system("$editor $commit_message_file");
print "\n";
}
else
{
# $has_errors is set to 1, but we're not in interactive mode so we
# can't wait for STDIN.
last;
}
}
else
{
# No errors, $has_errors is set to 0, finish.
last;
}
}
# Success.
return $has_errors
? $HOOK_EXIT_FAILURE
( run in 0.659 second using v1.01-cache-2.11-cpan-6aa56a78535 )