Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions examples/cost_centers/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
terraform {
required_providers {
github = {
source = "integrations/github"
version = "~> 6.0"
}
}
}

provider "github" {
token = var.github_token
}

variable "github_token" {
description = "GitHub classic personal access token (PAT) for an enterprise admin"
type = string
sensitive = true
}

variable "enterprise_slug" {
description = "The GitHub Enterprise slug"
type = string
}

variable "cost_center_name" {
description = "Name for the cost center"
type = string
}

variable "users" {
description = "Usernames to assign to the cost center"
type = list(string)
default = []
}

variable "organizations" {
description = "Organization logins to assign to the cost center"
type = list(string)
default = []
}

variable "repositories" {
description = "Repositories (full name, e.g. org/repo) to assign to the cost center"
type = list(string)
default = []
}

resource "github_enterprise_cost_center" "example" {
enterprise_slug = var.enterprise_slug
name = var.cost_center_name
}

# Authoritative assignments: Terraform will add/remove to match these lists.
resource "github_enterprise_cost_center_resources" "example" {
enterprise_slug = var.enterprise_slug
cost_center_id = github_enterprise_cost_center.example.id

users = var.users
organizations = var.organizations
repositories = var.repositories
}

data "github_enterprise_cost_center" "by_id" {
enterprise_slug = var.enterprise_slug
cost_center_id = github_enterprise_cost_center.example.id

depends_on = [github_enterprise_cost_center_resources.example]
}

data "github_enterprise_cost_centers" "active" {
enterprise_slug = var.enterprise_slug
state = "active"

depends_on = [github_enterprise_cost_center.example]
}

output "cost_center" {
description = "Created cost center"
value = {
id = github_enterprise_cost_center.example.id
name = github_enterprise_cost_center.example.name
state = github_enterprise_cost_center.example.state
azure_subscription = github_enterprise_cost_center.example.azure_subscription
}
}

output "cost_center_resources" {
description = "Effective assignments (read from API)"
value = {
users = sort(tolist(github_enterprise_cost_center_resources.example.users))
organizations = sort(tolist(github_enterprise_cost_center_resources.example.organizations))
repositories = sort(tolist(github_enterprise_cost_center_resources.example.repositories))
}
}

output "cost_center_from_data_source" {
description = "Cost center fetched by data source"
value = {
id = data.github_enterprise_cost_center.by_id.cost_center_id
name = data.github_enterprise_cost_center.by_id.name
state = data.github_enterprise_cost_center.by_id.state
}
}
93 changes: 93 additions & 0 deletions github/data_source_github_enterprise_cost_center.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package github

