From 2400d9d8261b17ee32c0d2448bce264b1687fd4e Mon Sep 17 00:00:00 2001 From: Andrea Turli Date: Wed, 11 Jul 2012 16:17:01 +0200 Subject: [PATCH] jenkins api: added lastBuil api --- .../jclouds/jenkins/v1/domain/LastBuild.java | 289 ++++++++++++++++++ .../jenkins/v1/features/JobAsyncClient.java | 13 +- .../jenkins/v1/features/JobClient.java | 5 +- .../v1/features/JobClientExpectTest.java | 24 ++ .../v1/features/JobClientLiveTest.java | 14 +- .../jenkins/v1/parse/LastBuildTest.java | 57 ++++ .../jenkins/src/test/resources/lastBuild.json | 127 ++++++++ 7 files changed, 520 insertions(+), 9 deletions(-) create mode 100644 labs/jenkins/src/main/java/org/jclouds/jenkins/v1/domain/LastBuild.java create mode 100644 labs/jenkins/src/test/java/org/jclouds/jenkins/v1/parse/LastBuildTest.java create mode 100644 labs/jenkins/src/test/resources/lastBuild.json diff --git a/labs/jenkins/src/main/java/org/jclouds/jenkins/v1/domain/LastBuild.java b/labs/jenkins/src/main/java/org/jclouds/jenkins/v1/domain/LastBuild.java new file mode 100644 index 0000000000..2739f28f5f --- /dev/null +++ b/labs/jenkins/src/main/java/org/jclouds/jenkins/v1/domain/LastBuild.java @@ -0,0 +1,289 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.jenkins.v1.domain; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.net.URI; + +import com.google.common.base.Objects; +import com.google.common.base.Objects.ToStringHelper; + +/** + * Minimal info about a LastBuild + * + * GET http://host/job/project/lastBuild/api/json + * + * @author Andrea Turli + */ +public class LastBuild { + + public static Builder builder() { + return new ConcreteBuilder(); + } + + public Builder toBuilder() { + return builder().fromJob(this); + } + + private static class ConcreteBuilder extends Builder { + } + + public static abstract class Builder> { + private String id; + private URI url; + private String description; + private String building; + private String duration; + private String estimatedDuration; + private String fullDisplayName; + private String result; + private String timestamp; + + @SuppressWarnings("unchecked") + protected B self() { + return (B) this; + } + + /** + * @see LastBuild#getId() + */ + public B id(String id) { + this.id = id; + return self(); + } + + /** + * @see LastBuild#getUrl() + */ + public B url(URI url) { + this.url = url; + return self(); + } + + /** + * @see LastBuild#getDescription() + */ + public B description(String description) { + this.description = description; + return self(); + } + + /** + * @see LastBuild#getBuilding() + */ + public B building(String building) { + this.building = building; + return self(); + } + + /** + * @see LastBuild#getDuration() + */ + public B duration(String duration) { + this.duration = duration; + return self(); + } + + /** + * @see LastBuild#getEstimatedDuration() + */ + public B estimatedDuration(String estimatedDuration) { + this.estimatedDuration = estimatedDuration; + return self(); + } + + /** + * @see LastBuild#getFullDisplayName() + */ + public B fullDisplayName(String fullDisplayName) { + this.fullDisplayName = fullDisplayName; + return self(); + } + + /** + * @see LastBuild#getResult() + */ + public B result(String result) { + this.result = result; + return self(); + } + + /** + * @see LastBuild#getTimestamp() + */ + public B timestamp(String timestamp) { + this.timestamp = timestamp; + return self(); + } + + public LastBuild build() { + return new LastBuild(this); + } + + protected B fromJob(LastBuild in) { + return id(in.getId()).url(in.getUrl()).description(in.getDescription()).building(in.getBuilding()) + .duration(in.getDuration()).estimatedDuration(in.getEstimatedDuration()) + .fullDisplayName(in.getFullDisplayName()).result(in.getResult()).timestamp(in.getTimestamp()); + } + } + + private final String id; + private final URI url; + private final String description; + private final String building; + private final String duration; + private final String estimatedDuration; + private final String fullDisplayName; + private final String result; + private final String timestamp; + + protected LastBuild(Builder builder) { + this.id = checkNotNull(builder.id, "id"); + this.url = checkNotNull(builder.url, "url"); + this.description = checkNotNull(builder.description, "description"); + this.building = checkNotNull(builder.building, "building"); + this.duration = checkNotNull(builder.duration, "duration"); + this.estimatedDuration = checkNotNull(builder.estimatedDuration, "estimatedDuration"); + this.fullDisplayName = checkNotNull(builder.fullDisplayName, "fullDisplayName"); + this.result = checkNotNull(builder.result, "result"); + this.timestamp = checkNotNull(builder.timestamp, "timestamp"); + } + + /** + * id of the lastBuild + */ + public String getId() { + return id; + } + + /** + * + * url of the lastBuild + */ + public URI getUrl() { + return url; + } + + /** + * + * building of the lastBuild + */ + public String getBuilding() { + return building; + } + + /** + * + * description of the lastBuild + */ + public String getDescription() { + return description; + } + + /** + * + * duration of the lastBuild + */ + public String getDuration() { + return duration; + } + + /** + * + * estimated duration of the lastBuild + */ + public String getEstimatedDuration() { + return estimatedDuration; + } + + /** + * + * full Display Name of the lastBuild + */ + public String getFullDisplayName() { + return fullDisplayName; + } + + /** + * + * result of the lastBuild + */ + public String getResult() { + return result; + } + + /** + * + * timestamp of the lastBuild + */ + public String getTimestamp() { + return timestamp; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + LastBuild that = LastBuild.class.cast(o); + return equal(this.id, that.id) + && equal(this.url, that.url) + && equal(this.building, that.building) + && equal(this.description, that.description) + && equal(this.duration, that.duration) + && equal(this.estimatedDuration, that.estimatedDuration) + && equal(this.fullDisplayName, that.fullDisplayName) + && equal(this.result, that.result) + && equal(this.timestamp, that.timestamp); + } + + public boolean clone(Object o) { + if (this == o) + return false; + if (o == null || getClass() != o.getClass()) + return false; + LastBuild that = LastBuild.class.cast(o); + return equal(this.description, that.description); + } + + @Override + public int hashCode() { + return Objects.hashCode(id, url, description, duration, estimatedDuration, fullDisplayName, result, timestamp); + } + + @Override + public String toString() { + return string().toString(); + } + + protected ToStringHelper string() { + return Objects.toStringHelper("") + .add("id", id) + .add("url", url) + .add("description", description) + .add("duration", duration) + .add("estimatedDuration", estimatedDuration) + .add("fullDisplayName", fullDisplayName) + .add("result", result) + .add("timestamp", timestamp); + } +} diff --git a/labs/jenkins/src/main/java/org/jclouds/jenkins/v1/features/JobAsyncClient.java b/labs/jenkins/src/main/java/org/jclouds/jenkins/v1/features/JobAsyncClient.java index f5b49a4114..a88ade1d0f 100644 --- a/labs/jenkins/src/main/java/org/jclouds/jenkins/v1/features/JobAsyncClient.java +++ b/labs/jenkins/src/main/java/org/jclouds/jenkins/v1/features/JobAsyncClient.java @@ -27,19 +27,16 @@ import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.UriInfo; import org.jclouds.jenkins.v1.binders.BindMapToOptionalParams; import org.jclouds.jenkins.v1.domain.JobDetails; +import org.jclouds.jenkins.v1.domain.LastBuild; import org.jclouds.jenkins.v1.filters.BasicAuthenticationUnlessAnonymous; import org.jclouds.jenkins.v1.functions.ReturnVoidOn302Or404; import org.jclouds.rest.annotations.BinderParam; import org.jclouds.rest.annotations.ExceptionParser; import org.jclouds.rest.annotations.RequestFilters; -import org.jclouds.rest.binders.BindMapToMatrixParams; -import org.jclouds.rest.binders.BindMapToStringPayload; import org.jclouds.rest.binders.BindToStringPayload; import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; @@ -105,4 +102,12 @@ public interface JobAsyncClient { @ExceptionParser(ReturnNullOnNotFoundOr404.class) ListenableFuture fetchConfigXML(@PathParam("displayName") String displayName); + /** + * @see JobClient#lastBuild + */ + @GET + @Path("/job/{displayName}/lastBuild/api/json") + @Consumes(MediaType.APPLICATION_JSON) + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + ListenableFuture lastBuild(@PathParam("displayName") String displayName); } diff --git a/labs/jenkins/src/main/java/org/jclouds/jenkins/v1/features/JobClient.java b/labs/jenkins/src/main/java/org/jclouds/jenkins/v1/features/JobClient.java index bff58a7735..b3c5f4e5e4 100644 --- a/labs/jenkins/src/main/java/org/jclouds/jenkins/v1/features/JobClient.java +++ b/labs/jenkins/src/main/java/org/jclouds/jenkins/v1/features/JobClient.java @@ -18,14 +18,12 @@ */ package org.jclouds.jenkins.v1.features; -import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; -import javax.ws.rs.core.UriInfo; - import org.jclouds.concurrent.Timeout; import org.jclouds.jenkins.v1.domain.JobDetails; +import org.jclouds.jenkins.v1.domain.LastBuild; /** * Job Services @@ -63,4 +61,5 @@ public interface JobClient { String fetchConfigXML(String displayName); + LastBuild lastBuild(String displayName); } diff --git a/labs/jenkins/src/test/java/org/jclouds/jenkins/v1/features/JobClientExpectTest.java b/labs/jenkins/src/test/java/org/jclouds/jenkins/v1/features/JobClientExpectTest.java index e41d1b6bf6..042e413d85 100644 --- a/labs/jenkins/src/test/java/org/jclouds/jenkins/v1/features/JobClientExpectTest.java +++ b/labs/jenkins/src/test/java/org/jclouds/jenkins/v1/features/JobClientExpectTest.java @@ -28,6 +28,7 @@ import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpResponse; import org.jclouds.jenkins.v1.JenkinsClient; import org.jclouds.jenkins.v1.internal.BaseJenkinsClientExpectTest; +import org.jclouds.jenkins.v1.parse.LastBuildTest; import org.jclouds.jenkins.v1.parse.ParseJobDetailsTest; import org.jclouds.util.Strings2; import org.testng.annotations.Test; @@ -149,4 +150,27 @@ public class JobClientExpectTest extends BaseJenkinsClientExpectTest { JenkinsClient getJobWhenGetd = requestSendsResponse(fetchConfig, fetchConfigResponse); getJobWhenGetd.getJobClient().fetchConfigXML("ddd"); } + + + HttpRequest lastBuild = HttpRequest.builder() + .method("GET") + .endpoint(URI.create("http://localhost:8080/job/ddd/lastBuild/api/json")) + .headers(ImmutableMultimap. builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .build(); + + public void testLastBuildWhenResponseIs2xx() { + HttpResponse lastBuildResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/lastBuild.json")).build(); + JenkinsClient clientWhenJobExists = requestSendsResponse(lastBuild, lastBuildResponse); + assertEquals(clientWhenJobExists.getJobClient().lastBuild("ddd").toString(), + new LastBuildTest().expected().toString()); + } + + public void testLastBuildWhenResponseIs404() { + HttpResponse lastBuildResponse = HttpResponse.builder().statusCode(404).build(); + JenkinsClient getJobWhenGetd = requestSendsResponse(lastBuild, lastBuildResponse); + assertNull(getJobWhenGetd.getJobClient().lastBuild("ddd")); + } } diff --git a/labs/jenkins/src/test/java/org/jclouds/jenkins/v1/features/JobClientLiveTest.java b/labs/jenkins/src/test/java/org/jclouds/jenkins/v1/features/JobClientLiveTest.java index 0312f90b95..241a4432c9 100644 --- a/labs/jenkins/src/test/java/org/jclouds/jenkins/v1/features/JobClientLiveTest.java +++ b/labs/jenkins/src/test/java/org/jclouds/jenkins/v1/features/JobClientLiveTest.java @@ -25,6 +25,7 @@ import java.io.IOException; import java.util.Map; import org.jclouds.jenkins.v1.domain.JobDetails; +import org.jclouds.jenkins.v1.domain.LastBuild; import org.jclouds.jenkins.v1.internal.BaseJenkinsClientLiveTest; import org.jclouds.util.Strings2; import org.testng.annotations.AfterClass; @@ -79,9 +80,18 @@ public class JobClientLiveTest extends BaseJenkinsClientLiveTest { public void testBuildJobWithParameters() throws IOException { Map parameters = ImmutableMap.of("name", "test1", "password", "secret"); getClient().buildWithParameters("jobWithParameters", parameters); - } + } - @Test(dependsOnMethods = "testBuildJob") + @Test(dependsOnMethods = "testBuildJobWithParameters") + public void testLastBuild() throws IOException { + LastBuild lastBuild = getClient().lastBuild("jobWithParameters"); + while(lastBuild == null || lastBuild.getResult() == null) { + lastBuild = getClient().lastBuild("jobWithParameters"); + } + assertEquals(lastBuild.getResult(), "SUCCESS"); + } + + @Test(dependsOnMethods = "testLastBuild") public void testDeleteJobWithParameters() { getClient().delete("jobWithParameters"); } diff --git a/labs/jenkins/src/test/java/org/jclouds/jenkins/v1/parse/LastBuildTest.java b/labs/jenkins/src/test/java/org/jclouds/jenkins/v1/parse/LastBuildTest.java new file mode 100644 index 0000000000..81cdd56aef --- /dev/null +++ b/labs/jenkins/src/test/java/org/jclouds/jenkins/v1/parse/LastBuildTest.java @@ -0,0 +1,57 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.jenkins.v1.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.jenkins.v1.domain.LastBuild; +import org.jclouds.json.BaseItemParserTest; +import org.testng.annotations.Test; + +/** + * + * @author Andrea Turli + */ +@Test(groups = "unit", testName = "LastBuildTest") +public class LastBuildTest extends BaseItemParserTest { + + @Override + public String resource() { + return "/lastBuild.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public LastBuild expected() { + return LastBuild.builder() + .id("2012-07-11_04-02-37") + .url(URI.create("http://dal36.poweredman.com:8080/job/poweredman-web-build/139/")) + .description("test") + .duration("505777") + .building("false") + .estimatedDuration("942619") + .fullDisplayName("poweredman-web-build #139") + .timestamp("1341997357461") + .result("SUCCESS") + .build(); + } +} diff --git a/labs/jenkins/src/test/resources/lastBuild.json b/labs/jenkins/src/test/resources/lastBuild.json new file mode 100644 index 0000000000..3843687aae --- /dev/null +++ b/labs/jenkins/src/test/resources/lastBuild.json @@ -0,0 +1,127 @@ +{ + "actions": [ + { + "causes": [ + { + "shortDescription": "Started by GitHub push by " + } + ] + }, + { + }, + { + "buildsByBranchName": { + "origin/master": { + "buildNumber": 139, + "buildResult": null, + "revision": { + "SHA1": "aabf3da75ef2f4169de1136a93d5eec609314436", + "branch": [ + { + "SHA1": "aabf3da75ef2f4169de1136a93d5eec609314436", + "name": "origin/HEAD" + }, + { + "SHA1": "aabf3da75ef2f4169de1136a93d5eec609314436", + "name": "origin/master" + } + ] + } + }, + "origin/HEAD": { + "buildNumber": 139, + "buildResult": null, + "revision": { + "SHA1": "aabf3da75ef2f4169de1136a93d5eec609314436", + "branch": [ + { + "SHA1": "aabf3da75ef2f4169de1136a93d5eec609314436", + "name": "origin/HEAD" + }, + { + "SHA1": "aabf3da75ef2f4169de1136a93d5eec609314436", + "name": "origin/master" + } + ] + } + } + }, + "lastBuiltRevision": { + "SHA1": "aabf3da75ef2f4169de1136a93d5eec609314436", + "branch": [ + { + "SHA1": "aabf3da75ef2f4169de1136a93d5eec609314436", + "name": "origin/HEAD" + }, + { + "SHA1": "aabf3da75ef2f4169de1136a93d5eec609314436", + "name": "origin/master" + } + ] + }, + "scmName": "" + }, + { + }, + { + }, + { + } + ], + "artifacts": [ + { + "displayPath": "poweredman-webapp-0.0.1-SNAPSHOT.zip", + "fileName": "poweredman-webapp-0.0.1-SNAPSHOT.zip", + "relativePath": "webapp/dist/poweredman-webapp-0.0.1-SNAPSHOT.zip" + } + ], + "building": false, + "description": "test", + "duration": 505777, + "estimatedDuration": 942619, + "fullDisplayName": "poweredman-web-build #139", + "id": "2012-07-11_04-02-37", + "keepLog": false, + "number": 139, + "result": "SUCCESS", + "timestamp": 1341997357461, + "url": "http://dal36.poweredman.com:8080/job/poweredman-web-build/139/", + "builtOn": "", + "changeSet": { + "items": [ + { + "affectedPaths": [ + "webapp/app/controllers/Application.java" + ], + "author": { + "absoluteUrl": "http://dal36.poweredman.com:8080/user/andrea.turli", + "fullName": "andrea.turli" + }, + "commitId": "aabf3da75ef2f4169de1136a93d5eec609314436", + "msg": "fixed signup process removing refuse Ebean.saveManyToManyAssociations(currentUser, \"companies\")", + "timestamp": 1341997059000, + "author (new)": { + "absoluteUrl": "http://dal36.poweredman.com:8080/user/andrea.turli", + "fullName": "andrea.turli" + }, + "comment": "fixed signup process removing refuse Ebean.saveManyToManyAssociations(currentUser, \"companies\")\n", + "date": "2012-07-11 03:57:39 +0200", + "id": "aabf3da75ef2f4169de1136a93d5eec609314436", + "msg (new)": "fixed signup process removing refuse Ebean.saveManyToManyAssociations(currentUser, \"companies\")", + "paths": [ + { + "editType": "edit", + "file": "webapp/app/controllers/Application.java" + } + ] + } + ], + "kind": null + }, + "culprits": [ + { + "absoluteUrl": "http://dal36.poweredman.com:8080/user/andrea.turli", + "fullName": "andrea.turli" + } + ] +} \ No newline at end of file