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

NAME

Git::Hooks::CheckFile - Git::Hooks plugin for checking files

VERSION

version 2.7.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]
    plugin = CheckFile
    admin = joe molly

  [githooks "checkfile"]
    name = *.p[lm] perlcritic --stern --verbose 10
    name = *.pp    puppet parser validate --verbose --debug
    name = *.pp    puppet-lint --no-variable_scope-check --no-documentation-check
    name = *.sh    bash -n
    name = *.sh    shellcheck --exclude=SC2046,SC2053,SC2086
    name = *.yml   yamllint
    name = *.js    eslint -c ~/.eslintrc.json

    sizelimit = 1M

    path.deny = ^.
    path.allow = ^[a-zA-Z0-1/_.-]$

    deny-case-conflict = true

    deny-token = \\b(FIXME|TODO)\\b

    executable = *.sh
    executable = *.csh
    executable = *.ksh
    executable = *.zsh
    not-executable = qr/\\.(?:c|cc|java|pl|pm|txt)$/

The first section enables the plugin and defines the users joe and molly as administrators, effectivelly exempting them from any restrictions the plugin may impose.

The second instance enables some of the options specific to this plugin.

The name options associate filenames with commands so that any file added or modified in the commit which name maches the glob pattern is checked with the associated command. The commands usually check the files's syntax and style.

The sizelimit option denies the addition or modification of any file bigger than 1MiB, preventing careless users to commit huge binary files.

The path.deny and path.allow options conspire to only allow the addition of files which names comprised of only a small set of characters, avoiding names which may cause problems.

The deny-case-conflict option rejects commits which add files with names that would conflict with each other or with the names of other files already in the repository in case-insensitive filesystems, such as the ones on Windows.

The deny-token option rejects commits which introduces lines containing the strings FIXME or TODO, as they are often committed by mistake.

The executable option rejects commits adding or modifying scripts (filenames with extensions .sh, .csh, .ksh, and .zsh) without the executable permission, which is a common source of errors.

The not-executable option rejects commits adding or modifying source files (filenames with extensions .c, .cc, .java, .pl, .pm, and .txt) with the executable permission.

DESCRIPTION

This Git::Hooks plugin hooks itself to the hooks below to check if the names and contents of files added to or modified in the repository meet specified constraints. If they don't, the commit/push is aborted.

  • pre-applypatch

  • pre-commit

  • update

  • pre-receive

  • ref-update

  • patchset-created

  • draft-published

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

    git config --add githooks.plugin CheckFile

NAME

CheckFile - Git::Hooks plugin for checking files

CONFIGURATION

The plugin is configured by the following git options.

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.

githooks.checkfile.name PATTERN COMMAND

This directive tells which COMMAND should be used to check files matching PATTERN.

Only the file's basename is matched against PATTERN.

PATTERN is usually expressed with globbing to match files based on their extensions, for example:

    git config githooks.checkfile.name *.pl perlcritic --stern

If you need more power than globs can provide you can match using regular expressions, using the qr// operator, for example:

    git config githooks.checkfile.name qr/xpto-\\d+.pl/ perlcritic --stern

COMMAND is everything that comes after the PATTERN. It is invoked once for each file matching PATTERN with the name of a temporary file containing the contents of the matching file passed to it as a last argument. If the command exits with any code different than 0 it is considered a violation and the hook complains, rejecting the commit or the push.

If the filename can't be the last argument to COMMAND you must tell where in the command-line it should go using the placeholder {} (like the argument to the find command's -exec option). For example:

    git config githooks.checkfile.name *.xpto cmd1 --file {} | cmd2

COMMAND is invoked as a single string passed to system, which means it can use shell operators such as pipes and redirections.

Some real examples:

    git config --add githooks.checkfile.name *.p[lm] perlcritic --stern --verbose 5
    git config --add githooks.checkfile.name *.pp    puppet parser validate --verbose --debug
    git config --add githooks.checkfile.name *.pp    puppet-lint --no-variable_scope-check
    git config --add githooks.checkfile.name *.sh    bash -n
    git config --add githooks.checkfile.name *.sh    shellcheck --exclude=SC2046,SC2053,SC2086
    git config --add githooks.checkfile.name *.erb   erb -P -x -T - {} | ruby -c

