]> Sergey Matveev's repositories - public-inbox.git/blob - t/clone-coderepo.t
clone: fix --post-update-hook behavior
[public-inbox.git] / t / clone-coderepo.t
1 #!perl -w
2 # Copyright (C) all contributors <meta@public-inbox.org>
3 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
4 use v5.12;
5 use PublicInbox::TestCommon;
6 use PublicInbox::Import;
7 use File::Temp;
8 use File::Path qw(remove_tree);
9 use Digest::SHA qw(sha1_hex);
10 require_mods(qw(json Plack::Builder HTTP::Date HTTP::Status));
11 require_git '1.8.5';
12 require_ok 'PublicInbox::LeiMirror';
13 my ($tmpdir, $for_destroy) = tmpdir();
14 my $pa = "$tmpdir/src/a.git";
15 my $pb = "$tmpdir/src/b.git";
16 PublicInbox::Import::init_bare($pa);
17 my ($stdout, $stderr) = ("$tmpdir/out.log", "$tmpdir/err.log");
18 my $pi_config = "$tmpdir/pi_config";
19 my $td;
20 my $tcp = tcp_server();
21 my $url = 'http://'.tcp_host_port($tcp).'/';
22 my $set_manifest = sub {
23         my ($m, $f) = @_;
24         $f //= "$tmpdir/src/manifest.js.gz";
25         my $ft = File::Temp->new(TMPDIR => $tmpdir, UNLINK => 0);
26         PublicInbox::LeiMirror::dump_manifest($m, $ft);
27         PublicInbox::LeiMirror::ft_rename($ft, $f, 0666);
28 };
29 my $read_manifest = sub {
30         my ($f) = @_;
31         open my $fh, '<', $f or xbail "open($f): $!";
32         PublicInbox::LeiMirror::decode_manifest($fh, $f, $f);
33 };
34
35 my $t0 = time - 1;
36 my $m; # manifest hashref
37
38 {
39         my $rdr = {};
40         my $fi_data = './t/git.fast-import-data';
41         open $rdr->{0}, '<', $fi_data or xbail "open($fi_data): $!";
42         my @git = ('git', "--git-dir=$pa");
43         xsys_e([@git, qw(fast-import --quiet)], undef, $rdr);
44         xsys_e([qw(/bin/cp -Rp a.git b.git)], undef, { -C => "$tmpdir/src" });
45         open my $fh, '>', $pi_config or xbail "open($pi_config): $!";
46         print $fh <<EOM or xbail "print: $!";
47 [publicinbox]
48         cgitrc = $tmpdir/cgitrc
49         cgit = fallback
50 EOM
51         close $fh or xbail "close: $!";
52
53         my $f = "$tmpdir/cgitrc";
54         open $fh, '>', $f or xbail "open($f): $!";
55         print $fh <<EOM or xbail "print: $!";
56 project-list=$tmpdir/src/projects.list
57 scan-path=$tmpdir/src
58 EOM
59         close $fh or xbail "close($f): $!";
60
61         my $cmd = [ '-httpd', '-W0', "--stdout=$stdout", "--stderr=$stderr",
62                 File::Spec->rel2abs('t/clone-coderepo.psgi') ];
63         my $env = { TEST_DOCROOT => "$tmpdir/src", PI_CONFIG => $pi_config };
64         $td = start_script($cmd, $env, { 3 => $tcp });
65         my $fp = sha1_hex(my $refs = xqx([@git, 'show-ref']));
66         $m = {
67                 '/a.git' => {
68                         fingerprint => $fp,
69                         modified => 1,
70                         owner => 'Alice',
71                 },
72                 '/b.git' => {
73                         fingerprint => $fp,
74                         modified => 1,
75                         owner => 'Bob',
76                 },
77         };
78         $set_manifest->($m);
79         $f = "$tmpdir/src/projects.list";
80         open $fh, '>', $f, or xbail "open($f): $!";
81         print $fh <<EOM or xbail "print($f): $!";
82 a.git
83 b.git
84 EOM
85         close $fh or xbail "close($f): $!";
86 }
87
88 my $cmd = [qw(-clone --inbox-config=never --manifest= --project-list=
89         --objstore= -p -q), $url, "$tmpdir/dst"];
90 ok(run_script($cmd), 'clone');
91 is(xqx([qw(git config gitweb.owner)], { GIT_DIR => "$tmpdir/dst/a.git" }),
92         "Alice\n", 'a.git gitweb.owner set');
93 is(xqx([qw(git config gitweb.owner)], { GIT_DIR => "$tmpdir/dst/b.git" }),
94         "Bob\n", 'b.git gitweb.owner set');
95
96 my $dst_pl = "$tmpdir/dst/projects.list";
97 my $dst_mf = "$tmpdir/dst/manifest.js.gz";
98 ok(!-d "$tmpdir/dst/objstore", 'no objstore created w/o forkgroups');
99 my $r = $read_manifest->($dst_mf);
100 is_deeply($r, $m, 'manifest matches');
101
102 is(PublicInbox::Git::try_cat($dst_pl), "a.git\nb.git\n",
103         'wrote projects.list');
104
105 { # check symlinks
106         $m->{'/a.git'}->{symlinks} = [ '/old/a.git' ];
107         $set_manifest->($m);
108         utime($t0, $t0, $dst_mf) or xbail "utime: $!";
109         ok(run_script($cmd), 'clone again +symlinks');
110         ok(-l "$tmpdir/dst/old/a.git", 'symlink created');
111         is(PublicInbox::Git::try_cat($dst_pl), "a.git\nb.git\n",
112                 'projects.list does not include symlink by default');
113
114         $r = $read_manifest->($dst_mf);
115         is_deeply($r, $m, 'updated manifest matches');
116 }
117 { # cleanup old projects from projects.list
118         open my $fh, '>>', $dst_pl or xbail $!;
119         print $fh "gone.git\n" or xbail $!;
120         close $fh or xbail $!;
121
122         utime($t0, $t0, $dst_mf) or xbail "utime: $!";
123         my $rdr = { 2 => \(my $err = '') };
124         ok(run_script($cmd, undef, $rdr), 'clone again for expired gone.git');
125         is(PublicInbox::Git::try_cat($dst_pl), "a.git\nb.git\n",
126                 'project list cleaned');
127         like($err, qr/no longer exist.*\bgone\.git\b/s, 'gone.git noted');
128 }
129
130 my $test_puh = sub {
131         my (@clone_arg) = @_;
132         my $x = [qw(-clone --inbox-config=never --manifest= --project-list=
133                 -q -p), $url, "$tmpdir/dst", @clone_arg,
134                 '--post-update-hook=./t/clone-coderepo-puh1.sh',
135                 '--post-update-hook=./t/clone-coderepo-puh2.sh' ];
136         my $log = "$tmpdir/puh.log";
137         my $env = { CLONE_CODEREPO_TEST_OUT => $log };
138         remove_tree("$tmpdir/dst");
139         ok(run_script($x, $env), "fresh clone @clone_arg w/ post-update-hook");
140         ok(-e $log, "hooks run on fresh clone @clone_arg");
141         open my $lh, '<', $log or xbail "open $log: $!";
142         chomp(my @l = readline($lh));
143         is(scalar(@l), 4, "4 lines written by hooks on @clone_arg");
144         for my $r (qw(a b)) {
145                 is_xdeeply(['uno', 'dos'],
146                         [ (map { s/ .+//; $_ } grep(m!/$r\.git\z!, @l)) ],
147                         "$r.git hooks ran in order") or diag explain(\@l);
148         }
149         unlink($log) or xbail "unlink: $!";
150         ok(run_script($x, $env), "no-op clone @clone_arg w/ post-update-hook");
151         ok(!-e $log, "hooks not run on no-op @clone_arg");
152 };
153 $test_puh->();
154 ok(!-e "$tmpdir/dst/objstore", 'no objstore, yet');
155
156 my $fgrp = 'fgrp';
157 $m->{'/a.git'}->{forkgroup} = $m->{'/b.git'}->{forkgroup} = $fgrp;
158 $set_manifest->($m);
159 $test_puh->('--objstore=');
160 ok(-e "$tmpdir/dst/objstore", 'objstore created');
161
162 done_testing;