github.com/google/go-github/v66@v66.0.0/github/teams.go (about)

     1  // Copyright 2018 The go-github AUTHORS. All rights reserved.
     2  //
     3  // Use of this source code is governed by a BSD-style
     4  // license that can be found in the LICENSE file.
     5  
     6  package github
     7  
     8  import (
     9  	"context"
    10  	"fmt"
    11  	"net/http"
    12  	"strings"
    13  )
    14  
    15  // TeamsService provides access to the team-related functions
    16  // in the GitHub API.
    17  //
    18  // GitHub API docs: https://docs.github.com/rest/teams/
    19  type TeamsService service
    20  
    21  // Team represents a team within a GitHub organization. Teams are used to
    22  // manage access to an organization's repositories.
    23  type Team struct {
    24  	ID          *int64  `json:"id,omitempty"`
    25  	NodeID      *string `json:"node_id,omitempty"`
    26  	Name        *string `json:"name,omitempty"`
    27  	Description *string `json:"description,omitempty"`
    28  	URL         *string `json:"url,omitempty"`
    29  	Slug        *string `json:"slug,omitempty"`
    30  
    31  	// Permission specifies the default permission for repositories owned by the team.
    32  	Permission *string `json:"permission,omitempty"`
    33  
    34  	// Permissions identifies the permissions that a team has on a given
    35  	// repository. This is only populated when calling Repositories.ListTeams.
    36  	Permissions map[string]bool `json:"permissions,omitempty"`
    37  
    38  	// Privacy identifies the level of privacy this team should have.
    39  	// Possible values are:
    40  	//     secret - only visible to organization owners and members of this team
    41  	//     closed - visible to all members of this organization
    42  	// Default is "secret".
    43  	Privacy *string `json:"privacy,omitempty"`
    44  
    45  	MembersCount    *int          `json:"members_count,omitempty"`
    46  	ReposCount      *int          `json:"repos_count,omitempty"`
    47  	Organization    *Organization `json:"organization,omitempty"`
    48  	HTMLURL         *string       `json:"html_url,omitempty"`
    49  	MembersURL      *string       `json:"members_url,omitempty"`
    50  	RepositoriesURL *string       `json:"repositories_url,omitempty"`
    51  	Parent          *Team         `json:"parent,omitempty"`
    52  
    53  	// LDAPDN is only available in GitHub Enterprise and when the team
    54  	// membership is synchronized with LDAP.
    55  	LDAPDN *string `json:"ldap_dn,omitempty"`
    56  }
    57  
    58  func (t Team) String() string {
    59  	return Stringify(t)
    60  }
    61  
    62  // Invitation represents a team member's invitation status.
    63  type Invitation struct {
    64  	ID     *int64  `json:"id,omitempty"`
    65  	NodeID *string `json:"node_id,omitempty"`
    66  	Login  *string `json:"login,omitempty"`
    67  	Email  *string `json:"email,omitempty"`
    68  	// Role can be one of the values - 'direct_member', 'admin', 'billing_manager', 'hiring_manager', or 'reinstate'.
    69  	Role              *string    `json:"role,omitempty"`
    70  	CreatedAt         *Timestamp `json:"created_at,omitempty"`
    71  	Inviter           *User      `json:"inviter,omitempty"`
    72  	TeamCount         *int       `json:"team_count,omitempty"`
    73  	InvitationTeamURL *string    `json:"invitation_team_url,omitempty"`
    74  	FailedAt          *Timestamp `json:"failed_at,omitempty"`
    75  	FailedReason      *string    `json:"failed_reason,omitempty"`
    76  }
    77  
    78  func (i Invitation) String() string {
    79  	return Stringify(i)
    80  }
    81  
    82  // ListTeams lists all of the teams for an organization.
    83  //
    84  // GitHub API docs: https://docs.github.com/rest/teams/teams#list-teams
    85  //
    86  //meta:operation GET /orgs/{org}/teams
    87  func (s *TeamsService) ListTeams(ctx context.Context, org string, opts *ListOptions) ([]*Team, *Response, error) {
    88  	u := fmt.Sprintf("orgs/%v/teams", org)
    89  	u, err := addOptions(u, opts)
    90  	if err != nil {
    91  		return nil, nil, err
    92  	}
    93  
    94  	req, err := s.client.NewRequest("GET", u, nil)
    95  	if err != nil {
    96  		return nil, nil, err
    97  	}
    98  
    99  	var teams []*Team
   100  	resp, err := s.client.Do(ctx, req, &teams)
   101  	if err != nil {
   102  		return nil, resp, err
   103  	}
   104  
   105  	return teams, resp, nil
   106  }
   107  
   108  // GetTeamByID fetches a team, given a specified organization ID, by ID.
   109  //
   110  // GitHub API docs: https://docs.github.com/rest/teams/teams#get-a-team-by-name
   111  //
   112  //meta:operation GET /orgs/{org}/teams/{team_slug}
   113  func (s *TeamsService) GetTeamByID(ctx context.Context, orgID, teamID int64) (*Team, *Response, error) {
   114  	u := fmt.Sprintf("organizations/%v/team/%v", orgID, teamID)
   115  	req, err := s.client.NewRequest("GET", u, nil)
   116  	if err != nil {
   117  		return nil, nil, err
   118  	}
   119  
   120  	t := new(Team)
   121  	resp, err := s.client.Do(ctx, req, t)
   122  	if err != nil {
   123  		return nil, resp, err
   124  	}
   125  
   126  	return t, resp, nil
   127  }
   128  
   129  // GetTeamBySlug fetches a team, given a specified organization name, by slug.
   130  //
   131  // GitHub API docs: https://docs.github.com/rest/teams/teams#get-a-team-by-name
   132  //
   133  //meta:operation GET /orgs/{org}/teams/{team_slug}
   134  func (s *TeamsService) GetTeamBySlug(ctx context.Context, org, slug string) (*Team, *Response, error) {
   135  	u := fmt.Sprintf("orgs/%v/teams/%v", org, slug)
   136  	req, err := s.client.NewRequest("GET", u, nil)
   137  	if err != nil {
   138  		return nil, nil, err
   139  	}
   140  
   141  	t := new(Team)
   142  	resp, err := s.client.Do(ctx, req, t)
   143  	if err != nil {
   144  		return nil, resp, err
   145  	}
   146  
   147  	return t, resp, nil
   148  }
   149  
   150  // NewTeam represents a team to be created or modified.
   151  type NewTeam struct {
   152  	Name         string   `json:"name"` // Name of the team. (Required.)
   153  	Description  *string  `json:"description,omitempty"`
   154  	Maintainers  []string `json:"maintainers,omitempty"`
   155  	RepoNames    []string `json:"repo_names,omitempty"`
   156  	ParentTeamID *int64   `json:"parent_team_id,omitempty"`
   157  
   158  	// NotificationSetting can be one of: "notifications_enabled", "notifications_disabled".
   159  	NotificationSetting *string `json:"notification_setting,omitempty"`
   160  
   161  	// Deprecated: Permission is deprecated when creating or editing a team in an org
   162  	// using the new GitHub permission model. It no longer identifies the
   163  	// permission a team has on its repos, but only specifies the default
   164  	// permission a repo is initially added with. Avoid confusion by
   165  	// specifying a permission value when calling AddTeamRepo.
   166  	Permission *string `json:"permission,omitempty"`
   167  
   168  	// Privacy identifies the level of privacy this team should have.
   169  	// Possible values are:
   170  	//     secret - only visible to organization owners and members of this team
   171  	//     closed - visible to all members of this organization
   172  	// Default is "secret".
   173  	Privacy *string `json:"privacy,omitempty"`
   174  
   175  	// LDAPDN may be used in GitHub Enterprise when the team membership
   176  	// is synchronized with LDAP.
   177  	LDAPDN *string `json:"ldap_dn,omitempty"`
   178  }
   179  
   180  func (s NewTeam) String() string {
   181  	return Stringify(s)
   182  }
   183  
   184  // CreateTeam creates a new team within an organization.
   185  //
   186  // GitHub API docs: https://docs.github.com/rest/teams/teams#create-a-team
   187  //
   188  //meta:operation POST /orgs/{org}/teams
   189  func (s *TeamsService) CreateTeam(ctx context.Context, org string, team NewTeam) (*Team, *Response, error) {
   190  	u := fmt.Sprintf("orgs/%v/teams", org)
   191  	req, err := s.client.NewRequest("POST", u, team)
   192  	if err != nil {
   193  		return nil, nil, err
   194  	}
   195  
   196  	t := new(Team)
   197  	resp, err := s.client.Do(ctx, req, t)
   198  	if err != nil {
   199  		return nil, resp, err
   200  	}
   201  
   202  	return t, resp, nil
   203  }
   204  
   205  // newTeamNoParent is the same as NewTeam but ensures that the
   206  // "parent_team_id" field will be null. It is for internal use
   207  // only and should not be exported.
   208  type newTeamNoParent struct {
   209  	Name                string   `json:"name"`
   210  	Description         *string  `json:"description,omitempty"`
   211  	Maintainers         []string `json:"maintainers,omitempty"`
   212  	RepoNames           []string `json:"repo_names,omitempty"`
   213  	ParentTeamID        *int64   `json:"parent_team_id"` // This will be "null"
   214  	NotificationSetting *string  `json:"notification_setting,omitempty"`
   215  	Privacy             *string  `json:"privacy,omitempty"`
   216  	LDAPDN              *string  `json:"ldap_dn,omitempty"`
   217  }
   218  
   219  // copyNewTeamWithoutParent is used to set the "parent_team_id"
   220  // field to "null" after copying the other fields from a NewTeam.
   221  // It is for internal use only and should not be exported.
   222  func copyNewTeamWithoutParent(team *NewTeam) *newTeamNoParent {
   223  	return &newTeamNoParent{
   224  		Name:                team.Name,
   225  		Description:         team.Description,
   226  		Maintainers:         team.Maintainers,
   227  		RepoNames:           team.RepoNames,
   228  		NotificationSetting: team.NotificationSetting,
   229  		Privacy:             team.Privacy,
   230  		LDAPDN:              team.LDAPDN,
   231  	}
   232  }
   233  
   234  // EditTeamByID edits a team, given an organization ID, selected by ID.
   235  //
   236  // GitHub API docs: https://docs.github.com/rest/teams/teams#update-a-team
   237  //
   238  //meta:operation PATCH /orgs/{org}/teams/{team_slug}
   239  func (s *TeamsService) EditTeamByID(ctx context.Context, orgID, teamID int64, team NewTeam, removeParent bool) (*Team, *Response, error) {
   240  	u := fmt.Sprintf("organizations/%v/team/%v", orgID, teamID)
   241  
   242  	var req *http.Request
   243  	var err error
   244  	if removeParent {
   245  		teamRemoveParent := copyNewTeamWithoutParent(&team)
   246  		req, err = s.client.NewRequest("PATCH", u, teamRemoveParent)
   247  	} else {
   248  		req, err = s.client.NewRequest("PATCH", u, team)
   249  	}
   250  	if err != nil {
   251  		return nil, nil, err
   252  	}
   253  
   254  	t := new(Team)
   255  	resp, err := s.client.Do(ctx, req, t)
   256  	if err != nil {
   257  		return nil, resp, err
   258  	}
   259  
   260  	return t, resp, nil
   261  }
   262  
   263  // EditTeamBySlug edits a team, given an organization name, by slug.
   264  //
   265  // GitHub API docs: https://docs.github.com/rest/teams/teams#update-a-team
   266  //
   267  //meta:operation PATCH /orgs/{org}/teams/{team_slug}
   268  func (s *TeamsService) EditTeamBySlug(ctx context.Context, org, slug string, team NewTeam, removeParent bool) (*Team, *Response, error) {
   269  	u := fmt.Sprintf("orgs/%v/teams/%v", org, slug)
   270  
   271  	var req *http.Request
   272  	var err error
   273  	if removeParent {
   274  		teamRemoveParent := copyNewTeamWithoutParent(&team)
   275  		req, err = s.client.NewRequest("PATCH", u, teamRemoveParent)
   276  	} else {
   277  		req, err = s.client.NewRequest("PATCH", u, team)
   278  	}
   279  	if err != nil {
   280  		return nil, nil, err
   281  	}
   282  
   283  	t := new(Team)
   284  	resp, err := s.client.Do(ctx, req, t)
   285  	if err != nil {
   286  		return nil, resp, err
   287  	}
   288  
   289  	return t, resp, nil
   290  }
   291  
   292  // DeleteTeamByID deletes a team referenced by ID.
   293  //
   294  // GitHub API docs: https://docs.github.com/rest/teams/teams#delete-a-team
   295  //
   296  //meta:operation DELETE /orgs/{org}/teams/{team_slug}
   297  func (s *TeamsService) DeleteTeamByID(ctx context.Context, orgID, teamID int64) (*Response, error) {
   298  	u := fmt.Sprintf("organizations/%v/team/%v", orgID, teamID)
   299  	req, err := s.client.NewRequest("DELETE", u, nil)
   300  	if err != nil {
   301  		return nil, err
   302  	}
   303  
   304  	return s.client.Do(ctx, req, nil)
   305  }
   306  
   307  // DeleteTeamBySlug deletes a team reference by slug.
   308  //
   309  // GitHub API docs: https://docs.github.com/rest/teams/teams#delete-a-team
   310  //
   311  //meta:operation DELETE /orgs/{org}/teams/{team_slug}
   312  func (s *TeamsService) DeleteTeamBySlug(ctx context.Context, org, slug string) (*Response, error) {
   313  	u := fmt.Sprintf("orgs/%v/teams/%v", org, slug)
   314  	req, err := s.client.NewRequest("DELETE", u, nil)
   315  	if err != nil {
   316  		return nil, err
   317  	}
   318  
   319  	return s.client.Do(ctx, req, nil)
   320  }
   321  
   322  // ListChildTeamsByParentID lists child teams for a parent team given parent ID.
   323  //
   324  // GitHub API docs: https://docs.github.com/rest/teams/teams#list-child-teams
   325  //
   326  //meta:operation GET /orgs/{org}/teams/{team_slug}/teams
   327  func (s *TeamsService) ListChildTeamsByParentID(ctx context.Context, orgID, teamID int64, opts *ListOptions) ([]*Team, *Response, error) {
   328  	u := fmt.Sprintf("organizations/%v/team/%v/teams", orgID, teamID)
   329  	u, err := addOptions(u, opts)
   330  	if err != nil {
   331  		return nil, nil, err
   332  	}
   333  
   334  	req, err := s.client.NewRequest("GET", u, nil)
   335  	if err != nil {
   336  		return nil, nil, err
   337  	}
   338  
   339  	var teams []*Team
   340  	resp, err := s.client.Do(ctx, req, &teams)
   341  	if err != nil {
   342  		return nil, resp, err
   343  	}
   344  
   345  	return teams, resp, nil
   346  }
   347  
   348  // ListChildTeamsByParentSlug lists child teams for a parent team given parent slug.
   349  //
   350  // GitHub API docs: https://docs.github.com/rest/teams/teams#list-child-teams
   351  //
   352  //meta:operation GET /orgs/{org}/teams/{team_slug}/teams
   353  func (s *TeamsService) ListChildTeamsByParentSlug(ctx context.Context, org, slug string, opts *ListOptions) ([]*Team, *Response, error) {
   354  	u := fmt.Sprintf("orgs/%v/teams/%v/teams", org, slug)
   355  	u, err := addOptions(u, opts)
   356  	if err != nil {
   357  		return nil, nil, err
   358  	}
   359  
   360  	req, err := s.client.NewRequest("GET", u, nil)
   361  	if err != nil {
   362  		return nil, nil, err
   363  	}
   364  
   365  	var teams []*Team
   366  	resp, err := s.client.Do(ctx, req, &teams)
   367  	if err != nil {
   368  		return nil, resp, err
   369  	}
   370  
   371  	return teams, resp, nil
   372  }
   373  
   374  // ListTeamReposByID lists the repositories given a team ID that the specified team has access to.
   375  //
   376  // GitHub API docs: https://docs.github.com/rest/teams/teams#list-team-repositories
   377  //
   378  //meta:operation GET /orgs/{org}/teams/{team_slug}/repos
   379  func (s *TeamsService) ListTeamReposByID(ctx context.Context, orgID, teamID int64, opts *ListOptions) ([]*Repository, *Response, error) {
   380  	u := fmt.Sprintf("organizations/%v/team/%v/repos", orgID, teamID)
   381  	u, err := addOptions(u, opts)
   382  	if err != nil {
   383  		return nil, nil, err
   384  	}
   385  
   386  	req, err := s.client.NewRequest("GET", u, nil)
   387  	if err != nil {
   388  		return nil, nil, err
   389  	}
   390  
   391  	// TODO: remove custom Accept header when topics API fully launches.
   392  	headers := []string{mediaTypeTopicsPreview}
   393  	req.Header.Set("Accept", strings.Join(headers, ", "))
   394  
   395  	var repos []*Repository
   396  	resp, err := s.client.Do(ctx, req, &repos)
   397  	if err != nil {
   398  		return nil, resp, err
   399  	}
   400  
   401  	return repos, resp, nil
   402  }
   403  
   404  // ListTeamReposBySlug lists the repositories given a team slug that the specified team has access to.
   405  //
   406  // GitHub API docs: https://docs.github.com/rest/teams/teams#list-team-repositories
   407  //
   408  //meta:operation GET /orgs/{org}/teams/{team_slug}/repos
   409  func (s *TeamsService) ListTeamReposBySlug(ctx context.Context, org, slug string, opts *ListOptions) ([]*Repository, *Response, error) {
   410  	u := fmt.Sprintf("orgs/%v/teams/%v/repos", org, slug)
   411  	u, err := addOptions(u, opts)
   412  	if err != nil {
   413  		return nil, nil, err
   414  	}
   415  
   416  	req, err := s.client.NewRequest("GET", u, nil)
   417  	if err != nil {
   418  		return nil, nil, err
   419  	}
   420  
   421  	// TODO: remove custom Accept header when topics API fully launches.
   422  	headers := []string{mediaTypeTopicsPreview}
   423  	req.Header.Set("Accept", strings.Join(headers, ", "))
   424  
   425  	var repos []*Repository
   426  	resp, err := s.client.Do(ctx, req, &repos)
   427  	if err != nil {
   428  		return nil, resp, err
   429  	}
   430  
   431  	return repos, resp, nil
   432  }
   433  
   434  // IsTeamRepoByID checks if a team, given its ID, manages the specified repository. If the
   435  // repository is managed by team, a Repository is returned which includes the
   436  // permissions team has for that repo.
   437  //
   438  // GitHub API docs: https://docs.github.com/rest/teams/teams#check-team-permissions-for-a-repository
   439  //
   440  //meta:operation GET /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}
   441  func (s *TeamsService) IsTeamRepoByID(ctx context.Context, orgID, teamID int64, owner, repo string) (*Repository, *Response, error) {
   442  	u := fmt.Sprintf("organizations/%v/team/%v/repos/%v/%v", orgID, teamID, owner, repo)
   443  	req, err := s.client.NewRequest("GET", u, nil)
   444  	if err != nil {
   445  		return nil, nil, err
   446  	}
   447  
   448  	headers := []string{mediaTypeOrgPermissionRepo}
   449  	req.Header.Set("Accept", strings.Join(headers, ", "))
   450  
   451  	repository := new(Repository)
   452  	resp, err := s.client.Do(ctx, req, repository)
   453  	if err != nil {
   454  		return nil, resp, err
   455  	}
   456  
   457  	return repository, resp, nil
   458  }
   459  
   460  // IsTeamRepoBySlug checks if a team, given its slug, manages the specified repository. If the
   461  // repository is managed by team, a Repository is returned which includes the
   462  // permissions team has for that repo.
   463  //
   464  // GitHub API docs: https://docs.github.com/rest/teams/teams#check-team-permissions-for-a-repository
   465  //
   466  //meta:operation GET /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}
   467  func (s *TeamsService) IsTeamRepoBySlug(ctx context.Context, org, slug, owner, repo string) (*Repository, *Response, error) {
   468  	u := fmt.Sprintf("orgs/%v/teams/%v/repos/%v/%v", org, slug, owner, repo)
   469  	req, err := s.client.NewRequest("GET", u, nil)
   470  	if err != nil {
   471  		return nil, nil, err
   472  	}
   473  
   474  	headers := []string{mediaTypeOrgPermissionRepo}
   475  	req.Header.Set("Accept", strings.Join(headers, ", "))
   476  
   477  	repository := new(Repository)
   478  	resp, err := s.client.Do(ctx, req, repository)
   479  	if err != nil {
   480  		return nil, resp, err
   481  	}
   482  
   483  	return repository, resp, nil
   484  }
   485  
   486  // TeamAddTeamRepoOptions specifies the optional parameters to the
   487  // TeamsService.AddTeamRepoByID and TeamsService.AddTeamRepoBySlug methods.
   488  type TeamAddTeamRepoOptions struct {
   489  	// Permission specifies the permission to grant the team on this repository.
   490  	// Possible values are:
   491  	//     pull - team members can pull, but not push to or administer this repository
   492  	//     push - team members can pull and push, but not administer this repository
   493  	//     admin - team members can pull, push and administer this repository
   494  	//     maintain - team members can manage the repository without access to sensitive or destructive actions.
   495  	//     triage - team members can proactively manage issues and pull requests without write access.
   496  	//
   497  	// If not specified, the team's permission attribute will be used.
   498  	Permission string `json:"permission,omitempty"`
   499  }
   500  
   501  // AddTeamRepoByID adds a repository to be managed by the specified team given the team ID.
   502  // The specified repository must be owned by the organization to which the team
   503  // belongs, or a direct fork of a repository owned by the organization.
   504  //
   505  // GitHub API docs: https://docs.github.com/rest/teams/teams#add-or-update-team-repository-permissions
   506  //
   507  //meta:operation PUT /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}
   508  func (s *TeamsService) AddTeamRepoByID(ctx context.Context, orgID, teamID int64, owner, repo string, opts *TeamAddTeamRepoOptions) (*Response, error) {
   509  	u := fmt.Sprintf("organizations/%v/team/%v/repos/%v/%v", orgID, teamID, owner, repo)
   510  	req, err := s.client.NewRequest("PUT", u, opts)
   511  	if err != nil {
   512  		return nil, err
   513  	}
   514  
   515  	return s.client.Do(ctx, req, nil)
   516  }
   517  
   518  // AddTeamRepoBySlug adds a repository to be managed by the specified team given the team slug.
   519  // The specified repository must be owned by the organization to which the team
   520  // belongs, or a direct fork of a repository owned by the organization.
   521  //
   522  // GitHub API docs: https://docs.github.com/rest/teams/teams#add-or-update-team-repository-permissions
   523  //
   524  //meta:operation PUT /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}
   525  func (s *TeamsService) AddTeamRepoBySlug(ctx context.Context, org, slug, owner, repo string, opts *TeamAddTeamRepoOptions) (*Response, error) {
   526  	u := fmt.Sprintf("orgs/%v/teams/%v/repos/%v/%v", org, slug, owner, repo)
   527  	req, err := s.client.NewRequest("PUT", u, opts)
   528  	if err != nil {
   529  		return nil, err
   530  	}
   531  
   532  	return s.client.Do(ctx, req, nil)
   533  }
   534  
   535  // RemoveTeamRepoByID removes a repository from being managed by the specified
   536  // team given the team ID. Note that this does not delete the repository, it
   537  // just removes it from the team.
   538  //
   539  // GitHub API docs: https://docs.github.com/rest/teams/teams#remove-a-repository-from-a-team
   540  //
   541  //meta:operation DELETE /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}
   542  func (s *TeamsService) RemoveTeamRepoByID(ctx context.Context, orgID, teamID int64, owner, repo string) (*Response, error) {
   543  	u := fmt.Sprintf("organizations/%v/team/%v/repos/%v/%v", orgID, teamID, owner, repo)
   544  	req, err := s.client.NewRequest("DELETE", u, nil)
   545  	if err != nil {
   546  		return nil, err
   547  	}
   548  
   549  	return s.client.Do(ctx, req, nil)
   550  }
   551  
   552  // RemoveTeamRepoBySlug removes a repository from being managed by the specified
   553  // team given the team slug. Note that this does not delete the repository, it
   554  // just removes it from the team.
   555  //
   556  // GitHub API docs: https://docs.github.com/rest/teams/teams#remove-a-repository-from-a-team
   557  //
   558  //meta:operation DELETE /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}
   559  func (s *TeamsService) RemoveTeamRepoBySlug(ctx context.Context, org, slug, owner, repo string) (*Response, error) {
   560  	u := fmt.Sprintf("orgs/%v/teams/%v/repos/%v/%v", org, slug, owner, repo)
   561  	req, err := s.client.NewRequest("DELETE", u, nil)
   562  	if err != nil {
   563  		return nil, err
   564  	}
   565  
   566  	return s.client.Do(ctx, req, nil)
   567  }
   568  
   569  // ListUserTeams lists a user's teams
   570  //
   571  // GitHub API docs: https://docs.github.com/rest/teams/teams#list-teams-for-the-authenticated-user
   572  //
   573  //meta:operation GET /user/teams
   574  func (s *TeamsService) ListUserTeams(ctx context.Context, opts *ListOptions) ([]*Team, *Response, error) {
   575  	u := "user/teams"
   576  	u, err := addOptions(u, opts)
   577  	if err != nil {
   578  		return nil, nil, err
   579  	}
   580  
   581  	req, err := s.client.NewRequest("GET", u, nil)
   582  	if err != nil {
   583  		return nil, nil, err
   584  	}
   585  
   586  	var teams []*Team
   587  	resp, err := s.client.Do(ctx, req, &teams)
   588  	if err != nil {
   589  		return nil, resp, err
   590  	}
   591  
   592  	return teams, resp, nil
   593  }
   594  
   595  // ListTeamProjectsByID lists the organization projects for a team given the team ID.
   596  //
   597  // GitHub API docs: https://docs.github.com/rest/teams/teams#list-team-projects
   598  //
   599  //meta:operation GET /orgs/{org}/teams/{team_slug}/projects
   600  func (s *TeamsService) ListTeamProjectsByID(ctx context.Context, orgID, teamID int64) ([]*Project, *Response, error) {
   601  	u := fmt.Sprintf("organizations/%v/team/%v/projects", orgID, teamID)
   602  
   603  	req, err := s.client.NewRequest("GET", u, nil)
   604  	if err != nil {
   605  		return nil, nil, err
   606  	}
   607  
   608  	// TODO: remove custom Accept header when this API fully launches.
   609  	acceptHeaders := []string{mediaTypeProjectsPreview}
   610  	req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
   611  
   612  	var projects []*Project
   613  	resp, err := s.client.Do(ctx, req, &projects)
   614  	if err != nil {
   615  		return nil, resp, err
   616  	}
   617  
   618  	return projects, resp, nil
   619  }
   620  
   621  // ListTeamProjectsBySlug lists the organization projects for a team given the team slug.
   622  //
   623  // GitHub API docs: https://docs.github.com/rest/teams/teams#list-team-projects
   624  //
   625  //meta:operation GET /orgs/{org}/teams/{team_slug}/projects
   626  func (s *TeamsService) ListTeamProjectsBySlug(ctx context.Context, org, slug string) ([]*Project, *Response, error) {
   627  	u := fmt.Sprintf("orgs/%v/teams/%v/projects", org, slug)
   628  
   629  	req, err := s.client.NewRequest("GET", u, nil)
   630  	if err != nil {
   631  		return nil, nil, err
   632  	}
   633  
   634  	// TODO: remove custom Accept header when this API fully launches.
   635  	acceptHeaders := []string{mediaTypeProjectsPreview}
   636  	req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
   637  
   638  	var projects []*Project
   639  	resp, err := s.client.Do(ctx, req, &projects)
   640  	if err != nil {
   641  		return nil, resp, err
   642  	}
   643  
   644  	return projects, resp, nil
   645  }
   646  
   647  // ReviewTeamProjectsByID checks whether a team, given its ID, has read, write, or admin
   648  // permissions for an organization project.
   649  //
   650  // GitHub API docs: https://docs.github.com/rest/teams/teams#check-team-permissions-for-a-project
   651  //
   652  //meta:operation GET /orgs/{org}/teams/{team_slug}/projects/{project_id}
   653  func (s *TeamsService) ReviewTeamProjectsByID(ctx context.Context, orgID, teamID, projectID int64) (*Project, *Response, error) {
   654  	u := fmt.Sprintf("organizations/%v/team/%v/projects/%v", orgID, teamID, projectID)
   655  	req, err := s.client.NewRequest("GET", u, nil)
   656  	if err != nil {
   657  		return nil, nil, err
   658  	}
   659  
   660  	// TODO: remove custom Accept header when this API fully launches.
   661  	acceptHeaders := []string{mediaTypeProjectsPreview}
   662  	req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
   663  
   664  	projects := &Project{}
   665  	resp, err := s.client.Do(ctx, req, &projects)
   666  	if err != nil {
   667  		return nil, resp, err
   668  	}
   669  
   670  	return projects, resp, nil
   671  }
   672  
   673  // ReviewTeamProjectsBySlug checks whether a team, given its slug, has read, write, or admin
   674  // permissions for an organization project.
   675  //
   676  // GitHub API docs: https://docs.github.com/rest/teams/teams#check-team-permissions-for-a-project
   677  //
   678  //meta:operation GET /orgs/{org}/teams/{team_slug}/projects/{project_id}
   679  func (s *TeamsService) ReviewTeamProjectsBySlug(ctx context.Context, org, slug string, projectID int64) (*Project, *Response, error) {
   680  	u := fmt.Sprintf("orgs/%v/teams/%v/projects/%v", org, slug, projectID)
   681  	req, err := s.client.NewRequest("GET", u, nil)
   682  	if err != nil {
   683  		return nil, nil, err
   684  	}
   685  
   686  	// TODO: remove custom Accept header when this API fully launches.
   687  	acceptHeaders := []string{mediaTypeProjectsPreview}
   688  	req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
   689  
   690  	projects := &Project{}
   691  	resp, err := s.client.Do(ctx, req, &projects)
   692  	if err != nil {
   693  		return nil, resp, err
   694  	}
   695  
   696  	return projects, resp, nil
   697  }
   698  
   699  // TeamProjectOptions specifies the optional parameters to the
   700  // TeamsService.AddTeamProject method.
   701  type TeamProjectOptions struct {
   702  	// Permission specifies the permission to grant to the team for this project.
   703  	// Possible values are:
   704  	//     "read" - team members can read, but not write to or administer this project.
   705  	//     "write" - team members can read and write, but not administer this project.
   706  	//     "admin" - team members can read, write and administer this project.
   707  	//
   708  	Permission *string `json:"permission,omitempty"`
   709  }
   710  
   711  // AddTeamProjectByID adds an organization project to a team given the team ID.
   712  // To add a project to a team or update the team's permission on a project, the
   713  // authenticated user must have admin permissions for the project.
   714  //
   715  // GitHub API docs: https://docs.github.com/rest/teams/teams#add-or-update-team-project-permissions
   716  //
   717  //meta:operation PUT /orgs/{org}/teams/{team_slug}/projects/{project_id}
   718  func (s *TeamsService) AddTeamProjectByID(ctx context.Context, orgID, teamID, projectID int64, opts *TeamProjectOptions) (*Response, error) {
   719  	u := fmt.Sprintf("organizations/%v/team/%v/projects/%v", orgID, teamID, projectID)
   720  	req, err := s.client.NewRequest("PUT", u, opts)
   721  	if err != nil {
   722  		return nil, err
   723  	}
   724  
   725  	// TODO: remove custom Accept header when this API fully launches.
   726  	acceptHeaders := []string{mediaTypeProjectsPreview}
   727  	req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
   728  
   729  	return s.client.Do(ctx, req, nil)
   730  }
   731  
   732  // AddTeamProjectBySlug adds an organization project to a team given the team slug.
   733  // To add a project to a team or update the team's permission on a project, the
   734  // authenticated user must have admin permissions for the project.
   735  //
   736  // GitHub API docs: https://docs.github.com/rest/teams/teams#add-or-update-team-project-permissions
   737  //
   738  //meta:operation PUT /orgs/{org}/teams/{team_slug}/projects/{project_id}
   739  func (s *TeamsService) AddTeamProjectBySlug(ctx context.Context, org, slug string, projectID int64, opts *TeamProjectOptions) (*Response, error) {
   740  	u := fmt.Sprintf("orgs/%v/teams/%v/projects/%v", org, slug, projectID)
   741  	req, err := s.client.NewRequest("PUT", u, opts)
   742  	if err != nil {
   743  		return nil, err
   744  	}
   745  
   746  	// TODO: remove custom Accept header when this API fully launches.
   747  	acceptHeaders := []string{mediaTypeProjectsPreview}
   748  	req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
   749  
   750  	return s.client.Do(ctx, req, nil)
   751  }
   752  
   753  // RemoveTeamProjectByID removes an organization project from a team given team ID.
   754  // An organization owner or a team maintainer can remove any project from the team.
   755  // To remove a project from a team as an organization member, the authenticated user
   756  // must have "read" access to both the team and project, or "admin" access to the team
   757  // or project.
   758  // Note: This endpoint removes the project from the team, but does not delete it.
   759  //
   760  // GitHub API docs: https://docs.github.com/rest/teams/teams#remove-a-project-from-a-team
   761  //
   762  //meta:operation DELETE /orgs/{org}/teams/{team_slug}/projects/{project_id}
   763  func (s *TeamsService) RemoveTeamProjectByID(ctx context.Context, orgID, teamID, projectID int64) (*Response, error) {
   764  	u := fmt.Sprintf("organizations/%v/team/%v/projects/%v", orgID, teamID, projectID)
   765  	req, err := s.client.NewRequest("DELETE", u, nil)
   766  	if err != nil {
   767  		return nil, err
   768  	}
   769  
   770  	// TODO: remove custom Accept header when this API fully launches.
   771  	acceptHeaders := []string{mediaTypeProjectsPreview}
   772  	req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
   773  
   774  	return s.client.Do(ctx, req, nil)
   775  }
   776  
   777  // RemoveTeamProjectBySlug removes an organization project from a team given team slug.
   778  // An organization owner or a team maintainer can remove any project from the team.
   779  // To remove a project from a team as an organization member, the authenticated user
   780  // must have "read" access to both the team and project, or "admin" access to the team
   781  // or project.
   782  // Note: This endpoint removes the project from the team, but does not delete it.
   783  //
   784  // GitHub API docs: https://docs.github.com/rest/teams/teams#remove-a-project-from-a-team
   785  //
   786  //meta:operation DELETE /orgs/{org}/teams/{team_slug}/projects/{project_id}
   787  func (s *TeamsService) RemoveTeamProjectBySlug(ctx context.Context, org, slug string, projectID int64) (*Response, error) {
   788  	u := fmt.Sprintf("orgs/%v/teams/%v/projects/%v", org, slug, projectID)
   789  	req, err := s.client.NewRequest("DELETE", u, nil)
   790  	if err != nil {
   791  		return nil, err
   792  	}
   793  
   794  	// TODO: remove custom Accept header when this API fully launches.
   795  	acceptHeaders := []string{mediaTypeProjectsPreview}
   796  	req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
   797  
   798  	return s.client.Do(ctx, req, nil)
   799  }
   800  
   801  // ListIDPGroupsOptions specifies the optional parameters to the ListIDPGroupsInOrganization method.
   802  type ListIDPGroupsOptions struct {
   803  	// Filters the results to return only those that begin with the value specified by this parameter.
   804  	Query string `url:"q,omitempty"`
   805  
   806  	ListCursorOptions
   807  }
   808  
   809  // IDPGroupList represents a list of external identity provider (IDP) groups.
   810  type IDPGroupList struct {
   811  	Groups []*IDPGroup `json:"groups"`
   812  }
   813  
   814  // IDPGroup represents an external identity provider (IDP) group.
   815  type IDPGroup struct {
   816  	GroupID          *string `json:"group_id,omitempty"`
   817  	GroupName        *string `json:"group_name,omitempty"`
   818  	GroupDescription *string `json:"group_description,omitempty"`
   819  }
   820  
   821  // ListIDPGroupsInOrganization lists IDP groups available in an organization.
   822  //
   823  // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/teams/team-sync#list-idp-groups-for-an-organization
   824  //
   825  //meta:operation GET /orgs/{org}/team-sync/groups
   826  func (s *TeamsService) ListIDPGroupsInOrganization(ctx context.Context, org string, opts *ListIDPGroupsOptions) (*IDPGroupList, *Response, error) {
   827  	u := fmt.Sprintf("orgs/%v/team-sync/groups", org)
   828  	u, err := addOptions(u, opts)
   829  	if err != nil {
   830  		return nil, nil, err
   831  	}
   832  
   833  	req, err := s.client.NewRequest("GET", u, nil)
   834  	if err != nil {
   835  		return nil, nil, err
   836  	}
   837  
   838  	groups := new(IDPGroupList)
   839  	resp, err := s.client.Do(ctx, req, groups)
   840  	if err != nil {
   841  		return nil, resp, err
   842  	}
   843  
   844  	return groups, resp, nil
   845  }
   846  
   847  // ListIDPGroupsForTeamByID lists IDP groups connected to a team on GitHub
   848  // given organization and team IDs.
   849  //
   850  // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/teams/team-sync#list-idp-groups-for-a-team
   851  //
   852  //meta:operation GET /orgs/{org}/teams/{team_slug}/team-sync/group-mappings
   853  func (s *TeamsService) ListIDPGroupsForTeamByID(ctx context.Context, orgID, teamID int64) (*IDPGroupList, *Response, error) {
   854  	u := fmt.Sprintf("organizations/%v/team/%v/team-sync/group-mappings", orgID, teamID)
   855  
   856  	req, err := s.client.NewRequest("GET", u, nil)
   857  	if err != nil {
   858  		return nil, nil, err
   859  	}
   860  
   861  	groups := new(IDPGroupList)
   862  	resp, err := s.client.Do(ctx, req, groups)
   863  	if err != nil {
   864  		return nil, resp, err
   865  	}
   866  
   867  	return groups, resp, nil
   868  }
   869  
   870  // ListIDPGroupsForTeamBySlug lists IDP groups connected to a team on GitHub
   871  // given organization name and team slug.
   872  //
   873  // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/teams/team-sync#list-idp-groups-for-a-team
   874  //
   875  //meta:operation GET /orgs/{org}/teams/{team_slug}/team-sync/group-mappings
   876  func (s *TeamsService) ListIDPGroupsForTeamBySlug(ctx context.Context, org, slug string) (*IDPGroupList, *Response, error) {
   877  	u := fmt.Sprintf("orgs/%v/teams/%v/team-sync/group-mappings", org, slug)
   878  
   879  	req, err := s.client.NewRequest("GET", u, nil)
   880  	if err != nil {
   881  		return nil, nil, err
   882  	}
   883  
   884  	groups := new(IDPGroupList)
   885  	resp, err := s.client.Do(ctx, req, groups)
   886  	if err != nil {
   887  		return nil, resp, err
   888  	}
   889  
   890  	return groups, resp, nil
   891  }
   892  
   893  // CreateOrUpdateIDPGroupConnectionsByID creates, updates, or removes a connection
   894  // between a team and an IDP group given organization and team IDs.
   895  //
   896  // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/teams/team-sync#create-or-update-idp-group-connections
   897  //
   898  //meta:operation PATCH /orgs/{org}/teams/{team_slug}/team-sync/group-mappings
   899  func (s *TeamsService) CreateOrUpdateIDPGroupConnectionsByID(ctx context.Context, orgID, teamID int64, opts IDPGroupList) (*IDPGroupList, *Response, error) {
   900  	u := fmt.Sprintf("organizations/%v/team/%v/team-sync/group-mappings", orgID, teamID)
   901  
   902  	req, err := s.client.NewRequest("PATCH", u, opts)
   903  	if err != nil {
   904  		return nil, nil, err
   905  	}
   906  
   907  	groups := new(IDPGroupList)
   908  	resp, err := s.client.Do(ctx, req, groups)
   909  	if err != nil {
   910  		return nil, resp, err
   911  	}
   912  
   913  	return groups, resp, nil
   914  }
   915  
   916  // CreateOrUpdateIDPGroupConnectionsBySlug creates, updates, or removes a connection
   917  // between a team and an IDP group given organization name and team slug.
   918  //
   919  // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/teams/team-sync#create-or-update-idp-group-connections
   920  //
   921  //meta:operation PATCH /orgs/{org}/teams/{team_slug}/team-sync/group-mappings
   922  func (s *TeamsService) CreateOrUpdateIDPGroupConnectionsBySlug(ctx context.Context, org, slug string, opts IDPGroupList) (*IDPGroupList, *Response, error) {
   923  	u := fmt.Sprintf("orgs/%v/teams/%v/team-sync/group-mappings", org, slug)
   924  
   925  	req, err := s.client.NewRequest("PATCH", u, opts)
   926  	if err != nil {
   927  		return nil, nil, err
   928  	}
   929  
   930  	groups := new(IDPGroupList)
   931  	resp, err := s.client.Do(ctx, req, groups)
   932  	if err != nil {
   933  		return nil, resp, err
   934  	}
   935  
   936  	return groups, resp, nil
   937  }
   938  
   939  // ExternalGroupMember represents a member of an external group.
   940  type ExternalGroupMember struct {
   941  	MemberID    *int64  `json:"member_id,omitempty"`
   942  	MemberLogin *string `json:"member_login,omitempty"`
   943  	MemberName  *string `json:"member_name,omitempty"`
   944  	MemberEmail *string `json:"member_email,omitempty"`
   945  }
   946  
   947  // ExternalGroupTeam represents a team connected to an external group.
   948  type ExternalGroupTeam struct {
   949  	TeamID   *int64  `json:"team_id,omitempty"`
   950  	TeamName *string `json:"team_name,omitempty"`
   951  }
   952  
   953  // ExternalGroup represents an external group.
   954  type ExternalGroup struct {
   955  	GroupID   *int64                 `json:"group_id,omitempty"`
   956  	GroupName *string                `json:"group_name,omitempty"`
   957  	UpdatedAt *Timestamp             `json:"updated_at,omitempty"`
   958  	Teams     []*ExternalGroupTeam   `json:"teams,omitempty"`
   959  	Members   []*ExternalGroupMember `json:"members,omitempty"`
   960  }
   961  
   962  // ExternalGroupList represents a list of external groups.
   963  type ExternalGroupList struct {
   964  	Groups []*ExternalGroup `json:"groups"`
   965  }
   966  
   967  // GetExternalGroup fetches an external group.
   968  //
   969  // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/teams/external-groups#get-an-external-group
   970  //
   971  //meta:operation GET /orgs/{org}/external-group/{group_id}
   972  func (s *TeamsService) GetExternalGroup(ctx context.Context, org string, groupID int64) (*ExternalGroup, *Response, error) {
   973  	u := fmt.Sprintf("orgs/%v/external-group/%v", org, groupID)
   974  	req, err := s.client.NewRequest("GET", u, nil)
   975  	if err != nil {
   976  		return nil, nil, err
   977  	}
   978  
   979  	externalGroup := new(ExternalGroup)
   980  	resp, err := s.client.Do(ctx, req, externalGroup)
   981  	if err != nil {
   982  		return nil, resp, err
   983  	}
   984  
   985  	return externalGroup, resp, nil
   986  }
   987  
   988  // ListExternalGroupsOptions specifies the optional parameters to the
   989  // TeamsService.ListExternalGroups method.
   990  type ListExternalGroupsOptions struct {
   991  	DisplayName *string `url:"display_name,omitempty"`
   992  
   993  	ListOptions
   994  }
   995  
   996  // ListExternalGroups lists external groups in an organization on GitHub.
   997  //
   998  // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/teams/external-groups#list-external-groups-in-an-organization
   999  //
  1000  //meta:operation GET /orgs/{org}/external-groups
  1001  func (s *TeamsService) ListExternalGroups(ctx context.Context, org string, opts *ListExternalGroupsOptions) (*ExternalGroupList, *Response, error) {
  1002  	u := fmt.Sprintf("orgs/%v/external-groups", org)
  1003  	u, err := addOptions(u, opts)
  1004  	if err != nil {
  1005  		return nil, nil, err
  1006  	}
  1007  
  1008  	req, err := s.client.NewRequest("GET", u, nil)
  1009  	if err != nil {
  1010  		return nil, nil, err
  1011  	}
  1012  
  1013  	externalGroups := new(ExternalGroupList)
  1014  	resp, err := s.client.Do(ctx, req, externalGroups)
  1015  	if err != nil {
  1016  		return nil, resp, err
  1017  	}
  1018  
  1019  	return externalGroups, resp, nil
  1020  }
  1021  
  1022  // ListExternalGroupsForTeamBySlug lists external groups connected to a team on GitHub.
  1023  //
  1024  // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/teams/external-groups#list-a-connection-between-an-external-group-and-a-team
  1025  //
  1026  //meta:operation GET /orgs/{org}/teams/{team_slug}/external-groups
  1027  func (s *TeamsService) ListExternalGroupsForTeamBySlug(ctx context.Context, org, slug string) (*ExternalGroupList, *Response, error) {
  1028  	u := fmt.Sprintf("orgs/%v/teams/%v/external-groups", org, slug)
  1029  
  1030  	req, err := s.client.NewRequest("GET", u, nil)
  1031  	if err != nil {
  1032  		return nil, nil, err
  1033  	}
  1034  
  1035  	externalGroups := new(ExternalGroupList)
  1036  	resp, err := s.client.Do(ctx, req, externalGroups)
  1037  	if err != nil {
  1038  		return nil, resp, err
  1039  	}
  1040  
  1041  	return externalGroups, resp, nil
  1042  }
  1043  
  1044  // UpdateConnectedExternalGroup updates the connection between an external group and a team.
  1045  //
  1046  // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/teams/external-groups#update-the-connection-between-an-external-group-and-a-team
  1047  //
  1048  //meta:operation PATCH /orgs/{org}/teams/{team_slug}/external-groups
  1049  func (s *TeamsService) UpdateConnectedExternalGroup(ctx context.Context, org, slug string, eg *ExternalGroup) (*ExternalGroup, *Response, error) {
  1050  	u := fmt.Sprintf("orgs/%v/teams/%v/external-groups", org, slug)
  1051  
  1052  	req, err := s.client.NewRequest("PATCH", u, eg)
  1053  	if err != nil {
  1054  		return nil, nil, err
  1055  	}
  1056  
  1057  	externalGroup := new(ExternalGroup)
  1058  	resp, err := s.client.Do(ctx, req, externalGroup)
  1059  	if err != nil {
  1060  		return nil, resp, err
  1061  	}
  1062  
  1063  	return externalGroup, resp, nil
  1064  }
  1065  
  1066  // RemoveConnectedExternalGroup removes the connection between an external group and a team.
  1067  //
  1068  // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/teams/external-groups#remove-the-connection-between-an-external-group-and-a-team
  1069  //
  1070  //meta:operation DELETE /orgs/{org}/teams/{team_slug}/external-groups
  1071  func (s *TeamsService) RemoveConnectedExternalGroup(ctx context.Context, org, slug string) (*Response, error) {
  1072  	u := fmt.Sprintf("orgs/%v/teams/%v/external-groups", org, slug)
  1073  
  1074  	req, err := s.client.NewRequest("DELETE", u, nil)
  1075  	if err != nil {
  1076  		return nil, err
  1077  	}
  1078  
  1079  	return s.client.Do(ctx, req, nil)
  1080  }