COMMAND may rely on the GIT_COMMIT environment variable to identify the commit being checked according to the hook being used, as follows.

  • pre-commit

    This hook does not check a complete commit, but the index tree. So, in this case the variable is set to :0. (See git help revisions.)

  • update, pre-receive, ref-updated

    In these hooks the variable is set to the SHA1 of the new commit to which the reference has been updated.

  • patchset-created, draft-published

    In these hooks the variable is set to the argument of the --commit option (a SHA1) passed to them by Gerrit.

The reason that led to the introduction of the GIT_COMMIT variable was to enable one to invoke an external command to check files which needed to grok some configuration from another file in the repository. Specifically, we wanted to check Python scripts with the pylint command passing to its --rcfile option the configuration file pylint.rc sitting on the repository root. So, we configured CheckFile like this:

    git config --add githooks.checkfile.name *.py mypylint.sh

And the mypylint.sh script was something like this:

    #!/bin/bash

    # Create a temporary file do save the pylint.rc
    RC=$(tempfile)
    trap 'rm $RC' EXIT

    git cat-file $GIT_COMMIT:pylint.rc >$RC

    pylint --rcfile=$RC "$@"

githooks.checkfile.sizelimit INT

This directive specifies a size limit (in bytes) for any file in the repository. If set explicitly to 0 (zero), no limit is imposed, which is the default. But it can be useful to override a global specification in a particular repository.

githooks.checkfile.basename.deny REGEXP

This directive denies files which basenames match REGEXP.

githooks.checkfile.basename.allow REGEXP

This directive allows files which basenames match REGEXP. Since by default all basenames are allowed this directive is useful only to prevent a githooks.checkfile.basename.deny directive to deny the same basename.

The basename checks are evaluated so that a file is denied only if it's basename matches any basename.deny directive and none of the basename.allow directives. So, for instance, you would apply it like this to allow the versioning of .gitignore file while denying any other file with a name beginning with a dot.

    [githooks "checkfile"]
        basename.allow ^\\.gitignore
        basename.deny  ^\\.

githooks.checkfile.basename.sizelimit BYTES REGEXP

This directive takes precedence over the githooks.checkfile.sizelimit for files which basename matches REGEXP.

githooks.checkfile.path.deny REGEXP

This directive denies files which full paths match REGEXP.

githooks.checkfile.path.allow REGEXP

This directive allows files which full paths match REGEXP. It's useful in the same way that githooks.checkfile.basename.deny is.

githooks.checkfile.deny-case-conflict BOOL

This directive checks for newly added files that would conflict in case-insensitive filesystems.

Git itself is case-sensitive with regards to file names. Many operating system's filesystems are case-sensitive too, such as Linux, macOS, and other Unix-derived systems. But Windows's filesystems are notoriously case-insensitive. So, if you want your repository to be absolutely safe for Windows users you don't want to add two files which filenames differ only in a case-sensitive manner. Enable this option to be safe

Note that this check have to check the newly added files against all files already in the repository. It can be a little slow for large repositories. Take heed!

githooks.checkfile.deny-token REGEXP

This directive rejects commits or pushes which diff (patch) matches REGEXP. 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.

Note that this option requires Git 1.7.4 or newer.

githooks.checkfile.executable PATTERN

This directive requires that all added or modified files with names matching PATTERN must have the executable permission. This allows you to detect common errors such as forgetting to set scripts as executable.

PATTERN is specified as described in the githooks.checkfile.name directive above.

You can specify this option multiple times so that all PATTERNs are considered.

githooks.checkfile.non-executable PATTERN

This directive requires that all added or modified files with names matching PATTERN must not have the executable permission. This allows you to detect common errors such as setting source code as executable.

PATTERN is specified as described in the githooks.checkfile.name directive above.

You can specify this option multiple times so that all PATTERNs are considered.

AUTHOR

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

COPYRIGHT AND LICENSE

This software is copyright (c) 2018 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.