Merge pull request #862 from octokit/haacked/836-handle-empty-content

Handle empty content better
This commit is contained in:
Brendan Forster
2015-09-10 11:34:09 +09:00
14 changed files with 199 additions and 89 deletions
+8 -2
View File
@@ -71,7 +71,8 @@ namespace Octokit.Tests.Conventions
.Where(x => x.Name.StartsWith("Get"));
var invalidMethods = methodsThatCanPaginate
.Where(x => !x.Name.StartsWith("GetAll"));
.Where(x => !x.Name.StartsWith("GetAll"))
.ToList();
if (invalidMethods.Any())
{
@@ -81,7 +82,12 @@ namespace Octokit.Tests.Conventions
public static IEnumerable<object[]> GetClientInterfaces()
{
return typeof(IEventsClient).Assembly.ExportedTypes.Where(TypeExtensions.IsClientInterface).Select(type => new[] { type });
return typeof(IEventsClient)
.Assembly
.ExportedTypes
.Where(TypeExtensions.IsClientInterface)
.Where(t => t != typeof(IStatisticsClient)) // This convention doesn't apply to this one type.
.Select(type => new[] { type });
}
public static IEnumerable<object[]> ModelTypes
@@ -1,12 +1,10 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reactive;
using System.Reflection;
using Octokit.Tests.Helpers;
using Xunit;
using Xunit.Extensions;
namespace Octokit.Tests.Conventions
{
@@ -22,13 +20,13 @@ namespace Octokit.Tests.Conventions
var mainNames = Array.ConvertAll(mainMethods, m => m.Name);
var observableNames = Array.ConvertAll(observableMethods, m => m.Name);
var methodsMissingOnReactiveClient = mainNames.Except(observableNames);
var methodsMissingOnReactiveClient = mainNames.Except(observableNames).ToList();
if (methodsMissingOnReactiveClient.Any())
{
throw new InterfaceMissingMethodsException(observableClient, methodsMissingOnReactiveClient);
}
var additionalMethodsOnReactiveClient = observableNames.Except(mainNames);
var additionalMethodsOnReactiveClient = observableNames.Except(mainNames).ToList();
if (additionalMethodsOnReactiveClient.Any())
{
throw new InterfaceHasAdditionalMethodsException(observableClient, additionalMethodsOnReactiveClient);
@@ -122,7 +120,12 @@ namespace Octokit.Tests.Conventions
public static IEnumerable<object[]> GetClientInterfaces()
{
return typeof(IEventsClient).Assembly.ExportedTypes.Where(TypeExtensions.IsClientInterface).Select(type => new[] { type });
return typeof(IEventsClient)
.Assembly
.ExportedTypes
.Where(TypeExtensions.IsClientInterface)
.Where(t => t != typeof(IStatisticsClient)) // This convention doesn't apply to this one type.
.Select(type => new[] { type });
}
}
}
@@ -1,5 +1,4 @@
using System.Linq;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Xunit;
@@ -18,21 +17,31 @@ namespace Octokit.Tests.Integration.Clients
}
[IntegrationTest]
public async Task CanCreateAndRetrieveCommit()
public async Task CanCreateAndRetrieveContributors()
{
var repository = await CreateRepository();
await CommitToRepository(repository);
var contributors = await _client.Repository.Statistics.GetContributors(repository.Owner, repository.Name);
Assert.NotNull(contributors);
Assert.True(contributors.Count() == 1);
Assert.Equal(1, contributors.Count);
var soleContributor = contributors.First();
Assert.NotNull(soleContributor.Author);
Assert.True(soleContributor.Author.Login == repository.Owner);
Assert.True(soleContributor.Weeks.Count() == 1);
Assert.True(soleContributor.Total == 1);
Assert.Equal(1, soleContributor.Weeks.Count);
Assert.Equal(1, soleContributor.Total);
}
[IntegrationTest]
public async Task CanCreateAndRetrieveEmptyContributors()
{
var repository = await CreateRepository(autoInit: false);
var contributors = await _client.Repository.Statistics.GetContributors(repository.Owner, repository.Name);
Assert.NotNull(contributors);
Assert.Empty(contributors);
}
[IntegrationTest]
@@ -42,10 +51,10 @@ namespace Octokit.Tests.Integration.Clients
await CommitToRepository(repository);
var commitActivities = await _client.Repository.Statistics.GetCommitActivity(repository.Owner, repository.Name);
Assert.NotNull(commitActivities);
Assert.True(commitActivities.Activity.Count() == 52);
Assert.Equal(52, commitActivities.Activity.Count);
var thisWeek = commitActivities.Activity.Last();
Assert.True(thisWeek.Total == 1);
Assert.Equal(1, thisWeek.Total);
Assert.NotNull(thisWeek.Days);
}
@@ -65,9 +74,7 @@ namespace Octokit.Tests.Integration.Clients
var repository = await CreateRepository();
await CommitToRepository(repository);
var weeklyCommitCounts = await _client.Repository.Statistics.GetParticipation(repository.Owner, repository.Name);
Assert.NotNull(weeklyCommitCounts);
Assert.NotNull(weeklyCommitCounts.All);
Assert.NotNull(weeklyCommitCounts.Owner);
Assert.Equal(52, weeklyCommitCounts.All.Count);
}
[IntegrationTest]
@@ -80,10 +87,10 @@ namespace Octokit.Tests.Integration.Clients
Assert.NotNull(punchCard.PunchPoints);
}
async Task<RepositorySummary> CreateRepository()
async Task<RepositorySummary> CreateRepository(bool autoInit = true)
{
var repoName = Helper.MakeNameWithTimestamp("public-repo");
var repository = await _client.Repository.Create(new NewRepository(repoName) { AutoInit = true });
var repository = await _client.Repository.Create(new NewRepository(repoName) { AutoInit = autoInit });
return new RepositorySummary
{
Owner = repository.Owner.Login,
+47 -15
View File
@@ -1,8 +1,9 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using NSubstitute;
using Octokit.Tests.Helpers;
using Octokit.Helpers;
using Xunit;
namespace Octokit.Tests.Clients
@@ -21,16 +22,18 @@ namespace Octokit.Tests.Clients
public class TheGetContributorsMethod
{
[Fact]
public void RequestsCorrectUrl()
public async Task RetrievesContributorsForCorrectUrl()
{
var expectedEndPoint = new Uri("/repos/username/repositoryName/stats/contributors", UriKind.Relative);
var client = Substitute.For<IApiConnection>();
IReadOnlyList<Contributor> contributors = new ReadOnlyCollection<Contributor>(new[] { new Contributor() });
client.GetQueuedOperation<Contributor>(expectedEndPoint, Args.CancellationToken)
.Returns(Task.FromResult(contributors));
var statisticsClient = new StatisticsClient(client);
statisticsClient.GetContributors("username","repositoryName");
var result = await statisticsClient.GetContributors("username","repositoryName");
client.Received().GetQueuedOperation<IEnumerable<Contributor>>(expectedEndPoint,Args.CancellationToken);
Assert.Equal(1, result.Count);
}
[Fact]
@@ -51,16 +54,24 @@ namespace Octokit.Tests.Clients
public class TheGetCommitActivityForTheLastYearMethod
{
[Fact]
public void RequestsCorrectUrl()
public async Task RequestsCorrectUrl()
{
var expectedEndPoint = new Uri("/repos/username/repositoryName/stats/commit_activity", UriKind.Relative);
var data = new WeeklyCommitActivity(new[] { 1, 2 }, 100, 42);
IReadOnlyList<WeeklyCommitActivity> response = new ReadOnlyCollection<WeeklyCommitActivity>(new[] { data });
var client = Substitute.For<IApiConnection>();
client.GetQueuedOperation<WeeklyCommitActivity>(expectedEndPoint, Args.CancellationToken)
.Returns(Task.FromResult(response));
var statisticsClient = new StatisticsClient(client);
statisticsClient.GetCommitActivity("username", "repositoryName");
var result = await statisticsClient.GetCommitActivity("username", "repositoryName");
client.Received().GetQueuedOperation<IReadOnlyList<WeeklyCommitActivity>>(expectedEndPoint, Args.CancellationToken);
Assert.Equal(2, result.Activity[0].Days.Count);
Assert.Equal(1, result.Activity[0].Days[0]);
Assert.Equal(2, result.Activity[0].Days[1]);
Assert.Equal(100, result.Activity[0].Total);
Assert.Equal(42, result.Activity[0].Week);
}
[Fact]
@@ -81,16 +92,31 @@ namespace Octokit.Tests.Clients
public class TheGetAdditionsAndDeletionsPerWeekMethod
{
[Fact]
public void RequestsCorrectUrl()
public async Task RequestsCorrectUrl()
{
var expectedEndPoint = new Uri("/repos/username/repositoryName/stats/code_frequency", UriKind.Relative);
long firstTimestamp = 159670861;
long secondTimestamp = 0;
IReadOnlyList<long[]> data = new ReadOnlyCollection<long[]>(new[]
{
new[] { firstTimestamp, 10, 52 },
new[] { secondTimestamp, 0, 9 }
});
var client = Substitute.For<IApiConnection>();
client.GetQueuedOperation<long[]>(expectedEndPoint, Args.CancellationToken)
.Returns(Task.FromResult(data));
var statisticsClient = new StatisticsClient(client);
statisticsClient.GetCodeFrequency("username", "repositoryName");
var codeFrequency = await statisticsClient.GetCodeFrequency("username", "repositoryName");
client.Received().GetQueuedOperation<IEnumerable<long[]>>(expectedEndPoint, Args.CancellationToken);
Assert.Equal(2, codeFrequency.AdditionsAndDeletionsByWeek.Count);
Assert.Equal(firstTimestamp.FromUnixTime(), codeFrequency.AdditionsAndDeletionsByWeek[0].Timestamp);
Assert.Equal(10, codeFrequency.AdditionsAndDeletionsByWeek[0].Additions);
Assert.Equal(52, codeFrequency.AdditionsAndDeletionsByWeek[0].Deletions);
Assert.Equal(secondTimestamp.FromUnixTime(), codeFrequency.AdditionsAndDeletionsByWeek[1].Timestamp);
Assert.Equal(0, codeFrequency.AdditionsAndDeletionsByWeek[1].Additions);
Assert.Equal(9, codeFrequency.AdditionsAndDeletionsByWeek[1].Deletions);
}
[Fact]
@@ -141,16 +167,22 @@ namespace Octokit.Tests.Clients
public class TheGetHourlyCommitCountsMethod
{
[Fact]
public void RequestsCorrectUrl()
public async Task RetrievesPunchCard()
{
var expectedEndPoint = new Uri("/repos/username/repositoryName/stats/punch_card", UriKind.Relative);
var client = Substitute.For<IApiConnection>();
IReadOnlyList<int[]> data = new ReadOnlyCollection<int[]>(new[] { new[] { 2, 8, 42 } });
client.GetQueuedOperation<int[]>(expectedEndPoint, Args.CancellationToken)
.Returns(Task.FromResult(data));
var statisticsClient = new StatisticsClient(client);
statisticsClient.GetPunchCard("username", "repositoryName");
var result = await statisticsClient.GetPunchCard("username", "repositoryName");
client.Received().GetQueuedOperation<IEnumerable<int[]>>(expectedEndPoint, Args.CancellationToken);
Assert.Equal(1, result.PunchPoints.Count);
Assert.Equal(DayOfWeek.Tuesday, result.PunchPoints[0].DayOfWeek);
Assert.Equal(8, result.PunchPoints[0].HourOfTheDay);
Assert.Equal(42, result.PunchPoints[0].CommitCount);
}
[Fact]
@@ -168,4 +200,4 @@ namespace Octokit.Tests.Clients
}
}
}
}
}
@@ -0,0 +1,46 @@
using System;
using Octokit.Helpers;
using Xunit;
public class UnixTimestampExtensionsTests
{
public class TheToUnixTimeMethod
{
[Fact]
public void ReturnsUnixEpochCorrectly()
{
var epoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
Assert.Equal(0, epoch.ToUnixTime());
}
[Fact]
public void ReturnsRandomDateCorrectly()
{
var epoch = new DateTimeOffset(1975, 1, 23, 1, 1, 1, TimeSpan.Zero);
Assert.Equal(159670861, epoch.ToUnixTime());
}
}
public class TheFromUnixTimeMethod
{
[Fact]
public void ReturnsDateFromUnixEpochCorrectly()
{
var epoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
var result = ((long)0).FromUnixTime();
Assert.Equal(epoch, result);
}
[Fact]
public void ReturnsDateFromRandomTimeCorrectly()
{
var expected = new DateTimeOffset(1975, 1, 23, 1, 1, 2, TimeSpan.Zero);
var result = ((long)159670862).FromUnixTime();
Assert.Equal(expected, result);
}
}
}
+37 -29
View File
@@ -6,7 +6,6 @@ using System.Threading;
using System.Threading.Tasks;
using NSubstitute;
using Octokit.Internal;
using Octokit.Tests.Helpers;
using Xunit;
namespace Octokit.Tests.Http
@@ -315,22 +314,6 @@ namespace Octokit.Tests.Http
public class TheGetQueuedOperationMethod
{
[Fact]
public async Task MakesGetRequest()
{
var queuedOperationUrl = new Uri("anything", UriKind.Relative);
const HttpStatusCode statusCode = HttpStatusCode.OK;
IApiResponse<object> response = new ApiResponse<object>(new Response(statusCode, null, new Dictionary<string, string>(), "application/json"), new object());
var connection = Substitute.For<IConnection>();
connection.GetResponse<object>(queuedOperationUrl,Args.CancellationToken).Returns(Task.FromResult(response));
var apiConnection = new ApiConnection(connection);
await apiConnection.GetQueuedOperation<object>(queuedOperationUrl,CancellationToken.None);
connection.Received().GetResponse<object>(queuedOperationUrl, Args.CancellationToken);
}
[Fact]
public async Task WhenGetReturnsNotOkOrAcceptedApiExceptionIsThrown()
{
@@ -350,15 +333,36 @@ namespace Octokit.Tests.Http
{
var queuedOperationUrl = new Uri("anything", UriKind.Relative);
var result = new object();
var result = new[] { new object() };
const HttpStatusCode statusCode = HttpStatusCode.OK;
IApiResponse<object> response = new ApiResponse<object>(new Response(statusCode, null, new Dictionary<string, string>(), "application/json"), result);
var httpResponse = new Response(statusCode, null, new Dictionary<string, string>(), "application/json");
IApiResponse<IReadOnlyList<object>> response = new ApiResponse<IReadOnlyList<object>>(httpResponse, result);
var connection = Substitute.For<IConnection>();
connection.GetResponse<object>(queuedOperationUrl, Args.CancellationToken).Returns(Task.FromResult(response));
connection.GetResponse<IReadOnlyList<object>>(queuedOperationUrl, Args.CancellationToken)
.Returns(Task.FromResult(response));
var apiConnection = new ApiConnection(connection);
var actualResult = await apiConnection.GetQueuedOperation<object>(queuedOperationUrl, Args.CancellationToken);
Assert.Same(actualResult,result);
Assert.Same(actualResult, result);
}
[Fact]
public async Task WhenGetReturnsNoContentThenReturnsEmptyCollection()
{
var queuedOperationUrl = new Uri("anything", UriKind.Relative);
var result = new [] { new object() };
const HttpStatusCode statusCode = HttpStatusCode.NoContent;
var httpResponse = new Response(statusCode, null, new Dictionary<string, string>(), "application/json");
IApiResponse<IReadOnlyList<object>> response = new ApiResponse<IReadOnlyList<object>>(
httpResponse, result);
var connection = Substitute.For<IConnection>();
connection.GetResponse<IReadOnlyList<object>>(queuedOperationUrl, Args.CancellationToken)
.Returns(Task.FromResult(response));
var apiConnection = new ApiConnection(connection);
var actualResult = await apiConnection.GetQueuedOperation<object>(queuedOperationUrl, Args.CancellationToken);
Assert.Empty(actualResult);
}
[Fact]
@@ -366,11 +370,13 @@ namespace Octokit.Tests.Http
{
var queuedOperationUrl = new Uri("anything", UriKind.Relative);
var result = new object();
IApiResponse<object> firstResponse = new ApiResponse<object>(new Response(HttpStatusCode.Accepted, null, new Dictionary<string, string>(), "application/json"), result);
IApiResponse<object> completedResponse = new ApiResponse<object>(new Response(HttpStatusCode.OK, null, new Dictionary<string, string>(), "application/json"), result);
var result = new [] { new object() };
IApiResponse<IReadOnlyList<object>> firstResponse = new ApiResponse<IReadOnlyList<object>>(
new Response(HttpStatusCode.Accepted, null, new Dictionary<string, string>(), "application/json"), result);
IApiResponse<IReadOnlyList<object>> completedResponse = new ApiResponse<IReadOnlyList<object>>(
new Response(HttpStatusCode.OK, null, new Dictionary<string, string>(), "application/json"), result);
var connection = Substitute.For<IConnection>();
connection.GetResponse<object>(queuedOperationUrl, Args.CancellationToken)
connection.GetResponse<IReadOnlyList<object>>(queuedOperationUrl, Args.CancellationToken)
.Returns(x => Task.FromResult(firstResponse),
x => Task.FromResult(firstResponse),
x => Task.FromResult(completedResponse));
@@ -379,17 +385,19 @@ namespace Octokit.Tests.Http
await apiConnection.GetQueuedOperation<object>(queuedOperationUrl, CancellationToken.None);
connection.Received(3).GetResponse<object>(queuedOperationUrl, Args.CancellationToken);
connection.Received(3).GetResponse<IReadOnlyList<object>>(queuedOperationUrl, Args.CancellationToken);
}
public async Task CanCancelQueuedOperation()
{
var queuedOperationUrl = new Uri("anything", UriKind.Relative);
var result = new object();
IApiResponse<object> accepted = new ApiResponse<object>(new Response(HttpStatusCode.Accepted, null, new Dictionary<string, string>(), "application/json"), result);
var result = new [] { new object() };
IApiResponse<IReadOnlyList<object>> accepted = new ApiResponse<IReadOnlyList<object>>(
new Response(HttpStatusCode.Accepted, null, new Dictionary<string, string>(), "application/json"), result);
var connection = Substitute.For<IConnection>();
connection.GetResponse<object>(queuedOperationUrl, Args.CancellationToken).Returns(x => Task.FromResult(accepted));
connection.GetResponse<IReadOnlyList<object>>(queuedOperationUrl, Args.CancellationToken)
.Returns(x => Task.FromResult(accepted));
var apiConnection = new ApiConnection(connection);
@@ -109,6 +109,7 @@
<Compile Include="Exceptions\TwoFactorRequiredExceptionTests.cs" />
<Compile Include="Helpers\NSubstituteExtensions.cs" />
<Compile Include="Helpers\ReflectionExtensions.cs" />
<Compile Include="Helpers\UnixTimestampExtensionsTests.cs" />
<Compile Include="Helpers\UriExtensionsTests.cs" />
<Compile Include="Http\ApiConnectionTests.cs" />
<Compile Include="Clients\AuthorizationsClientTests.cs" />
@@ -107,6 +107,7 @@
<Compile Include="Exceptions\TwoFactorRequiredExceptionTests.cs" />
<Compile Include="Helpers\NSubstituteExtensions.cs" />
<Compile Include="Helpers\ReflectionExtensions.cs" />
<Compile Include="Helpers\UnixTimestampExtensionsTests.cs" />
<Compile Include="Helpers\UriExtensionsTests.cs" />
<Compile Include="Http\ApiConnectionTests.cs" />
<Compile Include="Clients\AuthorizationsClientTests.cs" />
+1
View File
@@ -123,6 +123,7 @@
<Compile Include="Exceptions\TwoFactorRequiredExceptionTests.cs" />
<Compile Include="Helpers\NSubstituteExtensions.cs" />
<Compile Include="Helpers\ReflectionExtensions.cs" />
<Compile Include="Helpers\UnixTimestampExtensionsTests.cs" />
<Compile Include="Helpers\UriExtensionsTests.cs" />
<Compile Include="Http\ApiConnectionTests.cs" />
<Compile Include="Clients\AuthorizationsClientTests.cs" />
+2 -2
View File
@@ -18,7 +18,7 @@ namespace Octokit
/// <param name="owner">The owner of the repository</param>
/// <param name="repositoryName">The name of the repository</param>
/// <returns>A list of <see cref="Contributor"/></returns>
Task<IEnumerable<Contributor>> GetContributors(string owner, string repositoryName);
Task<IReadOnlyList<Contributor>> GetContributors(string owner, string repositoryName);
/// <summary>
/// Returns a list of <see cref="Contributor"/> for the given repository
@@ -27,7 +27,7 @@ namespace Octokit
/// <param name="repositoryName">The name of the repository</param>
/// <param name="cancellationToken">A token used to cancel this potentially long running request</param>
/// <returns>A list of <see cref="Contributor"/></returns>
Task<IEnumerable<Contributor>> GetContributors(string owner, string repositoryName, CancellationToken cancellationToken);
Task<IReadOnlyList<Contributor>> GetContributors(string owner, string repositoryName, CancellationToken cancellationToken);
/// <summary>
/// Returns the last year of commit activity grouped by week.
+9 -7
View File
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -26,7 +27,7 @@ namespace Octokit
/// <param name="owner">The owner of the repository</param>
/// <param name="repositoryName">The name of the repository</param>
/// <returns>A list of <see cref="Contributor"/></returns>
public Task<IEnumerable<Contributor>> GetContributors(string owner, string repositoryName)
public Task<IReadOnlyList<Contributor>> GetContributors(string owner, string repositoryName)
{
return GetContributors(owner, repositoryName, CancellationToken.None);
}
@@ -38,13 +39,13 @@ namespace Octokit
/// <param name="repositoryName">The name of the repository</param>
/// <param name="cancellationToken">A token used to cancel this potentially long running request</param>
/// <returns>A list of <see cref="Contributor"/></returns>
public async Task<IEnumerable<Contributor>> GetContributors(string owner, string repositoryName, CancellationToken cancellationToken)
public async Task<IReadOnlyList<Contributor>> GetContributors(string owner, string repositoryName, CancellationToken cancellationToken)
{
Ensure.ArgumentNotNullOrEmptyString(owner, "owner");
Ensure.ArgumentNotNullOrEmptyString(repositoryName, "repositoryName");
var endpoint = "/repos/{0}/{1}/stats/contributors".FormatUri(owner, repositoryName);
return await ApiConnection.GetQueuedOperation<IEnumerable<Contributor>>(endpoint, cancellationToken);
return await ApiConnection.GetQueuedOperation<Contributor>(endpoint, cancellationToken);
}
/// <summary>
@@ -71,7 +72,7 @@ namespace Octokit
Ensure.ArgumentNotNullOrEmptyString(repositoryName, "repositoryName");
var endpoint = "/repos/{0}/{1}/stats/commit_activity".FormatUri(owner, repositoryName);
var activity = await ApiConnection.GetQueuedOperation<IReadOnlyList<WeeklyCommitActivity>>(endpoint,cancellationToken);
var activity = await ApiConnection.GetQueuedOperation<WeeklyCommitActivity>(endpoint,cancellationToken);
return new CommitActivity(activity);
}
@@ -99,7 +100,7 @@ namespace Octokit
Ensure.ArgumentNotNullOrEmptyString(repositoryName, "repositoryName");
var endpoint = "/repos/{0}/{1}/stats/code_frequency".FormatUri(owner, repositoryName);
var rawFrequencies = await ApiConnection.GetQueuedOperation<IEnumerable<long[]>>(endpoint,cancellationToken);
var rawFrequencies = await ApiConnection.GetQueuedOperation<long[]>(endpoint,cancellationToken);
return new CodeFrequency(rawFrequencies);
}
@@ -127,7 +128,8 @@ namespace Octokit
Ensure.ArgumentNotNullOrEmptyString(repositoryName, "repositoryName");
var endpoint = "/repos/{0}/{1}/stats/participation".FormatUri(owner, repositoryName);
return await ApiConnection.GetQueuedOperation<Participation>(endpoint,cancellationToken);
var result = await ApiConnection.GetQueuedOperation<Participation>(endpoint,cancellationToken);
return result.FirstOrDefault();
}
/// <summary>
@@ -154,7 +156,7 @@ namespace Octokit
Ensure.ArgumentNotNullOrEmptyString(repositoryName, "repositoryName");
var endpoint = "/repos/{0}/{1}/stats/punch_card".FormatUri(owner, repositoryName);
var punchCardData = await ApiConnection.GetQueuedOperation<IEnumerable<int[]>>(endpoint, cancellationToken);
var punchCardData = await ApiConnection.GetQueuedOperation<int[]>(endpoint, cancellationToken);
return new PunchCard(punchCardData);
}
}
+3 -4
View File
@@ -7,8 +7,7 @@ namespace Octokit.Helpers
/// </summary>
public static class UnixTimestampExtensions
{
// Unix Epoch is January 1, 1970 00:00 -0:00
const long unixEpochTicks = 621355968000000000;
static readonly DateTimeOffset epoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
/// <summary>
/// Convert a Unix tick to a <see cref="DateTimeOffset"/> with UTC offset
@@ -16,7 +15,7 @@ namespace Octokit.Helpers
/// <param name="unixTime">UTC tick</param>
public static DateTimeOffset FromUnixTime(this long unixTime)
{
return new DateTimeOffset(unixTime * TimeSpan.TicksPerSecond + unixEpochTicks, TimeSpan.Zero);
return epoch.AddSeconds(unixTime);
}
/// <summary>
@@ -25,7 +24,7 @@ namespace Octokit.Helpers
/// <param name="date">Date Time with UTC offset</param>
public static long ToUnixTime(this DateTimeOffset date)
{
return (date.Ticks - unixEpochTicks) / TimeSpan.TicksPerSecond;
return Convert.ToInt64((date.ToUniversalTime() - epoch).TotalSeconds);
}
}
}
+11 -7
View File
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
@@ -422,33 +423,36 @@ namespace Octokit
}
/// <summary>
/// Executes a GET to the API object at the specified URI. This operation is appropriate for
/// API calls which queue long running calculations.
/// It expects the API to respond with an initial 202 Accepted, and queries again until a
/// 200 OK is received.
/// Executes a GET to the API object at the specified URI. This operation is appropriate for API calls which
/// queue long running calculations and return a collection of a resource.
/// It expects the API to respond with an initial 202 Accepted, and queries again until a 200 OK is received.
/// It returns an empty collection if it receives a 204 No Content response.
/// </summary>
/// <typeparam name="T">The API resource's type.</typeparam>
/// <param name="uri">URI of the API resource to update</param>
/// <param name="cancellationToken">A token used to cancel this potentially long running request</param>
/// <returns>The updated API resource.</returns>
/// <exception cref="ApiException">Thrown when an API error occurs.</exception>
public async Task<T> GetQueuedOperation<T>(Uri uri, CancellationToken cancellationToken)
public async Task<IReadOnlyList<T>> GetQueuedOperation<T>(Uri uri, CancellationToken cancellationToken)
{
while (true)
{
Ensure.ArgumentNotNull(uri, "uri");
var response = await Connection.GetResponse<T>(uri, cancellationToken);
var response = await Connection.GetResponse<IReadOnlyList<T>>(uri, cancellationToken);
switch (response.HttpResponse.StatusCode)
{
case HttpStatusCode.Accepted:
continue;
case HttpStatusCode.NoContent:
return new ReadOnlyCollection<T>(new T[] {});
case HttpStatusCode.OK:
return response.Body;
}
throw new ApiException("Queued Operations expect status codes of Accepted or OK.", response.HttpResponse.StatusCode);
throw new ApiException("Queued Operations expect status codes of Accepted, No Content, or OK.",
response.HttpResponse.StatusCode);
}
}
+6 -6
View File
@@ -252,16 +252,16 @@ namespace Octokit
Task<string> GetRedirect(Uri uri);
/// <summary>
/// Executes a GET to the API object at the specified URI. This operation is appropriate for
/// API calls which queue long running calculations.
/// It expects the API to respond with an initial 202 Accepted, and queries again until a
/// 200 OK is received.
/// Executes a GET to the API object at the specified URI. This operation is appropriate for API calls which
/// queue long running calculations and return a collection of a resource.
/// It expects the API to respond with an initial 202 Accepted, and queries again until a 200 OK is received.
/// It returns an empty collection if it receives a 204 No Content response.
/// </summary>
/// <typeparam name="T">The API resource's type.</typeparam>
/// <param name="uri">URI of the API resource to update</param>
/// <param name="cancellationToken">A token used to cancel this potentially long running request</param>
/// <returns>The updated API resource.</returns>
/// <exception cref="ApiException">Thrown when an API error occurs.</exception>
Task<T> GetQueuedOperation<T>(Uri uri,CancellationToken cancellationToken);
Task<IReadOnlyList<T>> GetQueuedOperation<T>(Uri uri, CancellationToken cancellationToken);
}
}
}