In this page

Overview

This page is about implementing the Commit Policy Plugin with the Git version control system and Bitbucket Server. If you use Git alone (i.e. without Bitbucket Server), please see the Git page instead.

Please note that Bitbucket Server was called Stash until its 4.0.0 version, when Atlassian decided to re-brand it. As this was essentially just a name change, everything written below is also applicable to Stash.

Working with Bitbucket Server commit policies

Bitbucket Server builds on the top of the Git version control system, extending that with repository, user and permission management capabilities, workflows and other high level functionality. Therefore, everything written in the Git page also applies when using Bitbucket Server.

From the Commit Policy Plugin's angle, the only difference between using Git alone and Git with Bitbucket Server is the set-up steps of the commit hook. This is detailed in the next section, but this is only relevant to you if you are an administrator of the Bitbucket Server. If you are a developer (making commits and pushing those to the Bitbucket Server), you can use your Git client regardless if the server runs Git alone or Git with Bitbucket Server.

In any case, make sure you read the Git page. It explains fixing rejected commits, working with Git features (branching, merging, rebasing, tagging, cherry-picking) and helps to resolve common problems.

Installing Bitbucket Server commit hooks

With other version control systems, integrating with Commit Policy Plugin for Jira requires installing hook scripts to the repositories in the filesystem. For Bitbucket Server, we offer completely web-based integration in the form of a Bitbucket Server app: Commit Policy Plugin for Bitbucket Server.

At its core, this app adds two new components to your Bitbucket Server:

  1. A new repository hook which is invoked when pushing commits to Bitbucket. It connects to Jira, passes the pushed commits, receives the verification result and accepts or rejects the pushed commits based on the result.
  2. A new merge check which is invoked when deciding about the mergeability of pull requests. It connects to Jira, passes the commits in the pull requests, receives the verification result and enables or disables the Merge button for the pull request.

In other words, this app is a bridge between Bitbucket Server and Jira.

Version compatibility

As this integration is composed of 3 components, each with its own versioning, the following table defines the recommended combinations:

Bitbucket ServerCommit Policy Plugin for Bitbucket ServerCommit Policy Plugin for Jira
5.2.x or newer3.0.x or newer3.0.x or newer
5.2.x or newer2.2.x1.3.x - 2.4.x
4.0.x - 5.1.x2.0.x - 2.1.x1.3.x - 2.4.x
3.7.x - 3.11.x0.8.x1.3.x or newer

Note: the compatible Jira version is any version that is compatible with the corresponding Commit Policy Plugin for Jira version.

Installing the Commit Policy Plugin for Bitbucket Server

You will need to execute these installation steps only once, to set up the integration between Bitbucket Server and Jira.

Steps:

  1. Install the Commit Policy Plugin for Jira to your Jira.
  2. Install the Commit Policy Plugin for Bitbucket Server to your Bitbucket Server.
  3. Create the application link between Bitbucket Server and Jira (see next section).
Linking Bitbucket Server to Jira

To establish connection between Bitbucket Server and Jira, the app is using a so-called application link. Application links are the standard and secure way of integrating Atlassian applications. If you already linked Bitbucket Server to Jira, then just review the existing link based on the next section, to make sure that the connection supports OAuth requests with impersonation.

If you haven't created the link yet, here is a short how-to video:

These are the required settings on the two end-points of the application link:

  1. At the Bitbucket Server side of the link:
    1. Login to Bitbucket Server as admin, go to AdministrationApplication Links
    2. Click Edit (pencil icon) at the application link pointing to your Jira
    3. Select OAuth (impersonation) as Local authentication for Outgoing direction
    4. Click Save changes
  2. At the Jira side of the link:
    1. Login to Jira as admin, go to AdministrationApplicationsApplication links
    2. Click Edit (pencil icon) at the application link pointing to your Bitbucket Server
    3. Select OAuth (impersonation) as Local authentication for Incoming direction
    4. Click Save changes

