MuleSoft – Continuous Integration and Delivery

Making technical changes to app or website code at any stage of development can be a tricky business! That’s why effective Continuous Integration and Continuous Delivery (CI/CD) is essential for successfully building and maintaining any application, website, or piece of software.

Author

Pavan Nagineni
Senior MuleSoft Consultant


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.

Git Branching Strategy

Continuous Integration and Continuous Delivery/Deployment is commonly called CI/CD – a standard software build and delivery practice.

Most MuleSoft CI/CD blogs only talk about how to compile/ build/ test/ deploy your MuleSoft applications to any of the runtimes, and that’s all. It’s hard to find a blog on the best way to tag/ release applications and how to take these released versions and deploy them to User Accepted Testing (UAT)/ Production environments as we would to follow organisation standards. 

So, I have developed this series of three chapters discussing the following concepts:

What is CI/CD & Git Branching Strategy? 

  • What is CI/CD
  • Branching strategies and best practices.

Continuous Integration

  • The CI tasks of CI/CD, compile/ test/ build/ development environment deployment. 
  • An example of CI in action with the help of an API in GitHub Actions. 

Continuous Delivery/Deployment

  • Achieving CD, the SIT/ environment deployments. 
  • How to release an application with the correct versioning and tagging by using maven on PR merges to a certain integration branch. 
  • See a plan to deploy the released tags to UAT/Production deployments. 

This is part one of the series in which we are going to discuss the concepts below: 

  • What is CI/CD? 
  • Git Branching Strategy and Best Practices 

What is CI/CD? 

  • The “CI” in CI/CD refers to Continuous Integration, an automation process for developers to continuously build the application for any changes. 
  • Successful CI means new code changes to an app are regularly tested, built, and merged into a shared repository.
  • 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. 
  • The most common tasks of CI/CD that organisations follow would look like below: 

Git Branching Strategy and Best Practices 

Distributed versioning control systems like Git/Atlassian Bitbucket/Azure Repos give you the flexibility of version controlling your source code and consistently sharing the code with your team. 

Branching strategies are patterns or approaches that technology teams use to organise & manage their source code through different branches in a version control system. 

Below are the different branching strategies that we can use: 

  1. Trunk-based branching strategy
  2. GitHub Flow/Feature branching strategy
  3. Personal branching strategy
  4. GitFlow branching strategy
  5. GitLab Flow branching strategy
  6. Custom Release branching strategy (that I have used in the past)

Trunk-based branching strategy: 

  • A trunk-based branching strategy encourages developers to make minor updates to the master branch frequently.
  • Developers are going to work with short-lived branches.
  • Advantages:
    • This reduces the merge conflicts and challenges that developers face in other branching strategies.
  • Disadvantages:
    • The main problem with this is that there are high chances of having the code in the master branch, which is not yet promoted to Production.
    • There is a high chance of having bugs in the main branch since the feature code is directly getting merged into the master branch. We need strong code reviews and test strategies to address this.

GitHub Flow/Feature branching strategy: 

  • Every feature gets its branch from the master branch.
  • Once we finish our changes, we will merge the changes to the master branch using pull requests.
  • Teams of any size can adopt this strategy after they’ve familiarised themselves with Git and used this centralised workflow. 
  • Advantages:
    • This is a relatively simple branching workflow to follow. 
    • Hardly any branching management is needed than clearing up feature branches once they are released. 
  • Disadvantages:
    • This requires some solid automation testing framework to ensure the features/bugs we release to the master branch are well tested. 
    • This strategy is unable to support multiple versions of the code in Production at the same time. 

Personal branching strategy: 

  • This will be similar to feature branching, except it does not have a separate branch for per feature, but per developer.
  • This can work if people are working on different bugs/features.
  • Advantages:
    • This strategy has the same advantage as Feature branching in having a separate branch to work with and when ready to merge the changes to the master branch.
    • Branch management is easier since only a few branches are involved.
  • Disadvantages:
    • It is hard for two developers to work on the same feature.
    • Also, If we are working on feature A and you get another one B as well, there is no easy way to merge back feature A without polluting the master branch.
    • This strategy is unable to support multiple versions of the code in Production at the same time. 

