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