update models with updated permission enum (#2633)

* update models with updated permission enum

* add suppress message attribute

* update integration tests

* refactor: new and legacy update teams endpint

* refactor: add new delete team endpoint

* use TeamPermission on NewTeam

* use updated delete on team context dispose

* add permission enum for team response object

* refactor: remove legacy suffix from method names

* introduce permissions object on Team

* refactor: rename enum to TeamRepositoryPermission

* fix formatting

* change Permission to string to match api specs

* add TeamRepository

* add CheckTeamPermission endpoint support

* fix convention tests

* update comments on TeamRepository props

* add two new endpoints in TeamsClient

* refactor: rename ApiUrl for TeamPermission

* fix test

* implement methods for new endpoints

* add the integration tests

* fix spelling

* update comments

* refactor: rename method name

* fix: add end tag for remarks

* refactor: remove unused method param

* fix docstring comment

* the unit tests are in finally

* add docs for teams api

* split CheckTeamPermissions into two methods

* Update ObservableTeamsClientTests.cs based on review

Co-authored-by: Keegan Campbell <me@kfcampbell.com>

* add cref to legacy update and delete endpoints

* remove editorconfig file

* Update Octokit.Tests/Clients/TeamsClientTests.cs

Co-authored-by: Keegan Campbell <me@kfcampbell.com>

* remove unused line

* rename variable based on review

* rename prop to match constructor param

* add comment to explain TeamPermission enum values on update

Co-authored-by: notauserx <notauserx@users.noreply.github.com>
Co-authored-by: Keegan Campbell <me@kfcampbell.com>
This commit is contained in:
notauserx
2023-01-21 00:48:00 +06:00
committed by GitHub
parent bf6678543f
commit 891015c39f
24 changed files with 2056 additions and 41 deletions

View File

@@ -125,15 +125,53 @@ namespace Octokit.Reactive
IObservable<Team> Create(string org, NewTeam team);
/// <summary>
/// Returns updated <see cref="Team" /> for the current org.
/// Updates a team
/// To edit a team, the authenticated user must either be an organization owner or a team maintainer
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#update-a-team">API documentation</a>
/// for more information.
/// </remarks>
/// <returns>updated <see cref="Team" /> for the current org</returns>
IObservable<Team> Update(string org, string teamSlug, UpdateTeam team);
/// <summary>
/// Returns updated <see cref="Team" /> for the current org.
/// This endpoint route is deprecated and will be removed from the Teams API.
/// We recommend migrating your existing code to use the new Update a team endpoint.
/// <see cref="Update(string, string, UpdateTeam)"/>
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#update-a-team-legacy">API documentation</a>
/// for more information.
/// </remarks>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>Updated <see cref="Team"/></returns>
IObservable<Team> Update(int id, UpdateTeam team);
/// <summary>
/// Delete a team - must have owner permissions to this
/// To delete a team, the authenticated user must be an organization owner or team maintainer.
/// If you are an organization owner, deleting a parent team will delete all of its child teams as well.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#delete-a-team">API documentation</a>
/// </remarks>
/// <param name="org">The organization name. The name is not case sensitive.</param>
/// <param name="teamSlug">The slug of the team name.</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns></returns>
IObservable<Unit> Delete(string org, string teamSlug);
/// <summary>
/// Delete a team - must have owner permissions to do this
/// This endpoint route is deprecated and will be removed from the Teams API.
/// We recommend migrating your existing code to use the new Delete a team endpoint.
/// <see cref="Delete(string, string)"/>.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#delete-a-team-legacy">API documentation</a>
/// </remarks>
/// <param name="id">The unique identifier of the team.</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns></returns>
IObservable<Unit> Delete(int id);
@@ -257,5 +295,72 @@ namespace Octokit.Reactive
/// <param name="options">Options to change API behaviour.</param>
/// <returns></returns>
IObservable<OrganizationMembershipInvitation> GetAllPendingInvitations(int id, ApiOptions options);
/// <summary>
/// Checks whether a team has admin, push, maintain, triage, or pull permission for a repository.
/// Repositories inherited through a parent team will also be checked.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#check-team-permissions-for-a-repository">API Documentation</a>
/// for more information.
/// </remarks>
/// <param name="org">The organization name. The name is not case sensitive.</param>
/// <param name="teamSlug">The slug of the team name.</param>
/// <param name="owner">The account owner of the repository. The name is not case sensitive.</param>
/// <param name="repo">The name of the repository. The name is not case sensitive.</param>
/// <returns></returns>
IObservable<bool> CheckTeamPermissionsForARepository(string org, string teamSlug, string owner, string repo);
/// <summary>
/// Checks whether a team has admin, push, maintain, triage, or pull permission for a repository.
/// Repositories inherited through a parent team will also be checked.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#check-team-permissions-for-a-repository">API Documentation</a>
/// for more information.
/// </remarks>
/// <param name="org">The organization name. The name is not case sensitive.</param>
/// <param name="teamSlug">The slug of the team name.</param>
/// <param name="owner">The account owner of the repository. The name is not case sensitive.</param>
/// <param name="repo">The name of the repository. The name is not case sensitive.</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns></returns>
IObservable<TeamRepository> CheckTeamPermissionsForARepositoryWithCustomAcceptHeader(string org, string teamSlug, string owner, string repo);
/// <summary>
/// Add or update team repository permissions
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#add-or-update-team-repository-permissions">API Documentation</a>
/// for more information.
/// </remarks>
/// <param name="org">The organization name. The name is not case sensitive.</param>
/// <param name="teamSlug">The slug of the team name.</param>
/// <param name="owner">The account owner of the repository. The name is not case sensitive.</param>
/// <param name="repo">The name of the repository. The name is not case sensitive.</param>
/// <param name="permission">
/// The permission to grant the team on this repository. We accept the following permissions to be set:
/// pull, triage, push, maintain, admin and you can also specify a custom repository role name, if the
/// owning organization has defined any. If no permission is specified, the team's permission attribute
/// will be used to determine what permission to grant the team on this repository
/// </param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns></returns>
IObservable<Unit> AddOrUpdateTeamRepositoryPermissions(string org, string teamSlug, string owner, string repo, string permission);
/// <summary>
/// Remove a repository from a team
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#remove-a-repository-from-a-team">API Documentation</a>
/// for more information.
/// </remarks>
/// <param name="org">The organization name. The name is not case sensitive.</param>
/// <param name="teamSlug">The slug of the team name.</param>
/// <param name="owner">The account owner of the repository. The name is not case sensitive.</param>
/// <param name="repo">The name of the repository. The name is not case sensitive.</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns></returns>
IObservable<Unit> RemoveRepositoryFromATeam(string org, string teamSlug, string owner, string repo);
}
}

View File

@@ -194,8 +194,33 @@ namespace Octokit.Reactive
}
/// <summary>
/// Returns updated <see cref="Team" /> for the current org.
/// Updates a team
/// To edit a team, the authenticated user must either be an organization owner or a team maintainer
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#update-a-team">API documentation</a>
/// for more information.
/// </remarks>
/// <returns>updated <see cref="Team" /> for the current org</returns>
public IObservable<Team> Update(string org, string teamSlug, UpdateTeam team)
{
Ensure.ArgumentNotNull(org, nameof(org));
Ensure.ArgumentNotNull(teamSlug, nameof(teamSlug));
Ensure.ArgumentNotNull(team, nameof(team));
return _client.Update(org, teamSlug, team).ToObservable();
}
/// <summary>
/// Returns updated <see cref="Team" /> for the current org.
/// This endpoint route is deprecated and will be removed from the Teams API.
/// We recommend migrating your existing code to use the new Update a team endpoint.
/// <see cref="Update(string, string, UpdateTeam)"/>.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#update-a-team-legacy">API documentation</a>
/// for more information.
/// </remarks>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>Updated <see cref="Team"/></returns>
public IObservable<Team> Update(int id, UpdateTeam team)
@@ -206,8 +231,34 @@ namespace Octokit.Reactive
}
/// <summary>
/// Delete a team - must have owner permissions to this
/// To delete a team, the authenticated user must be an organization owner or team maintainer.
/// If you are an organization owner, deleting a parent team will delete all of its child teams as well.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#delete-a-team">API documentation</a>
/// </remarks>
/// <param name="org">The organization name. The name is not case sensitive.</param>
/// <param name="teamSlug">The slug of the team name.</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns></returns>
public IObservable<Unit> Delete(string org, string teamSlug)
{
Ensure.ArgumentNotNull(org, nameof(org));
Ensure.ArgumentNotNull(teamSlug, nameof(teamSlug));
return _client.Delete(org, teamSlug).ToObservable();
}
/// <summary>
/// Delete a team - must have owner permissions to do this
/// This endpoint route is deprecated and will be removed from the Teams API.
/// We recommend migrating your existing code to use the new Delete a team endpoint.
/// <see cref="Delete(string, string)"/>.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#delete-a-team-legacy">API documentation</a>
/// </remarks>
/// <param name="id">The unique identifier of the team.</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns></returns>
public IObservable<Unit> Delete(int id)
@@ -391,5 +442,86 @@ namespace Octokit.Reactive
return _connection.GetAndFlattenAllPages<OrganizationMembershipInvitation>(ApiUrls.TeamPendingInvitations(id), null, options);
}
/// <summary>
/// Checks whether a team has admin, push, maintain, triage, or pull permission for a repository.
/// Repositories inherited through a parent team will also be checked.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#check-team-permissions-for-a-repository">API Documentation</a>
/// for more information.
/// </remarks>
/// <param name="org">The organization name. The name is not case sensitive.</param>
/// <param name="teamSlug">The slug of the team name.</param>
/// <param name="owner">The account owner of the repository. The name is not case sensitive.</param>
/// <param name="repo">The name of the repository. The name is not case sensitive.</param>
/// <returns></returns>
public IObservable<bool> CheckTeamPermissionsForARepository(string org, string teamSlug, string owner, string repo)
{
return _client.CheckTeamPermissionsForARepository(org, teamSlug, owner, repo).ToObservable();
}
/// <summary>
/// Checks whether a team has admin, push, maintain, triage, or pull permission for a repository.
/// Repositories inherited through a parent team will also be checked.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#check-team-permissions-for-a-repository">API Documentation</a>
/// for more information.
/// </remarks>
/// <param name="org">The organization name. The name is not case sensitive.</param>
/// <param name="teamSlug">The slug of the team name.</param>
/// <param name="owner">The account owner of the repository. The name is not case sensitive.</param>
/// <param name="repo">The name of the repository. The name is not case sensitive.</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns></returns>
public IObservable<TeamRepository> CheckTeamPermissionsForARepositoryWithCustomAcceptHeader(string org, string teamSlug, string owner, string repo)
{
return _client.CheckTeamPermissionsForARepositoryWithCustomAcceptHeader(org, teamSlug, owner, repo).ToObservable();
}
/// <summary>
/// Add or update team repository permissions
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#add-or-update-team-repository-permissions">API Documentation</a>
/// for more information.
/// </remarks>
/// <param name="org">The organization name. The name is not case sensitive.</param>
/// <param name="teamSlug">The slug of the team name.</param>
/// <param name="owner">The account owner of the repository. The name is not case sensitive.</param>
/// <param name="repo">The name of the repository. The name is not case sensitive.</param>
/// <param name="permission">
/// The permission to grant the team on this repository. We accept the following permissions to be set:
/// pull, triage, push, maintain, admin and you can also specify a custom repository role name, if the
/// owning organization has defined any. If no permission is specified, the team's permission attribute
/// will be used to determine what permission to grant the team on this repository
/// </param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns></returns>
[ManualRoute("PUT", "/orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}")]
public IObservable<Unit> AddOrUpdateTeamRepositoryPermissions(string org, string teamSlug, string owner, string repo, string permission)
{
return _client.AddOrUpdateTeamRepositoryPermissions(org, teamSlug, owner, repo, permission).ToObservable();
}
/// <summary>
/// Remove a repository from a team
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#remove-a-repository-from-a-team">API Documentation</a>
/// for more information.
/// </remarks>
/// <param name="org">The organization name. The name is not case sensitive.</param>
/// <param name="teamSlug">The slug of the team name.</param>
/// <param name="owner">The account owner of the repository. The name is not case sensitive.</param>
/// <param name="repo">The name of the repository. The name is not case sensitive.</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns></returns>
[ManualRoute("DELETE", "/orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}")]
public IObservable<Unit> RemoveRepositoryFromATeam(string org, string teamSlug, string owner, string repo)
{
return _client.RemoveRepositoryFromATeam(org, teamSlug, owner, repo).ToObservable();
}
}
}