If you are using some older version of Bitbucket or Jira, then the application link editing interface may look differently. In that case follow these instructions:

  1. At the Bitbucket Server side of the link:
    1. Login to Bitbucket Server as admin, go to AdministrationApplication Links
    2. Click Edit at the application link pointing to your Jira → Outgoing AuthenticationOAuth
    3. Check Enable outgoing 2-Legged OAuth requests
    4. Check Enable outgoing 2-Legged OAuth with Impersonation requests
  2. At the Jira side of the link:
    1. Login to Jira as admin, go to AdministrationApplicationsApplication links
    2. Click Edit at the application link pointing to your Bitbucket Server → Incoming AuthenticationOAuth
    3. Check Allow 2-Legged OAuth
    4. Check Allow user impersonation through 2-Legged OAuth

Note: the app will automatically detect if the link is not configured properly for OAuth impersonating authentication. If it finds so, it will display a warning message with some guidance directly in the hook configuration form.

Linking Bitbucket Server to multiple Jira instances

Using modern app versions, you can link the same Bitbucket instance to more than one Jira instances (typically in enterprise deployments). Any of those Jira's may optionally have the Commit Policy Plugin for Jira app installed.

Commit Policy Plugin for Bitbucket will enable selecting any commit policy managed in any of the linked Jira's while configuring hooks. The commit policies are grouped under the Jira instance that hosts them:

After the hook was configured, the commit policy will be transparently verified in the right Jira instance.

(since Commit Policy Plugin for Bitbucket 2.1.0)

About impersonating authentication

The link created in the previous section is a so-called impersonating link. Impersonating is a simple, but powerful concept. It technically means that the Git user's identity will be used to connect to Jira, and then the policy verification will be executed on his/her behalf! It may sound trivial, but this allows more precise verification than using a super-user account with "can-see-anything" permissions.

For example, you can use the currentUser() JQL function to enforce developers to commit against only those issues that are assigned to them:

project = FOOBAR and assignee = currentUser()

On the contrary, you have to pay attention and check if your developers have access to those resources (ex: projects) that are used for the verification. This is usually not a problem with the super-user scenario (as they have access to everything), and very rarely a problem in the impersonation scenario, but this is useful to be aware of.

Hooks and merge checks

Commits, branches and tags can be verified with two mechanisms:

  1. The pre-receive hook called Commit Policy Verification on Pushed Commits verifies the commits that are pushed to the repository, before those are accepted. This hook is your primary safety belt. You should always activate this.
  2. The merge check called Commit Policy Verification on Pull Requests verifies the commits that are sent through a pull request, before those are merged to the target repository. This is your secondary tool to protect the target repository.

Theoretically speaking, using merge checks is "redundant". Why? Say, you have a project-wide policy P, which is consistently enforced using the hook in every repository of that project. In this scenario, all commits sent in pull requests will satisfy P, therefore a merge check which verifies P will never find any commit to reject.

Still, there are two major reasons why we suggest activating merge checks:

  1. Frequently, this is not practical or sub-optimal to use the same exact commit policy with hooks and merge checks. Read the this section.
  2. If the hook is not activated in one of the forks or you have some external non-verified source repository for pull requests (ex: an external sub-contractor), then the merge check adds another level of safety.
Verifying commits, branches and tags pushed to Bitbucket

Majority of the changes are made in local clones and then pushed to Bitbucket managed repositories. It includes newly created commits, branches and tags.

If the commit policy rejects the pushed changes, the rejection information is returned to the VCS client:

You can "fix" the different types of rejected changes as explained in the Git page. After you fixed the change, just push that again.

Verifying branches and tags created in the Bitbucket interface

In addition to creating branches and tags locally and pushing those to the Bitbucket managed repositories, Bitbucket also allows creating branches and tags via its web interface. The branches and tags created using the Bitbucket interface are also verified if you configure the hook in the corresponding repository.

If the commit policy rejects the branch or the tag, the rejection information is shown:

You can "fix" the rejected branch or tag by entering a name that conforms the commit policy.

Verifying pull requests

Since Commit Policy Plugin for Bitbucket 2.2.0 and Bitbucket Server 5.2.0, this is possible to verify pull requests before merging. It aims to reject the pull requests that would violate the commit policy applied to the target repository. Consequently, it guarantees the same level of consistency around pull requests ("merged commits") as it does for regular "pushed commits".

