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

Add exception for exceeding the private quota #379

Merged
merged 1 commit into from
Feb 19, 2014
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
41 changes: 40 additions & 1 deletion Octokit.Tests.Integration/Clients/RepositoriesClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

public class RepositoriesClientTests
{
public class TheCreateMethodForUser
public class TheCreateMethodForUser : IDisposable
{
[IntegrationTest]
public async Task CreatesANewPublicRepository()
Expand Down Expand Up @@ -287,6 +287,45 @@ public async Task ThrowsRepositoryExistsExceptionForExistingRepository()
Helper.DeleteRepo(createdRepository);
}
}

[IntegrationTest]
public async Task ThrowsPrivateRepositoryQuotaExceededExceptionWhenOverQuota()
{
var github = new GitHubClient(new ProductHeaderValue("OctokitTests"))
{
Credentials = Helper.Credentials
};

for (int i = 0; i < 5; i++)
{
var repoName = Helper.MakeNameWithTimestamp("private-repo" + i);
var repository = new NewRepository { Name = repoName, Private = true };
await github.Repository.Create(repository);
}

var thrown = await AssertEx.Throws<PrivateRepositoryQuotaExceededException>(
async () => await github.Repository.Create(new NewRepository { Name = "x-private", Private = true }));
Assert.NotNull(thrown);
}

// Clean up the repos.
public void Dispose()
{
var github = new GitHubClient(new ProductHeaderValue("OctokitTests"))
{
Credentials = Helper.Credentials
};
var repositories = github.Repository.GetAllForCurrent().Result;

foreach (var repository in repositories)
{
try
{
github.Repository.Delete(repository.Owner.Login, repository.Name).Wait();
}
catch (Exception) { }
}
}
}

public class TheCreateMethodForOrganization
Expand Down
27 changes: 26 additions & 1 deletion Octokit.Tests/Clients/RepositoriesClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,38 @@ public async Task ThrowsRepositoryExistsExceptionWhenRepositoryExistsForCurrentU
.Returns<Task<Repository>>(_ => { throw new ApiValidationException(response); });
var client = new RepositoriesClient(connection);

var exception = await AssertEx.Throws<RepositoryExistsException>(async () => await client.Create(newRepository));
var exception = await AssertEx.Throws<RepositoryExistsException>(
async () => await client.Create(newRepository));

Assert.False(exception.OwnerIsOrganization);
Assert.Equal("haacked", exception.Owner);
Assert.Equal("aName", exception.RepositoryName);
Assert.Equal(new Uri("https://github.com/haacked/aName"), exception.ExistingRepositoryWebUrl);
}

