Merge branch 'master' into model-reorg
Zachary Stevens [Sun, 8 Nov 2009 12:47:05 +0000 (12:47 +0000)]
Conflicts:
t/01app.t

35 files changed:
Makefile.PL
README
gitalist.conf
lib/Gitalist/Controller/Root.pm
lib/Gitalist/Git/Object.pm
lib/Gitalist/Git/Project.pm
lib/Gitalist/Git/Repo.pm
lib/Gitalist/Git/Util.pm
lib/Gitalist/Model/Git.pm
t/01app.t
t/02git_util.t
t/gitalist.conf [new file with mode: 0644]
t/lib/repositories/nodescription/HEAD [new file with mode: 0644]
t/lib/repositories/nodescription/config [new file with mode: 0644]
t/lib/repositories/nodescription/hooks/applypatch-msg [new file with mode: 0644]
t/lib/repositories/nodescription/hooks/commit-msg [new file with mode: 0644]
t/lib/repositories/nodescription/hooks/post-commit [new file with mode: 0644]
t/lib/repositories/nodescription/hooks/post-update [new file with mode: 0644]
t/lib/repositories/nodescription/hooks/pre-applypatch [new file with mode: 0644]
t/lib/repositories/nodescription/hooks/pre-commit [new file with mode: 0644]
t/lib/repositories/nodescription/hooks/pre-rebase [new file with mode: 0644]
t/lib/repositories/nodescription/hooks/update [new file with mode: 0644]
t/lib/repositories/nodescription/info/exclude [new file with mode: 0644]
t/lib/repositories/nodescription/objects/14/5dc3ef5d307be84cb9b325d70bd08aeed0eceb [new file with mode: 0644]
t/lib/repositories/nodescription/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99 [new file with mode: 0644]
t/lib/repositories/nodescription/objects/36/c6c6708b8360d7023e8a1649c45bcf9b3bd818 [new file with mode: 0644]
t/lib/repositories/nodescription/objects/3b/c0634310b9c62222bb0e724c11ffdfb297b4ac [new file with mode: 0644]
t/lib/repositories/nodescription/objects/3f/7567c7bdf7e7ebf410926493b92d398333116e [new file with mode: 0644]
t/lib/repositories/nodescription/objects/57/16ca5987cbf97d6bb54920bea6adde242d87e6 [new file with mode: 0644]
t/lib/repositories/nodescription/objects/72/9a7c3f6ba5453b42d16a43692205f67fb23bc1 [new file with mode: 0644]
t/lib/repositories/nodescription/objects/82/b5fee28277349b6d46beff5fdf6a7152347ba0 [new file with mode: 0644]
t/lib/repositories/nodescription/objects/90/62594aebb5df0de7fb92413f17a9eced196c22 [new file with mode: 0644]
t/lib/repositories/nodescription/objects/pack/.gitignore [new file with mode: 0644]
t/lib/repositories/nodescription/refs/heads/master [new file with mode: 0644]
t/model_Git.t

index a1824c3..ee268f1 100644 (file)
@@ -6,9 +6,11 @@ use warnings;
 use inc::Module::Install;
 use Module::Install::AuthorRequires;
 use Module::Install::AuthorTests;
+use Module::Install::ReadmeFromPod;
 
 name 'Gitalist';
 all_from 'lib/Gitalist.pm';
+readme_from 'lib/Gitalist.pm';
 
 requires 'Catalyst::Runtime' => '5.80003';
 requires 'Catalyst::Plugin::ConfigLoader';
@@ -22,12 +24,14 @@ requires 'namespace::autoclean';
 requires 'Config::General'; # This should reflect the config file format you've chosen
                  # See Catalyst::Plugin::ConfigLoader for supported formats
 requires 'MooseX::Types::Common';
+requires 'MooseX::Types::Path::Class';
+requires 'MooseX::Types';
 requires 'File::Find::Rule';
 requires 'File::Stat::ModeString';
-requires 'File::Slurp';
 requires 'DateTime::Format::Mail';
 requires 'IO::Capture::Stdout';
 requires 'File::Which';
+requires 'aliased';
 requires 'CGI';
 requires 'DateTime';
 requires 'Git::PurePerl'; # Note - need the git version in broquaint's fork
@@ -48,7 +52,6 @@ test_requires 'Test::More' => '0.88';
 catalyst;
 
 author_tests 't/author';
-
 install_script glob('script/*.pl');
 auto_install;
 WriteAll;
diff --git a/README b/README
index cfddeac..6e221de 100644 (file)
--- a/README
+++ b/README
@@ -1,46 +1,26 @@
-Gitalist - a transitional project to convert gitweb.cgi to a Catalyst app.
+NAME
+    Gitalist - Catalyst based application
 
-The idea behind this project is to move gitweb.cgi away from a single
-monolithic CGI script and into a modern Catalyst app. Fortunately this is not
-as daunting as it might seem at first as gitweb.cgi follows an MVC type
-structure. Once gitweb.cgi has been suitably Catalysed then it can move from
-being "this was once gitweb.cgi" to a project of its own (hence the
-"transitional" in the description).
+SYNOPSIS
+        script/gitalist_server.pl
 
-As it stands Gitalist is very much in its infancy and hasn't got far
-beyond a layout template and a single controller.
+DESCRIPTION
+    [enter your description here]
 
-USAGE
+SEE ALSO
+    Gitalist::Controller::Root, Catalyst
 
-To get Gitalist up and running just set projectroot & repo_dir (one in
-the same unfortunately at this point) in gitalist.conf to point to the
-directory that contains your repositories. With that done just run:
+AUTHORS AND COPYRIGHT
+      Catalyst application:
+        (C) 2009 Venda Ltd and Dan Brook <dbrook@venda.com>
 
-  perl script/gitalist_server.pl
+      Original gitweb.cgi from which this was derived:
+        (C) 2005-2006, Kay Sievers <kay.sievers@vrfy.org>
+        (C) 2005, Christian Gierke
 
-DEPENDENCIES
+LICENSE
+    FIXME - Is this going to be GPLv2 as per gitweb? If so this is broken..
 
-  Catalyst
-  IO::Capture::Stdout
-  Catalyst::View::ContentNegotiation::XHTML
-  Template::Plugin::Cycle
-  DateTime
-  Path::Class
-  File::Find::Rule;
-  DateTime::Format::Mail
-  File::Stat::ModeString
-  List::MoreUtils
-  MooseX::Types::Common
-  # Probably others ...
+    This library is free software. You can redistribute it and/or modify it
+    under the same terms as Perl itself.
 
