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
3 changes: 3 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ linters:
- linters:
- staticcheck
text: "SA1019.*ByID.*deprecated"
- linters:
- modernize
text: "newexpr: call of Ptr"

issues:
max-issues-per-linter: 0
Expand Down
213 changes: 213 additions & 0 deletions github/data_source_github_enterprise_billing_premium_request_usage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
package github

import (
"context"

"github.com/google/go-github/v84/github"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

func dataSourceGithubEnterpriseBillingPremiumRequestUsage() *schema.Resource {
return &schema.Resource{
Description: "Gets a billing premium request usage report for a GitHub enterprise.",
ReadContext: dataSourceGithubEnterpriseBillingPremiumRequestUsageRead,
Schema: map[string]*schema.Schema{
"enterprise_slug": {
Type: schema.TypeString,
Required: true,
Description: "The slug of the enterprise.",
ValidateDiagFunc: validation.ToDiagFunc(validation.StringIsNotEmpty),
},
"year": {
Type: schema.TypeInt,
Optional: true,
Description: "If specified, only return results for a single year.",
ValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(2000)),
},
"month": {
Type: schema.TypeInt,
Optional: true,
Description: "If specified, only return results for a single month. Value between 1 and 12.",
ValidateDiagFunc: validation.ToDiagFunc(validation.IntBetween(1, 12)),
},
"day": {
Type: schema.TypeInt,
Optional: true,
Description: "If specified, only return results for a single day. Value between 1 and 31.",
ValidateDiagFunc: validation.ToDiagFunc(validation.IntBetween(1, 31)),
},
"organization": {
Type: schema.TypeString,
Optional: true,
Description: "The organization name to query usage for.",
},
"user": {
Type: schema.TypeString,
Optional: true,
Description: "The user name to query usage for.",
},
"model": {
Type: schema.TypeString,
Optional: true,
Description: "The model name to query usage for.",
},
"product": {
Type: schema.TypeString,
Optional: true,
Description: "The product name to query usage for.",
},
"cost_center_id": {
Type: schema.TypeString,
Optional: true,
Description: "The ID corresponding to a cost center. Use `none` to target usage not associated to any cost center.",
},
"time_period": {
Type: schema.TypeList,
Computed: true,
Description: "The time period of the report.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"year": {
Type: schema.TypeInt,
Computed: true,
Description: "The year of the time period.",
},
"month": {
Type: schema.TypeInt,
Computed: true,
Description: "The month of the time period.",
},
"day": {
Type: schema.TypeInt,
Computed: true,
Description: "The day of the time period.",
},
},
},
},
"enterprise": {
Type: schema.TypeString,
Computed: true,
Description: "The enterprise name from the report.",
},
"usage_items": {
Type: schema.TypeList,
Computed: true,
Description: "The list of premium request usage items.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"product": {
Type: schema.TypeString,
Computed: true,
Description: "The product name.",
},
"sku": {
Type: schema.TypeString,
Computed: true,
Description: "The SKU name.",
},
"model": {
Type: schema.TypeString,
Computed: true,
Description: "The model name.",
},
"unit_type": {
Type: schema.TypeString,
Computed: true,
Description: "The type of unit for the usage.",
},
"price_per_unit": {
Type: schema.TypeFloat,
Computed: true,
Description: "The price per unit of usage.",
},
"gross_quantity": {
Type: schema.TypeFloat,
Computed: true,
Description: "The gross quantity of usage.",
},
"gross_amount": {
Type: schema.TypeFloat,
Computed: true,
Description: "The gross amount of usage.",
},
"discount_quantity": {
Type: schema.TypeFloat,
Computed: true,
Description: "The discount quantity applied.",
},
"discount_amount": {
Type: schema.TypeFloat,
Computed: true,
Description: "The discount amount applied.",
},
"net_quantity": {
Type: schema.TypeFloat,
Computed: true,
Description: "The net quantity after discounts.",
},
"net_amount": {
Type: schema.TypeFloat,
Computed: true,
Description: "The net amount after discounts.",
},
},
},
},
},
}
}

func dataSourceGithubEnterpriseBillingPremiumRequestUsageRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
client := meta.(*Owner).v3client
enterpriseSlug := d.Get("enterprise_slug").(string)

