Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/api-sync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ jobs:

- name: Generate token
id: app-token
uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}

- name: Create Pull Request
if: steps.check.outputs.has_changes == 'true'
id: cpr
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
with:
token: ${{ steps.app-token.outputs.token }}
commit-message: "chore: sync API types from infrastructure"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/automerge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
- name: Generate token
id: app-token
if: ${{ steps.meta.outputs.update-type == null || steps.meta.outputs.update-type == 'version-update:semver-patch' || (!startsWith(steps.meta.outputs.previous-version, '0.') && steps.meta.outputs.update-type == 'version-update:semver-minor') }}
uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
go tool gotestsum -- -race -v -count=1 ./... \
-coverpkg="./cmd/...,./internal/...,${pkgs}" -coverprofile=coverage.out

- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: code-coverage-report
path: coverage.out
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ jobs:

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
Expand Down Expand Up @@ -89,6 +89,6 @@ jobs:
exit 1

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
with:
category: "/language:${{matrix.language}}"
2 changes: 1 addition & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
with:
fetch-depth: 0
- id: app-token
uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/install.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
mv tmp.$$.json package.json
npm pack

- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: installer
path: supabase-1.28.0.tgz
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/pg-prove.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
image_tag: supabase/pg_prove:${{ steps.version.outputs.pg_prove }}
steps:
- uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
- uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
load: true
context: https://github.com/horrendo/pg_prove.git
Expand Down Expand Up @@ -51,7 +51,7 @@ jobs:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- id: build
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
push: true
context: https://github.com/horrendo/pg_prove.git
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/publish-migra.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
image_tag: supabase/migra:${{ steps.version.outputs.migra }}
steps:
- uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
- uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
load: true
context: https://github.com/djrobstep/migra.git
Expand Down Expand Up @@ -51,7 +51,7 @@ jobs:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- id: build
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
push: true
context: https://github.com/djrobstep/migra.git
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-beta.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ jobs:
# use GitHub app to create a release token that can publish to homebrew-tap and scoop
- name: Generate token
id: app-token
uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
go-version-file: go.mod
cache: true
- id: app-token
uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
Expand All @@ -72,7 +72,7 @@ jobs:
go-version-file: go.mod
cache: true
- id: app-token
uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
Expand All @@ -96,7 +96,7 @@ jobs:
go-version-file: go.mod
cache: true
- id: app-token
uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
Expand All @@ -121,7 +121,7 @@ jobs:
go-version-file: go.mod
cache: true
- id: app-token
uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
Expand Down
30 changes: 30 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ func Execute() {
executedCmd, err := rootCmd.ExecuteC()
if executedCmd != nil {
if service := telemetry.FromContext(executedCmd.Context()); service != nil {
ensureProjectGroupsCached(executedCmd.Context(), service)
_ = service.Capture(executedCmd.Context(), telemetry.EventCommandExecuted, map[string]any{
telemetry.PropExitCode: exitCode(err),
telemetry.PropDurationMs: time.Since(startedAt).Milliseconds(),
Expand Down Expand Up @@ -200,6 +201,35 @@ func Execute() {
}
}

// ensureProjectGroupsCached populates the telemetry linked-project cache when
// a project ref is available but no cache exists. This ensures org/project
// PostHog groups are attached to all CLI events, not just those after `supabase link`.
//
// Does not overwrite an existing cache — `supabase link` is the authoritative source.
// Checks auth before calling the API to avoid the log.Fatalln in GetSupabase().
func ensureProjectGroupsCached(ctx context.Context, service *telemetry.Service) {
ref := flags.ProjectRef
if ref == "" {
return
}
fsys := afero.NewOsFs()
if telemetry.HasLinkedProject(fsys) {
return
}
if _, err := utils.LoadAccessTokenFS(fsys); err != nil {
return
}
resp, err := utils.GetSupabase().V1GetProjectWithResponse(ctx, ref)
if err != nil {
fmt.Fprintln(utils.GetDebugLogger(), err)
return
}
if resp.JSON200 == nil {
return
}
telemetry.CacheProjectAndIdentifyGroups(*resp.JSON200, service, fsys)
}

func exitCode(err error) int {
if err != nil {
return 1
Expand Down
7 changes: 3 additions & 4 deletions internal/db/declarative/declarative.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,9 @@ func WriteDeclarativeSchemas(output diff.DeclarativeOutput, fsys afero.Fs) error
return err
}
}
// When pg-delta has its own config section, the declarative path is the single
// source of truth there; do not overwrite [db.migrations] schema_paths.
if utils.IsPgDeltaEnabled() && utils.Config.Experimental.PgDelta != nil &&
len(utils.Config.Experimental.PgDelta.DeclarativeSchemaPath) > 0 {
// When pg-delta is enabled, the declarative directory (default or configured)
// is the source of truth; do not overwrite [db.migrations] schema_paths.
if utils.IsPgDeltaEnabled() {
return nil
}
utils.Config.Db.Migrations.SchemaPaths = []string{
Expand Down
60 changes: 60 additions & 0 deletions internal/db/declarative/declarative_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,34 @@ func TestWriteDeclarativeSchemas(t *testing.T) {
assert.Contains(t, string(cfg), `"database"`)
}

func TestWriteDeclarativeSchemasSkipsConfigUpdateWhenPgDeltaEnabled(t *testing.T) {
fsys := afero.NewMemMapFs()
originalConfig := "[db]\n"
require.NoError(t, afero.WriteFile(fsys, utils.ConfigPath, []byte(originalConfig), 0644))
original := utils.Config.Experimental.PgDelta
utils.Config.Experimental.PgDelta = &config.PgDeltaConfig{Enabled: true}
t.Cleanup(func() {
utils.Config.Experimental.PgDelta = original
})

output := diff.DeclarativeOutput{
Files: []diff.DeclarativeFile{
{Path: "schemas/public/tables/users.sql", SQL: "create table users(id bigint);"},
},
}

err := WriteDeclarativeSchemas(output, fsys)
require.NoError(t, err)

users, err := afero.ReadFile(fsys, filepath.Join(utils.DeclarativeDir, "schemas", "public", "tables", "users.sql"))
require.NoError(t, err)
assert.Equal(t, "create table users(id bigint);", string(users))

cfg, err := afero.ReadFile(fsys, utils.ConfigPath)
require.NoError(t, err)
assert.Equal(t, originalConfig, string(cfg))
}

func TestTryCacheMigrationsCatalogWritesPrefixedCache(t *testing.T) {
fsys := afero.NewMemMapFs()
original := utils.Config.Experimental.PgDelta
Expand Down Expand Up @@ -146,6 +174,38 @@ func TestWriteDeclarativeSchemasUsesConfiguredDir(t *testing.T) {
assert.Contains(t, string(cfg), `db/decl`)
}

func TestWriteDeclarativeSchemasSkipsConfigUpdateForPgDeltaCustomDir(t *testing.T) {
fsys := afero.NewMemMapFs()
originalConfig := "[db]\n"
require.NoError(t, afero.WriteFile(fsys, utils.ConfigPath, []byte(originalConfig), 0644))
original := utils.Config.Experimental.PgDelta
utils.Config.Experimental.PgDelta = &config.PgDeltaConfig{
Enabled: true,
DeclarativeSchemaPath: filepath.Join(utils.SupabaseDirPath, "db", "decl"),
}
t.Cleanup(func() {
utils.Config.Experimental.PgDelta = original
})

output := diff.DeclarativeOutput{
Files: []diff.DeclarativeFile{
{Path: "cluster/roles.sql", SQL: "create role app;"},
},
}

err := WriteDeclarativeSchemas(output, fsys)
require.NoError(t, err)

rolesPath := filepath.Join(utils.SupabaseDirPath, "db", "decl", "cluster", "roles.sql")
roles, err := afero.ReadFile(fsys, rolesPath)
require.NoError(t, err)
assert.Equal(t, "create role app;", string(roles))

cfg, err := afero.ReadFile(fsys, utils.ConfigPath)
require.NoError(t, err)
assert.Equal(t, originalConfig, string(cfg))
}

func TestWriteDeclarativeSchemasRejectsUnsafePath(t *testing.T) {
// Export paths must stay within supabase/declarative to prevent traversal.
fsys := afero.NewMemMapFs()
Expand Down
13 changes: 10 additions & 3 deletions internal/db/diff/templates/pgdelta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import {
createPlan,
deserializeCatalog,
formatSqlStatements,
} from "npm:@supabase/pg-delta@1.0.0-alpha.11";
import { supabase } from "npm:@supabase/pg-delta@1.0.0-alpha.11/integrations/supabase";
} from "npm:@supabase/pg-delta@1.0.0-alpha.13";
import { supabase } from "npm:@supabase/pg-delta@1.0.0-alpha.13/integrations/supabase";

async function resolveInput(ref: string | undefined) {
if (!ref) {
Expand All @@ -21,7 +21,14 @@ const target = Deno.env.get("TARGET");

const includedSchemas = Deno.env.get("INCLUDED_SCHEMAS");
if (includedSchemas) {
supabase.filter = { schema: includedSchemas.split(",") };
const schemas = includedSchemas.split(",");
const schemaFilter = {
or: [{ "*/schema": schemas }, { "schema/name": schemas }],
};
// CompositionPattern `and` is valid FilterDSL; Deno's structural typing is strict on `or` branches.
supabase.filter = {
and: [supabase.filter!, schemaFilter],
} as typeof supabase.filter;
}

const formatOptionsRaw = Deno.env.get("FORMAT_OPTIONS");
Expand Down
2 changes: 1 addition & 1 deletion internal/db/diff/templates/pgdelta_catalog_export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
extractCatalog,
serializeCatalog,
stringifyCatalogSnapshot,
} from "npm:@supabase/pg-delta@1.0.0-alpha.11";
} from "npm:@supabase/pg-delta@1.0.0-alpha.13";

const target = Deno.env.get("TARGET");
const role = Deno.env.get("ROLE") ?? undefined;
Expand Down
25 changes: 10 additions & 15 deletions internal/db/diff/templates/pgdelta_declarative_export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import {
createPlan,
deserializeCatalog,
exportDeclarativeSchema,
} from "npm:@supabase/pg-delta@1.0.0-alpha.11";
import { supabase } from "npm:@supabase/pg-delta@1.0.0-alpha.11/integrations/supabase";
} from "npm:@supabase/pg-delta@1.0.0-alpha.13";
import { supabase } from "npm:@supabase/pg-delta@1.0.0-alpha.13/integrations/supabase";

async function resolveInput(ref: string | undefined) {
if (!ref) {
Expand All @@ -21,29 +21,23 @@ async function resolveInput(ref: string | undefined) {

const source = Deno.env.get("SOURCE");
const target = Deno.env.get("TARGET");
supabase.filter = {
// Also allow dropped extensions from migrations to be capted in the declarative schema export
// TODO: fix upstream bug into pgdelta supabase integration
or: [
...supabase.filter.or,
{ type: "extension", operation: "drop", scope: "object" },
],
};

const includedSchemas = Deno.env.get("INCLUDED_SCHEMAS");
if (includedSchemas) {
const schemaFilter = { schema: includedSchemas.split(",") };
supabase.filter = supabase.filter
? { and: [supabase.filter, schemaFilter] }
: schemaFilter;
const schemas = includedSchemas.split(",");
const schemaFilter = {
or: [{ "*/schema": schemas }, { "schema/name": schemas }],
};
supabase.filter = {
and: [supabase.filter!, schemaFilter],
} as unknown as typeof supabase.filter;
}

const formatOptionsRaw = Deno.env.get("FORMAT_OPTIONS");
let formatOptions = undefined;
if (formatOptionsRaw) {
formatOptions = JSON.parse(formatOptionsRaw);
}

try {
const result = await createPlan(
await resolveInput(source),
Expand All @@ -63,6 +57,7 @@ try {
);
} else {
const output = exportDeclarativeSchema(result, {
integration: supabase,
formatOptions,
});
console.log(
Expand Down
2 changes: 1 addition & 1 deletion internal/db/pgcache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import {
extractCatalog,
serializeCatalog,
stringifyCatalogSnapshot,
} from "npm:@supabase/pg-delta@1.0.0-alpha.11";
} from "npm:@supabase/pg-delta@1.0.0-alpha.13";
const target = Deno.env.get("TARGET");
const role = Deno.env.get("ROLE") ?? undefined;
if (!target) {
Expand Down
Loading
Loading