orgs_teams.go 17 KB

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