Skip to content

Hello World application implements basic configuration to demonstrate the best practices for CICD setup.

Notifications You must be signed in to change notification settings

hectoralicea/cicd-hello-world

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

41 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CICD Hello World

Automated build ready for self-service

Project demonstrates DevOps best prectices, tooling and configuration and is mostly focused on CI.

Key areas:

  • Maven Repository (Nexus)
  • MUnit
  • Branching Strategy
  • CICD Pipelines - design
  • Release Management

Maven repository Nexus

Why is it important:

  • security
  • manages all the dependencies (external libraries as well as internally built libraries like)
  • manages and stores built packages - snapshots and releases

Repository mirroring

Mirroring enables organisation to use their own central repository to access all the required dependencies available outside their network. Developers can get access to any dependency they might need via the single point, which is local instance of maven repository (e.g. Nexus)

More details can be found in official documentation:

Sample Config in `settings.xml`

<mirrors>
<!-- maven central repository -->	
    <mirror>
      <id>mvn_repo_central_mirror</id>
      <mirrorOf>central</mirrorOf>
      <url>${MVNREPO_URL}/repository/${MVNREPO_CENTRAL}</url>
    </mirror>

<!-- MuleSoft public repository -->
    <mirror>
      <id>mule_repo_public_mirror</id>
      <mirrorOf>mule-public</mirrorOf>
      <url>${MVNREPO_URL}/repository/${MVNREPO_MULE_PUBLIC}</url>
    </mirror>
 
<!-- MuleSoft enterprise repository - credentials are required (provided by MuleSoft support team) -->	
    <mirror>
      <id>mule_repo_ee_mirror</id>
      <mirrorOf>mule-ee</mirrorOf>
      <url>${MVNREPO_URL}/repository/${MVNREPO_MULE_EE}</url>
    </mirror>
  </mirrors>
<mirrors>

Deploy package to Nexus

Section provides the details of configuration that is required to enable deployment of a package to Mave repository (e.g. Nexus).

Sample Config in pom.xml

<distributionManagement>
	<repository>
		<id>nexus</id>
		<name>Releases</name>
		<url>${MVNREPO_URL}/repository/${maven.repo.releases}</url>
	</repository>
	<snapshotRepository>
		<id>nexus</id>
		<name>Snapshot</name>
		<url>${MVNREPO_URL}/repository/${maven.repo.snapshots}</url>
	</snapshotRepository>
</distributionManagement>

${MVNREPO_URL} is configured as Jenkins variable, see Jenkins configuration for more details.

${maven.repo.releases}, and ${maven.repo.snapshots} are configured in pom as maven properties:

Sample - properties

<properties>
	<maven.repo.snapshots>maven-snapshots</maven.repo.snapshots>
	<maven.repo.releases>maven-releases</maven.repo.releases>
</properties>

Once the configuration is done you can test your deployment to mavne repository (e.g. Nexus) by running the command mvn clean deploy. If command was executed successfully new package should be visible in Nexus (either under snapshots or under releases, depending on the project version, e.g. <version>1.0.6-SNAPSHOT</version> would create a pacakge under snapshots).

MUnit

Chapter describes recommended best practices for automated unit testing.

  • Test coverage must be at least 80% (that includes application coverage and individual flow coverage).
  • Build should be configured to fail if percetage of test coverage is not sufficient.
  • Report generated as a result of the unit test should be archived on CI Server for future reference.
Sample Config

<plugin>
  <groupId>com.mulesoft.munit.tools</groupId>
  <artifactId>munit-maven-plugin</artifactId>
  <version>${munit.version}</version>
  <executions>
    <execution>
      <id>test</id>
      <phase>test</phase>
      <goals>
        <goal>test</goal>
      </goals>
    </execution>
  </executions>
  <configuration>
    <coverage>
      <runCoverage>true</runCoverage>
      <failBuild>true</failBuild>
      <requiredApplicationCoverage>80</requiredApplicationCoverage>
      <requiredFlowCoverage>80</requiredFlowCoverage>
      <formats>
        <format>html</format>
        <format>json</format>
      </formats>
    </coverage>
  </configuration>
</plugin>

Source code branching

The diagram below captures the suggested branching strategy, which also impacts the design of CI pipelines.

Branching strategy

Feature Branch

Feature development - branch usually maintained by one developer working on the specific feature. Naming conventions of the branch: feature-name where name is user story identifier (Jira ticket ID)

Main development branch

All the finalised features are merged into the development branch. The new releases or release candidates are created and built from this branch.

A developer can never merge feature branch to main development branch directly. The Pull Request must be used. The tech lead validates the Pull Request and approves or rejects the merge commit. The practice enforces the code review practices, team collaboration, and improves the stability of the releases.

Prod branch

Once the release is deployed to production, code from development branch is merged into Master that represents production code.

Merging development branch into PROD branch should be ideally semi-automatic activity managed via CICD.

Hotfix branch

Created from Mater/PROD branch if a critical issue is identified in production and an immediate fix is required.

Naming conventions of the branch: hotfix-identifier where identifier is ID of reported incident (e.g. Jira ticket ID - if Jira is used for incident tracking)

Once the hotfix is deployed to production the branch must be merged into Master/PROD branch and Main development branch

Note about Release branch

Even though the branching strategy is inspired by Gitflow Workflow, it does not consider having a separate release branch as a must-have requirement.

The reason for not introducing the release branch is unnecessary branch management, which can easily become too complex and difficult to maintain. In many scenarios, developers struggle or forget to merge branches properly and the code is either lost or damaged, which leads to missing feature in PROD or deploying the old defects fixed in the previous release but not merged into the main development branch.

The release can be built from the development branch and the commit, the package is created from, must be tagged in the repository in development branch so it is clear what code was used for what release candidate.

