Skip to content

Commit

Permalink
Implement Lock/Unlock Issue
Browse files Browse the repository at this point in the history
  • Loading branch information
prayankmathur committed Mar 25, 2016
1 parent f354d1b commit 6f5d31e
Show file tree
Hide file tree
Showing 9 changed files with 265 additions and 8 deletions.
23 changes: 22 additions & 1 deletion Octokit.Reactive/Clients/IObservableIssuesClient.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Reactive;

namespace Octokit.Reactive
{
Expand Down Expand Up @@ -156,5 +157,25 @@ public interface IObservableIssuesClient
/// </param>
/// <returns></returns>
IObservable<Issue> Update(string owner, string name, int number, IssueUpdate issueUpdate);

/// <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="owner">The owner of the repository</param>
/// <param name="name">The name of the repository</param>
/// <param name="number">The issue number</param>
/// <returns></returns>
IObservable<Unit> LockIssue(string owner, string name, int number);

/// <summary>
/// Unlocks an issue for the specified repository. Issue owners and users with push access can unlock an issue.
/// </summary>
/// <remarks>https://developer.github.com/v3/issues/#unlock-an-issue</remarks>
/// <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>
/// <returns></returns>
IObservable<Unit> UnlockIssue(string owner, string name, int number);
}
}
}
33 changes: 33 additions & 0 deletions Octokit.Reactive/Clients/ObservableIssuesClient.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Reactive.Threading.Tasks;
using Octokit.Reactive.Internal;
using System.Reactive;

namespace Octokit.Reactive
{
Expand Down Expand Up @@ -222,5 +223,37 @@ public IObservable<Issue> Update(string owner, string name, int number, IssueUpd

return _client.Update(owner, name, number, issueUpdate).ToObservable();
}

/// <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="owner">The owner of the repository</param>
/// <param name="name">The name of the repository</param>
/// <param name="number">The issue number</param>
/// <returns></returns>
public IObservable<Unit> LockIssue(string owner, string name, int number)
{
Ensure.ArgumentNotNullOrEmptyString(owner, "owner");
Ensure.ArgumentNotNullOrEmptyString(name, "name");

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

/// <summary>
/// Unlocks an issue for the specified repository. Issue owners and users with push access can unlock an issue.
/// </summary>
/// <remarks>https://developer.github.com/v3/issues/#unlock-an-issue</remarks>
/// <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>
/// <returns></returns>
public IObservable<Unit> UnlockIssue(string owner, string name, int number)
{
Ensure.ArgumentNotNullOrEmptyString(owner, "owner");
Ensure.ArgumentNotNullOrEmptyString(name, "name");

return _client.UnlockIssue(owner, name, number).ToObservable();
}
}
}
20 changes: 20 additions & 0 deletions Octokit.Tests.Integration/Clients/IssuesClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,26 @@ public async Task CanCreateRetrieveAndCloseIssue()
}

[IntegrationTest]
public async Task CanLockAndUnlockIssue()
{
var newIssue = new NewIssue("a test issue") { Body = "A new unassigned issue" };
var issue = await _issuesClient.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue);
var retrieved = await _issuesClient.Get(_context.RepositoryOwner, _context.RepositoryName, issue.Number);

Assert.Equal(false, issue.Locked);

await _issuesClient.LockIssue(_context.RepositoryOwner, _context.RepositoryName, issue.Number);
retrieved = await _issuesClient.Get(_context.RepositoryOwner, _context.RepositoryName, issue.Number);
Assert.NotNull(retrieved);
Assert.Equal(true, issue.Locked);

await _issuesClient.UnlockIssue(_context.RepositoryOwner, _context.RepositoryName, issue.Number);
retrieved = await _issuesClient.Get(_context.RepositoryOwner, _context.RepositoryName, issue.Number);
Assert.NotNull(retrieved);
Assert.Equal(false, issue.Locked);
}

[IntegrationTest]
public async Task CanListOpenIssuesWithDefaultSort()
{
var newIssue1 = new NewIssue("A test issue1") { Body = "A new unassigned issue" };
Expand Down
17 changes: 17 additions & 0 deletions Octokit.Tests.Integration/Reactive/ObservableIssuesClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,23 @@ public async Task CanCreateAndUpdateIssues()
Assert.Equal("Modified integration test issue", updateResult.Title);
}

[IntegrationTest]
public async Task CanLockAndUnlockIssues()
{
var newIssue = new NewIssue("Integration Test Issue");

var createResult = await _client.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue);
Assert.Equal(false, createResult.Locked);

