Last updated Feb 19, 2024

Fisheye smart commit tutorial

This tutorial will teach you how to write a simple smart commit handler which can look for "/cc @user1 @user2" style comments in commit messages and email mentioned users about the changeset.

Introduction To Smart Commits Handlers and Commit Hooks

A commit hook is a plugin class that is notified when a changeset has been processed by Fisheye/Crucible and has a chance to perform some operation in response to this. Smart commit handlers are special types of commit hooks that wish to be notified only when a certain regular expression matches the commit message of a changeset - ie they are selective in some way about which changesets they respond to.

Smart commit handlers are used to perform an operation based on an explicit command the committing user embedded in their commit message e.g. "FOO-123 #resolve" might be used to tell a smart commit handler to resolve JIRA issue FOO-123 or "+review" might start a review based on the files in the changeset.

Smart commits handlers are notified of new changesets in the order they were committed to the repository. For each changeset notification, the smart commit is supplied the changeset details, the repository details, the Fisheye user associated with the commit (if one can be found), and an object to collate error messages that have been encountered. Smart commit handlers are not invoked on the initial indexing of a repository, only on an incremental update. They are also not invoked when a changeset has been processed by another repository, for example pushing commits in Mercurial or Git between repositories indexed by Fisheye.

Because DVCS technologies like Mercurial and Git allow commits to be attributed to users other than those pushing the changes to the repository, if your Fisheye/Crucible instance has any DVCS repositories then all smart commit handlers will be disabled. This is a security measure to prevent privilege escalation. You can enable individual smart commit handlers from the Administration screen under Repositories > Smart Commits.

If errors are encountered by commit hooks or smart commit handlers while processing a changeset, a single per-changeset email (aggregating all the errors across all the commit hooks) is sent to the Fisheyeuser associated with the commit, if one can be found.  All errors are additionally logged.

Structure of a Smart Commit Handler

Writing a smart commit handler simply requires that you create a class implementing the CommitHook interface and that the following two methods are implemented:

  • getSyntaxPattern() - this must return a Pattern object that is crafted to identify the commit messages of changesets the smart commit would like to respond to
  • processHook(...) - this method is called by Fisheye/Crucible, once per changeset per smart commit handler, and is where your smart commit handler must respond to any commands embedded in the commit message

Because processHook(...) is called only once per changeset per smart commit, if there are multiple commands present in the commit message that the smart commit processor wants to act on, it should act on all of them before returning.

CCSmartCommit.java

1
2
public class CCSmartCommit implements CommitHook {
  public static final Pattern COMMAND_PATTERN = Pattern.compile("/cc((?:\\s+@(?:[a-z0-9]+))+)");

  public Pattern getSyntaxPattern() {
    return COMMAND_PATTERN;
  }

  public void processHook(ChangesetDataFE changeset, RepositoryDataFE repository,
                          UserData author, ErrorMessages errorMessages, Matcher matcher) {
    while(matcher.find()) {
      //Process each /cc in the changeset, grabbing usernames from matcher.group(1)
    }  }
}

Reporting Errors

When an error is encountered by a smart commit handler, such as an incorrect parameter in the command or a temporary communications failure with an external service, smart commit handlers should report these errors so that the committing user can be made aware of the failure and manually perform the operation if needed.

Reporting errors is achieved by calling add(...) on the ErrorMessages instance passed into CommitHook.processHook(...). You must supply:

  • The part of the commit message this error is related to (used to group errors in the error email)
  • The path to a Velocity template that will render a HTML version of the error message. This should render a HTML fragment
  • The path to a Velocity template that will render a plain text version of the error message. . This should render a plaintext fragment
  • The message to be added to the Fisheye/Crucible log (if null, the rendered plain text error message is used)
  • A map of properties to be passed in when rendering the Velocity templates supplied above

CCSmartCommit.java

1
2
//Code to report an error when one or more users are cc'd who don't exist

Set<String> usernames = ...

Map<String, Object> context = new HashMap<String, Object>();
context.put("usernames", usernames);

errorMessages.add(
  "/cc " + matcher.group(1),
  "/fecru-ccsmartcommit-templates/html/noSuchUser.vm",
  "/fecru-ccsmartcommit-templates/plaintext/noSuchUser.vm",
  "Log message",
  context);

And the Velocity templates:

/fecru-ccsmartcommit-templates/html/noSuchUser.vm

1
2
The users #joinAndHtmlEscape(usernames ",") could not be notified of the commit because they do not exist.

/fecru-ccsmartcommit-templates/plaintext/noSuchUser.vm

1
2
The users #join(usernames ",") could not be notified of the commit because they do not exist.

Apart from any properties you place in the Velocity context, the following properties are also made available to you:

Key

Type

Notes

user

com.atlassian.crucible.spi.data.UserData

The possibly null User object that mapped to this changeset.

changeset

com.atlassian.fisheye.spi.data.ChangesetDataFE

The changeset for the commit.

repository

com.atlassian.fisheye.spi.data.RepositoryDataFE

The repository for the changeset.

Declaring a Smart Commit Handler

Smart commit handlers are declared in atlassian-plugin.xml like so:

1
2
...

<commithook name="CC Smart Commit" key="ccsmartcommit" smartcommit="true" class="com.atlassian.fecru.smartcommits.cc.CCSmartCommit">
    <description>Defines a smart commit for processing "/cc @user1 @user2" commands</description>
</commithook>

...

Attributes

Name

Notes

name

A friendly name for this commit hook that can appear in error emails sent to the user.

Required: yes

key

The component key

Required: yes

smartcommit

Defaults to false. Determines whether this commit hook appears in the list of smart commits that can be globally enable or disabled in the Fisheye/Crucible administration page (Repositories > Smart Commits)

Required: no

class

The fully qualified Java class name for your smart commit.

Required: yes

helpPage

An optional URL to a help page for your smart commit and the syntax it supports. If supplied, this will be quoted in any error email for your smart commit.

Required: no

Rate this page: