From a57fb1278d1bca6375a6f80345da90c5dec5077f Mon Sep 17 00:00:00 2001 From: Martin Scholz Date: Wed, 28 Sep 2016 17:16:58 +0200 Subject: [PATCH] [WIP] Add repository traffic preview (#1457) * Add response models * Supress message * correct spelling Timestamp * implement traffic client * add reactive client * [WIP] unit tests * add argument check * finish unit tests * add integration tests * Change repositoryId from int to long Remove GetAll naming of endpoints and add to PaginationTest exclusions Rename View and Clone classes to be more specific Add handling of TimeStamp fields being UtcUnix time Add integration tests for repositoryId methods --- .../Clients/IObservableRepositoriesClient.cs | 8 + .../IObservableRepositoryTrafficClient.cs | 77 ++++++++ .../Clients/ObservableReleasesClient.cs | 2 +- .../Clients/ObservableRepositoriesClient.cs | 11 +- .../ObservableRepositoryTrafficClient.cs | 124 ++++++++++++ Octokit.Reactive/Octokit.Reactive-Mono.csproj | 2 + .../Octokit.Reactive-MonoAndroid.csproj | 2 + .../Octokit.Reactive-Monotouch.csproj | 2 + Octokit.Reactive/Octokit.Reactive.csproj | 2 + .../Clients/RepositoryTrafficClientTests.cs | 111 +++++++++++ .../Octokit.Tests.Integration.csproj | 1 + .../Clients/RepositoryTrafficClientTests.cs | 181 ++++++++++++++++++ Octokit.Tests/Octokit.Tests.csproj | 2 + .../ObservableRepositoryTrafficClientTests.cs | 179 +++++++++++++++++ Octokit/Clients/IRepositoriesClient.cs | 8 + Octokit/Clients/IRepositoryTrafficClient.cs | 82 ++++++++ Octokit/Clients/RepositoriesClient.cs | 9 + Octokit/Clients/RepositoryTrafficClient.cs | 118 ++++++++++++ Octokit/Helpers/AcceptHeaders.cs | 2 + Octokit/Helpers/ApiUrls.cs | 84 ++++++++ .../Request/RepositoryTrafficRequest.cs | 23 +++ .../Models/Response/RepositoryTrafficClone.cs | 75 ++++++++ .../Models/Response/RepositoryTrafficPath.cs | 35 ++++ .../Response/RepositoryTrafficReferrer.cs | 32 ++++ .../Models/Response/RepositoryTrafficView.cs | 69 +++++++ Octokit/Octokit-Mono.csproj | 7 + Octokit/Octokit-MonoAndroid.csproj | 7 + Octokit/Octokit-Monotouch.csproj | 7 + Octokit/Octokit-Portable.csproj | 7 + Octokit/Octokit-netcore45.csproj | 7 + Octokit/Octokit.csproj | 7 + 31 files changed, 1281 insertions(+), 2 deletions(-) create mode 100644 Octokit.Reactive/Clients/IObservableRepositoryTrafficClient.cs create mode 100644 Octokit.Reactive/Clients/ObservableRepositoryTrafficClient.cs create mode 100644 Octokit.Tests.Integration/Clients/RepositoryTrafficClientTests.cs create mode 100644 Octokit.Tests/Clients/RepositoryTrafficClientTests.cs create mode 100644 Octokit.Tests/Reactive/ObservableRepositoryTrafficClientTests.cs create mode 100644 Octokit/Clients/IRepositoryTrafficClient.cs create mode 100644 Octokit/Clients/RepositoryTrafficClient.cs create mode 100644 Octokit/Models/Request/RepositoryTrafficRequest.cs create mode 100644 Octokit/Models/Response/RepositoryTrafficClone.cs create mode 100644 Octokit/Models/Response/RepositoryTrafficPath.cs create mode 100644 Octokit/Models/Response/RepositoryTrafficReferrer.cs create mode 100644 Octokit/Models/Response/RepositoryTrafficView.cs diff --git a/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs b/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs index ef0f5636..5d61bd7b 100644 --- a/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs +++ b/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs @@ -592,5 +592,13 @@ namespace Octokit.Reactive /// See the Repository Invitations API documentation for more information. /// IObservableRepositoryInvitationsClient Invitation { get; } + + /// + /// Access GitHub's Repository Traffic API + /// + /// + /// Refer to the API documentation for more information: https://developer.github.com/v3/repos/traffic/ + /// + IObservableRepositoryTrafficClient Traffic { get; } } } diff --git a/Octokit.Reactive/Clients/IObservableRepositoryTrafficClient.cs b/Octokit.Reactive/Clients/IObservableRepositoryTrafficClient.cs new file mode 100644 index 00000000..637d6145 --- /dev/null +++ b/Octokit.Reactive/Clients/IObservableRepositoryTrafficClient.cs @@ -0,0 +1,77 @@ +using System; + +namespace Octokit.Reactive +{ + /// + /// A client for GitHub's Repository Traffic API. + /// + /// + /// See the Repository Traffic API documentation for more information. + /// + public interface IObservableRepositoryTrafficClient + { + /// + /// List the top 10 referrers over the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#list-referrers + /// The owner of the repository + /// The name of the repository + IObservable GetReferrers(string owner, string name); + + /// + /// List the top 10 referrers over the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#list-referrers + /// The owner of the repository + IObservable GetReferrers(long repositoryId); + + /// + /// List the top 10 popular contents over the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#list-paths + /// The owner of the repository + /// The name of the repository + IObservable GetPaths(string owner, string name); + + /// + /// List the top 10 popular contents over the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#list-paths + /// The owner of the repository + IObservable GetPaths(long repositoryId); + + /// + /// Get the total number of views and breakdown per day or week for the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#views + /// The owner of the repository + /// The name of the repository + /// Breakdown per day or week + IObservable GetViews(string owner, string name, RepositoryTrafficRequest per); + + /// + /// Get the total number of views and breakdown per day or week for the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#views + /// The owner of the repository + /// Breakdown per day or week + IObservable GetViews(long repositoryId, RepositoryTrafficRequest per); + + /// + /// Get the total number of clones and breakdown per day or week for the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#clones + /// The owner of the repository + /// The name of the repository + /// Breakdown per day or week + IObservable GetClones(string owner, string name, RepositoryTrafficRequest per); + + /// + /// Get the total number of clones and breakdown per day or week for the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#clones + /// The owner of the repository + /// Breakdown per day or week + IObservable GetClones(long repositoryId, RepositoryTrafficRequest per); + } +} diff --git a/Octokit.Reactive/Clients/ObservableReleasesClient.cs b/Octokit.Reactive/Clients/ObservableReleasesClient.cs index 5f233fda..2a98e85f 100644 --- a/Octokit.Reactive/Clients/ObservableReleasesClient.cs +++ b/Octokit.Reactive/Clients/ObservableReleasesClient.cs @@ -38,7 +38,7 @@ namespace Octokit.Reactive Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); Ensure.ArgumentNotNullOrEmptyString(name, "name"); - return GetAll(owner, name, ApiOptions.None); + return GetAll(owner, name, ApiOptions.None); } /// diff --git a/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs b/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs index 5f1d2fd0..7d7370df 100644 --- a/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs +++ b/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs @@ -36,6 +36,7 @@ namespace Octokit.Reactive Merging = new ObservableMergingClient(client); Page = new ObservableRepositoryPagesClient(client); Invitation = new ObservableRepositoryInvitationsClient(client); + Traffic = new ObservableRepositoryTrafficClient(client); } /// @@ -880,6 +881,14 @@ namespace Octokit.Reactive /// /// See the Repository Invitations API documentation for more information. /// - public IObservableRepositoryInvitationsClient Invitation { get; private set; } + public IObservableRepositoryInvitationsClient Invitation { get; private set; } + + /// + /// Access GitHub's Repository Traffic API + /// + /// + /// Refer to the API documentation for more information: https://developer.github.com/v3/repos/traffic/ + /// + public IObservableRepositoryTrafficClient Traffic { get; private set; } } } diff --git a/Octokit.Reactive/Clients/ObservableRepositoryTrafficClient.cs b/Octokit.Reactive/Clients/ObservableRepositoryTrafficClient.cs new file mode 100644 index 00000000..5978e49c --- /dev/null +++ b/Octokit.Reactive/Clients/ObservableRepositoryTrafficClient.cs @@ -0,0 +1,124 @@ +using System; +using System.Reactive.Linq; +using System.Reactive.Threading.Tasks; + +namespace Octokit.Reactive +{ + public class ObservableRepositoryTrafficClient : IObservableRepositoryTrafficClient + { + readonly IRepositoryTrafficClient _client; + + public ObservableRepositoryTrafficClient(IGitHubClient client) + { + Ensure.ArgumentNotNull(client, "client"); + + _client = client.Repository.Traffic; + } + + /// + /// List the top 10 popular contents over the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#list-paths + /// The owner of the repository + public IObservable GetPaths(long repositoryId) + { + return _client.GetPaths(repositoryId).ToObservable().SelectMany(x => x); + } + + /// + /// List the top 10 popular contents over the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#list-paths + /// The owner of the repository + /// The name of the repository + public IObservable GetPaths(string owner, string name) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return _client.GetPaths(owner, name).ToObservable().SelectMany(x => x); + } + + /// + /// List the top 10 referrers over the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#list-referrers + /// The owner of the repository + public IObservable GetReferrers(long repositoryId) + { + return _client.GetReferrers(repositoryId).ToObservable().SelectMany(x => x); + } + + /// + /// List the top 10 referrers over the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#list-referrers + /// The owner of the repository + /// The name of the repository + public IObservable GetReferrers(string owner, string name) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return _client.GetReferrers(owner, name).ToObservable().SelectMany(x => x); + } + + /// + /// Get the total number of clones and breakdown per day or week for the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#clones + /// The owner of the repository + /// Breakdown per day or week + public IObservable GetClones(long repositoryId, RepositoryTrafficRequest per) + { + Ensure.ArgumentNotNull(per, "per"); + + return _client.GetClones(repositoryId, per).ToObservable(); + } + + /// + /// Get the total number of clones and breakdown per day or week for the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#clones + /// The owner of the repository + /// The name of the repository + /// Breakdown per day or week + public IObservable GetClones(string owner, string name, RepositoryTrafficRequest per) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(per, "per"); + + return _client.GetClones(owner, name, per).ToObservable(); + } + + /// + /// Get the total number of views and breakdown per day or week for the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#views + /// The owner of the repository + /// Breakdown per day or week + public IObservable GetViews(long repositoryId, RepositoryTrafficRequest per) + { + Ensure.ArgumentNotNull(per, "per"); + + return _client.GetViews(repositoryId, per).ToObservable(); + } + + /// + /// Get the total number of views and breakdown per day or week for the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#views + /// The owner of the repository + /// The name of the repository + /// Breakdown per day or week + public IObservable GetViews(string owner, string name, RepositoryTrafficRequest per) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(per, "per"); + + return _client.GetViews(owner, name, per).ToObservable(); + } + } +} diff --git a/Octokit.Reactive/Octokit.Reactive-Mono.csproj b/Octokit.Reactive/Octokit.Reactive-Mono.csproj index 25287f12..1f39b439 100644 --- a/Octokit.Reactive/Octokit.Reactive-Mono.csproj +++ b/Octokit.Reactive/Octokit.Reactive-Mono.csproj @@ -196,6 +196,8 @@ + + diff --git a/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj b/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj index 38148d1d..2d50f637 100644 --- a/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj +++ b/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj @@ -212,6 +212,8 @@ + + diff --git a/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj b/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj index 4d123580..c38c9094 100644 --- a/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj +++ b/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj @@ -208,6 +208,8 @@ + + diff --git a/Octokit.Reactive/Octokit.Reactive.csproj b/Octokit.Reactive/Octokit.Reactive.csproj index 59ed1851..70733536 100644 --- a/Octokit.Reactive/Octokit.Reactive.csproj +++ b/Octokit.Reactive/Octokit.Reactive.csproj @@ -99,6 +99,7 @@ + @@ -141,6 +142,7 @@ + diff --git a/Octokit.Tests.Integration/Clients/RepositoryTrafficClientTests.cs b/Octokit.Tests.Integration/Clients/RepositoryTrafficClientTests.cs new file mode 100644 index 00000000..92720c65 --- /dev/null +++ b/Octokit.Tests.Integration/Clients/RepositoryTrafficClientTests.cs @@ -0,0 +1,111 @@ +using Octokit; +using Octokit.Tests.Integration; +using System.Threading.Tasks; +using Xunit; + +public class RepositoryTrafficClientTests +{ + readonly IRepositoryTrafficClient _fixture; + readonly IGitHubClient _github; + readonly string _owner; + readonly string _repo; + readonly long _repoId; + + public RepositoryTrafficClientTests() + { + _github = Helper.GetAuthenticatedClient(); + _fixture = _github.Repository.Traffic; + + _owner = "octokit"; + _repo = "octokit.net"; + _repoId = _github.Repository.Get(_owner, _repo).Result.Id; + } + + public class TheGetReferrersMethod : RepositoryTrafficClientTests + { + [IntegrationTest] + public async Task GetsReferrers() + { + var referrers = await _fixture.GetReferrers(_owner, _repo); + + Assert.True(referrers.Count > 0); + } + + [IntegrationTest] + public async Task GetsReferrersWithRepositoryId() + { + var referrers = await _fixture.GetReferrers(_repoId); + + Assert.True(referrers.Count > 0); + } + } + + public class TheGetPathsMethod : RepositoryTrafficClientTests + { + [IntegrationTest] + public async Task GetsPaths() + { + var paths = await _fixture.GetPaths(_owner, _repo); + + Assert.True(paths.Count > 0); + } + + [IntegrationTest] + public async Task GetsPathsWithRepositoryId() + { + var paths = await _fixture.GetPaths(_repoId); + + Assert.True(paths.Count > 0); + } + } + + public class TheGetClonesMethod : RepositoryTrafficClientTests + { + [IntegrationTest] + public async Task GetsClones() + { + var request = new RepositoryTrafficRequest(TrafficDayOrWeek.Day); + var clones = await _fixture.GetClones(_owner, _repo, request); + + Assert.True(clones.Count > 0); + Assert.True(clones.Clones.Count > 0); + Assert.True(clones.Uniques > 0); + } + + [IntegrationTest] + public async Task GetsClonesWithRepositoryId() + { + var request = new RepositoryTrafficRequest(TrafficDayOrWeek.Day); + var clones = await _fixture.GetClones(_repoId, request); + + Assert.True(clones.Count > 0); + Assert.True(clones.Clones.Count > 0); + Assert.True(clones.Uniques > 0); + } + } + + public class TheGetViewsMethod : RepositoryTrafficClientTests + { + [IntegrationTest] + public async Task GetsViews() + { + var request = new RepositoryTrafficRequest(TrafficDayOrWeek.Day); + var views = await _fixture.GetViews(_owner, _repo, request); + + Assert.True(views.Count > 0); + Assert.True(views.Views.Count > 0); + Assert.True(views.Uniques > 0); + } + + [IntegrationTest] + public async Task GetsViewsWithRepositoryId() + { + var request = new RepositoryTrafficRequest(TrafficDayOrWeek.Day); + var views = await _fixture.GetViews(_repoId, request); + + Assert.True(views.Count > 0); + Assert.True(views.Views.Count > 0); + Assert.True(views.Uniques > 0); + } + } +} diff --git a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj index f0176627..6aef864f 100644 --- a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj +++ b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj @@ -112,6 +112,7 @@ + diff --git a/Octokit.Tests/Clients/RepositoryTrafficClientTests.cs b/Octokit.Tests/Clients/RepositoryTrafficClientTests.cs new file mode 100644 index 00000000..4fc2ed97 --- /dev/null +++ b/Octokit.Tests/Clients/RepositoryTrafficClientTests.cs @@ -0,0 +1,181 @@ +using NSubstitute; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Xunit; + +namespace Octokit.Tests.Clients +{ + public class RepositoryTrafficClientTests + { + public class TheCtor + { + [Fact] + public void EnsuresNonNullArguments() + { + Assert.Throws( + () => new RepositoryTrafficClient(null)); + } + } + + public class TheGetAllReferrersMethod + { + [Fact] + public async Task RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoryTrafficClient(connection); + + await client.GetReferrers("fake", "repo"); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/traffic/popular/referrers"), "application/vnd.github.spiderman-preview"); + } + + [Fact] + public async Task RequestsCorrectUrlWithRepositoryId() + { + var connection = Substitute.For(); + var client = new RepositoryTrafficClient(connection); + + await client.GetReferrers(1); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repositories/1/traffic/popular/referrers"), "application/vnd.github.spiderman-preview"); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new RepositoryTrafficClient(Substitute.For()); + + await Assert.ThrowsAsync(() => client.GetReferrers(null, "name")); + await Assert.ThrowsAsync(() => client.GetReferrers("owner", null)); + + await Assert.ThrowsAsync(() => client.GetReferrers("", "name")); + await Assert.ThrowsAsync(() => client.GetReferrers("owner", "")); + } + } + + public class TheGetAllPathsMethod + { + [Fact] + public async Task RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoryTrafficClient(connection); + + await client.GetPaths("fake", "repo"); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/traffic/popular/paths"), "application/vnd.github.spiderman-preview"); + } + + [Fact] + public async Task RequestsCorrectUrlWithRepositoryId() + { + var connection = Substitute.For(); + var client = new RepositoryTrafficClient(connection); + + await client.GetPaths(1); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repositories/1/traffic/popular/paths"), "application/vnd.github.spiderman-preview"); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new RepositoryTrafficClient(Substitute.For()); + + await Assert.ThrowsAsync(() => client.GetPaths(null, "name")); + await Assert.ThrowsAsync(() => client.GetPaths("owner", null)); + + await Assert.ThrowsAsync(() => client.GetPaths("", "name")); + await Assert.ThrowsAsync(() => client.GetPaths("owner", "")); + } + } + + public class TheGetClonesMethod + { + [Fact] + public async Task RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoryTrafficClient(connection); + var per = new RepositoryTrafficRequest(TrafficDayOrWeek.Day); + + await client.GetClones("fake", "repo", per); + + connection.Received().Get(Arg.Is(u => u.ToString() == "repos/fake/repo/traffic/clones"), Arg.Is>(s => s["per"] == "day"), "application/vnd.github.spiderman-preview"); + } + + [Fact] + public async Task RequestsCorrectUrlWithRepositoryId() + { + var connection = Substitute.For(); + var client = new RepositoryTrafficClient(connection); + var per = new RepositoryTrafficRequest(TrafficDayOrWeek.Day); + + await client.GetClones(1, per); + + connection.Received().Get(Arg.Is(u => u.ToString() == "repositories/1/traffic/clones"), Arg.Is>(s => s["per"] == "day"), "application/vnd.github.spiderman-preview"); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new RepositoryTrafficClient(Substitute.For()); + var per = new RepositoryTrafficRequest(TrafficDayOrWeek.Day); + + await Assert.ThrowsAsync(() => client.GetClones(null, "name", per)); + await Assert.ThrowsAsync(() => client.GetClones("owner", null, per)); + await Assert.ThrowsAsync(() => client.GetClones("owner", "name", null)); + + await Assert.ThrowsAsync(() => client.GetClones("", "name", per)); + await Assert.ThrowsAsync(() => client.GetClones("owner", "", per)); + + await Assert.ThrowsAsync(() => client.GetClones(1, null)); + } + } + + public class TheGetViewsMethod + { + [Fact] + public async Task RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoryTrafficClient(connection); + var per = new RepositoryTrafficRequest(TrafficDayOrWeek.Day); + + await client.GetViews("fake", "repo", per); + + connection.Received().Get(Arg.Is(u => u.ToString() == "repos/fake/repo/traffic/views"), Arg.Is>(s => s["per"] == "day"), "application/vnd.github.spiderman-preview"); + } + + [Fact] + public async Task RequestsCorrectUrlWithRepositoryId() + { + var connection = Substitute.For(); + var client = new RepositoryTrafficClient(connection); + var per = new RepositoryTrafficRequest(TrafficDayOrWeek.Day); + + await client.GetViews(1, per); + + connection.Received().Get(Arg.Is(u => u.ToString() == "repositories/1/traffic/views"), Arg.Is>(s => s["per"] == "day"), "application/vnd.github.spiderman-preview"); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new RepositoryTrafficClient(Substitute.For()); + var per = new RepositoryTrafficRequest(TrafficDayOrWeek.Day); + + await Assert.ThrowsAsync(() => client.GetViews(null, "name", per)); + await Assert.ThrowsAsync(() => client.GetViews("owner", null, per)); + await Assert.ThrowsAsync(() => client.GetViews("owner", "name", null)); + + await Assert.ThrowsAsync(() => client.GetViews("", "name", per)); + await Assert.ThrowsAsync(() => client.GetViews("owner", "", per)); + + await Assert.ThrowsAsync(() => client.GetViews(1, null)); + } + } + } +} diff --git a/Octokit.Tests/Octokit.Tests.csproj b/Octokit.Tests/Octokit.Tests.csproj index e5715425..866b7ce4 100644 --- a/Octokit.Tests/Octokit.Tests.csproj +++ b/Octokit.Tests/Octokit.Tests.csproj @@ -109,6 +109,7 @@ + @@ -254,6 +255,7 @@ + diff --git a/Octokit.Tests/Reactive/ObservableRepositoryTrafficClientTests.cs b/Octokit.Tests/Reactive/ObservableRepositoryTrafficClientTests.cs new file mode 100644 index 00000000..7cb4dc25 --- /dev/null +++ b/Octokit.Tests/Reactive/ObservableRepositoryTrafficClientTests.cs @@ -0,0 +1,179 @@ +using NSubstitute; +using Octokit.Reactive; +using System; +using Xunit; + +namespace Octokit.Tests.Reactive +{ + public class ObservableRepositoryTrafficClientTests + { + public class TheCtor + { + [Fact] + public void EnsuresNonNullArguments() + { + Assert.Throws(() => new ObservableRepositoryTrafficClient(null)); + } + } + + public class TheGetAllReferrersMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryTrafficClient(gitHubClient); + + client.GetReferrers("fake", "repo"); + + gitHubClient.Received().Repository.Traffic.GetReferrers("fake", "repo"); + } + + [Fact] + public void RequestsCorrectUrlWithRepositoryId() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryTrafficClient(gitHubClient); + + client.GetReferrers(1); + + gitHubClient.Received().Repository.Traffic.GetReferrers(1); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var client = new ObservableRepositoryTrafficClient(Substitute.For()); + + Assert.Throws(() => client.GetReferrers(null, "name")); + Assert.Throws(() => client.GetReferrers("owner", null)); + + Assert.Throws(() => client.GetReferrers("", "name")); + Assert.Throws(() => client.GetReferrers("owner", "")); + } + } + + public class TheGetAllPathsMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryTrafficClient(gitHubClient); + + client.GetPaths("fake", "repo"); + + gitHubClient.Received().Repository.Traffic.GetPaths("fake", "repo"); + } + + [Fact] + public void RequestsCorrectUrlWithRepositoryId() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryTrafficClient(gitHubClient); + + client.GetPaths(1); + + gitHubClient.Received().Repository.Traffic.GetPaths(1); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var client = new ObservableRepositoryTrafficClient(Substitute.For()); + + Assert.Throws(() => client.GetPaths(null, "name")); + Assert.Throws(() => client.GetPaths("owner", null)); + + Assert.Throws(() => client.GetPaths("", "name")); + Assert.Throws(() => client.GetPaths("owner", "")); + } + } + + public class TheGetClonesMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryTrafficClient(gitHubClient); + var per = new RepositoryTrafficRequest(TrafficDayOrWeek.Day); + + client.GetClones("fake", "repo", per); + + gitHubClient.Received().Repository.Traffic.GetClones("fake", "repo", per); + } + + [Fact] + public void RequestsCorrectUrlWithRepositoryId() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryTrafficClient(gitHubClient); + var per = new RepositoryTrafficRequest(TrafficDayOrWeek.Day); + + client.GetClones(1, per); + + gitHubClient.Received().Repository.Traffic.GetClones(1, per); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var client = new ObservableRepositoryTrafficClient(Substitute.For()); + var per = new RepositoryTrafficRequest(TrafficDayOrWeek.Day); + + Assert.Throws(() => client.GetClones(null, "name", per)); + Assert.Throws(() => client.GetClones("owner", null, per)); + Assert.Throws(() => client.GetClones("owner", "name", null)); + + Assert.Throws(() => client.GetClones("", "name", per)); + Assert.Throws(() => client.GetClones("owner", "", per)); + + Assert.Throws(() => client.GetClones(1, null)); + } + } + + public class TheGetViewsMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryTrafficClient(gitHubClient); + var per = new RepositoryTrafficRequest(TrafficDayOrWeek.Day); + + client.GetViews("fake", "repo", per); + + gitHubClient.Received().Repository.Traffic.GetViews("fake", "repo", per); + } + + [Fact] + public void RequestsCorrectUrlWithRepositoryId() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryTrafficClient(gitHubClient); + var per = new RepositoryTrafficRequest(TrafficDayOrWeek.Day); + + client.GetViews(1, per); + + gitHubClient.Received().Repository.Traffic.GetViews(1, per); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var client = new ObservableRepositoryTrafficClient(Substitute.For()); + var per = new RepositoryTrafficRequest(TrafficDayOrWeek.Day); + + Assert.Throws(() => client.GetViews(null, "name", per)); + Assert.Throws(() => client.GetViews("owner", null, per)); + Assert.Throws(() => client.GetViews("owner", "name", null)); + + Assert.Throws(() => client.GetViews("", "name", per)); + Assert.Throws(() => client.GetViews("owner", "", per)); + + Assert.Throws(() => client.GetViews(1, null)); + } + } + } +} diff --git a/Octokit/Clients/IRepositoriesClient.cs b/Octokit/Clients/IRepositoriesClient.cs index e1375da8..8d9ab4a8 100644 --- a/Octokit/Clients/IRepositoriesClient.cs +++ b/Octokit/Clients/IRepositoriesClient.cs @@ -655,5 +655,13 @@ namespace Octokit /// See the Repository Invitations API documentation for more information. /// IRepositoryInvitationsClient Invitation { get; } + + /// + /// Access GitHub's Repository Traffic API + /// + /// + /// Refer to the API documentation for more information: https://developer.github.com/v3/repos/traffic/ + /// + IRepositoryTrafficClient Traffic { get; } } } diff --git a/Octokit/Clients/IRepositoryTrafficClient.cs b/Octokit/Clients/IRepositoryTrafficClient.cs new file mode 100644 index 00000000..d4be3eec --- /dev/null +++ b/Octokit/Clients/IRepositoryTrafficClient.cs @@ -0,0 +1,82 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Octokit +{ + /// + /// A client for GitHub's Repository Traffic API. + /// + /// + /// See the Repository Traffic API documentation for more information. + /// + public interface IRepositoryTrafficClient + { + /// + /// List the top 10 referrers over the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#list-referrers + /// The owner of the repository + /// The name of the repository + [ExcludeFromPaginationConventionTest] + Task> GetReferrers(string owner, string name); + + /// + /// List the top 10 referrers over the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#list-referrers + /// The owner of the repository + [ExcludeFromPaginationConventionTest] + Task> GetReferrers(long repositoryId); + + /// + /// List the top 10 popular contents over the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#list-paths + /// The owner of the repository + /// The name of the repository + [ExcludeFromPaginationConventionTest] + Task> GetPaths(string owner, string name); + + /// + /// List the top 10 popular contents over the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#list-paths + /// The owner of the repository + [ExcludeFromPaginationConventionTest] + Task> GetPaths(long repositoryId); + + /// + /// Get the total number of views and breakdown per day or week for the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#views + /// The owner of the repository + /// The name of the repository + /// Breakdown per day or week + Task GetViews(string owner, string name, RepositoryTrafficRequest per); + + /// + /// Get the total number of views and breakdown per day or week for the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#views + /// The owner of the repository + /// Breakdown per day or week + Task GetViews(long repositoryId, RepositoryTrafficRequest per); + + /// + /// Get the total number of clones and breakdown per day or week for the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#clones + /// The owner of the repository + /// The name of the repository + /// Breakdown per day or week + Task GetClones(string owner, string name, RepositoryTrafficRequest per); + + /// + /// Get the total number of clones and breakdown per day or week for the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#clones + /// The owner of the repository + /// Breakdown per day or week + Task GetClones(long repositoryId, RepositoryTrafficRequest per); + } +} diff --git a/Octokit/Clients/RepositoriesClient.cs b/Octokit/Clients/RepositoriesClient.cs index 67201d66..816bf7a4 100644 --- a/Octokit/Clients/RepositoriesClient.cs +++ b/Octokit/Clients/RepositoriesClient.cs @@ -39,6 +39,7 @@ namespace Octokit Page = new RepositoryPagesClient(apiConnection); Invitation = new RepositoryInvitationsClient(apiConnection); Branch = new RepositoryBranchesClient(apiConnection); + Traffic = new RepositoryTrafficClient(apiConnection); } /// @@ -957,5 +958,13 @@ namespace Octokit /// See the Repository Invitations API documentation for more information. /// public IRepositoryInvitationsClient Invitation { get; private set; } + + /// + /// Access GitHub's Repository Traffic API + /// + /// + /// Refer to the API documentation for more information: https://developer.github.com/v3/repos/traffic/ + /// + public IRepositoryTrafficClient Traffic { get; private set; } } } diff --git a/Octokit/Clients/RepositoryTrafficClient.cs b/Octokit/Clients/RepositoryTrafficClient.cs new file mode 100644 index 00000000..302b316c --- /dev/null +++ b/Octokit/Clients/RepositoryTrafficClient.cs @@ -0,0 +1,118 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Octokit +{ + public class RepositoryTrafficClient : ApiClient, IRepositoryTrafficClient + { + public RepositoryTrafficClient(IApiConnection apiConnection) : base(apiConnection) + { + } + + /// + /// List the top 10 popular contents over the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#list-paths + /// The owner of the repository + public Task> GetPaths(long repositoryId) + { + return ApiConnection.GetAll(ApiUrls.RepositoryTrafficPaths(repositoryId), AcceptHeaders.RepositoryTrafficApiPreview); + } + + /// + /// List the top 10 popular contents over the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#list-paths + /// The owner of the repository + /// The name of the repository + public Task> GetPaths(string owner, string name) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return ApiConnection.GetAll(ApiUrls.RepositoryTrafficPaths(owner, name), AcceptHeaders.RepositoryTrafficApiPreview); + } + + /// + /// List the top 10 referrers over the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#list-referrers + /// The owner of the repository + public Task> GetReferrers(long repositoryId) + { + return ApiConnection.GetAll(ApiUrls.RepositoryTrafficReferrers(repositoryId), AcceptHeaders.RepositoryTrafficApiPreview); + } + + /// + /// List the top 10 referrers over the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#list-referrers + /// The owner of the repository + /// The name of the repository + public Task> GetReferrers(string owner, string name) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return ApiConnection.GetAll(ApiUrls.RepositoryTrafficReferrers(owner, name), AcceptHeaders.RepositoryTrafficApiPreview); + } + + /// + /// Get the total number of clones and breakdown per day or week for the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#clones + /// The owner of the repository + /// Breakdown per day or week + public Task GetClones(long repositoryId, RepositoryTrafficRequest per) + { + Ensure.ArgumentNotNull(per, "per"); + + return ApiConnection.Get(ApiUrls.RepositoryTrafficClones(repositoryId), per.ToParametersDictionary(), AcceptHeaders.RepositoryTrafficApiPreview); + } + + /// + /// Get the total number of clones and breakdown per day or week for the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#clones + /// The owner of the repository + /// The name of the repository + /// Breakdown per day or week + public Task GetClones(string owner, string name, RepositoryTrafficRequest per) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(per, "per"); + + return ApiConnection.Get(ApiUrls.RepositoryTrafficClones(owner, name), per.ToParametersDictionary(), AcceptHeaders.RepositoryTrafficApiPreview); + } + + /// + /// Get the total number of views and breakdown per day or week for the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#views + /// The owner of the repository + /// Breakdown per day or week + public Task GetViews(long repositoryId, RepositoryTrafficRequest per) + { + Ensure.ArgumentNotNull(per, "per"); + + return ApiConnection.Get(ApiUrls.RepositoryTrafficViews(repositoryId), per.ToParametersDictionary(), AcceptHeaders.RepositoryTrafficApiPreview); + } + + /// + /// Get the total number of views and breakdown per day or week for the last 14 days + /// + /// https://developer.github.com/v3/repos/traffic/#views + /// The owner of the repository + /// The name of the repository + /// Breakdown per day or week + public Task GetViews(string owner, string name, RepositoryTrafficRequest per) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(per, "per"); + + return ApiConnection.Get(ApiUrls.RepositoryTrafficViews(owner, name), per.ToParametersDictionary(), AcceptHeaders.RepositoryTrafficApiPreview); + } + } +} diff --git a/Octokit/Helpers/AcceptHeaders.cs b/Octokit/Helpers/AcceptHeaders.cs index f85ebc32..20e01e51 100644 --- a/Octokit/Helpers/AcceptHeaders.cs +++ b/Octokit/Helpers/AcceptHeaders.cs @@ -40,5 +40,7 @@ namespace Octokit public const string PagesApiPreview = "application/vnd.github.mister-fantastic-preview+json"; public const string IssueTimelineApiPreview = "application/vnd.github.mockingbird-preview"; + + public const string RepositoryTrafficApiPreview = "application/vnd.github.spiderman-preview"; } } diff --git a/Octokit/Helpers/ApiUrls.cs b/Octokit/Helpers/ApiUrls.cs index bd88186a..6ae6b0b7 100644 --- a/Octokit/Helpers/ApiUrls.cs +++ b/Octokit/Helpers/ApiUrls.cs @@ -3203,5 +3203,89 @@ namespace Octokit { return "user/repository_invitations/{0}".FormatUri(invitationId); } + + /// + /// Returns the for repository traffice referrers. + /// + /// The owner of repo + /// The name of repo + /// The for repository traffic referrers. + public static Uri RepositoryTrafficReferrers(string owner, string repo) + { + return "repos/{0}/{1}/traffic/popular/referrers".FormatUri(owner, repo); + } + + /// + /// Returns the for repository traffice referrers. + /// + /// The id of the repository + /// The for repository traffic referrers. + public static Uri RepositoryTrafficReferrers(long repositoryId) + { + return "repositories/{0}/traffic/popular/referrers".FormatUri(repositoryId); + } + + /// + /// Returns the for repository traffice paths. + /// + /// The owner of repo + /// The name of repo + /// The for repository traffic paths. + public static Uri RepositoryTrafficPaths(string owner, string repo) + { + return "repos/{0}/{1}/traffic/popular/paths".FormatUri(owner, repo); + } + + /// + /// Returns the for repository traffice paths. + /// + /// The id of the repository + /// The for repository traffic paths. + public static Uri RepositoryTrafficPaths(long repositoryId) + { + return "repositories/{0}/traffic/popular/paths".FormatUri(repositoryId); + } + + /// + /// Returns the for repository traffice views. + /// + /// The owner of repo + /// The name of repo + /// The for repository traffic views. + public static Uri RepositoryTrafficViews(string owner, string repo) + { + return "repos/{0}/{1}/traffic/views".FormatUri(owner, repo); + } + + /// + /// Returns the for repository traffice views. + /// + /// The id of the repository + /// The for repository traffic views. + public static Uri RepositoryTrafficViews(long repositoryId) + { + return "repositories/{0}/traffic/views".FormatUri(repositoryId); + } + + /// + /// Returns the for repository traffice clones. + /// + /// The owner of repo + /// The name of repo + /// The for repository traffic clones. + public static Uri RepositoryTrafficClones(string owner, string repo) + { + return "repos/{0}/{1}/traffic/clones".FormatUri(owner, repo); + } + + /// + /// Returns the for repository traffice clones. + /// + /// The id of the repository + /// The for repository traffic clones. + public static Uri RepositoryTrafficClones(long repositoryId) + { + return "repositories/{0}/traffic/clones".FormatUri(repositoryId); + } } } diff --git a/Octokit/Models/Request/RepositoryTrafficRequest.cs b/Octokit/Models/Request/RepositoryTrafficRequest.cs new file mode 100644 index 00000000..9679a119 --- /dev/null +++ b/Octokit/Models/Request/RepositoryTrafficRequest.cs @@ -0,0 +1,23 @@ +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class RepositoryTrafficRequest : RequestParameters + { + public RepositoryTrafficRequest() { } + + public RepositoryTrafficRequest(TrafficDayOrWeek per) + { + Per = per; + } + + public TrafficDayOrWeek Per { get; private set; } + + internal string DebuggerDisplay + { + get { return string.Format(CultureInfo.InvariantCulture, "Per: {0}", Per); } + } + } +} diff --git a/Octokit/Models/Response/RepositoryTrafficClone.cs b/Octokit/Models/Response/RepositoryTrafficClone.cs new file mode 100644 index 00000000..9baf715e --- /dev/null +++ b/Octokit/Models/Response/RepositoryTrafficClone.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using Octokit.Helpers; +using Octokit.Internal; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class RepositoryTrafficCloneSummary + { + public RepositoryTrafficCloneSummary() { } + + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Justification = "It's a property from the api.")] + public RepositoryTrafficCloneSummary(int count, int uniques, IReadOnlyList clones) + { + Count = count; + Uniques = uniques; + Clones = clones; + } + + public int Count { get; protected set; } + + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Justification = "It's a property from the api.")] + public int Uniques { get; protected set; } + + public IReadOnlyList Clones { get; protected set; } + + internal string DebuggerDisplay + { + get { return string.Format(CultureInfo.InvariantCulture, "Number: {0} Uniques: {1}", Count, Uniques); } + } + } + + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class RepositoryTrafficClone + { + public RepositoryTrafficClone() { } + + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Justification = "It's a property from the api.")] + public RepositoryTrafficClone(long timestamp, int count, int uniques) + { + TimestampAsUtcEpochSeconds = timestamp; + Count = count; + Uniques = uniques; + } + + [Parameter(Key = "ignoreThisField")] + public DateTimeOffset Timestamp + { + get { return TimestampAsUtcEpochSeconds.FromUnixTime(); } + } + + [Parameter(Key = "timestamp")] + public long TimestampAsUtcEpochSeconds { get; protected set; } + + public int Count { get; protected set; } + + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Justification = "It's a property from the api.")] + public int Uniques { get; protected set; } + + internal string DebuggerDisplay + { + get { return string.Format(CultureInfo.InvariantCulture, "Number: {0} Uniques: {1}", Count, Uniques); } + } + } + + public enum TrafficDayOrWeek + { + Day, + Week + } +} diff --git a/Octokit/Models/Response/RepositoryTrafficPath.cs b/Octokit/Models/Response/RepositoryTrafficPath.cs new file mode 100644 index 00000000..fcac8ccc --- /dev/null +++ b/Octokit/Models/Response/RepositoryTrafficPath.cs @@ -0,0 +1,35 @@ +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class RepositoryTrafficPath + { + public RepositoryTrafficPath() { } + + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Justification = "It's a property from the api.")] + public RepositoryTrafficPath(string path, string title, int count, int uniques) + { + Path = path; + Title = title; + Count = count; + Uniques = uniques; + } + + public string Path { get; protected set; } + + public string Title { get; protected set; } + + public int Count { get; protected set; } + + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Justification = "It's a property from the api.")] + public int Uniques { get; protected set; } + + internal string DebuggerDisplay + { + get { return string.Format(CultureInfo.InvariantCulture, "Path: {0}, Title: {1}", Path, Title); } + } + } +} diff --git a/Octokit/Models/Response/RepositoryTrafficReferrer.cs b/Octokit/Models/Response/RepositoryTrafficReferrer.cs new file mode 100644 index 00000000..cc4d8932 --- /dev/null +++ b/Octokit/Models/Response/RepositoryTrafficReferrer.cs @@ -0,0 +1,32 @@ +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class RepositoryTrafficReferrer + { + public RepositoryTrafficReferrer() { } + + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Justification = "It's a property from the api.")] + public RepositoryTrafficReferrer(string referrer, int count, int uniques) + { + Referrer = referrer; + Count = count; + Uniques = uniques; + } + + public string Referrer { get; protected set; } + + public int Count { get; protected set; } + + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Justification = "It's a property from the api.")] + public int Uniques { get; protected set; } + + internal string DebuggerDisplay + { + get { return string.Format(CultureInfo.InvariantCulture, "Referrer: {0}, Count: {1}", Referrer, Count); } + } + } +} diff --git a/Octokit/Models/Response/RepositoryTrafficView.cs b/Octokit/Models/Response/RepositoryTrafficView.cs new file mode 100644 index 00000000..c9c8ae5a --- /dev/null +++ b/Octokit/Models/Response/RepositoryTrafficView.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using Octokit.Helpers; +using Octokit.Internal; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class RepositoryTrafficViewSummary + { + public RepositoryTrafficViewSummary() { } + + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Justification = "It's a property from the api.")] + public RepositoryTrafficViewSummary(int count, int uniques, IReadOnlyList views) + { + Count = count; + Uniques = uniques; + Views = views; + } + + public int Count { get; protected set; } + + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Justification = "It's a property from the api.")] + public int Uniques { get; protected set; } + + public IReadOnlyList Views { get; protected set; } + + internal string DebuggerDisplay + { + get { return string.Format(CultureInfo.InvariantCulture, "Number: {0} Uniques: {1}", Count, Uniques); } + } + } + + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class RepositoryTrafficView + { + public RepositoryTrafficView() { } + + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Justification = "It's a property from the api.")] + public RepositoryTrafficView(long timestamp, int count, int uniques) + { + TimestampAsUtcEpochSeconds = timestamp; + Count = count; + Uniques = uniques; + } + + [Parameter(Key = "ignoreThisField")] + public DateTimeOffset Timestamp + { + get { return TimestampAsUtcEpochSeconds.FromUnixTime(); } + } + + [Parameter(Key = "timestamp")] + public long TimestampAsUtcEpochSeconds { get; protected set; } + + public int Count { get; protected set; } + + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Justification = "It's a property from the api.")] + public int Uniques { get; protected set; } + + internal string DebuggerDisplay + { + get { return string.Format(CultureInfo.InvariantCulture, "Timestamp: {0} Number: {1} Uniques: {2}", Timestamp, Count, Uniques); } + } + } +} diff --git a/Octokit/Octokit-Mono.csproj b/Octokit/Octokit-Mono.csproj index 4f78f1f8..1890b1d9 100644 --- a/Octokit/Octokit-Mono.csproj +++ b/Octokit/Octokit-Mono.csproj @@ -494,6 +494,13 @@ + + + + + + + diff --git a/Octokit/Octokit-MonoAndroid.csproj b/Octokit/Octokit-MonoAndroid.csproj index a75a9594..843d485f 100644 --- a/Octokit/Octokit-MonoAndroid.csproj +++ b/Octokit/Octokit-MonoAndroid.csproj @@ -505,6 +505,13 @@ + + + + + + + diff --git a/Octokit/Octokit-Monotouch.csproj b/Octokit/Octokit-Monotouch.csproj index 652c55be..03f59ce5 100644 --- a/Octokit/Octokit-Monotouch.csproj +++ b/Octokit/Octokit-Monotouch.csproj @@ -501,6 +501,13 @@ + + + + + + + diff --git a/Octokit/Octokit-Portable.csproj b/Octokit/Octokit-Portable.csproj index 35140d86..2bef9a43 100644 --- a/Octokit/Octokit-Portable.csproj +++ b/Octokit/Octokit-Portable.csproj @@ -491,6 +491,13 @@ + + + + + + + diff --git a/Octokit/Octokit-netcore45.csproj b/Octokit/Octokit-netcore45.csproj index 456dc553..5c1b1ed4 100644 --- a/Octokit/Octokit-netcore45.csproj +++ b/Octokit/Octokit-netcore45.csproj @@ -498,6 +498,13 @@ + + + + + + + diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index bf40c6e0..9deb1cd6 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -65,6 +65,7 @@ + @@ -110,6 +111,7 @@ + @@ -160,6 +162,7 @@ + @@ -219,6 +222,10 @@ + + + +