diff --git a/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs b/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs index 84fdeeaee6..ee4eb04495 100644 --- a/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs +++ b/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs @@ -100,23 +100,99 @@ public interface IObservableRepositoriesClient IObservableCommitStatusClient CommitStatus { get; } /// - /// A client for GitHub's Repo Collaborators. + /// Gets all the branches for the specified repository. /// /// - /// See the Collaborators API documentation for more details + /// See the API documentation for more details /// - IObservableRepoCollaboratorsClient RepoCollaborators { get; } + /// The owner of the repository + /// The name of the repository + /// Thrown when a general API error occurs. + /// All es of the repository + IObservable GetAllBranches(string owner, string name); /// - /// Gets all the branches for the specified repository. + /// Gets all contributors for the specified repository. Does not include anonymous contributors. /// /// - /// See the API documentation for more details + /// See the API documentation for more details /// /// The owner of the repository /// The name of the repository - /// Thrown when a general API error occurs. - /// - IObservable GetAllBranches(string owner, string name); + /// All contributors of the repository. + IObservable GetAllContributors(string owner, string name); + + /// + /// Gets all contributors for the specified repository. With the option to include anonymous contributors. + /// + /// + /// See the API documentation for more details + /// + /// The owner of the repository + /// The name of the repository + /// True if anonymous contributors should be included in result; Otherwise false + /// All contributors of the repository. + IObservable GetAllContributors(string owner, string name, bool includeAnonymous); + + /// + /// Gets all languages for the specified repository. + /// + /// + /// See the API documentation for more details + /// + /// The owner of the repository + /// The name of the repository + /// All languages used in the repository and the number of bytes of each language. + IObservable GetAllLanguages(string owner, string name); + + /// + /// Gets all teams for the specified repository. + /// + /// + /// See the API documentation for more details + /// + /// The owner of the repository + /// The name of the repository + /// All s associated with the repository + IObservable GetAllTeams(string owner, string name); + + /// + /// Gets all tags for the specified repository. + /// + /// + /// See the API documentation for more details + /// + /// The owner of the repository + /// The name of the repository + /// All of the repositorys tags. + IObservable GetAllTags(string owner, string name); + + /// + /// Gets the specified branch. + /// + /// + /// See the API documentation for more details + /// + /// The owner of the repository + /// The name of the repository + /// The name of the branch + /// The specified + IObservable GetBranch(string owner, string repositoryName, string branchName); + + /// + /// Updates the specified repository with the values given in + /// + /// The owner of the repository + /// The name of the repository + /// New values to update the repository with + /// The updated + IObservable Edit(string owner, string name, RepositoryUpdate update); + + /// A client for GitHub's Repo Collaborators. + /// + /// + /// See the Collaborators API documentation for more details + /// + IObservableRepoCollaboratorsClient RepoCollaborators { get; } } } diff --git a/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs b/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs index 1dbdc36a52..5320f43432 100644 --- a/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs +++ b/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.Reactive; +using System.Reactive.Linq; using System.Reactive.Threading.Tasks; using Octokit.Reactive.Internal; @@ -148,6 +150,16 @@ public IObservable GetReadmeHtml(string owner, string name) return _client.GetReadmeHtml(owner, name).ToObservable(); } + /// + /// A client for GitHub's Commit Status API. + /// + /// + /// See the Commit Status API documentation for more + /// details. Also check out the blog post + /// that announced this feature. + /// + public IObservableCommitStatusClient CommitStatus { get; private set; } + /// /// Gets all the branches for the specified repository. /// @@ -157,23 +169,136 @@ public IObservable GetReadmeHtml(string owner, string name) /// The owner of the repository /// The name of the repository /// Thrown when a general API error occurs. - /// + /// All es of the repository public IObservable GetAllBranches(string owner, string name) { - return _connection.GetAndFlattenAllPages(ApiUrls.RepoBranches(owner, name)); + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + var endpoint = ApiUrls.RepoBranches(owner, name); + return _connection.GetAndFlattenAllPages(endpoint); } /// - /// A client for GitHub's Commit Status API. + /// Gets all contributors for the specified repository. Does not include anonymous contributors. /// /// - /// See the Commit Status API documentation for more - /// details. Also check out the blog post - /// that announced this feature. + /// See the API documentation for more details /// - public IObservableCommitStatusClient CommitStatus { get; private set; } + /// The owner of the repository + /// The name of the repository + /// All contributors of the repository. + public IObservable GetAllContributors(string owner, string name) + { + return GetAllContributors(owner, name, false); + } /// + /// Gets all contributors for the specified repository. With the option to include anonymous contributors. + /// + /// + /// See the API documentation for more details + /// + /// The owner of the repository + /// The name of the repository + /// True if anonymous contributors should be included in result; Otherwise false + /// All contributors of the repository. + public IObservable GetAllContributors(string owner, string name, bool includeAnonymous) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + var endpoint = ApiUrls.RepositoryContributors(owner, name); + var parameters = new Dictionary(); + if (includeAnonymous) + parameters.Add("anon", "1"); + + return _connection.GetAndFlattenAllPages(endpoint, parameters); + } + + /// + /// Gets all languages for the specified repository. + /// + /// + /// See the API documentation for more details + /// + /// The owner of the repository + /// The name of the repository + /// All languages used in the repository and the number of bytes of each language. + public IObservable GetAllLanguages(string owner, string name) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + var endpoint = ApiUrls.RepositoryLanguages(owner, name); + return _connection + .GetAndFlattenAllPages>(endpoint) + .Select(t => new RepositoryLanguage(t.Item1, t.Item2)); + } + + /// + /// Gets all teams for the specified repository. + /// + /// + /// See the API documentation for more details + /// + /// The owner of the repository + /// The name of the repository + /// All s associated with the repository + public IObservable GetAllTeams(string owner, string name) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + var endpoint = ApiUrls.RepositoryTeams(owner, name); + return _connection.GetAndFlattenAllPages(endpoint); + } + + /// + /// Gets all tags for the specified repository. + /// + /// + /// See the API documentation for more details + /// + /// The owner of the repository + /// The name of the repository + /// All of the repositorys tags. + public IObservable GetAllTags(string owner, string name) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + var endpoint = ApiUrls.RepositoryTags(owner, name); + return _connection.GetAndFlattenAllPages(endpoint); + } + + /// + /// Gets the specified branch. + /// + /// + /// See the API documentation for more details + /// + /// The owner of the repository + /// The name of the repository + /// The name of the branch + /// The specified + public IObservable GetBranch(string owner, string repositoryName, string branchName) + { + return _client.GetBranch(owner, repositoryName, branchName).ToObservable(); + } + + /// + /// Updates the specified repository with the values given in + /// + /// The owner of the repository + /// The name of the repository + /// New values to update the repository with + /// The updated + public IObservable Edit(string owner, string name, RepositoryUpdate update) + { + return _client.Edit(owner, name, update).ToObservable(); + } + /// A client for GitHub's Repo Collaborators. /// /// diff --git a/Octokit.Tests.Integration/Clients/RepositoriesClientTests.cs b/Octokit.Tests.Integration/Clients/RepositoriesClientTests.cs index fb4abee5ba..206ad0ec1e 100644 --- a/Octokit.Tests.Integration/Clients/RepositoriesClientTests.cs +++ b/Octokit.Tests.Integration/Clients/RepositoriesClientTests.cs @@ -1,4 +1,6 @@ -using System.Net.Http.Headers; +using System; +using System.Linq; +using System.Net.Http.Headers; using System.Threading.Tasks; using Octokit; using Octokit.Tests.Integration; @@ -299,6 +301,116 @@ public async Task CreatesANewPublicRepository() // TODO: Add a test for the team_id param once an overload that takes an oranization is added } + private static IGitHubClient CreateGitHubClient() + { + return new GitHubClient(new ProductHeaderValue("OctokitTests")) + { + Credentials = Helper.Credentials + }; + } + + public class TheEditMethod : IDisposable + { + Repository _repository; + + [IntegrationTest] + public async Task UpdatesName() + { + var github = CreateGitHubClient(); + var repoName = Helper.MakeNameWithTimestamp("public-repo"); + _repository = await github.Repository.Create(new NewRepository { Name = repoName, AutoInit = true }); + var updatedName = Helper.MakeNameWithTimestamp("updated-repo"); + var update = new RepositoryUpdate { Name = updatedName }; + + _repository = await github.Repository.Edit(Helper.UserName, repoName, update); + + Assert.Equal(update.Name, _repository.Name); + } + + [IntegrationTest] + public async Task UpdatesDescription() + { + var github = CreateGitHubClient(); + var repoName = Helper.MakeNameWithTimestamp("public-repo"); + _repository = await github.Repository.Create(new NewRepository { Name = repoName, AutoInit = true }); + var update = new RepositoryUpdate { Name = repoName, Description = "Updated description" }; + + _repository = await github.Repository.Edit(Helper.UserName, repoName, update); + + Assert.Equal("Updated description", _repository.Description); + } + + [IntegrationTest] + public async Task UpdatesHomepage() + { + var github = CreateGitHubClient(); + var repoName = Helper.MakeNameWithTimestamp("public-repo"); + _repository = await github.Repository.Create(new NewRepository { Name = repoName, AutoInit = true }); + var update = new RepositoryUpdate { Name = repoName, Homepage = "http://aUrl.to/nowhere" }; + + _repository = await github.Repository.Edit(Helper.UserName, repoName, update); + + Assert.Equal("http://aUrl.to/nowhere", _repository.Homepage); + } + + [IntegrationTest] + public async Task UpdatesPrivate() + { + var github = CreateGitHubClient(); + var repoName = Helper.MakeNameWithTimestamp("public-repo"); + _repository = await github.Repository.Create(new NewRepository { Name = repoName, AutoInit = true }); + var update = new RepositoryUpdate { Name = repoName, Private = true }; + + _repository = await github.Repository.Edit(Helper.UserName, repoName, update); + + Assert.Equal(true, _repository.Private); + } + + [IntegrationTest] + public async Task UpdatesHasDownloads() + { + var github = CreateGitHubClient(); + var repoName = Helper.MakeNameWithTimestamp("public-repo"); + _repository = await github.Repository.Create(new NewRepository { Name = repoName, AutoInit = true }); + var update = new RepositoryUpdate { Name = repoName, HasDownloads = false }; + + _repository = await github.Repository.Edit(Helper.UserName, repoName, update); + + Assert.Equal(false, _repository.HasDownloads); + } + + [IntegrationTest] + public async Task UpdatesHasIssues() + { + var github = CreateGitHubClient(); + var repoName = Helper.MakeNameWithTimestamp("public-repo"); + _repository = await github.Repository.Create(new NewRepository { Name = repoName, AutoInit = true }); + var update = new RepositoryUpdate { Name = repoName, HasIssues = false }; + + _repository = await github.Repository.Edit(Helper.UserName, repoName, update); + + Assert.Equal(false, _repository.HasIssues); + } + + [IntegrationTest] + public async Task UpdatesHasWiki() + { + var github = CreateGitHubClient(); + var repoName = Helper.MakeNameWithTimestamp("public-repo"); + _repository = await github.Repository.Create(new NewRepository { Name = repoName, AutoInit = true }); + var update = new RepositoryUpdate { Name = repoName, HasWiki = false }; + + _repository = await github.Repository.Edit(Helper.UserName, repoName, update); + + Assert.Equal(false, _repository.HasWiki); + } + + public void Dispose() + { + Helper.DeleteRepo(_repository); + } + } + public class TheDeleteMethod { [IntegrationTest] @@ -395,4 +507,58 @@ public async Task ReturnsReadmeHtmlForSeeGit() Assert.Contains("

