diff --git a/src/main/java/org/gitlab4j/api/GitLabApi.java b/src/main/java/org/gitlab4j/api/GitLabApi.java
index e3e931fce..aa19398f5 100644
--- a/src/main/java/org/gitlab4j/api/GitLabApi.java
+++ b/src/main/java/org/gitlab4j/api/GitLabApi.java
@@ -85,6 +85,7 @@ public String getApiNamespace() {
private RepositoryApi repositoryApi;
private RepositoryFileApi repositoryFileApi;
private ResourceLabelEventsApi resourceLabelEventsApi;
+ private ResourceStateEventsApi resourceStateEventsApi;
private RunnersApi runnersApi;
private SearchApi searchApi;
private ServicesApi servicesApi;
@@ -1488,6 +1489,25 @@ public ResourceLabelEventsApi getResourceLabelEventsApi() {
return (resourceLabelEventsApi);
}
+ /**
+ * Gets the ResourceStateEventsApi instance owned by this GitLabApi instance. The ResourceStateEventsApi
+ * is used to perform all Resource State Events related API calls.
+ *
+ * @return the ResourceStateEventsApi instance owned by this GitLabApi instance
+ */
+ public ResourceStateEventsApi getResourceStateEventsApi() {
+
+ if (resourceStateEventsApi == null) {
+ synchronized (this) {
+ if (resourceStateEventsApi == null) {
+ resourceStateEventsApi = new ResourceStateEventsApi(this);
+ }
+ }
+ }
+
+ return (resourceStateEventsApi);
+ }
+
/**
* Gets the RunnersApi instance owned by this GitLabApi instance. The RunnersApi is used
* to perform all Runner related API calls.
diff --git a/src/main/java/org/gitlab4j/api/ResourceStateEventsApi.java b/src/main/java/org/gitlab4j/api/ResourceStateEventsApi.java
new file mode 100644
index 000000000..ff4c42a59
--- /dev/null
+++ b/src/main/java/org/gitlab4j/api/ResourceStateEventsApi.java
@@ -0,0 +1,65 @@
+package org.gitlab4j.api;
+
+import org.gitlab4j.api.models.IssueEvent;
+import org.gitlab4j.api.models.LabelEvent;
+
+import javax.ws.rs.core.Response;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+
+/**
+ * This class provides an entry point to all the GitLab Resource state events API
+ * @see Resource state events API at GitLab
+ */
+public class ResourceStateEventsApi extends AbstractApi {
+
+ public ResourceStateEventsApi(GitLabApi gitLabApi) {
+ super(gitLabApi);
+ }
+
+ /**
+ * Gets a list of all state events for a single issue.
+ *
+ *
GitLab Endpoint: GET /projects/:id/issues/:issue_iid/resource_state_events
+ *
+ * @param projectIdOrPath id, path of the project, or a Project instance holding the project ID or path
+ * @param issueIid the IID of the issue
+ * @return a List of IssueEvent for the specified issue
+ * @throws GitLabApiException if any exception occurs
+ */
+ public List getIssueStateEvents(Object projectIdOrPath, Integer issueIid) throws GitLabApiException {
+ return (getIssueStateEvents(projectIdOrPath, issueIid, getDefaultPerPage()).all());
+ }
+
+ /**
+ * Gets a Pager of all state events for a single issue.
+ *
+ * GitLab Endpoint: GET /projects/:id/issues/:issue_iid/resource_state_events
+ *
+ * @param projectIdOrPath id, path of the project, or a Project instance holding the project ID or path
+ * @param issueIid the IID of the issue
+ * @param itemsPerPage the number of LabelEvent instances that will be fetched per page
+ * @return the Pager of IssueEvent instances for the specified issue IID
+ * @throws GitLabApiException if any exception occurs
+ */
+ public Pager getIssueStateEvents(Object projectIdOrPath, Integer issueIid, int itemsPerPage) throws GitLabApiException {
+ return (new Pager(this, IssueEvent.class, itemsPerPage, null,
+ "projects", getProjectIdOrPath(projectIdOrPath), "issues", issueIid, "resource_state_events"));
+ }
+
+ /**
+ * Gets a Stream of all state events for a single issue.
+ *
+ * GitLab Endpoint: GET /projects/:id/issues/:issue_iid/resource_state_events
+ *
+ * @param projectIdOrPath id, path of the project, or a Project instance holding the project ID or path
+ * @param issueIid the IID of the issue
+ * @return a Stream of IssueEvent for the specified issue
+ * @throws GitLabApiException if any exception occurs
+ */
+ public Stream getIssueStateEventsStream(Object projectIdOrPath, Integer issueIid) throws GitLabApiException {
+ return (getIssueStateEvents(projectIdOrPath, issueIid, getDefaultPerPage()).stream());
+ }
+}
diff --git a/src/main/java/org/gitlab4j/api/models/IssueEvent.java b/src/main/java/org/gitlab4j/api/models/IssueEvent.java
new file mode 100644
index 000000000..142621b81
--- /dev/null
+++ b/src/main/java/org/gitlab4j/api/models/IssueEvent.java
@@ -0,0 +1,93 @@
+package org.gitlab4j.api.models;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import org.gitlab4j.api.utils.JacksonJson;
+import org.gitlab4j.api.utils.JacksonJsonEnumHelper;
+
+public class IssueEvent {
+ /** Enum to use for specifying the state events resource type. */
+ public enum ResourceType {
+
+ ISSUE;
+
+ private static JacksonJsonEnumHelper enumHelper = new JacksonJsonEnumHelper<>(ResourceType.class,
+ true, true);
+
+ @JsonCreator
+ public static ResourceType forValue(String value) {
+ return enumHelper.forValue(value);
+ }
+
+ @JsonValue
+ public String toValue() {
+ return (enumHelper.toString(this));
+ }
+
+ @Override
+ public String toString() {
+ return (enumHelper.toString(this));
+ }
+ }
+
+ private int id;
+ private User user;
+ private String createdAt;
+ private ResourceType resourceType;
+ private int resourceId;
+ private String state;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public User getUser() {
+ return user;
+ }
+
+ public void setUser(User user) {
+ this.user = user;
+ }
+
+ public String getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setCreatedAt(String createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ public ResourceType getResourceType() {
+ return resourceType;
+ }
+
+ public void setResourceType(ResourceType resourceType) {
+ this.resourceType = resourceType;
+ }
+
+ public int getResourceId() {
+ return resourceId;
+ }
+
+ public void setResourceId(int resourceId) {
+ this.resourceId = resourceId;
+ }
+
+ public String getState() {
+ return state;
+ }
+
+ public void setState(String state) {
+ this.state = state;
+ }
+
+
+ @Override
+ public String toString() {
+ return (JacksonJson.toJsonString(this));
+ }
+}
diff --git a/src/test/java/org/gitlab4j/api/TestIssuesApi.java b/src/test/java/org/gitlab4j/api/TestIssuesApi.java
index 434769e66..d42146859 100644
--- a/src/test/java/org/gitlab4j/api/TestIssuesApi.java
+++ b/src/test/java/org/gitlab4j/api/TestIssuesApi.java
@@ -101,7 +101,7 @@ public static void teardown() throws GitLabApiException {
deleteAllTestIssues();
}
- private static void deleteAllTestIssues() {
+ public static void deleteAllTestIssues() {
if (gitLabApi != null) {
try {
diff --git a/src/test/java/org/gitlab4j/api/TestResourceStateEventsApi.java b/src/test/java/org/gitlab4j/api/TestResourceStateEventsApi.java
new file mode 100644
index 000000000..745f68e76
--- /dev/null
+++ b/src/test/java/org/gitlab4j/api/TestResourceStateEventsApi.java
@@ -0,0 +1,76 @@
+package org.gitlab4j.api;
+
+import org.gitlab4j.api.models.Issue;
+import org.gitlab4j.api.models.IssueEvent;
+import org.gitlab4j.api.models.Project;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import java.util.List;
+
+import static org.gitlab4j.api.TestIssuesApi.deleteAllTestIssues;
+import static org.junit.Assert.*;
+
+@Category(IntegrationTest.class)
+public class TestResourceStateEventsApi extends AbstractIntegrationTest {
+
+ private static GitLabApi gitLabApi;
+ private static Project testProject;
+
+ private static final String ISSUE_TITLE = "Test Issue Title";
+ private static final String ISSUE_DESCRIPTION = "This is a really nice description, not.";
+
+ public TestResourceStateEventsApi() {
+ super();
+ }
+
+ @BeforeClass
+ public static void setup() {
+ gitLabApi = baseTestSetup();
+ testProject = getTestProject();
+ }
+
+ @AfterClass
+ public static void teardown() {
+ deleteAllTestIssues();
+ }
+
+ @Test
+ public void testGetCloseReopenIssueEvents() throws GitLabApiException {
+ Integer projectId = testProject.getId();
+ Issue issue = gitLabApi.getIssuesApi().createIssue(projectId, ISSUE_TITLE, ISSUE_DESCRIPTION);
+
+ Issue closedIssue = gitLabApi.getIssuesApi().closeIssue(projectId, issue.getIid());
+ assertEquals(closedIssue.getState(), Constants.IssueState.CLOSED);
+
+ List issueEvents = gitLabApi.getResourceStateEventsApi().getIssueStateEvents(projectId, issue.getIid());
+ assertNotNull(issueEvents);
+ assertEquals(1, issueEvents.size());
+
+ assertEquals(1, issueEvents.stream()
+ .filter(issueEvent -> issueEvent.getState().equals(Constants.IssueState.CLOSED.toValue()))
+ .count());
+
+ Issue reopenedIssue = gitLabApi.getIssuesApi()
+ .updateIssue(projectId,
+ issue.getIid(),
+ null, null, null, null, null, null,
+ Constants.StateEvent.REOPEN,
+ null, null);
+ assertEquals(Constants.IssueState.OPENED.toValue(), reopenedIssue.getState().toValue());
+
+ issueEvents = gitLabApi.getResourceStateEventsApi().getIssueStateEvents(projectId, issue.getIid());
+ assertNotNull(issueEvents);
+ assertEquals(2, issueEvents.size());
+
+ assertEquals(1, issueEvents.stream()
+ .filter(issueEvent -> issueEvent.getState().equals(Constants.IssueState.CLOSED.toValue()))
+ .count());
+ assertEquals(1, issueEvents.stream()
+ .filter(issueEvent -> issueEvent.getState().equals(Constants.IssueState.REOPENED.toValue()))
+ .count());
+ }
+
+}