How To Create Bitbucket Custom Build & Deploy Pipelines For MuleSoft Applications

Author: Saddam Shaikh

What is Bitbucket?

Bitbucket is a source code repository platform that enables us to manage our repositories and empowers organizations to build, test, and deploy applications using Bitbucket Pipelines.

We can create either automated pipelines or custom pipelines using Bitbucket Pipelines.

Automated pipelines: They automatically trigger when a commit is made on a branch for which the pipeline is set up or enabled.

Custom pipelines: They allow us to customize CI/CD pipelines, enabling us to manually run them as per our requirements with custom inputs.

Let’s begin with the Bitbucket Pipeline implementation for Mule applications.

Bitbucket code:
  1. Create repository variables that will be used in the Bitbucket Pipeline.

From the repository, navigate to the Repository settings → Repository variables.

Repository variable section snapshot
  1. Follow the steps below to create a two-step custom pipeline (build & deploy) in Bitbucket.
  • Build Pipeline
  1. Create bitbucket-pipelines.yml file.
  2. In the bitbucket-pipelines.yml, create a custom build pipeline named ‘MSFT-build-pipeline’ using a custom keyword.
  3. In the build pipeline, we have the following three steps:
  • Step 1 (Invalidate Cache): invalidate the cache if there are any changes in the pom.xml file. To invalidate the existing cache, we are using the built-in bitbucket pipe “atlassian/bitbucket-clear-cache”.
  • Step 2 (Test): Run MUnits for the application and cache the Maven dependencies.
  • Step 3 (Package): We are packaging the application and uploading the generated build artifact to the Bitbucket Downloads artifactory using the Bitbucket built-in pipe ‘atlassian/bitbucket-upload-file’.

Build pipeline code snippet:

image: maven:3.6.3-jdk-8
    - step: &invalidate-cache
        name: Invalidate Cache
          - echo "Delete cache if changes in the pom.xml"
          - pipe: atlassian/bitbucket-clear-cache:3.1.1
              CACHES: ["maven"]
              - bitbucket-pipeline-poc/pom.xml
  custom: # Pipelines that are triggered manually
      - step: *invalidate-cache      
      - step:
          name: Test
          #trigger: 'manual'
            - maven 
