#!/usr/bin/perl use strict; use warnings; $|++; # program name: expand-deny-messages # DOCUMENTATION IS AT THE BOTTOM OF THIS FILE; PLEASE READ use lib $ENV{GL_LIBDIR}; use Gitolite::Rc; use Gitolite::Common; my %attempted_access = ( # see triggers.html 'ACCESS_1' => { 'R' => 'Repo read', 'W' => 'Repo write', }, 'ACCESS_2' => { 'W' => "Fast forward push", '+' => "Rewind push branch or overwrite tag", 'C' => "Create ref", 'D' => "Delete ref", } ); # env var to disable is set? exit 0 if $ENV{GL_OPTION_EDM_DISABLE}; # argument 1 my $a12 = shift; # ACCESS_1 or ACCESS_2 exit 0 if $a12 !~ /^ACCESS_[12]$/; # shouldn't happen; error in rc file? # the rest of the arguments my ( $repo, $user, $aa, $ref, $msg, $oldsha, $newsha ) = @ARGV; # we're only interested in deny messages exit 0 if $msg !~ /DENIED/; print STDERR "\nFATAL -- ACCESS DENIED\n"; _info( "Repo", $repo ); _info( "User", $user ); _info( "Stage", ( $a12 eq 'ACCESS_1' ? "Before git was called" : "From git's update hook" ) ); _info( "Ref", _ref($ref) ) if $a12 eq 'ACCESS_2'; _info( "Operation", _op( $a12, $aa, $oldsha, $newsha ) ); if ( $ref =~ m((^VREF/[^/]+)) ) { my $vref = $1; if ($ref =~ s(^VREF/NAME/)()) { print STDERR "You're apparently not allowed to push '$ref'"; } else { my $vref_text = slurp( _which( $vref, 'x' ) ); my $etag = '(?:help|explain|explanation)'; $vref_text =~ m(^\s*# $etag.start\n(.*)^\s*# $etag.end\n)sm and print STDERR "Explanation for $vref:\n$1"; } } print STDERR "\n"; print STDERR "$ENV{GL_OPTION_EDM_EXTRA_INFO}\n\n" if $ENV{GL_OPTION_EDM_EXTRA_INFO}; # ------------------------------------------------------------------------ sub _ref { my $r = shift; return "VREF '$r'" if $r =~ s(^VREF/)(); return "Branch '$r'" if $r =~ s(^refs/heads/)(); return "Tag '$r'" if $r =~ s(^refs/tags/)(); return "Non-standard ref '$r'"; } sub _info { printf STDERR "%-14s %-60s\n", @_; } sub _op { my ( $a12, $aa, $oldsha, $newsha ) = @_; # first remove the M part and save the text for later addition if needed my $merge = ( $aa =~ s/M// ? " with merge commit" : "" ); # next, the attempted access is modified to reflect the actual operation being # attempted. NOTE: this no longer necessarily reflects what the gitolite log # file stores; it's more granular and truly distinguishes a branch create from # an ff push, etc. Could help when user typos a branch name I suppose $aa = 'C' if $oldsha and $oldsha eq '0' x 40; $aa = 'D' if $newsha and $newsha eq '0' x 40; # then we map it, add merge text if any my $op = $attempted_access{$a12}{$aa} || "Unknown operation '$aa'"; $op .= $merge; return $op; } __END__ ENABLING THE FEATURE -------------------- To enable this feature, uncomment the line in the rc file if your gitolite was installed recently enough. Otherwise you will need to add these lines to the end of your rc file, just before the "%RC" block ends: ACCESS_1 => [ 'expand-deny-messages', ], ACCESS_2 => [ 'expand-deny-messages', ], Please don't miss the trailing commas! DISABLING IT FOR SPECIFIC REPOS ------------------------------- Once it is enabled at the rc file level, if you wish to disable it for specific repositories just add a line like this to those repos: option ENV.EDM_DISABLE = 1 Or you can also disable it for all repos, then enable it for some: repo @all option ENV.EDM_DISABLE = 1 # ... then later ... repo foo bar @baz option ENV.EDM_DISABLE = 0 (options.html[1] and pages linked from it will explain how that works). [1]: http://gitolite.com/gitolite/options.html SUPPLYING EXTRA INFORMATION --------------------------- You can also supply some extra information to be printed, by adding a line like this to each repository in the gitolite.conf file: option ENV.EDM_EXTRA_INFO = "please contact alice@example.com" You could of course add it under a "repo @all" section if you like. SUPPLYING EXTRA INFORMATION FOR VREFs ------------------------------------- If you have VREFs that do funky things and you want to **lecture** your users when they screw up, add something like the following to your VREF code. # help start Some help text. Some more help text. This can be multi-line. (etc etc etc) # help end Then everything between the "# help start" line and the "# help end" line will get printed if a users falls afoul of this VREF. If any of the lines shown are not valid syntax for your language, figure out some way to put the whole thing in a comment block. Here a C example: /* # help start line 1 line 2 ... last line # help end */ Even if your language does not support multi-line comments like C does, there may be other ways to specify those lines. Here's an example in shell: cat << EOF > /dev/null # help start line 1 line 2 ... last line # help end EOF