#!/usr/bin/env perl use strict; use warnings; use FindBin; use lib "$FindBin::RealBin/../lib"; use Getopt::Long (); use Pod::Usage (); use Try::Tiny (); use Git::Lint; my $VERSION = '1.000'; my %opt = ( profile => 'default', ); Getopt::Long::GetOptions( \%opt, 'check=s', 'profile=s', 'version' => sub { print "git-lint version $VERSION\n"; exit 0 }, 'help', ) or Pod::Usage::pod2usage( -exitval => 1 ); Pod::Usage::pod2usage( -exitval => 0, -verbose => 1 ) if ( $opt{help} ); Pod::Usage::pod2usage( -exitval => 1, -verbose => 0 ) unless $opt{check} && ( $opt{check} eq 'commit' || $opt{check} eq 'message' ); if ( $opt{check} eq 'message' ) { $opt{file} = shift @ARGV; Pod::Usage::pod2usage( -exitval => 1, -verbose => 0, -message => 'check message requires a filename' ) unless $opt{file}; } delete $opt{version}; delete $opt{help}; my $lint = Try::Tiny::try { return Git::Lint->new(); } Try::Tiny::catch { print STDERR "git-lint: [error] $_"; exit 0; }; Try::Tiny::try { $lint->run(\%opt); } Try::Tiny::catch { print STDERR "git-lint: [error] $_"; exit 0; }; if ( $lint->{issues} ) { if ($opt{check} eq 'commit') { foreach my $filename ( keys %{ $lint->{issues} } ) { foreach my $issue ( @{ $lint->{issues}{$filename} } ) { print STDERR "git-lint: [commit] $filename - " . $issue . "\n"; } } } else { foreach my $issue ( @{ $lint->{issues} } ) { print STDERR "git-lint: [message] " . $issue . "\n"; } } exit 1; } exit 0; __END__ =pod =head1 NAME git-lint - lint git commits and messages =head1 SYNOPSIS git-lint [--check commit] [--check message ] [--profile ] [--version] [--help] =head1 DESCRIPTION C is the commandline interface to L, a pluggable framework for linting git commits and messages. =head1 OPTIONS =over =item --check Run either check type C or C. If check type is C, C expects the file path of the commit message to check as an unnamed option. git-lint --check message message_file =item --profile Run a specific profile of check modules. Defaults to the 'default' profile. =item --version Print the version. =item --help Print the help menu. =back =head1 CHECK MODES C has 2 check modes, C and C. =head2 commit The C check mode checks each line of the commit diff for issues defined in the commit check modules. =head2 message The C check mode checks the commit message for issues defined in the message check modules. =head1 CONFIGURATION Configuration is done through C files (F<~/.gitconfig> or F). Only one profile, C, is defined internally. C contains all check modules by default. The C profile can be overridden through C files (F<~/.gitconfig> or F). To set the default profile to only run the C commit check: [lint "profiles.commit"] default = Whitespace Or set the default profile to C and the fictional commit check, C: [lint "profiles.commit"] default = Whitespace, Flipdoozler Additional profiles can be added with a new name and list of checks to run. [lint "profiles.commit"] default = Whitespace, Flipdoozler hardcore = Other, Module, Names Message check profiles can also be defined. [lint "profiles.message"] # override the default profile to only contain SummaryLength, SummaryEndingPeriod, and BlankLineAfterSummary default = SummaryLength, SummaryEndingPeriod, BlankLineAfterSummary # create a summary profile with specific modules summary = SummaryEndingPeriod, SummaryLength An example configuration is provided in the C directory of this project. Configuration is required. If no configuration exists, an error will be printed to STDERR, but the action allowed to complete. blaine@base ~/git/test (master *) $ git add test blaine@base ~/git/test (master +) $ git commit git-lint: [error] configuration setup is required. see the documentation for instructions. [master 894b6d0] test 1 file changed, 1 insertion(+), 1 deletion(-) blaine@base ~/git/test (master) $ =head1 ADDING NEW CHECK MODULES C can be configured to load check modules from a local directory using the C configuration setting. To load modules from a local directory, add the lint C setting, with C key and directory location to the git config file. [lint "config"] localdir = /home/blaine/tmp/git-lint/lib In this example, we're adding a new commit check, C. Create the local directory and path for the new module. $ mkdir -p /home/blaine/tmp/git-lint/lib/Git/Lint/Check/Commit Then add the new check module. $ vi /home/blaine/tmp/git-lint/lib/Git/Lint/Check/Commit/Flipdoozler.pm package Git::Lint::Check::Commit::Flipdoozler; ... Update the commit check profile to use the new module. [lint "profiles.commit"] default = Whitespace, IndentTabs, MixedIndentTabsSpaces, Flipdoozler C will now warn for the check contained in Flipdoozler. blaine@base ~/git/test (master +) $ git commit git-lint: [commit] test - Flipdoozler (line 18) blaine@base ~/git/test (master +) $ =head1 ENABLING CHECKS FOR REPOS To enable as a C hook, copy the C script from the C directory into the C<.git/hooks> directory of the repo you want to check. Once copied, update the path and options to match your path and preferred profile. To enable as a C hook, copy the C script from the C directory into the C<.git/hooks> directory of the repo you want to check. =head1 COPYRIGHT AND LICENSE Copyright (c) 2022 Blaine Motsinger under the MIT license. =head1 AUTHOR Blaine Motsinger C =cut