diff --git a/Octokit.Tests.Integration/Clients/IssuesClientTests.cs b/Octokit.Tests.Integration/Clients/IssuesClientTests.cs
index 2a92b35b59..0edfcbdcfe 100644
--- a/Octokit.Tests.Integration/Clients/IssuesClientTests.cs
+++ b/Octokit.Tests.Integration/Clients/IssuesClientTests.cs
@@ -213,6 +213,46 @@ public async Task CanCreateRetrieveAndCloseIssue()
}
}
+ [IntegrationTest]
+ public async Task CanCreateCloseAndReopenIssue()
+ {
+ var newIssue = new NewIssue("a test issue") { Body = "A new unassigned issue" };
+ newIssue.Labels.Add("test");
+ newIssue.Assignees.Add(_context.RepositoryOwner);
+
+ var issue = await _issuesClient.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue);
+ Assert.NotNull(issue);
+ Assert.True(issue.Assignees.All(x => x.Login == _context.RepositoryOwner));
+
+ var retrieved = await _issuesClient.Get(_context.RepositoryOwner, _context.RepositoryName, issue.Number);
+ Assert.NotNull(retrieved);
+ Assert.True(retrieved.Assignees.Count == 1);
+ Assert.True(retrieved.Assignees[0].Login == _context.RepositoryOwner);
+
+ var update = retrieved.ToUpdate();
+ update.State = ItemState.Closed;
+ update.StateReason = ItemStateReason.NotPlanned;
+
+ var closed = await _issuesClient.Update(_context.RepositoryOwner, _context.RepositoryName, issue.Number, update);
+ Assert.NotNull(closed);
+ Assert.Equal(ItemState.Closed, closed.State);
+ Assert.Equal(ItemStateReason.NotPlanned, closed.StateReason);
+
+ retrieved = await _issuesClient.Get(_context.RepositoryOwner, _context.RepositoryName, issue.Number);
+ Assert.NotNull(retrieved);
+ Assert.Equal(ItemState.Closed, retrieved.State);
+ Assert.Equal(ItemStateReason.NotPlanned, retrieved.StateReason);
+
+ update = retrieved.ToUpdate();
+ update.State = ItemState.Open;
+ update.StateReason = ItemStateReason.Reopened;
+
+ var reopened = await _issuesClient.Update(_context.RepositoryOwner, _context.RepositoryName, issue.Number, update);
+ Assert.NotNull(reopened);
+ Assert.Equal(ItemState.Open, reopened.State);
+ Assert.Equal(ItemStateReason.Reopened, reopened.StateReason);
+ }
+
[IntegrationTest]
public async Task CanCreateRetrieveAndCloseIssueWithRepositoryId()
{
diff --git a/Octokit.Tests/Models/IssueTest.cs b/Octokit.Tests/Models/IssueTest.cs
index 7d0e910f5e..8e34033383 100644
--- a/Octokit.Tests/Models/IssueTest.cs
+++ b/Octokit.Tests/Models/IssueTest.cs
@@ -145,6 +145,7 @@ public void CreatesAnIssueUpdateRequestObject()
""html_url"": ""https://github.com/octocat/Hello-World/issues/1347"",
""number"": 1347,
""state"": ""open"",
+""state_reason"": ""reopened"",
""title"": ""Found a bug"",
""body"": ""I'm having a problem with this."",
""user"": {
@@ -283,6 +284,7 @@ public void CreatesAnIssueUpdateRequestObject()
Assert.NotNull(update.Labels);
Assert.Equal(1, update.Milestone.GetValueOrDefault());
Assert.Equal("octocat", update.Assignees.FirstOrDefault());
+ Assert.Equal(ItemStateReason.Reopened, update.StateReason.GetValueOrDefault());
}
}
}
diff --git a/Octokit/Models/Request/IssueRequest.cs b/Octokit/Models/Request/IssueRequest.cs
index 8c6edc9a0f..c58792e967 100644
--- a/Octokit/Models/Request/IssueRequest.cs
+++ b/Octokit/Models/Request/IssueRequest.cs
@@ -167,6 +167,30 @@ public enum ItemState
Closed
}
+ ///
+ /// The reason for the state change.
+ ///
+ public enum ItemStateReason
+ {
+ ///
+ /// Item closed as completed.
+ ///
+ [Parameter(Value = "completed")]
+ Completed,
+
+ ///
+ /// Item closed as unplanned.
+ ///
+ [Parameter(Value = "not_planned")]
+ NotPlanned,
+
+ ///
+ /// Item reopened.
+ ///
+ [Parameter(Value = "reopened")]
+ Reopened
+ }
+
///
/// The available properties to sort issues by.
///
diff --git a/Octokit/Models/Request/IssueUpdate.cs b/Octokit/Models/Request/IssueUpdate.cs
index 8837e1e32a..34a4821244 100644
--- a/Octokit/Models/Request/IssueUpdate.cs
+++ b/Octokit/Models/Request/IssueUpdate.cs
@@ -53,6 +53,11 @@ public class IssueUpdate
///
public ItemState? State { get; set; }
+ ///
+ /// The reason for the state change. Ignored unless is changed.
+ ///
+ public ItemStateReason? StateReason { get; set; }
+
internal string DebuggerDisplay
{
get
@@ -157,4 +162,4 @@ public void RemoveLabel(string name)
}
}
}
-}
\ No newline at end of file
+}
diff --git a/Octokit/Models/Response/Issue.cs b/Octokit/Models/Response/Issue.cs
index ef25f3c26f..b18e99c931 100644
--- a/Octokit/Models/Response/Issue.cs
+++ b/Octokit/Models/Response/Issue.cs
@@ -12,7 +12,7 @@ public class Issue
{
public Issue() { }
- public Issue(string url, string htmlUrl, string commentsUrl, string eventsUrl, int number, ItemState state, string title, string body, User closedBy, User user, IReadOnlyList