Skip to content

Commit

Permalink
Add github_teams data source (#725)
Browse files Browse the repository at this point in the history
* Add github_teams data source

* Add id field to teams field of github_teams data source

* Add website docs for github_teams data source

* Fix linting errors in data_source_github_teams.go

* Rename github_teams to github_organization_teams

This better reflects that the data source fetches all teams for an organization.

* Add root_teams_only attribute to github_organization_teams

Setting the attribute to true causes the query to only return teams at the root of the organization.

* Add link to github_organization_teams docs in sidebar

* Use organization ID in datasource ID

This makes the ID deterministic and prevents overriding the  behaviour.

* Simplify ID of github_organization_teams data source

Adding the root_teams_only property to the ID is not needed.
Two datasources having the same ID property is no problem.
  • Loading branch information
reinoudk authored Apr 9, 2021
1 parent 9e571a9 commit c2cead9
Show file tree
Hide file tree
Showing 6 changed files with 295 additions and 0 deletions.
134 changes: 134 additions & 0 deletions github/data_source_github_organization_teams.go
Original file line number Diff line number Diff line change
@@ -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
}
90 changes: 90 additions & 0 deletions github/data_source_github_organization_teams_test.go
Original file line number Diff line number Diff line change
@@ -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)
})

})

}
1 change: 1 addition & 0 deletions github/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
25 changes: 25 additions & 0 deletions github/util_v4_teams.go
Original file line number Diff line number Diff line change
@@ -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)"`
}
42 changes: 42 additions & 0 deletions website/docs/d/organization_teams.html.markdown
Original file line number Diff line number Diff line change
@@ -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.
3 changes: 3 additions & 0 deletions website/github.erb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
<li>
<a href="/docs/providers/github/d/organization_team_sync_groups.html">github_organization_team_sync_groups</a>
</li>
<li>
<a href="/docs/providers/github/d/organization_teams.html">github_organization_teams</a>
</li>
<li>
<a href="/docs/providers/github/d/release.html">github_release</a>
</li>
Expand Down

0 comments on commit c2cead9

Please sign in to comment.