Dist-Conformance

 view release on metacpan or  search on metacpan

lib/Dist/Conformance/Check/GitHooks.pm  view on Meta::CPAN

package Dist::Conformance::Check::GitHooks 0.003;

# ABSTRACT: The git hooks are tracked, match their templates, and are installed

use 5.040;
use warnings FATAL => 'all';
use re '/aasx';
use Mojo::Base 'Dist::Conformance::Check', -signatures;

use Dist::Conformance::Schema();
use Dist::Conformance::Snapshot();


sub config_schema ($) {
    return {
        required   => [qw{directory hooks}],
        properties => {
            directory => $Dist::Conformance::Schema::PATH,
            hooks     => { type => 'object', additionalProperties => $Dist::Conformance::Schema::PATH },
            differ    => { %$Dist::Conformance::Schema::STATUS, default => 'info' },
            replace   => { type => 'boolean', default => 0 },
            install   => { type => 'boolean', default => 1 },
        },
    };
}


sub hook_path ( $self, $name ) { return $self->config->{directory} . "/$name" }


sub check ( $self, $snapshot ) {
    my $hooks   = $self->config->{hooks};
    my @names   = sort keys %$hooks;
    my @missing = $self->missing( $snapshot, map { $self->hook_path($_) } @names );
    return ( 'fail', 'missing: ' . join ', ', @missing ) if @missing;
    my @differ = grep { $snapshot->sha( $self->hook_path($_) ) ne Dist::Conformance::Snapshot::blob_sha( ( $self->template( $hooks->{$_} ) )[0] ) } @names;
    return ( $self->config->{differ}, 'customized or outdated: ' . join ', ', map { $self->hook_path($_) } @differ ) if @differ;
    return ( 'pass', 'match the templates' );
}


sub update ( $self, $update ) {
    my ( $hooks, $replace, $install ) = @{ $self->config }{qw{hooks replace install}};
    my $snapshot = $update->snapshot;
    for my $name ( sort keys %$hooks ) {
        my $path   = $self->hook_path($name);
        my ($text) = $self->template( $hooks->{$name} );
        my $have   = $snapshot->content($path);
        if ( !defined $have || ( $replace && $have ne $text ) ) {
            $have = $text if $self->write_template( $update, $path, $hooks->{$name}, oct 755 );
        }
        $update->install_hook( $name, $have ) if $install && defined $have;
    }
    return;
}

__END__

=pod

=encoding UTF-8

=head1 NAME

Dist::Conformance::Check::GitHooks - The git hooks are tracked, match their templates, and are installed

=head1 VERSION

version 0.003

=head1 DESCRIPTION

Git neither versions nor clones hooks, so the hooks of the harness are tracked
in a directory of the repository, and each clone installs them.

The check fails when a hook is missing from C<directory>.  It reports C<differ>
when a hook is there and its blob SHA differs from the SHA of its template:
the repository customized it, or it is older.  Otherwise it passes.  It compares
SHAs, so it reads no hook from a remote snapshot.

The update writes each missing hook from its template, executable.  It
overwrites a hook that differs only when C<replace> is true.  Then, when
C<install> is true, it installs each hook into F<.git/hooks> of the checkout,
or of the main checkout of a worktree, unless the installed hook is the same.
The check cannot see F<.git/hooks>, so a clone that never installed them passes
the check and still gets them from the update.

=head1 METHODS

=head2 hook_path

C<($name)>.  The path of the hook C<$name> in the repository.

=head2 check

=head2 update

Writes the missing hooks, replaces those that differ if C<replace>, and
installs them if C<install>.

=head1 IN A FLAVOR



( run in 1.670 second using v1.01-cache-2.11-cpan-1236ad508bc )