The app implements this mechanism by adding a new merge check type to the built-in merge checks in Bitbucket. After activating, the app will verify the commits in the pull requests, i.e. the commits that would be merged to the target repository. Those are verified against the commit policy applied to the target repository.

If the commit policy rejects the commits, the pull request cannot be merged and the Merge button becomes disabled. Clicking the button, detailed rejection information is shown:

You can "fix" the rejected pull request by fixing the commit(s) that triggered the rejection. After you fixed the commit locally and pushed that, the pull request gets refreshed and becomes compliant with the commit policy. And, then the Merge button becomes enabled, hooray!

Configuring commit policies

First off, create the policy you wanted to apply to your Bitbucket project or repository. For this, login to Jira as administrator, then go to Commits (in the top) → Commit Policies and create the policy. If you already have an existing policy that you want to use, you can skip this step.

Note that the same policy can be re-used by multiple Bitbucket projects or repositories if they require the same set of commit conditions. (I.e. if there is already an existing policy that you could use, do not create a new one.)

Configuring hooks

You can activate hooks at two levels:

  1. At project level by visiting the project → SettingsHooks. In this case, all repositories in that project inherit the setting.
  2. At individual repositories by visiting the repository → SettingsHooks.

Steps:

  1. Go to the Bitbucket project (for project level) or repository (for individual repositories) → SettingsHooks.
  2. Enable the hook called Commit Policy Verification.
  3. Select the policy from the drop-down. (Please note that the selectable options are the commit policies defined in Jira.) You may eventually see a warning box above the drop-down if the app finds some problems:
    1. If the application link is not created yet: create the application link!
    2. If the application link exist, but is not configured properly: review the configuration of the application link at both ends!
    3. If the Commit Policy Plugin for Jira is not installed to Jira: install that app!
    4. If there is no policy created yet: create a policy that you can use!
  4. Test:
    1. Try to create a commit which should be rejected.
      1. For example, if your policy requires at least one issue key, then make a commit with the message "No issue key here".
      2. Check if the commit is rejected.
    2. Try to create a commit which should be accepted.
      1. For example, if your policy requires at least one issue key, include a proper issue key in the commit message: "Fix for MYDB-17".
      2. Check if the commit is accepted.
  5. Have some chocolate, you did a great job!
Configuring merge checks

You can activate merge checks at two levels:

  1. At project level by visiting the project → SettingsMerge checks. In this case, all repositories in that project inherit the setting.
  2. At individual repositories by visiting the repository → SettingsMerge checks.

Steps:

  1. Go to the Bitbucket project (for project level) or repository (for individual repositories) → SettingsMerge checks.
  2. Enable the merge check called Commit Policy Verification.
  3. Select the policy from the drop-down. (Please note that the selectable options are the commit policies defined in Jira.) You may eventually see a warning box above the drop-down if the app finds some problems:
    1. If the application link is not created yet: create the application link!
    2. If the application link exist, but is not configured properly: review the configuration of the application link at both ends!
    3. If the Commit Policy Plugin for Jira is not installed to Jira: install that app!
    4. If there is no policy created yet: create a policy that you can use!
  4. Test:
    1. Try to merge a pull request which should be rejected.
      1. For example, if your policy requires at least one issue key, then include a commit in your pull request with the message "No issue key here".
      2. Check if the pull request cannot be merged.
    2. Try to merge a pull request which should be accepted.
      1. For example, if your policy requires at least one issue key, include a proper issue key in the commit message of each commit in your pull request: "Fix for MYDB-17".
      2. Check if the pull request can be merged.
  5. Have some chocolate, you did a great job!

Pro tip: if the pull request was rejected due to a relatively minor problem, you may eventually fix that directly via the web interface using the Power Editor app.

Optimizing commit policies for hooks vs. merge checks

