pre-commit
trigger (hook) that runs just before the commit gets into the repository. In fact, this is just a shell script of the same name that Subversion expects to find in the hooks/
repository directory. As one of its arguments, this script gets the ID of the current transaction. Using this identifier, the script can fully analyze the current commit: which files or directories have been added, deleted, changed, get new content of files, diff changes, etc. For this purpose, you can use the svnlook
utility or the SVN :: Look module.pre-commit
hook returns 0, then the commit will be safely saved, and if not, the entire transaction will be rejected (i.e., all files, directories, property changes). In this case, the output of the script to STDERR
will be redirected to the svn-client. Thus, by calling Perl::Critic
inside a pre-commit
hook, you can block the code with violations of the way to the repository.perlcritic-checker.pl
scriptwget http://perlcritic-checker.googlecode.com/files/perlcritic-checker-1.2.6.tar.gz tar -xzf perlcritic-checker-1.2.6.tar.gz cd perlcritic-checker-1.2.6 perl ./Makefile.PL make make test sudo make install
/usr/local
.export SVN_REPO = / tmp / svn_repo svnadmin create $ SVN_REPO
perlcritic-checker
'config:cat> $ SVN_REPO / hooks / perlcritic-checker.conf << 'EOF' # # perlcritic-checker's config example # { # Progressive mode: {0 | 1}. In progressive mode perlcritic-checker # doesn't complain about existing violations but # introducing new ones. Nice feature for applying Perl :: Critic # to the existing projects gradually. progressive_mode => 1, # Emergency commits: {0 | 1}. There are situations when you * need * # to commit changes bypassing all checks (eg emergency bug fixes). # This feat allows you to bypass Perl :: Critic using "magic" prefix in # comment message, eg: svn ci -m "NO CRITIC: I am in hurry" FooBar.pm allow_emergency_commits => 1, # Magic prefix described above can be customized: emergency_comment_prefix => 'NO CRITIC', # Limit maximal number of reported violations. This parameter works # differently in strict and progressive modes. In strict mode it # most severe violations # will be shown. In progressive mode such behavior has no sense, # that's why the user will be asked to run perlcritic locally. # # In fact, this parameter is a workaround for a subtle bug in generic # svn-client thats when svn hook (ie perlcritic-checker.pl) # outputs too much data: svn-client just reports "Connection closed # unexpectedly ". In order to reproduce this bug several additional # conditions should be met: # - repository access scheme: 'svn: //' (svnserve daemon) # - client and server on different machines # - svn-client and -server are running on linux # # If you face the same problem, try to use the option below. #max_violations => 50, # SVN repository path - to - Perl :: Critic's profile mapping. # # This feature allows you to apply different Perl :: Critic's # policies for different paths in the repository. For example, # you can be very strict with brand-new projects, make an # indulgence for some existing project and completely disable # checking of auto-generated or third-party code. # # Each modified (added, updated, copied, moved) file name in the # repository is matched against a sequence of patterns below. # Keep in mind, * last * matching rule - wins. # # Profile paths can be either absolute or relative. In the later # case they will be mapped under $ REPOS / hooks / perlcritic.d directory. profiles => [ # Apply very strict profile by default {pattern => qr {[.] (pm | pl | t) $}, profile => 'perlcritic-brutal.conf', }, ], } EOF
Perl::Critic
'a settings for all *.pm
, *.pl
and *.t
files must be taken from the perlcritic-brutal.conf
. We also enable the progressive mode (read below) and allow emergency commits, i.e. commits are not checked ( NO CRITIC
).Perl::Critic
'a profile ( perlcritic-brutal.conf
), which we referred to in the previous file:mkdir $ SVN_REPO / hooks / perlcritic.d cat> $ SVN_REPO / hooks / perlcritic.d / perlcritic-brutal.conf << 'EOF' # # Perl :: Critic profile example # # Make perlcritic very exacting severity = brutal # You can choose any level from 1 to 11, but 8 is recommended verbose = 8 # Colorize depending on their severity level color = 1 # Halt if this file contains errors profile-strictness = fatal # Enable only two groups of policies: Core and Perl Best Practices theme = core || pbp # Explicitly set full path to Perl :: Tidy's config [CodeLayout :: RequireTidyCode] perltidyrc = / etc / perltidyrc EOF
severity = brutal
), in which he will find fault even with trifles (however, we know that there are no trifles in aviation). The theme
directive indicates that of the entire set of available Policy, and there are about a hundred and fifty, you need to check only those listed in Core or Perl Best Practices groups. We also explicitly indicate the path to the settings of the perltidy
program, a utility for automatically formatting Perl-code. Formatting violation is one of the reasons why a commit may not pass.Perl::Critic
you can read the documentation: perldoc Perl::Critic
.perltidy
(with root privileges):sudo su - cat> / etc / perltidyrc << 'EOF' --perl-best-practices EOF exit
perltidy
format the code according to recommendations from the already mentioned Perl Best Practices book. If you're used to a different style, then the perltidy manual page (1p) will help you choose the formatting options you need.perltidy
first checks the user config $HOME/.perltidyrc
, and then the global one /etc/perltidyrc
. Thus, by placing the config in /etc
we will make it simultaneously accessible both to perlcritic-checker
'a (usually working under the svn
user) and to the perltidy
program perltidy
, whatever the user perltidy
it.perlcritic-checker.pl
script to verify commits. As you might guess, for this you need to edit the pre-commit
hook:cat> $ SVN_REPO / hooks / pre-commit << 'EOF' #! / bin / sh # # SVN pre-commit hook script example # REPOS = "$ 1" TXN = "$ 2" PREFIX = "/ usr / local" # Make sure that Perl code comply to coding standards $ PREFIX / bin / perlcritic-checker.pl \ --repository "$ REPOS" \ --config "$ REPOS / hooks / perlcritic-checker.conf" \ --transaction "$ TXN" || exit 1 # All checks have passed, so allow the commit exit 0 EOF chmod 755 $ SVN_REPO / hooks / pre-commit
export WORK_COPY = "/ tmp / test_project" svn mkdir file: // $ SVN_REPO / test_project -m "" svn checkout file: // $ SVN_REPO / test_project $ WORK_COPY
cat> $ WORK_COPY / good_file.pl << 'EOF' #! / usr / bin / perl # ================================================= ============================== # REVISION: $ Id $ # DESCRIPTION: File without violations # ================================================= ============================== use strict; use warnings; our $ VERSION = '1.0'; sub main { return; } main (); EOF chmod $ 755 WORK_COPY / good_file.pl
cat> $ WORK_COPY / bad_file.pl << 'EOF' #! / usr / bin / perl # ================================================= ============================== # REVISION: $ Id $ # DESCRIPTION: File with violations # ================================================= ============================== use strict; #use warnings; our $ VERSION = "1". "." . "0"; sub main () { return undef; } main (); EOF chmod 755 $ WORK_COPY / bad_file.pl
cd $ WORK_COPY svn add good_file.pl svn commit -m "This should be OK" good_file.pl
cd $ WORK_COPY svn add bad_file.pl svn commit -m "This commit should fail" bad_file.pl
Adding bad_file.pl Transmitting file data .svn: Commit failed (details follow): svn: Commit blocked by pre-commit hook (exit code 1) with output: test_project / bad_file.pl: [Subroutines :: ProhibitExplicitReturnUndef] "return" statement with explicit "undef" at line 15, column 5. (Severity: 5) test_project / bad_file.pl: [Subroutines :: ProhibitSubroutinePrototypes] Subroutine prototypes used at line 14, column 1. (Severity: 5) test_project / bad_file.pl: [TestingAndDebugging :: RequireUseWarnings] Code before warnings are enabled at line 12, column 1. (Severity: 4) test_project / bad_file.pl: [ValuesAndExpressions :: ProhibitNoisyQuotes] Quotes used at noisy string at line 12, column 22. (Severity: 2) test_project / bad_file.pl: [ValuesAndExpressions :: ProhibitInterpolationOfLiterals] Useless interpolation literal string at line 12, column 16. (Severity: 1) test_project / bad_file.pl: [ValuesAndExpressions :: ProhibitInterpolationOfLiterals] Useless interpolation literal string at line 12, column 22. (Severity: 1) test_project / bad_file.pl: [ValuesAndExpressions :: ProhibitInterpolationOfLiterals] Useless interpolation literal string at line 12, column 28. (Severity: 1) --- You can bypass all checks by saying "NO CRITIC" in, eg: svn ci -m "NO CRITIC: emergency hotfix" FooBar.pm
perlcritic --doc TestingAndDebugging::RequireUseWarnings | less
perlcritic --doc TestingAndDebugging::RequireUseWarnings | less
Perl::Critic
module and the list of established Policy, the output may differ slightly (to reduce the likelihood of this discrepancy, we specifically narrowed the list of active Policy using the theme
directive in the perlcritic-brutal.conf
).cd $ WORK_COPY svn commit -m "NO CRITIC: I am in hurry and I dont care" bad_file.pl
Perl::Critic
## no critic (Subroutines :: ProhibitExplicitReturnUndef)
## use critic
Perl::Critic
profile. Then, some policies can be configured. Often in the Policy configuration, you can override the threshold values ​​of its operation, set an exception list, change the operation mode, etc.perlcritic-checker
's progressive mode of operation. Without this capability, it would be impossible to implement this system in the framework of large existing Perl projects. As practice has shown, the number of violations in previously uncritical code (even at a non- severity
level) is simply off scale. Modifying the lion's share of the code, and working code, only for the sake of Perl::Critic
'is impractical, and the abuse of emergency commits ( NO CRITIC
) will reduce the value of this system to zero.perlcritic-checker
's progressive mode perlcritic-checker
? In the progressive mode, perlcritic-checker
for each modified file compares the list of violations to the TO and the list of violations NOW. Both lists of violations are grouped by the name Policy and are supplied with a counter of occurrence. So, if at least one violation was added to the file in the current commit before, then the entire commit will be rejected, and a message will be sent to the user, indicating what type of violations were added and in what quantity. Thus, the perlcritic-checker
closes its eyes to existing violations, but prohibits the introduction of new ones.NO CRITIC
. Fill in this file with new violations and fix some of the existing ones (will the perlcritic-checker
forgive the lack of use strict
in exchange for the included use warnings
?):cat> $ WORK_COPY / bad_file.pl << 'EOF' #! / usr / bin / perl # ================================================= ============================== # REVISION: $ Id $ # DESCRIPTION: File with violations (version 2) # ================================================= ============================== #use strict; use warnings; our $ VERSION = "1". "." . "0"; sub foo () { 1 + 1; } sub main () { return undef; } main (); EOF cd $ WORK_COPY svn commit -m "Add more file to file" bad_file.pl
Sending bad_file.pl Transmitting file data .svn: Commit failed (details follow): svn: Commit blocked by pre-commit hook (exit code 1) with output: test_project / bad_file.pl: [Subroutines :: ProhibitExplicitReturnUndef] "return" statement with explicit "undef" at line 18, column 5. (Severity: 5) test_project / bad_file.pl: [Subroutines :: ProhibitSubroutinePrototypes] Subroutine prototypes used at line 13, column 1. (Severity: 5) test_project / bad_file.pl: [Subroutines :: ProhibitSubroutinePrototypes] Subroutine prototypes used at line 17, column 1. (Severity: 5) test_project / bad_file.pl: [TestingAndDebugging :: RequireUseStrict] Code before strictures are enabled at line 11, column 1. (Severity: 5) test_project / bad_file.pl: [Subroutines :: RequireFinalReturn] Subroutine does not end with "return" at line 13, column 1. (Severity: 4) test_project / bad_file.pl: [ValuesAndExpressions :: ProhibitNoisyQuotes] Quotes used at a noisy string at line 11, column 22. (Severity: 2) test_project / bad_file.pl: [ValuesAndExpressions :: ProhibitInterpolationOfLiterals] Useless interpolation literal string at line 11, column 16. (Severity: 1) test_project / bad_file.pl: [ValuesAndExpressions :: ProhibitInterpolationOfLiterals] Useless interpolation literal string at line 11, column 22. (Severity: 1) test_project / bad_file.pl: [ValuesAndExpressions :: ProhibitInterpolationOfLiterals] Useless interpolation literal string at line 11, column 28. (Severity: 1) test_project / bad_file.pl: [Subroutines :: ProhibitSubroutinePrototypes] You should fix at least 1 violation (s) of this type (was: 1, now: 2) (Severity: 5) test_project / bad_file.pl: [TestingAndDebugging :: RequireUseStrict] you should fix at least 1 violation (s) of this type (was: 0, now: 1) (Severity: 5) test_project / bad_file.pl: [Subroutines :: RequireFinalReturn] You must fix at least 1 violation (s) of this type (was: 0, now: 1) (Severity: 4) --- You can bypass all checks by saying "NO CRITIC" in, eg: svn ci -m "NO CRITIC: emergency hotfix" FooBar.pm
perlcritic-checker
showed a kind of diff violations. In particular, it says that we added the second violation of the type [Subroutines::ProhibitSubroutinePrototypes]
and made two new violations that were previously not found in the file at all: [TestingAndDebugging::RequireUseStrict]
and [Subroutines::RequireFinalReturn]
. As follows from the report, the violation [TestingAndDebugging::RequireUseWarnings]
, which we have corrected, does not give any additional concessions, which was to be expected.perlcritic-checker
does not distinguish the violation of the type [Subroutines::ProhibitSubroutinePrototypes]
on line 13 and line 17. In order for this item to disappear from the “progressive” part of the report, the user can eliminate any of them. Thus, the upper part of the report serves as a kind of reference book in which, by the name of the Policy, you can find the line numbers in which this Policy was violated.NO CRITIC
works in the progressive mode too, but abuse of this feature is highly discouraged.perltidy
: VIM , Emacs .Perl::Critic
'profiles under version control and update the working copy on the server at each commit. So all members of your team will work locally with a single profile, and any changes in it perlcritic-checker
will pick up automatically.severity = brutal
, all Policy included) and add exceptions and corrections to it as necessary.*.pm
, *.pl
and *.t
files in your editor so that they are initially correct from the point of view of the critic.Perl::Critic
'into your production process, it is important to understand that this is just a convenient tool for restoring order, and not a dogma, all the rules (Policy) of which you must blindly follow. Approaching from this position, your team will eventually come to the configuration that perfectly fits your requirements, your project and your habits.Source: https://habr.com/ru/post/115395/
All Articles