Skip to content

Commit f47c3e4

Browse files
authored
Merge pull request #1319 from gsmet/discussion-payload
Add support for the Discussion payload
2 parents 48fe488 + 82cccc7 commit f47c3e4

File tree

6 files changed

+989
-0
lines changed

6 files changed

+989
-0
lines changed

src/main/java/org/kohsuke/github/GHEventPayload.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1477,4 +1477,39 @@ public GHLabelChanges getChanges() {
14771477
return changes;
14781478
}
14791479
}
1480+
1481+
/**
1482+
* A discussion was created, edited, deleted, pinned, unpinned, locked, unlocked, transferred, category_changed,
1483+
* answered, or unanswered.
1484+
*
1485+
* @see <a href=
1486+
* "https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#discussion">
1487+
* discussion event</a>
1488+
*/
1489+
public static class Discussion extends GHEventPayload {
1490+
1491+
private GHRepositoryDiscussion discussion;
1492+
1493+
private GHLabel label;
1494+
1495+
/**
1496+
* Gets discussion.
1497+
*
1498+
* @return the discussion
1499+
*/
1500+
@SuppressFBWarnings(value = { "EI_EXPOSE_REP" }, justification = "Expected")
1501+
public GHRepositoryDiscussion getDiscussion() {
1502+
return discussion;
1503+
}
1504+
1505+
/**
1506+
* Gets the added or removed label for labeled/unlabeled events.
1507+
*
1508+
* @return label the added or removed label
1509+
*/
1510+
@SuppressFBWarnings(value = { "EI_EXPOSE_REP" }, justification = "Expected")
1511+
public GHLabel getLabel() {
1512+
return label;
1513+
}
1514+
}
14801515
}
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
package org.kohsuke.github;
2+
3+
import org.kohsuke.github.internal.EnumUtils;
4+
5+
import java.io.IOException;
6+
import java.net.URL;
7+
import java.util.Date;
8+
9+
/**
10+
* A discussion in the repository.
11+
* <p>
12+
* This is different from Teams discussions (see {@link GHDiscussion}).
13+
* <p>
14+
* The discussion event exposes the GraphQL object (more or less - the ids are handled differently for instance)
15+
* directly. The new Discussions API is only available through GraphQL so for now you cannot execute any actions on this
16+
* object.
17+
*
18+
* @author Guillaume Smet
19+
* @see <a href="https://docs.github.com/en/graphql/guides/using-the-graphql-api-for-discussions#discussion">The GraphQL
20+
* API for Discussions</a>
21+
*/
22+
public class GHRepositoryDiscussion extends GHObject {
23+
24+
private Category category;
25+
26+
private String answerHtmlUrl;
27+
28+
private String answerChosenAt;
29+
private GHUser answerChosenBy;
30+
private String htmlUrl;
31+
32+
private int number;
33+
private String title;
34+
private GHUser user;
35+
private String state;
36+
private boolean locked;
37+
private int comments;
38+
private GHCommentAuthorAssociation authorAssociation;
39+
private String activeLockReason;
40+
private String body;
41+
private String timelineUrl;
42+
43+
public Category getCategory() {
44+
return category;
45+
}
46+
47+
public URL getAnswerHtmlUrl() {
48+
return GitHubClient.parseURL(answerHtmlUrl);
49+
}
50+
51+
public Date getAnswerChosenAt() {
52+
return GitHubClient.parseDate(answerChosenAt);
53+
}
54+
55+
public GHUser getAnswerChosenBy() throws IOException {
56+
return root().intern(answerChosenBy);
57+
}
58+
59+
public URL getHtmlUrl() {
60+
return GitHubClient.parseURL(htmlUrl);
61+
}
62+
63+
public int getNumber() {
64+
return number;
65+
}
66+
67+
public String getTitle() {
68+
return title;
69+
}
70+
71+
public GHUser getUser() throws IOException {
72+
return root().intern(user);
73+
}
74+
75+
public State getState() {
76+
return EnumUtils.getEnumOrDefault(State.class, state, State.UNKNOWN);
77+
}
78+
79+
public boolean isLocked() {
80+
return locked;
81+
}
82+
83+
public int getComments() {
84+
return comments;
85+
}
86+
87+
public GHCommentAuthorAssociation getAuthorAssociation() {
88+
return authorAssociation;
89+
}
90+
91+
public String getActiveLockReason() {
92+
return activeLockReason;
93+
}
94+
95+
public String getBody() {
96+
return body;
97+
}
98+
99+
public String getTimelineUrl() {
100+
return timelineUrl;
101+
}
102+
103+
/**
104+
* Category of a discussion.
105+
* <p>
106+
* Note that while it is relatively close to the GraphQL objects, some of the fields such as the id are handled
107+
* differently.
108+
*
109+
* @see <a href=
110+
* "https://docs.github.com/en/graphql/guides/using-the-graphql-api-for-discussions#discussioncategory">The
111+
* GraphQL API for Discussions</a>
112+
*/
113+
public static class Category {
114+
115+
private long id;
116+
private long repositoryId;
117+
private String emoji;
118+
private String name;
119+
private String description;
120+
private String createdAt;
121+
private String updatedAt;
122+
private String slug;
123+
private boolean isAnswerable;
124+
125+
public long getId() {
126+
return id;
127+
}
128+
129+
public long getRepositoryId() {
130+
return repositoryId;
131+
}
132+
133+
public String getEmoji() {
134+
return emoji;
135+
}
136+
137+
public String getName() {
138+
return name;
139+
}
140+
141+
public String getDescription() {
142+
return description;
143+
}
144+
145+
public Date getCreatedAt() {
146+
return GitHubClient.parseDate(createdAt);
147+
}
148+
149+
public Date getUpdatedAt() {
150+
return GitHubClient.parseDate(updatedAt);
151+
}
152+
153+
public String getSlug() {
154+
return slug;
155+
}
156+
157+
public boolean isAnswerable() {
158+
return isAnswerable;
159+
}
160+
}
161+
162+
public enum State {
163+
OPEN, LOCKED, UNKNOWN;
164+
}
165+
}

