Skip to content

feat(cli): detect and confirm branch targets in config push - #6446

Merged
Coly010 merged 6 commits into
developfrom
columferry/cli-2168-inform-users-of-the-branch-they-push-to
Sep 4, 2026
Merged

feat(cli): detect and confirm branch targets in config push#6446
Coly010 merged 6 commits into
developfrom
columferry/cli-2168-inform-users-of-the-branch-they-push-to

Conversation

@Coly010

@Coly010 Coly010 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

What changed

supabase config push now always reports the project or branch it resolved before doing anything — by name when known, e.g. Pushing config to project: My App (abcdefghijklmnopqrst) or Pushing config to branch: feat-x (bbbb…) plus its parent project. When the resolved target is a preview branch that was only inferred (from a prior supabase link <branch>, SUPABASE_PROJECT_ID, or the linked-ref cache — not named on this invocation), it gates behind a confirmation before any network mutation, skippable via the existing global --yes/SUPABASE_YES (CLI-2168).

--project-ref also now accepts a branch name or UUID, not just a raw ref, matching config diff's existing CLI-2167 vocabulary — so a config pull --project-ref <branch>/config push --project-ref <branch> round-trip no longer requires manually looking up the branch's raw ref (CLI-2289).

Why

config push gave no indication of whether the resolved ref was the main project or one of its branches, so a user linked to a branch (or overriding via env/flag) had no on-screen signal before mutating it. The confirmation defaults to decline in every non-interactive context without --yes (--output-format json/stream-json, a non-TTY with no piped answer) — fails the command rather than silently proceeding or silently no-opping, matching the existing projects delete/db reset convention for this shape of gate. An explicit --project-ref <name-or-uuid> this invocation skips the prompt entirely (the echo still prints) — same-invocation intent is treated as confirmation.

Notes for reviewers

The branch/project detection shared by link and status is hoisted into legacy-branch-target.ts; the --project-ref branch-name/UUID resolution shared by config diff and config push is hoisted into config.branch-target.ts — both existing commands are refactored onto the shared code in this same change, per this repo's hoisting policy. Neither command's own established behavior changes; their existing test suites are unmodified and green.

…, CLI-2289)

config push now always reports the project or branch it resolved (by
name when known), and gates an inferred branch target behind a
confirmation before any network mutation, skippable via the existing
--yes/SUPABASE_YES. --project-ref also now accepts a branch name or
UUID, matching config diff's existing vocabulary.

Hoists the branch/project detection shared by link and status into
legacy-branch-target.ts, and the --project-ref branch-name/UUID
resolution shared by config diff and config push into
config.branch-target.ts, refactoring both existing commands onto them.
@Coly010 Coly010 self-assigned this Sep 3, 2026
@Coly010

Coly010 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

/ai-review

@Coly010
Coly010 marked this pull request as ready for review September 3, 2026 14:39
@Coly010
Coly010 requested a review from a team as a code owner September 3, 2026 14:39
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Supabase CLI preview

npx --yes https://pkg.pr.new/supabase/cli/supabase@40c3107824ba90af6af29e1372852dcaabd44e75

Preview package for commit 40c3107.

A hostile-name test case embedded a literal ESC (0x1B) control byte in
the source instead of the \x1b JS string escape, which broke tools
that treat the raw diff as terminal output (gh pr diff, this repo's
own AI review pipeline). Same runtime string value, safe source bytes.
@Coly010

Coly010 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

/ai-review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 AI Review

Verified and deduplicated all 14 reported findings into 13 entries. Twelve are confirmed and one is refuted. The principal regression is that config push now decodes the base document before applying a matching remote overlay, rejecting configurations that become valid only after that overlay. Branch-target detection also introduces several confirmed reliability, diagnostics, and coverage gaps.

Findings

Severity Location Category Sources Claim
🟠 MAJOR apps/cli/src/legacy/commands/config/push/push.handler.ts:211 correctness claude+codex The preliminary target-less decode rejects configurations whose matching remote overlay would make the effective configuration valid, and matching remotes also repeat load-time warnings.
🟡 MINOR apps/cli/src/legacy/commands/config/push/push.branch-target.ts:157 error-handling claude Non-404 failures from the target-classification probe abort config push even though they could safely degrade to an uncertain branch classification.
🟡 MINOR apps/cli/src/legacy/commands/config/push/push.branch-target.ts:178 correctness claude A project lookup exceeding five seconds is reported as a branch and can cause an unattended plain-project push to be cancelled.
🟡 MINOR apps/cli/src/legacy/commands/config/push/push.integration.test.ts:1503 test-coverage claude The broken project-ref test does not reach the filesystem read whose failure it claims to verify.
🟡 MINOR apps/cli/src/legacy/commands/config/push/push.handler.ts:316 usability claude Machine-output branch cancellation omits the prompt's --yes recovery hint and reports only a generic cancellation error.
🟡 MINOR apps/cli/docs/supabase/config/push.md:9 documentation claude The user-facing documentation says preview-branch pushes ask for confirmation without documenting that explicit branch names and UUIDs bypass it.
🟡 MINOR apps/cli/src/legacy/commands/config/push/push.branch-target.ts:209 user-experience codex The best-effort branch-list request can leave text-mode users without progress feedback for up to five seconds.
🟡 MINOR apps/cli/src/legacy/commands/config/push/push.integration.test.ts:1544 test-coverage codex The new timeout-degradation branch is explicitly left untested despite the repository's command-handler branch-coverage requirement.
⚪ NIT apps/cli/src/legacy/commands/config/push/push.branch-target.ts:197 dead-code claude The knownBranch.parentRef-only recovery path and its UUID commentary are unreachable from the sole production caller.
⚪ NIT apps/cli/src/legacy/commands/config/push/push.branch-target.ts:173 progress-reporting claude A failed project probe clears its spinner instead of marking it failed.
⚪ NIT apps/cli/src/legacy/commands/config/push/push.handler.ts:316 behavior-change claude The new branch gate consumes an additional piped stdin line before existing per-service prompts, shifting scripted answer sequences.
⚪ NIT apps/cli/src/legacy/commands/status/status.integration.test.ts:1759 documentation claude A test title refers to the old timeout constant name, location, and visibility.