View File

@@ -70,7 +70,8 @@ namespace Octokit.Tests.Conventions
// https://developer.github.com/v3/repos/commits/#get-a-single-commit
"application/vnd.github.v3.sha",
// https://developer.github.com/v3/activity/starring/#alternative-response-with-star-creation-timestamps
"application/vnd.github.v3.star+json"
"application/vnd.github.v3.star+json",
"application/vnd.github.v3.repository+json"
};
var validHeaders = defaultHeaders.Concat(previewAcceptHeaders);

View File

@@ -1,6 +1,5 @@
using System;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Octokit;
using Octokit.Tests.Integration;
@@ -33,10 +32,12 @@ public class TeamsClientTests
Assert.Equal(teamName, team.Name);
Assert.Equal(teamDescription, team.Description);
Assert.Equal(TeamPrivacy.Closed, team.Privacy);
// Permission defaults to pull when no permission is specified when creating a team
Assert.Equal("pull", team.Permission);
Assert.Equal(1, team.MembersCount);
Assert.Equal(1, team.ReposCount);
await github.Organization.Team.Delete(team.Id);
await github.Organization.Team.Delete(Helper.Organization, team.Slug);
}
}
}
@@ -445,10 +446,49 @@ public class TeamsClientTests
{
var teamName = Helper.MakeNameWithTimestamp("updated-team");
var teamDescription = Helper.MakeNameWithTimestamp("updated description");
var update = new UpdateTeam(teamName)
{
Description = teamDescription,
Privacy = TeamPrivacy.Closed,
Permission = TeamPermission.Push,
ParentTeamId = parentTeamContext.TeamId
};
var team = await _github.Organization.Team.Update(Helper.Organization, teamContext.Team.Slug, update);
Assert.Equal(teamName, team.Name);
Assert.Equal(teamDescription, team.Description);
Assert.Equal(TeamPrivacy.Closed, team.Privacy);
Assert.Equal("push", team.Permission);
Assert.Equal(parentTeamContext.TeamId, team.Parent.Id);
}
}
}
public class TheUpdateLegacyMethod
{
private readonly IGitHubClient _github;
public TheUpdateLegacyMethod()
{
_github = Helper.GetAuthenticatedClient();
}
[OrganizationTest]
public async Task UpdatesTeamLegacy()
{
using (var parentTeamContext = await _github.CreateTeamContext(Helper.Organization, new NewTeam(Helper.MakeNameWithTimestamp("parent-team"))))
using (var teamContext = await _github.CreateTeamContext(Helper.Organization, new NewTeam(Helper.MakeNameWithTimestamp("team-fixture"))))
{
var teamName = Helper.MakeNameWithTimestamp("updated-team");
var teamDescription = Helper.MakeNameWithTimestamp("updated description");
var update = new UpdateTeam(teamName)
{
Description = teamDescription,
Privacy = TeamPrivacy.Closed,
Permission = TeamPermission.Push,
ParentTeamId = parentTeamContext.TeamId
};
@@ -457,8 +497,189 @@ public class TeamsClientTests
Assert.Equal(teamName, team.Name);
Assert.Equal(teamDescription, team.Description);
Assert.Equal(TeamPrivacy.Closed, team.Privacy);
Assert.Equal("push", team.Permission);
Assert.Equal(parentTeamContext.TeamId, team.Parent.Id);
}
}
}
public class TheCheckTeamPermissionsForARepositoryMethod
{
private readonly IGitHubClient github;
public TheCheckTeamPermissionsForARepositoryMethod()
{
github = Helper.GetAuthenticatedClient();
}
[OrganizationTest]
public async Task ChecksTeamPermissions()
{
using (var teamContext = await github.CreateTeamContext(Helper.Organization, new NewTeam(Helper.MakeNameWithTimestamp("team"))))
using (var repositoryContext = await github.CreateOrganizationRepositoryContext(Helper.Organization, new NewRepository(Helper.MakeNameWithTimestamp("teamrepo"))))
{
github.Organization.Team.AddRepository(teamContext.TeamId, Helper.Organization, repositoryContext.RepositoryName);
var teamPermissionResponse = await github.Organization.Team.CheckTeamPermissionsForARepository(
Helper.Organization,
teamContext.Team.Slug,
repositoryContext.RepositoryOwner,
repositoryContext.RepositoryName);
Assert.True(teamPermissionResponse);
}
}
[OrganizationTest]
public async Task ChecksTeamPermissionsReturnsFalseOnNonTeamRepository()
{
using (var teamContext = await github.CreateTeamContext(Helper.Organization, new NewTeam(Helper.MakeNameWithTimestamp("team"))))
using (var repositoryContext = await github.CreateOrganizationRepositoryContext(Helper.Organization, new NewRepository(Helper.MakeNameWithTimestamp("teamrepo"))))
{
var response = await github.Organization.Team.CheckTeamPermissionsForARepository(
Helper.Organization,
teamContext.Team.Slug,
repositoryContext.RepositoryOwner,
repositoryContext.RepositoryName);
Assert.False(response);
}
}
}
public class TheCheckTeamPermissionsForARepositoryWithCustomAcceptHeaderMethod
{
private readonly IGitHubClient github;
public TheCheckTeamPermissionsForARepositoryWithCustomAcceptHeaderMethod()
{
github = Helper.GetAuthenticatedClient();
}
[OrganizationTest]
public async Task ChecksTeamPermissionsWithRepositoryMediaTypeInAccepts()
{
using (var teamContext = await github.CreateTeamContext(Helper.Organization, new NewTeam(Helper.MakeNameWithTimestamp("team"))))
using (var repositoryContext = await github.CreateOrganizationRepositoryContext(Helper.Organization, new NewRepository(Helper.MakeNameWithTimestamp("teamrepo"))))
{
github.Organization.Team.AddRepository(teamContext.TeamId, Helper.Organization, repositoryContext.RepositoryName);
var teamPermission = await github.Organization.Team.CheckTeamPermissionsForARepositoryWithCustomAcceptHeader(
Helper.Organization,
teamContext.Team.Slug,
repositoryContext.RepositoryOwner,
repositoryContext.RepositoryName);
Assert.NotNull(teamPermission);
Assert.NotNull(teamPermission.Permissions);
Assert.True(teamPermission.Permissions.Pull);
}
}
[OrganizationTest]
public async Task ChecksTeamPermissionsThrowsNotFoundException()
{
using (var teamContext = await github.CreateTeamContext(Helper.Organization, new NewTeam(Helper.MakeNameWithTimestamp("team"))))
using (var repositoryContext = await github.CreateOrganizationRepositoryContext(Helper.Organization, new NewRepository(Helper.MakeNameWithTimestamp("teamrepo"))))
{
await Assert.ThrowsAsync<NotFoundException>(async () =>
await github.Organization.Team.CheckTeamPermissionsForARepositoryWithCustomAcceptHeader(
Helper.Organization,
teamContext.Team.Slug,
repositoryContext.RepositoryOwner,
repositoryContext.RepositoryName));
}
}
}
public class TheAddOrUpdateTeamRepositoryPermissionsMethod
{
[OrganizationTest]
public async Task AddsTeamRepositoryPermissions()
{
var github = Helper.GetAuthenticatedClient();
using (var teamContext = await github.CreateTeamContext(Helper.Organization, new NewTeam(Helper.MakeNameWithTimestamp("team"))))
using (var repoContext = await github.CreateOrganizationRepositoryContext(Helper.Organization, new NewRepository(Helper.MakeNameWithTimestamp("team-repository"))))
{
var teamRepositories = await github.Organization.Team.GetAllRepositories(teamContext.TeamId);
Assert.Equal(0, teamRepositories.Count);
await github.Organization.Team.AddOrUpdateTeamRepositoryPermissions(
Helper.Organization,
teamContext.Team.Slug,
repoContext.RepositoryOwner,
repoContext.RepositoryName,
"admin");
teamRepositories = await github.Organization.Team.GetAllRepositories(teamContext.TeamId);
Assert.True(teamRepositories.First(x => x.Id == repoContext.RepositoryId).Permissions.Admin);
}
}
[OrganizationTest]
public async Task UpdatesTeamRepositoryPermissions()
{
var github = Helper.GetAuthenticatedClient();
using (var teamContext = await github.CreateTeamContext(Helper.Organization, new NewTeam(Helper.MakeNameWithTimestamp("team"))))
using (var repoContext = await github.CreateOrganizationRepositoryContext(Helper.Organization, new NewRepository(Helper.MakeNameWithTimestamp("team-repository"))))
{
await github.Organization.Team.AddOrUpdateTeamRepositoryPermissions(
Helper.Organization,
teamContext.Team.Slug,
repoContext.RepositoryOwner,
repoContext.RepositoryName,
"admin");
var teamRepositories = await github.Organization.Team.GetAllRepositories(teamContext.TeamId);
Assert.True(teamRepositories.First(x => x.Id == repoContext.RepositoryId).Permissions.Admin);
await github.Organization.Team.AddOrUpdateTeamRepositoryPermissions(
Helper.Organization,
teamContext.Team.Slug,
repoContext.RepositoryOwner,
repoContext.RepositoryName,
"maintain");
teamRepositories = await github.Organization.Team.GetAllRepositories(teamContext.TeamId);
Assert.False(teamRepositories.First(x => x.Id == repoContext.RepositoryId).Permissions.Admin);
Assert.True(teamRepositories.First(x => x.Id == repoContext.RepositoryId).Permissions.Maintain);
}
}
}
public class TheRemoveRepositoryFromATeamMethod
{
[OrganizationTest]
public async Task RemovesRepositoryFromATeam()
{
var github = Helper.GetAuthenticatedClient();
using (var teamContext = await github.CreateTeamContext(Helper.Organization, new NewTeam(Helper.MakeNameWithTimestamp("team"))))
using (var repoContext = await github.CreateOrganizationRepositoryContext(Helper.Organization, new NewRepository(Helper.MakeNameWithTimestamp("team-repository"))))
{
await github.Organization.Team.AddOrUpdateTeamRepositoryPermissions(
Helper.Organization,
teamContext.Team.Slug,
repoContext.RepositoryOwner,
repoContext.RepositoryName,
"admin");
await github.Organization.Team.RemoveRepositoryFromATeam(
Helper.Organization,
teamContext.Team.Slug,
repoContext.RepositoryOwner,
repoContext.RepositoryName);
var addedRepo = await github.Organization.Team.GetAllRepositories(teamContext.TeamId);
Assert.Equal(0, addedRepo.Count);
}
}
}
}

