DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Java CI/CD: From Local Build to Jenkins Continuous Integration
  • Recipe To Implement the Jenkins Pipeline For MuleSoft Application [Videos]
  • Enterprise RIA With Spring 3, Flex 4 and GraniteDS
  • CI/CD: 5 Simple Steps To Deploy a Mule 4 Application in CloudHub Using Jenkins and GitHub

Trending

  • Transforming AI-Driven Data Analytics with DeepSeek: A New Era of Intelligent Insights
  • Build Your First AI Model in Python: A Beginner's Guide (1 of 3)
  • Streamlining Event Data in Event-Driven Ansible
  • How Large Tech Companies Architect Resilient Systems for Millions of Users
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Deployment
  4. Using Jenkins and Java for Continuous Integration

Using Jenkins and Java for Continuous Integration

By 
Jimena Garbarino user avatar
Jimena Garbarino
·
Apr. 29, 20 · Tutorial
Likes (17)
Comment
Save
Tweet
Share
17.9K Views

Join the DZone community and get the full member experience.

Join For Free

This tutorial will teach you about:

  • Pipeline configuration using a Jenkinsfile
  • Managing third-party credentials
  • Jenkins test reports integration
  • Poll and hook build triggers
  • Building pull requests

But first, let’s talk about Continuous Integration (CI). CI is a popular development practice that works as you validate—making sure software is high quality and deployable, as soon as you check in changes to the SCM. 

There are a few key pieces that need to be in place in order to adopt CI: 

  •  SCM system like Git and a shared repository
  • A CI server (like Jenkins)
  • Automated tests
  • Teamwork CI practices that allow you to keep build times short, fix broken builds immediately, make frequent commits, and keep changes small

Required tools:

  • Docker
  • Java 8

Running Jenkins

Jenkins is an open-source automation server developers can use for Continuous Integration, Continuous Delivery and Continuous Deployment. It is a fork from Hudson, a CI server written in Java at Sun Microsystems in 2004.

The Jenkins Pipeline is a suite of plugins you can use to automate builds, tests, and deployment. You can define the pipeline with specific syntax in a Jenkinsfile, which you can commit to a project’s repository and version, in a Pipeline-as-code model.

For a quick start, pull the Jenkins image from Docker HYub:

Shell
 




xxxxxxxxxx
1


 
1
docker pull jenkins/jenkins:lts


Then start a Jenkins container:

Shell
 




xxxxxxxxxx
1


 
1
docker run \
2
  -p 8081:8080 \
3
  -p 50000:50000 \
4
  --name my-jenkins \
5
  -v jenkins_data:/var/jenkins_home
6
  jenkins/jenkins:lts


In the command above, we mapped Jenkins port 8080 to the host port 8081 and Jenkins port 50000 to the host port 50000. We also defined a volume for the Jenkins home, in the host folder jenkins_data.

When the container starts, the initial installation will run, and Jenkins will log the admin password:

Plain Text
 




xxxxxxxxxx
1


 
1
Jenkins initial setup is required. An admin user has been created and a password generated.
2
Please use the following password to proceed to installation:
3

          
4
b518968d266d41d3beb0abef50834fa7
5

          
6
This may also be found at: /var/jenkins_home/secrets/initialAdminPassword


Copy the password and go to http://localhost:8081 to do the initial setup.

Paste the administrator password and continue. The setup process will give you the choice to customize the plugins you want to add. Choose Install Suggested Plugins and continue. Wait for the installation to complete.

