Repository: google/go-github
Pull request #3174 (2024-05-22 18:56:17)

Allow an empty array of BypassActors in Ruleset struct in CreateRuleset endpoint
Fixes: [#3137](https://github.com/google/go-github/issues/3137)

added an extra Ruleset struct and CreateRuleset endpoint in repo_rules.go to allow the BypassActors field to be passed as nil or an empty array

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/google/go-github/pull/3174?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 92.94%. Comparing base [(`2b8c7fa`)](https://app.codecov.io/gh/google/go-github/commit/2b8c7fa86fcd1cb4a89a44c8e7b5a49fe4be8a45?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google) to head [(`133421c`)](https://app.codecov.io/gh/google/go-github/pull/3174?dropdown=coverage&src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google).
> Report is 64 commits behind head on master.


<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master    #3174      +/-   ##
==========================================
- Coverage   97.72%   92.94%   -4.78%     
==========================================
  Files         153      171      +18     
  Lines       13390    11552    -1838     
==========================================
- Hits        13085    10737    -2348     
- Misses        215      724     +509     
- Partials       90       91       +1     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/google/go-github/pull/3174?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google).

Matthew-Reidy: Do you mean something like having an anonymous struct identical to Ruleset in the new functions scope that would just copy over the values of Ruleset to?

gmlewis: > Do you mean something like having an anonymous struct identical to Ruleset in the new functions scope that would just copy over the values of Ruleset to? I understand your idea but i'm confused about the implementation.

Yes, that is what I mean.

We have other examples of this in our repo.

Here is one of many: https://github.com/google/go-github/blob/master/github/repos.go#L546-L573

I found this by typing:

```bash
$ grep 'type [a-z]' github/*.go
```
Matthew-Reidy: Ok. I commited your suggested changes. I didn't know rulesetNoOmitBypassActors made it non exported. Learned something new about the language. Thanks!
gmlewis: Please re-run step 4 in CONTRIBUTING.md to re-generate the auto-generated files... then the tests should all pass.
You can also test locally before you push by running `go test ./...`

Patch:
diff --git a/README.md b/README.md
index b243c795..cbbcd485 100644
--- a/README.md
+++ b/README.md
@@ -101,8 +101,7 @@ For API methods that require HTTP Basic Authentication, use the
 
 #### As a GitHub App ####
 
-GitHub Apps authentication can be provided by the [ghinstallation](https://github.com/bradleyfalzon/ghinstallation)
-package.
+GitHub Apps authentication can be provided by different pkgs like [ghinstallation](https://github.com/bradleyfalzon/ghinstallation) or [go-githubauth](https://github.com/jferrl/go-githubauth).
 
 > **Note**: Most endpoints (ex. [`GET /rate_limit`]) require access token authentication
 > while a few others (ex. [`GET /app/hook/deliveries`]) require [JWT] authentication.
@@ -111,6 +110,9 @@ package.
 [`GET /app/hook/deliveries`]: https://docs.github.com/en/rest/apps/webhooks#list-deliveries-for-an-app-webhook
 [JWT]: https://docs.github.com/en/developers/apps/building-github-apps/authenticating-with-github-apps#authenticating-as-a-github-app
 
+`ghinstallation` provides `Transport`, which implements `http.RoundTripper` to provide authentication as an installation for GitHub Apps.
+
+Here is an example of how to authenticate as a GitHub App using the `ghinstallation` package:
 
 ```go
 import (
@@ -138,6 +140,44 @@ func main() {
 }
 ```
 
+`go-githubauth` implements a set of `oauth2.TokenSource` to be used with `oauth2.Client`. An `oauth2.Client` can be injected into the `github.Client` to authenticate requests.
+
+Other example using `go-githubauth`:
+
+```go
+package main
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "strconv"
+
+ "github.com/google/go-github/v62/github"
+ "github.com/jferrl/go-githubauth"
+ "golang.org/x/oauth2"
+)
+
+func main() {
+ privateKey := []byte(os.Getenv("GITHUB_APP_PRIVATE_KEY"))
+
+ appTokenSource, err := githubauth.NewApplicationTokenSource(1112, privateKey)
+ if err != nil {
+  fmt.Println("Error creating application token source:", err)
+  return
+ }
+
+ installationTokenSource := githubauth.NewInstallationTokenSource(1113, appTokenSource)
+
+ // oauth2.NewClient uses oauth2.ReuseTokenSource to reuse the token until it expires.
+ // The token will be automatically refreshed when it expires.
+ // InstallationTokenSource has the mechanism to refresh the token when it expires.
+ httpClient := oauth2.NewClient(context.Background(), installationTokenSource)
+
+ client := github.NewClient(httpClient)
+}
+```
+
 *Note*: In order to interact with certain APIs, for example writing a file to a repo, one must generate an installation token
 using the installation ID of the GitHub app and authenticate with the OAuth method mentioned above. See the examples.
 
diff --git a/github/apps.go b/github/apps.go
index 6969daba..16ef758c 100644
--- a/github/apps.go
+++ b/github/apps.go
@@ -78,6 +78,7 @@ type InstallationTokenListRepoOptions struct {
 //	https://docs.github.com/rest/apps#create-an-installation-access-token-for-an-app
 type InstallationPermissions struct {
 	Actions                       *string `json:"actions,omitempty"`
+	ActionsVariables              *string `json:"actions_variables,omitempty"`
 	Administration                *string `json:"administration,omitempty"`
 	Blocking                      *string `json:"blocking,omitempty"`
 	Checks                        *string `json:"checks,omitempty"`
@@ -93,6 +94,7 @@ type InstallationPermissions struct {
 	OrganizationAdministration    *string `json:"organization_administration,omitempty"`
 	OrganizationCustomProperties  *string `json:"organization_custom_properties,omitempty"`
 	OrganizationCustomRoles       *string `json:"organization_custom_roles,omitempty"`
+	OrganizationCustomOrgRoles    *string `json:"organization_custom_org_roles,omitempty"`
 	OrganizationHooks             *string `json:"organization_hooks,omitempty"`
 	OrganizationPackages          *string `json:"organization_packages,omitempty"`
 	OrganizationPlan              *string `json:"organization_plan,omitempty"`
diff --git a/github/enterprise_actions_runners.go b/github/enterprise_actions_runners.go
index a5364815..fa345aea 100644
--- a/github/enterprise_actions_runners.go
+++ b/github/enterprise_actions_runners.go
@@ -101,6 +101,27 @@ func (s *EnterpriseService) ListRunners(ctx context.Context, enterprise string,
 	return runners, resp, nil
 }
 
+// GetRunner gets a specific self-hosted runner configured in an enterprise.
+//
+// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/actions/self-hosted-runners#get-a-self-hosted-runner-for-an-enterprise
+//
+//meta:operation GET /enterprises/{enterprise}/actions/runners/{runner_id}
+func (s *EnterpriseService) GetRunner(ctx context.Context, enterprise string, runnerID int64) (*Runner, *Response, error) {
+	u := fmt.Sprintf("enterprises/%v/actions/runners/%v", enterprise, runnerID)
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	runner := new(Runner)
+	resp, err := s.client.Do(ctx, req, runner)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return runner, resp, nil
+}
+
 // RemoveRunner forces the removal of a self-hosted runner from an enterprise using the runner id.
 //
 // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/actions/self-hosted-runners#delete-a-self-hosted-runner-from-an-enterprise
diff --git a/github/github-accessors.go b/github/github-accessors.go
index 421922d3..5118791c 100644
--- a/github/github-accessors.go
+++ b/github/github-accessors.go
@@ -8822,6 +8822,14 @@ func (i *InstallationPermissions) GetActions() string {
 	return *i.Actions
 }
 
+// GetActionsVariables returns the ActionsVariables field if it's non-nil, zero value otherwise.
+func (i *InstallationPermissions) GetActionsVariables() string {
+	if i == nil || i.ActionsVariables == nil {
+		return ""
+	}
+	return *i.ActionsVariables
+}
+
 // GetAdministration returns the Administration field if it's non-nil, zero value otherwise.
 func (i *InstallationPermissions) GetAdministration() string {
 	if i == nil || i.Administration == nil {
@@ -8926,6 +8934,14 @@ func (i *InstallationPermissions) GetOrganizationAdministration() string {
 	return *i.OrganizationAdministration
 }
 
+// GetOrganizationCustomOrgRoles returns the OrganizationCustomOrgRoles field if it's non-nil, zero value otherwise.
+func (i *InstallationPermissions) GetOrganizationCustomOrgRoles() string {
+	if i == nil || i.OrganizationCustomOrgRoles == nil {
+		return ""
+	}
+	return *i.OrganizationCustomOrgRoles
+}
+
 // GetOrganizationCustomProperties returns the OrganizationCustomProperties field if it's non-nil, zero value otherwise.
 func (i *InstallationPermissions) GetOrganizationCustomProperties() string {
 	if i == nil || i.OrganizationCustomProperties == nil {
@@ -20078,6 +20094,14 @@ func (r *RepositoryPermissionLevel) GetPermission() string {
 	return *r.Permission
 }
 
+// GetRoleName returns the RoleName field if it's non-nil, zero value otherwise.
+func (r *RepositoryPermissionLevel) GetRoleName() string {
+	if r == nil || r.RoleName == nil {
+		return ""
+	}
+	return *r.RoleName
+}
+
 // GetUser returns the User field.
 func (r *RepositoryPermissionLevel) GetUser() *User {
 	if r == nil {
@@ -20854,6 +20878,14 @@ func (r *RulesetConditions) GetRepositoryName() *RulesetRepositoryNamesCondition
 	return r.RepositoryName
 }
 
+// GetRepositoryProperty returns the RepositoryProperty field.
+func (r *RulesetConditions) GetRepositoryProperty() *RulesetRepositoryPropertyConditionParameters {
+	if r == nil {
+		return nil
+	}
+	return r.RepositoryProperty
+}
+
 // GetHRef returns the HRef field if it's non-nil, zero value otherwise.
 func (r *RulesetLink) GetHRef() string {
 	if r == nil || r.HRef == nil {
diff --git a/github/repos_collaborators.go b/github/repos_collaborators.go
index 15a4e77a..d6c98535 100644
--- a/github/repos_collaborators.go
+++ b/github/repos_collaborators.go
@@ -99,6 +99,8 @@ type RepositoryPermissionLevel struct {
 	Permission *string `json:"permission,omitempty"`
 
 	User *User `json:"user,omitempty"`
+
+	RoleName *string `json:"role_name,omitempty"`
 }
 
 // GetPermissionLevel retrieves the specific permission level a collaborator has for a given repository.
diff --git a/github/repos_contents.go b/github/repos_contents.go
index c4453739..97539aee 100644
--- a/github/repos_contents.go
+++ b/github/repos_contents.go
@@ -150,7 +150,11 @@ func (s *RepositoriesService) DownloadContents(ctx context.Context, owner, repo,
 				return nil, resp, fmt.Errorf("no download link found for %s", filepath)
 			}
 
-			dlResp, err := s.client.client.Get(*contents.DownloadURL)
+			dlReq, err := http.NewRequestWithContext(ctx, http.MethodGet, *contents.DownloadURL, nil)
+			if err != nil {
+				return nil, resp, err
+			}
+			dlResp, err := s.client.client.Do(dlReq)
 			if err != nil {
 				return nil, &Response{Response: dlResp}, err
 			}
@@ -188,7 +192,11 @@ func (s *RepositoriesService) DownloadContentsWithMeta(ctx context.Context, owne
 				return nil, contents, resp, fmt.Errorf("no download link found for %s", filepath)
 			}
 
-			dlResp, err := s.client.client.Get(*contents.DownloadURL)
+			dlReq, err := http.NewRequestWithContext(ctx, http.MethodGet, *contents.DownloadURL, nil)
+			if err != nil {
+				return nil, contents, resp, err
+			}
+			dlResp, err := s.client.client.Do(dlReq)
 			if err != nil {
 				return nil, contents, &Response{Response: dlResp}, err
 			}
diff --git a/github/repos_rules.go b/github/repos_rules.go
index 6f046a35..2827f85a 100644
--- a/github/repos_rules.go
+++ b/github/repos_rules.go
@@ -48,12 +48,25 @@ type RulesetRepositoryIDsConditionParameters struct {
 	RepositoryIDs []int64 `json:"repository_ids,omitempty"`
 }
 
+// RulesetRepositoryPropertyTargetParameters represents a repository_property name and values to be used for targeting.
+type RulesetRepositoryPropertyTargetParameters struct {
+	Name   string   `json:"name"`
+	Values []string `json:"property_values"`
+}
+
+// RulesetRepositoryPropertyConditionParameters represents the conditions object for repository_property.
+type RulesetRepositoryPropertyConditionParameters struct {
+	Include []RulesetRepositoryPropertyTargetParameters `json:"include"`
+	Exclude []RulesetRepositoryPropertyTargetParameters `json:"exclude"`
+}
+
 // RulesetConditions represents the conditions object in a ruleset.
-// Set either RepositoryName or RepositoryID, not both.
+// Set either RepositoryName or RepositoryID or RepositoryProperty, not more than one.
 type RulesetConditions struct {
-	RefName        *RulesetRefConditionParameters             `json:"ref_name,omitempty"`
-	RepositoryName *RulesetRepositoryNamesConditionParameters `json:"repository_name,omitempty"`
-	RepositoryID   *RulesetRepositoryIDsConditionParameters   `json:"repository_id,omitempty"`
+	RefName            *RulesetRefConditionParameters                `json:"ref_name,omitempty"`
+	RepositoryName     *RulesetRepositoryNamesConditionParameters    `json:"repository_name,omitempty"`
+	RepositoryID       *RulesetRepositoryIDsConditionParameters      `json:"repository_id,omitempty"`
+	RepositoryProperty *RulesetRepositoryPropertyConditionParameters `json:"repository_property,omitempty"`
 }
 
 // RulePatternParameters represents the rule pattern parameters.
@@ -395,6 +408,24 @@ type Ruleset struct {
 	Rules        []*RepositoryRule  `json:"rules,omitempty"`
 }
 
+// rulesetNoOmitBypassActors represents a GitHub ruleset object. The struct does not omit bypassActors if the field is nil or an empty array is passed.
+type rulesetNoOmitBypassActors struct {
+	ID   *int64 `json:"id,omitempty"`
+	Name string `json:"name"`
+	// Possible values for Target are branch, tag
+	Target *string `json:"target,omitempty"`
+	// Possible values for SourceType are: Repository, Organization
+	SourceType *string `json:"source_type,omitempty"`
+	Source     string  `json:"source"`
+	// Possible values for Enforcement are: disabled, active, evaluate
+	Enforcement  string             `json:"enforcement"`
+	BypassActors []*BypassActor     `json:"bypass_actors"`
+	NodeID       *string            `json:"node_id,omitempty"`
+	Links        *RulesetLinks      `json:"_links,omitempty"`
+	Conditions   *RulesetConditions `json:"conditions,omitempty"`
+	Rules        []*RepositoryRule  `json:"rules,omitempty"`
+}
+
 // GetRulesForBranch gets all the rules that apply to the specified branch.
 //
 // GitHub API docs: https://docs.github.com/rest/repos/rules#get-rules-for-a-branch
@@ -507,6 +538,48 @@ func (s *RepositoriesService) UpdateRuleset(ctx context.Context, owner, repo str
 	return ruleset, resp, nil
 }
 
+// UpdateRulesetNoBypassActor updates a ruleset for the specified repository.
+//
+// This function is necessary as the UpdateRuleset function does not marshal ByPassActor if passed as nil or an empty array.
+//
+// GitHub API docs: https://docs.github.com/rest/repos/rules#update-a-repository-ruleset
+//
+//meta:operation PUT /repos/{owner}/{repo}/rulesets/{ruleset_id}
+func (s *RepositoriesService) UpdateRulesetNoBypassActor(ctx context.Context, owner, repo string, rulesetID int64, rs *Ruleset) (*Ruleset, *Response, error) {
+	u := fmt.Sprintf("repos/%v/%v/rulesets/%v", owner, repo, rulesetID)
+
+	rsNoBypassActor := &rulesetNoOmitBypassActors{}
+
+	if rs != nil {
+		rsNoBypassActor = &rulesetNoOmitBypassActors{
+			ID:           rs.ID,
+			Name:         rs.Name,
+			Target:       rs.Target,
+			SourceType:   rs.SourceType,
+			Source:       rs.Source,
+			Enforcement:  rs.Enforcement,
+			BypassActors: rs.BypassActors,
+			NodeID:       rs.NodeID,
+			Links:        rs.Links,
+			Conditions:   rs.Conditions,
+			Rules:        rs.Rules,
+		}
+	}
+
+	req, err := s.client.NewRequest("PUT", u, rsNoBypassActor)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var ruleSet *Ruleset
+	resp, err := s.client.Do(ctx, req, &ruleSet)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return ruleSet, resp, nil
+}
+
 // DeleteRuleset deletes a ruleset for the specified repository.
 //
 // GitHub API docs: https://docs.github.com/rest/repos/rules#delete-a-repository-ruleset
diff --git a/scrape/go.mod b/scrape/go.mod
index e940f8ea..b0105d95 100644
--- a/scrape/go.mod
+++ b/scrape/go.mod
@@ -9,7 +9,7 @@ require (
 	github.com/google/go-cmp v0.6.0
 	github.com/google/go-github/v61 v61.0.0
 	github.com/xlzd/gotp v0.1.0
-	golang.org/x/net v0.25.0
+	golang.org/x/net v0.27.0
 )
 
 require (
diff --git a/scrape/go.sum b/scrape/go.sum
index 316fda4c..d7a889f5 100644
--- a/scrape/go.sum
+++ b/scrape/go.sum
@@ -21,8 +21,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
-golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
-golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
+golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
+golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
diff --git a/tools/go.mod b/tools/go.mod
index 26e9fe45..9f3f2cfc 100644
--- a/tools/go.mod
+++ b/tools/go.mod
@@ -6,7 +6,7 @@ toolchain go1.22.0
 
 require (
 	github.com/alecthomas/kong v0.9.0
-	github.com/getkin/kin-openapi v0.124.0
+	github.com/getkin/kin-openapi v0.126.0
 	github.com/google/go-cmp v0.6.0
 	github.com/google/go-github/v62 v62.0.0
 	golang.org/x/sync v0.7.0
@@ -14,10 +14,10 @@ require (
 )
 
 require (
-	github.com/go-openapi/jsonpointer v0.20.2 // indirect
-	github.com/go-openapi/swag v0.22.8 // indirect
+	github.com/go-openapi/jsonpointer v0.21.0 // indirect
+	github.com/go-openapi/swag v0.23.0 // indirect
 	github.com/google/go-querystring v1.1.0 // indirect
-	github.com/invopop/yaml v0.2.0 // indirect
+	github.com/invopop/yaml v0.3.1 // indirect
 	github.com/josharian/intern v1.0.0 // indirect
 	github.com/mailru/easyjson v0.7.7 // indirect
 	github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
diff --git a/tools/go.sum b/tools/go.sum
index a9e50530..3f75ab72 100644
--- a/tools/go.sum
+++ b/tools/go.sum
@@ -6,12 +6,12 @@ github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc
 github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/getkin/kin-openapi v0.124.0 h1:VSFNMB9C9rTKBnQ/fpyDU8ytMTr4dWI9QovSKj9kz/M=
-github.com/getkin/kin-openapi v0.124.0/go.mod h1:wb1aSZA/iWmorQP9KTAS/phLj/t17B5jT7+fS8ed9NM=
-github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q=
-github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs=
-github.com/go-openapi/swag v0.22.8 h1:/9RjDSQ0vbFR+NyjGMkFTsA1IA0fmhKSThmfGZjicbw=
-github.com/go-openapi/swag v0.22.8/go.mod h1:6QT22icPLEqAM/z/TChgb4WAveCHF92+2gF0CNjHpPI=
+github.com/getkin/kin-openapi v0.126.0 h1:c2cSgLnAsS0xYfKsgt5oBV6MYRM/giU8/RtwUY4wyfY=
+github.com/getkin/kin-openapi v0.126.0/go.mod h1:7mONz8IwmSRg6RttPu6v8U/OJ+gr+J99qSFNjPGSQqw=
+github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
+github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
+github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
+github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
 github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
 github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
 github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@@ -21,8 +21,8 @@ github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD
 github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
 github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
 github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
-github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY=
-github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
+github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso=
+github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA=
 github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
 github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
 github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@@ -39,8 +39,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
 github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
-github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
-github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
 github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
 golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
@@ -49,6 +49,5 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
-gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 485e3978..d9e3d3ba 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -73,4 +73,4 @@ jobs:
 
     - name: Upload coverage to Codecov
       if: ${{ matrix.update-coverage }}
-      uses: codecov/codecov-action@125fc84a9a348dbcf27191600683ec096ec9021c #v4.4.1
+      uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 #v4.5.0
diff --git a/github/apps_test.go b/github/apps_test.go
index ea670344..bb060d7a 100644
--- a/github/apps_test.go
+++ b/github/apps_test.go
@@ -769,6 +769,7 @@ func TestInstallationPermissions_Marshal(t *testing.T) {
 		Metadata:                      String("md"),
 		Members:                       String("m"),
 		OrganizationAdministration:    String("oa"),
+		OrganizationCustomOrgRoles:    String("ocr"),
 		OrganizationHooks:             String("oh"),
 		OrganizationPlan:              String("op"),
 		OrganizationPreReceiveHooks:   String("opr"),
@@ -804,6 +805,7 @@ func TestInstallationPermissions_Marshal(t *testing.T) {
 		"metadata": "md",
 		"members": "m",
 		"organization_administration": "oa",
+		"organization_custom_org_roles": "ocr",
 		"organization_hooks": "oh",
 		"organization_plan": "op",
 		"organization_pre_receive_hooks": "opr",
@@ -869,6 +871,7 @@ func TestInstallation_Marshal(t *testing.T) {
 		SingleFilePaths:     []string{"s"},
 		Permissions: &InstallationPermissions{
 			Actions:                       String("a"),
+			ActionsVariables:              String("ac"),
 			Administration:                String("ad"),
 			Checks:                        String("c"),
 			Contents:                      String("co"),
@@ -879,6 +882,7 @@ func TestInstallation_Marshal(t *testing.T) {
 			Metadata:                      String("md"),
 			Members:                       String("m"),
 			OrganizationAdministration:    String("oa"),
+			OrganizationCustomOrgRoles:    String("ocr"),
 			OrganizationHooks:             String("oh"),
 			OrganizationPlan:              String("op"),
 			OrganizationPreReceiveHooks:   String("opr"),
@@ -967,6 +971,7 @@ func TestInstallation_Marshal(t *testing.T) {
 		],
 		"permissions": {
 			"actions": "a",
+			"actions_variables": "ac",
 			"administration": "ad",
 			"checks": "c",
 			"contents": "co",
@@ -977,6 +982,7 @@ func TestInstallation_Marshal(t *testing.T) {
 			"metadata": "md",
 			"members": "m",
 			"organization_administration": "oa",
+			"organization_custom_org_roles": "ocr",
 			"organization_hooks": "oh",
 			"organization_plan": "op",
 			"organization_pre_receive_hooks": "opr",
@@ -1035,6 +1041,7 @@ func TestInstallationTokenOptions_Marshal(t *testing.T) {
 		RepositoryIDs: []int64{1},
 		Permissions: &InstallationPermissions{
 			Actions:                       String("a"),
+			ActionsVariables:              String("ac"),
 			Administration:                String("ad"),
 			Checks:                        String("c"),
 			Contents:                      String("co"),
@@ -1045,6 +1052,7 @@ func TestInstallationTokenOptions_Marshal(t *testing.T) {
 			Metadata:                      String("md"),
 			Members:                       String("m"),
 			OrganizationAdministration:    String("oa"),
+			OrganizationCustomOrgRoles:    String("ocr"),
 			OrganizationHooks:             String("oh"),
 			OrganizationPlan:              String("op"),
 			OrganizationPreReceiveHooks:   String("opr"),
@@ -1073,6 +1081,7 @@ func TestInstallationTokenOptions_Marshal(t *testing.T) {
 		"repository_ids": [1],
 		"permissions": {
 			"actions": "a",
+			"actions_variables": "ac",
 			"administration": "ad",
 			"checks": "c",
 			"contents": "co",
@@ -1083,6 +1092,7 @@ func TestInstallationTokenOptions_Marshal(t *testing.T) {
 			"metadata": "md",
 			"members": "m",
 			"organization_administration": "oa",
+			"organization_custom_org_roles": "ocr",
 			"organization_hooks": "oh",
 			"organization_plan": "op",
 			"organization_pre_receive_hooks": "opr",
@@ -1118,6 +1128,7 @@ func TestInstallationToken_Marshal(t *testing.T) {
 		ExpiresAt: &Timestamp{referenceTime},
 		Permissions: &InstallationPermissions{
 			Actions:                       String("a"),
+			ActionsVariables:              String("ac"),
 			Administration:                String("ad"),
 			Checks:                        String("c"),
 			Contents:                      String("co"),
@@ -1128,6 +1139,7 @@ func TestInstallationToken_Marshal(t *testing.T) {
 			Metadata:                      String("md"),
 			Members:                       String("m"),
 			OrganizationAdministration:    String("oa"),
+			OrganizationCustomOrgRoles:    String("ocr"),
 			OrganizationHooks:             String("oh"),
 			OrganizationPlan:              String("op"),
 			OrganizationPreReceiveHooks:   String("opr"),
@@ -1164,6 +1176,7 @@ func TestInstallationToken_Marshal(t *testing.T) {
 		"expires_at": ` + referenceTimeStr + `,
 		"permissions": {
 			"actions": "a",
+			"actions_variables": "ac",
 			"administration": "ad",
 			"checks": "c",
 			"contents": "co",
@@ -1174,6 +1187,7 @@ func TestInstallationToken_Marshal(t *testing.T) {
 			"metadata": "md",
 			"members": "m",
 			"organization_administration": "oa",
+			"organization_custom_org_roles": "ocr",
 			"organization_hooks": "oh",
 			"organization_plan": "op",
 			"organization_pre_receive_hooks": "opr",
@@ -1243,6 +1257,7 @@ func TestApp_Marshal(t *testing.T) {
 		UpdatedAt:   &Timestamp{referenceTime},
 		Permissions: &InstallationPermissions{
 			Actions:                       String("a"),
+			ActionsVariables:              String("ac"),
 			Administration:                String("ad"),
 			Checks:                        String("c"),
 			Contents:                      String("co"),
@@ -1253,6 +1268,7 @@ func TestApp_Marshal(t *testing.T) {
 			Metadata:                      String("md"),
 			Members:                       String("m"),
 			OrganizationAdministration:    String("oa"),
+			OrganizationCustomOrgRoles:    String("ocr"),
 			OrganizationHooks:             String("oh"),
 			OrganizationPlan:              String("op"),
 			OrganizationPreReceiveHooks:   String("opr"),
@@ -1310,6 +1326,7 @@ func TestApp_Marshal(t *testing.T) {
 		"updated_at": ` + referenceTimeStr + `,
 		"permissions": {
 			"actions": "a",
+			"actions_variables": "ac",
 			"administration": "ad",
 			"checks": "c",
 			"contents": "co",
@@ -1320,6 +1337,7 @@ func TestApp_Marshal(t *testing.T) {
 			"metadata": "md",
 			"members": "m",
 			"organization_administration": "oa",
+			"organization_custom_org_roles": "ocr",
 			"organization_hooks": "oh",
 			"organization_plan": "op",
 			"organization_pre_receive_hooks": "opr",
diff --git a/github/enterprise_actions_runners_test.go b/github/enterprise_actions_runners_test.go
index 3bc3c737..d5efc6f7 100644
--- a/github/enterprise_actions_runners_test.go
+++ b/github/enterprise_actions_runners_test.go
@@ -145,6 +145,46 @@ func TestEnterpriseService_ListRunners(t *testing.T) {
 	})
 }
 
+func TestEnterpriseService_GetRunner(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/enterprises/e/actions/runners/23", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		fmt.Fprint(w, `{"id":23,"name":"MBP","os":"macos","status":"online"}`)
+	})
+
+	ctx := context.Background()
+	runner, _, err := client.Enterprise.GetRunner(ctx, "e", 23)
+	if err != nil {
+		t.Errorf("Enterprise.GetRunner returned error: %v", err)
+	}
+
+	want := &Runner{
+		ID:     Int64(23),
+		Name:   String("MBP"),
+		OS:     String("macos"),
+		Status: String("online"),
+	}
+	if !cmp.Equal(runner, want) {
+		t.Errorf("Enterprise.GetRunner returned %+v, want %+v", runner, want)
+	}
+
+	const methodName = "GetRunner"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Enterprise.GetRunner(ctx, "\n", 23)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Enterprise.GetRunner(ctx, "e", 23)
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
+
 func TestEnterpriseService_RemoveRunner(t *testing.T) {
 	client, mux, _, teardown := setup()
 	defer teardown()
diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go
index 8753c42b..03ebada6 100644
--- a/github/github-accessors_test.go
+++ b/github/github-accessors_test.go
@@ -10338,6 +10338,16 @@ func TestInstallationPermissions_GetActions(tt *testing.T) {
 	i.GetActions()
 }
 
+func TestInstallationPermissions_GetActionsVariables(tt *testing.T) {
+	var zeroValue string
+	i := &InstallationPermissions{ActionsVariables: &zeroValue}
+	i.GetActionsVariables()
+	i = &InstallationPermissions{}
+	i.GetActionsVariables()
+	i = nil
+	i.GetActionsVariables()
+}
+
 func TestInstallationPermissions_GetAdministration(tt *testing.T) {
 	var zeroValue string
 	i := &InstallationPermissions{Administration: &zeroValue}
@@ -10468,6 +10478,16 @@ func TestInstallationPermissions_GetOrganizationAdministration(tt *testing.T) {
 	i.GetOrganizationAdministration()
 }
 
+func TestInstallationPermissions_GetOrganizationCustomOrgRoles(tt *testing.T) {
+	var zeroValue string
+	i := &InstallationPermissions{OrganizationCustomOrgRoles: &zeroValue}
+	i.GetOrganizationCustomOrgRoles()
+	i = &InstallationPermissions{}
+	i.GetOrganizationCustomOrgRoles()
+	i = nil
+	i.GetOrganizationCustomOrgRoles()
+}
+
 func TestInstallationPermissions_GetOrganizationCustomProperties(tt *testing.T) {
 	var zeroValue string
 	i := &InstallationPermissions{OrganizationCustomProperties: &zeroValue}
@@ -23307,6 +23327,16 @@ func TestRepositoryPermissionLevel_GetPermission(tt *testing.T) {
 	r.GetPermission()
 }
 
+func TestRepositoryPermissionLevel_GetRoleName(tt *testing.T) {
+	var zeroValue string
+	r := &RepositoryPermissionLevel{RoleName: &zeroValue}
+	r.GetRoleName()
+	r = &RepositoryPermissionLevel{}
+	r.GetRoleName()
+	r = nil
+	r.GetRoleName()
+}
+
 func TestRepositoryPermissionLevel_GetUser(tt *testing.T) {
 	r := &RepositoryPermissionLevel{}
 	r.GetUser()
@@ -24232,6 +24262,13 @@ func TestRulesetConditions_GetRepositoryName(tt *testing.T) {
 	r.GetRepositoryName()
 }
 
+func TestRulesetConditions_GetRepositoryProperty(tt *testing.T) {
+	r := &RulesetConditions{}
+	r.GetRepositoryProperty()
+	r = nil
+	r.GetRepositoryProperty()
+}
+
 func TestRulesetLink_GetHRef(tt *testing.T) {
 	var zeroValue string
 	r := &RulesetLink{HRef: &zeroValue}
diff --git a/github/orgs_rules_test.go b/github/orgs_rules_test.go
index 0ed54ca8..d45469f2 100644
--- a/github/orgs_rules_test.go
+++ b/github/orgs_rules_test.go
@@ -395,7 +395,342 @@ func TestOrganizationsService_CreateOrganizationRuleset_RepoNames(t *testing.T)
 		return resp, err
 	})
 }
+func TestOrganizationsService_CreateOrganizationRuleset_RepoProperty(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
 
+	mux.HandleFunc("/orgs/o/rulesets", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "POST")
+		fmt.Fprint(w, `{
+			"id": 21,
+			"name": "ruleset",
+			"target": "branch",
+			"source_type": "Organization",
+			"source": "o",
+			"enforcement": "active",
+			"bypass_actors": [
+			  {
+				"actor_id": 234,
+				"actor_type": "Team"
+			  }
+			],
+			"conditions": {
+			  "repository_property": {
+				"include": [
+					{
+						"name": "testIncludeProp",
+						"source": "custom",
+						"property_values": [
+							"true"
+						]
+					}
+				],
+				"exclude": [
+					{
+						"name": "testExcludeProp",
+						"source": "custom",
+						"property_values": [
+							"false"
+						]
+					}
+				]
+			  }
+			},
+			"rules": [
+			  {
+				"type": "creation"
+			  },
+			  {
+				"type": "update",
+				"parameters": {
+				  "update_allows_fetch_and_merge": true
+				}
+			  },
+			  {
+				"type": "deletion"
+			  },
+			  {
+				"type": "merge_queue"
+			  },
+			  {
+				"type": "required_linear_history"
+			  },
+			  {
+				"type": "required_deployments",
+				"parameters": {
+				  "required_deployment_environments": ["test"]
+				}
+			  },
+			  {
+				"type": "required_signatures"
+			  },
+			  {
+				"type": "pull_request",
+				"parameters": {
+				  "dismiss_stale_reviews_on_push": true,
+				  "require_code_owner_review": true,
+				  "require_last_push_approval": true,
+				  "required_approving_review_count": 1,
+				  "required_review_thread_resolution": true
+				}
+			  },
+			  {
+				"type": "required_status_checks",
+				"parameters": {
+				  "required_status_checks": [
+					{
+					  "context": "test",
+					  "integration_id": 1
+					}
+				  ],
+				  "strict_required_status_checks_policy": true
+				}
+			  },
+			  {
+				"type": "non_fast_forward"
+			  },
+			  {
+				"type": "commit_message_pattern",
+				"parameters": {
+				  "name": "avoid test commits",
+				  "negate": true,
+				  "operator": "starts_with",
+				  "pattern": "[test]"
+				}
+			  },
+			  {
+				"type": "commit_author_email_pattern",
+				"parameters": {
+				  "operator": "contains",
+				  "pattern": "github"
+				}
+			  },
+			  {
+				"type": "committer_email_pattern",
+				"parameters": {
+				  "name": "avoid commit emails",
+				  "negate": true,
+				  "operator": "ends_with",
+				  "pattern": "abc"
+				}
+			  },
+			  {
+				"type": "branch_name_pattern",
+				"parameters": {
+				  "name": "avoid branch names",
+				  "negate": true,
+				  "operator": "regex",
+				  "pattern": "github$"
+				}
+			  },
+			  {
+				"type": "tag_name_pattern",
+				"parameters": {
+				  "name": "avoid tag names",
+				  "negate": true,
+				  "operator": "contains",
+				  "pattern": "github"
+				}
+			  }
+			]
+		  }`)
+	})
+
+	ctx := context.Background()
+	ruleset, _, err := client.Organizations.CreateOrganizationRuleset(ctx, "o", &Ruleset{
+		ID:          Int64(21),
+		Name:        "ruleset",
+		Target:      String("branch"),
+		SourceType:  String("Organization"),
+		Source:      "o",
+		Enforcement: "active",
+		BypassActors: []*BypassActor{
+			{
+				ActorID:   Int64(234),
+				ActorType: String("Team"),
+			},
+		},
+		Conditions: &RulesetConditions{
+			RepositoryProperty: &RulesetRepositoryPropertyConditionParameters{
+				Include: []RulesetRepositoryPropertyTargetParameters{
+					{
+						Name:   "testIncludeProp",
+						Values: []string{"true"},
+					},
+				},
+				Exclude: []RulesetRepositoryPropertyTargetParameters{
+					{
+						Name:   "testExcludeProp",
+						Values: []string{"false"},
+					},
+				},
+			},
+		},
+		Rules: []*RepositoryRule{
+			NewCreationRule(),
+			NewUpdateRule(&UpdateAllowsFetchAndMergeRuleParameters{
+				UpdateAllowsFetchAndMerge: true,
+			}),
+			NewDeletionRule(),
+			NewMergeQueueRule(),
+			NewRequiredLinearHistoryRule(),
+			NewRequiredDeploymentsRule(&RequiredDeploymentEnvironmentsRuleParameters{
+				RequiredDeploymentEnvironments: []string{"test"},
+			}),
+			NewRequiredSignaturesRule(),
+			NewPullRequestRule(&PullRequestRuleParameters{
+				RequireCodeOwnerReview:         true,
+				RequireLastPushApproval:        true,
+				RequiredApprovingReviewCount:   1,
+				RequiredReviewThreadResolution: true,
+				DismissStaleReviewsOnPush:      true,
+			}),
+			NewRequiredStatusChecksRule(&RequiredStatusChecksRuleParameters{
+				RequiredStatusChecks: []RuleRequiredStatusChecks{
+					{
+						Context:       "test",
+						IntegrationID: Int64(1),
+					},
+				},
+				StrictRequiredStatusChecksPolicy: true,
+			}),
+			NewNonFastForwardRule(),
+			NewCommitMessagePatternRule(&RulePatternParameters{
+				Name:     String("avoid test commits"),
+				Negate:   Bool(true),
+				Operator: "starts_with",
+				Pattern:  "[test]",
+			}),
+			NewCommitAuthorEmailPatternRule(&RulePatternParameters{
+				Operator: "contains",
+				Pattern:  "github",
+			}),
+			NewCommitterEmailPatternRule(&RulePatternParameters{
+				Name:     String("avoid commit emails"),
+				Negate:   Bool(true),
+				Operator: "ends_with",
+				Pattern:  "abc",
+			}),
+			NewBranchNamePatternRule(&RulePatternParameters{
+				Name:     String("avoid branch names"),
+				Negate:   Bool(true),
+				Operator: "regex",
+				Pattern:  "github$",
+			}),
+			NewTagNamePatternRule(&RulePatternParameters{
+				Name:     String("avoid tag names"),
+				Negate:   Bool(true),
+				Operator: "contains",
+				Pattern:  "github",
+			}),
+		},
+	})
+	if err != nil {
+		t.Errorf("Organizations.CreateOrganizationRuleset returned error: %v", err)
+	}
+
+	want := &Ruleset{
+		ID:          Int64(21),
+		Name:        "ruleset",
+		Target:      String("branch"),
+		SourceType:  String("Organization"),
+		Source:      "o",
+		Enforcement: "active",
+		BypassActors: []*BypassActor{
+			{
+				ActorID:   Int64(234),
+				ActorType: String("Team"),
+			},
+		},
+		Conditions: &RulesetConditions{
+			RepositoryProperty: &RulesetRepositoryPropertyConditionParameters{
+				Include: []RulesetRepositoryPropertyTargetParameters{
+					{
+						Name:   "testIncludeProp",
+						Values: []string{"true"},
+					},
+				},
+				Exclude: []RulesetRepositoryPropertyTargetParameters{
+					{
+						Name:   "testExcludeProp",
+						Values: []string{"false"},
+					},
+				},
+			},
+		},
+		Rules: []*RepositoryRule{
+			NewCreationRule(),
+			NewUpdateRule(&UpdateAllowsFetchAndMergeRuleParameters{
+				UpdateAllowsFetchAndMerge: true,
+			}),
+			NewDeletionRule(),
+			NewMergeQueueRule(),
+			NewRequiredLinearHistoryRule(),
+			NewRequiredDeploymentsRule(&RequiredDeploymentEnvironmentsRuleParameters{
+				RequiredDeploymentEnvironments: []string{"test"},
+			}),
+			NewRequiredSignaturesRule(),
+			NewPullRequestRule(&PullRequestRuleParameters{
+				RequireCodeOwnerReview:         true,
+				RequireLastPushApproval:        true,
+				RequiredApprovingReviewCount:   1,
+				RequiredReviewThreadResolution: true,
+				DismissStaleReviewsOnPush:      true,
+			}),
+			NewRequiredStatusChecksRule(&RequiredStatusChecksRuleParameters{
+				RequiredStatusChecks: []RuleRequiredStatusChecks{
+					{
+						Context:       "test",
+						IntegrationID: Int64(1),
+					},
+				},
+				StrictRequiredStatusChecksPolicy: true,
+			}),
+			NewNonFastForwardRule(),
+			NewCommitMessagePatternRule(&RulePatternParameters{
+				Name:     String("avoid test commits"),
+				Negate:   Bool(true),
+				Operator: "starts_with",
+				Pattern:  "[test]",
+			}),
+			NewCommitAuthorEmailPatternRule(&RulePatternParameters{
+				Operator: "contains",
+				Pattern:  "github",
+			}),
+			NewCommitterEmailPatternRule(&RulePatternParameters{
+				Name:     String("avoid commit emails"),
+				Negate:   Bool(true),
+				Operator: "ends_with",
+				Pattern:  "abc",
+			}),
+			NewBranchNamePatternRule(&RulePatternParameters{
+				Name:     String("avoid branch names"),
+				Negate:   Bool(true),
+				Operator: "regex",
+				Pattern:  "github$",
+			}),
+			NewTagNamePatternRule(&RulePatternParameters{
+				Name:     String("avoid tag names"),
+				Negate:   Bool(true),
+				Operator: "contains",
+				Pattern:  "github",
+			}),
+		},
+	}
+	if !cmp.Equal(ruleset, want) {
+		t.Errorf("Organizations.CreateOrganizationRuleset returned %+v, want %+v", ruleset, want)
+	}
+
+	const methodName = "CreateOrganizationRuleset"
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Organizations.CreateOrganizationRuleset(ctx, "o", nil)
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
 func TestOrganizationsService_CreateOrganizationRuleset_RepoIDs(t *testing.T) {
 	client, mux, _, teardown := setup()
 	defer teardown()
@@ -807,6 +1142,94 @@ func TestOrganizationsService_GetOrganizationRuleset(t *testing.T) {
 	})
 }
 
+func TestOrganizationsService_GetOrganizationRulesetWithRepoPropCondition(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/orgs/o/rulesets/26110", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		fmt.Fprint(w, `{
+			"id": 26110,
+			"name": "test ruleset",
+			"target": "branch",
+			"source_type": "Organization",
+			"source": "o",
+			"enforcement": "active",
+			"bypass_mode": "none",
+			"node_id": "nid",
+			"_links": {
+			  "self": {
+				"href": "https://api.github.com/orgs/o/rulesets/26110"
+			  }
+			},
+			"conditions": {
+			  "repository_property": {
+				"exclude": [],
+				"include": [
+				  {
+					"name": "testIncludeProp",
+					"source": "custom",
+					"property_values": [
+					  "true"
+					]
+				  }
+				]
+			  }
+			},
+			"rules": [
+			{
+				"type": "creation"
+			}
+			]
+		}`)
+	})
+
+	ctx := context.Background()
+	rulesets, _, err := client.Organizations.GetOrganizationRuleset(ctx, "o", 26110)
+	if err != nil {
+		t.Errorf("Organizations.GetOrganizationRepositoryRuleset returned error: %v", err)
+	}
+
+	want := &Ruleset{
+		ID:          Int64(26110),
+		Name:        "test ruleset",
+		Target:      String("branch"),
+		SourceType:  String("Organization"),
+		Source:      "o",
+		Enforcement: "active",
+		NodeID:      String("nid"),
+		Links: &RulesetLinks{
+			Self: &RulesetLink{HRef: String("https://api.github.com/orgs/o/rulesets/26110")},
+		},
+		Conditions: &RulesetConditions{
+			RepositoryProperty: &RulesetRepositoryPropertyConditionParameters{
+				Include: []RulesetRepositoryPropertyTargetParameters{
+					{
+						Name:   "testIncludeProp",
+						Values: []string{"true"},
+					},
+				},
+				Exclude: []RulesetRepositoryPropertyTargetParameters{},
+			},
+		},
+		Rules: []*RepositoryRule{
+			NewCreationRule(),
+		},
+	}
+	if !cmp.Equal(rulesets, want) {
+		t.Errorf("Organizations.GetOrganizationRuleset returned %+v, want %+v", rulesets, want)
+	}
+
+	const methodName = "GetOrganizationRuleset"
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Organizations.GetOrganizationRuleset(ctx, "o", 26110)
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
 func TestOrganizationsService_UpdateOrganizationRuleset(t *testing.T) {
 	client, mux, _, teardown := setup()
 	defer teardown()
@@ -922,6 +1345,113 @@ func TestOrganizationsService_UpdateOrganizationRuleset(t *testing.T) {
 	})
 }
 
+func TestOrganizationsService_UpdateOrganizationRulesetWithRepoProp(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/orgs/o/rulesets/26110", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "PUT")
+		fmt.Fprint(w, `{
+			"id": 26110,
+			"name": "test ruleset",
+			"target": "branch",
+			"source_type": "Organization",
+			"source": "o",
+			"enforcement": "active",
+			"bypass_mode": "none",
+			"node_id": "nid",
+			"_links": {
+			  "self": {
+				"href": "https://api.github.com/orgs/o/rulesets/26110"
+			  }
+			},
+			"conditions": {
+			  "repository_property": {
+				"exclude": [],
+				"include": [
+				  {
+					"name": "testIncludeProp",
+					"source": "custom",
+					"property_values": [
+					  "true"
+					]
+				  }
+				]
+			  }
+			  },
+			  "rules": [
+				{
+				  "type": "creation"
+				}
+			  ]
+		}`)
+	})
+
+	ctx := context.Background()
+	rulesets, _, err := client.Organizations.UpdateOrganizationRuleset(ctx, "o", 26110, &Ruleset{
+		Name:        "test ruleset",
+		Target:      String("branch"),
+		Enforcement: "active",
+		Conditions: &RulesetConditions{
+			RepositoryProperty: &RulesetRepositoryPropertyConditionParameters{
+				Include: []RulesetRepositoryPropertyTargetParameters{
+					{
+						Name:   "testIncludeProp",
+						Values: []string{"true"},
+					},
+				},
+				Exclude: []RulesetRepositoryPropertyTargetParameters{},
+			},
+		},
+		Rules: []*RepositoryRule{
+			NewCreationRule(),
+		},
+	})
+
+	if err != nil {
+		t.Errorf("Organizations.UpdateOrganizationRuleset returned error: %v", err)
+	}
+
+	want := &Ruleset{
+		ID:          Int64(26110),
+		Name:        "test ruleset",
+		Target:      String("branch"),
+		SourceType:  String("Organization"),
+		Source:      "o",
+		Enforcement: "active",
+		NodeID:      String("nid"),
+		Links: &RulesetLinks{
+			Self: &RulesetLink{HRef: String("https://api.github.com/orgs/o/rulesets/26110")},
+		},
+		Conditions: &RulesetConditions{
+			RepositoryProperty: &RulesetRepositoryPropertyConditionParameters{
+				Include: []RulesetRepositoryPropertyTargetParameters{
+					{
+						Name:   "testIncludeProp",
+						Values: []string{"true"},
+					},
+				},
+				Exclude: []RulesetRepositoryPropertyTargetParameters{},
+			},
+		},
+		Rules: []*RepositoryRule{
+			NewCreationRule(),
+		},
+	}
+	if !cmp.Equal(rulesets, want) {
+		t.Errorf("Organizations.UpdateOrganizationRuleset returned %+v, want %+v", rulesets, want)
+	}
+
+	const methodName = "UpdateOrganizationRuleset"
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Organizations.UpdateOrganizationRuleset(ctx, "o", 26110, nil)
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
 func TestOrganizationsService_DeleteOrganizationRuleset(t *testing.T) {
 	client, mux, _, teardown := setup()
 	defer teardown()
diff --git a/github/repos_rules_test.go b/github/repos_rules_test.go
index 23ffd3ed..065d3385 100644
--- a/github/repos_rules_test.go
+++ b/github/repos_rules_test.go
@@ -525,6 +525,58 @@ func TestRepositoriesService_GetRuleset(t *testing.T) {
 	})
 }
 
+func TestRepositoriesService_UpdateRulesetNoBypassActor(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	rs := &Ruleset{
+		Name:        "ruleset",
+		Source:      "o/repo",
+		Enforcement: "enabled",
+	}
+
+	mux.HandleFunc("/repos/o/repo/rulesets/42", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "PUT")
+		fmt.Fprint(w, `{
+			"id": 42,
+			"name": "ruleset",
+			"source_type": "Repository",
+			"source": "o/repo",
+			"enforcement": "enabled"
+		}`)
+	})
+
+	ctx := context.Background()
+
+	ruleSet, _, err := client.Repositories.UpdateRulesetNoBypassActor(ctx, "o", "repo", 42, rs)
+
+	if err != nil {
+		t.Errorf("Repositories.UpdateRulesetNoBypassActor returned error: %v \n", err)
+	}
+
+	want := &Ruleset{
+		ID:          Int64(42),
+		Name:        "ruleset",
+		SourceType:  String("Repository"),
+		Source:      "o/repo",
+		Enforcement: "enabled",
+	}
+
+	if !cmp.Equal(ruleSet, want) {
+		t.Errorf("Repositories.UpdateRulesetNoBypassActor returned %+v, want %+v", ruleSet, want)
+	}
+
+	const methodName = "UpdateRulesetNoBypassActor"
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Repositories.UpdateRulesetNoBypassActor(ctx, "o", "repo", 42, nil)
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
+
 func TestRepositoriesService_UpdateRuleset(t *testing.T) {
 	client, mux, _, teardown := setup()
 	defer teardown()
@@ -556,6 +608,7 @@ func TestRepositoriesService_UpdateRuleset(t *testing.T) {
 		Source:      "o/repo",
 		Enforcement: "enabled",
 	}
+
 	if !cmp.Equal(ruleSet, want) {
 		t.Errorf("Repositories.UpdateRuleset returned %+v, want %+v", ruleSet, want)
 	}