Upgrade to Bitbucket Server 4.0

This page describes how to migrate from Stash to Bitbucket Server 4.0. Release 4.1.2 is the first release that is compatible with Bitbucket Server.

Bitbucket Server is the next evolution of Stash, however Atlassian have taken it as an opportunity to bypass their usual API stability policy. As such, you will have to modify your scripts. Atlassian have intimated that this is a one-time change, and after this there will be several years of low friction in the API. If you don’t have any custom scripts, and are only using the simple conditions that come as examples in the plugin, you may well have nothing to do.

If you have any issues please contact us via our Service Desk.

This page is split up into a suggested upgrade procedure, and the possible areas you will need to change.

At the time of writing, the official page explaining the upgrade procedure is here, although there is currently permissioning on this page.

How to Upgrade

First you should create a clone of your production system that you can do a practice upgrade on. Creating staging systems is not well documented, but there is enough information in STASH-5271 and on this answer.

Once you have the staging system created, upgrade it to Bitbucket Server 4. Then install the ScriptRunner plugin.

The static type checker that was recently introduced to ScriptRunner for Jira is now available in ScriptRunner for Bitbucket Server, so you should be able to see quite quickly if you have any problems.

You should open each admin page that lists each extension point, eg pre-receive hooks, listeners etc. Look for code highlighted with red errors, and fix them

The condition script is not currently shown in the overview page, so click edit for each listener or hook etc, and check that the condition shows the green dot of successful compilation.


If practical, test your most important scripts and conditions in your staging server.

Production Upgrade

Finally, make sure that your maintenance window includes enough time to do your production upgrade, and then the modifications to the scripts that you have already tested in your staging server.

Areas of Change

This is not a definitive list, for that see the Atlassian guidelines. However, these are the changes I think you are most likely to have to make.

Package Names

Packages have been renamed from com.atlassian.stash to com.atlassian.bitbucket. This will affect you if you have custom scripts, or conditions, that import any classes.

If there are errors in your scripts you will see something like:

You can correct that in this case by just replacing the word stash with bitbucket.

Some event classes have changed package too, for example com.atlassian.stash.event.RepositoryCreatedEvent has moved to com.atlassian.bitbucket.event.repository.RepositoryCreatedEvent, that is, it’s moved under the repository package. Same for project events

Another example. If you were using the condition to check a user was in a group, it may have been:

import com.atlassian.sal.api.component.ComponentLocator import com.atlassian.stash.user.UserService import com.atlassian.stash.user.StashAuthenticationContext def userService = ComponentLocator.getComponent(UserService) def authContext = ComponentLocator.getComponent(StashAuthenticationContext) userService.isUserInGroup(authContext.getCurrentUser(), "project-creators")

Now it should be:

import com.atlassian.sal.api.component.ComponentLocator import com.atlassian.bitbucket.user.UserService import com.atlassian.bitbucket.auth.AuthenticationContext def userService = ComponentLocator.getComponent(UserService) def authContext = ComponentLocator.getComponent(AuthenticationContext) userService.isUserInGroup(authContext.getCurrentUser(), "project-creators")

Class Names

Some classes have changed names, for example RepositoryMetadataService has become RefService. StashUser is now BitbucketUser.

KeyedMessage Behavior Change

com.atlassian.bitbucket.i18n.KeyedMessage is used to cancel events in listeners. The signature is KeyedMessage(String key, String localisedMessage, String rootMessage).

The first parameter is the key, which is used for translating the messages into different languages. Typically in scripts you do not bother with localization, so previously you may have written:

event.cancel(new KeyedMessage(null, "some message", null)

Now all parameters are mandatory, so I suggest you use:

def msg = "some message" event.cancel(new KeyedMessage("dummy", msg, msg)
On this page