-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Arthur Axel 'fREW' Schmidt
committed
Nov 9, 2013
0 parents
commit e17c838
Showing
10 changed files
with
387 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
*.gz | ||
.build | ||
Git-Validate-* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
language: perl | ||
perl: | ||
- "5.18" | ||
- "5.16" | ||
- "5.14" | ||
- "5.12" | ||
- "5.10" | ||
- "5.8" | ||
|
||
install: | ||
- export RELEASE_TESTING=1 AUTOMATED_TESTING=1 AUTHOR_TESTING=1 HARNESS_OPTIONS=j10:c HARNESS_TIMER=1 | ||
- cpanm --quiet --notest Devel::Cover::Report::Coveralls SQL::Translator | ||
- cpanm --quiet --notest --installdeps . | ||
|
||
script: | ||
- PERL5OPT=-MDevel::Cover=-coverage,statement,branch,condition,path,subroutine prove -lrsv t | ||
- cover | ||
after_success: | ||
- cover -report coveralls |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
requires 'Moo' => 1.003001; | ||
requires 'namespace::clean' => 0.23; | ||
requires 'IPC::System::Simple' => 1.25; | ||
requires 'Module::Runtime' => 0.013; | ||
|
||
on test => sub { | ||
requires 'Test::More' => 1.001002; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
name = Git-Validate | ||
author = Arthur Axel "fREW" Schmidt <frioux+cpan@gmail.com> | ||
license = Perl_5 | ||
copyright_holder = Arthur Axel "fREW" Schmidt | ||
version = 0.001000 | ||
|
||
[NextRelease] | ||
[@Git] | ||
[@Basic] | ||
[GithubMeta] | ||
[MetaJSON] | ||
[PickyPodWeaver] | ||
[PkgVersion] | ||
[ReadmeFromPod] | ||
[PodSyntaxTests] | ||
[Prereqs::FromCPANfile] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
package Git::Validate; | ||
|
||
# ABSTRACT: Validate Git Commit Messages | ||
|
||
use IPC::System::Simple 'capture'; | ||
use Module::Runtime 'use_module'; | ||
|
||
use Moo; | ||
|
||
use namespace::clean; | ||
|
||
sub _get_commit_message { capture(qw(git log -1 --pretty=%B), $_[1]) } | ||
|
||
sub validate_commit { | ||
my ($self, $commit) = @_; | ||
|
||
$self->validate_message( | ||
$self->_get_commit_message($commit) | ||
) | ||
} | ||
|
||
sub validate_message { | ||
my ($self, $message) = @_; | ||
|
||
my @lines = split /\n/, $message; | ||
|
||
my @e; | ||
|
||
# check tense? | ||
# check initial case? | ||
push @e, use_module('Git::Validate::Error::LongLine') | ||
->new( line => $lines[0], max_length => 50 ) | ||
if length $lines[0] > 50; | ||
|
||
push @e, use_module('Git::Validate::Error::MissingBreak') | ||
->new( line => $lines[1] ) | ||
if $lines[1]; | ||
|
||
my $i = 2; | ||
for my $l (@lines[2..$#lines]) { | ||
$i++; | ||
push @e, use_module('Git::Validate::Error::LongLine') | ||
->new( line => $l, line_number => $i ) | ||
if $l =~ m/^\S/ && length $l > 72; | ||
} | ||
|
||
use_module('Git::Validate::Errors')->new(errors => \@e) | ||
} | ||
|
||
1; | ||
|
||
__END__ | ||
=pod | ||
=head1 SYNOPSIS | ||
use Git::Validate; | ||
my $validator = Git::Validate->new; | ||
my $errors = $validator->validate_commit('HEAD'); | ||
die "$errors\n" if $errors; | ||
Or if you want to be all classy and modern: | ||
for $e (@{$errors->errors}) { | ||
warn $e->line . " longer than " . $e->max_length . " characters!\n" | ||
if $e->isa('Git::Validate::Error::LongLine') | ||
} | ||
=head1 DESCRIPTION | ||
While many users apparently don't know it, there are actual correct ways to | ||
write a C<git> commit message. For a good summary of why, read | ||
L<< this blog post | http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html >>. | ||
This module does it's best to automatically check commit messages against The | ||
Rules. The current automatic checks are: | ||
=over 2 | ||
=item * First line should be 50 or fewer characters | ||
=item * Second line should be blank | ||
=item * Third and following lines should be less than 72 characters | ||
=back | ||
=head1 METHODS | ||
=head2 C<validate_commit> | ||
my $errors = $validator->validate_commit('HEAD'); | ||
returns L</ERRORS> for a given commit | ||
=head2 C<validate_message> | ||
my $errors = $validator->validate_message($commit_message); | ||
returns L</ERRORS> for a given message | ||
=head1 ERRORS | ||
The object containing errors conveniently C<stringifies> and C<boolifies>. If | ||
you need more information, please please please don't try to parse the returned | ||
strings. Instead, note that the errors returned are a set of objects. These | ||
are the objects you can check for: | ||
=over 2 | ||
=item * C<Git::Validate::Error::LongLine> | ||
=item * C<Git::Validate::Error::MissingBreak> | ||
=back | ||
The objects can be accessed with the C<errors> method, which returns an | ||
arrayref. The objects have C<line> and C<line_number> methods. | ||
The C<::LongLine> objects have a C<max_length> method as well. | ||
=cut | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package Git::Validate::Error::LongLine; | ||
|
||
use Moo; | ||
|
||
use overload q("") => '_stringify'; | ||
|
||
with 'Git::Validate::HasLine'; | ||
|
||
has '+line_number' => ( default => 1 ); | ||
|
||
has max_length => ( | ||
is => 'ro', | ||
default => 72, | ||
); | ||
|
||
sub _stringify { | ||
sprintf 'line %d is too long, max of %d chars, instead it is %d', | ||
$_[0]->line_number, $_[0]->max_length, length $_[0]->line | ||
} | ||
|
||
1; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package Git::Validate::Error::MissingBreak; | ||
|
||
use Moo; | ||
|
||
use overload q("") => '_stringify'; | ||
|
||
with 'Git::Validate::HasLine'; | ||
|
||
has '+line_number' => ( default => 2 ); | ||
|
||
sub _stringify { | ||
sprintf 'line %d should be blank, instead it was "%s"', | ||
$_[0]->line_number, $_[0]->line | ||
} | ||
|
||
1; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package Git::Validate::Errors; | ||
|
||
use Moo; | ||
use overload | ||
q("") => '_stringify', | ||
'bool' => '_boolify', | ||
; | ||
|
||
has errors => ( | ||
is => 'ro', | ||
required => 1, | ||
isa => sub { | ||
die 'errors must be an arrayref' | ||
unless ref $_[0] && ref $_[0] eq 'ARRAY' | ||
}, | ||
); | ||
|
||
sub _stringify { | ||
return "" . $_[0]->errors->[0] if @{$_[0]->errors} == 1; | ||
|
||
join "\n", map " * $_", @{$_[0]->errors} | ||
} | ||
|
||
sub _boolify { scalar @{$_[0]->errors} } | ||
|
||
1; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package Git::Validate::HasLine; | ||
|
||
use Moo::Role; | ||
|
||
has line => ( | ||
is => 'ro', | ||
required => 1, | ||
); | ||
|
||
has line_number => ( | ||
is => 'ro', | ||
required => 1, | ||
); | ||
|
||
1; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
#!/usr/bin/env perl | ||
|
||
use strict; | ||
use warnings; | ||
|
||
use Test::More; | ||
|
||
use Git::Validate; | ||
|
||
my $v = Git::Validate->new; | ||
|
||
{ | ||
my $m =<<'MESSAGE'; | ||
Fix computer | ||
MESSAGE | ||
ok(!@{$v->validate_message($m)->errors}, 'no errors for short simple message'); | ||
} | ||
|
||
{ | ||
my $m =<<'MESSAGE'; | ||
Test Message for thing abcdefghijklmnopqrstuvwxyzt | ||
MESSAGE | ||
ok(!@{$v->validate_message($m)->errors}, 'no errors for exactly 50 char message'); | ||
} | ||
|
||
{ | ||
my $m =<<'MESSAGE'; | ||
Test Message for thing abcdefghijklmnopqrstuvwxyzt | ||
This was a hard test to write, but we got it done. I'm glad we're nearly | ||
still friends! | ||
MESSAGE | ||
ok( | ||
!@{$v->validate_message($m)->errors}, | ||
'no errors for exactly 50 char message and exactly 72 char body', | ||
); | ||
} | ||
|
||
{ | ||
my $m =<<'MESSAGE'; | ||
Test Message for thing abcdefghijklmnopqrstuvwxyzt | ||
This was a hard test to write, but we got it done. I'm glad we're nearly | ||
still friends! | ||
INDENTED CODE IS FOR LITERALS AND THUS CAN BE LONGER THAN 72 CHARACTERS WOO WOO WOO | ||
MESSAGE | ||
ok( | ||
!@{$v->validate_message($m)->errors}, | ||
'no errors for exactly 50 char message and exactly 72 char body and long literal', | ||
); | ||
} | ||
|
||
{ | ||
local $TODO = 'check tense'; | ||
my $m =<<'MESSAGE'; | ||
Fixed computer | ||
MESSAGE | ||
ok(@{$v->validate_message($m)->errors}, 'no errors for short simple message'); | ||
|
||
$m =<<'MESSAGE'; | ||
Fixes computer | ||
MESSAGE | ||
ok(@{$v->validate_message($m)->errors}, 'no errors for short simple message'); | ||
|
||
$m =<<'MESSAGE'; | ||
Fixing computer | ||
MESSAGE | ||
ok(@{$v->validate_message($m)->errors}, 'no errors for short simple message'); | ||
} | ||
|
||
{ | ||
my $m =<<'MESSAGE'; | ||
Fix bug in some dumb thing; also do some other thing do show a long line | ||
MESSAGE | ||
my @e = @{$v->validate_message($m)->errors}; | ||
|
||
is(@e, 1, 'got an error due to long first line'); | ||
ok($e[0]->isa('Git::Validate::Error::LongLine'), 'correct error obj'); | ||
is($e[0]->line_number, 1, 'correct error line'); | ||
is('' . $e[0], 'line 1 is too long, max of 50 chars, instead it is 72', 'correct error line'); | ||
} | ||
|
||
{ | ||
my $m =<<'MESSAGE'; | ||
Fix bug in some dumb thing | ||
also do some other thing do show a non-blank line | ||
MESSAGE | ||
my @e = @{$v->validate_message($m)->errors}; | ||
|
||
is(@e, 1, 'got an error due to non-blank second line'); | ||
ok($e[0]->isa('Git::Validate::Error::MissingBreak'), 'correct error obj'); | ||
is($e[0]->line_number, 2, 'correct error line'); | ||
is('' . $e[0], 'line 2 should be blank, instead it was "also do some other thing do show a non-blank line"', 'correct error line'); | ||
} | ||
|
||
{ | ||
my $m =<<'MESSAGE'; | ||
Fix bug in some dumb thing | ||
Get too wordy and write a much too long body woo woo woo woo woo woo wo woo | ||
MESSAGE | ||
my @e = @{$v->validate_message($m)->errors}; | ||
|
||
is(@e, 1, 'got an error due to too long body line'); | ||
ok($e[0]->isa('Git::Validate::Error::LongLine'), 'correct error obj'); | ||
is($e[0]->line_number, 3, 'correct error line'); | ||
is('' . $e[0], 'line 3 is too long, max of 72 chars, instead it is 75', 'correct error line'); | ||
} | ||
|
||
{ # all together now | ||
my $m =<<'MESSAGE'; | ||
Fix bug in some dumb thing; also do some other thing do show a long line | ||
also do some other thing do show a non-blank line | ||
Get too wordy and write a much too long body woo woo woo woo woo woo wo woo | ||
MESSAGE | ||
my $e = $v->validate_message($m); | ||
my @e = @{$e->errors}; | ||
|
||
is(@e, 3, 'got all the errors'); | ||
|
||
ok($e[0]->isa('Git::Validate::Error::LongLine'), 'correct error obj'); | ||
is($e[0]->line_number, 1, 'correct error line'); | ||
|
||
ok($e[1]->isa('Git::Validate::Error::MissingBreak'), 'correct error obj'); | ||
is($e[1]->line_number, 2, 'correct error line'); | ||
|
||
ok($e[2]->isa('Git::Validate::Error::LongLine'), 'correct error obj'); | ||
is($e[2]->line_number, 3, 'correct error line'); | ||
is($e . "\n", <<'MSG', 'correct error line'); | ||
* line 1 is too long, max of 50 chars, instead it is 72 | ||
* line 2 should be blank, instead it was "also do some other thing do show a non-blank line" | ||
* line 3 is too long, max of 72 chars, instead it is 75 | ||
MSG | ||
} | ||
done_testing; |