Repository: google/go-github
Pull request #2890 (2023-08-20 15:43:08)

Add GenerateEnterpriseJITConfig
With version 3.10 of GitHub Enterprise server, the new just-in-time runner configuration is available for enterprises.

See: https://docs.github.com/en/enterprise-cloud@latest/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-configuration-for-a-just-in-time-runner-for-an-enterprise

CC: @mkulke 

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/google/go-github/pull/2890?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google) Report
> Merging [#2890](https://app.codecov.io/gh/google/go-github/pull/2890?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google) (4b55d56) into [master](https://app.codecov.io/gh/google/go-github/commit/7ceef94922277b3962cb8f61572983ff503e4819?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google) (7ceef94) will **increase** coverage by `0.00%`.
> The diff coverage is `100.00%`.

```diff
@@           Coverage Diff           @@
##           master    #2890   +/-   ##
=======================================
  Coverage   98.06%   98.06%           
=======================================
  Files         140      140           
  Lines       12293    12306   +13     
=======================================
+ Hits        12055    12068   +13     
  Misses        162      162           
  Partials       76       76           
```


| [Files Changed](https://app.codecov.io/gh/google/go-github/pull/2890?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google) | Coverage Δ | |
|---|---|---|
| [github/enterprise\_actions\_runners.go](https://app.codecov.io/gh/google/go-github/pull/2890?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google#diff-Z2l0aHViL2VudGVycHJpc2VfYWN0aW9uc19ydW5uZXJzLmdv) | `100.00% <100.00%> (ø)` | |


gmlewis: @WillAbides - do you have time for a code review on this one?
I apparently forgot to add the "NeedsReview" label on it a couple weeks ago - sorry about that, @gabriel-samfira !
gabriel-samfira: No worries at all @gmlewis !

Patch:
diff --git a/github/enterprise_actions_runner_groups.go b/github/enterprise_actions_runner_groups.go
new file mode 100644
index 00000000..b6bb70da
--- /dev/null
+++ b/github/enterprise_actions_runner_groups.go
@@ -0,0 +1,310 @@
+// Copyright 2023 The go-github AUTHORS. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package github
+
+import (
+	"context"
+	"fmt"
+)
+
+// ListOrganizations represents the response from the list orgs endpoints.
+type ListOrganizations struct {
+	TotalCount    *int            `json:"total_count,omitempty"`
+	Organizations []*Organization `json:"organizations"`
+}
+
+// EnterpriseRunnerGroup represents a self-hosted runner group configured in an enterprise.
+type EnterpriseRunnerGroup struct {
+	ID                           *int64   `json:"id,omitempty"`
+	Name                         *string  `json:"name,omitempty"`
+	Visibility                   *string  `json:"visibility,omitempty"`
+	Default                      *bool    `json:"default,omitempty"`
+	SelectedOrganizationsURL     *string  `json:"selected_organizations_url,omitempty"`
+	RunnersURL                   *string  `json:"runners_url,omitempty"`
+	Inherited                    *bool    `json:"inherited,omitempty"`
+	AllowsPublicRepositories     *bool    `json:"allows_public_repositories,omitempty"`
+	RestrictedToWorkflows        *bool    `json:"restricted_to_workflows,omitempty"`
+	SelectedWorkflows            []string `json:"selected_workflows,omitempty"`
+	WorkflowRestrictionsReadOnly *bool    `json:"workflow_restrictions_read_only,omitempty"`
+}
+
+// EnterpriseRunnerGroups represents a collection of self-hosted runner groups configured for an enterprise.
+type EnterpriseRunnerGroups struct {
+	TotalCount   *int                     `json:"total_count,omitempty"`
+	RunnerGroups []*EnterpriseRunnerGroup `json:"runner_groups"`
+}
+
+// CreateEnterpriseRunnerGroupRequest represents a request to create a Runner group for an enterprise.
+type CreateEnterpriseRunnerGroupRequest struct {
+	Name       *string `json:"name,omitempty"`
+	Visibility *string `json:"visibility,omitempty"`
+	// List of organization IDs that can access the runner group.
+	SelectedOrganizationIDs []int64 `json:"selected_organization_ids,omitempty"`
+	// Runners represent a list of runner IDs to add to the runner group.
+	Runners []int64 `json:"runners,omitempty"`
+	// If set to True, public repos can use this runner group
+	AllowsPublicRepositories *bool `json:"allows_public_repositories,omitempty"`
+	// If true, the runner group will be restricted to running only the workflows specified in the SelectedWorkflows slice.
+	RestrictedToWorkflows *bool `json:"restricted_to_workflows,omitempty"`
+	// List of workflows the runner group should be allowed to run. This setting will be ignored unless RestrictedToWorkflows is set to true.
+	SelectedWorkflows []string `json:"selected_workflows,omitempty"`
+}
+
+// UpdateEnterpriseRunnerGroupRequest represents a request to update a Runner group for an enterprise.
+type UpdateEnterpriseRunnerGroupRequest struct {
+	Name                     *string  `json:"name,omitempty"`
+	Visibility               *string  `json:"visibility,omitempty"`
+	AllowsPublicRepositories *bool    `json:"allows_public_repositories,omitempty"`
+	RestrictedToWorkflows    *bool    `json:"restricted_to_workflows,omitempty"`
+	SelectedWorkflows        []string `json:"selected_workflows,omitempty"`
+}
+
+// SetOrgAccessRunnerGroupRequest represents a request to replace the list of organizations
+// that can access a self-hosted runner group configured in an enterprise.
+type SetOrgAccessRunnerGroupRequest struct {
+	// Updated list of organization IDs that should be given access to the runner group.
+	SelectedOrganizationIDs []int64 `json:"selected_organization_ids"`
+}
+
+// ListEnterpriseRunnerGroupOptions extend ListOptions to have the optional parameters VisibleToOrganization.
+type ListEnterpriseRunnerGroupOptions struct {
+	ListOptions
+
+	// Only return runner groups that are allowed to be used by this organization.
+	VisibleToOrganization string `url:"visible_to_organization,omitempty"`
+}
+
+// ListRunnerGroups lists all self-hosted runner groups configured in an enterprise.
+//
+// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/actions/self-hosted-runner-groups?apiVersion=2022-11-28#list-self-hosted-runner-groups-for-an-enterprise
+func (s *EnterpriseService) ListRunnerGroups(ctx context.Context, enterprise string, opts *ListEnterpriseRunnerGroupOptions) (*EnterpriseRunnerGroups, *Response, error) {
+	u := fmt.Sprintf("enterprises/%v/actions/runner-groups", enterprise)
+	u, err := addOptions(u, opts)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	groups := &EnterpriseRunnerGroups{}
+	resp, err := s.client.Do(ctx, req, &groups)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return groups, resp, nil
+}
+
+// GetEnterpriseRunnerGroup gets a specific self-hosted runner group for an enterprise using its RunnerGroup ID.
+//
+// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/actions/self-hosted-runner-groups?apiVersion=2022-11-28#get-a-self-hosted-runner-group-for-an-enterprise
+func (s *EnterpriseService) GetEnterpriseRunnerGroup(ctx context.Context, enterprise string, groupID int64) (*EnterpriseRunnerGroup, *Response, error) {
+	u := fmt.Sprintf("enterprises/%v/actions/runner-groups/%v", enterprise, groupID)
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	runnerGroup := new(EnterpriseRunnerGroup)
+	resp, err := s.client.Do(ctx, req, runnerGroup)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return runnerGroup, resp, nil
+}
+
+// DeleteEnterpriseRunnerGroup deletes a self-hosted runner group from an enterprise.
+//
+// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/actions/self-hosted-runner-groups?apiVersion=2022-11-28#delete-a-self-hosted-runner-group-from-an-enterprise
+func (s *EnterpriseService) DeleteEnterpriseRunnerGroup(ctx context.Context, enterprise string, groupID int64) (*Response, error) {
+	u := fmt.Sprintf("enterprises/%v/actions/runner-groups/%v", enterprise, groupID)
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(ctx, req, nil)
+}
+
+// CreateEnterpriseRunnerGroup creates a new self-hosted runner group for an enterprise.
+//
+// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/actions/self-hosted-runner-groups?apiVersion=2022-11-28#create-a-self-hosted-runner-group-for-an-enterprise
+func (s *EnterpriseService) CreateEnterpriseRunnerGroup(ctx context.Context, enterprise string, createReq CreateEnterpriseRunnerGroupRequest) (*EnterpriseRunnerGroup, *Response, error) {
+	u := fmt.Sprintf("enterprises/%v/actions/runner-groups", enterprise)
+	req, err := s.client.NewRequest("POST", u, createReq)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	runnerGroup := new(EnterpriseRunnerGroup)
+	resp, err := s.client.Do(ctx, req, runnerGroup)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return runnerGroup, resp, nil
+}
+
+// UpdateEnterpriseRunnerGroup updates a self-hosted runner group for an enterprise.
+//
+// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/actions/self-hosted-runner-groups?apiVersion=2022-11-28#update-a-self-hosted-runner-group-for-an-enterprise
+func (s *EnterpriseService) UpdateEnterpriseRunnerGroup(ctx context.Context, enterprise string, groupID int64, updateReq UpdateEnterpriseRunnerGroupRequest) (*EnterpriseRunnerGroup, *Response, error) {
+	u := fmt.Sprintf("enterprises/%v/actions/runner-groups/%v", enterprise, groupID)
+	req, err := s.client.NewRequest("PATCH", u, updateReq)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	runnerGroup := new(EnterpriseRunnerGroup)
+	resp, err := s.client.Do(ctx, req, runnerGroup)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return runnerGroup, resp, nil
+}
+
+// ListOrganizationAccessRunnerGroup lists the organizations with access to a self-hosted runner group configured in an enterprise.
+//
+// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/actions/self-hosted-runner-groups?apiVersion=2022-11-28#list-organization-access-to-a-self-hosted-runner-group-in-an-enterprise
+func (s *EnterpriseService) ListOrganizationAccessRunnerGroup(ctx context.Context, enterprise string, groupID int64, opts *ListOptions) (*ListOrganizations, *Response, error) {
+	u := fmt.Sprintf("enterprises/%v/actions/runner-groups/%v/organizations", enterprise, groupID)
+	u, err := addOptions(u, opts)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	orgs := &ListOrganizations{}
+	resp, err := s.client.Do(ctx, req, &orgs)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return orgs, resp, nil
+}
+
+// SetOrganizationAccessRunnerGroup replaces the list of organizations that have access to a self-hosted runner group configured in an enterprise
+// with a new List of organizations.
+//
+// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/actions/self-hosted-runner-groups?apiVersion=2022-11-28#set-organization-access-for-a-self-hosted-runner-group-in-an-enterprise
+func (s *EnterpriseService) SetOrganizationAccessRunnerGroup(ctx context.Context, enterprise string, groupID int64, ids SetOrgAccessRunnerGroupRequest) (*Response, error) {
+	u := fmt.Sprintf("enterprises/%v/actions/runner-groups/%v/organizations", enterprise, groupID)
+
+	req, err := s.client.NewRequest("PUT", u, ids)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(ctx, req, nil)
+}
+
+// AddOrganizationAccessRunnerGroup adds an organization to the list of selected organizations that can access a self-hosted runner group.
+// The runner group must have visibility set to 'selected'.
+//
+// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/actions/self-hosted-runner-groups?apiVersion=2022-11-28#add-organization-access-to-a-self-hosted-runner-group-in-an-enterprise
+func (s *EnterpriseService) AddOrganizationAccessRunnerGroup(ctx context.Context, enterprise string, groupID, orgID int64) (*Response, error) {
+	u := fmt.Sprintf("enterprises/%v/actions/runner-groups/%v/organizations/%v", enterprise, groupID, orgID)
+
+	req, err := s.client.NewRequest("PUT", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(ctx, req, nil)
+}
+
+// RemoveOrganizationAccessRunnerGroup removes an organization from the list of selected organizations that can access a self-hosted runner group.
+// The runner group must have visibility set to 'selected'.
+//
+// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/actions/self-hosted-runner-groups?apiVersion=2022-11-28#remove-organization-access-to-a-self-hosted-runner-group-in-an-enterprise
+func (s *EnterpriseService) RemoveOrganizationAccessRunnerGroup(ctx context.Context, enterprise string, groupID, orgID int64) (*Response, error) {
+	u := fmt.Sprintf("enterprises/%v/actions/runner-groups/%v/organizations/%v", enterprise, groupID, orgID)
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(ctx, req, nil)
+}
+
+// ListRunnerGroupRunners lists self-hosted runners that are in a specific enterprise group.
+//
+// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/actions/self-hosted-runner-groups?apiVersion=2022-11-28#list-self-hosted-runners-in-a-group-for-an-enterprise
+func (s *EnterpriseService) ListRunnerGroupRunners(ctx context.Context, enterprise string, groupID int64, opts *ListOptions) (*Runners, *Response, error) {
+	u := fmt.Sprintf("enterprises/%v/actions/runner-groups/%v/runners", enterprise, groupID)
+	u, err := addOptions(u, opts)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	runners := &Runners{}
+	resp, err := s.client.Do(ctx, req, &runners)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return runners, resp, nil
+}
+
+// SetRunnerGroupRunners replaces the list of self-hosted runners that are part of an enterprise runner group
+// with a new list of runners.
+//
+// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/actions/self-hosted-runner-groups?apiVersion=2022-11-28#set-self-hosted-runners-in-a-group-for-an-enterprise
+func (s *EnterpriseService) SetRunnerGroupRunners(ctx context.Context, enterprise string, groupID int64, ids SetRunnerGroupRunnersRequest) (*Response, error) {
+	u := fmt.Sprintf("enterprises/%v/actions/runner-groups/%v/runners", enterprise, groupID)
+
+	req, err := s.client.NewRequest("PUT", u, ids)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(ctx, req, nil)
+}
+
+// AddRunnerGroupRunners adds a self-hosted runner to a runner group configured in an enterprise.
+//
+// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/actions/self-hosted-runner-groups?apiVersion=2022-11-28#add-a-self-hosted-runner-to-a-group-for-an-enterprise
+func (s *EnterpriseService) AddRunnerGroupRunners(ctx context.Context, enterprise string, groupID, runnerID int64) (*Response, error) {
+	u := fmt.Sprintf("enterprises/%v/actions/runner-groups/%v/runners/%v", enterprise, groupID, runnerID)
+
+	req, err := s.client.NewRequest("PUT", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(ctx, req, nil)
+}
+
+// RemoveRunnerGroupRunners removes a self-hosted runner from a group configured in an enterprise.
+// The runner is then returned to the default group.
+//
+// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/actions/self-hosted-runner-groups?apiVersion=2022-11-28#remove-a-self-hosted-runner-from-a-group-for-an-enterprise
+func (s *EnterpriseService) RemoveRunnerGroupRunners(ctx context.Context, enterprise string, groupID, runnerID int64) (*Response, error) {
+	u := fmt.Sprintf("enterprises/%v/actions/runner-groups/%v/runners/%v", enterprise, groupID, runnerID)
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(ctx, req, nil)
+}
diff --git a/github/enterprise_actions_runners.go b/github/enterprise_actions_runners.go
index daafc5e6..6fc30d50 100644
--- a/github/enterprise_actions_runners.go
+++ b/github/enterprise_actions_runners.go
@@ -29,6 +29,26 @@ func (s *EnterpriseService) ListRunnerApplicationDownloads(ctx context.Context,
 	return rads, resp, nil
 }
 
+// GenerateEnterpriseJITConfig generates a just-in-time configuration for an enterprise.
+//
+// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-configuration-for-a-just-in-time-runner-for-an-enterprise
+func (s *EnterpriseService) GenerateEnterpriseJITConfig(ctx context.Context, enterprise string, request *GenerateJITConfigRequest) (*JITRunnerConfig, *Response, error) {
+	u := fmt.Sprintf("enterprises/%v/actions/runners/generate-jitconfig", enterprise)
+
+	req, err := s.client.NewRequest("POST", u, request)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	jitConfig := new(JITRunnerConfig)
+	resp, err := s.client.Do(ctx, req, jitConfig)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return jitConfig, resp, nil
+}
+
 // CreateRegistrationToken creates a token that can be used to add a self-hosted runner.
 //
 // GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runners#create-a-registration-token-for-an-enterprise
diff --git a/github/github-accessors.go b/github/github-accessors.go
index 560e0892..a685a3ef 100644
--- a/github/github-accessors.go
+++ b/github/github-accessors.go
@@ -4574,6 +4574,38 @@ func (c *CreateCodespaceOptions) GetWorkingDirectory() string {
 	return *c.WorkingDirectory
 }
 
+// GetAllowsPublicRepositories returns the AllowsPublicRepositories field if it's non-nil, zero value otherwise.
+func (c *CreateEnterpriseRunnerGroupRequest) GetAllowsPublicRepositories() bool {
+	if c == nil || c.AllowsPublicRepositories == nil {
+		return false
+	}
+	return *c.AllowsPublicRepositories
+}
+
+// GetName returns the Name field if it's non-nil, zero value otherwise.
+func (c *CreateEnterpriseRunnerGroupRequest) GetName() string {
+	if c == nil || c.Name == nil {
+		return ""
+	}
+	return *c.Name
+}
+
+// GetRestrictedToWorkflows returns the RestrictedToWorkflows field if it's non-nil, zero value otherwise.
+func (c *CreateEnterpriseRunnerGroupRequest) GetRestrictedToWorkflows() bool {
+	if c == nil || c.RestrictedToWorkflows == nil {
+		return false
+	}
+	return *c.RestrictedToWorkflows
+}
+
+// GetVisibility returns the Visibility field if it's non-nil, zero value otherwise.
+func (c *CreateEnterpriseRunnerGroupRequest) GetVisibility() string {
+	if c == nil || c.Visibility == nil {
+		return ""
+	}
+	return *c.Visibility
+}
+
 // GetDescription returns the Description field if it's non-nil, zero value otherwise.
 func (c *CreateEvent) GetDescription() string {
 	if c == nil || c.Description == nil {
@@ -6630,6 +6662,94 @@ func (e *Enterprise) GetWebsiteURL() string {
 	return *e.WebsiteURL
 }
 
+// GetAllowsPublicRepositories returns the AllowsPublicRepositories field if it's non-nil, zero value otherwise.
+func (e *EnterpriseRunnerGroup) GetAllowsPublicRepositories() bool {
+	if e == nil || e.AllowsPublicRepositories == nil {
+		return false
+	}
+	return *e.AllowsPublicRepositories
+}
+
+// GetDefault returns the Default field if it's non-nil, zero value otherwise.
+func (e *EnterpriseRunnerGroup) GetDefault() bool {
+	if e == nil || e.Default == nil {
+		return false
+	}
+	return *e.Default
+}
+
+// GetID returns the ID field if it's non-nil, zero value otherwise.
+func (e *EnterpriseRunnerGroup) GetID() int64 {
+	if e == nil || e.ID == nil {
+		return 0
+	}
+	return *e.ID
+}
+
+// GetInherited returns the Inherited field if it's non-nil, zero value otherwise.
+func (e *EnterpriseRunnerGroup) GetInherited() bool {
+	if e == nil || e.Inherited == nil {
+		return false
+	}
+	return *e.Inherited
+}
+
+// GetName returns the Name field if it's non-nil, zero value otherwise.
+func (e *EnterpriseRunnerGroup) GetName() string {
+	if e == nil || e.Name == nil {
+		return ""
+	}
+	return *e.Name
+}
+
+// GetRestrictedToWorkflows returns the RestrictedToWorkflows field if it's non-nil, zero value otherwise.
+func (e *EnterpriseRunnerGroup) GetRestrictedToWorkflows() bool {
+	if e == nil || e.RestrictedToWorkflows == nil {
+		return false
+	}
+	return *e.RestrictedToWorkflows
+}
+
+// GetRunnersURL returns the RunnersURL field if it's non-nil, zero value otherwise.
+func (e *EnterpriseRunnerGroup) GetRunnersURL() string {
+	if e == nil || e.RunnersURL == nil {
+		return ""
+	}
+	return *e.RunnersURL
+}
+
+// GetSelectedOrganizationsURL returns the SelectedOrganizationsURL field if it's non-nil, zero value otherwise.
+func (e *EnterpriseRunnerGroup) GetSelectedOrganizationsURL() string {
+	if e == nil || e.SelectedOrganizationsURL == nil {
+		return ""
+	}
+	return *e.SelectedOrganizationsURL
+}
+
+// GetVisibility returns the Visibility field if it's non-nil, zero value otherwise.
+func (e *EnterpriseRunnerGroup) GetVisibility() string {
+	if e == nil || e.Visibility == nil {
+		return ""
+	}
+	return *e.Visibility
+}
+
+// GetWorkflowRestrictionsReadOnly returns the WorkflowRestrictionsReadOnly field if it's non-nil, zero value otherwise.
+func (e *EnterpriseRunnerGroup) GetWorkflowRestrictionsReadOnly() bool {
+	if e == nil || e.WorkflowRestrictionsReadOnly == nil {
+		return false
+	}
+	return *e.WorkflowRestrictionsReadOnly
+}
+
+// GetTotalCount returns the TotalCount field if it's non-nil, zero value otherwise.
+func (e *EnterpriseRunnerGroups) GetTotalCount() int {
+	if e == nil || e.TotalCount == nil {
+		return 0
+	}
+	return *e.TotalCount
+}
+
 // GetAdvancedSecurityEnabledForNewRepositories returns the AdvancedSecurityEnabledForNewRepositories field if it's non-nil, zero value otherwise.
 func (e *EnterpriseSecurityAnalysisSettings) GetAdvancedSecurityEnabledForNewRepositories() bool {
 	if e == nil || e.AdvancedSecurityEnabledForNewRepositories == nil {
@@ -10398,6 +10518,14 @@ func (l *ListExternalGroupsOptions) GetDisplayName() string {
 	return *l.DisplayName
 }
 
+// GetTotalCount returns the TotalCount field if it's non-nil, zero value otherwise.
+func (l *ListOrganizations) GetTotalCount() int {
+	if l == nil || l.TotalCount == nil {
+		return 0
+	}
+	return *l.TotalCount
+}
+
 // GetTotalCount returns the TotalCount field if it's non-nil, zero value otherwise.
 func (l *ListRepositories) GetTotalCount() int {
 	if l == nil || l.TotalCount == nil {
@@ -22822,6 +22950,38 @@ func (u *UpdateDefaultSetupConfigurationResponse) GetRunURL() string {
 	return *u.RunURL
 }
 
+// GetAllowsPublicRepositories returns the AllowsPublicRepositories field if it's non-nil, zero value otherwise.
+func (u *UpdateEnterpriseRunnerGroupRequest) GetAllowsPublicRepositories() bool {
+	if u == nil || u.AllowsPublicRepositories == nil {
+		return false
+	}
+	return *u.AllowsPublicRepositories
+}
+
+// GetName returns the Name field if it's non-nil, zero value otherwise.
+func (u *UpdateEnterpriseRunnerGroupRequest) GetName() string {
+	if u == nil || u.Name == nil {
+		return ""
+	}
+	return *u.Name
+}
+
+// GetRestrictedToWorkflows returns the RestrictedToWorkflows field if it's non-nil, zero value otherwise.
+func (u *UpdateEnterpriseRunnerGroupRequest) GetRestrictedToWorkflows() bool {
+	if u == nil || u.RestrictedToWorkflows == nil {
+		return false
+	}
+	return *u.RestrictedToWorkflows
+}
+
+// GetVisibility returns the Visibility field if it's non-nil, zero value otherwise.
+func (u *UpdateEnterpriseRunnerGroupRequest) GetVisibility() string {
+	if u == nil || u.Visibility == nil {
+		return ""
+	}
+	return *u.Visibility
+}
+
 // GetAllowsPublicRepositories returns the AllowsPublicRepositories field if it's non-nil, zero value otherwise.
 func (u *UpdateRunnerGroupRequest) GetAllowsPublicRepositories() bool {
 	if u == nil || u.AllowsPublicRepositories == nil {


Test patch:
diff --git a/github/enterprise_actions_runner_groups_test.go b/github/enterprise_actions_runner_groups_test.go
new file mode 100644
index 00000000..36036e41
--- /dev/null
+++ b/github/enterprise_actions_runner_groups_test.go
@@ -0,0 +1,666 @@
+// Copyright 2023 The go-github AUTHORS. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package github
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+)
+
+func TestEnterpriseService_ListRunnerGroups(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/enterprises/o/actions/runner-groups", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		testFormValues(t, r, values{"per_page": "2", "page": "2"})
+		fmt.Fprint(w, `{"total_count":3,"runner_groups":[{"id":1,"name":"Default","visibility":"all","default":true,"runners_url":"https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/1/runners","inherited":false,"allows_public_repositories":true,"restricted_to_workflows":true,"selected_workflows":["a","b"]},{"id":2,"name":"octo-runner-group","visibility":"selected","default":false,"selected_organizations_url":"https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/2/organizations","runners_url":"https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/2/runners","inherited":true,"allows_public_repositories":true,"restricted_to_workflows":false,"selected_workflows":[]},{"id":3,"name":"expensive-hardware","visibility":"private","default":false,"runners_url":"https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/3/runners","inherited":false,"allows_public_repositories":true,"restricted_to_workflows":false,"selected_workflows":[]}]}`)
+	})
+
+	opts := &ListEnterpriseRunnerGroupOptions{ListOptions: ListOptions{Page: 2, PerPage: 2}}
+	ctx := context.Background()
+	groups, _, err := client.Enterprise.ListRunnerGroups(ctx, "o", opts)
+	if err != nil {
+		t.Errorf("Enterprise.ListRunnerGroups returned error: %v", err)
+	}
+
+	want := &EnterpriseRunnerGroups{
+		TotalCount: Int(3),
+		RunnerGroups: []*EnterpriseRunnerGroup{
+			{ID: Int64(1), Name: String("Default"), Visibility: String("all"), Default: Bool(true), RunnersURL: String("https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/1/runners"), Inherited: Bool(false), AllowsPublicRepositories: Bool(true), RestrictedToWorkflows: Bool(true), SelectedWorkflows: []string{"a", "b"}},
+			{ID: Int64(2), Name: String("octo-runner-group"), Visibility: String("selected"), Default: Bool(false), SelectedOrganizationsURL: String("https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/2/organizations"), RunnersURL: String("https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/2/runners"), Inherited: Bool(true), AllowsPublicRepositories: Bool(true), RestrictedToWorkflows: Bool(false), SelectedWorkflows: []string{}},
+			{ID: Int64(3), Name: String("expensive-hardware"), Visibility: String("private"), Default: Bool(false), RunnersURL: String("https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/3/runners"), Inherited: Bool(false), AllowsPublicRepositories: Bool(true), RestrictedToWorkflows: Bool(false), SelectedWorkflows: []string{}},
+		},
+	}
+	if !cmp.Equal(groups, want) {
+		t.Errorf("Enterprise.ListRunnerGroups returned %+v, want %+v", groups, want)
+	}
+
+	const methodName = "ListRunnerGroups"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Enterprise.ListRunnerGroups(ctx, "\n", opts)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Enterprise.ListRunnerGroups(ctx, "o", opts)
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
+
+func TestEnterpriseService_ListRunnerGroupsVisibleToOrganization(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/enterprises/o/actions/runner-groups", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		testFormValues(t, r, values{"per_page": "2", "page": "2", "visible_to_organization": "github"})
+		fmt.Fprint(w, `{"total_count":3,"runner_groups":[{"id":1,"name":"Default","visibility":"all","default":true,"runners_url":"https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/1/runners","inherited":false,"allows_public_repositories":true,"restricted_to_workflows":false,"selected_workflows":[]},{"id":2,"name":"octo-runner-group","visibility":"selected","default":false,"selected_organizations_url":"https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/2/organizations","runners_url":"https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/2/runners","inherited":true,"allows_public_repositories":true,"restricted_to_workflows":false,"selected_workflows":[]},{"id":3,"name":"expensive-hardware","visibility":"private","default":false,"runners_url":"https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/3/runners","inherited":false,"allows_public_repositories":true,"restricted_to_workflows":false,"selected_workflows":[]}]}`)
+	})
+
+	opts := &ListEnterpriseRunnerGroupOptions{ListOptions: ListOptions{Page: 2, PerPage: 2}, VisibleToOrganization: "github"}
+	ctx := context.Background()
+	groups, _, err := client.Enterprise.ListRunnerGroups(ctx, "o", opts)
+	if err != nil {
+		t.Errorf("Enterprise.ListRunnerGroups returned error: %v", err)
+	}
+
+	want := &EnterpriseRunnerGroups{
+		TotalCount: Int(3),
+		RunnerGroups: []*EnterpriseRunnerGroup{
+			{ID: Int64(1), Name: String("Default"), Visibility: String("all"), Default: Bool(true), RunnersURL: String("https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/1/runners"), Inherited: Bool(false), AllowsPublicRepositories: Bool(true), RestrictedToWorkflows: Bool(false), SelectedWorkflows: []string{}},
+			{ID: Int64(2), Name: String("octo-runner-group"), Visibility: String("selected"), Default: Bool(false), SelectedOrganizationsURL: String("https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/2/organizations"), RunnersURL: String("https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/2/runners"), Inherited: Bool(true), AllowsPublicRepositories: Bool(true), RestrictedToWorkflows: Bool(false), SelectedWorkflows: []string{}},
+			{ID: Int64(3), Name: String("expensive-hardware"), Visibility: String("private"), Default: Bool(false), RunnersURL: String("https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/3/runners"), Inherited: Bool(false), AllowsPublicRepositories: Bool(true), RestrictedToWorkflows: Bool(false), SelectedWorkflows: []string{}},
+		},
+	}
+	if !cmp.Equal(groups, want) {
+		t.Errorf("Enterprise.ListRunnerGroups returned %+v, want %+v", groups, want)
+	}
+
+	const methodName = "ListRunnerGroups"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Enterprise.ListRunnerGroups(ctx, "\n", opts)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Enterprise.ListRunnerGroups(ctx, "o", opts)
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
+
+func TestEnterpriseService_GetRunnerGroup(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/enterprises/o/actions/runner-groups/2", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		fmt.Fprint(w, `{"id":2,"name":"octo-runner-group","visibility":"selected","default":false,"selected_organizations_url":"https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/2/organizations","runners_url":"https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/2/runners","inherited":false,"allows_public_repositories":true,"restricted_to_workflows":false,"selected_workflows":[]}`)
+	})
+
+	ctx := context.Background()
+	group, _, err := client.Enterprise.GetEnterpriseRunnerGroup(ctx, "o", 2)
+	if err != nil {
+		t.Errorf("Enterprise.GetRunnerGroup returned error: %v", err)
+	}
+
+	want := &EnterpriseRunnerGroup{
+		ID:                       Int64(2),
+		Name:                     String("octo-runner-group"),
+		Visibility:               String("selected"),
+		Default:                  Bool(false),
+		SelectedOrganizationsURL: String("https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/2/organizations"),
+		RunnersURL:               String("https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/2/runners"),
+		Inherited:                Bool(false),
+		AllowsPublicRepositories: Bool(true),
+		RestrictedToWorkflows:    Bool(false),
+		SelectedWorkflows:        []string{},
+	}
+
+	if !cmp.Equal(group, want) {
+		t.Errorf("Enterprise.GetRunnerGroup returned %+v, want %+v", group, want)
+	}
+
+	const methodName = "GetRunnerGroup"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Enterprise.GetEnterpriseRunnerGroup(ctx, "\n", 2)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Enterprise.GetEnterpriseRunnerGroup(ctx, "o", 2)
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
+
+func TestEnterpriseService_DeleteRunnerGroup(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/enterprises/o/actions/runner-groups/2", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "DELETE")
+	})
+
+	ctx := context.Background()
+	_, err := client.Enterprise.DeleteEnterpriseRunnerGroup(ctx, "o", 2)
+	if err != nil {
+		t.Errorf("Enterprise.DeleteRunnerGroup returned error: %v", err)
+	}
+
+	const methodName = "DeleteRunnerGroup"
+	testBadOptions(t, methodName, func() (err error) {
+		_, err = client.Enterprise.DeleteEnterpriseRunnerGroup(ctx, "\n", 2)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		return client.Enterprise.DeleteEnterpriseRunnerGroup(ctx, "o", 2)
+	})
+}
+
+func TestEnterpriseService_CreateRunnerGroup(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/enterprises/o/actions/runner-groups", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "POST")
+		fmt.Fprint(w, `{"id":2,"name":"octo-runner-group","visibility":"selected","default":false,"selected_organizations_url":"https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/2/organizations","runners_url":"https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/2/runners","inherited":false,"allows_public_repositories":true,"restricted_to_workflows":false,"selected_workflows":[]}`)
+	})
+
+	ctx := context.Background()
+	req := CreateEnterpriseRunnerGroupRequest{
+		Name:                     String("octo-runner-group"),
+		Visibility:               String("selected"),
+		AllowsPublicRepositories: Bool(true),
+		RestrictedToWorkflows:    Bool(false),
+		SelectedWorkflows:        []string{},
+	}
+	group, _, err := client.Enterprise.CreateEnterpriseRunnerGroup(ctx, "o", req)
+	if err != nil {
+		t.Errorf("Enterprise.CreateRunnerGroup returned error: %v", err)
+	}
+
+	want := &EnterpriseRunnerGroup{
+		ID:                       Int64(2),
+		Name:                     String("octo-runner-group"),
+		Visibility:               String("selected"),
+		Default:                  Bool(false),
+		SelectedOrganizationsURL: String("https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/2/organizations"),
+		RunnersURL:               String("https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/2/runners"),
+		Inherited:                Bool(false),
+		AllowsPublicRepositories: Bool(true),
+		RestrictedToWorkflows:    Bool(false),
+		SelectedWorkflows:        []string{},
+	}
+
+	if !cmp.Equal(group, want) {
+		t.Errorf("Enterprise.CreateRunnerGroup returned %+v, want %+v", group, want)
+	}
+
+	const methodName = "CreateRunnerGroup"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Enterprise.CreateEnterpriseRunnerGroup(ctx, "\n", req)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Enterprise.CreateEnterpriseRunnerGroup(ctx, "o", req)
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
+
+func TestEnterpriseService_UpdateRunnerGroup(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/enterprises/o/actions/runner-groups/2", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "PATCH")
+		fmt.Fprint(w, `{"id":2,"name":"octo-runner-group","visibility":"selected","default":false,"selected_organizations_url":"https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/2/organizations","runners_url":"https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/2/runners","inherited":false,"allows_public_repositories":true,"restricted_to_workflows":false,"selected_workflows":[]}`)
+	})
+
+	ctx := context.Background()
+	req := UpdateEnterpriseRunnerGroupRequest{
+		Name:                     String("octo-runner-group"),
+		Visibility:               String("selected"),
+		AllowsPublicRepositories: Bool(true),
+		RestrictedToWorkflows:    Bool(false),
+		SelectedWorkflows:        []string{},
+	}
+	group, _, err := client.Enterprise.UpdateEnterpriseRunnerGroup(ctx, "o", 2, req)
+	if err != nil {
+		t.Errorf("Enterprise.UpdateRunnerGroup returned error: %v", err)
+	}
+
+	want := &EnterpriseRunnerGroup{
+		ID:                       Int64(2),
+		Name:                     String("octo-runner-group"),
+		Visibility:               String("selected"),
+		Default:                  Bool(false),
+		SelectedOrganizationsURL: String("https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/2/organizations"),
+		RunnersURL:               String("https://api.github.com/enterprises/octo-enterprise/actions/runner_groups/2/runners"),
+		Inherited:                Bool(false),
+		AllowsPublicRepositories: Bool(true),
+		RestrictedToWorkflows:    Bool(false),
+		SelectedWorkflows:        []string{},
+	}
+
+	if !cmp.Equal(group, want) {
+		t.Errorf("Enterprise.UpdateRunnerGroup returned %+v, want %+v", group, want)
+	}
+
+	const methodName = "UpdateRunnerGroup"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Enterprise.UpdateEnterpriseRunnerGroup(ctx, "\n", 2, req)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Enterprise.UpdateEnterpriseRunnerGroup(ctx, "o", 2, req)
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
+
+func TestEnterpriseService_ListOrganizationAccessRunnerGroup(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/enterprises/o/actions/runner-groups/2/organizations", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		testFormValues(t, r, values{"per_page": "1", "page": "1"})
+		fmt.Fprint(w, `{"total_count": 1, "organizations": [{"id": 43, "node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5", "name": "Hello-World", "login": "octocat"}]}`)
+	})
+
+	ctx := context.Background()
+	opts := &ListOptions{Page: 1, PerPage: 1}
+	groups, _, err := client.Enterprise.ListOrganizationAccessRunnerGroup(ctx, "o", 2, opts)
+	if err != nil {
+		t.Errorf("Enterprise.ListOrganizationAccessRunnerGroup returned error: %v", err)
+	}
+
+	want := &ListOrganizations{
+		TotalCount: Int(1),
+		Organizations: []*Organization{
+			{ID: Int64(43), NodeID: String("MDEwOlJlcG9zaXRvcnkxMjk2MjY5"), Name: String("Hello-World"), Login: String("octocat")},
+		},
+	}
+	if !cmp.Equal(groups, want) {
+		t.Errorf("Enterprise.ListOrganizationAccessRunnerGroup returned %+v, want %+v", groups, want)
+	}
+
+	const methodName = "ListOrganizationAccessRunnerGroup"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Enterprise.ListOrganizationAccessRunnerGroup(ctx, "\n", 2, opts)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Enterprise.ListOrganizationAccessRunnerGroup(ctx, "o", 2, opts)
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
+
+func TestEnterpriseService_SetOrganizationAccessRunnerGroup(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/enterprises/o/actions/runner-groups/2/organizations", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "PUT")
+	})
+
+	req := SetOrgAccessRunnerGroupRequest{
+		SelectedOrganizationIDs: []int64{
+			1,
+			2,
+		},
+	}
+
+	ctx := context.Background()
+	_, err := client.Enterprise.SetOrganizationAccessRunnerGroup(ctx, "o", 2, req)
+	if err != nil {
+		t.Errorf("Enterprise.SetOrganizationAccessRunnerGroup returned error: %v", err)
+	}
+
+	const methodName = "SetRepositoryAccessRunnerGroup"
+	testBadOptions(t, methodName, func() (err error) {
+		_, err = client.Enterprise.SetOrganizationAccessRunnerGroup(ctx, "\n", 2, req)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		return client.Enterprise.SetOrganizationAccessRunnerGroup(ctx, "o", 2, req)
+	})
+}
+
+func TestEnterpriseService_AddOrganizationAccessRunnerGroup(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/enterprises/o/actions/runner-groups/2/organizations/42", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "PUT")
+	})
+
+	ctx := context.Background()
+	_, err := client.Enterprise.AddOrganizationAccessRunnerGroup(ctx, "o", 2, 42)
+	if err != nil {
+		t.Errorf("Enterprise.AddOrganizationAccessRunnerGroup returned error: %v", err)
+	}
+
+	const methodName = "AddOrganizationAccessRunnerGroup"
+	testBadOptions(t, methodName, func() (err error) {
+		_, err = client.Enterprise.AddOrganizationAccessRunnerGroup(ctx, "\n", 2, 42)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		return client.Enterprise.AddOrganizationAccessRunnerGroup(ctx, "o", 2, 42)
+	})
+}
+
+func TestEnterpriseService_RemoveOrganizationAccessRunnerGroup(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/enterprises/o/actions/runner-groups/2/organizations/42", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "DELETE")
+	})
+
+	ctx := context.Background()
+	_, err := client.Enterprise.RemoveOrganizationAccessRunnerGroup(ctx, "o", 2, 42)
+	if err != nil {
+		t.Errorf("Enterprise.RemoveOrganizationAccessRunnerGroup returned error: %v", err)
+	}
+
+	const methodName = "RemoveOrganizationAccessRunnerGroup"
+	testBadOptions(t, methodName, func() (err error) {
+		_, err = client.Enterprise.RemoveOrganizationAccessRunnerGroup(ctx, "\n", 2, 42)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		return client.Enterprise.RemoveOrganizationAccessRunnerGroup(ctx, "o", 2, 42)
+	})
+}
+
+func TestEnterpriseService_ListEnterpriseRunnerGroupRunners(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/enterprises/o/actions/runner-groups/2/runners", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		testFormValues(t, r, values{"per_page": "2", "page": "2"})
+		fmt.Fprint(w, `{"total_count":2,"runners":[{"id":23,"name":"MBP","os":"macos","status":"online"},{"id":24,"name":"iMac","os":"macos","status":"offline"}]}`)
+	})
+
+	opts := &ListOptions{Page: 2, PerPage: 2}
+	ctx := context.Background()
+	runners, _, err := client.Enterprise.ListRunnerGroupRunners(ctx, "o", 2, opts)
+	if err != nil {
+		t.Errorf("Enterprise.ListEnterpriseRunnerGroupRunners returned error: %v", err)
+	}
+
+	want := &Runners{
+		TotalCount: 2,
+		Runners: []*Runner{
+			{ID: Int64(23), Name: String("MBP"), OS: String("macos"), Status: String("online")},
+			{ID: Int64(24), Name: String("iMac"), OS: String("macos"), Status: String("offline")},
+		},
+	}
+	if !cmp.Equal(runners, want) {
+		t.Errorf("Enterprise.ListEnterpriseRunnerGroupRunners returned %+v, want %+v", runners, want)
+	}
+
+	const methodName = "ListEnterpriseRunnerGroupRunners"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Enterprise.ListRunnerGroupRunners(ctx, "\n", 2, opts)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Enterprise.ListRunnerGroupRunners(ctx, "o", 2, opts)
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
+
+func TestEnterpriseService_SetEnterpriseRunnerGroupRunners(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/enterprises/o/actions/runner-groups/2/runners", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "PUT")
+	})
+
+	req := SetRunnerGroupRunnersRequest{
+		Runners: []int64{
+			1,
+			2,
+		},
+	}
+
+	ctx := context.Background()
+	_, err := client.Enterprise.SetRunnerGroupRunners(ctx, "o", 2, req)
+	if err != nil {
+		t.Errorf("Enterprise.SetEnterpriseRunnerGroupRunners returned error: %v", err)
+	}
+
+	const methodName = "SetEnterpriseRunnerGroupRunners"
+	testBadOptions(t, methodName, func() (err error) {
+		_, err = client.Enterprise.SetRunnerGroupRunners(ctx, "\n", 2, req)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		return client.Enterprise.SetRunnerGroupRunners(ctx, "o", 2, req)
+	})
+}
+
+func TestEnterpriseService_AddEnterpriseRunnerGroupRunners(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/enterprises/o/actions/runner-groups/2/runners/42", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "PUT")
+	})
+
+	ctx := context.Background()
+	_, err := client.Enterprise.AddRunnerGroupRunners(ctx, "o", 2, 42)
+	if err != nil {
+		t.Errorf("Enterprise.AddEnterpriseRunnerGroupRunners returned error: %v", err)
+	}
+
+	const methodName = "AddEnterpriseRunnerGroupRunners"
+	testBadOptions(t, methodName, func() (err error) {
+		_, err = client.Enterprise.AddRunnerGroupRunners(ctx, "\n", 2, 42)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		return client.Enterprise.AddRunnerGroupRunners(ctx, "o", 2, 42)
+	})
+}
+
+func TestEnterpriseService_RemoveEnterpriseRunnerGroupRunners(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/enterprises/o/actions/runner-groups/2/runners/42", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "DELETE")
+	})
+
+	ctx := context.Background()
+	_, err := client.Enterprise.RemoveRunnerGroupRunners(ctx, "o", 2, 42)
+	if err != nil {
+		t.Errorf("Enterprise.RemoveEnterpriseRunnerGroupRunners returned error: %v", err)
+	}
+
+	const methodName = "RemoveEnterpriseRunnerGroupRunners"
+	testBadOptions(t, methodName, func() (err error) {
+		_, err = client.Enterprise.RemoveRunnerGroupRunners(ctx, "\n", 2, 42)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		return client.Enterprise.RemoveRunnerGroupRunners(ctx, "o", 2, 42)
+	})
+}
+
+func TestEnterpriseRunnerGroup_Marshal(t *testing.T) {
+	testJSONMarshal(t, &EnterpriseRunnerGroup{}, "{}")
+
+	u := &EnterpriseRunnerGroup{
+		ID:                       Int64(1),
+		Name:                     String("n"),
+		Visibility:               String("v"),
+		Default:                  Bool(true),
+		SelectedOrganizationsURL: String("s"),
+		RunnersURL:               String("r"),
+		Inherited:                Bool(true),
+		AllowsPublicRepositories: Bool(true),
+		RestrictedToWorkflows:    Bool(false),
+		SelectedWorkflows:        []string{},
+	}
+
+	want := `{
+		"id": 1,
+		"name": "n",
+		"visibility": "v",
+		"default": true,
+		"selected_organizations_url": "s",
+		"runners_url": "r",
+		"inherited": true,
+		"allows_public_repositories": true,
+		"restricted_to_workflows": false,
+		"selected_workflows": []
+	}`
+
+	testJSONMarshal(t, u, want)
+}
+
+func TestEnterpriseRunnerGroups_Marshal(t *testing.T) {
+	testJSONMarshal(t, &EnterpriseRunnerGroups{}, "{}")
+
+	u := &EnterpriseRunnerGroups{
+		TotalCount: Int(1),
+		RunnerGroups: []*EnterpriseRunnerGroup{
+			{
+				ID:                       Int64(1),
+				Name:                     String("n"),
+				Visibility:               String("v"),
+				Default:                  Bool(true),
+				SelectedOrganizationsURL: String("s"),
+				RunnersURL:               String("r"),
+				Inherited:                Bool(true),
+				AllowsPublicRepositories: Bool(true),
+				RestrictedToWorkflows:    Bool(false),
+				SelectedWorkflows:        []string{},
+			},
+		},
+	}
+
+	want := `{
+		"total_count": 1,
+		"runner_groups": [{
+			"id": 1,
+			"name": "n",
+			"visibility": "v",
+			"default": true,
+			"selected_organizations_url": "s",
+			"runners_url": "r",
+			"inherited": true,
+			"allows_public_repositories": true,
+			"restricted_to_workflows": false,
+			"selected_workflows": []
+		}]		
+	}`
+
+	testJSONMarshal(t, u, want)
+}
+
+func TestCreateEnterpriseRunnerGroupRequest_Marshal(t *testing.T) {
+	testJSONMarshal(t, &CreateEnterpriseRunnerGroupRequest{}, "{}")
+
+	u := &CreateEnterpriseRunnerGroupRequest{
+		Name:                     String("n"),
+		Visibility:               String("v"),
+		SelectedOrganizationIDs:  []int64{1},
+		Runners:                  []int64{1},
+		AllowsPublicRepositories: Bool(true),
+		RestrictedToWorkflows:    Bool(true),
+		SelectedWorkflows:        []string{"a", "b"},
+	}
+
+	want := `{
+		"name": "n",
+		"visibility": "v",
+		"selected_organization_ids": [1],
+		"runners": [1],
+		"allows_public_repositories": true,
+		"restricted_to_workflows": true,
+		"selected_workflows": ["a","b"]
+	}`
+
+	testJSONMarshal(t, u, want)
+}
+
+func TestUpdateEnterpriseRunnerGroupRequest_Marshal(t *testing.T) {
+	testJSONMarshal(t, &UpdateEnterpriseRunnerGroupRequest{}, "{}")
+
+	u := &UpdateEnterpriseRunnerGroupRequest{
+		Name:                     String("n"),
+		Visibility:               String("v"),
+		AllowsPublicRepositories: Bool(true),
+		RestrictedToWorkflows:    Bool(false),
+		SelectedWorkflows:        []string{},
+	}
+
+	want := `{
+		"name": "n",
+		"visibility": "v",
+		"allows_public_repositories": true,
+		"restricted_to_workflows": false,
+		"selected_workflows": []
+	}`
+
+	testJSONMarshal(t, u, want)
+}
+
+func TestSetOrgAccessRunnerGroupRequest_Marshal(t *testing.T) {
+	testJSONMarshal(t, &SetOrgAccessRunnerGroupRequest{}, "{}")
+
+	u := &SetOrgAccessRunnerGroupRequest{
+		SelectedOrganizationIDs: []int64{1},
+	}
+
+	want := `{
+		"selected_organization_ids": [1]
+	}`
+
+	testJSONMarshal(t, u, want)
+}
diff --git a/github/enterprise_actions_runners_test.go b/github/enterprise_actions_runners_test.go
index b7c3f78b..a1d3f17a 100644
--- a/github/enterprise_actions_runners_test.go
+++ b/github/enterprise_actions_runners_test.go
@@ -7,6 +7,7 @@ package github
 
 import (
 	"context"
+	"encoding/json"
 	"fmt"
 	"net/http"
 	"testing"
@@ -15,6 +16,50 @@ import (
 	"github.com/google/go-cmp/cmp"
 )
 
+func TestEnterpriseService_GenerateEnterpriseJITConfig(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	input := &GenerateJITConfigRequest{Name: "test", RunnerGroupID: 1, Labels: []string{"one", "two"}}
+
+	mux.HandleFunc("/enterprises/o/actions/runners/generate-jitconfig", func(w http.ResponseWriter, r *http.Request) {
+		v := new(GenerateJITConfigRequest)
+		json.NewDecoder(r.Body).Decode(v)
+
+		testMethod(t, r, "POST")
+		if !cmp.Equal(v, input) {
+			t.Errorf("Request body = %+v, want %+v", v, input)
+		}
+
+		fmt.Fprint(w, `{"encoded_jit_config":"foo"}`)
+	})
+
+	ctx := context.Background()
+	jitConfig, _, err := client.Enterprise.GenerateEnterpriseJITConfig(ctx, "o", input)
+	if err != nil {
+		t.Errorf("Enterprise.GenerateEnterpriseJITConfig returned error: %v", err)
+	}
+
+	want := &JITRunnerConfig{EncodedJITConfig: String("foo")}
+	if !cmp.Equal(jitConfig, want) {
+		t.Errorf("Enterprise.GenerateEnterpriseJITConfig returned %+v, want %+v", jitConfig, want)
+	}
+
+	const methodName = "GenerateEnterpriseJITConfig"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Enterprise.GenerateEnterpriseJITConfig(ctx, "\n", input)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Enterprise.GenerateEnterpriseJITConfig(ctx, "o", input)
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
+
 func TestEnterpriseService_CreateRegistrationToken(t *testing.T) {
 	client, mux, _, teardown := setup()
 	defer teardown()
diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go
index 262cdd5a..10ef017b 100644
--- a/github/github-accessors_test.go
+++ b/github/github-accessors_test.go
@@ -5400,6 +5400,46 @@ func TestCreateCodespaceOptions_GetWorkingDirectory(tt *testing.T) {
 	c.GetWorkingDirectory()
 }
 
+func TestCreateEnterpriseRunnerGroupRequest_GetAllowsPublicRepositories(tt *testing.T) {
+	var zeroValue bool
+	c := &CreateEnterpriseRunnerGroupRequest{AllowsPublicRepositories: &zeroValue}
+	c.GetAllowsPublicRepositories()
+	c = &CreateEnterpriseRunnerGroupRequest{}
+	c.GetAllowsPublicRepositories()
+	c = nil
+	c.GetAllowsPublicRepositories()
+}
+
+func TestCreateEnterpriseRunnerGroupRequest_GetName(tt *testing.T) {
+	var zeroValue string
+	c := &CreateEnterpriseRunnerGroupRequest{Name: &zeroValue}
+	c.GetName()
+	c = &CreateEnterpriseRunnerGroupRequest{}
+	c.GetName()
+	c = nil
+	c.GetName()
+}
+
+func TestCreateEnterpriseRunnerGroupRequest_GetRestrictedToWorkflows(tt *testing.T) {
+	var zeroValue bool
+	c := &CreateEnterpriseRunnerGroupRequest{RestrictedToWorkflows: &zeroValue}
+	c.GetRestrictedToWorkflows()
+	c = &CreateEnterpriseRunnerGroupRequest{}
+	c.GetRestrictedToWorkflows()
+	c = nil
+	c.GetRestrictedToWorkflows()
+}
+
+func TestCreateEnterpriseRunnerGroupRequest_GetVisibility(tt *testing.T) {
+	var zeroValue string
+	c := &CreateEnterpriseRunnerGroupRequest{Visibility: &zeroValue}
+	c.GetVisibility()
+	c = &CreateEnterpriseRunnerGroupRequest{}
+	c.GetVisibility()
+	c = nil
+	c.GetVisibility()
+}
+
 func TestCreateEvent_GetDescription(tt *testing.T) {
 	var zeroValue string
 	c := &CreateEvent{Description: &zeroValue}
@@ -7763,6 +7803,116 @@ func TestEnterprise_GetWebsiteURL(tt *testing.T) {
 	e.GetWebsiteURL()
 }
 
+func TestEnterpriseRunnerGroup_GetAllowsPublicRepositories(tt *testing.T) {
+	var zeroValue bool
+	e := &EnterpriseRunnerGroup{AllowsPublicRepositories: &zeroValue}
+	e.GetAllowsPublicRepositories()
+	e = &EnterpriseRunnerGroup{}
+	e.GetAllowsPublicRepositories()
+	e = nil
+	e.GetAllowsPublicRepositories()
+}
+
+func TestEnterpriseRunnerGroup_GetDefault(tt *testing.T) {
+	var zeroValue bool
+	e := &EnterpriseRunnerGroup{Default: &zeroValue}
+	e.GetDefault()
+	e = &EnterpriseRunnerGroup{}
+	e.GetDefault()
+	e = nil
+	e.GetDefault()
+}
+
+func TestEnterpriseRunnerGroup_GetID(tt *testing.T) {
+	var zeroValue int64
+	e := &EnterpriseRunnerGroup{ID: &zeroValue}
+	e.GetID()
+	e = &EnterpriseRunnerGroup{}
+	e.GetID()
+	e = nil
+	e.GetID()
+}
+
+func TestEnterpriseRunnerGroup_GetInherited(tt *testing.T) {
+	var zeroValue bool
+	e := &EnterpriseRunnerGroup{Inherited: &zeroValue}
+	e.GetInherited()
+	e = &EnterpriseRunnerGroup{}
+	e.GetInherited()
+	e = nil
+	e.GetInherited()
+}
+
+func TestEnterpriseRunnerGroup_GetName(tt *testing.T) {
+	var zeroValue string
+	e := &EnterpriseRunnerGroup{Name: &zeroValue}
+	e.GetName()
+	e = &EnterpriseRunnerGroup{}
+	e.GetName()
+	e = nil
+	e.GetName()
+}
+
+func TestEnterpriseRunnerGroup_GetRestrictedToWorkflows(tt *testing.T) {
+	var zeroValue bool
+	e := &EnterpriseRunnerGroup{RestrictedToWorkflows: &zeroValue}
+	e.GetRestrictedToWorkflows()
+	e = &EnterpriseRunnerGroup{}
+	e.GetRestrictedToWorkflows()
+	e = nil
+	e.GetRestrictedToWorkflows()
+}
+
+func TestEnterpriseRunnerGroup_GetRunnersURL(tt *testing.T) {
+	var zeroValue string
+	e := &EnterpriseRunnerGroup{RunnersURL: &zeroValue}
+	e.GetRunnersURL()
+	e = &EnterpriseRunnerGroup{}
+	e.GetRunnersURL()
+	e = nil
+	e.GetRunnersURL()
+}
+
+func TestEnterpriseRunnerGroup_GetSelectedOrganizationsURL(tt *testing.T) {
+	var zeroValue string
+	e := &EnterpriseRunnerGroup{SelectedOrganizationsURL: &zeroValue}
+	e.GetSelectedOrganizationsURL()
+	e = &EnterpriseRunnerGroup{}
+	e.GetSelectedOrganizationsURL()
+	e = nil
+	e.GetSelectedOrganizationsURL()
+}
+
+func TestEnterpriseRunnerGroup_GetVisibility(tt *testing.T) {
+	var zeroValue string
+	e := &EnterpriseRunnerGroup{Visibility: &zeroValue}
+	e.GetVisibility()
+	e = &EnterpriseRunnerGroup{}
+	e.GetVisibility()
+	e = nil
+	e.GetVisibility()
+}
+
+func TestEnterpriseRunnerGroup_GetWorkflowRestrictionsReadOnly(tt *testing.T) {
+	var zeroValue bool
+	e := &EnterpriseRunnerGroup{WorkflowRestrictionsReadOnly: &zeroValue}
+	e.GetWorkflowRestrictionsReadOnly()
+	e = &EnterpriseRunnerGroup{}
+	e.GetWorkflowRestrictionsReadOnly()
+	e = nil
+	e.GetWorkflowRestrictionsReadOnly()
+}
+
+func TestEnterpriseRunnerGroups_GetTotalCount(tt *testing.T) {
+	var zeroValue int
+	e := &EnterpriseRunnerGroups{TotalCount: &zeroValue}
+	e.GetTotalCount()
+	e = &EnterpriseRunnerGroups{}
+	e.GetTotalCount()
+	e = nil
+	e.GetTotalCount()
+}
+
 func TestEnterpriseSecurityAnalysisSettings_GetAdvancedSecurityEnabledForNewRepositories(tt *testing.T) {
 	var zeroValue bool
 	e := &EnterpriseSecurityAnalysisSettings{AdvancedSecurityEnabledForNewRepositories: &zeroValue}
@@ -12188,6 +12338,16 @@ func TestListExternalGroupsOptions_GetDisplayName(tt *testing.T) {
 	l.GetDisplayName()
 }
 
+func TestListOrganizations_GetTotalCount(tt *testing.T) {
+	var zeroValue int
+	l := &ListOrganizations{TotalCount: &zeroValue}
+	l.GetTotalCount()
+	l = &ListOrganizations{}
+	l.GetTotalCount()
+	l = nil
+	l.GetTotalCount()
+}
+
 func TestListRepositories_GetTotalCount(tt *testing.T) {
 	var zeroValue int
 	l := &ListRepositories{TotalCount: &zeroValue}
@@ -26560,6 +26720,46 @@ func TestUpdateDefaultSetupConfigurationResponse_GetRunURL(tt *testing.T) {
 	u.GetRunURL()
 }
 
+func TestUpdateEnterpriseRunnerGroupRequest_GetAllowsPublicRepositories(tt *testing.T) {
+	var zeroValue bool
+	u := &UpdateEnterpriseRunnerGroupRequest{AllowsPublicRepositories: &zeroValue}
+	u.GetAllowsPublicRepositories()
+	u = &UpdateEnterpriseRunnerGroupRequest{}
+	u.GetAllowsPublicRepositories()
+	u = nil
+	u.GetAllowsPublicRepositories()
+}
+
+func TestUpdateEnterpriseRunnerGroupRequest_GetName(tt *testing.T) {
+	var zeroValue string
+	u := &UpdateEnterpriseRunnerGroupRequest{Name: &zeroValue}
+	u.GetName()
+	u = &UpdateEnterpriseRunnerGroupRequest{}
+	u.GetName()
+	u = nil
+	u.GetName()
+}
+
+func TestUpdateEnterpriseRunnerGroupRequest_GetRestrictedToWorkflows(tt *testing.T) {
+	var zeroValue bool
+	u := &UpdateEnterpriseRunnerGroupRequest{RestrictedToWorkflows: &zeroValue}
+	u.GetRestrictedToWorkflows()
+	u = &UpdateEnterpriseRunnerGroupRequest{}
+	u.GetRestrictedToWorkflows()
+	u = nil
+	u.GetRestrictedToWorkflows()
+}
+
+func TestUpdateEnterpriseRunnerGroupRequest_GetVisibility(tt *testing.T) {
+	var zeroValue string
+	u := &UpdateEnterpriseRunnerGroupRequest{Visibility: &zeroValue}
+	u.GetVisibility()
+	u = &UpdateEnterpriseRunnerGroupRequest{}
+	u.GetVisibility()
+	u = nil
+	u.GetVisibility()
+}
+
 func TestUpdateRunnerGroupRequest_GetAllowsPublicRepositories(tt *testing.T) {
 	var zeroValue bool
 	u := &UpdateRunnerGroupRequest{AllowsPublicRepositories: &zeroValue}