orgs_teams.go 17 KB

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