diff --git a/github/data_source_github_organization_teams.go b/github/data_source_github_organization_teams.go new file mode 100644 index 0000000000..2bbac579ee --- /dev/null +++ b/github/data_source_github_organization_teams.go @@ -0,0 +1,134 @@ +package github + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/shurcooL/githubv4" + "log" +) + +func dataSourceGithubOrganizationTeams() *schema.Resource { + return &schema.Resource{ + Read: dataSourceGithubOrganizationTeamsRead, + + Schema: map[string]*schema.Schema{ + "root_teams_only": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "teams": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeInt, + Computed: true, + }, + "node_id": { + Type: schema.TypeString, + Computed: true, + }, + "slug": { + Type: schema.TypeString, + Required: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "privacy": { + Type: schema.TypeString, + Computed: true, + }, + "members": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + }, + } +} + +func dataSourceGithubOrganizationTeamsRead(d *schema.ResourceData, meta interface{}) error { + err := checkOrganization(meta) + if err != nil { + return err + } + + client := meta.(*Owner).v4client + orgName := meta.(*Owner).name + rootTeamsOnly := d.Get("root_teams_only").(bool) + + log.Print("[INFO] Refreshing GitHub Teams for Organization: ", orgName) + + var query TeamsQuery + variables := map[string]interface{}{ + "first": githubv4.Int(100), + "login": githubv4.String(orgName), + "cursor": (*githubv4.String)(nil), + "rootTeamsOnly": githubv4.Boolean(rootTeamsOnly), + } + + var teams []interface{} + for { + err = client.Query(meta.(*Owner).StopContext, &query, variables) + if err != nil { + return err + } + + additionalTeams := flattenGitHubTeams(query) + teams = append(teams, additionalTeams...) + + if !query.Organization.Teams.PageInfo.HasNextPage { + break + } + variables["cursor"] = githubv4.NewString(query.Organization.Teams.PageInfo.EndCursor) + } + + d.SetId(string(query.Organization.ID)) + d.Set("teams", teams) + + return nil +} + +func flattenGitHubTeams(tq TeamsQuery) []interface{} { + teams := tq.Organization.Teams.Nodes + + if len(teams) == 0 { + return make([]interface{}, 0) + } + + flatTeams := make([]interface{}, len(teams)) + + for i, team := range teams { + t := make(map[string]interface{}) + + t["id"] = team.DatabaseID + t["node_id"] = team.ID + t["slug"] = team.Slug + t["name"] = team.Name + t["description"] = team.Description + t["privacy"] = team.Privacy + + members := team.Members.Nodes + flatMembers := make([]string, len(members)) + + for i, member := range members { + flatMembers[i] = string(member.Login) + } + + t["members"] = flatMembers + + flatTeams[i] = t + } + + return flatTeams +} diff --git a/github/data_source_github_organization_teams_test.go b/github/data_source_github_organization_teams_test.go new file mode 100644 index 0000000000..1fb94910bb --- /dev/null +++ b/github/data_source_github_organization_teams_test.go @@ -0,0 +1,90 @@ +package github + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccGithubOrganizationTeamsDataSource(t *testing.T) { + + t.Run("queries without error", func(t *testing.T) { + + config := fmt.Sprintf(` + data "github_organization_teams" "all" {} + `) + + check := resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("data.github_organization_teams.all", "teams.0.id"), + resource.TestCheckResourceAttrSet("data.github_organization_teams.all", "teams.0.node_id"), + ) + + testCase := func(t *testing.T, mode string) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnlessMode(t, mode) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: config, + Check: check, + }, + }, + }) + } + + t.Run("with an anonymous account", func(t *testing.T) { + t.Skip("anonymous account not supported for this operation") + }) + + t.Run("with an individual account", func(t *testing.T) { + t.Skip("individual account not supported for this operation") + }) + + t.Run("with an organization account", func(t *testing.T) { + testCase(t, organization) + }) + + }) + + t.Run("queries root teams only without error", func(t *testing.T) { + + config := fmt.Sprintf(` + data "github_organization_teams" "root_teams" { + root_teams_only = true + } + `) + + check := resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("data.github_organization_teams.root_teams", "teams.0.id"), + resource.TestCheckResourceAttrSet("data.github_organization_teams.root_teams", "teams.0.node_id"), + ) + + testCase := func(t *testing.T, mode string) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnlessMode(t, mode) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: config, + Check: check, + }, + }, + }) + } + + t.Run("with an anonymous account", func(t *testing.T) { + t.Skip("anonymous account not supported for this operation") + }) + + t.Run("with an individual account", func(t *testing.T) { + t.Skip("individual account not supported for this operation") + }) + + t.Run("with an organization account", func(t *testing.T) { + testCase(t, organization) + }) + + }) + +} diff --git a/github/provider.go b/github/provider.go index 73129fa50c..bdbeaa2771 100644 --- a/github/provider.go +++ b/github/provider.go @@ -79,6 +79,7 @@ func Provider() terraform.ResourceProvider { "github_membership": dataSourceGithubMembership(), "github_organization": dataSourceGithubOrganization(), "github_organization_team_sync_groups": dataSourceGithubOrganizationTeamSyncGroups(), + "github_organization_teams": dataSourceGithubOrganizationTeams(), "github_release": dataSourceGithubRelease(), "github_repositories": dataSourceGithubRepositories(), "github_repository": dataSourceGithubRepository(), diff --git a/github/util_v4_teams.go b/github/util_v4_teams.go new file mode 100644 index 0000000000..dba6f98829 --- /dev/null +++ b/github/util_v4_teams.go @@ -0,0 +1,25 @@ +package github + +import "github.com/shurcooL/githubv4" + +type TeamsQuery struct { + Organization struct { + ID githubv4.String + Teams struct { + Nodes []struct { + ID githubv4.String + DatabaseID githubv4.Int + Slug githubv4.String + Name githubv4.String + Description githubv4.String + Privacy githubv4.String + Members struct { + Nodes []struct { + Login githubv4.String + } + } + } + PageInfo PageInfo + } `graphql:"teams(first:$first, after:$cursor, rootTeamsOnly:$rootTeamsOnly)"` + } `graphql:"organization(login:$login)"` +} diff --git a/website/docs/d/organization_teams.html.markdown b/website/docs/d/organization_teams.html.markdown new file mode 100644 index 0000000000..266670c6d5 --- /dev/null +++ b/website/docs/d/organization_teams.html.markdown @@ -0,0 +1,42 @@ +--- +layout: "github" +page_title: "GitHub: github_organization_teams" +description: |- + Get information on all GitHub teams of an organization. +--- + +# github\_organization\_teams + +Use this data source to retrieve information about all GitHub teams in an organization. + +## Example Usage + +To retrieve *all* teams of the organization: + +```hcl +data "github_organization_teams" "all" {} +``` + +To retrieve only the team's at the root of the organization: + +```hcl +data "github_organization_teams" "root_teams" { + root_teams_only = true +} +``` + +## Attributes Reference + +* `root_teams_only` - Only return teams that are at the organization's root, i.e. no nested teams. Defaults to `false`. +* `teams` - An Array of GitHub Teams. Each `team` block consists of the fields documented below. +___ + +The `team` block consists of: + + * `id` - the ID of the team. + * `node_id` - the Node ID of the team. + * `slug` - the slug of the team. + * `name` - the team's full name. + * `description` - the team's description. + * `privacy` - the team's privacy type. + * `members` - List of team members. diff --git a/website/github.erb b/website/github.erb index 4435d0b77d..f846bfc428 100644 --- a/website/github.erb +++ b/website/github.erb @@ -34,6 +34,9 @@