Skip to content

Chapter 3

MuleSoft CI/CD – Part Three – Continuous Deployment

This is part three of our series on MuleSoft CI/CD.

In this chapter, we will discuss the following topics. 

  • A recap on part two and GitHub Actions/Workflows we have built.
  • What Continuous Delivery/Deployment is? 
  • MuleSoft Continuous Delivery/Deployment(CD) implementation in GitHub Actions.

Recap on part two and GitHub Actions/Workflows we have built for this chapter.

  • In part two, we discussed the Continuous Integration(CI) concept and broke down the release CI/CD activities of the Custom branching strategy. 
  • We have also built the two GitHubActions part of the release plan:
    • Workflow is used to compile/test/run unit tests and deploy the project in the dev environment when any change happens to feature/* branches. 
    • Workflow to compile/test and deploy the Project in the SIT environment when any change happens to the develop branch. 
  • We must build the following GitHubActions part of this Continuous Delivery/Deployment (CD) blog. First, we will discuss “What is Continuous Delivery/Deployment?”
    • Workflow to clean/compile/test the Project and release the Project with the release activities(versioning and tagging). Make the tag available for the next UAT/Prod deployment when any change happens to the QA branch. 
    • A manual workflow to take the release version/tag, deploy it to a selected higher environment of choice(UAT/Prod), and merge the change from the QA branch to the master branch. 

What is Continuous Delivery/Deployment?

  • The “CD” in CI/CD refers to Continuous Delivery/Deployment, related concepts that sometimes get used interchangeably. 
  • Continuous Delivery usually means a developer’s changes to an application are automatically bug-tested, and the source code is bundled to the release candidate and uploaded to a repository (like GitHub or a container registry), where they can be deployed to further environments. 
  • Put simply, Continuous Delivery is a software development practice where code changes are automatically prepared for a production release.
  • When properly implemented, developers will always have a deployment-ready build artefact that has passed a standardised test process.
  • Continuous Deployment involves deploying every change to the configured environments from the respective branch where the change happened. As there is no human intervention, the pipeline execution is not held up for approval. This is the best practice for Dev/SIT environments but not for UAT and Production. 
  • Continuous Delivery, on the other hand, prepares the release artefacts, allowing IT teams to deploy changes quickly with the push of a button (Manual Workflows).

MuleSoft Continuous Delivery/Deployment (CD) implementation in GitHub Actions:

  • We will start implementing the GitHub workflow/Action “to clean/compile/test the Project and release the Project with the release activities(versioning and tagging) and make the tag available for the next UAT/Prod deployment when any change happens to the QA branch”.
    • We will set up the GitHub Action by following the below steps:
      • Set up your Repository and GitHub Workflow/Action.
      • Make some changes to the QA branch to verify the release. 
    • We have already been using  mule4-hello-world-impl repo, so we will continue to use the same here as well.
    • In the same .github/workflows folder, we will create qa-release.yaml and add the following content. 

name: Qa Release

run-name: Qa Release and Tagging

on:

  push:

    branches: [ qa ] 

jobs:

  build-release-qa:

    runs-on: ubuntu-latest

    steps:

      – name: Checkout this repo

        uses: actions/checkout@v4

      – name: Cache dependencies

        uses: actions/cache@v3.3.2

        with:

          path: ~/.m2/repository

          key: ${{ runner.os }}-maven

          restore-keys: |

            ${{ runner.os }}-maven

      – name: Set up JDK 1.8

        uses: actions/setup-java@v3

        with:

          distribution: ‘zulu’

          java-version: 8

      – name: Clean and Compile with Maven

        run: mvn clean compile 

      – name: Remove SNAPSHOT and prepare release

        run: mvn versions:set -DremoveSnapshot

      – name: Compile and Test the project 

        run: |

          mvn clean compile -U

          mvn test -Denv=sit 

      – name: Extract the POM version

        id: retrieve-pom-version

        run: |

          echo “POM_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)” >> $GITHUB_OUTPUT  

      – name: Tag the release and commit/push changes to remote repository

        env: 

          POM_VERSION: ${{ steps.retrieve-pom-version.outputs.POM_VERSION }}

        run: |

          echo “$POM_VERSION”

          git add pom.xml 

          git config –global user.email “naginenipavan@outlook.com”

          git config –global user.name “Pavan Nagineni”

          git commit -m “Release $POM_VERSION”

          git tag “$POM_VERSION”

          echo “Released to $POM_VERSION version.”

          git push origin qa “$POM_VERSION”

      – name: Checkout the Develop branch and Merge the Qa Release change

        env: 

          POM_VERSION: ${{ steps.retrieve-pom-version.outputs.POM_VERSION }}

        run: |

          git remote update –prune

          git checkout origin/develop –force

          git reset –hard origin/qa

      – name: Prepare the next development version in develop branch 

        run: |

          mvn build-helper:parse-version versions:set -DnewVersion=’${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.nextIncrementalVersion}-SNAPSHOT’

          mvn versions:commit

          git add pom.xml 

          git config –global user.email ‘naginenipavan@outlook.com’

          git config –global user.name “Pavan Nagineni” 

          echo “incremented to next $(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) version.”

          git commit -m “incremented to next $(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) version”

          git push -f -u origin HEAD:develop 

  • As we have already discussed the “name” and “on” sections in the Part-II blog, we will discuss the steps of the build-release-qa job. 
  • The first step is to check out the repository.

      – name: Checkout this repo

        uses: actions/checkout@v4

  • The second step caches the maven dependencies to make the subsequent runs to use the cached dependencies. 

      – name: Cache dependencies

        uses: actions/cache@v3.3.2

        with:

          path: ~/.m2/repository

          key: ${{ runner.os }}-maven

  • The third step sets the JDK version in the container where Github runs this GitHub Action. 

      – name: Set up JDK 1.8

        uses: actions/setup-java@v3

        with:

          distribution: ‘zulu’

          java-version: 8

  • The fourth step runs clean and compiles the Project using the maven lifecycle and phase. 

      – name: Clean with Maven

        run: mvn clean compile 

  • The fifth step is to remove the artefact SNAPSHOT version and prepare the project for release. 

      – name: Remove SNAPSHOT and prepare release

        run: mvn versions:set -DremoveSnapshot

  • The sixth step runs the project’s unit tests again to ensure the above change did not affect the Project.

  – name: Compile and Test the project 

     run: |

      mvn clean compile -U

      mvn test -Denv=sit 

  • The seventh step is to extract the POM version, which is the release version that will be useful in the next step to create the tag. The next step will use this step output. 

      – name: Extract the POM version

        id: retrieve-pom-version

        run: |

          echo “POM_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)” >> $GITHUB_OUTPUT  

  • The eighth step is the main step, where we do the actual release by committing the above artefact SNAPSHOT version removal change and creating the git tag. This step uses the last step output to save the POM version in a variable. 

      – name: Tag the release and commit/push changes to remote repository

        env: 

          POM_VERSION: ${{ steps.retrieve-pom-version.outputs.POM_VERSION }}

        run: |

          echo “$POM_VERSION”

          git add pom.xml 

          git config –global user.email “naginenipavan@outlook.com”

          git config –global user.name “Pavan Nagineni”

          git commit -m “Release $POM_VERSION”

          git tag “$POM_VERSION”

          echo “Released to $POM_VERSION version.”

          git push origin qa “$POM_VERSION”

  •  At this point, the QA branch has the release version and the release tag as well. Now it’s time to check out the develop branch and merge the same release change. This is the tenth step of the job. 

      – name: Checkout the Develop branch and Merge the Qa Release change

        env: 

          POM_VERSION: ${{ steps.retrieve-pom-version.outputs.POM_VERSION }}

        run: |

          git remote update –prune

          git checkout origin/develop –force

          git reset –hard origin/qa

  • The last and final step is to increment the develop branch POM version to the next SNAPSHOT and make this branch readily available for the next developments. 

      – name: Prepare the next development version in develop branch 

        run: |

          mvn build-helper:parse-version versions:set -DnewVersion=’${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.nextIncrementalVersion}-SNAPSHOT’

          mvn versions:commit

          git add pom.xml 

          git config –global user.email ‘naginenipavan@outlook.com’

          git config –global user.name “Pavan Nagineni” 

          echo “incremented to next $(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) version.”

          git commit -m “incremented to next $(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) version”

          git push -f -u origin HEAD:develop 

  • When we merge a change from the develop branch to the QA branch, the runs and releases the Project with the release version. Below is the screenshot of the 1.0.23 release.
  • Below are the GitHub Workflow/Action commits of the release on both the QA and develop branches.
  • Next, we will implement the manualGitHub workflow/Action “to take the release version/tag and deploy it to a selected higher environment of choice (UAT/Prod) and merge the change from the QA branch to the master branch”.
    • We will set up the GitHub Action by following the below steps:
      • Set up your Repository and GitHub Workflow/Action.
      • Make some changes to the QA branch to verify the release. 
    • We have already been using  mule4-hello-world-impl repo, so we will continue to use the same here as well.
    • In the same .github/workflows folder, we will create qa-release.yaml and add the following content.

name: Release

run-name: Release Deployment

on:

  workflow_dispatch: 

    inputs: 

      tag: 

        description: Tag Version in form of MAJOR.MINOR.VERSION like 1.0.0

        required: true

      env: 

        description: environment to deploy uat or prod 

        required: true

jobs: 

  release-deploy:

    runs-on: ubuntu-latest

    if:  ${{ inputs.tag }} 

    environment: ${{ inputs.env }}

    steps:

      – name: Checkout this repo

        uses: actions/checkout@v4

      – name: Cache dependencies

        uses: actions/cache@v3.3.2

        with:

          path: ~/.m2/repository

          key: ${{ runner.os }}-maven

          restore-keys: |

            ${{ runner.os }}-maven

      – name: Set up JDK 1.8

        uses: actions/setup-java@v3

        with:

          distribution: ‘zulu’

          java-version: 8

      – name: Clean and Compile with Maven

        env: 

          ENV: ${{ inputs.env }}

          TAG_VERSION: ${{ inputs.tag }}

        run: |

          echo “Deploying the $TAG_VERSION to environment: $ENV”

          git remote update –prune

          git checkout tags/”$TAG_VERSION”

      – name: Clean with Maven

        run: mvn clean compile 

      – name: Run Munit tests 

        run: mvn test -Denv=sit

      – name: Deploy to Release environment

        env:

          ENV: ${{ inputs.env }}

          USERNAME: ${{ secrets.anypoint_username }}

          PASSWORD: ${{ secrets.anypoint_password }}

          ANYPOINT_USERNAME: ${{ secrets.anypoint_platform_username }}

          ANYPOINT_PASSWORD: ${{ secrets.anypoint_platform_password }}

        run: |

          artifactName=$(ls *.jar | head -1)

          mvn deploy -s .maven/settings.xml -f pom.xml -DmuleDeploy \

           -Denv=$ENV \

           -Dmule.artifact=$artifactName \

           -Danypoint.username=”$USERNAME” \

           -Danypoint.password=”$PASSWORD” \

           -Danypoint_platform_username=”$ANYPOINT_USERNAME” \

           -Danypoint_platform_password=”$ANYPOINT_PASSWORD” 

      – name: Checkout the master branch and Merge the Tag

    if:  ${{ inputs.env == ‘prod’ }}

        env: 

          TAG_VERSION: ${{ inputs.tag }}

        run: |

          git remote update –prune

          git checkout origin/master –force

          git reset –hard tags/”$TAG_VERSION”          

  • The name field holds the name of the GitHub Action, which will appear in the UI under the Actions tab. 
  • The on field tells when a GitHub Action runs. For this Action, we have set it up with a manual trigger by providing the deployable tag(released tag) and the environment to deploy the project(uat/prod). These two inputs are mandatory for this workflow. 
  • Next, we will jump in to discuss the steps of the release-deploy job. The first 3 steps are the same as the previous workflow, So we are leaving it out to discuss them explicitly here, But they are part of this workflow as well. 
  • The fourth step is to clean and compile the Project with the help of the tag version provided in the inputs. 

      – name: Clean and Compile with Maven

        env: 

          ENV: ${{ inputs.env }}

          TAG_VERSION: ${{ inputs.tag }}

        run: |

          echo “Deploying the $TAG_VERSION to environment: $ENV”

          git remote update –prune

          git checkout tags/”$TAG_VERSION”

  • The fifth step runs the unit tests of the Project. 

        – name: Run Munit tests 

        run: mvn test -Denv=sit

  • After unit tests, it’s time to deploy the project by building it, and this sixth step does the same. 

      – name: Deploy to Release environment

        env:

          ENV: ${{ inputs.env }}

          USERNAME: ${{ secrets.anypoint_username }}

          PASSWORD: ${{ secrets.anypoint_password }}

          ANYPOINT_USERNAME: ${{ secrets.anypoint_platform_username }}

          ANYPOINT_PASSWORD: ${{ secrets.anypoint_platform_password }}

        run: |

          artifactName=$(ls *.jar | head -1)

          mvn deploy -s .maven/settings.xml -f pom.xml -DmuleDeploy \

           -Denv=$ENV \

           -Dmule.artifact=$artifactName \

           -Danypoint.username=”$USERNAME” \

           -Danypoint.password=”$PASSWORD” \

           -Danypoint_platform_username=”$ANYPOINT_USERNAME” \

           -Danypoint_platform_password=”$ANYPOINT_PASSWORD” 

  • Note:  We need to set the environments (uat/prod) and environment variables as we have set for the first two GitHub workflows/Actions in the Part-II blog. 
  • After successful Production deployment, we need to ensure we are merging the same release to the master branch as well. So, we will be making the master branch HEAD to point to the released tag. This is the last step of the CI/CD pipeline.
  • This last and final step runs only if the given environment variable “env” matches to “prod” only. 

      – name: Checkout the master branch and Merge the Tag (only after prod deployment)

        if:  ${{ inputs.env == ‘prod’ }}

        env: 

          TAG_VERSION: ${{ inputs.tag }}

        run: |

          git remote update –prune

          git checkout origin/master –force

          git reset –hard tags/”$TAG_VERSION”  

  • When we run a manual deployment to UAT and Production, both of the runs look like the below: 
  • Below are the commits of the GitHub Workflow/Action part of the Production deployment on the master branch.
  • The API works on UAT and Production:

Conclusion:

In this comprehensive three-part series on MuleSoft CI/CD, we’ve delved into the intricacies of Continuous Integration (CI), Continuous Delivery/Deployment (CD), and Git Branching Strategies, providing a detailed guide on their implementation using GitHub Actions. 

The series begins with exploring Git Branching Strategy, laying the foundation for an effective CI/CD pipeline. It then progresses to Continuous Integration, discussing the creation of workflows for compiling, testing, and deploying projects in development and SIT environments.

The third part, which is the focus of this blog, centres on Continuous Delivery/Deployment. It clarifies the distinction between the two: Continuous Delivery automates the process up to the production release, while Continuous Deployment goes a step further by deploying every change to the respective environments without human intervention. 

This blog outlines the steps to implement CD in GitHub Actions, including setting up workflows for releasing and tagging in the QA branch and deploying to higher environments like UAT or Production.

The approach we’ve used for our CI/CD pipeline can also be applied to other technologies. Most of the steps are consistent, with the only variations being the specific maven plugins and commands we employ to build, test, and deploy for each technology.

If you would like to discuss CI/CD further and learn how to implement GitHub Actions, then get in touch with one of our experts here.