import (
"context"
"fmt"
"strings"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func dataSourceGithubEnterpriseCostCenter() *schema.Resource {
return &schema.Resource{
Read: dataSourceGithubEnterpriseCostCenterRead,

Schema: map[string]*schema.Schema{
"enterprise_slug": {
Type: schema.TypeString,
Required: true,
Description: "The slug of the enterprise.",
},
"cost_center_id": {
Type: schema.TypeString,
Required: true,
Description: "The ID of the cost center.",
},
"name": {
Type: schema.TypeString,
Computed: true,
Description: "The name of the cost center.",
},
"state": {
Type: schema.TypeString,
Computed: true,
Description: "The state of the cost center.",
},
"azure_subscription": {
Type: schema.TypeString,
Computed: true,
Description: "The Azure subscription associated with the cost center.",
},
"resources": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"type": {
Type: schema.TypeString,
Computed: true,
},
"name": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
},
}
}

func dataSourceGithubEnterpriseCostCenterRead(d *schema.ResourceData, meta any) error {
client := meta.(*Owner).v3client
enterpriseSlug := d.Get("enterprise_slug").(string)
costCenterID := d.Get("cost_center_id").(string)

ctx := context.WithValue(context.Background(), ctxId, fmt.Sprintf("%s/%s", enterpriseSlug, costCenterID))

cc, err := enterpriseCostCenterGet(ctx, client, enterpriseSlug, costCenterID)
if err != nil {
return err
}

d.SetId(costCenterID)
_ = d.Set("name", cc.Name)

state := strings.ToLower(cc.State)
if state == "" {
state = "active"
}
_ = d.Set("state", state)
_ = d.Set("azure_subscription", cc.AzureSubscription)

resources := make([]map[string]any, 0)
for _, r := range cc.Resources {
resources = append(resources, map[string]any{
"type": r.Type,
"name": r.Name,
})
}
_ = d.Set("resources", resources)

return nil
}
48 changes: 48 additions & 0 deletions github/data_source_github_enterprise_cost_center_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package github

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccGithubEnterpriseCostCenterDataSource(t *testing.T) {
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)

if isEnterprise != "true" {
t.Skip("Skipping because `ENTERPRISE_ACCOUNT` is not set or set to false")
}
if testEnterprise == "" {
t.Skip("Skipping because `ENTERPRISE_SLUG` is not set")
}

config := fmt.Sprintf(`
data "github_enterprise" "enterprise" {
slug = "%s"
}

resource "github_enterprise_cost_center" "test" {
enterprise_slug = data.github_enterprise.enterprise.slug
name = "tf-acc-test-%s"
}

data "github_enterprise_cost_center" "test" {
enterprise_slug = data.github_enterprise.enterprise.slug
cost_center_id = github_enterprise_cost_center.test.id
}
`, testEnterprise, randomID)

check := resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrPair("data.github_enterprise_cost_center.test", "cost_center_id", "github_enterprise_cost_center.test", "id"),
resource.TestCheckResourceAttrPair("data.github_enterprise_cost_center.test", "name", "github_enterprise_cost_center.test", "name"),
resource.TestCheckResourceAttr("data.github_enterprise_cost_center.test", "state", "active"),
)

resource.Test(t, resource.TestCase{
PreCheck: func() { skipUnlessMode(t, enterprise) },
Providers: testAccProviders,
Steps: []resource.TestStep{{Config: config, Check: check}},
})
}
97 changes: 97 additions & 0 deletions github/data_source_github_enterprise_cost_centers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package github

import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

func dataSourceGithubEnterpriseCostCenters() *schema.Resource {
return &schema.Resource{
Read: dataSourceGithubEnterpriseCostCentersRead,

Schema: map[string]*schema.Schema{
"enterprise_slug": {
Type: schema.TypeString,
Required: true,
Description: "The slug of the enterprise.",
},
"state": {
Type: schema.TypeString,
Optional: true,
ValidateDiagFunc: toDiagFunc(validation.StringInSlice([]string{"active", "deleted"}, false), "state"),
Description: "Filter cost centers by state.",
},
"cost_centers": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
Computed: true,
},
"name": {
Type: schema.TypeString,
Computed: true,
},
"state": {
Type: schema.TypeString,
Computed: true,
},
"azure_subscription": {
Type: schema.TypeString,
Computed: true,
},
"resources": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"type": {Type: schema.TypeString, Computed: true},
"name": {Type: schema.TypeString, Computed: true},
},
},
},
},
},
},
},
}
}

func dataSourceGithubEnterpriseCostCentersRead(d *schema.ResourceData, meta any) error {
client := meta.(*Owner).v3client
enterpriseSlug := d.Get("enterprise_slug").(string)
state := ""
if v, ok := d.GetOk("state"); ok {
state = v.(string)
}

ctx := context.WithValue(context.Background(), ctxId, fmt.Sprintf("%s/cost-centers", enterpriseSlug))
centers, err := enterpriseCostCentersList(ctx, client, enterpriseSlug, state)
if err != nil {
return err
}

items := make([]any, 0, len(centers))
for _, cc := range centers {
resources := make([]map[string]any, 0)
for _, r := range cc.Resources {
resources = append(resources, map[string]any{"type": r.Type, "name": r.Name})
}
items = append(items, map[string]any{
"id": cc.ID,
"name": cc.Name,
"state": cc.State,
"azure_subscription": cc.AzureSubscription,
"resources": resources,
})
}

d.SetId(fmt.Sprintf("%s/%s", enterpriseSlug, state))
_ = d.Set("cost_centers", items)
return nil
}
Loading