View File

@@ -190,15 +190,15 @@ namespace Octokit.Tests.Integration
public static void DeleteTeam(IConnection connection, Team team)
{
if (team != null)
DeleteTeam(connection, team.Id);
DeleteTeam(connection, team.Slug);
}
public static void DeleteTeam(IConnection connection, int teamId)
public static void DeleteTeam(IConnection connection, string slug)
{
try
{
var client = new GitHubClient(connection);
client.Organization.Team.Delete(teamId).Wait(TimeSpan.FromSeconds(15));
client.Organization.Team.Delete(Organization, slug).Wait(TimeSpan.FromSeconds(15));
}
catch { }
}

View File

@@ -36,6 +36,13 @@ namespace Octokit.Tests.Integration.Helpers
return new TeamContext(client.Connection, team);
}
internal static async Task<RepositoryContext> CreateOrganizationRepositoryContext(this IObservableGitHubClient client, string organizationLogin, NewRepository newRepository)
{
var repo = await client.Repository.Create(organizationLogin, newRepository);
return new RepositoryContext(client.Connection, repo);
}
internal static async Task<EnterpriseUserContext> CreateEnterpriseUserContext(this IObservableGitHubClient client, NewUser newUser)
{
var user = await client.User.Administration.Create(newUser);

View File

@@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Octokit.Tests.Integration.Helpers
{

View File

@@ -386,12 +386,239 @@ public class ObservableTeamsClientTests
ParentTeamId = parentTeamContext.TeamId
};
var team = await _github.Organization.Team.Update(Helper.Organization, teamContext.Team.Slug, update);
Assert.Equal(teamName, team.Name);
Assert.Equal(teamDescription, team.Description);
Assert.Equal(TeamPrivacy.Closed, team.Privacy);
Assert.Equal(parentTeamContext.TeamId, team.Parent.Id);
_github.Organization.Team.Delete(Helper.Organization, team.Slug);
}
}
}
public class TheUpdateLegacyMethod
{
private readonly IObservableGitHubClient _github;
public TheUpdateLegacyMethod()
{
_github = new ObservableGitHubClient(Helper.GetAuthenticatedClient());
}
[OrganizationTest]
public async Task UpdatesTeamLegacy()
{
using (var parentTeamContext = await _github.CreateTeamContext(Helper.Organization, new NewTeam(Helper.MakeNameWithTimestamp("parent-team"))))
using (var teamContext = await _github.CreateTeamContext(Helper.Organization, new NewTeam(Helper.MakeNameWithTimestamp("team-fixture"))))
{
var teamName = Helper.MakeNameWithTimestamp("updated-team");
var teamDescription = Helper.MakeNameWithTimestamp("updated description");
var update = new UpdateTeam(teamName)
{
Description = teamDescription,
Privacy = TeamPrivacy.Closed,
ParentTeamId = parentTeamContext.TeamId
};
var team = await _github.Organization.Team.Update(teamContext.TeamId, update);
Assert.Equal(teamName, team.Name);
Assert.Equal(teamDescription, team.Description);
Assert.Equal(TeamPrivacy.Closed, team.Privacy);
Assert.Equal(parentTeamContext.TeamId, team.Parent.Id);
_github.Organization.Team.Delete(teamContext.TeamId);
}
}
}
public class TheCheckTeamPermissionsForARepositoryMethod
{
private readonly IObservableGitHubClient _github;
public TheCheckTeamPermissionsForARepositoryMethod()
{
_github = new ObservableGitHubClient(Helper.GetAuthenticatedClient());
}
[OrganizationTest]
public async Task ChecksTeamPermissions()
{
using (var teamContext = await _github.CreateTeamContext(Helper.Organization, new NewTeam(Helper.MakeNameWithTimestamp("team"))))
using (var repositoryContext = await _github.CreateOrganizationRepositoryContext(Helper.Organization, new NewRepository(Helper.MakeNameWithTimestamp("teamrepo"))))
{
_github.Organization.Team.AddRepository(teamContext.TeamId, Helper.Organization, repositoryContext.RepositoryName);
var teamPermissionResponse = await _github.Organization.Team.CheckTeamPermissionsForARepository(
Helper.Organization,
teamContext.Team.Slug,
repositoryContext.RepositoryOwner,
repositoryContext.RepositoryName);
Assert.True(teamPermissionResponse);
}
}
[OrganizationTest]
public async Task ChecksTeamPermissionsReturnsFalseOnNonTeamRepository()
{
using (var teamContext = await _github.CreateTeamContext(Helper.Organization, new NewTeam(Helper.MakeNameWithTimestamp("team"))))
using (var repositoryContext = await _github.CreateOrganizationRepositoryContext(Helper.Organization, new NewRepository(Helper.MakeNameWithTimestamp("teamrepo"))))
{
var response = await _github.Organization.Team.CheckTeamPermissionsForARepository(
Helper.Organization,
teamContext.Team.Slug,
repositoryContext.RepositoryOwner,
repositoryContext.RepositoryName);
Assert.False(response);
}
}
}
public class TheCheckTeamPermissionsForARepositoryWithCustomAcceptHeaderMethod
{
private readonly IObservableGitHubClient _github;
public TheCheckTeamPermissionsForARepositoryWithCustomAcceptHeaderMethod()
{
_github = new ObservableGitHubClient(Helper.GetAuthenticatedClient());
}
[OrganizationTest]
public async Task ChecksTeamPermissions()
{
using (var teamContext = await _github.CreateTeamContext(Helper.Organization, new NewTeam(Helper.MakeNameWithTimestamp("team"))))
using (var repositoryContext = await _github.CreateOrganizationRepositoryContext(Helper.Organization, new NewRepository(Helper.MakeNameWithTimestamp("teamrepo"))))
{
_github.Organization.Team.AddRepository(teamContext.TeamId, Helper.Organization, repositoryContext.RepositoryName);
var teamPermissionResponse = await _github.Organization.Team.CheckTeamPermissionsForARepositoryWithCustomAcceptHeader(
Helper.Organization,
teamContext.Team.Slug,
repositoryContext.RepositoryOwner,
repositoryContext.RepositoryName);
Assert.NotNull(teamPermissionResponse);
}
}
[OrganizationTest]
public async Task ChecksTeamPermissionsThrowsNotFoundException()
{
using (var teamContext = await _github.CreateTeamContext(Helper.Organization, new NewTeam(Helper.MakeNameWithTimestamp("team"))))
using (var repositoryContext = await _github.CreateOrganizationRepositoryContext(Helper.Organization, new NewRepository(Helper.MakeNameWithTimestamp("teamrepo"))))
{
await Assert.ThrowsAsync<NotFoundException>(async () =>
await _github.Organization.Team.CheckTeamPermissionsForARepositoryWithCustomAcceptHeader(
Helper.Organization,
teamContext.Team.Slug,
repositoryContext.RepositoryOwner,
repositoryContext.RepositoryName));
}
}
}
public class TheAddOrUpdateTeamRepositoryPermissionsMethod
{
private readonly IObservableGitHubClient _github;
public TheAddOrUpdateTeamRepositoryPermissionsMethod()
{
_github = new ObservableGitHubClient(Helper.GetAuthenticatedClient());
}
[OrganizationTest]
public async Task AddsTeamRepositoryPermissions()
{
using (var teamContext = await _github.CreateTeamContext(Helper.Organization, new NewTeam(Helper.MakeNameWithTimestamp("team"))))
using (var repoContext = await _github.CreateOrganizationRepositoryContext(Helper.Organization, new NewRepository(Helper.MakeNameWithTimestamp("team-repository"))))
{
var teamRepository = await _github.Organization.Team
.GetAllRepositories(teamContext.TeamId)
.FirstOrDefaultAsync(x => x.Id == repoContext.RepositoryId);
Assert.Null(teamRepository);
await _github.Organization.Team.AddOrUpdateTeamRepositoryPermissions(
Helper.Organization,
teamContext.Team.Slug,
repoContext.RepositoryOwner,
repoContext.RepositoryName,
"admin");
teamRepository = await _github.Organization.Team
.GetAllRepositories(teamContext.TeamId)
.FirstOrDefaultAsync(x => x.Id == repoContext.RepositoryId);
Assert.NotNull(teamRepository);
}
}
[OrganizationTest]
public async Task UpdatesTeamRepositoryPermissions()
{
using (var teamContext = await _github.CreateTeamContext(Helper.Organization, new NewTeam(Helper.MakeNameWithTimestamp("team"))))
using (var repoContext = await _github.CreateOrganizationRepositoryContext(Helper.Organization, new NewRepository(Helper.MakeNameWithTimestamp("team-repository"))))
{
await _github.Organization.Team.AddOrUpdateTeamRepositoryPermissions(
Helper.Organization,
teamContext.Team.Slug,
repoContext.RepositoryOwner,
repoContext.RepositoryName,
"admin");
var teamRepository = await _github.Organization.Team
.GetAllRepositories(teamContext.TeamId)
.FirstOrDefaultAsync(x => x.Id == repoContext.RepositoryId);
Assert.True(teamRepository.Permissions.Admin);
await _github.Organization.Team.AddOrUpdateTeamRepositoryPermissions(
Helper.Organization,
teamContext.Team.Slug,
repoContext.RepositoryOwner,
repoContext.RepositoryName,
"maintain");
teamRepository = await _github.Organization.Team
.GetAllRepositories(teamContext.TeamId)
.FirstOrDefaultAsync(x => x.Id == repoContext.RepositoryId);
Assert.True(teamRepository.Permissions.Maintain);
Assert.False(teamRepository.Permissions.Admin);
}
}
}
public class TheRemoveRepositoryFromATeamMethod
{
[OrganizationTest]
public async Task RemovesRepositoryFromATeam()
{
var github = new ObservableGitHubClient(Helper.GetAuthenticatedClient());
using (var teamContext = await github.CreateTeamContext(Helper.Organization, new NewTeam(Helper.MakeNameWithTimestamp("team"))))
using (var repoContext = await github.CreateOrganizationRepositoryContext(Helper.Organization, new NewRepository(Helper.MakeNameWithTimestamp("team-repository"))))
{
await github.Organization.Team.AddOrUpdateTeamRepositoryPermissions(
Helper.Organization,
teamContext.Team.Slug,
repoContext.RepositoryOwner,
repoContext.RepositoryName,
"admin");
await github.Organization.Team.RemoveRepositoryFromATeam(
Helper.Organization,
teamContext.Team.Slug,
repoContext.RepositoryOwner,
repoContext.RepositoryName);
var addedRepo = await github.Organization.Team.GetAllRepositories(teamContext.TeamId).ToList();
Assert.Equal(0, addedRepo.Count);
}
}
}

