DEV Community

bhaktraj
bhaktraj

Posted on

Automating CI/CD for a Java Application with Jenkins: A Complete Pipeline Guide

Introduction

in modern software development, Continuous Integration and Continuous Deployment (CI/CD) pipelines play a critical role in automating code integration, testing, artifact generation, and deployment. In this blog, we’ll walk through building a CI/CD pipeline for a Java-based web application using Jenkins, SonarQube, and Nexus.

Automating CI/CD for a Java Application with Jenkins

Pipeline Overview
The Java application, vProfile, is a web-based project developed using Maven. The pipeline automates the following tasks:

  • Fetching code from a Git repository.
  • Building the project with Maven.
  • Running automated tests.
  • Performing code quality analysis with SonarQube.
  • Uploading the generated artifact to Nexus.
  • Sending Slack notifications about the build status.

Prerequisites

Before setting up the pipeline, ensure the following tools and configurations are in place:

  • Jenkins: Installed and running with appropriate plugins:
  • Git Plugin
  • Maven Integration Plugin
  • SonarQube Scanner Plugin
  • Nexus Artifact Uploader Plugin
  • Slack Notification Plugin
  • SonarQube: Configured with a project
  • Nexus: Running and hosting a repository for the artifacts.
  • Slack: A workspace with an incoming webhook URL for notifications.
  • Source Code: Hosted in a Git repository.

Pipeline Script
Below is the complete Jenkins pipeline script:

pipeline {
    agent {
        label 'agent47'
    }
    tools {
        maven 'maven3'
        jdk 'jdk17'
    }
    stages{
        stage("Fetch the code"){
            steps{
                git url: 'https://github.com/hkhcoder/vprofile-project.git', branch: 'atom'
            }
        }
        stage('Build'){
            steps{
                sh 'mvn clean install -DskipTests'
            }
        }
        stage('Test'){
            steps{
                sh 'mvn test'
            }
        }
        stage('Code analysis with checkstyle'){

          environment {
             scannerHome = tool 'sonarserver'
          }

          steps {
            withSonarQubeEnv('sonarserver') {
               sh '''${scannerHome}/bin/sonar-scanner -Dsonar.projectKey=vprofile \
                   -Dsonar.projectName=vprofile-repo \
                   -Dsonar.projectVersion=1.0 \
                   -Dsonar.sources=src/ \
                   -Dsonar.java.binaries=target/test-classes/com/visualpathit/account/controllerTest/ \
                   -Dsonar.junit.reportsPath=target/surefire-reports/ \
                   -Dsonar.jacoco.reportsPath=target/jacoco.exec \
                   -Dsonar.java.checkstyle.reportPaths=target/checkstyle-result.xml'''
            }
        }
    }
    stage('upload artifact'){
        steps {
            nexusArtifactUploader(
                nexusVersion: 'nexus3',
                protocol: 'http',
                nexusUrl: '172.31.18.61:8081',
                groupId: 'QA',
                version: '${env.BUILD_ID}.${env.BUILD_TIMESTAMP}',
                repository: 'projectrepo',
                credentialsId: 'nexuscred',
                artifacts: [
                    [artifactId: 'vproapp',
                    classifier: '',
                    file: 'target/vprofile-v2.war',
                    type: 'war']
        ]
     )

        }
    }

    }

    post {
        success {
            slackSend(channel: '#all-javacicdproject', color: 'good', message: "Build #${env.BUILD_NUMBER} succeeded!")
        }
        failure {
            slackSend(channel: '#all-javacicdproject', color: 'danger', message: "Build #${env.BUILD_NUMBER} failed.")
        }
        always {
            slackSend(channel: '#all-javacicdproject', color: 'warning', message: "Build #${env.BUILD_NUMBER} completed.")
        }
    }
}
Enter fullscreen mode Exit fullscreen mode
  1. Agent Section The agent block determines where the pipeline will run. It could be a specific machine, a Docker container, or any available node in the Jenkins environment.

In our pipeline:

agent {
    label 'agent47'
}
Enter fullscreen mode Exit fullscreen mode
  • Label (agent47): Refers to a specific Jenkins node (agent) where the pipeline tasks will execute. This label helps Jenkins assign the job to a machine with the required configurations and tools installed.

Why Use Agents?

  • Distributed Builds: Agents allow Jenkins to run jobs on multiple machines, distributing the workload.
  • Resource Optimization: Specific agents can be optimized for tasks like builds, testing, or deployments.
  • Environment Isolation: Different agents can have unique environments for different project requirements.

If no specific label is mentioned, Jenkins uses the default agent available.

  1. Tools Section The tools block in the pipeline script specifies the required software versions that Jenkins needs to run the build and analysis processes. This ensures that the right versions of tools are available on the agent where the pipeline executes.

In our pipeline:

tools {
    maven 'maven3'
    jdk 'jdk17'
}
Enter fullscreen mode Exit fullscreen mode

By declaring tools, Jenkins ensures that the appropriate versions are installed and configured on the agent before executing the pipeline stages.

Key Pipeline Stages

  1. Fetch the Code

The pipeline begins by pulling the source code from the Git repository.

  1. Build

Using Maven, the project is built with the mvn clean install command. Tests are skipped in this stage to save time.

  1. Test

Automated unit tests are executed to validate the codebase.

  1. Code Analysis

SonarQube analyzes the code for potential issues and technical debt. Metrics include code smells, security vulnerabilities, and maintainability.

  1. Upload Artifact

The generated .war file is uploaded to a Nexus repository for future deployment.

  1. Post-Build Notifications

Slack notifications are sent to a designated channel to inform the team about the build status.

Top comments (0)