-COPYRIGHT AND LICENCE
-
-Copyright (C) 2009 Venda Ltd
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself, either Perl version 5.8.8 or,
-at your option, any later version of Perl 5 you may have available.
-
-gitweb.pm is based on the gitweb.perl from git-1.6.3.3
-(C) 2005-2006, Kay Sievers <kay.sievers@vrfy.org>
-(C) 2005, Christian Gierke
index 386071e..2dad2f7 100644 (file)
@@ -2,7 +2,6 @@ name Gitalist
 
 <Model::Git>
     #git /path/to/git
-    projectroot __path_to(../)__
     repo_dir __path_to(../)__
 </Model::Git>
 
index 91d0255..4be75a5 100644 (file)
@@ -119,18 +119,27 @@ A summary of what's happening in the repo.
 
 sub summary : Local {
   my ( $self, $c ) = @_;
-
+  $c->stash(current_model => 'GitRepos');
+  warn("project is " . $c->stash->{project});
+  my $project;
+  eval {
+      $project = $c->model()->project($c->stash->{project});
+  };
+  if ($@) {
+      $c->detach('error_404');
+  }
   my $commit = $self->_get_commit($c);
   $c->stash(
     commit    => $commit,
-    info      => $c->model()->project_info($c->model()->project),
-    log_lines => [$c->model()->list_revs(
-      sha1 => $commit->sha1, count => Gitalist->config->{paging}{summary}
+    info      => $project->info,
+    log_lines => [$project->list_revs(
+        sha1 => $commit->sha1,
+        count => Gitalist->config->{paging}{summary} || 50
     )],
-    refs      => $c->model()->references,
-    heads     => [$c->model()->heads],
+    refs      => $project->references,
+    heads     => [$project->heads],
     action    => 'summary',
-  );
+);
 }
 
 =head2 heads
@@ -591,6 +600,15 @@ sub end : ActionClass('RenderView') {
   }
 }
 
