[libcode-tidyall-perl] 163/374: various
Jonas Smedegaard
js at alioth.debian.org
Sun Sep 29 22:26:11 UTC 2013
This is an automated email from the git hooks/post-receive script.
js pushed a commit to branch master
in repository libcode-tidyall-perl.
commit 944645f8bd6ba24cd1a1c2e920401f7e3a4dbc50
Author: Jonathan Swartz <swartz at pobox.com>
Date: Sun Sep 2 17:57:20 2012 -0700
various
---
lib/Code/TidyAll/Git/Precommit.pm | 158 +++++++++++++++++++++++++++++++++++++
lib/Code/TidyAll/Git/Util.pm | 22 ++++++
lib/Code/TidyAll/Util.pm | 1 +
lib/Code/TidyAll/t/Git.pm | 77 ++++++++++++++++++
xt/author/Git.t | 3 +
5 files changed, 261 insertions(+)
diff --git a/lib/Code/TidyAll/Git/Precommit.pm b/lib/Code/TidyAll/Git/Precommit.pm
new file mode 100644
index 0000000..d942a07
--- /dev/null
+++ b/lib/Code/TidyAll/Git/Precommit.pm
@@ -0,0 +1,158 @@
+package Code::TidyAll::Git::Precommit;
+use Capture::Tiny qw(capture_stdout capture_stderr);
+use Code::TidyAll;
+use Code::TidyAll::Util qw(dirname mkpath realpath tempdir_simple write_file);
+use Cwd qw(cwd);
+use Guard;
+use Log::Any qw($log);
+use IPC::System::Simple qw(capturex run);
+use Moo;
+use SVN::Look;
+use Try::Tiny;
+
+# Public
+has 'conf_file' => ( is => 'ro', default => sub { "tidyall.ini" } );
+has 'reject_on_error' => ( is => 'ro' );
+has 'tidyall_class' => ( is => 'ro', default => sub { "Code::TidyAll" } );
+has 'tidyall_options' => ( is => 'ro', default => sub { {} } );
+
+sub check {
+ my ( $class, %params ) = @_;
+
+ my $fail_msg;
+
+ try {
+ my $self = $class->new(%params);
+ my $tidyall_class = $self->tidyall_class;
+
+ # Find conf file at git root
+ my $root_dir = capturex( "git", "rev-parse", "--show-toplevel" );
+ chomp($root_dir);
+ my $conf_file = join( "/", $root_dir, $self->conf_file );
+ die "could not find conf file '$conf_file'" unless -f $conf_file;
+
+ # Store the stash, and restore it upon exiting this scope
+ run("git stash -q --keep-index");
+ scope_guard { run("git stash pop -q") };
+
+ # Gather file paths to be committed
+ my $output = capturex( "git", "status", "--porcelain" );
+ my @files = ( $output =~ /^[MA]\s+(.*)/gm );
+
+ my $tidyall = $tidyall_class->new_from_conf_file(
+ $conf_file,
+ no_cache => 1,
+ check_only => 1,
+ mode => 'commit',
+ %{ $self->tidyall_options },
+ );
+ my @results = $tidyall->process_files( map { "$root_dir/$_" } @files );
+
+ if ( my @error_results = grep { $_->error } @results ) {
+ my $error_count = scalar(@error_results);
+ $fail_msg = join(
+ "\n",
+ sprintf(
+ "%d file%s did not pass tidyall check",
+ $error_count, $error_count > 1 ? "s" : ""
+ ),
+ map { join( ": ", $_->path, $_->msg ) } @error_results
+ );
+ }
+ }
+ catch {
+ my $error = $_;
+ die "Error during pre-commit hook (use --no-verify to skip hook):\n$error";
+ };
+ die $fail_msg if $fail_msg;
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Code::TidyAll::Git::Precommit - Git precommit hook that requires files to be
+tidyall'd
+
+=head1 SYNOPSIS
+
+ In .git/hooks/pre-commit:
+
+ #!/usr/bin/perl
+ use Code::TidyAll::Git::Precommit;
+ use strict;
+ use warnings;
+
+ Code::TidyAll::Git::Precommit->check();
+
+=head1 DESCRIPTION
+
+This module implements a L<Git pre-commit
+hook|http://git-scm.com/book/en/Customizing-Git-Git-Hooks> that checks if all
+files are tidied and valid according to L<tidyall|tidyall>, and rejects the
+commit if not.
+
+=head1 METHODS
+
+=over
+
+=item check (key/value params...)
+
+Class method. Check that all files being added or modified in this commit are
+tidied and valid according to L<tidyall|tidyall>. If not, then the entire
+commit is rejected and the reason(s) are output to the client. e.g.
+
+ % git commit -m "fixups" CHI.pm CHI/Driver.pm
+ 2 files did not pass tidyall check
+ lib/CHI.pm: *** 'PerlTidy': needs tidying
+ lib/CHI/Driver.pm: *** 'PerlCritic': Code before strictures are enabled
+ at /tmp/Code-TidyAll-0e6K/Driver.pm line 2
+ [TestingAndDebugging::RequireUseStrict]
+
+In an emergency the hook can be bypassed by passing --no-verify to commit:
+
+ % git commit --no-verify ...
+
+or you can just move C<.git/hooks/pre-commit> out of the way temporarily.
+
+The configuration file C<tidyall.ini> must be checked into git in the repo root
+directory i.e. next to the .git directory.
+
+The hook will stash any changes not in the index beforehand, and restore them
+afterwards, via
+
+ git stash -q --keep-index
+ ....
+ git stash pop -q
+
+This means that if C<tidyall.ini> has uncommitted changes that are not in the
+index, they will not be used during the tidyall run.
+
+Passes mode = "commit" by default; see L<modes|tidyall/MODES>.
+
+Key/value parameters:
+
+=over
+
+=item no_stash
+
+Don't attempt to stash changes not in the index. This means the hook will
+process all
+
+=item tidyall_class
+
+Subclass to use instead of L<Code::TidyAll|Code::TidyAll>
+
+=item tidyall_options
+
+Hashref of options to pass to the L<Code::TidyAll|Code::TidyAll> constructor
+
+=back
+
+=back
+
+=cut
diff --git a/lib/Code/TidyAll/Git/Util.pm b/lib/Code/TidyAll/Git/Util.pm
new file mode 100644
index 0000000..75600ab
--- /dev/null
+++ b/lib/Code/TidyAll/Git/Util.pm
@@ -0,0 +1,22 @@
+package Code::TidyAll::Git::Util;
+use Cwd qw(realpath);
+use Code::TidyAll::Util qw(pushd uniq);
+use IPC::System::Simple qw(capturex);
+use strict;
+use warnings;
+use base qw(Exporter);
+
+our @EXPORT_OK = qw(git_uncommitted_files);
+
+sub git_uncommitted_files {
+ my ($dir) = @_;
+
+ $dir = realpath($dir);
+ my $pushd = pushd($dir);
+ my $output = capturex( "git", "status" );
+ my @files = ( $output =~ /(?:new file|modified):\s+(.*)/g );
+ @files = uniq( map { "$dir/$_" } @files );
+ return @files;
+}
+
+1;
diff --git a/lib/Code/TidyAll/Util.pm b/lib/Code/TidyAll/Util.pm
index 212eb9b..0a0c351 100644
--- a/lib/Code/TidyAll/Util.pm
+++ b/lib/Code/TidyAll/Util.pm
@@ -6,6 +6,7 @@ use File::Path;
use File::Slurp qw(read_file write_file read_dir);
use File::Spec::Functions qw(abs2rel rel2abs);
use File::Temp qw(tempdir);
+use Guard;
use List::MoreUtils qw(uniq);
use Try::Tiny;
use strict;
diff --git a/lib/Code/TidyAll/t/Git.pm b/lib/Code/TidyAll/t/Git.pm
new file mode 100644
index 0000000..dcaa639
--- /dev/null
+++ b/lib/Code/TidyAll/t/Git.pm
@@ -0,0 +1,77 @@
+package Code::TidyAll::t::Git;
+use Capture::Tiny qw(capture_stdout capture_stderr capture);
+use Code::TidyAll::Git::Util qw(git_uncommitted_files);
+use Code::TidyAll::Util qw(dirname mkpath pushd read_file realpath tempdir_simple write_file);
+use Code::TidyAll;
+use IPC::System::Simple qw(run);
+use Test::Class::Most parent => 'Code::TidyAll::Test::Class';
+
+my ( $precommit_hook_template, $tidyall_ini_template );
+
+sub test_git : Tests {
+ my ($self) = @_;
+
+ my $temp_dir = tempdir_simple;
+ my $work_dir = "$temp_dir/work";
+ my $hooks_dir = "$work_dir/.git/hooks";
+ my ( $stdout, $stderr );
+
+ my $committed = sub {
+ $stdout = capture_stdout { system('git status') };
+ like( $stdout, qr/nothing to commit/, "committed" );
+ };
+
+ my $uncommitted = sub {
+ $stdout = capture_stdout { system('git status') };
+ unlike( $stdout, qr/nothing to commit/, "uncommitted" );
+ };
+
+ run( "git", "init", $work_dir );
+ ok( -d $_, "$_ exists" ) for ( $work_dir, $hooks_dir );
+ my $pushd = pushd($work_dir);
+
+ write_file( "$work_dir/tidyall.ini", sprintf($tidyall_ini_template) );
+ write_file( "$work_dir/.gitignore", ".tidyall.d" );
+ run( "git", "add", "tidyall.ini", ".gitignore" );
+ run( "git", "commit", "-m", "added", "tidyall.ini", ".gitignore" );
+
+ write_file( "$work_dir/foo.txt", "abc" );
+ cmp_deeply( [ git_uncommitted_files($work_dir) ], [], "no uncommitted files" );
+
+ run( "git", "add", "foo.txt" );
+ cmp_deeply( [ git_uncommitted_files($work_dir) ],
+ ["$work_dir/foo.txt"], "one uncommitted file" );
+
+ my $precommit_hook_file = "$hooks_dir/pre-commit";
+ my $precommit_hook = sprintf( $precommit_hook_template, realpath("lib") );
+ write_file( $precommit_hook_file, $precommit_hook );
+ chmod( 0775, $precommit_hook_file );
+
+ $stderr = capture_stderr { system( "git", "commit", "-m", "changed", "-a" ) };
+ like( $stderr, qr/1 file did not pass tidyall check/ );
+ like( $stderr, qr/needs tidying/ );
+ $uncommitted->();
+
+ write_file( "$work_dir/foo.txt", "ABC" );
+ $stderr = capture_stderr { system( "git", "commit", "-m", "changed", "-a" ) };
+ like( $stderr, qr/\[checked\] foo\.txt/ );
+ $committed->();
+}
+
+$precommit_hook_template = '#!/usr/bin/perl
+use lib qw(%s);
+use Code::TidyAll::Git::Precommit;
+use strict;
+use warnings;
+
+Code::TidyAll::Git::Precommit->check(
+ tidyall_options => { verbose => 1 }
+);
+';
+
+$tidyall_ini_template = '
+[+Code::TidyAll::Test::Plugin::UpperText]
+select = **/*.txt
+';
+
+1;
diff --git a/xt/author/Git.t b/xt/author/Git.t
new file mode 100644
index 0000000..89e2f84
--- /dev/null
+++ b/xt/author/Git.t
@@ -0,0 +1,3 @@
+#!/usr/bin/perl
+use Code::TidyAll::t::Git;
+Code::TidyAll::t::Git->runtests;
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-perl/packages/libcode-tidyall-perl.git
More information about the Pkg-perl-cvs-commits
mailing list