fix(cli): merge matching [remotes.*] block on config push#5618
Conversation
The native-TS port of `config push` aborted with "a [remotes.*] block
targets project ..., which config push does not yet support" whenever a
remote block matched the target ref — a regression from the Go CLI
(v2.105.0), which merges the matching remote's subtree over the base
config and pushes it.
Port Go's `mergeRemoteConfig` faithfully into `@supabase/config`:
`loadProjectConfig` now accepts an optional `{ projectRef }` and, when
set, deep-merges the matching `[remotes.<name>]` raw subtree over the
base document before schema decode (objects recurse, arrays/scalars
replace), forces `db.seed.enabled=false` when the remote omits it,
strips `remotes`, and returns the merged `document` + `appliedRemote`.
Duplicate `project_id` across remotes raises `DuplicateRemoteProjectIdError`
with Go's verbatim message. The merge is gated on `projectRef`, so other
callers are unaffected.
The push handler prints `Loading config override: [remotes.<name>]` when
a remote applies and derives pointer-section presence from the merged
document. Also consolidates `functions deploy` onto the shared merge,
deleting its divergent partial copy.
Closes CLI-1808
Supabase CLI previewnpx --yes https://pkg.pr.new/supabase/cli/supabase@65ab5daaf795bd669bfd441a1ec5678e58e610b1Preview package for commit |
|
I found one parity issue worth fixing before merge:
const matches = Object.entries(remotes)
.filter(([, remote]) => isObject(remote) && remote["project_id"] === projectRef)
.map(([name]) => name);The Go loader builds its duplicate map across all Since this PR is explicitly restoring Go parity for remote config loading, |
Go's loadFromFile builds the duplicate-detection map across every [remotes.*] block before applying the matching override, so clashes between non-target remotes (or two remotes omitting project_id, which viper reads as "") are rejected. The TS loader only compared remotes already matching projectRef, accepting configs Go rejects.
|
Good catch — fixed in 65ab5da.
Added two regression tests: duplicate IDs among non-target remotes, and two remotes omitting |
What changed
config pushregressed in v2.106.0 (the native-TS port): when a[remotes.<name>]block inconfig.tomltargeted the project ref, the command aborted withThe Go CLI (v2.105.0) instead merges that remote's subtree over the base config and pushes it. The port had punted on Go's
mergeRemoteConfig.This ports the merge faithfully and removes the abort.
Why this location
The merge is owned by
@supabase/config, mirroring Go doing it inpkg/config.loadProjectConfig/loadProjectConfigFilenow accept an optional{ projectRef }. When set, afterenv()interpolation and before schema decode, the matching[remotes.<name>]raw subtree is deep-merged over the base document (objects recurse; arrays and scalars replace wholesale — viper'sv.Setsemantics),db.seed.enabledis forcedfalsewhen the remote omits it, theremoteskey is stripped, and the merged document is decoded. Doing it on the raw document (not the decoded config) is essential: the decoded remote section carries full schema defaults that would otherwise clobber every field the block doesn't override.The merge is gated on
projectRef, so every otherloadProjectConfigcaller is unaffected.Notable details for reviewers
DuplicateRemoteProjectIdError(exported from@supabase/config) raised when two remotes share the targetproject_id, carrying Go's verbatim messageduplicate project_id for [remotes.<b>] and [remotes.<a>].LoadedProjectConfiggains optionaldocument(merged, post-interpolation raw doc) andappliedRemotefields.Loading config override: [remotes.<name>]to stderr (Go parity) when a remote applies, and now derives optional pointer-section presence (db.ssl_enforcement,storage.image_transformation,storage.s3_protocol, auth subsections) from the merged document instead of re-reading the file — so sections introduced by the remote are detected. Dead code removed (matchesRemoteProjectRef,resolveRemoteByProjectRef,LegacyConfigPushUnsupportedRemoteError).functions deployis consolidated onto the same shared merge, deleting its divergent partial copy (configForProjectRef/mergeFunctionConfigByPresence, which only handledfunctions.*andedge_runtime.deno_version). Verified behavior-preserving since deploy reads only those fields. This also corrects deploy's duplicate-project_idmessage to match Go (both remote names bracketed).Closes CLI-1808