Skip to content

Commit

Permalink
[Feat] Add Repository Autolinks Client (#2868)
Browse files Browse the repository at this point in the history
  • Loading branch information
SlyckLizzie authored Feb 1, 2024
1 parent c9ddf3e commit 2a87dd0
Show file tree
Hide file tree
Showing 13 changed files with 649 additions and 11 deletions.
2 changes: 1 addition & 1 deletion Octokit.Reactive/Clients/IObservableActionsOidcClient.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System;
using System.Reactive;
using System.Threading.Tasks;


namespace Octokit.Reactive
{
Expand Down
59 changes: 59 additions & 0 deletions Octokit.Reactive/Clients/IObservableAutolinksClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Reactive;

namespace Octokit.Reactive
{
/// <summary>
/// A client for GitHub's Repository Autolinks API
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/repos/autolinks">API documentation</a> for more information.
/// </remarks>
public interface IObservableAutolinksClient
{
/// <summary>
/// Returns a single autolink reference by ID that was configured for the given repository
/// </summary>
/// <param name="owner">The account owner of the repository</param>
/// <param name="repo">The name of the repository</param>
/// <param name="autolinkId">The unique identifier of the autolink</param>
/// <remarks>See the <a href="https://docs.github.com/en/rest/repos/autolinks#get-an-autolink-reference-of-a-repository">API documentation</a> for more information.</remarks>
IObservable<Autolink> Get(string owner, string repo, int autolinkId);

/// <summary>
/// Returns a list of autolinks configured for the given repository
/// </summary>
/// <param name="owner">The account owner of the repository</param>
/// <param name="repo">The name of the repository</param>
/// <remarks>See the <a href="https://docs.github.com/en/rest/repos/autolinks#list-all-autolinks-of-a-repository">API documentation</a> for more information.</remarks>
IObservable<Autolink> GetAll(string owner, string repo);

/// <summary>
/// Returns a list of autolinks configured for the given repository
/// </summary>
/// <param name="owner">The account owner of the repository</param>
/// <param name="repo">The name of the repository</param>
/// <param name="options">Options for changing the API response</param>
/// <remarks>See the <a href="https://docs.github.com/en/rest/repos/autolinks#list-all-autolinks-of-a-repository">API documentation</a> for more information.</remarks>
IObservable<Autolink> GetAll(string owner, string repo, ApiOptions options);

/// <summary>
/// Create an autolink reference for a repository
/// </summary>
/// <param name="owner">The account owner of the repository</param>
/// <param name="repo">The name of the repository</param>
/// <param name="autolink">The Autolink object to be created for the repository</param>
/// <remarks>See the <a href="https://docs.github.com/en/rest/repos/autolinks#create-an-autolink-reference-for-a-repository">API documentation</a> for more information.</remarks>
IObservable<Autolink> Create(string owner, string repo, AutolinkRequest autolink);

/// <summary>
/// Deletes a single autolink reference by ID that was configured for the given repository
/// </summary>
/// <param name="owner">The account owner of the repository</param>
/// <param name="repo">The name of the repository</param>
/// <param name="autolinkId">The unique identifier of the autolink</param>
/// <remarks>See the <a href="https://docs.github.com/en/rest/repos/autolinks#delete-an-autolink-reference-from-a-repository">API documentation</a> for more information.</remarks>
IObservable<Unit> Delete(string owner, string repo, int autolinkId);
}
}
11 changes: 9 additions & 2 deletions Octokit.Reactive/Clients/IObservableRepositoriesClient.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Reactive;
using System.Threading.Tasks;


namespace Octokit.Reactive
{
Expand Down Expand Up @@ -523,6 +522,14 @@ public interface IObservableRepositoriesClient
/// <returns>The updated <see cref="T:Octokit.Repository"/></returns>
IObservable<Repository> Edit(long repositoryId, RepositoryUpdate update);

/// <summary>
/// A client for GitHub's Repository Autolinks API
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/repos/autolinks">API documentation</a> for more information.
/// </remarks>
IObservableAutolinksClient Autolinks { get; }

/// <summary>
/// A client for GitHub's Repo Collaborators.
/// </summary>
Expand Down
72 changes: 72 additions & 0 deletions Octokit.Reactive/Clients/ObservableAutolinksClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using System;
using System.Reactive;
using System.Reactive.Threading.Tasks;
using Octokit.Reactive.Internal;


namespace Octokit.Reactive
{
/// <inheritdoc/>
public class ObservableAutolinksClient : IObservableAutolinksClient
{
readonly IAutolinksClient _client;
readonly IConnection _connection;


public ObservableAutolinksClient(IGitHubClient client)
{
Ensure.ArgumentNotNull(client, nameof(client));

_client = client.Repository.Autolinks;
_connection = client.Connection;
}


/// <inheritdoc/>
public IObservable<Autolink> Get(string owner, string repo, int autolinkId)
{
Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
Ensure.ArgumentNotNullOrEmptyString(repo, nameof(repo));

return _client.Get(owner, repo, autolinkId).ToObservable();
}

/// <inheritdoc/>
public IObservable<Autolink> GetAll(string owner, string repo)
{
Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
Ensure.ArgumentNotNullOrEmptyString(repo, nameof(repo));

return this.GetAll(owner, repo, ApiOptions.None);
}

/// <inheritdoc/>
public IObservable<Autolink> GetAll(string owner, string repo, ApiOptions options)
{
Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
Ensure.ArgumentNotNullOrEmptyString(repo, nameof(repo));
Ensure.ArgumentNotNull(options, nameof(options));

return _connection.GetAndFlattenAllPages<Autolink>(ApiUrls.AutolinksGetAll(owner, repo), options);
}

/// <inheritdoc/>
public IObservable<Autolink> Create(string owner, string repo, AutolinkRequest autolink)
{
Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
Ensure.ArgumentNotNullOrEmptyString(repo, nameof(repo));
Ensure.ArgumentNotNull(autolink, nameof(autolink));

return _client.Create(owner, repo, autolink).ToObservable();
}

/// <inheritdoc/>
public IObservable<Unit> Delete(string owner, string repo, int autolinkId)
{
Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
Ensure.ArgumentNotNullOrEmptyString(repo, nameof(repo));

return _client.Delete(owner, repo, autolinkId).ToObservable();
}
}
}
11 changes: 10 additions & 1 deletion Octokit.Reactive/Clients/ObservableRepositoriesClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
using System.Reactive;
using System.Reactive.Linq;
using System.Reactive.Threading.Tasks;
using System.Threading.Tasks;
using Octokit.Reactive.Clients;
using Octokit.Reactive.Internal;


namespace Octokit.Reactive
{
public class ObservableRepositoriesClient : IObservableRepositoriesClient
Expand Down Expand Up @@ -42,6 +42,7 @@ public ObservableRepositoriesClient(IGitHubClient client)
Traffic = new ObservableRepositoryTrafficClient(client);
Project = new ObservableProjectsClient(client);
Actions = new ObservableRepositoryActionsClient(client);
Autolinks = new ObservableAutolinksClient(client);
}

/// <summary>
Expand Down Expand Up @@ -824,6 +825,14 @@ public IObservable<CompareResult> Compare(string owner, string name, string @bas
/// </remarks>
public IObservableRepositoryActionsClient Actions { get; private set; }

/// <summary>
/// A client for GitHub's Repository Autolinks API
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/repos/autolinks">API documentation</a> for more information.
/// </remarks>
public IObservableAutolinksClient Autolinks { get; private set; }

/// <summary>
/// A client for GitHub's Repository Branches API.
/// </summary>
Expand Down
195 changes: 195 additions & 0 deletions Octokit.Tests/Clients/AutolinksClientTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
using NSubstitute;
using System;
using System.Threading.Tasks;
using Xunit;


namespace Octokit.Tests.Clients
{
public class AutolinksClientTests
{
public class TheCtor
{
[Fact]
public void EnsuresNonNullArguments()
{
Assert.Throws<ArgumentNullException>(() => new AutolinksClient(null));
}
}


public class TheGetMethod
{
[Fact]
public async Task RequestsCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new AutolinksClient(connection);

await client.Get("fakeOwner", "fakeRepo", 42);

connection.Received().Get<Autolink>(
Arg.Is<Uri>(u => u.ToString() == "repos/fakeOwner/fakeRepo/autolinks/42"));
}

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

await Assert.ThrowsAsync<ArgumentNullException>(() => client.Get(null, "repo", 42));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Get("owner", null, 42));
}

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

await Assert.ThrowsAsync<ArgumentException>(() => client.Get("", "repo", 42));
await Assert.ThrowsAsync<ArgumentException>(() => client.Get("owner", "", 42));
}
}

public class TheGetAllMethod
{
[Fact]
public async Task RequestsCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new AutolinksClient(connection);

await client.GetAll("fakeOwner", "fakeRepo");

connection.Received().GetAll<Autolink>(
Arg.Is<Uri>(u => u.ToString() == "repos/fakeOwner/fakeRepo/autolinks"), Args.ApiOptions);
}

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

var options = new ApiOptions
{
PageCount = 1,
PageSize = 1,
StartPage = 1
};

await client.GetAll("fakeOwner", "fakeRepo", options);

connection.Received(1)
.GetAll<Autolink>(Arg.Is<Uri>(u => u.ToString() == "repos/fakeOwner/fakeRepo/autolinks"),
options);
}

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

await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAll(null, "repo"));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAll("owner", null));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAll(null, "repo", ApiOptions.None));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAll("owner", null, ApiOptions.None));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAll("owner", "repo", null));
}

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

await Assert.ThrowsAsync<ArgumentException>(() => client.GetAll("", "repo"));
await Assert.ThrowsAsync<ArgumentException>(() => client.GetAll("owner", ""));
await Assert.ThrowsAsync<ArgumentException>(() => client.GetAll("", "repo", ApiOptions.None));
await Assert.ThrowsAsync<ArgumentException>(() => client.GetAll("owner", "", ApiOptions.None));
}
}

public class TheCreateMethod
{
[Fact]
public async Task PostsToCorrectUrl()
{
var newAutolink = new AutolinkRequest("fakeKeyPrefix", "fakeUrlTemplate", true);
var connection = Substitute.For<IApiConnection>();
var client = new AutolinksClient(connection);

await client.Create("fakeOwner", "fakeRepo", newAutolink);

connection.Received().Post<Autolink>(
Arg.Is<Uri>(u => u.ToString() == "repos/fakeOwner/fakeRepo/autolinks"),
Arg.Is<AutolinkRequest>(a => a.KeyPrefix == "fakeKeyPrefix"
&& a.UrlTemplate == "fakeUrlTemplate"
&& a.IsAlphanumeric == true));
}

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

var newAutolink = new AutolinkRequest("fakeKeyPrefix", "fakeUrlTemplate", true);

await Assert.ThrowsAsync<ArgumentNullException>(() => client.Create(null, "repo", newAutolink));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Create("owner", null, newAutolink));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Create("owner", "repo", null));
}

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

var newAutolink = new AutolinkRequest("fakeKeyPrefix", "fakeUrlTemplate", true);

await Assert.ThrowsAsync<ArgumentException>(() => client.Create("", "repo", newAutolink));
await Assert.ThrowsAsync<ArgumentException>(() => client.Create("owner", "", newAutolink));
}
}

public class TheDeleteMethod
{
[Fact]
public async Task DeletesCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new AutolinksClient(connection);

await client.Delete("fakeOwner", "fakeRepo", 42);

connection.Received().Delete(
Arg.Is<Uri>(u => u.ToString() == "repos/fakeOwner/fakeRepo/autolinks/42"));
}

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

await Assert.ThrowsAsync<ArgumentNullException>(() => client.Delete(null, "repo", 42));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Delete("owner", null, 42));
}

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

await Assert.ThrowsAsync<ArgumentException>(() => client.Delete("", "repo", 42));
await Assert.ThrowsAsync<ArgumentException>(() => client.Delete("owner", "", 42));
}
}
}
}
Loading

0 comments on commit 2a87dd0

Please sign in to comment.