-
-
Notifications
You must be signed in to change notification settings - Fork 205
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(config): add api config for branching override (#2761)
* feat: add remote utils for api config * chore: split api and remote api * Revert "chore: split api and remote api" This reverts commit 23173ec. * chore: make api public * Revert "Revert "chore: split api and remote api"" This reverts commit 65bc6d3. * chore: handle api enable * chore: make convert whitespace resilient * feat: add some errors handling for remotes config * chore: move diff into own package * chore: add some diff tests * chore: fix golint casting lints * Update internal/utils/cast/cast.go Co-authored-by: Han Qiao <[email protected]> * chore: use Errorf remote config error * chore: move diff and cast to pkg * chore: minor refactor * feat: implement remote config updater * chore: minor style changes * chore: refactor duplicate project ref check to getter * chore: update error message for consistency * chore: validate duplicate remote early --------- Co-authored-by: Han Qiao <[email protected]> Co-authored-by: Qiao Han <[email protected]>
- Loading branch information
1 parent
fe0097e
commit c7bdbc2
Showing
9 changed files
with
442 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package cast | ||
|
||
import "math" | ||
|
||
// UintToInt converts a uint to an int, handling potential overflow | ||
func UintToInt(value uint) int { | ||
if value <= math.MaxInt { | ||
result := int(value) | ||
return result | ||
} | ||
maxInt := math.MaxInt | ||
return maxInt | ||
} | ||
|
||
// IntToUint converts an int to a uint, handling negative values | ||
func IntToUint(value int) uint { | ||
if value < 0 { | ||
return 0 | ||
} | ||
return uint(value) | ||
} | ||
|
||
func Ptr[T any](v T) *T { | ||
return &v | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package config | ||
|
||
import ( | ||
"strings" | ||
|
||
v1API "github.com/supabase/cli/pkg/api" | ||
"github.com/supabase/cli/pkg/cast" | ||
"github.com/supabase/cli/pkg/diff" | ||
) | ||
|
||
type ( | ||
api struct { | ||
Enabled bool `toml:"enabled"` | ||
Schemas []string `toml:"schemas"` | ||
ExtraSearchPath []string `toml:"extra_search_path"` | ||
MaxRows uint `toml:"max_rows"` | ||
// Local only config | ||
Image string `toml:"-"` | ||
KongImage string `toml:"-"` | ||
Port uint16 `toml:"port"` | ||
Tls tlsKong `toml:"tls"` | ||
// TODO: replace [auth|studio].api_url | ||
ExternalUrl string `toml:"external_url"` | ||
} | ||
|
||
tlsKong struct { | ||
Enabled bool `toml:"enabled"` | ||
} | ||
) | ||
|
||
func (a *api) ToUpdatePostgrestConfigBody() v1API.UpdatePostgrestConfigBody { | ||
body := v1API.UpdatePostgrestConfigBody{} | ||
|
||
// When the api is disabled, remote side it just set the dbSchema to an empty value | ||
if !a.Enabled { | ||
body.DbSchema = cast.Ptr("") | ||
return body | ||
} | ||
|
||
// Convert Schemas to a comma-separated string | ||
if len(a.Schemas) > 0 { | ||
schemas := strings.Join(a.Schemas, ",") | ||
body.DbSchema = &schemas | ||
} | ||
|
||
// Convert ExtraSearchPath to a comma-separated string | ||
if len(a.ExtraSearchPath) > 0 { | ||
extraSearchPath := strings.Join(a.ExtraSearchPath, ",") | ||
body.DbExtraSearchPath = &extraSearchPath | ||
} | ||
|
||
// Convert MaxRows to int pointer | ||
if a.MaxRows > 0 { | ||
body.MaxRows = cast.Ptr(cast.UintToInt(a.MaxRows)) | ||
} | ||
|
||
// Note: DbPool is not present in the Api struct, so it's not set here | ||
return body | ||
} | ||
|
||
func (a *api) fromRemoteApiConfig(remoteConfig v1API.PostgrestConfigWithJWTSecretResponse) api { | ||
result := *a | ||
if remoteConfig.DbSchema == "" { | ||
result.Enabled = false | ||
return result | ||
} | ||
|
||
result.Enabled = true | ||
// Update Schemas if present in remoteConfig | ||
schemas := strings.Split(remoteConfig.DbSchema, ",") | ||
result.Schemas = make([]string, len(schemas)) | ||
// TODO: use slices.Map when upgrade go version | ||
for i, schema := range schemas { | ||
result.Schemas[i] = strings.TrimSpace(schema) | ||
} | ||
|
||
// Update ExtraSearchPath if present in remoteConfig | ||
extraSearchPath := strings.Split(remoteConfig.DbExtraSearchPath, ",") | ||
result.ExtraSearchPath = make([]string, len(extraSearchPath)) | ||
for i, path := range extraSearchPath { | ||
result.ExtraSearchPath[i] = strings.TrimSpace(path) | ||
} | ||
|
||
// Update MaxRows if present in remoteConfig | ||
result.MaxRows = cast.IntToUint(remoteConfig.MaxRows) | ||
|
||
return result | ||
} | ||
|
||
func (a *api) DiffWithRemote(remoteConfig v1API.PostgrestConfigWithJWTSecretResponse) ([]byte, error) { | ||
// Convert the config values into easily comparable remoteConfig values | ||
currentValue, err := ToTomlBytes(a) | ||
if err != nil { | ||
return nil, err | ||
} | ||
remoteCompare, err := ToTomlBytes(a.fromRemoteApiConfig(remoteConfig)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return diff.Diff("remote[api]", remoteCompare, "local[api]", currentValue), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
package config | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
v1API "github.com/supabase/cli/pkg/api" | ||
) | ||
|
||
func TestApiToUpdatePostgrestConfigBody(t *testing.T) { | ||
t.Run("converts all fields correctly", func(t *testing.T) { | ||
api := &api{ | ||
Enabled: true, | ||
Schemas: []string{"public", "private"}, | ||
ExtraSearchPath: []string{"extensions", "public"}, | ||
MaxRows: 1000, | ||
} | ||
|
||
body := api.ToUpdatePostgrestConfigBody() | ||
|
||
assert.Equal(t, "public,private", *body.DbSchema) | ||
assert.Equal(t, "extensions,public", *body.DbExtraSearchPath) | ||
assert.Equal(t, 1000, *body.MaxRows) | ||
}) | ||
|
||
t.Run("handles empty fields", func(t *testing.T) { | ||
api := &api{} | ||
|
||
body := api.ToUpdatePostgrestConfigBody() | ||
|
||
// remote api will be false by default, leading to an empty schema on api side | ||
assert.Equal(t, "", *body.DbSchema) | ||
}) | ||
} | ||
|
||
func TestApiDiffWithRemote(t *testing.T) { | ||
t.Run("detects differences", func(t *testing.T) { | ||
api := &api{ | ||
Enabled: true, | ||
Schemas: []string{"public", "private"}, | ||
ExtraSearchPath: []string{"extensions", "public"}, | ||
MaxRows: 1000, | ||
} | ||
|
||
remoteConfig := v1API.PostgrestConfigWithJWTSecretResponse{ | ||
DbSchema: "public", | ||
DbExtraSearchPath: "public", | ||
MaxRows: 500, | ||
} | ||
|
||
diff, err := api.DiffWithRemote(remoteConfig) | ||
assert.NoError(t, err, string(diff)) | ||
|
||
assert.Contains(t, string(diff), "-schemas = [\"public\"]") | ||
assert.Contains(t, string(diff), "+schemas = [\"public\", \"private\"]") | ||
assert.Contains(t, string(diff), "-extra_search_path = [\"public\"]") | ||
assert.Contains(t, string(diff), "+extra_search_path = [\"extensions\", \"public\"]") | ||
assert.Contains(t, string(diff), "-max_rows = 500") | ||
assert.Contains(t, string(diff), "+max_rows = 1000") | ||
}) | ||
|
||
t.Run("handles no differences", func(t *testing.T) { | ||
api := &api{ | ||
Enabled: true, | ||
Schemas: []string{"public"}, | ||
ExtraSearchPath: []string{"public"}, | ||
MaxRows: 500, | ||
} | ||
|
||
remoteConfig := v1API.PostgrestConfigWithJWTSecretResponse{ | ||
DbSchema: "public", | ||
DbExtraSearchPath: "public", | ||
MaxRows: 500, | ||
} | ||
|
||
diff, err := api.DiffWithRemote(remoteConfig) | ||
assert.NoError(t, err) | ||
|
||
assert.Empty(t, diff) | ||
}) | ||
|
||
t.Run("handles multiple schemas and search paths with spaces", func(t *testing.T) { | ||
api := &api{ | ||
Enabled: true, | ||
Schemas: []string{"public", "private"}, | ||
ExtraSearchPath: []string{"extensions", "public"}, | ||
MaxRows: 500, | ||
} | ||
|
||
remoteConfig := v1API.PostgrestConfigWithJWTSecretResponse{ | ||
DbSchema: "public, private", | ||
DbExtraSearchPath: "extensions, public", | ||
MaxRows: 500, | ||
} | ||
|
||
diff, err := api.DiffWithRemote(remoteConfig) | ||
assert.NoError(t, err) | ||
|
||
assert.Empty(t, diff) | ||
}) | ||
|
||
t.Run("handles api disabled on remote side", func(t *testing.T) { | ||
api := &api{ | ||
Enabled: true, | ||
Schemas: []string{"public", "private"}, | ||
ExtraSearchPath: []string{"extensions", "public"}, | ||
MaxRows: 500, | ||
} | ||
|
||
remoteConfig := v1API.PostgrestConfigWithJWTSecretResponse{ | ||
DbSchema: "", | ||
DbExtraSearchPath: "", | ||
MaxRows: 0, | ||
} | ||
|
||
diff, err := api.DiffWithRemote(remoteConfig) | ||
assert.NoError(t, err, string(diff)) | ||
|
||
assert.Contains(t, string(diff), "-enabled = false") | ||
assert.Contains(t, string(diff), "+enabled = true") | ||
}) | ||
|
||
t.Run("handles api disabled on local side", func(t *testing.T) { | ||
api := &api{ | ||
Enabled: false, | ||
Schemas: []string{"public"}, | ||
ExtraSearchPath: []string{"public"}, | ||
MaxRows: 500, | ||
} | ||
|
||
remoteConfig := v1API.PostgrestConfigWithJWTSecretResponse{ | ||
DbSchema: "public", | ||
DbExtraSearchPath: "public", | ||
MaxRows: 500, | ||
} | ||
|
||
diff, err := api.DiffWithRemote(remoteConfig) | ||
assert.NoError(t, err, string(diff)) | ||
|
||
assert.Contains(t, string(diff), "-enabled = true") | ||
assert.Contains(t, string(diff), "+enabled = false") | ||
}) | ||
} |
Oops, something went wrong.