WARNING: This is some haacky code.", readmeHtml); } } + + public class TheGetAllContributorsMethod + { + [IntegrationTest] + public async Task GetsContributors() + { + var github = CreateGitHubClient(); + + var contributors = await github.Repository.GetAllContributors("octokit", "octokit.net"); + + Assert.True(contributors.Any(c => c.Login == "pmacn")); + } + } + + public class TheGetAllLanguagesMethod + { + [IntegrationTest] + public async Task GetsLanguages() + { + var github = CreateGitHubClient(); + + var languages = await github.Repository.GetAllLanguages("octokit", "octokit.net"); + + Assert.NotEmpty(languages); + Assert.True(languages.Any(l => l.Name == "C#")); + } + } + + public class TheGetAllTagsMethod + { + [IntegrationTest] + public async Task GetsTags() + { + var github = CreateGitHubClient(); + + var tags = await github.Repository.GetAllTags("octokit", "octokit.net"); + + Assert.True(tags.Any(t => t.Name == "v0.1.0")); + } + } + + public class TheGetBranchMethod + { + [IntegrationTest] + public async Task GetsABranch() + { + var github = CreateGitHubClient(); + + var branch = await github.Repository.GetBranch("octokit", "octokit.net", "master"); + + Assert.NotNull(branch); + Assert.Equal("master", branch.Name); + } + } } diff --git a/Octokit.Tests/Clients/RepositoriesClientTests.cs b/Octokit.Tests/Clients/RepositoriesClientTests.cs index 3c3022bb86..db4cdbd29b 100644 --- a/Octokit.Tests/Clients/RepositoriesClientTests.cs +++ b/Octokit.Tests/Clients/RepositoriesClientTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Text; using System.Threading.Tasks; using NSubstitute; @@ -263,6 +264,178 @@ public void ReturnsBranches() connection.Received() .GetAll(Arg.Is(u => u.ToString() == "repos/owner/name/branches")); } + + [Fact] + public void EnsuresArguments() + { + var client = new RepositoriesClient(Substitute.For()); + + Assert.Throws(() => client.GetAllBranches(null, "repo")); + Assert.Throws(() => client.GetAllBranches("owner", null)); + Assert.Throws(() => client.GetAllBranches("", "repo")); + Assert.Throws(() => client.GetAllBranches("owner", "")); + } + } + + public class TheGetAllContributorsMethod + { + [Fact] + public void GetsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoriesClient(connection); + + client.GetAllContributors("owner", "name"); + + connection.Received() + .GetAll(Arg.Is(u => u.ToString() == "repos/owner/name/contributors"), Arg.Any>()); + } + + [Fact] + public void EnsuresArguments() + { + var client = new RepositoriesClient(Substitute.For()); + + Assert.Throws(() => client.GetAllContributors(null, "repo")); + Assert.Throws(() => client.GetAllContributors("owner", null)); + Assert.Throws(() => client.GetAllContributors("", "repo")); + Assert.Throws(() => client.GetAllContributors("owner", "")); + } + } + + public class TheGetAllLanguagesMethod + { + [Fact] + public void GetsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoriesClient(connection); + + client.GetAllLanguages("owner", "name"); + + connection.Received() + .Get>(Arg.Is(u => u.ToString() == "repos/owner/name/languages"), null); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var client = new RepositoriesClient(Substitute.For()); + + Assert.Throws(() => client.GetAllLanguages(null, "repo")); + Assert.Throws(() => client.GetAllLanguages("owner", null)); + Assert.Throws(() => client.GetAllLanguages("", "repo")); + Assert.Throws(() => client.GetAllLanguages("owner", "")); + } + } + + public class TheGetAllTeamsMethod + { + [Fact] + public void GetsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoriesClient(connection); + + client.GetAllTeams("owner", "name"); + + connection.Received() + .GetAll(Arg.Is(u => u.ToString() == "repos/owner/name/teams")); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var client = new RepositoriesClient(Substitute.For()); + + Assert.Throws(() => client.GetAllTeams(null, "repo")); + Assert.Throws(() => client.GetAllTeams("owner", null)); + Assert.Throws(() => client.GetAllTeams("", "repo")); + Assert.Throws(() => client.GetAllTeams("owner", "")); + } + } + + public class TheGetAllTagsMethod + { + [Fact] + public void GetsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoriesClient(connection); + + client.GetAllTags("owner", "name"); + + connection.Received() + .GetAll(Arg.Is(u => u.ToString() == "repos/owner/name/tags")); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var client = new RepositoriesClient(Substitute.For()); + + Assert.Throws(() => client.GetAllTags(null, "repo")); + Assert.Throws(() => client.GetAllTags("owner", null)); + Assert.Throws(() => client.GetAllTags("", "repo")); + Assert.Throws(() => client.GetAllTags("owner", "")); + } + } + + public class TheGetBranchMethod + { + [Fact] + public void GetsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoriesClient(connection); + + client.GetBranch("owner", "repo", "branch"); + + connection.Received() + .Get(Arg.Is(u => u.ToString() == "repos/owner/repo/branches/branch"), null); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var client = new RepositoriesClient(Substitute.For()); + + Assert.Throws(() => client.GetBranch(null, "repo", "branch")); + Assert.Throws(() => client.GetBranch("owner", null, "branch")); + Assert.Throws(() => client.GetBranch("owner", "repo", null)); + Assert.Throws(() => client.GetBranch("", "repo", "branch")); + Assert.Throws(() => client.GetBranch("owner", "", "branch")); + Assert.Throws(() => client.GetBranch("owner", "repo", "")); + } + } + + public class TheEditMethod + { + [Fact] + public void PatchesCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoriesClient(connection); + var update = new RepositoryUpdate(); + + client.Edit("owner", "repo", update); + + connection.Received() + .Patch(Arg.Is(u => u.ToString() == "repos/owner/repo"), Arg.Any()); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var client = new RepositoriesClient(Substitute.For()); + var update = new RepositoryUpdate(); + + Assert.Throws(() => client.Edit(null, "repo", update)); + Assert.Throws(() => client.Edit("owner", null, update)); + Assert.Throws(() => client.Edit("owner", "repo", null)); + Assert.Throws(() => client.Edit("", "repo", update)); + Assert.Throws(() => client.Edit("owner", "", update)); + } } } } diff --git a/Octokit.Tests/Models/RepositoryUpdateTests.cs b/Octokit.Tests/Models/RepositoryUpdateTests.cs new file mode 100644 index 0000000000..d21544bf30 --- /dev/null +++ b/Octokit.Tests/Models/RepositoryUpdateTests.cs @@ -0,0 +1,40 @@ +using Octokit.Internal; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace Octokit.Tests.Models +{ + public class RepositoryUpdateTests + { + [Fact] + public void CanSerialize() + { + var expected = "{\"name\":\"Hello-World\"," + + "\"description\":\"This is your first repository\"," + + "\"homepage\":\"https://github.com\"," + + "\"private\":true," + + "\"has_issues\":true," + + "\"has_wiki\":true," + + "\"has_downloads\":true}"; + + var update = new RepositoryUpdate + { + Name = "Hello-World", + Description = "This is your first repository", + Homepage = "https://github.com", + Private = true, + HasIssues = true, + HasWiki = true, + HasDownloads = true + }; + + var json = new SimpleJsonSerializer().Serialize(update); + + Assert.Equal(expected, json); + } + } +} diff --git a/Octokit.Tests/Octokit.Tests.csproj b/Octokit.Tests/Octokit.Tests.csproj index e6c24604f6..efaa950a9b 100644 --- a/Octokit.Tests/Octokit.Tests.csproj +++ b/Octokit.Tests/Octokit.Tests.csproj @@ -129,6 +129,7 @@ + diff --git a/Octokit.Tests/Reactive/ObservableRepositoriesClientTests.cs b/Octokit.Tests/Reactive/ObservableRepositoriesClientTests.cs index c48ceb0eea..9347be37ae 100644 --- a/Octokit.Tests/Reactive/ObservableRepositoriesClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableRepositoriesClientTests.cs @@ -162,6 +162,202 @@ public async Task StopsMakingNewRequestsWhenTakeIsFulfilled() } } + public class TheGetAllBranchesMethod + { + [Fact] + public void EnsuresArguments() + { + var client = new ObservableRepositoriesClient(Substitute.For()); + + Assert.Throws(() => client.GetAllBranches(null, "repo")); + Assert.Throws(() => client.GetAllBranches("owner", null)); + Assert.Throws(() => client.GetAllBranches("", "repo")); + Assert.Throws(() => client.GetAllBranches("owner", "")); + } + + [Fact] + public void GetsCorrectUrl() + { + var github = Substitute.For(); + var client = new ObservableRepositoriesClient(github); + var expected = new Uri("repos/owner/repo/branches", UriKind.Relative); + + client.GetAllBranches("owner", "repo"); + + github.Connection.Received(1).GetAsync>(expected); + } + } + + public class TheGetAllContributorsMethod + { + [Fact] + public void EnsuresArguments() + { + var client = new ObservableRepositoriesClient(Substitute.For()); + + Assert.Throws(() => client.GetAllContributors(null, "repo")); + Assert.Throws(() => client.GetAllContributors("owner", null)); + Assert.Throws(() => client.GetAllContributors("", "repo")); + Assert.Throws(() => client.GetAllContributors("owner", "")); + } + + [Fact] + public void GetsCorrectUrl() + { + var github = Substitute.For(); + var client = new ObservableRepositoriesClient(github); + var expected = new Uri("repos/owner/repo/contributors", UriKind.Relative); + + client.GetAllContributors("owner", "repo"); + + github.Connection.Received(1) + .GetAsync>(expected, + Arg.Any>(), + Arg.Any()); + } + + // TODO: Needs test for 'includeAnonymous' + } + + public class TheGetAllLanguagesMethod + { + [Fact] + public void EnsuresNonNullArguments() + { + var client = new ObservableRepositoriesClient(Substitute.For()); + + Assert.Throws(() => client.GetAllLanguages(null, "repo")); + Assert.Throws(() => client.GetAllLanguages("owner", null)); + Assert.Throws(() => client.GetAllLanguages("", "repo")); + Assert.Throws(() => client.GetAllLanguages("owner", "")); + } + + [Fact] + public void GetsCorrectUrl() + { + var github = Substitute.For(); + var client = new ObservableRepositoriesClient(github); + var expected = new Uri("repos/owner/repo/languages", UriKind.Relative); + + client.GetAllLanguages("owner", "repo"); + + github.Connection.Received(1).GetAsync>>(expected); + } + } + + public class TheGetAllTeamsMethod + { + [Fact] + public void EnsuresArguments() + { + var client = new ObservableRepositoriesClient(Substitute.For()); + + Assert.Throws(() => client.GetAllTeams(null, "repo")); + Assert.Throws(() => client.GetAllTeams("owner", null)); + Assert.Throws(() => client.GetAllTeams("", "repo")); + Assert.Throws(() => client.GetAllTeams("owner", "")); + } + + [Fact] + public void GetsCorrectUrl() + { + var github = Substitute.For(); + var client = new ObservableRepositoriesClient(github); + var expected = new Uri("repos/owner/repo/teams", UriKind.Relative); + + client.GetAllTeams("owner", "repo"); + + github.Connection.Received(1).GetAsync>(expected); + } + } + + public class TheGetAllTagsMethod + { + [Fact] + public void EnsuresArguments() + { + var client = new ObservableRepositoriesClient(Substitute.For()); + + Assert.Throws(() => client.GetAllTags(null, "repo")); + Assert.Throws(() => client.GetAllTags("owner", null)); + Assert.Throws(() => client.GetAllTags("", "repo")); + Assert.Throws(() => client.GetAllTags("owner", "")); + } + + [Fact] + public void GetsCorrectUrl() + { + var github = Substitute.For(); + var client = new ObservableRepositoriesClient(github); + var expected = new Uri("repos/owner/repo/tags", UriKind.Relative); + + client.GetAllTags("owner", "repo"); + + github.Connection.Received(1).GetAsync>(expected); + } + } + + public class TheGetBranchMethod + { + [Fact] + public async Task EnsuresArguments() + { + var github = Substitute.For(); + var nonreactiveClient = new RepositoriesClient(Substitute.For()); + github.Repository.Returns(nonreactiveClient); + var client = new ObservableRepositoriesClient(github); + + Assert.Throws(() => client.GetBranch(null, "repo", "branch")); + Assert.Throws(() => client.GetBranch("owner", null, "branch")); + Assert.Throws(() => client.GetBranch("owner", "repo", null)); + Assert.Throws(() => client.GetBranch("", "repo", "branch")); + Assert.Throws(() => client.GetBranch("owner", "", "branch")); + Assert.Throws(() => client.GetBranch("owner", "repo", "")); + } + + [Fact] + public void CallsIntoClient() + { + var github = Substitute.For(); + var client = new ObservableRepositoriesClient(github); + + client.GetBranch("owner", "repo", "branch"); + + github.Repository.Received(1).GetBranch("owner", "repo", "branch"); + } + } + + public class TheEditMethod + { + [Fact] + public async Task EnsuresArguments() + { + var github = Substitute.For(); + var nonreactiveClient = new RepositoriesClient(Substitute.For()); + github.Repository.Returns(nonreactiveClient); + var client = new ObservableRepositoriesClient(github); + var update = new RepositoryUpdate(); + + Assert.Throws(() => client.Edit(null, "repo", update)); + Assert.Throws(() => client.Edit("owner", null, update)); + Assert.Throws(() => client.Edit("owner", "repo", null)); + Assert.Throws(() => client.Edit("", "repo", update)); + Assert.Throws(() => client.Edit("owner", "", update)); + } + + [Fact] + public void CallsIntoClient() + { + var github = Substitute.For(); + var client = new ObservableRepositoriesClient(github); + var update = new RepositoryUpdate(); + + client.Edit("owner", "repo", update); + + github.Repository.Received(1).Edit("owner", "repo", update); + } + } + static ApiInfo CreateApiInfo(IDictionary links) { return new ApiInfo(links, new List(), new List(), "etag", new RateLimit(new Dictionary())); diff --git a/Octokit/Clients/IRepositoriesClient.cs b/Octokit/Clients/IRepositoriesClient.cs index 883f9781e3..47b6c7ae72 100644 --- a/Octokit/Clients/IRepositoriesClient.cs +++ b/Octokit/Clients/IRepositoriesClient.cs @@ -153,7 +153,84 @@ public interface IRepositoriesClient /// The owner of the repository /// The name of the repository /// Thrown when a general API error occurs. - /// + /// All es of the repository Task> GetAllBranches(string owner, string name); + + ///

