Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Epic Issue link association #969

Merged
merged 3 commits into from
May 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 29 additions & 28 deletions src/main/java/org/gitlab4j/api/EpicsApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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<Epic> getEpicIssues(Object groupIdOrPath, Long epicIid) throws GitLabApiException {
public List<EpicIssue> getEpicIssues(Object groupIdOrPath, Long epicIid) throws GitLabApiException {
return (getEpicIssues(groupIdOrPath, epicIid, getDefaultPerPage()).all());
}

Expand All @@ -364,12 +365,12 @@ public List<Epic> 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<Epic> getEpicIssues(Object groupIdOrPath, Long epicIid, int page, int perPage) throws GitLabApiException {
public List<EpicIssue> 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<List<Epic>>() { }));
return (response.readEntity(new GenericType<List<EpicIssue>>() { }));
}

/**
Expand All @@ -380,11 +381,11 @@ public List<Epic> 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<Epic> getEpicIssues(Object groupIdOrPath, Long epicIid, int itemsPerPage) throws GitLabApiException {
return (new Pager<Epic>(this, Epic.class, itemsPerPage, null, "groups", getGroupIdOrPath(groupIdOrPath), "epics", epicIid, "issues"));
public Pager<EpicIssue> getEpicIssues(Object groupIdOrPath, Long epicIid, int itemsPerPage) throws GitLabApiException {
return (new Pager<EpicIssue>(this, EpicIssue.class, itemsPerPage, null, "groups", getGroupIdOrPath(groupIdOrPath), "epics", epicIid, "issues"));
}

/**
Expand All @@ -394,10 +395,10 @@ public Pager<Epic> 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<Epic> getEpicIssuesStream(Object groupIdOrPath, Long epicIid) throws GitLabApiException {
public Stream<EpicIssue> getEpicIssuesStream(Object groupIdOrPath, Long epicIid) throws GitLabApiException {
return (getEpicIssues(groupIdOrPath, epicIid, getDefaultPerPage()).stream());
}

Expand All @@ -409,52 +410,52 @@ public Stream<Epic> 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.
*
* <pre><code>GitLab Endpoint: DELETE /groups/:id/epics/:epic_iid/issues/:issue_id</code></pre>
* <pre><code>GitLab Endpoint: DELETE /groups/:id/epics/:epic_iid/issues/:epic_issue_id</code></pre>
*
* @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.
*
* <pre><code>GitLab Endpoint: PUT /groups/:id/epics/:epic_iid/issues/:issue_id</code></pre>
* <pre><code>GitLab Endpoint: PUT /groups/:id/epics/:epic_iid/issues/:epic_issue_id</code></pre>
*
* @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<EpicIssue> 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<List<EpicIssue>>() {});
}
}
49 changes: 49 additions & 0 deletions src/main/java/org/gitlab4j/api/models/EpicIssueLink.java
Original file line number Diff line number Diff line change
@@ -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));
}
}
7 changes: 7 additions & 0 deletions src/test/java/org/gitlab4j/api/TestGitLabApiBeans.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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");
Expand Down
70 changes: 70 additions & 0 deletions src/test/resources/org/gitlab4j/api/epic-issue-link.json
Original file line number Diff line number Diff line change
@@ -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
}
}
}