From 4cea5f983a5f8ada8b54613f13d6dee85357f028 Mon Sep 17 00:00:00 2001 From: Patrizio Bonzani Date: Thu, 23 Aug 2018 08:10:58 +0200 Subject: [PATCH 1/2] Merge request discussion API implementation. --- src/main/java/org/gitlab/api/GitlabAPI.java | 252 ++++++++++++++++++ .../gitlab/api/models/GitlabDiscussion.java | 39 +++ 2 files changed, 291 insertions(+) create mode 100644 src/main/java/org/gitlab/api/models/GitlabDiscussion.java diff --git a/src/main/java/org/gitlab/api/GitlabAPI.java b/src/main/java/org/gitlab/api/GitlabAPI.java index f2cd7888..697d9669 100644 --- a/src/main/java/org/gitlab/api/GitlabAPI.java +++ b/src/main/java/org/gitlab/api/GitlabAPI.java @@ -1641,6 +1641,258 @@ public List getAllNotes(GitlabMergeRequest mergeRequest) { return retrieve().getAll(tailUrl, GitlabNote[].class); } + /** + * Get a discussion by id from a merge request. + * https://docs.gitlab.com/ce/api/discussions.html#get-single-merge-request-discussion + * + * @param mergeRequest to fetch the discussion from. + * @param discussionId The id of the discussion. + * + * @return The GitLab discussion identified by the given id. + * @throws IOException on a GitLab api call error + */ + public GitlabDiscussion getDiscussion(GitlabMergeRequest mergeRequest, int discussionId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + + GitlabDiscussion.URL + "/" + discussionId; + return retrieve().to(tailUrl, GitlabDiscussion.class); + } + + /** + * Get the discussions from a merge request. + * https://docs.gitlab.com/ce/api/discussions.html#list-project-merge-request-discussions + * + * @param mergeRequest to fetch the discussions from. + * + * @return The discussions contained in the given merge request. + * @throws IOException on a GitLab api call error + */ + public List getDiscussions(GitlabMergeRequest mergeRequest) throws IOException { + String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + + GitlabDiscussion.URL; + + GitlabDiscussion[] discussions = retrieve().to(tailUrl, GitlabDiscussion[].class); + return Arrays.asList(discussions); + } + + /** + * Create a discussion just with the required arguments. + * + * @param mergeRequest The merge request where the discussion is created. + * @param body The content of a discussion. + * @param positionBaseSha The base commit SHA in the source branch. + * @param positionStartSha The SHA referencing the commit in the target branch. + * @param positionHeadSha The SHA referencing the HEAD of this merge request. + * + * @return The created discussion object. + * @throws IOException on a GitLab api call error + */ + public GitlabDiscussion createDiscussion(GitlabMergeRequest mergeRequest, + String body, String positionBaseSha, String positionStartSha, + String positionHeadSha) throws IOException { + return createTextDiscussion(mergeRequest, body, null, + positionBaseSha, positionStartSha, positionHeadSha, + null, null, null, null); + } + + /** + * Create a new discussion with position type text on the given merge request. + * https://docs.gitlab.com/ce/api/discussions.html#create-new-merge-request-discussion + * + * @param mergeRequest The merge request where the discussion is created. + * @param body The content of a discussion. + * @param position The position when creating a diff note. (hash) + * @param positionBaseSha The base commit SHA in the source branch. + * @param positionStartSha The SHA referencing the commit in the target branch. + * @param positionHeadSha The SHA referencing the HEAD of this merge request. + * @param positionNewPath The file path after the change. + * @param positionNewLine The Line number after change + * @param positionOldPath The file path before the change. + * @param positionOldLine The Line number before change. + * + * @return The created discussion object. + * @throws IOException on a GitLab api call error + */ + public GitlabDiscussion createTextDiscussion(GitlabMergeRequest mergeRequest, + String body, String position, String positionBaseSha, String positionStartSha, + String positionHeadSha, String positionNewPath, Integer positionNewLine, + String positionOldPath, Integer positionOldLine) throws IOException { + checkRequiredCreateDiscussionArguments(body, positionBaseSha, positionStartSha, positionHeadSha); + + String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + + GitlabDiscussion.URL; + + return dispatch() + .with("body", body) + .with("position", position) + .with("position[base_sha]", positionBaseSha) + .with("position[start_sha]", positionStartSha) + .with("position[head_sha]", positionHeadSha) + .with("position[position_type]", "text") + .with("position[new_path]", positionNewPath) + .with("position[new_line]", positionNewLine) + .with("position[old_path]", positionOldPath) + .with("position[old_line]", positionOldLine) + .to(tailUrl, GitlabDiscussion.class); + } + + /** + * Create a new discussion with position type image on the given merge request. + * https://docs.gitlab.com/ce/api/discussions.html#create-new-merge-request-discussion + * + * @param mergeRequest The merge request where the discussion is created. + * @param body The content of a discussion. + * @param position The position when creating a diff note. (hash) + * @param positionBaseSha The base commit SHA in the source branch. + * @param positionStartSha The SHA referencing the commit in the target branch. + * @param positionHeadSha The SHA referencing the HEAD of this merge request. + * @param positionNewPath The file path after the change. + * @param positionOldPath The file path before the change. + * @param positionWidth The width of the image. + * @param positionHeight The height of the image. + * @param positionX The X coordinate. + * @param positionY The Y coordinate. + * + * @return The created discussion object. + * @throws IOException on a GitLab api call error + */ + public GitlabDiscussion createImageDiscussion(GitlabMergeRequest mergeRequest, + String body, String position, String positionBaseSha, String positionStartSha, + String positionHeadSha, String positionNewPath, String positionOldPath, + Integer positionWidth, Integer positionHeight, Integer positionX, Integer positionY) throws IOException { + checkRequiredCreateDiscussionArguments(body, positionBaseSha, positionStartSha, positionHeadSha); + + String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + + GitlabDiscussion.URL; + + return dispatch() + .with("body", body) + .with("position", position) + .with("position[base_sha]", positionBaseSha) + .with("position[start_sha]", positionStartSha) + .with("position[head_sha]", positionHeadSha) + .with("position[position_type]", "image") + .with("position[new_path]", positionNewPath) + .with("position[old_path]", positionOldPath) + .with("position[width]", positionWidth) + .with("position[height]", positionHeight) + .with("position[x]", positionX) + .with("position[y]", positionY) + .to(tailUrl, GitlabDiscussion.class); + } + + /** + * Check if the required arguments to create a discussion are present and contain values. + * + * @param body The content of a discussion. + * @param positionBaseSha The base commit SHA in the source branch. + * @param positionStartSha The SHA referencing commit in target branch + * @param positionHeadSha The SHA referencing HEAD of this merge request + */ + private void checkRequiredCreateDiscussionArguments(String body, String positionBaseSha, + String positionStartSha, String positionHeadSha) { + if (body == null || body.isEmpty()) { + throw new IllegalArgumentException("Missing required argument 'body'!"); + } else if (positionBaseSha == null || positionBaseSha.isEmpty()) { + throw new IllegalArgumentException("Missing required argument 'positionBaseSha'!"); + } else if (positionStartSha == null || positionStartSha.isEmpty()) { + throw new IllegalArgumentException("Missing required argument 'positionStartSha'!"); + } else if (positionHeadSha == null || positionHeadSha.isEmpty()) { + throw new IllegalArgumentException("Missing required argument 'positionHeadSha'!"); + } + } + + /** + * Resolve or unresolve a whole discussion of a merge request. + * + * @param mergeRequest The merge request of the discussion. + * @param discussionId The id of the discussion to resolve. + * @param resolved Resolve or unresolve the note. + * + * @return The discussion object. + * @throws IOException on a GitLab api call error + */ + public GitlabDiscussion resolveDiscussion(GitlabMergeRequest mergeRequest, int discussionId, + boolean resolved) throws IOException { + String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + + GitlabDiscussion.URL + "/" + discussionId; + return retrieve().method(PUT) + .with("resolved", resolved) + .to(tailUrl, GitlabDiscussion.class); + } + + /** + * Add a note to existing merge request discussion. + * + * @param mergeRequest The merge request of the discussion. + * @param discussionId The id of the discussion to add a note to. + * @param body The content of the discussion. + * + * @return The added note object. + * @throws IOException on a GitLab api call error + */ + public GitlabNote addDiscussionNote(GitlabMergeRequest mergeRequest, int discussionId, + String body) throws IOException { + String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + + GitlabDiscussion.URL + "/" + discussionId + + GitlabNote.URL; + return dispatch().with("body", body).to(tailUrl, GitlabNote.class); + } + + /** + * Modify or resolve an existing discussion note of the given merge request. + * + * @param mergeRequest The merge request of the discussion. + * @param discussionId The id of the discussion to modify. + * @param noteId The id of the discussion note. + * @param body The content of the discussion. + * @param resolved Resolve or unresolve the note. + * + * @return The modified note object. + * @throws IOException on a GitLab api call error + */ + public GitlabNote modifyDiscussionNote(GitlabMergeRequest mergeRequest, int discussionId, + int noteId, String body, Boolean resolved) throws IOException { + boolean bodyHasValue = false; + if (body != null && !body.isEmpty()) { + bodyHasValue = true; + } + if ((!bodyHasValue && resolved == null) || (bodyHasValue && resolved != null)) { + throw new IllegalArgumentException("Exactly one of body or resolved must be set!"); + } + String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + + GitlabDiscussion.URL + "/" + discussionId + + GitlabNote.URL + "/" + noteId; + return retrieve().method(PUT) + .with("body", body) + .with("resolved", resolved) + .to(tailUrl, GitlabNote.class); + } + + /** + * Delete a discussion note of a merge request. + * + * @param mergeRequest The merge request of the discussion. + * @param discussionId The id of the discussion to resolve. + * @param noteId The id of a discussion note. + * + * @return The deleted note object. + * @throws IOException on a GitLab api call error + */ + public void deleteDiscussionNote(GitlabMergeRequest mergeRequest, int discussionId, int noteId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + + GitlabDiscussion.URL + "/" + discussionId + + GitlabNote.URL + "/" + noteId; + retrieve().method(DELETE).to(tailUrl, Void.class); + } + // Get a specific commit identified by the commit hash or name of a branch or tag // GET /projects/:id/repository/commits/:sha public GitlabCommit getCommit(Serializable projectId, String commitHash) throws IOException { diff --git a/src/main/java/org/gitlab/api/models/GitlabDiscussion.java b/src/main/java/org/gitlab/api/models/GitlabDiscussion.java new file mode 100644 index 00000000..79a6fb4d --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabDiscussion.java @@ -0,0 +1,39 @@ +package org.gitlab.api.models; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author Patrizio Bonzani + */ +public class GitlabDiscussion { + + public static final String URL = "/discussions"; + + /** + * The ID of a discussion. + */ + private int id; + + /** + * The notes contained in this discussion. + */ + private List notes = new ArrayList(); + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public List getNotes() { + return notes; + } + + public void setNotes(List notes) { + this.notes = notes; + } +} From e56d8d072aedab00512749c35abe2c565d8596be Mon Sep 17 00:00:00 2001 From: Patrizio Bonzani Date: Tue, 28 Aug 2018 08:41:49 +0200 Subject: [PATCH 2/2] Improved model and added more doc. --- src/main/java/org/gitlab/api/GitlabAPI.java | 30 ++++++----- .../gitlab/api/models/GitlabDiscussion.java | 50 +++++++++++++++---- 2 files changed, 59 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/gitlab/api/GitlabAPI.java b/src/main/java/org/gitlab/api/GitlabAPI.java index 697d9669..8219d846 100644 --- a/src/main/java/org/gitlab/api/GitlabAPI.java +++ b/src/main/java/org/gitlab/api/GitlabAPI.java @@ -1616,7 +1616,8 @@ public GitlabMergeRequest acceptMergeRequest(Serializable projectId, Integer mer * @return the Gitlab Note * @throws IOException on gitlab api call error */ - public GitlabNote getNote(GitlabMergeRequest mergeRequest, Integer noteId) throws IOException { + public GitlabNote getNote(GitlabMergeRequest mergeRequest, + Integer noteId) throws IOException { String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + GitlabNote.URL + "/" + noteId; @@ -1651,7 +1652,8 @@ public List getAllNotes(GitlabMergeRequest mergeRequest) { * @return The GitLab discussion identified by the given id. * @throws IOException on a GitLab api call error */ - public GitlabDiscussion getDiscussion(GitlabMergeRequest mergeRequest, int discussionId) throws IOException { + public GitlabDiscussion getDiscussion(GitlabMergeRequest mergeRequest, + int discussionId) throws IOException { String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + GitlabDiscussion.URL + "/" + discussionId; @@ -1758,10 +1760,13 @@ public GitlabDiscussion createTextDiscussion(GitlabMergeRequest mergeRequest, * @return The created discussion object. * @throws IOException on a GitLab api call error */ - public GitlabDiscussion createImageDiscussion(GitlabMergeRequest mergeRequest, - String body, String position, String positionBaseSha, String positionStartSha, + public GitlabDiscussion createImageDiscussion( + GitlabMergeRequest mergeRequest, String body, String position, + String positionBaseSha, String positionStartSha, String positionHeadSha, String positionNewPath, String positionOldPath, - Integer positionWidth, Integer positionHeight, Integer positionX, Integer positionY) throws IOException { + Integer positionWidth, Integer positionHeight, Integer positionX, + Integer positionY + ) throws IOException { checkRequiredCreateDiscussionArguments(body, positionBaseSha, positionStartSha, positionHeadSha); String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + @@ -1785,15 +1790,16 @@ public GitlabDiscussion createImageDiscussion(GitlabMergeRequest mergeRequest, } /** - * Check if the required arguments to create a discussion are present and contain values. + * Check if the required arguments to create a discussion are present and + * contain values. * * @param body The content of a discussion. * @param positionBaseSha The base commit SHA in the source branch. * @param positionStartSha The SHA referencing commit in target branch * @param positionHeadSha The SHA referencing HEAD of this merge request */ - private void checkRequiredCreateDiscussionArguments(String body, String positionBaseSha, - String positionStartSha, String positionHeadSha) { + private void checkRequiredCreateDiscussionArguments(String body, + String positionBaseSha, String positionStartSha, String positionHeadSha) { if (body == null || body.isEmpty()) { throw new IllegalArgumentException("Missing required argument 'body'!"); } else if (positionBaseSha == null || positionBaseSha.isEmpty()) { @@ -1815,8 +1821,8 @@ private void checkRequiredCreateDiscussionArguments(String body, String position * @return The discussion object. * @throws IOException on a GitLab api call error */ - public GitlabDiscussion resolveDiscussion(GitlabMergeRequest mergeRequest, int discussionId, - boolean resolved) throws IOException { + public GitlabDiscussion resolveDiscussion(GitlabMergeRequest mergeRequest, + int discussionId, boolean resolved) throws IOException { String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + GitlabDiscussion.URL + "/" + discussionId; @@ -1835,8 +1841,8 @@ public GitlabDiscussion resolveDiscussion(GitlabMergeRequest mergeRequest, int d * @return The added note object. * @throws IOException on a GitLab api call error */ - public GitlabNote addDiscussionNote(GitlabMergeRequest mergeRequest, int discussionId, - String body) throws IOException { + public GitlabNote addDiscussionNote(GitlabMergeRequest mergeRequest, + int discussionId, String body) throws IOException { String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + GitlabDiscussion.URL + "/" + discussionId + diff --git a/src/main/java/org/gitlab/api/models/GitlabDiscussion.java b/src/main/java/org/gitlab/api/models/GitlabDiscussion.java index 79a6fb4d..5b4b6887 100644 --- a/src/main/java/org/gitlab/api/models/GitlabDiscussion.java +++ b/src/main/java/org/gitlab/api/models/GitlabDiscussion.java @@ -1,10 +1,16 @@ package org.gitlab.api.models; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + /** - * + * A class representing a GitLab discussion. A discussion is a collection of + * notes. + * * @author Patrizio Bonzani */ public class GitlabDiscussion { @@ -14,26 +20,52 @@ public class GitlabDiscussion { /** * The ID of a discussion. */ - private int id; + private String id; /** * The notes contained in this discussion. */ private List notes = new ArrayList(); - public int getId() { - return id; - } + @JsonProperty("individual_note") + private boolean individualNote; + + @SuppressWarnings("unused") + private GitlabDiscussion() {} - public void setId(int id) { + public GitlabDiscussion(String id) { this.id = id; } + /** + * Get the id of this discussion. + * + * @return The id of the discussion. + */ + public String getId() { + return id; + } + + /** + * Get the notes of this discussion. + * + * @return The notes contained in this discussion. + */ public List getNotes() { - return notes; + return Collections.unmodifiableList(notes); + } + + /** + * Add a note to the discussion. + * + * @param note The note to add to the discussion. + * @return true (as specified by {@link Collection#add}) + */ + public boolean addNote(GitlabNote note) { + return notes.add(note); } - public void setNotes(List notes) { - this.notes = notes; + public boolean isIndividualNote() { + return individualNote; } }