feat(cli): add config diff command - #6295
Draft
kanadgupta wants to merge 4 commits into
Draft
Conversation
Adds the pure comparison engine for supabase config diff: a managed-surface table (defined by the v2 project-config translation, so unmapped schema paths are unmanaged by construction), a change-set classifier with update / remote_only / local_only classes, order-insensitive type-aware equality, byte-size canonicalization, masked-secret transparency, and env-var name threading through the interpolation pipeline onto value origins. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… ADR 0019 (CLI-2156) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Read-only drift report between supabase/config.toml and the effective
configuration GET /v2/projects/{ref}/config reports for a target project or
branch. Target resolution via --target (branch name/UUID/ref, link-style
acceptance) or --project-ref or the linked ref; matching [remotes.*] blocks
become the merged local operand per ADR 0018. Text, --output-format
json/stream-json, and Go-compat -o encodings share one structured payload;
--exit-code flips exit 1 on drift after the payload is out. Hoists the branch
name/UUID resolver to legacy/shared with injected error mappers. Adds ADR
0019, SIDE_EFFECTS.md, a go-cli-divergences entry, 26 integration tests
(handler at 100% branch coverage), format unit tests, and a live golden path.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Colum confirmed on the ticket that net-new commands carry no Go parity contract, so the Go-compat -o/--output flag is now rejected outright (every value, pretty included) with an error pointing at --output-format, failing fast before target resolution or any network call. Drops the four Go-encoder emit branches, simplifies the JSON payload to always carry explicit nulls for unset sides, and updates SIDE_EFFECTS.md, the divergences entry, and the tests. Ticket acceptance criteria amended accordingly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements CLI-2156: a read-only
supabase config diffthat classifies drift betweensupabase/config.tomland the effective configurationGET /v2/projects/{ref}/configreports for a target project or branch. Never writes. Stacked on the CLI-2155 branch (sparse subtraction / versioned defaults), which it depends on.What changed
packages/config— the reusable comparison core (ADR 0019)config-diff.ts: pure classifier producing a typedConfigChangeSet(update/remote_only/local_only, plusmaskedandscope), with order-insensitive multiset array equality and type-aware scalar comparison ("8080"vs8080,"true"vstrue).config-diff.managed.ts+config-diff.auth.ts: the managed surface as a translation table — any schema path the table can read from the v2 response is managed; everything else ([studio], ports, image pins,[realtime]locals, …) is unmanaged by construction, so the managed set and the response-reading code cannot drift apart. The auth table (188 entries) is ported from the Go CLI'sFromRemoteAuthConfigat7b469f5b3, including inversions (enable_signup←!disable_signup), duration/enum transforms, SMS provider fan-out, and Apple/Google client-id joins.x-secretand Go's Secret machinery) are "present, unknown": never compared, never counted, surfaced viamaskedso a clean diff is visibly a partial claim.remote_onlyvalues equal to the schema default are suppressed (the CLI-2155 defaults baseline); optional-key paths with no materialized default suppress the type's zero value instead — otherwise every unconfigured OAuth provider reads as drift.io.ts/lib/env.ts: value origins now record the resolving env-var name, so a change on anenv()-fed property names the variable.apps/cli— legacy-shell commandlegacy/commands/config/diff/: command + handler + errors +SIDE_EFFECTS.md. Target resolution:--target <branch-name|uuid|ref>(same acceptance aslink; 404 → "runsupabase branches list"),--project-ref, else the linked ref;--target+--project-reftogether is a hard error. When the resolved ref matches a[remotes.*]block'sproject_id, the local operand is the branch's merged effective config (ADR 0018), otherwise the base config — the echoed scope line always says which.(unset)/(not returned);(from env VAR)annotations; masked note) and--output-format json|stream-json(structured payload withschema_version,target,scope,changes[],masked[],counts). The Go-compat-o/--outputflag is rejected outright (every value,prettyincluded) with an error pointing at--output-format— per the ticket-thread decision with Colum that net-new commands carry no Go parity contract.--exit-codesets exit 1 on drift viaProcessControl.setExitCodeafter the payload is emitted.legacy/shared/legacy-branch-ref.resolver.ts: the branch name/UUID/ref resolver hoisted out of the branches family (cross-family use) with injected error mappers; the branches family keeps a thin binding so its call sites are unchanged.Docs: ADR 0019 (classification + managed surface),
go-cli-divergences.mdTS-only command entry (replacing the ticket's stalego-cli-porting-status.mdcriterion — that file no longer has a per-command table), per-commandSIDE_EFFECTS.md.Decisions & assumptions worth reviewing
false/""/0/[]remotes). Judgment call made during implementation — without it the diff floods with unconfigured-provider noise; the cost is that a genuinely zero-valued remote override on such a path is not reported.schema_versionin the payload is the file's$schemaref (falling back to the current schema URL) — CLI-2155 shipped no separate version token.-osupport was implemented per the original acceptance criteria, then removed after Colum confirmed on the ticket that parity isn't a goal for net-new commands. The flag now fails fast with a bespoke invalid-input error; the JSON payload always carries explicitnullfor unset sides.masked[]/ a text note rather than silently skipped, and never affect--exit-code.local_onlywhen declared locally, silent otherwise; the scope line calls out missing blocks. (Today's v2 schema requires all six blocks, so this is belt-and-braces for API evolution and permission-trimmed keys.)config push'sconfig-sync/noted, not consolidated: those helpers render Go-parity per-service diff text against v1 endpoints for push previews. Consolidating push onto this core is a possible follow-up.sms_test_otp, mailer template contents, OAuth-server keys, third-party auth.🤖 Generated with Claude Code