Bitbucket Server plugin development

Aditi Dosi
5 min readDec 21, 2023

Introduction

Bitbucket offers the possibility of implementing repository hooks to add functionalities or enforce policies in your version control system. These hooks can be either local or on the server side. Clearly, a local hook only affects your local copy of the repository, whereas a server side hook works for all repository descendants, so long as it is added to the origin repository. The second option is obviously the better idea if you want to enforce policies among all collaborators.

However, according to Bitbucket’s documentation, creating a server side hook is strongly discouraged. As an alternative, they suggest using the Bitbucket Java Plugin Development Framework to create a hook wrapped inside a Bitbucket plugin.

The next sections will guide you through implementing, testing, and setting up a simple Bitbucket plugin that implements a pre-repository hook.

Prerequisites

Depending on your Bitbucket server version and the JRE running on it, there are important prerequisites to consider:

  • Before Bitbucket server 6.0: Although installing the SDK with a higher Java version would work, it is better to keep using Java 8 while working on the plugin. In fact, compiling with a different Java version could lead to inconsistencies at runtime.
  • Bitbucket 6.0 added support for Java 11, but it also still supports Java 8. This means it is possible to use both Java versions. Ideally, you should use the same distribution and version as the one on top of which your Bitbucket server is installed. Otherwise you could face at runtime problems saying that the plugin was compiled with a higher Java version.
  • You need to have Maven installed in order to be able to build the Bitbucket plugin module.

Create and Initialize the Plugin Skeleton

After the SDK is installed, it is time to create and initialize the Maven plugin project. The first step is to create the project skeleton using the following command:

Atlas-create-bitbucket-plugin

Next, the command line interface will prompt you to set the following values:

  • Group Id: e.g., intellij.plugin
  • Artifact Id: e.g., commit-message-vaidator-plugin
  • Use OSGi Java Config: Y

For the rest, just pressing “Enter” is sufficient, as this is a basic plugin.

The project generated by the above mentioned command contains the sample component classes MyPluginComponent and MyPluginComponentImpl, test classes, resources files (css, images, js, xml) and a Pom file. The important files and resources to keep are the pom.xml file and the atlassian-plugin.xml which is the descriptor where the plugin’s class implementation is declared and looks something like this:

<atlassian-plugin key=”${atlassian.plugin.key}” name=”${project.name}” plugins-version=”2">
<plugin-info>
<description>${project.description}</description>
<version>${project.version}</version>
<vendor name=”${project.organization.name}” url=”${project.organization.url}” />
<param name=”plugin-icon”>images/pluginIcon.png</param>
<param name=”plugin-logo”>images/pluginLogo.png</param>
</plugin-info>
</atlassian-plugin>

Adjusting the Pom File

Most likely, the project will not compile from the first shot. You will need to add a Maven central repository and the Bitbucket repositories, so that the dependencies (libraries, plugins) are downloaded:

<pluginRepositories>
<pluginRepository>
<id>spring-libs-milestones-plugins-repository</id>
<name>Spring lib M Repository</name>
<url>https://repo.spring.io/libs-milestone/</url>
</pluginRepository> <pluginRepository>
<id>maven-central-plugin-repository</id>
<name>Maven Central Plugin Repository</name
<url>https://repo.maven.apache.org/maven2</url>
</pluginRepository>
</pluginRepositories><repositories>
<repository>
<id>spring-libs-milestones-repository</id>
<name>Spring lib M Repository</name>
<url>https://repo.spring.io/libs-milestone/</url>
</repository> <repository>
<id>maven-central-repository</id>
<name>Maven Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
</repository>
</repositories>

The bitbucket-maven-plugin plugin module is responsible for the compilation and bundling of the project into an installable file (supported formats are Jar and Obr — an OSGi bundle repository supported by Bitbucket servers). By default, it is configured to use Java 8, so make sure not to include dependencies that need a higher version, as this would lead to inconsistencies during the build.

Using a different Java Version

The plugin created by the above mentioned SDK command is destined for Bitbucket 5.16.0 which basically supports Java 8. Eventually, you will have a newer Bitbucket server running on a higher Java version (e.g., Java 11). That means you will need to do some Pom clean up and version upgrades before continuing. I have a Bitbucket Server 7.5 running on top of Java 11, so I had to go through the following steps:

1- I changed the Bitbucket server version in the properties to the desired version, 7.5.0 (note the use of semantic versioning):

<bitbucket.version>7.5.0</bitbucket.version>

2. The Maven build command would automatically update the project dependencies (e.g., bitbucket-api) and freshly download them from the springs-libs-milestones-repository. The first build failed due to a missing dependency, so I just added them in order to finish building.

<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>

3. I updated the Java version used by the maven-compiler-plugin to 11.

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>

4. I told the maven-compiler-plugin to use Java 11 as well.

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>

Implementation

After creating a Maven compilable project with a clean Pom, it is time for the concrete implementation. There are different interfaces to be implemented, depending on what you want to achieve. As mentioned in the beginning, this article focuses on creating a pre-repository hook.

As a first step, create a plugin module using the following SDK command:

Atlas-create-bitbucket-plugin-module

The command line will prompt you to choose the module type. Currently, the following types are available: (Commit Indexer, Keyboard Shortcut, Repository Hook, SCM Request Check, SSH Request Handler, Component Import, Component, Downloadable Plugin Resource, Licensing API Support, Module Type, REST Plugin Module, Servlet Context Listener, Servlet Context Parameter, Servlet Filter, Servlet, Template Context Item, Web Item, Web Panel Renderer, Web Resource, Web Resource Transformer).

You should choose option 3 to create a repository hook plugin. When selecting the type, give the hook’s class/package name and answer the rest of the prompt messages with “N,” if there are no special requirements and/or additional modules. Then, the generated class is a Java class that implements the PreReceiveRepositoryHook interface. Its onReceive() method serves to implement some business logic whenever it receives an action on that repository (e.g., pushing a set of commits).

In the current example, I wanted to create some sort of control on the commit message whenever it is pushed to the origin. To achieve that, I decided to implement the PreRepositoryHook instead, as its preUpdate() method takes an PreRepositoryHookContext object in parameter which allows me to register a PreRepositoryHookCommitCallback object. The callback interface has a set of methods to be implemented depending on the action to be performed vis-à-vis a commit action. I therefore implemented the onCommitAdded() method as a way of enforcing some checks on the commit message before pushing in to the origin repository. The new implemented class representing the hook is automatically added to the descriptor file atlassian-plugin.xml. Any changes to the class name and/or its containing package should be updated in that file.

Conclusion

There a couple of things to consider when implementing a bitbucket plugin. The most important ones could be briefly summarized as follows:

  • The default Pom file is outdated, so make sure to clean it and update the versions of the dependencies.
  • Make sure the configured Bitbucket version is similar to the target Bitbucket server instance.
  • To develop and compile the plugin, use the same Java version as the one on top of which the target Bitbucket server is installed.
  • You will need to configure the maven-bitbucket-plugin with some tweaks so that the Bitbucket server can enable the plugin bundle.

--

--