- Services
- Our service portfolio
We bring your digital product vision to life, from crafting real-world testable prototypes to delivering comprehensive product solutions.
- Collaboration models
Explore collaboration models customized to your specific needs: Complete nearshoring teams, Local heroes from partners with the nearshoring team, or Mixed tech teams with partners.
- Way of working
Through close collaboration with your business, we create customized solutions aligned with your specific requirements, resulting in sustainable outcomes.
- Our service portfolio
- About Us
- Who we are
We are a full-service nearshoring provider for digital software products, uniquely positioned as a high-quality partner with native-speaking local experts, perfectly aligned with your business needs.
- Meet our team
ProductDock’s experienced team proficient in modern technologies and tools, boasts 15 years of successful projects, collaborating with prominent companies.
- Our locations
We are ProductDock, a full-service nearshoring provider for digital software products, headquartered in Berlin, with engineering hubs in Lisbon, Novi Sad, Banja Luka, and Doboj.
- Why nearshoring
Elevate your business efficiently with our premium full-service software development services that blend nearshore and local expertise to support you throughout your digital product journey.
- Who we are
- Our work
- Career
- Life at ProductDock
We’re all about fostering teamwork, creativity, and empowerment within our team of over 120 incredibly talented experts in modern technologies.
- Open positions
Do you enjoy working on exciting projects and feel rewarded when those efforts are successful? If so, we’d like you to join our team.
- Candidate info guide
How we choose our crew members? We think of you as a member of our crew. We are happy to share our process with you!
- Life at ProductDock
- Newsroom
- News
Stay engaged with our most recent updates and releases, ensuring you are always up-to-date with the latest developments in the dynamic world of ProductDock.
- Events
Expand your expertise through networking with like-minded individuals and engaging in knowledge-sharing sessions at our upcoming events.
- News
- Blog
- Get in touch
25. Sep 2024 •5 minutes read
Automating Mule deployments: From Dev to Prod with GitHub Actions
Danijel Dragičević
MuleSoft Developer
In this blog post, we will explore the automation of deployment of Mule applications to both CloudHub 1.0 and CloudHub 2.0 using GitHub Actions. We’ll walk through how to configure our Mule application for deployment on both versions of CloudHub, streamlining the process from build to deployment.
Throughout this guide, we’ll demonstrate how to deploy to different environments, which will be particularly helpful for teams transitioning between these two services. CloudHub 2.0 offers improved scalability, flexibility, and resource consumption. Also, in the future, it will be the main focus of MuleSoft when it comes to updates and security patches.
Configuring environments on the Anypoint Platform
To begin, set up the required environments on the Anypoint Platform. We can do this either through the platform’s UI’s Access Management section or the Anypoint CLI. While both methods are effective, the CLI allows for automation, faster execution, and greater scalability when managing multiple environments. The instructions for installing the Anypoint CLI are in the following documentation: Anypoint CLI Installation.
Once the Anypoint CLI is installed, authenticate using your platform credentials and create the necessary environments. If we’re on a free account, all environments must be of type “Sandbox,” while “Production” environments require a paid subscription.
# Authenticate:
$ anypoint-cli-v4 conf username <username>
$ anypoint-cli-v4 conf password <password>
$ anypoint-cli-v4 conf organization <organization>
# Create environments:
$ anypoint-cli-v4 account:environment:create dev --type sandbox
$ anypoint-cli-v4 account:environment:create qa --type sandbox
$ anypoint-cli-v4 account:environment:create prod --type sandbox
Preparing the Mule application for deployment
With our environments set up, the next step is to configure the Mule application. In this example, we’re using a basic application with a /ping endpoint, which returns key identifiers such as groupId, artifactId, and version.
The API contract is defined in a RAML file, a widely used specification in the MuleSoft ecosystem. The OpenAPI Specification is also supported and can be utilized if needed.
#%RAML 1.0
title: mule-github-actions-api
version: v1.0.0
/ping:
get:
displayName: Get application info
description: Shows application identifiers, fetched from the pom file
responses:
200:
body:
application/json:
type: !include dataTypes/ping-response-data-type.raml
example: !include examples/ping-response-example.raml
We configure pom.xml and property placeholders to populate these values dynamically during the build process.
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>config/common.yaml</include>
</includes>
</resource>
</resources>
This configuration instructs Maven to substitute values defined in the config/common.yaml with the values from the pom.xml.
Values in the config file can be accessed with the DataWeave using the p(propertyName: String) function:
%dw 2.0
output application/json skipNullOn="everywhere"
---
{
groupId: p('application.groupId'),
artifactId: p('application.artifactId'),
version: p('application.version')
}
For deploying to CloudHub 1.0 and CloudHub 2.0, the mule-maven-plugin is essential. We configure separate profiles in pom.xml to handle deployments to either CloudHub version. These profiles allow us to switch between deployment environments by specifying the relevant profile in the GitHub Action script.
Below is the plugin configuration for CloudHub 1.0 deployments:
<profiles>
<profile>
<id>cloudHubDeployment</id>
<build>
<plugins>
<plugin>
<groupId>org.mule.tools.maven</groupId>
<artifactId>mule-maven-plugin</artifactId>
<version>${mule.maven.plugin.version}</version>
<extensions>true</extensions>
<configuration>
<cloudHubDeployment>
<uri>https://anypoint.mulesoft.com</uri>
<muleVersion>${app.runtime}</muleVersion>
<username>${anypoint.username}</username>
<password>${anypoint.password}</password>
<applicationName>
${project.artifactId}-${anypoint.environment}
</applicationName>
<environment>${anypoint.environment}</environment>
<releaseChannel>EDGE</releaseChannel>
<javaVersion>17</javaVersion>
<workerType>MICRO</workerType>
<region>us-east-2</region>
<workers>1</workers>
<objectStoreV2>true</objectStoreV2>
</cloudHubDeployment>
<classifier>mule-application</classifier>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
And here is the configuration for CloudHub 2.0 deployments:
<profiles>
<profile>
<id>cloudhub2Deployment</id>
<build>
<plugins>
<plugin>
<groupId>org.mule.tools.maven</groupId>
<artifactId>mule-maven-plugin</artifactId>
<version>${mule.maven.plugin.version}</version>
<extensions>true</extensions>
<configuration>
<cloudhub2Deployment>
<uri>https://anypoint.mulesoft.com</uri>
<muleVersion>${app.runtime}</muleVersion>
<username>${anypoint.username}</username>
<password>${anypoint.password}</password>
<applicationName>
${project.artifactId}-${anypoint.environment}
</applicationName>
<environment>${anypoint.environment}</environment>
<releaseChannel>EDGE</releaseChannel>
<javaVersion>17</javaVersion>
<replicas>1</replicas>
<target>Cloudhub-US-East-2</target>
<vCores>0.1</vCores>
<provider>MC</provider>
<deploymentSettings>
<generateDefaultPublicUrl>true</generateDefaultPublicUrl>
</deploymentSettings>
</cloudhub2Deployment>
<classifier>mule-application</classifier>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
The configuration varies slightly between CloudHub 1.0 and 2.0, especially in terms of region, worker types, and other resource allocations. Refer to the MuleSoft Deployment Documentation for further details on each parameter.
Versioning is critical when deploying to CloudHub 2.0, as each deployment creates a new asset in Exchange. To ensure the application is ready for release, use the versions-maven-plugin to remove SNAPSHOT from the version. After deployment to production, increment the version for the next development cycle.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<version>2.8.1</version>
</plugin>
Setting up a GitHub repository
Next, we have to create a GitHub repository to store our source code and automate the deployment process. We can use the GitHub CLI to create and manage the repository or use the GitHub web interface for a more visual experience.
Once this tool is installed, we can authenticate and verify our GitHub account using:
# Authenticate:
$ gh auth login
# Verify:
$ gh auth status
github.com
✓ Logged in to github.com account danijeldragicevic (keyring)
- Active account: true
- Git operations protocol: https
- Token: gho_************************************
- Token scopes: 'gist', 'read:org', 'repo', 'workflow'
Ensure that our authentication token includes the repo scope, as we’ll need this token to interact with our repository through GitHub Actions.
To create a new repository for our application, run:
$ gh repo create mule-github-actions-app --public
✓ Created repository danijeldragicevic/mule-github-actions-app on GitHub
https://github.com/danijeldragicevic/mule-github-actions-app
It’s important to note that our repository must be public for free GitHub accounts to use GitHub Actions.
Set up a develop branch and protect it by requiring pull requests for all changes. This approach ensures that code merges into the branch only after review and approval.
$ cd ~/AnypointCodeBuilder/workspace/mule-github-actions-app
$ git init
$ git add .
$ git commit -m "first commit"
$ git remote add origin https://github.com/danijeldragicevic/mule-github-actions-app.git
$ git branch -M develop
$ git push -u origin develop
Create branch protection rule:
curl -X PUT \
-u danijeldragicevic:gToken \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/danijeldragicevic/mule-github-actions-app/branches/develop/protection \
-d '{
"required_pull_request_reviews": {
"required_approving_review_count": 1
},
"restrictions": {
"users": ["danijeldragicevic"]
},
"enforce_admins": true,
"required_status_checks": null
}'
This setup ensures that code can only be merged into this branch with at least one approval from a team member. We can adjust the number of required approvals based on the size of the team. The restrictions also apply to administrators, enforcing that all changes must go through pull requests rather than direct commits.
Finally, we have to create secrets in our GitHub repository for authentication against the Anypoint Platform and GitHub itself. GitHub Actions will use these secrets to securely handle authentication and authorization during the deployment process.
$ gh secret set ANYPOINT_PLATFORM_USERNAME -b"username" --repo danijeldragicevic/mule-github-actions-app
$ gh secret set ANYPOINT_PLATFORM_PASSWORD -b"password" --repo danijeldragicevic/mule-github-actions-app
$ gh secret set G_TOKEN -b"gToken" --repo danijeldragicevic/mule-github-actions-app
Automating deployments with GitHub Actions
With the repository and secrets configured, it’s time to set up GitHub Actions. First, we have to create a .github/workflows/main.yaml file at the root level of our project, which is a default location where GitHub looks for workflow definitions. When changes are pushed to the repository, GitHub checks this directory for .yaml files that define workflows to trigger actions. Our example uses the workflow_dispatch trigger, which allows for manual deployments to specific environments (dev, qa, prod).
on:
workflow_dispatch:
inputs:
environment:
description: 'Environment to deploy to'
type: choice
required: true
options:
- dev
- qa
- prod
Permissions are granted for GitHub Actions to commit to the repository when needed.
permissions:
contents: write
The workflow includes build, deploy, and verify jobs. The build job has an additional step to create a release if deployment is intended for the QA environment: removing SNAPSHOT from the application version and publishing the release.
- name: Create release
if: ${{ github.event.inputs.environment == 'qa' }}
run: |
mvn versions:set -DremoveSnapshot versions:commit
version=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git config --global user.name "github-actions[bot]"
git add pom.xml
git commit -m "Create release $version"
git push https://x-access-token:$githubToken@github.com/${{ github.repository }}.git develop
git tag $version
git push https://x-access-token:$githubToken@github.com/${{ github.repository }}.git $version
shell: bash
env:
githubToken: ${{ secrets.G_TOKEN }}
Although including a test job is common, Mule applications require a commercial license to access and download the MUnit library. While MUnit tests can be run locally (as the libs are included with Anypoint Studio or Anypoint Code Builder installation for free), this isn’t possible on a bare Linux instance, such as those used in GitHub Actions, without configuring the access to the Mule Soft’s Nexus repository.
The deploy job sets the deployment type and directs the deployment to CloudHub 1.0 or CloudHub 2.0, depending on the selected environment.
- name: Set deployment type
uses: ./.github/actions/deployment-type-config
with:
targetEnvironment: ${{ github.event.inputs.environment }}
- name: Deploy to CH1.0
if: env.deploymentType == 'cloudHubDeployment'
uses: ./.github/actions/deploy-to-ch1-config
with:
username: ${{ secrets.ANYPOINT_PLATFORM_USERNAME }}
password: ${{ secrets.ANYPOINT_PLATFORM_PASSWORD }}
targetEnvironment: ${{ github.event.inputs.environment }}
- name: Deploy to CH2.0
if: env.deploymentType == 'cloudhub2Deployment'
uses: ./.github/actions/deploy-to-ch2-config
with:
username: ${{ secrets.ANYPOINT_PLATFORM_USERNAME }}
password: ${{ secrets.ANYPOINT_PLATFORM_PASSWORD }}
targetEnvironment: ${{ github.event.inputs.environment }}
Our action script that deploys the application has two steps. The first step is to publish the built application to Anypoint Exchange, MuleSoft’s central repository for sharing and discovering reusable assets such as APIs and connectors.
- name: Publish to Exchange
run: |
mvn deploy --settings .maven/settings.xml -DskipMunitTests \
-Danypoint.username="$username" \
-Danypoint.password="$password" \
shell: bash
env:
username: ${{ inputs.username }}
password: ${{ inputs.password }}
Once the application is published to Exchange, the next step is to deploy it to the target environment (in this case, CloudHub 2.0):
- name: Deploy the application
run: |
artifactName=$(ls *.jar | head -1)
mvn deploy --settings .maven/settings.xml -DskipMunitTests -DmuleDeploy -Pcloudhub2Deployment\
-Dmule.artifact=$artifactName \
-Danypoint.username="$username" \
-Danypoint.password="$password" \
-Danypoint.environment="$targetEnvironment"
shell: bash
env:
username: ${{ inputs.username }}
password: ${{ inputs.password }}
targetEnvironment: ${{ inputs.targetEnvironment }}
Verifying deployments and preparing for the next cycle
After deployment, the verify job ensures the service is running and responding by pinging the appropriate instance of the application.
- name: Verify deployment
run: |
if [[ "$targetEnvironment" == "dev" ]]; then
curl -f http://mule-github-actions-app-dev.us-e2.cloudhub.io/api/ping || exit 1
elif [[ "$targetEnvironment" == "qa" ]]; then
curl -f http://mule-github-actions-app-qa.us-e2.cloudhub.io/api/ping || exit 1
elif [[ "$targetEnvironment" == "prod" ]]; then
curl -f https://mule-github-actions-app-prod-qefjd6.5sc6y6-3.usa-e2.cloudhub.io/api/ping || exit 1
else
echo "Skipping deployment verification"
exit 0
fi
shell: bash
env:
targetEnvironment: ${{ github.event.inputs.environment }}
If successful, the application version is incremented, and the branch is prepared for the next development cycle, ensuring that the project is ready for further work.
- name: Set next development cycle
if: ${{ github.event.inputs.environment == 'prod' }}
run: |
mvn versions:set -DnextSnapshot versions:commit
version=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git config --global user.name "github-actions[bot]"
git checkout develop || git checkout -b develop
git add pom.xml
git commit -m "Increase version to $version for next development cycle"
git push https://x-access-token:$githubToken@github.com/${{ github.repository }}.git develop
shell: bash
env:
githubToken: ${{ secrets.G_TOKEN }}
Conclusion
By integrating GitHub Actions with the Anypoint Platform, we can automate the entire deployment lifecycle of Mule applications — from building and testing to deploying and verifying. This approach reduces manual intervention, improves reliability, and ensures a consistent deployment process across all environments. As we continue to scale our deployments, leveraging tools like GitHub Actions and Anypoint CLI will become even more valuable, saving time and reducing errors.
To see the complete source code and this deployment process in action, visit the GitHub repository. Feel free to explore, fork, or contribute to the project!
Tags:
Danijel Dragičević
MuleSoft DeveloperDanijel is a MuleSoft developer, content creator, and mentor. He has been part of our family since April 2014. Over the past few years, he has focused on developing integrations using Java and MuleSoft’s Anypoint Platform, following the API-led connectivity strategy.