Mule 4 Continuous Integration Using Azure DevOps
An integration engineer gives a tutorial on creating an Azure project and integrating different branches together using Mule 4.
Join the DZone community and get the full member experience.
Join For FreeOnce we started developing applications in MuleSoft and storing our code in source control platforms like GitHub, Bitbucket, GitLab, or Azure, just to mention the most common ones, we needed to look into automating the process to deploy our applications either to CloudHub or an on-premise server.
In this post, I will try to explain how a MuleSoft application can be automatically deployed into CloudHub or an on-premise server from Azure DevOps as our main CI platform and source control platform.
Create a Project in Azure
The first step is to setup our project in Azure DevOps. For this, you need a Microsoft account, which you can set up here: https://dev.azure.com/.
Then we can create a new project, provide a name and a description, as well as set the privacy; by default, it comes set as "private."
Once this is created, we can go into the main page and locate the "Repos" section. Once we see the page, we can use the information to send our code directly from our local environment.
But just before actually pushing any code, we can create a pretty simple endpoint that we can hit later to verify everything is working. So, in Anypoint, create a pretty simple RAML definition:
#%RAML 1.0
title Sample API
/persons
get
responses
200
body
application/json
example
[{
"id": 1,
"name": "Edgar Moran",
"username": "emoran",
"email": "yucel.moran@some.test",
"address": {
"street": "Kulas Light",
"suite": "Apt. 556",
"city": "Gwenborough",
"zipcode": "92998-3874",
"geo": {
"lat": "-37.3159",
"lng": "81.1496"
}
}}]
Then we can generate the flows in our project: right-click on the RAML file > Mule > Generate Flows from Local REST API.
Then, once we have our flow generated, we can proceed to create our test.yaml
file in order to identify any value we want to attach to our environment.
It will look just like this:
xxxxxxxxxx
http
port"8081"
environment"[TEST]"
Then we can create a global.xml
configuration file in which to keep our configurations. We can add a Configuration Property config as shown below:
Then we can create a Global property, in this case called env
, which will allow us to know in which environment we are working.
I know, it's a lot, but let's try to do it right. Just before our final check to verify everything is working, let's add an environment variable called env
in our Run Configuration.
Then let's run the project. If all went okay, we'll see our project deployed!
So if it's all good, then we can start pushing our first version of this working code into our Azure repo. Let's do that next.
Generating a Personal Access Token
Let's go back into the Azure DevOps main project page:
And then let's create a personal access token:
Click on 'Create a new token.' You'll see a bunch of options; select the actions and permissions you consider best depending of your needs.
Once created, you'll have a new token which becomes your project password, so keep it safe!
Now we can push our code. If the terminal asks you for a password, use the token you just generated and your code should be on the master branch:
All right, so we have our code already in Azure. Now, let's create a new branch for our repository. Let's call it test, based on the master, and let's create a developer branch called emoran.
It's important to mention that during this example we will review the build on the emoran branch and we will deploy to CloudHub in the test branch.
Create an Artifact
Before we create our pipeline, we need to make sure we have the right information in our settings.xml
and pom.xml
files. This artifact will allow us to get the Distribution Management piece we need to set in our project. For this, we will need to go into our main project page and locate the artifact option on the left, then we need to click on "Connect to feed." Next, select Maven and it will show the information we need to put into our settings.xml
and pom.xml
files.
Preparing Our settings.xml and pom.xml Files
Now, the next task will be to prepare our files in order to make sure we can build and deploy our application into CloudHub.
Here's how my settings file looks:
xxxxxxxxxx
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<servers>
<server>
<id>yucelmoran-azure-pipeline</id>
<username>yucelmorans</username>
<!-- Treat this auth token like a password. Do not share it with anyone, including Microsoft support. -->
<!-- The generated token expires on or before 17/11/2019 -->
<password>${azure.password}</password>
</server>
<server>
<id>MuleRepository</id>
<username>${nexus.username}</username>
<password>${nexus.password}</password>
</server>
</servers>
<profiles>
<profile>
<id>Mule</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<repositories>
<repository>
<id>yucelmoran-azure-pipeline</id>
<url>https://pkgs.dev.azure.com/yucelmorans/yucelmoran-azure-pipeline/_packaging/yucelmoran-azure-pipeline/maven/v1</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>MuleRepository</id>
<name>MuleRepository</name>
<url>https://repository.mulesoft.org/nexus-ee/content/repositories/releases-ee/</url>
<layout>default</layout>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</profile>
</profiles>
</settings>
And here's the pom.xml
file:
xxxxxxxxxx
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.emoran</groupId>
<artifactId>yucelmoran-azure-pipeline</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>mule-application</packaging>
<name>yucelmoran-azure-pipeline</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<app.runtime>4.3.0</app.runtime>
<mule.maven.plugin.version>3.3.5</mule.maven.plugin.version>
<mule.tools.version>1.7</mule.tools.version>
</properties>
<scm>
<connection>scm:git:git@ssh.dev.azure.com:v3/yucelmorans/yucelmoran-azure-pipeline/yucelmoran-azure-pipeline</connection>
<developerConnection>scm:git@ssh.dev.azure.com:v3/yucelmorans/yucelmoran-azure-pipeline/yucelmoran-azure-pipeline</developerConnection>
<url>https://yucelmorans@dev.azure.com/yucelmorans/yucelmoran-azure-pipeline/_git/yucelmoran-azure-pipeline</url>
</scm>
<distributionManagement>
<repository>
<id>yucelmoran-azure-pipeline</id>
<url>https://pkgs.dev.azure.com/yucelmorans/yucelmoran-azure-pipeline/_packaging/yucelmoran-azure-pipeline/maven/v1</url>
</repository>
</distributionManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<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>4.3.0</muleVersion>
<!-- Deploy User Parameter -->
<username>${anypoint.username}</username>
<password>${anypoint.password}</password>
<!-- Environment Parameter -->
<environment>Sandbox</environment>
<applicationName>yucelmoran-azure-pipeline</applicationName>
<workerType>Micro</workerType>
<objectStoreV2>true</objectStoreV2>
<properties>
<env>${env}</env>
</properties>
</cloudHubDeployment>
</configuration>
<executions>
<execution>
<id>deploy</id>
<phase>deploy</phase>
<goals>
<goal>deploy</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<id>buildnumber</id>
<phase>validate</phase>
<goals>
<goal>create</goal>
</goals>
</execution>
</executions>
<configuration>
<format>{0,number}</format>
<items>
<item>buildNumber</item>
</items>
<doCheck>false</doCheck>
<doUpdate>false</doUpdate>
<revisionOnScmFailure>unknownbuild</revisionOnScmFailure>
</configuration>
</plugin>
<plugin>
<groupId>org.mule.tools.maven</groupId>
<artifactId>mule-app-maven-plugin</artifactId>
<version>${mule.tools.version}</version>
<extensions>true</extensions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.mule.connectors</groupId>
<artifactId>mule-http-connector</artifactId>
<version>1.5.17</version>
<classifier>mule-plugin</classifier>
</dependency>
<dependency>
<groupId>org.mule.connectors</groupId>
<artifactId>mule-sockets-connector</artifactId>
<version>1.1.6</version>
<classifier>mule-plugin</classifier>
</dependency>
<dependency>
<groupId>org.mule.modules</groupId>
<artifactId>mule-soapkit-module</artifactId>
<version>1.2.6</version>
<classifier>mule-plugin</classifier>
</dependency>
<dependency>
<groupId>org.mule.modules</groupId>
<artifactId>mule-apikit-module</artifactId>
<version>1.3.13</version>
<classifier>mule-plugin</classifier>
</dependency>
</dependencies>
<repositories>
<repository>
<id>yucelmoran-azure-pipeline</id>
<url>https://pkgs.dev.azure.com/yucelmorans/yucelmoran-azure-pipeline/_packaging/yucelmoran-azure-pipeline/maven/v1</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>MuleRepository</id>
<name>MuleRepository</name>
<url>https://repository.mulesoft.org/nexus-ee/content/repositories/releases-ee/</url>
<layout>default</layout>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>mulesoft-release</id>
<name>mulesoft release repository</name>
<layout>default</layout>
<url>http://repository.mulesoft.org/releases/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>mulesoft-release</id>
<name>mulesoft release repository</name>
<layout>default</layout>
<url>http://repository.mulesoft.org/releases/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>MuleRepository</id>
<name>MuleRepository</name>
<url>https://repository.mulesoft.org/nexus-ee/content/repositories/releases-ee/</url>
<layout>default</layout>
</pluginRepository>
</pluginRepositories>
</project>
Basically, we are specifying the location of our repository for source control purposes and then specifying where we want to deploy our application with the cloudHubDeployment configuration in the mule-maven-plugin
tag.
We can verify everything works using the following command:
xxxxxxxxxx
mvn clean install -s settings.xml -e
Create a Pipeline
Now we can create our pipeline configuration, find the Pipelines options, and select "Create Pipeline."
Select the Azure Repos Git option and select your repo from your project.
In the next step, we can select Maven and then a template YAML file will be generated (we will change this eventually).
# Maven
# Build your Java project and run tests with Apache Maven.
# Add steps that analyze code, save build artifacts, deploy, and more:
# https://docs.microsoft.com/azure/devops/pipelines/languages/java
trigger
master
pool
vmImage'ubuntu-latest'
steps
task Maven@3
inputs
mavenPomFile'pom.xml'
mavenOptions'-Xmx3072m'
javaHomeOption'JDKVersion'
jdkVersionOption'1.8'
jdkArchitectureOption'x64'
publishJUnitResultstrue
testResultsFiles'**/surefire-reports/TEST-*.xml'
goals'package'
When you finish the new YAML file will it appear as part of your code. We need to modify the script, in this case, leaving it as shown below:
xxxxxxxxxx
# Maven
# Aurthor: Edgar Moran
# Build your Java project and run tests with Apache Maven.
# Add steps that analyze code, save build artifacts, deploy, and more:
# https://docs.microsoft.com/azure/devops/pipelines/languages/java
trigger
test
emoran
pool
vmImage'ubuntu-latest'
steps
task Maven@3
condition and(succeeded(), eq(variables'Build.SourceBranch' , 'refs/heads/test'))
inputs
mavenPomFile'$(system.defaultWorkingDirectory)/pom.xml'
mavenOptions'-Xmx3072m'
javaHomeOption'JDKVersion'
jdkVersionOption'1.8'
jdkArchitectureOption'x64'
publishJUnitResultstrue
testResultsFiles'**/surefire-reports/TEST-*.xml'
goals'clean deploy -Danypoint.username=$(ANYPOINT_USERNAME) -Danypoint.password=$(ANYPOINT_PASSWORD) -Denv=test -Dazure.password=$(AZURE_TOKEN) -Dnexus.username=$(NEXUS_UERNAME) -Dnexus.password=$(NEXUS_PASSWORD) -s settings.xml -e'
task Maven@3
inputs
mavenPomFile'$(system.defaultWorkingDirectory)/pom.xml'
mavenOptions'-Xmx3072m'
javaHomeOption'JDKVersion'
jdkVersionOption'1.8'
jdkArchitectureOption'x64'
publishJUnitResultstrue
testResultsFiles'**/surefire-reports/TEST-*.xml'
goals'clean install -Dazure.password=$(AZURE_TOKEN) -Dnexus.username=$(NEXUS_UERNAME) -Dnexus.password=$(NEXUS_PASSWORD) -s settings.xml -e'
It is important at this step to set the variables we will use during deployment. For example, credentials to login to nexus repositories, Anypoint Platform, and our personal tokens we created in Azure.
Once we have created our pipeline we can select the option Variables:
Finally, let's create as many as we need, according to what we need from our YAML file:
So now the last piece of the puzzle is basically to send a change from the source control to Azure on the first step (sending a change on emoran) branch. For example:
We'll see our pipeline running the emoran branch:
When it finishes, we'll see this brach had a clean install build:
Now everything happens in source control, so if we want to deploy our application to Cloudhub, then we need to promote our changes from the emoran branch to the test branch.
Now, let's create a pull request from Azure, from the emoran branch to the test branch:
Once we click Create, then we need to complete the pull request and merge request in order to start the pipeline.
When the pipeline that we ran for the test branch finishes, we can see that the deployment happened this time:
So now we can go to Anypoint Platform and see our app deploying:
Finally, you can set as many branches as you need and try out other processes.
I hope this helps! You can find full code here.
I hope to hear from you in the comments!
Opinions expressed by DZone contributors are their own.
Comments