View File

@@ -169,6 +169,36 @@ namespace Octokit.Tests.Clients
var client = new TeamsClient(connection);
var team = new UpdateTeam("Octokittens");
var org = "org";
var slug = "slug";
client.Update(org, slug , team);
connection.Received().Patch<Team>(
Arg.Is<Uri>(u => u.ToString() == "orgs/org/teams/slug"),
team);
}
[Fact]
public async Task EnsuresNonNullArguments()
{
var connection = Substitute.For<IApiConnection>();
var client = new TeamsClient(connection);
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Update(null, "b", new UpdateTeam("update-team")));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Update("a", null, new UpdateTeam("update-team")));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Update("a", "b", null));
}
}
public class TheUpdateTeamLegacyMethod
{
[Fact]
public void RequestsTheCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new TeamsClient(connection);
var team = new UpdateTeam("Octokittens");
client.Update(1, team);
connection.Received().Patch<Team>(
@@ -187,6 +217,34 @@ namespace Octokit.Tests.Clients
}
public class TheDeleteTeamMethod
{
[Fact]
public void RequestsTheCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new TeamsClient(connection);
var org = "org";
var slug = "slug";
client.Delete(org, slug);
connection.Received().Delete(
Arg.Is<Uri>(u => u.ToString() == "orgs/org/teams/slug"));
}
[Fact]
public async Task EnsuresNonNullArguments()
{
var connection = Substitute.For<IApiConnection>();
var client = new TeamsClient(connection);
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Delete("a", null));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Delete(null, "a"));
}
}
public class TheDeleteTeamLegacyMethod
{
[Fact]
public void RequestsTheCorrectUrl()
@@ -413,5 +471,152 @@ namespace Octokit.Tests.Clients
Args.ApiOptions);
}
}
public class TheCheckTeamPermissionsForARepositoryMethod
{
[Fact]
public async Task EnsuresNonNullOrEmptyArguments()
{
var connection = Substitute.For<IApiConnection>();
var client = new TeamsClient(connection);
await Assert.ThrowsAsync<ArgumentNullException>(() => client.CheckTeamPermissionsForARepository(null, "teamSlug", "owner", "repo"));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.CheckTeamPermissionsForARepository("org", null, "owner", "repo"));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.CheckTeamPermissionsForARepository("org", "teamSlug", null, "repo"));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.CheckTeamPermissionsForARepository("org", "teamSlug", "owner", null));
}
[Fact]
public async Task RequestsTheCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new TeamsClient(connection);
await client.CheckTeamPermissionsForARepository("org", "teamSlug", "owner", "repo");
var expected = "/orgs/org/teams/teamSlug/repos/owner/repo";
connection.Received().Get<TeamRepository>(Arg.Is<Uri>(u => u.ToString() == expected));
}
}
public class TheCheckTeamPermissionsForARepositoryWithCustomAcceptHeaderMethod
{
[Fact]
public async Task EnsuresNonNullOrEmptyArguments()
{
var connection = Substitute.For<IApiConnection>();
var client = new TeamsClient(connection);
await Assert.ThrowsAsync<ArgumentNullException>(() =>
client.CheckTeamPermissionsForARepositoryWithCustomAcceptHeader(null, "teamSlug", "owner", "repo"));
await Assert.ThrowsAsync<ArgumentNullException>(() =>
client.CheckTeamPermissionsForARepositoryWithCustomAcceptHeader("org", null, "owner", "repo"));
await Assert.ThrowsAsync<ArgumentNullException>(() =>
client.CheckTeamPermissionsForARepositoryWithCustomAcceptHeader("org", "teamSlug", null, "repo"));
await Assert.ThrowsAsync<ArgumentNullException>(() =>
client.CheckTeamPermissionsForARepositoryWithCustomAcceptHeader("org", "teamSlug", "owner", null));
}
[Fact]
public async Task RequestsTheCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new TeamsClient(connection);
await client.CheckTeamPermissionsForARepositoryWithCustomAcceptHeader("org", "teamSlug", "owner", "repo");
var expected = "/orgs/org/teams/teamSlug/repos/owner/repo";
connection.Received().Get<TeamRepository>(
Arg.Is<Uri>(u => u.ToString() == expected),
null,
Arg.Is<string>(s => s.Equals("application/vnd.github.v3.repository+json")));
}
}
public class TheAddOrUpdateTeamRepositoryPermissionsMethod
{
[Fact]
public async Task EnsuresNonNullOrEmptyArguments()
{
var connection = Substitute.For<IApiConnection>();
var client = new TeamsClient(connection);
await Assert.ThrowsAsync<ArgumentNullException>(() => client.AddOrUpdateTeamRepositoryPermissions(null, "teamSlug", "owner", "repo", "permission"));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.AddOrUpdateTeamRepositoryPermissions("org", null, "owner", "repo", "permission"));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.AddOrUpdateTeamRepositoryPermissions("org", "teamSlug", null, "repo", "permission"));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.AddOrUpdateTeamRepositoryPermissions("org", "teamSlug", "owner", null, "permission"));
}
[Fact]
public async Task EnsuresNullPermissionValueDoesNotThrow()
{
var connection = Substitute.For<IApiConnection>();
var client = new TeamsClient(connection);
var exception = await Record.ExceptionAsync(() => client.AddOrUpdateTeamRepositoryPermissions("org", "teamSlug", "owner", "repo", null));
Assert.Null(exception);
}
[Fact]
public async Task RequestsTheCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new TeamsClient(connection);
var permission = "a";
await client.AddOrUpdateTeamRepositoryPermissions("org", "teamSlug", "owner", "repo", permission);
var expected = "/orgs/org/teams/teamSlug/repos/owner/repo";
connection.Received().Put(
Arg.Is<Uri>(u => u.ToString() == expected),
Arg.Any<object>());
}
[Fact]
public async Task PassesTheCorrestPermission()
{
var connection = Substitute.For<IApiConnection>();
var client = new TeamsClient(connection);
var permission = "a";
await client.AddOrUpdateTeamRepositoryPermissions("org", "teamSlug", "owner", "repo", permission);
connection.Received().Put(
Arg.Any<Uri>(),
Arg.Is<object>(o => o.GetType().GetProperty("permission").GetValue(o).ToString() == "a"));
}
}
public class TheRemoveRepositoryFromATeamMethod
{
[Fact]
public async Task EnsuresNonNullOrEmptyArguments()
{
var connection = Substitute.For<IApiConnection>();
var client = new TeamsClient(connection);
await Assert.ThrowsAsync<ArgumentNullException>(() => client.RemoveRepositoryFromATeam(null, "teamSlug", "owner", "repo"));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.RemoveRepositoryFromATeam("org", null, "owner", "repo"));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.RemoveRepositoryFromATeam("org", "teamSlug", null, "repo"));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.RemoveRepositoryFromATeam("org", "teamSlug", "owner", null));
}
[Fact]
public async Task RequestsTheCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new TeamsClient(connection);
await client.RemoveRepositoryFromATeam("org", "teamSlug", "owner", "repo");
var expected = "/orgs/org/teams/teamSlug/repos/owner/repo";
connection.Received().Delete(Arg.Is<Uri>(u => u.ToString() == expected));
}
}
}
}

View File

@@ -472,13 +472,10 @@ namespace Octokit.Tests
var result = new SimpleJsonSerializer().Deserialize<Team>(teamJson);
// original value works as expected
Assert.Equal(PermissionLevel.Admin, result.Permission.Value);
Assert.Equal("admin", result.Permission.StringValue);
Assert.Equal("admin", result.Permission);
// parent permission is marked as null and cannot be parsed
Assert.Equal("null", result.Parent.Permission.StringValue);
PermissionLevel value;
Assert.False(result.Parent.Permission.TryParse(out value));
Assert.Null(result.Parent.Permission);
}
}

View File