src/test/java/org/kohsuke/github/GHEventPayloadTest.java

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -919,4 +919,156 @@ public void label_deleted() throws Exception {
919919
assertThat(label.isDefault(), is(false));
920920
assertThat(label.getDescription(), is("description"));
921921
}
922+
923+
@Test
924+
public void discussion_created() throws Exception {
925+
final GHEventPayload.Discussion discussionPayload = GitHub.offline()
926+
.parseEventPayload(payload.asReader(), GHEventPayload.Discussion.class);
927+
928+
assertThat(discussionPayload.getAction(), is("created"));
929+
assertThat(discussionPayload.getRepository().getFullName(), is("gsmet/quarkus-bot-java-playground"));
930+
assertThat(discussionPayload.getSender().getLogin(), is("gsmet"));
931+
932+
GHRepositoryDiscussion discussion = discussionPayload.getDiscussion();
933+
934+
GHRepositoryDiscussion.Category category = discussion.getCategory();
935+
936+
assertThat(category.getId(), is(33522033L));
937+
assertThat(category.getEmoji(), is(":pray:"));
938+
assertThat(category.getName(), is("Q&A"));
939+
assertThat(category.getDescription(), is("Ask the community for help"));
940+
assertThat(category.getCreatedAt().getTime(), is(1636991431000L));
941+
assertThat(category.getUpdatedAt().getTime(), is(1636991431000L));
942+
assertThat(category.getSlug(), is("q-a"));
943+
assertThat(category.isAnswerable(), is(true));
944+
945+
assertThat(discussion.getAnswerHtmlUrl(), is(nullValue()));
946+
assertThat(discussion.getAnswerChosenAt(), is(nullValue()));
947+
assertThat(discussion.getAnswerChosenBy(), is(nullValue()));
948+
949+
assertThat(discussion.getHtmlUrl().toString(),
950+
is("https://github.com/gsmet/quarkus-bot-java-playground/discussions/78"));
951+
assertThat(discussion.getId(), is(3698909L));
952+
assertThat(discussion.getNodeId(), is("D_kwDOEq3cwc4AOHDd"));
953+
assertThat(discussion.getNumber(), is(78));
954+
assertThat(discussion.getTitle(), is("Title of discussion"));
955+
956+
assertThat(discussion.getUser().getLogin(), is("gsmet"));
957+
assertThat(discussion.getUser().getId(), is(1279749L));
958+
assertThat(discussion.getUser().getNodeId(), is("MDQ6VXNlcjEyNzk3NDk="));
959+
960+
assertThat(discussion.getState(), is(GHRepositoryDiscussion.State.OPEN));
961+
assertThat(discussion.isLocked(), is(false));
962+
assertThat(discussion.getComments(), is(0));
963+
assertThat(discussion.getCreatedAt().getTime(), is(1637584949000L));
964+
assertThat(discussion.getUpdatedAt().getTime(), is(1637584949000L));
965+
assertThat(discussion.getAuthorAssociation(), is(GHCommentAuthorAssociation.OWNER));
966+
assertThat(discussion.getActiveLockReason(), is(nullValue()));
967+
assertThat(discussion.getBody(), is("Body of discussion."));
968+
}
969+
970+
@Test
971+
public void discussion_answered() throws Exception {
972+
final GHEventPayload.Discussion discussionPayload = GitHub.offline()
973+
.parseEventPayload(payload.asReader(), GHEventPayload.Discussion.class);
974+
975+
assertThat(discussionPayload.getAction(), is("answered"));
976+
assertThat(discussionPayload.getRepository().getFullName(), is("gsmet/quarkus-bot-java-playground"));
977+
assertThat(discussionPayload.getSender().getLogin(), is("gsmet"));
978+
979+
GHRepositoryDiscussion discussion = discussionPayload.getDiscussion();
980+
981+
GHRepositoryDiscussion.Category category = discussion.getCategory();
982+
983+
assertThat(category.getId(), is(33522033L));
984+
assertThat(category.getEmoji(), is(":pray:"));
985+
assertThat(category.getName(), is("Q&A"));
986+
assertThat(category.getDescription(), is("Ask the community for help"));
987+
assertThat(category.getCreatedAt().getTime(), is(1636991431000L));
988+
assertThat(category.getUpdatedAt().getTime(), is(1636991431000L));
989+
assertThat(category.getSlug(), is("q-a"));
990+
assertThat(category.isAnswerable(), is(true));
991+
992+
assertThat(discussion.getAnswerHtmlUrl().toString(),
993+
is("https://github.com/gsmet/quarkus-bot-java-playground/discussions/78#discussioncomment-1681242"));
994+
assertThat(discussion.getAnswerChosenAt().getTime(), is(1637585047000L));
995+
assertThat(discussion.getAnswerChosenBy().getLogin(), is("gsmet"));
996+
997+
assertThat(discussion.getHtmlUrl().toString(),
998+
is("https://github.com/gsmet/quarkus-bot-java-playground/discussions/78"));
999+
assertThat(discussion.getId(), is(3698909L));
1000+
assertThat(discussion.getNodeId(), is("D_kwDOEq3cwc4AOHDd"));
1001+
assertThat(discussion.getNumber(), is(78));
1002+
assertThat(discussion.getTitle(), is("Title of discussion"));
1003+
1004+
assertThat(discussion.getUser().getLogin(), is("gsmet"));
1005+
assertThat(discussion.getUser().getId(), is(1279749L));
1006+
assertThat(discussion.getUser().getNodeId(), is("MDQ6VXNlcjEyNzk3NDk="));
1007+
1008+
assertThat(discussion.getState(), is(GHRepositoryDiscussion.State.OPEN));
1009+
assertThat(discussion.isLocked(), is(false));
1010+
assertThat(discussion.getComments(), is(1));
1011+
assertThat(discussion.getCreatedAt().getTime(), is(1637584949000L));
1012+
assertThat(discussion.getUpdatedAt().getTime(), is(1637585047000L));
1013+
assertThat(discussion.getAuthorAssociation(), is(GHCommentAuthorAssociation.OWNER));
1014+
assertThat(discussion.getActiveLockReason(), is(nullValue()));
1015+
assertThat(discussion.getBody(), is("Body of discussion."));
1016+
}
1017+
1018+
@Test
1019+
public void discussion_labeled() throws Exception {
1020+
final GHEventPayload.Discussion discussionPayload = GitHub.offline()
1021+
.parseEventPayload(payload.asReader(), GHEventPayload.Discussion.class);
1022+
1023+
assertThat(discussionPayload.getAction(), is("labeled"));
1024+
assertThat(discussionPayload.getRepository().getFullName(), is("gsmet/quarkus-bot-java-playground"));
1025+
assertThat(discussionPayload.getSender().getLogin(), is("gsmet"));
1026+
1027+
GHRepositoryDiscussion discussion = discussionPayload.getDiscussion();
1028+
1029+
GHRepositoryDiscussion.Category category = discussion.getCategory();
1030+
1031+
assertThat(category.getId(), is(33522033L));
1032+
assertThat(category.getEmoji(), is(":pray:"));
1033+
assertThat(category.getName(), is("Q&A"));
1034+
assertThat(category.getDescription(), is("Ask the community for help"));
1035+
assertThat(category.getCreatedAt().getTime(), is(1636991431000L));
1036+
assertThat(category.getUpdatedAt().getTime(), is(1636991431000L));
1037+
assertThat(category.getSlug(), is("q-a"));
1038+
assertThat(category.isAnswerable(), is(true));
1039+
1040+
assertThat(discussion.getAnswerHtmlUrl(), is(nullValue()));
1041+
assertThat(discussion.getAnswerChosenAt(), is(nullValue()));
1042+
assertThat(discussion.getAnswerChosenBy(), is(nullValue()));
1043+
1044+
assertThat(discussion.getHtmlUrl().toString(),
1045+
is("https://github.com/gsmet/quarkus-bot-java-playground/discussions/78"));
1046+
assertThat(discussion.getId(), is(3698909L));
1047+
assertThat(discussion.getNodeId(), is("D_kwDOEq3cwc4AOHDd"));
1048+
assertThat(discussion.getNumber(), is(78));
1049+
assertThat(discussion.getTitle(), is("Title of discussion"));
1050+
1051+
assertThat(discussion.getUser().getLogin(), is("gsmet"));
1052+
assertThat(discussion.getUser().getId(), is(1279749L));
1053+
assertThat(discussion.getUser().getNodeId(), is("MDQ6VXNlcjEyNzk3NDk="));
1054+
1055+
assertThat(discussion.getState(), is(GHRepositoryDiscussion.State.OPEN));
1056+
assertThat(discussion.isLocked(), is(false));
1057+
assertThat(discussion.getComments(), is(0));
1058+
assertThat(discussion.getCreatedAt().getTime(), is(1637584949000L));
1059+
assertThat(discussion.getUpdatedAt().getTime(), is(1637584961000L));
1060+
assertThat(discussion.getAuthorAssociation(), is(GHCommentAuthorAssociation.OWNER));
1061+
assertThat(discussion.getActiveLockReason(), is(nullValue()));
1062+
assertThat(discussion.getBody(), is("Body of discussion."));
1063+
1064+
GHLabel label = discussionPayload.getLabel();
1065+
assertThat(label.getId(), is(2543373314L));
1066+
assertThat(label.getNodeId(), is("MDU6TGFiZWwyNTQzMzczMzE0"));
1067+
assertThat(label.getUrl().toString(),
1068+
is("https://api.github.com/repos/gsmet/quarkus-bot-java-playground/labels/area/hibernate-validator"));
1069+
assertThat(label.getName(), is("area/hibernate-validator"));
1070+
assertThat(label.getColor(), is("ededed"));
1071+
assertThat(label.isDefault(), is(false));
1072+
assertThat(label.getDescription(), is(nullValue()));
1073+
}
9221074
}

0 commit comments

Comments
 (0)