Skip to content

Commit ecfa747

Browse files
committed
Implement approval for merge requests
1 parent 81f9ffd commit ecfa747

File tree

13 files changed

+319
-0
lines changed

13 files changed

+319
-0
lines changed

src/main/java/com/dabsquared/gitlabjenkins/gitlab/api/GitLabClient.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ public interface GitLabClient {
3636

3737
void deleteMergeRequestEmoji(MergeRequest mr, Integer awardId);
3838

39+
void approveMergeRequest(MergeRequest mr);
40+
41+
void unapproveMergeRequest(MergeRequest mr);
42+
3943
List<MergeRequest> getMergeRequests(String projectId, State state, int page, int perPage);
4044

4145
List<Branch> getBranches(String projectId);

src/main/java/com/dabsquared/gitlabjenkins/gitlab/api/impl/AutodetectingGitLabClient.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,32 @@ Void execute(GitLabClient client) {
204204
);
205205
}
206206

207+
@Override
208+
public void approveMergeRequest(final MergeRequest mr) {
209+
execute(
210+
new GitLabOperation<Void>() {
211+
@Override
212+
Void execute(GitLabClient client) {
213+
client.approveMergeRequest(mr);
214+
return null;
215+
}
216+
}
217+
);
218+
}
219+
220+
@Override
221+
public void unapproveMergeRequest(final MergeRequest mr) {
222+
execute(
223+
new GitLabOperation<Void>() {
224+
@Override
225+
Void execute(GitLabClient client) {
226+
client.unapproveMergeRequest(mr);
227+
return null;
228+
}
229+
}
230+
);
231+
}
232+
207233
@Override
208234
public List<MergeRequest> getMergeRequests(final String projectId, final State state, final int page, final int perPage) {
209235
return execute(

src/main/java/com/dabsquared/gitlabjenkins/gitlab/api/impl/GitLabApiProxy.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ interface GitLabApiProxy {
3636

3737
void deleteMergeRequestEmoji(Integer projectId, Integer mergeRequestId, Integer awardId);
3838

39+
void approveMergeRequest(Integer projectId, Integer mergeRequestId);
40+
41+
void unapproveMergeRequest(Integer projectId, Integer mergeRequestId);
42+
3943
List<MergeRequest> getMergeRequests(String projectId, State state, int page, int perPage);
4044

4145
List<Branch> getBranches(String projectId);

src/main/java/com/dabsquared/gitlabjenkins/gitlab/api/impl/ResteasyGitLabClient.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,16 @@ public void deleteMergeRequestEmoji(MergeRequest mr, Integer awardId) {
9595
api.deleteMergeRequestEmoji(mr.getProjectId(), mergeRequestIdProvider.apply(mr), awardId);
9696
}
9797

98+
@Override
99+
public void approveMergeRequest(MergeRequest mr) {
100+
api.approveMergeRequest(mr.getProjectId(), mergeRequestIdProvider.apply(mr));
101+
}
102+
103+
@Override
104+
public void unapproveMergeRequest(MergeRequest mr) {
105+
api.unapproveMergeRequest(mr.getProjectId(), mergeRequestIdProvider.apply(mr));
106+
}
107+
98108
@Override
99109
public List<MergeRequest> getMergeRequests(String projectId, State state, int page, int perPage) {
100110
return api.getMergeRequests(projectId, state, page, perPage);

src/main/java/com/dabsquared/gitlabjenkins/gitlab/api/impl/V3GitLabApiProxy.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,26 @@ MergeRequest createMergeRequest(
4646
@FormParam("target_branch") String targetBranch,
4747
@FormParam("title") String title);
4848

49+
/**
50+
* Unsupported in API v3
51+
*/
52+
@POST
53+
@Produces(MediaType.APPLICATION_JSON)
54+
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
55+
@Path("/projects/{projectId}/merge_requests/{mergeRequestIid}/approve")
56+
@Override
57+
void approveMergeRequest(@PathParam("projectId") Integer projectId, @PathParam("mergeRequestIid") Integer mergeRequestId);
58+
59+
/**
60+
* Unsupported in API v3
61+
*/
62+
@POST
63+
@Produces(MediaType.APPLICATION_JSON)
64+
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
65+
@Path("/projects/{projectId}/merge_requests/{mergeRequestIid}/unapprove")
66+
@Override
67+
void unapproveMergeRequest(Integer projectId, Integer mergeRequestId);
68+
4969
@GET
5070
@Produces(MediaType.APPLICATION_JSON)
5171
@Path("/projects/{projectName}")

src/main/java/com/dabsquared/gitlabjenkins/gitlab/api/impl/V4GitLabApiProxy.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,20 @@ MergeRequest createMergeRequest(
4646
@FormParam("target_branch") String targetBranch,
4747
@FormParam("title") String title);
4848

49+
@POST
50+
@Produces(MediaType.APPLICATION_JSON)
51+
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
52+
@Path("/projects/{projectId}/merge_requests/{mergeRequestIid}/approve")
53+
@Override
54+
void approveMergeRequest(@PathParam("projectId") Integer projectId, @PathParam("mergeRequestIid") Integer mergeRequestId);
55+
56+
@POST
57+
@Produces(MediaType.APPLICATION_JSON)
58+
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
59+
@Path("/projects/{projectId}/merge_requests/{mergeRequestIid}/unapprove")
60+
@Override
61+
void unapproveMergeRequest(@PathParam("projectId") Integer projectId, @PathParam("mergeRequestIid") Integer mergeRequestId);
62+
4963
@GET
5064
@Produces(MediaType.APPLICATION_JSON)
5165
@Path("/projects/{projectName}")
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package com.dabsquared.gitlabjenkins.publisher;
2+
3+
import com.dabsquared.gitlabjenkins.gitlab.api.GitLabClient;
4+
import com.dabsquared.gitlabjenkins.gitlab.api.model.MergeRequest;
5+
import hudson.Extension;
6+
import hudson.model.AbstractProject;
7+
import hudson.model.Result;
8+
import hudson.model.Run;
9+
import hudson.model.TaskListener;
10+
import hudson.tasks.BuildStepDescriptor;
11+
import hudson.tasks.Publisher;
12+
import org.kohsuke.stapler.DataBoundConstructor;
13+
14+
import javax.ws.rs.NotAuthorizedException;
15+
import javax.ws.rs.NotFoundException;
16+
import javax.ws.rs.ProcessingException;
17+
import javax.ws.rs.WebApplicationException;
18+
import java.util.logging.Level;
19+
import java.util.logging.Logger;
20+
21+
public class GitLabApproveMergeRequestPublisher extends MergeRequestNotifier {
22+
private static final Logger LOGGER = Logger.getLogger(GitLabApproveMergeRequestPublisher.class.getName());
23+
24+
private final boolean approveUnstableBuilds;
25+
26+
@DataBoundConstructor
27+
public GitLabApproveMergeRequestPublisher(boolean approveUnstableBuilds) {
28+
this.approveUnstableBuilds = approveUnstableBuilds;
29+
}
30+
31+
@Extension
32+
public static class DescriptorImpl extends BuildStepDescriptor<Publisher> {
33+
34+
@Override
35+
public boolean isApplicable(Class<? extends AbstractProject> aClass) {
36+
return true;
37+
}
38+
39+
@Override
40+
public String getHelpFile() {
41+
return "/plugin/gitlab-plugin/help/help-approve-gitlab-mergerequest.html";
42+
}
43+
44+
@Override
45+
public String getDisplayName() {
46+
return Messages.GitLabApproveMergeRequestPublisher_DisplayName();
47+
}
48+
}
49+
50+
public boolean isApproveUnstableBuilds() {
51+
return approveUnstableBuilds;
52+
}
53+
54+
@Override
55+
protected void perform(Run<?, ?> build, TaskListener listener, GitLabClient client, MergeRequest mergeRequest) {
56+
try {
57+
Result buildResult = build.getResult();
58+
if (build.getResult() == Result.SUCCESS || (buildResult == Result.UNSTABLE && isApproveUnstableBuilds())) {
59+
client.approveMergeRequest(mergeRequest);
60+
} else {
61+
client.unapproveMergeRequest(mergeRequest);
62+
}
63+
} catch (NotFoundException e) {
64+
String message = String.format(
65+
"Failed to approve/unapprove merge request '%s' for project '%s'.\n"
66+
+ "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());
67+
listener.getLogger().printf(message);
68+
LOGGER.log(Level.WARNING, message, e);
69+
} catch (NotAuthorizedException e) {
70+
String message = String.format(
71+
"Failed to approve/unapprove merge request '%s' for project '%s'.\n"
72+
+ "Got unexpected 401, are you using the wrong credentials?", mergeRequest.getIid(), mergeRequest.getProjectId());
73+
listener.getLogger().printf(message);
74+
LOGGER.log(Level.WARNING, message, e);
75+
} catch (WebApplicationException | ProcessingException e) {
76+
listener.getLogger().printf("Failed to approve/unapprove merge request for project '%s': %s%n", mergeRequest.getProjectId(), e.getMessage());
77+
LOGGER.log(Level.SEVERE, String.format("Failed to approve/unapprove merge request for project '%s'", mergeRequest.getProjectId()), e);
78+
}
79+
}
80+
81+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?jelly escape-by-default='true'?>
2+
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
3+
<f:advanced>
4+
<f:entry title="${%Approve unstable builds}" field="approveUnstableBuilds">
5+
<f:checkbox default="false"/>
6+
</f:entry>
7+
</f:advanced>
8+
</j:jelly>

src/main/resources/com/dabsquared/gitlabjenkins/publisher/Messages.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ name.required=Build name required.
33
GitLabMessagePublisher.DisplayName=Add note with build status on GitLab merge requests
44
GitLabVotePublisher.DisplayName=Add vote for build status on GitLab merge requests
55
GitLabAcceptMergeRequestPublisher.DisplayName=Accept GitLab merge request on success
6+
GitLabApproveMergeRequestPublisher.DisplayName=Approve / Revoke approval on GitLab merge request (EE-only)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<div>
2+
Approve the GitLab merge request if builds succeeds, or revoke the approval if it fails.<br/>
3+
The approval will be visible in the merge request UI. You must have at least one GitLab connection/server configured in the Jenkins global configuration.
4+
<p>
5+
<b><span style="background-color:#ff5c33;">Feature availability warning:</span></b>
6+
Merge request approvals were introduced in GitLab EE 9.0. They 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>.
7+
</p>
8+
</div>

0 commit comments

Comments
 (0)