diff --git a/apps/cli-go/cmd/branches.go b/apps/cli-go/cmd/branches.go index fee85fccb7..7402962c88 100644 --- a/apps/cli-go/cmd/branches.go +++ b/apps/cli-go/cmd/branches.go @@ -59,6 +59,9 @@ var ( if cmdFlags.Changed("notify-url") { body.NotifyUrl = ¬ifyURL } + if cmdFlags.Changed("git-branch") { + body.GitBranch = &gitBranch + } return create.Run(cmd.Context(), body, afero.NewOsFs()) }, } @@ -208,6 +211,7 @@ func init() { createFlags.BoolVar(&persistent, "persistent", false, "Whether to create a persistent branch.") createFlags.BoolVar(&withData, "with-data", false, "Whether to clone production data to the branch database.") createFlags.StringVar(¬ifyURL, "notify-url", "", "URL to notify when branch is active healthy.") + createFlags.StringVar(&gitBranch, "git-branch", "", "Associate a git branch with the new preview branch.") branchesCmd.AddCommand(branchCreateCmd) branchesCmd.AddCommand(branchListCmd) branchesCmd.AddCommand(branchGetCmd) diff --git a/apps/cli-go/internal/branches/create/create.go b/apps/cli-go/internal/branches/create/create.go index 25273456c1..8c0ac98c71 100644 --- a/apps/cli-go/internal/branches/create/create.go +++ b/apps/cli-go/internal/branches/create/create.go @@ -24,7 +24,9 @@ func Run(ctx context.Context, body api.CreateBranchBody, fsys afero.Fs) error { return errors.New(context.Canceled) } body.BranchName = gitBranch - body.GitBranch = &gitBranch + if body.GitBranch == nil { + body.GitBranch = &gitBranch + } } resp, err := utils.GetSupabase().V1CreateABranchWithResponse(ctx, flags.ProjectRef, body) diff --git a/apps/cli/src/legacy/commands/branches/create/SIDE_EFFECTS.md b/apps/cli/src/legacy/commands/branches/create/SIDE_EFFECTS.md index a763eee186..3c3c106a26 100644 --- a/apps/cli/src/legacy/commands/branches/create/SIDE_EFFECTS.md +++ b/apps/cli/src/legacy/commands/branches/create/SIDE_EFFECTS.md @@ -15,9 +15,9 @@ ## API Routes -| Method | Path | Auth | Request body | Response (used fields) | -| ------ | ----------------------------- | ------------ | --------------------------------------------------------------------------------------- | ---------------------- | -| `POST` | `/v1/projects/{ref}/branches` | Bearer token | `{branch_name?, region?, desired_instance_size?, persistent?, with_data?, notify_url?}` | `{id}` | +| Method | Path | Auth | Request body | Response (used fields) | +| ------ | ----------------------------- | ------------ | ---------------------------------------------------------------------------------------------------- | ---------------------- | +| `POST` | `/v1/projects/{ref}/branches` | Bearer token | `{branch_name?, region?, desired_instance_size?, persistent?, with_data?, notify_url?, git_branch?}` | `{id}` | ## Environment Variables @@ -55,5 +55,5 @@ One `result` event on success. ## Notes -- Flags: `[name]` (positional), `--region`, `--size`, `--persistent`, `--with-data`, `--notify-url`, `--project-ref`. +- Flags: `[name]` (positional), `--region`, `--size`, `--persistent`, `--with-data`, `--notify-url`, `--git-branch`, `--project-ref`. - Requires a linked project (reads `--project-ref` or `.supabase/config.json`). diff --git a/apps/cli/src/legacy/commands/branches/create/create.command.ts b/apps/cli/src/legacy/commands/branches/create/create.command.ts index a8f3d05a0b..dfb9a8864a 100644 --- a/apps/cli/src/legacy/commands/branches/create/create.command.ts +++ b/apps/cli/src/legacy/commands/branches/create/create.command.ts @@ -72,6 +72,10 @@ const config = { Flag.withDescription("URL to notify when branch is active healthy."), Flag.optional, ), + gitBranch: Flag.string("git-branch").pipe( + Flag.withDescription("Associate a git branch with the new preview branch."), + Flag.optional, + ), } as const; export type LegacyBranchesCreateFlags = CliCommand.Command.Config.Infer; diff --git a/apps/cli/src/legacy/commands/branches/create/create.handler.ts b/apps/cli/src/legacy/commands/branches/create/create.handler.ts index 6ee81f44cd..c1f964b739 100644 --- a/apps/cli/src/legacy/commands/branches/create/create.handler.ts +++ b/apps/cli/src/legacy/commands/branches/create/create.handler.ts @@ -14,5 +14,6 @@ export const legacyBranchesCreate = Effect.fn("legacy.branches.create")(function if (flags.persistent) args.push("--persistent"); if (flags.withData) args.push("--with-data"); if (Option.isSome(flags.notifyUrl)) args.push("--notify-url", flags.notifyUrl.value); + if (Option.isSome(flags.gitBranch)) args.push("--git-branch", flags.gitBranch.value); yield* proxy.exec(args); }); diff --git a/apps/cli/src/next/commands/branches/create/create.command.ts b/apps/cli/src/next/commands/branches/create/create.command.ts index dd2efa1b5f..237939a58e 100644 --- a/apps/cli/src/next/commands/branches/create/create.command.ts +++ b/apps/cli/src/next/commands/branches/create/create.command.ts @@ -85,6 +85,12 @@ const config = { Flag.withDescription("HTTP endpoint to notify when the branch becomes active and healthy."), Flag.optional, ), + gitBranch: Flag.string("git-branch").pipe( + Flag.withDescription( + "Git branch to associate with the new branch. Defaults to the current local git branch when the branch name is auto-detected.", + ), + Flag.optional, + ), switchAfter: Flag.boolean("switch").pipe( Flag.withDescription("Switch to the new branch after creation. Pass --no-switch to skip."), Flag.withDefault(true), @@ -118,6 +124,10 @@ export const createBranchesCommand = Command.make("create", config).pipe( command: "supabase branches create my-feature --with-data", description: "Create a branch and clone production data into it", }, + { + command: "supabase branches create my-feature --git-branch feature/login-page", + description: "Associate a specific git branch with the new branch", + }, ]), Command.withHandler((flags) => create(flags).pipe(withCommandInstrumentation(), withJsonErrorHandling), diff --git a/apps/cli/src/next/commands/branches/create/create.handler.ts b/apps/cli/src/next/commands/branches/create/create.handler.ts index b246895f22..99d6f9aa56 100644 --- a/apps/cli/src/next/commands/branches/create/create.handler.ts +++ b/apps/cli/src/next/commands/branches/create/create.handler.ts @@ -109,7 +109,8 @@ export const create = Effect.fn("branches.create")(function* (flags: CreateFlags const { project } = maybeLinkState.value; - const { branchName, gitBranch } = yield* resolveBranchName(flags.name); + const { branchName, gitBranch: detectedGitBranch } = yield* resolveBranchName(flags.name); + const gitBranch = Option.isSome(flags.gitBranch) ? flags.gitBranch : detectedGitBranch; const desiredInstanceSize = Option.getOrUndefined(flags.size); diff --git a/apps/cli/src/next/commands/branches/create/create.integration.test.ts b/apps/cli/src/next/commands/branches/create/create.integration.test.ts index ef129cf5f5..94db314cdf 100644 --- a/apps/cli/src/next/commands/branches/create/create.integration.test.ts +++ b/apps/cli/src/next/commands/branches/create/create.integration.test.ts @@ -64,6 +64,7 @@ const BASE_FLAGS: CreateFlags = { persistent: false, withData: false, notifyUrl: Option.none(), + gitBranch: Option.none(), switchAfter: true, }; @@ -316,6 +317,7 @@ describe("branches create handler", () => { persistent: true, withData: true, notifyUrl: Option.some("https://example.com/hook"), + gitBranch: Option.some("feature/login-page"), switchAfter: false, }; @@ -326,6 +328,25 @@ describe("branches create handler", () => { expect(api.capturedInput?.persistent).toBe(true); expect(api.capturedInput?.with_data).toBe(true); expect(api.capturedInput?.notify_url).toBe("https://example.com/hook"); + expect(api.capturedInput?.git_branch).toBe("feature/login-page"); + }), + ); + + it.live("prefers --git-branch over the auto-detected git branch", () => + Effect.gen(function* () { + const { layer, api } = setup({ + env: { GITHUB_HEAD_REF: "feature/auto-detect" }, + format: "json", + }); + const flags: CreateFlags = { + ...BASE_FLAGS, + gitBranch: Option.some("feature/explicit"), + }; + + yield* create(flags).pipe(Effect.provide(layer)); + + expect(api.capturedInput?.branch_name).toBe("feature/auto-detect"); + expect(api.capturedInput?.git_branch).toBe("feature/explicit"); }), );