diff --git a/Octokit.Tests/Clients/TeamsClientTests.cs b/Octokit.Tests/Clients/TeamsClientTests.cs new file mode 100644 index 00000000..fa224636 --- /dev/null +++ b/Octokit.Tests/Clients/TeamsClientTests.cs @@ -0,0 +1,112 @@ +using System; +using System.Threading.Tasks; +using NSubstitute; +using Octokit.Tests.Helpers; +using Xunit; + +namespace Octokit.Tests.Clients +{ + /// + /// Client tests mostly just need to make sure they call the IApiConnection with the correct + /// relative Uri. No need to fake up the response. All *those* tests are in ApiConnectionTests.cs. + /// + public class TeamsClientTests + { + public class TheConstructor + { + [Fact] + public void EnsuresNonNullArguments() + { + Assert.Throws(() => new TeamsClient(null)); + } + } + + public class TheGetAllMethod + { + [Fact] + public void RequestsTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new TeamsClient(connection); + + client.GetAllTeams("orgName"); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "orgs/orgName/teams")); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var teams = new TeamsClient(Substitute.For()); + + AssertEx.Throws(async () => await teams.GetAllTeams(null)); + } + } + + public class TheCreateTeamMethod + { + [Fact] + public void RequestsTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new TeamsClient(connection); + var team = new NewTeam("Octokittens"); + + client.CreateTeam("orgName", team); + + connection.Received().Post(Arg.Is(u => u.ToString() == "orgs/orgName/teams"), team); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var connection = Substitute.For(); + var client = new TeamsClient(connection); + + AssertEx.Throws(async () => await + client.CreateTeam("", new NewTeam("superstars"))); + AssertEx.Throws(async () => await + client.CreateTeam("name", null)); + } + } + + public class TheUpdateTeamMethod + { + [Fact] + public void RequestsTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new TeamsClient(connection); + var team = new UpdateTeam("Octokittens"); + + client.UpdateTeam(1, team); + + connection.Received().Patch(Arg.Is(u => u.ToString() == "teams/1"), team); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var connection = Substitute.For(); + var client = new TeamsClient(connection); + + AssertEx.Throws(async () => await + client.UpdateTeam(1, null)); + } + } + + public class TheDeleteTeamMethod + { + [Fact] + public void RequestsTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new TeamsClient(connection); + client.DeleteTeam(1); + + connection.Received().Delete(Arg.Is(u => u.ToString() == "teams/1")); + } + } + + } +} diff --git a/Octokit.Tests/OctoKit.Tests-NetCore45.csproj b/Octokit.Tests/OctoKit.Tests-NetCore45.csproj index 5545b5e3..7c005989 100644 --- a/Octokit.Tests/OctoKit.Tests-NetCore45.csproj +++ b/Octokit.Tests/OctoKit.Tests-NetCore45.csproj @@ -106,6 +106,7 @@ + diff --git a/Octokit.Tests/Octokit.Tests.csproj b/Octokit.Tests/Octokit.Tests.csproj index 7705960e..84daa12e 100644 --- a/Octokit.Tests/Octokit.Tests.csproj +++ b/Octokit.Tests/Octokit.Tests.csproj @@ -66,6 +66,7 @@ + diff --git a/Octokit/Clients/IOrganizationsClient.cs b/Octokit/Clients/IOrganizationsClient.cs index 917cd7ea..546e5cd2 100644 --- a/Octokit/Clients/IOrganizationsClient.cs +++ b/Octokit/Clients/IOrganizationsClient.cs @@ -19,6 +19,11 @@ namespace Octokit /// IOrganizationMembersClient Member { get; } + /// + /// Returns a client to manage teams of an organization. + /// + ITeamsClient Team { get; } + /// /// Returns the specified . /// diff --git a/Octokit/Clients/ITeamsClient.cs b/Octokit/Clients/ITeamsClient.cs new file mode 100644 index 00000000..3737e484 --- /dev/null +++ b/Octokit/Clients/ITeamsClient.cs @@ -0,0 +1,46 @@ +#if NET_45 +using System.Collections.Generic; +#endif +using System.Diagnostics.CodeAnalysis; +using System.Threading.Tasks; + +namespace Octokit +{ + /// + /// A client for GitHub's Org Teams API. + /// + /// + /// See the Orgs API documentation for more information. + /// + public interface ITeamsClient + { + /// + /// Returns all s for the current org. + /// + /// Thrown when a general API error occurs. + /// A list of the orgs's teams s. + Task> GetAllTeams(string org); + + /// + /// Returns newly created for the current org. + /// + /// Thrown when a general API error occurs. + /// Newly created + Task CreateTeam(string org, NewTeam team); + + /// + /// Returns updated for the current org. + /// + /// Thrown when a general API error occurs. + /// Updated + Task UpdateTeam(int id, UpdateTeam team); + + /// + /// Delte a team - must have owner permissions to this + /// + /// Thrown when a general API error occurs. + /// + Task DeleteTeam(int id); + + } +} diff --git a/Octokit/Clients/OrganizationsClient.cs b/Octokit/Clients/OrganizationsClient.cs index 4d214b03..ba7f7c5f 100644 --- a/Octokit/Clients/OrganizationsClient.cs +++ b/Octokit/Clients/OrganizationsClient.cs @@ -21,10 +21,16 @@ namespace Octokit public OrganizationsClient(IApiConnection apiConnection) : base(apiConnection) { Member = new OrganizationMembersClient(apiConnection); + Team = new TeamsClient(apiConnection); } public IOrganizationMembersClient Member { get; private set; } + /// + /// Returns a client to manage teams of an organization. + /// + public ITeamsClient Team { get; private set; } + /// /// Returns the specified . /// diff --git a/Octokit/Clients/TeamsClient.cs b/Octokit/Clients/TeamsClient.cs new file mode 100644 index 00000000..3cd08ba9 --- /dev/null +++ b/Octokit/Clients/TeamsClient.cs @@ -0,0 +1,81 @@ +#if NET_45 +using System.Collections.Generic; +#endif +using System.Diagnostics.CodeAnalysis; +using System.Threading.Tasks; + +namespace Octokit +{ + + /// + /// A client for GitHub's Org Teams API. + /// + /// + /// See the Orgs API documentation for more information. + /// + public class TeamsClient : ApiClient, ITeamsClient + { + /// + /// Initializes a new GitHub Orgs Team API client. + /// + /// An API connection. + public TeamsClient(IApiConnection apiConnection) + : base(apiConnection) + { + } + + /// + /// Returns all s for the current org. + /// + /// Thrown when a general API error occurs. + /// A list of the orgs's teams s. + public Task> GetAllTeams(string org) + { + Ensure.ArgumentNotNullOrEmptyString(org, "org"); + + var endpoint = "orgs/{0}/teams".FormatUri(org); + + return ApiConnection.GetAll(endpoint); + } + + + /// + /// Returns newly created for the current org. + /// + /// Thrown when a general API error occurs. + /// Newly created + public Task CreateTeam(string org, NewTeam team) + { + Ensure.ArgumentNotNullOrEmptyString(org, "org"); + Ensure.ArgumentNotNull(team, "team"); + + var endpoint = "orgs/{0}/teams".FormatUri(org); + + return ApiConnection.Post(endpoint, team); + } + + /// + /// Returns updated for the current org. + /// + /// Thrown when a general API error occurs. + /// Updated + public Task UpdateTeam(int id, UpdateTeam team) + { + Ensure.ArgumentNotNull(team, "team"); + + var endpoint = "teams/{0}".FormatUri(id); + return ApiConnection.Patch(endpoint, team); + } + + /// + /// Delte a team - must have owner permissions to this + /// + /// Thrown when a general API error occurs. + /// + public Task DeleteTeam(int id) + { + var endpoint = "teams/{0}".FormatUri(id); + return ApiConnection.Delete(endpoint); + } + } +} diff --git a/Octokit/Models/Request/NewTeam.cs b/Octokit/Models/Request/NewTeam.cs new file mode 100644 index 00000000..64e1ed58 --- /dev/null +++ b/Octokit/Models/Request/NewTeam.cs @@ -0,0 +1,34 @@ +using Octokit.Internal; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + public class NewTeam + { + public NewTeam(string name) + { + Name = name; + RepoNames = new Collection(); + Permission = Octokit.Permission.Pull; + } + + /// + /// team name + /// + public string Name { get; set; } + + /// + /// permission associated to this team + /// + public Permission Permission { get; set; } + + /// + /// array of repo_names this team has permissions to + /// + public Collection RepoNames { get; private set; } + } +} \ No newline at end of file diff --git a/Octokit/Models/Request/Permission.cs b/Octokit/Models/Request/Permission.cs new file mode 100644 index 00000000..4a858a2a --- /dev/null +++ b/Octokit/Models/Request/Permission.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")] + public enum Permission + { + /// + /// team members can pull, push and administer these repositories. + /// + Admin, + + /// + /// team members can pull and push, but not administer these repositories + /// + Push, + + /// + /// team members can pull, but not push to or administer these repositories + /// + Pull + } +} \ No newline at end of file diff --git a/Octokit/Models/Request/UpdateTeam.cs b/Octokit/Models/Request/UpdateTeam.cs new file mode 100644 index 00000000..1ef7c728 --- /dev/null +++ b/Octokit/Models/Request/UpdateTeam.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + public class UpdateTeam + { + public UpdateTeam(string team) + { + Name = team; + } + + public UpdateTeam(string team, Permission permission) + { + Name = team; + Permission = permission; + } + + /// + /// team name + /// + public string Name { get; set; } + + /// + /// permission for this team + /// + public Permission? Permission { get; set; } + } +} \ No newline at end of file diff --git a/Octokit/Models/Response/Team.cs b/Octokit/Models/Response/Team.cs new file mode 100644 index 00000000..9d8ce0ef --- /dev/null +++ b/Octokit/Models/Response/Team.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + /// + /// organization teams + /// + public class Team + { + /// + /// url for this team + /// + public Uri Url { get; set; } + + /// + /// team id + /// + public int Id { get; set; } + + /// + /// team name + /// + public string Name { get; set; } + + /// + /// permission attached to this team + /// + public Permission Permission { get; set; } + + /// + /// how many members in this team + /// + public int MembersCount { get; set; } + + /// + /// how many repo this team has access to + /// + public int ReposCount { get; set; } + + /// + /// who this team belongs to + /// + public Organization Organization { get; set; } + } +} \ No newline at end of file diff --git a/Octokit/Models/Response/TeamItem.cs b/Octokit/Models/Response/TeamItem.cs new file mode 100644 index 00000000..7d3343a8 --- /dev/null +++ b/Octokit/Models/Response/TeamItem.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + /// + /// organization teams - used for the list + /// + public class TeamItem + { + /// + /// team id + /// + public int Id { get; set; } + + /// + /// team name + /// + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/Octokit/Octokit-Mono.csproj b/Octokit/Octokit-Mono.csproj index 5473ddd6..4b2ae820 100644 --- a/Octokit/Octokit-Mono.csproj +++ b/Octokit/Octokit-Mono.csproj @@ -58,9 +58,11 @@ + + @@ -72,7 +74,10 @@ + + + @@ -94,6 +99,8 @@ + + diff --git a/Octokit/Octokit-MonoAndroid.csproj b/Octokit/Octokit-MonoAndroid.csproj index 556fe0dd..0847f4a8 100644 --- a/Octokit/Octokit-MonoAndroid.csproj +++ b/Octokit/Octokit-MonoAndroid.csproj @@ -206,6 +206,13 @@ + + + + + + + diff --git a/Octokit/Octokit-Monotouch.csproj b/Octokit/Octokit-Monotouch.csproj index 43a8e561..37824954 100644 --- a/Octokit/Octokit-Monotouch.csproj +++ b/Octokit/Octokit-Monotouch.csproj @@ -201,6 +201,13 @@ + + + + + + + diff --git a/Octokit/Octokit-netcore45.csproj b/Octokit/Octokit-netcore45.csproj index 24a83d44..4269348c 100644 --- a/Octokit/Octokit-netcore45.csproj +++ b/Octokit/Octokit-netcore45.csproj @@ -79,6 +79,7 @@ + @@ -89,6 +90,7 @@ + @@ -152,10 +154,13 @@ + + + @@ -189,6 +194,8 @@ + + diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index da8d975e..e4f6eb58 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -59,6 +59,8 @@ + + @@ -80,6 +82,8 @@ + + @@ -87,6 +91,9 @@ + + +