Checkstyle makes it easy to automate code reviews once the code has been committed, but wouldn't it be better if programming errors never made it that far? In this second half of "Automated code reviews with Checkstyle," authors ShriKant Vashishtha and Abhishek Gupta show you how to be proactive about code quality. Find out how to use Checkstyle's custom rules to enforce code standards and catch mistakes -- long before code is committed to your code base. Level: Intermediate
Enjoy premium bluetooth wireless Music and a lifetime warranty against sweat, at a significantly
Read NowIn the first half of this article, you learned how easy it is to create and use custom Checkstyle rules for automated code reviews. The solution we presented in that article was only partial, however: it offers custom rules but no mechanism for keeping faulty code out of your code base. In this article we'll show you how to use Checkstyle to proactively enforce code standards, first by catching them as they're written, and then by catching them at the source repository level. Proactively enforcing code standards at these levels will make code reviews less time-consuming, and will allow your team to concentrate on the finer points of code quality.
The first example is based on a custom Eclipse plugin, which displays a warning when it spots a problematic line of code. The second example, especially good for teams not using Eclipse, shows you how to use Subversion's pre-commit hook to check for code violations. This approach bars developers from committing source code with un-fixed violations.
We'll start with building the custom Eclipse plugin to handle custom checks. If you're not familiar with creating custom rules in Checkstyle, you should probably read the first half of this article before continuing. If you're not using the Eclipse IDE, skip ahead to learn about enforcing code standards with pre-commit hook.
The standard eclipse-cs Eclipse plugin works well for Checkstyle's built-in checks, but you'll need to create your own plugin to handle custom checks. For the sake of demonstration, we'll use IllegalExceptionThrowsCheck
, the simpler custom check from the first half of this article. The sample code for this article contains the source code for IllegalExceptionThrowsCheck
. Note that we assume familiarity with the Eclipse development environment and plugins.
Before you begin, you have the option to provide metadata in the form of a checkstyle-metadata.xml file for the custom checks; this makes it easier to use the capabilities of the Eclipse plugin's configuration editor. Place this file into the packages where your check classes reside. You'll be able to configure your custom check with the editor just as you can any standard Checkstyle module. Listing 1 contains the sample configuration for your custom check, IllegalExceptionThrowsCheck
.
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE checkstyle-metadata PUBLIC"-//eclipse-cs//DTD Check Metadata 1.0//EN""http://eclipse-cs.sourceforge.net/dtds/checkstyle-metadata_1_0.dtd"><checkstyle-metadata> <rule-group-metadata name="Custom Checks" priority="900"> <rule-metadata name="Illegal Exception Throw" internal-name="IllegalExceptionThrowsCheck" parent="TreeWalker"> <alternative-name internal-name="com.abc.checkstyle.check. IllegalExceptionThrowsCheck" /> <description></description> <property-metadata name="illegalExceptionsInThrows" datatype="String" default-value="Exception,java.lang.Exception"> <description></description> </property-metadata> </rule-metadata> </rule-group-metadata></checkstyle-metadata>
The root <checkstyle-metadata>
tag can contain the metadata of multiple rule groups, each with a <rule-group-metadata>
tag. The name
attribute is used as the display name, and the priority
attribute influences the order in which the groups appear in the configuration editor.
The rule-metadata
elements contain the metadata information for a check module. internal-name
is the logical name of the module, and parent
determines whether the module is a FileSet
check or a regular TreeWalker
check.
Every rule-metadata
element must contain at least one alternative-name
element that provides the mapping of this check with the one available in the Checkstyle configuration file created for custom checks. (That is, custom_check.xml, in this case the name could be something else.) This file is used to configure the custom Checkstyle checks and is placed in the <path-to-my-eclipse>/plug-ins/com.atlassw.tools.eclipse.checkstyle_x.x.x directory. The rule-metadata
element may also contain property-metadata
elements, which are used to configure the check in the plugin configuration editor.
Next, you need to package the already created custom checks into a JAR file and place that file in the <path-to-my-eclipse>/plug-ins/com.atlassw.tools.eclipse.checkstyle_x.x.x/extension-libraries directory. Then copy custom_check.xml to the Checkstyle plugin folder. After that, you'll need to make some changes in plugin.xml, which is located in the Checkstyle plugin folder (<path-to-my-eclipse>/plug-ins/com.atlassw.tools.eclipse.checkstyle_x.x.x). You'll put the details of your extensions under the <extension>
tag, as shown in Listing 2.
<!-- Standard plugin check configurations --> <extension id="checkstyle.CheckConfiguration" point="com.atlassw.tools.eclipse.checkstyle.configurations"> <check-configuration name="Sun Checks" location="sun_checks.xml" description="%SunChecks.description"/> <check-configuration name="Custom Checks" location="custom_check.xml" description="%CustomChecks.description"/> <check-configuration name="Sun Checks (Eclipse)" location="sun_checks_eclipse.xml" description="%SunChecksEclipse.description"/> </extension>
As the description
attribute of the check-configuration
tag can be internationalized, it is externalized in <path-to-my-eclipse>/plug-ins/com.atlassw.tools.eclipse.checkstyle_x.x.x/plugin.properties, as shown in Listing 3.
CustomChecks.description = Checkstyle configuration that checks the project specific coding conventions.
You will be able to see this configured description under the Description tab of the Checkstyle space in the Eclipse configuration, as illustrated in Figure 1.
Next, you need to restart Eclipse at the command prompt with the -clean
option, as follows:
<path-to-eclipse> eclipse -clean
Now, in Eclipse choose Windows > Preferences > Checkstyle. You'll see your custom checks in the editor, as illustrated in Figure 2. You can set this new set of checks as the default for an entire workspace, or can choose a subset of them for a specific project.
After you have configured your Eclipse project with the custom Checkstyle checks, code that violates the rules laid down in your Checkstyle configuration will cause an an error, along with message describing the problem. For example, if you configured a project with a rule limiting the number of methods that a class could have, going over that limit would result in a message like the one shown in Figure 3.
What if your project uses an IDE other than Eclipse? Or, even if your team does use Eclipse, what if one of your developers uses some other text editor to create Java classes and commit them into Subversion? It's very difficult to track these kinds of issues unless you're using a continuous integration environment for continuous builds.
One solution is to apply Checkstyle rules at the repository level, using Subversion. This approach bypasses the IDE and prevents developers who don't comply with project-level coding standards from committing source code to the SCM repository. If you want to be extra proactive, you can combine this approach with compile-time build checks via the Eclipse plugin or at Ant-based build time. By default your build tool will be able to tell you if your source code has passed the checks or not. Even developers who escape build-time checks will be caught when they attempt to commit the non-compliant code into Subversion. All of this is possible using SVN's repository hooks.
A hook is a program triggered by some repository event, such as the creation of a new revision or the modification of an unversioned property. Some hooks (so-called pre hooks) run in advance of a repository operation and provide a means by which to both report what is about to happen and to prevent it from happening at all. Other hooks (called post hooks) run after the completion of a repository event and are useful for performing tasks that examine -- but don't modify -- the repository. Each hook is given enough information to tell what an event is (or was), the specific repository changes proposed (or completed), and the username of the person who triggered the event.
The Subversion hooks subdirectory is, by default, filled with templates for various repository hooks, as you can see in Listing 4.
$ cd /home/shrikant/svn/myrepos/hooks$ lspost-commit.tmpl post-unlock.tmpl pre-revprop-change.tmplpost-lock.tmpl pre-commit.tmpl pre-unlock.tmplpost-revprop-change.tmpl pre-lock.tmpl start-commit.tmpl$
These are they types of hooks you can find in a Subversion repository:
start-commit
: Notification of the beginning of a commit.pre-commit
: Notification just prior to commit completion.post-commit
: Notification of a successful commit.pre-revprop-change
: Notification of a revision property change attempt.post-revprop-change
: Notification of a successful revision property change.pre-lock
: Notification of a path lock attempt.post-lock
: Notification of a successful path lock.pre-unlock
: Notification of a path unlock attempt.post-unlock
: Notification of a successful path unlock.As previously noted, the interesting hook for the purposes of this article is the pre-commit hook. This hook is run just before a commit transaction is promoted to a new revision. Typically, this hook is used to protect against commits that are disallowed due to content or location -- for example, the incoming log message should be non-empty, and the hook will prevent the commit if that's not the case.
If the pre-commit hook program returns a non-zero exit value, the commit is aborted, the commit transaction is removed, and anything printed to stderr
is marshaled back to the client.
It should be obvious at this point that a pre-commit hook can be used to check Java files against Checkstyle rules before those files are committed in Subversion. Pre-commit hooks are either shell scripts (on UNIX-like systems) or .bat/.exe files (on Windows systems). As soon as a new Subversion commit is processed, the Subversion kernel calls any repository hooks available. So, if a pre-commit hook could somehow call a Checkstyle command for each Subversion transaction (list of files) being committed, it would return a list of errors. For checking errors for a Java file, the Checkstyle command is as follows:
java -classpath checkstyle-customchecks.jar:checkstyle-all-<version>.jar com.puppycrawl.tools.checkstyle.Main -c <JavaFileName>
If a repository pre-commit hook could intercept files about to be committed, execute that command, format the errors, and display them to the developer, you'd be sitting pretty. Building something like that from scratch would take time and require knowledge of Subversion internals. Fortunately, some good open source projects are focused on the usage of Subversion hooks. One of them is Subversionchecker, a project based on Python. Subversionchecker is quite modular and provides you with sets of checks (Checkstyle, UnitTests, XMLValidator, AccessRights, Checkout, etc.) and handlers. For each kind of check, you can also configure what you want to do (send the message to console, for example, or to a file, or through e-mail); that comes under the handler's module.
For the purposes of this article, you'll use Checkstyle to check only the pre-commit hook of a repository. As you might have already guessed, Subversionchecker provides a configuration file to let you choose among checks and handlers. In the rest of this section, you'll configure Subversionchecker for your Subversion repository and custom Checkstyle check. Please note that all of these steps should be executed on your Subversion server machine.
To begin with, you'll need to download and install Python so that it's available for your pre-commit hook script. Download and install Subversionchecker as well.
Next, you need to check to see if a pre-commit hook script is already available in your Subversion repository in the hooks directory. If not, you may want to copy the existing pre-commit.tmpl file (which is located in that same hooks directory) to the pre-commit file. You'll want to make changes to the file as follows:
<Subversionchecker_installed_path>/Subversionchecker-<version>/Main.py PreCommit $REPOS $TXN || exit 1
To configure Subversionchecker, you need to provide information in a configuration file, called Subversioncheckerconfig.ini, which is located in the hooks directory of the Subversion repository. Listing 5 shows the configuration required for your Checkstyle check.
+1 [Default] +2 ; This property tells Subversionchecker about all checks (UnitTests, AccessRights, XMLValidator etc) it should execute. Separated with comma (",") +2 Main.PreCommitChecks=Checkstyle +4 ; Path of java executable to run Checkstyle command +3 Checkstyle.Java=/usr/bin/java +6 ; Classpath for executing Checkstyle rules +4 Checkstyle.Classpath= /home/shrikant/checkstyle/custom_checks.jar:/home/shrikant/checkstyle/checkstyle-all-4.3.jar +8 ; Configuration file for Checkstyle to run its rules. +5 Checkstyle.ConfigFile= /home/shrikant/checkstyle/custom_checks.xml +9 ; In case of failures, where should Subversionchecker redirect the errors +10 Checkstyle.FailureHandlers=Console
Note that in .ini files ;
denotes a comment. The meaning of each property should be fairly obvious. All of the properties in Listing 5 are mandatory for running Checkstyle with Subversionchecker.
As you can see, with Subversionchecker you can configure any kind of Checkstyle rules. Now, when you try to commit Java files with errors into Subversion, you'll get errors from Checkstyle of the kind shown in Listing 6.
~/svn/myrepo/SampleProject/src/com/sample$ svn commit -m "Sample" Sending sample/Test4.java Transmitting file data .svn: Commit failed (details follow): svn: MERGE request failed on '/svn/myrepo/SampleProject/src/com/sample' svn: 'pre-commit' hook failed with error output: ================================================================================ Coding style errors found: Starting audit... /tmp/tmpudEfyg/SampleProject/src/com/sample/Test4.java:2: too many methods, only 3 are allowed /tmp/tmpudEfyg/SampleProject/src/com/sample/Test4.java:18:35: Method call not allowed in Conditional Expr -> getLength Audit done. See Checkstyle documentation for a detailed description: http://checkstyle.sourceforge.net/ ================================================================================
Enjoy premium bluetooth wireless Music and a lifetime warranty against sweat, at a significantly
READ NOWThis two-part article has introduced you to building custom rules for automated code reviews, and then using them to proactively enforce code standards before code enters your code base. As we demonstrated in the first half of this article, creating custom rules for Checkstyle is actually easy to do. Once you have a set of custom rules, or checks, you can use them to enforce project-specific coding standards in automated code reviews. We showed you how to create both a simple rule and a more complex one; both examples can be found in the article source code.
In the second half of the article, we took the notion of proactive code reviews to the next level, showing you how to catch faulty code before it enters your code base. Creating a custom Eclipse plugin enables you to alert developers on your team when they violate custom rules (assuming they're using Eclipse). We also showed you how to use and configure SVN's pre-commit hook, which prevents developers from committing rule-breaking code to the project repository. Either way, the end result is cleaner code with less hassle for you. See the Resources section below to learn more about Checkstyle and other tools for monitoring, reviewing, and enforcing code quality.
聯(lián)系客服