Although most commit policies work identically with hooks and merge checks, there are differences that may require some consideration:

  1. "Timing" (the stage in the lifecycle of the referenced issues) is different for hooks and merge checks.
    For example, a typical commit policy used with a hook checks if the Jira issue referenced by the commit is in the "in progress" status:
    project = FOOBAR and status = "In progress"
    At the time the integrator is trying to merge the pull request, the issue is probably already in "in review" or "waiting for merge", therefore using the JQL condition with the same JQL query will not enable merging the pull request.
    How to deal with it?
    1. Worst: you could, of course, just drop the status check from the JQL at the cost of making the policy a lot less precise:
      project = FOOBAR
    2. Better: rewrite the JQL to match both cases, even if being sub-optimal in both:
      project = FOOBAR and status != "To do"
    3. Best: create a second variant of the same commit policy with a slightly different JQL (more about variants). This sample JQL checking another status is optimized for merge checks:
      project = FOOBAR and status = "In review"
  2. The JQL function currentUser() works differently with hooks and merge checks.
    In hooks it returns the Jira user who is pushing the commits, while in merge checks it returns the user who is trying to merge the pull request.
    For example, a typical commit policy used with a hook checks if the Jira issue referenced by the commit is assigned to user who is pushing the commit:
    project = FOOBAR and assignee = currentUser()
    At the time the integrator is trying to merge the pull request, currentUser() will return the integrator, therefore the commit policy is violated and the integrator will not be able to merge the pull request (unless the referenced issue is also assigned to him by "coincidence"). This is not wanted.
    How to deal with it?
    1. Worst: you could, of course, just drop the assignee check from the JQL at the cost of making the policy a lot less precise:
      project = FOOBAR
    2. Best: create a second variant of the same commit policy with a slightly different JQL (more about variants). This sample JQL allowing merging commits referenced by issues assigned to product developers:
      project = FOOBAR and assignee in membersOf("product-developers")
Using two variants of the same commit policy

For the most flexibility, you may want to create two separate, slightly different variants of the same commit policy: one optimized for the hook use case and the other optimized for the merge check use case. Although it results in a larger number of commit policies to maintain, keeping those as strict as possible is worth it in many cases.

A best practice is to express the two policies' relation using a simple naming convention: the hook optimized variant is called "My favourite policy (hook)", while the merge check optimized variant is called "My favourite policy (merge check)".

Then, just make sure that you apply the right variant at the hook and at the merge check.

Integrations

Power Editor for Bitbucket

Power Editor for Bitbucket is a popular app that enables adding, editing and deleting files directly on the Bitbucket user interface. Although you should not use it for major source code refactorings, it makes making quick changes like fixing a typo, rewriting a source code comment or increasing a version number, lighting-fast. It does so by eliminating the need of pulling the file, making the change, committing that and pushing that.

Committing changes with Power Editor

Changes made with Power Editor are verified against the commit policy (applied to the given repository) the same way as changes made with your "real" Git client are. In case of rejection, the result is shown right above the editor:

Using Power Editor together with Commit Policy Plugin you can both work fast and enforce a strict policy to your source code, change history, repository layout and content.

Fixing rejected pull requests with Power Editor

In addition to creating new commits, you can use Power Editor to fix rejected pull requests, although the possibilities are fairly limited here. You can fix those types of problems that can be fixed by adding a new commit to the ones already in the pull request. (Power Editor will not allow reworking existing commits.)

Or, you can add a new commit with a bypass tag if you want to bypass the commit verification for this pull request.

Commit Policy Plugin for Bitbucket alternatives

There are other Bitbucket apps existing with commit verification functionality. You may be wondering how the alternatives compare to Commit Policy Plugin for Bitbucket?

Comparison

Commit Policy Plugin for Bitbucket Jira Hooks for Bitbucket Yet Another Commit Checker
Project-level and repository-level configuration Yes Yes No (global and repository-level only)
Shared configuration Yes (reuse policies among projects and repositories) No No
Flexibility High (multiple per-branch or per-directory rules, multiple conditions combined with AND/OR) Low Low
Commit-time verification (with local hooks) Yes (super-fast!) No No
Push-time verification (with Bitbucket hooks) Yes Yes Yes
Pull request verification (with Bitbucket merge checks) Yes Yes No
Tag verification Tag name format, issue links No No
Branch verification Branch name format, issue links Branch name format, issue links Branch name format
Commit message verification Text format, issue links Text format, issue links Text format, issue links
Commit file verification File paths, issue links No No
Commit author verification Name, email, user account, Jira group membership No Name, email
Verification completeness Complete verification of all conditions on all changes Verification stops at first failure Verification stops at first failure
Support for multiple linked Jira instances Allows precisely selecting the Jira instance and the commit policy ? Repeats the verification in each linked Jira instance (may be inaccurate)
Support Supported Supported Supported by the user community