+sub error_404 :Private {
+    my ($self, $c) = @_;
+    $c->response->status(404);
+    $c->stash(
+        title => 'Page not found',
+        content => 'Page not found',
+    )
+}
+
 sub age_string {
        my $age = shift;
        my $age_str;
index 0346365..00f037e 100644 (file)
@@ -1,26 +1,29 @@
 use MooseX::Declare;
+use Moose::Autobox;
 
 class Gitalist::Git::Object {
     use MooseX::Types::Moose qw/Str Int/;
+    use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
     use File::Stat::ModeString qw/mode_to_string/;
     # project and sha1 are required initargs
     has project => ( isa => 'Gitalist::Git::Project',
                      required => 1,
                      is => 'ro',
+                     weak_ref => 1,
                      handles => [ 'run_cmd' ],
                  );
-    has sha1 => ( isa => Str,
+    has sha1 => ( isa => NonEmptySimpleStr,
                required => 1,
                is => 'ro' );
 
-    has $_ => ( isa => Str,
+    has $_ => ( isa => NonEmptySimpleStr,
                   required => 1,
                   is => 'ro',
                   lazy_build => 1 )
         for qw/type modestr size/;
 
     # objects can't determine their mode or filename
-    has file => ( isa => Str,
+    has file => ( isa => NonEmptySimpleStr,
                   required => 0,
                   is => 'ro' );
     has mode => ( isa => Int,
@@ -28,25 +31,23 @@ class Gitalist::Git::Object {
                 default => 0,
                 is => 'ro' );
 
-    method BUILD {
-        $self->$_() for qw/type modestr size/; # Ensure to build early.
-    }
+    method BUILD { $self->$_() for qw/type size modestr/ }
 
-    method _build_type {
-        my $output = $self->run_cmd(qw/cat-file -t/, $self->{sha1});
-        chomp($output);
-        return $output;
+    foreach my $key (qw/ type size /) {
+        method "_build_$key" {
+            my $v = $self->_cat_file_with_flag(substr($key, 0, 1));
+            chomp($v);
+            return $v;
+        }
     }
 
     method _build_modestr {
-        my $modestr = mode_to_string($self->{mode});
+        my $modestr = mode_to_string($self->mode);
         return $modestr;
     }
 
-    method _build_size {
-        my $output = $self->run_cmd(qw/cat-file -s/, $self->{sha1});
-        chomp($output);
-        return $output;
+    method _cat_file_with_flag ($flag) {
+        $self->run_cmd('cat-file', '-' . $flag, $self->{sha1})
     }
 
 =head2 contents
@@ -55,15 +56,13 @@ Return the contents of a given file.
 
 =cut
 
+    # FIXME - Should be an attribute so it gets cached?
     method contents {
         if ( $self->type ne 'blob' ) {
             die "object $self->sha1 is not a file\n"
         }
 
-        my $output = $self->run_cmd(qw/cat-file -p/, $self->sha1);
-        return unless $output;
-
-        return $output;
+        $self->_cat_file_with_flag('p');
     }
 
 } # end class
index e11da8e..9ce7e5a 100644 (file)
@@ -3,9 +3,9 @@ use MooseX::Declare;
 class Gitalist::Git::Project {
     # FIXME, use Types::Path::Class and coerce
     use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
-    use MooseX::Types::Moose qw/Str Maybe/;
+    use MooseX::Types::Moose qw/Str Maybe Bool HashRef/;
     use DateTime;
-    use Path::Class;
+    use MooseX::Types::Path::Class qw/Dir/;
     use Gitalist::Git::Util;
     use aliased 'Gitalist::Git::Object';
 
@@ -13,7 +13,7 @@ class Gitalist::Git::Project {
 
     has name => ( isa => NonEmptySimpleStr,
                   is => 'ro', required => 1 );
-    has path => ( isa => "Path::Class::Dir",
+    has path => ( isa => Dir,
                   is => 'ro', required => 1);
 
     has description => ( isa => Str,
@@ -31,9 +31,34 @@ class Gitalist::Git::Project {
     has _util => ( isa => 'Gitalist::Git::Util',
                    is => 'ro',
                    lazy_build => 1,
-                   handles => [ 'run_cmd' ],
+                   handles => [ 'run_cmd', 'get_gpp_object' ],
                );
 
+    has project_dir => ( isa => Dir,
+        is => 'ro',
+        lazy => 1,
+        default => sub {
+            my $self = shift;
+            $self->is_bare
+                ? $self->path
+                : $self->path->subdir('.git')
+        },
+    );
+    has is_bare => (
+        isa => Bool,
+        is => 'ro',
+        lazy => 1,
+        default => sub {
+            my $self = shift;
+            -f $self->path->file('.git', 'HEAD')
+                ? 0
+                : -f $self->path->file('HEAD')
+                    ? 1
+                    : confess("Cannot find " . $self->path . "/.git/HEAD or "
+                        . $self->path . "/HEAD");
+        },
+    );
+
     method BUILD {
         $self->$_() for qw/_util last_change owner description/; # Ensure to build early.
     }
@@ -46,21 +71,21 @@ class Gitalist::Git::Project {
 
     method _build__util {
         Gitalist::Git::Util->new(
-            gitdir => $self->_project_dir($self->path),
+            project => $self,
         );
     }
 
     method _build_description {
         my $description = "";
         eval {
-            $description = $self->path->file('description')->slurp;
+            $description = $self->project_dir->file('description')->slurp;
             chomp $description;
         };
         return $description;
     }
 
     method _build_owner {
-        my ($gecos, $name) = (getpwuid $self->path->stat->uid)[6,0];
+        my ($gecos, $name) = (getpwuid $self->project_dir->stat->uid)[6,0];
         $gecos =~ s/,+$//;
         return length($gecos) ? $gecos : $name;
     }
@@ -100,6 +125,28 @@ class Gitalist::Git::Project {
         return @ret;
     }
 
+    method references {
+       return $self->{references}
+               if $self->{references};
+
+       # 5dc01c595e6c6ec9ccda4f6f69c131c0dd945f8c refs/tags/v2.6.11
+       # c39ae07f393806ccf406ef966e9a15afc43cc36a refs/tags/v2.6.11^{}
+       my $cmdout = $self->run_cmd(qw(show-ref --dereference))
+               or return;
+        my @reflist = $cmdout ? split(/\n/, $cmdout) : ();
+       my %refs;
+       for(@reflist) {
+               push @{$refs{$1}}, $2
+                       if m!^($SHA1RE)\srefs/(.*)$!;
+       }
+
+       return $self->{references} = \%refs;
+}
+
+    method valid_rev (Str $rev) {
+        return ($rev =~ /^($SHA1RE)$/);
+    }
+
 
 =head2 head_hash
 
@@ -194,6 +241,50 @@ The keys for each item will be:
                 : $3;
     }
 
+    method list_revs ( NonEmptySimpleStr :$sha1!,
+                       Int :$count?,
+                       Int :$skip?,
+                       HashRef :$search?,
+                       NonEmptySimpleStr :$file?
+                   ) {
+        $sha1 = $self->head_hash($sha1)
+            if !$sha1 || $sha1 !~ $SHA1RE;
+
+       my @search_opts;
+        if($search) {
+            $search->{type} = 'grep'
+                if $search->{type} eq 'commit';
+            @search_opts = (
+                # This seems a little fragile ...
+                qq[--$search->{type}=$search->{text}],
+                '--regexp-ignore-case',
+                $search->{regexp} ? '--extended-regexp' : '--fixed-strings'
+            );
+        }
+
+        my $output = $self->run_cmd(
+            'rev-list',
+            '--header',
+            (defined $count ? "--max-count=$count" : ()),
+            (defined $skip ? "--skip=$skip"       : ()),
+            @search_opts,
+            $sha1,
+            '--',
+            ($file ? $file : ()),
+        );
+        return unless $output;
+
+        my @revs = $self->parse_rev_list($output);
+
+        return @revs;
+    }
+
+    method parse_rev_list ($output) {
+        return
+            map  $self->get_gpp_object($_),
+                grep $self->valid_rev($_),
+                    map  split(/\n/, $_, 6), split /\0/, $output;
+    }
 
 
     # Compatibility
index efddd96..4146575 100644 (file)
@@ -2,17 +2,20 @@ use MooseX::Declare;
 
 class Gitalist::Git::Repo {
     use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
-    use Path::Class;
+    use MooseX::Types::Path::Class qw/Dir/;
+    use MooseX::Types::Moose qw/ArrayRef/;
     use Gitalist::Git::Project;
-    has repo_dir => ( isa => NonEmptySimpleStr,
-                      is => 'ro',
-                      required => 1 );
+    has repo_dir => (
+        isa => Dir,
+        is => 'ro',
+        required => 1,
+        coerce => 1,
+    );
 
     method project (NonEmptySimpleStr $project) {
-        my $pd = $self->dir_from_project_name($project);
         return Gitalist::Git::Project->new(
             name => $project,
-            path => $pd,
+            path => $self->repo_dir->subdir($project),
         );
     }
 
@@ -28,18 +31,6 @@ C<git> repo.
         return -f $dir->file('HEAD') || -f $dir->file('.git', 'HEAD');
     }
 
-=head2 project_dir
-
-The directory under which the given project will reside i.e C<.git/..>
-
-=cut
-
-    method project_dir ($project) {
-        -f $project->file('.git', 'HEAD')
-            ? $project->subdir('.git')
-            : $project;
-    }
-
 =head2 list_projects
 
 For the C<repo_dir> specified in the config return an array of projects where
@@ -47,10 +38,16 @@ each item will contain the contents of L</project_info>.
 
 =cut
 
-    method list_projects {
-        my $base = dir($self->repo_dir);
-        my @ret;
+    has projects => (
+        isa => ArrayRef['Gitalist::Git::Project'],
+        reader => 'list_projects',
+        lazy_build => 1,
+    );
+
+    method _build_projects {
+        my $base = $self->repo_dir;
         my $dh = $base->open || die "Could not open $base";
+        my @ret;
         while (my $file = $dh->read) {
             next if $file =~ /^.{1,2}$/;
 
@@ -58,28 +55,12 @@ each item will contain the contents of L</project_info>.
             next unless -d $obj;
             next unless $self->_is_git_repo($obj);
 
-            # FIXME - Is resolving project_dir here sane?
-            #         I think not, just pass $obj down, and
-            #         resolve $project->path and $project->is_bare
-            #         in BUILDARGS
-            push @ret, Gitalist::Git::Project->new( name => $file,
-                                     path => $self->project_dir($obj),
-                                 );
+            push @ret, Gitalist::Git::Project->new(
+                name => $file,
+                path => $obj,
+            );
         }
 
-        return [sort { $a->{name} cmp $b->{name} } @ret];
+        return [sort { $a->name cmp $b->name } @ret];
     }
-
-=head2 dir_from_project_name
-
-Get the corresponding directory of a given project.
-
-=cut
-
-    method dir_from_project_name (Str $project) {
-        return dir($self->repo_dir)->subdir($project);
-    }
-
-
-
 }                               # end class
index d624c4d..a38eb70 100644 (file)
@@ -4,7 +4,12 @@ class Gitalist::Git::Util {
     use File::Which;
     use Git::PurePerl;
     use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
-    has gitdir => ( isa => 'Path::Class::Dir', is => 'ro', required => 1 );
+    has project => (
+        isa => 'Gitalist::Git::Project',
+        handles => { gitdir => 'project_dir' },
+        is => 'bare', # No accessor
+        weak_ref => 1, # Weak, you have to hold onto me.
+    );
     has _git      => ( isa => NonEmptySimpleStr, is => 'ro', lazy_build => 1 );
     sub _build__git {
         my $git = File::Which::which('git');
@@ -19,16 +24,15 @@ EOR
         return $git;
     }
 
-    has _gpp      => ( isa => 'Git::PurePerl',   is => 'rw', lazy_build => 1 );
-    method _build__gpp {
-        my $gpp = Git::PurePerl->new(gitdir => $self->gitdir);
-        return $gpp;
-    }
+    has _gpp      => (
+        isa => 'Git::PurePerl', is => 'ro', lazy => 1,
+        default => sub { Git::PurePerl->new(gitdir => shift->gitdir) },
+    );
 
     method run_cmd (@args) {
         unshift @args, ( '--git-dir' => $self->gitdir );
-        print STDERR 'RUNNING: ', $self->_git, qq[ @args], $/;
-        
+#        print STDERR 'RUNNING: ', $self->_git, qq[ @args], $/;
+
         open my $fh, '-|', $self->_git, @args
             or die "failed to run git command";
         binmode $fh, ':encoding(UTF-8)';
@@ -39,9 +43,8 @@ EOR
         return $output;
     }
 
+    method get_gpp_object (NonEmptySimpleStr $sha1) {
+        return $self->_gpp->get_object($sha1) || undef;
+    }
 
-
-
-
-#
 } # end class
index 63a03b7..a26a500 100644 (file)
@@ -129,7 +129,7 @@ Call out to the C<git> binary and return a string consisting of the output.
 sub run_cmd {
   my ($self, @args) = @_;
 
-  print STDERR 'RUNNING: ', $self->git, qq[ @args], $/;
+#  print STDERR 'RUNNING: ', $self->git, qq[ @args], $/;
 
   open my $fh, '-|', $self->git, @args
     or die "failed to run git command";
index 1c69c5b..dac001d 100644 (file)
--- a/t/01app.t
+++ b/t/01app.t
@@ -1,43 +1,45 @@
 #!/usr/bin/env perl
 use strict;
 use warnings;
-use Test::More qw/no_plan/;
+use Test::More;
+use FindBin qw/$Bin/;
 
-BEGIN { use_ok 'Catalyst::Test', 'Gitalist' }
-
-# Full tests are only run if the APP_TEST env var is set.
-# This is needed to load the test configuration.
-diag("*** SKIPPING app tests.
-*** Set APP_TEST for the tests to run fully") if !$ENV{APP_TEST};
-SKIP: {
-  skip "Set APP_TEST for the tests to run fully",
-    1 if !$ENV{APP_TEST};
+BEGIN {
+    $ENV{GITALIST_CONFIG} = $Bin;
+    use_ok 'Catalyst::Test', 'Gitalist'
+}
 
-  ok( request('/')->is_success, 'Request should succeed' );
+ok( request('/')->is_success, 'Request should succeed' );
 
+for my $p (qw/ repo1 nodescription /) {
+    my $path = '/summary?p=' . $p;
+    ok( request($path)->is_success, "$path should succeed");
+}
 
+is request('/summary?p=DoesNotExist')->code, 404,
+    '/summary?p=DoesNotExist 404s';
+{
   # URI tests for repo1
-  use Data::Dumper;
-  my $test_repo1 = curry_test_uri('repo1');
-  &$test_repo1('/summary');
-  &$test_repo1('/heads');
-  &$test_repo1('/shortlog');
-  &$test_repo1('/log');
-  &$test_repo1('/commit');
-  &$test_repo1('/commitdiff');
-  &$test_repo1('/tree');
+  local *test = curry_test_uri('repo1');
+  test('/summary');
+  test('/shortlog');
+  test('/log');
+  test('/commit');
+  test('/commitdiff', 'h=36c6c6708b8360d7023e8a1649c45bcf9b3bd818');
+  test('/tree', 'h=145dc3ef5d307be84cb9b325d70bd08aeed0eceb;hb=36c6c6708b8360d7023e8a1649c45bcf9b3bd818');
 
   # legacy URIs
-  &$test_repo1('/', 'a=summary');
-  &$test_repo1('/', 'a=heads');
-  &$test_repo1('/', 'a=shortlog');
-  &$test_repo1('/', 'a=log');
-  &$test_repo1('/', 'a=commit');
-  &$test_repo1('/', 'a=commitdiff');
-  &$test_repo1('/', 'a=tree');
-#  &$test_repo1('/', 'a=blob;f=file1');
-
-} # Close APP_TEST skip
+  test('/', 'a=summary');
+  test('/', 'a=heads');
+  test('/', 'a=shortlog');
+  test('/', 'a=log');
+  test('/', 'a=commit');
+  test('/', 'a=commitdiff');
+  test('/', 'a=tree');
+#  $test_repo1->('/', 'a=blob;f=file1');
+}
+
+done_testing;
 
 sub test_uri {
     my ($p, $uri, $qs) = @_;
index 730754a..1ba7f8c 100644 (file)
@@ -1,23 +1,28 @@
 use strict;
 use warnings;
 use FindBin qw/$Bin/;
-use Test::More qw/no_plan/;
+use Test::More;
 
 use Data::Dumper;
 
-BEGIN { use_ok 'Gitalist::Git::Util' }
+BEGIN {
+    use_ok 'Gitalist::Git::Util';
+    use_ok 'Gitalist::Git::Project';
+}
 
 use Path::Class;
 my $gitdir = dir("$Bin/lib/repositories/repo1");
 
-my $proj = Gitalist::Git::Util->new(
-    gitdir => $gitdir,
+my $proj = Gitalist::Git::Project->new(
+    path => $gitdir,
+    name => "repo1",
 );
-isa_ok($proj, 'Gitalist::Git::Util');
-
-like( $proj->_git, qr#/git$#, 'git binary found');
-isa_ok($proj->_gpp, 'Git::PurePerl', 'gpp instance created');
-is($proj->gitdir, $gitdir, 'repository path is set');
-
+my $util = Gitalist::Git::Util->new(
+    project => $proj,
+);
+isa_ok($util, 'Gitalist::Git::Util');
 
+like( $util->_git, qr#/git$#, 'git binary found');
+isa_ok($util->_gpp, 'Git::PurePerl', 'gpp instance created');
 
+done_testing;
diff --git a/t/gitalist.conf b/t/gitalist.conf
new file mode 100644 (file)
index 0000000..ca0d768
--- /dev/null
@@ -0,0 +1,4 @@
+<Model::Git>
+    repo_dir __path_to(t/lib/repositories)__
+</Model::Git>
+
diff --git a/t/lib/repositories/nodescription/HEAD b/t/lib/repositories/nodescription/HEAD
new file mode 100644 (file)
index 0000000..cb089cd
--- /dev/null
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/t/lib/repositories/nodescription/config b/t/lib/repositories/nodescription/config
new file mode 100644 (file)
index 0000000..07d359d
--- /dev/null
@@ -0,0 +1,4 @@
+[core]
+       repositoryformatversion = 0
+       filemode = true
+       bare = true
diff --git a/t/lib/repositories/nodescription/hooks/applypatch-msg b/t/lib/repositories/nodescription/hooks/applypatch-msg
new file mode 100644 (file)
index 0000000..02de1ef
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# An example hook script to check the commit log message taken by
+# applypatch from an e-mail message.
+#
+# The hook should exit with non-zero status after issuing an
+# appropriate message if it wants to stop the commit.  The hook is
+# allowed to edit the commit message file.
+#
+# To enable this hook, make this file executable.
+
+. git-sh-setup
+test -x "$GIT_DIR/hooks/commit-msg" &&
+       exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
+:
diff --git a/t/lib/repositories/nodescription/hooks/commit-msg b/t/lib/repositories/nodescription/hooks/commit-msg
new file mode 100644 (file)
index 0000000..9b04f2d
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/sh
+#
+# An example hook script to check the commit log message.
+# Called by git-commit with one argument, the name of the file
+# that has the commit message.  The hook should exit with non-zero
+# status after issuing an appropriate message if it wants to stop the
+# commit.  The hook is allowed to edit the commit message file.
+#
+# To enable this hook, make this file executable.
+
+# Uncomment the below to add a Signed-off-by line to the message.
+# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
+# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
+
+# This example catches duplicate Signed-off-by lines.
+
+test "" = "$(grep '^Signed-off-by: ' "$1" |
+        sort | uniq -c | sed -e '/^[   ]*1[    ]/d')" || {
+       echo >&2 Duplicate Signed-off-by lines.
+       exit 1
+}
+
diff --git a/t/lib/repositories/nodescription/hooks/post-commit b/t/lib/repositories/nodescription/hooks/post-commit
new file mode 100644 (file)
index 0000000..8be6f34
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+#
+# An example hook script that is called after a successful
+# commit is made.
+#
+# To enable this hook, make this file executable.
+
+: Nothing
diff --git a/t/lib/repositories/nodescription/hooks/post-update b/t/lib/repositories/nodescription/hooks/post-update
new file mode 100644 (file)
index 0000000..bcba893
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+#
+# An example hook script to prepare a packed repository for use over
+# dumb transports.
+#
+# To enable this hook, make this file executable by "chmod +x post-update".
+
+exec git-update-server-info
diff --git a/t/lib/repositories/nodescription/hooks/pre-applypatch b/t/lib/repositories/nodescription/hooks/pre-applypatch
new file mode 100644 (file)
index 0000000..5f56ce8
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# An example hook script to verify what is about to be committed
+# by applypatch from an e-mail message.
+#
+# The hook should exit with non-zero status after issuing an
+# appropriate message if it wants to stop the commit.
+#
+# To enable this hook, make this file executable.
+
+. git-sh-setup
+test -x "$GIT_DIR/hooks/pre-commit" &&
+       exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"}
+:
+
diff --git a/t/lib/repositories/nodescription/hooks/pre-commit b/t/lib/repositories/nodescription/hooks/pre-commit
new file mode 100644 (file)
index 0000000..723a9ef
--- /dev/null
@@ -0,0 +1,71 @@
+#!/bin/sh
+#
+# An example hook script to verify what is about to be committed.
+# Called by git-commit with no arguments.  The hook should
+# exit with non-zero status after issuing an appropriate message if
+# it wants to stop the commit.
+#
+# To enable this hook, make this file executable.
+
+# This is slightly modified from Andrew Morton's Perfect Patch.
+# Lines you introduce should not have trailing whitespace.
+# Also check for an indentation that has SP before a TAB.
+
+if git-rev-parse --verify HEAD 2>/dev/null
+then
+       git-diff-index -p -M --cached HEAD
+else
+       # NEEDSWORK: we should produce a diff with an empty tree here
+       # if we want to do the same verification for the initial import.
+       :
+fi |
+perl -e '
+    my $found_bad = 0;
+    my $filename;
+    my $reported_filename = "";
+    my $lineno;
+    sub bad_line {
+       my ($why, $line) = @_;
+       if (!$found_bad) {
+           print STDERR "*\n";
+           print STDERR "* You have some suspicious patch lines:\n";
+           print STDERR "*\n";
+           $found_bad = 1;
+       }
+       if ($reported_filename ne $filename) {
+           print STDERR "* In $filename\n";
+           $reported_filename = $filename;
+       }
+       print STDERR "* $why (line $lineno)\n";
+       print STDERR "$filename:$lineno:$line\n";
+    }
+    while (<>) {
+       if (m|^diff --git a/(.*) b/\1$|) {
+           $filename = $1;
+           next;
+       }
+       if (/^@@ -\S+ \+(\d+)/) {
+           $lineno = $1 - 1;
+           next;
+       }
+       if (/^ /) {
+           $lineno++;
+           next;
+       }
+       if (s/^\+//) {
+           $lineno++;
+           chomp;
+           if (/\s$/) {
+               bad_line("trailing whitespace", $_);
+           }
+           if (/^\s*   /) {
+               bad_line("indent SP followed by a TAB", $_);
+           }
+           if (/^(?:[<>=]){7}/) {
+               bad_line("unresolved merge conflict", $_);
+           }
+       }
+    }
+    exit($found_bad);
+'
+
diff --git a/t/lib/repositories/nodescription/hooks/pre-rebase b/t/lib/repositories/nodescription/hooks/pre-rebase
new file mode 100644 (file)
index 0000000..981c454
--- /dev/null
@@ -0,0 +1,150 @@
+#!/bin/sh
+#
+# Copyright (c) 2006 Junio C Hamano
+#
+
+publish=next
+basebranch="$1"
+if test "$#" = 2
+then
+       topic="refs/heads/$2"
+else
+       topic=`git symbolic-ref HEAD`
+fi
+
+case "$basebranch,$topic" in
+master,refs/heads/??/*)
+       ;;
+*)
+       exit 0 ;# we do not interrupt others.
+       ;;
+esac
+
+# Now we are dealing with a topic branch being rebased
+# on top of master.  Is it OK to rebase it?
+
+# Is topic fully merged to master?
+not_in_master=`git-rev-list --pretty=oneline ^master "$topic"`
+if test -z "$not_in_master"
+then
+       echo >&2 "$topic is fully merged to master; better remove it."
+       exit 1 ;# we could allow it, but there is no point.
+fi
+
+# Is topic ever merged to next?  If so you should not be rebasing it.
+only_next_1=`git-rev-list ^master "^$topic" ${publish} | sort`
+only_next_2=`git-rev-list ^master           ${publish} | sort`
+if test "$only_next_1" = "$only_next_2"
+then
+       not_in_topic=`git-rev-list "^$topic" master`
+       if test -z "$not_in_topic"
+       then
+               echo >&2 "$topic is already up-to-date with master"
+               exit 1 ;# we could allow it, but there is no point.
+       else
+               exit 0
+       fi
+else
+       not_in_next=`git-rev-list --pretty=oneline ^${publish} "$topic"`
+       perl -e '
+               my $topic = $ARGV[0];
+               my $msg = "* $topic has commits already merged to public branch:\n";
+               my (%not_in_next) = map {
+                       /^([0-9a-f]+) /;
+                       ($1 => 1);
+               } split(/\n/, $ARGV[1]);
+               for my $elem (map {
+                               /^([0-9a-f]+) (.*)$/;
+                               [$1 => $2];
+                       } split(/\n/, $ARGV[2])) {
+                       if (!exists $not_in_next{$elem->[0]}) {
+                               if ($msg) {
+                                       print STDERR $msg;
+                                       undef $msg;
+                               }
+                               print STDERR " $elem->[1]\n";
+                       }
+               }
+       ' "$topic" "$not_in_next" "$not_in_master"
+       exit 1
+fi
+
+exit 0
+
+################################################################
+
+This sample hook safeguards topic branches that have been
+published from being rewound.
+
+The workflow assumed here is:
+
+ * Once a topic branch forks from "master", "master" is never
+   merged into it again (either directly or indirectly).
+
+ * Once a topic branch is fully cooked and merged into "master",
+   it is deleted.  If you need to build on top of it to correct
+   earlier mistakes, a new topic branch is created by forking at
+   the tip of the "master".  This is not strictly necessary, but
+   it makes it easier to keep your history simple.
+
+ * Whenever you need to test or publish your changes to topic
+   branches, merge them into "next" branch.
+
+The script, being an example, hardcodes the publish branch name
+to be "next", but it is trivial to make it configurable via
+$GIT_DIR/config mechanism.
+
+With this workflow, you would want to know:
+
+(1) ... if a topic branch has ever been merged to "next".  Young
+    topic branches can have stupid mistakes you would rather
+    clean up before publishing, and things that have not been
+    merged into other branches can be easily rebased without
+    affecting other people.  But once it is published, you would
+    not want to rewind it.
+
+(2) ... if a topic branch has been fully merged to "master".
+    Then you can delete it.  More importantly, you should not
+    build on top of it -- other people may already want to
+    change things related to the topic as patches against your
+    "master", so if you need further changes, it is better to
+    fork the topic (perhaps with the same name) afresh from the
+    tip of "master".
+
+Let's look at this example:
+
+                  o---o---o---o---o---o---o---o---o---o "next"
+                 /       /           /           /
+                /   a---a---b A     /           /
+               /   /               /           /
+              /   /   c---c---c---c B         /
+             /   /   /             \         /
+            /   /   /   b---b C     \       /
+           /   /   /   /             \     /
+    ---o---o---o---o---o---o---o---o---o---o---o "master"
+
+
+A, B and C are topic branches.
+
+ * A has one fix since it was merged up to "next".
+
+ * B has finished.  It has been fully merged up to "master" and "next",
+   and is ready to be deleted.
+
+ * C has not merged to "next" at all.
+
+We would want to allow C to be rebased, refuse A, and encourage
+B to be deleted.
+
+To compute (1):
+
+       git-rev-list ^master ^topic next
+       git-rev-list ^master        next
+
+       if these match, topic has not merged in next at all.
+
+To compute (2):
+
+       git-rev-list master..topic
+
+       if this is empty, it is fully merged to "master".
diff --git a/t/lib/repositories/nodescription/hooks/update b/t/lib/repositories/nodescription/hooks/update
new file mode 100644 (file)
index 0000000..e8c536f
--- /dev/null
@@ -0,0 +1,285 @@
+#!/bin/sh
+#
+# An example hook script to mail out commit update information.
+# It can also blocks tags that aren't annotated.
+# Called by git-receive-pack with arguments: refname sha1-old sha1-new
+#
+# To enable this hook, make this file executable by "chmod +x update".
+#
+# Config
+# ------
+# hooks.mailinglist
+#   This is the list that all pushes will go to; leave it blank to not send
+#   emails frequently.  The log email will list every log entry in full between
+#   the old ref value and the new ref value.
+# hooks.announcelist
+#   This is the list that all pushes of annotated tags will go to.  Leave it
+#   blank to just use the mailinglist field.  The announce emails list the
+#   short log summary of the changes since the last annotated tag
+# hooks.allowunannotated
+#   This boolean sets whether unannotated tags will be allowed into the
+#   repository.  By default they won't be.
+#
+# Notes
+# -----
+# All emails have their subjects prefixed with "[SCM]" to aid filtering.
+# All emails include the headers "X-Git-Refname", "X-Git-Oldrev",
+# "X-Git-Newrev", and "X-Git-Reftype" to enable fine tuned filtering and info.
+
+# --- Constants
+EMAILPREFIX="[SCM] "
+LOGBEGIN="- Log -----------------------------------------------------------------"
+LOGEND="-----------------------------------------------------------------------"
+DATEFORMAT="%F %R %z"
+
+# --- Command line
+refname="$1"
+oldrev="$2"
+newrev="$3"
+
+# --- Safety check
+if [ -z "$GIT_DIR" ]; then
+       echo "Don't run this script from the command line." >&2
+       echo " (if you want, you could supply GIT_DIR then run" >&2
+       echo "  $0 <ref> <oldrev> <newrev>)" >&2
+       exit 1
+fi
+
+if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
+       echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
+       exit 1
+fi
+
+# --- Config
+projectdesc=$(cat $GIT_DIR/description)
+recipients=$(git-repo-config hooks.mailinglist)
+announcerecipients=$(git-repo-config hooks.announcelist)
+allowunannotated=$(git-repo-config --bool hooks.allowunannotated)
+
+# --- Check types
+newrev_type=$(git-cat-file -t "$newrev")
+
+case "$refname","$newrev_type" in
+       refs/tags/*,commit)
+               # un-annotated tag
+               refname_type="tag"
+               short_refname=${refname##refs/tags/}
+               if [ $allowunannotated != "true" ]; then
+                       echo "*** The un-annotated tag, $short_refname is not allowed in this repository" >&2
+                       echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
+                       exit 1
+               fi
+               ;;
+       refs/tags/*,tag)
+               # annotated tag
+               refname_type="annotated tag"
+               short_refname=${refname##refs/tags/}
+               # change recipients
+               if [ -n "$announcerecipients" ]; then
+                       recipients="$announcerecipients"
+               fi
+               ;;
+       refs/heads/*,commit)
+               # branch
+               refname_type="branch"
+               short_refname=${refname##refs/heads/}
+               ;;
+       refs/remotes/*,commit)
+               # tracking branch
+               refname_type="tracking branch"
+               short_refname=${refname##refs/remotes/}
+               # Should this even be allowed?
+               echo "*** Push-update of tracking branch, $refname.  No email generated." >&2
+               exit 0
+               ;;
+       *)
+               # Anything else (is there anything else?)
+               echo "*** Update hook: unknown type of update, \"$newrev_type\", to ref $refname" >&2
+               exit 1
+               ;;
+esac
+
+# Check if we've got anyone to send to
+if [ -z "$recipients" ]; then
+       # If the email isn't sent, then at least give the user some idea of what command
+       # would generate the email at a later date
+       echo "*** No recipients found - no email will be sent, but the push will continue" >&2
+       echo "*** for $0 $1 $2 $3" >&2
+       exit 0
+fi
+
+# --- Email parameters
+committer=$(git show --pretty=full -s $newrev | grep "^Commit: " | sed -e "s/^Commit: //")
+describe=$(git describe $newrev 2>/dev/null)
+if [ -z "$describe" ]; then
+       describe=$newrev
+fi
+
+# --- Email (all stdout will be the email)
+(
+# Generate header
+cat <<-EOF
+From: $committer
+To: $recipients
+Subject: ${EMAILPREFIX}$projectdesc $refname_type, $short_refname now at $describe
+X-Git-Refname: $refname
+X-Git-Reftype: $refname_type
+X-Git-Oldrev: $oldrev
+X-Git-Newrev: $newrev
+
+Hello,
+
+This is an automated email from the git hooks/update script, it was
+generated because a ref change was pushed to the repository.
+
+Updating $refname_type, $short_refname,
+EOF
+
+case "$refname_type" in
+       "tracking branch"|branch)
+               if expr "$oldrev" : '0*$' >/dev/null
+               then
+                       # If the old reference is "0000..0000" then this is a new branch
+                       # and so oldrev is not valid
+                       echo "  as a new  $refname_type"
+                   echo "        to  $newrev ($newrev_type)"
+                       echo ""
+                       echo $LOGBEGIN
+                       # This shows all log entries that are not already covered by
+                       # another ref - i.e. commits that are now accessible from this
+                       # ref that were previously not accessible
+                       git-rev-parse --not --all | git-rev-list --stdin --pretty $newref
+                       echo $LOGEND
+               else
+                       # oldrev is valid
+                       oldrev_type=$(git-cat-file -t "$oldrev")
+
+                       # Now the problem is for cases like this:
+                       #   * --- * --- * --- * (oldrev)
+                       #          \
+                       #           * --- * --- * (newrev)
+                       # i.e. there is no guarantee that newrev is a strict subset
+                       # of oldrev - (would have required a force, but that's allowed).
+                       # So, we can't simply say rev-list $oldrev..$newrev.  Instead
+                       # we find the common base of the two revs and list from there
+                       baserev=$(git-merge-base $oldrev $newrev)
+
+                       # Commit with a parent
+                       for rev in $(git-rev-list $newrev ^$baserev)
+                       do
+                               revtype=$(git-cat-file -t "$rev")
+                               echo "       via  $rev ($revtype)"
+                       done
+                       if [ "$baserev" = "$oldrev" ]; then
+                               echo "      from  $oldrev ($oldrev_type)"
+                       else
+                               echo "  based on  $baserev"
+                               echo "      from  $oldrev ($oldrev_type)"
+                               echo ""
+                               echo "This ref update crossed a branch point; i.e. the old rev is not a strict subset"
+                               echo "of the new rev.  This occurs, when you --force push a change in a situation"
+                               echo "like this:"
+                               echo ""
+                               echo " * -- * -- B -- O -- O -- O ($oldrev)"
+                               echo "            \\"
+                               echo "             N -- N -- N ($newrev)"
+                               echo ""
+                               echo "Therefore, we assume that you've already had alert emails for all of the O"
+                               echo "revisions, and now give you all the revisions in the N branch from the common"
+                               echo "base, B ($baserev), up to the new revision."
+                       fi
+                       echo ""
+                       echo $LOGBEGIN
+                       git-rev-list --pretty $newrev ^$baserev
+                       echo $LOGEND
+                       echo ""
+                       echo "Diffstat:"
+                       git-diff-tree --no-color --stat -M -C --find-copies-harder $newrev ^$baserev
+               fi
+               ;;
+       "annotated tag")
+               # Should we allow changes to annotated tags?
+               if expr "$oldrev" : '0*$' >/dev/null
+               then
+                       # If the old reference is "0000..0000" then this is a new atag
+                       # and so oldrev is not valid
+                       echo "        to  $newrev ($newrev_type)"
+               else
+                       echo "        to  $newrev ($newrev_type)"
+                       echo "      from  $oldrev"
+               fi
+
+               # If this tag succeeds another, then show which tag it replaces
+               prevtag=$(git describe $newrev^ 2>/dev/null | sed 's/-g.*//')
+               if [ -n "$prevtag" ]; then
+                       echo "  replaces  $prevtag"
+               fi
+
+               # Read the tag details
+               eval $(git cat-file tag $newrev | \
+                       sed -n '4s/tagger \([^>]*>\)[^0-9]*\([0-9]*\).*/tagger="\1" ts="\2"/p')
+               tagged=$(date --date="1970-01-01 00:00:00 +0000 $ts seconds" +"$DATEFORMAT")
+
+               echo " tagged by  $tagger"
+               echo "        on  $tagged"
+
+               echo ""
+               echo $LOGBEGIN
+               echo ""
+
+               if [ -n "$prevtag" ]; then
+                       git rev-list --pretty=short "$prevtag..$newrev" | git shortlog
+               else
+                       git rev-list --pretty=short $newrev | git shortlog
+               fi
+
+               echo $LOGEND
+               echo ""
+               ;;
+       *)
+               # By default, unannotated tags aren't allowed in; if
+               # they are though, it's debatable whether we would even want an
+               # email to be generated; however, I don't want to add another config
+               # option just for that.
+               #
+               # Unannotated tags are more about marking a point than releasing
+               # a version; therefore we don't do the shortlog summary that we
+               # do for annotated tags above - we simply show that the point has
+               # been marked, and print the log message for the marked point for
+               # reference purposes
+               #
+               # Note this section also catches any other reference type (although
+               # there aren't any) and deals with them in the same way.
+               if expr "$oldrev" : '0*$' >/dev/null
+               then
+                       # If the old reference is "0000..0000" then this is a new tag
+                       # and so oldrev is not valid
+                       echo "  as a new  $refname_type"
+                       echo "        to  $newrev ($newrev_type)"
+               else
+                       echo "        to  $newrev ($newrev_type)"
+                       echo "      from  $oldrev"
+               fi
+               echo ""
+               echo $LOGBEGIN
+               git-show --no-color --root -s $newrev
+               echo $LOGEND
+               echo ""
+               ;;
+esac
+
+# Footer
+cat <<-EOF
+
+hooks/update
+---
+Git Source Code Management System
+$0 $1 \\
+  $2 \\
+  $3
+EOF
+#) | cat >&2
+) | /usr/sbin/sendmail -t
+
+# --- Finished
+exit 0
diff --git a/t/lib/repositories/nodescription/info/exclude b/t/lib/repositories/nodescription/info/exclude
new file mode 100644 (file)
index 0000000..2c87b72
--- /dev/null
@@ -0,0 +1,6 @@
+# git-ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/t/lib/repositories/nodescription/objects/14/5dc3ef5d307be84cb9b325d70bd08aeed0eceb b/t/lib/repositories/nodescription/objects/14/5dc3ef5d307be84cb9b325d70bd08aeed0eceb
new file mode 100644 (file)
index 0000000..d26a4fe
Binary files /dev/null and b/t/lib/repositories/nodescription/objects/14/5dc3ef5d307be84cb9b325d70bd08aeed0eceb differ
diff --git a/t/lib/repositories/nodescription/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99 b/t/lib/repositories/nodescription/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99
new file mode 100644 (file)
index 0000000..f95e389
Binary files /dev/null and b/t/lib/repositories/nodescription/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99 differ
diff --git a/t/lib/repositories/nodescription/objects/36/c6c6708b8360d7023e8a1649c45bcf9b3bd818 b/t/lib/repositories/nodescription/objects/36/c6c6708b8360d7023e8a1649c45bcf9b3bd818
new file mode 100644 (file)
index 0000000..fefba84
--- /dev/null
@@ -0,0 +1,2 @@
+xœÎAj\ 31\f@Ñ®}
\v‰dGc(¥«\1e 7°,95L2Ÿ\14zú–\1e\ f\ f~=n·>!Æü4‡;В¬²·dŒ¢¾-U³rL&¨†[q7ôê\1a>Ëðû\ 4n’V©¢ÖÄŵ-„9®KfÍÑ8oÌL´z(_óã\18ð¾\1f£—;\Êõ»Ï\1fx\19¥íoæú\17OǸ¾\ 2‘p$Œ’à\19      1ÔÿÅé\ fáPÌÀú së»Çð\vk:H…
\ No newline at end of file
diff --git a/t/lib/repositories/nodescription/objects/3b/c0634310b9c62222bb0e724c11ffdfb297b4ac b/t/lib/repositories/nodescription/objects/3b/c0634310b9c62222bb0e724c11ffdfb297b4ac
new file mode 100644 (file)
index 0000000..fa8f88a
Binary files /dev/null and b/t/lib/repositories/nodescription/objects/3b/c0634310b9c62222bb0e724c11ffdfb297b4ac differ
diff --git a/t/lib/repositories/nodescription/objects/3f/7567c7bdf7e7ebf410926493b92d398333116e b/t/lib/repositories/nodescription/objects/3f/7567c7bdf7e7ebf410926493b92d398333116e
new file mode 100644 (file)
index 0000000..38437d2
Binary files /dev/null and b/t/lib/repositories/nodescription/objects/3f/7567c7bdf7e7ebf410926493b92d398333116e differ
diff --git a/t/lib/repositories/nodescription/objects/57/16ca5987cbf97d6bb54920bea6adde242d87e6 b/t/lib/repositories/nodescription/objects/57/16ca5987cbf97d6bb54920bea6adde242d87e6
new file mode 100644 (file)
index 0000000..fc906d8
Binary files /dev/null and b/t/lib/repositories/nodescription/objects/57/16ca5987cbf97d6bb54920bea6adde242d87e6 differ
diff --git a/t/lib/repositories/nodescription/objects/72/9a7c3f6ba5453b42d16a43692205f67fb23bc1 b/t/lib/repositories/nodescription/objects/72/9a7c3f6ba5453b42d16a43692205f67fb23bc1
new file mode 100644 (file)
index 0000000..e59ece5
Binary files /dev/null and b/t/lib/repositories/nodescription/objects/72/9a7c3f6ba5453b42d16a43692205f67fb23bc1 differ
diff --git a/t/lib/repositories/nodescription/objects/82/b5fee28277349b6d46beff5fdf6a7152347ba0 b/t/lib/repositories/nodescription/objects/82/b5fee28277349b6d46beff5fdf6a7152347ba0
new file mode 100644 (file)
index 0000000..7a1eb5e
Binary files /dev/null and b/t/lib/repositories/nodescription/objects/82/b5fee28277349b6d46beff5fdf6a7152347ba0 differ
diff --git a/t/lib/repositories/nodescription/objects/90/62594aebb5df0de7fb92413f17a9eced196c22 b/t/lib/repositories/nodescription/objects/90/62594aebb5df0de7fb92413f17a9eced196c22
new file mode 100644 (file)
index 0000000..236ca51
Binary files /dev/null and b/t/lib/repositories/nodescription/objects/90/62594aebb5df0de7fb92413f17a9eced196c22 differ
diff --git a/t/lib/repositories/nodescription/objects/pack/.gitignore b/t/lib/repositories/nodescription/objects/pack/.gitignore
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/t/lib/repositories/nodescription/refs/heads/master b/t/lib/repositories/nodescription/refs/heads/master
new file mode 100644 (file)
index 0000000..7c4a265
--- /dev/null
@@ -0,0 +1 @@
+36c6c6708b8360d7023e8a1649c45bcf9b3bd818
index 4598bc4..d6fb5e2 100644 (file)
@@ -23,7 +23,7 @@ my $repoEmpty = Path::Class::Dir->new('t/lib/repositories/empty.git');
 ok( ! $m->is_git_repo( $repoEmpty ), 'is_git_repo is false for empty dir' );
 
 my $projectList = $m->list_projects('t/lib/repositories');
-ok( scalar @{$projectList} == 2, 'list_projects returns an array with the correct number of members' );
+ok( scalar @{$projectList} == 3, 'list_projects returns an array with the correct number of members' );
 is( $projectList->[0]->{name}, 'bare.git', 'list_projects has correct name for "bare.git" repo' );
 #ok( $projectList->[1]->{name} eq 'working/.git', 'list_projects has correct name for "working" repo' );