GitFlow branching strategy: 

  • Gitflow is a branching model for Git, created by Vincent Driessen. It has attracted much attention because it is very well suited to collaboration and scaling the development team.
  • Branching workflow: 
    • New developments (new features, non-emergency bug fixes) are built-in feature branches.
    • Feature branches are branched from the develop branch, and once the changes are ready, feature branches will be merged to develop branches with pull requests.
    • When it is time to make a release, a release branch is created off the develop branch.
    • The code in the release branch is deployed to higher test environments and tested, and any problems are fixed directly in the release branch. This deploy -> test -> fix -> redeploy -> retest cycle continues until you’re happy that the release is good enough to release to customers.
    • When the release is finished, the release branch is merged into the master and into develop to ensure that any changes made in the release branch aren’t accidentally lost by new development.
    • Hotfix branches are used to create emergency fixes.
    • They are branched directly from a tagged release in the master branch and when finished, are merged back into both master and develop to make sure that the hotfix isn’t accidentally lost when the next regular release occurs.
  • Advantages:
    • Parallel Development
    • Collaboration
    • Release Staging Area
    • Support For Emergency Fixes
  • Disadvantages:
    • There are too many branches to track, and complicated for teams to follow. It can be easy to miss small changes, resulting in git conflicts.
    • There is a need to educate the team and any new members on how the branching strategy works to avoid conflicts with the ways of working.

(Image from: GitFlow branching Explanation)

