Repository: google/go-github
Pull request #2604 (2022-12-20 14:02:37)

Add support for GitHub Actions cache API
@gmlewis   Ready for review. Please mention if something needs a change.
Thanks 

Fixes: #2584.

google-cla[bot]: Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this [failed invocation](https://github.com/google/go-github/pull/2604/checks?check_run_id=10208446253) of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.
codecov[bot]: # [Codecov](https://codecov.io/gh/google/go-github/pull/2604?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google) Report
> Merging [#2604](https://codecov.io/gh/google/go-github/pull/2604?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google) (8f80847) into [master](https://codecov.io/gh/google/go-github/commit/2b4d59656c6908765328c51d32e63e0ef8a0fa6b?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google) (2b4d596) will **increase** coverage by `0.01%`.
> The diff coverage is `100.00%`.

```diff
@@            Coverage Diff             @@
##           master    #2604      +/-   ##
==========================================
+ Coverage   97.99%   98.01%   +0.01%     
==========================================
  Files         126      127       +1     
  Lines       10913    11008      +95     
==========================================
+ Hits        10694    10789      +95     
  Misses        150      150              
  Partials       69       69              
```


| [Impacted Files](https://codecov.io/gh/google/go-github/pull/2604?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google) | Coverage Δ | |
|---|---|---|
| [github/actions\_cache.go](https://codecov.io/gh/google/go-github/pull/2604/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google#diff-Z2l0aHViL2FjdGlvbnNfY2FjaGUuZ28=) | `100.00% <100.00%> (ø)` | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google)

alidevhere: @gmlewis  I have made all requested changes and re ran all tests and commands. 

Please review again and do mention if something is still missing.
Thanks  😃 

Patch:
diff --git a/README.md b/README.md
index 9406f76e..030fd090 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 # go-github #
 
 [![go-github release (latest SemVer)](https://img.shields.io/github/v/release/google/go-github?sort=semver)](https://github.com/google/go-github/releases)
-[![GoDoc](https://img.shields.io/static/v1?label=godoc&message=reference&color=blue)](https://pkg.go.dev/github.com/google/go-github/v48/github)
+[![GoDoc](https://img.shields.io/static/v1?label=godoc&message=reference&color=blue)](https://pkg.go.dev/github.com/google/go-github/v49/github)
 [![Test Status](https://github.com/google/go-github/workflows/tests/badge.svg)](https://github.com/google/go-github/actions?query=workflow%3Atests)
 [![Test Coverage](https://codecov.io/gh/google/go-github/branch/master/graph/badge.svg)](https://codecov.io/gh/google/go-github)
 [![Discuss at go-github@googlegroups.com](https://img.shields.io/badge/discuss-go--github%40googlegroups.com-blue.svg)](https://groups.google.com/group/go-github)
@@ -24,7 +24,7 @@ If you're interested in using the [GraphQL API v4][], the recommended library is
 go-github is compatible with modern Go releases in module mode, with Go installed:
 
 ```bash
-go get github.com/google/go-github/v48
+go get github.com/google/go-github/v49
 ```
 
 will resolve and add the package to the current development module, along with its dependencies.
@@ -32,7 +32,7 @@ will resolve and add the package to the current development module, along with i
 Alternatively the same can be achieved if you use import in a package:
 
 ```go
-import "github.com/google/go-github/v48/github"
+import "github.com/google/go-github/v49/github"
 ```
 
 and run `go get` without parameters.
@@ -40,13 +40,13 @@ and run `go get` without parameters.
 Finally, to use the top-of-trunk version of this repo, use the following command:
 
 ```bash
-go get github.com/google/go-github/v48@master
+go get github.com/google/go-github/v49@master
 ```
 
 ## Usage ##
 
 ```go
-import "github.com/google/go-github/v48/github"	// with go modules enabled (GO111MODULE=on or outside GOPATH)
+import "github.com/google/go-github/v49/github"	// with go modules enabled (GO111MODULE=on or outside GOPATH)
 import "github.com/google/go-github/github" // with go modules disabled
 ```
 
@@ -135,7 +135,7 @@ import (
 	"net/http"
 
 	"github.com/bradleyfalzon/ghinstallation/v2"
-	"github.com/google/go-github/v48/github"
+	"github.com/google/go-github/v49/github"
 )
 
 func main() {
@@ -290,7 +290,7 @@ For complete usage of go-github, see the full [package docs][].
 [oauth2]: https://github.com/golang/oauth2
 [oauth2 docs]: https://godoc.org/golang.org/x/oauth2
 [personal API token]: https://github.com/blog/1509-personal-api-tokens
-[package docs]: https://pkg.go.dev/github.com/google/go-github/v48/github
+[package docs]: https://pkg.go.dev/github.com/google/go-github/v49/github
 [GraphQL API v4]: https://developer.github.com/v4/
 [shurcooL/githubv4]: https://github.com/shurcooL/githubv4
 [GitHub webhook events]: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads
@@ -363,9 +363,9 @@ Versions prior to 48.2.0 are not listed.
 
 | go-github Version | GitHub v3 API Version |
 | ----------------- | --------------------- |
+| 49.0.0            | 2022-11-28            |
 | 48.2.0            | 2022-11-28            |
 
-
 ## License ##
 
 This library is distributed under the BSD-style license found in the [LICENSE](./LICENSE)
diff --git a/example/actionpermissions/main.go b/example/actionpermissions/main.go
index c568d572..4c9912d9 100644
--- a/example/actionpermissions/main.go
+++ b/example/actionpermissions/main.go
@@ -14,7 +14,7 @@ import (
 	"log"
 	"os"
 
-	"github.com/google/go-github/v48/github"
+	"github.com/google/go-github/v49/github"
 	"golang.org/x/oauth2"
 )
 
diff --git a/example/appengine/app.go b/example/appengine/app.go
index e4ba5d96..3ad9f122 100644
--- a/example/appengine/app.go
+++ b/example/appengine/app.go
@@ -12,7 +12,7 @@ import (
 	"net/http"
 	"os"
 
-	"github.com/google/go-github/v48/github"
+	"github.com/google/go-github/v49/github"
 	"golang.org/x/oauth2"
 	"google.golang.org/appengine"
 	"google.golang.org/appengine/log"
diff --git a/example/basicauth/main.go b/example/basicauth/main.go
index 43604434..bfb9c681 100644
--- a/example/basicauth/main.go
+++ b/example/basicauth/main.go
@@ -22,7 +22,7 @@ import (
 	"strings"
 	"syscall"
 
-	"github.com/google/go-github/v48/github"
+	"github.com/google/go-github/v49/github"
 	"golang.org/x/crypto/ssh/terminal"
 )
 
diff --git a/example/commitpr/main.go b/example/commitpr/main.go
index 1d60625d..ca6ffc85 100644
--- a/example/commitpr/main.go
+++ b/example/commitpr/main.go
@@ -30,7 +30,7 @@ import (
 	"strings"
 	"time"
 
-	"github.com/google/go-github/v48/github"
+	"github.com/google/go-github/v49/github"
 	"golang.org/x/oauth2"
 )
 
diff --git a/example/go.mod b/example/go.mod
index f1041907..a28bcb85 100644
--- a/example/go.mod
+++ b/example/go.mod
@@ -1,10 +1,10 @@
-module github.com/google/go-github/v48/example
+module github.com/google/go-github/v49/example
 
 go 1.17
 
 require (
 	github.com/bradleyfalzon/ghinstallation/v2 v2.0.4
-	github.com/google/go-github/v48 v48.2.0
+	github.com/google/go-github/v49 v49.0.0
 	golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
 	golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be
 	google.golang.org/appengine v1.6.7
@@ -21,4 +21,4 @@ require (
 )
 
 // Use version at HEAD, not the latest published.
-replace github.com/google/go-github/v48 => ../
+replace github.com/google/go-github/v49 => ../
diff --git a/example/listenvironments/main.go b/example/listenvironments/main.go
index ddee688d..f86b1a2d 100644
--- a/example/listenvironments/main.go
+++ b/example/listenvironments/main.go
@@ -18,7 +18,7 @@ import (
 	"log"
 	"os"
 
-	"github.com/google/go-github/v48/github"
+	"github.com/google/go-github/v49/github"
 	"golang.org/x/oauth2"
 )
 
diff --git a/example/migrations/main.go b/example/migrations/main.go
index 096085ce..015e18e2 100644
--- a/example/migrations/main.go
+++ b/example/migrations/main.go
@@ -12,7 +12,7 @@ import (
 	"context"
 	"fmt"
 
-	"github.com/google/go-github/v48/github"
+	"github.com/google/go-github/v49/github"
 	"golang.org/x/oauth2"
 )
 
diff --git a/example/newfilewithappauth/main.go b/example/newfilewithappauth/main.go
index a448a056..0e64d93d 100644
--- a/example/newfilewithappauth/main.go
+++ b/example/newfilewithappauth/main.go
@@ -16,7 +16,7 @@ import (
 	"time"
 
 	"github.com/bradleyfalzon/ghinstallation/v2"
-	"github.com/google/go-github/v48/github"
+	"github.com/google/go-github/v49/github"
 	"golang.org/x/oauth2"
 )
 
diff --git a/example/newrepo/main.go b/example/newrepo/main.go
index 46378f98..5f796d33 100644
--- a/example/newrepo/main.go
+++ b/example/newrepo/main.go
@@ -16,7 +16,7 @@ import (
 	"log"
 	"os"
 
-	"github.com/google/go-github/v48/github"
+	"github.com/google/go-github/v49/github"
 	"golang.org/x/oauth2"
 )
 
diff --git a/example/newreposecretwithlibsodium/go.mod b/example/newreposecretwithlibsodium/go.mod
index a190c0a8..04ff0c16 100644
--- a/example/newreposecretwithlibsodium/go.mod
+++ b/example/newreposecretwithlibsodium/go.mod
@@ -4,9 +4,9 @@ go 1.15
 
 require (
 	github.com/GoKillers/libsodium-go v0.0.0-20171022220152-dd733721c3cb
-	github.com/google/go-github/v48 v48.2.0
+	github.com/google/go-github/v49 v49.0.0
 	golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43
 )
 
 // Use version at HEAD, not the latest published.
-replace github.com/google/go-github/v48 => ../..
+replace github.com/google/go-github/v49 => ../..
diff --git a/example/newreposecretwithlibsodium/main.go b/example/newreposecretwithlibsodium/main.go
index fb66df83..3e932c5e 100644
--- a/example/newreposecretwithlibsodium/main.go
+++ b/example/newreposecretwithlibsodium/main.go
@@ -36,7 +36,7 @@ import (
 	"os"
 
 	sodium "github.com/GoKillers/libsodium-go/cryptobox"
-	"github.com/google/go-github/v48/github"
+	"github.com/google/go-github/v49/github"
 	"golang.org/x/oauth2"
 )
 
diff --git a/example/newreposecretwithxcrypto/main.go b/example/newreposecretwithxcrypto/main.go
index c4f38f34..bb688372 100644
--- a/example/newreposecretwithxcrypto/main.go
+++ b/example/newreposecretwithxcrypto/main.go
@@ -36,7 +36,7 @@ import (
 	"log"
 	"os"
 
-	"github.com/google/go-github/v48/github"
+	"github.com/google/go-github/v49/github"
 	"golang.org/x/crypto/nacl/box"
 	"golang.org/x/oauth2"
 )
diff --git a/example/simple/main.go b/example/simple/main.go
index ed68b4ee..29b22ecc 100644
--- a/example/simple/main.go
+++ b/example/simple/main.go
@@ -12,7 +12,7 @@ import (
 	"context"
 	"fmt"
 
-	"github.com/google/go-github/v48/github"
+	"github.com/google/go-github/v49/github"
 )
 
 // Fetch all the public organizations' membership of a user.
diff --git a/example/tagprotection/main.go b/example/tagprotection/main.go
index 09ae4dcf..12ec91a6 100644
--- a/example/tagprotection/main.go
+++ b/example/tagprotection/main.go
@@ -19,7 +19,7 @@ import (
 	"strings"
 	"syscall"
 
-	"github.com/google/go-github/v48/github"
+	"github.com/google/go-github/v49/github"
 	"golang.org/x/crypto/ssh/terminal"
 	"golang.org/x/oauth2"
 )
diff --git a/example/tokenauth/main.go b/example/tokenauth/main.go
index c6ef3cd4..ed489d72 100644
--- a/example/tokenauth/main.go
+++ b/example/tokenauth/main.go
@@ -14,7 +14,7 @@ import (
 	"log"
 	"syscall"
 
-	"github.com/google/go-github/v48/github"
+	"github.com/google/go-github/v49/github"
 	"golang.org/x/crypto/ssh/terminal"
 	"golang.org/x/oauth2"
 )
diff --git a/example/topics/main.go b/example/topics/main.go
index 1033c276..489b9c71 100644
--- a/example/topics/main.go
+++ b/example/topics/main.go
@@ -12,7 +12,7 @@ import (
 	"context"
 	"fmt"
 
-	"github.com/google/go-github/v48/github"
+	"github.com/google/go-github/v49/github"
 )
 
 // Fetch and lists all the public topics associated with the specified GitHub topic
diff --git a/github/actions_cache.go b/github/actions_cache.go
new file mode 100644
index 00000000..9592d9ab
--- /dev/null
+++ b/github/actions_cache.go
@@ -0,0 +1,235 @@
+// Copyright 2022 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"
+)
+
+// ActionsCache represents a GitHub action cache.
+//
+// GitHub API docs: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#about-the-cache-api
+type ActionsCache struct {
+	ID             *int64     `json:"id,omitempty" url:"-"`
+	Ref            *string    `json:"ref,omitempty" url:"ref"`
+	Key            *string    `json:"key,omitempty" url:"key"`
+	Version        *string    `json:"version,omitempty" url:"-"`
+	LastAccessedAt *Timestamp `json:"last_accessed_at,omitempty" url:"-"`
+	CreatedAt      *Timestamp `json:"created_at,omitempty" url:"-"`
+	SizeInBytes    *int64     `json:"size_in_bytes,omitempty" url:"-"`
+}
+
+// ActionsCacheList represents a list of GitHub actions Cache.
+//
+// GitHub API docs: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#list-github-actions-caches-for-a-repository
+type ActionsCacheList struct {
+	TotalCount    int             `json:"total_count"`
+	ActionsCaches []*ActionsCache `json:"actions_caches,omitempty"`
+}
+
+// ActionsCacheUsage represents a GitHub Actions Cache Usage object.
+//
+// GitHub API docs: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#get-github-actions-cache-usage-for-a-repository
+type ActionsCacheUsage struct {
+	FullName                string `json:"full_name"`
+	ActiveCachesSizeInBytes int64  `json:"active_caches_size_in_bytes"`
+	ActiveCachesCount       int    `json:"active_caches_count"`
+}
+
+// ActionsCacheUsageList represents a list of repositories with GitHub Actions cache usage for an organization.
+//
+// GitHub API docs: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#get-github-actions-cache-usage-for-a-repository
+type ActionsCacheUsageList struct {
+	TotalCount     int                  `json:"total_count"`
+	RepoCacheUsage []*ActionsCacheUsage `json:"repository_cache_usages,omitempty"`
+}
+
+// TotalCacheUsage represents total GitHub actions cache usage of an organization or enterprise.
+//
+// GitHub API docs: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#get-github-actions-cache-usage-for-an-enterprise
+type TotalCacheUsage struct {
+	TotalActiveCachesUsageSizeInBytes int64 `json:"total_active_caches_size_in_bytes"`
+	TotalActiveCachesCount            int   `json:"total_active_caches_count"`
+}
+
+// ActionsCacheListOptions represents a list of all possible optional Query parameters for ListCaches method.
+//
+// GitHub API docs:  https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#list-github-actions-caches-for-a-repository
+type ActionsCacheListOptions struct {
+	ListOptions
+	// The Git reference for the results you want to list.
+	// The ref for a branch can be formatted either as refs/heads/<branch name>
+	// or simply <branch name>. To reference a pull request use refs/pull/<number>/merge
+	Ref *string `url:"ref,omitempty"`
+	Key *string `url:"key,omitempty"`
+	// Can be one of: "created_at", "last_accessed_at", "size_in_bytes". Default: "last_accessed_at"
+	Sort *string `url:"sort,omitempty"`
+	// Can be one of: "asc", "desc" Default: desc
+	Direction *string `url:"direction,omitempty"`
+}
+
+// ListCaches lists the GitHub Actions caches for a repository.
+// You must authenticate using an access token with the repo scope to use this endpoint.
+//
+// Permissions: must have the actions:read permission to use this endpoint.
+//
+// GitHub API docs: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#list-github-actions-caches-for-a-repository
+func (s *ActionsService) ListCaches(ctx context.Context, owner, repo string, opts *ActionsCacheListOptions) (*ActionsCacheList, *Response, error) {
+	u := fmt.Sprintf("repos/%v/%v/actions/caches", owner, repo)
+	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
+	}
+
+	actionCacheList := new(ActionsCacheList)
+	resp, err := s.client.Do(ctx, req, actionCacheList)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return actionCacheList, resp, nil
+}
+
+// DeleteCachesByKey deletes one or more GitHub Actions caches for a repository, using a complete cache key.
+// By default, all caches that match the provided key are deleted, but you can optionally provide
+// a Git ref to restrict deletions to caches that match both the provided key and the Git ref.
+// The ref for a branch can be formatted either as "refs/heads/<branch name>" or simply "<branch name>".
+// To reference a pull request use "refs/pull/<number>/merge". If you don't want to use ref just pass nil in parameter.
+//
+// Permissions: You must authenticate using an access token with the repo scope to use this endpoint. GitHub Apps must have the actions:write permission to use this endpoint.
+//
+// GitHub API docs: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#delete-github-actions-caches-for-a-repository-using-a-cache-key
+func (s *ActionsService) DeleteCachesByKey(ctx context.Context, owner, repo, key string, ref *string) (*Response, error) {
+	u := fmt.Sprintf("repos/%v/%v/actions/caches", owner, repo)
+	u, err := addOptions(u, ActionsCache{Key: &key, Ref: ref})
+	if err != nil {
+		return nil, err
+	}
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(ctx, req, nil)
+}
+
+// DeleteCachesByID deletes a GitHub Actions cache for a repository, using a cache ID.
+//
+// Permissions: You must authenticate using an access token with the repo scope to use this endpoint. GitHub Apps must have the actions:write permission to use this endpoint.
+//
+// GitHub API docs: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#delete-a-github-actions-cache-for-a-repository-using-a-cache-id
+func (s *ActionsService) DeleteCachesByID(ctx context.Context, owner, repo string, cacheID int64) (*Response, error) {
+	u := fmt.Sprintf("repos/%v/%v/actions/caches/%v", owner, repo, cacheID)
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(ctx, req, nil)
+}
+
+// GetCacheUsageForRepo gets GitHub Actions cache usage for a repository. The data fetched using this API is refreshed approximately every 5 minutes,
+// so values returned from this endpoint may take at least 5 minutes to get updated.
+//
+// Permissions: Anyone with read access to the repository can use this endpoint. If the repository is private, you must use an
+// access token with the repo scope. GitHub Apps must have the actions:read permission to use this endpoint.
+//
+// GitHub API docs: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#get-github-actions-cache-usage-for-a-repository
+func (s *ActionsService) GetCacheUsageForRepo(ctx context.Context, owner, repo string) (*ActionsCacheUsage, *Response, error) {
+	u := fmt.Sprintf("repos/%v/%v/actions/cache/usage", owner, repo)
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	cacheUsage := new(ActionsCacheUsage)
+	res, err := s.client.Do(ctx, req, cacheUsage)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return cacheUsage, res, err
+}
+
+// ListCacheUsageByRepoForOrg lists repositories and their GitHub Actions cache usage for an organization. The data fetched using this API is
+// refreshed approximately every 5 minutes, so values returned from this endpoint may take at least 5 minutes to get updated.
+//
+// Permissions: You must authenticate using an access token with the read:org scope to use this endpoint.
+// GitHub Apps must have the organization_admistration:read permission to use this endpoint.
+//
+// GitHub API docs: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#list-repositories-with-github-actions-cache-usage-for-an-organization
+func (s *ActionsService) ListCacheUsageByRepoForOrg(ctx context.Context, org string, opts *ListOptions) (*ActionsCacheUsageList, *Response, error) {
+	u := fmt.Sprintf("orgs/%v/actions/cache/usage-by-repository", org)
+	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
+	}
+
+	cacheUsage := new(ActionsCacheUsageList)
+	res, err := s.client.Do(ctx, req, cacheUsage)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return cacheUsage, res, err
+}
+
+// GetTotalCacheUsageForOrg gets the total GitHub Actions cache usage for an organization. The data fetched using this API is refreshed approximately every
+// 5 minutes, so values returned from this endpoint may take at least 5 minutes to get updated.
+//
+// Permissions: You must authenticate using an access token with the read:org scope to use this endpoint.
+// GitHub Apps must have the organization_admistration:read permission to use this endpoint.
+//
+// GitHub API docs: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#get-github-actions-cache-usage-for-an-organization
+func (s *ActionsService) GetTotalCacheUsageForOrg(ctx context.Context, org string) (*TotalCacheUsage, *Response, error) {
+	u := fmt.Sprintf("orgs/%v/actions/cache/usage", org)
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	cacheUsage := new(TotalCacheUsage)
+	res, err := s.client.Do(ctx, req, cacheUsage)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return cacheUsage, res, err
+}
+
+// GetTotalCacheUsageForEnterprise gets the total GitHub Actions cache usage for an enterprise. The data fetched using this API is refreshed approximately every 5 minutes,
+// so values returned from this endpoint may take at least 5 minutes to get updated.
+//
+// Permissions: You must authenticate using an access token with the "admin:enterprise" scope to use this endpoint.
+//
+// GitHub API docs: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#get-github-actions-cache-usage-for-an-enterprise
+func (s *ActionsService) GetTotalCacheUsageForEnterprise(ctx context.Context, enterprise string) (*TotalCacheUsage, *Response, error) {
+	u := fmt.Sprintf("enterprises/%v/actions/cache/usage", enterprise)
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	cacheUsage := new(TotalCacheUsage)
+	res, err := s.client.Do(ctx, req, cacheUsage)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return cacheUsage, res, err
+}
diff --git a/github/doc.go b/github/doc.go
index 0c4afaa3..1401f07f 100644
--- a/github/doc.go
+++ b/github/doc.go
@@ -8,7 +8,7 @@ Package github provides a client for using the GitHub API.
 
 Usage:
 
-	import "github.com/google/go-github/v48/github"	// with go modules enabled (GO111MODULE=on or outside GOPATH)
+	import "github.com/google/go-github/v49/github"	// with go modules enabled (GO111MODULE=on or outside GOPATH)
 	import "github.com/google/go-github/github"     // with go modules disabled
 
 Construct a new GitHub client, then use the various services on the client to
diff --git a/github/github-accessors.go b/github/github-accessors.go
index 422d8bc0..9ed960fb 100644
--- a/github/github-accessors.go
+++ b/github/github-accessors.go
@@ -38,6 +38,94 @@ func (a *ActionsAllowed) GetVerifiedAllowed() bool {
 	return *a.VerifiedAllowed
 }
 
+// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise.
+func (a *ActionsCache) GetCreatedAt() Timestamp {
+	if a == nil || a.CreatedAt == nil {
+		return Timestamp{}
+	}
+	return *a.CreatedAt
+}
+
+// GetID returns the ID field if it's non-nil, zero value otherwise.
+func (a *ActionsCache) GetID() int64 {
+	if a == nil || a.ID == nil {
+		return 0
+	}
+	return *a.ID
+}
+
+// GetKey returns the Key field if it's non-nil, zero value otherwise.
+func (a *ActionsCache) GetKey() string {
+	if a == nil || a.Key == nil {
+		return ""
+	}
+	return *a.Key
+}
+
+// GetLastAccessedAt returns the LastAccessedAt field if it's non-nil, zero value otherwise.
+func (a *ActionsCache) GetLastAccessedAt() Timestamp {
+	if a == nil || a.LastAccessedAt == nil {
+		return Timestamp{}
+	}
+	return *a.LastAccessedAt
+}
+
+// GetRef returns the Ref field if it's non-nil, zero value otherwise.
+func (a *ActionsCache) GetRef() string {
+	if a == nil || a.Ref == nil {
+		return ""
+	}
+	return *a.Ref
+}
+
+// GetSizeInBytes returns the SizeInBytes field if it's non-nil, zero value otherwise.
+func (a *ActionsCache) GetSizeInBytes() int64 {
+	if a == nil || a.SizeInBytes == nil {
+		return 0
+	}
+	return *a.SizeInBytes
+}
+
+// GetVersion returns the Version field if it's non-nil, zero value otherwise.
+func (a *ActionsCache) GetVersion() string {
+	if a == nil || a.Version == nil {
+		return ""
+	}
+	return *a.Version
+}
+
+// GetDirection returns the Direction field if it's non-nil, zero value otherwise.
+func (a *ActionsCacheListOptions) GetDirection() string {
+	if a == nil || a.Direction == nil {
+		return ""
+	}
+	return *a.Direction
+}
+
+// GetKey returns the Key field if it's non-nil, zero value otherwise.
+func (a *ActionsCacheListOptions) GetKey() string {
+	if a == nil || a.Key == nil {
+		return ""
+	}
+	return *a.Key
+}
+
+// GetRef returns the Ref field if it's non-nil, zero value otherwise.
+func (a *ActionsCacheListOptions) GetRef() string {
+	if a == nil || a.Ref == nil {
+		return ""
+	}
+	return *a.Ref
+}
+
+// GetSort returns the Sort field if it's non-nil, zero value otherwise.
+func (a *ActionsCacheListOptions) GetSort() string {
+	if a == nil || a.Sort == nil {
+		return ""
+	}
+	return *a.Sort
+}
+
 // GetAllowedActions returns the AllowedActions field if it's non-nil, zero value otherwise.
 func (a *ActionsPermissions) GetAllowedActions() string {
 	if a == nil || a.AllowedActions == nil {
diff --git a/github/github.go b/github/github.go
index 3599a88d..d5aa1c68 100644
--- a/github/github.go
+++ b/github/github.go
@@ -27,7 +27,7 @@ import (
 )
 
 const (
-	Version = "v48.2.0"
+	Version = "v49.0.0"
 
 	defaultAPIVersion = "2022-11-28"
 	defaultBaseURL    = "https://api.github.com/"
diff --git a/github/repos_environments.go b/github/repos_environments.go
index 365f8d92..2e85fdf9 100644
--- a/github/repos_environments.go
+++ b/github/repos_environments.go
@@ -9,6 +9,7 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
+	"net/http"
 )
 
 // Environment represents a single environment in a repository.
@@ -168,6 +169,13 @@ type CreateUpdateEnvironment struct {
 	DeploymentBranchPolicy *BranchPolicy   `json:"deployment_branch_policy"`
 }
 
+// createUpdateEnvironmentNoEnterprise represents the fields accepted for Pro/Teams private repos.
+// Ref: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment
+// See https://github.com/google/go-github/issues/2602 for more information.
+type createUpdateEnvironmentNoEnterprise struct {
+	DeploymentBranchPolicy *BranchPolicy `json:"deployment_branch_policy"`
+}
+
 // CreateUpdateEnvironment create or update a new environment for a repository.
 //
 // GitHub API docs: https://docs.github.com/en/rest/deployments/environments#create-or-update-an-environment
@@ -179,6 +187,33 @@ func (s *RepositoriesService) CreateUpdateEnvironment(ctx context.Context, owner
 		return nil, nil, err
 	}
 
+	e := new(Environment)
+	resp, err := s.client.Do(ctx, req, e)
+	if err != nil {
+		// The API returns 422 when the pricing plan doesn't support all the fields sent.
+		// This path will be executed for Pro/Teams private repos.
+		// For public repos, regardless of the pricing plan, all fields supported.
+		// For Free plan private repos the returned error code is 404.
+		// We are checking that the user didn't try to send a value for unsupported fields,
+		// and return an error if they did.
+		if resp != nil && resp.StatusCode == http.StatusUnprocessableEntity && environment != nil && len(environment.Reviewers) == 0 && environment.GetWaitTimer() == 0 {
+			return s.createNewEnvNoEnterprise(ctx, u, environment)
+		}
+		return nil, resp, err
+	}
+	return e, resp, nil
+}
+
+// createNewEnvNoEnterprise is an internal function for cases where the original call returned 422.
+// Currently only the `deployment_branch_policy` parameter is supported for Pro/Team private repos.
+func (s *RepositoriesService) createNewEnvNoEnterprise(ctx context.Context, u string, environment *CreateUpdateEnvironment) (*Environment, *Response, error) {
+	req, err := s.client.NewRequest("PUT", u, &createUpdateEnvironmentNoEnterprise{
+		DeploymentBranchPolicy: environment.DeploymentBranchPolicy,
+	})
+	if err != nil {
+		return nil, nil, err
+	}
+
 	e := new(Environment)
 	resp, err := s.client.Do(ctx, req, e)
 	if err != nil {
diff --git a/go.mod b/go.mod
index 656bb754..4f7880fd 100644
--- a/go.mod
+++ b/go.mod
@@ -1,4 +1,4 @@
-module github.com/google/go-github/v48
+module github.com/google/go-github/v49
 
 require (
 	github.com/google/go-cmp v0.5.9
diff --git a/scrape/apps.go b/scrape/apps.go
index 55afeb6c..693addeb 100644
--- a/scrape/apps.go
+++ b/scrape/apps.go
@@ -17,7 +17,7 @@ import (
 	"strings"
 
 	"github.com/PuerkitoBio/goquery"
-	"github.com/google/go-github/v48/github"
+	"github.com/google/go-github/v49/github"
 )
 
 // AppRestrictionsEnabled returns whether the specified organization has
diff --git a/scrape/go.mod b/scrape/go.mod
index 65e2b6eb..01a68390 100644
--- a/scrape/go.mod
+++ b/scrape/go.mod
@@ -5,7 +5,7 @@ go 1.13
 require (
 	github.com/PuerkitoBio/goquery v1.8.0
 	github.com/google/go-cmp v0.5.9
-	github.com/google/go-github/v48 v48.2.0
+	github.com/google/go-github/v49 v49.0.0
 	github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119
 	golang.org/x/net v0.0.0-20210916014120-12bc252f5db8
 )
diff --git a/scrape/go.sum b/scrape/go.sum
index ce4b6dc2..f32e7440 100644
--- a/scrape/go.sum
+++ b/scrape/go.sum
@@ -7,8 +7,8 @@ github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
 github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
 github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/go-github/v48 v48.2.0 h1:68puzySE6WqUY9KWmpOsDEQfDZsso98rT6pZcz9HqcE=
-github.com/google/go-github/v48 v48.2.0/go.mod h1:dDlehKBDo850ZPvCTK0sEqTCVWcrGl2LcDiajkYi89Y=
+github.com/google/go-github/v49 v49.0.0 h1:vSz1fnOeGztFxDe48q0RCOrd8Cg4o8INcZBPVpGPNaY=
+github.com/google/go-github/v49 v49.0.0/go.mod h1:MUUzHPrhGniB6vUKa27y37likpipzG+BXXJbG04J334=
 github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
 github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
 github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119 h1:YyPWX3jLOtYKulBR6AScGIs74lLrJcgeKRwcbAuQOG4=
diff --git a/update-urls/go.mod b/update-urls/go.mod
index 2fed223a..d01d8de9 100644
--- a/update-urls/go.mod
+++ b/update-urls/go.mod
@@ -1,4 +1,4 @@
-module github.com/google/go-github/v48/update-urls
+module github.com/google/go-github/v49/update-urls
 
 go 1.16
 


Test patch:
diff --git a/github/actions_cache_test.go b/github/actions_cache_test.go
new file mode 100644
index 00000000..b72d5cb8
--- /dev/null
+++ b/github/actions_cache_test.go
@@ -0,0 +1,517 @@
+// Copyright 2022 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 TestActionsService_ListCaches(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/repos/o/r/actions/caches", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		testFormValues(t, r, values{"page": "2"})
+		fmt.Fprint(w,
+			`{
+				"total_count":1,
+				"actions_caches":[{"id":1}]
+			}`,
+		)
+	})
+
+	opts := &ActionsCacheListOptions{ListOptions: ListOptions{Page: 2}}
+	ctx := context.Background()
+	cacheList, _, err := client.Actions.ListCaches(ctx, "o", "r", opts)
+	if err != nil {
+		t.Errorf("Actions.ListCaches returned error: %v", err)
+	}
+
+	want := &ActionsCacheList{TotalCount: 1, ActionsCaches: []*ActionsCache{{ID: Int64(1)}}}
+	if !cmp.Equal(cacheList, want) {
+		t.Errorf("Actions.ListCaches returned %+v, want %+v", cacheList, want)
+	}
+
+	const methodName = "ListCaches"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Actions.ListCaches(ctx, "\n", "\n", opts)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Actions.ListCaches(ctx, "o", "r", opts)
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
+
+func TestActionsService_ListCaches_invalidOwner(t *testing.T) {
+	client, _, _, teardown := setup()
+	defer teardown()
+
+	ctx := context.Background()
+	_, _, err := client.Actions.ListCaches(ctx, "%", "r", nil)
+	testURLParseError(t, err)
+}
+
+func TestActionsService_ListCaches_invalidRepo(t *testing.T) {
+	client, _, _, teardown := setup()
+	defer teardown()
+
+	ctx := context.Background()
+	_, _, err := client.Actions.ListCaches(ctx, "o", "%", nil)
+	testURLParseError(t, err)
+}
+
+func TestActionsService_ListCaches_notFound(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/repos/o/r/actions/caches", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		w.WriteHeader(http.StatusNotFound)
+	})
+
+	ctx := context.Background()
+	caches, resp, err := client.Actions.ListCaches(ctx, "o", "r", nil)
+	if err == nil {
+		t.Errorf("Expected HTTP 404 response")
+	}
+	if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want {
+		t.Errorf("Actions.ListCaches return status %d, want %d", got, want)
+	}
+	if caches != nil {
+		t.Errorf("Actions.ListCaches return %+v, want nil", caches)
+	}
+}
+
+func TestActionsService_DeleteCachesByKey(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/repos/o/r/actions/caches", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "DELETE")
+		testFormValues(t, r, values{"key": "1", "ref": "main"})
+	})
+
+	ctx := context.Background()
+	_, err := client.Actions.DeleteCachesByKey(ctx, "o", "r", "1", String("main"))
+	if err != nil {
+		t.Errorf("Actions.DeleteCachesByKey return error: %v", err)
+	}
+
+	const methodName = "DeleteCachesByKey"
+	testBadOptions(t, methodName, func() (err error) {
+		_, err = client.Actions.DeleteCachesByKey(ctx, "\n", "\n", "\n", String("\n"))
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		return client.Actions.DeleteCachesByKey(ctx, "o", "r", "1", String("main"))
+	})
+}
+
+func TestActionsService_DeleteCachesByKey_invalidOwner(t *testing.T) {
+	client, _, _, teardown := setup()
+	defer teardown()
+
+	ctx := context.Background()
+	_, err := client.Actions.DeleteCachesByKey(ctx, "%", "r", "1", String("main"))
+	testURLParseError(t, err)
+}
+
+func TestActionsService_DeleteCachesByKey_invalidRepo(t *testing.T) {
+	client, _, _, teardown := setup()
+	defer teardown()
+
+	ctx := context.Background()
+	_, err := client.Actions.DeleteCachesByKey(ctx, "o", "%", "1", String("main"))
+	testURLParseError(t, err)
+}
+func TestActionsService_DeleteCachesByKey_notFound(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/repos/o/r/actions/artifacts/1", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "DELETE")
+		w.WriteHeader(http.StatusNotFound)
+	})
+
+	ctx := context.Background()
+	resp, err := client.Actions.DeleteCachesByKey(ctx, "o", "r", "1", String("main"))
+	if err == nil {
+		t.Errorf("Expected HTTP 404 response")
+	}
+	if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want {
+		t.Errorf("Actions.DeleteCachesByKey return status %d, want %d", got, want)
+	}
+}
+
+func TestActionsService_DeleteCachesByID(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/repos/o/r/actions/caches/1", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "DELETE")
+	})
+
+	ctx := context.Background()
+	_, err := client.Actions.DeleteCachesByID(ctx, "o", "r", 1)
+	if err != nil {
+		t.Errorf("Actions.DeleteCachesByID return error: %v", err)
+	}
+
+	const methodName = "DeleteCachesByID"
+	testBadOptions(t, methodName, func() (err error) {
+		_, err = client.Actions.DeleteCachesByID(ctx, "\n", "\n", 0)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		return client.Actions.DeleteCachesByID(ctx, "o", "r", 1)
+	})
+}
+
+func TestActionsService_DeleteCachesByID_invalidOwner(t *testing.T) {
+	client, _, _, teardown := setup()
+	defer teardown()
+
+	ctx := context.Background()
+	_, err := client.Actions.DeleteCachesByID(ctx, "%", "r", 1)
+	testURLParseError(t, err)
+}
+
+func TestActionsService_DeleteCachesByID_invalidRepo(t *testing.T) {
+	client, _, _, teardown := setup()
+	defer teardown()
+
+	ctx := context.Background()
+	_, err := client.Actions.DeleteCachesByID(ctx, "o", "%", 1)
+	testURLParseError(t, err)
+}
+
+func TestActionsService_DeleteCachesByID_notFound(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("repos/o/r/actions/caches/1", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "DELETE")
+		w.WriteHeader(http.StatusNotFound)
+	})
+
+	ctx := context.Background()
+	resp, err := client.Actions.DeleteCachesByID(ctx, "o", "r", 1)
+	if err == nil {
+		t.Errorf("Expected HTTP 404 response")
+	}
+	if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want {
+		t.Errorf("Actions.DeleteCachesByID return status %d, want %d", got, want)
+	}
+}
+
+func TestActionsService_GetCacheUsageForRepo(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/repos/o/r/actions/cache/usage", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		fmt.Fprint(w,
+			`{
+				"full_name":"test-cache",
+				"active_caches_size_in_bytes":1000,
+				"active_caches_count":1
+			}`,
+		)
+	})
+
+	ctx := context.Background()
+	cacheUse, _, err := client.Actions.GetCacheUsageForRepo(ctx, "o", "r")
+	if err != nil {
+		t.Errorf("Actions.GetCacheUsageForRepo returned error: %v", err)
+	}
+
+	want := &ActionsCacheUsage{FullName: "test-cache", ActiveCachesSizeInBytes: 1000, ActiveCachesCount: 1}
+	if !cmp.Equal(cacheUse, want) {
+		t.Errorf("Actions.GetCacheUsageForRepo returned %+v, want %+v", cacheUse, want)
+	}
+
+	const methodName = "GetCacheUsageForRepo"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Actions.GetCacheUsageForRepo(ctx, "\n", "\n")
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Actions.GetCacheUsageForRepo(ctx, "o", "r")
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
+
+func TestActionsService_GetCacheUsageForRepo_invalidOwner(t *testing.T) {
+	client, _, _, teardown := setup()
+	defer teardown()
+
+	ctx := context.Background()
+	_, _, err := client.Actions.GetCacheUsageForRepo(ctx, "%", "r")
+	testURLParseError(t, err)
+}
+
+func TestActionsService_GetCacheUsageForRepo_invalidRepo(t *testing.T) {
+	client, _, _, teardown := setup()
+	defer teardown()
+
+	ctx := context.Background()
+	_, _, err := client.Actions.GetCacheUsageForRepo(ctx, "o", "%")
+	testURLParseError(t, err)
+}
+
+func TestActionsService_GetCacheUsageForRepo_notFound(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/repos/o/r/actions/cache/usage", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		w.WriteHeader(http.StatusNotFound)
+	})
+
+	ctx := context.Background()
+	caches, resp, err := client.Actions.GetCacheUsageForRepo(ctx, "o", "r")
+	if err == nil {
+		t.Errorf("Expected HTTP 404 response")
+	}
+	if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want {
+		t.Errorf("Actions.GetCacheUsageForRepo return status %d, want %d", got, want)
+	}
+	if caches != nil {
+		t.Errorf("Actions.GetCacheUsageForRepo return %+v, want nil", caches)
+	}
+}
+
+func TestActionsService_ListCacheUsageByRepoForOrg(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/orgs/o/actions/cache/usage-by-repository", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		testFormValues(t, r, values{"page": "2", "per_page": "1"})
+		fmt.Fprint(w,
+			`{
+				"total_count":1,
+				"repository_cache_usages":[{"full_name":"test-cache","active_caches_size_in_bytes":1000,"active_caches_count":1}]
+			}`,
+		)
+	})
+
+	opts := &ListOptions{PerPage: 1, Page: 2}
+	ctx := context.Background()
+	cacheList, _, err := client.Actions.ListCacheUsageByRepoForOrg(ctx, "o", opts)
+	if err != nil {
+		t.Errorf("Actions.ListCacheUsageByRepoForOrg returned error: %v", err)
+	}
+
+	want := &ActionsCacheUsageList{TotalCount: 1, RepoCacheUsage: []*ActionsCacheUsage{{FullName: "test-cache", ActiveCachesSizeInBytes: 1000, ActiveCachesCount: 1}}}
+	if !cmp.Equal(cacheList, want) {
+		t.Errorf("Actions.ListCacheUsageByRepoForOrg returned %+v, want %+v", cacheList, want)
+	}
+
+	const methodName = "ListCacheUsageByRepoForOrg"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Actions.ListCacheUsageByRepoForOrg(ctx, "\n", opts)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Actions.ListCacheUsageByRepoForOrg(ctx, "o", opts)
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
+
+func TestActionsService_ListCacheUsageByRepoForOrg_invalidOrganization(t *testing.T) {
+	client, _, _, teardown := setup()
+	defer teardown()
+
+	ctx := context.Background()
+	_, _, err := client.Actions.ListCacheUsageByRepoForOrg(ctx, "%", nil)
+	testURLParseError(t, err)
+}
+
+func TestActionsService_ListCacheUsageByRepoForOrg_notFound(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/orgs/o/actions/cache/usage-by-repository", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		w.WriteHeader(http.StatusNotFound)
+	})
+
+	ctx := context.Background()
+	caches, resp, err := client.Actions.ListCacheUsageByRepoForOrg(ctx, "o", nil)
+	if err == nil {
+		t.Errorf("Expected HTTP 404 response")
+	}
+	if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want {
+		t.Errorf("Actions.ListCacheUsageByRepoForOrg return status %d, want %d", got, want)
+	}
+	if caches != nil {
+		t.Errorf("Actions.ListCacheUsageByRepoForOrg return %+v, want nil", caches)
+	}
+}
+
+func TestActionsService_GetCacheUsageForOrg(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/orgs/o/actions/cache/usage", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		fmt.Fprint(w,
+			`{
+				"total_active_caches_size_in_bytes":1000,
+				"total_active_caches_count":1
+			}`,
+		)
+	})
+
+	ctx := context.Background()
+	cache, _, err := client.Actions.GetTotalCacheUsageForOrg(ctx, "o")
+	if err != nil {
+		t.Errorf("Actions.GetTotalCacheUsageForOrg returned error: %v", err)
+	}
+
+	want := &TotalCacheUsage{TotalActiveCachesUsageSizeInBytes: 1000, TotalActiveCachesCount: 1}
+	if !cmp.Equal(cache, want) {
+		t.Errorf("Actions.GetTotalCacheUsageForOrg returned %+v, want %+v", cache, want)
+	}
+
+	const methodName = "GetTotalCacheUsageForOrg"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Actions.GetTotalCacheUsageForOrg(ctx, "\n")
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Actions.GetTotalCacheUsageForOrg(ctx, "o")
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
+
+func TestActionsService_GetCacheUsageForOrg_invalidOrganization(t *testing.T) {
+	client, _, _, teardown := setup()
+	defer teardown()
+
+	ctx := context.Background()
+	_, _, err := client.Actions.GetTotalCacheUsageForOrg(ctx, "%")
+	testURLParseError(t, err)
+}
+
+func TestActionsService_GetCacheUsageForOrg_notFound(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/orgs/o/actions/cache/usage", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		w.WriteHeader(http.StatusNotFound)
+	})
+
+	ctx := context.Background()
+	caches, resp, err := client.Actions.GetTotalCacheUsageForOrg(ctx, "o")
+	if err == nil {
+		t.Errorf("Expected HTTP 404 response")
+	}
+	if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want {
+		t.Errorf("Actions.GetTotalCacheUsageForOrg return status %d, want %d", got, want)
+	}
+	if caches != nil {
+		t.Errorf("Actions.GetTotalCacheUsageForOrg return %+v, want nil", caches)
+	}
+}
+
+func TestActionsService_GetCacheUsageForEnterprise(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/enterprises/e/actions/cache/usage", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		fmt.Fprint(w,
+			`{
+				"total_active_caches_size_in_bytes":1000,
+				"total_active_caches_count":1
+			}`,
+		)
+	})
+
+	ctx := context.Background()
+	cache, _, err := client.Actions.GetTotalCacheUsageForEnterprise(ctx, "e")
+	if err != nil {
+		t.Errorf("Actions.GetTotalCacheUsageForEnterprise returned error: %v", err)
+	}
+
+	want := &TotalCacheUsage{TotalActiveCachesUsageSizeInBytes: 1000, TotalActiveCachesCount: 1}
+	if !cmp.Equal(cache, want) {
+		t.Errorf("Actions.GetTotalCacheUsageForEnterprise returned %+v, want %+v", cache, want)
+	}
+
+	const methodName = "GetTotalCacheUsageForEnterprise"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Actions.GetTotalCacheUsageForEnterprise(ctx, "\n")
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Actions.GetTotalCacheUsageForEnterprise(ctx, "e")
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
+
+func TestActionsService_GetCacheUsageForEnterprise_invalidEnterprise(t *testing.T) {
+	client, _, _, teardown := setup()
+	defer teardown()
+
+	ctx := context.Background()
+	_, _, err := client.Actions.GetTotalCacheUsageForEnterprise(ctx, "%")
+	testURLParseError(t, err)
+}
+
+func TestActionsService_GetCacheUsageForEnterprise_notFound(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/enterprises/e/actions/cache/usage", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		w.WriteHeader(http.StatusNotFound)
+	})
+
+	ctx := context.Background()
+	caches, resp, err := client.Actions.GetTotalCacheUsageForEnterprise(ctx, "o")
+	if err == nil {
+		t.Errorf("Expected HTTP 404 response")
+	}
+	if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want {
+		t.Errorf("Actions.GetTotalCacheUsageForEnterprise return status %d, want %d", got, want)
+	}
+	if caches != nil {
+		t.Errorf("Actions.GetTotalCacheUsageForEnterprise return %+v, want nil", caches)
+	}
+}
diff --git a/github/examples_test.go b/github/examples_test.go
index 79c226fc..efd4f024 100644
--- a/github/examples_test.go
+++ b/github/examples_test.go
@@ -12,7 +12,7 @@ import (
 	"fmt"
 	"log"
 
-	"github.com/google/go-github/v48/github"
+	"github.com/google/go-github/v49/github"
 )
 
 func ExampleClient_Markdown() {
diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go
index efa66e78..17d8504a 100644
--- a/github/github-accessors_test.go
+++ b/github/github-accessors_test.go
@@ -45,6 +45,116 @@ func TestActionsAllowed_GetVerifiedAllowed(tt *testing.T) {
 	a.GetVerifiedAllowed()
 }
 
+func TestActionsCache_GetCreatedAt(tt *testing.T) {
+	var zeroValue Timestamp
+	a := &ActionsCache{CreatedAt: &zeroValue}
+	a.GetCreatedAt()
+	a = &ActionsCache{}
+	a.GetCreatedAt()
+	a = nil
+	a.GetCreatedAt()
+}
+
+func TestActionsCache_GetID(tt *testing.T) {
+	var zeroValue int64
+	a := &ActionsCache{ID: &zeroValue}
+	a.GetID()
+	a = &ActionsCache{}
+	a.GetID()
+	a = nil
+	a.GetID()
+}
+
+func TestActionsCache_GetKey(tt *testing.T) {
+	var zeroValue string
+	a := &ActionsCache{Key: &zeroValue}
+	a.GetKey()
+	a = &ActionsCache{}
+	a.GetKey()
+	a = nil
+	a.GetKey()
+}
+
+func TestActionsCache_GetLastAccessedAt(tt *testing.T) {
+	var zeroValue Timestamp
+	a := &ActionsCache{LastAccessedAt: &zeroValue}
+	a.GetLastAccessedAt()
+	a = &ActionsCache{}
+	a.GetLastAccessedAt()
+	a = nil
+	a.GetLastAccessedAt()
+}
+
+func TestActionsCache_GetRef(tt *testing.T) {
+	var zeroValue string
+	a := &ActionsCache{Ref: &zeroValue}
+	a.GetRef()
+	a = &ActionsCache{}
+	a.GetRef()
+	a = nil
+	a.GetRef()
+}
+
+func TestActionsCache_GetSizeInBytes(tt *testing.T) {
+	var zeroValue int64
+	a := &ActionsCache{SizeInBytes: &zeroValue}
+	a.GetSizeInBytes()
+	a = &ActionsCache{}
+	a.GetSizeInBytes()
+	a = nil
+	a.GetSizeInBytes()
+}
+
+func TestActionsCache_GetVersion(tt *testing.T) {
+	var zeroValue string
+	a := &ActionsCache{Version: &zeroValue}
+	a.GetVersion()
+	a = &ActionsCache{}
+	a.GetVersion()
+	a = nil
+	a.GetVersion()
+}
+
+func TestActionsCacheListOptions_GetDirection(tt *testing.T) {
+	var zeroValue string
+	a := &ActionsCacheListOptions{Direction: &zeroValue}
+	a.GetDirection()
+	a = &ActionsCacheListOptions{}
+	a.GetDirection()
+	a = nil
+	a.GetDirection()
+}
+
+func TestActionsCacheListOptions_GetKey(tt *testing.T) {
+	var zeroValue string
+	a := &ActionsCacheListOptions{Key: &zeroValue}
+	a.GetKey()
+	a = &ActionsCacheListOptions{}
+	a.GetKey()
+	a = nil
+	a.GetKey()
+}
+
+func TestActionsCacheListOptions_GetRef(tt *testing.T) {
+	var zeroValue string
+	a := &ActionsCacheListOptions{Ref: &zeroValue}
+	a.GetRef()
+	a = &ActionsCacheListOptions{}
+	a.GetRef()
+	a = nil
+	a.GetRef()
+}
+
+func TestActionsCacheListOptions_GetSort(tt *testing.T) {
+	var zeroValue string
+	a := &ActionsCacheListOptions{Sort: &zeroValue}
+	a.GetSort()
+	a = &ActionsCacheListOptions{}
+	a.GetSort()
+	a = nil
+	a.GetSort()
+}
+
 func TestActionsPermissions_GetAllowedActions(tt *testing.T) {
 	var zeroValue string
 	a := &ActionsPermissions{AllowedActions: &zeroValue}
diff --git a/github/repos_environments_test.go b/github/repos_environments_test.go
index 93d0fc25..0b27da93 100644
--- a/github/repos_environments_test.go
+++ b/github/repos_environments_test.go
@@ -220,6 +220,110 @@ func TestRepositoriesService_CreateEnvironment(t *testing.T) {
 	})
 }
 
