diff --git a/github/repos.go b/github/repos.go index f6236b432f7..98d62882310 100644 --- a/github/repos.go +++ b/github/repos.go @@ -1037,6 +1037,34 @@ func (s *RepositoriesService) getBranchFromURL(ctx context.Context, u string, fo return resp, err } +// renameBranchRequest represents a request to rename a branch. +type renameBranchRequest struct { + NewName string `json:"new_name"` +} + +// RenameBranch renames a branch in a repository. +// +// To rename a non-default branch: Users must have push access. GitHub Apps must have the `contents:write` repository permission. +// To rename the default branch: Users must have admin or owner permissions. GitHub Apps must have the `administration:write` repository permission. +// +// GitHub API docs: https://docs.github.com/en/rest/reference/repos#rename-a-branch +func (s *RepositoriesService) RenameBranch(ctx context.Context, owner, repo, branch, newName string) (*Branch, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/branches/%v/rename", owner, repo, branch) + r := &renameBranchRequest{NewName: newName} + req, err := s.client.NewRequest("POST", u, r) + if err != nil { + return nil, nil, err + } + + b := new(Branch) + resp, err := s.client.Do(ctx, req, b) + if err != nil { + return nil, resp, err + } + + return b, resp, nil +} + // GetBranchProtection gets the protection of a given branch. // // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#get-branch-protection diff --git a/github/repos_test.go b/github/repos_test.go index 4c799048abb..e2a5d5931f3 100644 --- a/github/repos_test.go +++ b/github/repos_test.go @@ -981,6 +981,51 @@ func TestRepositoriesService_GetBranch_notFound(t *testing.T) { }) } +func TestRepositoriesService_RenameBranch(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + renameBranchReq := "nn" + + mux.HandleFunc("/repos/o/r/branches/b/rename", func(w http.ResponseWriter, r *http.Request) { + v := new(renameBranchRequest) + json.NewDecoder(r.Body).Decode(v) + + testMethod(t, r, "POST") + want := &renameBranchRequest{NewName: "nn"} + if !cmp.Equal(v, want) { + t.Errorf("Request body = %+v, want %+v", v, want) + } + + fmt.Fprint(w, `{"protected":true,"name":"nn"}`) + }) + + ctx := context.Background() + got, _, err := client.Repositories.RenameBranch(ctx, "o", "r", "b", renameBranchReq) + if err != nil { + t.Errorf("Repositories.RenameBranch returned error: %v", err) + } + + want := &Branch{Name: String("nn"), Protected: Bool(true)} + if !cmp.Equal(got, want) { + t.Errorf("Repositories.RenameBranch returned %+v, want %+v", got, want) + } + + const methodName = "RenameBranch" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.RenameBranch(ctx, "\n", "\n", "\n", renameBranchReq) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.RenameBranch(ctx, "o", "r", "b", renameBranchReq) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + func TestRepositoriesService_GetBranchProtection(t *testing.T) { client, mux, _, teardown := setup() defer teardown()