Conversation
✅ Deploy Preview for olmv1 ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #2100 +/- ##
==========================================
- Coverage 67.97% 67.01% -0.96%
==========================================
Files 144 147 +3
Lines 10573 11118 +545
==========================================
+ Hits 7187 7451 +264
- Misses 2866 3122 +256
- Partials 520 545 +25
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
closing this as stale - please reopen if needed |
c7edbd2 to
559b18f
Compare
There was a problem hiding this comment.
Pull Request Overview
This pull request refactors the catalogd storage layer to introduce GraphQL support for querying catalog data. The changes extract HTTP handler logic into a separate server package, introduce a service layer for GraphQL schema management with caching, and replace direct struct initialization with a constructor pattern for LocalDirV1.
- Introduces a new GraphQL endpoint at
/api/v1/graphqlwith dynamic schema generation - Refactors HTTP handlers into a dedicated
serverpackage with cleaner separation of concerns - Adds a GraphQL service layer with schema caching to improve performance
- Updates
LocalDirV1to use a constructor pattern (NewLocalDirV1) for proper initialization
Reviewed Changes
Copilot reviewed 13 out of 14 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| internal/catalogd/storage/localdir.go | Refactored to use constructor pattern, added GraphQL service integration, moved HTTP handlers to server package |
| internal/catalogd/storage/localdir_test.go | Updated all test instantiations to use new NewLocalDirV1 constructor |
| internal/catalogd/storage/http_preconditions_check.go | Removed (moved to server package with simplified implementation) |
| internal/catalogd/server/handlers.go | New file implementing HTTP handlers extracted from storage layer |
| internal/catalogd/server/http_helpers.go | New file with simplified HTTP precondition checking |
| internal/catalogd/service/graphql_service.go | New GraphQL service with caching for schema generation |
| internal/catalogd/graphql/graphql.go | New dynamic GraphQL schema generation implementation |
| internal/catalogd/graphql/graphql_test.go | Tests for GraphQL schema discovery |
| internal/catalogd/graphql/discovery_test.go | Additional comprehensive tests for schema discovery edge cases |
| internal/catalogd/graphql/sample-queries.txt | Documentation of sample GraphQL queries |
| internal/catalogd/graphql/README.md | Documentation for GraphQL integration |
| cmd/catalogd/main.go | Updated to use NewLocalDirV1 constructor |
| go.mod, go.sum | Added graphql-go/graphql dependency |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
b9a05a8 to
58fbad3
Compare
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 15 out of 16 changed files in this pull request and generated 12 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
closing as stale |
346cf0d to
61a60be
Compare
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 18 out of 19 changed files in this pull request and generated 7 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| features: | ||
| enabled: | ||
| - APIV1MetasHandler | ||
| - GraphQLCatalogQueries |
2752f1f to
e358467
Compare
e358467 to
0d2d4e4
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 19 out of 20 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (2)
internal/shared/util/tlsprofiles/mozilla_data.go:17
internal/shared/util/tlsprofiles/mozilla_data.goappears to have been truncated to ~17 lines (missing closing braces and theintermediateTLSProfile/oldTLSProfiledefinitions). This will not compile and also breaks TLS profile selection at runtime. Re-runhack/tools/update-tls-profiles.sh(and ensure the generated file is fully committed and gofmt’d) so all profiles are present and themodernTLSProfileliteral is complete.
import (
"crypto/tls"
)
var modernTLSProfile = tlsProfile{
ciphers: cipherSlice{
cipherNums: []uint16{
tls.TLS_AES_128_GCM_SHA256,
tls.TLS_AES_256_GCM_SHA384,
tls.TLS_CHACHA20_POLY1305_SHA256,
internal/catalogd/storage/localdir_test.go:252
- The new
/api/v1/graphqlHTTP route isn’t covered by the existing storage/server handler tests (e.g.,TestLocalDirServerHandlerandTestMetasEndpointcover/alland/metasonly). Add an HTTP-level test that exercises the GraphQL endpoint (method handling, invalid body/query, and a basic successful query) to prevent regressions in request parsing and wiring.
func TestLocalDirServerHandler(t *testing.T) {
store := NewLocalDirV1(t.TempDir(), &url.URL{Path: urlPrefix}, MetasHandlerDisabled, GraphQLQueriesDisabled)
if store.Store(context.Background(), "test-catalog", createTestFS(t)) != nil {
t.Fatal("failed to store test catalog and start server")
}
testServer := httptest.NewServer(store.StorageServerHandler())
defer testServer.Close()
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
0d2d4e4 to
711c9d8
Compare
711c9d8 to
888a0d6
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 17 out of 19 changed files in this pull request and generated 7 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
888a0d6 to
2fddf00
Compare
Signed-off-by: grokspawn <jordan@nimblewidget.com>
Signed-off-by: grokspawn <jordan@nimblewidget.com>
2fddf00 to
7e3fb82
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 17 out of 18 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (1)
internal/catalogd/storage/localdir.go:1
- Typo in comment:
slightflightshould besingleflight.
package storage
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
7e3fb82 to
67d2d10
Compare
67d2d10 to
cd55ca7
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 19 out of 20 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| The GraphQL endpoint is now available as part of the catalogd storage server at: | ||
|
|
||
| ``` | ||
| {catalog}/api/v1/graphql | ||
| ``` | ||
|
|
||
| Where `{catalog}` is replaced by the actual catalog name at runtime. | ||
|
|
||
| ## Example Usage | ||
|
|
||
| ### Making a GraphQL Request | ||
|
|
||
| ```bash | ||
| curl -X POST http://localhost:8080/my-catalog/api/v1/graphql \ | ||
| -H "Content-Type: application/json" \ |
There was a problem hiding this comment.
The README’s endpoint examples omit the /catalogs/ prefix used by catalogd (e.g. https://.../catalogs/<catalog>/api/v1/graphql), which can mislead users trying to hit the endpoint. Please update the documented URL and curl example to match the actual route registered by CatalogHandlers.
| // CachedGraphQLService implements GraphQLService with an in-memory schema cache | ||
| type CachedGraphQLService struct { | ||
| schemaMux sync.RWMutex | ||
| schemaCache map[string]*gql.DynamicSchema | ||
| buildGroup singleflight.Group // Prevents duplicate concurrent schema builds | ||
| } | ||
|
|
||
| // NewCachedGraphQLService creates a new GraphQL service with caching | ||
| func NewCachedGraphQLService() *CachedGraphQLService { | ||
| return &CachedGraphQLService{ | ||
| schemaCache: make(map[string]*gql.DynamicSchema), | ||
| } | ||
| } | ||
|
|
||
| // GetSchema returns the GraphQL schema for a catalog, using cache if available | ||
| func (s *CachedGraphQLService) GetSchema(catalog string, catalogFS fs.FS) (*gql.DynamicSchema, error) { | ||
| // Check cache first (read lock) | ||
| s.schemaMux.RLock() | ||
| if cachedSchema, ok := s.schemaCache[catalog]; ok { | ||
| s.schemaMux.RUnlock() | ||
| return cachedSchema, nil | ||
| } | ||
| s.schemaMux.RUnlock() | ||
|
|
||
| // Use singleflight to prevent duplicate concurrent builds for the same catalog | ||
| result, err, _ := s.buildGroup.Do(catalog, func() (interface{}, error) { | ||
| // Double-check cache after acquiring singleflight lock | ||
| s.schemaMux.RLock() | ||
| if cachedSchema, ok := s.schemaCache[catalog]; ok { | ||
| s.schemaMux.RUnlock() | ||
| return cachedSchema, nil | ||
| } | ||
| s.schemaMux.RUnlock() | ||
|
|
||
| // Schema not in cache, build it | ||
| dynamicSchema, err := buildSchemaFromFS(catalogFS) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| // Cache the result (write lock) | ||
| s.schemaMux.Lock() | ||
| s.schemaCache[catalog] = dynamicSchema | ||
| s.schemaMux.Unlock() | ||
|
|
||
| return dynamicSchema, nil | ||
| }) | ||
|
|
||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| return result.(*gql.DynamicSchema), nil | ||
| } | ||
|
|
||
| // ExecuteQuery executes a GraphQL query against a catalog | ||
| func (s *CachedGraphQLService) ExecuteQuery(catalog string, catalogFS fs.FS, query string) (*graphql.Result, error) { | ||
| // Get or build the schema (uses cache and singleflight) | ||
| dynamicSchema, err := s.GetSchema(catalog, catalogFS) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("failed to get GraphQL schema: %w", err) | ||
| } | ||
|
|
||
| // Execute the query | ||
| result := graphql.Do(graphql.Params{ | ||
| Schema: dynamicSchema.Schema, | ||
| RequestString: query, | ||
| }) | ||
|
|
||
| return result, nil | ||
| } | ||
|
|
||
| // InvalidateCache removes the cached schema for a catalog | ||
| func (s *CachedGraphQLService) InvalidateCache(catalog string) { | ||
| s.schemaMux.Lock() | ||
| delete(s.schemaCache, catalog) | ||
| s.schemaMux.Unlock() | ||
| } |
There was a problem hiding this comment.
New caching/singleflight behavior in CachedGraphQLService (schema cache hits, invalidation, and concurrent build de-duplication) is not covered by tests. Adding focused unit tests would help prevent regressions (e.g., cache reuse across calls, InvalidateCache behavior, and only-one-build under concurrency).
| httpError(w, err) | ||
| return | ||
| } | ||
| catalogDir := s.catalogDir(catalog) |
There was a problem hiding this comment.
GetCatalogFS returns os.DirFS(catalogDir) without checking that catalogDir exists. For a nonexistent catalog, this returns nil error and later GraphQL execution will likely surface a non-fs.ErrNotExist error, producing a 500 instead of a 404. Consider os.Stat(catalogDir) (or the expected file within it) and returning fs.ErrNotExist when missing so the HTTP layer maps it to 404.
| catalogDir := s.catalogDir(catalog) | |
| catalogDir := s.catalogDir(catalog) | |
| info, err := os.Stat(catalogDir) | |
| if err != nil { | |
| if errors.Is(err, os.ErrNotExist) { | |
| return nil, fs.ErrNotExist | |
| } | |
| return nil, err | |
| } | |
| if !info.IsDir() { | |
| return nil, fmt.Errorf("catalog path %q is not a directory", catalogDir) | |
| } |
cd55ca7 to
12549ed
Compare
Signed-off-by: Jordan <jordan@nimblewidget.com>
12549ed to
a1b458e
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 19 out of 20 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| The GraphQL endpoint is now available as part of the catalogd storage server at: | ||
|
|
||
| ``` | ||
| {catalog}/api/v1/graphql | ||
| ``` | ||
|
|
||
| Where `{catalog}` is replaced by the actual catalog name at runtime. |
There was a problem hiding this comment.
The endpoint path shown here (and in the curl example below) omits the "/catalogs/" prefix used by catalogd’s storage server (baseStorageURL is ".../catalogs/"). To prevent confusion, update the examples to use the full path, e.g. "/catalogs//api/v1/graphql" (and the correct scheme/port per the deployment docs).
Description
Reviewer Checklist