From 5aca03d23521bf307973a3170f0760ce0d143f95 Mon Sep 17 00:00:00 2001 From: ChristopherDancy Date: Tue, 31 Jan 2017 21:27:00 -0500 Subject: [PATCH] ISSUE-37: Added CommitsApi with 'get' endpoint. --- .../cdancy/bitbucket/rest/BitbucketApi.java | 4 + .../{pullrequest => commit}/Commit.java | 18 ++-- .../{pullrequest => commit}/CommitPage.java | 2 +- .../rest/fallbacks/BitbucketFallbacks.java | 14 ++++ .../bitbucket/rest/features/CommitsApi.java | 51 +++++++++++ .../rest/features/PullRequestApi.java | 5 +- .../rest/features/CommitsApiLiveTest.java | 53 ++++++++++++ .../rest/features/CommitsApiMockTest.java | 84 +++++++++++++++++++ .../rest/features/PullRequestApiLiveTest.java | 2 +- .../rest/features/PullRequestApiMockTest.java | 2 +- src/test/resources/commit-error.json | 9 ++ src/test/resources/commit.json | 16 ++++ 12 files changed, 248 insertions(+), 12 deletions(-) rename src/main/java/com/cdancy/bitbucket/rest/domain/{pullrequest => commit}/Commit.java (68%) rename src/main/java/com/cdancy/bitbucket/rest/domain/{pullrequest => commit}/CommitPage.java (97%) create mode 100644 src/main/java/com/cdancy/bitbucket/rest/features/CommitsApi.java create mode 100644 src/test/java/com/cdancy/bitbucket/rest/features/CommitsApiLiveTest.java create mode 100644 src/test/java/com/cdancy/bitbucket/rest/features/CommitsApiMockTest.java create mode 100644 src/test/resources/commit-error.json create mode 100644 src/test/resources/commit.json diff --git a/src/main/java/com/cdancy/bitbucket/rest/BitbucketApi.java b/src/main/java/com/cdancy/bitbucket/rest/BitbucketApi.java index f6c1b08e..89e2a3ee 100644 --- a/src/main/java/com/cdancy/bitbucket/rest/BitbucketApi.java +++ b/src/main/java/com/cdancy/bitbucket/rest/BitbucketApi.java @@ -21,6 +21,7 @@ import com.cdancy.bitbucket.rest.features.BranchApi; import com.cdancy.bitbucket.rest.features.CommentsApi; +import com.cdancy.bitbucket.rest.features.CommitsApi; import com.cdancy.bitbucket.rest.features.ProjectApi; import com.cdancy.bitbucket.rest.features.PullRequestApi; import com.cdancy.bitbucket.rest.features.RepositoryApi; @@ -37,6 +38,9 @@ public interface BitbucketApi extends Closeable { @Delegate CommentsApi commentsApi(); + @Delegate + CommitsApi commitsApi(); + @Delegate ProjectApi projectApi(); diff --git a/src/main/java/com/cdancy/bitbucket/rest/domain/pullrequest/Commit.java b/src/main/java/com/cdancy/bitbucket/rest/domain/commit/Commit.java similarity index 68% rename from src/main/java/com/cdancy/bitbucket/rest/domain/pullrequest/Commit.java rename to src/main/java/com/cdancy/bitbucket/rest/domain/commit/Commit.java index b3948705..b7cc6219 100644 --- a/src/main/java/com/cdancy/bitbucket/rest/domain/pullrequest/Commit.java +++ b/src/main/java/com/cdancy/bitbucket/rest/domain/commit/Commit.java @@ -15,26 +15,33 @@ * limitations under the License. */ -package com.cdancy.bitbucket.rest.domain.pullrequest; +package com.cdancy.bitbucket.rest.domain.commit; +import com.cdancy.bitbucket.rest.domain.common.Error; +import com.cdancy.bitbucket.rest.domain.common.ErrorsHolder; +import com.cdancy.bitbucket.rest.domain.pullrequest.Author; +import com.cdancy.bitbucket.rest.domain.pullrequest.Parents; import java.util.List; import org.jclouds.json.SerializedNames; import com.cdancy.bitbucket.rest.utils.Utils; import com.google.auto.value.AutoValue; +import org.jclouds.javax.annotation.Nullable; @AutoValue -public abstract class Commit { +public abstract class Commit implements ErrorsHolder { public abstract String id(); public abstract String displayId(); + @Nullable public abstract Author author(); public abstract long authorTimestamp(); + @Nullable public abstract String message(); public abstract List parents(); @@ -43,9 +50,10 @@ public abstract class Commit { } @SerializedNames({ "id", "displayId", "author", "authorTimestamp", - "message", "parents" }) + "message", "parents", "errors" }) public static Commit create(String id, String displayId, Author author, - long authorTimestamp, String message, List parents) { - return new AutoValue_Commit(id, displayId, author, authorTimestamp, message, Utils.nullToEmpty(parents)); + long authorTimestamp, String message, List parents, List errors) { + return new AutoValue_Commit(Utils.nullToEmpty(errors), id, displayId, author, + authorTimestamp, message, Utils.nullToEmpty(parents)); } } diff --git a/src/main/java/com/cdancy/bitbucket/rest/domain/pullrequest/CommitPage.java b/src/main/java/com/cdancy/bitbucket/rest/domain/commit/CommitPage.java similarity index 97% rename from src/main/java/com/cdancy/bitbucket/rest/domain/pullrequest/CommitPage.java rename to src/main/java/com/cdancy/bitbucket/rest/domain/commit/CommitPage.java index d873f35f..769075e9 100644 --- a/src/main/java/com/cdancy/bitbucket/rest/domain/pullrequest/CommitPage.java +++ b/src/main/java/com/cdancy/bitbucket/rest/domain/commit/CommitPage.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package com.cdancy.bitbucket.rest.domain.pullrequest; +package com.cdancy.bitbucket.rest.domain.commit; import java.util.List; diff --git a/src/main/java/com/cdancy/bitbucket/rest/fallbacks/BitbucketFallbacks.java b/src/main/java/com/cdancy/bitbucket/rest/fallbacks/BitbucketFallbacks.java index 9ab4d7a6..4bc014fc 100644 --- a/src/main/java/com/cdancy/bitbucket/rest/fallbacks/BitbucketFallbacks.java +++ b/src/main/java/com/cdancy/bitbucket/rest/fallbacks/BitbucketFallbacks.java @@ -26,6 +26,7 @@ import com.cdancy.bitbucket.rest.domain.branch.Branch; import com.cdancy.bitbucket.rest.domain.common.Error; import com.cdancy.bitbucket.rest.domain.project.Project; +import com.cdancy.bitbucket.rest.domain.commit.Commit; import com.cdancy.bitbucket.rest.domain.pullrequest.MergeStatus; import com.cdancy.bitbucket.rest.domain.repository.Repository; import com.cdancy.bitbucket.rest.domain.tags.Tag; @@ -59,6 +60,15 @@ public Object createOrPropagate(Throwable throwable) throws Exception { throw propagate(throwable); } } + + public static final class CommitOnError implements Fallback { + public Object createOrPropagate(Throwable throwable) throws Exception { + if (checkNotNull(throwable, "throwable") != null) { + return createCommitFromErrors(getErrors(throwable.getMessage())); + } + throw propagate(throwable); + } + } public static final class TagOnError implements Fallback { public Object createOrPropagate(Throwable throwable) throws Exception { @@ -108,6 +118,10 @@ public Object createOrPropagate(Throwable throwable) throws Exception { public static Branch createBranchFromErrors(List errors) { return Branch.create(null, null, null, null, null, false, errors); } + + public static Commit createCommitFromErrors(List errors) { + return Commit.create("-1", "-1", null, 0, null, null, errors); + } public static Tag createTagFromErrors(List errors) { return Tag.create(null, null, null, null, null, null, errors); diff --git a/src/main/java/com/cdancy/bitbucket/rest/features/CommitsApi.java b/src/main/java/com/cdancy/bitbucket/rest/features/CommitsApi.java new file mode 100644 index 00000000..97dc3957 --- /dev/null +++ b/src/main/java/com/cdancy/bitbucket/rest/features/CommitsApi.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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 com.cdancy.bitbucket.rest.features; + +import com.cdancy.bitbucket.rest.domain.commit.Commit; +import com.cdancy.bitbucket.rest.fallbacks.BitbucketFallbacks; +import com.cdancy.bitbucket.rest.filters.BitbucketAuthentication; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.RequestFilters; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +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.MediaType; +import org.jclouds.javax.annotation.Nullable; + +@Produces(MediaType.APPLICATION_JSON) +@RequestFilters(BitbucketAuthentication.class) +@Path("/rest/api/{jclouds.api-version}/projects") +public interface CommitsApi { + + @Named("commits:get") + @Consumes(MediaType.APPLICATION_JSON) + @Path("/{project}/repos/{repo}/commits/{commitId}") + @Fallback(BitbucketFallbacks.CommitOnError.class) + @GET + Commit get(@PathParam("project") String project, + @PathParam("repo") String repo, + @PathParam("commitId") String commitId, + @Nullable @QueryParam("path") String path); +} diff --git a/src/main/java/com/cdancy/bitbucket/rest/features/PullRequestApi.java b/src/main/java/com/cdancy/bitbucket/rest/features/PullRequestApi.java index 5f7a1196..075a84cc 100644 --- a/src/main/java/com/cdancy/bitbucket/rest/features/PullRequestApi.java +++ b/src/main/java/com/cdancy/bitbucket/rest/features/PullRequestApi.java @@ -31,20 +31,17 @@ import com.cdancy.bitbucket.rest.domain.pullrequest.MergeStatus; import com.cdancy.bitbucket.rest.domain.pullrequest.ChangePage; -import com.cdancy.bitbucket.rest.domain.pullrequest.CommitPage; +import com.cdancy.bitbucket.rest.domain.commit.CommitPage; import com.cdancy.bitbucket.rest.options.CreatePullRequest; import org.jclouds.javax.annotation.Nullable; import org.jclouds.rest.annotations.BinderParam; import org.jclouds.rest.annotations.Fallback; -import org.jclouds.rest.annotations.Payload; -import org.jclouds.rest.annotations.PayloadParam; import org.jclouds.rest.annotations.RequestFilters; import com.cdancy.bitbucket.rest.domain.pullrequest.PullRequest; import com.cdancy.bitbucket.rest.fallbacks.BitbucketFallbacks.PullRequestOnError; import com.cdancy.bitbucket.rest.fallbacks.BitbucketFallbacks.MergeStatusOnError; import com.cdancy.bitbucket.rest.filters.BitbucketAuthentication; -import org.jclouds.rest.annotations.SelectJson; import org.jclouds.rest.binders.BindToJsonPayload; @Produces(MediaType.APPLICATION_JSON) diff --git a/src/test/java/com/cdancy/bitbucket/rest/features/CommitsApiLiveTest.java b/src/test/java/com/cdancy/bitbucket/rest/features/CommitsApiLiveTest.java new file mode 100644 index 00000000..249c467a --- /dev/null +++ b/src/test/java/com/cdancy/bitbucket/rest/features/CommitsApiLiveTest.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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 com.cdancy.bitbucket.rest.features; + +import com.cdancy.bitbucket.rest.BaseBitbucketApiLiveTest; +import com.cdancy.bitbucket.rest.domain.commit.Commit; + +import org.testng.annotations.Test; + +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +@Test(groups = "live", testName = "CommitsApiLiveTest", singleThreaded = true) +public class CommitsApiLiveTest extends BaseBitbucketApiLiveTest { + + String projectKey = "TEST"; + String repoKey = "dev"; + String commitHash = "d90ca08fa076e2e4c076592fce3832aba80a494f"; + + @Test + public void testGetCommit() { + Commit commit = api().get(projectKey, repoKey, commitHash, null); + assertNotNull(commit); + assertTrue(commit.errors().isEmpty()); + assertTrue(commit.id().equals(commitHash)); + } + + @Test + public void testGetCommitNonExistent() { + Commit commit = api().get(projectKey, repoKey, "1234567890", null); + assertNotNull(commit); + assertTrue(commit.errors().size() > 0); + } + + private CommitsApi api() { + return api.commitsApi(); + } +} diff --git a/src/test/java/com/cdancy/bitbucket/rest/features/CommitsApiMockTest.java b/src/test/java/com/cdancy/bitbucket/rest/features/CommitsApiMockTest.java new file mode 100644 index 00000000..4fafd612 --- /dev/null +++ b/src/test/java/com/cdancy/bitbucket/rest/features/CommitsApiMockTest.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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 com.cdancy.bitbucket.rest.features; + +import com.cdancy.bitbucket.rest.BitbucketApi; +import com.cdancy.bitbucket.rest.BitbucketApiMetadata; +import com.cdancy.bitbucket.rest.domain.commit.Commit; +import com.cdancy.bitbucket.rest.internal.BaseBitbucketMockTest; +import com.squareup.okhttp.mockwebserver.MockResponse; +import com.squareup.okhttp.mockwebserver.MockWebServer; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +/** + * Mock tests for the {@link CommitsApi} class. + */ +@Test(groups = "unit", testName = "CommitApiMockTest") +public class CommitsApiMockTest extends BaseBitbucketMockTest { + + public void testGetCommit() throws Exception { + MockWebServer server = mockEtcdJavaWebServer(); + + server.enqueue(new MockResponse().setBody(payloadFromResource("/commit.json")).setResponseCode(200)); + BitbucketApi baseApi = api(server.getUrl("/")); + CommitsApi api = baseApi.commitsApi(); + try { + String projectKey = "PRJ"; + String repoKey = "myrepo"; + String commitHash = "abcdef0123abcdef4567abcdef8987abcdef6543"; + + Commit commit = api.get(projectKey, repoKey, commitHash, null); + assertNotNull(commit); + assertTrue(commit.errors().isEmpty()); + assertTrue(commit.id().equalsIgnoreCase(commitHash)); + + assertSent(server, "GET", "/rest/api/" + BitbucketApiMetadata.API_VERSION + + "/projects/" + projectKey + "/repos/" + repoKey + "/commits/" + commitHash); + } finally { + baseApi.close(); + server.shutdown(); + } + } + + public void testGetCommitNonExistent() throws Exception { + MockWebServer server = mockEtcdJavaWebServer(); + + server.enqueue(new MockResponse().setBody(payloadFromResource("/commit-error.json")).setResponseCode(404)); + BitbucketApi baseApi = api(server.getUrl("/")); + CommitsApi api = baseApi.commitsApi(); + try { + String projectKey = "PRJ"; + String repoKey = "myrepo"; + String commitHash = "abcdef0123abcdef4567abcdef8987abcdef6543"; + + Commit commit = api.get(projectKey, repoKey, commitHash, null); + assertNotNull(commit); + assertTrue(commit.errors().size() > 0); + + assertSent(server, "GET", "/rest/api/" + BitbucketApiMetadata.API_VERSION + + "/projects/" + projectKey + "/repos/" + repoKey + "/commits/" + commitHash); + } finally { + baseApi.close(); + server.shutdown(); + } + } +} diff --git a/src/test/java/com/cdancy/bitbucket/rest/features/PullRequestApiLiveTest.java b/src/test/java/com/cdancy/bitbucket/rest/features/PullRequestApiLiveTest.java index c4065d38..83bb2e03 100644 --- a/src/test/java/com/cdancy/bitbucket/rest/features/PullRequestApiLiveTest.java +++ b/src/test/java/com/cdancy/bitbucket/rest/features/PullRequestApiLiveTest.java @@ -24,7 +24,7 @@ import com.cdancy.bitbucket.rest.domain.pullrequest.MinimalRepository; import com.cdancy.bitbucket.rest.domain.pullrequest.MergeStatus; import com.cdancy.bitbucket.rest.domain.pullrequest.ChangePage; -import com.cdancy.bitbucket.rest.domain.pullrequest.CommitPage; +import com.cdancy.bitbucket.rest.domain.commit.CommitPage; import com.cdancy.bitbucket.rest.domain.pullrequest.ProjectKey; import com.cdancy.bitbucket.rest.domain.pullrequest.PullRequest; import com.cdancy.bitbucket.rest.domain.pullrequest.Reference; diff --git a/src/test/java/com/cdancy/bitbucket/rest/features/PullRequestApiMockTest.java b/src/test/java/com/cdancy/bitbucket/rest/features/PullRequestApiMockTest.java index a2a6f882..b509660f 100644 --- a/src/test/java/com/cdancy/bitbucket/rest/features/PullRequestApiMockTest.java +++ b/src/test/java/com/cdancy/bitbucket/rest/features/PullRequestApiMockTest.java @@ -28,7 +28,7 @@ import com.cdancy.bitbucket.rest.domain.pullrequest.MergeStatus; import com.cdancy.bitbucket.rest.domain.pullrequest.MinimalRepository; import com.cdancy.bitbucket.rest.domain.pullrequest.ChangePage; -import com.cdancy.bitbucket.rest.domain.pullrequest.CommitPage; +import com.cdancy.bitbucket.rest.domain.commit.CommitPage; import com.cdancy.bitbucket.rest.domain.pullrequest.ProjectKey; import com.cdancy.bitbucket.rest.domain.pullrequest.PullRequest; import com.cdancy.bitbucket.rest.domain.pullrequest.Reference; diff --git a/src/test/resources/commit-error.json b/src/test/resources/commit-error.json new file mode 100644 index 00000000..f1977f18 --- /dev/null +++ b/src/test/resources/commit-error.json @@ -0,0 +1,9 @@ +{ + "errors":[ + { + "context":null, + "message":"The changeset '1234567890' does not exist in repository 'prpc-platform'", + "exceptionName":"com.atlassian.stash.exception.NoSuchChangesetException" + } + ] +} \ No newline at end of file diff --git a/src/test/resources/commit.json b/src/test/resources/commit.json new file mode 100644 index 00000000..91714052 --- /dev/null +++ b/src/test/resources/commit.json @@ -0,0 +1,16 @@ +{ + "id": "abcdef0123abcdef4567abcdef8987abcdef6543", + "displayId": "abcdef0123a", + "author": { + "name": "charlie", + "emailAddress": "charlie@example.com" + }, + "authorTimestamp": 1484800877151, + "message": "WIP on feature 1", + "parents": [ + { + "id": "abcdef0123abcdef4567abcdef8987abcdef6543", + "displayId": "abcdef0" + } + ] +} \ No newline at end of file