Automating DevOps with Bitbucket Pipelines – Configuring Triggers and Branch Protection Rules

Series Navigation:

  1. Automating DevOps with Bitbucket Pipelines: Setting Up Repositories and CICD in BitBucket
  2. Automating DevOps with Bitbucket Pipelines: Configuring Triggers and Branch Protection Rules (This Article)

Introduction

This article is part of a series on setting up CI/CD in BitBucket. In this article, you’ll learn about pipeline triggers and branch protection rules – two essential concepts for efficient & secure pipelines.

Triggers in a CI/CD pipeline are the actions or conditions that initiate a pipeline run. They ensure pipelines run automatically, saving time and reducing errors. Pushes to a branch, pull request creation, or manually started pipeline runs are examples of triggers.

Branch protection rules are a set of permissions and checks that control the actions that can be performed on key branches and the users who can make those changes.

Pipeline Triggers

Triggers are the start conditions for your pipelines. They are defined in a pipelines property in the bitbucket-pipelines.yml file. This property includes the pipeline trigger and steps that should be run when the pipeline is started.

[!tip]
Restricting your pipelines to start certain conditions e.g only when a pull request is created or updated can reduce the number of build minutes used by your team

Pipelines can be triggered by any of the following:

  • a commit to any branch — This is the Default start condition.
  • a commit to a specific branch — This is the Branches start condition
  • when a pull request is made or updated — Known as the Pull Request start condition
  • when a git tag is created — The Tags start condition.
  • Run when manually started by the user. — The Custom start condition.

Let’s cover examples of start conditions in the next section.

Push to any branch

This is the default start condition that matches pushes to any branch that does not match a pipeline definition in other sections of the bitbucket-pipelines.yml file.

pipelines:
    default:
        - step:
            name: All pushes
            script:
                - echo "Hello, World"

This pipeline runs on every push to the repository unless a branch-specific pipeline is defined.

Push To A Specific Branch

To trigger pipelines for pushes to a specific branch, use the branches property. Pushes to a branch specified under branches do not trigger the default pipeline.

pipelines:
    branches:
        develop:
            - step:
                name: All pushes to develop branch
                script:
                    - echo "Hello, Develop!"
        staging:
            - step:
                name: All pushes to staging branch
                script:
                    - echo "Hello, Staging!"

The example below shows a pipeline definition for steps run when code is pushed to the develop and staging branches.

Pull Request

To run pipelines when Pull Requests are created, use the pull-requests property:

pipelines:
    pull-requests:
        staging:
            - step:
              name: Unit tests for staging branch pull request
              script:
                  - echo: "Hello, staging branch pull request"
        hotfix/*:
            - step:
              name: Lint checks for hotfix branch pull request
              script:
                  - echo: "Hello, hotfix PR"

        '**':
            - step:
              name: Build for all other pull requests
              script:
                  - echo: "Hello, non staging or hotfix pull request."

The example above shows triggers for pull requests made against the staging and hostfix branches. hotfix/* will match any PR to a branch that starts with hotfix/. The last pull request pipeline ('**') runs for pull requests to any other branch that doesn’t match the first two, similar to how a default branch pipeline works.

Git Tags

Git Tags are used to mark specific versions of your code. To run pipelines against tags in BitBucket, use the tags property:

pipelines:
    tags:
        '**':
            - step:
                script:
                    - echo "This will run the pipeline for all tags"
       '*-release*':
           - step:
                script:
                    - echo "This will run the pipeline for all tags containing 'release' in them."

The first example will run the first pipeline whenever a git tag is encountered that doesn’t match any other tags defined under the tags property in the bitbucket-pipelines.yml file. The next pipeline runs whenever there’s a [[Git Tags|git tag]] that contains the word release in it. This can be useful for tagging

Manual (Custom) Pipelines

This is used to define pipelines that are only run manually or scheduled through the BitBucket UI. These types of pipelines are useful for deployments to production environments where you need signoff before deployments.****

pipelines:
    custom:
        run-migrations:
            - step:
              name: Run Database Migrations
              script:
                  - echo "Applying database migrations"

        deploy-to-staging:
            - step:
              name: Deploy to Staging
              script:
                  - echo "Deploying to staging environment"

        release-build:
            - step:
              name: Create Release Build
              script:
                  - echo "Building release version"
Scheduled Pipeline Runs

Custom pipelines can be used to create scheduled pipeline runs. In the examples below, I’ll create scheduled pipelines to deploy to staging and main (production) branches.
![[Bitbucket CICD Pipeline Documentation#Create Scheduled Pipeline Runs]]

Create Scheduled Pipeline Runs

  1. Navigate to your repository and click “Pipelines” in the left navigation menu.
  2. Select Schedules and “New Schedule” to create a new scheduled Pipeline”
    ![[scheduled_pipeline.png]]
  3. Set the branch, pipeline to run and frequency
    ![[Pasted image 20241205160407.png]]
    To create a scheduled pipeline for both staging and production, do the following:
    For staging pipelines:
  • select the staging branch under “Branch”,
  • select “custom: staging” under Pipeline and
  • under “Schedule” select your preferred Schedule. The custom pipelines must be defined in the bitbucket-pipelines.yml file in your repository.

For production pipelines:

  • Select the main branch under “Branch
  • Select “custom: production” under “Pipeline”
  • Set the desired schedule under “Schedule

Tips

  1. To push code and skip CI triggering runs, add [skip ci] or [ci skip] anywhere in your commit message.
  2. If Pull request and branch specific pipeline definitions overlap, you’ll get two pipelines running at the same time. An example of this is when you have a lint pipeline defined in a default pipeline trigger and a similar lint step defined in a pull-requests trigger. Whenever a push is made to the branch with an open PR, the same pipeline would run twice. To avoid this, consider replacing the pipeline defined in branches with pull-request so you only have the pipeline running when PRs are created and not on every push to the branch.

Branch Protection Rules

Branch protection rules or “branch restrictions” as they are called in BitBucket are a set of rules and permissions that govern what actions can be performed on specific project branches. These rules control who can push or merge code to a branch and what conditions have to be met before a push can be made.

Having branch protection rules in place is an important aspect of CI that does the following for you:

  1. Ensures quality: Requiring merges to occur only when code has been fully tested and certain conditions such as passing tests, builds, and lint checks are met helps to enforce high code quality.
  2. Prevent accidental changes: Protection rules protect branches from accidental deletion and restrict who can push directly to critical branches like main or production, ensuring that only authorised changes from the CICD pipeline are introduced.
  3. Encourage Code Reviews: Using branch protection rules, you can require Pull Requests for changes, enabling code reviews to maintain code standards and reduce errors.

Add Branch Restrictions

To add branch restrictions in BitBucket, navigate to the Projects menu.

BitBucket Projects selection screen

Select a project to create rules for and click “Project settings” on the left panel and then select “Branch restrictions” under the “Workflow” section:

BitBucket UI left navigation bar with branch restrictions menu highlighted.

Click the “Add a branch restriction” button to add a new restriction rule.:

Add branch restriction button

A dialog window appears. This window allows you to set branch permissions and merge settings.

Branch permissions

In the Branch permissions tab, you specify settings such as the branch or branch type you’re creating the rule for, the users with write access to the branch and whether or not users can create Pull Requests for the branch.

Add branch restriction dialog

Merge Settings

The Merge settings tab has a list of conditions you can check before allowing a merge to a branch to occur

BitBucket merge settings screen

Here, you can check for conditions such as a minimum number of approvals, pull request status, ensure only changes with passing builds get merged or tie merges to code reviews.

Benefits of using branch protection rules

Using rules such as merge checks has the following benefits:

  • ensures users submit changes with passing builds
  • tie merges to code review
  • get your team to work collaboratively through Pull Requests
  • Keep your workflow consistent so your developers always know what they have to do to merge.
  • create tasks in pull requests to mark changes that need to be made and ensure all tasks in the pull request are complete before a merge.
  • minimise the risk of errors and bugs reaching production

Best Practices for Pipeline triggers and Protection rules

  • Use pipeline triggers to automate repetitive tasks but avoid unnecessary pipeline runs to conserve build minutes.
  • Protect critical branches with strict rules. Consider disallowing direct commits or enforcing build success before code is merged into the branch.
  • Collaborate with your team to create branch rules that match your workflow. For example, instead of having pipeline runs whenever a push is made to a branch, you can configure them to run only when certain files in a branch are changed, e.g run pipelines only for changes to src/ or tests/.
  • Use event-specific triggers: trigger pipelines only for specific events that require action. For example, run test and lint pipelines on pull request creation to minimise resource usage.
  • implement manual triggers for running specific stages such as deployments to production, this helps avoid unintended deployments.

Branch protection rules best practices

  • Require pull requests for important branches like main.
  • Limit write access to key branches.
  • Restrict or block force pushes to critical branches.

Conclusion

In this article, you’ve seen how to set up BitBucket pipeline triggers and branch protection rules. Pipeline triggers or start conditions allow you to ensure pipelines run only when needed. Branch protection rules safeguard critical branches and enforce high-quality code standards.

In the next article, I’ll cover setting up deployment servers with BitBucket pipelines.

Further Reading

  1. BitBucket Branch Restriction Documentation
  2. Using Branch Permissions