Unverified Commit f9fbd882 authored by Mike Cook's avatar Mike Cook Committed by GitHub
Browse files

Add method to update code_owner_approval_required flag to Protected Branches API (#870)

parent 0ec95c19
...@@ -26,6 +26,9 @@ local.properties ...@@ -26,6 +26,9 @@ local.properties
.classpath .classpath
.settings/ .settings/
.loadpath .loadpath
### Visual Studio Code ###
.vscode
# External tool builders # External tool builders
.externalToolBuilders/ .externalToolBuilders/
...@@ -45,7 +48,7 @@ target/ ...@@ -45,7 +48,7 @@ target/
# Test properties file for gitlab4j # Test properties file for gitlab4j
test-gitlab4j.properties test-gitlab4j.properties
!src/test/resoures/test-gitlab4j.properties !src/test/resources/test-gitlab4j.properties
# git-changelog plugin # # git-changelog plugin #
.okhttpcache .okhttpcache
...@@ -272,6 +272,42 @@ public abstract class AbstractApi implements Constants { ...@@ -272,6 +272,42 @@ public abstract class AbstractApi implements Constants {
} }
} }
/**
* Perform an HTTP PATCH call with the specified query parameters and path objects, returning
* a ClientResponse instance with the data returned from the endpoint.
*
* @param expectedStatus the HTTP status that should be returned from the server
* @param queryParams multivalue map of request parameters
* @param pathArgs variable list of arguments used to build the URI
* @return a ClientResponse instance with the data returned from the endpoint
* @throws GitLabApiException if any exception occurs during execution
*/
protected Response patch(Response.Status expectedStatus, MultivaluedMap<String, String> queryParams, Object... pathArgs) throws GitLabApiException {
try {
return validate(getApiClient().patch(queryParams, pathArgs), expectedStatus);
} catch (Exception e) {
throw handle(e);
}
}
/**
* Perform an HTTP PATCH call with the specified query parameters and URL, returning
* a ClientResponse instance with the data returned from the endpoint.
*
* @param expectedStatus the HTTP status that should be returned from the server
* @param queryParams multivalue map of request parameters
* @param url the fully formed path to the GitLab API endpoint
* @return a ClientResponse instance with the data returned from the endpoint
* @throws GitLabApiException if any exception occurs during execution
*/
protected Response patch(Response.Status expectedStatus, MultivaluedMap<String, String> queryParams, URL url) throws GitLabApiException {
try {
return validate(getApiClient().patch(queryParams, url), expectedStatus);
} catch (Exception e) {
throw handle(e);
}
}
/** /**
* Perform an HTTP POST call with the specified form data and path objects, returning * Perform an HTTP POST call with the specified form data and path objects, returning
* a ClientResponse instance with the data returned from the endpoint. * a ClientResponse instance with the data returned from the endpoint.
......
...@@ -287,8 +287,8 @@ public class GitLabApiClient implements AutoCloseable { ...@@ -287,8 +287,8 @@ public class GitLabApiClient implements AutoCloseable {
* @param readTimeout the per request read timeout in milliseconds, can be null to use default * @param readTimeout the per request read timeout in milliseconds, can be null to use default
*/ */
void setRequestTimeout(Integer connectTimeout, Integer readTimeout) { void setRequestTimeout(Integer connectTimeout, Integer readTimeout) {
this.connectTimeout = connectTimeout; this.connectTimeout = connectTimeout;
this.readTimeout = readTimeout; this.readTimeout = readTimeout;
} }
/** /**
...@@ -470,6 +470,35 @@ public class GitLabApiClient implements AutoCloseable { ...@@ -470,6 +470,35 @@ public class GitLabApiClient implements AutoCloseable {
return (invocation(url, queryParams).head()); return (invocation(url, queryParams).head());
} }
/**
* Perform an HTTP PATCH call with the specified query parameters and path objects, returning
* a ClientResponse instance with the data returned from the endpoint.
*
* @param queryParams multivalue map of request parameters
* @param pathArgs variable list of arguments used to build the URI
* @return a ClientResponse instance with the data returned from the endpoint
* @throws IOException if an error occurs while constructing the URL
*/
protected Response patch(MultivaluedMap<String, String> queryParams, Object... pathArgs) throws IOException {
URL url = getApiUrl(pathArgs);
return (patch(queryParams, url));
}
/**
* Perform an HTTP PATCH call with the specified query parameters and URL, returning
* a ClientResponse instance with the data returned from the endpoint.
*
* @param queryParams multivalue map of request parameters
* @param url the fully formed path to the GitLab API endpoint
* @return a ClientResponse instance with the data returned from the endpoint
*/
protected Response patch(MultivaluedMap<String, String> queryParams, URL url) {
Entity<?> empty = Entity.text("");
// use "X-HTTP-Method-Override" header on POST to override to unsupported PATCH
return (invocation(url, queryParams)
.header("X-HTTP-Method-Override", "PATCH").post(empty));
}
/** /**
* Perform an HTTP POST call with the specified form data and path objects, returning * Perform an HTTP POST call with the specified form data and path objects, returning
* a ClientResponse instance with the data returned from the endpoint. * a ClientResponse instance with the data returned from the endpoint.
...@@ -918,7 +947,7 @@ public class GitLabApiClient implements AutoCloseable { ...@@ -918,7 +947,7 @@ public class GitLabApiClient implements AutoCloseable {
// Ignore differences between given hostname and certificate hostname // Ignore differences between given hostname and certificate hostname
HostnameVerifier hostnameVerifier = new HostnameVerifier() { HostnameVerifier hostnameVerifier = new HostnameVerifier() {
@Override @Override
public boolean verify(String hostname, SSLSession session) { public boolean verify(String hostname, SSLSession session) {
return true; return true;
} }
}; };
......
...@@ -154,8 +154,8 @@ public class ProtectedBranchesApi extends AbstractApi { ...@@ -154,8 +154,8 @@ public class ProtectedBranchesApi extends AbstractApi {
* @throws GitLabApiException if any exception occurs * @throws GitLabApiException if any exception occurs
*/ */
public ProtectedBranch protectBranch(Object projectIdOrPath, String branchName, public ProtectedBranch protectBranch(Object projectIdOrPath, String branchName,
AccessLevel pushAccessLevel, AccessLevel mergeAccessLevel, AccessLevel unprotectAccessLevel, AccessLevel pushAccessLevel, AccessLevel mergeAccessLevel, AccessLevel unprotectAccessLevel,
Boolean codeOwnerApprovalRequired) throws GitLabApiException { Boolean codeOwnerApprovalRequired) throws GitLabApiException {
Form formData = new GitLabApiForm() Form formData = new GitLabApiForm()
.withParam("name", branchName, true) .withParam("name", branchName, true)
.withParam("push_access_level", pushAccessLevel) .withParam("push_access_level", pushAccessLevel)
...@@ -184,10 +184,10 @@ public class ProtectedBranchesApi extends AbstractApi { ...@@ -184,10 +184,10 @@ public class ProtectedBranchesApi extends AbstractApi {
* @throws GitLabApiException if any exception occurs * @throws GitLabApiException if any exception occurs
*/ */
public ProtectedBranch protectBranch(Object projectIdOrPath, String branchName, public ProtectedBranch protectBranch(Object projectIdOrPath, String branchName,
Integer allowedToPushUserId, Integer allowedToMergeUserId, Integer allowedToUnprotectUserId, Integer allowedToPushUserId, Integer allowedToMergeUserId, Integer allowedToUnprotectUserId,
Boolean codeOwnerApprovalRequired) throws GitLabApiException { Boolean codeOwnerApprovalRequired) throws GitLabApiException {
Form formData = new GitLabApiForm() Form formData = new GitLabApiForm()
.withParam("name", branchName, true) .withParam("name", branchName, true)
.withParam("allowed_to_push[][user_id]", allowedToPushUserId) .withParam("allowed_to_push[][user_id]", allowedToPushUserId)
.withParam("allowed_to_merge[][user_id]", allowedToMergeUserId) .withParam("allowed_to_merge[][user_id]", allowedToMergeUserId)
...@@ -215,22 +215,46 @@ public class ProtectedBranchesApi extends AbstractApi { ...@@ -215,22 +215,46 @@ public class ProtectedBranchesApi extends AbstractApi {
* @throws GitLabApiException if any exception occurs * @throws GitLabApiException if any exception occurs
*/ */
public ProtectedBranch protectBranch(Object projectIdOrPath, String branchName, public ProtectedBranch protectBranch(Object projectIdOrPath, String branchName,
AllowedTo allowedToPush, AllowedTo allowedToMerge, AllowedTo allowedToUnprotect, AllowedTo allowedToPush, AllowedTo allowedToMerge, AllowedTo allowedToUnprotect,
Boolean codeOwnerApprovalRequired) throws GitLabApiException { Boolean codeOwnerApprovalRequired) throws GitLabApiException {
GitLabApiForm formData = new GitLabApiForm() GitLabApiForm formData = new GitLabApiForm()
.withParam("name", branchName, true) .withParam("name", branchName, true)
.withParam("code_owner_approval_required", codeOwnerApprovalRequired); .withParam("code_owner_approval_required", codeOwnerApprovalRequired);
if (allowedToPush != null) if (allowedToPush != null)
allowedToPush.getForm(formData, "allowed_to_push"); allowedToPush.getForm(formData, "allowed_to_push");
if (allowedToMerge != null) if (allowedToMerge != null)
allowedToMerge.getForm(formData, "allowed_to_merge"); allowedToMerge.getForm(formData, "allowed_to_merge");
if (allowedToUnprotect != null) if (allowedToUnprotect != null)
allowedToUnprotect.getForm(formData, "allowed_to_unprotect"); allowedToUnprotect.getForm(formData, "allowed_to_unprotect");
Response response = post(Response.Status.CREATED, formData.asMap(), Response response = post(Response.Status.CREATED, formData.asMap(),
"projects", getProjectIdOrPath(projectIdOrPath), "protected_branches"); "projects", getProjectIdOrPath(projectIdOrPath), "protected_branches");
return (response.readEntity(ProtectedBranch.class)); return (response.readEntity(ProtectedBranch.class));
} }
/**
* Sets the code_owner_approval_required flag on the specified protected branch.
*
* <p>NOTE: This method is only available in GitLab Premium or higher.</p>
*
* <pre><code>GitLab Endpoint: PATCH /projects/:id/protected_branches/:branch_name?code_owner_approval_required=true</code></pre>
*
* @param projectIdOrPath the project in the form of an Long(ID), String(path), or Project instance
* @param branchName the name of the branch to protect, can be a wildcard
* @param codeOwnerApprovalRequired prevent pushes to this branch if it matches an item in the CODEOWNERS file.
* @return the branch info for the protected branch
* @throws GitLabApiException if any exception occurs
*/
public ProtectedBranch setCodeOwnerApprovalRequired(Object projectIdOrPath, String branchName,
Boolean codeOwnerApprovalRequired) throws GitLabApiException {
Form formData = new GitLabApiForm()
.withParam("code_owner_approval_required", codeOwnerApprovalRequired);
Response response = patch(Response.Status.OK, formData.asMap(),
"projects", this.getProjectIdOrPath(projectIdOrPath),
"protected_branches", urlEncode(branchName));
return (response.readEntity(ProtectedBranch.class));
}
} }
package org.gitlab4j.api; package org.gitlab4j.api;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assumptions.assumeTrue; import static org.junit.jupiter.api.Assumptions.assumeTrue;
...@@ -45,7 +47,7 @@ public class TestProtectedBranchesApi extends AbstractIntegrationTest { ...@@ -45,7 +47,7 @@ public class TestProtectedBranchesApi extends AbstractIntegrationTest {
@BeforeAll @BeforeAll
public static void setup() { public static void setup() {
// Must setup the connection to the GitLab test server and get the test Project instance // Must setup the connection to the GitLab test server and get the test Project instance
gitLabApi = baseTestSetup(); gitLabApi = baseTestSetup();
testProject = getTestProject(); testProject = getTestProject();
} }
...@@ -124,4 +126,20 @@ public class TestProtectedBranchesApi extends AbstractIntegrationTest { ...@@ -124,4 +126,20 @@ public class TestProtectedBranchesApi extends AbstractIntegrationTest {
assertTrue(branches.stream() assertTrue(branches.stream()
.anyMatch((protectedBranch) -> protectedBranch.getName().equals(TEST_BRANCH_NAME))); .anyMatch((protectedBranch) -> protectedBranch.getName().equals(TEST_BRANCH_NAME)));
} }
@Test
public void testSetCodeOwnerApprovalRequired() throws GitLabApiException {
assumeTrue(testProject != null);
ProtectedBranch branch = gitLabApi.getProtectedBranchesApi().getProtectedBranch(testProject, TEST_BRANCH_NAME);
assertNotNull(branch);
// current version returns null, but will return boolean (false) with newer Premium
assertFalse(branch.getCodeOwnerApprovalRequired() != null);
// current version returns 404, but will return branch with "code_owner_approval_required = true" with newer Premium
GitLabApiException gae = assertThrowsExactly(GitLabApiException.class,
() -> gitLabApi.getProtectedBranchesApi().setCodeOwnerApprovalRequired(testProject, TEST_BRANCH_NAME, true));
assertTrue(gae.getHttpStatus() == 404);
}
} }
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment