Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] Add Repository Autolinks Client #2868

Merged
merged 1 commit into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading