Skip to content
This repository was archived by the owner on Apr 15, 2026. It is now read-only.

Commit 3a7bf00

Browse files
feat(cost-centers): add data sources for enterprise cost centers
Add two data sources: - github_enterprise_cost_center: retrieve a cost center by ID - github_enterprise_cost_centers: list cost centers with optional state filter Includes: - Data source implementations - Acceptance tests - Documentation
1 parent d1a2726 commit 3a7bf00

6 files changed

Lines changed: 364 additions & 0 deletions
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package github
2+
3+
import (
4+
"context"
5+
6+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
8+
)
9+
10+
func dataSourceGithubEnterpriseCostCenter() *schema.Resource {
11+
return &schema.Resource{
12+
Description: "Use this data source to retrieve information about a specific enterprise cost center.",
13+
ReadContext: dataSourceGithubEnterpriseCostCenterRead,
14+
15+
Schema: map[string]*schema.Schema{
16+
"enterprise_slug": {
17+
Type: schema.TypeString,
18+
Required: true,
19+
Description: "The slug of the enterprise.",
20+
},
21+
"cost_center_id": {
22+
Type: schema.TypeString,
23+
Required: true,
24+
Description: "The ID of the cost center.",
25+
},
26+
"name": {
27+
Type: schema.TypeString,
28+
Computed: true,
29+
Description: "The name of the cost center.",
30+
},
31+
"state": {
32+
Type: schema.TypeString,
33+
Computed: true,
34+
Description: "The state of the cost center.",
35+
},
36+
"azure_subscription": {
37+
Type: schema.TypeString,
38+
Computed: true,
39+
Description: "The Azure subscription associated with the cost center.",
40+
},
41+
"users": {
42+
Type: schema.TypeSet,
43+
Computed: true,
44+
Elem: &schema.Schema{Type: schema.TypeString},
45+
Description: "The usernames assigned to this cost center.",
46+
},
47+
"organizations": {
48+
Type: schema.TypeSet,
49+
Computed: true,
50+
Elem: &schema.Schema{Type: schema.TypeString},
51+
Description: "The organization logins assigned to this cost center.",
52+
},
53+
"repositories": {
54+
Type: schema.TypeSet,
55+
Computed: true,
56+
Elem: &schema.Schema{Type: schema.TypeString},
57+
Description: "The repositories (full name) assigned to this cost center.",
58+
},
59+
},
60+
}
61+
}
62+
63+
func dataSourceGithubEnterpriseCostCenterRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
64+
client := meta.(*Owner).v3client
65+
enterpriseSlug := d.Get("enterprise_slug").(string)
66+
costCenterID := d.Get("cost_center_id").(string)
67+
68+
cc, _, err := client.Enterprise.GetCostCenter(ctx, enterpriseSlug, costCenterID)
69+
if err != nil {
70+
return diag.FromErr(err)
71+
}
72+
73+
d.SetId(costCenterID)
74+
if err := d.Set("name", cc.Name); err != nil {
75+
return diag.FromErr(err)
76+
}
77+
78+
if err := d.Set("state", cc.GetState()); err != nil {
79+
return diag.FromErr(err)
80+
}
81+
if err := d.Set("azure_subscription", cc.GetAzureSubscription()); err != nil {
82+
return diag.FromErr(err)
83+
}
84+
85+
// Extract resources by type
86+
users := make([]string, 0)
87+
organizations := make([]string, 0)
88+
repositories := make([]string, 0)
89+
for _, resource := range cc.Resources {
90+
if resource == nil {
91+
continue
92+
}
93+
switch resource.Type {
94+
case "User":
95+
users = append(users, resource.Name)
96+
case "Org":
97+
organizations = append(organizations, resource.Name)
98+
case "Repo":
99+
repositories = append(repositories, resource.Name)
100+
}
101+
}
102+
103+
if err := d.Set("users", users); err != nil {
104+
return diag.FromErr(err)
105+
}
106+
if err := d.Set("organizations", organizations); err != nil {
107+
return diag.FromErr(err)
108+
}
109+
if err := d.Set("repositories", repositories); err != nil {
110+
return diag.FromErr(err)
111+
}
112+
113+
return nil
114+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package github
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
9+
)
10+
11+
func TestAccGithubEnterpriseCostCenterDataSource(t *testing.T) {
12+
randomID := acctest.RandString(5)
13+
14+
resource.Test(t, resource.TestCase{
15+
PreCheck: func() { skipUnlessEnterprise(t) },
16+
ProviderFactories: providerFactories,
17+
Steps: []resource.TestStep{{
18+
Config: fmt.Sprintf(`
19+
data "github_enterprise" "enterprise" {
20+
slug = "%s"
21+
}
22+
23+
resource "github_enterprise_cost_center" "test" {
24+
enterprise_slug = data.github_enterprise.enterprise.slug
25+
name = "%s%s"
26+
}
27+
28+
data "github_enterprise_cost_center" "test" {
29+
enterprise_slug = data.github_enterprise.enterprise.slug
30+
cost_center_id = github_enterprise_cost_center.test.id
31+
}
32+
`, testAccConf.enterpriseSlug, testResourcePrefix, randomID),
33+
Check: resource.ComposeTestCheckFunc(
34+
resource.TestCheckResourceAttrPair("data.github_enterprise_cost_center.test", "cost_center_id", "github_enterprise_cost_center.test", "id"),
35+
resource.TestCheckResourceAttrPair("data.github_enterprise_cost_center.test", "name", "github_enterprise_cost_center.test", "name"),
36+
resource.TestCheckResourceAttr("data.github_enterprise_cost_center.test", "state", "active"),
37+
),
38+
}},
39+
})
40+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package github
2+
3+
import (
4+
"context"
5+
6+
"github.com/google/go-github/v81/github"
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
10+
)
11+
12+
func dataSourceGithubEnterpriseCostCenters() *schema.Resource {
13+
return &schema.Resource{
14+
Description: "Use this data source to retrieve a list of enterprise cost centers.",
15+
ReadContext: dataSourceGithubEnterpriseCostCentersRead,
16+
17+
Schema: map[string]*schema.Schema{
18+
"enterprise_slug": {
19+
Type: schema.TypeString,
20+
Required: true,
21+
Description: "The slug of the enterprise.",
22+
},
23+
"state": {
24+
Type: schema.TypeString,
25+
Optional: true,
26+
ValidateDiagFunc: validation.ToDiagFunc(validation.StringInSlice([]string{"active", "deleted"}, false)),
27+
Description: "Filter cost centers by state.",
28+
},
29+
"cost_centers": {
30+
Type: schema.TypeSet,
31+
Computed: true,
32+
Description: "The list of cost centers.",
33+
Elem: &schema.Resource{
34+
Schema: map[string]*schema.Schema{
35+
"id": {
36+
Type: schema.TypeString,
37+
Computed: true,
38+
Description: "The cost center ID.",
39+
},
40+
"name": {
41+
Type: schema.TypeString,
42+
Computed: true,
43+
Description: "The name of the cost center.",
44+
},
45+
"state": {
46+
Type: schema.TypeString,
47+
Computed: true,
48+
Description: "The state of the cost center.",
49+
},
50+
"azure_subscription": {
51+
Type: schema.TypeString,
52+
Computed: true,
53+
Description: "The Azure subscription associated with the cost center.",
54+
},
55+
},
56+
},
57+
},
58+
},
59+
}
60+
}
61+
62+
func dataSourceGithubEnterpriseCostCentersRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
63+
client := meta.(*Owner).v3client
64+
enterpriseSlug := d.Get("enterprise_slug").(string)
65+
var state *string
66+
if v, ok := d.GetOk("state"); ok {
67+
state = github.Ptr(v.(string))
68+
}
69+
70+
result, _, err := client.Enterprise.ListCostCenters(ctx, enterpriseSlug, &github.ListCostCenterOptions{State: state})
71+
if err != nil {
72+
return diag.FromErr(err)
73+
}
74+
75+
items := make([]any, 0, len(result.CostCenters))
76+
for _, cc := range result.CostCenters {
77+
if cc == nil {
78+
continue
79+
}
80+
items = append(items, map[string]any{
81+
"id": cc.ID,
82+
"name": cc.Name,
83+
"state": cc.GetState(),
84+
"azure_subscription": cc.GetAzureSubscription(),
85+
})
86+
}
87+
88+
stateStr := "all"
89+
if state != nil {
90+
stateStr = *state
91+
}
92+
id, err := buildID(enterpriseSlug, stateStr)
93+
if err != nil {
94+
return diag.FromErr(err)
95+
}
96+
d.SetId(id)
97+
if err := d.Set("cost_centers", items); err != nil {
98+
return diag.FromErr(err)
99+
}
100+
return nil
101+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package github
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
9+
)
10+
11+
func TestAccGithubEnterpriseCostCentersDataSource(t *testing.T) {
12+
randomID := acctest.RandString(5)
13+
14+
config := fmt.Sprintf(`
15+
data "github_enterprise" "enterprise" {
16+
slug = "%s"
17+
}
18+
19+
resource "github_enterprise_cost_center" "test" {
20+
enterprise_slug = data.github_enterprise.enterprise.slug
21+
name = "%s%s"
22+
}
23+
24+
data "github_enterprise_cost_centers" "test" {
25+
enterprise_slug = data.github_enterprise.enterprise.slug
26+
state = "active"
27+
depends_on = [github_enterprise_cost_center.test]
28+
}
29+
`, testAccConf.enterpriseSlug, testResourcePrefix, randomID)
30+
31+
resource.Test(t, resource.TestCase{
32+
PreCheck: func() { skipUnlessEnterprise(t) },
33+
ProviderFactories: providerFactories,
34+
Steps: []resource.TestStep{{
35+
Config: config,
36+
Check: resource.ComposeTestCheckFunc(
37+
resource.TestCheckResourceAttr("data.github_enterprise_cost_centers.test", "state", "active"),
38+
resource.TestCheckTypeSetElemAttrPair("data.github_enterprise_cost_centers.test", "cost_centers.*.id", "github_enterprise_cost_center.test", "id"),
39+
),
40+
}},
41+
})
42+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
layout: "github"
3+
page_title: "GitHub: github_enterprise_cost_center"
4+
description: |-
5+
Get a GitHub enterprise cost center by ID.
6+
---
7+
8+
# github_enterprise_cost_center
9+
10+
Use this data source to retrieve a GitHub enterprise cost center by ID.
11+
12+
## Example Usage
13+
14+
```
15+
data "github_enterprise_cost_center" "example" {
16+
enterprise_slug = "example-enterprise"
17+
cost_center_id = "cc_123456"
18+
}
19+
```
20+
21+
## Argument Reference
22+
23+
* `enterprise_slug` - (Required) The slug of the enterprise.
24+
* `cost_center_id` - (Required) The ID of the cost center.
25+
26+
## Attributes Reference
27+
28+
* `name` - The name of the cost center.
29+
* `state` - The state of the cost center.
30+
* `azure_subscription` - The Azure subscription associated with the cost center.
31+
* `users` - The usernames currently assigned to the cost center.
32+
* `organizations` - The organization logins currently assigned to the cost center.
33+
* `repositories` - The repositories currently assigned to the cost center.
34+
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
layout: "github"
3+
page_title: "GitHub: github_enterprise_cost_centers"
4+
description: |-
5+
List GitHub enterprise cost centers.
6+
---
7+
8+
# github_enterprise_cost_centers
9+
10+
Use this data source to list GitHub enterprise cost centers.
11+
12+
## Example Usage
13+
14+
```
15+
data "github_enterprise_cost_centers" "active" {
16+
enterprise_slug = "example-enterprise"
17+
state = "active"
18+
}
19+
```
20+
21+
## Argument Reference
22+
23+
* `enterprise_slug` - (Required) The slug of the enterprise.
24+
* `state` - (Optional) Filter cost centers by state. Valid values are `active` and `deleted`.
25+
26+
## Attributes Reference
27+
28+
* `cost_centers` - A set of cost centers.
29+
* `id` - The cost center ID.
30+
* `name` - The name of the cost center.
31+
* `state` - The state of the cost center.
32+
* `azure_subscription` - The Azure subscription associated with the cost center.
33+

0 commit comments

Comments
 (0)