Skip to content

Commit 6d866d1

Browse files
authored
feat: Add support for conditional requests via local cache (#17368)
<!-- 🎉 Thank you for making CloudQuery awesome by submitting a PR 🎉 --> #### Summary Implements https://github.com/google/go-github?tab=readme-ov-file#conditional-requests Tested it and indeed saw some requests returned from the cache and not counting towards the limit <!-- Use the following steps to ensure your PR is ready to be reviewed - [ ] Read the [contribution guidelines](https://github.com/cloudquery/cloudquery/blob/main/CONTRIBUTING.md) 🧑‍🎓 - [ ] Run `make lint` to ensure the proposed changes follow the coding style 🚨 (install golangci-lint [here](https://golangci-lint.run/usage/install/#local-installation)) - [ ] Run `make test` to ensure the proposed changes pass the tests 🧪 - [ ] If changing a source plugin run `make gen` to ensure docs are up to date 📝 - [ ] Ensure the status checks below are successful ✅ --->
1 parent 0d7c975 commit 6d866d1

7 files changed

Lines changed: 45 additions & 3 deletions

File tree

plugins/source/github/client/client.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010
"time"
1111

1212
"github.com/bradleyfalzon/ghinstallation/v2"
13+
"github.com/cloudquery/httpcache"
14+
"github.com/cloudquery/httpcache/diskcache"
1315
"github.com/cloudquery/plugin-sdk/v4/schema"
1416
"github.com/gofri/go-github-ratelimit/github_ratelimit"
1517
"github.com/google/go-github/v59/github"
@@ -91,10 +93,15 @@ func New(ctx context.Context, logger zerolog.Logger, spec Spec) (schema.ClientMe
9193
if err != nil {
9294
return nil, fmt.Errorf("failed to parse InstallationID %v: %w", auth.InstallationID, err)
9395
}
96+
transport := http.DefaultTransport
97+
if spec.LocalCachePath != "" {
98+
cache := diskcache.New(spec.LocalCachePath)
99+
transport = httpcache.NewTransport(cache)
100+
}
94101
if auth.PrivateKeyPath != "" {
95-
itr, err = ghinstallation.NewKeyFromFile(http.DefaultTransport, appId, installationId, auth.PrivateKeyPath)
102+
itr, err = ghinstallation.NewKeyFromFile(transport, appId, installationId, auth.PrivateKeyPath)
96103
} else {
97-
itr, err = ghinstallation.New(http.DefaultTransport, appId, installationId, []byte(auth.PrivateKey))
104+
itr, err = ghinstallation.New(transport, appId, installationId, []byte(auth.PrivateKey))
98105
}
99106
if err != nil {
100107
return nil, fmt.Errorf("failed to create GitHub client for org %v: %w", auth.Org, err)
@@ -111,7 +118,12 @@ func New(ctx context.Context, logger zerolog.Logger, spec Spec) (schema.ClientMe
111118

112119
var defaultServices GithubServices
113120
if spec.AccessToken != "" {
114-
httpClient := github.NewClient(nil).WithAuthToken(spec.AccessToken)
121+
var cl *http.Client
122+
if spec.LocalCachePath != "" {
123+
cache := diskcache.New(spec.LocalCachePath)
124+
cl = httpcache.NewTransport(cache).Client()
125+
}
126+
httpClient := github.NewClient(cl).WithAuthToken(spec.AccessToken)
115127
ghc, err := githubClientForHTTPClient(httpClient.Client().Transport, logger, spec.EnterpriseSettings)
116128
if err != nil {
117129
return nil, fmt.Errorf("failed to create GitHub client for access token: %w", err)

plugins/source/github/client/schema.json

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plugins/source/github/client/spec.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package client
33
import (
44
_ "embed"
55
"fmt"
6+
"os"
67

78
"github.com/invopop/jsonschema"
89
)
@@ -25,6 +26,8 @@ type Spec struct {
2526
DiscoveryConcurrency int `json:"discovery_concurrency,omitempty" jsonschema:"default=1"`
2627
// Include archived repositories when discovering repositories.
2728
IncludeArchivedRepos bool `json:"include_archived_repos,omitempty"`
29+
// Path to a local directory that will hold the cache. If set, the plugin will cache the GitHub API responses in this directory. Defaults to an empty string (no cache)
30+
LocalCachePath string `json:"local_cache_path,omitempty"`
2831
}
2932

3033
type EnterpriseSettings struct {
@@ -87,6 +90,15 @@ func (s *Spec) Validate() error {
8790
return err
8891
}
8992
}
93+
if s.LocalCachePath != "" {
94+
fileInfo, err := os.Stat(s.LocalCachePath)
95+
if err != nil && !os.IsNotExist(err) {
96+
return fmt.Errorf("error accessing local cache path: %w", err)
97+
}
98+
if fileInfo != nil && !fileInfo.IsDir() {
99+
return fmt.Errorf("local cache path is not a directory")
100+
}
101+
}
90102
return nil
91103
}
92104

plugins/source/github/docs/_configuration.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ spec:
3838
# concurrency: 1500 # Optional. The best effort maximum number of Go routines to use. Lower this number to reduce memory usage or to avoid hitting GitHub API rate limits. Default 1500.
3939
# discovery_concurrency: 1 # Optional. Number of concurrent requests to GitHub API during discovery phase. Default 1.
4040
# include_archived_repos: false # Optional. Include archived repositories in the sync. Default false.
41+
# local_cache_path: "" # Optional. Path to a local directory that will hold the cache. If set, the plugin will cache the GitHub API responses in this directory. Defaults to an empty string (no cache).
4142
```
4243

4344
See [tables](/docs/plugins/sources/github/tables) for a full list of available tables.

plugins/source/github/docs/overview.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,7 @@ This is the (nested) spec used by GitHub Source Plugin
4141
- `include_archived_repos` (`bool`) (default: `false`)
4242

4343
By default archived repositories are not included in the sync. To include archived repositories set `include_archived_repos` to `true`.
44+
45+
- `local_cache_path` (`string`, optional, default: empty):
46+
Path to a local directory that will hold the cache. If set, the plugin will cache the GitHub API responses in this directory. Defaults to an empty string (no cache).
47+
By using a cache, the plugin can use [conditional requests when appropriate](https://docs.github.com/en/rest/using-the-rest-api/best-practices-for-using-the-rest-api?#use-conditional-requests-if-appropriate), and help avoid hitting GitHub API rate limits.

plugins/source/github/go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ require (
66
github.com/apache/arrow/go/v15 v15.0.0-20240114144300-7e703aae55c1
77
github.com/bradleyfalzon/ghinstallation/v2 v2.9.0
88
github.com/cloudquery/codegen v0.3.13
9+
github.com/cloudquery/httpcache v0.0.0-20240402185306-9cae36e50fd1
910
github.com/cloudquery/plugin-sdk/v4 v4.36.3
1011
github.com/ghodss/yaml v1.0.0
1112
github.com/gofri/go-github-ratelimit v1.0.3
@@ -54,6 +55,7 @@ require (
5455
github.com/golang/protobuf v1.5.3 // indirect
5556
github.com/golang/snappy v0.0.4 // indirect
5657
github.com/gomarkdown/markdown v0.0.0-20231222211730-1d6d20845b47 // indirect
58+
github.com/google/btree v1.1.2 // indirect
5759
github.com/google/flatbuffers v23.5.26+incompatible // indirect
5860
github.com/google/go-github/v57 v57.0.0 // indirect
5961
github.com/google/go-querystring v1.1.0 // indirect
@@ -86,6 +88,7 @@ require (
8688
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
8789
github.com/modern-go/reflect2 v1.0.2 // indirect
8890
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
91+
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
8992
github.com/pierrec/lz4/v4 v4.1.21 // indirect
9093
github.com/pmezard/go-difflib v1.0.0 // indirect
9194
github.com/russross/blackfriday/v2 v2.1.0 // indirect

plugins/source/github/go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ github.com/cloudquery/cloudquery-api-go v1.9.0 h1:yjy/Hrma6/1JdtGYE59xMtH+xAsaGL
5151
github.com/cloudquery/cloudquery-api-go v1.9.0/go.mod h1:F4kuaNBAVqsS9ZRHuX+tV2m6+Khoa2Rb9lROGhinGPk=
5252
github.com/cloudquery/codegen v0.3.13 h1:ZQZhaN/xXyr8qBhIlyPuTyncssI8JqsKwIQamWxIAPM=
5353
github.com/cloudquery/codegen v0.3.13/go.mod h1:gF9EOua45yxt5n5Zc8NrZ63HT6rGc6wDCV+Apc9d0Mg=
54+
github.com/cloudquery/httpcache v0.0.0-20240402185306-9cae36e50fd1 h1:KFXFLIF3t1KPAZJe1TmM/ro9T1PfD+hkuLonCurwwcU=
55+
github.com/cloudquery/httpcache v0.0.0-20240402185306-9cae36e50fd1/go.mod h1:0wYLAQ8f+qoGzvTQghj43oLHKmov4NtURVrW1pLI9kA=
5456
github.com/cloudquery/jsonschema v0.0.0-20240220124159-92878faa2a66 h1:OZLPSIBYEfvkAUeOeM8CwTgVQy5zhayI99ishCrsFV0=
5557
github.com/cloudquery/jsonschema v0.0.0-20240220124159-92878faa2a66/go.mod h1:0SoZ/U7yJlNOR+fWsBSeTvTbGXB6DK01tzJ7m2Xfg34=
5658
github.com/cloudquery/plugin-pb-go v1.19.7 h1:9AfnIIFRFTuo0CMP0SCbMGWfDQ0I6C9m/jrglWcqDzA=
@@ -115,6 +117,8 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
115117
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
116118
github.com/gomarkdown/markdown v0.0.0-20231222211730-1d6d20845b47 h1:k4Tw0nt6lwro3Uin8eqoET7MDA4JnT8YgbCjc/g5E3k=
117119
github.com/gomarkdown/markdown v0.0.0-20231222211730-1d6d20845b47/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
120+
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
121+
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
118122
github.com/google/flatbuffers v23.5.26+incompatible h1:M9dgRyhJemaM4Sw8+66GHBu8ioaQmyPLg1b8VwK5WJg=
119123
github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
120124
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@@ -209,6 +213,8 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY
209213
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
210214
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
211215
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
216+
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
217+
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
212218
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
213219
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
214220
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=

0 commit comments

Comments
 (0)