The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Git::Hooks::CheckDiff - Git::Hooks plugin to enforce commit policies

VERSION

version 3.3.1

SYNOPSIS

As a Git::Hooks plugin you don't use this Perl module directly. Instead, you may configure it in a Git configuration file like this:

  [githooks]

    # Enable the plugin
    plugin = CheckDiff

    # These users are exempt from all checks
    admin = joe molly

  [githooks "checkdiff"]

    # Reject commits adding lines containing FIXME
    deny-token = \\bFIXME\\b

    # Reject commits adding lines containing TODO (ignoring case) but only on
    # files under the directories lib/ and t/.
    deny-token = (?i)\\bTODO\\b -- ^lib/ ^t/

    # Reject commits which change lines containing the string COPYRIGHT
    shell = /usr/bin/grep COPYRIGHT && false

    # Reject commits which add lines containing secrets
    shell = /path/to/script/find-secret-leakage-in-git-diff.pl

DESCRIPTION

This Git::Hooks plugin hooks itself to the hooks below to check commit diffs.

  • pre-commit, pre-applypatch

    This hook is invoked before a commit is made to check the diffs that it would record.

  • update

    This hook is invoked multiple times in the remote repository during git push, once per branch being updated, to check the differences being committed in it.

  • pre-receive

    This hook is invoked once in the remote repository during git push, to check the differences being committed in all of of affected references.

  • ref-update

    This hook is invoked when a direct push request is received by Gerrit Code Review, to check the differences being committed.

  • commit-received

    This hook is invoked when a push request is received by Gerrit Code Review to create a change for review, to check the differences being committed.

  • submit

    This hook is invoked when a change is submitted in Gerrit Code Review, to check the differences being committed.

  • patchset-created

    This hook is invoked when a push request is received by Gerrit Code Review for a virtual branch (refs/for/*), to check the differences being committed.

To enable this plugin you should add it to the githooks.plugin configuration option:

    [githooks]
      plugin = CheckDiff

NAME

Git::Hooks::CheckDiff - Git::Hooks plugin to check commit diffs

CONFIGURATION

The plugin is configured by the following git options under the githooks.checkdiff subsection.

It can be disabled for specific references via the githooks.ref and githooks.noref options about which you can read in the Git::Hooks documentation.

deny-token REGEXP [-- FILTER ...]

This directive rejects commits or pushes which add lines matching REGEXP, which is a Perl regular expression. This is a multi-valued directive, i.e., you can specify it multiple times to check several REGEXes.

It is useful to detect marks left by developers in the code while developing, such as FIXME or TODO. These marks are usually a reminder to fix things before commit, but as it so often happens, they end up being forgotten.

By default the token are looked for in all added lines in the whole commit or commit sequence diff. Optional filters may be specified to restrict which files should be considered. Only differences of affected files which names match at least one filter are checked for tokens.

The REGEXP and the FILTERs are separated by two hyphens.

A FILTER is a string used to match file paths. It can be optionally initiated by a '!' character, which reverses the matching logic, effectively selecting paths not matching it. If the remaining string initiates with a '^' it's treated as a Perl regular expression anchored at the beginning, which is used to match file paths. Otherwise, the string matches files paths having it as a prefix.

shell COMMAND

This directive invokes COMMAND as a single string passed to /bin/sh -c, which means it can use shell operators such as pipes and redirections.

COMMAND must read from its STDIN the output of git-diff invoked like this:

  git diff* -p -U0 --no-color --diff-filter=AM --no-prefix

(The actual sub-command may be diff-index or diff-tree, depending on the actual hook being invoked. The options above are meant to fix the output format.)

The output format of this command is something like this:

  diff --git Changes Changes
  index cbddd73..2679af9 100644
  --- Changes
  +++ Changes
  @@ -4,0 +5,6 @@ Revision history for perl module Git-Hooks. -*- text -*-
  +2.10.1    2018-12-20 21:33:27-02:00 America/Sao_Paulo
  +
  +[Fix]
  +
  +  - The hook-specific help-on-error config wasn't being used.
  +
  diff --git README.pod README.pod
  index ead2a0a..2ccfb4d 100644
  --- README.pod
  +++ README.pod
  @@ -72 +72 @@ plugins provided by the distribution are these:
  -For a gentler introduction you can read our L<Git::Hooks::Tutorial>. They have
  +For a gentler introduction you can read our L<Git::Hooks::Tutorial>. It has
  diff --git lib/Git/Hooks.pm lib/Git/Hooks.pm
  index c60d098..87fee38 100644
  --- lib/Git/Hooks.pm
  +++ lib/Git/Hooks.pm
  @@ -37 +37 @@ BEGIN {                         ## no critic (RequireArgUnpacking)
  -                package => scalar(caller(1)),
  +                package => scalar(caller),

It's up to COMMAND to check the diff and exit with a code telling if everything is fine (0) or if there is something wrong in it (not 0). Any output from COMMAND (STDOUT or STDERR) will end up being shown to the user.

The script find-secret-leakage-in-git-diff.pl, which is part of the Git::Hooks module, is a good example of a script which can detect problems in a Git diff.

Since the shell commands may take much time to run, the plugin checks if the githooks.timeout option has been violated after each shell runs.

AUTHOR

Gustavo L. de M. Chaves <gnustavo@cpan.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2022 by CPQD <www.cpqd.com.br>.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.