Findings outside the diff

  • ⚪ NIT apps/cli/src/legacy/commands/status/status.integration.test.ts:1759 — A test title refers to the old timeout constant name, location, and visibility.
Refuted findings (kept for transparency, not posted as review comments)
  • apps/cli/src/legacy/commands/config/push/push.handler.ts:315 (behavior-change): An explicit ref-shaped --project-ref should bypass the branch confirmation gate under the PR's same-invocation-intent rule.
    Refuted: The implementation and accompanying contract consistently distinguish raw 20-letter refs from branch names/UUIDs. config.branch-target.ts:121-122 intentionally leaves branchResolution absent for raw refs, and push.handler.ts:305-315 expressly gates such targets if the later probe identifies them as branches. The alleged contradiction is therefore absent; this is the documented safety behavior of the change.

Stats

Claude findings: 11 · Codex findings: 3 · Confirmed: 12 · Refuted: 1 · Uncertain: 0


Models: claude-opus-5 + gpt-5.6-sol · Trigger: manual · Workflow run

This review runs once per PR. A maintainer can request another with a /ai-review comment.

Comment thread apps/cli/src/legacy/commands/config/push/push.branch-target.ts Outdated
Comment thread apps/cli/src/legacy/commands/config/push/push.branch-target.ts Outdated
Comment thread apps/cli/src/legacy/commands/config/push/push.handler.ts Outdated
Comment thread apps/cli/src/legacy/commands/config/push/push.integration.test.ts Outdated
Comment thread apps/cli/src/legacy/commands/config/push/push.handler.ts Outdated
Comment thread apps/cli/src/legacy/commands/config/push/push.branch-target.ts Outdated
Comment thread apps/cli/src/legacy/commands/config/push/push.branch-target.ts Outdated
Comment thread apps/cli/src/legacy/commands/config/push/push.handler.ts
Comment thread apps/cli/src/legacy/commands/config/push/push.branch-target.ts Outdated
Comment thread apps/cli/src/legacy/commands/config/push/push.integration.test.ts Outdated
- config.toml now loads AFTER the push target resolves, in one call
  with the resolved ref, instead of a load-resolve-maybe-reload split:
  a [remotes.*] overlay is merged inside loadCliConfig itself before
  its one full schema decode, so a base document that's only valid
  once its matching remote applies is no longer wrongly rejected, and
  load-time warnings no longer fire twice on a real remote match.

- The live getProject probe that tells config push whether a target is
  the linked project or a branch is now fully best-effort: a timeout,
  transport failure, or any non-200/404 status degrades to a new
  "unknown" target (never silently "project", which would skip the
  confirmation gate for a real branch; never a hard failure, which
  would abort an otherwise-successful push over a diagnostic-only read
  or a scoped token that can't read the project record). "unknown"
  never gates a confirmation and omits is_branch from the machine
  payload rather than asserting it. Removes the two error classes this
  made dead.

- LegacyConfigPushKnownBranch is now a discriminated union of the only
  two shapes a real caller produces (name: both fields; uuid: neither),
  removing an unreachable partial-state branch in the resolver.

- The target-detection probe and the branch-name recovery lookup now
  show progress feedback (a spinner, marked failed on a genuine
  probe error) instead of running silently for up to 5 seconds.

- The declined-branch-gate error now carries a --yes/SUPABASE_YES
  suggestion, so a machine-mode or non-TTY decline (which never
  renders the interactive prompt's own inline hint) still surfaces it.

- Docs/SIDE_EFFECTS.md: document that an explicit --project-ref
  name/UUID bypasses the confirmation gate, and that the gate shifts
  piped stdin answers by one for a script targeting an inferred branch.

- Test fixes: the malformed-config test now asserts branch resolution
  running before config load (the corrected, intentional order); the
  EISDIR regression test now actually reaches the read it claims to
  verify; the two former probe-hard-failure tests now assert the
  degrade-to-unknown behavior; a stale test title in
  status.integration.test.ts is updated for the timeout constant's
  current name/location.

Also fixes the failing "Check code quality" CI job (oxfmt table
padding in SIDE_EFFECTS.md/push.md, unformatted by the prior commit).
…lope

The json-mode branch-decline test only checked for
LegacyConfigPushCancelledError's tag, not that its suggestion field
(the only place a machine-mode/non-TTY decline surfaces the --yes
escape hatch) actually carries the hint.
…8-inform-users-of-the-branch-they-push-to

# Conflicts:
#	apps/cli/src/legacy/commands/config/diff/diff.handler.ts
@Coly010
Coly010 added this pull request to the merge queue Sep 4, 2026
Merged via the queue into develop with commit ace845a Sep 4, 2026
26 checks passed
@Coly010
Coly010 deleted the columferry/cli-2168-inform-users-of-the-branch-they-push-to branch September 4, 2026 08:23
Coly010 added a commit that referenced this pull request Sep 4, 2026
Carries #6446 (branch-target detection and confirmation in config push)
onto the diff-first handler: target resolution and the inferred-branch
confirmation gate run before the cost-matrix read, the resolved target
line replaces the bare ref line, and the machine payload gains the
target fields. Adopts #6447's public diffProjectConfig entrypoint and
re-applies the family hoists on develop's diff handler/formatter.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants