Skip to content
6 changes: 4 additions & 2 deletions Octokit.Reactive/Clients/IObservableIssuesClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -324,15 +324,17 @@ public interface IObservableIssuesClient
/// <param name="owner">The owner of the repository</param>
/// <param name="name">The name of the repository</param>
/// <param name="number">The issue number</param>
IObservable<Unit> Lock(string owner, string name, int number);
/// <param name="lockReason">The reason for locking the issue</param>
IObservable<Unit> Lock(string owner, string name, int number, LockReason? lockReason = null);

/// <summary>
/// Locks an issue for the specified repository. Issue owners and users with push access can lock an issue.
/// </summary>
/// <remarks>https://developer.github.com/v3/issues/#lock-an-issue</remarks>
/// <param name="repositoryId">The Id of the repository</param>
/// <param name="number">The issue number</param>
IObservable<Unit> Lock(long repositoryId, int number);
/// <param name="lockReason">The reason for locking the issue</param>
IObservable<Unit> Lock(long repositoryId, int number, LockReason? lockReason = null);

/// <summary>
/// Unlocks an issue for the specified repository. Issue owners and users with push access can unlock an issue.
Expand Down
10 changes: 6 additions & 4 deletions Octokit.Reactive/Clients/ObservableIssuesClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -480,12 +480,13 @@ public IObservable<Issue> Update(long repositoryId, int number, IssueUpdate issu
/// <param name="owner">The owner of the repository</param>
/// <param name="name">The name of the repository</param>
/// <param name="number">The issue number</param>
public IObservable<Unit> Lock(string owner, string name, int number)
/// <param name="lockReason">The reason for locking the issue</param>
public IObservable<Unit> Lock(string owner, string name, int number, LockReason? lockReason = null)
{
Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));

return _client.Lock(owner, name, number).ToObservable();
return _client.Lock(owner, name, number, lockReason).ToObservable();
}

/// <summary>
Expand All @@ -494,9 +495,10 @@ public IObservable<Unit> Lock(string owner, string name, int number)
/// <remarks>https://developer.github.com/v3/issues/#lock-an-issue</remarks>
/// <param name="repositoryId">The Id of the repository</param>
/// <param name="number">The issue number</param>
public IObservable<Unit> Lock(long repositoryId, int number)
/// <param name="lockReason">The reason for locking the issue</param>
public IObservable<Unit> Lock(long repositoryId, int number, LockReason? lockReason = null)
{
return _client.Lock(repositoryId, number).ToObservable();
return _client.Lock(repositoryId, number, lockReason).ToObservable();
}

/// <summary>
Expand Down
14 changes: 14 additions & 0 deletions Octokit.Tests.Integration/Clients/IssuesClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,20 @@ public async Task CanLockAndUnlockIssue()
Assert.False(retrieved.Locked);
}

[IntegrationTest]
public async Task CanAccessActiveLockReason()
{
var newIssue = new NewIssue("a test issue") { Body = "A new unassigned issue" };
var issue = await _issuesClient.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue);
Assert.False(issue.Locked);

await _issuesClient.Lock(_context.RepositoryOwner, _context.RepositoryName, issue.Number, LockReason.OffTopic);
var retrieved = await _issuesClient.Get(_context.RepositoryOwner, _context.RepositoryName, issue.Number);
Assert.NotNull(retrieved);
Assert.True(retrieved.Locked);
Assert.Equal(retrieved.ActiveLockReason, LockReason.OffTopic);
}

[IntegrationTest]
public async Task CanLockAndUnlockIssueWithRepositoryId()
{
Expand Down
6 changes: 4 additions & 2 deletions Octokit.Tests/Models/IssueTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,9 @@ public void CanBeDeserialized()
""events_url"": ""https://api.github.com/users/octocat/events{/privacy}"",
""received_events_url"": ""https://api.github.com/users/octocat/received_events"",
""type"": ""User"",
""site_admin"": false
}
""site_admin"": false,
},
""active_lock_reason"": null
}";
var serializer = new SimpleJsonSerializer();

Expand All @@ -130,6 +131,7 @@ public void CanBeDeserialized()
Assert.Equal(1347, issue.Number);
Assert.Equal("octocat", issue.User.Login);
Assert.Equal("bug", issue.Labels.First().Name);
Assert.Null(issue.ActiveLockReason);
}

public class TheToUpdateMethod
Expand Down
6 changes: 4 additions & 2 deletions Octokit/Clients/IIssuesClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -321,15 +321,17 @@ public interface IIssuesClient
/// <param name="owner">The owner of the repository</param>
/// <param name="name">The name of the repository</param>
/// <param name="number">The issue number</param>
Task Lock(string owner, string name, int number);
/// <param name="lockReason">The reason for locking the issue</param>
Task Lock(string owner, string name, int number, LockReason? lockReason = null);

/// <summary>
/// Locks an issue for the specified repository. Issue owners and users with push access can lock an issue.
/// </summary>
/// <remarks>https://developer.github.com/v3/issues/#lock-an-issue</remarks>
/// <param name="repositoryId">The Id of the repository</param>
/// <param name="number">The issue number</param>
Task Lock(long repositoryId, int number);
/// <param name="lockReason">The reason for locking the issue</param>
Task Lock(long repositoryId, int number, LockReason? lockReason = null);

/// <summary>
/// Unlocks an issue for the specified repository. Issue owners and users with push access can unlock an issue.
Expand Down
10 changes: 6 additions & 4 deletions Octokit/Clients/IssuesClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -500,13 +500,14 @@ public Task<Issue> Update(long repositoryId, int number, IssueUpdate issueUpdate
/// <param name="owner">The owner of the repository</param>
/// <param name="name">The name of the repository</param>
/// <param name="number">The issue number</param>
/// <param name="lockReason">The reason for locking the issue</param>
[ManualRoute("PUT", "/repos/{owner}/{repo}/issues/{issue_number}/lock")]
public Task Lock(string owner, string name, int number)
public Task Lock(string owner, string name, int number, LockReason? lockReason = null)
{
Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));

return ApiConnection.Put<Issue>(ApiUrls.IssueLock(owner, name, number), new object());
return ApiConnection.Put<Issue>(ApiUrls.IssueLock(owner, name, number), lockReason.HasValue ? new { LockReason = lockReason } : new object());
}

/// <summary>
Expand All @@ -515,10 +516,11 @@ public Task Lock(string owner, string name, int number)
/// <remarks>https://developer.github.com/v3/issues/#lock-an-issue</remarks>
/// <param name="repositoryId">The Id of the repository</param>
/// <param name="number">The issue number</param>
/// <param name="lockReason">The reason for locking the issue</param>
[ManualRoute("PUT", "/repositories/{id}/issues/{number}/lock")]
public Task Lock(long repositoryId, int number)
public Task Lock(long repositoryId, int number, LockReason? lockReason = null)
{
return ApiConnection.Put<Issue>(ApiUrls.IssueLock(repositoryId, number), new object());
return ApiConnection.Put<Issue>(ApiUrls.IssueLock(repositoryId, number), lockReason.HasValue ? new { LockReaons = lockReason } : new object());
}

/// <summary>
Expand Down
26 changes: 26 additions & 0 deletions Octokit/Models/Common/LockReason.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Octokit.Internal;

namespace Octokit
{
/// <summary>
/// The possible reasons that an issue or pull request was locked.
/// </summary>
public enum LockReason
{
// The issue or pull request was locked because the conversation was off-topic.
[Parameter(Value = "off-topic")]
OffTopic,

// The issue or pull request was locked because the conversation was resolved.
[Parameter(Value = "resolved")]
Resolved,

// The issue or pull request was locked because the conversation was spam.
[Parameter(Value = "spam")]
Spam,

// The issue or pull request was locked because the conversation was too heated.
[Parameter(Value = "too heated")]
TooHeated
}
}
9 changes: 8 additions & 1 deletion Octokit/Models/Response/Issue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
using System.Globalization;
using System.Linq;


namespace Octokit
{
[DebuggerDisplay("{DebuggerDisplay,nq}")]
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<Label> labels, User assignee, IReadOnlyList<User> assignees, Milestone milestone, int comments, PullRequest pullRequest, DateTimeOffset? closedAt, DateTimeOffset createdAt, DateTimeOffset? updatedAt, int id, string nodeId, bool locked, Repository repository, ReactionSummary reactions)
public Issue(string url, string htmlUrl, string commentsUrl, string eventsUrl, int number, ItemState state, string title, string body, User closedBy, User user, IReadOnlyList<Label> labels, User assignee, IReadOnlyList<User> assignees, Milestone milestone, int comments, PullRequest pullRequest, DateTimeOffset? closedAt, DateTimeOffset createdAt, DateTimeOffset? updatedAt, int id, string nodeId, bool locked, Repository repository, ReactionSummary reactions, LockReason? activeLockReason)
{
Id = id;
NodeId = nodeId;
Expand All @@ -37,6 +38,7 @@ public Issue(string url, string htmlUrl, string commentsUrl, string eventsUrl, i
Locked = locked;
Repository = repository;
Reactions = reactions;
ActiveLockReason = activeLockReason;
}

/// <summary>
Expand Down Expand Up @@ -156,6 +158,11 @@ public Issue(string url, string htmlUrl, string commentsUrl, string eventsUrl, i
/// </summary>
public ReactionSummary Reactions { get; protected set; }

/// <summary>
/// Reason that the conversation was locked.
/// </summary>
public StringEnum<LockReason>? ActiveLockReason { get; protected set; }

internal string DebuggerDisplay
{
get
Expand Down