opts := &EnterprisePremiumRequestUsageOptions{}
if yearVal, ok := d.GetOk("year"); ok {
opts.Year = github.Ptr(yearVal.(int))
}
if monthVal, ok := d.GetOk("month"); ok {
opts.Month = github.Ptr(monthVal.(int))
}
if dayVal, ok := d.GetOk("day"); ok {
opts.Day = github.Ptr(dayVal.(int))
}
if orgVal, ok := d.GetOk("organization"); ok {
opts.Organization = github.Ptr(orgVal.(string))
}
if userVal, ok := d.GetOk("user"); ok {
opts.User = github.Ptr(userVal.(string))
}
if modelVal, ok := d.GetOk("model"); ok {
opts.Model = github.Ptr(modelVal.(string))
}
if productVal, ok := d.GetOk("product"); ok {
opts.Product = github.Ptr(productVal.(string))
}
if costCenterID, ok := d.GetOk("cost_center_id"); ok {
opts.CostCenterID = github.Ptr(costCenterID.(string))
}

report, err := getEnterprisePremiumRequestUsage(ctx, client, enterpriseSlug, opts)
if err != nil {
return diag.Errorf("error getting enterprise billing premium request usage for %q: %s", enterpriseSlug, err)
}

d.SetId(buildTwoPartID(enterpriseSlug, "billing-premium-request-usage"))

if err := d.Set("time_period", flattenTimePeriod(report.TimePeriod)); err != nil {
return diag.FromErr(err)
}
if report.Enterprise != nil {
if err := d.Set("enterprise", *report.Enterprise); err != nil {
return diag.FromErr(err)
}
}
if err := d.Set("usage_items", flattenPremiumRequestUsageItems(report.UsageItems)); err != nil {
return diag.FromErr(err)
}

return nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package github

import (
"fmt"
"regexp"
"testing"

"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/knownvalue"
"github.com/hashicorp/terraform-plugin-testing/statecheck"
"github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
)

func TestAccGithubEnterpriseBillingPremiumRequestUsage(t *testing.T) {
t.Run("reads premium request usage without error", func(t *testing.T) {
config := fmt.Sprintf(`
data "github_enterprise_billing_premium_request_usage" "test" {
enterprise_slug = "%s"
}
`, testAccConf.enterpriseSlug)

resource.Test(t, resource.TestCase{
PreCheck: func() { skipUnlessMode(t, enterprise) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: config,
ConfigStateChecks: []statecheck.StateCheck{
statecheck.ExpectKnownValue("data.github_enterprise_billing_premium_request_usage.test",
tfjsonpath.New("enterprise_slug"),
knownvalue.StringExact(testAccConf.enterpriseSlug),
),
statecheck.ExpectKnownValue("data.github_enterprise_billing_premium_request_usage.test",
tfjsonpath.New("id"),
knownvalue.StringRegexp(regexp.MustCompile(`^.+:billing-premium-request-usage$`)),
),
statecheck.ExpectKnownValue("data.github_enterprise_billing_premium_request_usage.test",
tfjsonpath.New("usage_items"),
knownvalue.NotNull(),
),
statecheck.ExpectKnownValue("data.github_enterprise_billing_premium_request_usage.test",
tfjsonpath.New("time_period"),
knownvalue.NotNull(),
),
},
},
},
})
})

t.Run("reads premium request usage with filters without error", func(t *testing.T) {
config := fmt.Sprintf(`
data "github_enterprise_billing_premium_request_usage" "test" {
enterprise_slug = "%s"
year = 2025
month = 1
}
`, testAccConf.enterpriseSlug)

resource.Test(t, resource.TestCase{
PreCheck: func() { skipUnlessMode(t, enterprise) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: config,
ConfigStateChecks: []statecheck.StateCheck{
statecheck.ExpectKnownValue("data.github_enterprise_billing_premium_request_usage.test",
tfjsonpath.New("enterprise_slug"),
knownvalue.StringExact(testAccConf.enterpriseSlug),
),
statecheck.ExpectKnownValue("data.github_enterprise_billing_premium_request_usage.test",
tfjsonpath.New("usage_items"),
knownvalue.NotNull(),
),
statecheck.ExpectKnownValue("data.github_enterprise_billing_premium_request_usage.test",
tfjsonpath.New("time_period"),
knownvalue.NotNull(),
),
},
},
},
})
})
}
Loading