Skip to content

Commit b9b2a52

Browse files
committed
Add methods to manage related epics
1 parent 68416b5 commit b9b2a52

File tree

7 files changed

+374
-1
lines changed

7 files changed

+374
-1
lines changed

src/main/java/org/gitlab4j/api/EpicsApi.java

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
import org.gitlab4j.api.models.Epic;
1515
import org.gitlab4j.api.models.EpicIssue;
1616
import org.gitlab4j.api.models.EpicIssueLink;
17+
import org.gitlab4j.api.models.LinkType;
18+
import org.gitlab4j.api.models.RelatedEpic;
19+
import org.gitlab4j.api.models.RelatedEpicLink;
1720

1821
/**
1922
* This class implements the client side API for the GitLab Epics and Epic Issues API calls.
@@ -461,7 +464,6 @@ public List<EpicIssue> updateIssue(Object groupIdOrPath, Long epicIid, Long epic
461464
return response.readEntity(new GenericType<List<EpicIssue>>() {});
462465
}
463466

464-
465467
/**
466468
* Gets all child epics of an epic and the authenticated user has access to.
467469
*
@@ -581,4 +583,88 @@ public ChildEpic unassignChildEpic(Object groupIdOrPath, Long epicIid, Long chil
581583
"groups", getGroupIdOrPath(groupIdOrPath), "epics", epicIid, "epics", childEpicId);
582584
return (response.readEntity(ChildEpic.class));
583585
}
586+
587+
/**
588+
* Gets all linked epics of an epic filtered according to the user authorizations.
589+
*
590+
* <pre><code>GitLab Endpoint: GET /groups/:id/epics/:epic_iid/related_epics</code></pre>
591+
*
592+
* @param groupIdOrPath the group ID, path of the group, or a Group instance holding the group ID or path
593+
* @param epicIid the IID of the epic to get child epics for
594+
* @return a list of all related epics of the specified epic
595+
* @throws GitLabApiException if any exception occurs
596+
*/
597+
public List<RelatedEpic> getRelatedEpics(Object groupIdOrPath, Long epicIid) throws GitLabApiException {
598+
return (getRelatedEpics(groupIdOrPath, epicIid, getDefaultPerPage()).all());
599+
}
600+
601+
/**
602+
* Get a Pager of all linked epics of an epic filtered according to the user authorizations.
603+
*
604+
* <pre><code>GitLab Endpoint: GET /groups/:id/epics/:epic_iid/related_epics</code></pre>
605+
*
606+
* @param groupIdOrPath the group ID, path of the group, or a Group instance holding the group ID or path
607+
* @param epicIid the IID of the epic to get child epics for
608+
* @param itemsPerPage the number of child epics per page
609+
* @return the Pager of all related epics of the specified epic
610+
* @throws GitLabApiException if any exception occurs
611+
*/
612+
public Pager<RelatedEpic> getRelatedEpics(Object groupIdOrPath, Long epicIid, int itemsPerPage) throws GitLabApiException {
613+
return (new Pager<RelatedEpic>(this, RelatedEpic.class, itemsPerPage, null, "groups", getGroupIdOrPath(groupIdOrPath), "epics", epicIid, "related_epics"));
614+
}
615+
616+
/**
617+
* Gets all linked epics of an epic filtered according to the user authorizations to as a Stream.
618+
*
619+
* <pre><code>GitLab Endpoint: GET /groups/:id/epics/:epic_iid/related_epics</code></pre>
620+
*
621+
* @param groupIdOrPath the group ID, path of the group, or a Group instance holding the group ID or path
622+
* @param epicIid the IID of the epic to get child epics for
623+
* @return a Stream of all related epics of the specified epic
624+
* @throws GitLabApiException if any exception occurs
625+
*/
626+
public Stream<RelatedEpic> getRelatedEpicsStream(Object groupIdOrPath, Long epicIid) throws GitLabApiException {
627+
return (getRelatedEpics(groupIdOrPath, epicIid, getDefaultPerPage()).stream());
628+
}
629+
630+
/**
631+
* Create a two-way relation between two epics. The user must have at least the Guest role for both groups.
632+
*
633+
* <pre><code>GitLab Endpoint: POST /groups/:id/epics/:epic_iid/related_epics</code></pre>
634+
*
635+
* @param groupIdOrPath the group ID, path of the group, or a Group instance holding the group ID or path
636+
* @param epicIid the Epic IID to assign the child epic to
637+
* @param targetGroupIdOrPath the group ID, path of the group, or a Group instance holding the group ID or path of the target group’s epic
638+
* @param targetEpicIid the Epic IID of the target group’s epic.
639+
* @param linkType the type of the relation (optional), defaults to {@link LinkType#RELATES_TO}.
640+
* @return an RelatedEpic instance containing info on the newly assigned child epic
641+
* @throws GitLabApiException if any exception occurs
642+
*/
643+
public RelatedEpicLink createRelatedEpicLink(Object groupIdOrPath, Long epicIid, Object targetGroupIdOrPath, Long targetEpicIid, LinkType linkType) throws GitLabApiException {
644+
Form formData = new GitLabApiForm()
645+
.withParam("target_group_id", getGroupIdOrPath(targetGroupIdOrPath), true)
646+
.withParam("target_epic_iid", targetEpicIid, true)
647+
.withParam("link_type", linkType);
648+
Response response = post(Response.Status.CREATED, formData.asMap(),
649+
"groups", getGroupIdOrPath(groupIdOrPath), "epics", epicIid, "related_epics");
650+
return (response.readEntity(RelatedEpicLink.class));
651+
}
652+
653+
/**
654+
* Delete a two-way relation between two epics. The user must have at least the Guest role for both groups.
655+
*
656+
* <pre><code>GitLab Endpoint: DELETE /groups/:id/epics/:epic_iid/related_epics/:related_epic_link_id</code></pre>
657+
*
658+
* @param groupIdOrPath the group ID, path of the group, or a Group instance holding the group ID or path
659+
* @param epicIid the Epic IID to remove the child epic from
660+
* @param relatedEpicLinkId the ID a related epic link.
661+
* @return an RelatedEpicLink instance containing info on the removed related epic
662+
* @throws GitLabApiException if any exception occurs
663+
*/
664+
public RelatedEpicLink deleteRelatedEpicLink(Object groupIdOrPath, Long epicIid, Long relatedEpicLinkId) throws GitLabApiException {
665+
Response response = delete(Response.Status.OK, null,
666+
"groups", getGroupIdOrPath(groupIdOrPath), "epics", epicIid, "related_epics", relatedEpicLinkId);
667+
return (response.readEntity(RelatedEpicLink.class));
668+
}
669+
584670
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package org.gitlab4j.api.models;
2+
3+
import org.gitlab4j.api.utils.JacksonJson;
4+
5+
public class EpicInLink extends AbstractEpic<EpicInLink> {
6+
7+
public String toString() {
8+
return (JacksonJson.toJsonString(this));
9+
}
10+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package org.gitlab4j.api.models;
2+
3+
import java.util.Date;
4+
5+
import org.gitlab4j.api.utils.JacksonJson;
6+
7+
public class RelatedEpic extends AbstractEpic<RelatedEpic> {
8+
9+
private Boolean startDateIsFixed;
10+
private Boolean dueDateIsFixed;
11+
private Date dueDateFromInheritedSource;
12+
private Long relatedEpicLinkId;
13+
private LinkType linkType;
14+
private Date linkCreatedAt;
15+
private Date linkUpdatedAt;
16+
17+
public Boolean getStartDateIsFixed() {
18+
return startDateIsFixed;
19+
}
20+
21+
public void setStartDateIsFixed(Boolean startDateIsFixed) {
22+
this.startDateIsFixed = startDateIsFixed;
23+
}
24+
25+
public Boolean getDueDateIsFixed() {
26+
return dueDateIsFixed;
27+
}
28+
29+
public void setDueDateIsFixed(Boolean dueDateIsFixed) {
30+
this.dueDateIsFixed = dueDateIsFixed;
31+
}
32+
33+
public Date getDueDateFromInheritedSource() {
34+
return dueDateFromInheritedSource;
35+
}
36+
37+
public void setDueDateFromInheritedSource(Date dueDateFromInheritedSource) {
38+
this.dueDateFromInheritedSource = dueDateFromInheritedSource;
39+
}
40+
41+
public Long getRelatedEpicLinkId() {
42+
return relatedEpicLinkId;
43+
}
44+
45+
public void setRelatedEpicLinkId(Long relatedEpicLinkId) {
46+
this.relatedEpicLinkId = relatedEpicLinkId;
47+
}
48+
49+
public LinkType getLinkType() {
50+
return linkType;
51+
}
52+
53+
public void setLinkType(LinkType linkType) {
54+
this.linkType = linkType;
55+
}
56+
57+
public Date getLinkCreatedAt() {
58+
return linkCreatedAt;
59+
}
60+
61+
public void setLinkCreatedAt(Date linkCreatedAt) {
62+
this.linkCreatedAt = linkCreatedAt;
63+
}
64+
65+
public Date getLinkUpdatedAt() {
66+
return linkUpdatedAt;
67+
}
68+
69+
public void setLinkUpdatedAt(Date linkUpdatedAt) {
70+
this.linkUpdatedAt = linkUpdatedAt;
71+
}
72+
73+
public String toString() {
74+
return (JacksonJson.toJsonString(this));
75+
}
76+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package org.gitlab4j.api.models;
2+
3+
import java.util.Date;
4+
5+
import org.gitlab4j.api.utils.JacksonJson;
6+
7+
public class RelatedEpicLink {
8+
9+
private Long id;
10+
private EpicInLink sourceEpic;
11+
private EpicInLink targetEpic;
12+
private LinkType linkType;
13+
private Date createdAt;
14+
private Date updatedAt;
15+
16+
public Long getId() {
17+
return id;
18+
}
19+
20+
public void setId(Long id) {
21+
this.id = id;
22+
}
23+
24+
public EpicInLink getSourceEpic() {
25+
return sourceEpic;
26+
}
27+
28+
public void setSourceEpic(EpicInLink sourceEpic) {
29+
this.sourceEpic = sourceEpic;
30+
}
31+
32+
public EpicInLink getTargetEpic() {
33+
return targetEpic;
34+
}
35+
36+
public void setTargetEpic(EpicInLink targetEpic) {
37+
this.targetEpic = targetEpic;
38+
}
39+
40+
public LinkType getLinkType() {
41+
return linkType;
42+
}
43+
44+
public void setLinkType(LinkType linkType) {
45+
this.linkType = linkType;
46+
}
47+
48+
public Date getCreatedAt() {
49+
return createdAt;
50+
}
51+
52+
public void setCreatedAt(Date createdAt) {
53+
this.createdAt = createdAt;
54+
}
55+
56+
public Date getUpdatedAt() {
57+
return updatedAt;
58+
}
59+
60+
public void setUpdatedAt(Date updatedAt) {
61+
this.updatedAt = updatedAt;
62+
}
63+
64+
public String toString() {
65+
return (JacksonJson.toJsonString(this));
66+
}
67+
}

src/test/java/org/gitlab4j/api/TestGitLabApiBeans.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@
103103
import org.gitlab4j.api.models.ProtectedTag;
104104
import org.gitlab4j.api.models.PushRules;
105105
import org.gitlab4j.api.models.RegistryRepository;
106+
import org.gitlab4j.api.models.RelatedEpic;
107+
import org.gitlab4j.api.models.RelatedEpicLink;
106108
import org.gitlab4j.api.models.Release;
107109
import org.gitlab4j.api.models.RemoteMirror;
108110
import org.gitlab4j.api.models.RepositoryFile;
@@ -551,6 +553,18 @@ public void testRegistryRepositories() throws Exception {
551553
assertTrue(compareJson(repos, "registry-repositories.json"));
552554
}
553555

556+
@Test
557+
public void testRelatedEpicLink() throws Exception {
558+
RelatedEpicLink relatedEpics = unmarshalResource(RelatedEpicLink.class, "related-epic-link.json");
559+
assertTrue(compareJson(relatedEpics, "related-epic-link.json"));
560+
}
561+
562+
@Test
563+
public void testRelatedEpics() throws Exception {
564+
List<RelatedEpic> relatedEpics = unmarshalResourceList(RelatedEpic.class, "related-epics.json");
565+
assertTrue(compareJson(relatedEpics, "related-epics.json"));
566+
}
567+
554568
@Test
555569
public void testReleases() throws Exception {
556570
List<Release> releases = unmarshalResourceList(Release.class, "releases.json");
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
{
2+
"id": 1,
3+
"created_at": "2022-01-31T15:10:44.988Z",
4+
"updated_at": "2022-01-31T15:10:44.988Z",
5+
"link_type": "relates_to",
6+
"source_epic": {
7+
"id": 21,
8+
"iid": 1,
9+
"color": "#1068bf",
10+
"group_id": 26,
11+
"title": "Aspernatur recusandae distinctio omnis et qui est iste.",
12+
"description": "some description",
13+
"author": {
14+
"id": 15,
15+
"username": "trina",
16+
"name": "Theresia Robel",
17+
"state": "active",
18+
"avatar_url": "https://www.gravatar.com/avatar/085e28df717e16484cbf6ceca75e9a93?s=80&d=identicon",
19+
"web_url": "http://gitlab.example.com/trina"
20+
},
21+
"state": "opened",
22+
"web_url": "http://gitlab.example.com/groups/flightjs/-/epics/1",
23+
"references": {
24+
"short": "&1",
25+
"relative": "&1",
26+
"full": "flightjs&1"
27+
},
28+
"created_at": "2022-01-31T15:10:44.988Z",
29+
"updated_at": "2022-03-16T09:32:35.712Z",
30+
"labels": [],
31+
"upvotes": 0,
32+
"downvotes": 0,
33+
"_links": {
34+
"self": "http://gitlab.example.com/api/v4/groups/26/epics/1",
35+
"epic_issues": "http://gitlab.example.com/api/v4/groups/26/epics/1/issues",
36+
"group": "http://gitlab.example.com/api/v4/groups/26"
37+
}
38+
},
39+
"target_epic": {
40+
"id": 25,
41+
"iid": 5,
42+
"color": "#1068bf",
43+
"group_id": 26,
44+
"title": "Aut assumenda id nihil distinctio fugiat vel numquam est.",
45+
"description": "some description",
46+
"author": {
47+
"id": 3,
48+
"username": "valerie",
49+
"name": "Erika Wolf",
50+
"state": "active",
51+
"avatar_url": "https://www.gravatar.com/avatar/9ef7666abb101418a4716a8ed4dded80?s=80&d=identicon",
52+
"web_url": "http://gitlab.example.com/valerie"
53+
},
54+
"state": "opened",
55+
"web_url": "http://gitlab.example.com/groups/flightjs/-/epics/5",
56+
"references": {
57+
"short": "&5",
58+
"relative": "&5",
59+
"full": "flightjs&5"
60+
},
61+
"created_at": "2022-01-31T15:10:45.080Z",
62+
"updated_at": "2022-03-16T09:32:35.842Z",
63+
"labels": [],
64+
"upvotes": 0,
65+
"downvotes": 0,
66+
"_links": {
67+
"self": "http://gitlab.example.com/api/v4/groups/26/epics/5",
68+
"epic_issues": "http://gitlab.example.com/api/v4/groups/26/epics/5/issues",
69+
"group": "http://gitlab.example.com/api/v4/groups/26"
70+
}
71+
}
72+
}

0 commit comments

Comments
 (0)