@@ -126,15 +126,53 @@ namespace Octokit
Task<Team> Create(string org, NewTeam team);
/// <summary>
/// Returns updated <see cref="Team" /> for the current org.
/// Updates a team
/// To edit a team, the authenticated user must either be an organization owner or a team maintainer
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#update-a-team">API documentation</a>
/// for more information.
/// </remarks>
/// <returns>updated <see cref="Team" /> for the current org</returns>
Task<Team> Update(string org, string teamSlug, UpdateTeam team);
/// <summary>
/// Returns updated <see cref="Team" /> for the current org.
/// This endpoint route is deprecated and will be removed from the Teams API.
/// We recommend migrating your existing code to use the new Update a team endpoint.
/// <see cref="Update(string, string, UpdateTeam)"/>.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#update-a-team-legacy">API documentation</a>
/// for more information.
/// </remarks>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>Updated <see cref="Team"/></returns>
Task<Team> Update(int id, UpdateTeam team);
/// <summary>
/// Delte a team - must have owner permissions to this
/// To delete a team, the authenticated user must be an organization owner or team maintainer.
/// If you are an organization owner, deleting a parent team will delete all of its child teams as well.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#delete-a-team">API documentation</a>
/// </remarks>
/// <param name="org">The organization name. The name is not case sensitive.</param>
/// <param name="teamSlug">The slug of the team name.</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns></returns>
Task Delete(string org, string teamSlug);
/// <summary>
/// Delete a team - must have owner permissions to do this
/// This endpoint route is deprecated and will be removed from the Teams API.
/// We recommend migrating your existing code to use the new Delete a team endpoint.
/// <see cref="Delete(string, string)"/>.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#delete-a-team-legacy">API documentation</a>
/// </remarks>
/// <param name="id">The unique identifier of the team.</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns></returns>
Task Delete(int id);
@@ -249,5 +287,72 @@ namespace Octokit
/// <param name="options">Options to change API behaviour.</param>
/// <returns></returns>
Task<IReadOnlyList<OrganizationMembershipInvitation>> GetAllPendingInvitations(int id, ApiOptions options);
/// <summary>
/// Checks whether a team has admin, push, maintain, triage, or pull permission for a repository.
/// Repositories inherited through a parent team will also be checked.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#check-team-permissions-for-a-repository">API Documentation</a>
/// for more information.
/// </remarks>
/// <param name="org">The organization name. The name is not case sensitive.</param>
/// <param name="teamSlug">The slug of the team name.</param>
/// <param name="owner">The account owner of the repository. The name is not case sensitive.</param>
/// <param name="repo">The name of the repository. The name is not case sensitive.</param>
/// <returns></returns>
Task<bool> CheckTeamPermissionsForARepository(string org, string teamSlug, string owner, string repo);
/// <summary>
/// Checks whether a team has admin, push, maintain, triage, or pull permission for a repository.
/// Repositories inherited through a parent team will also be checked.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#check-team-permissions-for-a-repository">API Documentation</a>
/// for more information.
/// </remarks>
/// <param name="org">The organization name. The name is not case sensitive.</param>
/// <param name="teamSlug">The slug of the team name.</param>
/// <param name="owner">The account owner of the repository. The name is not case sensitive.</param>
/// <param name="repo">The name of the repository. The name is not case sensitive.</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns></returns>
Task<TeamRepository> CheckTeamPermissionsForARepositoryWithCustomAcceptHeader(string org, string teamSlug, string owner, string repo);
/// <summary>
/// Add or update team repository permissions
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#add-or-update-team-repository-permissions">API Documentation</a>
/// for more information.
/// </remarks>
/// <param name="org">The organization name. The name is not case sensitive.</param>
/// <param name="teamSlug">The slug of the team name.</param>
/// <param name="owner">The account owner of the repository. The name is not case sensitive.</param>
/// <param name="repo">The name of the repository. The name is not case sensitive.</param>
/// <param name="permission">
/// The permission to grant the team on this repository. We accept the following permissions to be set:
/// pull, triage, push, maintain, admin and you can also specify a custom repository role name, if the
/// owning organization has defined any. If no permission is specified, the team's permission attribute
/// will be used to determine what permission to grant the team on this repository
/// </param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns></returns>
Task AddOrUpdateTeamRepositoryPermissions(string org, string teamSlug, string owner, string repo, string permission);
/// <summary>
/// Remove a repository from a team
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#remove-a-repository-from-a-team">API Documentation</a>
/// for more information.
/// </remarks>
/// <param name="org">The organization name. The name is not case sensitive.</param>
/// <param name="teamSlug">The slug of the team name.</param>
/// <param name="owner">The account owner of the repository. The name is not case sensitive.</param>
/// <param name="repo">The name of the repository. The name is not case sensitive.</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns></returns>
Task RemoveRepositoryFromATeam(string org, string teamSlug, string owner, string repo);
}
}

View File

@@ -228,8 +228,35 @@ namespace Octokit
}
/// <summary>
/// Returns updated <see cref="Team" /> for the current org.
/// Updates a team
/// To edit a team, the authenticated user must either be an organization owner or a team maintainer
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#update-a-team">API documentation</a>
/// for more information.
/// </remarks>
/// <returns>updated <see cref="Team" /> for the current org</returns>
[ManualRoute("PATCH", "/orgs/{org}/teams/{team_slug}")]
public Task<Team> Update(string org, string teamSlug, UpdateTeam team)
{
Ensure.ArgumentNotNull(org, nameof(org));
Ensure.ArgumentNotNull(teamSlug, nameof(teamSlug));
Ensure.ArgumentNotNull(team, nameof(team));
var endpoint = ApiUrls.TeamsByOrganizationAndSlug(org, teamSlug);
return ApiConnection.Patch<Team>(endpoint, team);
}
/// <summary>
/// Returns updated <see cref="Team" /> for the current org.
/// This endpoint route is deprecated and will be removed from the Teams API.
/// We recommend migrating your existing code to use the new Update a team endpoint.
/// <see cref="Update(string, string, UpdateTeam)"/>.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#update-a-team-legacy">API documentation</a>
/// for more information.
/// </remarks>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>Updated <see cref="Team"/></returns>
[ManualRoute("PATCH", "/teams/{team_id}")]
@@ -242,8 +269,37 @@ namespace Octokit
}
/// <summary>
/// Delte a team - must have owner permissions to this
/// To delete a team, the authenticated user must be an organization owner or team maintainer.
/// If you are an organization owner, deleting a parent team will delete all of its child teams as well.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#delete-a-team">API documentation</a>
/// </remarks>
/// <param name="org">The organization name. The name is not case sensitive.</param>
/// <param name="teamSlug">The slug of the team name.</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns></returns>
[ManualRoute("DELETE", "/orgs/{org}/teams/{team_slug}")]
public Task Delete(string org, string teamSlug)
{
Ensure.ArgumentNotNull(org, nameof(org));
Ensure.ArgumentNotNull(teamSlug, nameof(teamSlug));
var endpoint = ApiUrls.TeamsByOrganizationAndSlug(org, teamSlug);
return ApiConnection.Delete(endpoint);
}
/// <summary>
/// Delete a team - must have owner permissions to do this
/// This endpoint route is deprecated and will be removed from the Teams API.
/// We recommend migrating your existing code to use the new Delete a team endpoint.
/// <see cref="Delete(string, string)"/>.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#delete-a-team-legacy">API documentation</a>
/// </remarks>
/// <param name="id">The unique identifier of the team.</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns></returns>
[ManualRoute("DELETE", "/teams/{team_id}")]
@@ -332,11 +388,13 @@ namespace Octokit
}
/// <summary>
/// Add a repository to the team
/// Add or update team repository permissions (Legacy)
/// Deprecation Notice: This endpoint route is deprecated and will be removed from the Teams API.
/// We recommend migrating your existing code to use the new "Add or update team repository permissions" endpoint.
/// </summary>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns></returns>
[ManualRoute("PUT", "/orgs/{org}/team/{team_slug}/repos/{owner}/{repo}")]
[ManualRoute("PUT", "/teams/{team_id}/repos/{owner}/{repo}")]
public async Task<bool> AddRepository(int id, string organization, string repoName)
{
Ensure.ArgumentNotNullOrEmptyString(organization, nameof(organization));
@@ -368,7 +426,9 @@ namespace Octokit
}
/// <summary>
/// Add a repository to the team
/// Add or update team repository permissions (Legacy)
/// Deprecation Notice: This endpoint route is deprecated and will be removed from the Teams API.
/// We recommend migrating your existing code to use the new "Add or update team repository permissions" endpoint.
/// </summary>
/// <param name="id">The team identifier.</param>
/// <param name="organization">Org to associate the repo with.</param>
@@ -376,7 +436,7 @@ namespace Octokit
/// <param name="permission">The permission to grant the team on this repository.</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns></returns>
[ManualRoute("PUT", "/orgs/{org}/team/{team_slug}/repos/{owner}/{repo}")]
[ManualRoute("PUT", "/teams/{team_id}/repos/{owner}/{repo}")]
public async Task<bool> AddRepository(int id, string organization, string repoName, RepositoryPermissionRequest permission)
{
Ensure.ArgumentNotNullOrEmptyString(organization, nameof(organization));
@@ -408,11 +468,13 @@ namespace Octokit
}
/// <summary>
/// Remove a repository from the team
/// Remove a repository from a team (Legacy)
/// Deprecation Notice: This endpoint route is deprecated and will be removed from the Teams API.
/// We recommend migrating your existing code to use the new Remove a repository from a team endpoint.
/// </summary>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns></returns>
[ManualRoute("DELETE", "/orgs/:org/teams/:team_slug/repos/:owner/:repo")]
[ManualRoute("DELETE", "/teams/{team_id}/repos/{owner}/{repo}")]
public async Task<bool> RemoveRepository(int id, string organization, string repoName)
{
Ensure.ArgumentNotNullOrEmptyString(organization, nameof(organization));
@@ -505,5 +567,124 @@ namespace Octokit
{
return ApiConnection.GetAll<OrganizationMembershipInvitation>(ApiUrls.TeamPendingInvitations(id), null, options);
}
/// <summary>
/// Checks whether a team has admin, push, maintain, triage, or pull permission for a repository.
/// Repositories inherited through a parent team will also be checked.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#check-team-permissions-for-a-repository">API Documentation</a>
/// for more information.
/// </remarks>
/// <param name="org">The organization name. The name is not case sensitive.</param>
/// <param name="teamSlug">The slug of the team name.</param>
/// <param name="owner">The account owner of the repository. The name is not case sensitive.</param>
/// <param name="repo">The name of the repository. The name is not case sensitive.</param>
/// <returns></returns>
[ManualRoute("GET", "/orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}")]
public async Task<bool> CheckTeamPermissionsForARepository(string org, string teamSlug, string owner, string repo)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
Ensure.ArgumentNotNullOrEmptyString(teamSlug, nameof(teamSlug));
Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
Ensure.ArgumentNotNullOrEmptyString(repo, nameof(repo));
var endpoint = ApiUrls.TeamPermissionsForARepository(org, teamSlug, owner, repo);
try
{
var response = await ApiConnection.Get<TeamRepository>(endpoint);
return response == null;
}
catch(NotFoundException)
{
return false;
}
}
/// <summary>
/// Checks whether a team has admin, push, maintain, triage, or pull permission for a repository.
/// Repositories inherited through a parent team will also be checked.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#check-team-permissions-for-a-repository">API Documentation</a>
/// for more information.
/// </remarks>
/// <param name="org">The organization name. The name is not case sensitive.</param>
/// <param name="teamSlug">The slug of the team name.</param>
/// <param name="owner">The account owner of the repository. The name is not case sensitive.</param>
/// <param name="repo">The name of the repository. The name is not case sensitive.</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns></returns>
[ManualRoute("GET", "/orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}")]
public Task<TeamRepository> CheckTeamPermissionsForARepositoryWithCustomAcceptHeader(string org, string teamSlug, string owner, string repo)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
Ensure.ArgumentNotNullOrEmptyString(teamSlug, nameof(teamSlug));
Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
Ensure.ArgumentNotNullOrEmptyString(repo, nameof(repo));
var endpoint = ApiUrls.TeamPermissionsForARepository(org, teamSlug, owner, repo);
return ApiConnection.Get<TeamRepository>(endpoint, null, AcceptHeaders.RepositoryContentMediaType);
}
/// <summary>
/// Add or update team repository permissions
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#add-or-update-team-repository-permissions">API Documentation</a>
/// for more information.
/// </remarks>
/// <param name="org">The organization name. The name is not case sensitive.</param>
/// <param name="teamSlug">The slug of the team name.</param>
/// <param name="owner">The account owner of the repository. The name is not case sensitive.</param>
/// <param name="repo">The name of the repository. The name is not case sensitive.</param>
/// <param name="permission">
/// The permission to grant the team on this repository. We accept the following permissions to be set:
/// pull, triage, push, maintain, admin and you can also specify a custom repository role name, if the
/// owning organization has defined any. If no permission is specified, the team's permission attribute
/// will be used to determine what permission to grant the team on this repository
/// </param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns></returns>
[ManualRoute("PUT", "/orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}")]
public Task AddOrUpdateTeamRepositoryPermissions(string org, string teamSlug, string owner, string repo, string permission)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
Ensure.ArgumentNotNullOrEmptyString(teamSlug, nameof(teamSlug));
Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
Ensure.ArgumentNotNullOrEmptyString(repo, nameof(repo));
var endpoint = ApiUrls.TeamPermissionsForARepository(org, teamSlug, owner, repo);
return ApiConnection.Put(endpoint, new { permission });
}
/// <summary>
/// Remove a repository from a team
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#remove-a-repository-from-a-team">API Documentation</a>
/// for more information.
/// </remarks>
/// <param name="org">The organization name. The name is not case sensitive.</param>
/// <param name="teamSlug">The slug of the team name.</param>
/// <param name="owner">The account owner of the repository. The name is not case sensitive.</param>
/// <param name="repo">The name of the repository. The name is not case sensitive.</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns></returns>
[ManualRoute("DELETE", "/orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}")]
public Task RemoveRepositoryFromATeam(string org, string teamSlug, string owner, string repo)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
Ensure.ArgumentNotNullOrEmptyString(teamSlug, nameof(teamSlug));
Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
Ensure.ArgumentNotNullOrEmptyString(repo, nameof(repo));
var endpoint = ApiUrls.TeamPermissionsForARepository(org, teamSlug, owner, repo);
return ApiConnection.Delete(endpoint);
}
}
}

