From 00cb33b331cfb8e1c5b3716dfcbb34241563db3c Mon Sep 17 00:00:00 2001 From: Jeremie Bresson Date: Thu, 27 Apr 2023 16:06:53 +0200 Subject: [PATCH 1/2] Fix Epic Issue link association Fixes #729 --- src/main/java/org/gitlab4j/api/EpicsApi.java | 53 +++++++------- .../gitlab4j/api/models/EpicIssueLink.java | 49 +++++++++++++ .../org/gitlab4j/api/TestGitLabApiBeans.java | 7 ++ .../org/gitlab4j/api/epic-issue-link.json | 70 +++++++++++++++++++ 4 files changed, 153 insertions(+), 26 deletions(-) create mode 100644 src/main/java/org/gitlab4j/api/models/EpicIssueLink.java create mode 100644 src/test/resources/org/gitlab4j/api/epic-issue-link.json diff --git a/src/main/java/org/gitlab4j/api/EpicsApi.java b/src/main/java/org/gitlab4j/api/EpicsApi.java index 6eb59a1cf..1cc488f4f 100644 --- a/src/main/java/org/gitlab4j/api/EpicsApi.java +++ b/src/main/java/org/gitlab4j/api/EpicsApi.java @@ -11,6 +11,7 @@ import org.gitlab4j.api.models.Epic; import org.gitlab4j.api.models.EpicIssue; +import org.gitlab4j.api.models.EpicIssueLink; /** * This class implements the client side API for the GitLab Epics and Epic Issues API calls. @@ -347,10 +348,10 @@ public void deleteEpic(Object groupIdOrPath, Long epicIid) throws GitLabApiExcep * * @param groupIdOrPath the group ID, path of the group, or a Group instance holding the group ID or path * @param epicIid the IID of the epic to get issues for - * @return a list of all epic issues belonging to the specified epic + * @return a list of all issues belonging to the specified epic * @throws GitLabApiException if any exception occurs */ - public List getEpicIssues(Object groupIdOrPath, Long epicIid) throws GitLabApiException { + public List getEpicIssues(Object groupIdOrPath, Long epicIid) throws GitLabApiException { return (getEpicIssues(groupIdOrPath, epicIid, getDefaultPerPage()).all()); } @@ -364,7 +365,7 @@ public List getEpicIssues(Object groupIdOrPath, Long epicIid) throws GitLa * @param epicIid the IID of the epic to get issues for * @param page the page to get * @param perPage the number of issues per page - * @return a list of all epic issues belonging to the specified epic in the specified range + * @return a list of all issues belonging to the specified epic in the specified range * @throws GitLabApiException if any exception occurs */ public List getEpicIssues(Object groupIdOrPath, Long epicIid, int page, int perPage) throws GitLabApiException { @@ -380,11 +381,11 @@ public List getEpicIssues(Object groupIdOrPath, Long epicIid, int page, in * @param groupIdOrPath the group ID, path of the group, or a Group instance holding the group ID or path * @param epicIid the IID of the epic to get issues for * @param itemsPerPage the number of issues per page - * @return the Pager of all epic issues belonging to the specified epic + * @return the Pager of all issues belonging to the specified epic * @throws GitLabApiException if any exception occurs */ - public Pager getEpicIssues(Object groupIdOrPath, Long epicIid, int itemsPerPage) throws GitLabApiException { - return (new Pager(this, Epic.class, itemsPerPage, null, "groups", getGroupIdOrPath(groupIdOrPath), "epics", epicIid, "issues")); + public Pager getEpicIssues(Object groupIdOrPath, Long epicIid, int itemsPerPage) throws GitLabApiException { + return (new Pager(this, EpicIssue.class, itemsPerPage, null, "groups", getGroupIdOrPath(groupIdOrPath), "epics", epicIid, "issues")); } /** @@ -394,10 +395,10 @@ public Pager getEpicIssues(Object groupIdOrPath, Long epicIid, int itemsPe * * @param groupIdOrPath the group ID, path of the group, or a Group instance holding the group ID or path * @param epicIid the IID of the epic to get issues for - * @return a Stream of all epic issues belonging to the specified epic + * @return a Stream of all issues belonging to the specified epic * @throws GitLabApiException if any exception occurs */ - public Stream getEpicIssuesStream(Object groupIdOrPath, Long epicIid) throws GitLabApiException { + public Stream getEpicIssuesStream(Object groupIdOrPath, Long epicIid) throws GitLabApiException { return (getEpicIssues(groupIdOrPath, epicIid, getDefaultPerPage()).stream()); } @@ -409,52 +410,52 @@ public Stream getEpicIssuesStream(Object groupIdOrPath, Long epicIid) thro * * @param groupIdOrPath the group ID, path of the group, or a Group instance holding the group ID or path * @param epicIid the Epic IID to assign the issue to - * @param issueIid the issue IID of the issue to assign to the epic + * @param issueId the issue ID of the issue to assign to the epic * @return an EpicIssue instance containing info on the newly assigned epic issue * @throws GitLabApiException if any exception occurs */ - public EpicIssue assignIssue(Object groupIdOrPath, Long epicIid, Long issueIid) throws GitLabApiException { + public EpicIssue assignIssue(Object groupIdOrPath, Long epicIid, Long issueId) throws GitLabApiException { Response response = post(Response.Status.CREATED, (Form)null, - "groups", getGroupIdOrPath(groupIdOrPath), "epics", epicIid, "issues", issueIid); + "groups", getGroupIdOrPath(groupIdOrPath), "epics", epicIid, "issues", issueId); return (response.readEntity(EpicIssue.class)); } /** * Remove an epic - issue association. * - *
GitLab Endpoint: DELETE /groups/:id/epics/:epic_iid/issues/:issue_id
+ *
GitLab Endpoint: DELETE /groups/:id/epics/:epic_iid/issues/:epic_issue_id
* * @param groupIdOrPath the group ID, path of the group, or a Group instance holding the group ID or path * @param epicIid the Epic IID to remove the issue from - * @param issueIid the issue IID of the issue to remove from the epic - * @return an EpicIssue instance containing info on the removed issue + * @param epicIssueId the ID of the "issue - epic" association of the issue to remove from the epic + * @return an EpicIssueLink instance containing info on the removed issue * @throws GitLabApiException if any exception occurs */ - public EpicIssue removeIssue(Object groupIdOrPath, Long epicIid, Long issueIid) throws GitLabApiException { + public EpicIssueLink removeIssue(Object groupIdOrPath, Long epicIid, Long epicIssueId) throws GitLabApiException { Response response = delete(Response.Status.OK, null, - "groups", getGroupIdOrPath(groupIdOrPath), "epics", epicIid, "issues", issueIid); - return (response.readEntity(EpicIssue.class)); + "groups", getGroupIdOrPath(groupIdOrPath), "epics", epicIid, "issues", epicIssueId); + return (response.readEntity(EpicIssueLink.class)); } /** * Updates an epic - issue association. * - *
GitLab Endpoint: PUT /groups/:id/epics/:epic_iid/issues/:issue_id
+ *
GitLab Endpoint: PUT /groups/:id/epics/:epic_iid/issues/:epic_issue_id
* * @param groupIdOrPath the group ID, path of the group, or a Group instance holding the group ID or path * @param epicIid the Epic IID that the issue is assigned to - * @param issueIid the issue IID to update - * @param moveBeforeId the ID of the issue - epic association that should be placed before the link in the question (optional) - * @param moveAfterId the ID of the issue - epic association that should be placed after the link in the question (optional) - * @return an EpicIssue instance containing info on the newly assigned epic issue + * @param epicIssueId the ID of the "issue - epic" association + * @param moveBeforeId the ID of the "issue - epic" association that should be placed before the link in the question (optional) + * @param moveAfterId the ID of the "issue - epic" association that should be placed after the link in the question (optional) + * @return a list of all issues belonging to the specified epic * @throws GitLabApiException if any exception occurs */ - public EpicIssue updateIssue(Object groupIdOrPath, Long epicIid, Long issueIid, Long moveBeforeId, Long moveAfterId) throws GitLabApiException { + public List updateIssue(Object groupIdOrPath, Long epicIid, Long epicIssueId, Long moveBeforeId, Long moveAfterId) throws GitLabApiException { GitLabApiForm form = new GitLabApiForm() .withParam("move_before_id", moveBeforeId) .withParam("move_after_id", moveAfterId); - Response response = post(Response.Status.OK, form, - "groups", getGroupIdOrPath(groupIdOrPath), "epics", epicIid, "issues", issueIid); - return (response.readEntity(EpicIssue.class)); + Response response = put(Response.Status.OK, form, + "groups", getGroupIdOrPath(groupIdOrPath), "epics", epicIid, "issues", epicIssueId); + return response.readEntity(new GenericType>() {}); } } diff --git a/src/main/java/org/gitlab4j/api/models/EpicIssueLink.java b/src/main/java/org/gitlab4j/api/models/EpicIssueLink.java new file mode 100644 index 000000000..b169b6c8e --- /dev/null +++ b/src/main/java/org/gitlab4j/api/models/EpicIssueLink.java @@ -0,0 +1,49 @@ + +package org.gitlab4j.api.models; + +import org.gitlab4j.api.utils.JacksonJson; + +public class EpicIssueLink { + + private Long id; + private Integer relativePosition; + private Epic epic; + private Issue issue; + + public Long getId() { + return id; + } + + public void setId(Long epicIssueId) { + this.id = epicIssueId; + } + + public Integer getRelativePosition() { + return relativePosition; + } + + public void setRelativePosition(Integer relativePosition) { + this.relativePosition = relativePosition; + } + + public Epic getEpic() { + return epic; + } + + public void setEpic(Epic epic) { + this.epic = epic; + } + + public Issue getIssue() { + return issue; + } + + public void setIssue(Issue issue) { + this.issue = issue; + } + + @Override + public String toString() { + return (JacksonJson.toJsonString(this)); + } +} diff --git a/src/test/java/org/gitlab4j/api/TestGitLabApiBeans.java b/src/test/java/org/gitlab4j/api/TestGitLabApiBeans.java index 5afc24a75..f6dd7d107 100644 --- a/src/test/java/org/gitlab4j/api/TestGitLabApiBeans.java +++ b/src/test/java/org/gitlab4j/api/TestGitLabApiBeans.java @@ -60,6 +60,7 @@ import org.gitlab4j.api.models.Environment; import org.gitlab4j.api.models.Epic; import org.gitlab4j.api.models.EpicIssue; +import org.gitlab4j.api.models.EpicIssueLink; import org.gitlab4j.api.models.Event; import org.gitlab4j.api.models.ExportStatus; import org.gitlab4j.api.models.ExternalStatusCheck; @@ -254,6 +255,12 @@ public void testEpicIssue() throws Exception { assertTrue(compareJson(epicIssue, "epic-issue.json")); } + @Test + public void testEpicIssueLink() throws Exception { + EpicIssueLink epicIssueLink = unmarshalResource(EpicIssueLink.class, "epic-issue-link.json"); + assertTrue(compareJson(epicIssueLink, "epic-issue-link.json")); + } + @Test public void testEvent() throws Exception { Event event = unmarshalResource(Event.class, "event.json"); diff --git a/src/test/resources/org/gitlab4j/api/epic-issue-link.json b/src/test/resources/org/gitlab4j/api/epic-issue-link.json new file mode 100644 index 000000000..85b64909f --- /dev/null +++ b/src/test/resources/org/gitlab4j/api/epic-issue-link.json @@ -0,0 +1,70 @@ +{ + "id": 237, + "relative_position": -1026, + "epic": { + "id": 25, + "iid": 1, + "color": "#1068bf", + "group_id": 139, + "title": "Test group Epic", + "description": "", + "author": { + "id": 1, + "username": "pipin", + "name": "Pip", + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon", + "web_url": "https://gitlab.example.com/pipin" + }, + "state": "opened", + "web_url": "https://gitlab.example.com/groups/my/test-group/-/epics/1", + "references": { + "short": "&1", + "relative": "&1", + "full": "my/test-group&1" + }, + "reference": "my/test-group&1", + "created_at": "2022-08-23T13:50:08.507Z", + "updated_at": "2023-04-27T13:36:34.636Z", + "labels": [], + "upvotes": 0, + "downvotes": 0, + "_links": { + "self": "https://gitlab.example.com/api/v4/groups/139/epics/1", + "epic_issues": "https://gitlab.example.com/api/v4/groups/139/epics/1/issues", + "group": "https://gitlab.example.com/api/v4/groups/139" } + }, + "issue": { + "id": 1106, + "iid": 9, + "project_id": 58, + "title": "a title", + "description": "a description", + "state": "opened", + "created_at": "2022-09-12T07:30:09.431Z", + "updated_at": "2023-04-27T13:36:34.703Z", + "labels": [], + "assignees": [], + "author": { + "id": 1, + "username": "pipin", + "name": "Pip", + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon", + "web_url": "https://gitlab.example.com/pipin" + }, + "user_notes_count": 0, + "merge_requests_count": 1, + "upvotes": 0, + "downvotes": 0, + "web_url": "https://gitlab.example.com/my/test-group/a-project/-/issues/9", + "time_stats": { + "time_estimate": 0, + "total_time_spent": 0 + }, + "task_completion_status": { + "count": 0, + "completed_count": 0 + } + } +} \ No newline at end of file From 91994e34141d819a022830a2f7da6b6a65369ef5 Mon Sep 17 00:00:00 2001 From: Jeremie Bresson Date: Wed, 3 May 2023 13:58:58 +0200 Subject: [PATCH 2/2] Change return type --- src/main/java/org/gitlab4j/api/EpicsApi.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/gitlab4j/api/EpicsApi.java b/src/main/java/org/gitlab4j/api/EpicsApi.java index 1cc488f4f..9c6a25791 100644 --- a/src/main/java/org/gitlab4j/api/EpicsApi.java +++ b/src/main/java/org/gitlab4j/api/EpicsApi.java @@ -368,9 +368,9 @@ public List getEpicIssues(Object groupIdOrPath, Long epicIid) throws * @return a list of all issues belonging to the specified epic in the specified range * @throws GitLabApiException if any exception occurs */ - public List getEpicIssues(Object groupIdOrPath, Long epicIid, int page, int perPage) throws GitLabApiException { + public List getEpicIssues(Object groupIdOrPath, Long epicIid, int page, int perPage) throws GitLabApiException { Response response = get(Response.Status.OK, getPageQueryParams(page, perPage), "groups", getGroupIdOrPath(groupIdOrPath), "epics", epicIid, "issues"); - return (response.readEntity(new GenericType>() { })); + return (response.readEntity(new GenericType>() { })); } /**