+func TestRepositoriesService_CreateEnvironment_noEnterprise(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	input := &CreateUpdateEnvironment{}
+	callCount := 0
+
+	mux.HandleFunc("/repos/o/r/environments/e", func(w http.ResponseWriter, r *http.Request) {
+		v := new(CreateUpdateEnvironment)
+		json.NewDecoder(r.Body).Decode(v)
+
+		testMethod(t, r, "PUT")
+		if callCount == 0 {
+			w.WriteHeader(http.StatusUnprocessableEntity)
+			callCount++
+		} else {
+			want := &CreateUpdateEnvironment{}
+			if !cmp.Equal(v, want) {
+				t.Errorf("Request body = %+v, want %+v", v, want)
+			}
+			fmt.Fprint(w, `{"id": 1, "name": "staging",	"protection_rules": []}`)
+		}
+	})
+
+	ctx := context.Background()
+	release, _, err := client.Repositories.CreateUpdateEnvironment(ctx, "o", "r", "e", input)
+	if err != nil {
+		t.Errorf("Repositories.CreateUpdateEnvironment returned error: %v", err)
+	}
+
+	want := &Environment{ID: Int64(1), Name: String("staging"), ProtectionRules: []*ProtectionRule{}}
+	if !cmp.Equal(release, want) {
+		t.Errorf("Repositories.CreateUpdateEnvironment returned %+v, want %+v", release, want)
+	}
+}
+
+func TestRepositoriesService_createNewEnvNoEnterprise(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	input := &CreateUpdateEnvironment{
+		DeploymentBranchPolicy: &BranchPolicy{
+			ProtectedBranches:    Bool(true),
+			CustomBranchPolicies: Bool(false),
+		},
+	}
+
+	mux.HandleFunc("/repos/o/r/environments/e", func(w http.ResponseWriter, r *http.Request) {
+		v := new(createUpdateEnvironmentNoEnterprise)
+		json.NewDecoder(r.Body).Decode(v)
+
+		testMethod(t, r, "PUT")
+		want := &createUpdateEnvironmentNoEnterprise{
+			DeploymentBranchPolicy: &BranchPolicy{
+				ProtectedBranches:    Bool(true),
+				CustomBranchPolicies: Bool(false),
+			},
+		}
+		if !cmp.Equal(v, want) {
+			t.Errorf("Request body = %+v, want %+v", v, want)
+		}
+		fmt.Fprint(w, `{"id": 1, "name": "staging",	"protection_rules": [{"id": 1, "node_id": "id", "type": "branch_policy"}], "deployment_branch_policy": {"protected_branches": true, "custom_branch_policies": false}}`)
+	})
+
+	ctx := context.Background()
+	release, _, err := client.Repositories.createNewEnvNoEnterprise(ctx, "repos/o/r/environments/e", input)
+	if err != nil {
+		t.Errorf("Repositories.createNewEnvNoEnterprise returned error: %v", err)
+	}
+
+	want := &Environment{
+		ID:   Int64(1),
+		Name: String("staging"),
+		ProtectionRules: []*ProtectionRule{
+			{
+				ID:     Int64(1),
+				NodeID: String("id"),
+				Type:   String("branch_policy"),
+			},
+		},
+		DeploymentBranchPolicy: &BranchPolicy{
+			ProtectedBranches:    Bool(true),
+			CustomBranchPolicies: Bool(false),
+		},
+	}
+	if !cmp.Equal(release, want) {
+		t.Errorf("Repositories.createNewEnvNoEnterprise returned %+v, want %+v", release, want)
+	}
+
+	const methodName = "createNewEnvNoEnterprise"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Repositories.createNewEnvNoEnterprise(ctx, "\n", input)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Repositories.createNewEnvNoEnterprise(ctx, "repos/o/r/environments/e", input)
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
+
 func TestRepositoriesService_DeleteEnvironment(t *testing.T) {
 	client, mux, _, teardown := setup()
 	defer teardown()
diff --git a/scrape/apps_test.go b/scrape/apps_test.go
index 97265629..6750f807 100644
--- a/scrape/apps_test.go
+++ b/scrape/apps_test.go
@@ -5,7 +5,7 @@ import (
 	"testing"
 
 	"github.com/google/go-cmp/cmp"
-	"github.com/google/go-github/v48/github"
+	"github.com/google/go-github/v49/github"
 )
 
 func Test_AppRestrictionsEnabled(t *testing.T) {
diff --git a/test/fields/fields.go b/test/fields/fields.go
index 3d42b7c4..61e422f7 100644
--- a/test/fields/fields.go
+++ b/test/fields/fields.go
@@ -25,7 +25,7 @@ import (
 	"reflect"
 	"strings"
 
-	"github.com/google/go-github/v48/github"
+	"github.com/google/go-github/v49/github"
 	"golang.org/x/oauth2"
 )
 
diff --git a/test/integration/activity_test.go b/test/integration/activity_test.go
index 5d2f231b..c89cf248 100644
--- a/test/integration/activity_test.go
+++ b/test/integration/activity_test.go
@@ -12,7 +12,7 @@ import (
 	"context"
 	"testing"
 
-	"github.com/google/go-github/v48/github"
+	"github.com/google/go-github/v49/github"
 )
 
 const (
diff --git a/test/integration/authorizations_test.go b/test/integration/authorizations_test.go
index 50d38e0c..b2b313f8 100644
--- a/test/integration/authorizations_test.go
+++ b/test/integration/authorizations_test.go
@@ -17,7 +17,7 @@ import (
 	"testing"
 	"time"
 
-	"github.com/google/go-github/v48/github"
+	"github.com/google/go-github/v49/github"
 )
 
 const msgEnvMissing = "Skipping test because the required environment variable (%v) is not present."
diff --git a/test/integration/github_test.go b/test/integration/github_test.go
index aabada85..b65f9626 100644
--- a/test/integration/github_test.go
+++ b/test/integration/github_test.go
@@ -15,7 +15,7 @@ import (
 	"net/http"
 	"os"
 
-	"github.com/google/go-github/v48/github"
+	"github.com/google/go-github/v49/github"
 	"golang.org/x/oauth2"
 )
 
diff --git a/test/integration/repos_test.go b/test/integration/repos_test.go
index 49ff98f0..e4ccfce2 100644
--- a/test/integration/repos_test.go
+++ b/test/integration/repos_test.go
@@ -15,7 +15,7 @@ import (
 	"testing"
 
 	"github.com/google/go-cmp/cmp"
-	"github.com/google/go-github/v48/github"
+	"github.com/google/go-github/v49/github"
 )
 
 func TestRepositories_CRUD(t *testing.T) {
diff --git a/test/integration/users_test.go b/test/integration/users_test.go
index cd7797b6..0be9cce2 100644
--- a/test/integration/users_test.go
+++ b/test/integration/users_test.go
@@ -14,7 +14,7 @@ import (
 	"math/rand"
 	"testing"
 
-	"github.com/google/go-github/v48/github"
+	"github.com/google/go-github/v49/github"
 )
 
 func TestUsers_Get(t *testing.T) {