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