github.com/google/go-github/v65@v65.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  	Privacy      *string  `json:"privacy,omitempty"`
   215  	LDAPDN       *string  `json:"ldap_dn,omitempty"`
   216  }
   217  
   218  // copyNewTeamWithoutParent is used to set the "parent_team_id"
   219  // field to "null" after copying the other fields from a NewTeam.
   220  // It is for internal use only and should not be exported.
   221  func copyNewTeamWithoutParent(team *NewTeam) *newTeamNoParent {
   222  	return &newTeamNoParent{
   223  		Name:        team.Name,
   224  		Description: team.Description,
   225  		Maintainers: team.Maintainers,
   226  		RepoNames:   team.RepoNames,
   227  		Privacy:     team.Privacy,
   228  		LDAPDN:      team.LDAPDN,
   229  	}
   230  }
   231  
   232  // EditTeamByID edits a team, given an organization ID, selected by ID.
   233  //
   234  // GitHub API docs: https://docs.github.com/rest/teams/teams#update-a-team
   235  //
   236  //meta:operation PATCH /orgs/{org}/teams/{team_slug}
   237  func (s *TeamsService) EditTeamByID(ctx context.Context, orgID, teamID int64, team NewTeam, removeParent bool) (*Team, *Response, error) {
   238  	u := fmt.Sprintf("organizations/%v/team/%v", orgID, teamID)
   239  
   240  	var req *http.Request
   241  	var err error
   242  	if removeParent {
   243  		teamRemoveParent := copyNewTeamWithoutParent(&team)
   244  		req, err = s.client.NewRequest("PATCH", u, teamRemoveParent)
   245  	} else {
   246  		req, err = s.client.NewRequest("PATCH", u, team)
   247  	}
   248  	if err != nil {
   249  		return nil, nil, err
   250  	}
   251  
   252  	t := new(Team)
   253  	resp, err := s.client.Do(ctx, req, t)
   254  	if err != nil {
   255  		return nil, resp, err
   256  	}
   257  
   258  	return t, resp, nil
   259  }
   260  
   261  // EditTeamBySlug edits a team, given an organization name, by slug.
   262  //
   263  // GitHub API docs: https://docs.github.com/rest/teams/teams#update-a-team
   264  //
   265  //meta:operation PATCH /orgs/{org}/teams/{team_slug}
   266  func (s *TeamsService) EditTeamBySlug(ctx context.Context, org, slug string, team NewTeam, removeParent bool) (*Team, *Response, error) {
   267  	u := fmt.Sprintf("orgs/%v/teams/%v", org, slug)
   268  
   269  	var req *http.Request
   270  	var err error
   271  	if removeParent {
   272  		teamRemoveParent := copyNewTeamWithoutParent(&team)
   273  		req, err = s.client.NewRequest("PATCH", u, teamRemoveParent)
   274  	} else {
   275  		req, err = s.client.NewRequest("PATCH", u, team)
   276  	}
   277  	if err != nil {
   278  		return nil, nil, err
   279  	}
   280  
   281  	t := new(Team)
   282  	resp, err := s.client.Do(ctx, req, t)
   283  	if err != nil {
   284  		return nil, resp, err
   285  	}
   286  
   287  	return t, resp, nil
   288  }
   289  
   290  // DeleteTeamByID deletes a team referenced by ID.
   291  //
   292  // GitHub API docs: https://docs.github.com/rest/teams/teams#delete-a-team
   293  //
   294  //meta:operation DELETE /orgs/{org}/teams/{team_slug}
   295  func (s *TeamsService) DeleteTeamByID(ctx context.Context, orgID, teamID int64) (*Response, error) {
   296  	u := fmt.Sprintf("organizations/%v/team/%v", orgID, teamID)
   297  	req, err := s.client.NewRequest("DELETE", u, nil)
   298  	if err != nil {
   299  		return nil, err
   300  	}
   301  
   302  	return s.client.Do(ctx, req, nil)
   303  }
   304  
   305  // DeleteTeamBySlug deletes a team reference by slug.
   306  //
   307  // GitHub API docs: https://docs.github.com/rest/teams/teams#delete-a-team
   308  //
   309  //meta:operation DELETE /orgs/{org}/teams/{team_slug}
   310  func (s *TeamsService) DeleteTeamBySlug(ctx context.Context, org, slug string) (*Response, error) {
   311  	u := fmt.Sprintf("orgs/%v/teams/%v", org, slug)
   312  	req, err := s.client.NewRequest("DELETE", u, nil)
   313  	if err != nil {
   314  		return nil, err
   315  	}
   316  
   317  	return s.client.Do(ctx, req, nil)
   318  }
   319  
   320  // ListChildTeamsByParentID lists child teams for a parent team given parent ID.
   321  //
   322  // GitHub API docs: https://docs.github.com/rest/teams/teams#list-child-teams
   323  //
   324  //meta:operation GET /orgs/{org}/teams/{team_slug}/teams
   325  func (s *TeamsService) ListChildTeamsByParentID(ctx context.Context, orgID, teamID int64, opts *ListOptions) ([]*Team, *Response, error) {
   326  	u := fmt.Sprintf("organizations/%v/team/%v/teams", orgID, teamID)
   327  	u, err := addOptions(u, opts)
   328  	if err != nil {
   329  		return nil, nil, err
   330  	}
   331  
   332  	req, err := s.client.NewRequest("GET", u, nil)
   333  	if err != nil {
   334  		return nil, nil, err
   335  	}
   336  
   337  	var teams []*Team
   338  	resp, err := s.client.Do(ctx, req, &teams)
   339  	if err != nil {
   340  		return nil, resp, err
   341  	}
   342  
   343  	return teams, resp, nil
   344  }
   345  
   346  // ListChildTeamsByParentSlug lists child teams for a parent team given parent slug.
   347  //
   348  // GitHub API docs: https://docs.github.com/rest/teams/teams#list-child-teams
   349  //
   350  //meta:operation GET /orgs/{org}/teams/{team_slug}/teams
   351  func (s *TeamsService) ListChildTeamsByParentSlug(ctx context.Context, org, slug string, opts *ListOptions) ([]*Team, *Response, error) {
   352  	u := fmt.Sprintf("orgs/%v/teams/%v/teams", org, slug)
   353  	u, err := addOptions(u, opts)
   354  	if err != nil {
   355  		return nil, nil, err
   356  	}
   357  
   358  	req, err := s.client.NewRequest("GET", u, nil)
   359  	if err != nil {
   360  		return nil, nil, err
   361  	}
   362  
   363  	var teams []*Team
   364  	resp, err := s.client.Do(ctx, req, &teams)
   365  	if err != nil {
   366  		return nil, resp, err
   367  	}
   368  
   369  	return teams, resp, nil
   370  }
   371  
   372  // ListTeamReposByID lists the repositories given a team ID that the specified team has access to.
   373  //
   374  // GitHub API docs: https://docs.github.com/rest/teams/teams#list-team-repositories
   375  //
   376  //meta:operation GET /orgs/{org}/teams/{team_slug}/repos
   377  func (s *TeamsService) ListTeamReposByID(ctx context.Context, orgID, teamID int64, opts *ListOptions) ([]*Repository, *Response, error) {
   378  	u := fmt.Sprintf("organizations/%v/team/%v/repos", orgID, teamID)
   379  	u, err := addOptions(u, opts)
   380  	if err != nil {
   381  		return nil, nil, err
   382  	}
   383  
   384  	req, err := s.client.NewRequest("GET", u, nil)
   385  	if err != nil {
   386  		return nil, nil, err
   387  	}
   388  
   389  	// TODO: remove custom Accept header when topics API fully launches.
   390  	headers := []string{mediaTypeTopicsPreview}
   391  	req.Header.Set("Accept", strings.Join(headers, ", "))
   392  
   393  	var repos []*Repository
   394  	resp, err := s.client.Do(ctx, req, &repos)
   395  	if err != nil {
   396  		return nil, resp, err
   397  	}
   398  
   399  	return repos, resp, nil
   400  }
   401  
   402  // ListTeamReposBySlug lists the repositories given a team slug that the specified team has access to.
   403  //
   404  // GitHub API docs: https://docs.github.com/rest/teams/teams#list-team-repositories
   405  //
   406  //meta:operation GET /orgs/{org}/teams/{team_slug}/repos
   407  func (s *TeamsService) ListTeamReposBySlug(ctx context.Context, org, slug string, opts *ListOptions) ([]*Repository, *Response, error) {
   408  	u := fmt.Sprintf("orgs/%v/teams/%v/repos", org, slug)
   409  	u, err := addOptions(u, opts)
   410  	if err != nil {
   411  		return nil, nil, err
   412  	}
   413  
   414  	req, err := s.client.NewRequest("GET", u, nil)
   415  	if err != nil {
   416  		return nil, nil, err
   417  	}
   418  
   419  	// TODO: remove custom Accept header when topics API fully launches.
   420  	headers := []string{mediaTypeTopicsPreview}
   421  	req.Header.Set("Accept", strings.Join(headers, ", "))
   422  
   423  	var repos []*Repository
   424  	resp, err := s.client.Do(ctx, req, &repos)
   425  	if err != nil {
   426  		return nil, resp, err
   427  	}
   428  
   429  	return repos, resp, nil
   430  }
   431  
   432  // IsTeamRepoByID checks if a team, given its ID, manages the specified repository. If the
   433  // repository is managed by team, a Repository is returned which includes the
   434  // permissions team has for that repo.
   435  //
   436  // GitHub API docs: https://docs.github.com/rest/teams/teams#check-team-permissions-for-a-repository
   437  //
   438  //meta:operation GET /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}
   439  func (s *TeamsService) IsTeamRepoByID(ctx context.Context, orgID, teamID int64, owner, repo string) (*Repository, *Response, error) {
   440  	u := fmt.Sprintf("organizations/%v/team/%v/repos/%v/%v", orgID, teamID, owner, repo)
   441  	req, err := s.client.NewRequest("GET", u, nil)
   442  	if err != nil {
   443  		return nil, nil, err
   444  	}
   445  
   446  	headers := []string{mediaTypeOrgPermissionRepo}
   447  	req.Header.Set("Accept", strings.Join(headers, ", "))
   448  
   449  	repository := new(Repository)
   450  	resp, err := s.client.Do(ctx, req, repository)
   451  	if err != nil {
   452  		return nil, resp, err
   453  	}
   454  
   455  	return repository, resp, nil
   456  }
   457  
   458  // IsTeamRepoBySlug checks if a team, given its slug, manages the specified repository. If the
   459  // repository is managed by team, a Repository is returned which includes the
   460  // permissions team has for that repo.
   461  //
   462  // GitHub API docs: https://docs.github.com/rest/teams/teams#check-team-permissions-for-a-repository
   463  //
   464  //meta:operation GET /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}
   465  func (s *TeamsService) IsTeamRepoBySlug(ctx context.Context, org, slug, owner, repo string) (*Repository, *Response, error) {
   466  	u := fmt.Sprintf("orgs/%v/teams/%v/repos/%v/%v", org, slug, owner, repo)
   467  	req, err := s.client.NewRequest("GET", u, nil)
   468  	if err != nil {
   469  		return nil, nil, err
   470  	}
   471  
   472  	headers := []string{mediaTypeOrgPermissionRepo}
   473  	req.Header.Set("Accept", strings.Join(headers, ", "))
   474  
   475  	repository := new(Repository)
   476  	resp, err := s.client.Do(ctx, req, repository)
   477  	if err != nil {
   478  		return nil, resp, err
   479  	}
   480  
   481  	return repository, resp, nil
   482  }
   483  
   484  // TeamAddTeamRepoOptions specifies the optional parameters to the
   485  // TeamsService.AddTeamRepoByID and TeamsService.AddTeamRepoBySlug methods.
   486  type TeamAddTeamRepoOptions struct {
   487  	// Permission specifies the permission to grant the team on this repository.
   488  	// Possible values are:
   489  	//     pull - team members can pull, but not push to or administer this repository
   490  	//     push - team members can pull and push, but not administer this repository
   491  	//     admin - team members can pull, push and administer this repository
   492  	//     maintain - team members can manage the repository without access to sensitive or destructive actions.
   493  	//     triage - team members can proactively manage issues and pull requests without write access.
   494  	//
   495  	// If not specified, the team's permission attribute will be used.
   496  	Permission string `json:"permission,omitempty"`
   497  }
   498  
   499  // AddTeamRepoByID adds a repository to be managed by the specified team given the team ID.
   500  // The specified repository must be owned by the organization to which the team
   501  // belongs, or a direct fork of a repository owned by the organization.
   502  //
   503  // GitHub API docs: https://docs.github.com/rest/teams/teams#add-or-update-team-repository-permissions
   504  //
   505  //meta:operation PUT /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}
   506  func (s *TeamsService) AddTeamRepoByID(ctx context.Context, orgID, teamID int64, owner, repo string, opts *TeamAddTeamRepoOptions) (*Response, error) {
   507  	u := fmt.Sprintf("organizations/%v/team/%v/repos/%v/%v", orgID, teamID, owner, repo)
   508  	req, err := s.client.NewRequest("PUT", u, opts)
   509  	if err != nil {
   510  		return nil, err
   511  	}
   512  
   513  	return s.client.Do(ctx, req, nil)
   514  }
   515  
   516  // AddTeamRepoBySlug adds a repository to be managed by the specified team given the team slug.
   517  // The specified repository must be owned by the organization to which the team
   518  // belongs, or a direct fork of a repository owned by the organization.
   519  //
   520  // GitHub API docs: https://docs.github.com/rest/teams/teams#add-or-update-team-repository-permissions
   521  //
   522  //meta:operation PUT /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}
   523  func (s *TeamsService) AddTeamRepoBySlug(ctx context.Context, org, slug, owner, repo string, opts *TeamAddTeamRepoOptions) (*Response, error) {
   524  	u := fmt.Sprintf("orgs/%v/teams/%v/repos/%v/%v", org, slug, owner, repo)
   525  	req, err := s.client.NewRequest("PUT", u, opts)
   526  	if err != nil {
   527  		return nil, err
   528  	}
   529  
   530  	return s.client.Do(ctx, req, nil)
   531  }
   532  
   533  // RemoveTeamRepoByID removes a repository from being managed by the specified
   534  // team given the team ID. Note that this does not delete the repository, it
   535  // just removes it from the team.
   536  //
   537  // GitHub API docs: https://docs.github.com/rest/teams/teams#remove-a-repository-from-a-team
   538  //
   539  //meta:operation DELETE /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}
   540  func (s *TeamsService) RemoveTeamRepoByID(ctx context.Context, orgID, teamID int64, owner, repo string) (*Response, error) {
   541  	u := fmt.Sprintf("organizations/%v/team/%v/repos/%v/%v", orgID, teamID, owner, repo)
   542  	req, err := s.client.NewRequest("DELETE", u, nil)
   543  	if err != nil {
   544  		return nil, err
   545  	}
   546  
   547  	return s.client.Do(ctx, req, nil)
   548  }
   549  
   550  // RemoveTeamRepoBySlug removes a repository from being managed by the specified
   551  // team given the team slug. Note that this does not delete the repository, it
   552  // just removes it from the team.
   553  //
   554  // GitHub API docs: https://docs.github.com/rest/teams/teams#remove-a-repository-from-a-team
   555  //
   556  //meta:operation DELETE /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}
   557  func (s *TeamsService) RemoveTeamRepoBySlug(ctx context.Context, org, slug, owner, repo string) (*Response, error) {
   558  	u := fmt.Sprintf("orgs/%v/teams/%v/repos/%v/%v", org, slug, owner, repo)
   559  	req, err := s.client.NewRequest("DELETE", u, nil)
   560  	if err != nil {
   561  		return nil, err
   562  	}
   563  
   564  	return s.client.Do(ctx, req, nil)
   565  }
   566  
   567  // ListUserTeams lists a user's teams
   568  //
   569  // GitHub API docs: https://docs.github.com/rest/teams/teams#list-teams-for-the-authenticated-user
   570  //
   571  //meta:operation GET /user/teams
   572  func (s *TeamsService) ListUserTeams(ctx context.Context, opts *ListOptions) ([]*Team, *Response, error) {
   573  	u := "user/teams"
   574  	u, err := addOptions(u, opts)
   575  	if err != nil {
   576  		return nil, nil, err
   577  	}
   578  
   579  	req, err := s.client.NewRequest("GET", u, nil)
   580  	if err != nil {
   581  		return nil, nil, err
   582  	}
   583  
   584  	var teams []*Team
   585  	resp, err := s.client.Do(ctx, req, &teams)
   586  	if err != nil {
   587  		return nil, resp, err
   588  	}
   589  
   590  	return teams, resp, nil
   591  }
   592  
   593  // ListTeamProjectsByID lists the organization projects for a team given the team ID.
   594  //
   595  // GitHub API docs: https://docs.github.com/rest/teams/teams#list-team-projects
   596  //
   597  //meta:operation GET /orgs/{org}/teams/{team_slug}/projects
   598  func (s *TeamsService) ListTeamProjectsByID(ctx context.Context, orgID, teamID int64) ([]*Project, *Response, error) {
   599  	u := fmt.Sprintf("organizations/%v/team/%v/projects", orgID, teamID)
   600  
   601  	req, err := s.client.NewRequest("GET", u, nil)
   602  	if err != nil {
   603  		return nil, nil, err
   604  	}
   605  
   606  	// TODO: remove custom Accept header when this API fully launches.
   607  	acceptHeaders := []string{mediaTypeProjectsPreview}
   608  	req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
   609  
   610  	var projects []*Project
   611  	resp, err := s.client.Do(ctx, req, &projects)
   612  	if err != nil {
   613  		return nil, resp, err
   614  	}
   615  
   616  	return projects, resp, nil
   617  }
   618  
   619  // ListTeamProjectsBySlug lists the organization projects for a team given the team slug.
   620  //
   621  // GitHub API docs: https://docs.github.com/rest/teams/teams#list-team-projects
   622  //
   623  //meta:operation GET /orgs/{org}/teams/{team_slug}/projects
   624  func (s *TeamsService) ListTeamProjectsBySlug(ctx context.Context, org, slug string) ([]*Project, *Response, error) {
   625  	u := fmt.Sprintf("orgs/%v/teams/%v/projects", org, slug)
   626  
   627  	req, err := s.client.NewRequest("GET", u, nil)
   628  	if err != nil {
   629  		return nil, nil, err
   630  	}
   631  
   632  	// TODO: remove custom Accept header when this API fully launches.
   633  	acceptHeaders := []string{mediaTypeProjectsPreview}
   634  	req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
   635  
   636  	var projects []*Project
   637  	resp, err := s.client.Do(ctx, req, &projects)
   638  	if err != nil {
   639  		return nil, resp, err
   640  	}
   641  
   642  	return projects, resp, nil
   643  }
   644  
   645  // ReviewTeamProjectsByID checks whether a team, given its ID, has read, write, or admin
   646  // permissions for an organization project.
   647  //
   648  // GitHub API docs: https://docs.github.com/rest/teams/teams#check-team-permissions-for-a-project
   649  //
   650  //meta:operation GET /orgs/{org}/teams/{team_slug}/projects/{project_id}
   651  func (s *TeamsService) ReviewTeamProjectsByID(ctx context.Context, orgID, teamID, projectID int64) (*Project, *Response, error) {
   652  	u := fmt.Sprintf("organizations/%v/team/%v/projects/%v", orgID, teamID, projectID)
   653  	req, err := s.client.NewRequest("GET", u, nil)
   654  	if err != nil {
   655  		return nil, nil, err
   656  	}
   657  
   658  	// TODO: remove custom Accept header when this API fully launches.
   659  	acceptHeaders := []string{mediaTypeProjectsPreview}
   660  	req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
   661  
   662  	projects := &Project{}
   663  	resp, err := s.client.Do(ctx, req, &projects)
   664  	if err != nil {
   665  		return nil, resp, err
   666  	}
   667  
   668  	return projects, resp, nil
   669  }
   670  
   671  // ReviewTeamProjectsBySlug checks whether a team, given its slug, has read, write, or admin
   672  // permissions for an organization project.
   673  //
   674  // GitHub API docs: https://docs.github.com/rest/teams/teams#check-team-permissions-for-a-project
   675  //
   676  //meta:operation GET /orgs/{org}/teams/{team_slug}/projects/{project_id}
   677  func (s *TeamsService) ReviewTeamProjectsBySlug(ctx context.Context, org, slug string, projectID int64) (*Project, *Response, error) {
   678  	u := fmt.Sprintf("orgs/%v/teams/%v/projects/%v", org, slug, projectID)
   679  	req, err := s.client.NewRequest("GET", u, nil)
   680  	if err != nil {
   681  		return nil, nil, err
   682  	}
   683  
   684  	// TODO: remove custom Accept header when this API fully launches.
   685  	acceptHeaders := []string{mediaTypeProjectsPreview}
   686  	req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
   687  
   688  	projects := &Project{}
   689  	resp, err := s.client.Do(ctx, req, &projects)
   690  	if err != nil {
   691  		return nil, resp, err
   692  	}
   693  
   694  	return projects, resp, nil
   695  }
   696  
   697  // TeamProjectOptions specifies the optional parameters to the
   698  // TeamsService.AddTeamProject method.
   699  type TeamProjectOptions struct {
   700  	// Permission specifies the permission to grant to the team for this project.
   701  	// Possible values are:
   702  	//     "read" - team members can read, but not write to or administer this project.
   703  	//     "write" - team members can read and write, but not administer this project.
   704  	//     "admin" - team members can read, write and administer this project.
   705  	//
   706  	Permission *string `json:"permission,omitempty"`
   707  }
   708  
   709  // AddTeamProjectByID adds an organization project to a team given the team ID.
   710  // To add a project to a team or update the team's permission on a project, the
   711  // authenticated user must have admin permissions for the project.
   712  //
   713  // GitHub API docs: https://docs.github.com/rest/teams/teams#add-or-update-team-project-permissions
   714  //
   715  //meta:operation PUT /orgs/{org}/teams/{team_slug}/projects/{project_id}
   716  func (s *TeamsService) AddTeamProjectByID(ctx context.Context, orgID, teamID, projectID int64, opts *TeamProjectOptions) (*Response, error) {
   717  	u := fmt.Sprintf("organizations/%v/team/%v/projects/%v", orgID, teamID, projectID)
   718  	req, err := s.client.NewRequest("PUT", u, opts)
   719  	if err != nil {
   720  		return nil, err
   721  	}
   722  
   723  	// TODO: remove custom Accept header when this API fully launches.
   724  	acceptHeaders := []string{mediaTypeProjectsPreview}
   725  	req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
   726  
   727  	return s.client.Do(ctx, req, nil)
   728  }
   729  
   730  // AddTeamProjectBySlug adds an organization project to a team given the team slug.
   731  // To add a project to a team or update the team's permission on a project, the
   732  // authenticated user must have admin permissions for the project.
   733  //
   734  // GitHub API docs: https://docs.github.com/rest/teams/teams#add-or-update-team-project-permissions
   735  //
   736  //meta:operation PUT /orgs/{org}/teams/{team_slug}/projects/{project_id}
   737  func (s *TeamsService) AddTeamProjectBySlug(ctx context.Context, org, slug string, projectID int64, opts *TeamProjectOptions) (*Response, error) {
   738  	u := fmt.Sprintf("orgs/%v/teams/%v/projects/%v", org, slug, projectID)
   739  	req, err := s.client.NewRequest("PUT", u, opts)
   740  	if err != nil {
   741  		return nil, err
   742  	}
   743  
   744  	// TODO: remove custom Accept header when this API fully launches.
   745  	acceptHeaders := []string{mediaTypeProjectsPreview}
   746  	req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
   747  
   748  	return s.client.Do(ctx, req, nil)
   749  }
   750  
   751  // RemoveTeamProjectByID removes an organization project from a team given team ID.
   752  // An organization owner or a team maintainer can remove any project from the team.
   753  // To remove a project from a team as an organization member, the authenticated user
   754  // must have "read" access to both the team and project, or "admin" access to the team
   755  // or project.
   756  // Note: This endpoint removes the project from the team, but does not delete it.
   757  //
   758  // GitHub API docs: https://docs.github.com/rest/teams/teams#remove-a-project-from-a-team
   759  //
   760  //meta:operation DELETE /orgs/{org}/teams/{team_slug}/projects/{project_id}
   761  func (s *TeamsService) RemoveTeamProjectByID(ctx context.Context, orgID, teamID, projectID int64) (*Response, error) {
   762  	u := fmt.Sprintf("organizations/%v/team/%v/projects/%v", orgID, teamID, projectID)
   763  	req, err := s.client.NewRequest("DELETE", u, nil)
   764  	if err != nil {
   765  		return nil, err
   766  	}
   767  
   768  	// TODO: remove custom Accept header when this API fully launches.
   769  	acceptHeaders := []string{mediaTypeProjectsPreview}
   770  	req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
   771  
   772  	return s.client.Do(ctx, req, nil)
   773  }
   774  
   775  // RemoveTeamProjectBySlug removes an organization project from a team given team slug.
   776  // An organization owner or a team maintainer can remove any project from the team.
   777  // To remove a project from a team as an organization member, the authenticated user
   778  // must have "read" access to both the team and project, or "admin" access to the team
   779  // or project.
   780  // Note: This endpoint removes the project from the team, but does not delete it.
   781  //
   782  // GitHub API docs: https://docs.github.com/rest/teams/teams#remove-a-project-from-a-team
   783  //
   784  //meta:operation DELETE /orgs/{org}/teams/{team_slug}/projects/{project_id}
   785  func (s *TeamsService) RemoveTeamProjectBySlug(ctx context.Context, org, slug string, projectID int64) (*Response, error) {
   786  	u := fmt.Sprintf("orgs/%v/teams/%v/projects/%v", org, slug, projectID)
   787  	req, err := s.client.NewRequest("DELETE", u, nil)
   788  	if err != nil {
   789  		return nil, err
   790  	}
   791  
   792  	// TODO: remove custom Accept header when this API fully launches.
   793  	acceptHeaders := []string{mediaTypeProjectsPreview}
   794  	req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
   795  
   796  	return s.client.Do(ctx, req, nil)
   797  }
   798  
   799  // ListIDPGroupsOptions specifies the optional parameters to the ListIDPGroupsInOrganization method.
   800  type ListIDPGroupsOptions struct {
   801  	// Filters the results to return only those that begin with the value specified by this parameter.
   802  	Query string `url:"q,omitempty"`
   803  
   804  	ListCursorOptions
   805  }
   806  
   807  // IDPGroupList represents a list of external identity provider (IDP) groups.
   808  type IDPGroupList struct {
   809  	Groups []*IDPGroup `json:"groups"`
   810  }
   811  
   812  // IDPGroup represents an external identity provider (IDP) group.
   813  type IDPGroup struct {
   814  	GroupID          *string `json:"group_id,omitempty"`
   815  	GroupName        *string `json:"group_name,omitempty"`
   816  	GroupDescription *string `json:"group_description,omitempty"`
   817  }
   818  
   819  // ListIDPGroupsInOrganization lists IDP groups available in an organization.
   820  //
   821  // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/teams/team-sync#list-idp-groups-for-an-organization
   822  //
   823  //meta:operation GET /orgs/{org}/team-sync/groups
   824  func (s *TeamsService) ListIDPGroupsInOrganization(ctx context.Context, org string, opts *ListIDPGroupsOptions) (*IDPGroupList, *Response, error) {
   825  	u := fmt.Sprintf("orgs/%v/team-sync/groups", org)
   826  	u, err := addOptions(u, opts)
   827  	if err != nil {
   828  		return nil, nil, err
   829  	}
   830  
   831  	req, err := s.client.NewRequest("GET", u, nil)
   832  	if err != nil {
   833  		return nil, nil, err
   834  	}
   835  
   836  	groups := new(IDPGroupList)
   837  	resp, err := s.client.Do(ctx, req, groups)
   838  	if err != nil {
   839  		return nil, resp, err
   840  	}
   841  
   842  	return groups, resp, nil
   843  }
   844  
   845  // ListIDPGroupsForTeamByID lists IDP groups connected to a team on GitHub
   846  // given organization and team IDs.
   847  //
   848  // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/teams/team-sync#list-idp-groups-for-a-team
   849  //
   850  //meta:operation GET /orgs/{org}/teams/{team_slug}/team-sync/group-mappings
   851  func (s *TeamsService) ListIDPGroupsForTeamByID(ctx context.Context, orgID, teamID int64) (*IDPGroupList, *Response, error) {
   852  	u := fmt.Sprintf("organizations/%v/team/%v/team-sync/group-mappings", orgID, teamID)
   853  
   854  	req, err := s.client.NewRequest("GET", u, nil)
   855  	if err != nil {
   856  		return nil, nil, err
   857  	}
   858  
   859  	groups := new(IDPGroupList)
   860  	resp, err := s.client.Do(ctx, req, groups)
   861  	if err != nil {
   862  		return nil, resp, err
   863  	}
   864  
   865  	return groups, resp, nil
   866  }
   867  
   868  // ListIDPGroupsForTeamBySlug lists IDP groups connected to a team on GitHub
   869  // given organization name and team slug.
   870  //
   871  // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/teams/team-sync#list-idp-groups-for-a-team
   872  //
   873  //meta:operation GET /orgs/{org}/teams/{team_slug}/team-sync/group-mappings
   874  func (s *TeamsService) ListIDPGroupsForTeamBySlug(ctx context.Context, org, slug string) (*IDPGroupList, *Response, error) {
   875  	u := fmt.Sprintf("orgs/%v/teams/%v/team-sync/group-mappings", org, slug)
   876  
   877  	req, err := s.client.NewRequest("GET", u, nil)
   878  	if err != nil {
   879  		return nil, nil, err
   880  	}
   881  
   882  	groups := new(IDPGroupList)
   883  	resp, err := s.client.Do(ctx, req, groups)
   884  	if err != nil {
   885  		return nil, resp, err
   886  	}
   887  
   888  	return groups, resp, nil
   889  }
   890  
   891  // CreateOrUpdateIDPGroupConnectionsByID creates, updates, or removes a connection
   892  // between a team and an IDP group given organization and team IDs.
   893  //
   894  // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/teams/team-sync#create-or-update-idp-group-connections
   895  //
   896  //meta:operation PATCH /orgs/{org}/teams/{team_slug}/team-sync/group-mappings
   897  func (s *TeamsService) CreateOrUpdateIDPGroupConnectionsByID(ctx context.Context, orgID, teamID int64, opts IDPGroupList) (*IDPGroupList, *Response, error) {
   898  	u := fmt.Sprintf("organizations/%v/team/%v/team-sync/group-mappings", orgID, teamID)
   899  
   900  	req, err := s.client.NewRequest("PATCH", u, opts)
   901  	if err != nil {
   902  		return nil, nil, err
   903  	}
   904  
   905  	groups := new(IDPGroupList)
   906  	resp, err := s.client.Do(ctx, req, groups)
   907  	if err != nil {
   908  		return nil, resp, err
   909  	}
   910  
   911  	return groups, resp, nil
   912  }
   913  
   914  // CreateOrUpdateIDPGroupConnectionsBySlug creates, updates, or removes a connection
   915  // between a team and an IDP group given organization name and team slug.
   916  //
   917  // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/teams/team-sync#create-or-update-idp-group-connections
   918  //
   919  //meta:operation PATCH /orgs/{org}/teams/{team_slug}/team-sync/group-mappings
   920  func (s *TeamsService) CreateOrUpdateIDPGroupConnectionsBySlug(ctx context.Context, org, slug string, opts IDPGroupList) (*IDPGroupList, *Response, error) {
   921  	u := fmt.Sprintf("orgs/%v/teams/%v/team-sync/group-mappings", org, slug)
   922  
   923  	req, err := s.client.NewRequest("PATCH", u, opts)
   924  	if err != nil {
   925  		return nil, nil, err
   926  	}
   927  
   928  	groups := new(IDPGroupList)
   929  	resp, err := s.client.Do(ctx, req, groups)
   930  	if err != nil {
   931  		return nil, resp, err
   932  	}
   933  
   934  	return groups, resp, nil
   935  }
   936  
   937  // ExternalGroupMember represents a member of an external group.
   938  type ExternalGroupMember struct {
   939  	MemberID    *int64  `json:"member_id,omitempty"`
   940  	MemberLogin *string `json:"member_login,omitempty"`
   941  	MemberName  *string `json:"member_name,omitempty"`
   942  	MemberEmail *string `json:"member_email,omitempty"`
   943  }
   944  
   945  // ExternalGroupTeam represents a team connected to an external group.
   946  type ExternalGroupTeam struct {
   947  	TeamID   *int64  `json:"team_id,omitempty"`
   948  	TeamName *string `json:"team_name,omitempty"`
   949  }
   950  
   951  // ExternalGroup represents an external group.
   952  type ExternalGroup struct {
   953  	GroupID   *int64                 `json:"group_id,omitempty"`
   954  	GroupName *string                `json:"group_name,omitempty"`
   955  	UpdatedAt *Timestamp             `json:"updated_at,omitempty"`
   956  	Teams     []*ExternalGroupTeam   `json:"teams,omitempty"`
   957  	Members   []*ExternalGroupMember `json:"members,omitempty"`
   958  }
   959  
   960  // ExternalGroupList represents a list of external groups.
   961  type ExternalGroupList struct {
   962  	Groups []*ExternalGroup `json:"groups"`
   963  }
   964  
   965  // GetExternalGroup fetches an external group.
   966  //
   967  // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/teams/external-groups#get-an-external-group
   968  //
   969  //meta:operation GET /orgs/{org}/external-group/{group_id}
   970  func (s *TeamsService) GetExternalGroup(ctx context.Context, org string, groupID int64) (*ExternalGroup, *Response, error) {
   971  	u := fmt.Sprintf("orgs/%v/external-group/%v", org, groupID)
   972  	req, err := s.client.NewRequest("GET", u, nil)
   973  	if err != nil {
   974  		return nil, nil, err
   975  	}
   976  
   977  	externalGroup := new(ExternalGroup)
   978  	resp, err := s.client.Do(ctx, req, externalGroup)
   979  	if err != nil {
   980  		return nil, resp, err
   981  	}
   982  
   983  	return externalGroup, resp, nil
   984  }
   985  
   986  // ListExternalGroupsOptions specifies the optional parameters to the
   987  // TeamsService.ListExternalGroups method.
   988  type ListExternalGroupsOptions struct {
   989  	DisplayName *string `url:"display_name,omitempty"`
   990  
   991  	ListOptions
   992  }
   993  
   994  // ListExternalGroups lists external groups in an organization on GitHub.
   995  //
   996  // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/teams/external-groups#list-external-groups-in-an-organization
   997  //
   998  //meta:operation GET /orgs/{org}/external-groups
   999  func (s *TeamsService) ListExternalGroups(ctx context.Context, org string, opts *ListExternalGroupsOptions) (*ExternalGroupList, *Response, error) {
  1000  	u := fmt.Sprintf("orgs/%v/external-groups", org)
  1001  	u, err := addOptions(u, opts)
  1002  	if err != nil {
  1003  		return nil, nil, err
  1004  	}
  1005  
  1006  	req, err := s.client.NewRequest("GET", u, nil)
  1007  	if err != nil {
  1008  		return nil, nil, err
  1009  	}
  1010  
  1011  	externalGroups := new(ExternalGroupList)
  1012  	resp, err := s.client.Do(ctx, req, externalGroups)
  1013  	if err != nil {
  1014  		return nil, resp, err
  1015  	}
  1016  
  1017  	return externalGroups, resp, nil
  1018  }
  1019  
  1020  // ListExternalGroupsForTeamBySlug lists external groups connected to a team on GitHub.
  1021  //
  1022  // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/teams/external-groups#list-a-connection-between-an-external-group-and-a-team
  1023  //
  1024  //meta:operation GET /orgs/{org}/teams/{team_slug}/external-groups
  1025  func (s *TeamsService) ListExternalGroupsForTeamBySlug(ctx context.Context, org, slug string) (*ExternalGroupList, *Response, error) {
  1026  	u := fmt.Sprintf("orgs/%v/teams/%v/external-groups", org, slug)
  1027  
  1028  	req, err := s.client.NewRequest("GET", u, nil)
  1029  	if err != nil {
  1030  		return nil, nil, err
  1031  	}
  1032  
  1033  	externalGroups := new(ExternalGroupList)
  1034  	resp, err := s.client.Do(ctx, req, externalGroups)
  1035  	if err != nil {
  1036  		return nil, resp, err
  1037  	}
  1038  
  1039  	return externalGroups, resp, nil
  1040  }
  1041  
  1042  // UpdateConnectedExternalGroup updates the connection between an external group and a team.
  1043  //
  1044  // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/teams/external-groups#update-the-connection-between-an-external-group-and-a-team
  1045  //
  1046  //meta:operation PATCH /orgs/{org}/teams/{team_slug}/external-groups
  1047  func (s *TeamsService) UpdateConnectedExternalGroup(ctx context.Context, org, slug string, eg *ExternalGroup) (*ExternalGroup, *Response, error) {
  1048  	u := fmt.Sprintf("orgs/%v/teams/%v/external-groups", org, slug)
  1049  
  1050  	req, err := s.client.NewRequest("PATCH", u, eg)
  1051  	if err != nil {
  1052  		return nil, nil, err
  1053  	}
  1054  
  1055  	externalGroup := new(ExternalGroup)
  1056  	resp, err := s.client.Do(ctx, req, externalGroup)
  1057  	if err != nil {
  1058  		return nil, resp, err
  1059  	}
  1060  
  1061  	return externalGroup, resp, nil
  1062  }
  1063  
  1064  // RemoveConnectedExternalGroup removes the connection between an external group and a team.
  1065  //
  1066  // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/teams/external-groups#remove-the-connection-between-an-external-group-and-a-team
  1067  //
  1068  //meta:operation DELETE /orgs/{org}/teams/{team_slug}/external-groups
  1069  func (s *TeamsService) RemoveConnectedExternalGroup(ctx context.Context, org, slug string) (*Response, error) {
  1070  	u := fmt.Sprintf("orgs/%v/teams/%v/external-groups", org, slug)
  1071  
  1072  	req, err := s.client.NewRequest("DELETE", u, nil)
  1073  	if err != nil {
  1074  		return nil, err
  1075  	}
  1076  
  1077  	return s.client.Do(ctx, req, nil)
  1078  }