From 6d81562f2673cbbcba713e447900d6970415fbc8 Mon Sep 17 00:00:00 2001 From: Alex Orr Date: Mon, 20 Jan 2020 16:39:03 -0800 Subject: [PATCH 01/10] fix: update general teams endpoints --- github/teams.go | 52 ++++++++++++++--------------- github/teams_test.go | 78 ++++++++++++++++++++++---------------------- 2 files changed, 65 insertions(+), 65 deletions(-) diff --git a/github/teams.go b/github/teams.go index 03284874466..ab55cc15fe7 100644 --- a/github/teams.go +++ b/github/teams.go @@ -215,8 +215,8 @@ func copyNewTeamWithoutParent(team *NewTeam) *newTeamNoParent { // EditTeam edits a team. // // GitHub API docs: https://developer.github.com/v3/teams/#edit-team -func (s *TeamsService) EditTeam(ctx context.Context, id int64, team NewTeam, removeParent bool) (*Team, *Response, error) { - u := fmt.Sprintf("teams/%v", id) +func (s *TeamsService) EditTeam(ctx context.Context, org, slug string, team NewTeam, removeParent bool) (*Team, *Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v", org, slug) var req *http.Request var err error @@ -242,8 +242,8 @@ func (s *TeamsService) EditTeam(ctx context.Context, id int64, team NewTeam, rem // DeleteTeam deletes a team. // // GitHub API docs: https://developer.github.com/v3/teams/#delete-team -func (s *TeamsService) DeleteTeam(ctx context.Context, team int64) (*Response, error) { - u := fmt.Sprintf("teams/%v", team) +func (s *TeamsService) DeleteTeam(ctx context.Context, org, slug string) (*Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v", org, slug) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err @@ -255,8 +255,8 @@ func (s *TeamsService) DeleteTeam(ctx context.Context, team int64) (*Response, e // ListChildTeams lists child teams for a team. // // GitHub API docs: https://developer.github.com/v3/teams/#list-child-teams -func (s *TeamsService) ListChildTeams(ctx context.Context, teamID int64, opt *ListOptions) ([]*Team, *Response, error) { - u := fmt.Sprintf("teams/%v/teams", teamID) +func (s *TeamsService) ListChildTeams(ctx context.Context, org, slug string, opt *ListOptions) ([]*Team, *Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/teams", org, slug) u, err := addOptions(u, opt) if err != nil { return nil, nil, err @@ -279,8 +279,8 @@ func (s *TeamsService) ListChildTeams(ctx context.Context, teamID int64, opt *Li // ListTeamRepos lists the repositories that the specified team has access to. // // GitHub API docs: https://developer.github.com/v3/teams/#list-team-repos -func (s *TeamsService) ListTeamRepos(ctx context.Context, team int64, opt *ListOptions) ([]*Repository, *Response, error) { - u := fmt.Sprintf("teams/%v/repos", team) +func (s *TeamsService) ListTeamRepos(ctx context.Context, org, slug string, opt *ListOptions) ([]*Repository, *Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/repos", org, slug) u, err := addOptions(u, opt) if err != nil { return nil, nil, err @@ -309,8 +309,8 @@ func (s *TeamsService) ListTeamRepos(ctx context.Context, team int64, opt *ListO // permissions team has for that repo. // // GitHub API docs: https://developer.github.com/v3/teams/#check-if-a-team-manages-a-repository -func (s *TeamsService) IsTeamRepo(ctx context.Context, team int64, owner string, repo string) (*Repository, *Response, error) { - u := fmt.Sprintf("teams/%v/repos/%v/%v", team, owner, repo) +func (s *TeamsService) IsTeamRepo(ctx context.Context, org, slug, owner, repo string) (*Repository, *Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/repos/%v/%v", org, slug, owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err @@ -346,8 +346,8 @@ type TeamAddTeamRepoOptions struct { // belongs, or a direct fork of a repository owned by the organization. // // GitHub API docs: https://developer.github.com/v3/teams/#add-team-repo -func (s *TeamsService) AddTeamRepo(ctx context.Context, team int64, owner string, repo string, opt *TeamAddTeamRepoOptions) (*Response, error) { - u := fmt.Sprintf("teams/%v/repos/%v/%v", team, owner, repo) +func (s *TeamsService) AddTeamRepo(ctx context.Context, org, slug, owner, repo string, opt *TeamAddTeamRepoOptions) (*Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/repos/%v/%v", org, slug, owner, repo) req, err := s.client.NewRequest("PUT", u, opt) if err != nil { return nil, err @@ -361,8 +361,8 @@ func (s *TeamsService) AddTeamRepo(ctx context.Context, team int64, owner string // from the team. // // GitHub API docs: https://developer.github.com/v3/teams/#remove-team-repo -func (s *TeamsService) RemoveTeamRepo(ctx context.Context, team int64, owner string, repo string) (*Response, error) { - u := fmt.Sprintf("teams/%v/repos/%v/%v", team, owner, repo) +func (s *TeamsService) RemoveTeamRepo(ctx context.Context, org, slug, owner, repo string) (*Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/repos/%v/%v", org, slug, owner, repo) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err @@ -397,8 +397,8 @@ func (s *TeamsService) ListUserTeams(ctx context.Context, opt *ListOptions) ([]* // ListTeamProjects lists the organization projects for a team. // // GitHub API docs: https://developer.github.com/v3/teams/#list-team-projects -func (s *TeamsService) ListTeamProjects(ctx context.Context, teamID int64) ([]*Project, *Response, error) { - u := fmt.Sprintf("teams/%v/projects", teamID) +func (s *TeamsService) ListTeamProjects(ctx context.Context, org, slug string) ([]*Project, *Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/projects", org, slug) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -422,8 +422,8 @@ func (s *TeamsService) ListTeamProjects(ctx context.Context, teamID int64) ([]*P // permissions for an organization project. // // GitHub API docs: https://developer.github.com/v3/teams/#review-a-team-project -func (s *TeamsService) ReviewTeamProjects(ctx context.Context, teamID, projectID int64) (*Project, *Response, error) { - u := fmt.Sprintf("teams/%v/projects/%v", teamID, projectID) +func (s *TeamsService) ReviewTeamProjects(ctx context.Context, org, slug string, projectID int64) (*Project, *Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/projects/%v", org, slug, projectID) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err @@ -459,8 +459,8 @@ type TeamProjectOptions struct { // permissions for the project. // // GitHub API docs: https://developer.github.com/v3/teams/#add-or-update-team-project -func (s *TeamsService) AddTeamProject(ctx context.Context, teamID, projectID int64, opt *TeamProjectOptions) (*Response, error) { - u := fmt.Sprintf("teams/%v/projects/%v", teamID, projectID) +func (s *TeamsService) AddTeamProject(ctx context.Context, org, slug string, projectID int64, opt *TeamProjectOptions) (*Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/projects/%v", org, slug, projectID) req, err := s.client.NewRequest("PUT", u, opt) if err != nil { return nil, err @@ -480,8 +480,8 @@ func (s *TeamsService) AddTeamProject(ctx context.Context, teamID, projectID int // Note: This endpoint removes the project from the team, but does not delete it. // // GitHub API docs: https://developer.github.com/v3/teams/#remove-team-project -func (s *TeamsService) RemoveTeamProject(ctx context.Context, teamID int64, projectID int64) (*Response, error) { - u := fmt.Sprintf("teams/%v/projects/%v", teamID, projectID) +func (s *TeamsService) RemoveTeamProject(ctx context.Context, org, slug string, projectID int64) (*Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/projects/%v", org, slug, projectID) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err @@ -532,8 +532,8 @@ func (s *TeamsService) ListIDPGroupsInOrganization(ctx context.Context, org stri // ListIDPGroupsForTeam lists IDP groups connected to a team on GitHub. // // GitHub API docs: https://developer.github.com/v3/teams/team_sync/#list-idp-groups-for-a-team -func (s *TeamsService) ListIDPGroupsForTeam(ctx context.Context, teamID string) (*IDPGroupList, *Response, error) { - u := fmt.Sprintf("teams/%v/team-sync/group-mappings", teamID) +func (s *TeamsService) ListIDPGroupsForTeam(ctx context.Context, org, slug string) (*IDPGroupList, *Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/team-sync/group-mappings", org, slug) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -552,8 +552,8 @@ func (s *TeamsService) ListIDPGroupsForTeam(ctx context.Context, teamID string) // and an IDP group. // // GitHub API docs: https://developer.github.com/v3/teams/team_sync/#create-or-update-idp-group-connections -func (s *TeamsService) CreateOrUpdateIDPGroupConnections(ctx context.Context, teamID string, opt IDPGroupList) (*IDPGroupList, *Response, error) { - u := fmt.Sprintf("teams/%v/team-sync/group-mappings", teamID) +func (s *TeamsService) CreateOrUpdateIDPGroupConnections(ctx context.Context, org, slug string, opt IDPGroupList) (*IDPGroupList, *Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/team-sync/group-mappings", org, slug) req, err := s.client.NewRequest("PATCH", u, opt) if err != nil { diff --git a/github/teams_test.go b/github/teams_test.go index ce7ece54b06..4c60af7f6a4 100644 --- a/github/teams_test.go +++ b/github/teams_test.go @@ -183,7 +183,7 @@ func TestTeamsService_EditTeam(t *testing.T) { input := NewTeam{Name: "n", Privacy: String("closed")} - mux.HandleFunc("/teams/1", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/o/teams/s", func(w http.ResponseWriter, r *http.Request) { v := new(NewTeam) json.NewDecoder(r.Body).Decode(v) @@ -195,7 +195,7 @@ func TestTeamsService_EditTeam(t *testing.T) { fmt.Fprint(w, `{"id":1}`) }) - team, _, err := client.Teams.EditTeam(context.Background(), 1, input, false) + team, _, err := client.Teams.EditTeam(context.Background(), "o", "s", input, false) if err != nil { t.Errorf("Teams.EditTeam returned error: %v", err) } @@ -213,7 +213,7 @@ func TestTeamsService_EditTeam_RemoveParent(t *testing.T) { input := NewTeam{Name: "n", Privacy: String("closed")} var body string - mux.HandleFunc("/teams/1", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/o/teams/s", func(w http.ResponseWriter, r *http.Request) { v := new(NewTeam) buf, err := ioutil.ReadAll(r.Body) if err != nil { @@ -230,7 +230,7 @@ func TestTeamsService_EditTeam_RemoveParent(t *testing.T) { fmt.Fprint(w, `{"id":1}`) }) - team, _, err := client.Teams.EditTeam(context.Background(), 1, input, true) + team, _, err := client.Teams.EditTeam(context.Background(), "o", "s", input, true) if err != nil { t.Errorf("Teams.EditTeam returned error: %v", err) } @@ -249,11 +249,11 @@ func TestTeamsService_DeleteTeam(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/teams/1", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/o/teams/s", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") }) - _, err := client.Teams.DeleteTeam(context.Background(), 1) + _, err := client.Teams.DeleteTeam(context.Background(), "o", "s") if err != nil { t.Errorf("Teams.DeleteTeam returned error: %v", err) } @@ -263,14 +263,14 @@ func TestTeamsService_ListChildTeams(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/teams/1/teams", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/o/teams/s/teams", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") testFormValues(t, r, values{"page": "2"}) fmt.Fprint(w, `[{"id":2}]`) }) opt := &ListOptions{Page: 2} - teams, _, err := client.Teams.ListChildTeams(context.Background(), 1, opt) + teams, _, err := client.Teams.ListChildTeams(context.Background(), "o", "s", opt) if err != nil { t.Errorf("Teams.ListTeams returned error: %v", err) } @@ -285,7 +285,7 @@ func TestTeamsService_ListTeamRepos(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/teams/1/repos", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/o/teams/s/repos", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") wantAcceptHeaders := []string{mediaTypeTopicsPreview} testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", ")) @@ -294,7 +294,7 @@ func TestTeamsService_ListTeamRepos(t *testing.T) { }) opt := &ListOptions{Page: 2} - members, _, err := client.Teams.ListTeamRepos(context.Background(), 1, opt) + members, _, err := client.Teams.ListTeamRepos(context.Background(), "o", "s", opt) if err != nil { t.Errorf("Teams.ListTeamRepos returned error: %v", err) } @@ -309,14 +309,14 @@ func TestTeamsService_IsTeamRepo_true(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/teams/1/repos/o/r", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/org/teams/slug/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") wantAcceptHeaders := []string{mediaTypeOrgPermissionRepo} testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", ")) fmt.Fprint(w, `{"id":1}`) }) - repo, _, err := client.Teams.IsTeamRepo(context.Background(), 1, "o", "r") + repo, _, err := client.Teams.IsTeamRepo(context.Background(), "org", "slug", "owner", "repo") if err != nil { t.Errorf("Teams.IsTeamRepo returned error: %v", err) } @@ -331,12 +331,12 @@ func TestTeamsService_IsTeamRepo_false(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/teams/1/repos/o/r", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/org/teams/slug/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") w.WriteHeader(http.StatusNotFound) }) - repo, resp, err := client.Teams.IsTeamRepo(context.Background(), 1, "o", "r") + repo, resp, err := client.Teams.IsTeamRepo(context.Background(), "org", "slug", "owner", "repo") if err == nil { t.Errorf("Expected HTTP 404 response") } @@ -352,12 +352,12 @@ func TestTeamsService_IsTeamRepo_error(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/teams/1/repos/o/r", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/org/teams/slug/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") http.Error(w, "BadRequest", http.StatusBadRequest) }) - repo, resp, err := client.Teams.IsTeamRepo(context.Background(), 1, "o", "r") + repo, resp, err := client.Teams.IsTeamRepo(context.Background(), "org", "slug", "owner", "repo") if err == nil { t.Errorf("Expected HTTP 400 response") } @@ -373,7 +373,7 @@ func TestTeamsService_IsTeamRepo_invalidOwner(t *testing.T) { client, _, _, teardown := setup() defer teardown() - _, _, err := client.Teams.IsTeamRepo(context.Background(), 1, "%", "r") + _, _, err := client.Teams.IsTeamRepo(context.Background(), "o", "s", "%", "r") testURLParseError(t, err) } @@ -383,7 +383,7 @@ func TestTeamsService_AddTeamRepo(t *testing.T) { opt := &TeamAddTeamRepoOptions{Permission: "admin"} - mux.HandleFunc("/teams/1/repos/o/r", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/org/teams/slug/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { v := new(TeamAddTeamRepoOptions) json.NewDecoder(r.Body).Decode(v) @@ -395,7 +395,7 @@ func TestTeamsService_AddTeamRepo(t *testing.T) { w.WriteHeader(http.StatusNoContent) }) - _, err := client.Teams.AddTeamRepo(context.Background(), 1, "o", "r", opt) + _, err := client.Teams.AddTeamRepo(context.Background(), "org", "slug", "owner", "repo", opt) if err != nil { t.Errorf("Teams.AddTeamRepo returned error: %v", err) } @@ -405,12 +405,12 @@ func TestTeamsService_AddTeamRepo_noAccess(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/teams/1/repos/o/r", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/org/teams/slug/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") w.WriteHeader(http.StatusUnprocessableEntity) }) - _, err := client.Teams.AddTeamRepo(context.Background(), 1, "o", "r", nil) + _, err := client.Teams.AddTeamRepo(context.Background(), "org", "slug", "owner", "repo", nil) if err == nil { t.Errorf("Expcted error to be returned") } @@ -420,7 +420,7 @@ func TestTeamsService_AddTeamRepo_invalidOwner(t *testing.T) { client, _, _, teardown := setup() defer teardown() - _, err := client.Teams.AddTeamRepo(context.Background(), 1, "%", "r", nil) + _, err := client.Teams.AddTeamRepo(context.Background(), "o", "s", "%", "r", nil) testURLParseError(t, err) } @@ -428,12 +428,12 @@ func TestTeamsService_RemoveTeamRepo(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/teams/1/repos/o/r", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/org/teams/slug/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") w.WriteHeader(http.StatusNoContent) }) - _, err := client.Teams.RemoveTeamRepo(context.Background(), 1, "o", "r") + _, err := client.Teams.RemoveTeamRepo(context.Background(), "org", "slug", "owner", "repo") if err != nil { t.Errorf("Teams.RemoveTeamRepo returned error: %v", err) } @@ -443,7 +443,7 @@ func TestTeamsService_RemoveTeamRepo_invalidOwner(t *testing.T) { client, _, _, teardown := setup() defer teardown() - _, err := client.Teams.RemoveTeamRepo(context.Background(), 1, "%", "r") + _, err := client.Teams.RemoveTeamRepo(context.Background(), "o", "s", "%", "r") testURLParseError(t, err) } @@ -551,13 +551,13 @@ func TestTeamsService_ListProjects(t *testing.T) { defer teardown() wantAcceptHeaders := []string{mediaTypeProjectsPreview} - mux.HandleFunc("/teams/1/projects", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/o/teams/s/projects", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", ")) fmt.Fprint(w, `[{"id":1}]`) }) - projects, _, err := client.Teams.ListTeamProjects(context.Background(), 1) + projects, _, err := client.Teams.ListTeamProjects(context.Background(), "o", "s") if err != nil { t.Errorf("Teams.ListTeamProjects returned error: %v", err) } @@ -573,13 +573,13 @@ func TestTeamsService_ReviewProjects(t *testing.T) { defer teardown() wantAcceptHeaders := []string{mediaTypeProjectsPreview} - mux.HandleFunc("/teams/1/projects/1", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/o/teams/s/projects/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", ")) fmt.Fprint(w, `{"id":1}`) }) - project, _, err := client.Teams.ReviewTeamProjects(context.Background(), 1, 1) + project, _, err := client.Teams.ReviewTeamProjects(context.Background(), "o", "s", 1) if err != nil { t.Errorf("Teams.ReviewTeamProjects returned error: %v", err) } @@ -599,7 +599,7 @@ func TestTeamsService_AddTeamProject(t *testing.T) { } wantAcceptHeaders := []string{mediaTypeProjectsPreview} - mux.HandleFunc("/teams/1/projects/1", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/o/teams/s/projects/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", ")) @@ -612,7 +612,7 @@ func TestTeamsService_AddTeamProject(t *testing.T) { w.WriteHeader(http.StatusNoContent) }) - _, err := client.Teams.AddTeamProject(context.Background(), 1, 1, opt) + _, err := client.Teams.AddTeamProject(context.Background(), "o", "s", 1, opt) if err != nil { t.Errorf("Teams.AddTeamProject returned error: %v", err) } @@ -623,13 +623,13 @@ func TestTeamsService_RemoveTeamProject(t *testing.T) { defer teardown() wantAcceptHeaders := []string{mediaTypeProjectsPreview} - mux.HandleFunc("/teams/1/projects/1", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/o/teams/s/projects/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", ")) w.WriteHeader(http.StatusNoContent) }) - _, err := client.Teams.RemoveTeamProject(context.Background(), 1, 1) + _, err := client.Teams.RemoveTeamProject(context.Background(), "o", "s", 1) if err != nil { t.Errorf("Teams.RemoveTeamProject returned error: %v", err) } @@ -671,12 +671,12 @@ func TestTeamsService_ListIDPGroupsForTeam(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/teams/1/team-sync/group-mappings", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/o/teams/s/team-sync/group-mappings", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"groups": [{"group_id": "1", "group_name": "n", "group_description": "d"}]}`) }) - groups, _, err := client.Teams.ListIDPGroupsForTeam(context.Background(), "1") + groups, _, err := client.Teams.ListIDPGroupsForTeam(context.Background(), "o", "s") if err != nil { t.Errorf("Teams.ListIDPGroupsForTeam returned error: %v", err) } @@ -699,7 +699,7 @@ func TestTeamsService_CreateOrUpdateIDPGroupConnections(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/teams/1/team-sync/group-mappings", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/o/teams/s/team-sync/group-mappings", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PATCH") fmt.Fprint(w, `{"groups": [{"group_id": "1", "group_name": "n", "group_description": "d"}]}`) }) @@ -714,7 +714,7 @@ func TestTeamsService_CreateOrUpdateIDPGroupConnections(t *testing.T) { }, } - groups, _, err := client.Teams.CreateOrUpdateIDPGroupConnections(context.Background(), "1", input) + groups, _, err := client.Teams.CreateOrUpdateIDPGroupConnections(context.Background(), "o", "s", input) if err != nil { t.Errorf("Teams.CreateOrUpdateIDPGroupConnections returned error: %v", err) } @@ -737,7 +737,7 @@ func TestTeamsService_CreateOrUpdateIDPGroupConnections_empty(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/teams/1/team-sync/group-mappings", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/o/teams/s/team-sync/group-mappings", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PATCH") fmt.Fprint(w, `{"groups": []}`) }) @@ -746,7 +746,7 @@ func TestTeamsService_CreateOrUpdateIDPGroupConnections_empty(t *testing.T) { Groups: []*IDPGroup{}, } - groups, _, err := client.Teams.CreateOrUpdateIDPGroupConnections(context.Background(), "1", input) + groups, _, err := client.Teams.CreateOrUpdateIDPGroupConnections(context.Background(), "o", "s", input) if err != nil { t.Errorf("Teams.CreateOrUpdateIDPGroupConnections returned error: %v", err) } From 95f39e2f2566d9d119f00b8de47e85130dac04e5 Mon Sep 17 00:00:00 2001 From: Alex Orr Date: Mon, 20 Jan 2020 17:07:10 -0800 Subject: [PATCH 02/10] fix: update team members endpoints --- github/teams_members.go | 20 ++++---- github/teams_members_test.go | 94 +++++++++++++++++++++++++++++++++--- github/teams_test.go | 78 ------------------------------ 3 files changed, 96 insertions(+), 96 deletions(-) diff --git a/github/teams_members.go b/github/teams_members.go index 2a211fe9072..e35ba2328f0 100644 --- a/github/teams_members.go +++ b/github/teams_members.go @@ -24,8 +24,8 @@ type TeamListTeamMembersOptions struct { // team. // // GitHub API docs: https://developer.github.com/v3/teams/members/#list-team-members -func (s *TeamsService) ListTeamMembers(ctx context.Context, team int64, opt *TeamListTeamMembersOptions) ([]*User, *Response, error) { - u := fmt.Sprintf("teams/%v/members", team) +func (s *TeamsService) ListTeamMembers(ctx context.Context, org, slug string, opt *TeamListTeamMembersOptions) ([]*User, *Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/members", org, slug) u, err := addOptions(u, opt) if err != nil { return nil, nil, err @@ -66,8 +66,8 @@ func (s *TeamsService) IsTeamMember(ctx context.Context, team int64, user string // GetTeamMembership returns the membership status for a user in a team. // // GitHub API docs: https://developer.github.com/v3/teams/members/#get-team-membership -func (s *TeamsService) GetTeamMembership(ctx context.Context, team int64, user string) (*Membership, *Response, error) { - u := fmt.Sprintf("teams/%v/memberships/%v", team, user) +func (s *TeamsService) GetTeamMembership(ctx context.Context, org, slug, user string) (*Membership, *Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/memberships/%v", org, slug, user) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err @@ -114,8 +114,8 @@ type TeamAddTeamMembershipOptions struct { // added as a member of the team. // // GitHub API docs: https://developer.github.com/v3/teams/members/#add-or-update-team-membership -func (s *TeamsService) AddTeamMembership(ctx context.Context, team int64, user string, opt *TeamAddTeamMembershipOptions) (*Membership, *Response, error) { - u := fmt.Sprintf("teams/%v/memberships/%v", team, user) +func (s *TeamsService) AddTeamMembership(ctx context.Context, org, slug, user string, opt *TeamAddTeamMembershipOptions) (*Membership, *Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/memberships/%v", org, slug, user) req, err := s.client.NewRequest("PUT", u, opt) if err != nil { return nil, nil, err @@ -133,8 +133,8 @@ func (s *TeamsService) AddTeamMembership(ctx context.Context, team int64, user s // RemoveTeamMembership removes a user from a team. // // GitHub API docs: https://developer.github.com/v3/teams/members/#remove-team-membership -func (s *TeamsService) RemoveTeamMembership(ctx context.Context, team int64, user string) (*Response, error) { - u := fmt.Sprintf("teams/%v/memberships/%v", team, user) +func (s *TeamsService) RemoveTeamMembership(ctx context.Context, org, slug, user string) (*Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/memberships/%v", org, slug, user) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err @@ -148,8 +148,8 @@ func (s *TeamsService) RemoveTeamMembership(ctx context.Context, team int64, use // Preview features are not supported for production use. // // GitHub API docs: https://developer.github.com/v3/teams/members/#list-pending-team-invitations -func (s *TeamsService) ListPendingTeamInvitations(ctx context.Context, team int64, opt *ListOptions) ([]*Invitation, *Response, error) { - u := fmt.Sprintf("teams/%v/invitations", team) +func (s *TeamsService) ListPendingTeamInvitations(ctx context.Context, org, slug string, opt *ListOptions) ([]*Invitation, *Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/invitations", org, slug) u, err := addOptions(u, opt) if err != nil { return nil, nil, err diff --git a/github/teams_members_test.go b/github/teams_members_test.go index 616a747b410..7c89171586a 100644 --- a/github/teams_members_test.go +++ b/github/teams_members_test.go @@ -12,20 +12,21 @@ import ( "net/http" "reflect" "testing" + "time" ) func TestTeamsService__ListTeamMembers(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/teams/1/members", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/o/teams/s/members", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") testFormValues(t, r, values{"role": "member", "page": "2"}) fmt.Fprint(w, `[{"id":1}]`) }) opt := &TeamListTeamMembersOptions{Role: "member", ListOptions: ListOptions{Page: 2}} - members, _, err := client.Teams.ListTeamMembers(context.Background(), 1, opt) + members, _, err := client.Teams.ListTeamMembers(context.Background(), "o", "s", opt) if err != nil { t.Errorf("Teams.ListTeamMembers returned error: %v", err) } @@ -104,12 +105,12 @@ func TestTeamsService__GetTeamMembership(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/teams/1/memberships/u", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/o/teams/s/memberships/u", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"url":"u", "state":"active"}`) }) - membership, _, err := client.Teams.GetTeamMembership(context.Background(), 1, "u") + membership, _, err := client.Teams.GetTeamMembership(context.Background(), "o", "s", "u") if err != nil { t.Errorf("Teams.GetTeamMembership returned error: %v", err) } @@ -126,7 +127,7 @@ func TestTeamsService__AddTeamMembership(t *testing.T) { opt := &TeamAddTeamMembershipOptions{Role: "maintainer"} - mux.HandleFunc("/teams/1/memberships/u", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/o/teams/s/memberships/u", func(w http.ResponseWriter, r *http.Request) { v := new(TeamAddTeamMembershipOptions) json.NewDecoder(r.Body).Decode(v) @@ -138,7 +139,7 @@ func TestTeamsService__AddTeamMembership(t *testing.T) { fmt.Fprint(w, `{"url":"u", "state":"pending"}`) }) - membership, _, err := client.Teams.AddTeamMembership(context.Background(), 1, "u", opt) + membership, _, err := client.Teams.AddTeamMembership(context.Background(), "o", "s", "u", opt) if err != nil { t.Errorf("Teams.AddTeamMembership returned error: %v", err) } @@ -153,13 +154,90 @@ func TestTeamsService__RemoveTeamMembership(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/teams/1/memberships/u", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/o/teams/s/memberships/u", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") w.WriteHeader(http.StatusNoContent) }) - _, err := client.Teams.RemoveTeamMembership(context.Background(), 1, "u") + _, err := client.Teams.RemoveTeamMembership(context.Background(), "o", "s", "u") if err != nil { t.Errorf("Teams.RemoveTeamMembership returned error: %v", err) } } + +func TestTeamsService_ListPendingTeamInvitations(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/teams/s/invitations", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testFormValues(t, r, values{"page": "1"}) + fmt.Fprint(w, `[ + { + "id": 1, + "login": "monalisa", + "email": "octocat@github.com", + "role": "direct_member", + "created_at": "2017-01-21T00:00:00Z", + "inviter": { + "login": "other_user", + "id": 1, + "avatar_url": "https://github.com/images/error/other_user_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/other_user", + "html_url": "https://github.com/other_user", + "followers_url": "https://api.github.com/users/other_user/followers", + "following_url": "https://api.github.com/users/other_user/following/other_user", + "gists_url": "https://api.github.com/users/other_user/gists/gist_id", + "starred_url": "https://api.github.com/users/other_user/starred/owner/repo", + "subscriptions_url": "https://api.github.com/users/other_user/subscriptions", + "organizations_url": "https://api.github.com/users/other_user/orgs", + "repos_url": "https://api.github.com/users/other_user/repos", + "events_url": "https://api.github.com/users/other_user/events/privacy", + "received_events_url": "https://api.github.com/users/other_user/received_events/privacy", + "type": "User", + "site_admin": false + } + } + ]`) + }) + + opt := &ListOptions{Page: 1} + invitations, _, err := client.Teams.ListPendingTeamInvitations(context.Background(), "o", "s", opt) + if err != nil { + t.Errorf("Teams.ListPendingTeamInvitations returned error: %v", err) + } + + createdAt := time.Date(2017, time.January, 21, 0, 0, 0, 0, time.UTC) + want := []*Invitation{ + { + ID: Int64(1), + Login: String("monalisa"), + Email: String("octocat@github.com"), + Role: String("direct_member"), + CreatedAt: &createdAt, + Inviter: &User{ + Login: String("other_user"), + ID: Int64(1), + AvatarURL: String("https://github.com/images/error/other_user_happy.gif"), + GravatarID: String(""), + URL: String("https://api.github.com/users/other_user"), + HTMLURL: String("https://github.com/other_user"), + FollowersURL: String("https://api.github.com/users/other_user/followers"), + FollowingURL: String("https://api.github.com/users/other_user/following/other_user"), + GistsURL: String("https://api.github.com/users/other_user/gists/gist_id"), + StarredURL: String("https://api.github.com/users/other_user/starred/owner/repo"), + SubscriptionsURL: String("https://api.github.com/users/other_user/subscriptions"), + OrganizationsURL: String("https://api.github.com/users/other_user/orgs"), + ReposURL: String("https://api.github.com/users/other_user/repos"), + EventsURL: String("https://api.github.com/users/other_user/events/privacy"), + ReceivedEventsURL: String("https://api.github.com/users/other_user/received_events/privacy"), + Type: String("User"), + SiteAdmin: Bool(false), + }, + }} + + if !reflect.DeepEqual(invitations, want) { + t.Errorf("Teams.ListPendingTeamInvitations returned %+v, want %+v", invitations, want) + } +} diff --git a/github/teams_test.go b/github/teams_test.go index 4c60af7f6a4..ca0e8bcd107 100644 --- a/github/teams_test.go +++ b/github/teams_test.go @@ -15,7 +15,6 @@ import ( "reflect" "strings" "testing" - "time" ) func TestTeamsService_ListTeams(t *testing.T) { @@ -469,83 +468,6 @@ func TestTeamsService_ListUserTeams(t *testing.T) { } } -func TestTeamsService_ListPendingTeamInvitations(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/teams/1/invitations", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - testFormValues(t, r, values{"page": "1"}) - fmt.Fprint(w, `[ - { - "id": 1, - "login": "monalisa", - "email": "octocat@github.com", - "role": "direct_member", - "created_at": "2017-01-21T00:00:00Z", - "inviter": { - "login": "other_user", - "id": 1, - "avatar_url": "https://github.com/images/error/other_user_happy.gif", - "gravatar_id": "", - "url": "https://api.github.com/users/other_user", - "html_url": "https://github.com/other_user", - "followers_url": "https://api.github.com/users/other_user/followers", - "following_url": "https://api.github.com/users/other_user/following/other_user", - "gists_url": "https://api.github.com/users/other_user/gists/gist_id", - "starred_url": "https://api.github.com/users/other_user/starred/owner/repo", - "subscriptions_url": "https://api.github.com/users/other_user/subscriptions", - "organizations_url": "https://api.github.com/users/other_user/orgs", - "repos_url": "https://api.github.com/users/other_user/repos", - "events_url": "https://api.github.com/users/other_user/events/privacy", - "received_events_url": "https://api.github.com/users/other_user/received_events/privacy", - "type": "User", - "site_admin": false - } - } - ]`) - }) - - opt := &ListOptions{Page: 1} - invitations, _, err := client.Teams.ListPendingTeamInvitations(context.Background(), 1, opt) - if err != nil { - t.Errorf("Teams.ListPendingTeamInvitations returned error: %v", err) - } - - createdAt := time.Date(2017, time.January, 21, 0, 0, 0, 0, time.UTC) - want := []*Invitation{ - { - ID: Int64(1), - Login: String("monalisa"), - Email: String("octocat@github.com"), - Role: String("direct_member"), - CreatedAt: &createdAt, - Inviter: &User{ - Login: String("other_user"), - ID: Int64(1), - AvatarURL: String("https://github.com/images/error/other_user_happy.gif"), - GravatarID: String(""), - URL: String("https://api.github.com/users/other_user"), - HTMLURL: String("https://github.com/other_user"), - FollowersURL: String("https://api.github.com/users/other_user/followers"), - FollowingURL: String("https://api.github.com/users/other_user/following/other_user"), - GistsURL: String("https://api.github.com/users/other_user/gists/gist_id"), - StarredURL: String("https://api.github.com/users/other_user/starred/owner/repo"), - SubscriptionsURL: String("https://api.github.com/users/other_user/subscriptions"), - OrganizationsURL: String("https://api.github.com/users/other_user/orgs"), - ReposURL: String("https://api.github.com/users/other_user/repos"), - EventsURL: String("https://api.github.com/users/other_user/events/privacy"), - ReceivedEventsURL: String("https://api.github.com/users/other_user/received_events/privacy"), - Type: String("User"), - SiteAdmin: Bool(false), - }, - }} - - if !reflect.DeepEqual(invitations, want) { - t.Errorf("Teams.ListPendingTeamInvitations returned %+v, want %+v", invitations, want) - } -} - func TestTeamsService_ListProjects(t *testing.T) { client, mux, _, teardown := setup() defer teardown() From 1809f4bb7db90776f89c6f080f97db7c5abc326c Mon Sep 17 00:00:00 2001 From: Alex Orr Date: Tue, 21 Jan 2020 23:22:53 -0800 Subject: [PATCH 03/10] fix: add implementation for using team and org IDs --- github/teams.go | 317 +++++++++++++++++++++++--- github/teams_test.go | 514 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 743 insertions(+), 88 deletions(-) diff --git a/github/teams.go b/github/teams.go index ab55cc15fe7..20fc209fbf8 100644 --- a/github/teams.go +++ b/github/teams.go @@ -116,7 +116,26 @@ func (s *TeamsService) GetTeam(ctx context.Context, team int64) (*Team, *Respons return t, resp, nil } -// GetTeamBySlug fetches a team by slug. +// GetTeamByID fetches a team, given a specified organization ID, by ID. +// +// Github API docs: https://developer.github.com/v3/teams/#get-team-by-name +func (s *TeamsService) GetTeamByID(ctx context.Context, orgID, teamID int64) (*Team, *Response, error) { + u := fmt.Sprintf("organizations/%v/teams/%v", orgID, teamID) + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + t := new(Team) + resp, err := s.client.Do(ctx, req, t) + if err != nil { + return nil, resp, err + } + + return t, resp, nil +} + +// GetTeamBySlug fetches a team, given a specified organization name, by slug. // // GitHub API docs: https://developer.github.com/v3/teams/#get-team-by-name func (s *TeamsService) GetTeamBySlug(ctx context.Context, org, slug string) (*Team, *Response, error) { @@ -212,10 +231,37 @@ func copyNewTeamWithoutParent(team *NewTeam) *newTeamNoParent { } } -// EditTeam edits a team. +// EditTeamByID edits a team, given an organization ID, selected by ID. +// +// GitHub API docs: https://developer.github.com/v3/teams/#edit-team +func (s *TeamsService) EditTeamByID(ctx context.Context, orgID, teamID int64, team NewTeam, removeParent bool) (*Team, *Response, error) { + u := fmt.Sprintf("organizations/%v/teams/%v", orgID, teamID) + + var req *http.Request + var err error + if removeParent { + teamRemoveParent := copyNewTeamWithoutParent(&team) + req, err = s.client.NewRequest("PATCH", u, teamRemoveParent) + } else { + req, err = s.client.NewRequest("PATCH", u, team) + } + if err != nil { + return nil, nil, err + } + + t := new(Team) + resp, err := s.client.Do(ctx, req, t) + if err != nil { + return nil, resp, err + } + + return t, resp, nil +} + +// EditTeamByName edits a team, given an organiation name, by name. // // GitHub API docs: https://developer.github.com/v3/teams/#edit-team -func (s *TeamsService) EditTeam(ctx context.Context, org, slug string, team NewTeam, removeParent bool) (*Team, *Response, error) { +func (s *TeamsService) EditTeamByName(ctx context.Context, org, slug string, team NewTeam, removeParent bool) (*Team, *Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v", org, slug) var req *http.Request @@ -239,10 +285,23 @@ func (s *TeamsService) EditTeam(ctx context.Context, org, slug string, team NewT return t, resp, nil } -// DeleteTeam deletes a team. +// DeleteTeamByID deletes a team referenced by ID. // // GitHub API docs: https://developer.github.com/v3/teams/#delete-team -func (s *TeamsService) DeleteTeam(ctx context.Context, org, slug string) (*Response, error) { +func (s *TeamsService) DeleteTeamByID(ctx context.Context, orgID, teamID int64) (*Response, error) { + u := fmt.Sprintf("organizations/%v/teams/%v", orgID, teamID) + req, err := s.client.NewRequest("DELETE", u, nil) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} + +// DeleteTeamByName deletes a team reference by Name. +// +// GitHub API docs: https://developer.github.com/v3/teams/#delete-team +func (s *TeamsService) DeleteTeamByName(ctx context.Context, org, slug string) (*Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v", org, slug) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { @@ -252,10 +311,34 @@ func (s *TeamsService) DeleteTeam(ctx context.Context, org, slug string) (*Respo return s.client.Do(ctx, req, nil) } -// ListChildTeams lists child teams for a team. +// ListChildTeamsByParentID lists child teams for a parent team given parent ID. +// +// GitHub API docs: https://developer.github.com/v3/teams/#list-child-teams +func (s *TeamsService) ListChildTeamsByParentID(ctx context.Context, orgID, teamID int64, opt *ListOptions) ([]*Team, *Response, error) { + u := fmt.Sprintf("organizations/%v/teams/%v/teams", orgID, teamID) + u, err := addOptions(u, opt) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var teams []*Team + resp, err := s.client.Do(ctx, req, &teams) + if err != nil { + return nil, resp, err + } + + return teams, resp, nil +} + +// ListChildTeamsByParentName lists child teams for a parent team given parent name. // // GitHub API docs: https://developer.github.com/v3/teams/#list-child-teams -func (s *TeamsService) ListChildTeams(ctx context.Context, org, slug string, opt *ListOptions) ([]*Team, *Response, error) { +func (s *TeamsService) ListChildTeamsByParentName(ctx context.Context, org, slug string, opt *ListOptions) ([]*Team, *Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v/teams", org, slug) u, err := addOptions(u, opt) if err != nil { @@ -276,10 +359,38 @@ func (s *TeamsService) ListChildTeams(ctx context.Context, org, slug string, opt return teams, resp, nil } -// ListTeamRepos lists the repositories that the specified team has access to. +// ListTeamReposByID lists the repositories given a team ID that the specified team has access to. +// +// GitHub API docs: https://developer.github.com/v3/teams/#list-team-repos +func (s *TeamsService) ListTeamReposByID(ctx context.Context, orgID, teamID int64, opt *ListOptions) ([]*Repository, *Response, error) { + u := fmt.Sprintf("organizations/%v/teams/%v/repos", orgID, teamID) + u, err := addOptions(u, opt) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when topics API fully launches. + headers := []string{mediaTypeTopicsPreview} + req.Header.Set("Accept", strings.Join(headers, ", ")) + + var repos []*Repository + resp, err := s.client.Do(ctx, req, &repos) + if err != nil { + return nil, resp, err + } + + return repos, resp, nil +} + +// ListTeamReposByName lists the repositories given a team name that the specified team has access to. // // GitHub API docs: https://developer.github.com/v3/teams/#list-team-repos -func (s *TeamsService) ListTeamRepos(ctx context.Context, org, slug string, opt *ListOptions) ([]*Repository, *Response, error) { +func (s *TeamsService) ListTeamReposByName(ctx context.Context, org, slug string, opt *ListOptions) ([]*Repository, *Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v/repos", org, slug) u, err := addOptions(u, opt) if err != nil { @@ -304,12 +415,36 @@ func (s *TeamsService) ListTeamRepos(ctx context.Context, org, slug string, opt return repos, resp, nil } -// IsTeamRepo checks if a team manages the specified repository. If the +// IsTeamRepoByID checks if a team, given it's ID, manages the specified repository. If the +// repository is managed by team, a Repository is returned which includes the +// permissions team has for that repo. +// +// GitHub API docs: https://developer.github.com/v3/teams/#check-if-a-team-manages-a-repository +func (s *TeamsService) IsTeamRepoByID(ctx context.Context, orgID, teamID int64, owner, repo string) (*Repository, *Response, error) { + u := fmt.Sprintf("organizations/%v/teams/%v/repos/%v/%v", orgID, teamID, owner, repo) + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + headers := []string{mediaTypeOrgPermissionRepo} + req.Header.Set("Accept", strings.Join(headers, ", ")) + + repository := new(Repository) + resp, err := s.client.Do(ctx, req, repository) + if err != nil { + return nil, resp, err + } + + return repository, resp, nil +} + +// IsTeamRepoByName checks if a team, given it's name, manages the specified repository. If the // repository is managed by team, a Repository is returned which includes the // permissions team has for that repo. // // GitHub API docs: https://developer.github.com/v3/teams/#check-if-a-team-manages-a-repository -func (s *TeamsService) IsTeamRepo(ctx context.Context, org, slug, owner, repo string) (*Repository, *Response, error) { +func (s *TeamsService) IsTeamRepoByName(ctx context.Context, org, slug, owner, repo string) (*Repository, *Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v/repos/%v/%v", org, slug, owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -341,12 +476,27 @@ type TeamAddTeamRepoOptions struct { Permission string `json:"permission,omitempty"` } -// AddTeamRepo adds a repository to be managed by the specified team. The -// specified repository must be owned by the organization to which the team +// AddTeamRepoByID adds a repository to be managed by the specified team given the team ID. +// The specified repository must be owned by the organization to which the team +// belongs, or a direct fork of a repository owned by the organization. +// +// GitHub API docs: https://developer.github.com/v3/teams/#add-team-repo +func (s *TeamsService) AddTeamRepoByID(ctx context.Context, orgID, teamID int64, owner, repo string, opt *TeamAddTeamRepoOptions) (*Response, error) { + u := fmt.Sprintf("organizations/%v/teams/%v/repos/%v/%v", orgID, teamID, owner, repo) + req, err := s.client.NewRequest("PUT", u, opt) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} + +// AddTeamRepoByName adds a repository to be managed by the specified team given the team name. +// The specified repository must be owned by the organization to which the team // belongs, or a direct fork of a repository owned by the organization. // // GitHub API docs: https://developer.github.com/v3/teams/#add-team-repo -func (s *TeamsService) AddTeamRepo(ctx context.Context, org, slug, owner, repo string, opt *TeamAddTeamRepoOptions) (*Response, error) { +func (s *TeamsService) AddTeamRepoByName(ctx context.Context, org, slug, owner, repo string, opt *TeamAddTeamRepoOptions) (*Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v/repos/%v/%v", org, slug, owner, repo) req, err := s.client.NewRequest("PUT", u, opt) if err != nil { @@ -356,12 +506,27 @@ func (s *TeamsService) AddTeamRepo(ctx context.Context, org, slug, owner, repo s return s.client.Do(ctx, req, nil) } -// RemoveTeamRepo removes a repository from being managed by the specified -// team. Note that this does not delete the repository, it just removes it -// from the team. +// RemoveTeamRepoByID removes a repository from being managed by the specified +// team given the team ID. Note that this does not delete the repository, it +// just removes it from the team. +// +// GitHub API docs: https://developer.github.com/v3/teams/#remove-team-repo +func (s *TeamsService) RemoveTeamRepoByID(ctx context.Context, orgID, teamID int64, owner, repo string) (*Response, error) { + u := fmt.Sprintf("organizations/%v/teams/%v/repos/%v/%v", orgID, teamID, owner, repo) + req, err := s.client.NewRequest("DELETE", u, nil) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} + +// RemoveTeamRepoByName removes a repository from being managed by the specified +// team given the team Name. Note that this does not delete the repository, it +// just removes it from the team. // // GitHub API docs: https://developer.github.com/v3/teams/#remove-team-repo -func (s *TeamsService) RemoveTeamRepo(ctx context.Context, org, slug, owner, repo string) (*Response, error) { +func (s *TeamsService) RemoveTeamRepoByName(ctx context.Context, org, slug, owner, repo string) (*Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v/repos/%v/%v", org, slug, owner, repo) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { @@ -394,10 +559,34 @@ func (s *TeamsService) ListUserTeams(ctx context.Context, opt *ListOptions) ([]* return teams, resp, nil } -// ListTeamProjects lists the organization projects for a team. +// ListTeamProjectsByID lists the organization projects for a team given the team ID. +// +// GitHub API docs: https://developer.github.com/v3/teams/#list-team-projects +func (s *TeamsService) ListTeamProjectsByID(ctx context.Context, orgID, teamID int64) ([]*Project, *Response, error) { + u := fmt.Sprintf("organizations/%v/teams/%v/projects", orgID, teamID) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + acceptHeaders := []string{mediaTypeProjectsPreview} + req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) + + var projects []*Project + resp, err := s.client.Do(ctx, req, &projects) + if err != nil { + return nil, resp, err + } + + return projects, resp, nil +} + +// ListTeamProjectsByName lists the organization projects for a team given the team name. // // GitHub API docs: https://developer.github.com/v3/teams/#list-team-projects -func (s *TeamsService) ListTeamProjects(ctx context.Context, org, slug string) ([]*Project, *Response, error) { +func (s *TeamsService) ListTeamProjectsByName(ctx context.Context, org, slug string) ([]*Project, *Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v/projects", org, slug) req, err := s.client.NewRequest("GET", u, nil) @@ -418,11 +607,35 @@ func (s *TeamsService) ListTeamProjects(ctx context.Context, org, slug string) ( return projects, resp, nil } -// ReviewTeamProjects checks whether a team has read, write, or admin +// ReviewTeamProjectsByID checks whether a team, given it's ID, has read, write, or admin +// permissions for an organization project. +// +// GitHub API docs: https://developer.github.com/v3/teams/#review-a-team-project +func (s *TeamsService) ReviewTeamProjectsByID(ctx context.Context, orgID, teamID, projectID int64) (*Project, *Response, error) { + u := fmt.Sprintf("organizations/%v/teams/%v/projects/%v", orgID, teamID, projectID) + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + acceptHeaders := []string{mediaTypeProjectsPreview} + req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) + + projects := &Project{} + resp, err := s.client.Do(ctx, req, &projects) + if err != nil { + return nil, resp, err + } + + return projects, resp, nil +} + +// ReviewTeamProjectsByName checks whether a team, given it's ID, has read, write, or admin // permissions for an organization project. // // GitHub API docs: https://developer.github.com/v3/teams/#review-a-team-project -func (s *TeamsService) ReviewTeamProjects(ctx context.Context, org, slug string, projectID int64) (*Project, *Response, error) { +func (s *TeamsService) ReviewTeamProjectsByName(ctx context.Context, org, slug string, projectID int64) (*Project, *Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v/projects/%v", org, slug, projectID) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -454,12 +667,31 @@ type TeamProjectOptions struct { Permission *string `json:"permission,omitempty"` } -// AddTeamProject adds an organization project to a team. To add a project to a team or -// update the team's permission on a project, the authenticated user must have admin -// permissions for the project. +// AddTeamProjectByID adds an organization project to a team given the team ID. +// To add a project to a team or update the team's permission on a project, the +// authenticated user must have admin permissions for the project. +// +// GitHub API docs: https://developer.github.com/v3/teams/#add-or-update-team-project +func (s *TeamsService) AddTeamProjectByID(ctx context.Context, orgID, teamID, projectID int64, opt *TeamProjectOptions) (*Response, error) { + u := fmt.Sprintf("organizations/%v/teams/%v/projects/%v", orgID, teamID, projectID) + req, err := s.client.NewRequest("PUT", u, opt) + if err != nil { + return nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + acceptHeaders := []string{mediaTypeProjectsPreview} + req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) + + return s.client.Do(ctx, req, nil) +} + +// AddTeamProjectByName adds an organization project to a team given the team name. +// To add a project to a team or update the team's permission on a project, the +// authenticated user must have admin permissions for the project. // // GitHub API docs: https://developer.github.com/v3/teams/#add-or-update-team-project -func (s *TeamsService) AddTeamProject(ctx context.Context, org, slug string, projectID int64, opt *TeamProjectOptions) (*Response, error) { +func (s *TeamsService) AddTeamProjectByName(ctx context.Context, org, slug string, projectID int64, opt *TeamProjectOptions) (*Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v/projects/%v", org, slug, projectID) req, err := s.client.NewRequest("PUT", u, opt) if err != nil { @@ -473,14 +705,37 @@ func (s *TeamsService) AddTeamProject(ctx context.Context, org, slug string, pro return s.client.Do(ctx, req, nil) } -// RemoveTeamProject removes an organization project from a team. An organization owner or -// a team maintainer can remove any project from the team. To remove a project from a team -// as an organization member, the authenticated user must have "read" access to both the team -// and project, or "admin" access to the team or project. +// RemoveTeamProjectByID removes an organization project from a team given team ID. +// An organization owner or a team maintainer can remove any project from the team. +// To remove a project from a team as an organization member, the authenticated user +// must have "read" access to both the team and project, or "admin" access to the team +// or project. +// Note: This endpoint removes the project from the team, but does not delete it. +// +// GitHub API docs: https://developer.github.com/v3/teams/#remove-team-project +func (s *TeamsService) RemoveTeamProjectByID(ctx context.Context, orgID, teamID, projectID int64) (*Response, error) { + u := fmt.Sprintf("organizations/%v/teams/%v/projects/%v", orgID, teamID, projectID) + req, err := s.client.NewRequest("DELETE", u, nil) + if err != nil { + return nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + acceptHeaders := []string{mediaTypeProjectsPreview} + req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) + + return s.client.Do(ctx, req, nil) +} + +// RemoveTeamProjectByName removes an organization project from a team given team name. +// An organization owner or a team maintainer can remove any project from the team. +// To remove a project from a team as an organization member, the authenticated user +// must have "read" access to both the team and project, or "admin" access to the team +// or project. // Note: This endpoint removes the project from the team, but does not delete it. // // GitHub API docs: https://developer.github.com/v3/teams/#remove-team-project -func (s *TeamsService) RemoveTeamProject(ctx context.Context, org, slug string, projectID int64) (*Response, error) { +func (s *TeamsService) RemoveTeamProjectByName(ctx context.Context, org, slug string, projectID int64) (*Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v/projects/%v", org, slug, projectID) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { diff --git a/github/teams_test.go b/github/teams_test.go index ca0e8bcd107..4eab6a03d69 100644 --- a/github/teams_test.go +++ b/github/teams_test.go @@ -90,6 +90,47 @@ func TestTeamsService_GetTeam_nestedTeams(t *testing.T) { } } +func TestTeamsService_GetTeamByID(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/organizations/1/teams/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{"id":1, "name":"n", "description": "d", "url":"u", "slug": "s", "permission":"p", "ldap_dn":"cn=n,ou=groups,dc=example,dc=com", "parent":null}`) + }) + + team, _, err := client.Teams.GetTeamByID(context.Background(), 1, 1) + if err != nil { + t.Errorf("Teams.GetTeamByID returned error: %v", err) + } + + want := &Team{ID: Int64(1), Name: String("n"), Description: String("d"), URL: String("u"), Slug: String("s"), Permission: String("p"), LDAPDN: String("cn=n,ou=groups,dc=example,dc=com")} + if !reflect.DeepEqual(team, want) { + t.Errorf("Teams.GetTeamByID returned %+v, want %+v", team, want) + } +} + +func TestTeamsService_GetTeamByID_notFound(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/organizations/1/teams/2", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + w.WriteHeader(http.StatusNotFound) + }) + + team, resp, err := client.Teams.GetTeamByID(context.Background(), 1, 2) + if err == nil { + t.Errorf("Expected HTTP 404 response") + } + if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want { + t.Errorf("Teams.GetTeamByID returned status %d, want %d", got, want) + } + if team != nil { + t.Errorf("Teams.GetTeamByID returned %+v, want nil", team) + } +} + func TestTeamsService_GetTeamBySlug(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -176,7 +217,75 @@ func TestTeamsService_CreateTeam_invalidOrg(t *testing.T) { testURLParseError(t, err) } -func TestTeamsService_EditTeam(t *testing.T) { +func TestTeamsService_EditTeamByID(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + input := NewTeam{Name: "n", Privacy: String("closed")} + + mux.HandleFunc("/organizations/1/teams/1", func(w http.ResponseWriter, r *http.Request) { + v := new(NewTeam) + json.NewDecoder(r.Body).Decode(v) + + testMethod(t, r, "PATCH") + if !reflect.DeepEqual(v, &input) { + t.Errorf("Request body = %+v, want %+v", v, input) + } + + fmt.Fprint(w, `{"id":1}`) + }) + + team, _, err := client.Teams.EditTeamByID(context.Background(), 1, 1, input, false) + if err != nil { + t.Errorf("Teams.EditTeamByID returned error: %v", err) + } + + want := &Team{ID: Int64(1)} + if !reflect.DeepEqual(team, want) { + t.Errorf("Teams.EditTeamByID returned %+v, want %+v", team, want) + } +} + +func TestTeamsService_EditTeamByID_RemoveParent(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + input := NewTeam{Name: "n", Privacy: String("closed")} + var body string + + mux.HandleFunc("/organizations/1/teams/1", func(w http.ResponseWriter, r *http.Request) { + v := new(NewTeam) + buf, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Errorf("Unable to read body: %v", err) + } + body = string(buf) + json.NewDecoder(bytes.NewBuffer(buf)).Decode(v) + + testMethod(t, r, "PATCH") + if !reflect.DeepEqual(v, &input) { + t.Errorf("Request body = %+v, want %+v", v, input) + } + + fmt.Fprint(w, `{"id":1}`) + }) + + team, _, err := client.Teams.EditTeamByID(context.Background(), 1, 1, input, true) + if err != nil { + t.Errorf("Teams.EditTeamByID returned error: %v", err) + } + + want := &Team{ID: Int64(1)} + if !reflect.DeepEqual(team, want) { + t.Errorf("Teams.EditTeamByID returned %+v, want %+v", team, want) + } + + if want := `{"name":"n","parent_team_id":null,"privacy":"closed"}` + "\n"; body != want { + t.Errorf("Teams.EditTeamByID body = %+v, want %+v", body, want) + } +} + +func TestTeamsService_EditTeamByName(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -194,18 +303,18 @@ func TestTeamsService_EditTeam(t *testing.T) { fmt.Fprint(w, `{"id":1}`) }) - team, _, err := client.Teams.EditTeam(context.Background(), "o", "s", input, false) + team, _, err := client.Teams.EditTeamByName(context.Background(), "o", "s", input, false) if err != nil { - t.Errorf("Teams.EditTeam returned error: %v", err) + t.Errorf("Teams.EditTeamByName returned error: %v", err) } want := &Team{ID: Int64(1)} if !reflect.DeepEqual(team, want) { - t.Errorf("Teams.EditTeam returned %+v, want %+v", team, want) + t.Errorf("Teams.EditTeamByName returned %+v, want %+v", team, want) } } -func TestTeamsService_EditTeam_RemoveParent(t *testing.T) { +func TestTeamsService_EditTeamByName_RemoveParent(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -229,7 +338,7 @@ func TestTeamsService_EditTeam_RemoveParent(t *testing.T) { fmt.Fprint(w, `{"id":1}`) }) - team, _, err := client.Teams.EditTeam(context.Background(), "o", "s", input, true) + team, _, err := client.Teams.EditTeamByName(context.Background(), "o", "s", input, true) if err != nil { t.Errorf("Teams.EditTeam returned error: %v", err) } @@ -244,7 +353,21 @@ func TestTeamsService_EditTeam_RemoveParent(t *testing.T) { } } -func TestTeamsService_DeleteTeam(t *testing.T) { +func TestTeamsService_DeleteTeamByID(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/organizations/1/teams/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + }) + + _, err := client.Teams.DeleteTeamByID(context.Background(), 1, 1) + if err != nil { + t.Errorf("Teams.DeleteTeamByID returned error: %v", err) + } +} + +func TestTeamsService_DeleteTeamByName(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -252,13 +375,35 @@ func TestTeamsService_DeleteTeam(t *testing.T) { testMethod(t, r, "DELETE") }) - _, err := client.Teams.DeleteTeam(context.Background(), "o", "s") + _, err := client.Teams.DeleteTeamByName(context.Background(), "o", "s") if err != nil { - t.Errorf("Teams.DeleteTeam returned error: %v", err) + t.Errorf("Teams.DeleteTeamByName returned error: %v", err) } } -func TestTeamsService_ListChildTeams(t *testing.T) { +func TestTeamsService_ListChildTeamsByParentID(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/organizations/1/teams/2/teams", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testFormValues(t, r, values{"page": "2"}) + fmt.Fprint(w, `[{"id":2}]`) + }) + + opt := &ListOptions{Page: 2} + teams, _, err := client.Teams.ListChildTeamsByParentID(context.Background(), 1, 2, opt) + if err != nil { + t.Errorf("Teams.ListChildTeamsByParentID returned error: %v", err) + } + + want := []*Team{{ID: Int64(2)}} + if !reflect.DeepEqual(teams, want) { + t.Errorf("Teams.ListChildTeamsByParentID returned %+v, want %+v", teams, want) + } +} + +func TestTeamsService_ListChildTeamsByParentName(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -269,18 +414,42 @@ func TestTeamsService_ListChildTeams(t *testing.T) { }) opt := &ListOptions{Page: 2} - teams, _, err := client.Teams.ListChildTeams(context.Background(), "o", "s", opt) + teams, _, err := client.Teams.ListChildTeamsByParentName(context.Background(), "o", "s", opt) if err != nil { - t.Errorf("Teams.ListTeams returned error: %v", err) + t.Errorf("Teams.ListChildTeamsByParentName returned error: %v", err) } want := []*Team{{ID: Int64(2)}} if !reflect.DeepEqual(teams, want) { - t.Errorf("Teams.ListTeams returned %+v, want %+v", teams, want) + t.Errorf("Teams.ListChildTeamsByParentName returned %+v, want %+v", teams, want) + } +} + +func TestTeamsService_ListTeamReposByID(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/organizations/1/teams/1/repos", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + wantAcceptHeaders := []string{mediaTypeTopicsPreview} + testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", ")) + testFormValues(t, r, values{"page": "2"}) + fmt.Fprint(w, `[{"id":1}]`) + }) + + opt := &ListOptions{Page: 2} + members, _, err := client.Teams.ListTeamReposByID(context.Background(), 1, 1, opt) + if err != nil { + t.Errorf("Teams.ListTeamReposByID returned error: %v", err) + } + + want := []*Repository{{ID: Int64(1)}} + if !reflect.DeepEqual(members, want) { + t.Errorf("Teams.ListTeamReposByID returned %+v, want %+v", members, want) } } -func TestTeamsService_ListTeamRepos(t *testing.T) { +func TestTeamsService_ListTeamReposByName(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -293,18 +462,40 @@ func TestTeamsService_ListTeamRepos(t *testing.T) { }) opt := &ListOptions{Page: 2} - members, _, err := client.Teams.ListTeamRepos(context.Background(), "o", "s", opt) + members, _, err := client.Teams.ListTeamReposByName(context.Background(), "o", "s", opt) if err != nil { - t.Errorf("Teams.ListTeamRepos returned error: %v", err) + t.Errorf("Teams.ListTeamReposByName returned error: %v", err) } want := []*Repository{{ID: Int64(1)}} if !reflect.DeepEqual(members, want) { - t.Errorf("Teams.ListTeamRepos returned %+v, want %+v", members, want) + t.Errorf("Teams.ListTeamReposByName returned %+v, want %+v", members, want) + } +} + +func TestTeamsService_IsTeamRepoByID_true(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/organizations/1/teams/1/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + wantAcceptHeaders := []string{mediaTypeOrgPermissionRepo} + testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", ")) + fmt.Fprint(w, `{"id":1}`) + }) + + repo, _, err := client.Teams.IsTeamRepoByID(context.Background(), 1, 1, "owner", "repo") + if err != nil { + t.Errorf("Teams.IsTeamRepoByID returned error: %v", err) + } + + want := &Repository{ID: Int64(1)} + if !reflect.DeepEqual(repo, want) { + t.Errorf("Teams.IsTeamRepoByID returned %+v, want %+v", repo, want) } } -func TestTeamsService_IsTeamRepo_true(t *testing.T) { +func TestTeamsService_IsTeamRepoByName_true(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -315,18 +506,39 @@ func TestTeamsService_IsTeamRepo_true(t *testing.T) { fmt.Fprint(w, `{"id":1}`) }) - repo, _, err := client.Teams.IsTeamRepo(context.Background(), "org", "slug", "owner", "repo") + repo, _, err := client.Teams.IsTeamRepoByName(context.Background(), "org", "slug", "owner", "repo") if err != nil { - t.Errorf("Teams.IsTeamRepo returned error: %v", err) + t.Errorf("Teams.IsTeamRepoByName returned error: %v", err) } want := &Repository{ID: Int64(1)} if !reflect.DeepEqual(repo, want) { - t.Errorf("Teams.IsTeamRepo returned %+v, want %+v", repo, want) + t.Errorf("Teams.IsTeamRepoByName returned %+v, want %+v", repo, want) } } -func TestTeamsService_IsTeamRepo_false(t *testing.T) { +func TestTeamsService_IsTeamRepoByID_false(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/organizations/1/teams/1/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + w.WriteHeader(http.StatusNotFound) + }) + + repo, resp, err := client.Teams.IsTeamRepoByID(context.Background(), 1, 1, "owner", "repo") + if err == nil { + t.Errorf("Expected HTTP 404 response") + } + if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want { + t.Errorf("Teams.IsTeamRepoByID returned status %d, want %d", got, want) + } + if repo != nil { + t.Errorf("Teams.IsTeamRepoByID returned %+v, want nil", repo) + } +} + +func TestTeamsService_IsTeamRepoByName_false(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -335,19 +547,40 @@ func TestTeamsService_IsTeamRepo_false(t *testing.T) { w.WriteHeader(http.StatusNotFound) }) - repo, resp, err := client.Teams.IsTeamRepo(context.Background(), "org", "slug", "owner", "repo") + repo, resp, err := client.Teams.IsTeamRepoByName(context.Background(), "org", "slug", "owner", "repo") if err == nil { t.Errorf("Expected HTTP 404 response") } if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want { - t.Errorf("Teams.IsTeamRepo returned status %d, want %d", got, want) + t.Errorf("Teams.IsTeamRepoByID returned status %d, want %d", got, want) + } + if repo != nil { + t.Errorf("Teams.IsTeamRepoByID returned %+v, want nil", repo) + } +} + +func TestTeamsService_IsTeamRepoByID_error(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/organizations/1/teams/1/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + http.Error(w, "BadRequest", http.StatusBadRequest) + }) + + repo, resp, err := client.Teams.IsTeamRepoByID(context.Background(), 1, 1, "owner", "repo") + if err == nil { + t.Errorf("Expected HTTP 400 response") + } + if got, want := resp.Response.StatusCode, http.StatusBadRequest; got != want { + t.Errorf("Teams.IsTeamRepoByID returned status %d, want %d", got, want) } if repo != nil { - t.Errorf("Teams.IsTeamRepo returned %+v, want nil", repo) + t.Errorf("Teams.IsTeamRepoByID returned %+v, want nil", repo) } } -func TestTeamsService_IsTeamRepo_error(t *testing.T) { +func TestTeamsService_IsTeamRepoByName_error(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -356,27 +589,59 @@ func TestTeamsService_IsTeamRepo_error(t *testing.T) { http.Error(w, "BadRequest", http.StatusBadRequest) }) - repo, resp, err := client.Teams.IsTeamRepo(context.Background(), "org", "slug", "owner", "repo") + repo, resp, err := client.Teams.IsTeamRepoByName(context.Background(), "org", "slug", "owner", "repo") if err == nil { t.Errorf("Expected HTTP 400 response") } if got, want := resp.Response.StatusCode, http.StatusBadRequest; got != want { - t.Errorf("Teams.IsTeamRepo returned status %d, want %d", got, want) + t.Errorf("Teams.IsTeamRepoByName returned status %d, want %d", got, want) } if repo != nil { - t.Errorf("Teams.IsTeamRepo returned %+v, want nil", repo) + t.Errorf("Teams.IsTeamRepoByName returned %+v, want nil", repo) } } -func TestTeamsService_IsTeamRepo_invalidOwner(t *testing.T) { +func TestTeamsService_IsTeamRepoByID_invalidOwner(t *testing.T) { + client, _, _, teardown := setup() + defer teardown() + + _, _, err := client.Teams.IsTeamRepoByID(context.Background(), 1, 1, "%", "r") + testURLParseError(t, err) +} + +func TestTeamsService_IsTeamRepoByName_invalidOwner(t *testing.T) { client, _, _, teardown := setup() defer teardown() - _, _, err := client.Teams.IsTeamRepo(context.Background(), "o", "s", "%", "r") + _, _, err := client.Teams.IsTeamRepoByName(context.Background(), "o", "s", "%", "r") testURLParseError(t, err) } -func TestTeamsService_AddTeamRepo(t *testing.T) { +func TestTeamsService_AddTeamRepoByID(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + opt := &TeamAddTeamRepoOptions{Permission: "admin"} + + mux.HandleFunc("/organizations/1/teams/1/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { + v := new(TeamAddTeamRepoOptions) + json.NewDecoder(r.Body).Decode(v) + + testMethod(t, r, "PUT") + if !reflect.DeepEqual(v, opt) { + t.Errorf("Request body = %+v, want %+v", v, opt) + } + + w.WriteHeader(http.StatusNoContent) + }) + + _, err := client.Teams.AddTeamRepoByID(context.Background(), 1, 1, "owner", "repo", opt) + if err != nil { + t.Errorf("Teams.AddTeamRepoByID returned error: %v", err) + } +} + +func TestTeamsService_AddTeamRepoByName(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -394,13 +659,28 @@ func TestTeamsService_AddTeamRepo(t *testing.T) { w.WriteHeader(http.StatusNoContent) }) - _, err := client.Teams.AddTeamRepo(context.Background(), "org", "slug", "owner", "repo", opt) + _, err := client.Teams.AddTeamRepoByName(context.Background(), "org", "slug", "owner", "repo", opt) if err != nil { - t.Errorf("Teams.AddTeamRepo returned error: %v", err) + t.Errorf("Teams.AddTeamRepoByName returned error: %v", err) + } +} + +func TestTeamsService_AddTeamRepoByID_noAccess(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/organizations/1/teams/1/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + w.WriteHeader(http.StatusUnprocessableEntity) + }) + + _, err := client.Teams.AddTeamRepoByID(context.Background(), 1, 1, "owner", "repo", nil) + if err == nil { + t.Errorf("Expcted error to be returned") } } -func TestTeamsService_AddTeamRepo_noAccess(t *testing.T) { +func TestTeamsService_AddTeamRepoByName_noAccess(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -409,21 +689,44 @@ func TestTeamsService_AddTeamRepo_noAccess(t *testing.T) { w.WriteHeader(http.StatusUnprocessableEntity) }) - _, err := client.Teams.AddTeamRepo(context.Background(), "org", "slug", "owner", "repo", nil) + _, err := client.Teams.AddTeamRepoByName(context.Background(), "org", "slug", "owner", "repo", nil) if err == nil { t.Errorf("Expcted error to be returned") } } -func TestTeamsService_AddTeamRepo_invalidOwner(t *testing.T) { +func TestTeamsService_AddTeamRepoByID_invalidOwner(t *testing.T) { + client, _, _, teardown := setup() + defer teardown() + + _, err := client.Teams.AddTeamRepoByID(context.Background(), 1, 1, "%", "r", nil) + testURLParseError(t, err) +} + +func TestTeamsService_AddTeamRepoByName_invalidOwner(t *testing.T) { client, _, _, teardown := setup() defer teardown() - _, err := client.Teams.AddTeamRepo(context.Background(), "o", "s", "%", "r", nil) + _, err := client.Teams.AddTeamRepoByName(context.Background(), "o", "s", "%", "r", nil) testURLParseError(t, err) } -func TestTeamsService_RemoveTeamRepo(t *testing.T) { +func TestTeamsService_RemoveTeamRepoByID(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/organizations/1/teams/1/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + w.WriteHeader(http.StatusNoContent) + }) + + _, err := client.Teams.RemoveTeamRepoByID(context.Background(), 1, 1, "owner", "repo") + if err != nil { + t.Errorf("Teams.RemoveTeamRepoByID returned error: %v", err) + } +} + +func TestTeamsService_RemoveTeamRepoByName(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -432,17 +735,25 @@ func TestTeamsService_RemoveTeamRepo(t *testing.T) { w.WriteHeader(http.StatusNoContent) }) - _, err := client.Teams.RemoveTeamRepo(context.Background(), "org", "slug", "owner", "repo") + _, err := client.Teams.RemoveTeamRepoByName(context.Background(), "org", "slug", "owner", "repo") if err != nil { - t.Errorf("Teams.RemoveTeamRepo returned error: %v", err) + t.Errorf("Teams.RemoveTeamRepoByName returned error: %v", err) } } -func TestTeamsService_RemoveTeamRepo_invalidOwner(t *testing.T) { +func TestTeamsService_RemoveTeamRepoByID_invalidOwner(t *testing.T) { + client, _, _, teardown := setup() + defer teardown() + + _, err := client.Teams.RemoveTeamRepoByID(context.Background(), 1, 1, "%", "r") + testURLParseError(t, err) +} + +func TestTeamsService_RemoveTeamRepoByName_invalidOwner(t *testing.T) { client, _, _, teardown := setup() defer teardown() - _, err := client.Teams.RemoveTeamRepo(context.Background(), "o", "s", "%", "r") + _, err := client.Teams.RemoveTeamRepoByName(context.Background(), "o", "s", "%", "r") testURLParseError(t, err) } @@ -468,7 +779,29 @@ func TestTeamsService_ListUserTeams(t *testing.T) { } } -func TestTeamsService_ListProjects(t *testing.T) { +func TestTeamsService_ListProjectsByID(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + wantAcceptHeaders := []string{mediaTypeProjectsPreview} + mux.HandleFunc("/organizations/1/teams/1/projects", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", ")) + fmt.Fprint(w, `[{"id":1}]`) + }) + + projects, _, err := client.Teams.ListTeamProjectsByID(context.Background(), 1, 1) + if err != nil { + t.Errorf("Teams.ListTeamProjectsByID returned error: %v", err) + } + + want := []*Project{{ID: Int64(1)}} + if !reflect.DeepEqual(projects, want) { + t.Errorf("Teams.ListTeamProjectsByID returned %+v, want %+v", projects, want) + } +} + +func TestTeamsService_ListProjectsByName(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -479,18 +812,40 @@ func TestTeamsService_ListProjects(t *testing.T) { fmt.Fprint(w, `[{"id":1}]`) }) - projects, _, err := client.Teams.ListTeamProjects(context.Background(), "o", "s") + projects, _, err := client.Teams.ListTeamProjectsByName(context.Background(), "o", "s") if err != nil { - t.Errorf("Teams.ListTeamProjects returned error: %v", err) + t.Errorf("Teams.ListTeamProjectsByName returned error: %v", err) } want := []*Project{{ID: Int64(1)}} if !reflect.DeepEqual(projects, want) { - t.Errorf("Teams.ListTeamProjects returned %+v, want %+v", projects, want) + t.Errorf("Teams.ListTeamProjectsByName returned %+v, want %+v", projects, want) } } -func TestTeamsService_ReviewProjects(t *testing.T) { +func TestTeamsService_ReviewProjectsByID(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + wantAcceptHeaders := []string{mediaTypeProjectsPreview} + mux.HandleFunc("/organizations/1/teams/1/projects/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", ")) + fmt.Fprint(w, `{"id":1}`) + }) + + project, _, err := client.Teams.ReviewTeamProjectsByID(context.Background(), 1, 1, 1) + if err != nil { + t.Errorf("Teams.ReviewTeamProjectsByID returned error: %v", err) + } + + want := &Project{ID: Int64(1)} + if !reflect.DeepEqual(project, want) { + t.Errorf("Teams.ReviewTeamProjectsByID returned %+v, want %+v", project, want) + } +} + +func TestTeamsService_ReviewProjectsByName(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -501,18 +856,46 @@ func TestTeamsService_ReviewProjects(t *testing.T) { fmt.Fprint(w, `{"id":1}`) }) - project, _, err := client.Teams.ReviewTeamProjects(context.Background(), "o", "s", 1) + project, _, err := client.Teams.ReviewTeamProjectsByName(context.Background(), "o", "s", 1) if err != nil { - t.Errorf("Teams.ReviewTeamProjects returned error: %v", err) + t.Errorf("Teams.ReviewTeamProjectsByName returned error: %v", err) } want := &Project{ID: Int64(1)} if !reflect.DeepEqual(project, want) { - t.Errorf("Teams.ReviewTeamProjects returned %+v, want %+v", project, want) + t.Errorf("Teams.ReviewTeamProjectsByName returned %+v, want %+v", project, want) } } -func TestTeamsService_AddTeamProject(t *testing.T) { +func TestTeamsService_AddTeamProjectByID(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + opt := &TeamProjectOptions{ + Permission: String("admin"), + } + + wantAcceptHeaders := []string{mediaTypeProjectsPreview} + mux.HandleFunc("/organizations/1/teams/1/projects/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", ")) + + v := &TeamProjectOptions{} + json.NewDecoder(r.Body).Decode(v) + if !reflect.DeepEqual(v, opt) { + t.Errorf("Request body = %+v, want %+v", v, opt) + } + + w.WriteHeader(http.StatusNoContent) + }) + + _, err := client.Teams.AddTeamProjectByID(context.Background(), 1, 1, 1, opt) + if err != nil { + t.Errorf("Teams.AddTeamProjectByID returned error: %v", err) + } +} + +func TestTeamsService_AddTeamProjectByName(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -534,13 +917,30 @@ func TestTeamsService_AddTeamProject(t *testing.T) { w.WriteHeader(http.StatusNoContent) }) - _, err := client.Teams.AddTeamProject(context.Background(), "o", "s", 1, opt) + _, err := client.Teams.AddTeamProjectByName(context.Background(), "o", "s", 1, opt) + if err != nil { + t.Errorf("Teams.AddTeamProjectByName returned error: %v", err) + } +} + +func TestTeamsService_RemoveTeamProjectByID(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + wantAcceptHeaders := []string{mediaTypeProjectsPreview} + mux.HandleFunc("/organizations/1/teams/1/projects/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", ")) + w.WriteHeader(http.StatusNoContent) + }) + + _, err := client.Teams.RemoveTeamProjectByID(context.Background(), 1, 1, 1) if err != nil { - t.Errorf("Teams.AddTeamProject returned error: %v", err) + t.Errorf("Teams.RemoveTeamProjectByID returned error: %v", err) } } -func TestTeamsService_RemoveTeamProject(t *testing.T) { +func TestTeamsService_RemoveTeamProjectByName(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -551,9 +951,9 @@ func TestTeamsService_RemoveTeamProject(t *testing.T) { w.WriteHeader(http.StatusNoContent) }) - _, err := client.Teams.RemoveTeamProject(context.Background(), "o", "s", 1) + _, err := client.Teams.RemoveTeamProjectByName(context.Background(), "o", "s", 1) if err != nil { - t.Errorf("Teams.RemoveTeamProject returned error: %v", err) + t.Errorf("Teams.RemoveTeamProjectByName returned error: %v", err) } } From 61f02c692634e5386b46da5678a6e7bc452dc28c Mon Sep 17 00:00:00 2001 From: Alex Orr Date: Wed, 22 Jan 2020 22:13:55 -0800 Subject: [PATCH 04/10] fix: teams members functions added to get by ID, fix ID endpoints for general teams --- github/teams.go | 24 ++--- github/teams_members.go | 147 ++++++++++++++++++++++++-- github/teams_members_test.go | 199 +++++++++++++++++++++++++++++++---- github/teams_test.go | 34 +++--- 4 files changed, 346 insertions(+), 58 deletions(-) diff --git a/github/teams.go b/github/teams.go index 20fc209fbf8..7c1b9afb3ce 100644 --- a/github/teams.go +++ b/github/teams.go @@ -120,7 +120,7 @@ func (s *TeamsService) GetTeam(ctx context.Context, team int64) (*Team, *Respons // // Github API docs: https://developer.github.com/v3/teams/#get-team-by-name func (s *TeamsService) GetTeamByID(ctx context.Context, orgID, teamID int64) (*Team, *Response, error) { - u := fmt.Sprintf("organizations/%v/teams/%v", orgID, teamID) + u := fmt.Sprintf("organizations/%v/team/%v", orgID, teamID) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err @@ -235,7 +235,7 @@ func copyNewTeamWithoutParent(team *NewTeam) *newTeamNoParent { // // GitHub API docs: https://developer.github.com/v3/teams/#edit-team func (s *TeamsService) EditTeamByID(ctx context.Context, orgID, teamID int64, team NewTeam, removeParent bool) (*Team, *Response, error) { - u := fmt.Sprintf("organizations/%v/teams/%v", orgID, teamID) + u := fmt.Sprintf("organizations/%v/team/%v", orgID, teamID) var req *http.Request var err error @@ -289,7 +289,7 @@ func (s *TeamsService) EditTeamByName(ctx context.Context, org, slug string, tea // // GitHub API docs: https://developer.github.com/v3/teams/#delete-team func (s *TeamsService) DeleteTeamByID(ctx context.Context, orgID, teamID int64) (*Response, error) { - u := fmt.Sprintf("organizations/%v/teams/%v", orgID, teamID) + u := fmt.Sprintf("organizations/%v/team/%v", orgID, teamID) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err @@ -315,7 +315,7 @@ func (s *TeamsService) DeleteTeamByName(ctx context.Context, org, slug string) ( // // GitHub API docs: https://developer.github.com/v3/teams/#list-child-teams func (s *TeamsService) ListChildTeamsByParentID(ctx context.Context, orgID, teamID int64, opt *ListOptions) ([]*Team, *Response, error) { - u := fmt.Sprintf("organizations/%v/teams/%v/teams", orgID, teamID) + u := fmt.Sprintf("organizations/%v/team/%v/teams", orgID, teamID) u, err := addOptions(u, opt) if err != nil { return nil, nil, err @@ -363,7 +363,7 @@ func (s *TeamsService) ListChildTeamsByParentName(ctx context.Context, org, slug // // GitHub API docs: https://developer.github.com/v3/teams/#list-team-repos func (s *TeamsService) ListTeamReposByID(ctx context.Context, orgID, teamID int64, opt *ListOptions) ([]*Repository, *Response, error) { - u := fmt.Sprintf("organizations/%v/teams/%v/repos", orgID, teamID) + u := fmt.Sprintf("organizations/%v/team/%v/repos", orgID, teamID) u, err := addOptions(u, opt) if err != nil { return nil, nil, err @@ -421,7 +421,7 @@ func (s *TeamsService) ListTeamReposByName(ctx context.Context, org, slug string // // GitHub API docs: https://developer.github.com/v3/teams/#check-if-a-team-manages-a-repository func (s *TeamsService) IsTeamRepoByID(ctx context.Context, orgID, teamID int64, owner, repo string) (*Repository, *Response, error) { - u := fmt.Sprintf("organizations/%v/teams/%v/repos/%v/%v", orgID, teamID, owner, repo) + u := fmt.Sprintf("organizations/%v/team/%v/repos/%v/%v", orgID, teamID, owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err @@ -482,7 +482,7 @@ type TeamAddTeamRepoOptions struct { // // GitHub API docs: https://developer.github.com/v3/teams/#add-team-repo func (s *TeamsService) AddTeamRepoByID(ctx context.Context, orgID, teamID int64, owner, repo string, opt *TeamAddTeamRepoOptions) (*Response, error) { - u := fmt.Sprintf("organizations/%v/teams/%v/repos/%v/%v", orgID, teamID, owner, repo) + u := fmt.Sprintf("organizations/%v/team/%v/repos/%v/%v", orgID, teamID, owner, repo) req, err := s.client.NewRequest("PUT", u, opt) if err != nil { return nil, err @@ -512,7 +512,7 @@ func (s *TeamsService) AddTeamRepoByName(ctx context.Context, org, slug, owner, // // GitHub API docs: https://developer.github.com/v3/teams/#remove-team-repo func (s *TeamsService) RemoveTeamRepoByID(ctx context.Context, orgID, teamID int64, owner, repo string) (*Response, error) { - u := fmt.Sprintf("organizations/%v/teams/%v/repos/%v/%v", orgID, teamID, owner, repo) + u := fmt.Sprintf("organizations/%v/team/%v/repos/%v/%v", orgID, teamID, owner, repo) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err @@ -563,7 +563,7 @@ func (s *TeamsService) ListUserTeams(ctx context.Context, opt *ListOptions) ([]* // // GitHub API docs: https://developer.github.com/v3/teams/#list-team-projects func (s *TeamsService) ListTeamProjectsByID(ctx context.Context, orgID, teamID int64) ([]*Project, *Response, error) { - u := fmt.Sprintf("organizations/%v/teams/%v/projects", orgID, teamID) + u := fmt.Sprintf("organizations/%v/team/%v/projects", orgID, teamID) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -612,7 +612,7 @@ func (s *TeamsService) ListTeamProjectsByName(ctx context.Context, org, slug str // // GitHub API docs: https://developer.github.com/v3/teams/#review-a-team-project func (s *TeamsService) ReviewTeamProjectsByID(ctx context.Context, orgID, teamID, projectID int64) (*Project, *Response, error) { - u := fmt.Sprintf("organizations/%v/teams/%v/projects/%v", orgID, teamID, projectID) + u := fmt.Sprintf("organizations/%v/team/%v/projects/%v", orgID, teamID, projectID) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err @@ -673,7 +673,7 @@ type TeamProjectOptions struct { // // GitHub API docs: https://developer.github.com/v3/teams/#add-or-update-team-project func (s *TeamsService) AddTeamProjectByID(ctx context.Context, orgID, teamID, projectID int64, opt *TeamProjectOptions) (*Response, error) { - u := fmt.Sprintf("organizations/%v/teams/%v/projects/%v", orgID, teamID, projectID) + u := fmt.Sprintf("organizations/%v/team/%v/projects/%v", orgID, teamID, projectID) req, err := s.client.NewRequest("PUT", u, opt) if err != nil { return nil, err @@ -714,7 +714,7 @@ func (s *TeamsService) AddTeamProjectByName(ctx context.Context, org, slug strin // // GitHub API docs: https://developer.github.com/v3/teams/#remove-team-project func (s *TeamsService) RemoveTeamProjectByID(ctx context.Context, orgID, teamID, projectID int64) (*Response, error) { - u := fmt.Sprintf("organizations/%v/teams/%v/projects/%v", orgID, teamID, projectID) + u := fmt.Sprintf("organizations/%v/team/%v/projects/%v", orgID, teamID, projectID) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err diff --git a/github/teams_members.go b/github/teams_members.go index e35ba2328f0..e35177b0873 100644 --- a/github/teams_members.go +++ b/github/teams_members.go @@ -20,11 +20,36 @@ type TeamListTeamMembersOptions struct { ListOptions } -// ListTeamMembers lists all of the users who are members of the specified -// team. +// ListTeamMembersByID lists all of the users who are members of the specified +// team given the team ID and organization ID. // // GitHub API docs: https://developer.github.com/v3/teams/members/#list-team-members -func (s *TeamsService) ListTeamMembers(ctx context.Context, org, slug string, opt *TeamListTeamMembersOptions) ([]*User, *Response, error) { +func (s *TeamsService) ListTeamMembersByID(ctx context.Context, orgID, teamID int64, opt *TeamListTeamMembersOptions) ([]*User, *Response, error) { + u := fmt.Sprintf("organizations/%v/team/%v/members", orgID, teamID) + u, err := addOptions(u, opt) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var members []*User + resp, err := s.client.Do(ctx, req, &members) + if err != nil { + return nil, resp, err + } + + return members, resp, nil +} + +// ListTeamMembersByName lists all of the users who are members of the specified +// team given the team slug and organization name. +// +// GitHub API docs: https://developer.github.com/v3/teams/members/#list-team-members +func (s *TeamsService) ListTeamMembersByName(ctx context.Context, org, slug string, opt *TeamListTeamMembersOptions) ([]*User, *Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v/members", org, slug) u, err := addOptions(u, opt) if err != nil { @@ -63,10 +88,31 @@ func (s *TeamsService) IsTeamMember(ctx context.Context, team int64, user string return member, resp, err } -// GetTeamMembership returns the membership status for a user in a team. +// GetTeamMembershipByID returns the membership status for a user in a team +// given the team ID and organization ID. // // GitHub API docs: https://developer.github.com/v3/teams/members/#get-team-membership -func (s *TeamsService) GetTeamMembership(ctx context.Context, org, slug, user string) (*Membership, *Response, error) { +func (s *TeamsService) GetTeamMembershipByID(ctx context.Context, orgID, teamID int64, user string) (*Membership, *Response, error) { + u := fmt.Sprintf("organizations/%v/team/%v/memberships/%v", orgID, teamID, user) + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + t := new(Membership) + resp, err := s.client.Do(ctx, req, t) + if err != nil { + return nil, resp, err + } + + return t, resp, nil +} + +// GetTeamMembershipByName returns the membership status for a user in a team +// given the team slug and organization name.. +// +// GitHub API docs: https://developer.github.com/v3/teams/members/#get-team-membership +func (s *TeamsService) GetTeamMembershipByName(ctx context.Context, org, slug, user string) (*Membership, *Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v/memberships/%v", org, slug, user) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -96,7 +142,8 @@ type TeamAddTeamMembershipOptions struct { Role string `json:"role,omitempty"` } -// AddTeamMembership adds or invites a user to a team. +// AddTeamMembershipByID adds or invites a user to a team by the team ID +// and organization ID. // // In order to add a membership between a user and a team, the authenticated // user must have 'admin' permissions to the team or be an owner of the @@ -114,7 +161,42 @@ type TeamAddTeamMembershipOptions struct { // added as a member of the team. // // GitHub API docs: https://developer.github.com/v3/teams/members/#add-or-update-team-membership -func (s *TeamsService) AddTeamMembership(ctx context.Context, org, slug, user string, opt *TeamAddTeamMembershipOptions) (*Membership, *Response, error) { +func (s *TeamsService) AddTeamMembershipByID(ctx context.Context, orgID, teamID int64, user string, opt *TeamAddTeamMembershipOptions) (*Membership, *Response, error) { + u := fmt.Sprintf("organizations/%v/team/%v/memberships/%v", orgID, teamID, user) + req, err := s.client.NewRequest("PUT", u, opt) + if err != nil { + return nil, nil, err + } + + t := new(Membership) + resp, err := s.client.Do(ctx, req, t) + if err != nil { + return nil, resp, err + } + + return t, resp, nil +} + +// AddTeamMembershipByName adds or invites a user to a team by the team slug +// and organiation name. +// +// In order to add a membership between a user and a team, the authenticated +// user must have 'admin' permissions to the team or be an owner of the +// organization that the team is associated with. +// +// If the user is already a part of the team's organization (meaning they're on +// at least one other team in the organization), this endpoint will add the +// user to the team. +// +// If the user is completely unaffiliated with the team's organization (meaning +// they're on none of the organization's teams), this endpoint will send an +// invitation to the user via email. This newly-created membership will be in +// the "pending" state until the user accepts the invitation, at which point +// the membership will transition to the "active" state and the user will be +// added as a member of the team. +// +// GitHub API docs: https://developer.github.com/v3/teams/members/#add-or-update-team-membership +func (s *TeamsService) AddTeamMembershipByName(ctx context.Context, org, slug, user string, opt *TeamAddTeamMembershipOptions) (*Membership, *Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v/memberships/%v", org, slug, user) req, err := s.client.NewRequest("PUT", u, opt) if err != nil { @@ -130,10 +212,25 @@ func (s *TeamsService) AddTeamMembership(ctx context.Context, org, slug, user st return t, resp, nil } -// RemoveTeamMembership removes a user from a team. +// RemoveTeamMembershipByID removes a user from a team given the team ID and +// organization ID. +// +// GitHub API docs: https://developer.github.com/v3/teams/members/#remove-team-membership +func (s *TeamsService) RemoveTeamMembershipByID(ctx context.Context, orgID, teamID int64, user string) (*Response, error) { + u := fmt.Sprintf("organizations/%v/team/%v/memberships/%v", orgID, teamID, user) + req, err := s.client.NewRequest("DELETE", u, nil) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} + +// RemoveTeamMembershipByName removes a user from a team given the team slug +// and organization name. // // GitHub API docs: https://developer.github.com/v3/teams/members/#remove-team-membership -func (s *TeamsService) RemoveTeamMembership(ctx context.Context, org, slug, user string) (*Response, error) { +func (s *TeamsService) RemoveTeamMembershipByName(ctx context.Context, org, slug, user string) (*Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v/memberships/%v", org, slug, user) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { @@ -143,12 +240,40 @@ func (s *TeamsService) RemoveTeamMembership(ctx context.Context, org, slug, user return s.client.Do(ctx, req, nil) } -// ListPendingTeamInvitations get pending invitaion list in team. +// ListPendingTeamInvitationsByID get pending invitaion list in team given the +// team ID and organization ID. +// Warning: The API may change without advance notice during the preview period. +// Preview features are not supported for production use. +// +// GitHub API docs: https://developer.github.com/v3/teams/members/#list-pending-team-invitations +func (s *TeamsService) ListPendingTeamInvitationsByID(ctx context.Context, orgID, teamID int64, opt *ListOptions) ([]*Invitation, *Response, error) { + u := fmt.Sprintf("organizations/%v/team/%v/invitations", orgID, teamID) + u, err := addOptions(u, opt) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var pendingInvitations []*Invitation + resp, err := s.client.Do(ctx, req, &pendingInvitations) + if err != nil { + return nil, resp, err + } + + return pendingInvitations, resp, nil +} + +// ListPendingTeamInvitationsByName get pending invitaion list in team given the +// team slug and organization name. // Warning: The API may change without advance notice during the preview period. // Preview features are not supported for production use. // // GitHub API docs: https://developer.github.com/v3/teams/members/#list-pending-team-invitations -func (s *TeamsService) ListPendingTeamInvitations(ctx context.Context, org, slug string, opt *ListOptions) ([]*Invitation, *Response, error) { +func (s *TeamsService) ListPendingTeamInvitationsByName(ctx context.Context, org, slug string, opt *ListOptions) ([]*Invitation, *Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v/invitations", org, slug) u, err := addOptions(u, opt) if err != nil { diff --git a/github/teams_members_test.go b/github/teams_members_test.go index 7c89171586a..c9b7f996780 100644 --- a/github/teams_members_test.go +++ b/github/teams_members_test.go @@ -15,7 +15,29 @@ import ( "time" ) -func TestTeamsService__ListTeamMembers(t *testing.T) { +func TestTeamsService__ListTeamMembersByID(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/organizations/1/team/1/members", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testFormValues(t, r, values{"role": "member", "page": "2"}) + fmt.Fprint(w, `[{"id":1}]`) + }) + + opt := &TeamListTeamMembersOptions{Role: "member", ListOptions: ListOptions{Page: 2}} + members, _, err := client.Teams.ListTeamMembersByID(context.Background(), 1, 1, opt) + if err != nil { + t.Errorf("Teams.ListTeamMembersByID returned error: %v", err) + } + + want := []*User{{ID: Int64(1)}} + if !reflect.DeepEqual(members, want) { + t.Errorf("Teams.ListTeamMembersByID returned %+v, want %+v", members, want) + } +} + +func TestTeamsService__ListTeamMembersByName(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -26,9 +48,9 @@ func TestTeamsService__ListTeamMembers(t *testing.T) { }) opt := &TeamListTeamMembersOptions{Role: "member", ListOptions: ListOptions{Page: 2}} - members, _, err := client.Teams.ListTeamMembers(context.Background(), "o", "s", opt) + members, _, err := client.Teams.ListTeamMembersByName(context.Background(), "o", "s", opt) if err != nil { - t.Errorf("Teams.ListTeamMembers returned error: %v", err) + t.Errorf("Teams.ListTeamMembersByName returned error: %v", err) } want := []*User{{ID: Int64(1)}} @@ -101,7 +123,27 @@ func TestTeamsService__IsTeamMember_invalidUser(t *testing.T) { testURLParseError(t, err) } -func TestTeamsService__GetTeamMembership(t *testing.T) { +func TestTeamsService__GetTeamMembershipByID(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/organizations/1/team/1/memberships/u", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{"url":"u", "state":"active"}`) + }) + + membership, _, err := client.Teams.GetTeamMembershipByID(context.Background(), 1, 1, "u") + if err != nil { + t.Errorf("Teams.GetTeamMembershipByID returned error: %v", err) + } + + want := &Membership{URL: String("u"), State: String("active")} + if !reflect.DeepEqual(membership, want) { + t.Errorf("Teams.GetTeamMembershipByID returned %+v, want %+v", membership, want) + } +} + +func TestTeamsService__GetTeamMembershipByName(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -110,18 +152,47 @@ func TestTeamsService__GetTeamMembership(t *testing.T) { fmt.Fprint(w, `{"url":"u", "state":"active"}`) }) - membership, _, err := client.Teams.GetTeamMembership(context.Background(), "o", "s", "u") + membership, _, err := client.Teams.GetTeamMembershipByName(context.Background(), "o", "s", "u") if err != nil { - t.Errorf("Teams.GetTeamMembership returned error: %v", err) + t.Errorf("Teams.GetTeamMembershipByName returned error: %v", err) } want := &Membership{URL: String("u"), State: String("active")} if !reflect.DeepEqual(membership, want) { - t.Errorf("Teams.GetTeamMembership returned %+v, want %+v", membership, want) + t.Errorf("Teams.GetTeamMembershipByName returned %+v, want %+v", membership, want) + } +} + +func TestTeamsService__AddTeamMembershipByID(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + opt := &TeamAddTeamMembershipOptions{Role: "maintainer"} + + mux.HandleFunc("/organizations/1/team/1/memberships/u", func(w http.ResponseWriter, r *http.Request) { + v := new(TeamAddTeamMembershipOptions) + json.NewDecoder(r.Body).Decode(v) + + testMethod(t, r, "PUT") + if !reflect.DeepEqual(v, opt) { + t.Errorf("Request body = %+v, want %+v", v, opt) + } + + fmt.Fprint(w, `{"url":"u", "state":"pending"}`) + }) + + membership, _, err := client.Teams.AddTeamMembershipByID(context.Background(), 1, 1, "u", opt) + if err != nil { + t.Errorf("Teams.AddTeamMembershipByID returned error: %v", err) + } + + want := &Membership{URL: String("u"), State: String("pending")} + if !reflect.DeepEqual(membership, want) { + t.Errorf("Teams.AddTeamMembershipByID returned %+v, want %+v", membership, want) } } -func TestTeamsService__AddTeamMembership(t *testing.T) { +func TestTeamsService__AddTeamMembershipByName(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -139,18 +210,33 @@ func TestTeamsService__AddTeamMembership(t *testing.T) { fmt.Fprint(w, `{"url":"u", "state":"pending"}`) }) - membership, _, err := client.Teams.AddTeamMembership(context.Background(), "o", "s", "u", opt) + membership, _, err := client.Teams.AddTeamMembershipByName(context.Background(), "o", "s", "u", opt) if err != nil { - t.Errorf("Teams.AddTeamMembership returned error: %v", err) + t.Errorf("Teams.AddTeamMembershipByName returned error: %v", err) } want := &Membership{URL: String("u"), State: String("pending")} if !reflect.DeepEqual(membership, want) { - t.Errorf("Teams.AddTeamMembership returned %+v, want %+v", membership, want) + t.Errorf("Teams.AddTeamMembershipByName returned %+v, want %+v", membership, want) } } -func TestTeamsService__RemoveTeamMembership(t *testing.T) { +func TestTeamsService__RemoveTeamMembershipByID(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/organizations/1/team/1/memberships/u", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + w.WriteHeader(http.StatusNoContent) + }) + + _, err := client.Teams.RemoveTeamMembershipByID(context.Background(), 1, 1, "u") + if err != nil { + t.Errorf("Teams.RemoveTeamMembershipByID returned error: %v", err) + } +} + +func TestTeamsService__RemoveTeamMembershipByName(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -159,13 +245,90 @@ func TestTeamsService__RemoveTeamMembership(t *testing.T) { w.WriteHeader(http.StatusNoContent) }) - _, err := client.Teams.RemoveTeamMembership(context.Background(), "o", "s", "u") + _, err := client.Teams.RemoveTeamMembershipByName(context.Background(), "o", "s", "u") if err != nil { - t.Errorf("Teams.RemoveTeamMembership returned error: %v", err) + t.Errorf("Teams.RemoveTeamMembershipByName returned error: %v", err) + } +} + +func TestTeamsService_ListPendingTeamInvitationsByID(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/organizations/1/team/1/invitations", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testFormValues(t, r, values{"page": "1"}) + fmt.Fprint(w, `[ + { + "id": 1, + "login": "monalisa", + "email": "octocat@github.com", + "role": "direct_member", + "created_at": "2017-01-21T00:00:00Z", + "inviter": { + "login": "other_user", + "id": 1, + "avatar_url": "https://github.com/images/error/other_user_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/other_user", + "html_url": "https://github.com/other_user", + "followers_url": "https://api.github.com/users/other_user/followers", + "following_url": "https://api.github.com/users/other_user/following/other_user", + "gists_url": "https://api.github.com/users/other_user/gists/gist_id", + "starred_url": "https://api.github.com/users/other_user/starred/owner/repo", + "subscriptions_url": "https://api.github.com/users/other_user/subscriptions", + "organizations_url": "https://api.github.com/users/other_user/orgs", + "repos_url": "https://api.github.com/users/other_user/repos", + "events_url": "https://api.github.com/users/other_user/events/privacy", + "received_events_url": "https://api.github.com/users/other_user/received_events/privacy", + "type": "User", + "site_admin": false + } + } + ]`) + }) + + opt := &ListOptions{Page: 1} + invitations, _, err := client.Teams.ListPendingTeamInvitationsByID(context.Background(), 1, 1, opt) + if err != nil { + t.Errorf("Teams.ListPendingTeamInvitationsByID returned error: %v", err) + } + + createdAt := time.Date(2017, time.January, 21, 0, 0, 0, 0, time.UTC) + want := []*Invitation{ + { + ID: Int64(1), + Login: String("monalisa"), + Email: String("octocat@github.com"), + Role: String("direct_member"), + CreatedAt: &createdAt, + Inviter: &User{ + Login: String("other_user"), + ID: Int64(1), + AvatarURL: String("https://github.com/images/error/other_user_happy.gif"), + GravatarID: String(""), + URL: String("https://api.github.com/users/other_user"), + HTMLURL: String("https://github.com/other_user"), + FollowersURL: String("https://api.github.com/users/other_user/followers"), + FollowingURL: String("https://api.github.com/users/other_user/following/other_user"), + GistsURL: String("https://api.github.com/users/other_user/gists/gist_id"), + StarredURL: String("https://api.github.com/users/other_user/starred/owner/repo"), + SubscriptionsURL: String("https://api.github.com/users/other_user/subscriptions"), + OrganizationsURL: String("https://api.github.com/users/other_user/orgs"), + ReposURL: String("https://api.github.com/users/other_user/repos"), + EventsURL: String("https://api.github.com/users/other_user/events/privacy"), + ReceivedEventsURL: String("https://api.github.com/users/other_user/received_events/privacy"), + Type: String("User"), + SiteAdmin: Bool(false), + }, + }} + + if !reflect.DeepEqual(invitations, want) { + t.Errorf("Teams.ListPendingTeamInvitationsByID returned %+v, want %+v", invitations, want) } } -func TestTeamsService_ListPendingTeamInvitations(t *testing.T) { +func TestTeamsService_ListPendingTeamInvitationsByName(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -203,9 +366,9 @@ func TestTeamsService_ListPendingTeamInvitations(t *testing.T) { }) opt := &ListOptions{Page: 1} - invitations, _, err := client.Teams.ListPendingTeamInvitations(context.Background(), "o", "s", opt) + invitations, _, err := client.Teams.ListPendingTeamInvitationsByName(context.Background(), "o", "s", opt) if err != nil { - t.Errorf("Teams.ListPendingTeamInvitations returned error: %v", err) + t.Errorf("Teams.ListPendingTeamInvitationsByName returned error: %v", err) } createdAt := time.Date(2017, time.January, 21, 0, 0, 0, 0, time.UTC) @@ -238,6 +401,6 @@ func TestTeamsService_ListPendingTeamInvitations(t *testing.T) { }} if !reflect.DeepEqual(invitations, want) { - t.Errorf("Teams.ListPendingTeamInvitations returned %+v, want %+v", invitations, want) + t.Errorf("Teams.ListPendingTeamInvitationsByName returned %+v, want %+v", invitations, want) } } diff --git a/github/teams_test.go b/github/teams_test.go index 4eab6a03d69..76231e03d79 100644 --- a/github/teams_test.go +++ b/github/teams_test.go @@ -94,7 +94,7 @@ func TestTeamsService_GetTeamByID(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/organizations/1/teams/1", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/organizations/1/team/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"id":1, "name":"n", "description": "d", "url":"u", "slug": "s", "permission":"p", "ldap_dn":"cn=n,ou=groups,dc=example,dc=com", "parent":null}`) }) @@ -114,7 +114,7 @@ func TestTeamsService_GetTeamByID_notFound(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/organizations/1/teams/2", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/organizations/1/team/2", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") w.WriteHeader(http.StatusNotFound) }) @@ -223,7 +223,7 @@ func TestTeamsService_EditTeamByID(t *testing.T) { input := NewTeam{Name: "n", Privacy: String("closed")} - mux.HandleFunc("/organizations/1/teams/1", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/organizations/1/team/1", func(w http.ResponseWriter, r *http.Request) { v := new(NewTeam) json.NewDecoder(r.Body).Decode(v) @@ -253,7 +253,7 @@ func TestTeamsService_EditTeamByID_RemoveParent(t *testing.T) { input := NewTeam{Name: "n", Privacy: String("closed")} var body string - mux.HandleFunc("/organizations/1/teams/1", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/organizations/1/team/1", func(w http.ResponseWriter, r *http.Request) { v := new(NewTeam) buf, err := ioutil.ReadAll(r.Body) if err != nil { @@ -357,7 +357,7 @@ func TestTeamsService_DeleteTeamByID(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/organizations/1/teams/1", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/organizations/1/team/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") }) @@ -385,7 +385,7 @@ func TestTeamsService_ListChildTeamsByParentID(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/organizations/1/teams/2/teams", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/organizations/1/team/2/teams", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") testFormValues(t, r, values{"page": "2"}) fmt.Fprint(w, `[{"id":2}]`) @@ -429,7 +429,7 @@ func TestTeamsService_ListTeamReposByID(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/organizations/1/teams/1/repos", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/organizations/1/team/1/repos", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") wantAcceptHeaders := []string{mediaTypeTopicsPreview} testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", ")) @@ -477,7 +477,7 @@ func TestTeamsService_IsTeamRepoByID_true(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/organizations/1/teams/1/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/organizations/1/team/1/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") wantAcceptHeaders := []string{mediaTypeOrgPermissionRepo} testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", ")) @@ -521,7 +521,7 @@ func TestTeamsService_IsTeamRepoByID_false(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/organizations/1/teams/1/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/organizations/1/team/1/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") w.WriteHeader(http.StatusNotFound) }) @@ -563,7 +563,7 @@ func TestTeamsService_IsTeamRepoByID_error(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/organizations/1/teams/1/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/organizations/1/team/1/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") http.Error(w, "BadRequest", http.StatusBadRequest) }) @@ -623,7 +623,7 @@ func TestTeamsService_AddTeamRepoByID(t *testing.T) { opt := &TeamAddTeamRepoOptions{Permission: "admin"} - mux.HandleFunc("/organizations/1/teams/1/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/organizations/1/team/1/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { v := new(TeamAddTeamRepoOptions) json.NewDecoder(r.Body).Decode(v) @@ -669,7 +669,7 @@ func TestTeamsService_AddTeamRepoByID_noAccess(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/organizations/1/teams/1/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/organizations/1/team/1/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") w.WriteHeader(http.StatusUnprocessableEntity) }) @@ -715,7 +715,7 @@ func TestTeamsService_RemoveTeamRepoByID(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/organizations/1/teams/1/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/organizations/1/team/1/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") w.WriteHeader(http.StatusNoContent) }) @@ -784,7 +784,7 @@ func TestTeamsService_ListProjectsByID(t *testing.T) { defer teardown() wantAcceptHeaders := []string{mediaTypeProjectsPreview} - mux.HandleFunc("/organizations/1/teams/1/projects", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/organizations/1/team/1/projects", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", ")) fmt.Fprint(w, `[{"id":1}]`) @@ -828,7 +828,7 @@ func TestTeamsService_ReviewProjectsByID(t *testing.T) { defer teardown() wantAcceptHeaders := []string{mediaTypeProjectsPreview} - mux.HandleFunc("/organizations/1/teams/1/projects/1", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/organizations/1/team/1/projects/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", ")) fmt.Fprint(w, `{"id":1}`) @@ -876,7 +876,7 @@ func TestTeamsService_AddTeamProjectByID(t *testing.T) { } wantAcceptHeaders := []string{mediaTypeProjectsPreview} - mux.HandleFunc("/organizations/1/teams/1/projects/1", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/organizations/1/team/1/projects/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", ")) @@ -928,7 +928,7 @@ func TestTeamsService_RemoveTeamProjectByID(t *testing.T) { defer teardown() wantAcceptHeaders := []string{mediaTypeProjectsPreview} - mux.HandleFunc("/organizations/1/teams/1/projects/1", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/organizations/1/team/1/projects/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", ")) w.WriteHeader(http.StatusNoContent) From eddabd208981d0e872104369ab633555308c29a0 Mon Sep 17 00:00:00 2001 From: Alex Orr Date: Wed, 22 Jan 2020 23:19:23 -0800 Subject: [PATCH 05/10] fix: add functions for team discussion comments endpoints --- github/teams_discussion_comments.go | 140 ++++++++++++-- github/teams_discussion_comments_test.go | 230 ++++++++++++++++++++--- 2 files changed, 331 insertions(+), 39 deletions(-) diff --git a/github/teams_discussion_comments.go b/github/teams_discussion_comments.go index ff871f22be0..97376e8cd3a 100644 --- a/github/teams_discussion_comments.go +++ b/github/teams_discussion_comments.go @@ -39,12 +39,13 @@ type DiscussionCommentListOptions struct { Direction string `url:"direction,omitempty"` } -// ListComments lists all comments on a team discussion. +// ListCommentsByID lists all comments on a team discussion +// given a team ID and organization ID. // Authenticated user must grant read:discussion scope. // // GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#list-comments -func (s *TeamsService) ListComments(ctx context.Context, teamID int64, discussionNumber int, options *DiscussionCommentListOptions) ([]*DiscussionComment, *Response, error) { - u := fmt.Sprintf("teams/%v/discussions/%v/comments", teamID, discussionNumber) +func (s *TeamsService) ListCommentsByID(ctx context.Context, orgID, teamID int64, discussionNumber int, options *DiscussionCommentListOptions) ([]*DiscussionComment, *Response, error) { + u := fmt.Sprintf("organizations/%v/team/%v/discussions/%v/comments", orgID, teamID, discussionNumber) u, err := addOptions(u, options) if err != nil { return nil, nil, err @@ -64,12 +65,39 @@ func (s *TeamsService) ListComments(ctx context.Context, teamID int64, discussio return comments, resp, nil } -// GetComment gets a specific comment on a team discussion. +// ListCommentsByName lists all comments on a team discussion +// given a team slug and organization name. +// Authenticated user must grant read:discussion scope. +// +// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#list-comments +func (s *TeamsService) ListCommentsByName(ctx context.Context, org, slug string, discussionNumber int, options *DiscussionCommentListOptions) ([]*DiscussionComment, *Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v/comments", org, slug, discussionNumber) + u, err := addOptions(u, options) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var comments []*DiscussionComment + resp, err := s.client.Do(ctx, req, &comments) + if err != nil { + return nil, resp, err + } + + return comments, resp, nil +} + +// GetComment gets a specific comment on a team discussion +// given a team ID and organization ID. // Authenticated user must grant read:discussion scope. // // GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#get-a-single-comment -func (s *TeamsService) GetComment(ctx context.Context, teamID int64, discussionNumber, commentNumber int) (*DiscussionComment, *Response, error) { - u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v", teamID, discussionNumber, commentNumber) +func (s *TeamsService) GetCommentByID(ctx context.Context, orgID, teamID int64, discussionNumber, commentNumber int) (*DiscussionComment, *Response, error) { + u := fmt.Sprintf("organizations/%v/team/%v/discussions/%v/comments/%v", orgID, teamID, discussionNumber, commentNumber) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err @@ -84,12 +112,34 @@ func (s *TeamsService) GetComment(ctx context.Context, teamID int64, discussionN return discussionComment, resp, nil } -// CreateComment creates a new discussion post on a team discussion. +// GetComment gets a specific comment on a team discussion +// given a team slug and organization name. +// Authenticated user must grant read:discussion scope. +// +// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#get-a-single-comment +func (s *TeamsService) GetCommentByName(ctx context.Context, org, slug string, discussionNumber, commentNumber int) (*DiscussionComment, *Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v/comments/%v", org, slug, discussionNumber, commentNumber) + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + discussionComment := &DiscussionComment{} + resp, err := s.client.Do(ctx, req, discussionComment) + if err != nil { + return nil, resp, err + } + + return discussionComment, resp, nil +} + +// CreateCommentByID creates a new discussion post on a team discussion +// given a team ID and organization ID. // Authenticated user must grant write:discussion scope. // // GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#create-a-comment -func (s *TeamsService) CreateComment(ctx context.Context, teamID int64, discsusionNumber int, comment DiscussionComment) (*DiscussionComment, *Response, error) { - u := fmt.Sprintf("teams/%v/discussions/%v/comments", teamID, discsusionNumber) +func (s *TeamsService) CreateCommentByID(ctx context.Context, orgID, teamID int64, discsusionNumber int, comment DiscussionComment) (*DiscussionComment, *Response, error) { + u := fmt.Sprintf("organizations/%v/team/%v/discussions/%v/comments", orgID, teamID, discsusionNumber) req, err := s.client.NewRequest("POST", u, comment) if err != nil { return nil, nil, err @@ -104,13 +154,57 @@ func (s *TeamsService) CreateComment(ctx context.Context, teamID int64, discsusi return discussionComment, resp, nil } -// EditComment edits the body text of a discussion comment. +// CreateCommentByName creates a new discussion post on a team discussion +// given a team slug and organization name. +// Authenticated user must grant write:discussion scope. +// +// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#create-a-comment +func (s *TeamsService) CreateCommentByName(ctx context.Context, org, slug string, discsusionNumber int, comment DiscussionComment) (*DiscussionComment, *Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v/comments", org, slug, discsusionNumber) + req, err := s.client.NewRequest("POST", u, comment) + if err != nil { + return nil, nil, err + } + + discussionComment := &DiscussionComment{} + resp, err := s.client.Do(ctx, req, discussionComment) + if err != nil { + return nil, resp, err + } + + return discussionComment, resp, nil +} + +// EditCommentByID edits the body text of a discussion comment +// given a team ID and organization ID. +// Authenticated user must grant write:discussion scope. +// User is allowed to edit body of a comment only. +// +// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#edit-a-comment +func (s *TeamsService) EditCommentByID(ctx context.Context, orgID, teamID int64, discussionNumber, commentNumber int, comment DiscussionComment) (*DiscussionComment, *Response, error) { + u := fmt.Sprintf("organizations/%v/team/%v/discussions/%v/comments/%v", orgID, teamID, discussionNumber, commentNumber) + req, err := s.client.NewRequest("PATCH", u, comment) + if err != nil { + return nil, nil, err + } + + discussionComment := &DiscussionComment{} + resp, err := s.client.Do(ctx, req, discussionComment) + if err != nil { + return nil, resp, err + } + + return discussionComment, resp, nil +} + +// EditCommentByName edits the body text of a discussion comment +// given a team slug and organization name. // Authenticated user must grant write:discussion scope. // User is allowed to edit body of a comment only. // // GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#edit-a-comment -func (s *TeamsService) EditComment(ctx context.Context, teamID int64, discussionNumber, commentNumber int, comment DiscussionComment) (*DiscussionComment, *Response, error) { - u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v", teamID, discussionNumber, commentNumber) +func (s *TeamsService) EditCommentByName(ctx context.Context, org, slug string, discussionNumber, commentNumber int, comment DiscussionComment) (*DiscussionComment, *Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v/comments/%v", org, slug, discussionNumber, commentNumber) req, err := s.client.NewRequest("PATCH", u, comment) if err != nil { return nil, nil, err @@ -125,12 +219,28 @@ func (s *TeamsService) EditComment(ctx context.Context, teamID int64, discussion return discussionComment, resp, nil } -// DeleteComment deletes a comment on a team discussion. +// DeleteCommentByID deletes a comment on a team discussion +// given a team ID and organiation ID. +// Authenticated user must grant write:discussion scope. +// +// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#delete-a-comment +func (s *TeamsService) DeleteCommentByID(ctx context.Context, orgID, teamID int64, discussionNumber, commentNumber int) (*Response, error) { + u := fmt.Sprintf("organizations/%v/team/%v/discussions/%v/comments/%v", orgID, teamID, discussionNumber, commentNumber) + req, err := s.client.NewRequest("DELETE", u, nil) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} + +// DeleteCommentByName deletes a comment on a team discussion +// given a team slug and organization name. // Authenticated user must grant write:discussion scope. // // GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#delete-a-comment -func (s *TeamsService) DeleteComment(ctx context.Context, teamID int64, discussionNumber, commentNumber int) (*Response, error) { - u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v", teamID, discussionNumber, commentNumber) +func (s *TeamsService) DeleteCommentByName(ctx context.Context, org, slug string, discussionNumber, commentNumber int) (*Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v/comments/%v", org, slug, discussionNumber, commentNumber) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err diff --git a/github/teams_discussion_comments_test.go b/github/teams_discussion_comments_test.go index 96ed1464109..c94810fdfdc 100644 --- a/github/teams_discussion_comments_test.go +++ b/github/teams_discussion_comments_test.go @@ -15,11 +15,11 @@ import ( "time" ) -func TestTeamsService_ListComments(t *testing.T) { +func TestTeamsService_ListCommentsByID(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/teams/2/discussions/3/comments", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/organizations/1/team/2/discussions/3/comments", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") testFormValues(t, r, values{ "direction": "desc", @@ -61,9 +61,9 @@ func TestTeamsService_ListComments(t *testing.T) { ]`) }) - comments, _, err := client.Teams.ListComments(context.Background(), 2, 3, &DiscussionCommentListOptions{"desc"}) + comments, _, err := client.Teams.ListCommentsByID(context.Background(), 1, 2, 3, &DiscussionCommentListOptions{"desc"}) if err != nil { - t.Errorf("Teams.ListComments returned error: %v", err) + t.Errorf("Teams.ListCommentsByID returned error: %v", err) } want := []*DiscussionComment{ @@ -101,37 +101,147 @@ func TestTeamsService_ListComments(t *testing.T) { }, } if !reflect.DeepEqual(comments, want) { - t.Errorf("Teams.ListComments returned %+v, want %+v", comments, want) + t.Errorf("Teams.ListCommentsByID returned %+v, want %+v", comments, want) } } -func TestTeamsService_GetComment(t *testing.T) { +func TestTeamsService_ListCommentsByName(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/teams/2/discussions/3/comments/4", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/o/teams/s/discussions/3/comments", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testFormValues(t, r, values{ + "direction": "desc", + }) + fmt.Fprintf(w, + `[ + { + "author": { + "login": "author", + "id": 0, + "avatar_url": "https://avatars1.githubusercontent.com/u/0?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/author", + "html_url": "https://github.com/author", + "followers_url": "https://api.github.com/users/author/followers", + "following_url": "https://api.github.com/users/author/following{/other_user}", + "gists_url": "https://api.github.com/users/author/gists{/gist_id}", + "starred_url": "https://api.github.com/users/author/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/author/subscriptions", + "organizations_url": "https://api.github.com/users/author/orgs", + "repos_url": "https://api.github.com/users/author/repos", + "events_url": "https://api.github.com/users/author/events{/privacy}", + "received_events_url": "https://api.github.com/users/author/received_events", + "type": "User", + "site_admin": false + }, + "body": "comment", + "body_html": "

comment

", + "body_version": "version", + "created_at": "2018-01-01T00:00:00Z", + "last_edited_at": null, + "discussion_url": "https://api.github.com/teams/2/discussions/3", + "html_url": "https://github.com/orgs/1/teams/2/discussions/3/comments/4", + "node_id": "node", + "number": 4, + "updated_at": "2018-01-01T00:00:00Z", + "url": "https://api.github.com/teams/2/discussions/3/comments/4" + } + ]`) + }) + + comments, _, err := client.Teams.ListCommentsByName(context.Background(), "o", "s", 3, &DiscussionCommentListOptions{"desc"}) + if err != nil { + t.Errorf("Teams.ListCommentsByName returned error: %v", err) + } + + want := []*DiscussionComment{ + { + Author: &User{ + Login: String("author"), + ID: Int64(0), + AvatarURL: String("https://avatars1.githubusercontent.com/u/0?v=4"), + GravatarID: String(""), + URL: String("https://api.github.com/users/author"), + HTMLURL: String("https://github.com/author"), + FollowersURL: String("https://api.github.com/users/author/followers"), + FollowingURL: String("https://api.github.com/users/author/following{/other_user}"), + GistsURL: String("https://api.github.com/users/author/gists{/gist_id}"), + StarredURL: String("https://api.github.com/users/author/starred{/owner}{/repo}"), + SubscriptionsURL: String("https://api.github.com/users/author/subscriptions"), + OrganizationsURL: String("https://api.github.com/users/author/orgs"), + ReposURL: String("https://api.github.com/users/author/repos"), + EventsURL: String("https://api.github.com/users/author/events{/privacy}"), + ReceivedEventsURL: String("https://api.github.com/users/author/received_events"), + Type: String("User"), + SiteAdmin: Bool(false), + }, + Body: String("comment"), + BodyHTML: String("

comment

"), + BodyVersion: String("version"), + CreatedAt: &Timestamp{time.Date(2018, time.January, 1, 0, 0, 0, 0, time.UTC)}, + LastEditedAt: nil, + DiscussionURL: String("https://api.github.com/teams/2/discussions/3"), + HTMLURL: String("https://github.com/orgs/1/teams/2/discussions/3/comments/4"), + NodeID: String("node"), + Number: Int(4), + UpdatedAt: &Timestamp{time.Date(2018, time.January, 1, 0, 0, 0, 0, time.UTC)}, + URL: String("https://api.github.com/teams/2/discussions/3/comments/4"), + }, + } + if !reflect.DeepEqual(comments, want) { + t.Errorf("Teams.ListCommentsByName returned %+v, want %+v", comments, want) + } +} + +func TestTeamsService_GetCommentByID(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/organizations/1/team/2/discussions/3/comments/4", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{"number":4}`) + }) + + comment, _, err := client.Teams.GetCommentByID(context.Background(), 1, 2, 3, 4) + if err != nil { + t.Errorf("Teams.GetCommentByID returned error: %v", err) + } + + want := &DiscussionComment{Number: Int(4)} + if !reflect.DeepEqual(comment, want) { + t.Errorf("Teams.GetCommentByID returned %+v, want %+v", comment, want) + } +} + +func TestTeamsService_GetCommentByName(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/teams/s/discussions/3/comments/4", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"number":4}`) }) - comment, _, err := client.Teams.GetComment(context.Background(), 2, 3, 4) + comment, _, err := client.Teams.GetCommentByName(context.Background(), "o", "s", 3, 4) if err != nil { - t.Errorf("Teams.GetComment returned error: %v", err) + t.Errorf("Teams.GetCommentByName returned error: %v", err) } want := &DiscussionComment{Number: Int(4)} if !reflect.DeepEqual(comment, want) { - t.Errorf("Teams.GetComment returned %+v, want %+v", comment, want) + t.Errorf("Teams.GetCommentByName returned %+v, want %+v", comment, want) } } -func TestTeamsService_CreateComment(t *testing.T) { +func TestTeamsService_CreateCommentByID(t *testing.T) { client, mux, _, teardown := setup() defer teardown() input := DiscussionComment{Body: String("c")} - mux.HandleFunc("/teams/2/discussions/3/comments", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/organizations/1/team/2/discussions/3/comments", func(w http.ResponseWriter, r *http.Request) { v := new(DiscussionComment) json.NewDecoder(r.Body).Decode(v) @@ -143,24 +253,53 @@ func TestTeamsService_CreateComment(t *testing.T) { fmt.Fprint(w, `{"number":4}`) }) - comment, _, err := client.Teams.CreateComment(context.Background(), 2, 3, input) + comment, _, err := client.Teams.CreateCommentByID(context.Background(), 1, 2, 3, input) if err != nil { - t.Errorf("Teams.CreateComment returned error: %v", err) + t.Errorf("Teams.CreateCommentByID returned error: %v", err) } want := &DiscussionComment{Number: Int(4)} if !reflect.DeepEqual(comment, want) { - t.Errorf("Teams.CreateComment returned %+v, want %+v", comment, want) + t.Errorf("Teams.CreateCommentByID returned %+v, want %+v", comment, want) } } -func TestTeamsService_EditComment(t *testing.T) { +func TestTeamsService_CreateCommentByName(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + input := DiscussionComment{Body: String("c")} + + mux.HandleFunc("/orgs/o/teams/s/discussions/3/comments", func(w http.ResponseWriter, r *http.Request) { + v := new(DiscussionComment) + json.NewDecoder(r.Body).Decode(v) + + testMethod(t, r, "POST") + if !reflect.DeepEqual(v, &input) { + t.Errorf("Request body = %+v, want %+v", v, input) + } + + fmt.Fprint(w, `{"number":4}`) + }) + + comment, _, err := client.Teams.CreateCommentByName(context.Background(), "o", "s", 3, input) + if err != nil { + t.Errorf("Teams.CreateCommentByName returned error: %v", err) + } + + want := &DiscussionComment{Number: Int(4)} + if !reflect.DeepEqual(comment, want) { + t.Errorf("Teams.CreateCommentByName returned %+v, want %+v", comment, want) + } +} + +func TestTeamsService_EditCommentByID(t *testing.T) { client, mux, _, teardown := setup() defer teardown() input := DiscussionComment{Body: String("e")} - mux.HandleFunc("/teams/2/discussions/3/comments/4", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/organizations/1/team/2/discussions/3/comments/4", func(w http.ResponseWriter, r *http.Request) { v := new(DiscussionComment) json.NewDecoder(r.Body).Decode(v) @@ -172,27 +311,70 @@ func TestTeamsService_EditComment(t *testing.T) { fmt.Fprint(w, `{"number":4}`) }) - comment, _, err := client.Teams.EditComment(context.Background(), 2, 3, 4, input) + comment, _, err := client.Teams.EditCommentByID(context.Background(), 1, 2, 3, 4, input) if err != nil { - t.Errorf("Teams.EditComment returned error: %v", err) + t.Errorf("Teams.EditCommentByID returned error: %v", err) } want := &DiscussionComment{Number: Int(4)} if !reflect.DeepEqual(comment, want) { - t.Errorf("Teams.EditComment returned %+v, want %+v", comment, want) + t.Errorf("Teams.EditCommentByID returned %+v, want %+v", comment, want) + } +} + +func TestTeamsService_EditCommentByName(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + input := DiscussionComment{Body: String("e")} + + mux.HandleFunc("/orgs/o/teams/s/discussions/3/comments/4", func(w http.ResponseWriter, r *http.Request) { + v := new(DiscussionComment) + json.NewDecoder(r.Body).Decode(v) + + testMethod(t, r, "PATCH") + if !reflect.DeepEqual(v, &input) { + t.Errorf("Request body = %+v, want %+v", v, input) + } + + fmt.Fprint(w, `{"number":4}`) + }) + + comment, _, err := client.Teams.EditCommentByName(context.Background(), "o", "s", 3, 4, input) + if err != nil { + t.Errorf("Teams.EditCommentByName returned error: %v", err) + } + + want := &DiscussionComment{Number: Int(4)} + if !reflect.DeepEqual(comment, want) { + t.Errorf("Teams.EditCommentByName returned %+v, want %+v", comment, want) + } +} + +func TestTeamsService_DeleteCommentByID(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/organizations/1/team/2/discussions/3/comments/4", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + }) + + _, err := client.Teams.DeleteCommentByID(context.Background(), 1, 2, 3, 4) + if err != nil { + t.Errorf("Teams.DeleteCommentByID returned error: %v", err) } } -func TestTeamsService_DeleteComment(t *testing.T) { +func TestTeamsService_DeleteCommentByName(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/teams/2/discussions/3/comments/4", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/o/teams/s/discussions/3/comments/4", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") }) - _, err := client.Teams.DeleteComment(context.Background(), 2, 3, 4) + _, err := client.Teams.DeleteCommentByName(context.Background(), "o", "s", 3, 4) if err != nil { - t.Errorf("Teams.DeleteComment returned error: %v", err) + t.Errorf("Teams.DeleteCommentByName returned error: %v", err) } } From 5307f59a36c58a2524d819deac7fc4b69533e77f Mon Sep 17 00:00:00 2001 From: Alex Orr Date: Wed, 22 Jan 2020 23:19:45 -0800 Subject: [PATCH 06/10] fix: add functions for team discussion endpoints --- github/teams_discussions.go | 140 ++++++++++++++++-- github/teams_discussions_test.go | 235 ++++++++++++++++++++++++++++--- 2 files changed, 338 insertions(+), 37 deletions(-) diff --git a/github/teams_discussions.go b/github/teams_discussions.go index 433d01595a6..31212c7b308 100644 --- a/github/teams_discussions.go +++ b/github/teams_discussions.go @@ -44,12 +44,13 @@ type DiscussionListOptions struct { Direction string `url:"direction,omitempty"` } -// ListDiscussions lists all discussions on team's page. +// ListDiscussionsByID lists all discussions on team's page +// given the team ID and organization ID. // Authenticated user must grant read:discussion scope. // // GitHub API docs: https://developer.github.com/v3/teams/discussions/#list-discussions -func (s *TeamsService) ListDiscussions(ctx context.Context, teamID int64, options *DiscussionListOptions) ([]*TeamDiscussion, *Response, error) { - u := fmt.Sprintf("teams/%v/discussions", teamID) +func (s *TeamsService) ListDiscussionsByID(ctx context.Context, orgID, teamID int64, options *DiscussionListOptions) ([]*TeamDiscussion, *Response, error) { + u := fmt.Sprintf("organizations/%v/team/%v/discussions", orgID, teamID) u, err := addOptions(u, options) if err != nil { return nil, nil, err @@ -69,12 +70,39 @@ func (s *TeamsService) ListDiscussions(ctx context.Context, teamID int64, option return teamDiscussions, resp, nil } -// GetDiscussion gets a specific discussion on a team's page. +// ListDiscussionsByName lists all discussions on team's page +// given the team slug and organization name. +// Authenticated user must grant read:discussion scope. +// +// GitHub API docs: https://developer.github.com/v3/teams/discussions/#list-discussions +func (s *TeamsService) ListDiscussionsByName(ctx context.Context, org, slug string, options *DiscussionListOptions) ([]*TeamDiscussion, *Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/discussions", org, slug) + u, err := addOptions(u, options) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var teamDiscussions []*TeamDiscussion + resp, err := s.client.Do(ctx, req, &teamDiscussions) + if err != nil { + return nil, resp, err + } + + return teamDiscussions, resp, nil +} + +// GetDiscussionByID gets a specific discussion on a team's page +// given the team ID and organization ID. // Authenticated user must grant read:discussion scope. // // GitHub API docs: https://developer.github.com/v3/teams/discussions/#get-a-single-discussion -func (s *TeamsService) GetDiscussion(ctx context.Context, teamID int64, discussionNumber int) (*TeamDiscussion, *Response, error) { - u := fmt.Sprintf("teams/%v/discussions/%v", teamID, discussionNumber) +func (s *TeamsService) GetDiscussionByID(ctx context.Context, orgID, teamID int64, discussionNumber int) (*TeamDiscussion, *Response, error) { + u := fmt.Sprintf("organizations/%v/team/%v/discussions/%v", orgID, teamID, discussionNumber) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err @@ -89,12 +117,34 @@ func (s *TeamsService) GetDiscussion(ctx context.Context, teamID int64, discussi return teamDiscussion, resp, nil } -// CreateDiscussion creates a new discussion post on a team's page. +// GetDiscussionByName gets a specific discussion on a team's page +// given the team slug and organization name. +// Authenticated user must grant read:discussion scope. +// +// GitHub API docs: https://developer.github.com/v3/teams/discussions/#get-a-single-discussion +func (s *TeamsService) GetDiscussionByName(ctx context.Context, org, slug string, discussionNumber int) (*TeamDiscussion, *Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v", org, slug, discussionNumber) + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + teamDiscussion := &TeamDiscussion{} + resp, err := s.client.Do(ctx, req, teamDiscussion) + if err != nil { + return nil, resp, err + } + + return teamDiscussion, resp, nil +} + +// CreateDiscussionByID creates a new discussion post on a team's page +// given the team ID and organization ID. // Authenticated user must grant write:discussion scope. // // GitHub API docs: https://developer.github.com/v3/teams/discussions/#create-a-discussion -func (s *TeamsService) CreateDiscussion(ctx context.Context, teamID int64, discussion TeamDiscussion) (*TeamDiscussion, *Response, error) { - u := fmt.Sprintf("teams/%v/discussions", teamID) +func (s *TeamsService) CreateDiscussionByID(ctx context.Context, orgID, teamID int64, discussion TeamDiscussion) (*TeamDiscussion, *Response, error) { + u := fmt.Sprintf("organizations/%v/team/%v/discussions", orgID, teamID) req, err := s.client.NewRequest("POST", u, discussion) if err != nil { return nil, nil, err @@ -109,13 +159,57 @@ func (s *TeamsService) CreateDiscussion(ctx context.Context, teamID int64, discu return teamDiscussion, resp, nil } -// EditDiscussion edits the title and body text of a discussion post. +// CreateDiscussionByName creates a new discussion post on a team's page +// given the team slug and organization name. +// Authenticated user must grant write:discussion scope. +// +// GitHub API docs: https://developer.github.com/v3/teams/discussions/#create-a-discussion +func (s *TeamsService) CreateDiscussionByName(ctx context.Context, org, slug string, discussion TeamDiscussion) (*TeamDiscussion, *Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/discussions", org, slug) + req, err := s.client.NewRequest("POST", u, discussion) + if err != nil { + return nil, nil, err + } + + teamDiscussion := &TeamDiscussion{} + resp, err := s.client.Do(ctx, req, teamDiscussion) + if err != nil { + return nil, resp, err + } + + return teamDiscussion, resp, nil +} + +// EditDiscussionByID edits the title and body text of a discussion post +// for a given team ID and organization ID. +// Authenticated user must grant write:discussion scope. +// User is allowed to change Title and Body of a discussion only. +// +// GitHub API docs: https://developer.github.com/v3/teams/discussions/#edit-a-discussion +func (s *TeamsService) EditDiscussionByID(ctx context.Context, orgID, teamID int64, discussionNumber int, discussion TeamDiscussion) (*TeamDiscussion, *Response, error) { + u := fmt.Sprintf("organizations/%v/team/%v/discussions/%v", orgID, teamID, discussionNumber) + req, err := s.client.NewRequest("PATCH", u, discussion) + if err != nil { + return nil, nil, err + } + + teamDiscussion := &TeamDiscussion{} + resp, err := s.client.Do(ctx, req, teamDiscussion) + if err != nil { + return nil, resp, err + } + + return teamDiscussion, resp, nil +} + +// EditDiscussionByName edits the title and body text of a discussion post +// for a given team slug and organization name. // Authenticated user must grant write:discussion scope. // User is allowed to change Title and Body of a discussion only. // // GitHub API docs: https://developer.github.com/v3/teams/discussions/#edit-a-discussion -func (s *TeamsService) EditDiscussion(ctx context.Context, teamID int64, discussionNumber int, discussion TeamDiscussion) (*TeamDiscussion, *Response, error) { - u := fmt.Sprintf("teams/%v/discussions/%v", teamID, discussionNumber) +func (s *TeamsService) EditDiscussionByName(ctx context.Context, org, slug string, discussionNumber int, discussion TeamDiscussion) (*TeamDiscussion, *Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v", org, slug, discussionNumber) req, err := s.client.NewRequest("PATCH", u, discussion) if err != nil { return nil, nil, err @@ -130,12 +224,28 @@ func (s *TeamsService) EditDiscussion(ctx context.Context, teamID int64, discuss return teamDiscussion, resp, nil } -// DeleteDiscussion deletes a discussion from team's page. +// DeleteDiscussionByID deletes a discussion from team's page +// given the team ID and organization ID. +// Authenticated user must grant write:discussion scope. +// +// GitHub API docs: https://developer.github.com/v3/teams/discussions/#delete-a-discussion +func (s *TeamsService) DeleteDiscussionByID(ctx context.Context, orgID, teamID int64, discussionNumber int) (*Response, error) { + u := fmt.Sprintf("organizations/%v/team/%v/discussions/%v", orgID, teamID, discussionNumber) + req, err := s.client.NewRequest("DELETE", u, nil) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} + +// DeleteDiscussionByName deletes a discussion from team's page +// given the team slug and organization name. // Authenticated user must grant write:discussion scope. // // GitHub API docs: https://developer.github.com/v3/teams/discussions/#delete-a-discussion -func (s *TeamsService) DeleteDiscussion(ctx context.Context, teamID int64, discussionNumber int) (*Response, error) { - u := fmt.Sprintf("teams/%v/discussions/%v", teamID, discussionNumber) +func (s *TeamsService) DeleteDiscussionByName(ctx context.Context, org, slug string, discussionNumber int) (*Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v", org, slug, discussionNumber) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err diff --git a/github/teams_discussions_test.go b/github/teams_discussions_test.go index 65be1ce6f3d..a5b73b78a85 100644 --- a/github/teams_discussions_test.go +++ b/github/teams_discussions_test.go @@ -15,11 +15,11 @@ import ( "time" ) -func TestTeamsService_ListDiscussions(t *testing.T) { +func TestTeamsService_ListDiscussionsByID(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/teams/2/discussions", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/organizations/1/team/2/discussions", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") testFormValues(t, r, values{ "direction": "desc", @@ -65,9 +65,9 @@ func TestTeamsService_ListDiscussions(t *testing.T) { } ]`) }) - discussions, _, err := client.Teams.ListDiscussions(context.Background(), 2, &DiscussionListOptions{"desc"}) + discussions, _, err := client.Teams.ListDiscussionsByID(context.Background(), 1, 2, &DiscussionListOptions{"desc"}) if err != nil { - t.Errorf("Teams.ListDiscussions returned error: %v", err) + t.Errorf("Teams.ListDiscussionsByID returned error: %v", err) } want := []*TeamDiscussion{ @@ -110,37 +110,156 @@ func TestTeamsService_ListDiscussions(t *testing.T) { }, } if !reflect.DeepEqual(discussions, want) { - t.Errorf("Teams.ListDiscussions returned %+v, want %+v", discussions, want) + t.Errorf("Teams.ListDiscussionsByID returned %+v, want %+v", discussions, want) } } -func TestTeamsService_GetDiscussion(t *testing.T) { +func TestTeamsService_ListDiscussionsByName(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/teams/2/discussions/3", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/o/teams/s/discussions", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testFormValues(t, r, values{ + "direction": "desc", + }) + fmt.Fprintf(w, + `[ + { + "author": { + "login": "author", + "id": 0, + "avatar_url": "https://avatars1.githubusercontent.com/u/0?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/author", + "html_url": "https://github.com/author", + "followers_url": "https://api.github.com/users/author/followers", + "following_url": "https://api.github.com/users/author/following{/other_user}", + "gists_url": "https://api.github.com/users/author/gists{/gist_id}", + "starred_url": "https://api.github.com/users/author/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/author/subscriptions", + "organizations_url": "https://api.github.com/users/author/orgs", + "repos_url": "https://api.github.com/users/author/repos", + "events_url": "https://api.github.com/users/author/events{/privacy}", + "received_events_url": "https://api.github.com/users/author/received_events", + "type": "User", + "site_admin": false + }, + "body": "test", + "body_html": "

test

", + "body_version": "version", + "comments_count": 1, + "comments_url": "https://api.github.com/teams/2/discussions/3/comments", + "created_at": "2018-01-01T00:00:00Z", + "last_edited_at": null, + "html_url": "https://github.com/orgs/1/teams/2/discussions/3", + "node_id": "node", + "number": 3, + "pinned": false, + "private": false, + "team_url": "https://api.github.com/teams/2", + "title": "test", + "updated_at": "2018-01-01T00:00:00Z", + "url": "https://api.github.com/teams/2/discussions/3" + } + ]`) + }) + discussions, _, err := client.Teams.ListDiscussionsByName(context.Background(), "o", "s", &DiscussionListOptions{"desc"}) + if err != nil { + t.Errorf("Teams.ListDiscussionsByName returned error: %v", err) + } + + want := []*TeamDiscussion{ + { + Author: &User{ + Login: String("author"), + ID: Int64(0), + AvatarURL: String("https://avatars1.githubusercontent.com/u/0?v=4"), + GravatarID: String(""), + URL: String("https://api.github.com/users/author"), + HTMLURL: String("https://github.com/author"), + FollowersURL: String("https://api.github.com/users/author/followers"), + FollowingURL: String("https://api.github.com/users/author/following{/other_user}"), + GistsURL: String("https://api.github.com/users/author/gists{/gist_id}"), + StarredURL: String("https://api.github.com/users/author/starred{/owner}{/repo}"), + SubscriptionsURL: String("https://api.github.com/users/author/subscriptions"), + OrganizationsURL: String("https://api.github.com/users/author/orgs"), + ReposURL: String("https://api.github.com/users/author/repos"), + EventsURL: String("https://api.github.com/users/author/events{/privacy}"), + ReceivedEventsURL: String("https://api.github.com/users/author/received_events"), + Type: String("User"), + SiteAdmin: Bool(false), + }, + Body: String("test"), + BodyHTML: String("

test

"), + BodyVersion: String("version"), + CommentsCount: Int(1), + CommentsURL: String("https://api.github.com/teams/2/discussions/3/comments"), + CreatedAt: &Timestamp{time.Date(2018, time.January, 1, 0, 0, 0, 0, time.UTC)}, + LastEditedAt: nil, + HTMLURL: String("https://github.com/orgs/1/teams/2/discussions/3"), + NodeID: String("node"), + Number: Int(3), + Pinned: Bool(false), + Private: Bool(false), + TeamURL: String("https://api.github.com/teams/2"), + Title: String("test"), + UpdatedAt: &Timestamp{time.Date(2018, time.January, 1, 0, 0, 0, 0, time.UTC)}, + URL: String("https://api.github.com/teams/2/discussions/3"), + }, + } + if !reflect.DeepEqual(discussions, want) { + t.Errorf("Teams.ListDiscussionsByName returned %+v, want %+v", discussions, want) + } +} + +func TestTeamsService_GetDiscussionByID(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/organizations/1/team/2/discussions/3", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{"number":3}`) + }) + + discussion, _, err := client.Teams.GetDiscussionByID(context.Background(), 1, 2, 3) + if err != nil { + t.Errorf("Teams.GetDiscussionByID returned error: %v", err) + } + + want := &TeamDiscussion{Number: Int(3)} + if !reflect.DeepEqual(discussion, want) { + t.Errorf("Teams.GetDiscussionByID returned %+v, want %+v", discussion, want) + } +} + +func TestTeamsService_GetDiscussionByName(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/teams/s/discussions/3", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"number":3}`) }) - discussion, _, err := client.Teams.GetDiscussion(context.Background(), 2, 3) + discussion, _, err := client.Teams.GetDiscussionByName(context.Background(), "o", "s", 3) if err != nil { - t.Errorf("Teams.GetDiscussion returned error: %v", err) + t.Errorf("Teams.GetDiscussionByName returned error: %v", err) } want := &TeamDiscussion{Number: Int(3)} if !reflect.DeepEqual(discussion, want) { - t.Errorf("Teams.GetDiscussion returned %+v, want %+v", discussion, want) + t.Errorf("Teams.GetDiscussionByName returned %+v, want %+v", discussion, want) } } -func TestTeamsService_CreateDiscussion(t *testing.T) { +func TestTeamsService_CreateDiscussionByID(t *testing.T) { client, mux, _, teardown := setup() defer teardown() input := TeamDiscussion{Title: String("c_t"), Body: String("c_b")} - mux.HandleFunc("/teams/2/discussions", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/organizations/1/team/2/discussions", func(w http.ResponseWriter, r *http.Request) { v := new(TeamDiscussion) json.NewDecoder(r.Body).Decode(v) @@ -152,24 +271,53 @@ func TestTeamsService_CreateDiscussion(t *testing.T) { fmt.Fprint(w, `{"number":3}`) }) - comment, _, err := client.Teams.CreateDiscussion(context.Background(), 2, input) + comment, _, err := client.Teams.CreateDiscussionByID(context.Background(), 1, 2, input) if err != nil { - t.Errorf("Teams.CreateDiscussion returned error: %v", err) + t.Errorf("Teams.CreateDiscussionByID returned error: %v", err) } want := &TeamDiscussion{Number: Int(3)} if !reflect.DeepEqual(comment, want) { - t.Errorf("Teams.CreateDiscussion returned %+v, want %+v", comment, want) + t.Errorf("Teams.CreateDiscussionByID returned %+v, want %+v", comment, want) } } -func TestTeamsService_EditDiscussion(t *testing.T) { +func TestTeamsService_CreateDiscussionByName(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + input := TeamDiscussion{Title: String("c_t"), Body: String("c_b")} + + mux.HandleFunc("/orgs/o/teams/s/discussions", func(w http.ResponseWriter, r *http.Request) { + v := new(TeamDiscussion) + json.NewDecoder(r.Body).Decode(v) + + testMethod(t, r, "POST") + if !reflect.DeepEqual(v, &input) { + t.Errorf("Request body = %+v, want %+v", v, input) + } + + fmt.Fprint(w, `{"number":3}`) + }) + + comment, _, err := client.Teams.CreateDiscussionByName(context.Background(), "o", "s", input) + if err != nil { + t.Errorf("Teams.CreateDiscussionByName returned error: %v", err) + } + + want := &TeamDiscussion{Number: Int(3)} + if !reflect.DeepEqual(comment, want) { + t.Errorf("Teams.CreateDiscussionByName returned %+v, want %+v", comment, want) + } +} + +func TestTeamsService_EditDiscussionByID(t *testing.T) { client, mux, _, teardown := setup() defer teardown() input := TeamDiscussion{Title: String("e_t"), Body: String("e_b")} - mux.HandleFunc("/teams/2/discussions/3", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/organizations/1/team/2/discussions/3", func(w http.ResponseWriter, r *http.Request) { v := new(TeamDiscussion) json.NewDecoder(r.Body).Decode(v) @@ -181,7 +329,36 @@ func TestTeamsService_EditDiscussion(t *testing.T) { fmt.Fprint(w, `{"number":3}`) }) - comment, _, err := client.Teams.EditDiscussion(context.Background(), 2, 3, input) + comment, _, err := client.Teams.EditDiscussionByID(context.Background(), 1, 2, 3, input) + if err != nil { + t.Errorf("Teams.EditDiscussionByID returned error: %v", err) + } + + want := &TeamDiscussion{Number: Int(3)} + if !reflect.DeepEqual(comment, want) { + t.Errorf("Teams.EditDiscussionByID returned %+v, want %+v", comment, want) + } +} + +func TestTeamsService_EditDiscussionByName(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + input := TeamDiscussion{Title: String("e_t"), Body: String("e_b")} + + mux.HandleFunc("/orgs/o/teams/s/discussions/3", func(w http.ResponseWriter, r *http.Request) { + v := new(TeamDiscussion) + json.NewDecoder(r.Body).Decode(v) + + testMethod(t, r, "PATCH") + if !reflect.DeepEqual(v, &input) { + t.Errorf("Request body = %+v, want %+v", v, input) + } + + fmt.Fprint(w, `{"number":3}`) + }) + + comment, _, err := client.Teams.EditDiscussionByName(context.Background(), "o", "s", 3, input) if err != nil { t.Errorf("Teams.EditDiscussion returned error: %v", err) } @@ -192,16 +369,30 @@ func TestTeamsService_EditDiscussion(t *testing.T) { } } -func TestTeamsService_DeleteDiscussion(t *testing.T) { +func TestTeamsService_DeleteDiscussionByID(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/organizations/1/team/2/discussions/3", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + }) + + _, err := client.Teams.DeleteDiscussionByID(context.Background(), 1, 2, 3) + if err != nil { + t.Errorf("Teams.DeleteDiscussionByID returned error: %v", err) + } +} + +func TestTeamsService_DeleteDiscussionByName(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/teams/2/discussions/3", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/o/teams/s/discussions/3", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") }) - _, err := client.Teams.DeleteDiscussion(context.Background(), 2, 3) + _, err := client.Teams.DeleteDiscussionByName(context.Background(), "o", "s", 3) if err != nil { - t.Errorf("Teams.DeleteDiscussion returned error: %v", err) + t.Errorf("Teams.DeleteDiscussionByName returned error: %v", err) } } From 591d90d9a273220bd69724435e665a634e144c68 Mon Sep 17 00:00:00 2001 From: Alex Orr Date: Sat, 25 Jan 2020 12:06:00 -0800 Subject: [PATCH 07/10] style: linting and formatting fixes --- github/teams_discussion_comments.go | 4 ++-- github/teams_members.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/github/teams_discussion_comments.go b/github/teams_discussion_comments.go index 97376e8cd3a..9bc17cf6353 100644 --- a/github/teams_discussion_comments.go +++ b/github/teams_discussion_comments.go @@ -91,7 +91,7 @@ func (s *TeamsService) ListCommentsByName(ctx context.Context, org, slug string, return comments, resp, nil } -// GetComment gets a specific comment on a team discussion +// GetCommentByID gets a specific comment on a team discussion // given a team ID and organization ID. // Authenticated user must grant read:discussion scope. // @@ -112,7 +112,7 @@ func (s *TeamsService) GetCommentByID(ctx context.Context, orgID, teamID int64, return discussionComment, resp, nil } -// GetComment gets a specific comment on a team discussion +// GetCommentByName gets a specific comment on a team discussion // given a team slug and organization name. // Authenticated user must grant read:discussion scope. // diff --git a/github/teams_members.go b/github/teams_members.go index e35177b0873..5ab4dc530b7 100644 --- a/github/teams_members.go +++ b/github/teams_members.go @@ -88,7 +88,7 @@ func (s *TeamsService) IsTeamMember(ctx context.Context, team int64, user string return member, resp, err } -// GetTeamMembershipByID returns the membership status for a user in a team +// GetTeamMembershipByID returns the membership status for a user in a team // given the team ID and organization ID. // // GitHub API docs: https://developer.github.com/v3/teams/members/#get-team-membership @@ -212,7 +212,7 @@ func (s *TeamsService) AddTeamMembershipByName(ctx context.Context, org, slug, u return t, resp, nil } -// RemoveTeamMembershipByID removes a user from a team given the team ID and +// RemoveTeamMembershipByID removes a user from a team given the team ID and // organization ID. // // GitHub API docs: https://developer.github.com/v3/teams/members/#remove-team-membership From 03ec6948334c09f7989081a020bf10b4a9e3572e Mon Sep 17 00:00:00 2001 From: Alex Orr Date: Sat, 25 Jan 2020 12:06:46 -0800 Subject: [PATCH 08/10] update teams synchronization endpoints and house them in separate file --- github/teams.go | 107 ++----------- github/teams_synchronization.go | 128 +++++++++++++++ github/teams_synchronization_test.go | 230 +++++++++++++++++++++++++++ github/teams_test.go | 124 --------------- 4 files changed, 374 insertions(+), 215 deletions(-) create mode 100644 github/teams_synchronization.go create mode 100644 github/teams_synchronization_test.go diff --git a/github/teams.go b/github/teams.go index 7c1b9afb3ce..c8e5ceeb1fc 100644 --- a/github/teams.go +++ b/github/teams.go @@ -476,7 +476,7 @@ type TeamAddTeamRepoOptions struct { Permission string `json:"permission,omitempty"` } -// AddTeamRepoByID adds a repository to be managed by the specified team given the team ID. +// AddTeamRepoByID adds a repository to be managed by the specified team given the team ID. // The specified repository must be owned by the organization to which the team // belongs, or a direct fork of a repository owned by the organization. // @@ -491,7 +491,7 @@ func (s *TeamsService) AddTeamRepoByID(ctx context.Context, orgID, teamID int64, return s.client.Do(ctx, req, nil) } -// AddTeamRepoByName adds a repository to be managed by the specified team given the team name. +// AddTeamRepoByName adds a repository to be managed by the specified team given the team name. // The specified repository must be owned by the organization to which the team // belongs, or a direct fork of a repository owned by the organization. // @@ -507,7 +507,7 @@ func (s *TeamsService) AddTeamRepoByName(ctx context.Context, org, slug, owner, } // RemoveTeamRepoByID removes a repository from being managed by the specified -// team given the team ID. Note that this does not delete the repository, it +// team given the team ID. Note that this does not delete the repository, it // just removes it from the team. // // GitHub API docs: https://developer.github.com/v3/teams/#remove-team-repo @@ -522,7 +522,7 @@ func (s *TeamsService) RemoveTeamRepoByID(ctx context.Context, orgID, teamID int } // RemoveTeamRepoByName removes a repository from being managed by the specified -// team given the team Name. Note that this does not delete the repository, it +// team given the team Name. Note that this does not delete the repository, it // just removes it from the team. // // GitHub API docs: https://developer.github.com/v3/teams/#remove-team-repo @@ -667,8 +667,8 @@ type TeamProjectOptions struct { Permission *string `json:"permission,omitempty"` } -// AddTeamProjectByID adds an organization project to a team given the team ID. -// To add a project to a team or update the team's permission on a project, the +// AddTeamProjectByID adds an organization project to a team given the team ID. +// To add a project to a team or update the team's permission on a project, the // authenticated user must have admin permissions for the project. // // GitHub API docs: https://developer.github.com/v3/teams/#add-or-update-team-project @@ -686,8 +686,8 @@ func (s *TeamsService) AddTeamProjectByID(ctx context.Context, orgID, teamID, pr return s.client.Do(ctx, req, nil) } -// AddTeamProjectByName adds an organization project to a team given the team name. -// To add a project to a team or update the team's permission on a project, the +// AddTeamProjectByName adds an organization project to a team given the team name. +// To add a project to a team or update the team's permission on a project, the // authenticated user must have admin permissions for the project. // // GitHub API docs: https://developer.github.com/v3/teams/#add-or-update-team-project @@ -705,10 +705,10 @@ func (s *TeamsService) AddTeamProjectByName(ctx context.Context, org, slug strin return s.client.Do(ctx, req, nil) } -// RemoveTeamProjectByID removes an organization project from a team given team ID. -// An organization owner or a team maintainer can remove any project from the team. -// To remove a project from a team as an organization member, the authenticated user -// must have "read" access to both the team and project, or "admin" access to the team +// RemoveTeamProjectByID removes an organization project from a team given team ID. +// An organization owner or a team maintainer can remove any project from the team. +// To remove a project from a team as an organization member, the authenticated user +// must have "read" access to both the team and project, or "admin" access to the team // or project. // Note: This endpoint removes the project from the team, but does not delete it. // @@ -727,10 +727,10 @@ func (s *TeamsService) RemoveTeamProjectByID(ctx context.Context, orgID, teamID, return s.client.Do(ctx, req, nil) } -// RemoveTeamProjectByName removes an organization project from a team given team name. -// An organization owner or a team maintainer can remove any project from the team. -// To remove a project from a team as an organization member, the authenticated user -// must have "read" access to both the team and project, or "admin" access to the team +// RemoveTeamProjectByName removes an organization project from a team given team name. +// An organization owner or a team maintainer can remove any project from the team. +// To remove a project from a team as an organization member, the authenticated user +// must have "read" access to both the team and project, or "admin" access to the team // or project. // Note: This endpoint removes the project from the team, but does not delete it. // @@ -748,78 +748,3 @@ func (s *TeamsService) RemoveTeamProjectByName(ctx context.Context, org, slug st return s.client.Do(ctx, req, nil) } - -// IDPGroupList represents a list of external identity provider (IDP) groups. -type IDPGroupList struct { - Groups []*IDPGroup `json:"groups"` -} - -// IDPGroup represents an external identity provider (IDP) group. -type IDPGroup struct { - GroupID *string `json:"group_id,omitempty"` - GroupName *string `json:"group_name,omitempty"` - GroupDescription *string `json:"group_description,omitempty"` -} - -// ListIDPGroupsInOrganization lists IDP groups available in an organization. -// -// GitHub API docs: https://developer.github.com/v3/teams/team_sync/#list-idp-groups-in-an-organization -func (s *TeamsService) ListIDPGroupsInOrganization(ctx context.Context, org string, opt *ListCursorOptions) (*IDPGroupList, *Response, error) { - u := fmt.Sprintf("orgs/%v/team-sync/groups", org) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - groups := new(IDPGroupList) - resp, err := s.client.Do(ctx, req, groups) - if err != nil { - return nil, resp, err - } - return groups, resp, nil -} - -// ListIDPGroupsForTeam lists IDP groups connected to a team on GitHub. -// -// GitHub API docs: https://developer.github.com/v3/teams/team_sync/#list-idp-groups-for-a-team -func (s *TeamsService) ListIDPGroupsForTeam(ctx context.Context, org, slug string) (*IDPGroupList, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/team-sync/group-mappings", org, slug) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - groups := new(IDPGroupList) - resp, err := s.client.Do(ctx, req, groups) - if err != nil { - return nil, resp, err - } - return groups, resp, err -} - -// CreateOrUpdateIDPGroupConnections creates, updates, or removes a connection between a team -// and an IDP group. -// -// GitHub API docs: https://developer.github.com/v3/teams/team_sync/#create-or-update-idp-group-connections -func (s *TeamsService) CreateOrUpdateIDPGroupConnections(ctx context.Context, org, slug string, opt IDPGroupList) (*IDPGroupList, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/team-sync/group-mappings", org, slug) - - req, err := s.client.NewRequest("PATCH", u, opt) - if err != nil { - return nil, nil, err - } - - groups := new(IDPGroupList) - resp, err := s.client.Do(ctx, req, groups) - if err != nil { - return nil, resp, err - } - - return groups, resp, nil -} diff --git a/github/teams_synchronization.go b/github/teams_synchronization.go new file mode 100644 index 00000000000..1e275a33aba --- /dev/null +++ b/github/teams_synchronization.go @@ -0,0 +1,128 @@ +// Copyright 2018 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import ( + "context" + "fmt" +) + +// IDPGroupList represents a list of external identity provider (IDP) groups. +type IDPGroupList struct { + Groups []*IDPGroup `json:"groups"` +} + +// IDPGroup represents an external identity provider (IDP) group. +type IDPGroup struct { + GroupID *string `json:"group_id,omitempty"` + GroupName *string `json:"group_name,omitempty"` + GroupDescription *string `json:"group_description,omitempty"` +} + +// ListIDPGroupsInOrganization lists IDP groups available in an organization. +// +// GitHub API docs: https://developer.github.com/v3/teams/team_sync/#list-idp-groups-in-an-organization +func (s *TeamsService) ListIDPGroupsInOrganization(ctx context.Context, org string, opt *ListOptions) (*IDPGroupList, *Response, error) { + u := fmt.Sprintf("orgs/%v/team-sync/groups", org) + u, err := addOptions(u, opt) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + groups := new(IDPGroupList) + resp, err := s.client.Do(ctx, req, groups) + if err != nil { + return nil, resp, err + } + return groups, resp, nil +} + +// ListIDPGroupsForTeamByID lists IDP groups connected to a team on GitHub +// given a team ID and organization ID. +// +// GitHub API docs: https://developer.github.com/v3/teams/team_sync/#list-idp-groups-for-a-team +func (s *TeamsService) ListIDPGroupsForTeamByID(ctx context.Context, orgID, teamID int64) (*IDPGroupList, *Response, error) { + u := fmt.Sprintf("organizations/%v/team/%v/team-sync/group-mappings", orgID, teamID) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + groups := new(IDPGroupList) + resp, err := s.client.Do(ctx, req, groups) + if err != nil { + return nil, resp, err + } + return groups, resp, err +} + +// ListIDPGroupsForTeamByName lists IDP groups connected to a team on GitHub +// given a team slug and orgnization name. +// +// GitHub API docs: https://developer.github.com/v3/teams/team_sync/#list-idp-groups-for-a-team +func (s *TeamsService) ListIDPGroupsForTeamByName(ctx context.Context, org, slug string) (*IDPGroupList, *Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/team-sync/group-mappings", org, slug) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + groups := new(IDPGroupList) + resp, err := s.client.Do(ctx, req, groups) + if err != nil { + return nil, resp, err + } + return groups, resp, err +} + +// CreateOrUpdateIDPGroupConnectionsByID creates, updates, or removes a connection between a team +// and an IDP group. Identifies organization and team by ID. +// +// GitHub API docs: https://developer.github.com/v3/teams/team_sync/#create-or-update-idp-group-connections +func (s *TeamsService) CreateOrUpdateIDPGroupConnectionsByID(ctx context.Context, orgID, teamID int64, opt IDPGroupList) (*IDPGroupList, *Response, error) { + u := fmt.Sprintf("organizations/%v/team/%v/team-sync/group-mappings", orgID, teamID) + + req, err := s.client.NewRequest("PATCH", u, opt) + if err != nil { + return nil, nil, err + } + + groups := new(IDPGroupList) + resp, err := s.client.Do(ctx, req, groups) + if err != nil { + return nil, resp, err + } + + return groups, resp, nil +} + +// CreateOrUpdateIDPGroupConnectionsByName creates, updates, or removes a connection between a team +// and an IDP group. Identifies organization by name and team by slug. +// +// GitHub API docs: https://developer.github.com/v3/teams/team_sync/#create-or-update-idp-group-connections +func (s *TeamsService) CreateOrUpdateIDPGroupConnectionsByName(ctx context.Context, org, slug string, opt IDPGroupList) (*IDPGroupList, *Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/team-sync/group-mappings", org, slug) + + req, err := s.client.NewRequest("PATCH", u, opt) + if err != nil { + return nil, nil, err + } + + groups := new(IDPGroupList) + resp, err := s.client.Do(ctx, req, groups) + if err != nil { + return nil, resp, err + } + + return groups, resp, nil +} diff --git a/github/teams_synchronization_test.go b/github/teams_synchronization_test.go new file mode 100644 index 00000000000..c604b157204 --- /dev/null +++ b/github/teams_synchronization_test.go @@ -0,0 +1,230 @@ +// Copyright 2018 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import ( + "context" + "fmt" + "net/http" + "reflect" + "testing" +) + +func TestTeamsService_ListIDPGroupsInOrganization(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/team-sync/groups", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testFormValues(t, r, values{ + "page": "2", + }) + fmt.Fprint(w, `{"groups": [{"group_id": "1", "group_name": "n", "group_description": "d"}]}`) + }) + + opt := &ListOptions{Page: 2} + groups, _, err := client.Teams.ListIDPGroupsInOrganization(context.Background(), "o", opt) + if err != nil { + t.Errorf("Teams.ListIDPGroupsInOrganization returned error: %v", err) + } + + want := &IDPGroupList{ + Groups: []*IDPGroup{ + { + GroupID: String("1"), + GroupName: String("n"), + GroupDescription: String("d"), + }, + }, + } + if !reflect.DeepEqual(groups, want) { + t.Errorf("Teams.ListIDPGroupsInOrganization returned %+v. want %+v", groups, want) + } +} + +func TestTeamsService_ListIDPGroupsForTeamByID(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/organizations/1/team/1/team-sync/group-mappings", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{"groups": [{"group_id": "1", "group_name": "n", "group_description": "d"}]}`) + }) + + groups, _, err := client.Teams.ListIDPGroupsForTeamByID(context.Background(), 1, 1) + if err != nil { + t.Errorf("Teams.ListIDPGroupsForTeamByID returned error: %v", err) + } + + want := &IDPGroupList{ + Groups: []*IDPGroup{ + { + GroupID: String("1"), + GroupName: String("n"), + GroupDescription: String("d"), + }, + }, + } + if !reflect.DeepEqual(groups, want) { + t.Errorf("Teams.ListIDPGroupsForTeamByID returned %+v. want %+v", groups, want) + } +} + +func TestTeamsService_ListIDPGroupsForTeamByName(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/teams/s/team-sync/group-mappings", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{"groups": [{"group_id": "1", "group_name": "n", "group_description": "d"}]}`) + }) + + groups, _, err := client.Teams.ListIDPGroupsForTeamByName(context.Background(), "o", "s") + if err != nil { + t.Errorf("Teams.ListIDPGroupsForTeamByName returned error: %v", err) + } + + want := &IDPGroupList{ + Groups: []*IDPGroup{ + { + GroupID: String("1"), + GroupName: String("n"), + GroupDescription: String("d"), + }, + }, + } + if !reflect.DeepEqual(groups, want) { + t.Errorf("Teams.ListIDPGroupsForTeamByName returned %+v. want %+v", groups, want) + } +} + +func TestTeamsService_CreateOrUpdateIDPGroupConnectionsByID(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/organizations/1/team/1/team-sync/group-mappings", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PATCH") + fmt.Fprint(w, `{"groups": [{"group_id": "1", "group_name": "n", "group_description": "d"}]}`) + }) + + input := IDPGroupList{ + Groups: []*IDPGroup{ + { + GroupID: String("1"), + GroupName: String("n"), + GroupDescription: String("d"), + }, + }, + } + + groups, _, err := client.Teams.CreateOrUpdateIDPGroupConnectionsByID(context.Background(), 1, 1, input) + if err != nil { + t.Errorf("Teams.CreateOrUpdateIDPGroupConnectionsByID returned error: %v", err) + } + + want := &IDPGroupList{ + Groups: []*IDPGroup{ + { + GroupID: String("1"), + GroupName: String("n"), + GroupDescription: String("d"), + }, + }, + } + if !reflect.DeepEqual(groups, want) { + t.Errorf("Teams.CreateOrUpdateIDPGroupConnectionsByID returned %+v. want %+v", groups, want) + } +} + +func TestTeamsService_CreateOrUpdateIDPGroupConnectionsByName(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/teams/s/team-sync/group-mappings", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PATCH") + fmt.Fprint(w, `{"groups": [{"group_id": "1", "group_name": "n", "group_description": "d"}]}`) + }) + + input := IDPGroupList{ + Groups: []*IDPGroup{ + { + GroupID: String("1"), + GroupName: String("n"), + GroupDescription: String("d"), + }, + }, + } + + groups, _, err := client.Teams.CreateOrUpdateIDPGroupConnectionsByName(context.Background(), "o", "s", input) + if err != nil { + t.Errorf("Teams.CreateOrUpdateIDPGroupConnectionsByName returned error: %v", err) + } + + want := &IDPGroupList{ + Groups: []*IDPGroup{ + { + GroupID: String("1"), + GroupName: String("n"), + GroupDescription: String("d"), + }, + }, + } + if !reflect.DeepEqual(groups, want) { + t.Errorf("Teams.CreateOrUpdateIDPGroupConnectionsByName returned %+v. want %+v", groups, want) + } +} + +func TestTeamsService_CreateOrUpdateIDPGroupConnectionsByID_empty(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/organizations/1/team/1/team-sync/group-mappings", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PATCH") + fmt.Fprint(w, `{"groups": []}`) + }) + + input := IDPGroupList{ + Groups: []*IDPGroup{}, + } + + groups, _, err := client.Teams.CreateOrUpdateIDPGroupConnectionsByID(context.Background(), 1, 1, input) + if err != nil { + t.Errorf("Teams.CreateOrUpdateIDPGroupConnectionsByID returned error: %v", err) + } + + want := &IDPGroupList{ + Groups: []*IDPGroup{}, + } + if !reflect.DeepEqual(groups, want) { + t.Errorf("Teams.CreateOrUpdateIDPGroupConnectionsByID returned %+v. want %+v", groups, want) + } +} + +func TestTeamsService_CreateOrUpdateIDPGroupConnectionsByName_empty(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/teams/s/team-sync/group-mappings", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PATCH") + fmt.Fprint(w, `{"groups": []}`) + }) + + input := IDPGroupList{ + Groups: []*IDPGroup{}, + } + + groups, _, err := client.Teams.CreateOrUpdateIDPGroupConnectionsByName(context.Background(), "o", "s", input) + if err != nil { + t.Errorf("Teams.CreateOrUpdateIDPGroupConnectionsByName returned error: %v", err) + } + + want := &IDPGroupList{ + Groups: []*IDPGroup{}, + } + if !reflect.DeepEqual(groups, want) { + t.Errorf("Teams.CreateOrUpdateIDPGroupConnectionsByName returned %+v. want %+v", groups, want) + } +} diff --git a/github/teams_test.go b/github/teams_test.go index 76231e03d79..8817cc603c6 100644 --- a/github/teams_test.go +++ b/github/teams_test.go @@ -956,127 +956,3 @@ func TestTeamsService_RemoveTeamProjectByName(t *testing.T) { t.Errorf("Teams.RemoveTeamProjectByName returned error: %v", err) } } - -func TestTeamsService_ListIDPGroupsInOrganization(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/orgs/o/team-sync/groups", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - testFormValues(t, r, values{ - "page": "url-encoded-next-page-token", - }) - fmt.Fprint(w, `{"groups": [{"group_id": "1", "group_name": "n", "group_description": "d"}]}`) - }) - - opt := &ListCursorOptions{Page: "url-encoded-next-page-token"} - groups, _, err := client.Teams.ListIDPGroupsInOrganization(context.Background(), "o", opt) - if err != nil { - t.Errorf("Teams.ListIDPGroupsInOrganization returned error: %v", err) - } - - want := &IDPGroupList{ - Groups: []*IDPGroup{ - { - GroupID: String("1"), - GroupName: String("n"), - GroupDescription: String("d"), - }, - }, - } - if !reflect.DeepEqual(groups, want) { - t.Errorf("Teams.ListIDPGroupsInOrganization returned %+v. want %+v", groups, want) - } -} - -func TestTeamsService_ListIDPGroupsForTeam(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/orgs/o/teams/s/team-sync/group-mappings", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - fmt.Fprint(w, `{"groups": [{"group_id": "1", "group_name": "n", "group_description": "d"}]}`) - }) - - groups, _, err := client.Teams.ListIDPGroupsForTeam(context.Background(), "o", "s") - if err != nil { - t.Errorf("Teams.ListIDPGroupsForTeam returned error: %v", err) - } - - want := &IDPGroupList{ - Groups: []*IDPGroup{ - { - GroupID: String("1"), - GroupName: String("n"), - GroupDescription: String("d"), - }, - }, - } - if !reflect.DeepEqual(groups, want) { - t.Errorf("Teams.ListIDPGroupsForTeam returned %+v. want %+v", groups, want) - } -} - -func TestTeamsService_CreateOrUpdateIDPGroupConnections(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/orgs/o/teams/s/team-sync/group-mappings", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "PATCH") - fmt.Fprint(w, `{"groups": [{"group_id": "1", "group_name": "n", "group_description": "d"}]}`) - }) - - input := IDPGroupList{ - Groups: []*IDPGroup{ - { - GroupID: String("1"), - GroupName: String("n"), - GroupDescription: String("d"), - }, - }, - } - - groups, _, err := client.Teams.CreateOrUpdateIDPGroupConnections(context.Background(), "o", "s", input) - if err != nil { - t.Errorf("Teams.CreateOrUpdateIDPGroupConnections returned error: %v", err) - } - - want := &IDPGroupList{ - Groups: []*IDPGroup{ - { - GroupID: String("1"), - GroupName: String("n"), - GroupDescription: String("d"), - }, - }, - } - if !reflect.DeepEqual(groups, want) { - t.Errorf("Teams.CreateOrUpdateIDPGroupConnections returned %+v. want %+v", groups, want) - } -} - -func TestTeamsService_CreateOrUpdateIDPGroupConnections_empty(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/orgs/o/teams/s/team-sync/group-mappings", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "PATCH") - fmt.Fprint(w, `{"groups": []}`) - }) - - input := IDPGroupList{ - Groups: []*IDPGroup{}, - } - - groups, _, err := client.Teams.CreateOrUpdateIDPGroupConnections(context.Background(), "o", "s", input) - if err != nil { - t.Errorf("Teams.CreateOrUpdateIDPGroupConnections returned error: %v", err) - } - - want := &IDPGroupList{ - Groups: []*IDPGroup{}, - } - if !reflect.DeepEqual(groups, want) { - t.Errorf("Teams.CreateOrUpdateIDPGroupConnections returned %+v. want %+v", groups, want) - } -} From 60a41cf33f4e1bed91fb1bf357e8905aed317433 Mon Sep 17 00:00:00 2001 From: Alex Orr Date: Mon, 27 Jan 2020 20:24:41 -0800 Subject: [PATCH 09/10] fix: remove deprecated functions --- github/teams.go | 19 ----------- github/teams_members.go | 18 ---------- github/teams_members_test.go | 64 ------------------------------------ github/teams_test.go | 43 ------------------------ 4 files changed, 144 deletions(-) diff --git a/github/teams.go b/github/teams.go index c8e5ceeb1fc..1e73f459011 100644 --- a/github/teams.go +++ b/github/teams.go @@ -97,25 +97,6 @@ func (s *TeamsService) ListTeams(ctx context.Context, org string, opt *ListOptio return teams, resp, nil } -// GetTeam fetches a team by ID. -// -// GitHub API docs: https://developer.github.com/v3/teams/#get-team -func (s *TeamsService) GetTeam(ctx context.Context, team int64) (*Team, *Response, error) { - u := fmt.Sprintf("teams/%v", team) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - t := new(Team) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, nil -} - // GetTeamByID fetches a team, given a specified organization ID, by ID. // // Github API docs: https://developer.github.com/v3/teams/#get-team-by-name diff --git a/github/teams_members.go b/github/teams_members.go index 5ab4dc530b7..031130a6e4a 100644 --- a/github/teams_members.go +++ b/github/teams_members.go @@ -70,24 +70,6 @@ func (s *TeamsService) ListTeamMembersByName(ctx context.Context, org, slug stri return members, resp, nil } -// IsTeamMember checks if a user is a member of the specified team. -// -// GitHub API docs: https://developer.github.com/v3/teams/members/#get-team-member -// -// Deprecated: This API has been marked as deprecated in the Github API docs, -// TeamsService.GetTeamMembership method should be used instead. -func (s *TeamsService) IsTeamMember(ctx context.Context, team int64, user string) (bool, *Response, error) { - u := fmt.Sprintf("teams/%v/members/%v", team, user) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return false, nil, err - } - - resp, err := s.client.Do(ctx, req, nil) - member, err := parseBoolResponse(err) - return member, resp, err -} - // GetTeamMembershipByID returns the membership status for a user in a team // given the team ID and organization ID. // diff --git a/github/teams_members_test.go b/github/teams_members_test.go index c9b7f996780..6f50000621e 100644 --- a/github/teams_members_test.go +++ b/github/teams_members_test.go @@ -59,70 +59,6 @@ func TestTeamsService__ListTeamMembersByName(t *testing.T) { } } -func TestTeamsService__IsTeamMember_true(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/teams/1/members/u", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - }) - - member, _, err := client.Teams.IsTeamMember(context.Background(), 1, "u") - if err != nil { - t.Errorf("Teams.IsTeamMember returned error: %v", err) - } - if want := true; member != want { - t.Errorf("Teams.IsTeamMember returned %+v, want %+v", member, want) - } -} - -// ensure that a 404 response is interpreted as "false" and not an error -func TestTeamsService__IsTeamMember_false(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/teams/1/members/u", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - w.WriteHeader(http.StatusNotFound) - }) - - member, _, err := client.Teams.IsTeamMember(context.Background(), 1, "u") - if err != nil { - t.Errorf("Teams.IsTeamMember returned error: %+v", err) - } - if want := false; member != want { - t.Errorf("Teams.IsTeamMember returned %+v, want %+v", member, want) - } -} - -// ensure that a 400 response is interpreted as an actual error, and not simply -// as "false" like the above case of a 404 -func TestTeamsService__IsTeamMember_error(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/teams/1/members/u", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - http.Error(w, "BadRequest", http.StatusBadRequest) - }) - - member, _, err := client.Teams.IsTeamMember(context.Background(), 1, "u") - if err == nil { - t.Errorf("Expected HTTP 400 response") - } - if want := false; member != want { - t.Errorf("Teams.IsTeamMember returned %+v, want %+v", member, want) - } -} - -func TestTeamsService__IsTeamMember_invalidUser(t *testing.T) { - client, _, _, teardown := setup() - defer teardown() - - _, _, err := client.Teams.IsTeamMember(context.Background(), 1, "%") - testURLParseError(t, err) -} - func TestTeamsService__GetTeamMembershipByID(t *testing.T) { client, mux, _, teardown := setup() defer teardown() diff --git a/github/teams_test.go b/github/teams_test.go index 8817cc603c6..56694a193f3 100644 --- a/github/teams_test.go +++ b/github/teams_test.go @@ -47,49 +47,6 @@ func TestTeamsService_ListTeams_invalidOrg(t *testing.T) { testURLParseError(t, err) } -func TestTeamsService_GetTeam(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/teams/1", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - fmt.Fprint(w, `{"id":1, "name":"n", "description": "d", "url":"u", "slug": "s", "permission":"p", "ldap_dn":"cn=n,ou=groups,dc=example,dc=com", "parent":null}`) - }) - - team, _, err := client.Teams.GetTeam(context.Background(), 1) - if err != nil { - t.Errorf("Teams.GetTeam returned error: %v", err) - } - - want := &Team{ID: Int64(1), Name: String("n"), Description: String("d"), URL: String("u"), Slug: String("s"), Permission: String("p"), LDAPDN: String("cn=n,ou=groups,dc=example,dc=com")} - if !reflect.DeepEqual(team, want) { - t.Errorf("Teams.GetTeam returned %+v, want %+v", team, want) - } -} - -func TestTeamsService_GetTeam_nestedTeams(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/teams/1", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - fmt.Fprint(w, `{"id":1, "name":"n", "description": "d", "url":"u", "slug": "s", "permission":"p", - "parent": {"id":2, "name":"n", "description": "d", "parent": null}}`) - }) - - team, _, err := client.Teams.GetTeam(context.Background(), 1) - if err != nil { - t.Errorf("Teams.GetTeam returned error: %v", err) - } - - want := &Team{ID: Int64(1), Name: String("n"), Description: String("d"), URL: String("u"), Slug: String("s"), Permission: String("p"), - Parent: &Team{ID: Int64(2), Name: String("n"), Description: String("d")}, - } - if !reflect.DeepEqual(team, want) { - t.Errorf("Teams.GetTeam returned %+v, want %+v", team, want) - } -} - func TestTeamsService_GetTeamByID(t *testing.T) { client, mux, _, teardown := setup() defer teardown() From 3cda28d9a5eacf3beb9064f77896de4f420e6b48 Mon Sep 17 00:00:00 2001 From: Alex Orr Date: Tue, 28 Jan 2020 20:02:00 -0800 Subject: [PATCH 10/10] fix: revert changes to team discussion, team discussion comments, team members and team synchronization endpoints, and make fixes per PR review --- github/teams.go | 127 +++++++--- github/teams_discussion_comments.go | 140 ++--------- github/teams_discussion_comments_test.go | 230 ++---------------- github/teams_discussions.go | 140 ++--------- github/teams_discussions_test.go | 235 ++----------------- github/teams_members.go | 159 +++---------- github/teams_members_test.go | 283 +++++------------------ github/teams_synchronization.go | 128 ---------- github/teams_synchronization_test.go | 230 ------------------ github/teams_test.go | 238 ++++++++++++++----- 10 files changed, 437 insertions(+), 1473 deletions(-) delete mode 100644 github/teams_synchronization.go delete mode 100644 github/teams_synchronization_test.go diff --git a/github/teams.go b/github/teams.go index 1e73f459011..4e411464eee 100644 --- a/github/teams.go +++ b/github/teams.go @@ -99,7 +99,7 @@ func (s *TeamsService) ListTeams(ctx context.Context, org string, opt *ListOptio // GetTeamByID fetches a team, given a specified organization ID, by ID. // -// Github API docs: https://developer.github.com/v3/teams/#get-team-by-name +// GitHub API docs: https://developer.github.com/v3/teams/#get-team-by-name func (s *TeamsService) GetTeamByID(ctx context.Context, orgID, teamID int64) (*Team, *Response, error) { u := fmt.Sprintf("organizations/%v/team/%v", orgID, teamID) req, err := s.client.NewRequest("GET", u, nil) @@ -239,10 +239,10 @@ func (s *TeamsService) EditTeamByID(ctx context.Context, orgID, teamID int64, te return t, resp, nil } -// EditTeamByName edits a team, given an organiation name, by name. +// EditTeamBySlug edits a team, given an organization name, by slug. // // GitHub API docs: https://developer.github.com/v3/teams/#edit-team -func (s *TeamsService) EditTeamByName(ctx context.Context, org, slug string, team NewTeam, removeParent bool) (*Team, *Response, error) { +func (s *TeamsService) EditTeamBySlug(ctx context.Context, org, slug string, team NewTeam, removeParent bool) (*Team, *Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v", org, slug) var req *http.Request @@ -279,10 +279,10 @@ func (s *TeamsService) DeleteTeamByID(ctx context.Context, orgID, teamID int64) return s.client.Do(ctx, req, nil) } -// DeleteTeamByName deletes a team reference by Name. +// DeleteTeamBySlug deletes a team reference by slug. // // GitHub API docs: https://developer.github.com/v3/teams/#delete-team -func (s *TeamsService) DeleteTeamByName(ctx context.Context, org, slug string) (*Response, error) { +func (s *TeamsService) DeleteTeamBySlug(ctx context.Context, org, slug string) (*Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v", org, slug) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { @@ -316,10 +316,10 @@ func (s *TeamsService) ListChildTeamsByParentID(ctx context.Context, orgID, team return teams, resp, nil } -// ListChildTeamsByParentName lists child teams for a parent team given parent name. +// ListChildTeamsByParentSlug lists child teams for a parent team given parent slug. // // GitHub API docs: https://developer.github.com/v3/teams/#list-child-teams -func (s *TeamsService) ListChildTeamsByParentName(ctx context.Context, org, slug string, opt *ListOptions) ([]*Team, *Response, error) { +func (s *TeamsService) ListChildTeamsByParentSlug(ctx context.Context, org, slug string, opt *ListOptions) ([]*Team, *Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v/teams", org, slug) u, err := addOptions(u, opt) if err != nil { @@ -368,10 +368,10 @@ func (s *TeamsService) ListTeamReposByID(ctx context.Context, orgID, teamID int6 return repos, resp, nil } -// ListTeamReposByName lists the repositories given a team name that the specified team has access to. +// ListTeamReposBySlug lists the repositories given a team slug that the specified team has access to. // // GitHub API docs: https://developer.github.com/v3/teams/#list-team-repos -func (s *TeamsService) ListTeamReposByName(ctx context.Context, org, slug string, opt *ListOptions) ([]*Repository, *Response, error) { +func (s *TeamsService) ListTeamReposBySlug(ctx context.Context, org, slug string, opt *ListOptions) ([]*Repository, *Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v/repos", org, slug) u, err := addOptions(u, opt) if err != nil { @@ -396,7 +396,7 @@ func (s *TeamsService) ListTeamReposByName(ctx context.Context, org, slug string return repos, resp, nil } -// IsTeamRepoByID checks if a team, given it's ID, manages the specified repository. If the +// IsTeamRepoByID checks if a team, given its ID, manages the specified repository. If the // repository is managed by team, a Repository is returned which includes the // permissions team has for that repo. // @@ -420,12 +420,12 @@ func (s *TeamsService) IsTeamRepoByID(ctx context.Context, orgID, teamID int64, return repository, resp, nil } -// IsTeamRepoByName checks if a team, given it's name, manages the specified repository. If the +// IsTeamRepoBySlug checks if a team, given its slug, manages the specified repository. If the // repository is managed by team, a Repository is returned which includes the // permissions team has for that repo. // // GitHub API docs: https://developer.github.com/v3/teams/#check-if-a-team-manages-a-repository -func (s *TeamsService) IsTeamRepoByName(ctx context.Context, org, slug, owner, repo string) (*Repository, *Response, error) { +func (s *TeamsService) IsTeamRepoBySlug(ctx context.Context, org, slug, owner, repo string) (*Repository, *Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v/repos/%v/%v", org, slug, owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -472,12 +472,12 @@ func (s *TeamsService) AddTeamRepoByID(ctx context.Context, orgID, teamID int64, return s.client.Do(ctx, req, nil) } -// AddTeamRepoByName adds a repository to be managed by the specified team given the team name. +// AddTeamRepoBySlug adds a repository to be managed by the specified team given the team slug. // The specified repository must be owned by the organization to which the team // belongs, or a direct fork of a repository owned by the organization. // // GitHub API docs: https://developer.github.com/v3/teams/#add-team-repo -func (s *TeamsService) AddTeamRepoByName(ctx context.Context, org, slug, owner, repo string, opt *TeamAddTeamRepoOptions) (*Response, error) { +func (s *TeamsService) AddTeamRepoBySlug(ctx context.Context, org, slug, owner, repo string, opt *TeamAddTeamRepoOptions) (*Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v/repos/%v/%v", org, slug, owner, repo) req, err := s.client.NewRequest("PUT", u, opt) if err != nil { @@ -502,12 +502,12 @@ func (s *TeamsService) RemoveTeamRepoByID(ctx context.Context, orgID, teamID int return s.client.Do(ctx, req, nil) } -// RemoveTeamRepoByName removes a repository from being managed by the specified -// team given the team Name. Note that this does not delete the repository, it +// RemoveTeamRepoBySlug removes a repository from being managed by the specified +// team given the team slug. Note that this does not delete the repository, it // just removes it from the team. // // GitHub API docs: https://developer.github.com/v3/teams/#remove-team-repo -func (s *TeamsService) RemoveTeamRepoByName(ctx context.Context, org, slug, owner, repo string) (*Response, error) { +func (s *TeamsService) RemoveTeamRepoBySlug(ctx context.Context, org, slug, owner, repo string) (*Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v/repos/%v/%v", org, slug, owner, repo) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { @@ -564,10 +564,10 @@ func (s *TeamsService) ListTeamProjectsByID(ctx context.Context, orgID, teamID i return projects, resp, nil } -// ListTeamProjectsByName lists the organization projects for a team given the team name. +// ListTeamProjectsBySlug lists the organization projects for a team given the team slug. // // GitHub API docs: https://developer.github.com/v3/teams/#list-team-projects -func (s *TeamsService) ListTeamProjectsByName(ctx context.Context, org, slug string) ([]*Project, *Response, error) { +func (s *TeamsService) ListTeamProjectsBySlug(ctx context.Context, org, slug string) ([]*Project, *Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v/projects", org, slug) req, err := s.client.NewRequest("GET", u, nil) @@ -588,7 +588,7 @@ func (s *TeamsService) ListTeamProjectsByName(ctx context.Context, org, slug str return projects, resp, nil } -// ReviewTeamProjectsByID checks whether a team, given it's ID, has read, write, or admin +// ReviewTeamProjectsByID checks whether a team, given its ID, has read, write, or admin // permissions for an organization project. // // GitHub API docs: https://developer.github.com/v3/teams/#review-a-team-project @@ -612,11 +612,11 @@ func (s *TeamsService) ReviewTeamProjectsByID(ctx context.Context, orgID, teamID return projects, resp, nil } -// ReviewTeamProjectsByName checks whether a team, given it's ID, has read, write, or admin +// ReviewTeamProjectsBySlug checks whether a team, given its slug, has read, write, or admin // permissions for an organization project. // // GitHub API docs: https://developer.github.com/v3/teams/#review-a-team-project -func (s *TeamsService) ReviewTeamProjectsByName(ctx context.Context, org, slug string, projectID int64) (*Project, *Response, error) { +func (s *TeamsService) ReviewTeamProjectsBySlug(ctx context.Context, org, slug string, projectID int64) (*Project, *Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v/projects/%v", org, slug, projectID) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -667,12 +667,12 @@ func (s *TeamsService) AddTeamProjectByID(ctx context.Context, orgID, teamID, pr return s.client.Do(ctx, req, nil) } -// AddTeamProjectByName adds an organization project to a team given the team name. +// AddTeamProjectBySlug adds an organization project to a team given the team slug. // To add a project to a team or update the team's permission on a project, the // authenticated user must have admin permissions for the project. // // GitHub API docs: https://developer.github.com/v3/teams/#add-or-update-team-project -func (s *TeamsService) AddTeamProjectByName(ctx context.Context, org, slug string, projectID int64, opt *TeamProjectOptions) (*Response, error) { +func (s *TeamsService) AddTeamProjectBySlug(ctx context.Context, org, slug string, projectID int64, opt *TeamProjectOptions) (*Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v/projects/%v", org, slug, projectID) req, err := s.client.NewRequest("PUT", u, opt) if err != nil { @@ -708,7 +708,7 @@ func (s *TeamsService) RemoveTeamProjectByID(ctx context.Context, orgID, teamID, return s.client.Do(ctx, req, nil) } -// RemoveTeamProjectByName removes an organization project from a team given team name. +// RemoveTeamProjectBySlug removes an organization project from a team given team slug. // An organization owner or a team maintainer can remove any project from the team. // To remove a project from a team as an organization member, the authenticated user // must have "read" access to both the team and project, or "admin" access to the team @@ -716,7 +716,7 @@ func (s *TeamsService) RemoveTeamProjectByID(ctx context.Context, orgID, teamID, // Note: This endpoint removes the project from the team, but does not delete it. // // GitHub API docs: https://developer.github.com/v3/teams/#remove-team-project -func (s *TeamsService) RemoveTeamProjectByName(ctx context.Context, org, slug string, projectID int64) (*Response, error) { +func (s *TeamsService) RemoveTeamProjectBySlug(ctx context.Context, org, slug string, projectID int64) (*Response, error) { u := fmt.Sprintf("orgs/%v/teams/%v/projects/%v", org, slug, projectID) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { @@ -729,3 +729,78 @@ func (s *TeamsService) RemoveTeamProjectByName(ctx context.Context, org, slug st return s.client.Do(ctx, req, nil) } + +// IDPGroupList represents a list of external identity provider (IDP) groups. +type IDPGroupList struct { + Groups []*IDPGroup `json:"groups"` +} + +// IDPGroup represents an external identity provider (IDP) group. +type IDPGroup struct { + GroupID *string `json:"group_id,omitempty"` + GroupName *string `json:"group_name,omitempty"` + GroupDescription *string `json:"group_description,omitempty"` +} + +// ListIDPGroupsInOrganization lists IDP groups available in an organization. +// +// GitHub API docs: https://developer.github.com/v3/teams/team_sync/#list-idp-groups-in-an-organization +func (s *TeamsService) ListIDPGroupsInOrganization(ctx context.Context, org string, opt *ListCursorOptions) (*IDPGroupList, *Response, error) { + u := fmt.Sprintf("orgs/%v/team-sync/groups", org) + u, err := addOptions(u, opt) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + groups := new(IDPGroupList) + resp, err := s.client.Do(ctx, req, groups) + if err != nil { + return nil, resp, err + } + return groups, resp, nil +} + +// ListIDPGroupsForTeam lists IDP groups connected to a team on GitHub. +// +// GitHub API docs: https://developer.github.com/v3/teams/team_sync/#list-idp-groups-for-a-team +func (s *TeamsService) ListIDPGroupsForTeam(ctx context.Context, teamID string) (*IDPGroupList, *Response, error) { + u := fmt.Sprintf("teams/%v/team-sync/group-mappings", teamID) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + groups := new(IDPGroupList) + resp, err := s.client.Do(ctx, req, groups) + if err != nil { + return nil, resp, err + } + return groups, resp, err +} + +// CreateOrUpdateIDPGroupConnections creates, updates, or removes a connection between a team +// and an IDP group. +// +// GitHub API docs: https://developer.github.com/v3/teams/team_sync/#create-or-update-idp-group-connections +func (s *TeamsService) CreateOrUpdateIDPGroupConnections(ctx context.Context, teamID string, opt IDPGroupList) (*IDPGroupList, *Response, error) { + u := fmt.Sprintf("teams/%v/team-sync/group-mappings", teamID) + + req, err := s.client.NewRequest("PATCH", u, opt) + if err != nil { + return nil, nil, err + } + + groups := new(IDPGroupList) + resp, err := s.client.Do(ctx, req, groups) + if err != nil { + return nil, resp, err + } + + return groups, resp, nil +} diff --git a/github/teams_discussion_comments.go b/github/teams_discussion_comments.go index 9bc17cf6353..ff871f22be0 100644 --- a/github/teams_discussion_comments.go +++ b/github/teams_discussion_comments.go @@ -39,13 +39,12 @@ type DiscussionCommentListOptions struct { Direction string `url:"direction,omitempty"` } -// ListCommentsByID lists all comments on a team discussion -// given a team ID and organization ID. +// ListComments lists all comments on a team discussion. // Authenticated user must grant read:discussion scope. // // GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#list-comments -func (s *TeamsService) ListCommentsByID(ctx context.Context, orgID, teamID int64, discussionNumber int, options *DiscussionCommentListOptions) ([]*DiscussionComment, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/discussions/%v/comments", orgID, teamID, discussionNumber) +func (s *TeamsService) ListComments(ctx context.Context, teamID int64, discussionNumber int, options *DiscussionCommentListOptions) ([]*DiscussionComment, *Response, error) { + u := fmt.Sprintf("teams/%v/discussions/%v/comments", teamID, discussionNumber) u, err := addOptions(u, options) if err != nil { return nil, nil, err @@ -65,39 +64,12 @@ func (s *TeamsService) ListCommentsByID(ctx context.Context, orgID, teamID int64 return comments, resp, nil } -// ListCommentsByName lists all comments on a team discussion -// given a team slug and organization name. -// Authenticated user must grant read:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#list-comments -func (s *TeamsService) ListCommentsByName(ctx context.Context, org, slug string, discussionNumber int, options *DiscussionCommentListOptions) ([]*DiscussionComment, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v/comments", org, slug, discussionNumber) - u, err := addOptions(u, options) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var comments []*DiscussionComment - resp, err := s.client.Do(ctx, req, &comments) - if err != nil { - return nil, resp, err - } - - return comments, resp, nil -} - -// GetCommentByID gets a specific comment on a team discussion -// given a team ID and organization ID. +// GetComment gets a specific comment on a team discussion. // Authenticated user must grant read:discussion scope. // // GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#get-a-single-comment -func (s *TeamsService) GetCommentByID(ctx context.Context, orgID, teamID int64, discussionNumber, commentNumber int) (*DiscussionComment, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/discussions/%v/comments/%v", orgID, teamID, discussionNumber, commentNumber) +func (s *TeamsService) GetComment(ctx context.Context, teamID int64, discussionNumber, commentNumber int) (*DiscussionComment, *Response, error) { + u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v", teamID, discussionNumber, commentNumber) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err @@ -112,34 +84,12 @@ func (s *TeamsService) GetCommentByID(ctx context.Context, orgID, teamID int64, return discussionComment, resp, nil } -// GetCommentByName gets a specific comment on a team discussion -// given a team slug and organization name. -// Authenticated user must grant read:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#get-a-single-comment -func (s *TeamsService) GetCommentByName(ctx context.Context, org, slug string, discussionNumber, commentNumber int) (*DiscussionComment, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v/comments/%v", org, slug, discussionNumber, commentNumber) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - discussionComment := &DiscussionComment{} - resp, err := s.client.Do(ctx, req, discussionComment) - if err != nil { - return nil, resp, err - } - - return discussionComment, resp, nil -} - -// CreateCommentByID creates a new discussion post on a team discussion -// given a team ID and organization ID. +// CreateComment creates a new discussion post on a team discussion. // Authenticated user must grant write:discussion scope. // // GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#create-a-comment -func (s *TeamsService) CreateCommentByID(ctx context.Context, orgID, teamID int64, discsusionNumber int, comment DiscussionComment) (*DiscussionComment, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/discussions/%v/comments", orgID, teamID, discsusionNumber) +func (s *TeamsService) CreateComment(ctx context.Context, teamID int64, discsusionNumber int, comment DiscussionComment) (*DiscussionComment, *Response, error) { + u := fmt.Sprintf("teams/%v/discussions/%v/comments", teamID, discsusionNumber) req, err := s.client.NewRequest("POST", u, comment) if err != nil { return nil, nil, err @@ -154,57 +104,13 @@ func (s *TeamsService) CreateCommentByID(ctx context.Context, orgID, teamID int6 return discussionComment, resp, nil } -// CreateCommentByName creates a new discussion post on a team discussion -// given a team slug and organization name. -// Authenticated user must grant write:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#create-a-comment -func (s *TeamsService) CreateCommentByName(ctx context.Context, org, slug string, discsusionNumber int, comment DiscussionComment) (*DiscussionComment, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v/comments", org, slug, discsusionNumber) - req, err := s.client.NewRequest("POST", u, comment) - if err != nil { - return nil, nil, err - } - - discussionComment := &DiscussionComment{} - resp, err := s.client.Do(ctx, req, discussionComment) - if err != nil { - return nil, resp, err - } - - return discussionComment, resp, nil -} - -// EditCommentByID edits the body text of a discussion comment -// given a team ID and organization ID. -// Authenticated user must grant write:discussion scope. -// User is allowed to edit body of a comment only. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#edit-a-comment -func (s *TeamsService) EditCommentByID(ctx context.Context, orgID, teamID int64, discussionNumber, commentNumber int, comment DiscussionComment) (*DiscussionComment, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/discussions/%v/comments/%v", orgID, teamID, discussionNumber, commentNumber) - req, err := s.client.NewRequest("PATCH", u, comment) - if err != nil { - return nil, nil, err - } - - discussionComment := &DiscussionComment{} - resp, err := s.client.Do(ctx, req, discussionComment) - if err != nil { - return nil, resp, err - } - - return discussionComment, resp, nil -} - -// EditCommentByName edits the body text of a discussion comment -// given a team slug and organization name. +// EditComment edits the body text of a discussion comment. // Authenticated user must grant write:discussion scope. // User is allowed to edit body of a comment only. // // GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#edit-a-comment -func (s *TeamsService) EditCommentByName(ctx context.Context, org, slug string, discussionNumber, commentNumber int, comment DiscussionComment) (*DiscussionComment, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v/comments/%v", org, slug, discussionNumber, commentNumber) +func (s *TeamsService) EditComment(ctx context.Context, teamID int64, discussionNumber, commentNumber int, comment DiscussionComment) (*DiscussionComment, *Response, error) { + u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v", teamID, discussionNumber, commentNumber) req, err := s.client.NewRequest("PATCH", u, comment) if err != nil { return nil, nil, err @@ -219,28 +125,12 @@ func (s *TeamsService) EditCommentByName(ctx context.Context, org, slug string, return discussionComment, resp, nil } -// DeleteCommentByID deletes a comment on a team discussion -// given a team ID and organiation ID. -// Authenticated user must grant write:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#delete-a-comment -func (s *TeamsService) DeleteCommentByID(ctx context.Context, orgID, teamID int64, discussionNumber, commentNumber int) (*Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/discussions/%v/comments/%v", orgID, teamID, discussionNumber, commentNumber) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// DeleteCommentByName deletes a comment on a team discussion -// given a team slug and organization name. +// DeleteComment deletes a comment on a team discussion. // Authenticated user must grant write:discussion scope. // // GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#delete-a-comment -func (s *TeamsService) DeleteCommentByName(ctx context.Context, org, slug string, discussionNumber, commentNumber int) (*Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v/comments/%v", org, slug, discussionNumber, commentNumber) +func (s *TeamsService) DeleteComment(ctx context.Context, teamID int64, discussionNumber, commentNumber int) (*Response, error) { + u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v", teamID, discussionNumber, commentNumber) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err diff --git a/github/teams_discussion_comments_test.go b/github/teams_discussion_comments_test.go index c94810fdfdc..96ed1464109 100644 --- a/github/teams_discussion_comments_test.go +++ b/github/teams_discussion_comments_test.go @@ -15,11 +15,11 @@ import ( "time" ) -func TestTeamsService_ListCommentsByID(t *testing.T) { +func TestTeamsService_ListComments(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/organizations/1/team/2/discussions/3/comments", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/teams/2/discussions/3/comments", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") testFormValues(t, r, values{ "direction": "desc", @@ -61,9 +61,9 @@ func TestTeamsService_ListCommentsByID(t *testing.T) { ]`) }) - comments, _, err := client.Teams.ListCommentsByID(context.Background(), 1, 2, 3, &DiscussionCommentListOptions{"desc"}) + comments, _, err := client.Teams.ListComments(context.Background(), 2, 3, &DiscussionCommentListOptions{"desc"}) if err != nil { - t.Errorf("Teams.ListCommentsByID returned error: %v", err) + t.Errorf("Teams.ListComments returned error: %v", err) } want := []*DiscussionComment{ @@ -101,147 +101,37 @@ func TestTeamsService_ListCommentsByID(t *testing.T) { }, } if !reflect.DeepEqual(comments, want) { - t.Errorf("Teams.ListCommentsByID returned %+v, want %+v", comments, want) + t.Errorf("Teams.ListComments returned %+v, want %+v", comments, want) } } -func TestTeamsService_ListCommentsByName(t *testing.T) { +func TestTeamsService_GetComment(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/orgs/o/teams/s/discussions/3/comments", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - testFormValues(t, r, values{ - "direction": "desc", - }) - fmt.Fprintf(w, - `[ - { - "author": { - "login": "author", - "id": 0, - "avatar_url": "https://avatars1.githubusercontent.com/u/0?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/author", - "html_url": "https://github.com/author", - "followers_url": "https://api.github.com/users/author/followers", - "following_url": "https://api.github.com/users/author/following{/other_user}", - "gists_url": "https://api.github.com/users/author/gists{/gist_id}", - "starred_url": "https://api.github.com/users/author/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/author/subscriptions", - "organizations_url": "https://api.github.com/users/author/orgs", - "repos_url": "https://api.github.com/users/author/repos", - "events_url": "https://api.github.com/users/author/events{/privacy}", - "received_events_url": "https://api.github.com/users/author/received_events", - "type": "User", - "site_admin": false - }, - "body": "comment", - "body_html": "

comment

", - "body_version": "version", - "created_at": "2018-01-01T00:00:00Z", - "last_edited_at": null, - "discussion_url": "https://api.github.com/teams/2/discussions/3", - "html_url": "https://github.com/orgs/1/teams/2/discussions/3/comments/4", - "node_id": "node", - "number": 4, - "updated_at": "2018-01-01T00:00:00Z", - "url": "https://api.github.com/teams/2/discussions/3/comments/4" - } - ]`) - }) - - comments, _, err := client.Teams.ListCommentsByName(context.Background(), "o", "s", 3, &DiscussionCommentListOptions{"desc"}) - if err != nil { - t.Errorf("Teams.ListCommentsByName returned error: %v", err) - } - - want := []*DiscussionComment{ - { - Author: &User{ - Login: String("author"), - ID: Int64(0), - AvatarURL: String("https://avatars1.githubusercontent.com/u/0?v=4"), - GravatarID: String(""), - URL: String("https://api.github.com/users/author"), - HTMLURL: String("https://github.com/author"), - FollowersURL: String("https://api.github.com/users/author/followers"), - FollowingURL: String("https://api.github.com/users/author/following{/other_user}"), - GistsURL: String("https://api.github.com/users/author/gists{/gist_id}"), - StarredURL: String("https://api.github.com/users/author/starred{/owner}{/repo}"), - SubscriptionsURL: String("https://api.github.com/users/author/subscriptions"), - OrganizationsURL: String("https://api.github.com/users/author/orgs"), - ReposURL: String("https://api.github.com/users/author/repos"), - EventsURL: String("https://api.github.com/users/author/events{/privacy}"), - ReceivedEventsURL: String("https://api.github.com/users/author/received_events"), - Type: String("User"), - SiteAdmin: Bool(false), - }, - Body: String("comment"), - BodyHTML: String("

comment

"), - BodyVersion: String("version"), - CreatedAt: &Timestamp{time.Date(2018, time.January, 1, 0, 0, 0, 0, time.UTC)}, - LastEditedAt: nil, - DiscussionURL: String("https://api.github.com/teams/2/discussions/3"), - HTMLURL: String("https://github.com/orgs/1/teams/2/discussions/3/comments/4"), - NodeID: String("node"), - Number: Int(4), - UpdatedAt: &Timestamp{time.Date(2018, time.January, 1, 0, 0, 0, 0, time.UTC)}, - URL: String("https://api.github.com/teams/2/discussions/3/comments/4"), - }, - } - if !reflect.DeepEqual(comments, want) { - t.Errorf("Teams.ListCommentsByName returned %+v, want %+v", comments, want) - } -} - -func TestTeamsService_GetCommentByID(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/organizations/1/team/2/discussions/3/comments/4", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - fmt.Fprint(w, `{"number":4}`) - }) - - comment, _, err := client.Teams.GetCommentByID(context.Background(), 1, 2, 3, 4) - if err != nil { - t.Errorf("Teams.GetCommentByID returned error: %v", err) - } - - want := &DiscussionComment{Number: Int(4)} - if !reflect.DeepEqual(comment, want) { - t.Errorf("Teams.GetCommentByID returned %+v, want %+v", comment, want) - } -} - -func TestTeamsService_GetCommentByName(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/orgs/o/teams/s/discussions/3/comments/4", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/teams/2/discussions/3/comments/4", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"number":4}`) }) - comment, _, err := client.Teams.GetCommentByName(context.Background(), "o", "s", 3, 4) + comment, _, err := client.Teams.GetComment(context.Background(), 2, 3, 4) if err != nil { - t.Errorf("Teams.GetCommentByName returned error: %v", err) + t.Errorf("Teams.GetComment returned error: %v", err) } want := &DiscussionComment{Number: Int(4)} if !reflect.DeepEqual(comment, want) { - t.Errorf("Teams.GetCommentByName returned %+v, want %+v", comment, want) + t.Errorf("Teams.GetComment returned %+v, want %+v", comment, want) } } -func TestTeamsService_CreateCommentByID(t *testing.T) { +func TestTeamsService_CreateComment(t *testing.T) { client, mux, _, teardown := setup() defer teardown() input := DiscussionComment{Body: String("c")} - mux.HandleFunc("/organizations/1/team/2/discussions/3/comments", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/teams/2/discussions/3/comments", func(w http.ResponseWriter, r *http.Request) { v := new(DiscussionComment) json.NewDecoder(r.Body).Decode(v) @@ -253,53 +143,24 @@ func TestTeamsService_CreateCommentByID(t *testing.T) { fmt.Fprint(w, `{"number":4}`) }) - comment, _, err := client.Teams.CreateCommentByID(context.Background(), 1, 2, 3, input) + comment, _, err := client.Teams.CreateComment(context.Background(), 2, 3, input) if err != nil { - t.Errorf("Teams.CreateCommentByID returned error: %v", err) + t.Errorf("Teams.CreateComment returned error: %v", err) } want := &DiscussionComment{Number: Int(4)} if !reflect.DeepEqual(comment, want) { - t.Errorf("Teams.CreateCommentByID returned %+v, want %+v", comment, want) + t.Errorf("Teams.CreateComment returned %+v, want %+v", comment, want) } } -func TestTeamsService_CreateCommentByName(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - input := DiscussionComment{Body: String("c")} - - mux.HandleFunc("/orgs/o/teams/s/discussions/3/comments", func(w http.ResponseWriter, r *http.Request) { - v := new(DiscussionComment) - json.NewDecoder(r.Body).Decode(v) - - testMethod(t, r, "POST") - if !reflect.DeepEqual(v, &input) { - t.Errorf("Request body = %+v, want %+v", v, input) - } - - fmt.Fprint(w, `{"number":4}`) - }) - - comment, _, err := client.Teams.CreateCommentByName(context.Background(), "o", "s", 3, input) - if err != nil { - t.Errorf("Teams.CreateCommentByName returned error: %v", err) - } - - want := &DiscussionComment{Number: Int(4)} - if !reflect.DeepEqual(comment, want) { - t.Errorf("Teams.CreateCommentByName returned %+v, want %+v", comment, want) - } -} - -func TestTeamsService_EditCommentByID(t *testing.T) { +func TestTeamsService_EditComment(t *testing.T) { client, mux, _, teardown := setup() defer teardown() input := DiscussionComment{Body: String("e")} - mux.HandleFunc("/organizations/1/team/2/discussions/3/comments/4", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/teams/2/discussions/3/comments/4", func(w http.ResponseWriter, r *http.Request) { v := new(DiscussionComment) json.NewDecoder(r.Body).Decode(v) @@ -311,70 +172,27 @@ func TestTeamsService_EditCommentByID(t *testing.T) { fmt.Fprint(w, `{"number":4}`) }) - comment, _, err := client.Teams.EditCommentByID(context.Background(), 1, 2, 3, 4, input) + comment, _, err := client.Teams.EditComment(context.Background(), 2, 3, 4, input) if err != nil { - t.Errorf("Teams.EditCommentByID returned error: %v", err) + t.Errorf("Teams.EditComment returned error: %v", err) } want := &DiscussionComment{Number: Int(4)} if !reflect.DeepEqual(comment, want) { - t.Errorf("Teams.EditCommentByID returned %+v, want %+v", comment, want) - } -} - -func TestTeamsService_EditCommentByName(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - input := DiscussionComment{Body: String("e")} - - mux.HandleFunc("/orgs/o/teams/s/discussions/3/comments/4", func(w http.ResponseWriter, r *http.Request) { - v := new(DiscussionComment) - json.NewDecoder(r.Body).Decode(v) - - testMethod(t, r, "PATCH") - if !reflect.DeepEqual(v, &input) { - t.Errorf("Request body = %+v, want %+v", v, input) - } - - fmt.Fprint(w, `{"number":4}`) - }) - - comment, _, err := client.Teams.EditCommentByName(context.Background(), "o", "s", 3, 4, input) - if err != nil { - t.Errorf("Teams.EditCommentByName returned error: %v", err) - } - - want := &DiscussionComment{Number: Int(4)} - if !reflect.DeepEqual(comment, want) { - t.Errorf("Teams.EditCommentByName returned %+v, want %+v", comment, want) - } -} - -func TestTeamsService_DeleteCommentByID(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/organizations/1/team/2/discussions/3/comments/4", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "DELETE") - }) - - _, err := client.Teams.DeleteCommentByID(context.Background(), 1, 2, 3, 4) - if err != nil { - t.Errorf("Teams.DeleteCommentByID returned error: %v", err) + t.Errorf("Teams.EditComment returned %+v, want %+v", comment, want) } } -func TestTeamsService_DeleteCommentByName(t *testing.T) { +func TestTeamsService_DeleteComment(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/orgs/o/teams/s/discussions/3/comments/4", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/teams/2/discussions/3/comments/4", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") }) - _, err := client.Teams.DeleteCommentByName(context.Background(), "o", "s", 3, 4) + _, err := client.Teams.DeleteComment(context.Background(), 2, 3, 4) if err != nil { - t.Errorf("Teams.DeleteCommentByName returned error: %v", err) + t.Errorf("Teams.DeleteComment returned error: %v", err) } } diff --git a/github/teams_discussions.go b/github/teams_discussions.go index 31212c7b308..433d01595a6 100644 --- a/github/teams_discussions.go +++ b/github/teams_discussions.go @@ -44,13 +44,12 @@ type DiscussionListOptions struct { Direction string `url:"direction,omitempty"` } -// ListDiscussionsByID lists all discussions on team's page -// given the team ID and organization ID. +// ListDiscussions lists all discussions on team's page. // Authenticated user must grant read:discussion scope. // // GitHub API docs: https://developer.github.com/v3/teams/discussions/#list-discussions -func (s *TeamsService) ListDiscussionsByID(ctx context.Context, orgID, teamID int64, options *DiscussionListOptions) ([]*TeamDiscussion, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/discussions", orgID, teamID) +func (s *TeamsService) ListDiscussions(ctx context.Context, teamID int64, options *DiscussionListOptions) ([]*TeamDiscussion, *Response, error) { + u := fmt.Sprintf("teams/%v/discussions", teamID) u, err := addOptions(u, options) if err != nil { return nil, nil, err @@ -70,39 +69,12 @@ func (s *TeamsService) ListDiscussionsByID(ctx context.Context, orgID, teamID in return teamDiscussions, resp, nil } -// ListDiscussionsByName lists all discussions on team's page -// given the team slug and organization name. -// Authenticated user must grant read:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussions/#list-discussions -func (s *TeamsService) ListDiscussionsByName(ctx context.Context, org, slug string, options *DiscussionListOptions) ([]*TeamDiscussion, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/discussions", org, slug) - u, err := addOptions(u, options) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var teamDiscussions []*TeamDiscussion - resp, err := s.client.Do(ctx, req, &teamDiscussions) - if err != nil { - return nil, resp, err - } - - return teamDiscussions, resp, nil -} - -// GetDiscussionByID gets a specific discussion on a team's page -// given the team ID and organization ID. +// GetDiscussion gets a specific discussion on a team's page. // Authenticated user must grant read:discussion scope. // // GitHub API docs: https://developer.github.com/v3/teams/discussions/#get-a-single-discussion -func (s *TeamsService) GetDiscussionByID(ctx context.Context, orgID, teamID int64, discussionNumber int) (*TeamDiscussion, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/discussions/%v", orgID, teamID, discussionNumber) +func (s *TeamsService) GetDiscussion(ctx context.Context, teamID int64, discussionNumber int) (*TeamDiscussion, *Response, error) { + u := fmt.Sprintf("teams/%v/discussions/%v", teamID, discussionNumber) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err @@ -117,34 +89,12 @@ func (s *TeamsService) GetDiscussionByID(ctx context.Context, orgID, teamID int6 return teamDiscussion, resp, nil } -// GetDiscussionByName gets a specific discussion on a team's page -// given the team slug and organization name. -// Authenticated user must grant read:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussions/#get-a-single-discussion -func (s *TeamsService) GetDiscussionByName(ctx context.Context, org, slug string, discussionNumber int) (*TeamDiscussion, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v", org, slug, discussionNumber) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - teamDiscussion := &TeamDiscussion{} - resp, err := s.client.Do(ctx, req, teamDiscussion) - if err != nil { - return nil, resp, err - } - - return teamDiscussion, resp, nil -} - -// CreateDiscussionByID creates a new discussion post on a team's page -// given the team ID and organization ID. +// CreateDiscussion creates a new discussion post on a team's page. // Authenticated user must grant write:discussion scope. // // GitHub API docs: https://developer.github.com/v3/teams/discussions/#create-a-discussion -func (s *TeamsService) CreateDiscussionByID(ctx context.Context, orgID, teamID int64, discussion TeamDiscussion) (*TeamDiscussion, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/discussions", orgID, teamID) +func (s *TeamsService) CreateDiscussion(ctx context.Context, teamID int64, discussion TeamDiscussion) (*TeamDiscussion, *Response, error) { + u := fmt.Sprintf("teams/%v/discussions", teamID) req, err := s.client.NewRequest("POST", u, discussion) if err != nil { return nil, nil, err @@ -159,57 +109,13 @@ func (s *TeamsService) CreateDiscussionByID(ctx context.Context, orgID, teamID i return teamDiscussion, resp, nil } -// CreateDiscussionByName creates a new discussion post on a team's page -// given the team slug and organization name. -// Authenticated user must grant write:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussions/#create-a-discussion -func (s *TeamsService) CreateDiscussionByName(ctx context.Context, org, slug string, discussion TeamDiscussion) (*TeamDiscussion, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/discussions", org, slug) - req, err := s.client.NewRequest("POST", u, discussion) - if err != nil { - return nil, nil, err - } - - teamDiscussion := &TeamDiscussion{} - resp, err := s.client.Do(ctx, req, teamDiscussion) - if err != nil { - return nil, resp, err - } - - return teamDiscussion, resp, nil -} - -// EditDiscussionByID edits the title and body text of a discussion post -// for a given team ID and organization ID. -// Authenticated user must grant write:discussion scope. -// User is allowed to change Title and Body of a discussion only. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussions/#edit-a-discussion -func (s *TeamsService) EditDiscussionByID(ctx context.Context, orgID, teamID int64, discussionNumber int, discussion TeamDiscussion) (*TeamDiscussion, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/discussions/%v", orgID, teamID, discussionNumber) - req, err := s.client.NewRequest("PATCH", u, discussion) - if err != nil { - return nil, nil, err - } - - teamDiscussion := &TeamDiscussion{} - resp, err := s.client.Do(ctx, req, teamDiscussion) - if err != nil { - return nil, resp, err - } - - return teamDiscussion, resp, nil -} - -// EditDiscussionByName edits the title and body text of a discussion post -// for a given team slug and organization name. +// EditDiscussion edits the title and body text of a discussion post. // Authenticated user must grant write:discussion scope. // User is allowed to change Title and Body of a discussion only. // // GitHub API docs: https://developer.github.com/v3/teams/discussions/#edit-a-discussion -func (s *TeamsService) EditDiscussionByName(ctx context.Context, org, slug string, discussionNumber int, discussion TeamDiscussion) (*TeamDiscussion, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v", org, slug, discussionNumber) +func (s *TeamsService) EditDiscussion(ctx context.Context, teamID int64, discussionNumber int, discussion TeamDiscussion) (*TeamDiscussion, *Response, error) { + u := fmt.Sprintf("teams/%v/discussions/%v", teamID, discussionNumber) req, err := s.client.NewRequest("PATCH", u, discussion) if err != nil { return nil, nil, err @@ -224,28 +130,12 @@ func (s *TeamsService) EditDiscussionByName(ctx context.Context, org, slug strin return teamDiscussion, resp, nil } -// DeleteDiscussionByID deletes a discussion from team's page -// given the team ID and organization ID. -// Authenticated user must grant write:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussions/#delete-a-discussion -func (s *TeamsService) DeleteDiscussionByID(ctx context.Context, orgID, teamID int64, discussionNumber int) (*Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/discussions/%v", orgID, teamID, discussionNumber) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// DeleteDiscussionByName deletes a discussion from team's page -// given the team slug and organization name. +// DeleteDiscussion deletes a discussion from team's page. // Authenticated user must grant write:discussion scope. // // GitHub API docs: https://developer.github.com/v3/teams/discussions/#delete-a-discussion -func (s *TeamsService) DeleteDiscussionByName(ctx context.Context, org, slug string, discussionNumber int) (*Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v", org, slug, discussionNumber) +func (s *TeamsService) DeleteDiscussion(ctx context.Context, teamID int64, discussionNumber int) (*Response, error) { + u := fmt.Sprintf("teams/%v/discussions/%v", teamID, discussionNumber) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err diff --git a/github/teams_discussions_test.go b/github/teams_discussions_test.go index a5b73b78a85..65be1ce6f3d 100644 --- a/github/teams_discussions_test.go +++ b/github/teams_discussions_test.go @@ -15,11 +15,11 @@ import ( "time" ) -func TestTeamsService_ListDiscussionsByID(t *testing.T) { +func TestTeamsService_ListDiscussions(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/organizations/1/team/2/discussions", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/teams/2/discussions", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") testFormValues(t, r, values{ "direction": "desc", @@ -65,9 +65,9 @@ func TestTeamsService_ListDiscussionsByID(t *testing.T) { } ]`) }) - discussions, _, err := client.Teams.ListDiscussionsByID(context.Background(), 1, 2, &DiscussionListOptions{"desc"}) + discussions, _, err := client.Teams.ListDiscussions(context.Background(), 2, &DiscussionListOptions{"desc"}) if err != nil { - t.Errorf("Teams.ListDiscussionsByID returned error: %v", err) + t.Errorf("Teams.ListDiscussions returned error: %v", err) } want := []*TeamDiscussion{ @@ -110,156 +110,37 @@ func TestTeamsService_ListDiscussionsByID(t *testing.T) { }, } if !reflect.DeepEqual(discussions, want) { - t.Errorf("Teams.ListDiscussionsByID returned %+v, want %+v", discussions, want) + t.Errorf("Teams.ListDiscussions returned %+v, want %+v", discussions, want) } } -func TestTeamsService_ListDiscussionsByName(t *testing.T) { +func TestTeamsService_GetDiscussion(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/orgs/o/teams/s/discussions", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - testFormValues(t, r, values{ - "direction": "desc", - }) - fmt.Fprintf(w, - `[ - { - "author": { - "login": "author", - "id": 0, - "avatar_url": "https://avatars1.githubusercontent.com/u/0?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/author", - "html_url": "https://github.com/author", - "followers_url": "https://api.github.com/users/author/followers", - "following_url": "https://api.github.com/users/author/following{/other_user}", - "gists_url": "https://api.github.com/users/author/gists{/gist_id}", - "starred_url": "https://api.github.com/users/author/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/author/subscriptions", - "organizations_url": "https://api.github.com/users/author/orgs", - "repos_url": "https://api.github.com/users/author/repos", - "events_url": "https://api.github.com/users/author/events{/privacy}", - "received_events_url": "https://api.github.com/users/author/received_events", - "type": "User", - "site_admin": false - }, - "body": "test", - "body_html": "

test

", - "body_version": "version", - "comments_count": 1, - "comments_url": "https://api.github.com/teams/2/discussions/3/comments", - "created_at": "2018-01-01T00:00:00Z", - "last_edited_at": null, - "html_url": "https://github.com/orgs/1/teams/2/discussions/3", - "node_id": "node", - "number": 3, - "pinned": false, - "private": false, - "team_url": "https://api.github.com/teams/2", - "title": "test", - "updated_at": "2018-01-01T00:00:00Z", - "url": "https://api.github.com/teams/2/discussions/3" - } - ]`) - }) - discussions, _, err := client.Teams.ListDiscussionsByName(context.Background(), "o", "s", &DiscussionListOptions{"desc"}) - if err != nil { - t.Errorf("Teams.ListDiscussionsByName returned error: %v", err) - } - - want := []*TeamDiscussion{ - { - Author: &User{ - Login: String("author"), - ID: Int64(0), - AvatarURL: String("https://avatars1.githubusercontent.com/u/0?v=4"), - GravatarID: String(""), - URL: String("https://api.github.com/users/author"), - HTMLURL: String("https://github.com/author"), - FollowersURL: String("https://api.github.com/users/author/followers"), - FollowingURL: String("https://api.github.com/users/author/following{/other_user}"), - GistsURL: String("https://api.github.com/users/author/gists{/gist_id}"), - StarredURL: String("https://api.github.com/users/author/starred{/owner}{/repo}"), - SubscriptionsURL: String("https://api.github.com/users/author/subscriptions"), - OrganizationsURL: String("https://api.github.com/users/author/orgs"), - ReposURL: String("https://api.github.com/users/author/repos"), - EventsURL: String("https://api.github.com/users/author/events{/privacy}"), - ReceivedEventsURL: String("https://api.github.com/users/author/received_events"), - Type: String("User"), - SiteAdmin: Bool(false), - }, - Body: String("test"), - BodyHTML: String("

test

"), - BodyVersion: String("version"), - CommentsCount: Int(1), - CommentsURL: String("https://api.github.com/teams/2/discussions/3/comments"), - CreatedAt: &Timestamp{time.Date(2018, time.January, 1, 0, 0, 0, 0, time.UTC)}, - LastEditedAt: nil, - HTMLURL: String("https://github.com/orgs/1/teams/2/discussions/3"), - NodeID: String("node"), - Number: Int(3), - Pinned: Bool(false), - Private: Bool(false), - TeamURL: String("https://api.github.com/teams/2"), - Title: String("test"), - UpdatedAt: &Timestamp{time.Date(2018, time.January, 1, 0, 0, 0, 0, time.UTC)}, - URL: String("https://api.github.com/teams/2/discussions/3"), - }, - } - if !reflect.DeepEqual(discussions, want) { - t.Errorf("Teams.ListDiscussionsByName returned %+v, want %+v", discussions, want) - } -} - -func TestTeamsService_GetDiscussionByID(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/organizations/1/team/2/discussions/3", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - fmt.Fprint(w, `{"number":3}`) - }) - - discussion, _, err := client.Teams.GetDiscussionByID(context.Background(), 1, 2, 3) - if err != nil { - t.Errorf("Teams.GetDiscussionByID returned error: %v", err) - } - - want := &TeamDiscussion{Number: Int(3)} - if !reflect.DeepEqual(discussion, want) { - t.Errorf("Teams.GetDiscussionByID returned %+v, want %+v", discussion, want) - } -} - -func TestTeamsService_GetDiscussionByName(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/orgs/o/teams/s/discussions/3", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/teams/2/discussions/3", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"number":3}`) }) - discussion, _, err := client.Teams.GetDiscussionByName(context.Background(), "o", "s", 3) + discussion, _, err := client.Teams.GetDiscussion(context.Background(), 2, 3) if err != nil { - t.Errorf("Teams.GetDiscussionByName returned error: %v", err) + t.Errorf("Teams.GetDiscussion returned error: %v", err) } want := &TeamDiscussion{Number: Int(3)} if !reflect.DeepEqual(discussion, want) { - t.Errorf("Teams.GetDiscussionByName returned %+v, want %+v", discussion, want) + t.Errorf("Teams.GetDiscussion returned %+v, want %+v", discussion, want) } } -func TestTeamsService_CreateDiscussionByID(t *testing.T) { +func TestTeamsService_CreateDiscussion(t *testing.T) { client, mux, _, teardown := setup() defer teardown() input := TeamDiscussion{Title: String("c_t"), Body: String("c_b")} - mux.HandleFunc("/organizations/1/team/2/discussions", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/teams/2/discussions", func(w http.ResponseWriter, r *http.Request) { v := new(TeamDiscussion) json.NewDecoder(r.Body).Decode(v) @@ -271,53 +152,24 @@ func TestTeamsService_CreateDiscussionByID(t *testing.T) { fmt.Fprint(w, `{"number":3}`) }) - comment, _, err := client.Teams.CreateDiscussionByID(context.Background(), 1, 2, input) + comment, _, err := client.Teams.CreateDiscussion(context.Background(), 2, input) if err != nil { - t.Errorf("Teams.CreateDiscussionByID returned error: %v", err) + t.Errorf("Teams.CreateDiscussion returned error: %v", err) } want := &TeamDiscussion{Number: Int(3)} if !reflect.DeepEqual(comment, want) { - t.Errorf("Teams.CreateDiscussionByID returned %+v, want %+v", comment, want) + t.Errorf("Teams.CreateDiscussion returned %+v, want %+v", comment, want) } } -func TestTeamsService_CreateDiscussionByName(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - input := TeamDiscussion{Title: String("c_t"), Body: String("c_b")} - - mux.HandleFunc("/orgs/o/teams/s/discussions", func(w http.ResponseWriter, r *http.Request) { - v := new(TeamDiscussion) - json.NewDecoder(r.Body).Decode(v) - - testMethod(t, r, "POST") - if !reflect.DeepEqual(v, &input) { - t.Errorf("Request body = %+v, want %+v", v, input) - } - - fmt.Fprint(w, `{"number":3}`) - }) - - comment, _, err := client.Teams.CreateDiscussionByName(context.Background(), "o", "s", input) - if err != nil { - t.Errorf("Teams.CreateDiscussionByName returned error: %v", err) - } - - want := &TeamDiscussion{Number: Int(3)} - if !reflect.DeepEqual(comment, want) { - t.Errorf("Teams.CreateDiscussionByName returned %+v, want %+v", comment, want) - } -} - -func TestTeamsService_EditDiscussionByID(t *testing.T) { +func TestTeamsService_EditDiscussion(t *testing.T) { client, mux, _, teardown := setup() defer teardown() input := TeamDiscussion{Title: String("e_t"), Body: String("e_b")} - mux.HandleFunc("/organizations/1/team/2/discussions/3", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/teams/2/discussions/3", func(w http.ResponseWriter, r *http.Request) { v := new(TeamDiscussion) json.NewDecoder(r.Body).Decode(v) @@ -329,36 +181,7 @@ func TestTeamsService_EditDiscussionByID(t *testing.T) { fmt.Fprint(w, `{"number":3}`) }) - comment, _, err := client.Teams.EditDiscussionByID(context.Background(), 1, 2, 3, input) - if err != nil { - t.Errorf("Teams.EditDiscussionByID returned error: %v", err) - } - - want := &TeamDiscussion{Number: Int(3)} - if !reflect.DeepEqual(comment, want) { - t.Errorf("Teams.EditDiscussionByID returned %+v, want %+v", comment, want) - } -} - -func TestTeamsService_EditDiscussionByName(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - input := TeamDiscussion{Title: String("e_t"), Body: String("e_b")} - - mux.HandleFunc("/orgs/o/teams/s/discussions/3", func(w http.ResponseWriter, r *http.Request) { - v := new(TeamDiscussion) - json.NewDecoder(r.Body).Decode(v) - - testMethod(t, r, "PATCH") - if !reflect.DeepEqual(v, &input) { - t.Errorf("Request body = %+v, want %+v", v, input) - } - - fmt.Fprint(w, `{"number":3}`) - }) - - comment, _, err := client.Teams.EditDiscussionByName(context.Background(), "o", "s", 3, input) + comment, _, err := client.Teams.EditDiscussion(context.Background(), 2, 3, input) if err != nil { t.Errorf("Teams.EditDiscussion returned error: %v", err) } @@ -369,30 +192,16 @@ func TestTeamsService_EditDiscussionByName(t *testing.T) { } } -func TestTeamsService_DeleteDiscussionByID(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/organizations/1/team/2/discussions/3", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "DELETE") - }) - - _, err := client.Teams.DeleteDiscussionByID(context.Background(), 1, 2, 3) - if err != nil { - t.Errorf("Teams.DeleteDiscussionByID returned error: %v", err) - } -} - -func TestTeamsService_DeleteDiscussionByName(t *testing.T) { +func TestTeamsService_DeleteDiscussion(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/orgs/o/teams/s/discussions/3", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/teams/2/discussions/3", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") }) - _, err := client.Teams.DeleteDiscussionByName(context.Background(), "o", "s", 3) + _, err := client.Teams.DeleteDiscussion(context.Background(), 2, 3) if err != nil { - t.Errorf("Teams.DeleteDiscussionByName returned error: %v", err) + t.Errorf("Teams.DeleteDiscussion returned error: %v", err) } } diff --git a/github/teams_members.go b/github/teams_members.go index 031130a6e4a..2a211fe9072 100644 --- a/github/teams_members.go +++ b/github/teams_members.go @@ -20,12 +20,12 @@ type TeamListTeamMembersOptions struct { ListOptions } -// ListTeamMembersByID lists all of the users who are members of the specified -// team given the team ID and organization ID. +// ListTeamMembers lists all of the users who are members of the specified +// team. // // GitHub API docs: https://developer.github.com/v3/teams/members/#list-team-members -func (s *TeamsService) ListTeamMembersByID(ctx context.Context, orgID, teamID int64, opt *TeamListTeamMembersOptions) ([]*User, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/members", orgID, teamID) +func (s *TeamsService) ListTeamMembers(ctx context.Context, team int64, opt *TeamListTeamMembersOptions) ([]*User, *Response, error) { + u := fmt.Sprintf("teams/%v/members", team) u, err := addOptions(u, opt) if err != nil { return nil, nil, err @@ -45,57 +45,29 @@ func (s *TeamsService) ListTeamMembersByID(ctx context.Context, orgID, teamID in return members, resp, nil } -// ListTeamMembersByName lists all of the users who are members of the specified -// team given the team slug and organization name. +// IsTeamMember checks if a user is a member of the specified team. // -// GitHub API docs: https://developer.github.com/v3/teams/members/#list-team-members -func (s *TeamsService) ListTeamMembersByName(ctx context.Context, org, slug string, opt *TeamListTeamMembersOptions) ([]*User, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/members", org, slug) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var members []*User - resp, err := s.client.Do(ctx, req, &members) - if err != nil { - return nil, resp, err - } - - return members, resp, nil -} - -// GetTeamMembershipByID returns the membership status for a user in a team -// given the team ID and organization ID. +// GitHub API docs: https://developer.github.com/v3/teams/members/#get-team-member // -// GitHub API docs: https://developer.github.com/v3/teams/members/#get-team-membership -func (s *TeamsService) GetTeamMembershipByID(ctx context.Context, orgID, teamID int64, user string) (*Membership, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/memberships/%v", orgID, teamID, user) +// Deprecated: This API has been marked as deprecated in the Github API docs, +// TeamsService.GetTeamMembership method should be used instead. +func (s *TeamsService) IsTeamMember(ctx context.Context, team int64, user string) (bool, *Response, error) { + u := fmt.Sprintf("teams/%v/members/%v", team, user) req, err := s.client.NewRequest("GET", u, nil) if err != nil { - return nil, nil, err + return false, nil, err } - t := new(Membership) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, nil + resp, err := s.client.Do(ctx, req, nil) + member, err := parseBoolResponse(err) + return member, resp, err } -// GetTeamMembershipByName returns the membership status for a user in a team -// given the team slug and organization name.. +// GetTeamMembership returns the membership status for a user in a team. // // GitHub API docs: https://developer.github.com/v3/teams/members/#get-team-membership -func (s *TeamsService) GetTeamMembershipByName(ctx context.Context, org, slug, user string) (*Membership, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/memberships/%v", org, slug, user) +func (s *TeamsService) GetTeamMembership(ctx context.Context, team int64, user string) (*Membership, *Response, error) { + u := fmt.Sprintf("teams/%v/memberships/%v", team, user) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err @@ -124,8 +96,7 @@ type TeamAddTeamMembershipOptions struct { Role string `json:"role,omitempty"` } -// AddTeamMembershipByID adds or invites a user to a team by the team ID -// and organization ID. +// AddTeamMembership adds or invites a user to a team. // // In order to add a membership between a user and a team, the authenticated // user must have 'admin' permissions to the team or be an owner of the @@ -143,8 +114,8 @@ type TeamAddTeamMembershipOptions struct { // added as a member of the team. // // GitHub API docs: https://developer.github.com/v3/teams/members/#add-or-update-team-membership -func (s *TeamsService) AddTeamMembershipByID(ctx context.Context, orgID, teamID int64, user string, opt *TeamAddTeamMembershipOptions) (*Membership, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/memberships/%v", orgID, teamID, user) +func (s *TeamsService) AddTeamMembership(ctx context.Context, team int64, user string, opt *TeamAddTeamMembershipOptions) (*Membership, *Response, error) { + u := fmt.Sprintf("teams/%v/memberships/%v", team, user) req, err := s.client.NewRequest("PUT", u, opt) if err != nil { return nil, nil, err @@ -159,61 +130,11 @@ func (s *TeamsService) AddTeamMembershipByID(ctx context.Context, orgID, teamID return t, resp, nil } -// AddTeamMembershipByName adds or invites a user to a team by the team slug -// and organiation name. -// -// In order to add a membership between a user and a team, the authenticated -// user must have 'admin' permissions to the team or be an owner of the -// organization that the team is associated with. -// -// If the user is already a part of the team's organization (meaning they're on -// at least one other team in the organization), this endpoint will add the -// user to the team. -// -// If the user is completely unaffiliated with the team's organization (meaning -// they're on none of the organization's teams), this endpoint will send an -// invitation to the user via email. This newly-created membership will be in -// the "pending" state until the user accepts the invitation, at which point -// the membership will transition to the "active" state and the user will be -// added as a member of the team. -// -// GitHub API docs: https://developer.github.com/v3/teams/members/#add-or-update-team-membership -func (s *TeamsService) AddTeamMembershipByName(ctx context.Context, org, slug, user string, opt *TeamAddTeamMembershipOptions) (*Membership, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/memberships/%v", org, slug, user) - req, err := s.client.NewRequest("PUT", u, opt) - if err != nil { - return nil, nil, err - } - - t := new(Membership) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, nil -} - -// RemoveTeamMembershipByID removes a user from a team given the team ID and -// organization ID. -// -// GitHub API docs: https://developer.github.com/v3/teams/members/#remove-team-membership -func (s *TeamsService) RemoveTeamMembershipByID(ctx context.Context, orgID, teamID int64, user string) (*Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/memberships/%v", orgID, teamID, user) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// RemoveTeamMembershipByName removes a user from a team given the team slug -// and organization name. +// RemoveTeamMembership removes a user from a team. // // GitHub API docs: https://developer.github.com/v3/teams/members/#remove-team-membership -func (s *TeamsService) RemoveTeamMembershipByName(ctx context.Context, org, slug, user string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/memberships/%v", org, slug, user) +func (s *TeamsService) RemoveTeamMembership(ctx context.Context, team int64, user string) (*Response, error) { + u := fmt.Sprintf("teams/%v/memberships/%v", team, user) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err @@ -222,41 +143,13 @@ func (s *TeamsService) RemoveTeamMembershipByName(ctx context.Context, org, slug return s.client.Do(ctx, req, nil) } -// ListPendingTeamInvitationsByID get pending invitaion list in team given the -// team ID and organization ID. -// Warning: The API may change without advance notice during the preview period. -// Preview features are not supported for production use. -// -// GitHub API docs: https://developer.github.com/v3/teams/members/#list-pending-team-invitations -func (s *TeamsService) ListPendingTeamInvitationsByID(ctx context.Context, orgID, teamID int64, opt *ListOptions) ([]*Invitation, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/invitations", orgID, teamID) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var pendingInvitations []*Invitation - resp, err := s.client.Do(ctx, req, &pendingInvitations) - if err != nil { - return nil, resp, err - } - - return pendingInvitations, resp, nil -} - -// ListPendingTeamInvitationsByName get pending invitaion list in team given the -// team slug and organization name. +// ListPendingTeamInvitations get pending invitaion list in team. // Warning: The API may change without advance notice during the preview period. // Preview features are not supported for production use. // // GitHub API docs: https://developer.github.com/v3/teams/members/#list-pending-team-invitations -func (s *TeamsService) ListPendingTeamInvitationsByName(ctx context.Context, org, slug string, opt *ListOptions) ([]*Invitation, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/invitations", org, slug) +func (s *TeamsService) ListPendingTeamInvitations(ctx context.Context, team int64, opt *ListOptions) ([]*Invitation, *Response, error) { + u := fmt.Sprintf("teams/%v/invitations", team) u, err := addOptions(u, opt) if err != nil { return nil, nil, err diff --git a/github/teams_members_test.go b/github/teams_members_test.go index 6f50000621e..616a747b410 100644 --- a/github/teams_members_test.go +++ b/github/teams_members_test.go @@ -12,129 +12,121 @@ import ( "net/http" "reflect" "testing" - "time" ) -func TestTeamsService__ListTeamMembersByID(t *testing.T) { +func TestTeamsService__ListTeamMembers(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/organizations/1/team/1/members", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/teams/1/members", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") testFormValues(t, r, values{"role": "member", "page": "2"}) fmt.Fprint(w, `[{"id":1}]`) }) opt := &TeamListTeamMembersOptions{Role: "member", ListOptions: ListOptions{Page: 2}} - members, _, err := client.Teams.ListTeamMembersByID(context.Background(), 1, 1, opt) + members, _, err := client.Teams.ListTeamMembers(context.Background(), 1, opt) if err != nil { - t.Errorf("Teams.ListTeamMembersByID returned error: %v", err) + t.Errorf("Teams.ListTeamMembers returned error: %v", err) } want := []*User{{ID: Int64(1)}} if !reflect.DeepEqual(members, want) { - t.Errorf("Teams.ListTeamMembersByID returned %+v, want %+v", members, want) + t.Errorf("Teams.ListTeamMembers returned %+v, want %+v", members, want) } } -func TestTeamsService__ListTeamMembersByName(t *testing.T) { +func TestTeamsService__IsTeamMember_true(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/orgs/o/teams/s/members", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/teams/1/members/u", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") - testFormValues(t, r, values{"role": "member", "page": "2"}) - fmt.Fprint(w, `[{"id":1}]`) }) - opt := &TeamListTeamMembersOptions{Role: "member", ListOptions: ListOptions{Page: 2}} - members, _, err := client.Teams.ListTeamMembersByName(context.Background(), "o", "s", opt) + member, _, err := client.Teams.IsTeamMember(context.Background(), 1, "u") if err != nil { - t.Errorf("Teams.ListTeamMembersByName returned error: %v", err) + t.Errorf("Teams.IsTeamMember returned error: %v", err) } - - want := []*User{{ID: Int64(1)}} - if !reflect.DeepEqual(members, want) { - t.Errorf("Teams.ListTeamMembers returned %+v, want %+v", members, want) + if want := true; member != want { + t.Errorf("Teams.IsTeamMember returned %+v, want %+v", member, want) } } -func TestTeamsService__GetTeamMembershipByID(t *testing.T) { +// ensure that a 404 response is interpreted as "false" and not an error +func TestTeamsService__IsTeamMember_false(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/organizations/1/team/1/memberships/u", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/teams/1/members/u", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") - fmt.Fprint(w, `{"url":"u", "state":"active"}`) + w.WriteHeader(http.StatusNotFound) }) - membership, _, err := client.Teams.GetTeamMembershipByID(context.Background(), 1, 1, "u") + member, _, err := client.Teams.IsTeamMember(context.Background(), 1, "u") if err != nil { - t.Errorf("Teams.GetTeamMembershipByID returned error: %v", err) + t.Errorf("Teams.IsTeamMember returned error: %+v", err) } - - want := &Membership{URL: String("u"), State: String("active")} - if !reflect.DeepEqual(membership, want) { - t.Errorf("Teams.GetTeamMembershipByID returned %+v, want %+v", membership, want) + if want := false; member != want { + t.Errorf("Teams.IsTeamMember returned %+v, want %+v", member, want) } } -func TestTeamsService__GetTeamMembershipByName(t *testing.T) { +// ensure that a 400 response is interpreted as an actual error, and not simply +// as "false" like the above case of a 404 +func TestTeamsService__IsTeamMember_error(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/orgs/o/teams/s/memberships/u", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/teams/1/members/u", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") - fmt.Fprint(w, `{"url":"u", "state":"active"}`) + http.Error(w, "BadRequest", http.StatusBadRequest) }) - membership, _, err := client.Teams.GetTeamMembershipByName(context.Background(), "o", "s", "u") - if err != nil { - t.Errorf("Teams.GetTeamMembershipByName returned error: %v", err) + member, _, err := client.Teams.IsTeamMember(context.Background(), 1, "u") + if err == nil { + t.Errorf("Expected HTTP 400 response") } - - want := &Membership{URL: String("u"), State: String("active")} - if !reflect.DeepEqual(membership, want) { - t.Errorf("Teams.GetTeamMembershipByName returned %+v, want %+v", membership, want) + if want := false; member != want { + t.Errorf("Teams.IsTeamMember returned %+v, want %+v", member, want) } } -func TestTeamsService__AddTeamMembershipByID(t *testing.T) { - client, mux, _, teardown := setup() +func TestTeamsService__IsTeamMember_invalidUser(t *testing.T) { + client, _, _, teardown := setup() defer teardown() - opt := &TeamAddTeamMembershipOptions{Role: "maintainer"} - - mux.HandleFunc("/organizations/1/team/1/memberships/u", func(w http.ResponseWriter, r *http.Request) { - v := new(TeamAddTeamMembershipOptions) - json.NewDecoder(r.Body).Decode(v) + _, _, err := client.Teams.IsTeamMember(context.Background(), 1, "%") + testURLParseError(t, err) +} - testMethod(t, r, "PUT") - if !reflect.DeepEqual(v, opt) { - t.Errorf("Request body = %+v, want %+v", v, opt) - } +func TestTeamsService__GetTeamMembership(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() - fmt.Fprint(w, `{"url":"u", "state":"pending"}`) + mux.HandleFunc("/teams/1/memberships/u", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{"url":"u", "state":"active"}`) }) - membership, _, err := client.Teams.AddTeamMembershipByID(context.Background(), 1, 1, "u", opt) + membership, _, err := client.Teams.GetTeamMembership(context.Background(), 1, "u") if err != nil { - t.Errorf("Teams.AddTeamMembershipByID returned error: %v", err) + t.Errorf("Teams.GetTeamMembership returned error: %v", err) } - want := &Membership{URL: String("u"), State: String("pending")} + want := &Membership{URL: String("u"), State: String("active")} if !reflect.DeepEqual(membership, want) { - t.Errorf("Teams.AddTeamMembershipByID returned %+v, want %+v", membership, want) + t.Errorf("Teams.GetTeamMembership returned %+v, want %+v", membership, want) } } -func TestTeamsService__AddTeamMembershipByName(t *testing.T) { +func TestTeamsService__AddTeamMembership(t *testing.T) { client, mux, _, teardown := setup() defer teardown() opt := &TeamAddTeamMembershipOptions{Role: "maintainer"} - mux.HandleFunc("/orgs/o/teams/s/memberships/u", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/teams/1/memberships/u", func(w http.ResponseWriter, r *http.Request) { v := new(TeamAddTeamMembershipOptions) json.NewDecoder(r.Body).Decode(v) @@ -146,197 +138,28 @@ func TestTeamsService__AddTeamMembershipByName(t *testing.T) { fmt.Fprint(w, `{"url":"u", "state":"pending"}`) }) - membership, _, err := client.Teams.AddTeamMembershipByName(context.Background(), "o", "s", "u", opt) + membership, _, err := client.Teams.AddTeamMembership(context.Background(), 1, "u", opt) if err != nil { - t.Errorf("Teams.AddTeamMembershipByName returned error: %v", err) + t.Errorf("Teams.AddTeamMembership returned error: %v", err) } want := &Membership{URL: String("u"), State: String("pending")} if !reflect.DeepEqual(membership, want) { - t.Errorf("Teams.AddTeamMembershipByName returned %+v, want %+v", membership, want) + t.Errorf("Teams.AddTeamMembership returned %+v, want %+v", membership, want) } } -func TestTeamsService__RemoveTeamMembershipByID(t *testing.T) { +func TestTeamsService__RemoveTeamMembership(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/organizations/1/team/1/memberships/u", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/teams/1/memberships/u", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") w.WriteHeader(http.StatusNoContent) }) - _, err := client.Teams.RemoveTeamMembershipByID(context.Background(), 1, 1, "u") + _, err := client.Teams.RemoveTeamMembership(context.Background(), 1, "u") if err != nil { - t.Errorf("Teams.RemoveTeamMembershipByID returned error: %v", err) - } -} - -func TestTeamsService__RemoveTeamMembershipByName(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/orgs/o/teams/s/memberships/u", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "DELETE") - w.WriteHeader(http.StatusNoContent) - }) - - _, err := client.Teams.RemoveTeamMembershipByName(context.Background(), "o", "s", "u") - if err != nil { - t.Errorf("Teams.RemoveTeamMembershipByName returned error: %v", err) - } -} - -func TestTeamsService_ListPendingTeamInvitationsByID(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/organizations/1/team/1/invitations", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - testFormValues(t, r, values{"page": "1"}) - fmt.Fprint(w, `[ - { - "id": 1, - "login": "monalisa", - "email": "octocat@github.com", - "role": "direct_member", - "created_at": "2017-01-21T00:00:00Z", - "inviter": { - "login": "other_user", - "id": 1, - "avatar_url": "https://github.com/images/error/other_user_happy.gif", - "gravatar_id": "", - "url": "https://api.github.com/users/other_user", - "html_url": "https://github.com/other_user", - "followers_url": "https://api.github.com/users/other_user/followers", - "following_url": "https://api.github.com/users/other_user/following/other_user", - "gists_url": "https://api.github.com/users/other_user/gists/gist_id", - "starred_url": "https://api.github.com/users/other_user/starred/owner/repo", - "subscriptions_url": "https://api.github.com/users/other_user/subscriptions", - "organizations_url": "https://api.github.com/users/other_user/orgs", - "repos_url": "https://api.github.com/users/other_user/repos", - "events_url": "https://api.github.com/users/other_user/events/privacy", - "received_events_url": "https://api.github.com/users/other_user/received_events/privacy", - "type": "User", - "site_admin": false - } - } - ]`) - }) - - opt := &ListOptions{Page: 1} - invitations, _, err := client.Teams.ListPendingTeamInvitationsByID(context.Background(), 1, 1, opt) - if err != nil { - t.Errorf("Teams.ListPendingTeamInvitationsByID returned error: %v", err) - } - - createdAt := time.Date(2017, time.January, 21, 0, 0, 0, 0, time.UTC) - want := []*Invitation{ - { - ID: Int64(1), - Login: String("monalisa"), - Email: String("octocat@github.com"), - Role: String("direct_member"), - CreatedAt: &createdAt, - Inviter: &User{ - Login: String("other_user"), - ID: Int64(1), - AvatarURL: String("https://github.com/images/error/other_user_happy.gif"), - GravatarID: String(""), - URL: String("https://api.github.com/users/other_user"), - HTMLURL: String("https://github.com/other_user"), - FollowersURL: String("https://api.github.com/users/other_user/followers"), - FollowingURL: String("https://api.github.com/users/other_user/following/other_user"), - GistsURL: String("https://api.github.com/users/other_user/gists/gist_id"), - StarredURL: String("https://api.github.com/users/other_user/starred/owner/repo"), - SubscriptionsURL: String("https://api.github.com/users/other_user/subscriptions"), - OrganizationsURL: String("https://api.github.com/users/other_user/orgs"), - ReposURL: String("https://api.github.com/users/other_user/repos"), - EventsURL: String("https://api.github.com/users/other_user/events/privacy"), - ReceivedEventsURL: String("https://api.github.com/users/other_user/received_events/privacy"), - Type: String("User"), - SiteAdmin: Bool(false), - }, - }} - - if !reflect.DeepEqual(invitations, want) { - t.Errorf("Teams.ListPendingTeamInvitationsByID returned %+v, want %+v", invitations, want) - } -} - -func TestTeamsService_ListPendingTeamInvitationsByName(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/orgs/o/teams/s/invitations", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - testFormValues(t, r, values{"page": "1"}) - fmt.Fprint(w, `[ - { - "id": 1, - "login": "monalisa", - "email": "octocat@github.com", - "role": "direct_member", - "created_at": "2017-01-21T00:00:00Z", - "inviter": { - "login": "other_user", - "id": 1, - "avatar_url": "https://github.com/images/error/other_user_happy.gif", - "gravatar_id": "", - "url": "https://api.github.com/users/other_user", - "html_url": "https://github.com/other_user", - "followers_url": "https://api.github.com/users/other_user/followers", - "following_url": "https://api.github.com/users/other_user/following/other_user", - "gists_url": "https://api.github.com/users/other_user/gists/gist_id", - "starred_url": "https://api.github.com/users/other_user/starred/owner/repo", - "subscriptions_url": "https://api.github.com/users/other_user/subscriptions", - "organizations_url": "https://api.github.com/users/other_user/orgs", - "repos_url": "https://api.github.com/users/other_user/repos", - "events_url": "https://api.github.com/users/other_user/events/privacy", - "received_events_url": "https://api.github.com/users/other_user/received_events/privacy", - "type": "User", - "site_admin": false - } - } - ]`) - }) - - opt := &ListOptions{Page: 1} - invitations, _, err := client.Teams.ListPendingTeamInvitationsByName(context.Background(), "o", "s", opt) - if err != nil { - t.Errorf("Teams.ListPendingTeamInvitationsByName returned error: %v", err) - } - - createdAt := time.Date(2017, time.January, 21, 0, 0, 0, 0, time.UTC) - want := []*Invitation{ - { - ID: Int64(1), - Login: String("monalisa"), - Email: String("octocat@github.com"), - Role: String("direct_member"), - CreatedAt: &createdAt, - Inviter: &User{ - Login: String("other_user"), - ID: Int64(1), - AvatarURL: String("https://github.com/images/error/other_user_happy.gif"), - GravatarID: String(""), - URL: String("https://api.github.com/users/other_user"), - HTMLURL: String("https://github.com/other_user"), - FollowersURL: String("https://api.github.com/users/other_user/followers"), - FollowingURL: String("https://api.github.com/users/other_user/following/other_user"), - GistsURL: String("https://api.github.com/users/other_user/gists/gist_id"), - StarredURL: String("https://api.github.com/users/other_user/starred/owner/repo"), - SubscriptionsURL: String("https://api.github.com/users/other_user/subscriptions"), - OrganizationsURL: String("https://api.github.com/users/other_user/orgs"), - ReposURL: String("https://api.github.com/users/other_user/repos"), - EventsURL: String("https://api.github.com/users/other_user/events/privacy"), - ReceivedEventsURL: String("https://api.github.com/users/other_user/received_events/privacy"), - Type: String("User"), - SiteAdmin: Bool(false), - }, - }} - - if !reflect.DeepEqual(invitations, want) { - t.Errorf("Teams.ListPendingTeamInvitationsByName returned %+v, want %+v", invitations, want) + t.Errorf("Teams.RemoveTeamMembership returned error: %v", err) } } diff --git a/github/teams_synchronization.go b/github/teams_synchronization.go deleted file mode 100644 index 1e275a33aba..00000000000 --- a/github/teams_synchronization.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2018 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// IDPGroupList represents a list of external identity provider (IDP) groups. -type IDPGroupList struct { - Groups []*IDPGroup `json:"groups"` -} - -// IDPGroup represents an external identity provider (IDP) group. -type IDPGroup struct { - GroupID *string `json:"group_id,omitempty"` - GroupName *string `json:"group_name,omitempty"` - GroupDescription *string `json:"group_description,omitempty"` -} - -// ListIDPGroupsInOrganization lists IDP groups available in an organization. -// -// GitHub API docs: https://developer.github.com/v3/teams/team_sync/#list-idp-groups-in-an-organization -func (s *TeamsService) ListIDPGroupsInOrganization(ctx context.Context, org string, opt *ListOptions) (*IDPGroupList, *Response, error) { - u := fmt.Sprintf("orgs/%v/team-sync/groups", org) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - groups := new(IDPGroupList) - resp, err := s.client.Do(ctx, req, groups) - if err != nil { - return nil, resp, err - } - return groups, resp, nil -} - -// ListIDPGroupsForTeamByID lists IDP groups connected to a team on GitHub -// given a team ID and organization ID. -// -// GitHub API docs: https://developer.github.com/v3/teams/team_sync/#list-idp-groups-for-a-team -func (s *TeamsService) ListIDPGroupsForTeamByID(ctx context.Context, orgID, teamID int64) (*IDPGroupList, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/team-sync/group-mappings", orgID, teamID) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - groups := new(IDPGroupList) - resp, err := s.client.Do(ctx, req, groups) - if err != nil { - return nil, resp, err - } - return groups, resp, err -} - -// ListIDPGroupsForTeamByName lists IDP groups connected to a team on GitHub -// given a team slug and orgnization name. -// -// GitHub API docs: https://developer.github.com/v3/teams/team_sync/#list-idp-groups-for-a-team -func (s *TeamsService) ListIDPGroupsForTeamByName(ctx context.Context, org, slug string) (*IDPGroupList, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/team-sync/group-mappings", org, slug) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - groups := new(IDPGroupList) - resp, err := s.client.Do(ctx, req, groups) - if err != nil { - return nil, resp, err - } - return groups, resp, err -} - -// CreateOrUpdateIDPGroupConnectionsByID creates, updates, or removes a connection between a team -// and an IDP group. Identifies organization and team by ID. -// -// GitHub API docs: https://developer.github.com/v3/teams/team_sync/#create-or-update-idp-group-connections -func (s *TeamsService) CreateOrUpdateIDPGroupConnectionsByID(ctx context.Context, orgID, teamID int64, opt IDPGroupList) (*IDPGroupList, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/team-sync/group-mappings", orgID, teamID) - - req, err := s.client.NewRequest("PATCH", u, opt) - if err != nil { - return nil, nil, err - } - - groups := new(IDPGroupList) - resp, err := s.client.Do(ctx, req, groups) - if err != nil { - return nil, resp, err - } - - return groups, resp, nil -} - -// CreateOrUpdateIDPGroupConnectionsByName creates, updates, or removes a connection between a team -// and an IDP group. Identifies organization by name and team by slug. -// -// GitHub API docs: https://developer.github.com/v3/teams/team_sync/#create-or-update-idp-group-connections -func (s *TeamsService) CreateOrUpdateIDPGroupConnectionsByName(ctx context.Context, org, slug string, opt IDPGroupList) (*IDPGroupList, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/team-sync/group-mappings", org, slug) - - req, err := s.client.NewRequest("PATCH", u, opt) - if err != nil { - return nil, nil, err - } - - groups := new(IDPGroupList) - resp, err := s.client.Do(ctx, req, groups) - if err != nil { - return nil, resp, err - } - - return groups, resp, nil -} diff --git a/github/teams_synchronization_test.go b/github/teams_synchronization_test.go deleted file mode 100644 index c604b157204..00000000000 --- a/github/teams_synchronization_test.go +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright 2018 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "net/http" - "reflect" - "testing" -) - -func TestTeamsService_ListIDPGroupsInOrganization(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/orgs/o/team-sync/groups", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - testFormValues(t, r, values{ - "page": "2", - }) - fmt.Fprint(w, `{"groups": [{"group_id": "1", "group_name": "n", "group_description": "d"}]}`) - }) - - opt := &ListOptions{Page: 2} - groups, _, err := client.Teams.ListIDPGroupsInOrganization(context.Background(), "o", opt) - if err != nil { - t.Errorf("Teams.ListIDPGroupsInOrganization returned error: %v", err) - } - - want := &IDPGroupList{ - Groups: []*IDPGroup{ - { - GroupID: String("1"), - GroupName: String("n"), - GroupDescription: String("d"), - }, - }, - } - if !reflect.DeepEqual(groups, want) { - t.Errorf("Teams.ListIDPGroupsInOrganization returned %+v. want %+v", groups, want) - } -} - -func TestTeamsService_ListIDPGroupsForTeamByID(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/organizations/1/team/1/team-sync/group-mappings", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - fmt.Fprint(w, `{"groups": [{"group_id": "1", "group_name": "n", "group_description": "d"}]}`) - }) - - groups, _, err := client.Teams.ListIDPGroupsForTeamByID(context.Background(), 1, 1) - if err != nil { - t.Errorf("Teams.ListIDPGroupsForTeamByID returned error: %v", err) - } - - want := &IDPGroupList{ - Groups: []*IDPGroup{ - { - GroupID: String("1"), - GroupName: String("n"), - GroupDescription: String("d"), - }, - }, - } - if !reflect.DeepEqual(groups, want) { - t.Errorf("Teams.ListIDPGroupsForTeamByID returned %+v. want %+v", groups, want) - } -} - -func TestTeamsService_ListIDPGroupsForTeamByName(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/orgs/o/teams/s/team-sync/group-mappings", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - fmt.Fprint(w, `{"groups": [{"group_id": "1", "group_name": "n", "group_description": "d"}]}`) - }) - - groups, _, err := client.Teams.ListIDPGroupsForTeamByName(context.Background(), "o", "s") - if err != nil { - t.Errorf("Teams.ListIDPGroupsForTeamByName returned error: %v", err) - } - - want := &IDPGroupList{ - Groups: []*IDPGroup{ - { - GroupID: String("1"), - GroupName: String("n"), - GroupDescription: String("d"), - }, - }, - } - if !reflect.DeepEqual(groups, want) { - t.Errorf("Teams.ListIDPGroupsForTeamByName returned %+v. want %+v", groups, want) - } -} - -func TestTeamsService_CreateOrUpdateIDPGroupConnectionsByID(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/organizations/1/team/1/team-sync/group-mappings", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "PATCH") - fmt.Fprint(w, `{"groups": [{"group_id": "1", "group_name": "n", "group_description": "d"}]}`) - }) - - input := IDPGroupList{ - Groups: []*IDPGroup{ - { - GroupID: String("1"), - GroupName: String("n"), - GroupDescription: String("d"), - }, - }, - } - - groups, _, err := client.Teams.CreateOrUpdateIDPGroupConnectionsByID(context.Background(), 1, 1, input) - if err != nil { - t.Errorf("Teams.CreateOrUpdateIDPGroupConnectionsByID returned error: %v", err) - } - - want := &IDPGroupList{ - Groups: []*IDPGroup{ - { - GroupID: String("1"), - GroupName: String("n"), - GroupDescription: String("d"), - }, - }, - } - if !reflect.DeepEqual(groups, want) { - t.Errorf("Teams.CreateOrUpdateIDPGroupConnectionsByID returned %+v. want %+v", groups, want) - } -} - -func TestTeamsService_CreateOrUpdateIDPGroupConnectionsByName(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/orgs/o/teams/s/team-sync/group-mappings", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "PATCH") - fmt.Fprint(w, `{"groups": [{"group_id": "1", "group_name": "n", "group_description": "d"}]}`) - }) - - input := IDPGroupList{ - Groups: []*IDPGroup{ - { - GroupID: String("1"), - GroupName: String("n"), - GroupDescription: String("d"), - }, - }, - } - - groups, _, err := client.Teams.CreateOrUpdateIDPGroupConnectionsByName(context.Background(), "o", "s", input) - if err != nil { - t.Errorf("Teams.CreateOrUpdateIDPGroupConnectionsByName returned error: %v", err) - } - - want := &IDPGroupList{ - Groups: []*IDPGroup{ - { - GroupID: String("1"), - GroupName: String("n"), - GroupDescription: String("d"), - }, - }, - } - if !reflect.DeepEqual(groups, want) { - t.Errorf("Teams.CreateOrUpdateIDPGroupConnectionsByName returned %+v. want %+v", groups, want) - } -} - -func TestTeamsService_CreateOrUpdateIDPGroupConnectionsByID_empty(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/organizations/1/team/1/team-sync/group-mappings", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "PATCH") - fmt.Fprint(w, `{"groups": []}`) - }) - - input := IDPGroupList{ - Groups: []*IDPGroup{}, - } - - groups, _, err := client.Teams.CreateOrUpdateIDPGroupConnectionsByID(context.Background(), 1, 1, input) - if err != nil { - t.Errorf("Teams.CreateOrUpdateIDPGroupConnectionsByID returned error: %v", err) - } - - want := &IDPGroupList{ - Groups: []*IDPGroup{}, - } - if !reflect.DeepEqual(groups, want) { - t.Errorf("Teams.CreateOrUpdateIDPGroupConnectionsByID returned %+v. want %+v", groups, want) - } -} - -func TestTeamsService_CreateOrUpdateIDPGroupConnectionsByName_empty(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/orgs/o/teams/s/team-sync/group-mappings", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "PATCH") - fmt.Fprint(w, `{"groups": []}`) - }) - - input := IDPGroupList{ - Groups: []*IDPGroup{}, - } - - groups, _, err := client.Teams.CreateOrUpdateIDPGroupConnectionsByName(context.Background(), "o", "s", input) - if err != nil { - t.Errorf("Teams.CreateOrUpdateIDPGroupConnectionsByName returned error: %v", err) - } - - want := &IDPGroupList{ - Groups: []*IDPGroup{}, - } - if !reflect.DeepEqual(groups, want) { - t.Errorf("Teams.CreateOrUpdateIDPGroupConnectionsByName returned %+v. want %+v", groups, want) - } -} diff --git a/github/teams_test.go b/github/teams_test.go index 56694a193f3..414ad78e7fc 100644 --- a/github/teams_test.go +++ b/github/teams_test.go @@ -242,7 +242,7 @@ func TestTeamsService_EditTeamByID_RemoveParent(t *testing.T) { } } -func TestTeamsService_EditTeamByName(t *testing.T) { +func TestTeamsService_EditTeamBySlug(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -260,18 +260,18 @@ func TestTeamsService_EditTeamByName(t *testing.T) { fmt.Fprint(w, `{"id":1}`) }) - team, _, err := client.Teams.EditTeamByName(context.Background(), "o", "s", input, false) + team, _, err := client.Teams.EditTeamBySlug(context.Background(), "o", "s", input, false) if err != nil { - t.Errorf("Teams.EditTeamByName returned error: %v", err) + t.Errorf("Teams.EditTeamBySlug returned error: %v", err) } want := &Team{ID: Int64(1)} if !reflect.DeepEqual(team, want) { - t.Errorf("Teams.EditTeamByName returned %+v, want %+v", team, want) + t.Errorf("Teams.EditTeamBySlug returned %+v, want %+v", team, want) } } -func TestTeamsService_EditTeamByName_RemoveParent(t *testing.T) { +func TestTeamsService_EditTeamBySlug_RemoveParent(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -295,7 +295,7 @@ func TestTeamsService_EditTeamByName_RemoveParent(t *testing.T) { fmt.Fprint(w, `{"id":1}`) }) - team, _, err := client.Teams.EditTeamByName(context.Background(), "o", "s", input, true) + team, _, err := client.Teams.EditTeamBySlug(context.Background(), "o", "s", input, true) if err != nil { t.Errorf("Teams.EditTeam returned error: %v", err) } @@ -324,7 +324,7 @@ func TestTeamsService_DeleteTeamByID(t *testing.T) { } } -func TestTeamsService_DeleteTeamByName(t *testing.T) { +func TestTeamsService_DeleteTeamBySlug(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -332,9 +332,9 @@ func TestTeamsService_DeleteTeamByName(t *testing.T) { testMethod(t, r, "DELETE") }) - _, err := client.Teams.DeleteTeamByName(context.Background(), "o", "s") + _, err := client.Teams.DeleteTeamBySlug(context.Background(), "o", "s") if err != nil { - t.Errorf("Teams.DeleteTeamByName returned error: %v", err) + t.Errorf("Teams.DeleteTeamBySlug returned error: %v", err) } } @@ -360,7 +360,7 @@ func TestTeamsService_ListChildTeamsByParentID(t *testing.T) { } } -func TestTeamsService_ListChildTeamsByParentName(t *testing.T) { +func TestTeamsService_ListChildTeamsByParentSlug(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -371,14 +371,14 @@ func TestTeamsService_ListChildTeamsByParentName(t *testing.T) { }) opt := &ListOptions{Page: 2} - teams, _, err := client.Teams.ListChildTeamsByParentName(context.Background(), "o", "s", opt) + teams, _, err := client.Teams.ListChildTeamsByParentSlug(context.Background(), "o", "s", opt) if err != nil { - t.Errorf("Teams.ListChildTeamsByParentName returned error: %v", err) + t.Errorf("Teams.ListChildTeamsByParentSlug returned error: %v", err) } want := []*Team{{ID: Int64(2)}} if !reflect.DeepEqual(teams, want) { - t.Errorf("Teams.ListChildTeamsByParentName returned %+v, want %+v", teams, want) + t.Errorf("Teams.ListChildTeamsByParentSlug returned %+v, want %+v", teams, want) } } @@ -406,7 +406,7 @@ func TestTeamsService_ListTeamReposByID(t *testing.T) { } } -func TestTeamsService_ListTeamReposByName(t *testing.T) { +func TestTeamsService_ListTeamReposBySlug(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -419,14 +419,14 @@ func TestTeamsService_ListTeamReposByName(t *testing.T) { }) opt := &ListOptions{Page: 2} - members, _, err := client.Teams.ListTeamReposByName(context.Background(), "o", "s", opt) + members, _, err := client.Teams.ListTeamReposBySlug(context.Background(), "o", "s", opt) if err != nil { - t.Errorf("Teams.ListTeamReposByName returned error: %v", err) + t.Errorf("Teams.ListTeamReposBySlug returned error: %v", err) } want := []*Repository{{ID: Int64(1)}} if !reflect.DeepEqual(members, want) { - t.Errorf("Teams.ListTeamReposByName returned %+v, want %+v", members, want) + t.Errorf("Teams.ListTeamReposBySlug returned %+v, want %+v", members, want) } } @@ -452,7 +452,7 @@ func TestTeamsService_IsTeamRepoByID_true(t *testing.T) { } } -func TestTeamsService_IsTeamRepoByName_true(t *testing.T) { +func TestTeamsService_IsTeamRepoBySlug_true(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -463,14 +463,14 @@ func TestTeamsService_IsTeamRepoByName_true(t *testing.T) { fmt.Fprint(w, `{"id":1}`) }) - repo, _, err := client.Teams.IsTeamRepoByName(context.Background(), "org", "slug", "owner", "repo") + repo, _, err := client.Teams.IsTeamRepoBySlug(context.Background(), "org", "slug", "owner", "repo") if err != nil { - t.Errorf("Teams.IsTeamRepoByName returned error: %v", err) + t.Errorf("Teams.IsTeamRepoBySlug returned error: %v", err) } want := &Repository{ID: Int64(1)} if !reflect.DeepEqual(repo, want) { - t.Errorf("Teams.IsTeamRepoByName returned %+v, want %+v", repo, want) + t.Errorf("Teams.IsTeamRepoBySlug returned %+v, want %+v", repo, want) } } @@ -495,16 +495,16 @@ func TestTeamsService_IsTeamRepoByID_false(t *testing.T) { } } -func TestTeamsService_IsTeamRepoByName_false(t *testing.T) { +func TestTeamsService_IsTeamRepoBySlug_false(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/orgs/org/teams/slug/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/org/teams/slug/repos/o/r", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") w.WriteHeader(http.StatusNotFound) }) - repo, resp, err := client.Teams.IsTeamRepoByName(context.Background(), "org", "slug", "owner", "repo") + repo, resp, err := client.Teams.IsTeamRepoBySlug(context.Background(), "org", "slug", "owner", "repo") if err == nil { t.Errorf("Expected HTTP 404 response") } @@ -537,7 +537,7 @@ func TestTeamsService_IsTeamRepoByID_error(t *testing.T) { } } -func TestTeamsService_IsTeamRepoByName_error(t *testing.T) { +func TestTeamsService_IsTeamRepoBySlug_error(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -546,15 +546,15 @@ func TestTeamsService_IsTeamRepoByName_error(t *testing.T) { http.Error(w, "BadRequest", http.StatusBadRequest) }) - repo, resp, err := client.Teams.IsTeamRepoByName(context.Background(), "org", "slug", "owner", "repo") + repo, resp, err := client.Teams.IsTeamRepoBySlug(context.Background(), "org", "slug", "owner", "repo") if err == nil { t.Errorf("Expected HTTP 400 response") } if got, want := resp.Response.StatusCode, http.StatusBadRequest; got != want { - t.Errorf("Teams.IsTeamRepoByName returned status %d, want %d", got, want) + t.Errorf("Teams.IsTeamRepoBySlug returned status %d, want %d", got, want) } if repo != nil { - t.Errorf("Teams.IsTeamRepoByName returned %+v, want nil", repo) + t.Errorf("Teams.IsTeamRepoBySlug returned %+v, want nil", repo) } } @@ -566,11 +566,11 @@ func TestTeamsService_IsTeamRepoByID_invalidOwner(t *testing.T) { testURLParseError(t, err) } -func TestTeamsService_IsTeamRepoByName_invalidOwner(t *testing.T) { +func TestTeamsService_IsTeamRepoBySlug_invalidOwner(t *testing.T) { client, _, _, teardown := setup() defer teardown() - _, _, err := client.Teams.IsTeamRepoByName(context.Background(), "o", "s", "%", "r") + _, _, err := client.Teams.IsTeamRepoBySlug(context.Background(), "o", "s", "%", "r") testURLParseError(t, err) } @@ -598,7 +598,7 @@ func TestTeamsService_AddTeamRepoByID(t *testing.T) { } } -func TestTeamsService_AddTeamRepoByName(t *testing.T) { +func TestTeamsService_AddTeamRepoBySlug(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -616,9 +616,9 @@ func TestTeamsService_AddTeamRepoByName(t *testing.T) { w.WriteHeader(http.StatusNoContent) }) - _, err := client.Teams.AddTeamRepoByName(context.Background(), "org", "slug", "owner", "repo", opt) + _, err := client.Teams.AddTeamRepoBySlug(context.Background(), "org", "slug", "owner", "repo", opt) if err != nil { - t.Errorf("Teams.AddTeamRepoByName returned error: %v", err) + t.Errorf("Teams.AddTeamRepoBySlug returned error: %v", err) } } @@ -637,16 +637,16 @@ func TestTeamsService_AddTeamRepoByID_noAccess(t *testing.T) { } } -func TestTeamsService_AddTeamRepoByName_noAccess(t *testing.T) { +func TestTeamsService_AddTeamRepoBySlug_noAccess(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/orgs/org/teams/slug/repos/owner/repo", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/orgs/org/teams/slug/repos/o/r", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") w.WriteHeader(http.StatusUnprocessableEntity) }) - _, err := client.Teams.AddTeamRepoByName(context.Background(), "org", "slug", "owner", "repo", nil) + _, err := client.Teams.AddTeamRepoBySlug(context.Background(), "org", "slug", "owner", "repo", nil) if err == nil { t.Errorf("Expcted error to be returned") } @@ -660,11 +660,11 @@ func TestTeamsService_AddTeamRepoByID_invalidOwner(t *testing.T) { testURLParseError(t, err) } -func TestTeamsService_AddTeamRepoByName_invalidOwner(t *testing.T) { +func TestTeamsService_AddTeamRepoBySlug_invalidOwner(t *testing.T) { client, _, _, teardown := setup() defer teardown() - _, err := client.Teams.AddTeamRepoByName(context.Background(), "o", "s", "%", "r", nil) + _, err := client.Teams.AddTeamRepoBySlug(context.Background(), "o", "s", "%", "r", nil) testURLParseError(t, err) } @@ -683,7 +683,7 @@ func TestTeamsService_RemoveTeamRepoByID(t *testing.T) { } } -func TestTeamsService_RemoveTeamRepoByName(t *testing.T) { +func TestTeamsService_RemoveTeamRepoBySlug(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -692,9 +692,9 @@ func TestTeamsService_RemoveTeamRepoByName(t *testing.T) { w.WriteHeader(http.StatusNoContent) }) - _, err := client.Teams.RemoveTeamRepoByName(context.Background(), "org", "slug", "owner", "repo") + _, err := client.Teams.RemoveTeamRepoBySlug(context.Background(), "org", "slug", "owner", "repo") if err != nil { - t.Errorf("Teams.RemoveTeamRepoByName returned error: %v", err) + t.Errorf("Teams.RemoveTeamRepoBySlug returned error: %v", err) } } @@ -706,11 +706,11 @@ func TestTeamsService_RemoveTeamRepoByID_invalidOwner(t *testing.T) { testURLParseError(t, err) } -func TestTeamsService_RemoveTeamRepoByName_invalidOwner(t *testing.T) { +func TestTeamsService_RemoveTeamRepoBySlug_invalidOwner(t *testing.T) { client, _, _, teardown := setup() defer teardown() - _, err := client.Teams.RemoveTeamRepoByName(context.Background(), "o", "s", "%", "r") + _, err := client.Teams.RemoveTeamRepoBySlug(context.Background(), "o", "s", "%", "r") testURLParseError(t, err) } @@ -758,7 +758,7 @@ func TestTeamsService_ListProjectsByID(t *testing.T) { } } -func TestTeamsService_ListProjectsByName(t *testing.T) { +func TestTeamsService_ListProjectsBySlug(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -769,14 +769,14 @@ func TestTeamsService_ListProjectsByName(t *testing.T) { fmt.Fprint(w, `[{"id":1}]`) }) - projects, _, err := client.Teams.ListTeamProjectsByName(context.Background(), "o", "s") + projects, _, err := client.Teams.ListTeamProjectsBySlug(context.Background(), "o", "s") if err != nil { - t.Errorf("Teams.ListTeamProjectsByName returned error: %v", err) + t.Errorf("Teams.ListTeamProjectsBySlug returned error: %v", err) } want := []*Project{{ID: Int64(1)}} if !reflect.DeepEqual(projects, want) { - t.Errorf("Teams.ListTeamProjectsByName returned %+v, want %+v", projects, want) + t.Errorf("Teams.ListTeamProjectsBySlug returned %+v, want %+v", projects, want) } } @@ -802,7 +802,7 @@ func TestTeamsService_ReviewProjectsByID(t *testing.T) { } } -func TestTeamsService_ReviewProjectsByName(t *testing.T) { +func TestTeamsService_ReviewProjectsBySlug(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -813,14 +813,14 @@ func TestTeamsService_ReviewProjectsByName(t *testing.T) { fmt.Fprint(w, `{"id":1}`) }) - project, _, err := client.Teams.ReviewTeamProjectsByName(context.Background(), "o", "s", 1) + project, _, err := client.Teams.ReviewTeamProjectsBySlug(context.Background(), "o", "s", 1) if err != nil { - t.Errorf("Teams.ReviewTeamProjectsByName returned error: %v", err) + t.Errorf("Teams.ReviewTeamProjectsBySlug returned error: %v", err) } want := &Project{ID: Int64(1)} if !reflect.DeepEqual(project, want) { - t.Errorf("Teams.ReviewTeamProjectsByName returned %+v, want %+v", project, want) + t.Errorf("Teams.ReviewTeamProjectsBySlug returned %+v, want %+v", project, want) } } @@ -852,7 +852,7 @@ func TestTeamsService_AddTeamProjectByID(t *testing.T) { } } -func TestTeamsService_AddTeamProjectByName(t *testing.T) { +func TestTeamsService_AddTeamProjectBySlug(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -874,9 +874,9 @@ func TestTeamsService_AddTeamProjectByName(t *testing.T) { w.WriteHeader(http.StatusNoContent) }) - _, err := client.Teams.AddTeamProjectByName(context.Background(), "o", "s", 1, opt) + _, err := client.Teams.AddTeamProjectBySlug(context.Background(), "o", "s", 1, opt) if err != nil { - t.Errorf("Teams.AddTeamProjectByName returned error: %v", err) + t.Errorf("Teams.AddTeamProjectBySlug returned error: %v", err) } } @@ -897,7 +897,7 @@ func TestTeamsService_RemoveTeamProjectByID(t *testing.T) { } } -func TestTeamsService_RemoveTeamProjectByName(t *testing.T) { +func TestTeamsService_RemoveTeamProjectBySlug(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -908,8 +908,132 @@ func TestTeamsService_RemoveTeamProjectByName(t *testing.T) { w.WriteHeader(http.StatusNoContent) }) - _, err := client.Teams.RemoveTeamProjectByName(context.Background(), "o", "s", 1) + _, err := client.Teams.RemoveTeamProjectBySlug(context.Background(), "o", "s", 1) + if err != nil { + t.Errorf("Teams.RemoveTeamProjectBySlug returned error: %v", err) + } +} + +func TestTeamsService_ListIDPGroupsInOrganization(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/team-sync/groups", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testFormValues(t, r, values{ + "page": "url-encoded-next-page-token", + }) + fmt.Fprint(w, `{"groups": [{"group_id": "1", "group_name": "n", "group_description": "d"}]}`) + }) + + opt := &ListCursorOptions{Page: "url-encoded-next-page-token"} + groups, _, err := client.Teams.ListIDPGroupsInOrganization(context.Background(), "o", opt) + if err != nil { + t.Errorf("Teams.ListIDPGroupsInOrganization returned error: %v", err) + } + + want := &IDPGroupList{ + Groups: []*IDPGroup{ + { + GroupID: String("1"), + GroupName: String("n"), + GroupDescription: String("d"), + }, + }, + } + if !reflect.DeepEqual(groups, want) { + t.Errorf("Teams.ListIDPGroupsInOrganization returned %+v. want %+v", groups, want) + } +} + +func TestTeamsService_ListIDPGroupsForTeam(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/teams/1/team-sync/group-mappings", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{"groups": [{"group_id": "1", "group_name": "n", "group_description": "d"}]}`) + }) + + groups, _, err := client.Teams.ListIDPGroupsForTeam(context.Background(), "1") + if err != nil { + t.Errorf("Teams.ListIDPGroupsForTeam returned error: %v", err) + } + + want := &IDPGroupList{ + Groups: []*IDPGroup{ + { + GroupID: String("1"), + GroupName: String("n"), + GroupDescription: String("d"), + }, + }, + } + if !reflect.DeepEqual(groups, want) { + t.Errorf("Teams.ListIDPGroupsForTeam returned %+v. want %+v", groups, want) + } +} + +func TestTeamsService_CreateOrUpdateIDPGroupConnections(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/teams/1/team-sync/group-mappings", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PATCH") + fmt.Fprint(w, `{"groups": [{"group_id": "1", "group_name": "n", "group_description": "d"}]}`) + }) + + input := IDPGroupList{ + Groups: []*IDPGroup{ + { + GroupID: String("1"), + GroupName: String("n"), + GroupDescription: String("d"), + }, + }, + } + + groups, _, err := client.Teams.CreateOrUpdateIDPGroupConnections(context.Background(), "1", input) if err != nil { - t.Errorf("Teams.RemoveTeamProjectByName returned error: %v", err) + t.Errorf("Teams.CreateOrUpdateIDPGroupConnections returned error: %v", err) + } + + want := &IDPGroupList{ + Groups: []*IDPGroup{ + { + GroupID: String("1"), + GroupName: String("n"), + GroupDescription: String("d"), + }, + }, + } + if !reflect.DeepEqual(groups, want) { + t.Errorf("Teams.CreateOrUpdateIDPGroupConnections returned %+v. want %+v", groups, want) + } +} + +func TestTeamsService_CreateOrUpdateIDPGroupConnections_empty(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/teams/1/team-sync/group-mappings", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PATCH") + fmt.Fprint(w, `{"groups": []}`) + }) + + input := IDPGroupList{ + Groups: []*IDPGroup{}, + } + + groups, _, err := client.Teams.CreateOrUpdateIDPGroupConnections(context.Background(), "1", input) + if err != nil { + t.Errorf("Teams.CreateOrUpdateIDPGroupConnections returned error: %v", err) + } + + want := &IDPGroupList{ + Groups: []*IDPGroup{}, + } + if !reflect.DeepEqual(groups, want) { + t.Errorf("Teams.CreateOrUpdateIDPGroupConnections returned %+v. want %+v", groups, want) } }