Getting Started with Jenkins Java Client

Jenkins is an open source automation server that reliably builds, tests, and deploys software. Jenkins also comes with its own intuitive UI that allows you to create new jobs, schedule the execution of existing jobs, navigate into defined jobs on the system, and more.

However, occasions may arise when you need to programmatically perform the above functionalities including retrieving information, creating a new job, triggering a new build based on certain conditions, etc.

For requirements and functionalities such as these, Jenkins provides REST-like remote access APIs. Many wrapper projects have also been developed in Python, Ruby, and Java that consume the Jenkins JSON APIs and aim to allow access to all remote APIs that Jenkins provides.

One such Jenkins client project, which is written in Java and makes use of the Jenkins APIs, is jenkins-rest. In this article, I’ll show how to set up and get started using jenkins-rest.

jenkins-rest is a Java client that is built on the top of jclouds for working with Jenkins REST API. jclouds, one of the main components, is used as the backend for communicating with Jenkins REST API.

The following sections describe the following:

  • Setup of jenkins-rest client 
  • Different ways of connecting to Jenkins server using jenkins-rest
  • A comprehensive example showing how to trigger a remote job using jenkins-rest

Maven Setup

The following dependency has to be added to the pom file:

<dependency>

<groupId>io.github.cdancy</groupId>

<artifactId>jenkins-rest</artifactId>

<version>1.0.1</version>

</dependency>

Connecting to Jenkins — Credentials

jenkins-rest can connect to the Jenkins server in one of the following ways:

admin:apiToken:

  • Use JenkinsClient.builder().apiToken("admin:apiToken")

Colon delimited username and password: admin:password:

  • Use JenkinsClient.builder().credentials("admin:password")

Base64 encoded username followed by password or api token:

  • Use JenkinsClient.builder().credentials("password")
  • Use JenkinsClient.builder().apiToken("apiToken")

The following Java method takes Jenkins URL, username, and the token as inputs and returns JenkinsClient.

public JenkinsClient getConnection( String url, String userName, String token) throws IOException {

JenkinsClient client = JenkinsClient.builder().endPoint(url)

.credentials(userName+”:”+token).build();

return client;

}

Example

At a high level, the steps to trigger a job and get its corresponding status are as follows:

  1. Invoke JobsApi build method. IntegerResponse object is returned that contains the queue id number of the submitted job.
  2. Poll the QueueApi queueItem method using the queue id number from the Integer Response. This returns a QueueItem object containing the state of the build in the queue. The state could be one of the following:
    a. Build cancellation before the build even starts (abort the polling, the build will never run)
    b. Build pending (continue to wait or time out
    c. Build executing with a build number (stop polling the queue)
  3. Poll the JobsApi buildInfo method using the QueueItem build number. This step returns a BuildInfo object. When the result method no longer returns null, the build is done. The result method returns a string representing the build status (passed, failed, etc.).

The Java snippet below makes use of the methods from the jenkins-rest library to accomplish the above functionality:

public PipelineBuildInfo build(InputForPipelineExecution buildPipelineReq) throws IOException, InterruptedException {

PipelineBuildInfo pipelineBuildInfo = new PipelineBuildInfo();

pipelineBuildInfo.setPipelineName(buildPipelineReq.getPipelineName());

pipelineBuildInfo.setPipelineId(buildPipelineReq.getPipelineId());

JenkinsClient client = getConnection(buildPipelineReq.getUrl(), buildPipelineReq.getUserName(),

buildPipelineReq.getToken());

IntegerResponse queueId = client.api().jobsApi().build(null, buildPipelineReq.getPipelineName());

if (queueId.errors().size() > 0) {

logger.debug(“The Queue Errors are ->” + queueId.errors());

pipelineBuildInfo.setMessage(queueId.errors().toString());

pipelineBuildInfo.setStatus(PipelineExecutionStatus.Failed.toString());

return pipelineBuildInfo;

}

logger.debug(“Check for the status”);

QueueItem queueItem = client.api().queueApi().queueItem(queueId.value().intValue());

while (true) {

if (queueItem.cancelled()) {

logger.debug(“Job Cancelled”);

pipelineBuildInfo.setMessage(queueItem.why());

pipelineBuildInfo.setStatus(PipelineExecutionStatus.Cancelled.toString());

break;

}

if (queueItem.executable() != null) {

logger.debug(“Build is executing with # = “ + queueItem.executable().number());

break;

}

Thread.sleep(1000);

queueItem = client.api().queueApi().queueItem(queueId.value().intValue());

}

BuildInfo buildInfo = client.api().jobsApi().buildInfo(null, buildPipelineReq.getPipelineName(),

queueItem.executable().number());

while (buildInfo.result() == null) {

Thread.sleep(10000);

buildInfo = client.api().jobsApi().buildInfo(null, buildPipelineReq.getPipelineName(),

queueItem.executable().number());

}

pipelineBuildInfo.setDuration(buildInfo.duration());

pipelineBuildInfo.setBuildNumber(buildInfo.number());

pipelineBuildInfo.setMessage(buildInfo.result());

pipelineBuildInfo.setStatus(PipelineExecutionStatus.Successful.toString());

logger.debug(“Build status: “ + buildInfo.result());

return pipelineBuildInfo;

}

Conclusion

The real power of jenkins-rest lies in combining multiple Jenkins API calls for accomplishing a given use case. A use case to trigger a build would ideally involve the following steps: submit a job, track its progress, and report on the build status, which have been demonstrated in the example shown here.

References

Jenkins-rest GitHub page
Remote Access API

Disclaimer: The views expressed in this article are mine and my employer does not subscribe to the substance or veracity of my views.

FOSSlife Newsetter

Comments