From b1243e41c6a02f318d515db56aa6ee4743311198 Mon Sep 17 00:00:00 2001 From: bradam12 <5084044+bradam12@users.noreply.github.com> Date: Mon, 18 Mar 2024 16:27:35 -0400 Subject: [PATCH] feat: `add github_enterprise_actions_runner_group` (#2158) Co-authored-by: Keegan Campbell --- github/data_source_github_enterprise.go | 9 + github/provider.go | 1 + ...hub_enteprise_actions_runner_group_test.go | 228 +++++++++++ ..._github_enterprise_actions_runner_group.go | 360 ++++++++++++++++++ ...resource_github_enterprise_organization.go | 16 + website/docs/d/enterprise.html.markdown | 1 + ...erprise_actions_runner_group.html.markdown | 65 ++++ .../r/enterprise_organization.html.markdown | 3 +- website/github.erb | 3 + 9 files changed, 685 insertions(+), 1 deletion(-) create mode 100644 github/resource_github_enteprise_actions_runner_group_test.go create mode 100644 github/resource_github_enterprise_actions_runner_group.go create mode 100644 website/docs/r/enterprise_actions_runner_group.html.markdown diff --git a/github/data_source_github_enterprise.go b/github/data_source_github_enterprise.go index 407b7c8437..7a00664dbf 100644 --- a/github/data_source_github_enterprise.go +++ b/github/data_source_github_enterprise.go @@ -12,6 +12,10 @@ func dataSourceGithubEnterprise() *schema.Resource { return &schema.Resource{ Read: dataSourceGithubEnterpriseRead, Schema: map[string]*schema.Schema{ + "database_id": { + Type: schema.TypeInt, + Computed: true, + }, "slug": { Type: schema.TypeString, Required: true, @@ -40,6 +44,7 @@ func dataSourceGithubEnterpriseRead(data *schema.ResourceData, meta interface{}) var query struct { Enterprise struct { ID githubv4.String + DatabaseId githubv4.Int Name githubv4.String Description githubv4.String CreatedAt githubv4.String @@ -76,6 +81,10 @@ func dataSourceGithubEnterpriseRead(data *schema.ResourceData, meta interface{}) if err != nil { return err } + err = data.Set("database_id", query.Enterprise.DatabaseId) + if err != nil { + return err + } return nil } diff --git a/github/provider.go b/github/provider.go index 8f1aec968e..39741a2c1d 100644 --- a/github/provider.go +++ b/github/provider.go @@ -194,6 +194,7 @@ func Provider() *schema.Provider { "github_user_invitation_accepter": resourceGithubUserInvitationAccepter(), "github_user_ssh_key": resourceGithubUserSshKey(), "github_enterprise_organization": resourceGithubEnterpriseOrganization(), + "github_enterprise_actions_runner_group": resourceGithubActionsEnterpriseRunnerGroup(), }, DataSourcesMap: map[string]*schema.Resource{ diff --git a/github/resource_github_enteprise_actions_runner_group_test.go b/github/resource_github_enteprise_actions_runner_group_test.go new file mode 100644 index 0000000000..1ffb73e090 --- /dev/null +++ b/github/resource_github_enteprise_actions_runner_group_test.go @@ -0,0 +1,228 @@ +package github + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccGithubActionsEnterpriseRunnerGroup(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") + } + + t.Run("creates enterprise runner groups without error", func(t *testing.T) { + config := fmt.Sprintf(` + data "github_enterprise" "enterprise" { + slug = "%s" + } + + resource "github_enterprise_actions_runner_group" "test" { + enterprise_slug = data.github_enterprise.enterprise.slug + name = "tf-acc-test-%s" + visibility = "all" + allows_public_repositories = true + } + `, testEnterprise, randomID) + + check := resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet( + "github_enterprise_actions_runner_group.test", "name", + ), + resource.TestCheckResourceAttr( + "github_enterprise_actions_runner_group.test", "name", + fmt.Sprintf(`tf-acc-test-%s`, randomID), + ), + resource.TestCheckResourceAttr( + "github_enterprise_actions_runner_group.test", "visibility", + "all", + ), + resource.TestCheckResourceAttr( + "github_enterprise_actions_runner_group.test", "allows_public_repositories", + "true", + ), + ) + + testCase := func(t *testing.T, mode string) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnlessMode(t, mode) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: config, + Check: check, + }, + }, + }) + } + + t.Run("with an enterprise account", func(t *testing.T) { + testCase(t, enterprise) + }) + }) + + t.Run("manages runner group visibility to selected orgs", func(t *testing.T) { + + config := fmt.Sprintf(` + data "github_enterprise" "enterprise" { + slug = "%s" + } + + data "github_organization" "org" { + name = "%s" + } + + resource "github_enterprise_actions_runner_group" "test" { + enterprise_slug = data.github_enterprise.enterprise.slug + name = "tf-acc-test-%s" + visibility = "selected" + selected_organization_ids = [data.github_organization.org.id] + } + `, testEnterprise, testOrganization, randomID) + + check := resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet( + "github_enterprise_actions_runner_group.test", "name", + ), + resource.TestCheckResourceAttr( + "github_enterprise_actions_runner_group.test", "name", + fmt.Sprintf(`tf-acc-test-%s`, randomID), + ), + resource.TestCheckResourceAttr( + "github_enterprise_actions_runner_group.test", "visibility", + "selected", + ), + resource.TestCheckResourceAttr( + "github_enterprise_actions_runner_group.test", "selected_organization_ids.#", + "1", + ), + resource.TestCheckResourceAttrSet( + "github_enterprise_actions_runner_group.test", "selected_organizations_url", + ), + ) + + testCase := func(t *testing.T, mode string) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnlessMode(t, mode) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: config, + Check: check, + }, + }, + }) + } + + t.Run("with an enterprise account", func(t *testing.T) { + testCase(t, enterprise) + }) + }) + + t.Run("imports an all runner group without error", func(t *testing.T) { + config := fmt.Sprintf(` + data "github_enterprise" "enterprise" { + slug = "%s" + } + + resource "github_enterprise_actions_runner_group" "test" { + enterprise_slug = data.github_enterprise.enterprise.slug + name = "tf-acc-test-%s" + visibility = "all" + } + `, testEnterprise, randomID) + + check := resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("github_enterprise_actions_runner_group.test", "name"), + resource.TestCheckResourceAttrSet("github_enterprise_actions_runner_group.test", "visibility"), + resource.TestCheckResourceAttr("github_enterprise_actions_runner_group.test", "visibility", "all"), + resource.TestCheckResourceAttr("github_enterprise_actions_runner_group.test", "name", fmt.Sprintf(`tf-acc-test-%s`, randomID)), + ) + + testCase := func(t *testing.T, mode string) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnlessMode(t, mode) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: config, + Check: check, + }, + { + ResourceName: "github_enterprise_actions_runner_group.test", + ImportState: true, + ImportStateVerify: true, + ImportStateIdPrefix: fmt.Sprintf(`%s/`, testEnterprise), + }, + }, + }) + } + + t.Run("with an enterprise account", func(t *testing.T) { + testCase(t, enterprise) + }) + }) + + t.Run("imports a runner group with selected orgs without error", func(t *testing.T) { + + config := fmt.Sprintf(` + data "github_enterprise" "enterprise" { + slug = "%s" + } + + data "github_organization" "org" { + name = "%s" + } + + resource "github_enterprise_actions_runner_group" "test" { + enterprise_slug = data.github_enterprise.enterprise.slug + name = "tf-acc-test-%s" + visibility = "selected" + selected_organization_ids = [data.github_organization.org.id] + } + `, testEnterprise, testOrganization, randomID) + + check := resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("github_enterprise_actions_runner_group.test", "name"), + resource.TestCheckResourceAttr("github_enterprise_actions_runner_group.test", "name", fmt.Sprintf(`tf-acc-test-%s`, randomID)), + resource.TestCheckResourceAttrSet("github_enterprise_actions_runner_group.test", "visibility"), + resource.TestCheckResourceAttr("github_enterprise_actions_runner_group.test", "visibility", "selected"), + resource.TestCheckResourceAttr( + "github_enterprise_actions_runner_group.test", "selected_organization_ids.#", + "1", + ), + ) + + testCase := func(t *testing.T, mode string) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnlessMode(t, mode) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: config, + Check: check, + }, + { + ResourceName: "github_enterprise_actions_runner_group.test", + ImportState: true, + ImportStateVerify: true, + ImportStateIdPrefix: fmt.Sprintf(`%s/`, testEnterprise), + }, + }, + }) + } + + t.Run("with an enterprise account", func(t *testing.T) { + testCase(t, enterprise) + }) + }) +} diff --git a/github/resource_github_enterprise_actions_runner_group.go b/github/resource_github_enterprise_actions_runner_group.go new file mode 100644 index 0000000000..c8e60de8ec --- /dev/null +++ b/github/resource_github_enterprise_actions_runner_group.go @@ -0,0 +1,360 @@ +package github + +import ( + "context" + "fmt" + "log" + "net/http" + "strconv" + "strings" + + "github.com/google/go-github/v57/github" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func resourceGithubActionsEnterpriseRunnerGroup() *schema.Resource { + return &schema.Resource{ + Create: resourceGithubActionsEnterpriseRunnerGroupCreate, + Read: resourceGithubActionsEnterpriseRunnerGroupRead, + Update: resourceGithubActionsEnterpriseRunnerGroupUpdate, + Delete: resourceGithubActionsEnterpriseRunnerGroupDelete, + Importer: &schema.ResourceImporter{ + State: resourceGithubActionsEnterpriseRunnerGroupImport, + }, + + Schema: map[string]*schema.Schema{ + "enterprise_slug": { + Type: schema.TypeString, + Required: true, + Description: "The slug of the enterprise.", + }, + "allows_public_repositories": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Whether public repositories can be added to the runner group.", + }, + "default": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether this is the default runner group.", + }, + "etag": { + Type: schema.TypeString, + Computed: true, + Description: "An etag representing the runner group object", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "Name of the runner group.", + }, + "runners_url": { + Type: schema.TypeString, + Computed: true, + Description: "The GitHub API URL for the runner group's runners.", + }, + "visibility": { + Type: schema.TypeString, + Required: true, + Description: "The visibility of the runner group.", + ValidateDiagFunc: toDiagFunc(validation.StringInSlice([]string{"all", "selected"}, false), "visibility"), + }, + "restricted_to_workflows": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "If 'true', the runner group will be restricted to running only the workflows specified in the 'selected_workflows' array. Defaults to 'false'.", + }, + "selected_workflows": { + Type: schema.TypeList, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + Description: "List of workflows the runner group should be allowed to run. This setting will be ignored unless restricted_to_workflows is set to 'true'.", + }, + "selected_organization_ids": { + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + Set: schema.HashInt, + Optional: true, + Description: "List of organization IDs that can access the runner group.", + }, + "selected_organizations_url": { + Type: schema.TypeString, + Computed: true, + Description: "GitHub API URL for the runner group's organizations.", + }, + }, + } +} + +func resourceGithubActionsEnterpriseRunnerGroupCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*Owner).v3client + + name := d.Get("name").(string) + enterpriseSlug := d.Get("enterprise_slug").(string) + restrictedToWorkflows := d.Get("restricted_to_workflows").(bool) + visibility := d.Get("visibility").(string) + selectedOrganizations, hasSelectedOrganizations := d.GetOk("selected_organization_ids") + allowsPublicRepositories := d.Get("allows_public_repositories").(bool) + + selectedWorkflows := []string{} + if workflows, ok := d.GetOk("selected_workflows"); ok { + for _, workflow := range workflows.([]interface{}) { + selectedWorkflows = append(selectedWorkflows, workflow.(string)) + } + } + + if visibility != "selected" && hasSelectedOrganizations { + return fmt.Errorf("cannot use selected_organization_ids without visibility being set to selected") + } + + selectedOrganizationIDs := []int64{} + + if hasSelectedOrganizations { + ids := selectedOrganizations.(*schema.Set).List() + + for _, id := range ids { + selectedOrganizationIDs = append(selectedOrganizationIDs, int64(id.(int))) + } + } + + ctx := context.Background() + + enterpriseRunnerGroup, resp, err := client.Enterprise.CreateEnterpriseRunnerGroup(ctx, + enterpriseSlug, + github.CreateEnterpriseRunnerGroupRequest{ + Name: &name, + Visibility: &visibility, + SelectedOrganizationIDs: selectedOrganizationIDs, + AllowsPublicRepositories: &allowsPublicRepositories, + RestrictedToWorkflows: &restrictedToWorkflows, + SelectedWorkflows: selectedWorkflows, + }, + ) + if err != nil { + return err + } + d.SetId(strconv.FormatInt(enterpriseRunnerGroup.GetID(), 10)) + if err = d.Set("etag", resp.Header.Get("ETag")); err != nil { + return err + } + if err = d.Set("allows_public_repositories", enterpriseRunnerGroup.GetAllowsPublicRepositories()); err != nil { + return err + } + if err = d.Set("default", enterpriseRunnerGroup.GetDefault()); err != nil { + return err + } + if err = d.Set("name", enterpriseRunnerGroup.GetName()); err != nil { + return err + } + if err = d.Set("runners_url", enterpriseRunnerGroup.GetRunnersURL()); err != nil { + return err + } + if err = d.Set("selected_organizations_url", enterpriseRunnerGroup.GetSelectedOrganizationsURL()); err != nil { + return err + } + if err = d.Set("visibility", enterpriseRunnerGroup.GetVisibility()); err != nil { + return err + } + if err = d.Set("selected_organization_ids", selectedOrganizationIDs); err != nil { // Note: enterpriseRunnerGroup has no method to get selected organization IDs + return err + } + if err = d.Set("restricted_to_workflows", enterpriseRunnerGroup.GetRestrictedToWorkflows()); err != nil { + return err + } + if err = d.Set("selected_workflows", enterpriseRunnerGroup.SelectedWorkflows); err != nil { + return err + } + if err = d.Set("enterprise_slug", enterpriseSlug); err != nil { + return err + } + + return resourceGithubActionsEnterpriseRunnerGroupRead(d, meta) +} + +func getEnterpriseRunnerGroup(client *github.Client, ctx context.Context, ent string, groupID int64) (*github.EnterpriseRunnerGroup, *github.Response, error) { + enterpriseRunnerGroup, resp, err := client.Enterprise.GetEnterpriseRunnerGroup(ctx, ent, groupID) + if err != nil { + if ghErr, ok := err.(*github.ErrorResponse); ok && ghErr.Response.StatusCode == http.StatusNotModified { + // ignore error StatusNotModified + return enterpriseRunnerGroup, resp, nil + } + } + return enterpriseRunnerGroup, resp, err +} + +func resourceGithubActionsEnterpriseRunnerGroupRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*Owner).v3client + + enterpriseSlug := d.Get("enterprise_slug").(string) + runnerGroupID, err := strconv.ParseInt(d.Id(), 10, 64) + if err != nil { + return err + } + ctx := context.WithValue(context.Background(), ctxId, d.Id()) + if !d.IsNewResource() { + ctx = context.WithValue(ctx, ctxEtag, d.Get("etag").(string)) + } + + enterpriseRunnerGroup, resp, err := getEnterpriseRunnerGroup(client, ctx, enterpriseSlug, runnerGroupID) + if err != nil { + if ghErr, ok := err.(*github.ErrorResponse); ok { + if ghErr.Response.StatusCode == http.StatusNotFound { + log.Printf("[INFO] Removing enterprise runner group %s/%s from state because it no longer exists in GitHub", + enterpriseSlug, d.Id()) + d.SetId("") + return nil + } + } + return err + } + + //if runner group is nil (typically not modified) we can return early + if enterpriseRunnerGroup == nil { + return nil + } + + if err = d.Set("etag", resp.Header.Get("ETag")); err != nil { + return err + } + if err = d.Set("allows_public_repositories", enterpriseRunnerGroup.GetAllowsPublicRepositories()); err != nil { + return err + } + if err = d.Set("default", enterpriseRunnerGroup.GetDefault()); err != nil { + return err + } + if err = d.Set("name", enterpriseRunnerGroup.GetName()); err != nil { + return err + } + if err = d.Set("runners_url", enterpriseRunnerGroup.GetRunnersURL()); err != nil { + return err + } + if err = d.Set("selected_organizations_url", enterpriseRunnerGroup.GetSelectedOrganizationsURL()); err != nil { + return err + } + if err = d.Set("visibility", enterpriseRunnerGroup.GetVisibility()); err != nil { + return err + } + if err = d.Set("restricted_to_workflows", enterpriseRunnerGroup.GetRestrictedToWorkflows()); err != nil { + return err + } + if err = d.Set("selected_workflows", enterpriseRunnerGroup.SelectedWorkflows); err != nil { + return err + } + if err = d.Set("enterprise_slug", enterpriseSlug); err != nil { + return err + } + + selectedOrganizationIDs := []int64{} + optionsOrgs := github.ListOptions{ + PerPage: maxPerPage, + } + + for { + enterpriseRunnerGroupOrganizations, resp, err := client.Enterprise.ListOrganizationAccessRunnerGroup(ctx, enterpriseSlug, runnerGroupID, &optionsOrgs) + if err != nil { + return err + } + + for _, org := range enterpriseRunnerGroupOrganizations.Organizations { + selectedOrganizationIDs = append(selectedOrganizationIDs, *org.ID) + } + + if resp.NextPage == 0 { + break + } + + optionsOrgs.Page = resp.NextPage + } + + if err = d.Set("selected_organization_ids", selectedOrganizationIDs); err != nil { + return err + } + + return nil +} + +func resourceGithubActionsEnterpriseRunnerGroupUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*Owner).v3client + + name := d.Get("name").(string) + enterpriseSlug := d.Get("enterprise_slug").(string) + visibility := d.Get("visibility").(string) + restrictedToWorkflows := d.Get("restricted_to_workflows").(bool) + selectedWorkflows := []string{} + allowsPublicRepositories := d.Get("allows_public_repositories").(bool) + if workflows, ok := d.GetOk("selected_workflows"); ok { + for _, workflow := range workflows.([]interface{}) { + selectedWorkflows = append(selectedWorkflows, workflow.(string)) + } + } + + options := github.UpdateEnterpriseRunnerGroupRequest{ + Name: &name, + Visibility: &visibility, + RestrictedToWorkflows: &restrictedToWorkflows, + SelectedWorkflows: selectedWorkflows, + AllowsPublicRepositories: &allowsPublicRepositories, + } + + runnerGroupID, err := strconv.ParseInt(d.Id(), 10, 64) + if err != nil { + return err + } + ctx := context.WithValue(context.Background(), ctxId, d.Id()) + + if _, _, err := client.Enterprise.UpdateEnterpriseRunnerGroup(ctx, enterpriseSlug, runnerGroupID, options); err != nil { + return err + } + + selectedOrganizations, hasSelectedOrganizations := d.GetOk("selected_organization_ids") + selectedOrganizationIDs := []int64{} + + if hasSelectedOrganizations { + ids := selectedOrganizations.(*schema.Set).List() + + for _, id := range ids { + selectedOrganizationIDs = append(selectedOrganizationIDs, int64(id.(int))) + } + } + + orgOptions := github.SetOrgAccessRunnerGroupRequest{SelectedOrganizationIDs: selectedOrganizationIDs} + + if _, err := client.Enterprise.SetOrganizationAccessRunnerGroup(ctx, enterpriseSlug, runnerGroupID, orgOptions); err != nil { + return err + } + + return resourceGithubActionsEnterpriseRunnerGroupRead(d, meta) +} + +func resourceGithubActionsEnterpriseRunnerGroupDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*Owner).v3client + enterpriseSlug := d.Get("enterprise_slug").(string) + enterpriseRunnerGroupID, err := strconv.ParseInt(d.Id(), 10, 64) + if err != nil { + return err + } + ctx := context.WithValue(context.Background(), ctxId, d.Id()) + + log.Printf("[INFO] Deleting enterprise runner group: %s/%s (%s)", enterpriseSlug, d.Get("name"), d.Id()) + _, err = client.Enterprise.DeleteEnterpriseRunnerGroup(ctx, enterpriseSlug, enterpriseRunnerGroupID) + return err +} + +func resourceGithubActionsEnterpriseRunnerGroupImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + parts := strings.Split(d.Id(), "/") + if len(parts) != 2 { + return nil, fmt.Errorf("invalid import specified: supplied import must be written as /") + } + + enterpriseId, runnerGroupID := parts[0], parts[1] + + d.SetId(runnerGroupID) + d.Set("enterprise_slug", enterpriseId) + + return []*schema.ResourceData{d}, nil +} diff --git a/github/resource_github_enterprise_organization.go b/github/resource_github_enterprise_organization.go index 4117cfa062..809a16cf39 100644 --- a/github/resource_github_enterprise_organization.go +++ b/github/resource_github_enterprise_organization.go @@ -27,6 +27,16 @@ func resourceGithubEnterpriseOrganization() *schema.Resource { ForceNew: true, Description: "The ID of the enterprise.", }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The node ID of the organization.", + }, + "database_id": { + Type: schema.TypeInt, + Computed: true, + Description: "The database ID of the organization.", + }, "name": { Type: schema.TypeString, Required: true, @@ -128,6 +138,7 @@ func resourceGithubEnterpriseOrganizationRead(data *schema.ResourceData, meta in Node struct { Organization struct { ID githubv4.ID + DatabaseId githubv4.Int Name githubv4.String Login githubv4.String Description githubv4.String @@ -199,6 +210,11 @@ func resourceGithubEnterpriseOrganizationRead(data *schema.ResourceData, meta in return err } + err = data.Set("database_id", query.Node.Organization.DatabaseId) + if err != nil { + return err + } + err = data.Set("description", query.Node.Organization.Description) return err } diff --git a/website/docs/d/enterprise.html.markdown b/website/docs/d/enterprise.html.markdown index b81f0b103e..251e0ee951 100644 --- a/website/docs/d/enterprise.html.markdown +++ b/website/docs/d/enterprise.html.markdown @@ -20,6 +20,7 @@ data "github_enterprise" "example" { ## Attributes Reference * `id` - The ID of the enterprise. +* `database_id` - The database ID of the enterprise. * `slug` - The URL slug identifying the enterprise. * `name` - The name of the enterprise. * `description` - The description of the enterprise. diff --git a/website/docs/r/enterprise_actions_runner_group.html.markdown b/website/docs/r/enterprise_actions_runner_group.html.markdown new file mode 100644 index 0000000000..a4627a85ca --- /dev/null +++ b/website/docs/r/enterprise_actions_runner_group.html.markdown @@ -0,0 +1,65 @@ +--- +layout: "github" +page_title: "GitHub: github_enterprise_actions_runner_group" +description: |- + Creates and manages an Actions Runner Group within a GitHub enterprise. +--- + +# github_enterprise_actions_runner_group + +This resource allows you to create and manage GitHub Actions runner groups within your GitHub enterprise. +You must have admin access to an enterprise to use this resource. + +## Example Usage + +```hcl +data "github_enterprise" "enterprise" { + slug = "my-enterprise" +} + +resource "github_enterprise_organization" "enterprise_organization" { + enterprise_id = data.github_enterprise.enterprise.id + name = "my-organization" + billing_email = "octocat@octo.cat" + admin_logins = ["octocat"] +} + +resource "github_enterprise_actions_runner_group" "example" { + name = "my-awesome-runner-group" + enterprise_slug = data.github_enterprise.enterprise.slug + allows_public_repositories = true + visibility = "selected" + selected_organization_ids = [github_enterprise_organization.enterprise_organization.database_id] + restricted_to_workflows = true + selected_workflows = ["my-organization/my-repo/.github/workflows/cool-workflow.yaml@refs/tags/v1"] +} +``` + +## Argument Reference + +The following arguments are supported: +* `enterprise_slug` - (Required) The slug of the enterprise. +* `name` - (Required) Name of the runner group +* `visibility` - (Optional) Visibility of a runner group to enterprise organizations. Whether the runner group can include `all` or `selected` +* `selected_organization_ids` - (Optional) IDs of the organizations which should be added to the runner group +* `allows_public_repositories` - (Optional) Whether public repositories can be added to the runner group. Defaults to false. +* `restricted_to_workflows` - (Optional) If true, the runner group will be restricted to running only the workflows specified in the selected_workflows array. Defaults to false. +* `selected_workflows` - (Optional) List of workflows the runner group should be allowed to run. This setting will be ignored unless restricted_to_workflows is set to true. + +## Attributes Reference + +The following additional attributes are exported: + +* `id` - The ID of the runner group +* `default` - Whether this is the default runner group +* `etag` - An etag representing the runner group object +* `runners_url` - The GitHub API URL for the runner group's runners +* `selected_organizations_url` - The GitHub API URL for the runner group's selected organizations + +## Import + +This resource can be imported using the enterprise slug and the ID of the runner group: + +``` +$ terraform import github_enterprise_actions_runner_group.test enterprise-slug/42 +``` diff --git a/website/docs/r/enterprise_organization.html.markdown b/website/docs/r/enterprise_organization.html.markdown index b490284a88..94b39e94ee 100644 --- a/website/docs/r/enterprise_organization.html.markdown +++ b/website/docs/r/enterprise_organization.html.markdown @@ -37,7 +37,8 @@ resource "github_enterprise_organization" "org" { The following additional attributes are exported: -* `id` - The ID of the organization. +* `id` - The node ID of the organization for use with the v4 API. +* `database_id` - The ID of the organization. ## Import diff --git a/website/github.erb b/website/github.erb index ec7cd08f20..62cac71347 100644 --- a/website/github.erb +++ b/website/github.erb @@ -256,6 +256,9 @@
  • github_codespaces_user_secret
  • +
  • + github_enterprise_actions_runner_group +
  • github_enterprise_organization