MuleSoft - CI/CD with GitHub Actions
With GitHub Actions, it makes it very easy to automate our build, test and deploy workflows providing a sustainable CI/CD solution, managed directly from the GitHub repository.
Let's get started
Prerequisites
- Active Anypoint Platform access (Can be a trial account).
- Access to deploy an application to the CloudHub Anypoint Environment Org/Business Group
- Access to GitHub repository where the mule application source code resides.
- The MUnit maven plugin is configured to run the MUnit test cases and generate code-coverage (Optional but good to have)
- Mule maven plugin to deploy to CloudHub. Below is an example configuration
<plugin>
<groupId>org.mule.tools.maven</groupId>
<artifactId>mule-maven-plugin</artifactId>
<version>${mule.maven.plugin.version}</version>
<extensions>true</extensions>
<configuration>
<classifier>mule-application</classifier>
<cloudHubDeployment>
<uri>https://anypoint.mulesoft.com</uri>
<muleVersion>${app.runtime}</muleVersion>
<username>${username}</username>
<password>${password}</password>
<applicationName>${project.name}</applicationName>
<environment>Sandbox</environment>
<workerType>MICRO</workerType>
<region>us-east-2</region>
<workers>1</workers>
<objectStoreV2>true</objectStoreV2>
</cloudHubDeployment>
</configuration>
</plugin>
The variables that appear between ${} are externalized and supplied during GitHub Action execution using secrets.
GitHub Actions configuration
- Login to the GitHub repository and navigate to the Actions tab. Click on "New workflow" and select the simple workflow.
- Give a good name for your workflow/pipeline and paste the below content as the body and save it:
# This is a basic workflow to help you get started with Actions
name: MuleSoft deployment with GitHub Actions CI
# Controls when the action will run.
on:
# Triggers the workflow on push or pull request events but only for the main branch
push:
branches: [ dev ]
pull_request:
branches: [ dev ]
jobs:
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
- name: Cache
uses: actions/cache@v2.1.5
with:
# A list of files, directories, and wildcard patterns to cache and restore
path: /home/runner/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Setup Java JDK
uses: actions/setup-java@v1
with:
# The Java version to set up. Takes a whole or semver Java version. See examples of supported syntax in README file
java-version: 1.8
- name: maven-settings-xml-action
uses: whelk-io/maven-settings-xml-action@v16
with:
repositories: |
[
{
"id": "MuleRepository",
"name": "MuleRepository",
"url": "https://repository.mulesoft.org/nexus-ee/content/repositories/releases-ee/",
"releases": {
"enabled": "true"
},
"snapshots": {
"enabled": "true"
}
}
]
servers: |
[
{
"id": "anypoint-exchange-v2",
"username": "${{ secrets.ANYPOINT_USERNAME }}",
"password": "${{ secrets.ANYPOINT_PASSWORD }}",
"configuration": {
"httpConfiguration": {
"all": {
"usePreemptive": "true"
}
}
}
},
{
"id": "MuleRepository",
"username": "${{ secrets.ENT_ID }}",
"password": "${{ secrets.ENT_PASSWORD }}",
"configuration": {
"httpConfiguration": {
"all": {
"usePreemptive": "true"
}
}
}
}
]
# Runs a single command using the runners shell
- name: Build
run: mvn clean package
# Runs a set of commands using the runners shell
- name: Artifact file name with commit hash
run: |
artifactName1=$(ls target/*.jar | head -1)
commitHash=$(git rev-parse -short "$GITHUB_SHA")
artifactName2=$(ls target/*.jar | head -1 | sed "s/.jar/.$comitHash.jar/g")
mv $artifactName1 $artifactName2
- name: Upload a Build Artifact
uses: actions/upload-artifact@v2.2.3
with:
# Artifact name
name: build_artifact
# A file, directory or wildcard pattern that describes what to upload
path: target/*.jar
deploy-dev:
needs: build
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
- name: Cache
uses: actions/cache@v2.1.5
with:
# A list of files, directories, and wildcard patterns to cache and restore
path: /home/runner/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Setup Java JDK
uses: actions/setup-java@v1
with:
# The Java version to set up. Takes a whole or semver Java version. See examples of supported syntax in README file
java-version: 1.8
- name: Download a Build Artifact
uses: actions/download-artifact@v2.0.9
with:
# Artifact name
name: build_artifact
- name: Deploy to Anypoint Platform
env:
USERNAME: ${{ secrets.ANYPOINT_USERNAME }}
PASSWORD: ${{ secrets.ANYPOINT_PASSWORD }}
run: |
artifactName=$(ls *.jar | head -1)
mvn mule:deploy -Dmule.artifact=$artifactName -Dusername=$USERNAME -Dpassword=$PASSWORD
deploy-test:
needs: deploy-dev
# The type of runner that the job will run on
runs-on: ubuntu-latest
environment: Test
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
- name: Cache
uses: actions/cache@v2.1.5
with:
# A list of files, directories, and wildcard patterns to cache and restore
path: /home/runner/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Setup Java JDK
uses: actions/setup-java@v1
with:
# The Java version to set up. Takes a whole or semver Java version. See examples of supported syntax in README file
java-version: 1.8
- name: Download a Build Artifact
uses: actions/download-artifact@v2.0.9
with:
# Artifact name
name: build_artifact
- name: Deploy to Anypoint Platform
env:
USERNAME: ${{ secrets.ANYPOINT_USERNAME }}
PASSWORD: ${{ secrets.ANYPOINT_PASSWORD }}
run: |
artifactName=$(ls *.jar | head -1)
mvn mule:deploy -Dmule.artifact=$artifactName -Dusername=$USERNAME -Dpassword=$PASSWORD
deploy-production:
needs: deploy-test
# The type of runner that the job will run on
runs-on: ubuntu-latest
environment: Production
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
- name: Cache
uses: actions/cache@v2.1.5
with:
# A list of files, directories, and wildcard patterns to cache and restore
path: /home/runner/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Setup Java JDK
uses: actions/setup-java@v1
with:
# The Java version to set up. Takes a whole or semver Java version. See examples of supported syntax in README file
java-version: 1.8
- name: Download a Build Artifact
uses: actions/download-artifact@v2.0.9
with:
# Artifact name
name: build_artifact
- name: Deploy to Anypoint Platform
env:
USERNAME: ${{ secrets.ANYPOINT_USERNAME }}
PASSWORD: ${{ secrets.ANYPOINT_PASSWORD }}
run: |
artifactName=$(ls *.jar | head -1)
mvn mule:deploy -Dmule.artifact=$artifactName -Dusername=$USERNAME -Dpassword=$PASSWORD
So let's see what this workflow does:
- It runs on any push/pull-request on branch dev
- It has the jobs defined as build, deploy-dev, deploy-test and deploy-production running sequentially one after the other with certain conditions.
Build Stage
- Here besides the usual checkout and caching of the .m2/repositories, we are also making use of the whelk-io/maven-settings-xml-action@v16 action to set the maven settings.xml file
- This is necessary because, we need to have the Anypoint-exchange and Mule Enterprise Nexus repositories defined and also the credentials to connect to them.
- Next we use the mvn clean package command to build our mule application and then create a unique name for the build artifact (appending the commitHash). Eg: "contactapi.2e34d9f.jar"
- This artifact is then uploaded as a Build artifact for the subsequent workflow steps using the actions/upload-artifact@v2.2.3 action.
Deploy stage
- All the subsequent deploy stages follows the same workflow - downloads the build artifact that was generated and uploaded as part of the build stage and then deploy to Anypoint platform using the mvn mule:deploy command.
- The username and the password used in the mvn command are stored as secrets in the repository and passed during runtime to the workflow.
- The deploy-test and deploy-production follows the Continuous Delivery principle wherein a manual intervention is required. For this, the workflow is configured to listen to environmental configuration
Running the workflow
- As said earlier, this workflow gets triggered by doing any push or pull request on the dev branch. After the commit, click on the Actions tab to find the workflow run
- So here you see, on push to dev branch the build and deploy-dev got executed but now its waiting for a review/manual approval to deploy to test.
- The individual steps of the stages can be viewed clicking on the stage from the left side
- The reviewer can click the "Review deployments" from the right corner of the summary page and provide his approval or rejection with his comments.
- Similar review is also setup for production deployment, wherein it deploys only on manual approval.
- It also shows who has approved the deployment and his according comments for the same under the Deployment reviews section of the summary page.
Conclusion
GitHub actions provides with an effective CI/CD solution where-in the complete orchestration is driven from the source control itself without involving any other CI/CD or artifact repository tools. This ensures us with a streamlined and effective CI/CD workflow for our mule applications.