From 261758b6472bfda40aeef6aa7bf00fb3bedcb74c Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Wed, 6 Mar 2019 08:09:08 +1000 Subject: [PATCH 01/18] Add new settings to the Organization model --- Octokit/Models/Response/Organization.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Octokit/Models/Response/Organization.cs b/Octokit/Models/Response/Organization.cs index 9a0ad5dc25..1e53b875ab 100644 --- a/Octokit/Models/Response/Organization.cs +++ b/Octokit/Models/Response/Organization.cs @@ -10,10 +10,12 @@ public class Organization : Account { public Organization() { } - public Organization(string avatarUrl, string bio, string blog, int collaborators, string company, DateTimeOffset createdAt, int diskUsage, string email, int followers, int following, bool? hireable, string htmlUrl, int totalPrivateRepos, int id, string nodeId, string location, string login, string name, int ownedPrivateRepos, Plan plan, int privateGists, int publicGists, int publicRepos, string url, string billingAddress) + public Organization(string avatarUrl, string bio, string blog, int collaborators, string company, DateTimeOffset createdAt, int diskUsage, string email, int followers, int following, bool? hireable, string htmlUrl, int totalPrivateRepos, int id, string nodeId, string location, string login, string name, int ownedPrivateRepos, Plan plan, int privateGists, int publicGists, int publicRepos, string url, string billingAddress, string defaultRepositoryPermission, bool membersCanCreateRepositories) : base(avatarUrl, bio, blog, collaborators, company, createdAt, diskUsage, email, followers, following, hireable, htmlUrl, totalPrivateRepos, id, location, login, name, nodeId, ownedPrivateRepos, plan, privateGists, publicGists, publicRepos, AccountType.Organization, url) { BillingAddress = billingAddress; + DefaultRepositoryPermission = defaultRepositoryPermission; + MembersCanCreateRepositories = membersCanCreateRepositories; } /// @@ -21,6 +23,16 @@ public Organization(string avatarUrl, string bio, string blog, int collaborators /// an organization. /// public string BillingAddress { get; protected set; } + + /// + /// Default permission level members have for organization repositories. + /// + public string DefaultRepositoryPermission { get; protected set; } + + /// + /// Toggles the ability of non-admin organization members to create repositories. + /// + public bool MembersCanCreateRepositories { get; protected set; } internal string DebuggerDisplay { From 2ac60271050ca8151de5344ef17c7f43a99d47ea Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Fri, 15 Mar 2019 23:10:53 +1000 Subject: [PATCH 02/18] Add new settings to organization update request model --- Octokit/Models/Request/OrganizationUpdate.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Octokit/Models/Request/OrganizationUpdate.cs b/Octokit/Models/Request/OrganizationUpdate.cs index a960460be7..682e158976 100644 --- a/Octokit/Models/Request/OrganizationUpdate.cs +++ b/Octokit/Models/Request/OrganizationUpdate.cs @@ -43,6 +43,16 @@ public class OrganizationUpdate /// public string Description { get; set; } + /// + /// Gets or sets the default permission level members have for organization repositories. + /// + public string DefaultRepositoryPermission { get; set; } + + /// + /// Toggles the ability of non-admin organization members to create repositories. + /// + public bool MembersCanCreateRepositories { get; set; } + internal string DebuggerDisplay { get From 9cc156b800551084818e2e4fd9574ebe88a01976 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Fri, 15 Mar 2019 23:47:38 +1000 Subject: [PATCH 03/18] Add ability to filter collaborators by affiliation --- .../IObservableRepoCollaboratorsClient.cs | 29 ++++++++++- .../ObservableRepoCollaboratorsClient.cs | 49 ++++++++++++++++--- Octokit/Clients/IRepoCollaboratorsClient.cs | 29 ++++++++++- Octokit/Clients/RepoCollaboratorsClient.cs | 49 ++++++++++++++++--- Octokit/Models/Request/Affiliation.cs | 27 ++++++++++ .../Models/Request/ListCollaboratorRequest.cs | 23 +++++++++ 6 files changed, 190 insertions(+), 16 deletions(-) create mode 100644 Octokit/Models/Request/Affiliation.cs create mode 100644 Octokit/Models/Request/ListCollaboratorRequest.cs diff --git a/Octokit.Reactive/Clients/IObservableRepoCollaboratorsClient.cs b/Octokit.Reactive/Clients/IObservableRepoCollaboratorsClient.cs index 49deeb9874..8e3287b78e 100644 --- a/Octokit.Reactive/Clients/IObservableRepoCollaboratorsClient.cs +++ b/Octokit.Reactive/Clients/IObservableRepoCollaboratorsClient.cs @@ -22,6 +22,18 @@ public interface IObservableRepoCollaboratorsClient /// Thrown when a general API error occurs. IObservable GetAll(string owner, string name); + /// + /// Gets all the collaborators on a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The owner of the repository + /// The name of the repository + /// Details to filter the request, such as by affiliation. + /// Thrown when a general API error occurs. + IObservable GetAll(string owner, string name, ListCollaboratorRequest listCollaboratorRequest); + /// /// Gets all the collaborators on a repository. /// @@ -32,6 +44,17 @@ public interface IObservableRepoCollaboratorsClient /// Thrown when a general API error occurs. IObservable GetAll(long repositoryId); + /// + /// Gets all the collaborators on a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The id of the repository + /// Details to filter the request, such as by affiliation. + /// Thrown when a general API error occurs. + IObservable GetAll(long repositoryId, ListCollaboratorRequest listCollaboratorRequest); + /// /// Gets all the collaborators on a repository. /// @@ -40,9 +63,10 @@ public interface IObservableRepoCollaboratorsClient /// /// The owner of the repository /// The name of the repository + /// Details to filter the request, such as by affiliation. /// Options for changing the API response /// Thrown when a general API error occurs. - IObservable GetAll(string owner, string name, ApiOptions options); + IObservable GetAll(string owner, string name, ListCollaboratorRequest listCollaboratorRequest, ApiOptions options); /// /// Gets all the collaborators on a repository. @@ -51,9 +75,10 @@ public interface IObservableRepoCollaboratorsClient /// See the API documentation for more information. /// /// The id of the repository + /// Details to filter the request, such as by affiliation. /// Options for changing the API response /// Thrown when a general API error occurs. - IObservable GetAll(long repositoryId, ApiOptions options); + IObservable GetAll(long repositoryId, ListCollaboratorRequest listCollaboratorRequest, ApiOptions options); /// /// Checks if a user is a collaborator on a repository. diff --git a/Octokit.Reactive/Clients/ObservableRepoCollaboratorsClient.cs b/Octokit.Reactive/Clients/ObservableRepoCollaboratorsClient.cs index 719d8614bc..39d1269369 100644 --- a/Octokit.Reactive/Clients/ObservableRepoCollaboratorsClient.cs +++ b/Octokit.Reactive/Clients/ObservableRepoCollaboratorsClient.cs @@ -42,7 +42,26 @@ public IObservable GetAll(string owner, string name) Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); Ensure.ArgumentNotNullOrEmptyString(name, nameof(name)); - return GetAll(owner, name, ApiOptions.None); + return GetAll(owner, name, new ListCollaboratorRequest(), ApiOptions.None); + } + + /// + /// Gets all the collaborators on a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The owner of the repository + /// The name of the repository + /// Details to filter the request, such as by affiliation. + /// Thrown when a general API error occurs. + public IObservable GetAll(string owner, string name, ListCollaboratorRequest listCollaboratorRequest) + { + Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); + Ensure.ArgumentNotNullOrEmptyString(name, nameof(name)); + Ensure.ArgumentNotNull(listCollaboratorRequest, nameof(listCollaboratorRequest)); + + return GetAll(owner, name, listCollaboratorRequest, ApiOptions.None); } /// @@ -55,7 +74,23 @@ public IObservable GetAll(string owner, string name) /// Thrown when a general API error occurs. public IObservable GetAll(long repositoryId) { - return GetAll(repositoryId, ApiOptions.None); + return GetAll(repositoryId, new ListCollaboratorRequest(), ApiOptions.None); + } + + /// + /// Gets all the collaborators on a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The id of the repository + /// Details to filter the request, such as by affiliation. + /// Thrown when a general API error occurs. + public IObservable GetAll(long repositoryId, ListCollaboratorRequest listCollaboratorRequest) + { + Ensure.ArgumentNotNull(listCollaboratorRequest, nameof(listCollaboratorRequest)); + + return GetAll(repositoryId, listCollaboratorRequest, ApiOptions.None); } /// @@ -66,15 +101,16 @@ public IObservable GetAll(long repositoryId) /// /// The owner of the repository /// The name of the repository + /// Details to filter the request, such as by affiliation. /// Options for changing the API response /// Thrown when a general API error occurs. - public IObservable GetAll(string owner, string name, ApiOptions options) + public IObservable GetAll(string owner, string name, ListCollaboratorRequest listCollaboratorRequest, ApiOptions options) { Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); Ensure.ArgumentNotNullOrEmptyString(name, nameof(name)); Ensure.ArgumentNotNull(options, nameof(options)); - return _connection.GetAndFlattenAllPages(ApiUrls.RepoCollaborators(owner, name), options); + return _connection.GetAndFlattenAllPages(ApiUrls.RepoCollaborators(owner, name), listCollaboratorRequest.ToParametersDictionary(), AcceptHeaders.OrganizationMembershipPreview, options); } /// @@ -84,13 +120,14 @@ public IObservable GetAll(string owner, string name, ApiOptions options) /// See the API documentation for more information. /// /// The id of the repository + /// Details to filter the request, such as by affiliation. /// Options for changing the API response /// Thrown when a general API error occurs. - public IObservable GetAll(long repositoryId, ApiOptions options) + public IObservable GetAll(long repositoryId, ListCollaboratorRequest listCollaboratorRequest, ApiOptions options) { Ensure.ArgumentNotNull(options, nameof(options)); - return _connection.GetAndFlattenAllPages(ApiUrls.RepoCollaborators(repositoryId), options); + return _connection.GetAndFlattenAllPages(ApiUrls.RepoCollaborators(repositoryId), listCollaboratorRequest.ToParametersDictionary(), AcceptHeaders.OrganizationMembershipPreview, options); } /// diff --git a/Octokit/Clients/IRepoCollaboratorsClient.cs b/Octokit/Clients/IRepoCollaboratorsClient.cs index 2986795f54..3571d785c0 100644 --- a/Octokit/Clients/IRepoCollaboratorsClient.cs +++ b/Octokit/Clients/IRepoCollaboratorsClient.cs @@ -22,6 +22,18 @@ public interface IRepoCollaboratorsClient /// Thrown when a general API error occurs. Task> GetAll(string owner, string name); + /// + /// Gets all the collaborators on a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The owner of the repository + /// The name of the repository + /// Details to filter the request, such as by affiliation. + /// Thrown when a general API error occurs. + Task> GetAll(string owner, string name, ListCollaboratorRequest listCollaboratorRequest); + /// /// Gets all the collaborators on a repository. /// @@ -32,6 +44,17 @@ public interface IRepoCollaboratorsClient /// Thrown when a general API error occurs. Task> GetAll(long repositoryId); + /// + /// Gets all the collaborators on a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The id of the repository + /// Details to filter the request, such as by affiliation. + /// Thrown when a general API error occurs. + Task> GetAll(long repositoryId, ListCollaboratorRequest listCollaboratorRequest); + /// /// Gets all the collaborators on a repository. /// @@ -40,9 +63,10 @@ public interface IRepoCollaboratorsClient /// /// The owner of the repository /// The name of the repository + /// Details to filter the request, such as by affiliation. /// Options for changing the API response /// Thrown when a general API error occurs. - Task> GetAll(string owner, string name, ApiOptions options); + Task> GetAll(string owner, string name, ListCollaboratorRequest listCollaboratorRequest, ApiOptions options); /// /// Gets all the collaborators on a repository. @@ -51,9 +75,10 @@ public interface IRepoCollaboratorsClient /// See the API documentation for more information. /// /// The id of the repository + /// Details to filter the request, such as by affiliation. /// Options for changing the API response /// Thrown when a general API error occurs. - Task> GetAll(long repositoryId, ApiOptions options); + Task> GetAll(long repositoryId, ListCollaboratorRequest listCollaboratorRequest, ApiOptions options); /// /// Checks if a user is a collaborator on a repository. diff --git a/Octokit/Clients/RepoCollaboratorsClient.cs b/Octokit/Clients/RepoCollaboratorsClient.cs index fd3afe2a9a..9f5e3a4c47 100644 --- a/Octokit/Clients/RepoCollaboratorsClient.cs +++ b/Octokit/Clients/RepoCollaboratorsClient.cs @@ -34,7 +34,26 @@ public Task> GetAll(string owner, string name) Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); Ensure.ArgumentNotNullOrEmptyString(name, nameof(name)); - return GetAll(owner, name, ApiOptions.None); + return GetAll(owner, name, new ListCollaboratorRequest(), ApiOptions.None); + } + + /// + /// Gets all the collaborators on a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The owner of the repository + /// The name of the repository + /// Details to filter the request, such as by affiliation. + /// Thrown when a general API error occurs. + public Task> GetAll(string owner, string name, ListCollaboratorRequest listCollaboratorRequest) + { + Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); + Ensure.ArgumentNotNullOrEmptyString(name, nameof(name)); + Ensure.ArgumentNotNull(listCollaboratorRequest, nameof(listCollaboratorRequest)); + + return GetAll(owner, name, listCollaboratorRequest, ApiOptions.None); } /// @@ -47,7 +66,23 @@ public Task> GetAll(string owner, string name) /// Thrown when a general API error occurs. public Task> GetAll(long repositoryId) { - return GetAll(repositoryId, ApiOptions.None); + return GetAll(repositoryId, new ListCollaboratorRequest(), ApiOptions.None); + } + + /// + /// Gets all the collaborators on a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The id of the repository + /// Details to filter the request, such as by affiliation. + /// Thrown when a general API error occurs. + public Task> GetAll(long repositoryId, ListCollaboratorRequest listCollaboratorRequest) + { + Ensure.ArgumentNotNull(listCollaboratorRequest, nameof(listCollaboratorRequest)); + + return GetAll(repositoryId, listCollaboratorRequest, ApiOptions.None); } /// @@ -58,15 +93,16 @@ public Task> GetAll(long repositoryId) /// /// The owner of the repository /// The name of the repository + /// Details to filter the request, such as by affiliation. /// Options for changing the API response /// Thrown when a general API error occurs. - public Task> GetAll(string owner, string name, ApiOptions options) + public Task> GetAll(string owner, string name, ListCollaboratorRequest listCollaboratorRequest, ApiOptions options) { Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); Ensure.ArgumentNotNullOrEmptyString(name, nameof(name)); Ensure.ArgumentNotNull(options, nameof(options)); - return ApiConnection.GetAll(ApiUrls.RepoCollaborators(owner, name), options); + return ApiConnection.GetAll(ApiUrls.RepoCollaborators(owner, name), listCollaboratorRequest.ToParametersDictionary(), AcceptHeaders.OrganizationMembershipPreview, options); } /// @@ -76,13 +112,14 @@ public Task> GetAll(string owner, string name, ApiOptions op /// See the API documentation for more information. /// /// The id of the repository + /// Details to filter the request, such as by affiliation. /// Options for changing the API response /// Thrown when a general API error occurs. - public Task> GetAll(long repositoryId, ApiOptions options) + public Task> GetAll(long repositoryId, ListCollaboratorRequest listCollaboratorRequest, ApiOptions options) { Ensure.ArgumentNotNull(options, nameof(options)); - return ApiConnection.GetAll(ApiUrls.RepoCollaborators(repositoryId), options); + return ApiConnection.GetAll(ApiUrls.RepoCollaborators(repositoryId), listCollaboratorRequest.ToParametersDictionary(), AcceptHeaders.OrganizationMembershipPreview, options); } /// diff --git a/Octokit/Models/Request/Affiliation.cs b/Octokit/Models/Request/Affiliation.cs new file mode 100644 index 0000000000..9b35555453 --- /dev/null +++ b/Octokit/Models/Request/Affiliation.cs @@ -0,0 +1,27 @@ +using Octokit.Internal; + +namespace Octokit +{ + /// + /// Used to filter collaborators returned by their affiliation. + /// + public enum Affiliation + { + /// + /// All collaborators the authenticated user can see. + /// + [Parameter(Value = "all")] + All, + /// + /// All collaborators with permissions to an organization-owned repository, + /// regardless of organization membership status. + /// + [Parameter(Value = "direct")] + Direct, + /// + /// All outside collaborators of an organization-owned repository. + /// + [Parameter(Value = "outside")] + Outside + } +} diff --git a/Octokit/Models/Request/ListCollaboratorRequest.cs b/Octokit/Models/Request/ListCollaboratorRequest.cs new file mode 100644 index 0000000000..5425bd2ae5 --- /dev/null +++ b/Octokit/Models/Request/ListCollaboratorRequest.cs @@ -0,0 +1,23 @@ +using System.Diagnostics; +using Octokit.Internal; + +namespace Octokit +{ + /// + /// Filter collaborators returned by their affiliation. + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class ListCollaboratorRequest : RequestParameters + { + public ListCollaboratorRequest() + { + Affiliation = Affiliation.All; + } + + [Parameter(Key = "affiliation")] + public Affiliation Affiliation { get; set; } + + internal string DebuggerDisplay => $"Affiliation {Affiliation} "; + } + +} From 8e8f4afd0c338faa2441bf999749e669e5c17989 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Fri, 15 Mar 2019 23:48:12 +1000 Subject: [PATCH 04/18] Fix existing tests --- .../RepositoryCollaboratorClientTests.cs | 331 +++++++++--------- Octokit.Tests.Integration/Helper.cs | 12 +- ...rvableRepositoryCollaboratorClientTests.cs | 136 ++++--- .../Clients/RepoCollaboratorsClientTests.cs | 39 ++- .../ObservableRepoCollaboratorsClientTests.cs | 52 +-- Octokit.sln.DotSettings | 1 + 6 files changed, 313 insertions(+), 258 deletions(-) diff --git a/Octokit.Tests.Integration/Clients/RepositoryCollaboratorClientTests.cs b/Octokit.Tests.Integration/Clients/RepositoryCollaboratorClientTests.cs index 0859a81431..7394081a47 100644 --- a/Octokit.Tests.Integration/Clients/RepositoryCollaboratorClientTests.cs +++ b/Octokit.Tests.Integration/Clients/RepositoryCollaboratorClientTests.cs @@ -1,66 +1,78 @@ using System; +using System.Linq; using System.Threading.Tasks; using Octokit; +using Octokit.Tests.Clients; using Octokit.Tests.Integration; using Xunit; using Octokit.Tests.Integration.Helpers; public class RepositoryCollaboratorClientTests { + static async Task AcceptInvitation(IGitHubClient github, IGitHubClient github2, long repositoryId, string user) + { + var invitations = await github.Repository.Invitation.GetAllForRepository(repositoryId); + await github2.Repository.Invitation.Accept(invitations.First(i => i.Invitee.Login == user).Id); + } + public class TheGetAllMethod { - [IntegrationTest] - public async Task ReturnsAllCollaborators() + readonly IGitHubClient github; + readonly IRepoCollaboratorsClient client; + + readonly IGitHubClient github2; + + public TheGetAllMethod() { - var github = Helper.GetAuthenticatedClient(); - var repoName = Helper.MakeNameWithTimestamp("public-repo"); + github = Helper.GetAuthenticatedClient(); + client = github.Repository.Collaborator; - using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) + github2 = Helper.GetAuthenticatedClient(true); + } + + [DualAccountTest] + public async Task ReturnsAllCollaborators() + { + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext("public-repo")) { - var fixture = github.Repository.Collaborator; - // add a collaborator - await fixture.Add(context.RepositoryOwner, context.RepositoryName, "m-zuber-octokit-integration-tests"); + await client.Add(context.RepositoryOwner, context.RepositoryName, collaborator); + await AcceptInvitation(github, github2, context.RepositoryId, collaborator); - var collaborators = await fixture.GetAll(context.RepositoryOwner, context.RepositoryName); + var collaborators = await client.GetAll(context.RepositoryOwner, context.RepositoryName); Assert.NotNull(collaborators); Assert.Equal(2, collaborators.Count); Assert.NotNull(collaborators[0].Permissions); Assert.NotNull(collaborators[1].Permissions); } } - - [IntegrationTest] + + [DualAccountTest] public async Task ReturnsAllCollaboratorsWithRepositoryId() { - var github = Helper.GetAuthenticatedClient(); - var repoName = Helper.MakeNameWithTimestamp("public-repo"); - - using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext("public-repo")) { - var fixture = github.Repository.Collaborator; - // add a collaborator - await fixture.Add(context.Repository.Id, "m-zuber-octokit-integration-tests"); + await client.Add(context.Repository.Id, collaborator); + await AcceptInvitation(github, github2, context.Repository.Id, collaborator); - var collaborators = await fixture.GetAll(context.Repository.Id); + var collaborators = await client.GetAll(context.Repository.Id); Assert.NotNull(collaborators); Assert.Equal(2, collaborators.Count); } } - [IntegrationTest] + [DualAccountTest] public async Task ReturnsCorrectCountOfCollaboratorsWithoutStart() { - var github = Helper.GetAuthenticatedClient(); - var repoName = Helper.MakeNameWithTimestamp("public-repo"); - - using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext("public-repo")) { - var fixture = github.Repository.Collaborator; - // add some collaborators - await fixture.Add(context.RepositoryOwner, context.RepositoryName, "m-zuber-octokit-integration-tests"); + await client.Add(context.RepositoryOwner, context.RepositoryName, collaborator); + await AcceptInvitation(github, github2, context.RepositoryId, collaborator); var options = new ApiOptions { @@ -68,24 +80,21 @@ public async Task ReturnsCorrectCountOfCollaboratorsWithoutStart() PageCount = 1 }; - var collaborators = await fixture.GetAll(context.RepositoryOwner, context.RepositoryName, options); + var collaborators = await client.GetAll(context.RepositoryOwner, context.RepositoryName, new ListCollaboratorRequest(), options); Assert.NotNull(collaborators); Assert.Equal(1, collaborators.Count); } } - [IntegrationTest] + [DualAccountTest] public async Task ReturnsCorrectCountOfCollaboratorsWithoutStartAndRepositoryId() { - var github = Helper.GetAuthenticatedClient(); - var repoName = Helper.MakeNameWithTimestamp("public-repo"); - - using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext("public-repo")) { - var fixture = github.Repository.Collaborator; - // add some collaborators - await fixture.Add(context.Repository.Id, "m-zuber-octokit-integration-tests"); + await client.Add(context.Repository.Id, collaborator); + await AcceptInvitation(github, github2, context.Repository.Id, collaborator); var options = new ApiOptions { @@ -93,24 +102,21 @@ public async Task ReturnsCorrectCountOfCollaboratorsWithoutStartAndRepositoryId( PageCount = 1 }; - var collaborators = await fixture.GetAll(context.Repository.Id, options); + var collaborators = await client.GetAll(context.Repository.Id, new ListCollaboratorRequest(), options); Assert.NotNull(collaborators); Assert.Equal(1, collaborators.Count); } } - [IntegrationTest] + [DualAccountTest] public async Task ReturnsCorrectCountOfCollaboratorsWithStart() { - var github = Helper.GetAuthenticatedClient(); - var repoName = Helper.MakeNameWithTimestamp("public-repo"); - - using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext("public-repo")) { - var fixture = github.Repository.Collaborator; - // add some collaborators - await fixture.Add(context.RepositoryOwner, context.RepositoryName, "m-zuber-octokit-integration-tests"); + await client.Add(context.RepositoryOwner, context.RepositoryName, collaborator); + await AcceptInvitation(github, github2, context.RepositoryId, collaborator); var options = new ApiOptions { @@ -119,24 +125,21 @@ public async Task ReturnsCorrectCountOfCollaboratorsWithStart() StartPage = 2 }; - var collaborators = await fixture.GetAll(context.RepositoryOwner, context.RepositoryName, options); + var collaborators = await client.GetAll(context.RepositoryOwner, context.RepositoryName, new ListCollaboratorRequest(), options); Assert.NotNull(collaborators); Assert.Equal(1, collaborators.Count); } } - [IntegrationTest] + [DualAccountTest] public async Task ReturnsCorrectCountOfCollaboratorsWithStartAndRepositoryId() { - var github = Helper.GetAuthenticatedClient(); - var repoName = Helper.MakeNameWithTimestamp("public-repo"); - - using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext("public-repo")) { - var fixture = github.Repository.Collaborator; - // add some collaborators - await fixture.Add(context.Repository.Id, "m-zuber-octokit-integration-tests"); + await client.Add(context.Repository.Id, collaborator); + await AcceptInvitation(github, github2, context.Repository.Id, collaborator); var options = new ApiOptions { @@ -145,24 +148,21 @@ public async Task ReturnsCorrectCountOfCollaboratorsWithStartAndRepositoryId() StartPage = 2 }; - var collaborators = await fixture.GetAll(context.Repository.Id, options); + var collaborators = await client.GetAll(context.Repository.Id, new ListCollaboratorRequest(), options); Assert.NotNull(collaborators); Assert.Equal(1, collaborators.Count); } } - [IntegrationTest] + [DualAccountTest] public async Task ReturnsDistinctResultsBasedOnStartPage() { - var github = Helper.GetAuthenticatedClient(); - var repoName = Helper.MakeNameWithTimestamp("public-repo"); - - using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext("public-repo")) { - var fixture = github.Repository.Collaborator; - // add some collaborators - await fixture.Add(context.RepositoryOwner, context.RepositoryName, "m-zuber-octokit-integration-tests"); + await client.Add(context.RepositoryOwner, context.RepositoryName, collaborator); + await AcceptInvitation(github, github2, context.RepositoryId, collaborator); var startOptions = new ApiOptions { @@ -170,7 +170,7 @@ public async Task ReturnsDistinctResultsBasedOnStartPage() PageCount = 1 }; - var firstPage = await fixture.GetAll(context.RepositoryOwner, context.RepositoryName, startOptions); + var firstPage = await client.GetAll(context.RepositoryOwner, context.RepositoryName, new ListCollaboratorRequest(), startOptions); var skipStartOptions = new ApiOptions { @@ -179,24 +179,21 @@ public async Task ReturnsDistinctResultsBasedOnStartPage() StartPage = 2 }; - var secondPage = await fixture.GetAll(context.RepositoryOwner, context.RepositoryName, skipStartOptions); + var secondPage = await client.GetAll(context.RepositoryOwner, context.RepositoryName, new ListCollaboratorRequest(), skipStartOptions); Assert.NotEqual(firstPage[0].Id, secondPage[0].Id); } } - [IntegrationTest] + [DualAccountTest] public async Task ReturnsDistinctResultsBasedOnStartPageWithRepositoryId() { - var github = Helper.GetAuthenticatedClient(); - var repoName = Helper.MakeNameWithTimestamp("public-repo"); - - using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext("public-repo")) { - var fixture = github.Repository.Collaborator; - // add some collaborators - await fixture.Add(context.Repository.Id, "m-zuber-octokit-integration-tests"); + await client.Add(context.Repository.Id, collaborator); + await AcceptInvitation(github, github2, context.Repository.Id, collaborator); var startOptions = new ApiOptions { @@ -204,7 +201,7 @@ public async Task ReturnsDistinctResultsBasedOnStartPageWithRepositoryId() PageCount = 1 }; - var firstPage = await fixture.GetAll(context.Repository.Id, startOptions); + var firstPage = await client.GetAll(context.Repository.Id, new ListCollaboratorRequest(), startOptions); var skipStartOptions = new ApiOptions { @@ -213,48 +210,56 @@ public async Task ReturnsDistinctResultsBasedOnStartPageWithRepositoryId() StartPage = 2 }; - var secondPage = await fixture.GetAll(context.Repository.Id, skipStartOptions); + var secondPage = await client.GetAll(context.Repository.Id, new ListCollaboratorRequest(), skipStartOptions); Assert.NotEqual(firstPage[0].Id, secondPage[0].Id); } } + } public class TheIsCollaboratorMethod { - [IntegrationTest] - public async Task ReturnsTrueIfUserIsCollaborator() + readonly IGitHubClient github; + readonly IRepoCollaboratorsClient client; + + readonly IGitHubClient github2; + + public TheIsCollaboratorMethod() { - var github = Helper.GetAuthenticatedClient(); - var repoName = Helper.MakeNameWithTimestamp("public-repo"); + github = Helper.GetAuthenticatedClient(); + client = github.Repository.Collaborator; - using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) + github2 = Helper.GetAuthenticatedClient(true); + } + + [DualAccountTest] + public async Task ReturnsTrueIfUserIsCollaborator() + { + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext("public-repo")) { - var fixture = github.Repository.Collaborator; - // add a collaborator - await fixture.Add(context.RepositoryOwner, context.RepositoryName, "m-zuber-octokit-integration-tests"); + await client.Add(context.RepositoryOwner, context.RepositoryName, collaborator); + await AcceptInvitation(github, github2, context.RepositoryId, collaborator); - var isCollab = await fixture.IsCollaborator(context.RepositoryOwner, context.RepositoryName, "m-zuber-octokit-integration-tests"); + var isCollab = await client.IsCollaborator(context.RepositoryOwner, context.RepositoryName, collaborator); Assert.True(isCollab); } } - [IntegrationTest] + [DualAccountTest] public async Task ReturnsTrueIfUserIsCollaboratorWithRepositoryId() { - var github = Helper.GetAuthenticatedClient(); - var repoName = Helper.MakeNameWithTimestamp("public-repo"); - - using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext("public-repo")) { - var fixture = github.Repository.Collaborator; - // add a collaborator - await fixture.Add(context.Repository.Id, "m-zuber-octokit-integration-tests"); + await client.Add(context.Repository.Id, collaborator); + await AcceptInvitation(github, github2, context.Repository.Id, collaborator); - var isCollab = await fixture.IsCollaborator(context.Repository.Id, "m-zuber-octokit-integration-tests"); + var isCollab = await client.IsCollaborator(context.Repository.Id, collaborator); Assert.True(isCollab); } @@ -263,71 +268,68 @@ public async Task ReturnsTrueIfUserIsCollaboratorWithRepositoryId() public class TheReviewPermissionMethod { - [IntegrationTest] - public async Task ReturnsReadPermissionForNonCollaborator() + readonly IGitHubClient github; + readonly IRepoCollaboratorsClient client; + + readonly IGitHubClient github2; + + public TheReviewPermissionMethod() { - var github = Helper.GetAuthenticatedClient(); - var repoName = Helper.MakeNameWithTimestamp("public-repo"); + github = Helper.GetAuthenticatedClient(); + client = github.Repository.Collaborator; - using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) + github2 = Helper.GetAuthenticatedClient(true); + } + + [DualAccountTest] + public async Task ReturnsReadPermissionForNonCollaborator() + { + using (var context = await github.CreateRepositoryContext("public-repo")) { - var fixture = github.Repository.Collaborator; - - var permission = await fixture.ReviewPermission(context.RepositoryOwner, context.RepositoryName, "octokitnet-test1"); + var permission = await client.ReviewPermission(context.RepositoryOwner, context.RepositoryName, Helper.UserName2); Assert.Equal(PermissionLevel.Read, permission.Permission); } } - [IntegrationTest] + [DualAccountTest] public async Task ReturnsReadPermissionForNonCollaboratorWithRepositoryId() { - var github = Helper.GetAuthenticatedClient(); - var repoName = Helper.MakeNameWithTimestamp("public-repo"); - - using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) + using (var context = await github.CreateRepositoryContext("public-repo")) { - var fixture = github.Repository.Collaborator; - - var permission = await fixture.ReviewPermission(context.RepositoryId, "octokitnet-test1"); + var permission = await client.ReviewPermission(context.RepositoryId, Helper.UserName2); Assert.Equal(PermissionLevel.Read, permission.Permission); } } - [IntegrationTest] + [DualAccountTest] public async Task ReturnsWritePermissionForCollaborator() { - var github = Helper.GetAuthenticatedClient(); - var repoName = Helper.MakeNameWithTimestamp("public-repo"); - - using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext("public-repo")) { - var fixture = github.Repository.Collaborator; - // add a collaborator - await fixture.Add(context.RepositoryOwner, context.RepositoryName, "octokitnet-test1"); + await client.Add(context.RepositoryOwner, context.RepositoryName, collaborator); + await AcceptInvitation(github, github2, context.RepositoryId, collaborator); - var permission = await fixture.ReviewPermission(context.RepositoryOwner, context.RepositoryName, "octokitnet-test1"); + var permission = await client.ReviewPermission(context.RepositoryOwner, context.RepositoryName, collaborator); Assert.Equal(PermissionLevel.Write, permission.Permission); } } - [IntegrationTest] + [DualAccountTest] public async Task ReturnsWritePermissionForCollaboratorWithRepositoryId() { - var github = Helper.GetAuthenticatedClient(); - var repoName = Helper.MakeNameWithTimestamp("public-repo"); - - using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext("public-repo")) { - var fixture = github.Repository.Collaborator; - // add a collaborator - await fixture.Add(context.RepositoryOwner, context.RepositoryName, "octokitnet-test1"); + await client.Add(context.RepositoryOwner, context.RepositoryName, collaborator); + await AcceptInvitation(github, github2, context.Repository.Id, collaborator); - var permission = await fixture.ReviewPermission(context.RepositoryId, "octokitnet-test1"); + var permission = await client.ReviewPermission(context.RepositoryId, collaborator); Assert.Equal(PermissionLevel.Write, permission.Permission); } @@ -336,14 +338,9 @@ public async Task ReturnsWritePermissionForCollaboratorWithRepositoryId() [IntegrationTest] public async Task ReturnsAdminPermissionForOwner() { - var github = Helper.GetAuthenticatedClient(); - var repoName = Helper.MakeNameWithTimestamp("public-repo"); - - using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) + using (var context = await github.CreateRepositoryContext("public-repo")) { - var fixture = github.Repository.Collaborator; - - var permission = await fixture.ReviewPermission(context.RepositoryOwner, context.RepositoryName, context.RepositoryOwner); + var permission = await client.ReviewPermission(context.RepositoryOwner, context.RepositoryName, context.RepositoryOwner); Assert.Equal(PermissionLevel.Admin, permission.Permission); } @@ -352,14 +349,9 @@ public async Task ReturnsAdminPermissionForOwner() [IntegrationTest] public async Task ReturnsAdminPermissionForOwnerWithRepositoryId() { - var github = Helper.GetAuthenticatedClient(); - var repoName = Helper.MakeNameWithTimestamp("public-repo"); - - using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) + using (var context = await github.CreateRepositoryContext("public-repo")) { - var fixture = github.Repository.Collaborator; - - var permission = await fixture.ReviewPermission(context.RepositoryId, context.RepositoryOwner); + var permission = await client.ReviewPermission(context.RepositoryId, context.RepositoryOwner); Assert.Equal(PermissionLevel.Admin, permission.Permission); } @@ -368,7 +360,6 @@ public async Task ReturnsAdminPermissionForOwnerWithRepositoryId() [PaidAccountTest] public async Task ReturnsNonePermissionForPrivateRepository() { - var github = Helper.GetAuthenticatedClient(); var userDetails = await github.User.Current(); if (userDetails.Plan.PrivateRepos == 0) { @@ -378,9 +369,7 @@ public async Task ReturnsNonePermissionForPrivateRepository() var repoName = Helper.MakeNameWithTimestamp("private-repo"); using (var context = await github.CreateRepositoryContext(new NewRepository(repoName) { Private = true })) { - var fixture = github.Repository.Collaborator; - - var permission = await fixture.ReviewPermission(context.RepositoryOwner, context.RepositoryName, "octokitnet-test1"); + var permission = await client.ReviewPermission(context.RepositoryOwner, context.RepositoryName, "octokitnet-test1"); Assert.Equal(PermissionLevel.None, permission.Permission); } @@ -389,7 +378,6 @@ public async Task ReturnsNonePermissionForPrivateRepository() [PaidAccountTest] public async Task ReturnsNonePermissionForPrivateRepositoryWithRepositoryId() { - var github = Helper.GetAuthenticatedClient(); var userDetails = await github.User.Current(); if (userDetails.Plan.PrivateRepos == 0) { @@ -399,9 +387,7 @@ public async Task ReturnsNonePermissionForPrivateRepositoryWithRepositoryId() var repoName = Helper.MakeNameWithTimestamp("private-repo"); using (var context = await github.CreateRepositoryContext(new NewRepository(repoName) { Private = true })) { - var fixture = github.Repository.Collaborator; - - var permission = await fixture.ReviewPermission(context.RepositoryId, "octokitnet-test1"); + var permission = await client.ReviewPermission(context.RepositoryId, "octokitnet-test1"); Assert.Equal(PermissionLevel.None, permission.Permission); } @@ -410,45 +396,52 @@ public async Task ReturnsNonePermissionForPrivateRepositoryWithRepositoryId() public class TheDeleteMethod { - [IntegrationTest] - public async Task CheckDeleteMethod() + readonly IGitHubClient github; + readonly IRepoCollaboratorsClient client; + + readonly IGitHubClient github2; + + public TheDeleteMethod() { - var github = Helper.GetAuthenticatedClient(); - var repoName = Helper.MakeNameWithTimestamp("public-repo"); + github = Helper.GetAuthenticatedClient(); + client = github.Repository.Collaborator; - using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) + github2 = Helper.GetAuthenticatedClient(true); + } + + [DualAccountTest] + public async Task CheckDeleteMethod() + { + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext("public-repo")) { - var fixture = github.Repository.Collaborator; - // add a collaborator - await fixture.Add(context.RepositoryOwner, context.RepositoryName, "m-zuber-octokit-integration-tests"); + await client.Add(context.RepositoryOwner, context.RepositoryName, collaborator); + await AcceptInvitation(github, github2, context.RepositoryId, collaborator); // and remove - await fixture.Delete(context.RepositoryOwner, context.RepositoryName, "m-zuber-octokit-integration-tests"); + await client.Delete(context.RepositoryOwner, context.RepositoryName, collaborator); - var isCollab = await fixture.IsCollaborator(context.RepositoryOwner, context.RepositoryName, "m-zuber-octokit-integration-tests"); + var isCollab = await client.IsCollaborator(context.RepositoryOwner, context.RepositoryName, collaborator); Assert.False(isCollab); } } - [IntegrationTest] + [DualAccountTest] public async Task CheckDeleteMethodWithRepositoryId() { - var github = Helper.GetAuthenticatedClient(); - var repoName = Helper.MakeNameWithTimestamp("public-repo"); - - using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext("public-repo")) { - var fixture = github.Repository.Collaborator; - // add a collaborator - await fixture.Add(context.Repository.Id, "m-zuber-octokit-integration-tests"); + await client.Add(context.Repository.Id, collaborator); + await AcceptInvitation(github, github2, context.Repository.Id, collaborator); // and remove - await fixture.Delete(context.Repository.Id, "m-zuber-octokit-integration-tests"); + await client.Delete(context.Repository.Id, collaborator); - var isCollab = await fixture.IsCollaborator(context.Repository.Id, "m-zuber-octokit-integration-tests"); + var isCollab = await client.IsCollaborator(context.Repository.Id, collaborator); Assert.False(isCollab); } diff --git a/Octokit.Tests.Integration/Helper.cs b/Octokit.Tests.Integration/Helper.cs index f005e0ffb9..482dbcd663 100644 --- a/Octokit.Tests.Integration/Helper.cs +++ b/Octokit.Tests.Integration/Helper.cs @@ -29,10 +29,17 @@ public static class Helper return new Credentials(githubUsername, githubPassword); }); - static readonly Lazy _credentialsSecondUserThunk = new Lazy(() => + private static readonly Lazy _credentialsSecondUserThunk = new Lazy(() => { var githubUsername = Environment.GetEnvironmentVariable("OCTOKIT_GITHUBUSERNAME_2"); - + UserName2 = githubUsername; + + var githubToken = Environment.GetEnvironmentVariable("OCTOKIT_OAUTHTOKEN_2"); + if (githubToken != null) + { + return new Credentials(githubToken); + } + var githubPassword = Environment.GetEnvironmentVariable("OCTOKIT_GITHUBPASSWORD_2"); if (githubUsername == null || githubPassword == null) @@ -113,6 +120,7 @@ static Helper() } public static string UserName { get; private set; } + public static string UserName2 { get; private set; } public static string Organization { get; private set; } /// diff --git a/Octokit.Tests.Integration/Reactive/ObservableRepositoryCollaboratorClientTests.cs b/Octokit.Tests.Integration/Reactive/ObservableRepositoryCollaboratorClientTests.cs index 363e7465a8..0d3570e836 100644 --- a/Octokit.Tests.Integration/Reactive/ObservableRepositoryCollaboratorClientTests.cs +++ b/Octokit.Tests.Integration/Reactive/ObservableRepositoryCollaboratorClientTests.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Reactive.Linq; using System.Threading.Tasks; using Octokit; @@ -9,22 +10,38 @@ public class ObservableRepositoryCollaboratorClientTests { + static async Task AcceptInvitation(IGitHubClient github, IGitHubClient github2, long repositoryId, string user) + { + var invitations = await github.Repository.Invitation.GetAllForRepository(repositoryId); + await github2.Repository.Invitation.Accept(invitations.First(i => i.Invitee.Login == user).Id); + } + public class TheGetAllMethod { - [IntegrationTest] - public async Task ReturnsAllCollaborators() + readonly IGitHubClient github; + readonly IObservableRepoCollaboratorsClient client; + + readonly IGitHubClient github2; + + public TheGetAllMethod() { - var github = Helper.GetAuthenticatedClient(); - var repoName = Helper.MakeNameWithTimestamp("public-repo"); + github = Helper.GetAuthenticatedClient(); + client = new ObservableRepoCollaboratorsClient(github); - using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) - { - var fixture = new ObservableRepoCollaboratorsClient(github); + github2 = Helper.GetAuthenticatedClient(true); + } + [DualAccountTest] + public async Task ReturnsAllCollaborators() + { + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext("public-repo")) + { // add a collaborator - await fixture.Add(context.RepositoryOwner, context.RepositoryName, "m-zuber-octokit-integration-tests"); + await client.Add(context.RepositoryOwner, context.RepositoryName, collaborator); + await AcceptInvitation(github, github2, context.RepositoryId, collaborator); - var collaborators = await fixture.GetAll(context.RepositoryOwner, context.RepositoryName).ToList(); + var collaborators = await client.GetAll(context.RepositoryOwner, context.RepositoryName).ToList(); Assert.NotNull(collaborators); Assert.Equal(2, collaborators.Count); Assert.NotNull(collaborators[0].Permissions); @@ -32,18 +49,15 @@ public async Task ReturnsAllCollaborators() } } - [IntegrationTest] + [DualAccountTest] public async Task ReturnsCorrectCountOfCollaboratorsWithoutStart() { - var github = Helper.GetAuthenticatedClient(); - var repoName = Helper.MakeNameWithTimestamp("public-repo"); - - using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext("public-repo")) { - var fixture = new ObservableRepoCollaboratorsClient(github); - // add some collaborators - await fixture.Add(context.RepositoryOwner, context.RepositoryName, "m-zuber-octokit-integration-tests"); + await client.Add(context.RepositoryOwner, context.RepositoryName, collaborator); + await AcceptInvitation(github, github2, context.RepositoryId, collaborator); var options = new ApiOptions { @@ -51,24 +65,21 @@ public async Task ReturnsCorrectCountOfCollaboratorsWithoutStart() PageCount = 1 }; - var collaborators = await fixture.GetAll(context.RepositoryOwner, context.RepositoryName, options).ToList(); + var collaborators = await client.GetAll(context.RepositoryOwner, context.RepositoryName, new ListCollaboratorRequest(), options).ToList(); Assert.NotNull(collaborators); Assert.Equal(1, collaborators.Count); } } - [IntegrationTest] + [DualAccountTest] public async Task ReturnsCorrectCountOfCollaboratorsWithStart() { - var github = Helper.GetAuthenticatedClient(); - var repoName = Helper.MakeNameWithTimestamp("public-repo"); - - using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext("public-repo")) { - var fixture = new ObservableRepoCollaboratorsClient(github); - // add some collaborators - await fixture.Add(context.RepositoryOwner, context.RepositoryName, "m-zuber-octokit-integration-tests"); + await client.Add(context.RepositoryOwner, context.RepositoryName, collaborator); + await AcceptInvitation(github, github2, context.RepositoryId, collaborator); var options = new ApiOptions { @@ -77,24 +88,21 @@ public async Task ReturnsCorrectCountOfCollaboratorsWithStart() StartPage = 2 }; - var collaborators = await fixture.GetAll(context.RepositoryOwner, context.RepositoryName, options).ToList(); + var collaborators = await client.GetAll(context.RepositoryOwner, context.RepositoryName, new ListCollaboratorRequest(), options).ToList(); Assert.NotNull(collaborators); Assert.Equal(1, collaborators.Count); } } - [IntegrationTest] + [DualAccountTest] public async Task ReturnsDistinctResultsBasedOnStartPage() { - var github = Helper.GetAuthenticatedClient(); - var repoName = Helper.MakeNameWithTimestamp("public-repo"); - - using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext("public-repo")) { - var fixture = new ObservableRepoCollaboratorsClient(github); - // add some collaborators - await fixture.Add(context.RepositoryOwner, context.RepositoryName, "m-zuber-octokit-integration-tests"); + await client.Add(context.RepositoryOwner, context.RepositoryName, collaborator); + await AcceptInvitation(github, github2, context.RepositoryId, collaborator); var startOptions = new ApiOptions { @@ -102,7 +110,7 @@ public async Task ReturnsDistinctResultsBasedOnStartPage() PageCount = 1 }; - var firstPage = await fixture.GetAll(context.RepositoryOwner, context.RepositoryName, startOptions).ToList(); + var firstPage = await client.GetAll(context.RepositoryOwner, context.RepositoryName, new ListCollaboratorRequest(), startOptions).ToList(); var skipStartOptions = new ApiOptions { @@ -111,7 +119,7 @@ public async Task ReturnsDistinctResultsBasedOnStartPage() StartPage = 2 }; - var secondPage = await fixture.GetAll(context.RepositoryOwner, context.RepositoryName, skipStartOptions).ToList(); + var secondPage = await client.GetAll(context.RepositoryOwner, context.RepositoryName, new ListCollaboratorRequest(), skipStartOptions).ToList(); Assert.NotEqual(firstPage[0].Id, secondPage[0].Id); } @@ -120,20 +128,30 @@ public async Task ReturnsDistinctResultsBasedOnStartPage() public class TheIsCollaboratorMethod { - [IntegrationTest] - public async Task ReturnsTrueIfUserIsCollaborator() + readonly IGitHubClient github; + readonly IObservableRepoCollaboratorsClient client; + + readonly IGitHubClient github2; + + public TheIsCollaboratorMethod() { - var github = Helper.GetAuthenticatedClient(); - var repoName = Helper.MakeNameWithTimestamp("public-repo"); + github = Helper.GetAuthenticatedClient(); + client = new ObservableRepoCollaboratorsClient(github); - using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) - { - var fixture = new ObservableRepoCollaboratorsClient(github); + github2 = Helper.GetAuthenticatedClient(true); + } + [DualAccountTest] + public async Task ReturnsTrueIfUserIsCollaborator() + { + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext("public-repo")) + { // add a collaborator - fixture.Add(context.RepositoryOwner, context.RepositoryName, "m-zuber-octokit-integration-tests"); + client.Add(context.RepositoryOwner, context.RepositoryName, collaborator); + await AcceptInvitation(github, github2, context.RepositoryId, collaborator); - var isCollab = await fixture.IsCollaborator(context.RepositoryOwner, context.RepositoryName, "m-zuber-octokit-integration-tests"); + var isCollab = await client.IsCollaborator(context.RepositoryOwner, context.RepositoryName, collaborator); Assert.True(isCollab); } @@ -150,7 +168,7 @@ public async Task ReturnsReadPermissionForNonCollaborator() using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) { var fixture = new ObservableRepoCollaboratorsClient(github); - + var permission = await fixture.ReviewPermission(context.RepositoryOwner, context.RepositoryName, "octokitnet-test1"); Assert.Equal(PermissionLevel.Read, permission.Permission); @@ -173,39 +191,47 @@ public async Task ReturnsReadPermissionForNonCollaboratorWithRepositoryId() } } - [IntegrationTest] + [DualAccountTest] public async Task ReturnsWritePermissionForCollaborator() { var github = Helper.GetAuthenticatedClient(); var repoName = Helper.MakeNameWithTimestamp("public-repo"); + var github2 = Helper.GetAuthenticatedClient(true); + + var collaborator = Helper.UserName2; using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) { var fixture = new ObservableRepoCollaboratorsClient(github); - + // add a collaborator - await fixture.Add(context.RepositoryOwner, context.RepositoryName, "octokitnet-test1"); + await fixture.Add(context.RepositoryOwner, context.RepositoryName, collaborator); + await AcceptInvitation(github, github2, context.RepositoryId, collaborator); - var permission = await fixture.ReviewPermission(context.RepositoryOwner, context.RepositoryName, "octokitnet-test1"); + var permission = await fixture.ReviewPermission(context.RepositoryOwner, context.RepositoryName, collaborator); Assert.Equal(PermissionLevel.Write, permission.Permission); } } - [IntegrationTest] + [DualAccountTest] public async Task ReturnsWritePermissionForCollaboratorWithRepositoryId() { var github = Helper.GetAuthenticatedClient(); var repoName = Helper.MakeNameWithTimestamp("public-repo"); + var github2 = Helper.GetAuthenticatedClient(true); + + var collaborator = Helper.UserName2; using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) { var fixture = new ObservableRepoCollaboratorsClient(github); - + // add a collaborator - await fixture.Add(context.RepositoryOwner, context.RepositoryName, "octokitnet-test1"); + await fixture.Add(context.RepositoryOwner, context.RepositoryName, collaborator); + await AcceptInvitation(github, github2, context.RepositoryId, collaborator); - var permission = await fixture.ReviewPermission(context.RepositoryId, "octokitnet-test1"); + var permission = await fixture.ReviewPermission(context.RepositoryId, collaborator); Assert.Equal(PermissionLevel.Write, permission.Permission); } diff --git a/Octokit.Tests/Clients/RepoCollaboratorsClientTests.cs b/Octokit.Tests/Clients/RepoCollaboratorsClientTests.cs index edd87c8944..39fd13664c 100644 --- a/Octokit.Tests/Clients/RepoCollaboratorsClientTests.cs +++ b/Octokit.Tests/Clients/RepoCollaboratorsClientTests.cs @@ -33,7 +33,11 @@ public void RequestsCorrectUrl() client.GetAll("owner", "test"); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/owner/test/collaborators"), Args.ApiOptions); + connection.Received().GetAll( + Arg.Is(u => u.ToString() == "repos/owner/test/collaborators"), + Arg.Is>(d => d["affiliation"] == "all"), + "application/vnd.github.korra-preview+json", + Args.ApiOptions); } [Fact] @@ -44,7 +48,11 @@ public void RequestsCorrectUrlWithRepositoryId() client.GetAll(1); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "repositories/1/collaborators"), Args.ApiOptions); + connection.Received().GetAll( + Arg.Is(u => u.ToString() == "repositories/1/collaborators"), + Arg.Is>(d => d["affiliation"] == "all"), + "application/vnd.github.korra-preview+json", + Args.ApiOptions); } [Fact] @@ -60,10 +68,14 @@ public void RequestsCorrectUrlWithApiOptions() StartPage = 1 }; - client.GetAll("owner", "test", options); + client.GetAll("owner", "test", new ListCollaboratorRequest(), options); connection.Received() - .GetAll(Arg.Is(u => u.ToString() == "repos/owner/test/collaborators"), options); + .GetAll( + Arg.Is(u => u.ToString() == "repos/owner/test/collaborators"), + Arg.Is>(d => d["affiliation"] == "all"), + "application/vnd.github.korra-preview+json", + options); } [Fact] @@ -79,10 +91,14 @@ public void RequestsCorrectUrlWithApiOptionsAndRepositoryId() StartPage = 1 }; - client.GetAll(1, options); + client.GetAll(1, new ListCollaboratorRequest(), options); connection.Received() - .GetAll(Arg.Is(u => u.ToString() == "repositories/1/collaborators"), options); + .GetAll( + Arg.Is(u => u.ToString() == "repositories/1/collaborators"), + Arg.Is>(d => d["affiliation"] == "all"), + "application/vnd.github.korra-preview+json", + options); } [Fact] @@ -95,11 +111,13 @@ public async Task EnsuresNonNullArguments() await Assert.ThrowsAsync(() => client.GetAll("owner", null)); await Assert.ThrowsAsync(() => client.GetAll("owner", "")); - await Assert.ThrowsAsync(() => client.GetAll(null, "test", ApiOptions.None)); - await Assert.ThrowsAsync(() => client.GetAll("owner", null, ApiOptions.None)); - await Assert.ThrowsAsync(() => client.GetAll("owner", "test", null)); + await Assert.ThrowsAsync(() => client.GetAll(null, "test", new ListCollaboratorRequest(), ApiOptions.None)); + await Assert.ThrowsAsync(() => client.GetAll("owner", null, new ListCollaboratorRequest(), ApiOptions.None)); + await Assert.ThrowsAsync(() => client.GetAll("owner", "name", null, ApiOptions.None)); + await Assert.ThrowsAsync(() => client.GetAll("owner", "test", new ListCollaboratorRequest(), null)); await Assert.ThrowsAsync(() => client.GetAll(1, null)); + await Assert.ThrowsAsync(() => client.GetAll(1, new ListCollaboratorRequest(), null)); } } @@ -360,7 +378,8 @@ public async Task EnsuresNonNullArguments() await Assert.ThrowsAsync(() => client.Delete("owner", "test", null)); await Assert.ThrowsAsync(() => client.Delete(1, null)); - await Assert.ThrowsAsync(() => client.Delete("", "test", "user1")); ; + await Assert.ThrowsAsync(() => client.Delete("", "test", "user1")); + ; await Assert.ThrowsAsync(() => client.Delete("owner", "", "user1")); await Assert.ThrowsAsync(() => client.Delete("owner", "test", "")); await Assert.ThrowsAsync(() => client.Delete(1, "")); diff --git a/Octokit.Tests/Reactive/ObservableRepoCollaboratorsClientTests.cs b/Octokit.Tests/Reactive/ObservableRepoCollaboratorsClientTests.cs index 57d2231981..4d8e2a2add 100644 --- a/Octokit.Tests/Reactive/ObservableRepoCollaboratorsClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableRepoCollaboratorsClientTests.cs @@ -40,14 +40,18 @@ public void EnsuresNonNullArguments() Assert.Throws(() => _client.GetAll(null, name)); Assert.Throws(() => _client.GetAll(owner, null)); Assert.Throws(() => _client.GetAll(owner, name, null)); + Assert.Throws(() => _client.GetAll(owner, name, new ListCollaboratorRequest(), null)); Assert.Throws(() => _client.GetAll(repositoryId, null)); + Assert.Throws(() => _client.GetAll(repositoryId, new ListCollaboratorRequest(), null)); } [Fact] public void EnsuresNonEmptyArguments() { Assert.Throws(() => _client.GetAll("", name)); + Assert.Throws(() => _client.GetAll("", name, new ListCollaboratorRequest())); Assert.Throws(() => _client.GetAll(owner, "")); + Assert.Throws(() => _client.GetAll(owner, "", new ListCollaboratorRequest())); } [Fact] @@ -57,6 +61,10 @@ await AssertEx.ThrowsWhenGivenWhitespaceArgument( async whitespace => await _client.GetAll(whitespace, name)); await AssertEx.ThrowsWhenGivenWhitespaceArgument( async whitespace => await _client.GetAll(owner, whitespace)); + await AssertEx.ThrowsWhenGivenWhitespaceArgument( + async whitespace => await _client.GetAll(whitespace, name, new ListCollaboratorRequest())); + await AssertEx.ThrowsWhenGivenWhitespaceArgument( + async whitespace => await _client.GetAll(owner, whitespace, new ListCollaboratorRequest())); } [Fact] @@ -67,8 +75,8 @@ public void RequestsCorrectUrl() _client.GetAll(owner, name); _githubClient.Connection.Received(1) .Get>(Arg.Is(u => u.ToString() == expectedUrl), - Arg.Is>(dictionary => dictionary.Count == 0), - Arg.Any()); + Arg.Is>(dictionary => dictionary["affiliation"] == "all"), + "application/vnd.github.korra-preview+json"); } [Fact] @@ -79,8 +87,8 @@ public void RequestsCorrectUrlWithRepositoryId() _client.GetAll(repositoryId); _githubClient.Connection.Received(1) .Get>(Arg.Is(u => u.ToString() == expectedUrl), - Arg.Is>(dictionary => dictionary.Count == 0), - Arg.Any()); + Arg.Is>(dictionary => dictionary["affiliation"] == "all"), + "application/vnd.github.korra-preview+json"); } [Fact] @@ -96,11 +104,11 @@ public void RequestsCorrectUrlWithApiOptions() PageSize = 1 }; - _client.GetAll(owner, name, options); + _client.GetAll(owner, name, new ListCollaboratorRequest(), options); _githubClient.Connection.Received(1) .Get>(Arg.Is(u => u.ToString() == expectedUrl), - Arg.Is>(dictionary => dictionary.Count == 2), - null); + Arg.Is>(dictionary => dictionary.Count == 3 && dictionary["affiliation"] == "all"), + "application/vnd.github.korra-preview+json"); // StartPage is setted => only 1 option (StartPage) in dictionary options = new ApiOptions @@ -108,11 +116,11 @@ public void RequestsCorrectUrlWithApiOptions() StartPage = 1 }; - _client.GetAll(owner, name, options); + _client.GetAll(owner, name, new ListCollaboratorRequest(), options); _githubClient.Connection.Received(1) .Get>(Arg.Is(u => u.ToString() == expectedUrl), - Arg.Is>(dictionary => dictionary.Count == 1), - null); + Arg.Is>(dictionary => dictionary.Count == 2 && dictionary["affiliation"] == "all"), + "application/vnd.github.korra-preview+json"); // PageCount is setted => none of options in dictionary options = new ApiOptions @@ -120,11 +128,11 @@ public void RequestsCorrectUrlWithApiOptions() PageCount = 1 }; - _client.GetAll(owner, name, options); + _client.GetAll(owner, name, new ListCollaboratorRequest(), options); _githubClient.Connection.Received(1) .Get>(Arg.Is(u => u.ToString() == expectedUrl), - Arg.Is>(dictionary => dictionary.Count == 0), - null); + Arg.Is>(dictionary => dictionary.Count == 1 && dictionary["affiliation"] == "all"), + "application/vnd.github.korra-preview+json"); } [Fact] @@ -140,11 +148,11 @@ public void RequestsCorrectUrlWithApiOptionsAndRepositoryId() PageSize = 1 }; - _client.GetAll(repositoryId, options); + _client.GetAll(repositoryId, new ListCollaboratorRequest(), options); _githubClient.Connection.Received(1) .Get>(Arg.Is(u => u.ToString() == expectedUrl), - Arg.Is>(dictionary => dictionary.Count == 2), - null); + Arg.Is>(dictionary => dictionary.Count == 3 && dictionary["affiliation"] == "all"), + "application/vnd.github.korra-preview+json"); // StartPage is setted => only 1 option (StartPage) in dictionary options = new ApiOptions @@ -152,11 +160,11 @@ public void RequestsCorrectUrlWithApiOptionsAndRepositoryId() StartPage = 1 }; - _client.GetAll(repositoryId, options); + _client.GetAll(repositoryId, new ListCollaboratorRequest(), options); _githubClient.Connection.Received(1) .Get>(Arg.Is(u => u.ToString() == expectedUrl), - Arg.Is>(dictionary => dictionary.Count == 1), - null); + Arg.Is>(dictionary => dictionary.Count == 2 && dictionary["affiliation"] == "all"), + "application/vnd.github.korra-preview+json"); // PageCount is setted => none of options in dictionary options = new ApiOptions @@ -164,11 +172,11 @@ public void RequestsCorrectUrlWithApiOptionsAndRepositoryId() PageCount = 1 }; - _client.GetAll(repositoryId, options); + _client.GetAll(repositoryId, new ListCollaboratorRequest(), options); _githubClient.Connection.Received(1) .Get>(Arg.Is(u => u.ToString() == expectedUrl), - Arg.Is>(dictionary => dictionary.Count == 0), - null); + Arg.Is>(dictionary => dictionary.Count == 1 && dictionary["affiliation"] == "all"), + "application/vnd.github.korra-preview+json"); } } diff --git a/Octokit.sln.DotSettings b/Octokit.sln.DotSettings index 50852c97ec..7f9262b459 100644 --- a/Octokit.sln.DotSettings +++ b/Octokit.sln.DotSettings @@ -269,6 +269,7 @@ II.2.12 <HandlesEvent /> True True True + True True True True From a28f420ee111969a04427f1c432931ddda385bf5 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Sat, 16 Mar 2019 01:35:36 +1000 Subject: [PATCH 05/18] Missed null check --- Octokit/Clients/RepoCollaboratorsClient.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Octokit/Clients/RepoCollaboratorsClient.cs b/Octokit/Clients/RepoCollaboratorsClient.cs index 9f5e3a4c47..f7b0fa041b 100644 --- a/Octokit/Clients/RepoCollaboratorsClient.cs +++ b/Octokit/Clients/RepoCollaboratorsClient.cs @@ -100,6 +100,7 @@ public Task> GetAll(string owner, string name, ListCollabora { Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); Ensure.ArgumentNotNullOrEmptyString(name, nameof(name)); + Ensure.ArgumentNotNull(listCollaboratorRequest, nameof(listCollaboratorRequest)); Ensure.ArgumentNotNull(options, nameof(options)); return ApiConnection.GetAll(ApiUrls.RepoCollaborators(owner, name), listCollaboratorRequest.ToParametersDictionary(), AcceptHeaders.OrganizationMembershipPreview, options); From 895cc43fe77d63ae0ca7e919d5f549ae4109cfaa Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Sat, 16 Mar 2019 01:56:13 +1000 Subject: [PATCH 06/18] Add missing ApiOption overloads --- Octokit/Clients/IRepoCollaboratorsClient.cs | 23 +++++++++++++ Octokit/Clients/RepoCollaboratorsClient.cs | 36 +++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/Octokit/Clients/IRepoCollaboratorsClient.cs b/Octokit/Clients/IRepoCollaboratorsClient.cs index 3571d785c0..3effd2ac30 100644 --- a/Octokit/Clients/IRepoCollaboratorsClient.cs +++ b/Octokit/Clients/IRepoCollaboratorsClient.cs @@ -34,6 +34,18 @@ public interface IRepoCollaboratorsClient /// Thrown when a general API error occurs. Task> GetAll(string owner, string name, ListCollaboratorRequest listCollaboratorRequest); + /// + /// Gets all the collaborators on a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The owner of the repository + /// The name of the repository + /// Options for changing the API response + /// Thrown when a general API error occurs. + Task> GetAll(string owner, string name, ApiOptions options); + /// /// Gets all the collaborators on a repository. /// @@ -55,6 +67,17 @@ public interface IRepoCollaboratorsClient /// Thrown when a general API error occurs. Task> GetAll(long repositoryId, ListCollaboratorRequest listCollaboratorRequest); + /// + /// Gets all the collaborators on a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The id of the repository + /// Options for changing the API response + /// Thrown when a general API error occurs. + Task> GetAll(long repositoryId, ApiOptions options); + /// /// Gets all the collaborators on a repository. /// diff --git a/Octokit/Clients/RepoCollaboratorsClient.cs b/Octokit/Clients/RepoCollaboratorsClient.cs index f7b0fa041b..d5b5c62d23 100644 --- a/Octokit/Clients/RepoCollaboratorsClient.cs +++ b/Octokit/Clients/RepoCollaboratorsClient.cs @@ -56,6 +56,25 @@ public Task> GetAll(string owner, string name, ListCollabora return GetAll(owner, name, listCollaboratorRequest, ApiOptions.None); } + /// + /// Gets all the collaborators on a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The owner of the repository + /// The name of the repository + /// Options for changing the API response + /// Thrown when a general API error occurs. + public Task> GetAll(string owner, string name, ApiOptions options) + { + Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); + Ensure.ArgumentNotNullOrEmptyString(name, nameof(name)); + Ensure.ArgumentNotNull(options, nameof(options)); + + return GetAll(owner, name, new ListCollaboratorRequest(), options); + } + /// /// Gets all the collaborators on a repository. /// @@ -85,6 +104,22 @@ public Task> GetAll(long repositoryId, ListCollaboratorReque return GetAll(repositoryId, listCollaboratorRequest, ApiOptions.None); } + /// + /// Gets all the collaborators on a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The id of the repository + /// Options for changing the API response + /// Thrown when a general API error occurs. + public Task> GetAll(long repositoryId, ApiOptions options) + { + Ensure.ArgumentNotNull(options, nameof(options)); + + return GetAll(repositoryId, new ListCollaboratorRequest(), options); + } + /// /// Gets all the collaborators on a repository. /// @@ -118,6 +153,7 @@ public Task> GetAll(string owner, string name, ListCollabora /// Thrown when a general API error occurs. public Task> GetAll(long repositoryId, ListCollaboratorRequest listCollaboratorRequest, ApiOptions options) { + Ensure.ArgumentNotNull(listCollaboratorRequest, nameof(listCollaboratorRequest)); Ensure.ArgumentNotNull(options, nameof(options)); return ApiConnection.GetAll(ApiUrls.RepoCollaborators(repositoryId), listCollaboratorRequest.ToParametersDictionary(), AcceptHeaders.OrganizationMembershipPreview, options); From f92bf8c801d4323029e0a70baebd94341885389b Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Sat, 16 Mar 2019 01:56:40 +1000 Subject: [PATCH 07/18] Fix failing tests --- Octokit.Tests/Clients/RepoCollaboratorsClientTests.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Octokit.Tests/Clients/RepoCollaboratorsClientTests.cs b/Octokit.Tests/Clients/RepoCollaboratorsClientTests.cs index 39fd13664c..7154582e00 100644 --- a/Octokit.Tests/Clients/RepoCollaboratorsClientTests.cs +++ b/Octokit.Tests/Clients/RepoCollaboratorsClientTests.cs @@ -116,7 +116,9 @@ public async Task EnsuresNonNullArguments() await Assert.ThrowsAsync(() => client.GetAll("owner", "name", null, ApiOptions.None)); await Assert.ThrowsAsync(() => client.GetAll("owner", "test", new ListCollaboratorRequest(), null)); - await Assert.ThrowsAsync(() => client.GetAll(1, null)); + await Assert.ThrowsAsync(() => client.GetAll(1, listCollaboratorRequest: null)); + await Assert.ThrowsAsync(() => client.GetAll(1, options: null)); + await Assert.ThrowsAsync(() => client.GetAll(1, null, ApiOptions.None)); await Assert.ThrowsAsync(() => client.GetAll(1, new ListCollaboratorRequest(), null)); } } From b5d3dc75d3a44c15df1299ac021caa4fbbc55e9b Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Sat, 16 Mar 2019 02:09:31 +1000 Subject: [PATCH 08/18] Add missing observable methods and fix tests --- .../IObservableRepoCollaboratorsClient.cs | 23 ++++++++++++ .../ObservableRepoCollaboratorsClient.cs | 35 +++++++++++++++++++ .../ObservableRepoCollaboratorsClientTests.cs | 4 +-- 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/Octokit.Reactive/Clients/IObservableRepoCollaboratorsClient.cs b/Octokit.Reactive/Clients/IObservableRepoCollaboratorsClient.cs index 8e3287b78e..3e9724b1ef 100644 --- a/Octokit.Reactive/Clients/IObservableRepoCollaboratorsClient.cs +++ b/Octokit.Reactive/Clients/IObservableRepoCollaboratorsClient.cs @@ -34,6 +34,18 @@ public interface IObservableRepoCollaboratorsClient /// Thrown when a general API error occurs. IObservable GetAll(string owner, string name, ListCollaboratorRequest listCollaboratorRequest); + /// + /// Gets all the collaborators on a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The owner of the repository + /// The name of the repository + /// Options for changing the API response + /// Thrown when a general API error occurs. + IObservable GetAll(string owner, string name, ApiOptions options); + /// /// Gets all the collaborators on a repository. /// @@ -55,6 +67,17 @@ public interface IObservableRepoCollaboratorsClient /// Thrown when a general API error occurs. IObservable GetAll(long repositoryId, ListCollaboratorRequest listCollaboratorRequest); + /// + /// Gets all the collaborators on a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The id of the repository + /// Options for changing the API response + /// Thrown when a general API error occurs. + IObservable GetAll(long repositoryId, ApiOptions options); + /// /// Gets all the collaborators on a repository. /// diff --git a/Octokit.Reactive/Clients/ObservableRepoCollaboratorsClient.cs b/Octokit.Reactive/Clients/ObservableRepoCollaboratorsClient.cs index 39d1269369..77e7747e07 100644 --- a/Octokit.Reactive/Clients/ObservableRepoCollaboratorsClient.cs +++ b/Octokit.Reactive/Clients/ObservableRepoCollaboratorsClient.cs @@ -64,6 +64,25 @@ public IObservable GetAll(string owner, string name, ListCollaboratorReque return GetAll(owner, name, listCollaboratorRequest, ApiOptions.None); } + /// + /// Gets all the collaborators on a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The owner of the repository + /// The name of the repository + /// Options for changing the API response + /// Thrown when a general API error occurs. + public IObservable GetAll(string owner, string name, ApiOptions options) + { + Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); + Ensure.ArgumentNotNullOrEmptyString(name, nameof(name)); + Ensure.ArgumentNotNull(options, nameof(options)); + + return GetAll(owner, name, new ListCollaboratorRequest(), options); + } + /// /// Gets all the collaborators on a repository. /// @@ -93,6 +112,22 @@ public IObservable GetAll(long repositoryId, ListCollaboratorRequest listC return GetAll(repositoryId, listCollaboratorRequest, ApiOptions.None); } + /// + /// Gets all the collaborators on a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The id of the repository + /// Options for changing the API response + /// Thrown when a general API error occurs. + public IObservable GetAll(long repositoryId, ApiOptions options) + { + Ensure.ArgumentNotNull(options, nameof(options)); + + return GetAll(repositoryId, new ListCollaboratorRequest(), options); + } + /// /// Gets all the collaborators on a repository. /// diff --git a/Octokit.Tests/Reactive/ObservableRepoCollaboratorsClientTests.cs b/Octokit.Tests/Reactive/ObservableRepoCollaboratorsClientTests.cs index 4d8e2a2add..2d1a4263b1 100644 --- a/Octokit.Tests/Reactive/ObservableRepoCollaboratorsClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableRepoCollaboratorsClientTests.cs @@ -39,9 +39,9 @@ public void EnsuresNonNullArguments() { Assert.Throws(() => _client.GetAll(null, name)); Assert.Throws(() => _client.GetAll(owner, null)); - Assert.Throws(() => _client.GetAll(owner, name, null)); + Assert.Throws(() => _client.GetAll(owner, name, null, ApiOptions.None)); Assert.Throws(() => _client.GetAll(owner, name, new ListCollaboratorRequest(), null)); - Assert.Throws(() => _client.GetAll(repositoryId, null)); + Assert.Throws(() => _client.GetAll(repositoryId, null, ApiOptions.None)); Assert.Throws(() => _client.GetAll(repositoryId, new ListCollaboratorRequest(), null)); } From 40d11f654d3dda170c54605c152172be87ade848 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Sat, 16 Mar 2019 02:15:38 +1000 Subject: [PATCH 09/18] More null checks that were missed --- Octokit.Reactive/Clients/ObservableRepoCollaboratorsClient.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Octokit.Reactive/Clients/ObservableRepoCollaboratorsClient.cs b/Octokit.Reactive/Clients/ObservableRepoCollaboratorsClient.cs index 77e7747e07..2890a7e954 100644 --- a/Octokit.Reactive/Clients/ObservableRepoCollaboratorsClient.cs +++ b/Octokit.Reactive/Clients/ObservableRepoCollaboratorsClient.cs @@ -143,6 +143,7 @@ public IObservable GetAll(string owner, string name, ListCollaboratorReque { Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); Ensure.ArgumentNotNullOrEmptyString(name, nameof(name)); + Ensure.ArgumentNotNull(listCollaboratorRequest, nameof(listCollaboratorRequest)); Ensure.ArgumentNotNull(options, nameof(options)); return _connection.GetAndFlattenAllPages(ApiUrls.RepoCollaborators(owner, name), listCollaboratorRequest.ToParametersDictionary(), AcceptHeaders.OrganizationMembershipPreview, options); @@ -160,6 +161,7 @@ public IObservable GetAll(string owner, string name, ListCollaboratorReque /// Thrown when a general API error occurs. public IObservable GetAll(long repositoryId, ListCollaboratorRequest listCollaboratorRequest, ApiOptions options) { + Ensure.ArgumentNotNull(listCollaboratorRequest, nameof(listCollaboratorRequest)); Ensure.ArgumentNotNull(options, nameof(options)); return _connection.GetAndFlattenAllPages(ApiUrls.RepoCollaborators(repositoryId), listCollaboratorRequest.ToParametersDictionary(), AcceptHeaders.OrganizationMembershipPreview, options); From 4d5586106d89adffdf0054378b83122bc5fec7e7 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Sat, 16 Mar 2019 08:11:55 +1000 Subject: [PATCH 10/18] Add unit tests --- .../Clients/RepoCollaboratorsClientTests.cs | 110 +++++++++++++++++- .../ObservableRepoCollaboratorsClientTests.cs | 98 ++++++++++++++++ 2 files changed, 207 insertions(+), 1 deletion(-) diff --git a/Octokit.Tests/Clients/RepoCollaboratorsClientTests.cs b/Octokit.Tests/Clients/RepoCollaboratorsClientTests.cs index 7154582e00..d760c2f96a 100644 --- a/Octokit.Tests/Clients/RepoCollaboratorsClientTests.cs +++ b/Octokit.Tests/Clients/RepoCollaboratorsClientTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using NSubstitute; using Xunit; @@ -68,7 +69,7 @@ public void RequestsCorrectUrlWithApiOptions() StartPage = 1 }; - client.GetAll("owner", "test", new ListCollaboratorRequest(), options); + client.GetAll("owner", "test", options); connection.Received() .GetAll( @@ -78,6 +79,64 @@ public void RequestsCorrectUrlWithApiOptions() options); } + [Fact] + public void RequestsCorrectUrlWithListCollaboratorRequest() + { + var connection = Substitute.For(); + var client = new RepoCollaboratorsClient(connection); + + var listCollaboratorRequest = new ListCollaboratorRequest + { + Affiliation = Affiliation.Outside + }; + + client.GetAll("owner", "test", listCollaboratorRequest); + + connection.Received() + .GetAll( + Arg.Is(u => u.ToString() == "repos/owner/test/collaborators"), + Arg.Is>(d => d["affiliation"] == "outside"), + "application/vnd.github.korra-preview+json", + Args.ApiOptions); + } + + [Fact] + public void RequestsCorrectUrlWithListCollaboratorRequestAndApiOptions() + { + var connection = Substitute.For(); + var client = new RepoCollaboratorsClient(connection); + + var listCollaboratorRequest = new ListCollaboratorRequest + { + Affiliation = Affiliation.Outside + }; + + var options = new ApiOptions + { + PageSize = 1, + PageCount = 1, + StartPage = 1 + }; + + client.GetAll("owner", "test", listCollaboratorRequest, options); + + connection.Received() + .GetAll( + Arg.Is(u => u.ToString() == "repos/owner/test/collaborators"), + Arg.Is>(d => d["affiliation"] == "outside"), + "application/vnd.github.korra-preview+json", + options); + + client.GetAll("owner", "test", listCollaboratorRequest); + + connection.Received() + .GetAll( + Arg.Is(u => u.ToString() == "repos/owner/test/collaborators"), + Arg.Is>(d => d["affiliation"] == "outside"), + "application/vnd.github.korra-preview+json", + Args.ApiOptions); + } + [Fact] public void RequestsCorrectUrlWithApiOptionsAndRepositoryId() { @@ -101,6 +160,55 @@ public void RequestsCorrectUrlWithApiOptionsAndRepositoryId() options); } + [Fact] + public void RequestsCorrectUrlWithListCollaboratorRequestAndRepositoryId() + { + var connection = Substitute.For(); + var client = new RepoCollaboratorsClient(connection); + + var listCollaboratorRequest = new ListCollaboratorRequest + { + Affiliation = Affiliation.Outside + }; + + client.GetAll(1, listCollaboratorRequest); + + connection.Received() + .GetAll( + Arg.Is(u => u.ToString() == "repositories/1/collaborators"), + Arg.Is>(d => d["affiliation"] == "outside"), + "application/vnd.github.korra-preview+json", + Args.ApiOptions); + } + + [Fact] + public void RequestsCorrectUrlWithListCollaboratorRequestApiOptionsAndRepositoryId() + { + var connection = Substitute.For(); + var client = new RepoCollaboratorsClient(connection); + + var listCollaboratorRequest = new ListCollaboratorRequest + { + Affiliation = Affiliation.Outside + }; + + var options = new ApiOptions + { + PageSize = 1, + PageCount = 1, + StartPage = 1 + }; + + client.GetAll(1, listCollaboratorRequest, options); + + connection.Received() + .GetAll( + Arg.Is(u => u.ToString() == "repositories/1/collaborators"), + Arg.Is>(d => d["affiliation"] == "outside"), + "application/vnd.github.korra-preview+json", + options); + } + [Fact] public async Task EnsuresNonNullArguments() { diff --git a/Octokit.Tests/Reactive/ObservableRepoCollaboratorsClientTests.cs b/Octokit.Tests/Reactive/ObservableRepoCollaboratorsClientTests.cs index 2d1a4263b1..d45285c4f4 100644 --- a/Octokit.Tests/Reactive/ObservableRepoCollaboratorsClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableRepoCollaboratorsClientTests.cs @@ -135,6 +135,55 @@ public void RequestsCorrectUrlWithApiOptions() "application/vnd.github.korra-preview+json"); } + [Fact] + public void RequestsCorrectUrlWithListCollaboratorRequestAndApiOptions() + { + var expectedUrl = string.Format("repos/{0}/{1}/collaborators", owner, name); + + var listCollaboratorRequest = new ListCollaboratorRequest + { + Affiliation = Affiliation.Outside + }; + + // all properties are setted => only 2 options (StartPage, PageSize) in dictionary + var options = new ApiOptions + { + StartPage = 1, + PageCount = 1, + PageSize = 1 + }; + + _client.GetAll(owner, name, listCollaboratorRequest, options); + _githubClient.Connection.Received(1) + .Get>(Arg.Is(u => u.ToString() == expectedUrl), + Arg.Is>(dictionary => dictionary.Count == 3 && dictionary["affiliation"] == "outside"), + "application/vnd.github.korra-preview+json"); + + // StartPage is setted => only 1 option (StartPage) in dictionary + options = new ApiOptions + { + StartPage = 1 + }; + + _client.GetAll(owner, name, listCollaboratorRequest, options); + _githubClient.Connection.Received(1) + .Get>(Arg.Is(u => u.ToString() == expectedUrl), + Arg.Is>(dictionary => dictionary.Count == 2 && dictionary["affiliation"] == "outside"), + "application/vnd.github.korra-preview+json"); + + // PageCount is setted => none of options in dictionary + options = new ApiOptions + { + PageCount = 1 + }; + + _client.GetAll(owner, name, listCollaboratorRequest, options); + _githubClient.Connection.Received(1) + .Get>(Arg.Is(u => u.ToString() == expectedUrl), + Arg.Is>(dictionary => dictionary.Count == 1 && dictionary["affiliation"] == "outside"), + "application/vnd.github.korra-preview+json"); + } + [Fact] public void RequestsCorrectUrlWithApiOptionsAndRepositoryId() { @@ -178,6 +227,55 @@ public void RequestsCorrectUrlWithApiOptionsAndRepositoryId() Arg.Is>(dictionary => dictionary.Count == 1 && dictionary["affiliation"] == "all"), "application/vnd.github.korra-preview+json"); } + + [Fact] + public void RequestsCorrectUrlWithListCollaboratorRequestApiOptionsAndRepositoryId() + { + var expectedUrl = string.Format("repositories/{0}/collaborators", repositoryId); + + var listCollaboratorRequest = new ListCollaboratorRequest + { + Affiliation = Affiliation.Outside + }; + + // all properties are setted => only 2 options (StartPage, PageSize) in dictionary + var options = new ApiOptions + { + StartPage = 1, + PageCount = 1, + PageSize = 1 + }; + + _client.GetAll(repositoryId, listCollaboratorRequest, options); + _githubClient.Connection.Received(1) + .Get>(Arg.Is(u => u.ToString() == expectedUrl), + Arg.Is>(dictionary => dictionary.Count == 3 && dictionary["affiliation"] == "outside"), + "application/vnd.github.korra-preview+json"); + + // StartPage is setted => only 1 option (StartPage) in dictionary + options = new ApiOptions + { + StartPage = 1 + }; + + _client.GetAll(repositoryId, listCollaboratorRequest, options); + _githubClient.Connection.Received(1) + .Get>(Arg.Is(u => u.ToString() == expectedUrl), + Arg.Is>(dictionary => dictionary.Count == 2 && dictionary["affiliation"] == "outside"), + "application/vnd.github.korra-preview+json"); + + // PageCount is setted => none of options in dictionary + options = new ApiOptions + { + PageCount = 1 + }; + + _client.GetAll(repositoryId, listCollaboratorRequest, options); + _githubClient.Connection.Received(1) + .Get>(Arg.Is(u => u.ToString() == expectedUrl), + Arg.Is>(dictionary => dictionary.Count == 1 && dictionary["affiliation"] == "outside"), + "application/vnd.github.korra-preview+json"); + } } public class TheIsCollaboratorMethod From 05472ec2bc7cb8e948ce87f1413ff28c17d7a79f Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Sat, 16 Mar 2019 08:39:23 +1000 Subject: [PATCH 11/18] Add integration tests --- .../RepositoryCollaboratorClientTests.cs | 96 ++++++++++++++++++- ...rvableRepositoryCollaboratorClientTests.cs | 46 +++++++++ 2 files changed, 138 insertions(+), 4 deletions(-) diff --git a/Octokit.Tests.Integration/Clients/RepositoryCollaboratorClientTests.cs b/Octokit.Tests.Integration/Clients/RepositoryCollaboratorClientTests.cs index 7394081a47..80cd9050b4 100644 --- a/Octokit.Tests.Integration/Clients/RepositoryCollaboratorClientTests.cs +++ b/Octokit.Tests.Integration/Clients/RepositoryCollaboratorClientTests.cs @@ -64,6 +64,94 @@ public async Task ReturnsAllCollaboratorsWithRepositoryId() } } + [DualAccountTest] + public async Task ReturnsOutsideCollaborators() + { + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext(Helper.Organization, new NewRepository("public-repo"))) + { + // add a collaborator + await client.Add(context.RepositoryOwner, context.RepositoryName, collaborator); + await AcceptInvitation(github, github2, context.RepositoryId, collaborator); + + var listCollaboratorRequest = new ListCollaboratorRequest + { + Affiliation = Affiliation.Outside + }; + + var collaborators = await client.GetAll(context.RepositoryOwner, context.RepositoryName, listCollaboratorRequest); + Assert.NotNull(collaborators); + Assert.Equal(1, collaborators.Count); + Assert.Equal(collaborator, collaborators[0].Login); + } + } + + [DualAccountTest] + public async Task ReturnsOutsideCollaboratorsWithRepositoryId() + { + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext(Helper.Organization, new NewRepository("public-repo"))) + { + // add a collaborator + await client.Add(context.Repository.Id, collaborator); + await AcceptInvitation(github, github2, context.Repository.Id, collaborator); + + var listCollaboratorRequest = new ListCollaboratorRequest + { + Affiliation = Affiliation.Outside + }; + + var collaborators = await client.GetAll(context.Repository.Id, listCollaboratorRequest); + Assert.NotNull(collaborators); + Assert.Equal(1, collaborators.Count); + Assert.Equal(collaborator, collaborators[0].Login); + } + } + + [DualAccountTest] + public async Task ReturnsDirectCollaborators() + { + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext(Helper.Organization, new NewRepository("public-repo"))) + { + // add a collaborator + await client.Add(context.RepositoryOwner, context.RepositoryName, collaborator); + await AcceptInvitation(github, github2, context.RepositoryId, collaborator); + + var listCollaboratorRequest = new ListCollaboratorRequest + { + Affiliation = Affiliation.Direct + }; + + var collaborators = await client.GetAll(context.RepositoryOwner, context.RepositoryName, listCollaboratorRequest); + Assert.NotNull(collaborators); + Assert.Equal(1, collaborators.Count); + Assert.Equal(collaborator, collaborators[0].Login); + } + } + + [DualAccountTest] + public async Task ReturnsDirectCollaboratorsWithRepositoryId() + { + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext(Helper.Organization, new NewRepository("public-repo"))) + { + // add a collaborator + await client.Add(context.Repository.Id, collaborator); + await AcceptInvitation(github, github2, context.Repository.Id, collaborator); + + var listCollaboratorRequest = new ListCollaboratorRequest + { + Affiliation = Affiliation.Direct + }; + + var collaborators = await client.GetAll(context.Repository.Id, listCollaboratorRequest); + Assert.NotNull(collaborators); + Assert.Equal(1, collaborators.Count); + Assert.Equal(collaborator, collaborators[0].Login); + } + } + [DualAccountTest] public async Task ReturnsCorrectCountOfCollaboratorsWithoutStart() { @@ -80,7 +168,7 @@ public async Task ReturnsCorrectCountOfCollaboratorsWithoutStart() PageCount = 1 }; - var collaborators = await client.GetAll(context.RepositoryOwner, context.RepositoryName, new ListCollaboratorRequest(), options); + var collaborators = await client.GetAll(context.RepositoryOwner, context.RepositoryName, options); Assert.NotNull(collaborators); Assert.Equal(1, collaborators.Count); } @@ -102,7 +190,7 @@ public async Task ReturnsCorrectCountOfCollaboratorsWithoutStartAndRepositoryId( PageCount = 1 }; - var collaborators = await client.GetAll(context.Repository.Id, new ListCollaboratorRequest(), options); + var collaborators = await client.GetAll(context.Repository.Id, options); Assert.NotNull(collaborators); Assert.Equal(1, collaborators.Count); } @@ -125,7 +213,7 @@ public async Task ReturnsCorrectCountOfCollaboratorsWithStart() StartPage = 2 }; - var collaborators = await client.GetAll(context.RepositoryOwner, context.RepositoryName, new ListCollaboratorRequest(), options); + var collaborators = await client.GetAll(context.RepositoryOwner, context.RepositoryName, options); Assert.NotNull(collaborators); Assert.Equal(1, collaborators.Count); } @@ -148,7 +236,7 @@ public async Task ReturnsCorrectCountOfCollaboratorsWithStartAndRepositoryId() StartPage = 2 }; - var collaborators = await client.GetAll(context.Repository.Id, new ListCollaboratorRequest(), options); + var collaborators = await client.GetAll(context.Repository.Id, options); Assert.NotNull(collaborators); Assert.Equal(1, collaborators.Count); } diff --git a/Octokit.Tests.Integration/Reactive/ObservableRepositoryCollaboratorClientTests.cs b/Octokit.Tests.Integration/Reactive/ObservableRepositoryCollaboratorClientTests.cs index 0d3570e836..8586d1d4e0 100644 --- a/Octokit.Tests.Integration/Reactive/ObservableRepositoryCollaboratorClientTests.cs +++ b/Octokit.Tests.Integration/Reactive/ObservableRepositoryCollaboratorClientTests.cs @@ -49,6 +49,52 @@ public async Task ReturnsAllCollaborators() } } + [DualAccountTest] + public async Task ReturnsOutsideCollaborators() + { + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext("public-repo")) + { + // add a collaborator + await client.Add(context.RepositoryOwner, context.RepositoryName, collaborator); + await AcceptInvitation(github, github2, context.RepositoryId, collaborator); + + var listCollaboratorRequest = new ListCollaboratorRequest + { + Affiliation = Affiliation.Outside + }; + + var collaborators = await client.GetAll(context.RepositoryOwner, context.RepositoryName, listCollaboratorRequest).ToList(); + Assert.NotNull(collaborators); + Assert.Equal(1, collaborators.Count); + Assert.NotNull(collaborators[0].Permissions); + Assert.Equal(collaborator, collaborators[0].Login); + } + } + + [DualAccountTest] + public async Task ReturnsDirectCollaborators() + { + var collaborator = Helper.UserName2; + using (var context = await github.CreateRepositoryContext("public-repo")) + { + // add a collaborator + await client.Add(context.RepositoryOwner, context.RepositoryName, collaborator); + await AcceptInvitation(github, github2, context.RepositoryId, collaborator); + + var listCollaboratorRequest = new ListCollaboratorRequest + { + Affiliation = Affiliation.Direct + }; + + var collaborators = await client.GetAll(context.RepositoryOwner, context.RepositoryName, listCollaboratorRequest).ToList(); + Assert.NotNull(collaborators); + Assert.Equal(1, collaborators.Count); + Assert.NotNull(collaborators[0].Permissions); + Assert.Equal(collaborator, collaborators[0].Login); + } + } + [DualAccountTest] public async Task ReturnsCorrectCountOfCollaboratorsWithoutStart() { From 00c019632e12dd4d349c4d795aac6d798404d1af Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Thu, 21 Mar 2019 21:52:17 +1000 Subject: [PATCH 12/18] Revert inadvertent change to this file --- Octokit.sln.DotSettings | 1 - 1 file changed, 1 deletion(-) diff --git a/Octokit.sln.DotSettings b/Octokit.sln.DotSettings index 7f9262b459..50852c97ec 100644 --- a/Octokit.sln.DotSettings +++ b/Octokit.sln.DotSettings @@ -269,7 +269,6 @@ II.2.12 <HandlesEvent /> True True True - True True True True From ae159a566678ba9a11e6039105efd96bb7d3022a Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Thu, 21 Mar 2019 22:26:53 +1000 Subject: [PATCH 13/18] Should've been an enum from the beginning --- .../Models/Common/DefaultRepositoryPermission.cs | 16 ++++++++++++++++ Octokit/Models/Request/OrganizationUpdate.cs | 2 +- Octokit/Models/Response/Organization.cs | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 Octokit/Models/Common/DefaultRepositoryPermission.cs diff --git a/Octokit/Models/Common/DefaultRepositoryPermission.cs b/Octokit/Models/Common/DefaultRepositoryPermission.cs new file mode 100644 index 0000000000..4ce1338f2b --- /dev/null +++ b/Octokit/Models/Common/DefaultRepositoryPermission.cs @@ -0,0 +1,16 @@ +using Octokit.Internal; + +namespace Octokit +{ + public enum DefaultRepositoryPermission + { + [Parameter(Value = "read")] + Read, + [Parameter(Value = "write")] + Write, + [Parameter(Value = "admin")] + Admin, + [Parameter(Value = "none")] + None + } +} diff --git a/Octokit/Models/Request/OrganizationUpdate.cs b/Octokit/Models/Request/OrganizationUpdate.cs index 682e158976..ff6bb5ec1b 100644 --- a/Octokit/Models/Request/OrganizationUpdate.cs +++ b/Octokit/Models/Request/OrganizationUpdate.cs @@ -46,7 +46,7 @@ public class OrganizationUpdate /// /// Gets or sets the default permission level members have for organization repositories. /// - public string DefaultRepositoryPermission { get; set; } + public DefaultRepositoryPermission DefaultRepositoryPermission { get; set; } /// /// Toggles the ability of non-admin organization members to create repositories. diff --git a/Octokit/Models/Response/Organization.cs b/Octokit/Models/Response/Organization.cs index 1e53b875ab..a9ab910aea 100644 --- a/Octokit/Models/Response/Organization.cs +++ b/Octokit/Models/Response/Organization.cs @@ -27,7 +27,7 @@ public Organization(string avatarUrl, string bio, string blog, int collaborators /// /// Default permission level members have for organization repositories. /// - public string DefaultRepositoryPermission { get; protected set; } + public StringEnum DefaultRepositoryPermission { get; protected set; } /// /// Toggles the ability of non-admin organization members to create repositories. From 6f076d8a62f9f9b7967d2a38fd07595c115c0dc3 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Thu, 21 Mar 2019 22:27:53 +1000 Subject: [PATCH 14/18] Add new property for specifying what repo a member is allowed to create --- .../Clients/ObservableOrganizationsClient.cs | 10 +++++----- Octokit/Clients/OrganizationsClient.cs | 12 ++++++------ Octokit/Helpers/AcceptHeaders.cs | 2 ++ .../Common/MembersAllowedRepositoryCreationType.cs | 14 ++++++++++++++ Octokit/Models/Request/OrganizationUpdate.cs | 5 +++++ Octokit/Models/Response/Organization.cs | 8 +++++++- 6 files changed, 39 insertions(+), 12 deletions(-) create mode 100644 Octokit/Models/Common/MembersAllowedRepositoryCreationType.cs diff --git a/Octokit.Reactive/Clients/ObservableOrganizationsClient.cs b/Octokit.Reactive/Clients/ObservableOrganizationsClient.cs index 690375eb2b..687e99e0d1 100644 --- a/Octokit.Reactive/Clients/ObservableOrganizationsClient.cs +++ b/Octokit.Reactive/Clients/ObservableOrganizationsClient.cs @@ -70,7 +70,7 @@ public IObservable GetAllForCurrent(ApiOptions options) { Ensure.ArgumentNotNull(options, nameof(options)); - return _connection.GetAndFlattenAllPages(ApiUrls.UserOrganizations()); + return _connection.GetAndFlattenAllPages(ApiUrls.UserOrganizations(), null, AcceptHeaders.Concat(AcceptHeaders.OrganizationMembershipPreview, AcceptHeaders.RepositoryCreationPermissionsApiPreview)); } /// @@ -82,7 +82,7 @@ public IObservable GetAllForUser(string user) { Ensure.ArgumentNotNullOrEmptyString(user, nameof(user)); - return _connection.GetAndFlattenAllPages(ApiUrls.UserOrganizations(user)); + return _connection.GetAndFlattenAllPages(ApiUrls.UserOrganizations(user), null, AcceptHeaders.Concat(AcceptHeaders.OrganizationMembershipPreview, AcceptHeaders.RepositoryCreationPermissionsApiPreview)); } /// @@ -96,7 +96,7 @@ public IObservable GetAllForUser(string user, ApiOptions options) Ensure.ArgumentNotNullOrEmptyString(user, nameof(user)); Ensure.ArgumentNotNull(options, nameof(options)); - return _connection.GetAndFlattenAllPages(ApiUrls.UserOrganizations(user), options); + return _connection.GetAndFlattenAllPages(ApiUrls.UserOrganizations(user), null, AcceptHeaders.Concat(AcceptHeaders.OrganizationMembershipPreview, AcceptHeaders.RepositoryCreationPermissionsApiPreview), options); } /// @@ -105,7 +105,7 @@ public IObservable GetAllForUser(string user, ApiOptions options) /// public IObservable GetAll() { - return _connection.GetAndFlattenAllPages(ApiUrls.AllOrganizations()); + return _connection.GetAndFlattenAllPages(ApiUrls.AllOrganizations(), null, AcceptHeaders.Concat(AcceptHeaders.OrganizationMembershipPreview, AcceptHeaders.RepositoryCreationPermissionsApiPreview)); } /// @@ -119,7 +119,7 @@ public IObservable GetAll(OrganizationRequest request) var url = ApiUrls.AllOrganizations(request.Since); - return _connection.GetAndFlattenAllPages(url); + return _connection.GetAndFlattenAllPages(url, null, AcceptHeaders.Concat(AcceptHeaders.OrganizationMembershipPreview, AcceptHeaders.RepositoryCreationPermissionsApiPreview)); } /// diff --git a/Octokit/Clients/OrganizationsClient.cs b/Octokit/Clients/OrganizationsClient.cs index 02d8eb2f2e..77d3660b66 100644 --- a/Octokit/Clients/OrganizationsClient.cs +++ b/Octokit/Clients/OrganizationsClient.cs @@ -48,7 +48,7 @@ public Task Get(string org) { Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); - return ApiConnection.Get(ApiUrls.Organization(org)); + return ApiConnection.Get(ApiUrls.Organization(org), null, AcceptHeaders.Concat(AcceptHeaders.OrganizationMembershipPreview, AcceptHeaders.RepositoryCreationPermissionsApiPreview)); } /// @@ -71,7 +71,7 @@ public Task> GetAllForCurrent(ApiOptions options) { Ensure.ArgumentNotNull(options, nameof(options)); - return ApiConnection.GetAll(ApiUrls.UserOrganizations(), options); + return ApiConnection.GetAll(ApiUrls.UserOrganizations(), null, AcceptHeaders.Concat(AcceptHeaders.OrganizationMembershipPreview, AcceptHeaders.RepositoryCreationPermissionsApiPreview), options); } /// @@ -99,7 +99,7 @@ public Task> GetAllForUser(string user, ApiOptions o Ensure.ArgumentNotNullOrEmptyString(user, nameof(user)); Ensure.ArgumentNotNull(options, nameof(options)); - return ApiConnection.GetAll(ApiUrls.UserOrganizations(user), options); + return ApiConnection.GetAll(ApiUrls.UserOrganizations(user), null, AcceptHeaders.Concat(AcceptHeaders.OrganizationMembershipPreview, AcceptHeaders.RepositoryCreationPermissionsApiPreview), options); } @@ -110,7 +110,7 @@ public Task> GetAllForUser(string user, ApiOptions o /// A list of s. public Task> GetAll() { - return ApiConnection.GetAll(ApiUrls.AllOrganizations()); + return ApiConnection.GetAll(ApiUrls.AllOrganizations(), AcceptHeaders.Concat(AcceptHeaders.OrganizationMembershipPreview, AcceptHeaders.RepositoryCreationPermissionsApiPreview)); } /// @@ -125,7 +125,7 @@ public Task> GetAll(OrganizationRequest request) var url = ApiUrls.AllOrganizations(request.Since); - return ApiConnection.GetAll(url); + return ApiConnection.GetAll(url, AcceptHeaders.Concat(AcceptHeaders.OrganizationMembershipPreview, AcceptHeaders.RepositoryCreationPermissionsApiPreview)); } /// @@ -142,7 +142,7 @@ public Task Update(string organizationName, OrganizationUpdate upd var updateUri = new Uri("orgs/" + organizationName, UriKind.Relative); - return ApiConnection.Patch(updateUri, updateRequest); + return ApiConnection.Patch(updateUri, updateRequest, AcceptHeaders.Concat(AcceptHeaders.OrganizationMembershipPreview, AcceptHeaders.RepositoryCreationPermissionsApiPreview)); } } } diff --git a/Octokit/Helpers/AcceptHeaders.cs b/Octokit/Helpers/AcceptHeaders.cs index 085ff4f3af..11f4c5ba7b 100644 --- a/Octokit/Helpers/AcceptHeaders.cs +++ b/Octokit/Helpers/AcceptHeaders.cs @@ -67,6 +67,8 @@ public static class AcceptHeaders public const string ProtectedBranchesRequiredApprovingApiPreview = "application/vnd.github.luke-cage-preview+json"; + public const string RepositoryCreationPermissionsApiPreview = "application/vnd.github.surtur-preview+json"; + /// /// Combines multiple preview headers. GitHub API supports Accept header with multiple /// values separated by comma. diff --git a/Octokit/Models/Common/MembersAllowedRepositoryCreationType.cs b/Octokit/Models/Common/MembersAllowedRepositoryCreationType.cs new file mode 100644 index 0000000000..a9641165d3 --- /dev/null +++ b/Octokit/Models/Common/MembersAllowedRepositoryCreationType.cs @@ -0,0 +1,14 @@ +using Octokit.Internal; + +namespace Octokit +{ + public enum MembersAllowedRepositoryCreationType + { + [Parameter(Value = "all")] + All, + [Parameter(Value = "private")] + Private, + [Parameter(Value = "none")] + None + } +} \ No newline at end of file diff --git a/Octokit/Models/Request/OrganizationUpdate.cs b/Octokit/Models/Request/OrganizationUpdate.cs index ff6bb5ec1b..c3f3a34209 100644 --- a/Octokit/Models/Request/OrganizationUpdate.cs +++ b/Octokit/Models/Request/OrganizationUpdate.cs @@ -52,6 +52,11 @@ public class OrganizationUpdate /// Toggles the ability of non-admin organization members to create repositories. /// public bool MembersCanCreateRepositories { get; set; } + + /// + /// Specifies which types of repositories non-admin organization members can create. + /// + public MembersAllowedRepositoryCreationType MembersAllowedRepositoryCreationType { get; set; } internal string DebuggerDisplay { diff --git a/Octokit/Models/Response/Organization.cs b/Octokit/Models/Response/Organization.cs index a9ab910aea..60715317fb 100644 --- a/Octokit/Models/Response/Organization.cs +++ b/Octokit/Models/Response/Organization.cs @@ -10,12 +10,13 @@ public class Organization : Account { public Organization() { } - public Organization(string avatarUrl, string bio, string blog, int collaborators, string company, DateTimeOffset createdAt, int diskUsage, string email, int followers, int following, bool? hireable, string htmlUrl, int totalPrivateRepos, int id, string nodeId, string location, string login, string name, int ownedPrivateRepos, Plan plan, int privateGists, int publicGists, int publicRepos, string url, string billingAddress, string defaultRepositoryPermission, bool membersCanCreateRepositories) + public Organization(string avatarUrl, string bio, string blog, int collaborators, string company, DateTimeOffset createdAt, int diskUsage, string email, int followers, int following, bool? hireable, string htmlUrl, int totalPrivateRepos, int id, string nodeId, string location, string login, string name, int ownedPrivateRepos, Plan plan, int privateGists, int publicGists, int publicRepos, string url, string billingAddress, string defaultRepositoryPermission, bool membersCanCreateRepositories, string membersAllowedRepositoryCreationType) : base(avatarUrl, bio, blog, collaborators, company, createdAt, diskUsage, email, followers, following, hireable, htmlUrl, totalPrivateRepos, id, location, login, name, nodeId, ownedPrivateRepos, plan, privateGists, publicGists, publicRepos, AccountType.Organization, url) { BillingAddress = billingAddress; DefaultRepositoryPermission = defaultRepositoryPermission; MembersCanCreateRepositories = membersCanCreateRepositories; + MembersAllowedRepositoryCreationType = membersAllowedRepositoryCreationType; } /// @@ -34,6 +35,11 @@ public Organization(string avatarUrl, string bio, string blog, int collaborators /// public bool MembersCanCreateRepositories { get; protected set; } + /// + /// Specifies which types of repositories non-admin organization members can create. + /// + public StringEnum MembersAllowedRepositoryCreationType { get; protected set; } + internal string DebuggerDisplay { get From bb6034377071cf099a0411094486e4a8be0e4c60 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Thu, 21 Mar 2019 23:09:33 +1000 Subject: [PATCH 15/18] Update tests --- .../Clients/OrganizationsClientTests.cs | 44 +++++++++++++++---- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/Octokit.Tests/Clients/OrganizationsClientTests.cs b/Octokit.Tests/Clients/OrganizationsClientTests.cs index 2dbf0a2a73..0eb159a4c4 100644 --- a/Octokit.Tests/Clients/OrganizationsClientTests.cs +++ b/Octokit.Tests/Clients/OrganizationsClientTests.cs @@ -30,7 +30,10 @@ public async Task RequestsCorrectUrl() await client.Get("orgName"); - connection.Received().Get(Arg.Is(u => u.ToString() == "orgs/orgName")); + connection.Received().Get( + Arg.Is(u => u.ToString() == "orgs/orgName"), + null, + "application/vnd.github.korra-preview+json,application/vnd.github.surtur-preview+json"); } [Fact] @@ -54,7 +57,11 @@ public async Task RequestsTheCorrectUrl() await client.GetAllForUser("username"); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "users/username/orgs"), Args.ApiOptions); + connection.Received().GetAll(Arg.Is( + u => u.ToString() == "users/username/orgs"), + null, + "application/vnd.github.korra-preview+json,application/vnd.github.surtur-preview+json", + Args.ApiOptions); } [Fact] @@ -72,7 +79,11 @@ public async Task RequestsTheCorrectUrlWithApiOptions() await client.GetAllForUser("username", options); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "users/username/orgs"), options); + connection.Received().GetAll( + Arg.Is(u => u.ToString() == "users/username/orgs"), + null, + "application/vnd.github.korra-preview+json,application/vnd.github.surtur-preview+json", + options); } [Fact] @@ -100,7 +111,11 @@ public async Task RequestsTheCorrectUrl() await client.GetAllForCurrent(); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "user/orgs"), Args.ApiOptions); + connection.Received().GetAll( + Arg.Is(u => u.ToString() == "user/orgs"), + null, + "application/vnd.github.korra-preview+json,application/vnd.github.surtur-preview+json", + Args.ApiOptions); } [Fact] @@ -118,7 +133,11 @@ public async Task RequestsTheCorrectUrlWithApiOptions() await client.GetAllForCurrent(options); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "user/orgs"), options); + connection.Received().GetAll( + Arg.Is(u => u.ToString() == "user/orgs"), + null, + "application/vnd.github.korra-preview+json,application/vnd.github.surtur-preview+json", + options); } [Fact] @@ -141,7 +160,10 @@ public async Task RequestsTheCorrectUrl() await client.GetAll(); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "organizations")); + connection.Received().GetAll( + Arg.Is(u => u.ToString() == "organizations"), + null, + "application/vnd.github.korra-preview+json,application/vnd.github.surtur-preview+json"); } [Fact] @@ -154,7 +176,10 @@ public async Task RequestsTheCorrectUrlWithRequestParameter() await client.GetAll(request); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "organizations?since=1")); + connection.Received().GetAll( + Arg.Is(u => u.ToString() == "organizations?since=1"), + null, + "application/vnd.github.korra-preview+json,application/vnd.github.surtur-preview+json"); } [Fact] @@ -177,7 +202,10 @@ public async Task RequestsTheCorrectUrl() await client.Update("initrode", new OrganizationUpdate()); - connection.Received().Patch(Arg.Is(u => u.ToString() == "orgs/initrode"), Args.OrganizationUpdate); + connection.Received().Patch( + Arg.Is(u => u.ToString() == "orgs/initrode"), + Args.OrganizationUpdate, + "application/vnd.github.korra-preview+json,application/vnd.github.surtur-preview+json"); } [Fact] From f74cd17e3e0a6ed9ff243183e0065d90e414566f Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Thu, 21 Mar 2019 23:41:43 +1000 Subject: [PATCH 16/18] Was a bit too quick on the copy-paste --- Octokit.Tests/Clients/OrganizationsClientTests.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Octokit.Tests/Clients/OrganizationsClientTests.cs b/Octokit.Tests/Clients/OrganizationsClientTests.cs index 0eb159a4c4..86a3a4640d 100644 --- a/Octokit.Tests/Clients/OrganizationsClientTests.cs +++ b/Octokit.Tests/Clients/OrganizationsClientTests.cs @@ -162,7 +162,6 @@ public async Task RequestsTheCorrectUrl() connection.Received().GetAll( Arg.Is(u => u.ToString() == "organizations"), - null, "application/vnd.github.korra-preview+json,application/vnd.github.surtur-preview+json"); } @@ -178,7 +177,6 @@ public async Task RequestsTheCorrectUrlWithRequestParameter() connection.Received().GetAll( Arg.Is(u => u.ToString() == "organizations?since=1"), - null, "application/vnd.github.korra-preview+json,application/vnd.github.surtur-preview+json"); } From ab7430aceba5f17b2adced877f711a5fdb8340aa Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Fri, 22 Mar 2019 07:59:32 +1000 Subject: [PATCH 17/18] Remove white space and method modifier --- Octokit.Tests.Integration/Helper.cs | 2 +- .../ObservableRepositoryCollaboratorClientTests.cs | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Octokit.Tests.Integration/Helper.cs b/Octokit.Tests.Integration/Helper.cs index 482dbcd663..52e6ddb7c1 100644 --- a/Octokit.Tests.Integration/Helper.cs +++ b/Octokit.Tests.Integration/Helper.cs @@ -29,7 +29,7 @@ public static class Helper return new Credentials(githubUsername, githubPassword); }); - private static readonly Lazy _credentialsSecondUserThunk = new Lazy(() => + static readonly Lazy _credentialsSecondUserThunk = new Lazy(() => { var githubUsername = Environment.GetEnvironmentVariable("OCTOKIT_GITHUBUSERNAME_2"); UserName2 = githubUsername; diff --git a/Octokit.Tests.Integration/Reactive/ObservableRepositoryCollaboratorClientTests.cs b/Octokit.Tests.Integration/Reactive/ObservableRepositoryCollaboratorClientTests.cs index 8586d1d4e0..85fb7ac492 100644 --- a/Octokit.Tests.Integration/Reactive/ObservableRepositoryCollaboratorClientTests.cs +++ b/Octokit.Tests.Integration/Reactive/ObservableRepositoryCollaboratorClientTests.cs @@ -13,7 +13,7 @@ public class ObservableRepositoryCollaboratorClientTests static async Task AcceptInvitation(IGitHubClient github, IGitHubClient github2, long repositoryId, string user) { var invitations = await github.Repository.Invitation.GetAllForRepository(repositoryId); - await github2.Repository.Invitation.Accept(invitations.First(i => i.Invitee.Login == user).Id); + await github2.Repository.Invitation.Accept(invitations.First(i => i.Invitee.Login == user).Id); } public class TheGetAllMethod @@ -203,6 +203,7 @@ public async Task ReturnsTrueIfUserIsCollaborator() } } } + public class TheReviewPermissionMethod { [IntegrationTest] @@ -214,7 +215,7 @@ public async Task ReturnsReadPermissionForNonCollaborator() using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) { var fixture = new ObservableRepoCollaboratorsClient(github); - + var permission = await fixture.ReviewPermission(context.RepositoryOwner, context.RepositoryName, "octokitnet-test1"); Assert.Equal(PermissionLevel.Read, permission.Permission); @@ -249,7 +250,7 @@ public async Task ReturnsWritePermissionForCollaborator() using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) { var fixture = new ObservableRepoCollaboratorsClient(github); - + // add a collaborator await fixture.Add(context.RepositoryOwner, context.RepositoryName, collaborator); await AcceptInvitation(github, github2, context.RepositoryId, collaborator); @@ -272,7 +273,7 @@ public async Task ReturnsWritePermissionForCollaboratorWithRepositoryId() using (var context = await github.CreateRepositoryContext(new NewRepository(repoName))) { var fixture = new ObservableRepoCollaboratorsClient(github); - + // add a collaborator await fixture.Add(context.RepositoryOwner, context.RepositoryName, collaborator); await AcceptInvitation(github, github2, context.RepositoryId, collaborator); @@ -357,4 +358,4 @@ public async Task ReturnsNonePermissionForPrivateRepositoryWithRepositoryId() } } } -} \ No newline at end of file +} From 383a9cec13c910f6fc9e71a7ee6ca153590931a3 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Sat, 30 Mar 2019 14:48:35 +1000 Subject: [PATCH 18/18] Use enum types in ctor --- Octokit/Models/Response/Organization.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Octokit/Models/Response/Organization.cs b/Octokit/Models/Response/Organization.cs index 60715317fb..38c05deb8b 100644 --- a/Octokit/Models/Response/Organization.cs +++ b/Octokit/Models/Response/Organization.cs @@ -10,7 +10,7 @@ public class Organization : Account { public Organization() { } - public Organization(string avatarUrl, string bio, string blog, int collaborators, string company, DateTimeOffset createdAt, int diskUsage, string email, int followers, int following, bool? hireable, string htmlUrl, int totalPrivateRepos, int id, string nodeId, string location, string login, string name, int ownedPrivateRepos, Plan plan, int privateGists, int publicGists, int publicRepos, string url, string billingAddress, string defaultRepositoryPermission, bool membersCanCreateRepositories, string membersAllowedRepositoryCreationType) + public Organization(string avatarUrl, string bio, string blog, int collaborators, string company, DateTimeOffset createdAt, int diskUsage, string email, int followers, int following, bool? hireable, string htmlUrl, int totalPrivateRepos, int id, string nodeId, string location, string login, string name, int ownedPrivateRepos, Plan plan, int privateGists, int publicGists, int publicRepos, string url, string billingAddress, StringEnum defaultRepositoryPermission, bool membersCanCreateRepositories, StringEnum membersAllowedRepositoryCreationType) : base(avatarUrl, bio, blog, collaborators, company, createdAt, diskUsage, email, followers, following, hireable, htmlUrl, totalPrivateRepos, id, location, login, name, nodeId, ownedPrivateRepos, plan, privateGists, publicGists, publicRepos, AccountType.Organization, url) { BillingAddress = billingAddress;