Skip to content

Commit

Permalink
ADDED: BranchApi with endpoints 'create', 'getDefault', 'updateDefault'.
Browse files Browse the repository at this point in the history
  • Loading branch information
cdancy committed Jun 22, 2016
1 parent 055397b commit cd70952
Show file tree
Hide file tree
Showing 9 changed files with 413 additions and 30 deletions.
3 changes: 3 additions & 0 deletions src/main/java/com/cdancy/bitbucket/rest/BitbucketApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@

public interface BitbucketApi extends Closeable {

@Delegate
BranchApi branchApi();

@Delegate
ProjectApi projectApi();

Expand Down
60 changes: 60 additions & 0 deletions src/main/java/com/cdancy/bitbucket/rest/domain/branch/Branch.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* 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.domain.branch;

import com.cdancy.bitbucket.rest.error.Error;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.SerializedNames;

import java.util.List;

@AutoValue
public abstract class Branch {

@Nullable
public abstract String id();

@Nullable
public abstract String displayId();

@Nullable
public abstract String type();

@Nullable
public abstract String latestCommit();

@Nullable
public abstract String latestChangeset();

public abstract boolean isDefault();

@Nullable
public abstract List<Error> errors();

Branch() {
}

@SerializedNames({ "id", "displayId", "type", "latestCommit", "latestChangeset", "isDefault", "errors" })
public static Branch create(String id, String displayId, String type,
String latestCommit, String latestChangeset, boolean isDefault, List<Error> errors) {
return new AutoValue_Branch(id, displayId, type, latestCommit, latestChangeset, isDefault,
errors != null ? ImmutableList.copyOf(errors) : ImmutableList.<Error> of());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.Iterator;
import java.util.List;

import com.cdancy.bitbucket.rest.domain.branch.Branch;
import com.cdancy.bitbucket.rest.domain.project.Project;
import com.cdancy.bitbucket.rest.domain.pullrequest.MergeStatus;
import com.cdancy.bitbucket.rest.domain.repository.Repository;
Expand All @@ -38,7 +39,7 @@

public final class BitbucketFallbacks {

private static final JsonParser parser = new JsonParser();
private static final JsonParser parser = new JsonParser();

public static final class FalseOnError implements Fallback<Object> {
public Object createOrPropagate(Throwable t) throws Exception {
Expand All @@ -49,6 +50,15 @@ public Object createOrPropagate(Throwable t) throws Exception {
}
}

public static final class BranchOnError implements Fallback<Object> {
public Object createOrPropagate(Throwable t) throws Exception {
if (checkNotNull(t, "throwable") != null) {
return createBranchFromErrors(getErrors(t.getMessage()));
}
throw propagate(t);
}
}

public static final class TagOnError implements Fallback<Object> {
public Object createOrPropagate(Throwable t) throws Exception {
if (checkNotNull(t, "throwable") != null) {
Expand Down Expand Up @@ -76,43 +86,26 @@ public Object createOrPropagate(Throwable t) throws Exception {
}
}

public static final class PullRequestOnError implements Fallback<Object> {
public Object createOrPropagate(Throwable t) throws Exception {
if (checkNotNull(t, "throwable") != null) {
return createPullRequestFromErrors(getErrors(t.getMessage()));
}
throw propagate(t);
}
}
public static final class PullRequestOnError implements Fallback<Object> {
public Object createOrPropagate(Throwable t) throws Exception {
if (checkNotNull(t, "throwable") != null) {
return createPullRequestFromErrors(getErrors(t.getMessage()));
}
throw propagate(t);
}
}

public static final class MergeStatusOnError implements Fallback<Object> {
public static final class MergeStatusOnError implements Fallback<Object> {
public Object createOrPropagate(Throwable t) throws Exception {
if (checkNotNull(t, "throwable") != null) {
return createMergeStatusFromErrors(getErrors(t.getMessage()));
}
throw propagate(t);
}
}

public static List<Error> getErrors(String output) {
JsonElement element = parser.parse(output);
JsonObject object = element.getAsJsonObject();
JsonArray errorsArray = object.get("errors").getAsJsonArray();

List<Error> errors = Lists.newArrayList();
Iterator<JsonElement> it = errorsArray.iterator();
while (it.hasNext()) {
JsonObject obj = it.next().getAsJsonObject();
JsonElement context = obj.get("context");
JsonElement message = obj.get("message");
JsonElement exceptionName = obj.get("exceptionName");
Error error = Error.create(!context.isJsonNull() ? context.getAsString() : null,
!message.isJsonNull() ? message.getAsString() : null,
!exceptionName.isJsonNull() ? exceptionName.getAsString() : null);
errors.add(error);
}
}

return errors;
public static Branch createBranchFromErrors(List<Error> errors) {
return Branch.create(null, null, null, null, null, false, errors);
}

public static Tag createTagFromErrors(List<Error> errors) {
Expand All @@ -137,4 +130,25 @@ public static PullRequest createPullRequestFromErrors(List<Error> errors) {
public static MergeStatus createMergeStatusFromErrors(List<Error> errors) {
return MergeStatus.create(false, false, null, errors);
}

public static List<Error> getErrors(String output) {
JsonElement element = parser.parse(output);
JsonObject object = element.getAsJsonObject();
JsonArray errorsArray = object.get("errors").getAsJsonArray();

List<Error> errors = Lists.newArrayList();
Iterator<JsonElement> it = errorsArray.iterator();
while (it.hasNext()) {
JsonObject obj = it.next().getAsJsonObject();
JsonElement context = obj.get("context");
JsonElement message = obj.get("message");
JsonElement exceptionName = obj.get("exceptionName");
Error error = Error.create(!context.isJsonNull() ? context.getAsString() : null,
!message.isJsonNull() ? message.getAsString() : null,
!exceptionName.isJsonNull() ? exceptionName.getAsString() : null);
errors.add(error);
}

return errors;
}
}
60 changes: 60 additions & 0 deletions src/main/java/com/cdancy/bitbucket/rest/features/BranchApi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* 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.branch.Branch;
import com.cdancy.bitbucket.rest.domain.tags.Tag;
import com.cdancy.bitbucket.rest.fallbacks.BitbucketFallbacks;
import com.cdancy.bitbucket.rest.filters.BitbucketAuthentication;
import com.cdancy.bitbucket.rest.options.CreateBranch;
import com.cdancy.bitbucket.rest.options.CreateTag;
import org.jclouds.Fallbacks;
import org.jclouds.rest.annotations.*;
import org.jclouds.rest.binders.BindToJsonPayload;

import javax.inject.Named;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;

@Produces(MediaType.APPLICATION_JSON)
@RequestFilters(BitbucketAuthentication.class)
@Path("/rest/api/{jclouds.api-version}/projects")
public interface BranchApi {

@Named("branch:create")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/{project}/repos/{repo}/branches")
@Fallback(BitbucketFallbacks.BranchOnError.class)
@POST
Branch create(@PathParam("project") String project, @PathParam("repo") String repo, @BinderParam(BindToJsonPayload.class) CreateBranch createBranch);

@Named("branch:update-default")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/{project}/repos/{repo}/branches/default")
@Fallback(BitbucketFallbacks.FalseOnError.class)
@Payload("%7B \"id\": \"{id}\" %7D")
@PUT
boolean updateDefault(@PathParam("project") String project, @PathParam("repo") String repo, @PayloadParam("id") String id);

@Named("branch:get-default")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/{project}/repos/{repo}/branches/default")
@Fallback(BitbucketFallbacks.BranchOnError.class)
@GET
Branch getDefault(@PathParam("project") String project, @PathParam("repo") String repo);
}
42 changes: 42 additions & 0 deletions src/main/java/com/cdancy/bitbucket/rest/options/CreateBranch.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* 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.options;

import com.google.auto.value.AutoValue;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.SerializedNames;

@AutoValue
public abstract class CreateBranch {

public abstract String name();

public abstract String startPoint();

// defaults to value of name if null
@Nullable
public abstract String message();

CreateBranch() {
}

@SerializedNames({ "name", "startPoint", "message" })
public static CreateBranch create(String name, String startPoint, String message) {
return new AutoValue_CreateBranch(name, startPoint, message != null ? message : name);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* 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.branch.Branch;
import com.cdancy.bitbucket.rest.domain.tags.Tag;
import com.cdancy.bitbucket.rest.options.CreateBranch;
import com.cdancy.bitbucket.rest.options.CreateTag;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import static org.testng.Assert.*;

@Test(groups = "live", testName = "BranchApiLiveTest", singleThreaded = true)
public class BranchApiLiveTest extends BaseBitbucketApiLiveTest {

/*
String projectKey = randomStringLettersOnly();
String repoKey = randomStringLettersOnly();
String tagName = randomStringLettersOnly();
String commitHash = "";
*/

String projectKey = "TEST";
String repoKey = "dev";
String branchName = randomStringLettersOnly();
String commitHash = "d90ca08fa076e2e4c076592fce3832aba80a494f";

String defaultBranchId = "refs/heads/master";

@BeforeClass
public void init() {
Branch branch = api().getDefault(projectKey, repoKey);
assertNotNull(branch);
assertTrue(branch.errors().size() == 0);
defaultBranchId = branch.id();
}

@Test
public void testCreateBranch() {
CreateBranch createBranch = CreateBranch.create(branchName, commitHash, null);
Branch branch = api().create(projectKey, repoKey, createBranch);
assertNotNull(branch);
assertTrue(branch.errors().size() == 0);
assertTrue(branch.id().endsWith(branchName));
assertTrue(branch.latestCommit().equalsIgnoreCase(commitHash));
}

@Test (dependsOnMethods = "testCreateBranch")
public void testUpdateDefaultBranch() {
boolean success = api().updateDefault(projectKey, repoKey, "refs/heads/" + branchName);
assertTrue(success);
}

@Test (dependsOnMethods = "testUpdateDefaultBranch")
public void testGetNewDefaultBranch() {
Branch branch = api().getDefault(projectKey, repoKey);
assertNotNull(branch);
assertTrue(branch.errors().size() == 0);
assertNotNull(branch.id());
}

@AfterClass
public void fin() {
boolean success = api().updateDefault(projectKey, repoKey, defaultBranchId);
assertTrue(success);
}

private BranchApi api() { return api.branchApi(); }
}

0 comments on commit cd70952

Please sign in to comment.