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 6package github 7 8import ( 9 "context" 10 "fmt" 11 "strings" 12 "time" 13) 14 15// TeamsService provides access to the team-related functions 16// in the GitHub API. 17// 18// GitHub API docs: https://developer.github.com/v3/teams/ 19type TeamsService service 20 21// Team represents a team within a GitHub organization. Teams are used to 22// manage access to an organization's repositories. 23type Team struct { 24 ID *int64 `json:"id,omitempty"` 25 Name *string `json:"name,omitempty"` 26 Description *string `json:"description,omitempty"` 27 URL *string `json:"url,omitempty"` 28 Slug *string `json:"slug,omitempty"` 29 30 // Permission specifies the default permission for repositories owned by the team. 31 Permission *string `json:"permission,omitempty"` 32 33 // Privacy identifies the level of privacy this team should have. 34 // Possible values are: 35 // secret - only visible to organization owners and members of this team 36 // closed - visible to all members of this organization 37 // Default is "secret". 38 Privacy *string `json:"privacy,omitempty"` 39 40 MembersCount *int `json:"members_count,omitempty"` 41 ReposCount *int `json:"repos_count,omitempty"` 42 Organization *Organization `json:"organization,omitempty"` 43 MembersURL *string `json:"members_url,omitempty"` 44 RepositoriesURL *string `json:"repositories_url,omitempty"` 45 Parent *Team `json:"parent,omitempty"` 46 47 // LDAPDN is only available in GitHub Enterprise and when the team 48 // membership is synchronized with LDAP. 49 LDAPDN *string `json:"ldap_dn,omitempty"` 50} 51 52func (t Team) String() string { 53 return Stringify(t) 54} 55 56// Invitation represents a team member's invitation status. 57type Invitation struct { 58 ID *int64 `json:"id,omitempty"` 59 Login *string `json:"login,omitempty"` 60 Email *string `json:"email,omitempty"` 61 // Role can be one of the values - 'direct_member', 'admin', 'billing_manager', 'hiring_manager', or 'reinstate'. 62 Role *string `json:"role,omitempty"` 63 CreatedAt *time.Time `json:"created_at,omitempty"` 64 Inviter *User `json:"inviter,omitempty"` 65 TeamCount *int `json:"team_count,omitempty"` 66 InvitationTeamURL *string `json:"invitation_team_url,omitempty"` 67} 68 69func (i Invitation) String() string { 70 return Stringify(i) 71} 72 73// ListTeams lists all of the teams for an organization. 74// 75// GitHub API docs: https://developer.github.com/v3/teams/#list-teams 76func (s *TeamsService) ListTeams(ctx context.Context, org string, opt *ListOptions) ([]*Team, *Response, error) { 77 u := fmt.Sprintf("orgs/%v/teams", org) 78 u, err := addOptions(u, opt) 79 if err != nil { 80 return nil, nil, err 81 } 82 83 req, err := s.client.NewRequest("GET", u, nil) 84 if err != nil { 85 return nil, nil, err 86 } 87 88 // TODO: remove custom Accept header when this API fully launches. 89 req.Header.Set("Accept", mediaTypeNestedTeamsPreview) 90 91 var teams []*Team 92 resp, err := s.client.Do(ctx, req, &teams) 93 if err != nil { 94 return nil, resp, err 95 } 96 97 return teams, resp, nil 98} 99 100// GetTeam fetches a team by ID. 101// 102// GitHub API docs: https://developer.github.com/v3/teams/#get-team 103func (s *TeamsService) GetTeam(ctx context.Context, team int64) (*Team, *Response, error) { 104 u := fmt.Sprintf("teams/%v", team) 105 req, err := s.client.NewRequest("GET", u, nil) 106 if err != nil { 107 return nil, nil, err 108 } 109 110 // TODO: remove custom Accept header when this API fully launches. 111 req.Header.Set("Accept", mediaTypeNestedTeamsPreview) 112 113 t := new(Team) 114 resp, err := s.client.Do(ctx, req, t) 115 if err != nil { 116 return nil, resp, err 117 } 118 119 return t, resp, nil 120} 121 122// NewTeam represents a team to be created or modified. 123type NewTeam struct { 124 Name string `json:"name"` // Name of the team. (Required.) 125 Description *string `json:"description,omitempty"` 126 Maintainers []string `json:"maintainers,omitempty"` 127 RepoNames []string `json:"repo_names,omitempty"` 128 ParentTeamID *int64 `json:"parent_team_id,omitempty"` 129 130 // Deprecated: Permission is deprecated when creating or editing a team in an org 131 // using the new GitHub permission model. It no longer identifies the 132 // permission a team has on its repos, but only specifies the default 133 // permission a repo is initially added with. Avoid confusion by 134 // specifying a permission value when calling AddTeamRepo. 135 Permission *string `json:"permission,omitempty"` 136 137 // Privacy identifies the level of privacy this team should have. 138 // Possible values are: 139 // secret - only visible to organization owners and members of this team 140 // closed - visible to all members of this organization 141 // Default is "secret". 142 Privacy *string `json:"privacy,omitempty"` 143 144 // LDAPDN may be used in GitHub Enterprise when the team membership 145 // is synchronized with LDAP. 146 LDAPDN *string `json:"ldap_dn,omitempty"` 147} 148 149func (s NewTeam) String() string { 150 return Stringify(s) 151} 152 153// CreateTeam creates a new team within an organization. 154// 155// GitHub API docs: https://developer.github.com/v3/teams/#create-team 156func (s *TeamsService) CreateTeam(ctx context.Context, org string, team NewTeam) (*Team, *Response, error) { 157 u := fmt.Sprintf("orgs/%v/teams", org) 158 req, err := s.client.NewRequest("POST", u, team) 159 if err != nil { 160 return nil, nil, err 161 } 162 163 // TODO: remove custom Accept header when this API fully launches. 164 req.Header.Set("Accept", mediaTypeNestedTeamsPreview) 165 166 t := new(Team) 167 resp, err := s.client.Do(ctx, req, t) 168 if err != nil { 169 return nil, resp, err 170 } 171 172 return t, resp, nil 173} 174 175// EditTeam edits a team. 176// 177// GitHub API docs: https://developer.github.com/v3/teams/#edit-team 178func (s *TeamsService) EditTeam(ctx context.Context, id int64, team NewTeam) (*Team, *Response, error) { 179 u := fmt.Sprintf("teams/%v", id) 180 req, err := s.client.NewRequest("PATCH", u, team) 181 if err != nil { 182 return nil, nil, err 183 } 184 185 // TODO: remove custom Accept header when this API fully launches. 186 req.Header.Set("Accept", mediaTypeNestedTeamsPreview) 187 188 t := new(Team) 189 resp, err := s.client.Do(ctx, req, t) 190 if err != nil { 191 return nil, resp, err 192 } 193 194 return t, resp, nil 195} 196 197// DeleteTeam deletes a team. 198// 199// GitHub API docs: https://developer.github.com/v3/teams/#delete-team 200func (s *TeamsService) DeleteTeam(ctx context.Context, team int64) (*Response, error) { 201 u := fmt.Sprintf("teams/%v", team) 202 req, err := s.client.NewRequest("DELETE", u, nil) 203 if err != nil { 204 return nil, err 205 } 206 207 req.Header.Set("Accept", mediaTypeNestedTeamsPreview) 208 209 return s.client.Do(ctx, req, nil) 210} 211 212// ListChildTeams lists child teams for a team. 213// 214// GitHub API docs: https://developer.github.com/v3/teams/#list-child-teams 215func (s *TeamsService) ListChildTeams(ctx context.Context, teamID int64, opt *ListOptions) ([]*Team, *Response, error) { 216 u := fmt.Sprintf("teams/%v/teams", teamID) 217 u, err := addOptions(u, opt) 218 if err != nil { 219 return nil, nil, err 220 } 221 222 req, err := s.client.NewRequest("GET", u, nil) 223 if err != nil { 224 return nil, nil, err 225 } 226 227 req.Header.Set("Accept", mediaTypeNestedTeamsPreview) 228 229 var teams []*Team 230 resp, err := s.client.Do(ctx, req, &teams) 231 if err != nil { 232 return nil, resp, err 233 } 234 235 return teams, resp, nil 236} 237 238// ListTeamRepos lists the repositories that the specified team has access to. 239// 240// GitHub API docs: https://developer.github.com/v3/teams/#list-team-repos 241func (s *TeamsService) ListTeamRepos(ctx context.Context, team int64, opt *ListOptions) ([]*Repository, *Response, error) { 242 u := fmt.Sprintf("teams/%v/repos", team) 243 u, err := addOptions(u, opt) 244 if err != nil { 245 return nil, nil, err 246 } 247 248 req, err := s.client.NewRequest("GET", u, nil) 249 if err != nil { 250 return nil, nil, err 251 } 252 253 // TODO: remove custom Accept header when topics API fully launches. 254 headers := []string{mediaTypeTopicsPreview, mediaTypeNestedTeamsPreview} 255 req.Header.Set("Accept", strings.Join(headers, ", ")) 256 257 var repos []*Repository 258 resp, err := s.client.Do(ctx, req, &repos) 259 if err != nil { 260 return nil, resp, err 261 } 262 263 return repos, resp, nil 264} 265 266// IsTeamRepo checks if a team manages the specified repository. If the 267// repository is managed by team, a Repository is returned which includes the 268// permissions team has for that repo. 269// 270// GitHub API docs: https://developer.github.com/v3/teams/#check-if-a-team-manages-a-repository 271func (s *TeamsService) IsTeamRepo(ctx context.Context, team int64, owner string, repo string) (*Repository, *Response, error) { 272 u := fmt.Sprintf("teams/%v/repos/%v/%v", team, owner, repo) 273 req, err := s.client.NewRequest("GET", u, nil) 274 if err != nil { 275 return nil, nil, err 276 } 277 278 headers := []string{mediaTypeOrgPermissionRepo, mediaTypeNestedTeamsPreview} 279 req.Header.Set("Accept", strings.Join(headers, ", ")) 280 281 repository := new(Repository) 282 resp, err := s.client.Do(ctx, req, repository) 283 if err != nil { 284 return nil, resp, err 285 } 286 287 return repository, resp, nil 288} 289 290// TeamAddTeamRepoOptions specifies the optional parameters to the 291// TeamsService.AddTeamRepo method. 292type TeamAddTeamRepoOptions struct { 293 // Permission specifies the permission to grant the team on this repository. 294 // Possible values are: 295 // pull - team members can pull, but not push to or administer this repository 296 // push - team members can pull and push, but not administer this repository 297 // admin - team members can pull, push and administer this repository 298 // 299 // If not specified, the team's permission attribute will be used. 300 Permission string `json:"permission,omitempty"` 301} 302 303// AddTeamRepo adds a repository to be managed by the specified team. The 304// specified repository must be owned by the organization to which the team 305// belongs, or a direct fork of a repository owned by the organization. 306// 307// GitHub API docs: https://developer.github.com/v3/teams/#add-team-repo 308func (s *TeamsService) AddTeamRepo(ctx context.Context, team int64, owner string, repo string, opt *TeamAddTeamRepoOptions) (*Response, error) { 309 u := fmt.Sprintf("teams/%v/repos/%v/%v", team, owner, repo) 310 req, err := s.client.NewRequest("PUT", u, opt) 311 if err != nil { 312 return nil, err 313 } 314 315 return s.client.Do(ctx, req, nil) 316} 317 318// RemoveTeamRepo removes a repository from being managed by the specified 319// team. Note that this does not delete the repository, it just removes it 320// from the team. 321// 322// GitHub API docs: https://developer.github.com/v3/teams/#remove-team-repo 323func (s *TeamsService) RemoveTeamRepo(ctx context.Context, team int64, owner string, repo string) (*Response, error) { 324 u := fmt.Sprintf("teams/%v/repos/%v/%v", team, owner, repo) 325 req, err := s.client.NewRequest("DELETE", u, nil) 326 if err != nil { 327 return nil, err 328 } 329 330 return s.client.Do(ctx, req, nil) 331} 332 333// ListUserTeams lists a user's teams 334// GitHub API docs: https://developer.github.com/v3/teams/#list-user-teams 335func (s *TeamsService) ListUserTeams(ctx context.Context, opt *ListOptions) ([]*Team, *Response, error) { 336 u := "user/teams" 337 u, err := addOptions(u, opt) 338 if err != nil { 339 return nil, nil, err 340 } 341 342 req, err := s.client.NewRequest("GET", u, nil) 343 if err != nil { 344 return nil, nil, err 345 } 346 347 // TODO: remove custom Accept header when this API fully launches. 348 req.Header.Set("Accept", mediaTypeNestedTeamsPreview) 349 350 var teams []*Team 351 resp, err := s.client.Do(ctx, req, &teams) 352 if err != nil { 353 return nil, resp, err 354 } 355 356 return teams, resp, nil 357} 358