package TestFor::Code::TidyAll::Git;
use Capture::Tiny qw(capture_stdout capture_stderr capture);
use Code::TidyAll::Git::Util qw(git_files_to_commit git_modified_files);
use Code::TidyAll::Util qw(pushd tempdir_simple);
use Code::TidyAll;
use IPC::System::Simple qw(capturex run);
use Path::Tiny qw(path);
use Test::Class::Most parent => 'TestHelper::Test::Class';
my ( $precommit_hook_template, $prereceive_hook_template, $tidyall_ini_template );
sub test_git : Tests {
my ($self) = @_;
$self->require_executable('git');
my $temp_dir = tempdir_simple;
my $work_dir = $temp_dir->child('work');
my $hooks_dir = $work_dir->child(qw( .git hooks ));
my $output;
my $committed = sub {
like( capturex( 'git', 'status' ), qr/nothing to commit/, "committed" );
};
my $uncommitted = sub {
unlike( capturex( 'git', 'status' ), qr/nothing to commit/, "committed" );
};
my $pushed = sub {
unlike( capturex( 'git', 'status' ), qr/Your branch is ahead/, "pushed" );
};
my $unpushed = sub {
like( capturex( 'git', 'status' ), qr/Your branch is ahead/, "unpushed" );
};
my $lib_dirs = join q{ }, map { path($_)->realpath } qw( lib t/lib );
# Create the repo
#
run( "git", "init", $work_dir );
ok( -d $_, "$_ exists" ) for ( $work_dir, $hooks_dir );
my $pushd = pushd($work_dir);
# Add tidyall.ini and .gitignore
#
$work_dir->child('tidyall.ini')->spew( sprintf($tidyall_ini_template) );
$work_dir->child('.gitignore')->spew('.tidyall.d');
run( "git", "add", "tidyall.ini", ".gitignore" );
run( "git", "commit", "-q", "-m", "added", "tidyall.ini", ".gitignore" );
# Add foo.txt, which needs tidying
#
$work_dir->child('foo.txt')->spew("abc\n");
cmp_deeply( [ git_files_to_commit($work_dir) ], [], "no files to commit" );
# git add foo.txt and make sure it is now in uncommitted list
#
run(qw( git add foo.txt ));
cmp_deeply(
[ map { $_->stringify } git_files_to_commit($work_dir) ],
[ $work_dir->child('foo.txt')->stringify ], "one file to commit"
);
# Add pre-commit hook
#
my $precommit_hook_file = $hooks_dir->child('pre-commit');
my $precommit_hook = sprintf( $precommit_hook_template, $lib_dirs );
$precommit_hook_file->spew($precommit_hook);
$precommit_hook_file->chmod(0755);
# Try to commit, make sure we get error
#
$output = capture_stderr { system( "git", "commit", "-m", "changed", "-a" ) };
like( $output, qr/1 file did not pass tidyall check/, "1 file did not pass tidyall check" );
like( $output, qr/needs tidying/, "needs tidying" );
$uncommitted->();
# Fix file and commit successfully
#
$work_dir->child('foo.txt')->spew("ABC\n");
$output = capture_stderr { run( "git", "commit", "-m", "changed", "-a" ) };
like( $output, qr/\[checked\] foo\.txt/, "checked foo.txt" );
$committed->();
$work_dir->child('bar.txt')->spew("ABC");
run( "git", "add", "bar.txt" );
run( "git", "commit", "-q", "-m", "bar.txt" );
$work_dir->child('bar.txt')->spew("def");
cmp_deeply( [ git_files_to_commit($work_dir) ], [], "no files to commit" );
cmp_deeply(
[ map { $_->stringify } git_modified_files($work_dir) ],
["$work_dir/bar.txt"],
"one file was modified"
);
# Create a bare shared repo, then a clone of that
#
my $shared_dir = $temp_dir->child('shared');
my $clone_dir = $temp_dir->child('clone');
run( "git", "clone", "-q", "--bare", $work_dir, $shared_dir );
run( "git", "clone", "-q", $shared_dir, $clone_dir );
chdir($clone_dir);
$committed->();
# Add prereceive hook to shared repo
#
my $prereceive_hook_file = $shared_dir->child(qw( hooks pre-receive ));
my $prereceive_hook = sprintf( $prereceive_hook_template, $lib_dirs );
$prereceive_hook_file->spew($prereceive_hook);
$prereceive_hook_file->chmod(0775);
# Unfix file and commit
#
$clone_dir->child('foo.txt')->spew("def\n");
run( "git", "commit", "-m", "changed", "-a" );
$committed->();
# Try to push, make sure we get error back
#
$unpushed->();
$output = capture_stderr { system( "git", "push" ) };
like( $output, qr/master -> master/, "master -> master" );
like( $output, qr/1 file did not pass tidyall check/, "1 file did not pass tidyall check" );
like( $output, qr/needs tidying/, "needs tidying" );
$unpushed->();
# Fix file and push successfully
#
$clone_dir->child('foo.txt')->spew("DEF\n");
$output = capture_stderr { run( "git", "commit", "-m", "changed", "-a" ) };
$committed->();
$output = capture_stderr { system( "git", "push" ) };
like( $output, qr/master -> master/, "master -> master" );
$pushed->();
# Unfix file and commit
#
$clone_dir->child('foo.txt')->spew("def\n");
run( "git", "commit", "-m", "changed", "-a" );
$committed->();
# Try #1: make sure we get error back
#
$unpushed->();
$output = capture_stderr { system( "git", "push" ) };
like( $output, qr/needs tidying/, "needs tidying" );
$unpushed->();
# Try #2: make sure we get error and repeat notification back
#
$unpushed->();
$output = capture_stderr { system( "git", "push" ) };
like( $output, qr/needs tidying/, "needs tidying" );
like( $output, qr/Identical push seen 2 times/, "Identical push seen 2 times" );
$unpushed->();
}
$precommit_hook_template = '#!' . $^X . "\n" . <<'EOF';
use lib qw(%s);
use Code::TidyAll::Git::Precommit;
use strict;
use warnings;
Code::TidyAll::Git::Precommit->check(
tidyall_options => { verbose => 1 }
);
EOF
$prereceive_hook_template = '#!' . $^X . "\n" . <<'EOF';
use lib qw(%s);
use Code::TidyAll::Git::Prereceive;
use strict;
use warnings;
Code::TidyAll::Git::Prereceive->check();
EOF
$tidyall_ini_template = <<'EOF';
[+TestHelper::Plugin::UpperText]
select = **/*.txt
EOF
1;