View File

@@ -13,5 +13,7 @@
/// </summary>
/// <remarks>https://developer.github.com/v3/repos/contents/#custom-media-types</remarks>
public const string RawContentMediaType = "application/vnd.github.v3.raw";
public const string RepositoryContentMediaType = "application/vnd.github.v3.repository+json";
}
}

View File

@@ -1922,6 +1922,18 @@ namespace Octokit
return "teams/{0}".FormatUri(id);
}
/// <summary>
/// Returns the <see cref="Uri"/> for teams
/// use for updating, or deleteing a <see cref="Team"/>.
/// </summary>
/// <param name="org"></param>
/// <param name="teamSlug"></param>
/// <returns></returns>
public static Uri TeamsByOrganizationAndSlug(string org, string teamSlug)
{
return "orgs/{0}/teams/{1}".FormatUri(org,teamSlug);
}
/// <summary>
/// returns the <see cref="Uri"/> for team member
/// </summary>
@@ -1961,6 +1973,18 @@ namespace Octokit
return "teams/{0}/repos/{1}/{2}".FormatUri(id, organization, repoName);
}
/// <summary>
/// returns the <see cref="Uri"/> for a team repository
/// </summary>
/// <param name="org">The organization name. The name is not case sensitive.</param>
/// <param name="teamSlug">The slug of the team name.</param>
/// <param name="owner">The account owner of the repository. The name is not case sensitive.</param>
/// <param name="repo">The name of the repository. The name is not case sensitive.</param>
public static Uri TeamPermissionsForARepository(string org, string teamSlug, string owner, string repo)
{
return "/orgs/{0}/teams/{1}/repos/{2}/{3}".FormatUri(org, teamSlug, owner, repo);
}
/// <summary>
/// returns the <see cref="Uri"/> for the teams pending invitations
/// </summary>

View File

@@ -338,6 +338,20 @@ namespace Octokit
return Connection.Put(uri);
}
/// <summary>
/// Creates or replaces the API resource at the specified URI
/// </summary>
/// <param name="uri">URI of the API resource to put</param>
/// <param name="data">Object that describes the API resource; this will be serialized and used as the request's body</param>
/// <returns>A <see cref="Task"/> for the request's execution.</returns>
public Task Put(Uri uri, object data)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
Ensure.ArgumentNotNull(data, nameof(data));
return Connection.Put(uri, data);
}
/// <summary>
/// Creates or replaces the API resource at the specified URI.
/// </summary>

View File

@@ -498,14 +498,14 @@ namespace Octokit
/// Performs an asynchronous HTTP PUT request that expects an empty response.
/// </summary>
/// <param name="uri">URI endpoint to send request to</param>
/// <param name="accepts">Specifies accepted response media types.</param>
/// <param name="body">The object to serialize as the body of the request</param>
/// <returns>The returned <seealso cref="HttpStatusCode"/></returns>
public async Task<HttpStatusCode> Put(Uri uri, string accepts)
public async Task<HttpStatusCode> Put(Uri uri, object body)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
Ensure.ArgumentNotNull(accepts, nameof(accepts));
Ensure.ArgumentNotNull(body, nameof(body));
var response = await SendData<object>(uri, HttpMethod.Put, null, accepts, null, CancellationToken.None).ConfigureAwait(false);
var response = await SendData<object>(uri, HttpMethod.Put, body, null, null, CancellationToken.None).ConfigureAwait(false);
return response.HttpResponse.StatusCode;
}

View File

@@ -234,6 +234,14 @@ namespace Octokit
/// <returns>A <see cref="Task"/> for the request's execution.</returns>
Task Put(Uri uri);
/// <summary>
/// Creates or replaces the API resource at the specified URI
/// </summary>
/// <param name="uri">URI of the API resource to put</param>
/// <param name="data">Object that describes the API resource; this will be serialized and used as the request's body</param>
/// <returns>A <see cref="Task"/> for the request's execution.</returns>
Task Put(Uri uri, object data);
/// <summary>
/// Creates or replaces the API resource at the specified URI.
/// </summary>

View File

@@ -251,9 +251,9 @@ namespace Octokit
/// Performs an asynchronous HTTP PUT request that expects an empty response.
/// </summary>
/// <param name="uri">URI endpoint to send request to</param>
/// <param name="accepts">Specifies accepted response media types.</param>
/// <param name="body">The object to serialize as the body of the request</param>
/// <returns>The returned <seealso cref="HttpStatusCode"/></returns>
Task<HttpStatusCode> Put(Uri uri, string accepts);
Task<HttpStatusCode> Put(Uri uri, object body);
/// <summary>
/// Performs an asynchronous HTTP DELETE request that expects an empty response.

View File

@@ -55,7 +55,7 @@ namespace Octokit
/// <summary>
/// The permission that new repositories will be added to the team with when none is specified (default: Pull)
/// </summary>
public Permission? Permission { get; set; }
public TeamPermission? Permission { get; set; }
/// <summary>
/// Id of a team to set as the parent team

View File

@@ -1,4 +1,6 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using Octokit.Internal;
namespace Octokit
@@ -39,4 +41,86 @@ namespace Octokit
[Parameter(Value = "pull")]
Pull
}
/// <summary>
/// Deprecated. The permission that new repositories will be added to the team with when none is specified
/// Default: pull
/// Can be one of: pull, push
/// </summary>
[SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")]
public enum TeamPermission
{
/// <summary>
/// team members can pull, but not push to these repositories
/// </summary>
[Parameter(Value = "pull")]
Pull,
/// <summary>
/// team members can pull and push to these repositories
/// </summary>
[Parameter(Value = "push")]
Push
}
/// <summary>
/// Object for team repository permissions
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class TeamRepositoryPermissions
{
public TeamRepositoryPermissions() { }
public TeamRepositoryPermissions(bool pull, bool triage, bool push, bool maintain, bool admin)
{
Pull = pull;
Triage = triage;
Push = push;
Maintain = maintain;
Admin = admin;
}
/// <summary>
/// Can read and clone repository.
/// Can also open and comment on issues and pull requests.
/// Required
/// </summary>
public bool Pull { get; private set; }
/// <summary>
/// Can read and clone repository.
/// Can also manage issues and pull requests.
/// Required
/// </summary>
public bool Triage { get; private set; }
/// <summary>
/// Can read, clone, and push to repository.
/// Can also manage issues and pull requests.
/// Required
/// </summary>
public bool Push { get; private set; }
/// <summary>
/// Can read, clone, and push to repository.
/// They can also manage issues, pull requests, and some repository settings.
/// Required
/// </summary>
public bool Maintain { get; private set; }
/// <summary>
/// Can read, clone, and push to repository.
/// Can also manage issues, pull requests, and repository settings, including adding collaborators.
/// Required
/// </summary>
public bool Admin { get; private set; }
internal string DebuggerDisplay
{
get
{
return string.Format(CultureInfo.InvariantCulture,
$"Permissions: Pull: {Pull}, Triage: {Triage}, Push: {Push}, Maintain: {Maintain}, Admin: {Admin}");
}
}
}
}

