In this page

Better Commit Policy for Bitbucket integrates the Better Commit Policy for Jira app to Bitbucket repositories with a fully native experience. Therefore, if you haven't yet, read the Better Commit Policy for Jira documentation first.

Installing Bitbucket Server commit hooks

For most version control systems, integrating the Better Commit Policy for Jira app to the VCS requires installing hook scripts to the repositories. For Bitbucket Server, we offer completely web-based integration in the form of the free Better Commit Policy for Bitbucket app.

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.

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 Better Commit Policy for Jira app installed.

Better Commit Policy 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 Better Commit Policy 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 Better Commit Policy 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 Better Commit Policy 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 Better Commit Policy 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.

Questions?

Ask us any time.