Set the admin user data and continue. As this is a test, leave the default Jenkins URL (http://localhost:8081/) and finish it.

We are ready to create the first Jenkins Pipeline.

Simple Application with Okta OIDC Authentication

We are going to use Jenkins to automate the build of a simple Java application with Okta OIDC authentication, so let’s first create the app with Spring Intializr:

Shell
 




xxxxxxxxxx
1


 
1
curl https://start.spring.io/starter.zip -d dependencies=web,okta \
2
-d language=java \
3
-d type=maven-project \
4
-d groupId=com.okta.developer \
5
-d artifactId=simpleapp  \
6
-d name="Simple Application" \
7
-d description="Demo project for Jenkins CI test" \
8
-d packageName=com.okta.developer.simpleapp \
9
-o simple-app.zip


Unzip the file:

Shell
 




xxxxxxxxxx
1


 
1
unzip simple-app.zip -d simple-app
2
cd simple-app


If you don’t have an Okta developer account already, execute the Okta Maven Plugin to create one (for free!) and configure the authentication in the app:

Plain Text
 




xxxxxxxxxx
1


 
1
./mvnw com.okta:okta-maven-plugin:setup


You should see the following output:

Plain Text
 




xxxxxxxxxx
1
12


 
1
First name: Jimena
2
Last name: Garbarino
3
Email address: ***
4
Company: ***
5
Creating new Okta Organization, this may take a minute:
6
OrgUrl: ***
7
Check your email address to verify your account.
8

          
9
Writing Okta SDK config to: /home/indiepopart/.okta/okta.yaml
10

          
11
Configuring a new OIDC, almost done:
12
Created OIDC application, client-id: ***


Check your email and follow the instructions to activate your Okta account.

The Maven plugin will generate the OIDC client ID, secret, and issuer URL in src/main/resources/application.properties. As we are going to use a public GitHub repository for the CI test, copy the credentials somewhere else, and delete them from the properties file.

If you already have an Okta Developer account, sign in and create a new application: - From the Applications page, choose Add Application. - On the Create New Application page, select Web. - Give your app a memorable name, and add http://localhost:8080/login/oauth2/code/okta as Login redirect URIs.

Copy the issuer (you can find it under API > Authorization Servers), client ID, and client secret for later.

Add A REST Controller

Create a GreetingController class to greet the user on login.

Java
 




xxxxxxxxxx
1
16


 
1
package com.okta.developer.simpleapp;
2

          
3
import org.springframework.security.core.annotation.AuthenticationPrincipal;
4
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
5
import org.springframework.web.bind.annotation.GetMapping;
6
import org.springframework.web.bind.annotation.RestController;
7

          
8
@RestController
9
public class GreetingController {
10

          
11

          
12
    @GetMapping("/greeting")
13
    public String greet(@AuthenticationPrincipal OidcUser user){
14
        return "Hello " + user.getEmail();
15
    }
16
}


Test the application with the Maven Spring Boot plugin:

Java
 




xxxxxxxxxx
1


 
1
OKTA_OAUTH2_CLIENT_ID={youtOktaClientId} \
2
OKTA_OAUTH2_CLIENT_SECRET={yourOktaClientSecret} \
3
OKTA_OAUTH2_ISSUER={yourOktaDomain}/oauth2/default \
4
mvn spring-boot:run


Go to http://localhost:8080/greeting. The app should redirect to Okta for the login:

After the login, the app should display the greeting response:

Plain Text
 




xxxxxxxxxx
1


 
1
Hello jimena@***.com


Create a GitHub public repository for the simple-app and follow the instructions to push your existing code.

Shell
 




xxxxxxxxxx
1


 
1
git init
2
git add .
3
git commit -m "initial commit"
4
git remote add origin https://github.com/<your-username>/simple-app.git
5
git push -u origin master


Jenkins Pipeline and the Jenkinsfile

In the Jenkins dashboard, select Create New Jobs, set simple-app as the item name, and select Pipeline as the project type.

In the next screen, select the tab Advanced Project Options. From the drop-down menu on the right, select GitHub + Maven to get the Jenkinsfile template we are going to customize.

Copy the pipeline script to a file in the root of the simple-app project named Jenkinsfile. Update the GitHub repository URL and set up the Okta credentials for the build. Also change the Maven command to use the wrapped Maven in the project.

Groovy
 




xxxxxxxxxx
1
34


 
1
pipeline {
2
   agent any
3

          
4
   environment {
5
       // use your actual issuer URL here and NOT the placeholder {yourOktaDomain}
6
       OKTA_OAUTH2_ISSUER           = '{yourOktaDomain}/oauth2/default'
7
       OKTA_OAUTH2_CLIENT_ID        = credentials('OKTA_OAUTH2_CLIENT_ID')
8
       OKTA_OAUTH2_CLIENT_SECRET    = credentials('OKTA_OAUTH2_CLIENT_SECRET')
9
   }
10

          
11
   stages {
12
      stage('Build') {
13
         steps {
14
            // Get some code from a GitHub repository
15
            git 'https://github.com/<your-username>/simple-app.git'
16

          
17
            // Run Maven on a Unix agent.
18
            sh "./mvnw -Dmaven.test.failure.ignore=true clean package"
19

          
20
            // To run Maven on a Windows agent, use
21
            // bat "mvn -Dmaven.test.failure.ignore=true clean package"
22
         }
23

          
24
         post {
25
            // If Maven was able to run the tests, even if some of the test
26
            // failed, record the test results and archive the jar file.
27
            success {
28
               junit '**/target/surefire-reports/TEST-*.xml'
29
               archiveArtifacts 'target/*.jar'
30
            }
31
         }
32
      }
33
   }
34
}


We are using the environment directive of the pipeline syntax to define the OKTA_* variables the build requires. The directive supports a credentials() helper to retrieve the values from the Jenkins environment.

Then, before requesting a project build, we need to set up the Okta managed credentials in Jenkins.

Push the Jenkinsfile to the public repository.

In the Advanced Project Options, for the Pipeline Definition, select Pipeline script from SCM and complete the repository information:

  • SCM: GitHub
  • Repository URL: https://github.com/<your-username>/simple-app.git
  • Credentials: none
  • Branch Specifier: \*/master
  • Script Path: Jenkinsfile

Click Save to create the project.

Credential Management

Jenkins allows you to store credentials for third-party applications securely, allowing Pipeline projects to use them for the interactions with these third-party services. Let’s add the credentials for Okta authentication.

In the Jenkins Dashboard, go to Credentials on the left menu, then choose global.

Create a "Secret text" credential for the OKTA_OAUTH2_CLIENT_ID, click Add Credentials, and select the following options:

  • Kind: Secret text
  • Scope: global
  • Secret: {yourOktaClientID}
  • ID: OKTA_OAUTH2_CLIENT_ID

Note: Replace {yourOktaClientID} with your actual Client ID.

Do the same for OKTA_OAUTH2_CLIENT_SECRET.

Note: Storing secrets in Jenkins and building pull-requests from forked repositories should not be used together. Building pull requests from outside of your organization is the same as executing arbitrary code, and needs to be done with great care and is outside the scope of this article.

Now we are ready to build the project. Go to simple-app and select Build Now. Go to the Build History and select the build #1. Then select the option Console Output to monitor the task.

Add a Controller Test

The Jenkinsfile template for GitHub and Maven already integrates test reports and makes them accessible from the build summary. Let’s add a controller test in the app to verify this feature.

Add spring-security-test dependency to the pom.xml:

XML
 




xxxxxxxxxx
1


 
1
<dependency>
2
  <groupId>org.springframework.security</groupId>
3
  <artifactId>spring-security-test</artifactId>
4
  <scope>test</scope>
5
</dependency>


Create a new class: src/test/java/com/okta/developer/simpleapp/GreetingControllerTest.java:

Java
 




xxxxxxxxxx
1
69


 
1
package com.okta.developer.simpleapp;
2

          
3
import org.junit.jupiter.api.Test;
4
import org.springframework.beans.factory.annotation.Autowired;
5
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
6
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
7
import org.springframework.security.core.GrantedAuthority;
8
import org.springframework.security.core.authority.SimpleGrantedAuthority;
9
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
10
import org.springframework.security.oauth2.core.oidc.OidcIdToken;
11
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
12
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
13
import org.springframework.test.context.ContextConfiguration;
14
import org.springframework.test.web.servlet.MockMvc;
15
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
16

          
17
import java.time.Instant;
18
import java.util.ArrayList;
19
import java.util.Collection;
20
import java.util.HashMap;
21
import java.util.Map;
22

          
23
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
24
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
25
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
26

          
27
@AutoConfigureMockMvc
28
@WebMvcTest
29
@ContextConfiguration(classes={GreetingController.class})
30
public class GreetingControllerTest {
31

          
32
    private final static String ID_TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9" +
33
            ".eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsIm" +
34
            "p0aSI6ImQzNWRmMTRkLTA5ZjYtNDhmZi04YTkzLTdjNmYwMzM5MzE1OSIsImlhdCI6MTU0M" +
35
            "Tk3MTU4MywiZXhwIjoxNTQxOTc1MTgzfQ.QaQOarmV8xEUYV7yvWzX3cUE_4W1luMcWCwpr" +
36
            "oqqUrg";
37

          
38

          
39
    @Autowired
40
    private MockMvc mvc;
41

          
42
    @Test
43
    void testGreet() throws Exception {
44
        OidcIdToken idToken = createOidcToken();
45
        this.mvc.perform(get("/greeting")
46
                .with(authentication(createMockOAuth2AuthenticationToken(idToken))))
47
                .andExpect(MockMvcResultMatchers.status().isOk())
48
                .andExpect(content().string("Hello user@email.com"));
49
    }
50

          
51
    private OAuth2AuthenticationToken createMockOAuth2AuthenticationToken(OidcIdToken idToken) {
52
        Collection<GrantedAuthority> authorities = new ArrayList<>();
53
        authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
54
        OidcUser user = new DefaultOidcUser(authorities, idToken);
55

          
56
        return new OAuth2AuthenticationToken(user, authorities, "oidc");
57
    }
58

          
59

          
60
    private OidcIdToken createOidcToken(){
61
        Map<String, Object> claims = new HashMap<>();
62
        claims.put("groups", "ROLE_USER");
63
        claims.put("email", "user@email.com");
64
        claims.put("sub", 123);
65
        OidcIdToken idToken = new OidcIdToken(ID_TOKEN, Instant.now(),
66
                Instant.now().plusSeconds(60), claims);
67
        return idToken;
68
    }
69
}


Push the changes to the repository and schedule a new build. Once it completes, you can see the Test Results at the global or package level:

Polling for Changes

Pipelines support several types of triggers to schedule the builds. One of them periodically polls the SCM System (GitHub) for changes. If a new change exists, it will re-trigger the Pipeline. The triggers directive in the Jenkinsfile configures the build triggers:

Groovy
 




xxxxxxxxxx
1


 
1
pipeline {
2
   agent any
3

          
4
   triggers { pollSCM('H/15 * * * *
5
') } // poll every 15 minutes
6

          
7
   environment {
8
...


The trigger type pollSCM has a cron expression that configures the pipeline to poll GitHub every 15 minutes.

Note: To install the trigger in Jenkins, you must first schedule a manual build from Jenkins, after pushing the updated Jenkinsfile.

Multibranch Pipelines

Multibranch Pipeline projects discover Pipelines for branches automatically and can be used to validate pull requests. The GitHub Branch Source plugin provides the validation functionality, and Cloudbees hosts its documentation. You installed these features with the suggested plugins, so let’s walk through the configuration.

In the Jenkins dashboard, go to New Item, type an item name, and then choose Multibranch Pipeline. Then, in the configuration form, go to Branch Sources and choose GitHub. Select the option Repository Scan. In the Owner field, set your GitHub user, and select the repository to scan. To simplify this test, we already created a public repository, so we can skip the GitHub credentials setup.

Select the tab Scan Multibranch Pipeline Triggers, tick Periodically if not otherwise run, and set 5 minutes as the interval.

Click Save to add the new project.

Trigger a Build

Create a README.md file in the root folder of the simple-app project:

Markdown
 




xxxxxxxxxx
1
11


 
1
# Simple Application with Okta OIDC Authentication
2

          
3
Clone the project and run the application with Maven:
4
```shell
5
git clone https://github.com/<your-username>/simple-app.git
6
cd simple-api
7
OKTA_OAUTH2_CLIENT_ID={youtOktaClientId} \
8
OKTA_OAUTH2_CLIENT_SECRET={yourOktaClientSecret} \
9
OKTA_OAUTH2_ISSUER={yourOktaDomain}/oauth2/default \
10
./mvnw spring-boot:run
11
```


Create a branch for the change and a pull request. In the next periodic scan, Jenkins will create a job for the pull request.

Shell
 




x


 
1
git checkout -b add-readme
2
git add README.md
3
git commit -m "added readme"
4
git push origin add-readme


The GitHub Branch Source plugin allows you to create a project based on the repository structure of a GitHub organization as well, using the project type "GitHub Organization". For such projects, the plugin will scan and import all or a subset of repositories as jobs, according to a configured criteria.

GitHub Hook Trigger

Jenkins has a GitHub plugin to trigger builds after receiving notifications for push changes and pull requests. Through GitHub Webhooks, when the event is triggered, GitHub will send an HTTP POST payload to the Jenkins webhook’s configured URL. Upon receiving the POST, Jenkins will simply kick the internal polling to the SCM.

You can configure the Jenkins hook’s URL at GitHub manually or Jenkins itself can manage the hooks for the project based on the configuration. For the managed mode, you must also configure authentication to GitHub, and at the moment of writing this tutorial, Jenkins cannot authenticate if you have enabled two-factor authentication in GitHub.

The use of GitHub Webhooks requires that Jenkins must be reachable from the internet. The plugin documentation also mentions the hook URL is unique for all repositories but does not mention any kind of authentication required for the caller side. There are other security implications listed in the documentation that should be evaluated before using this feature.

Learn More

I hope you enjoyed this tutorial and could see the benefits of the Continuous Integration practice and the different options for validating changes as soon as you create them.

To learn more, check out these guides:

  • Add CI/CD to Your Spring Boot App with Jenkins X and Kubernetes
  • Testing Spring Security OAuth
  • GitHub Branch Source Plugin

If you have questions, please leave a comment below. If you liked this tutorial, follow @oktadev on Twitter, follow us on LinkedIn, or subscribe to our YouTube channel.

Continuous Integration/Deployment Jenkins (software) Java (programming language) GitHub Integration Pipeline (software) Repository (version control) Spring Framework application Plain text

Published at DZone with permission of Jimena Garbarino, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Java CI/CD: From Local Build to Jenkins Continuous Integration
  • Recipe To Implement the Jenkins Pipeline For MuleSoft Application [Videos]
  • Enterprise RIA With Spring 3, Flex 4 and GraniteDS
  • CI/CD: 5 Simple Steps To Deploy a Mule 4 Application in CloudHub Using Jenkins and GitHub

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!