GitLab Flow branching strategy: 

  • The GitLab Flow branching strategy is similar to the Github Flow branching strategy. The main difference is that GitLab flow will have additional environment branches like PROD, release, etc, depending on the organisation’s standards. 
  • Let’s take the below branching workflow to explain how this flow works:
    • feature/*** – feature branch 
    • master – master branch 
    • PROD – production branch 
    • Hotfix- hotfix branch 
  • Branching workflow: 
    • New developments (new features, non-emergency bug fixes) are built-in feature branches.
    • Feature branches are branched from the master branch, and once the changes are ready, feature branches will be merged into master branches with pull requests.
    • When it is time to make a release, the master branch source code will be merged into the PROD branch. 
    • PROD branch serves here as the source of truth for Production deployment-ready code. 
    • Hotfix branches are used to create emergency fixes.
    • They are branched directly from a tagged release in the master branch and when finished, are merged back into both master and PROD to make sure that the hotfix isn’t accidentally lost when the next regular release occurs.
  • Advantages:
    • Comparing this to the GitFlow strategy, this is more simple. 
    • This also has the same benefits as the GitFlow strategy regarding Parallel Development, Collaboration, and support for Emergency fixes.  
  • Disadvantages:
    • If organisations customise it by enabling more environmental branches like QA/SIT and QA/UAT, then this kind of modification results in high chances of merge conflicts between the branch merges. 

Custom Release branching strategy (that I have used in the past): 

  • In this Custom-release branching strategy, we had the following branches:
    • master – production code
    • qa – release branch
    • develop – integration branch
    • feature/**** – feature branches
  • Branching workflow: 
    • The developers first check the code from the develop branch to work on any features/bugs
    • Once the developer completes the changes, They will push the code to his feature branch – which will compile/test/build the source code and deploy the change to the Dev environment.
    • If the tests are good in the Dev environment, the Developer now raises a PR(pull request) from the feature/**** branch to the develop branch and merges the changes in the develop branch. This will also compile/test/build the source code and deploy the change to the Sit/Integration environment.
    • The testers do the integration end-to-end tests –
      • If they find any issues:
        • The developer will make the changes in the same feature branch.
        • Once the change is deployed to the Dev environment (on push to his feature branch), they must raise a PR to the develop branch.
      • Note: here, it is the developer’s responsibility to check and pull any changes in the develop branch made by anyone else within this time:
        • Once the additional changes have been merged to the develop branch, the difference will automatically deploy to the Sit environment.
        • The testing team will redo the testing on the same feature. If any bugs are found, the same process will repeat for any required changes. Otherwise, the feature will get sign-off to higher environments.
      • If none, the feature will get sign-off to higher environments.
    • To promote the change to higher environments (Uat/PreProd) –
      • The Developer raises a PR from the develop branch to the QA branch.
      • The PR will get merged once the team members review it.
      • As soon as this merges into the QA branchthe release must happen for the API/application, and the git tag will be created.
    • At the time of the deployment to Production, the git version will be merged to the master branch, which will be production-based code.
  • Advantages:
    • This also has the same benefits as the GitFlow strategy in terms of Parallel Development, Collaboration, and support for Emergency fixes.  
    • Since this strategy does not have the release and environmental branches, it is easy for team members to track the changes.  Also, it is simple for teams to educate any new team members. 
  • Disadvantages:
    • If organisations customise it by enabling more environmental branches like QA/SIT and QA/UAT, then this kind of modification results in high chances of merge conflicts between the branch merges. 
    • This also has four branches to track the changes. 
  • Note: We can even customise this Custom branching strategy to remove the QA branch and do the tag/release on the develop branch. However, having an intermediate branch after the develop stage (Sit deployment) gives more robustness to the releases that we are doing on this branch. 

Conclusion: 

CI/CD is a key tool in today’s software development world. It helps making and sharing software more efficient. While many articles discuss the basic steps like building and testing software, there’s more to the story. This includes correctly labelling and releasing software. This part of the three-part blog series, covers the basics of CI/CD and the use of Git Branching Strategy.

CI/CD is a two-part system. The CI part, or Continuous Integration, is about constantly adding and checking new software changes to ensure everything works well together. The CD part, which stands for Continuous Delivery/Deployment, is about getting those changes ready and out to users smoothly.

Git, helps teams manage their software projects. Instead of mixing all the code, Git uses “branches” to keep things organised. We discussed several ways to use these branches, each with its own set of rules and benefits. For example, one method is to create a separate branch for each new feature. Another approach is to have a branch for each developer. I also shared a custom method I’ve used before, which combines elements from other strategies.

In conclusion, selecting the right branching strategy to build robust CI/CD pipelines in the organisation is essential. It involves testing and organising new code in a way that makes sense. This blog offered insights into how to do that more effectively. 

In my opinion, the branching strategy need not be as complicated as GitFlow. And ideally, it should also not be like the Feature/Personal branching example provided. Instead, we need to set the minimum viable branching strategy like the custom strategy we have discussed.

If you want to discuss CI/CD further and learn how to better implement a Git Branching Strategy for your company. Get in touch with one of our experts here.


Continuous Integration 

This is part two of our series on MuleSoft CI/CD. In the previous chapter, we discussed the introduction of MuleSoft CI/CD and Git Branching Strategies. 

In this chapter, we will discuss the following topics. 

  • Recap on part one and Custom Branching Strategy Release Plan 
  • What is Continuous Integration? 
  • MuleSoft Continuous Integration(CI) implementation in GitHub Actions 

Recap on part one and Custom Branching Strategy Release Plan: 

  • In part one of the blog, we discussed CI/CD and Git Branching strategies. 
  • Let’s now look at the Custom Branching strategy and try to implement the entire build/release and deploy components of it using GitHub Actions. 
  • As we have already discussed the Custom Branching Strategy in the last blog, let’s break down the CI/CD pipeline workflows that we need to implement:
    1. A workflow that compiles and tests the Project and deploys it to the Dev environment when any changes happen to the feature/* branches.
      • The developer does the dev tests, and once the developer is happy, they will merge the feature to develop the branch. The source code from the develop branch needs to be deployed to the SIT environment. This allows us to build the following workflow. 
    2. A workflow that compiles/tests the Project and deploys it to the SIT environment when any changes happen to the develop branch.
      • Testers do the end-to-end integration testing in the SIT environment and sign off on the feature. 
      • The developer needs to merge the develop branch to a branch where the release happens for the source code. 
      • This is the place where we need a workflow to run the same compile/build/unit tests again and do the release on the Project. Preparing the release means removing the artefact SNAPSHOT version and creating a tag with the release version. 
    3. A workflow to compile and test the Project (QA) and then release the Project with their release activities(versioning and tagging) and make the tag available for the next UAT/Prod deployment.
      • This workflow will produce the release candidate available for the Operations team to deploy the Project to higher (UAT/Prod) environments.
      • So, here, we need a manual trigger-based workflow/Action to deploy the released tag to higher environments(UAT/Prod). This also needs to ensure the same QA branch source code change is merged to the master once the Production deployment is completed. 
    4. A manual workflow to take the release version/tag and deploy it to a selected higher environment of choice(UAT/Prod). Also, this workflow needs to merge the same QA branch change to the master branch once the Production deployment has been completed. 
  • We have a total of four workflows to be built to deliver the entire CI/CD pipeline. 
  • In this chapter, we will see the first two workflows from the “MuleSoft CI implementation in GitHub Action” section.
    1. The first one is to compile/test/run unit tests and deploy the Project in the Dev environment when any change happens to feature/* branches. 
    2. The second one is to compile/test/run unit tests and deploy the Project in the SIT environment when any change happens to the develop branch. 
  • The next two workflows(mentioned below) will be discussed in the next blog part of “MuleSoft CI/CD Part-III Continuous Delivery/Deployment”.
    1. The third one is 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.
    2. The fourth is a manual workflow 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. 

What is Continuous Integration? 

  • The “CI” in CI/CD refers to Continuous Integration (CI), an automation process for developers to build the application for any changes continuously. 
  • Continuous Integration (CI) is a development practice where developers integrate code into a shared repository frequently.  Each code integration can then be verified by an automated build and automated tests (not mandatorily auto-tested, but most organisations do follow automated tests). 
  • One of the key benefits of Continuous Integration (CI) is that we can detect defects early and quickly. 
  • As each change is typically small, pinpointing the specific change that introduced the defect can be done quickly. 
  • Usually, Continuous Integration (CI) has the following tasks:
    • Checkout source code of the Project 
    • Compile the Project 
    • Run the unit tests
    • Deploy the Project to the Dev environment
  • We will see these tasks or CI steps in the next section, where we implement these steps for the MuleSoft API in GitHub Actions. 

MuleSoft Continuous Integration(CI) implementation in GitHub Actions

We will implement the first GitHub Actions Workflow to compile/test and deploy the Project in the Dev environment when any change happens to feature/* branches. 

We will set up the GitHub Action by following the below steps:

  • Setup your Repository
  • Setup the environments on the Repository 
  • Setup the environment variables on the Repository 
  • Run the pipeline 

Note: We are not storing the artifacts by building them separately for deploying them to environments instead, We are building and deploying in one step. 

Setup your Repository: 

  • We won’t go into the details of setting up the repository here. You can take a look at the mule4-hello-world-impl repo, which we will be using here for our CI implementation. 
  • Once you have the GitHub repository, Create a folder called .github and inside it another folder called workflows. Here, We will create dev-deploy.yaml and add the following content. 

name: Dev Deploy

run-name: Dev Build and Deployment

on:

  push:

    branches: [ feature/* ] 

jobs:

  build-dev:

    environment: dev

    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 with Maven

        run: mvn clean compile 

      – name: Run Munit tests 

        run: mvn test

      – name: Deploy to Dev environment 

        env:

          ENV: ${{ vars.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” 

  • This file explains the CI steps to be performed on the MuleSoft API repository once any commit goes into the branches whose names start with feature/*. 
  • Content of the file:
    • 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 to run when any commit happens on the branches whose name starts with the feature
    • A GitHub Action workflow is made up of jobs. Jobs will always run in parallel unless we mention any particular job with the needs keyword. A Job can have multiple steps to run in the workflow. 
    • For more information on GitHub Actions, you can refer to GitHub Actions. 
  • 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 runs the unit tests(Munits) of the Project. 

      – name: Run Munit tests 

        run: mvn test -Denv=dev

  • The last step builds the project and deploys the built jar file to CloudHub. 

– name: Deploy to Dev environment 

        env:

          ENV: ${{ vars.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” 

Setup the environments on Repository: 

  • We can set up multiple environments on the GitHub Repository to deploy the project to multiple environments. 
  • For this, We need to go to the Project Settings and Environments section and add the environments. 

Setup the environment variables on Repository:

  • After creating the environment variables, it’s time to create the required environment variables that are used by the GitHub Action. 
  • Create the below environment variables in dev environment
    • ENV: dev
    • APP_NAME: mule4-hello-world-impl-pavann-dev
    • Secrets:
      • ANYPOINT_USERNAME
      • ANYPOINT_PASSWORD
      • ANYPOINT_PLATFORM_USERNAME
      • ANYPOINT_PLATFORM_PASSWORD
      • Here, the first username and password are the Anypoint Platform access credentials to deploy the API, and the last two usernames and passwords are the dev environment API Manager connectivity platform credentials. 

Run the pipeline: 

  • With this setup on the API Github repository, any changes to the repository in the feature/* branches can trigger this GitHub Action automatically. 
  • You can go into the Actions tab to see the workflows. We can also click on the job to see the logs of each step included in the job, which will help debug the GitHub Action.

The second workflow we discussed to “compile/test/run unit tests and deploy the Project in SIT environment when any change happens to develop branch” also looks like the same as the first GitHub workflow we developed above other than the environment change. We will just change the environment and environment variables to deploy. Below is the GitHub Workflow(Action) for the same: 

Conclusion: 

In this chapter, we delved deeper into the intricacies of Continuous Integration (CI) and its implementation using GitHub Actions. 

CI, a cornerstone of modern software development, is where developers frequently merge code changes into a shared repository. This continuous merging allows for swift detection of defects, as each change is usually small and can be quickly verified through automated builds and tests.

We discussed the importance of a structured CI/CD release plan, particularly in MuleSoft API. By leveraging a custom branching strategy, developers can streamline the process of building, testing, and deploying their projects. The blog outlines four distinct workflows, each catering to different stages of the development lifecycle, from initial feature development to final production deployment.

We looked at the practical implementation of these workflows using GitHub Actions and guided you in setting up repositories, defining environment variables, and crafting workflows to automate the CI process.

In summary, this blog is a comprehensive guide for those looking to harness the power of CI and GitHub Actions in their MuleSoft API projects. By breaking down the CI/CD release plan into manageable workflows, developers can ensure a smooth and efficient development process, from code integration to deployment.


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/Deploymen?

  • 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:

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. 

Conclusion:

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.