+ /// Gets all contributors for the specified repository. Does not include anonymous contributors. + /// + /// + /// See the API documentation for more details + /// + /// The owner of the repository + /// The name of the repository + /// All contributors of the repository. + Task> GetAllContributors(string owner, string name); + + /// + /// Gets all contributors for the specified repository. With the option to include anonymous contributors. + /// + /// + /// See the API documentation for more details + /// + /// The owner of the repository + /// The name of the repository + /// True if anonymous contributors should be included in result; Otherwise false + /// All contributors of the repository. + Task> GetAllContributors(string owner, string name, bool includeAnonymous); + + /// + /// Gets all languages for the specified repository. + /// + /// + /// See the API documentation for more details + /// + /// The owner of the repository + /// The name of the repository + /// All languages used in the repository and the number of bytes of each language. + Task> GetAllLanguages(string owner, string name); + + /// + /// Gets all teams for the specified repository. + /// + /// + /// See the API documentation for more details + /// + /// The owner of the repository + /// The name of the repository + /// All s associated with the repository + Task> GetAllTeams(string owner, string name); + + /// + /// Gets all tags for the specified repository. + /// + /// + /// See the API documentation for more details + /// + /// The owner of the repository + /// The name of the repository + /// All of the repositorys tags. + Task> GetAllTags(string owner, string name); + + /// + /// Gets the specified branch. + /// + /// + /// See the API documentation for more details + /// + /// The owner of the repository + /// The name of the repository + /// The name of the branch + /// The specified + Task GetBranch(string owner, string repositoryName, string branchName); + + /// + /// Updates the specified repository with the values given in + /// + /// The owner of the repository + /// The name of the repository + /// New values to update the repository with + /// The updated + Task Edit(string owner, string name, RepositoryUpdate update); } } diff --git a/Octokit/Clients/RepositoriesClient.cs b/Octokit/Clients/RepositoriesClient.cs index 7ec5e31d16..c894c17962 100644 --- a/Octokit/Clients/RepositoriesClient.cs +++ b/Octokit/Clients/RepositoriesClient.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; #endif using System.Threading.Tasks; +using System.Linq; +using System.Collections.ObjectModel; namespace Octokit { @@ -81,6 +83,22 @@ public Task Delete(string owner, string name) return ApiConnection.Delete(endpoint); } + /// + /// Updates the specified repository with the values given in + /// + /// The owner of the repository + /// The name of the repository + /// New values to update the repository with + /// The updated + public Task Edit(string owner, string name, RepositoryUpdate update) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(update, "update"); + + return ApiConnection.Patch(ApiUrls.Repository(owner, name), update); + } + /// /// Gets the specified repository. /// @@ -214,11 +232,127 @@ public Task GetReadmeHtml(string owner, string name) /// The owner of the repository /// The name of the repository /// Thrown when a general API error occurs. - /// + /// All es of the repository public Task> GetAllBranches(string owner, string name) { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + var endpoint = ApiUrls.RepoBranches(owner, name); return ApiConnection.GetAll(endpoint); } + + + /// + /// Gets all contributors for the specified repository. Does not include anonymous contributors. + /// + /// + /// See the API documentation for more details + /// + /// The owner of the repository + /// The name of the repository + /// All contributors of the repository. + public Task> GetAllContributors(string owner, string name) + { + return GetAllContributors(owner, name, false); + } + + /// + /// Gets all contributors for the specified repository. With the option to include anonymous contributors. + /// + /// + /// See the API documentation for more details + /// + /// The owner of the repository + /// The name of the repository + /// True if anonymous contributors should be included in result; Otherwise false + /// All contributors of the repository. + public Task> GetAllContributors(string owner, string name, bool includeAnonymous) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + var parameters = new Dictionary(); + if (includeAnonymous) + parameters.Add("anon", "1"); + + return ApiConnection.GetAll(ApiUrls.RepositoryContributors(owner, name), parameters); + } + + /// + /// Gets all languages for the specified repository. + /// + /// + /// See the API documentation for more details + /// + /// The owner of the repository + /// The name of the repository + /// All languages used in the repository and the number of bytes of each language. + public Task> GetAllLanguages(string owner, string name) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return ApiConnection + .Get>(ApiUrls.RepositoryLanguages(owner, name)) + .ContinueWith>(t => + new ReadOnlyCollection( + t.Result.Select(kvp => new RepositoryLanguage(kvp.Key, kvp.Value)).ToList() + ), + TaskContinuationOptions.OnlyOnRanToCompletion); + } + + /// + /// Gets all teams for the specified repository. + /// + /// + /// See the API documentation for more details + /// + /// The owner of the repository + /// The name of the repository + /// All s associated with the repository + public Task> GetAllTeams(string owner, string name) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return ApiConnection.GetAll(ApiUrls.RepositoryTeams(owner, name)); + } + + /// + /// Gets all tags for the specified repository. + /// + /// + /// See the API documentation for more details + /// + /// The owner of the repository + /// The name of the repository + /// All of the repositorys tags. + public Task> GetAllTags(string owner, string name) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return ApiConnection.GetAll(ApiUrls.RepositoryTags(owner, name)); + } + + /// + /// Gets the specified branch. + /// + /// + /// See the API documentation for more details + /// + /// The owner of the repository + /// The name of the repository + /// The name of the branch + /// The specified + public Task GetBranch(string owner, string repositoryName, string branchName) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(repositoryName, "repositoryName"); + Ensure.ArgumentNotNullOrEmptyString(branchName, "branchName"); + + return ApiConnection.Get(ApiUrls.RepoBranch(owner, repositoryName, branchName)); + } } } diff --git a/Octokit/Helpers/ApiUrls.cs b/Octokit/Helpers/ApiUrls.cs index c8f147dbde..1155799afd 100644 --- a/Octokit/Helpers/ApiUrls.cs +++ b/Octokit/Helpers/ApiUrls.cs @@ -884,6 +884,72 @@ public static Uri SearchCode() } /// + /// Returns the for repository contributors. + /// + /// The owner of the repository + /// The name of the repository + /// + public static Uri RepositoryContributors(string owner, string name) + { + return "repos/{0}/{1}/contributors".FormatUri(owner, name); + } + + /// + /// Returns the for repository languages. + /// + /// The owner of the repository + /// The name of the repository + /// + public static Uri RepositoryLanguages(string owner, string name) + { + return "repos/{0}/{1}/languages".FormatUri(owner, name); + } + + /// + /// Returns the for repository teams. + /// + /// The owner of the repository + /// The name of the repository + /// + public static Uri RepositoryTeams(string owner, string name) + { + return "repos/{0}/{1}/teams".FormatUri(owner, name); + } + + /// + /// Returns the for repository tags. + /// + /// The owner of the repository + /// The name of the repository + /// + public static Uri RepositoryTags(string owner, string name) + { + return "repos/{0}/{1}/tags".FormatUri(owner, name); + } + + /// + /// Returns the for a repository branch. + /// + /// The owner of the repository + /// The name of the repository + /// The name of the branch + /// + public static Uri RepoBranch(string owner, string repositoryName, string branchName) + { + return "repos/{0}/{1}/branches/{2}".FormatUri(owner, repositoryName, branchName); + } + + /// + /// Returns the for a repository. + /// + /// The owner of the repository + /// The name of the repository + /// + public static Uri Repository(string owner, string name) + { + return "repos/{0}/{1}".FormatUri(owner, name); + } + /// Returns the for the Deployments API for the given repository. /// /// Owner of the repository diff --git a/Octokit/Models/Request/RepositoryUpdate.cs b/Octokit/Models/Request/RepositoryUpdate.cs new file mode 100644 index 0000000000..ab9ee632a7 --- /dev/null +++ b/Octokit/Models/Request/RepositoryUpdate.cs @@ -0,0 +1,55 @@ + +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; + +namespace Octokit +{ + /// + /// Represents updatable fields on a repository. Values that are null will not be sent in the request. + /// Use string.empty if you want to clear a value. + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class RepositoryUpdate + { + /// + /// Required. Gets or sets the repository name. + /// + public string Name { get; set; } + /// + /// Optional. Gets or sets the repository description. The default is null (do not update) + /// + public string Description { get; set; } + /// + /// Optional. Gets or sets the repository homepage url. The default is null (do not update). + /// + public string Homepage { get; set; } + /// + /// Gets or sets whether to make the repository private. The default is null (do not update). + /// + public bool? Private { get; set; } + /// + /// Gets or sets whether to enable issues for the repository. The default is null (do not update). + /// + public bool? HasIssues { get; set; } + /// + /// Optional. Gets or sets whether to enable the wiki for the repository. The default is null (do not update). + /// + public bool? HasWiki { get; set; } + /// + /// Optional. Gets or sets whether to enable downloads for the repository. The default is null (do not update). + /// + public bool? HasDownloads { get; set; } + /// + /// Optional. Gets or sets the default branch. The default is null (do not update). + /// + public string DefaultBranch { get; set; } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private string DebuggerDisplay + { + get { return String.Format(CultureInfo.CurrentCulture, "RepositoryUpdate: Name: {0}", Name); } + } + } +} diff --git a/Octokit/Models/Response/RepositoryLanguage.cs b/Octokit/Models/Response/RepositoryLanguage.cs new file mode 100644 index 0000000000..3f8ff8c696 --- /dev/null +++ b/Octokit/Models/Response/RepositoryLanguage.cs @@ -0,0 +1,32 @@ + +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class RepositoryLanguage + { + public RepositoryLanguage(string name, long numberOfBytes) + { + this.Name = name; + this.NumberOfBytes = numberOfBytes; + } + + public string Name { get; set; } + public long NumberOfBytes { get; set; } + + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, + "RepositoryLangauge: Name: {0} Bytes: {1}", Name, NumberOfBytes); + } + } + } +} diff --git a/Octokit/Models/Response/RepositoryTag.cs b/Octokit/Models/Response/RepositoryTag.cs new file mode 100644 index 0000000000..74a416b450 --- /dev/null +++ b/Octokit/Models/Response/RepositoryTag.cs @@ -0,0 +1,28 @@ +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class RepositoryTag + { + public string Name { get; set; } + public GitReference Commit { get; set; } + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Zipball")] + public string ZipballUrl { get; set; } + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Tarball")] + public string TarballUrl { get; set; } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, + "RepositoryTag: Name: {0} Commit: {1}", Name, Commit); + } + } + } +} diff --git a/Octokit/Octokit-Mono.csproj b/Octokit/Octokit-Mono.csproj index b32722402a..ddb25017f9 100644 --- a/Octokit/Octokit-Mono.csproj +++ b/Octokit/Octokit-Mono.csproj @@ -266,6 +266,9 @@ + + + diff --git a/Octokit/Octokit-MonoAndroid.csproj b/Octokit/Octokit-MonoAndroid.csproj index 2e3f3c04e4..283271d871 100644 --- a/Octokit/Octokit-MonoAndroid.csproj +++ b/Octokit/Octokit-MonoAndroid.csproj @@ -266,6 +266,9 @@ + + + diff --git a/Octokit/Octokit-Monotouch.csproj b/Octokit/Octokit-Monotouch.csproj index f351c9e0a9..4082510cc8 100644 --- a/Octokit/Octokit-Monotouch.csproj +++ b/Octokit/Octokit-Monotouch.csproj @@ -261,6 +261,9 @@ + + + diff --git a/Octokit/Octokit-netcore45.csproj b/Octokit/Octokit-netcore45.csproj index af66536aae..6e4d63cd7d 100644 --- a/Octokit/Octokit-netcore45.csproj +++ b/Octokit/Octokit-netcore45.csproj @@ -267,6 +267,9 @@ + + + diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index 21256b4dc4..53422d1249 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -89,6 +89,7 @@ Code + @@ -133,6 +134,8 @@ + +