Java Spring Continuous Integration#
This guide shows you how to use Semaphore to set up a continuous integration (CI) pipeline for a Java Spring application.
Demo project#
Semaphore maintains an example Java Spring project:
In the repository you will find an annotated Semaphore configuration file
.semaphore/semaphore.yml
.
The application uses Spring Boot, Maven, JUnit for unit and integration tests, JMeter for performance testing, and Docker for deployment.
Overview of the CI/CD pipeline#
The Semaphore pipeline performs the following tasks:
- Build the project
- Run unit and integration tests in parallel
- Run performance tests
- Build Docker image
- Push image to a container registry
Sample configuration#
The entry pipeline performs build and test steps:
# .semaphore/semaphore.yml
# Use the latest stable version of Semaphore 2.0 YML syntax:
version: v1.0
# Name of your pipeline. In this example we connect two pipelines with
# a promotion, so it helps to differentiate what's the job of each.
name: Java Spring example CI pipeline on Semaphore
# An agent defines the environment in which your code runs.
# It is a combination of one of available machine types and operating
# system images. See:
# https://docs.semaphoreci.com/ci-cd-environment/machine-types/
# https://docs.semaphoreci.com/ci-cd-environment/ubuntu-18.04-image/
agent:
machine:
type: e1-standard-2
os_image: ubuntu1804
# Blocks are the heart of a pipeline and are executed sequentially.
# Each block has a task that defines one or more jobs. Jobs define the
# commands to execute.
# See https://docs.semaphoreci.com/guided-tour/concepts/
blocks:
- name: "Build"
task:
# Set environment variables that your project requires.
# See https://docs.semaphoreci.com/guided-tour/environment-variables-and-secrets/
env_vars:
- name: MAVEN_OPTS
value: "-Dmaven.repo.local=.m2"
jobs:
- name: Build
commands:
# Checkout code from Git repository. This step is mandatory if the
# job is to work with your code.
- checkout
# Restore dependencies from cache, command won't fail if it's
# missing.
# More on caching: https://docs.semaphoreci.com/essentials/caching-dependencies-and-directories/
- cache restore
- mvn -q package jmeter:configure -Dmaven.test.skip=true
# Store the latest version of dependencies in cache,
# to be used in next blocks and future workflows:
- cache store
- name: "Test"
task:
env_vars:
- name: MAVEN_OPTS
value: "-Dmaven.repo.local=.m2"
# This block runs two jobs in parallel and they both share common
# setup steps. We can group them in a prologue.
# See https://docs.semaphoreci.com/reference/pipeline-yaml-reference/#prologue
prologue:
commands:
- checkout
- cache restore
- mvn -q test-compile -Dmaven.test.skip=true
jobs:
- name: Unit tests
commands:
- mvn test
- name: Integration tests
commands:
- mvn test -Pintegration-testing
- name: "Performance tests"
task:
env_vars:
- name: MAVEN_OPTS
value: "-Dmaven.repo.local=.m2"
prologue:
commands:
- checkout
- cache restore
jobs:
- name: Benchmark
commands:
- java -version
# Run application in detached mode:
- java -jar target/spring-pipeline-demo.jar > /dev/null &
# Wait for the spring boot application to boot
- sleep 20
- mvn -q jmeter:jmeter
- mvn jmeter:results
# If all tests pass, we move on to build a Docker image.
# This is a job for a separate pipeline which we link with a promotion.
#
# What happens outside semaphore.yml will not appear in GitHub pull
# request status report.
#
# In this example we run docker build automatically on every branch.
# You may want to limit it by branch name, or trigger it manually.
# For more on such options, see:
# https://docs.semaphoreci.com/reference/pipeline-yaml-reference/#promotions
promotions:
- name: Dockerize
pipeline_file: docker-build.yml
auto_promote_on:
- result: passed
The pipeline ends with a promotion which is triggered automatically if all blocks finished successfully.
Authenticate with a Docker registry#
The Docker build pipeline produces a container image and pushes it to a Docker registry. In this case, the registry is Docker Hub, but you can use any other. For pipeline to work, you need to authenticate.
Add your container registry credentials to ./docker-hub-secret.yml
, which is
provided in the repository as a template. The credentials should remain
private, so don't publish them to your Git repository by mistake.
Create a secret on Semaphore so that you can safely export
DOCKER_USERNAME
and DOCKER_PASSWORD
environment variables in your pipeline:
sem create -f docker-hub-secret.yml
The Docker build pipeline#
# .semaphore/docker-build.yml
version: v1.0
name: Docker build
agent:
machine:
# Use a machine type with more RAM and CPU power for faster container
# builds:
type: e1-standard-4
os_image: ubuntu1804
blocks:
- name: "Build"
task:
env_vars:
- name: MAVEN_OPTS
value: "-Dmaven.repo.local=.m2"
- name: ENVIRONMENT
value: "dev"
# Mount a secret which defines DOCKER_USERNAME and DOCKER_PASSWORD
# environment variables.
# For info on creating secrets, see:
# https://docs.semaphoreci.com/guided-tour/environment-variables-and-secrets/
secrets:
- name: docker-hub
prologue:
commands:
- checkout
- cache restore
jobs:
- name: Build and deploy docker container
commands:
- mvn -q package -Dmaven.test.skip=true
# Authenticate with Docker Hub
# using environment variables docker-hub secret:
- echo $DOCKER_PASSWORD | docker login --username "$DOCKER_USERNAME" --password-stdin
# Use docker layer caching and reuse unchanged layers to build a new
# container image faster.
# To do that, we first need to pull a previous version of container:
- docker pull semaphoredemos/semaphore-demo-java-spring:latest || true
# Build a new image based on pulled image, if present.
# You could use $SEMAPHORE_WORKFLOW_ID environment variable to
# produce a unique image tag. For a list of available environment
# variables on Semaphore, see:
# https://docs.semaphoreci.com/ci-cd-environment/environment-variables/
- docker build --cache-from semaphoredemos/semaphore-demo-java-spring:latest --build-arg ENVIRONMENT="${ENVIRONMENT}" -t semaphoredemos/semaphore-demo-java-spring:latest .
# Push a new image to container registry:
- docker push semaphoredemos/semaphore-demo-java-spring:latest
Run the demo project yourself#
A good way to start using Semaphore is to take a demo project and run it yourself. Here’s how to build the demo project with your own account:
- Fork the project on GitHub to your own account.
- Clone the repository on your local machine.
- In Semaphore, follow the link in the sidebar to create a new project.
- Create your secret as per instructions above.
- Edit any file and push GitHub, and Semaphore will run the CI/CD pipeline.