await _client.LockIssue(_context.RepositoryOwner, _context.RepositoryName, createResult.Number);
var lockResult = await _client.Get(_context.RepositoryOwner, _context.RepositoryName, createResult.Number);
Assert.Equal(true, lockResult.Locked);

await _client.UnlockIssue(_context.RepositoryOwner, _context.RepositoryName, createResult.Number);
var unlockIssueResult = await _client.Get(_context.RepositoryOwner, _context.RepositoryName, createResult.Number);
Assert.Equal(false, unlockIssueResult.Locked);
}

public void Dispose()
{
_context.Dispose();
Expand Down
52 changes: 52 additions & 0 deletions Octokit.Tests/Clients/IssuesClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,58 @@ public async Task EnsuresArgumentsNotNull()
}
}

public class TheLockIssueMethod
{
[Fact]
public void PostsToCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new IssuesClient(connection);

client.LockIssue("fake", "repo", 42);

connection.Received().Put(Arg.Is<Uri>(u => u.ToString() == "repos/fake/repo/issues/42/lock"));
}

[Fact]
public async Task EnsuresArgumentsNotNull()
{
var connection = Substitute.For<IApiConnection>();
var client = new IssuesClient(connection);

await Assert.ThrowsAsync<ArgumentNullException>(() => client.LockIssue(null, "name", 1));
await Assert.ThrowsAsync<ArgumentException>(() => client.LockIssue("", "name", 1));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.LockIssue("owner", null, 1));
await Assert.ThrowsAsync<ArgumentException>(() => client.LockIssue("owner", "", 1));
}
}

public class TheUnlockIssueMethod
{
[Fact]
public void PostsToCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new IssuesClient(connection);

client.UnlockIssue("fake", "repo", 42);

connection.Received().Delete(Arg.Is<Uri>(u => u.ToString() == "repos/fake/repo/issues/42/lock"));
}

[Fact]
public async Task EnsuresArgumentsNotNull()
{
var connection = Substitute.For<IApiConnection>();
var client = new IssuesClient(connection);

await Assert.ThrowsAsync<ArgumentNullException>(() => client.UnlockIssue(null, "name", 1));
await Assert.ThrowsAsync<ArgumentException>(() => client.UnlockIssue("", "name", 1));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.UnlockIssue("owner", null, 1));
await Assert.ThrowsAsync<ArgumentException>(() => client.UnlockIssue("owner", "", 1));
}
}

public class TheCtor
{
[Fact]
Expand Down
60 changes: 55 additions & 5 deletions Octokit.Tests/Reactive/ObservableIssuesClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -329,11 +329,61 @@ public void EnsuresArgumentsNotNull()
var gitHubClient = Substitute.For<IGitHubClient>();
var client = new ObservableIssuesClient(gitHubClient);

Assert.Throws<ArgumentNullException>(() => client.Create(null, "name", new NewIssue("title")));
Assert.Throws<ArgumentException>(() => client.Create("", "name", new NewIssue("x")));
Assert.Throws<ArgumentNullException>(() => client.Create("owner", null, new NewIssue("x")));
Assert.Throws<ArgumentException>(() => client.Create("owner", "", new NewIssue("x")));
Assert.Throws<ArgumentNullException>(() => client.Create("owner", "name", null));
Assert.Throws<ArgumentNullException>(() => client.Update(null, "name", 42, new IssueUpdate()));
Assert.Throws<ArgumentException>(() => client.Update("", "name", 42, new IssueUpdate()));
Assert.Throws<ArgumentNullException>(() => client.Update("owner", null, 42, new IssueUpdate()));
Assert.Throws<ArgumentException>(() => client.Update("owner", "", 42, new IssueUpdate()));
Assert.Throws<ArgumentNullException>(() => client.Update("owner", "name", 42, null));
}
}

public class TheLockIssueMethod
{
[Fact]
public void LockIssue()
{
var gitHubClient = Substitute.For<IGitHubClient>();
var client = new ObservableIssuesClient(gitHubClient);

client.LockIssue("fake", "repo", 42);
gitHubClient.Issue.Received().LockIssue("fake", "repo", 42);
}

[Fact]
public void EnsuresArgumentsNotNull()
{
var gitHubClient = Substitute.For<IGitHubClient>();
var client = new ObservableIssuesClient(gitHubClient);

Assert.Throws<ArgumentNullException>(() => client.LockIssue(null, "name", 42));
Assert.Throws<ArgumentException>(() => client.LockIssue("", "name", 42));
Assert.Throws<ArgumentNullException>(() => client.LockIssue("owner", null, 42));
Assert.Throws<ArgumentException>(() => client.LockIssue("owner", "", 42));
}
}

