-
Notifications
You must be signed in to change notification settings - Fork 619
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement approval for merge requests
- Loading branch information
Showing
13 changed files
with
319 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
81 changes: 81 additions & 0 deletions
81
src/main/java/com/dabsquared/gitlabjenkins/publisher/GitLabApproveMergeRequestPublisher.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package com.dabsquared.gitlabjenkins.publisher; | ||
|
||
import com.dabsquared.gitlabjenkins.gitlab.api.GitLabClient; | ||
import com.dabsquared.gitlabjenkins.gitlab.api.model.MergeRequest; | ||
import hudson.Extension; | ||
import hudson.model.AbstractProject; | ||
import hudson.model.Result; | ||
import hudson.model.Run; | ||
import hudson.model.TaskListener; | ||
import hudson.tasks.BuildStepDescriptor; | ||
import hudson.tasks.Publisher; | ||
import org.kohsuke.stapler.DataBoundConstructor; | ||
|
||
import javax.ws.rs.NotAuthorizedException; | ||
import javax.ws.rs.NotFoundException; | ||
import javax.ws.rs.ProcessingException; | ||
import javax.ws.rs.WebApplicationException; | ||
import java.util.logging.Level; | ||
import java.util.logging.Logger; | ||
|
||
public class GitLabApproveMergeRequestPublisher extends MergeRequestNotifier { | ||
private static final Logger LOGGER = Logger.getLogger(GitLabApproveMergeRequestPublisher.class.getName()); | ||
|
||
private final boolean approveUnstableBuilds; | ||
|
||
@DataBoundConstructor | ||
public GitLabApproveMergeRequestPublisher(boolean approveUnstableBuilds) { | ||
this.approveUnstableBuilds = approveUnstableBuilds; | ||
} | ||
|
||
@Extension | ||
public static class DescriptorImpl extends BuildStepDescriptor<Publisher> { | ||
|
||
@Override | ||
public boolean isApplicable(Class<? extends AbstractProject> aClass) { | ||
return true; | ||
} | ||
|
||
@Override | ||
public String getHelpFile() { | ||
return "/plugin/gitlab-plugin/help/help-approve-gitlab-mergerequest.html"; | ||
} | ||
|
||
@Override | ||
public String getDisplayName() { | ||
return Messages.GitLabApproveMergeRequestPublisher_DisplayName(); | ||
} | ||
} | ||
|
||
public boolean isApproveUnstableBuilds() { | ||
return approveUnstableBuilds; | ||
} | ||
|
||
@Override | ||
protected void perform(Run<?, ?> build, TaskListener listener, GitLabClient client, MergeRequest mergeRequest) { | ||
try { | ||
Result buildResult = build.getResult(); | ||
if (build.getResult() == Result.SUCCESS || (buildResult == Result.UNSTABLE && isApproveUnstableBuilds())) { | ||
client.approveMergeRequest(mergeRequest); | ||
} else { | ||
client.unapproveMergeRequest(mergeRequest); | ||
} | ||
} catch (NotFoundException e) { | ||
String message = String.format( | ||
"Failed to approve/unapprove merge request '%s' for project '%s'.\n" | ||
+ "Got unexpected 404. Does your GitLab edition or GitLab.com tier really support approvals, and are you are an eligible approver for this merge request?", mergeRequest.getIid(), mergeRequest.getProjectId()); | ||
listener.getLogger().printf(message); | ||
LOGGER.log(Level.WARNING, message, e); | ||
} catch (NotAuthorizedException e) { | ||
String message = String.format( | ||
"Failed to approve/unapprove merge request '%s' for project '%s'.\n" | ||
+ "Got unexpected 401, are you using the wrong credentials?", mergeRequest.getIid(), mergeRequest.getProjectId()); | ||
listener.getLogger().printf(message); | ||
LOGGER.log(Level.WARNING, message, e); | ||
} catch (WebApplicationException | ProcessingException e) { | ||
listener.getLogger().printf("Failed to approve/unapprove merge request for project '%s': %s%n", mergeRequest.getProjectId(), e.getMessage()); | ||
LOGGER.log(Level.SEVERE, String.format("Failed to approve/unapprove merge request for project '%s'", mergeRequest.getProjectId()), e); | ||
} | ||
} | ||
|
||
} |
8 changes: 8 additions & 0 deletions
8
...es/com/dabsquared/gitlabjenkins/publisher/GitLabApproveMergeRequestPublisher/config.jelly
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<?jelly escape-by-default='true'?> | ||
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form"> | ||
<f:advanced> | ||
<f:entry title="${%Approve unstable builds}" field="approveUnstableBuilds"> | ||
<f:checkbox default="false"/> | ||
</f:entry> | ||
</f:advanced> | ||
</j:jelly> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<div> | ||
Approve the GitLab merge request if builds succeeds, or revoke the approval if it fails.<br/> | ||
The approval will be visible merge request UI. You must have at least one GitLab connection/server configured in the Jenkins global configuration. | ||
<p> | ||
<b><span style="background-color:#ff5c33;">Feature availability warning:</span></b> | ||
Merge request approvals are not available in every <a href="https://docs.gitlab.com/ee/user/project/merge_requests/merge_request_approvals.html" target="_blank">GitLab Edition or GitLab.com tier</a>. | ||
</p> | ||
</div> |
123 changes: 123 additions & 0 deletions
123
...t/java/com/dabsquared/gitlabjenkins/publisher/GitLabApproveMergeRequestPublisherTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
package com.dabsquared.gitlabjenkins.publisher; | ||
|
||
import hudson.model.AbstractBuild; | ||
import hudson.model.BuildListener; | ||
import hudson.model.Result; | ||
import hudson.model.StreamBuildListener; | ||
import org.junit.*; | ||
import org.jvnet.hudson.test.JenkinsRule; | ||
import org.mockserver.client.server.MockServerClient; | ||
import org.mockserver.junit.MockServerRule; | ||
import org.mockserver.model.HttpRequest; | ||
|
||
import java.io.IOException; | ||
import java.io.UnsupportedEncodingException; | ||
import java.nio.charset.Charset; | ||
|
||
import static com.dabsquared.gitlabjenkins.publisher.TestUtility.*; | ||
import static org.mockserver.model.HttpRequest.request; | ||
import static org.mockserver.model.HttpResponse.response; | ||
|
||
public class GitLabApproveMergeRequestPublisherTest { | ||
|
||
@ClassRule | ||
public static MockServerRule mockServer = new MockServerRule(new Object()); | ||
|
||
@ClassRule | ||
public static JenkinsRule jenkins = new JenkinsRule(); | ||
|
||
private MockServerClient mockServerClient; | ||
private BuildListener listener; | ||
|
||
@BeforeClass | ||
public static void setupClass() throws IOException { | ||
setupGitLabConnections(jenkins, mockServer); | ||
} | ||
|
||
@Before | ||
public void setup() { | ||
listener = new StreamBuildListener(jenkins.createTaskListener().getLogger(), Charset.defaultCharset()); | ||
mockServerClient = new MockServerClient("localhost", mockServer.getPort()); | ||
} | ||
|
||
@After | ||
public void cleanup() { | ||
mockServerClient.reset(); | ||
} | ||
|
||
@Test | ||
public void matrixAggregatable() throws InterruptedException, IOException { | ||
verifyMatrixAggregatable(GitLabApproveMergeRequestPublisher.class, listener); | ||
} | ||
|
||
@Test | ||
public void success_approve_unstable_v4() throws IOException, InterruptedException { | ||
performApprovalAndVerify(mockSimpleBuild(GITLAB_CONNECTION_V4, Result.SUCCESS), "v4", MERGE_REQUEST_IID, true); | ||
} | ||
|
||
@Test | ||
public void success_v4() throws IOException, InterruptedException { | ||
performApprovalAndVerify(mockSimpleBuild(GITLAB_CONNECTION_V4, Result.SUCCESS), "v4", MERGE_REQUEST_IID, false); | ||
} | ||
|
||
@Test | ||
public void unstable_approve_unstable_v4() throws IOException, InterruptedException { | ||
performApprovalAndVerify(mockSimpleBuild(GITLAB_CONNECTION_V4, Result.UNSTABLE), "v4", MERGE_REQUEST_IID, true); | ||
} | ||
|
||
@Test | ||
public void unstable_dontapprove_v4() throws IOException, InterruptedException { | ||
performUnapprovalAndVerify(mockSimpleBuild(GITLAB_CONNECTION_V4, Result.UNSTABLE), "v4", MERGE_REQUEST_IID, false); | ||
} | ||
|
||
@Test | ||
public void failed_approve_unstable_v4() throws IOException, InterruptedException { | ||
performUnapprovalAndVerify(mockSimpleBuild(GITLAB_CONNECTION_V4, Result.FAILURE), "v4", MERGE_REQUEST_IID, true); | ||
} | ||
|
||
@Test | ||
public void failed_v4() throws IOException, InterruptedException { | ||
performUnapprovalAndVerify(mockSimpleBuild(GITLAB_CONNECTION_V4, Result.FAILURE), "v4", MERGE_REQUEST_IID, false); | ||
} | ||
|
||
private void performApprovalAndVerify(AbstractBuild build, String apiLevel, int mergeRequestId, boolean approveUnstable) throws InterruptedException, IOException { | ||
GitLabApproveMergeRequestPublisher publisher = preparePublisher(new GitLabApproveMergeRequestPublisher(approveUnstable), build); | ||
publisher.perform(build, null, listener); | ||
|
||
mockServerClient.verify(prepareSendApprovalWithSuccessResponse(build, apiLevel, mergeRequestId)); | ||
} | ||
|
||
private void performUnapprovalAndVerify(AbstractBuild build, String apiLevel, int mergeRequestId, boolean approveUnstable) throws InterruptedException, IOException { | ||
GitLabApproveMergeRequestPublisher publisher = preparePublisher(new GitLabApproveMergeRequestPublisher(approveUnstable), build); | ||
publisher.perform(build, null, listener); | ||
|
||
mockServerClient.verify(prepareSendUnapprovalWithSuccessResponse(build, apiLevel, mergeRequestId)); | ||
} | ||
|
||
private HttpRequest prepareSendApprovalWithSuccessResponse(AbstractBuild build, String apiLevel, int mergeRequestId) throws UnsupportedEncodingException { | ||
HttpRequest approvalRequest = prepareSendApproval(apiLevel, mergeRequestId); | ||
mockServerClient.when(approvalRequest).respond(response().withStatusCode(200)); | ||
return approvalRequest; | ||
} | ||
|
||
private HttpRequest prepareSendUnapprovalWithSuccessResponse(AbstractBuild build, String apiLevel, int mergeRequestId) throws UnsupportedEncodingException { | ||
HttpRequest unapprovalRequest = prepareSendUnapproval(apiLevel, mergeRequestId); | ||
mockServerClient.when(unapprovalRequest).respond(response().withStatusCode(200)); | ||
return unapprovalRequest; | ||
} | ||
|
||
private HttpRequest prepareSendApproval(final String apiLevel, int mergeRequestId) throws UnsupportedEncodingException { | ||
return request() | ||
.withPath("/gitlab/api/" + apiLevel + "/projects/" + PROJECT_ID + "/merge_requests/" + mergeRequestId + "/approve") | ||
.withMethod("POST") | ||
.withHeader("PRIVATE-TOKEN", "secret"); | ||
} | ||
|
||
private HttpRequest prepareSendUnapproval(final String apiLevel, int mergeRequestId) throws UnsupportedEncodingException { | ||
return request() | ||
.withPath("/gitlab/api/" + apiLevel + "/projects/" + PROJECT_ID + "/merge_requests/" + mergeRequestId + "/unapprove") | ||
.withMethod("POST") | ||
.withHeader("PRIVATE-TOKEN", "secret"); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters