Skip to content

Commit c98f366

Browse files
Thomas StrombergThomas Stromberg
authored andcommitted
upgrade go mods
1 parent f65fe88 commit c98f366

File tree

11 files changed

+268
-62
lines changed

11 files changed

+268
-62
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ client := prx.NewClient(token, prx.WithCacheStore(store))
231231
To disable caching persistence (memory-only):
232232

233233
```go
234-
import "github.com/codeGROOVE-dev/sfcache/pkg/store/null"
234+
import "github.com/codeGROOVE-dev/fido/pkg/store/null"
235235

236236
client := prx.NewClient(token, prx.WithCacheStore(null.New[string, prx.PullRequestData]()))
237237
```

cmd/prx/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ import (
1616
"strings"
1717
"time"
1818

19+
"github.com/codeGROOVE-dev/fido/pkg/store/null"
1920
"github.com/codeGROOVE-dev/prx/pkg/prx"
20-
"github.com/codeGROOVE-dev/sfcache/pkg/store/null"
2121
)
2222

2323
const (

go.mod

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,14 @@ module github.com/codeGROOVE-dev/prx
33
go 1.25.4
44

55
require (
6-
github.com/codeGROOVE-dev/retry v1.3.0
7-
github.com/codeGROOVE-dev/sfcache v1.4.0
6+
github.com/codeGROOVE-dev/fido v1.10.0
7+
github.com/codeGROOVE-dev/fido/pkg/store/localfs v1.10.0
8+
github.com/codeGROOVE-dev/fido/pkg/store/null v1.10.0
9+
github.com/codeGROOVE-dev/retry v1.3.1
810
)
911

10-
require github.com/codeGROOVE-dev/sfcache/pkg/store/localfs v1.4.0
12+
require (
13+
github.com/codeGROOVE-dev/fido/pkg/store/compress v1.10.0 // indirect
14+
github.com/klauspost/compress v1.18.2 // indirect
15+
github.com/puzpuzpuz/xsync/v4 v4.2.0 // indirect
16+
)

go.sum

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
1-
github.com/codeGROOVE-dev/retry v1.3.0 h1:/+ipAWRJLL6y1R1vprYo0FSjSBvH6fE5j9LKXjpD54g=
2-
github.com/codeGROOVE-dev/retry v1.3.0/go.mod h1:8OgefgV1XP7lzX2PdKlCXILsYKuz6b4ZpHa/20iLi8E=
3-
github.com/codeGROOVE-dev/sfcache v1.4.0 h1:F00PqIYuenn/t2uK72MJ2zUCrrhW8WC5xaV+C16VNE4=
4-
github.com/codeGROOVE-dev/sfcache v1.4.0/go.mod h1:ksV5Y1RwKmOPZZiV0zXpsBOENGUCgO0fVgr/P8f/DJM=
5-
github.com/codeGROOVE-dev/sfcache/pkg/store/localfs v1.4.0 h1:oyHwsawHd9kUFdAuXSCKYiEQTXuHAVd4y7cdBatjsLY=
6-
github.com/codeGROOVE-dev/sfcache/pkg/store/localfs v1.4.0/go.mod h1:D/Y1sYT1m3VXHZRkQjHjFwtKQOsb587QZP/GtfJEDSE=
1+
github.com/codeGROOVE-dev/fido v1.10.0 h1:i4Wb6LDd5nD/4Fnp47KAVUVhG1O1mN5jSRbCYPpBYjw=
2+
github.com/codeGROOVE-dev/fido v1.10.0/go.mod h1:/mqfMeKCTYTGt/Y0cWm6gh8gYBKG1w8xBsTDmu+A/pU=
3+
github.com/codeGROOVE-dev/fido/pkg/store/compress v1.10.0 h1:W3AYtR6eyPHQ8QhTsuqjNZYWk/Fev0cJiAiuw04uhlk=
4+
github.com/codeGROOVE-dev/fido/pkg/store/compress v1.10.0/go.mod h1:0hFYQ8Y6jfrYuJb8eBimYz66tg7DDuVWbZqaI944LQM=
5+
github.com/codeGROOVE-dev/fido/pkg/store/localfs v1.10.0 h1:oaPwuHHBuzhsWnPm7UCxgwjz7+jG3O0JenSSgPSwqv8=
6+
github.com/codeGROOVE-dev/fido/pkg/store/localfs v1.10.0/go.mod h1:zUGzODSWykosAod0IHycxdxUOMcd2eVqd6eUdOsU73E=
7+
github.com/codeGROOVE-dev/fido/pkg/store/null v1.10.0 h1:3F6absPj3zUaPsK7ohTTlwOXZ2XAr+/TudIPCYPamsw=
8+
github.com/codeGROOVE-dev/fido/pkg/store/null v1.10.0/go.mod h1:mvPXZ0lHnaQuxkSozpmWf2ZKL5bzKe/IIGFLlcQH/F4=
9+
github.com/codeGROOVE-dev/retry v1.3.1 h1:BAkfDzs6FssxLCGWGgM97bb+6/8GTa40Cs147vXkJOg=
10+
github.com/codeGROOVE-dev/retry v1.3.1/go.mod h1:+b3huqYGY1+ZJyuCmR8nBVLjd3WJ7qAFss+sI4s6FSc=
11+
github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk=
12+
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
13+
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
14+
github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
15+
github.com/puzpuzpuz/xsync/v4 v4.2.0 h1:dlxm77dZj2c3rxq0/XNvvUKISAmovoXF4a4qM6Wvkr0=
16+
github.com/puzpuzpuz/xsync/v4 v4.2.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSfNKu5bLYFQo=

pkg/prx/client.go

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ import (
1717
"strings"
1818
"time"
1919

20+
"github.com/codeGROOVE-dev/fido"
21+
"github.com/codeGROOVE-dev/fido/pkg/store/localfs"
2022
"github.com/codeGROOVE-dev/prx/pkg/prx/github"
21-
"github.com/codeGROOVE-dev/sfcache"
22-
"github.com/codeGROOVE-dev/sfcache/pkg/store/localfs"
2323
)
2424

2525
const (
@@ -29,20 +29,30 @@ const (
2929
idleConnTimeoutSec = 90
3030

3131
// Cache TTL constants.
32-
prCacheTTL = 20 * 24 * time.Hour // 20 days
33-
collaboratorsCacheTTL = 4 * time.Hour
32+
prCacheTTL = 20 * 24 * time.Hour // 20 days - validity checked against reference time
33+
checkRunsCacheTTL = 20 * 24 * time.Hour // 20 days - validity checked against reference time
34+
collaboratorsCacheTTL = 3 * time.Hour // 3 hours - repo-level, simple TTL
35+
rulesetsCacheTTL = 3 * time.Hour // 3 hours - repo-level, simple TTL
3436
)
3537

38+
// cachedCheckRuns stores check run events with a timestamp for cache validation.
39+
type cachedCheckRuns struct {
40+
CachedAt time.Time
41+
Events []Event
42+
}
43+
3644
// PRStore is the interface for PR cache storage backends.
37-
// This is an alias for sfcache.Store with the appropriate type parameters.
38-
type PRStore = sfcache.Store[string, PullRequestData]
45+
// This is an alias for fido.Store with the appropriate type parameters.
46+
type PRStore = fido.Store[string, PullRequestData]
3947

4048
// Client provides methods to fetch GitHub pull request events.
4149
type Client struct {
4250
github *github.Client
4351
logger *slog.Logger
44-
collaboratorsCache *sfcache.MemoryCache[string, map[string]string]
45-
prCache *sfcache.TieredCache[string, PullRequestData]
52+
collaboratorsCache *fido.Cache[string, map[string]string]
53+
rulesetsCache *fido.Cache[string, []string]
54+
checkRunsCache *fido.Cache[string, cachedCheckRuns]
55+
prCache *fido.TieredCache[string, PullRequestData]
4656
token string // Store token for recreating client with new transport
4757
}
4858

@@ -73,7 +83,7 @@ func WithHTTPClient(httpClient *http.Client) Option {
7383
// Use null.New[string, prx.PullRequestData]() to disable persistence.
7484
func WithCacheStore(store PRStore) Option {
7585
return func(c *Client) {
76-
prCache, err := sfcache.NewTiered(store, sfcache.TTL(prCacheTTL))
86+
prCache, err := fido.NewTiered(store, fido.TTL(prCacheTTL))
7787
if err != nil {
7888
c.logger.Warn("failed to create cache from store, using default", "error", err)
7989
return
@@ -97,7 +107,9 @@ func NewClient(token string, opts ...Option) *Client {
97107
c := &Client{
98108
logger: slog.Default(),
99109
token: token,
100-
collaboratorsCache: sfcache.New[string, map[string]string](sfcache.TTL(collaboratorsCacheTTL)),
110+
collaboratorsCache: fido.New[string, map[string]string](fido.TTL(collaboratorsCacheTTL)),
111+
rulesetsCache: fido.New[string, []string](fido.TTL(rulesetsCacheTTL)),
112+
checkRunsCache: fido.New[string, cachedCheckRuns](fido.TTL(checkRunsCacheTTL)),
101113
github: newGitHubClient(
102114
&http.Client{
103115
Transport: &github.Transport{Base: transport},
@@ -120,7 +132,7 @@ func NewClient(token string, opts ...Option) *Client {
120132
return c
121133
}
122134

123-
func createDefaultCache(log *slog.Logger) *sfcache.TieredCache[string, PullRequestData] {
135+
func createDefaultCache(log *slog.Logger) *fido.TieredCache[string, PullRequestData] {
124136
dir, err := os.UserCacheDir()
125137
if err != nil {
126138
dir = os.TempDir()
@@ -135,7 +147,7 @@ func createDefaultCache(log *slog.Logger) *sfcache.TieredCache[string, PullReque
135147
log.Warn("failed to create cache store, caching disabled", "error", err)
136148
return nil
137149
}
138-
cache, err := sfcache.NewTiered(store, sfcache.TTL(prCacheTTL))
150+
cache, err := fido.NewTiered(store, fido.TTL(prCacheTTL))
139151
if err != nil {
140152
log.Warn("failed to create cache, caching disabled", "error", err)
141153
return nil
@@ -156,7 +168,7 @@ func (c *Client) PullRequestWithReferenceTime(
156168
refTime time.Time,
157169
) (*PullRequestData, error) {
158170
if c.prCache == nil {
159-
return c.pullRequestViaGraphQL(ctx, owner, repo, pr)
171+
return c.pullRequestViaGraphQL(ctx, owner, repo, pr, refTime)
160172
}
161173

162174
key := prCacheKey(owner, repo, pr)
@@ -180,8 +192,8 @@ func (c *Client) PullRequestWithReferenceTime(
180192
"owner", owner, "repo", repo, "pr", pr)
181193
}
182194

183-
result, err := c.prCache.GetSet(ctx, key, func(ctx context.Context) (PullRequestData, error) {
184-
data, err := c.pullRequestViaGraphQL(ctx, owner, repo, pr)
195+
result, err := c.prCache.Fetch(ctx, key, func(ctx context.Context) (PullRequestData, error) {
196+
data, err := c.pullRequestViaGraphQL(ctx, owner, repo, pr, refTime)
185197
if err != nil {
186198
return PullRequestData{}, err
187199
}
@@ -230,3 +242,13 @@ func prCacheKey(owner, repo string, prNumber int) string {
230242
func collaboratorsCacheKey(owner, repo string) string {
231243
return fmt.Sprintf("%s/%s", owner, repo)
232244
}
245+
246+
// rulesetsCacheKey generates a cache key for rulesets data.
247+
func rulesetsCacheKey(owner, repo string) string {
248+
return fmt.Sprintf("%s/%s", owner, repo)
249+
}
250+
251+
// checkRunsCacheKey generates a cache key for check runs data.
252+
func checkRunsCacheKey(owner, repo, sha string) string {
253+
return fmt.Sprintf("%s/%s/%s", owner, repo, sha)
254+
}

pkg/prx/client_cache_test.go

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ func TestCacheClient(t *testing.T) {
124124
}
125125
afterSecondRequest := requestCount
126126

127-
// We expect zero API requests for cached call (sfcache handles persistence)
127+
// We expect zero API requests for cached call (fido handles persistence)
128128
if afterSecondRequest != beforeSecondRequest {
129129
t.Logf("Note: Got %d API requests for cached call (cache may need warming)", afterSecondRequest-beforeSecondRequest)
130130
}
@@ -191,3 +191,130 @@ func TestIsHexString(t *testing.T) {
191191
}
192192
}
193193
}
194+
195+
func TestRulesetsCacheKey(t *testing.T) {
196+
key1 := rulesetsCacheKey("owner", "repo")
197+
key2 := rulesetsCacheKey("owner", "repo")
198+
199+
if key1 != key2 {
200+
t.Errorf("Same inputs produced different keys: %s vs %s", key1, key2)
201+
}
202+
203+
key3 := rulesetsCacheKey("other", "repo")
204+
if key1 == key3 {
205+
t.Error("Different inputs produced same key")
206+
}
207+
208+
// Verify format
209+
expected := "owner/repo"
210+
if key1 != expected {
211+
t.Errorf("Expected key %q, got %q", expected, key1)
212+
}
213+
}
214+
215+
func TestRulesetsCache(t *testing.T) {
216+
// Track API calls to rulesets endpoint
217+
rulesetsAPICallCount := 0
218+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
219+
switch r.URL.Path {
220+
case "/graphql":
221+
response := `{"data": {"repository": {"pullRequest": {
222+
"number": 1,
223+
"title": "Test PR",
224+
"body": "Test body",
225+
"state": "OPEN",
226+
"isDraft": false,
227+
"createdAt": "2023-01-01T00:00:00Z",
228+
"updatedAt": "2023-01-01T01:00:00Z",
229+
"closedAt": null,
230+
"mergedAt": null,
231+
"mergedBy": null,
232+
"mergeable": "UNKNOWN",
233+
"mergeStateStatus": "UNKNOWN",
234+
"additions": 10,
235+
"deletions": 5,
236+
"changedFiles": 2,
237+
"author": {"login": "testuser"},
238+
"authorAssociation": "CONTRIBUTOR",
239+
"headRef": {"target": {"oid": "abc123"}},
240+
"baseRef": {"name": "main", "target": {"oid": "def456"}},
241+
"assignees": {"nodes": []},
242+
"labels": {"nodes": []},
243+
"reviews": {"nodes": []},
244+
"reviewRequests": {"nodes": []},
245+
"reviewThreads": {"nodes": []},
246+
"commits": {"nodes": []},
247+
"statusCheckRollup": null,
248+
"timelineItems": {"nodes": [], "pageInfo": {"hasNextPage": false}},
249+
"comments": {"nodes": []}
250+
}}}}`
251+
if _, err := w.Write([]byte(response)); err != nil {
252+
http.Error(w, err.Error(), http.StatusInternalServerError)
253+
return
254+
}
255+
case "/repos/test/repo/rulesets":
256+
rulesetsAPICallCount++
257+
// Return rulesets with a required check
258+
response := `[{"id": 1, "name": "main protection", "target": "branch", "rules": [{"type": "required_status_checks", "parameters": {"required_status_checks": [{"context": "ci/test"}]}}]}]`
259+
if _, err := w.Write([]byte(response)); err != nil {
260+
http.Error(w, err.Error(), http.StatusInternalServerError)
261+
return
262+
}
263+
case "/repos/test/repo/commits/abc123/check-runs":
264+
if _, err := w.Write([]byte(`{"check_runs": []}`)); err != nil {
265+
http.Error(w, err.Error(), http.StatusInternalServerError)
266+
return
267+
}
268+
default:
269+
if _, err := w.Write([]byte("[]")); err != nil {
270+
http.Error(w, err.Error(), http.StatusInternalServerError)
271+
return
272+
}
273+
}
274+
}))
275+
defer server.Close()
276+
277+
client := NewClient("test-token",
278+
WithHTTPClient(&http.Client{Transport: &http.Transport{}}),
279+
WithLogger(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelDebug}))),
280+
)
281+
client.github = newTestGitHubClient(&http.Client{Transport: &http.Transport{}}, "test-token", server.URL)
282+
defer func() {
283+
if err := client.Close(); err != nil {
284+
t.Errorf("Failed to close client: %v", err)
285+
}
286+
}()
287+
288+
ctx := context.Background()
289+
refTime := time.Now()
290+
291+
// First request - should call rulesets API
292+
_, err := client.pullRequestViaGraphQL(ctx, "test", "repo", 1, refTime)
293+
if err != nil {
294+
t.Fatalf("First request failed: %v", err)
295+
}
296+
297+
if rulesetsAPICallCount != 1 {
298+
t.Errorf("Expected 1 rulesets API call, got %d", rulesetsAPICallCount)
299+
}
300+
301+
// Second request - should use cached rulesets
302+
_, err = client.pullRequestViaGraphQL(ctx, "test", "repo", 1, refTime)
303+
if err != nil {
304+
t.Fatalf("Second request failed: %v", err)
305+
}
306+
307+
if rulesetsAPICallCount != 1 {
308+
t.Errorf("Expected rulesets to be cached (still 1 API call), got %d", rulesetsAPICallCount)
309+
}
310+
311+
// Third request for same repo - should still use cache
312+
_, err = client.pullRequestViaGraphQL(ctx, "test", "repo", 2, refTime)
313+
if err != nil {
314+
t.Fatalf("Third request failed: %v", err)
315+
}
316+
317+
if rulesetsAPICallCount != 1 {
318+
t.Errorf("Expected rulesets cache to be used across PRs in same repo, got %d API calls", rulesetsAPICallCount)
319+
}
320+
}

0 commit comments

Comments
 (0)