The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
# -*- cperl -*-

use 5.010;
use strict;
use warnings;
use lib 't';
use Test::More tests => 6;
use Path::Tiny;

BEGIN { require "test-functions.pl" };

my ($repo, $ofile, $clone) = new_repos();

sub commit_on {
    my ($branch) = @_;
    $repo->command(checkout => '-q', $branch);
    my $file = path("$ofile.$branch");
    $file->append('xxx');
    $repo->command(add => "$file");
    $repo->command(commit => '-m', "commit on $branch");
}

# Since the hook cannot abort the commit --amend but just generate a
# suitable error message on stderr we need to check for this message
# instead.

sub check_can_amend {
    my ($testname) = @_;
    my $branch = $repo->get_current_branch();
    $branch =~ s:.*/::;
    my $file = path("$ofile.$branch");
    $file->append($testname);
    $repo->command(add => "$file");

    test_ok_match($testname, qr/^\[master /s, $repo, 'commit', '--amend', '-m', $testname);
}

sub check_cannot_amend {
    my ($testname, $regex) = @_;
    my $branch = $repo->get_current_branch();
    $branch =~ s:.*/::;
    my $file = path("$ofile.$branch");
    $file->append($testname);
    $repo->command(add => "$file");

    test_ok_match($testname, $regex, $repo, 'commit', '--amend', '-m', $testname);
}

sub check_can_rebase {
    my ($testname) = @_;
    test_ok($testname, $repo, 'rebase', 'master', 'fork');
}

sub check_cannot_rebase {
    my ($testname, $regex) = @_;
    test_nok_match($testname, $regex, $repo, 'rebase', 'master');
}


install_hooks($repo, undef, qw/pre-commit post-commit pre-rebase/);

$repo->command(qw/config githooks.plugin CheckRewrite/);

# Create a first commit in master
$repo->command(qw/commit --allow-empty -mx/);
commit_on('master');

# Create a branch and a commit in it
$repo->command(qw/branch fork master/);
commit_on('fork');

# Create a new commit on master to diverge from fork
commit_on('master');

# CHECK AMEND
check_can_amend('allow amend on tip');

my $ammend_message = qr/unsafe "git commit --amend"/;

$repo->command(qw/branch x/);
check_cannot_amend('deny amend with a local branch pointing to HEAD', $ammend_message);

$repo->command(qw/branch -D x/);
$repo->command(qw/push -q clone master/);
check_cannot_amend('deny amend of an already pushed commit', $ammend_message);

$repo->command(qw/reset --hard HEAD/);

# CHECK REBASE
check_can_rebase('allow clean rebase');

my $rebase_message = qr/unsafe rebase/;

commit_on('master');

$repo->command(qw/checkout -q -b x fork/);
check_cannot_rebase('deny rebase with a local branch pointing to HEAD', $rebase_message);

$repo->command(qw/checkout -q fork/);
$repo->command(qw/branch -D x/);
$repo->command(qw/push -q clone fork/);
check_cannot_rebase('deny rebase of an already pushed branch', $rebase_message);