View File

@@ -36,8 +36,11 @@ namespace Octokit
/// <summary>
/// The permission that new repositories will be added to the team with when none is specified (default: Pull)
/// Although permission can be one of : pull, push, or admin based on documentation, passing admin results in an error response.
/// That's why TeamPermission does not contain an admin value.
/// See the issue here https://github.com/github/rest-api-description/issues/1952
/// </summary>
public Permission? Permission { get; set; }
public TeamPermission? Permission { get; set; }
/// <summary>
/// Id of a team to set as the parent team

View File

@@ -12,7 +12,7 @@ namespace Octokit
{
public Team() { }
public Team(string url, string htmlUrl, int id, string nodeId, string slug, string name, string description, TeamPrivacy privacy, PermissionLevel permission, int membersCount, int reposCount, Organization organization, Team parent, string ldapDistinguishedName)
public Team(string url, string htmlUrl, int id, string nodeId, string slug, string name, string description, TeamPrivacy privacy, string permission, TeamRepositoryPermissions teamRepositoryPermissions, int membersCount, int reposCount, Organization organization, Team parent, string ldapDistinguishedName)
{
Url = url;
HtmlUrl = htmlUrl;
@@ -23,6 +23,7 @@ namespace Octokit
Description = description;
Privacy = privacy;
Permission = permission;
TeamRepositoryPermissions = teamRepositoryPermissions;
MembersCount = membersCount;
ReposCount = reposCount;
Organization = organization;
@@ -71,9 +72,14 @@ namespace Octokit
public StringEnum<TeamPrivacy> Privacy { get; private set; }
/// <summary>
/// permission attached to this team
/// Deprecated. The permission that new repositories will be added to the team with when none is specified
/// </summary>
public StringEnum<PermissionLevel> Permission { get; private set; }
public string Permission { get; private set; }
/// <summary>
///
/// </summary>
public TeamRepositoryPermissions TeamRepositoryPermissions { get; private set; }
/// <summary>
/// how many members in this team

View File

@@ -0,0 +1,618 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
namespace Octokit
{
/// <summary>
/// A teams's repository
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class TeamRepository
{
public TeamRepository() { }
public TeamRepository(int id,
string nodeId,
string name,
string fullName,
LicenseMetadata license,
TeamRepositoryPermissions permissions,
string roleName,
User owner,
bool @private,
string htmlUrl,
string description,
bool fork,
string url,
string archiveUrl,
string assigneesUrl,
string blobsUrl,
string branchesUrl,
string collaboratorsUrl,
string commentsUrl,
string commitsUrl,
string compareUrl,
string contentsUrl,
string contributorsUrl,
string deploymentsUrl,
string downloadsUrl,
string eventsUrl,
string forksUrl,
string gitCommitUrl,
string gitRefsUrl,
string gitTagsUrl,
string gitUrl,
string issueCommentUrl,
string issueEventsUrl,
string issuesUrl,
string keysUrl,
string labelsUrl,
string languagesUrl,
string mergesUrl,
string milestonesUrl,
string notificationsUrl,
string pullsUrl,
string releasesUrl,
string sshUrl,
string stargazersUrl,
string statusesUrl,
string subscribersUrl,
string subscriptionUrl,
string tagsUrl,
string teamsUrl,
string treesUrl,
string cloneUrl,
string mirrorUrl,
string hooksUrl,
string svnUrl,
string homePage,
string language,
int forksCount,
int stargazersCount,
int watchersCount,
int size,
string defaultBranch,
int openIssuesCount,
bool isTemplate,
IReadOnlyList<string> topics,
bool hasIssues,
bool hasProjects,
bool hasWiki,
bool hasPages,
bool hasDownloads,
bool archived,
bool disabled,
RepositoryVisibility? visibility,
DateTimeOffset? pushedAt,
DateTimeOffset createdAt,
DateTimeOffset updatedAt,
bool? allowRebaseMerge,
Repository templateRepository,
string tempCloneToken,
bool? allowSquashMerge,
bool? allowAutoMerge,
bool? deleteBranchOnMerge,
bool? allowMergeCommit,
bool? allowForking,
bool? webCommitSignoffRequired,
int subscribersCount,
int networkCount,
int openIssues,
int watchers,
string masterBranch)
{
Id = id;
NodeId = nodeId;
Name = name;
FullName = fullName;
License = license;
Permissions = permissions;
RoleName = roleName;
Owner = owner;
Private = @private;
HtmlUrl = htmlUrl;
Description = description;
Fork = fork;
Url = url;
ArchiveUrl = archiveUrl;
AssigneesUrl = assigneesUrl;
BlobsUrl = blobsUrl;
BranchesUrl = branchesUrl;
CollaboratorsUrl = collaboratorsUrl;
CommentsUrl = commentsUrl;
CommitsUrl = commitsUrl;
CompareUrl = compareUrl;
ContentsUrl = contentsUrl;
ContributorsUrl = contributorsUrl;
DeploymentsUrl = deploymentsUrl;
DownloadsUrl = downloadsUrl;
EventsUrl = eventsUrl;
ForksUrl = forksUrl;
GitCommitUrl = gitCommitUrl;
GitRefsUrl = gitRefsUrl;
GitTagsUrl = gitTagsUrl;
GitUrl = gitUrl;
IssueCommentUrl = issueCommentUrl;
IssueEventsUrl = issueEventsUrl;
IssuesUrl = issuesUrl;
KeysUrl = keysUrl;
LabelsUrl = labelsUrl;
LanguagesUrl = languagesUrl;
MergesUrl = mergesUrl;
MilestonesUrl = milestonesUrl;
NotificationsUrl = notificationsUrl;
PullsUrl = pullsUrl;
ReleasesUrl = releasesUrl;
SshUrl = sshUrl;
StargazersUrl = stargazersUrl;
StatusesUrl = statusesUrl;
SubscribersUrl = subscribersUrl;
SubscriptionUrl = subscriptionUrl;
TagsUrl = tagsUrl;
TeamsUrl = teamsUrl;
TreesUrl = treesUrl;
CloneUrl = cloneUrl;
MirrorUrl = mirrorUrl;
HooksUrl = hooksUrl;
SvnUrl = svnUrl;
HomePage = homePage;
Language = language;
ForksCount = forksCount;
StargazersCount = stargazersCount;
WatchersCount = watchersCount;
Size = size;
DefaultBranch = defaultBranch;
OpenIssuesCount = openIssuesCount;
IsTemplate = isTemplate;
Topics = topics;
HasIssues = hasIssues;
HasProjects = hasProjects;
HasWiki = hasWiki;
HasPages = hasPages;
HasDownloads = hasDownloads;
Archived = archived;
Disabled = disabled;
Visibility = visibility;
PushedAt = pushedAt;
CreatedAt = createdAt;
UpdatedAt = updatedAt;
AllowRebaseMerge = allowRebaseMerge;
TemplateRepository = templateRepository;
TempCloneToken = tempCloneToken;
AllowSquashMerge = allowSquashMerge;
AllowAutoMerge = allowAutoMerge;
DeleteBranchOnMerge = deleteBranchOnMerge;
AllowMergeCommit = allowMergeCommit;
AllowForking = allowForking;
WebCommitSignoffRequired = webCommitSignoffRequired;
SubscribersCount = subscribersCount;
NetworkCount = networkCount;
OpenIssues = openIssues;
Watchers = watchers;
MasterBranch = masterBranch;
}
/// <summary>
/// Unique identifier of the repository
/// </summary>
public int Id { get; private set; }
/// <summary>
/// GraphQL Node Id
/// </summary>
public string NodeId { get; private set; }
/// <summary>
/// The name of the repository
/// </summary>
public string Name { get; private set; }
/// <summary>
/// example: octocat/Hello-World
/// </summary>
public string FullName { get; private set; }
public LicenseMetadata License { get; private set; }
public TeamRepositoryPermissions Permissions { get; private set; }
public string RoleName { get; private set; }
public User Owner { get; private set; }
/// <summary>
/// hether the repository is private or public.
/// default: false
/// </summary>
public bool Private { get; private set; }
/// <summary>
/// format: uri
/// example: https://github.com/octocat/Hello-World
/// </summary>
public string HtmlUrl { get; private set; }
/// <summary>
/// example: This your first repo!
/// nullable: true
/// </summary>
public string Description { get; private set; }
public bool Fork { get; private set; }
/// <summary>
/// format: uri
/// example: https://api.github.com/repos/octocat/Hello-World
/// </summary>
public string Url { get; private set; }
/// <summary>
/// example: http://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}
/// </summary>
public string ArchiveUrl { get; private set; }
/// <summary>
/// example: http://api.github.com/repos/octocat/Hello-World/assignees{/user}
/// </summary>
public string AssigneesUrl { get; private set; }
/// <summary>
/// example: http://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}
/// </summary>
public string BlobsUrl { get; private set; }
/// <summary>
/// example: http://api.github.com/repos/octocat/Hello-World/branches{/branch}
/// </summary>
public string BranchesUrl { get; private set; }
/// <summary>
/// example: http://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}
/// </summary>
public string CollaboratorsUrl { get; private set; }
/// <summary>
/// example: http://api.github.com/repos/octocat/Hello-World/comments{/number}
/// </summary>
public string CommentsUrl { get; private set; }
/// <summary>
/// example: http://api.github.com/repos/octocat/Hello-World/commits{/sha}
/// </summary>
public string CommitsUrl { get; private set; }
/// <summary>
/// example: http://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}
/// </summary>
public string CompareUrl { get; private set; }
/// <summary>
/// example: http://api.github.com/repos/octocat/Hello-World/contents/{+path}
/// </summary>
public string ContentsUrl { get; private set; }
/// <summary>
/// format: uri
/// example: http://api.github.com/repos/octocat/Hello-World/contributors
/// </summary>
public string ContributorsUrl { get; private set; }
/// <summary>
/// format: uri
/// example: http://api.github.com/repos/octocat/Hello-World/deployments
/// </summary>
public string DeploymentsUrl { get; private set; }
/// <summary>
/// format: uri
/// example: http://api.github.com/repos/octocat/Hello-World/downloads
/// </summary>
public string DownloadsUrl { get; private set; }
/// <summary>
/// format: uri
/// example: http://api.github.com/repos/octocat/Hello-World/events
/// </summary>
public string EventsUrl { get; private set; }
/// <summary>
/// format: uri
/// example: http://api.github.com/repos/octocat/Hello-World/forks
/// </summary>
public string ForksUrl { get; private set; }
///example: http://api.github.com/repos/octocat/Hello-World/git/commits{/sha}
public string GitCommitUrl { get; private set; }
/// <summary>
/// example: http://api.github.com/repos/octocat/Hello-World/git/refs{/sha}
/// </summary>
public string GitRefsUrl { get; private set; }
/// <summary>
/// example: http://api.github.com/repos/octocat/Hello-World/git/tags{/sha}
/// </summary>
public string GitTagsUrl { get; private set; }
/// <summary>
/// example: git:github.com/octocat/Hello-World.git
/// </summary>
public string GitUrl { get; private set; }
/// <summary>
/// example: http://api.github.com/repos/octocat/Hello-World/issues/comments{/number}
/// </summary>
public string IssueCommentUrl { get; private set; }
/// <summary>
/// example: http://api.github.com/repos/octocat/Hello-World/issues/events{/number}
/// </summary>
public string IssueEventsUrl { get; private set; }
/// <summary>
/// example: http://api.github.com/repos/octocat/Hello-World/issues{/number}
/// </summary>
public string IssuesUrl { get; private set; }
/// <summary>
/// example: http://api.github.com/repos/octocat/Hello-World/keys{/key_id}
/// </summary>
public string KeysUrl { get; private set; }
/// <summary>
/// example: http://api.github.com/repos/octocat/Hello-World/labels{/name}
/// </summary>
public string LabelsUrl { get; private set; }
/// <summary>
/// format: uri
/// example: http://api.github.com/repos/octocat/Hello-World/languages
/// </summary>
public string LanguagesUrl { get; private set; }
/// <summary>
/// format: uri
/// example: http://api.github.com/repos/octocat/Hello-World/merges
/// </summary>
public string MergesUrl { get; private set; }
/// <summary>
/// example: http://api.github.com/repos/octocat/Hello-World/milestones{/number}
/// </summary>
public string MilestonesUrl { get; private set; }
/// <summary>
/// example: http://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}
/// </summary>
public string NotificationsUrl { get; private set; }
/// <summary>
/// example: http://api.github.com/repos/octocat/Hello-World/pulls{/number}
/// </summary>
public string PullsUrl { get; private set; }
/// <summary>
/// example: http://api.github.com/repos/octocat/Hello-World/releases{/id}
/// </summary>
public string ReleasesUrl { get; private set; }
/// <summary>
/// example: git @github.com:octocat/Hello-World.git
///
/// </summary>
public string SshUrl { get; private set; }
/// <summary>
/// format: uri
/// example: http://api.github.com/repos/octocat/Hello-World/stargazers
/// </summary>
public string StargazersUrl { get; private set; }
/// <summary>
/// example: http://api.github.com/repos/octocat/Hello-World/statuses/{sha}
/// </summary>
public string StatusesUrl { get; private set; }
/// <summary>
/// format: uri
/// example: http://api.github.com/repos/octocat/Hello-World/subscribers
/// </summary>
public string SubscribersUrl { get; private set; }
/// <summary>
/// format: uri
/// example: http://api.github.com/repos/octocat/Hello-World/subscription
/// </summary>
public string SubscriptionUrl { get; private set; }
/// <summary>
/// format: uri
/// example: http://api.github.com/repos/octocat/Hello-World/tags
/// </summary>
public string TagsUrl { get; private set; }
/// <summary>
/// format: uri
/// example: http://api.github.com/repos/octocat/Hello-World/teams
/// </summary>
public string TeamsUrl { get; private set; }
/// <summary>
/// example: http://api.github.com/repos/octocat/Hello-World/git/trees{/sha}
/// </summary>
public string TreesUrl { get; private set; }
/// <summary>
/// example: https://github.com/octocat/Hello-World.git
/// </summary>
public string CloneUrl { get; private set; }
/// <summary>
/// format: uri
/// example: git:git.example.com/octocat/Hello-World
/// nullable: true
/// </summary>
public string MirrorUrl { get; private set; }
/// <summary>
/// format: uri
/// example: http://api.github.com/repos/octocat/Hello-World/hooks
/// </summary>
public string HooksUrl { get; private set; }
/// <summary>
/// format: uri
/// example: https://svn.github.com/octocat/Hello-World
/// </summary>
public string SvnUrl { get; private set; }
/// <summary>
/// format: uri
/// example: https://github.com
/// </summary>
public string HomePage { get; private set; }
public string Language { get; private set; }
public int ForksCount { get; private set; }
public int StargazersCount { get; private set; }
public int WatchersCount { get; private set; }
public int Size { get; private set; }
/// <summary>
/// he default branch of the repository.
/// example: master
/// </summary>
public string DefaultBranch { get; private set; }
public int OpenIssuesCount { get; private set; }
/// <summary>
/// Whether this repository acts as a template that can be used to generate new repositories
/// default: false
/// </summary>
public bool IsTemplate { get; private set; }
public IReadOnlyList<string> Topics { get; private set; }
/// <summary>
/// Whether issues are enabled.
/// </summary>
public bool HasIssues { get; private set; }
/// <summary>
/// Whether projects are enabled.
/// </summary>
public bool HasProjects { get; private set; }
/// <summary>
/// Whether the wiki is enabled
/// </summary>
public bool HasWiki { get; private set; }
public bool HasPages { get; private set; }
/// <summary>
/// Whether downloads are enabled
/// default: true
/// </summary>
public bool HasDownloads { get; private set; }
/// <summary>
/// Whether the repository is archived
/// </summary>
public bool Archived { get; private set; }
/// <summary>
/// Returns whether or not this repository disabled.
/// </summary>
public bool Disabled { get; private set; }
/// <summary>
/// The repository visibility: public, private, or internal.
/// </summary>
public RepositoryVisibility? Visibility { get; private set; }
/// <summary>
/// format: date-time
/// example: '2011-01-26T19:06:43Z'
/// </summary>
public DateTimeOffset? PushedAt { get; private set; }
/// <summary>
/// format: date-time
/// example: '2011-01-26T19:01:12Z'
/// </summary>
public DateTimeOffset CreatedAt { get; private set; }
/// <summary>
/// format: date-time
/// example: '2011-01-26T19:14:43Z'
/// </summary>
public DateTimeOffset UpdatedAt { get; private set; }
/// <summary>
/// Whether to allow rebase merges for pull requests.
/// </summary>
public bool? AllowRebaseMerge { get; private set; }
/// <summary>
/// Template repository (nullable)
/// </summary>
public Repository TemplateRepository { get; private set; }
public string TempCloneToken { get; private set; }
/// <summary>
/// Whether to allow squash merges for pull requests.
/// </summary>
public bool? AllowSquashMerge { get; private set; }
/// <summary>
/// Whether to allow Auto-merge to be used on pull requests.
/// </summary>
public bool? AllowAutoMerge { get; private set; }
/// <summary>
/// Whether to delete head branches when pull requests are merged
/// </summary>
public bool? DeleteBranchOnMerge { get; private set; }
/// <summary>
/// hether to allow merge commits for pull requests.
/// </summary>
public bool? AllowMergeCommit { get; private set; }
/// <summary>
/// Whether to allow forking this repo
/// </summary>
public bool? AllowForking { get; private set; }
/// <summary>
/// Whether to require contributors to sign off on web-based commits
/// </summary>
public bool? WebCommitSignoffRequired { get; private set; }
public int SubscribersCount { get; private set; }
public int NetworkCount { get; private set; }
public int OpenIssues { get; private set; }
public int Watchers { get; private set; }
public string MasterBranch { get; private set; }
internal string DebuggerDisplay
{
get { return string.Format(CultureInfo.InvariantCulture, "Name: {0} ", FullName); }
}
}
}

77
docs/teams.md Normal file
View File

@@ -0,0 +1,77 @@
# Working with Teams
To access the teams API, you need to be an authenticated member of the organization's team. OAuth access tokens require the read:org scope. The ITeamsClient houses the endpoints for the teams API.
### Create, update or delete teams
To create a new team, you need to be a member of owner of the organization.
```csharp
var newTeam = new NewTeam("team-name")
{
Description = "my cool team description",
Privacy = TeamPrivacy.Closed
};
newTeam.Maintainers.Add("maintainer-name");
newTeam.RepoNames.Add("repository-name");
var team = await github.Organization.Team.Create("organization-name", newTeam);
```
Updating and deleting a team is also possible
```csharp
var update = new UpdateTeam("team-name",)
{
Description = "my new team description",
Privacy = TeamPrivacy.Closed,
Permission = TeamPermission.Push,
};
var team = await _github.Organization.Team.Update("organization-name", "team-slug", update);
```
```csharp
var team = await _github.Organization.Team.Delete("organization-name", "team-slug");
```
### Working with repositories for the team
You can get the list of repositories for the team by following
```csharp
var allRepositories = await github.Organization.Team.GetAllRepositories(teamContext.TeamId);
```
Or check permissions for a specific repository with the CheckTeamPermissionsForARepository method.
```csharp
await github.Organization.Team.CheckTeamPermissionsForARepository(
"organization-name",
"team-slug",
"repository-owner",
"repository-name",
false);
```
The following snippet shows how to add or update team repository permissions.
Permissions can be one of pull, triage, push, maintain, admin and you can also specify a custom repository role name, if the owning organization has defined any. If no permission is specified, the team's permission attribute will be used to determine what permission to grant the team on this repository.
```csharp
await github.Organization.Team.AddOrUpdateTeamRepositoryPermissions(
"organization-name",
"team-slug",
"repository-owner",
"repository-name",
"admin");
```
To remove a repository form a team, use
```csharp
await github.Organization.Team.RemoveRepositoryFromATeam(
"organization-name",
"team-slug",
"repository-owner",
"repository-name");
```