Skip to content
Draft
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
122 changes: 122 additions & 0 deletions github/data_source_github_actions_hosted_runner_custom_image.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package github

import (
"context"
"fmt"
"strconv"

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

func dataSourceGithubActionsHostedRunnerCustomImage() *schema.Resource {
return &schema.Resource{
ReadContext: dataSourceGithubActionsHostedRunnerCustomImageRead,

Schema: map[string]*schema.Schema{
"image_id": {
Type: schema.TypeInt,
Required: true,
Description: "The custom image definition ID.",
},
"platform": {
Type: schema.TypeString,
Computed: true,
Description: "Platform of the image (e.g., linux-x64).",
},
"name": {
Type: schema.TypeString,
Computed: true,
Description: "Name of the custom image.",
},
"source": {
Type: schema.TypeString,
Computed: true,
Description: "Source of the image.",
},
"versions_count": {
Type: schema.TypeInt,
Computed: true,
Description: "Number of versions of this image.",
},
"total_versions_size": {
Type: schema.TypeInt,
Computed: true,
Description: "Total size of all versions in GB.",
},
"latest_version": {
Type: schema.TypeString,
Computed: true,
Description: "Latest version string.",
},
"state": {
Type: schema.TypeString,
Computed: true,
Description: "State of the image (e.g., Ready).",
},
},
}
}

func dataSourceGithubActionsHostedRunnerCustomImageRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
err := checkOrganization(meta)
if err != nil {
return diag.FromErr(err)
}

client := meta.(*Owner).v3client
orgName := meta.(*Owner).name
imageID := d.Get("image_id").(int)

req, err := client.NewRequest("GET", fmt.Sprintf("orgs/%s/actions/hosted-runners/images/custom/%d", orgName, imageID), nil)
if err != nil {
return diag.FromErr(err)
}

var image map[string]any
_, err = client.Do(ctx, req, &image)
if err != nil {
return diag.FromErr(err)
}

if id, ok := image["id"].(float64); ok {
d.SetId(strconv.FormatInt(int64(id), 10))
}
if v, ok := image["platform"].(string); ok {
if err := d.Set("platform", v); err != nil {
return diag.FromErr(err)
}
}
if v, ok := image["name"].(string); ok {
if err := d.Set("name", v); err != nil {
return diag.FromErr(err)
}
}
if v, ok := image["source"].(string); ok {
if err := d.Set("source", v); err != nil {
return diag.FromErr(err)
}
}
if v, ok := image["versions_count"].(float64); ok {
if err := d.Set("versions_count", int(v)); err != nil {
return diag.FromErr(err)
}
}
if v, ok := image["total_versions_size"].(float64); ok {
if err := d.Set("total_versions_size", int(v)); err != nil {
return diag.FromErr(err)
}
}
if v, ok := image["latest_version"].(string); ok {
if err := d.Set("latest_version", v); err != nil {
return diag.FromErr(err)
}
}
if v, ok := image["state"].(string); ok {
if err := d.Set("state", v); err != nil {
return diag.FromErr(err)
}
}

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

import (
"fmt"
"testing"

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

func TestAccGithubActionsHostedRunnerCustomImageDataSource(t *testing.T) {
t.Run("queries a single custom image for hosted runners", func(t *testing.T) {
// This test requires a custom image to exist in the org.
// Set GITHUB_HOSTED_RUNNER_CUSTOM_IMAGE_ID env var to a valid image ID.
imageID := testAccGetCustomImageID(t)

config := fmt.Sprintf(`
data "github_actions_hosted_runner_custom_image" "test" {
image_id = %s
}
`, imageID)

check := resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("data.github_actions_hosted_runner_custom_image.test", "name"),
resource.TestCheckResourceAttrSet("data.github_actions_hosted_runner_custom_image.test", "platform"),
resource.TestCheckResourceAttrSet("data.github_actions_hosted_runner_custom_image.test", "state"),
)

resource.Test(t, resource.TestCase{
PreCheck: func() { skipUnlessHasPaidOrgs(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: config,
Check: check,
},
},
})
})
}

func testAccGetCustomImageID(t *testing.T) string {
t.Helper()
id := testOrganization + "_CUSTOM_IMAGE_ID"
// For CI, we'd look up from env. For now, skip if not available.
t.Skipf("Skipping: requires a custom image in the org (set %s)", id)
return ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package github

import (
"context"
"fmt"
"strconv"

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

func dataSourceGithubActionsHostedRunnerCustomImageVersions() *schema.Resource {
return &schema.Resource{
ReadContext: dataSourceGithubActionsHostedRunnerCustomImageVersionsRead,

Schema: map[string]*schema.Schema{
"image_id": {
Type: schema.TypeInt,
Required: true,
Description: "The custom image definition ID.",
},
"versions": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"version": {
Type: schema.TypeString,
Computed: true,
Description: "Version string (e.g., 1.0.0).",
},
"size_gb": {
Type: schema.TypeInt,
Computed: true,
Description: "Size of the image version in GB.",
},
"state": {
Type: schema.TypeString,
Computed: true,
Description: "State of the version (e.g., Ready).",
},
"created_on": {
Type: schema.TypeString,
Computed: true,
Description: "Timestamp when the version was created.",
},
},
},
Description: "List of versions for this custom image.",
},
},
}
}

func dataSourceGithubActionsHostedRunnerCustomImageVersionsRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
err := checkOrganization(meta)
if err != nil {
return diag.FromErr(err)
}

client := meta.(*Owner).v3client
orgName := meta.(*Owner).name
imageID := d.Get("image_id").(int)

req, err := client.NewRequest("GET", fmt.Sprintf("orgs/%s/actions/hosted-runners/images/custom/%d/versions", orgName, imageID), nil)
if err != nil {
return diag.FromErr(err)
}

var result struct {
TotalCount int `json:"total_count"`
ImageVersions []map[string]any `json:"image_versions"`
}
_, err = client.Do(ctx, req, &result)
if err != nil {
return diag.FromErr(err)
}

var allVersions []map[string]any
for _, v := range result.ImageVersions {
m := map[string]any{}
if ver, ok := v["version"].(string); ok {
m["version"] = ver
}
if size, ok := v["size_gb"].(float64); ok {
m["size_gb"] = int(size)
}
if state, ok := v["state"].(string); ok {
m["state"] = state
}
if created, ok := v["created_on"].(string); ok {
m["created_on"] = created
}
allVersions = append(allVersions, m)
}

d.SetId(fmt.Sprintf("%s/%s", orgName, strconv.Itoa(imageID)))
if err := d.Set("versions", allVersions); err != nil {
return diag.FromErr(err)
}

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

import (
"fmt"
"testing"

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

func TestAccGithubActionsHostedRunnerCustomImageVersionsDataSource(t *testing.T) {
t.Run("queries versions of a custom image for hosted runners", func(t *testing.T) {
imageID := testAccGetCustomImageIDForVersions(t)

config := fmt.Sprintf(`
data "github_actions_hosted_runner_custom_image_versions" "test" {
image_id = %s
}
`, imageID)

check := resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("data.github_actions_hosted_runner_custom_image_versions.test", "versions.#"),
)

resource.Test(t, resource.TestCase{
PreCheck: func() { skipUnlessHasPaidOrgs(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: config,
Check: check,
},
},
})
})
}

func testAccGetCustomImageIDForVersions(t *testing.T) string {
t.Helper()
id := testOrganization + "_CUSTOM_IMAGE_ID"
t.Skipf("Skipping: requires a custom image in the org (set %s)", id)
return ""
}
Loading