Skip to content
Open
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
99 changes: 99 additions & 0 deletions examples/cost_centers/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
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.
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
}

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.example.users))
organizations = sort(tolist(github_enterprise_cost_center.example.organizations))
repositories = sort(tolist(github_enterprise_cost_center.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
users = sort(tolist(data.github_enterprise_cost_center.by_id.users))
organizations = sort(tolist(data.github_enterprise_cost_center.by_id.organizations))
repositories = sort(tolist(data.github_enterprise_cost_center.by_id.repositories))
}
}
121 changes: 121 additions & 0 deletions github/data_source_github_enterprise_cost_center.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package github

import (
"context"
"fmt"
"sort"
"strings"

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

func dataSourceGithubEnterpriseCostCenter() *schema.Resource {
return &schema.Resource{
ReadContext: 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.",
},
"users": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
Description: "The usernames assigned to this cost center.",
},
"organizations": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
Description: "The organization logins assigned to this cost center.",
},
"repositories": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
Description: "The repositories (full name) assigned to this 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(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
client := meta.(*Owner).v3client
enterpriseSlug := d.Get("enterprise_slug").(string)
costCenterID := d.Get("cost_center_id").(string)

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

cc, err := enterpriseCostCenterGet(ctx, client, enterpriseSlug, costCenterID)
if err != nil {
return diag.FromErr(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)

users, organizations, repositories := enterpriseCostCenterSplitResources(cc.Resources)
sort.Strings(users)
sort.Strings(organizations)
sort.Strings(repositories)
_ = d.Set("users", stringSliceToAnySlice(users))
_ = d.Set("organizations", stringSliceToAnySlice(organizations))
_ = d.Set("repositories", stringSliceToAnySlice(repositories))

return nil
}
79 changes: 79 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,79 @@
package github

import (
"fmt"
"os"
"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")
}
testEnterpriseCostCenterOrganization := os.Getenv("ENTERPRISE_TEST_ORGANIZATION")
testEnterpriseCostCenterRepository := os.Getenv("ENTERPRISE_TEST_REPOSITORY")
testEnterpriseCostCenterUsers := os.Getenv("ENTERPRISE_TEST_USERS")

if testEnterpriseCostCenterOrganization == "" {
t.Skip("Skipping because `ENTERPRISE_TEST_ORGANIZATION` is not set")
}
if testEnterpriseCostCenterRepository == "" {
t.Skip("Skipping because `ENTERPRISE_TEST_REPOSITORY` is not set")
}
if testEnterpriseCostCenterUsers == "" {
t.Skip("Skipping because `ENTERPRISE_TEST_USERS` is not set")
}

users := splitCommaSeparated(testEnterpriseCostCenterUsers)
if len(users) == 0 {
t.Skip("Skipping because `ENTERPRISE_TEST_USERS` must contain at least one username")
}

userList := fmt.Sprintf("%q", users[0])

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"

users = [%s]
organizations = [%q]
repositories = [%q]
}

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

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.TestCheckResourceAttr("data.github_enterprise_cost_center.test", "organizations.#", "1"),
resource.TestCheckTypeSetElemAttr("data.github_enterprise_cost_center.test", "organizations.*", testEnterpriseCostCenterOrganization),
resource.TestCheckResourceAttr("data.github_enterprise_cost_center.test", "repositories.#", "1"),
resource.TestCheckTypeSetElemAttr("data.github_enterprise_cost_center.test", "repositories.*", testEnterpriseCostCenterRepository),
resource.TestCheckResourceAttr("data.github_enterprise_cost_center.test", "users.#", "1"),
resource.TestCheckTypeSetElemAttr("data.github_enterprise_cost_center.test", "users.*", users[0]),
)

resource.Test(t, resource.TestCase{
PreCheck: func() { skipUnlessMode(t, enterprise) },
Providers: testAccProviders,
Steps: []resource.TestStep{{Config: config, Check: check}},
})
}
Loading