From 63bc90ea521e54a8c9636a1216a2931ecad66547 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Cepl?= Date: Wed, 15 Apr 2026 17:27:47 +0000 Subject: [PATCH] feat(branches): add rename subcommand (#939) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements the 'branches rename' command to rename a branch in a repository. This wraps the Gitea API endpoint PATCH /repos/{owner}/{repo}/branches/{branch}. Usage: tea branches rename Example: tea branches rename -r owner/repo main factory This resolves issue #938. Reviewed-on: https://gitea.com/gitea/tea/pulls/939 Reviewed-by: Lunny Xiao Co-authored-by: Matěj Cepl Co-committed-by: Matěj Cepl --- cmd/branches.go | 1 + cmd/branches/rename.go | 78 +++++++++++++++++++++++++++++++++++++ cmd/branches/rename_test.go | 46 ++++++++++++++++++++++ docs/CLI.md | 20 ++++++++++ 4 files changed, 145 insertions(+) create mode 100644 cmd/branches/rename.go create mode 100644 cmd/branches/rename_test.go diff --git a/cmd/branches.go b/cmd/branches.go index 557688c..625b412 100644 --- a/cmd/branches.go +++ b/cmd/branches.go @@ -24,6 +24,7 @@ var CmdBranches = cli.Command{ &branches.CmdBranchesList, &branches.CmdBranchesProtect, &branches.CmdBranchesUnprotect, + &branches.CmdBranchesRename, }, Flags: append([]cli.Flag{ &cli.BoolFlag{ diff --git a/cmd/branches/rename.go b/cmd/branches/rename.go new file mode 100644 index 0000000..bf99cec --- /dev/null +++ b/cmd/branches/rename.go @@ -0,0 +1,78 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package branches + +import ( + stdctx "context" + "fmt" + + "code.gitea.io/tea/cmd/flags" + "code.gitea.io/tea/modules/context" + + "code.gitea.io/sdk/gitea" + "github.com/urfave/cli/v3" +) + +// CmdBranchesRenameFlags Flags for command rename +var CmdBranchesRenameFlags = append([]cli.Flag{ + branchFieldsFlag, + &flags.PaginationPageFlag, + &flags.PaginationLimitFlag, +}, flags.AllDefaultFlags...) + +// CmdBranchesRename represents a sub command of branches to rename a branch +var CmdBranchesRename = cli.Command{ + Name: "rename", + Aliases: []string{"rn"}, + Usage: "Rename a branch", + Description: `Rename a branch in a repository`, + ArgsUsage: " ", + Action: RunBranchesRename, + Flags: CmdBranchesRenameFlags, +} + +// RunBranchesRename function to rename a branch +func RunBranchesRename(_ stdctx.Context, cmd *cli.Command) error { + ctx, err := context.InitCommand(cmd) + if err != nil { + return err + } + if err := ctx.Ensure(context.CtxRequirement{RemoteRepo: true}); err != nil { + return err + } + + if err := ValidateRenameArgs(ctx.Args().Slice()); err != nil { + return err + } + + oldBranchName := ctx.Args().Get(0) + newBranchName := ctx.Args().Get(1) + + owner := ctx.Owner + if ctx.IsSet("owner") { + owner = ctx.String("owner") + } + + successful, _, err := ctx.Login.Client().RenameRepoBranch(owner, ctx.Repo, oldBranchName, gitea.RenameRepoBranchOption{ + Name: newBranchName, + }) + if err != nil { + return fmt.Errorf("failed to rename branch: %w", err) + } + if !successful { + return fmt.Errorf("failed to rename branch") + } + + fmt.Printf("Successfully renamed branch '%s' to '%s'\n", oldBranchName, newBranchName) + + return nil +} + +// ValidateRenameArgs validates arguments for the rename command +func ValidateRenameArgs(args []string) error { + if len(args) != 2 { + return fmt.Errorf("must specify exactly two arguments: ") + } + return nil +} diff --git a/cmd/branches/rename_test.go b/cmd/branches/rename_test.go new file mode 100644 index 0000000..cf3efd7 --- /dev/null +++ b/cmd/branches/rename_test.go @@ -0,0 +1,46 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package branches + +import ( + "testing" +) + +func TestBranchesRenameArgs(t *testing.T) { + tests := []struct { + name string + args []string + wantErr bool + }{ + { + name: "valid args", + args: []string{"main", "develop"}, + wantErr: false, + }, + { + name: "missing both args", + args: []string{}, + wantErr: true, + }, + { + name: "missing new branch name", + args: []string{"main"}, + wantErr: true, + }, + { + name: "too many args", + args: []string{"main", "develop", "extra"}, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := ValidateRenameArgs(tt.args) + if (err != nil) != tt.wantErr { + t.Errorf("ValidateRenameArgs() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/docs/CLI.md b/docs/CLI.md index 05f43e5..5a79d0e 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -1381,6 +1381,26 @@ Unprotect branches **--repo, -r**="": Override local repository path or gitea repository slug to interact with. Optional +### rename, rn + +Rename a branch + +**--fields, -f**="": Comma-separated list of fields to print. Available values: + name,protected,user-can-merge,user-can-push,protection + (default: "name,protected,user-can-merge,user-can-push") + +**--limit, --lm**="": specify limit of items per page (default: 30) + +**--login, -l**="": Use a different Gitea Login. Optional + +**--output, -o**="": Output format. (simple, table, csv, tsv, yaml, json) + +**--page, -p**="": specify page (default: 1) + +**--remote, -R**="": Discover Gitea login from remote. Optional + +**--repo, -r**="": Override local repository path or gitea repository slug to interact with. Optional + ## actions, action Manage repository actions