[Fact]
public async Task ThrowsExceptionWhenPrivateRepositoryQuotaExceeded()
{
var newRepository = new NewRepository { Name = "aName", Private = true };
var response = Substitute.For<IResponse>();
response.StatusCode.Returns((HttpStatusCode)422);
response.Body.Returns(@"{""message"":""Validation Failed"",""documentation_url"":"
+ @"""http://developer.github.com/v3/repos/#create"",""errors"":[{""resource"":""Repository"","
+ @"""code"":""custom"",""field"":""name"",""message"":"
+ @"""name can't be private. You are over your quota.""}]}");
var credentials = new Credentials("haacked", "pwd");
var connection = Substitute.For<IApiConnection>();
connection.Connection.BaseAddress.Returns(GitHubClient.GitHubApiUrl);
connection.Connection.Credentials.Returns(credentials);
connection.Post<Repository>(Args.Uri, newRepository)
.Returns<Task<Repository>>(_ => { throw new ApiValidationException(response); });
var client = new RepositoriesClient(connection);

var exception = await AssertEx.Throws<PrivateRepositoryQuotaExceededException>(
async () => await client.Create(newRepository));

Assert.NotNull(exception);
}
}

public class TheCreateMethodForOrganization
Expand Down
11 changes: 10 additions & 1 deletion Octokit/Clients/RepositoriesClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,11 @@ async Task<Repository> Create(Uri url, string organizationLogin, NewRepository n
}
catch (ApiValidationException e)
{
string errorMessage = e.ApiError.FirstErrorMessageSafe();

if (String.Equals(
"name already exists on this account",
e.ApiError.FirstErrorMessageSafe(),
errorMessage,
StringComparison.OrdinalIgnoreCase))
{
string owner = organizationLogin ?? Connection.Credentials.Login;
Expand All @@ -89,6 +91,13 @@ async Task<Repository> Create(Uri url, string organizationLogin, NewRepository n
organizationLogin != null,
baseAddress, e);
}
if (String.Equals(
"name can't be private. You are over your quota.",
errorMessage,
StringComparison.OrdinalIgnoreCase))
{
throw new PrivateRepositoryQuotaExceededException(e);
}
throw;
}
}
Expand Down
52 changes: 52 additions & 0 deletions Octokit/Exceptions/PrivateRepositoryQuotaExceededException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;

namespace Octokit
{
/// <summary>
/// Exception thrown when creating a private repository, but the user's private quota is or would be exceeded
/// by creating it.
/// </summary>
#if !NETFX_CORE
[Serializable]
#endif
[SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors",
Justification = "These exceptions are specific to the GitHub API and not general purpose exceptions")]
public class PrivateRepositoryQuotaExceededException : ApiValidationException
{
/// <summary>
/// Constructs an instance of PrivateRepositoryQuotaExceededException.
/// </summary>
/// <param name="owner">The login of the owner of the existing repository</param>
/// <param name="name">The name of the existing repository</param>
/// <param name="ownerIsOrganization">True if the owner is an organization</param>
/// <param name="baseAddress">The base address of the repository.</param>
/// <param name="innerException">The inner validation exception.</param>
public PrivateRepositoryQuotaExceededException(ApiValidationException innerException)
: base(innerException)
{
}

public override string Message
{
get
{
// TODO: Would be nice to show the actual numbers, but that requires another request.
return "You are currently at your limit of private repositories. Either delete a private repository "
+ "you no longer use or upgrade your account to a plan that allows for more private repositories.";
}
}

#if !NETFX_CORE
protected PrivateRepositoryQuotaExceededException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
#endif
}
}
1 change: 1 addition & 0 deletions Octokit/Octokit-Mono.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@
<Compile Include="Models\Response\PullRequestCommit.cs" />
<Compile Include="Exceptions\RepositoryExistsException.cs" />
<Compile Include="Helpers\ApiErrorExtensions.cs" />
<Compile Include="Exceptions\PrivateRepositoryQuotaExceededException.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
1 change: 1 addition & 0 deletions Octokit/Octokit-MonoAndroid.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@
<Compile Include="Models\Response\PullRequestCommit.cs" />
<Compile Include="Exceptions\RepositoryExistsException.cs" />
<Compile Include="Helpers\ApiErrorExtensions.cs" />
<Compile Include="Exceptions\PrivateRepositoryQuotaExceededException.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Novell\Novell.MonoDroid.CSharp.targets" />
</Project>
1 change: 1 addition & 0 deletions Octokit/Octokit-Monotouch.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@
<Compile Include="Models\Response\PullRequestCommit.cs" />
<Compile Include="Exceptions\RepositoryExistsException.cs" />
<Compile Include="Helpers\ApiErrorExtensions.cs" />
<Compile Include="Exceptions\PrivateRepositoryQuotaExceededException.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
1 change: 1 addition & 0 deletions Octokit/Octokit-netcore45.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@
<Compile Include="Models\Response\PullRequestCommit.cs" />
<Compile Include="Exceptions\RepositoryExistsException.cs" />
<Compile Include="Helpers\ApiErrorExtensions.cs" />
<Compile Include="Exceptions\PrivateRepositoryQuotaExceededException.cs" />
</ItemGroup>
<ItemGroup>
<CodeAnalysisDictionary Include="..\CustomDictionary.xml">
Expand Down
1 change: 1 addition & 0 deletions Octokit/Octokit.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
<Link>Properties\SolutionInfo.cs</Link>
</Compile>
<Compile Include="Clients\ActivitiesClient.cs" />
<Compile Include="Exceptions\PrivateRepositoryQuotaExceededException.cs" />
<Compile Include="Exceptions\RepositoryExistsException.cs" />
<Compile Include="Helpers\ApiErrorExtensions.cs" />
<Compile Include="Models\Response\DeploymentStatus.cs" />
Expand Down