Skip to content

AGDIGGER-60 - allow to stream artifacts #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
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
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@ A java integration library for AeroGear Digger

## Usage

Build a default client:
```
DiggerClient client = DiggerClient.createDefaultWithAuth("https://digger.com", "admin", "password");
```

Build a customized client:
```
DiggerClient client = DiggerClient.builder()
.jobService(new JobService())
.triggerBuildService(new BuildService(10000, 100))
.artifactsService(artifactsService)
.withAuth("https://digger.com", "admin", "password")
.build();
```

Create job:

```
Expand Down
27 changes: 18 additions & 9 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,21 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>groupId</groupId>
<groupId>org.jboss.aerogear</groupId>
<artifactId>jenkins-client</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>

<properties>
<junit.version>4.11</junit.version>
<mockito-core.version>1.9.5</mockito-core.version>
<jenkins.client.version>0.3.7-SNAPSHOT</jenkins.client.version>
<jtwig.templates.version>5.65</jtwig.templates.version>
<slf4j.api.version>1.7.21</slf4j.api.version>
<slf4j-log4j12.version>1.7.21</slf4j-log4j12.version>
<assertj-core.version>3.6.1</assertj-core.version>
</properties>

<licenses>
<license>
<name>Apache License, Version 2.0</name>
Expand All @@ -22,42 +32,41 @@
<dependency>
<groupId>com.offbytwo.jenkins</groupId>
<artifactId>jenkins-client</artifactId>
<version>0.3.7-SNAPSHOT</version>
<version>${jenkins.client.version}</version>
</dependency>
<dependency>
<groupId>org.jtwig</groupId>
<artifactId>jtwig-core</artifactId>
<version>5.65</version>
<version>${jtwig.templates.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
<version>${slf4j.api.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
<version>${slf4j-log4j12.version}</version>
</dependency>

<!--Testing-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.10.19</version>
<version>${mockito-core.version}</version>
Copy link
Owner

Choose a reason for hiding this comment

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

Good point: let's use properties for versions... I will do this for the rest of the deps

Copy link
Owner

Choose a reason for hiding this comment

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

@wtrocki as we talked. maybe you can do it for the rest of the deps too.

Choose a reason for hiding this comment

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

IMO it's a bit redundant nevertheless since they are used only in one place each

Copy link

Choose a reason for hiding this comment

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

but it's usually much nicer to have those covered in a properties section

<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.6.1</version>
<version>${assertj-core.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
Expand Down
115 changes: 98 additions & 17 deletions src/main/java/com/redhat/digkins/DiggerClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@

import com.offbytwo.jenkins.JenkinsServer;
import com.redhat.digkins.model.BuildStatus;
import com.redhat.digkins.services.CreateJobService;
import com.redhat.digkins.services.ArtifactsService;
import com.redhat.digkins.services.JobService;
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.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;

Expand All @@ -22,30 +25,82 @@ public class DiggerClient {

public static final long DEFAULT_BUILD_TIMEOUT = 60 * 1000;

private final JenkinsServer jenkins;
private JenkinsServer jenkinsServer;

public DiggerClient(JenkinsAuth auth) throws URISyntaxException {
this.jenkins = new JenkinsServer(new URI(auth.getUrl()), auth.getUser(), auth.getPassword());
private JobService jobService;
private TriggerBuildService triggerBuildService;
private ArtifactsService artifactsService;

private DiggerClient() {
}

/**
* Create client using provided url and credentials
* Create a client with defaults using provided url and credentials.
* <p>
* This client will use the defaults for the services. This is perfectly fine for majorith of the cases.
*
* @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.");
public static DiggerClient createDefaultWithAuth(String url, String user, String password) throws DiggerClientException {
TriggerBuildService triggerBuildService = new TriggerBuildService(TriggerBuildService.DEFAULT_FIRST_CHECK_DELAY, TriggerBuildService.DEFAULT_POLL_PERIOD);
JobService jobService = new JobService();
ArtifactsService artifactsService = new ArtifactsService();
return DiggerClient.builder()
.createJobService(jobService)
.triggerBuildService(triggerBuildService)
.artifactsService(artifactsService)
.withAuth(url, user, password)
.build();
}

public static DiggerClientBuilder builder() {
return new DiggerClientBuilder();
}
public static class DiggerClientBuilder {
private JenkinsAuth auth;
private JobService jobService;
private TriggerBuildService triggerBuildService;
private ArtifactsService artifactsService;

public DiggerClientBuilder withAuth(String url, String user, String password) {
this.auth = new JenkinsAuth(url, user, password);
return this;
}

public DiggerClientBuilder createJobService(JobService jobService) {
this.jobService = jobService;
return this;
}

public DiggerClientBuilder triggerBuildService(TriggerBuildService triggerBuildService) {
this.triggerBuildService = triggerBuildService;
return this;
}

public DiggerClientBuilder artifactsService(ArtifactsService artifactsService) {
this.artifactsService = artifactsService;
return this;
}

public DiggerClient build() throws DiggerClientException {
final DiggerClient client = new DiggerClient();
try {
client.jenkinsServer = new JenkinsServer(new URI(auth.getUrl()), auth.getUser(), auth.getPassword());
client.jobService = this.jobService;
client.triggerBuildService = this.triggerBuildService;
client.artifactsService = this.artifactsService;
return client;
} catch (URISyntaxException e) {
throw new DiggerClientException("Invalid jenkins url format.");
}
}
}


/**
* Create new Digger job on Jenkins platform
*
Expand All @@ -55,9 +110,8 @@ public static DiggerClient from(String url, String user, String password) throws
* @throws DiggerClientException if something goes wrong
*/
public void createJob(String name, String gitRepo, String gitBranch) throws DiggerClientException {
CreateJobService service = new CreateJobService(this.jenkins);
try {
service.create(name, gitRepo, gitBranch);
jobService.create(this.jenkinsServer, name, gitRepo, gitBranch);
} catch (Throwable e) {
throw new DiggerClientException(e);
}
Expand All @@ -72,22 +126,21 @@ public void createJob(String name, String gitRepo, String gitBranch) throws Digg
* 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
* Please note that timeout period is never meant to be very precise. It has the resolution of {@link TriggerBuildService#DEFAULT_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 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}
* Should be larger than {@link TriggerBuildService#DEFAULT_FIRST_CHECK_DELAY}
* @return the build status
* @throws DiggerClientException if connection problems occur during connecting to Jenkins
*/
public BuildStatus build(String jobName, long timeout) throws DiggerClientException {
final TriggerBuildService triggerBuildService = new TriggerBuildService(jenkins);
try {
return triggerBuildService.build(jobName, timeout);
return triggerBuildService.build(this.jenkinsServer, jobName, timeout);
} catch (IOException e) {
LOG.debug("Exception while connecting to Jenkins", e);
throw new DiggerClientException(e);
Expand All @@ -114,4 +167,32 @@ public BuildStatus build(String jobName) throws DiggerClientException {
return this.build(jobName, DEFAULT_BUILD_TIMEOUT);
}

/**
* Fetch artifacts urls for specific job and build number
*
* @param jobName name of the job
* @param buildNumber job build number
* @param artifactName - name of the artifact to fetch - can be regexp
* @return InputStream with file contents
* @throws DiggerClientException - when problem with fetching artifacts from jenkins
*/
public InputStream fetchArtifact(String jobName, int buildNumber, String artifactName) throws DiggerClientException {
return artifactsService.streamArtifact(jenkinsServer,jobName, buildNumber, artifactName);
}

/**
* Save artifact for specified location for specific job, build number and artifact name.
* If name would be an regular expression method would return stream for the first match.
*
* @param jobName name of the job
* @param buildNumber job build number
* @param artifactName name of the artifact to fetch - can be regexp for example *.apk
* @param outputFile file (location) used to save artifact
*
* @throws DiggerClientException when problem with fetching artifacts from jenkins
* @throws IOException when one of the files cannot be saved
*/
public void saveArtifact(String jobName, int buildNumber, String artifactName, File outputFile) throws DiggerClientException, IOException {
artifactsService.saveArtifact(jenkinsServer,jobName, buildNumber, artifactName,outputFile);
}
}
36 changes: 36 additions & 0 deletions src/main/java/com/redhat/digkins/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.redhat.digkins;

import com.redhat.digkins.services.JobService;
import com.redhat.digkins.services.TriggerBuildService;
import com.redhat.digkins.util.DiggerClientException;
import org.apache.commons.io.IOUtils;

import java.io.*;

/**
*/
public class Main {

public static void main(String[] args) throws DiggerClientException, IOException {
DiggerClient client = DiggerClient.builder()
.createJobService(new JobService())
.triggerBuildService(new TriggerBuildService(10000, 100))
.withAuth("https://jenkins-digger2.osm3.feedhenry.net", "admin", "Vu8ysYH5f2dJiLgL")
.build();
//client.createJob("wtr-java-tests2", "https://github.com/wtrocki/helloworld-android-gradle", "master");
//client.build("wtr-java-tests2");
InputStream inputStream = client.fetchArtifact("wtr-java-tests2", 1, "app-debug.apk");
if(inputStream != null){
File targetFile = new File("artifact.tmp");
OutputStream outStream = new FileOutputStream(targetFile);

byte[] buffer = new byte[8 * 1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outStream.write(buffer, 0, bytesRead);
}
IOUtils.closeQuietly(inputStream);
IOUtils.closeQuietly(outStream);
}
}
}
Loading