The release branch can be created in special cases, however, it should be avoidable in a truly agile environment with efficient CICD. Example of such a scenario: Release Candidate has been built and deployed and the critical defect that requires fix is identified during UAT and there is no possibility to implement hotfix on top of the main development branch because new features that are not part of the current release have been already merged into the main development branch.

CICD Pipeline design

The main focus of this document is to provide detailed view on CI pipeline definition. CD pipelines are mentioned mostly to maintain completed DevOps picture.

Continuous Integration

CI pipeline design

As displayed on the diagram above, package creation and deployment (to Nexus and DEV environment) is triggered only for development branch (name starts with 'dev-'). Feature branch and PROD branch do not create any packages, neither do deployment. The only purpose of these pipelines is to run the MUnit tests to ensure code quality.

Continuous Deployment

CD pipeline design

Deployment on DEV is the only deployment considered and implemented in this example. Deployment on development environment should be triggered every time there is a commit to development brach (as per the configuration in Jenkinsfile, every branch starting with 'dev-' is considered as development branch). Mule maven plugin is used for deployement to development environment.

Sample DEV deployment config - on-prem runtime

<plugin>
  <groupId>org.mule.tools.maven</groupId>
  <artifactId>mule-maven-plugin</artifactId>
  <version>2.2.1</version>
  <configuration>
    <deploymentType>arm</deploymentType>
    <username>${MULEANYPOINT_USER}</username>
    <password>${MULEANYPOINT_PASSWORD}</password>
    <target>summer</target>
    <!-- One of: server, serverGroup, cluster -->
    <targetType>server</targetType>
    <environment>TEST</environment>
  </configuration>
  <executions>
    <execution>
      <id>deploy</id>
      <phase>deploy</phase>
      <goals>
        <goal>deploy</goal>
      </goals>
    </execution>
  </executions>
</plugin>

${MULEANYPOINT_USER} and ${MULEANYPOINT_PASSWORD} are configured as Jenkins Credentials, see Jenkins configuration for more details.

Special technical user should be created with specific permission to deploy applications. Production should have the separate deployment user, so user used for deployment to other environments can't be abused for PROD deployment.

Deployment on TEST and PROD are included just for illustration purposes. There are different tools and approaches that could help with the application deployment. Some of them are mentioned in Recommendations section.

Pipeline as a Code

Pipeline defined in Jenkinsfile implements different stages of the build process depending on the source code branch that triggered the build execution as desribed in parent section.

Benefits of Pipeline

  • Code: Pipelines are implemented in code and typically checked into source control, giving teams the ability to edit, review, and iterate upon their delivery pipeline.
  • Durable: Pipelines can survive both planned and unplanned restarts of CI server
  • Pausable: Pipelines can optionally stop and wait for human input or approval before continuing the Pipeline run.
  • Versatile: Pipelines support complex real-world continuous delivery requirements, including the ability to fork/join, loop, and perform work in parallel.

Jenkins configuration

  • Environment properties (configured in Jenkinsfile)

    • MVNREPO_USER = credentials('nexus_user')
    • MVNREPO_PASSWORD = credentials('nexus_psswd')
    • MULEREPO_USER = credentials('mulerepo_usr')
    • MULEREPO_PASSWORD = credentials('mulerepo_psswd')
    • MULEANYPOINT_USER = credentials('anypoint_username')
    • MULEANYPOINT_PASSWORD = credentials('anypoint_password')
    • SCM_USER = credentials('scm_user')
    • SCM_PASSWORD = credentials('scm_psswd')
    • MVNREPO_URL = credentials('mvn_repo_url') //e.g. http://172.17.0.7:8081
    • MVNREPO_CENTRAL = 'maven-central/'
    • MVNREPO_MULE_EE = 'maven-mule-ee/'
    • MVNREPO_MULE_PUBLIC = 'maven-mule-public/'
  • settings.xml for Jenkins - see mvn-settings.xml

Release management

Releases are prepared by Maven release plugin against the dev-main branch.

Sample Config - pom.xml

<scm>
	<developerConnection>scm:git:https://${SCM_USER}@github.com/mulesoft-consulting/cicd_build_hello_world.git</developerConnection>
	<tag>HEAD</tag>
</scm>
<build>
	<plugins>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-release-plugin</artifactId>
			<version>2.5.3</version>
			<configuration>
				<checkModificationExcludes>
					<checkModificationExclude>pom.xml</checkModificationExclude>
				</checkModificationExcludes>
			</configuration>
		</plugin>
	
		<plugin>
			<artifactId>maven-scm-plugin</artifactId>
			<version>1.9.5</version>
			<configuration>
				<tag>${project.artifactId}-${project.version}</tag>
				<username>${SCM_USER}</username>
				<password>${SCM_PASSWORD}</password>
			</configuration>
		</plugin>
	</plugins>
</build>

The plugin maven-scm-plugin is required to ensure that -SNAPSHOT is removed from release version and proper tag is created and committed to repository.

${SCM_USER} and ${SCM_PASSWORD} are configured as Jenkins Credentials, see Jenkins configuration for more details.

To enable maven release plugin to commit changes to repository following configuration must be included in maven's settings.xml file.

Sample Config - settings.xml

<server>
	<id>github.com</id>
	<username>${SCM_USER}</username>
	<password>${SCM_PASSWORD}</password>
</server>

How to use cicd-hello-world

This project implements all patterns discussed above. It gives us the ability to quickly test and prove design decisions and configuration.

Recommendations

Check the following project for establishing simple CD within the organisation.

About

Hello World application implements basic configuration to demonstrate the best practices for CICD setup.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Groovy 86.7%
  • RAML 8.2%
  • DataWeave 5.1%