Advanced topics

Installing Bitbucket Server commit hooks using Git hook scripts

This section describes an alternative method to integrate Bitbucket Server with Jira. It takes a lower level approach, based on native Git hooks (instead of Bitbucket Server hooks). It should be used very rarely, in situations when you want more control or custom behaviour. It works by adding actual Git hook scripts to the repositories managed by Bitbucket Server, without conflicting with the hook scripts dynamically generated by Bitbucket Server.

The idea is that we will use a Bitbucket Server hook type called External Pre Receive Hook, which can execute external commands on the server. We will configure this hook to execute the Python interpreter with the Commit Policy Plugin's hook script! That way the policy checker hook script becomes a natural part of the Bitbucket Server managed hooks.

Before starting the hook installation, we strongly suggest reading this section. It is about Git workflows in general, and about deciding which repositories you should install the hooks into.

Actual installation steps:

  1. If it is not installed yet, install the External Hooks Plugin to Bitbucket Server. It is free and it provides the hook type we're going to use. If it is already installed, skip this step.
    Installing the app requires administrator permissions to Bitbucket Server, and it is described in the Installation tab here.
  2. Generate a hook script package for Git, the same way you'd do when using Git without Bitbucket Server.
  3. Extract the ZIP to some temporary directory.
  4. Because Bitbucket Server has its own hook script called pre-receive, we need to avoid the conflict: rename the file pre-receive to pre-receive.jcp in the temporary directory.
  5. Login to Bitbucket Server as administrator. Go to the SettingsRepository details page of the repository to which you want to install the hook script. The Location on disk field will show you the repository's directory in the server's filesystem.
  6. Go to that directory in the filesystem, and then to its hooks subdirectory. Move the files from the temporary directory to this directory.
  7. As instructed by the Hook Script Generator's guide (step 4), add the execution permission to pre-receive.jcp (not pre-receive!) and run pre-receive.jcp (not pre-receive!) in diagnostic mode to verify if it works.
  8. Open pre-receive.jcp in a plain text editor and change this line (around line 28):
    return not sys.argv[0].startswith("hooks")
    to:
    return False
  9. Go back to Bitbucket Server, to the SettingsHooks page of the repository. Enable the External Pre Receive Hook with the following parameters:
    • Executable: /usr/bin/python
      This is the full path of the Python executable in your server which will be launched by this hook. If you mistype this, the hook will fail to execute Python.
    • Safe mode: leave it unchecked
    • Positional parameters: <YOUR_REPOSITORY_DIRECTORY>/hooks/pre-receive.jcp
      This is the full path of the Commit Policy Plugin's hook script. Don't forget to enter the actual directory path to the <YOUR_REPOSITORY_DIRECTORY> placeholder. The final path should be similar to this: /srv/atlassian-stash-data/shared/data/repositories/71/hooks/pre-receive.jcp. If you mistype this, Python will fail to find the script.
  10. Do some testing by commiting changes that should be rejected (negative testing) or accepted (positive testing).
  11. Have a chocolate, coffee or beer - depending on the period of the day.

Troubleshooting

I see an error message "An error occurred while processing the request" at pull requests

Secondary symptoms: the spinner of the "Merge" button does not stop and an exception was thrown in PullRequestService.canMerge().

This is caused by a minor Bitbucket bug (BSERV-10045) which was fixed in Bitbucket 5.4.0.

You can safely ignore the red error message: it is harmless and it is displayed only once. Just reload the page in your browser to make it disappear. And then as an actual solution, upgrade to Bitbucket 5.4.0+.

Questions?

Ask us any time.