- echo "Runnning MUnits for $application_name on branch $BITBUCKET_BRANCH"
            - mvn -f $application_name/pom.xml test -s settings.xml #-DskipTests    
      - step:
          name: Package
            - echo "Build number is $BITBUCKET_BUILD_NUMBER"
            - mvn -f $application_name/pom.xml clean package -DskipTests -s settings.xml -Djenkins.version=$BITBUCKET_BUILD_NUMBER 
            - export artifactName=$(ls $application_name/target/*.jar | head -1)
            - echo "Artifact $artifactName created"
            - echo "Uploading artifact to Bitbucket Downloads"
            - pipe: atlassian/bitbucket-upload-file:0.1.2
                FILENAME: $artifactName
            - echo "Artifact $artifactName is succeesfully uploaded to Bitbucket Downloads"
  • Deploy Pipeline
  1. In the bitbucket-pipelines.yml, create a custom deploy pipeline named ‘MSFT-deploy-pipeline’ using a custom keyword.
  2. The deploy pipeline takes the CloudHub environment name to which the artifact needs to be deployed/redeployed, and the artifact/jar build number to download it from Bitbucket Downloads.
  3. In the deploy pipeline, we have the following two steps:
  • Step 1 (Get Artifact): Retrieve the Bitbucket Downloads artifact name using the build number by making a Bitbucket REST API call. Once we have the artifact filename, download the artifact from Bitbucket Downloads using the REST API, and share this artifact and artifact name with the next step, ‘Deploy Application,’ by using the Bitbucket artifacts keyword.
  • Step 2 (Deploy Application): We set up some environment variables based on the CloudHub environment selected by executing the external shell script. Once the environment variables are set, we deploy the artifact downloaded in the previous step to CloudHub using the Mule Maven command. In the after-script section, we send success/error notifications via Email & Slack channels by leveraging the built-in pipe provided by Bitbucket.

Deploy pipeline code snippet:

      - variables:    
        - name: cloudhub_env_c
          default: Dev
            - "Dev"
            - "Test"
            - "Uat"
            - "Prod"      
        - name: build_number_c
      - step:
          name: Get Artifact
 - echo "Build number is $build_number_c"
            - |
                export filename=$(curl -v --request GET "https://$BITBUCKET_USERNAME:$$BITBUCKET_REPO_OWNER/$BITBUCKET_REPO_SLUG/downloads" | grep -o "[^\"/]*-B$build_number_c-[^\"]*.jar" | head -1)
            - echo $filename 
            - mkdir -p target1/
            - |
                curl --location -v --request GET "https://$BITBUCKET_USERNAME:$$BITBUCKET_REPO_OWNER/$BITBUCKET_REPO_SLUG/downloads/$filename" -o target1/$filename
            - ls target1/*.jar | head -1 > ./file.txt
            - target1/*.jar             
            - file.txt
      - step:
          name: Deploy Application
          trigger : 'manual'
            - echo "Deploy Application"
            - . # to execute external bash script     
            - echo "config file is $config_file and application name is $application_name_c"
            - export file=$(cat file.txt)      
            - mvn -f $application_name/pom.xml mule:deploy -s settings.xml -DskipTests -Dmule.artifact=$file -Dconnectedapp.clientid=$connected_app_client_id -Dconnectedapp.clientsecret=$connected_app_client_secret -Danypoint.platform.environment=$cloudhub_env_c -Dmule.env=$config_file -Dapplication.muleVersion=$mule_version$application_name_c -
Dapplication.region=$region -Dvault.key=$key -Dapplication.workers=$workers -Dapplication.workerType=$worker_type$anypoint_platform_client_id -Danypoint.platform.client.secret=$anypoint_platform_client_secret
            - ALERT_TYPE="SUCCESS"
            - export file=$(cat file.txt | cut -d / -f 2)
            - app_env_suffix=$( echo "$cloudhub_env_c" | tr -s  '[:upper:]'  '[:lower:]' )
            - content="$(echo \"$(cat bitbucket-email-template.html)\")"
            - eval echo "$content" > email-notification.html
            - if ! [[ "$emailEnabledEnvironment" == *"$cloudhub_env_c"*  && $email == "true" && $BITBUCKET_EXIT_CODE == "0" ]]; then 
               ALERT_TYPE="ERROR" ;fi
            - pipe: atlassian/email-notify:0.7.0
                USERNAME: ''
                PASSWORD: $GPASSWORD
                FROM: ''
                TO: ',mulesoft-poc-receipient@***'
                HOST: ''
                DEBUG: 'true'
                SUBJECT: '${ALERT_TYPE}:${application_name} Bitbucket Pipeline Notification for branch ${BITBUCKET_BRANCH}'
                BODY_HTML: 'email-notification.html'   

Shell script code snippet:

if [ $cloudhub_env_c == "Dev" ]; then

elif [ $cloudhub_env_c == "Test" ]; then

elif [ $cloudhub_env_c == "Uat" ]; then

elif [ $cloudhub_env_c == "Production"  ]; then

    echo "error"
    exit 0;

HTML email notification code snippet:


        table {
            font-family: arial, sans-serif;
            border-collapse: collapse;
            width: 100%;

        td {
            border: 1px solid #000000;
            text-align: left;
            padding: 8px;


    <h3>Dear Team,<br><br>Build number ${build_number_c} has been successfully deployed to ${cloudhub_env_c} environment</h3>
        Please find below additional details<br></h3>
                <td>CloudHub Application Name</td>
                <td>Bitbucket Repository Name</td>
                <td>Branch Name</td>
                <td>CloudHub Environment</td>
                <td>Bitbucket Artifact File Name</td>
                <td>Build Pipeline Build Number</td>
                <td>Deploy Pipeline Build Number</td>


MuleSoft code:
  1. Create a simple Mule Application.
  2. Add CloudHubDeployment configuration in Mule Maven Plugin.
Mule Maven Plugin Snippet
  1. Add the settings.xml file to the repository’s root directory.
settings.xml file snapshot

Test the bitbucket pipeline:

  1. Go to the Pipelines section, and click on ‘Run pipeline.’ A pop-up window will appear, allowing you to select the branch on which you want to run the pipeline and the pipeline (build/deploy) to run. First, we are going to run a build pipeline on the feature branch ‘feature/feature-314’ to create the artifact and upload it to the Bitbucket Downloads.
Build pipeline UI snapshot
  1. The build pipeline has been successfully completed, and the artifact has been uploaded to the Bitbucket Downloads. The build pipeline build number is 131.
Build Pipeline run status snapshot
Bitbucket Downloads snapshot
  1. Run the deploy pipeline to deploy the generated artifact/jar to the CloudHub target environment. To run the build pipeline, we need to provide the CloudHub environment name on which we want to deploy our application and the build pipeline build number, so that we can download that artifact from Downloads.
Build pipeline UI snapshot
  1. The deploy pipeline has been successfully completed, and the application is deployed to the CloudHub Dev environment. Additionally, notifications are triggered to the email and Slack channel.
Deploy pipeline run status snapshot
Email notification snapshot
Slack notification snapshot

Custom pipeline advantages:

  1. It saves pipeline build minutes in Bitbucket, as we won’t be running the pipeline on every commit.
  2. YYou can run a custom pipeline on any branch (e.g., working, hotfix, feature, etc.).
  3. It allows us to build the application on any branch and deploy that build artifact to multiple target environments.

Custom pipeline disadvantages:

  1. Manual intervention is required to run the pipeline.

Current pipeline limitations:

  1. To obtain the artifact filename using the build number in the deploy pipeline step, we are using the REST API. However, this API supports pagination, and currently, I have not implemented pagination logic. As a result, if our build number is not present on the first page, the pipeline will fail. To address this issue, we have two solutions: either implement pagination logic or, instead of providing the build number in the deploy pipeline, provide the complete artifact/jar name and remove the logic to get the artifact filename based on the build number. 

Hope you enjoy reading this blog.



We use cookies on this site to enhance your user experience. For a complete overview of how we use cookies, please see our privacy policy.