public class TheUnlockIssueMethod
{
[Fact]
public void UnlockIssue()
{
var gitHubClient = Substitute.For<IGitHubClient>();
var client = new ObservableIssuesClient(gitHubClient);

client.UnlockIssue("fake", "repo", 42);
gitHubClient.Issue.Received().UnlockIssue("fake", "repo", 42);
}

[Fact]
public void EnsuresArgumentsNotNull()
{
var gitHubClient = Substitute.For<IGitHubClient>();
var client = new ObservableIssuesClient(gitHubClient);

Assert.Throws<ArgumentNullException>(() => client.UnlockIssue(null, "name", 42));
Assert.Throws<ArgumentException>(() => client.UnlockIssue("", "name", 42));
Assert.Throws<ArgumentNullException>(() => client.UnlockIssue("owner", null, 42));
Assert.Throws<ArgumentException>(() => client.UnlockIssue("owner", "", 42));
}
}

Expand Down
24 changes: 22 additions & 2 deletions Octokit/Clients/IIssuesClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,16 +152,36 @@ public interface IIssuesClient
Task<Issue> Create(string owner, string name, NewIssue newIssue);

/// <summary>
/// Creates an issue for the specified repository. Any user with pull access to a repository can create an
/// Updates an issue for the specified repository. Any user with pull access to a repository can update an
/// issue.
/// </summary>
/// <remarks>http://developer.github.com/v3/issues/#create-an-issue</remarks>
/// <remarks>http://developer.github.com/v3/issues/#edit-an-issue</remarks>
/// <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="issueUpdate">An <see cref="IssueUpdate"/> instance describing the changes to make to the issue
/// </param>
/// <returns></returns>
Task<Issue> Update(string owner, string name, int number, IssueUpdate issueUpdate);

/// <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="owner">The owner of the repository</param>
/// <param name="name">The name of the repository</param>
/// <param name="number">The issue number</param>
/// <returns></returns>
Task LockIssue(string owner, string name, int number);

/// <summary>
/// Unlocks an issue for the specified repository. Issue owners and users with push access can unlock an issue.
/// </summary>
/// <remarks>https://developer.github.com/v3/issues/#unlock-an-issue</remarks>
/// <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>
/// <returns></returns>
Task UnlockIssue(string owner, string name, int number);
}
}
32 changes: 32 additions & 0 deletions Octokit/Clients/IssuesClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -225,5 +225,37 @@ public Task<Issue> Update(string owner, string name, int number, IssueUpdate iss

return ApiConnection.Patch<Issue>(ApiUrls.Issue(owner, name, number), issueUpdate);
}

/// <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="owner">The owner of the repository</param>
/// <param name="name">The name of the repository</param>
/// <param name="number">The issue number</param>
/// <returns></returns>
public Task LockIssue(string owner, string name, int number)
{
Ensure.ArgumentNotNullOrEmptyString(owner, "owner");
Ensure.ArgumentNotNullOrEmptyString(name, "name");

return ApiConnection.Put(ApiUrls.IssueLock(owner, name, number));
}

/// <summary>
/// Unlocks an issue for the specified repository. Issue owners and users with push access can unlock an issue.
/// </summary>
/// <remarks>https://developer.github.com/v3/issues/#unlock-an-issue</remarks>
/// <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>
/// <returns></returns>
public Task UnlockIssue(string owner, string name, int number)
{
Ensure.ArgumentNotNullOrEmptyString(owner, "owner");
Ensure.ArgumentNotNullOrEmptyString(name, "name");

return ApiConnection.Delete(ApiUrls.IssueLock(owner, name, number));
}
}
}
12 changes: 12 additions & 0 deletions Octokit/Helpers/ApiUrls.cs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,18 @@ public static Uri Issue(string owner, string name, int number)
return "repos/{0}/{1}/issues/{2}".FormatUri(owner, name, number);
}

/// <summary>
/// Returns the <see cref="Uri"/> for the specified issue to be locked/unlocked.
/// </summary>
/// <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>
/// <returns></returns>
public static Uri IssueLock(string owner, string name, int number)
{
return "repos/{0}/{1}/issues/{2}/lock".FormatUri(owner, name, number);
}

/// <summary>
/// Returns the <see cref="Uri"/> for the comments for all issues in a specific repo.
/// </summary>
Expand Down

0 comments on commit 6f5d31e

Please sign in to comment.