Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# EditorConfig is awesome: http://EditorConfig.org

# top-most EditorConfig file
root = true

# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_style = space
indent_size = 2
9 changes: 7 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
target/

pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
Expand All @@ -7,7 +8,11 @@ release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
.idea
jenkins-client.iml

# Exclude maven wrapper
!/.mvn/wrapper/maven-wrapper.jar

# Intellij Idea files
.idea
*.iml

10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,18 @@ Create job:
client.createJob("java-client-job1","https://github.com/wtrocki/helloworld-android-gradle","master");
```

Trigger a job:

```
...
BuildStatus buildStatus = client.build("java-client-job1");
```

## Requirements

Client works with Java6 and above.

## Building

`mvn clean package`
`mvn clean package`

42 changes: 40 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,56 @@
</licenses>

<dependencies>
<!--Compile time-->
<dependency>
<groupId>com.offbytwo.jenkins</groupId>
<artifactId>jenkins-client</artifactId>
<version>0.3.6</version>
<version>0.3.7-SNAPSHOT</version>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do they have a CI running somewhere, where we can suck down the dependency ?
Not a blocker - just asking

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@matzew good point!
I looked now, but couldn't find anything. I checked the pom.xml files in the source code to see some repository reference. There is one, but that's not the snapshot repository.
No mention of CI.

@khmarbaise Where can we suck Jenkins-Java-client SNAPSHOT? Unfortunately, I haven't still got the approval to post to mailing list (https://groups.google.com/d/forum/java-client-api).
As a quick introduction: we are building a mobile application build farm on top of Jenkins 😎

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

</dependency>
<dependency>
<groupId>org.jtwig</groupId>
<artifactId>jtwig-core</artifactId>
<version>5.65</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>

<!--Testing-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.6.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>jcenter</id>
<url>https://jcenter.bintray.com/</url>
</repository>
</repositories>

<build>
<plugins>
<plugin>
Expand All @@ -46,6 +79,11 @@
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
</plugin>
</plugins>
</build>
</project>
</project>
97 changes: 79 additions & 18 deletions src/main/java/com/redhat/digkins/DiggerClient.java
Original file line number Diff line number Diff line change
@@ -1,32 +1,58 @@
package com.redhat.digkins;

import com.offbytwo.jenkins.JenkinsServer;
import com.redhat.digkins.model.BuildStatus;
import com.redhat.digkins.services.CreateJobService;
import com.redhat.digkins.util.JenkinsAuth;
import com.redhat.digkins.services.TriggerBuildService;
import com.redhat.digkins.util.DiggerClientException;
import com.redhat.digkins.util.JenkinsAuth;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

/**
* Digger Java Client
* <p>
* Interact with digger jenkins api!
* Digger Java Client interact with Digger Jenkins api.
*/
public class DiggerClient {

private static final Logger LOG = LoggerFactory.getLogger(DiggerClient.class);

public static final long DEFAULT_BUILD_TIMEOUT = 60 * 1000;

private final JenkinsServer jenkins;

public DiggerClient(JenkinsAuth auth) throws URISyntaxException {
this.jenkins = new JenkinsServer(new URI(auth.getUrl()), auth.getUser(), auth.getPassword());
}

/**
* Create new digger job on jenkins platform
* Create client using provided url and credentials
*
* @param url Jenkins url
* @param user Jenkins user
* @param password Jenkins password
* @return client instance
* @throws DiggerClientException if something goes wrong
*/
public static DiggerClient from(String url, String user, String password) throws DiggerClientException {
try {
JenkinsAuth jenkinsAuth = new JenkinsAuth(url, user, password);
return new DiggerClient(jenkinsAuth);
} catch (URISyntaxException e) {
throw new DiggerClientException("Invalid jenkins url format.");
}
}

/**
* Create new Digger job on Jenkins platform
*
* @param name - job name that can be used later to reference job
* @param gitRepo - git repository url (full git repository url. e.g [email protected]:wtrocki/helloworld-android-gradle.git
* @param gitBranch - git repository branch (default branch used to checkout source code)
* @param name job name that can be used later to reference job
* @param gitRepo git repository url (full git repository url. e.g [email protected]:wtrocki/helloworld-android-gradle.git
* @param gitBranch git repository branch (default branch used to checkout source code)
* @throws DiggerClientException if something goes wrong
*/
public void createJob(String name, String gitRepo, String gitBranch) throws DiggerClientException {
CreateJobService service = new CreateJobService(this.jenkins);
Expand All @@ -38,19 +64,54 @@ public void createJob(String name, String gitRepo, String gitBranch) throws Digg
}

/**
* Create client using provided url and credentials
* Triggers a build for the given job and waits until it leaves the queue and actually starts.
* <p>
* Jenkins puts the build requests in a queue and once there is a slave available, it starts building
* it and a build number is assigned to the build.
* <p>
* This method will block until there is a build number, or the given timeout period is passed. If the build is still in the queue
* after the given timeout period, a {@code BuildStatus} is returned with state {@link BuildStatus.State#TIMED_OUT}.
* <p>
* Please note that timeout period is never meant to be very precise. It has the resolution of {@link TriggerBuildService#POLL_PERIOD} because
* timeout is checked before every pull.
* <p>
* Similarly, {@link BuildStatus.State#CANCELLED_IN_QUEUE} is returned if the build is cancelled on Jenkins side and
* {@link BuildStatus.State#STUCK_IN_QUEUE} is returned if the build is stuck.
*
* @param url - jenkins url
* @param user - jenkins user
* @param password - jenkins password
* @return client instance
* @param jobName name of the job to trigger the build
* @param timeout how many milliseconds should this call block before returning {@link BuildStatus.State#TIMED_OUT}.
* Should be larger than {@link TriggerBuildService#FIRST_CHECK_DELAY}
* @return the build status
* @throws DiggerClientException if connection problems occur during connecting to Jenkins
*/
public static DiggerClient from(String url, String user, String password) throws DiggerClientException {
public BuildStatus build(String jobName, long timeout) throws DiggerClientException {
final TriggerBuildService triggerBuildService = new TriggerBuildService(jenkins);
try {
JenkinsAuth jenkinsAuth = new JenkinsAuth(url, user, password);
return new DiggerClient(jenkinsAuth);
} catch (URISyntaxException e) {
throw new DiggerClientException("Invalid jenkins url format.");
return triggerBuildService.build(jobName, timeout);
} catch (IOException e) {
LOG.debug("Exception while connecting to Jenkins", e);
throw new DiggerClientException(e);
} catch (InterruptedException e) {
LOG.debug("Exception while waiting on Jenkins", e);
throw new DiggerClientException(e);
} catch (Throwable e) {
LOG.debug("Exception while triggering a build", e);
throw new DiggerClientException(e);
}
}

/**
* Triggers a build for the given job and waits until it leaves the queue and actually starts.
* <p>
* Calls {@link #build(String, long)} with a default timeout of {@link #DEFAULT_BUILD_TIMEOUT}.
*
* @param jobName name of the job
* @return the build status
* @throws DiggerClientException if connection problems occur during connecting to Jenkins
* @see #build(String, long)
*/
public BuildStatus build(String jobName) throws DiggerClientException {
return this.build(jobName, DEFAULT_BUILD_TIMEOUT);
}

}
67 changes: 67 additions & 0 deletions src/main/java/com/redhat/digkins/model/BuildStatus.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.redhat.digkins.model;

/**
* Represents the status of a build.
* <p>
* The field {@link #buildNumber} will only be set if the
* {@link #state} is {@link State#BUILDING}.
**/
public class BuildStatus {

public enum State {
/**
* Build is out of the queue and it is currently being executed.
*/
BUILDING,

/**
* The max time to wait for the build get executed has passed.
* This state doesn't have to mean build is stuck or etc.
* It just means, the max waiting time has passed on the client side.
*/
TIMED_OUT,

/**
* The build is cancelled in Jenkins before it started being executed.
*/
CANCELLED_IN_QUEUE,

/**
* The build is stuck on Jenkins queue.
*/
STUCK_IN_QUEUE
}

private final State state;
private final int buildNumber;

public BuildStatus(State state, int buildNumber) {
this.state = state;
this.buildNumber = buildNumber;
}

/**
* @return state of the build
*/
public State getState() {
return state;
}

/**
* This should only be valid if the
* {@link #state} is {@link State#BUILDING}.
*
* @return the build number assigned by Jenkins
*/
public int getBuildNumber() {
return buildNumber;
}

@Override
public String toString() {
return "BuildStatus{" +
"state=" + state +
", buildNumber=" + buildNumber +
'}';
}
}
15 changes: 7 additions & 8 deletions src/main/java/com/redhat/digkins/services/CreateJobService.java
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
package com.redhat.digkins.services;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use org.aerogear.*** as package for all of this

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's do the package change in a SEPARATE PR

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1


import com.offbytwo.jenkins.JenkinsServer;
import org.apache.commons.io.FileUtils;
import org.jtwig.JtwigModel;
import org.jtwig.JtwigTemplate;

import java.io.File;
import java.io.IOException;

/**
* Create digger job on jenkins platform
*/
public class CreateJobService {

private JenkinsServer jenkins;
private final static String GIT_REPO_URL = "GIT_REPO_URL";
private final static String GIT_REPO_BRANCH = "GIT_REPO_BRANCH";

private final static String GIT_REPO_URL = "GIT_REPO_URL", GIT_REPO_BRANCH = "GIT_REPO_BRANCH";
private JenkinsServer jenkins;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be final as in DiggerClient?


/**
* @param jenkins - jenkins api instance
* @param jenkins jenkins api instance
*/
public CreateJobService(JenkinsServer jenkins) {
this.jenkins = jenkins;
Expand All @@ -27,9 +26,9 @@ public CreateJobService(JenkinsServer jenkins) {
/**
* Create new digger job on jenkins platform
*
* @param name - job name that can be used later to reference job
* @param gitRepo - git repository url (full git repository url. e.g [email protected]:digger/helloworld.git
* @param gitBranch - git repository branch (default branch used to checkout source code)
* @param name job name that can be used later to reference job
* @param gitRepo git repository url (full git repository url. e.g [email protected]:digger/helloworld.git
* @param gitBranch git repository branch (default branch used to checkout source code)
*/
public void create(String name, String gitRepo, String gitBranch) throws IOException {
JtwigTemplate template = JtwigTemplate.classpathTemplate("templates/job.xml");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I strongly recommend to extract hardcoded strings into a constant field, this way it can be found, checked and modified easier when needed.

Expand Down
Loading