1) CI/CD pipeline using Maven
Creating a CI/CD pipeline using Java, Maven, Git, Jenkins,
Jenkinsfile, SonarQube, Nexus, and Groovy script
involves integrating these tools for a seamless build, test, code quality
analysis, and deployment process. Here's a step-by-step guide:
1. Set Up the Tools
Ø
Git: Ensure your code is stored in a Git
repository (GitHub, GitLab, or Bitbucket).
Ø
Maven: Configure your project with a
pom.xml for build and dependency management.
Ø
Jenkins: Install Jenkins and required
plugins:
ü
Git Plugin
ü
Maven Integration
ü
Pipeline Plugin
ü
SonarQube Scanner
ü
Nexus Artifact Uploader
Ø
SonarQube: Install and configure
SonarQube for static code analysis.
Ø
Nexus: Install Nexus for artifact storage
and hosting.
Ø
Groovy: Use Groovy for custom Jenkins
pipelines.
2. Jenkins Pipeline Configuration
- Connect
Jenkins with Git:
Ø
Add your Git repository credentials in Jenkins.
Ø
In the job configuration, link your Git
repository.
- Install
SonarQube Scanner:
Ø
Configure SonarQube in Jenkins under Manage
Jenkins > Configure System.
Ø
Add SonarQube server details and authentication
tokens.
- Configure
Nexus:
Ø
Set up a repository in Nexus for storing artifacts.
Ø
Generate a user token for uploading artifacts.
- Create
a Jenkinsfile: Define your CI/CD pipeline using a Jenkinsfile. Save it
in the root directory of your Git repository.
3. Sample Jenkinsfile
This file defines the CI/CD stages: clone, build, test, code
analysis, and deploy.
groovy
pipeline { agent any tools { maven 'Maven_3.8.6' // Replace with
your Maven version jdk 'JDK_11' // Replace with your Java version } environment { SONAR_TOKEN =
credentials('sonarqube-token') // Store SonarQube token in Jenkins
credentials NEXUS_URL =
'http://nexus.example.com/repository/releases/' // Replace with your Nexus
URL } stages { stage('Clone Repository') { steps { git branch: 'main', url:
'https://github.com/your-repo/project.git' } } stage('Build') { steps { sh 'mvn clean install' } } stage('Unit Tests') { steps { sh 'mvn test' } } stage('Code Quality Analysis') { steps { withSonarQubeEnv('SonarQube')
{ sh 'mvn sonar:sonar
-Dsonar.projectKey=your_project_key -Dsonar.login=$SONAR_TOKEN' } } } stage('Upload to Nexus') { steps { script { def artifactPath =
"target/your-artifact.jar" nexusArtifactUploader( nexusVersion:
'nexus3', protocol: 'http', nexusUrl:
'nexus.example.com', groupId:
'com.example', artifactId: 'your-artifact', version: '1.0.0', repository:
'releases', file: artifactPath ) } } } } post { success { echo 'Pipeline completed
successfully!' } failure { echo 'Pipeline failed. Please
check the logs.' } } } |
4. Explanation of Jenkinsfile Stages
- Clone
Repository:
Ø
Clones the code from the Git repository.
- Build:
Ø
Uses Maven to compile and package the
application.
- Unit
Tests:
Ø
Executes tests to validate functionality.
- Code
Quality Analysis:
Ø
Runs static analysis using SonarQube.
- Upload
to Nexus:
Ø
Uploads the Maven artifact (e.g., JAR or WAR
file) to Nexus.
2) CI/CD pipeline using Maven to
extract maven project version name
To make the version dynamic in your CI/CD pipeline, you can
extract it from your Maven project's pom.xml file or pass it as a parameter in
the Jenkins job. Here's how you can do it:
Option 1: Extract Version from pom.xml
- Use
Maven to read the version from pom.xml:
groovy
stage('Determine
Version') { steps { script { def pom = readMavenPom file:
'pom.xml' env.APP_VERSION = pom.version echo "Project version is:
${env.APP_VERSION}" } } } |
- Update
the Upload to Nexus stage to use the extracted version:
groovy
stage('Upload
to Nexus') { steps { script { def artifactPath =
"target/your-artifact.jar" nexusArtifactUploader( nexusVersion: 'nexus3', protocol: 'http', nexusUrl:
'nexus.example.com', groupId: 'com.example', artifactId: 'your-artifact', version: env.APP_VERSION, repository: 'releases', file: artifactPath ) } } } |
Option 2: Pass Version as a Jenkins Parameter
- Add
a parameter to the Jenkins job:
- Go
to the job configuration.
- Check
"This project is parameterized."
- Add
a "String Parameter" named VERSION.
- Access
the parameter in the pipeline:
groovy
pipeline { parameters { string(name: 'VERSION', defaultValue:
'1.0.0', description: 'Application version') } stages { stage('Upload to Nexus') { steps { script { def artifactPath =
"target/your-artifact.jar" nexusArtifactUploader( nexusVersion:
'nexus3', protocol: 'http', nexusUrl:
'nexus.example.com', groupId:
'com.example', artifactId:
'your-artifact', version:
params.VERSION, repository:
'releases', file: artifactPath ) } } } } } |
Option 3: Generate Version Dynamically
You can generate the version dynamically based on a
timestamp or Git commit hash.
groovy
stage('Determine
Version') { steps { script { def timestamp = new
Date().format("yyyyMMddHHmmss") env.APP_VERSION =
"1.0.0-${timestamp}" echo "Generated version is:
${env.APP_VERSION}" } } } |
Use env.APP_VERSION wherever the version is required.
Final Pipeline with Dynamic Version
Here's a complete example combining Option 1 and Option 2:
groovy
pipeline { agent any parameters { string(name: 'VERSION', defaultValue:
'', description: 'Specify application version (leave blank to use pom.xml
version)') } stages { stage('Determine Version') { steps { script { if (params.VERSION) { env.APP_VERSION =
params.VERSION } else { def pom =
readMavenPom file: 'pom.xml' env.APP_VERSION = pom.version } echo "Using
application version: ${env.APP_VERSION}" } } } stage('Upload to Nexus') { steps { script { def artifactPath =
"target/your-artifact.jar" nexusArtifactUploader( nexusVersion:
'nexus3', protocol: 'http', nexusUrl:
'nexus.example.com', groupId:
'com.example', artifactId:
'your-artifact', version:
env.APP_VERSION, repository:
'releases', file: artifactPath ) } } } } } |
This approach ensures flexibility while maintaining
consistency across builds.
3) CI/CD pipeline using Maven to
extract version, groupId and artifactId
To make the version, groupId, and artifactId dynamic in your
CI/CD pipeline, you can extract these values from the Maven pom.xml file using
Jenkins' Pipeline Utility Steps Plugin. Here's how you can achieve this:
Extract Dynamic Values from pom.xml
Use the readMavenPom step to read the pom.xml and extract
groupId, artifactId, and version.
Pipeline Example
groovy
pipeline { agent any tools { maven 'Maven_3.8.6' // Specify your
Maven installation jdk 'JDK_11' // Specify your JDK installation } environment { NEXUS_URL =
'http://nexus.example.com/repository/releases/' // Replace with your Nexus
URL } stages { stage('Extract Metadata') { steps { script { // Read pom.xml def pom = readMavenPom
file: 'pom.xml' // Extract values env.GROUP_ID = pom.groupId env.ARTIFACT_ID =
pom.artifactId env.VERSION = pom.version echo "Group ID:
${env.GROUP_ID}" echo "Artifact ID:
${env.ARTIFACT_ID}" echo "Version:
${env.VERSION}" } } } stage('Build') { steps { sh 'mvn clean install' } } stage('Upload to Nexus') { steps { script { def artifactPath = "target/${env.ARTIFACT_ID}-${env.VERSION}.jar" nexusArtifactUploader( nexusVersion:
'nexus3', protocol: 'http', nexusUrl:
'nexus.example.com', groupId: env.GROUP_ID, artifactId:
env.ARTIFACT_ID, version: env.VERSION, repository:
'releases', file: artifactPath ) } } } } post { success { echo 'Pipeline completed
successfully!' } failure { echo 'Pipeline failed. Please
check the logs.' } } } |
Key Steps Explained
- Extract Metadata:
- Use readMavenPom to read
pom.xml.
- Extract the groupId,
artifactId, and version dynamically.
- Dynamic Artifact Path:
- Use
${env.ARTIFACT_ID}-${env.VERSION}.jar to construct the artifact path
dynamically based on extracted values.
- Nexus Upload:
- Pass groupId,
artifactId, and version dynamically to nexusArtifactUploader.
Prerequisites
- Jenkins Plugins:
- Install the Pipeline
Utility Steps Plugin for readMavenPom.
- Install the Nexus
Artifact Uploader Plugin.
- Maven Project:
- Ensure your pom.xml has
valid groupId, artifactId, and version fields.
- Jenkins Credentials:
- Add Nexus credentials in
Jenkins for secure uploads.
4) CI/CD pipeline using Maven with
Veracode scan setup
Adding Veracode Scan to the CI/CD pipeline further
enhances security by performing advanced application security testing. Below is
a detailed CI/CD pipeline setup integrating Maven, Git, Jenkins,
Jenkinsfile, SonarQube, Security Scan (OWASP
Dependency-Check), Veracode Scan, Nexus, and Groovy Script.
Step 1: Prerequisites
- Jenkins:
Install and configure Jenkins with these plugins:
Ø
Git Plugin
Ø
Maven Integration Plugin
Ø
Pipeline Plugin
Ø
SonarQube Scanner Plugin
Ø
OWASP Dependency-Check Plugin
Ø
Veracode Jenkins Plugin
Ø
Nexus Artifact Uploader Plugin
- SonarQube:
Set up SonarQube server and generate an API token.
- Veracode:
Configure Veracode credentials and API keys.
- Maven
Project:
Ø
Ensure pom.xml is configured with required
dependencies.
- Nexus:
Install and configure Nexus as a repository for artifacts.
Step 2: Design the CI/CD Pipeline
The pipeline includes these stages:
- Clone
Repository: Fetch code from Git.
- Build:
Compile the application using Maven.
- Unit
Tests: Execute tests with Maven.
- Static
Code Analysis: Analyze code quality using SonarQube.
- Security
Scans:
Ø
OWASP Dependency-Check
Ø
Veracode Scan
- Upload
Artifact: Publish the build artifact to Nexus.
Step 3: Jenkinsfile with Veracode Integration
groovy
pipeline { agent any tools { maven 'Maven_3.8.6' // Specify Maven
version jdk 'JDK_11' // Specify JDK version } environment { SONAR_TOKEN =
credentials('sonarqube-token') // SonarQube token from Jenkins credentials VERACODE_CREDENTIALS =
credentials('veracode-api-key') // Veracode credentials (ID and Key) NEXUS_URL =
'http://nexus.example.com/repository/releases/' // Nexus URL } stages { stage('Clone Repository') { steps { git branch: 'main', url:
'https://github.com/your-repo/project.git' } } stage('Build') { steps { sh 'mvn clean install' } } stage('Unit Tests') { steps { sh 'mvn test' } } stage('Code Quality Analysis') { steps { withSonarQubeEnv('SonarQube')
{ sh 'mvn sonar:sonar
-Dsonar.projectKey=your_project_key -Dsonar.login=$SONAR_TOKEN' } } } stage('Security Scan - Dependency
Check') { steps { script { sh 'mvn org.owasp:dependency-check-maven:check' } archiveArtifacts artifacts:
'**/dependency-check-report.html', allowEmptyArchive: true echo "Dependency-Check
completed. Report archived." } } stage('Security Scan - Veracode') { steps { script {
veracodeApplicationAnalysis( credentialsId:
'veracode-api-key', // Veracode credentials in Jenkins appName: 'Your
Application', // Replace with your
Veracode app name sandboxName:
'Default', // Optional:
Specify sandbox fileNamePattern:
'**/*.jar', // Artifacts to scan createProfile: false, scanType: 'STATIC', waitForCompletion:
true ) } echo "Veracode scan
completed." } } stage('Upload to Nexus') { steps { script { def pom = readMavenPom
file: 'pom.xml' def artifactPath =
"target/${pom.artifactId}-${pom.version}.jar" nexusArtifactUploader( nexusVersion:
'nexus3', protocol: 'http', nexusUrl:
'nexus.example.com', groupId: pom.groupId, artifactId:
pom.artifactId, version: pom.version, repository:
'releases', file: artifactPath ) } } } } post { success { echo 'Pipeline completed
successfully!' } failure { echo 'Pipeline failed. Check the
logs for details.' } } } |
Step 4: Explanation of Stages
- Clone
Repository:
Ø
Fetch the latest code from Git.
- Build:
Ø
Build and package the application using Maven.
- Unit
Tests:
Ø
Run unit tests using Maven.
- Code
Quality Analysis:
Ø
Perform static code analysis using SonarQube.
- Security
Scan - Dependency Check:
Ø
Scan for known vulnerabilities using OWASP
Dependency-Check.
- Security
Scan - Veracode:
Ø
Upload the built artifact (e.g., JAR) to
Veracode for a comprehensive security scan.
- Upload
to Nexus:
Ø
Publish the artifact dynamically to the Nexus
repository.
Step 5: Prerequisites for Veracode Integration
- Configure
Veracode API Key:
Ø
Add Veracode API credentials (ID and Key) to
Jenkins:
ü
Go to Manage Jenkins > Credentials >
System > Global credentials.
ü
Add Veracode credentials.
- Verify
Veracode Plugin:
Ø
Install the Veracode Jenkins Plugin.
Ø
Configure the Veracode credentials in Jenkins.
- Define
Veracode Application:
Ø
Ensure the application exists in Veracode for
the scan.
Step 6: Running the Pipeline
- Commit
the Jenkinsfile to your Git repository.
- Create
a new Jenkins Pipeline job:
Ø
Link it to your Git repository and branch.
- Trigger
the pipeline and monitor its execution in Jenkins.
Key Benefits of This Pipeline
Ø Automation:
Fully automates build, test, code quality, and security scans.
Ø Dynamic
Artifact Handling: Automatically fetches groupId, artifactId, and version
from pom.xml.
Ø Comprehensive
Security: Leverages OWASP Dependency-Check and Veracode for enhanced
security.
Ø Artifact
Management: Stores artifacts in Nexus for easy distribution.
5) CI/CD pipeline using Maven with
dependencyManagement
Understanding <dependencyManagement> in Maven
The <dependencyManagement> section in Maven is a
powerful feature that allows you to centrally manage dependency versions
and scope declarations for a project and its submodules (in a
multi-module project). It helps maintain consistency and avoid version
conflicts across multiple modules.
Key Points
- Centralized
Version Control:
- Versions
for dependencies are specified in the <dependencyManagement>
section.
- Child
modules can inherit these versions without specifying them explicitly.
- Dependency
Declaration:
- Dependencies
listed in <dependencyManagement> are not included in the build
unless they are explicitly added in a module’s <dependencies>
section.
- Scope
Inheritance:
- Dependency
scope (e.g., compile, test, provided) can also be managed and inherited.
- Overrides:
- It
allows overriding transitive dependencies' versions to ensure consistent
versions across the project.
Structure of <dependencyManagement>
xml
<dependencyManagement> <dependencies> <dependency>
<groupId>com.example</groupId>
<artifactId>my-library</artifactId>
<version>1.0.0</version> <!-- Version managed here
--> </dependency> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.10</version>
<scope>compile</scope> </dependency> </dependencies> </dependencyManagement> |
How It Works
- Parent
pom.xml:
- Place
the <dependencyManagement> section in the parent POM file.
xml
<project>
<groupId>com.example</groupId> <artifactId>parent-project</artifactId> <version>1.0.0</version> <packaging>pom</packaging> <modules> <module>module-a</module> <module>module-b</module> </modules> <dependencyManagement> <dependencies> <dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1.1-jre</version> </dependency> </dependencies> </dependencyManagement> </project> |
- Child
Module POM (module-a):
- The
child module does not need to specify the version for guava. It inherits
the version from the parent POM.
xml
<project> <parent>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId> <version>1.0.0</version> </parent> <dependencies> <dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId> <!-- Version inherited
--> </dependency> </dependencies> </project> |
Benefits of <dependencyManagement>
- Consistency:
- Ensures
all modules use the same version of a dependency.
- Simplified
Child POMs:
- Reduces
boilerplate by allowing child modules to omit the version.
- Conflict
Resolution:
- Overrides
transitive dependency versions to prevent mismatches.
- Centralized
Updates:
- Changing
a version in the parent POM updates it for all child modules.
Difference Between <dependencyManagement> and
<dependencies>
Feature |
<dependencyManagement> |
<dependencies> |
Purpose |
Define dependency versions and scope
for inheritance. |
Include specific dependencies in the
build. |
Automatic Inclusion |
No, child modules must explicitly
declare the dependency. |
Yes, dependencies are automatically
included. |
Use in Parent POM |
Typically used in parent POMs for
centralized version control. |
Directly adds dependencies for the
current project. |
Scope Inheritance |
Yes, can define default scopes for
dependencies. |
No, scope is only applicable to the
current project. |
Example with Transitive Dependency Version Conflict
Problem:
Suppose two dependencies pull different versions of the same
transitive dependency, causing a conflict:
xml
<dependencies> <dependency>
<groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.3.10</version> </dependency> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId> <version>5.3.9</version> </dependency> </dependencies> |
Solution:
Use <dependencyManagement> to specify a unified
version:
xml
<dependencyManagement> <dependencies> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.10</version> </dependency> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.10</version> </dependency> </dependencies> </dependencyManagement> |
Best Practices
- Use
<dependencyManagement> in parent POMs for multi-module projects.
- Define
only versions and scopes; avoid adding unnecessary dependencies.
- Regularly
update the managed versions to include the latest security patches.
- Use
dependency management to resolve transitive dependency conflicts.
CI/CD pipeline using Maven |
For Tools information, visit:
Ø
Auto-Update
Batch File with Latest JAR & Start App Automatically
Ø
Connectingto IBM WebSphere MQ in Java
Ø
How
to create maven project
Ø
VisualVM
monitoring like jconsole
Ø
Stylus
studio convert edifact message
Ø
JConsole
Monitoring for Java Standalone or Web application project
Ø Apache
Cluster router load balancer
Ø
Generate
a Token in Sonatype Nexus & Use It in Maven & Jenkins
Ø
CI/CD
Pipeline in Jenkins: Staging & Production Artifact Flow in java app
0 Comments