The transition from a legacy Jenkins environment to a modernized GitLab CI/CD framework requires a precise understanding of how pipeline orchestration, job execution, and environment configuration differ between these two ecosystems. In the context of Maven-based Java projects, this migration involves shifting from a Jenkinsfile or freestyle project configuration to a .gitlab-ci.yml definition. This architectural shift is not merely a change in syntax but a move toward a more integrated, version-controlled approach to continuous integration and continuous delivery. When migrating Maven workloads, the primary objective is to maintain the integrity of the build, test, and install lifecycles while leveraging GitLab's native features such as runner executors, global variables, and sophisticated caching mechanisms to optimize the software delivery pipeline.
Jenkins to GitLab CI/CD Migration Paradigms
The migration process is designed to be flexible, as multiple Jenkins configurations—regardless of their specific implementation method—can be consolidated into a single, standardized GitLab CI/CD pipeline configuration. This uniformity ensures that whether a team is moving from a complex declarative pipeline or a simple freestyle project, the end result in GitLab remains consistent.
There are three primary Jenkins configurations typically encountered during this migration process:
- Freestyle with shell execution: This involves using the built-in shell execution option within Jenkins to call
mvncommands directly from the shell on the agent. This approach is functionally similar to utilizing a GitLab Runner with a shell executor. - Freestyle with Maven task plugin: This method employs the Maven plugin in Jenkins to declare and execute specific goals in the Maven build lifecycle. This plugin necessitates that Maven be installed on the Jenkins agent and utilizes a script wrapper for the execution of Maven commands.
- Declarative pipelines: This uses a structured
pipelineblock, often stored in aJenkinsfile, which defines agents, tools (such asmaven-3.6.3andjdk11), and stages. An example of such a configuration includes:
groovy
pipeline {
agent any
tools {
maven 'maven-3.6.3'
jdk 'jdk11'
}
stages {
stage('Build') {
steps {
sh "mvn package -DskipTests"
}
}
stage('Test') {
steps {
sh "mvn test"
}
}
stage('Install') {
steps {
sh "mvn install -DskipTests"
}
}
}
}
Regardless of which of these three methods was previously utilized, they can all be migrated to GitLab CI/CD using a unified pipeline configuration that mimics the behavior and syntax of building, testing, and installing.
Technical Prerequisites for Pipeline Execution
To successfully execute a Maven pipeline in GitLab, specific infrastructure requirements must be met. These prerequisites ensure that the environment has the necessary binaries and runtime environments to compile Java code and manage dependencies.
- A GitLab Runner with a Shell executor: This allows the pipeline to execute commands directly on the host machine's shell.
- Maven 3.6.3: This specific version of the Maven build tool must be installed on the shell runner.
- Java 11 JDK: The Java Development Kit version 11 must be present on the shell runner to provide the necessary compiler and runtime environment.
For users leveraging GitLab.com, these prerequisites can be managed by utilizing public instance runners, which provide a managed environment, reducing the need for self-hosted infrastructure.
Anatomizing the .gitlab-ci.yml Configuration
The .gitlab-ci.yml file serves as the blueprint for the entire CI/CD process. In a migrated Maven configuration, the structure consists of global keywords followed by specific job definitions.
Global Configuration Keywords
Global keywords define the environment and the sequence of execution for all jobs within the pipeline.
Stages
The stages keyword defines the logical grouping of jobs. In the Maven migration example, three stages are defined:
- build
- test
- install
These stages run in a strict sequential order. This means that all jobs assigned to the build stage must complete successfully before any jobs in the test stage begin, and similarly, the test stage must finish before the install stage commences.
Variables
The variables section defines CI/CD variables that are globally accessible to all jobs in the pipeline. This ensures consistency across different execution environments and simplifies the management of Maven flags.
The following variables are critical for Maven operations:
MAVEN_OPTS: These are Maven environment variables required whenever Maven is executed.
- -Dhttps.protocols=TLSv1.2: This setting forces the TLS protocol to version 1.2 for all HTTP requests made during the pipeline, ensuring secure communication with remote repositories.
- -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository: This command redirects the local Maven repository to a specific directory within the GitLab project directory on the runner. This is essential because it allows the job to access and modify the repository within the project's own workspace.
MAVEN_CLI_OPTS: These are specific arguments added to the mvn command line.
- -DskipTests: This flag is used to skip the test stage during the Maven build lifecycle, which is particularly useful during the build and install phases to reduce execution time when tests are handled by a dedicated job.
Default Configuration
In advanced configurations, a default keyword is used to standardize the environment across jobs. This includes:
- image:
maven:3.6.3-openjdk-11(Specifies the Docker image to use for the job). - cache: This is used to optimize pipeline speed. By defining a cache key as
$CI_COMMIT_REF_SLUGand setting the path to.m2/, the pipeline avoids the catastrophic time loss of re-installing all dependencies from scratch between every single job run.
Detailed Job Definitions
Jobs are the smallest units of work in a GitLab pipeline. Each job is assigned to a stage and contains a script that defines the actual shell commands to be executed.
Build Job: build-JAR
The build-JAR job is assigned to the build stage. Its purpose is to compile the code and create the primary artifact.
- Stage:
build - Script:
mvn $MAVEN_CLI_OPTS package
By using the $MAVEN_CLI_OPTS variable, this job executes the package goal while skipping tests, ensuring that the build is focused solely on artifact creation.
Test Job: test-code
The test-code job is assigned to the test stage. This is the critical quality assurance phase where the codebase is validated.
- Stage:
test - Script:
mvn test
Unlike the build job, this job does not use the skipTests flag, as the primary purpose of this stage is to execute the Maven test suite.
Install Job: install-JAR
The install-JAR job is assigned to the install stage. This represents the final phase of the local build lifecycle.
- Stage:
install - Script:
mvn $MAVEN_CLI_OPTS install
This job utilizes the install goal to move the packaged artifact into the local repository, again utilizing $MAVEN_CLI_OPTS to avoid redundant test execution.
Summary of Pipeline Components
The following table provides a structured overview of the Maven migration configuration.
| Component | GitLab Keyword | Value/Command | Purpose |
|---|---|---|---|
| Pipeline Stage 1 | stages |
build |
Initial compilation and packaging |
| Pipeline Stage 2 | stages |
test |
Execution of the test suite |
| Pipeline Stage 3 | stages |
install |
Deployment to local repository |
| Maven Env Var | variables |
MAVEN_OPTS |
TLS 1.2 and local repo path |
| Maven CLI Var | variables |
MAVEN_CLI_OPTS |
Skipping tests (-DskipTests) |
| Docker Image | default |
maven:3.6.3-openjdk-11 |
Standardized build environment |
| Cache Path | cache |
.m2/ |
Dependency persistence |
Broader GitLab CI/CD Ecosystem and Use Cases
Beyond basic Maven migrations, GitLab CI/CD provides a vast array of examples and resources applicable across various tiers (Free, Premium, and Ultimate) and offerings (GitLab.com, Self-Managed, and Dedicated).
The platform supports a wide range of specialized implementation patterns:
- Deployment with Dpl: Using the Dpl tool for application deployment.
- GitLab Pages: Automatic CI/CD deployment for publishing static websites.
- Multi-project pipelines: Architecting complex workflows that build, test, and deploy across multiple interdependent projects.
- npm with semantic-release: Managing the publication of npm packages specifically to the GitLab package registry.
- Composer and npm with SCP: Utilizing Secure Copy Protocol (SCP) to deploy scripts.
- PHP with PHPUnit and atoum: Specialized testing frameworks for PHP projects.
- Secrets management with Vault: Integrating HashiCorp Vault to authenticate and securely read sensitive secrets during the pipeline execution.
Additionally, the GitLab ecosystem includes community-contributed examples, which provide a wider range of implementation strategies maintained by the user community rather than directly by GitLab.
Analysis of the Migration Impact
The shift from Jenkins to GitLab CI/CD for Maven projects results in a more transparent and maintainable infrastructure. In Jenkins, the configuration is often fragmented between the UI (for freestyle projects) or a separate Jenkinsfile. GitLab consolidates this into the .gitlab-ci.yml file, which lives alongside the source code.
The use of the shell executor in GitLab provides a direct parallel to Jenkins' agent-based execution. However, the introduction of the default image and cache keywords allows teams to move toward containerized builds. By caching the .m2/ directory, the pipeline significantly reduces the "cold start" time of jobs, as Maven does not need to download the same set of dependencies from Maven Central for every stage.
The logical flow—Build, then Test, then Install—ensures that resources are not wasted on testing a build that cannot be compiled, and artifacts are not installed into the repository if the tests fail. This sequential dependency is the cornerstone of an efficient CI/CD pipeline.