172 lines
4.3 KiB
Go
172 lines
4.3 KiB
Go
package rename
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/MakeNowJust/heredoc"
|
|
"github.com/cli/cli/v2/api"
|
|
ghContext "github.com/cli/cli/v2/context"
|
|
"github.com/cli/cli/v2/git"
|
|
"github.com/cli/cli/v2/internal/gh"
|
|
"github.com/cli/cli/v2/internal/ghrepo"
|
|
"github.com/cli/cli/v2/pkg/cmdutil"
|
|
"github.com/cli/cli/v2/pkg/iostreams"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
type iprompter interface {
|
|
Input(string, string) (string, error)
|
|
Confirm(string, bool) (bool, error)
|
|
}
|
|
|
|
type RenameOptions struct {
|
|
HttpClient func() (*http.Client, error)
|
|
GitClient *git.Client
|
|
IO *iostreams.IOStreams
|
|
Prompter iprompter
|
|
Config func() (gh.Config, error)
|
|
BaseRepo func() (ghrepo.Interface, error)
|
|
Remotes func() (ghContext.Remotes, error)
|
|
DoConfirm bool
|
|
HasRepoOverride bool
|
|
newRepoSelector string
|
|
}
|
|
|
|
func NewCmdRename(f *cmdutil.Factory, runf func(*RenameOptions) error) *cobra.Command {
|
|
opts := &RenameOptions{
|
|
IO: f.IOStreams,
|
|
HttpClient: f.HttpClient,
|
|
GitClient: f.GitClient,
|
|
Remotes: f.Remotes,
|
|
Config: f.Config,
|
|
Prompter: f.Prompter,
|
|
}
|
|
|
|
var confirm bool
|
|
|
|
cmd := &cobra.Command{
|
|
Use: "rename [<new-name>]",
|
|
Short: "Rename a repository",
|
|
Long: heredoc.Doc(`Rename a GitHub repository.
|
|
|
|
By default, this renames the current repository; otherwise renames the specified repository.`),
|
|
Args: cobra.MaximumNArgs(1),
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
opts.BaseRepo = f.BaseRepo
|
|
opts.HasRepoOverride = cmd.Flags().Changed("repo")
|
|
|
|
if len(args) > 0 {
|
|
opts.newRepoSelector = args[0]
|
|
} else if !opts.IO.CanPrompt() {
|
|
return cmdutil.FlagErrorf("new name argument required when not running interactively")
|
|
}
|
|
|
|
if len(args) == 1 && !confirm && !opts.HasRepoOverride {
|
|
if !opts.IO.CanPrompt() {
|
|
return cmdutil.FlagErrorf("--yes required when passing a single argument")
|
|
}
|
|
opts.DoConfirm = true
|
|
}
|
|
|
|
if runf != nil {
|
|
return runf(opts)
|
|
}
|
|
|
|
return renameRun(opts)
|
|
},
|
|
}
|
|
|
|
cmdutil.EnableRepoOverride(cmd, f)
|
|
cmd.Flags().BoolVar(&confirm, "confirm", false, "Skip confirmation prompt")
|
|
_ = cmd.Flags().MarkDeprecated("confirm", "use `--yes` instead")
|
|
cmd.Flags().BoolVarP(&confirm, "yes", "y", false, "Skip the confirmation prompt")
|
|
|
|
return cmd
|
|
}
|
|
|
|
func renameRun(opts *RenameOptions) error {
|
|
httpClient, err := opts.HttpClient()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
newRepoName := opts.newRepoSelector
|
|
|
|
currRepo, err := opts.BaseRepo()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if newRepoName == "" {
|
|
if newRepoName, err = opts.Prompter.Input(fmt.Sprintf(
|
|
"Rename %s to:", ghrepo.FullName(currRepo)), ""); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if opts.DoConfirm {
|
|
var confirmed bool
|
|
if confirmed, err = opts.Prompter.Confirm(fmt.Sprintf(
|
|
"Rename %s to %s?", ghrepo.FullName(currRepo), newRepoName), false); err != nil {
|
|
return err
|
|
}
|
|
if !confirmed {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
apiClient := api.NewClientFromHTTP(httpClient)
|
|
|
|
newRepo, err := api.RenameRepo(apiClient, currRepo, newRepoName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
cs := opts.IO.ColorScheme()
|
|
if opts.IO.IsStdoutTTY() {
|
|
fmt.Fprintf(opts.IO.Out, "%s Renamed repository %s\n", cs.SuccessIcon(), ghrepo.FullName(newRepo))
|
|
}
|
|
|
|
if opts.HasRepoOverride {
|
|
return nil
|
|
}
|
|
|
|
remote, err := updateRemote(currRepo, newRepo, opts)
|
|
if err != nil {
|
|
if remote != nil {
|
|
fmt.Fprintf(opts.IO.ErrOut, "%s Warning: unable to update remote %q: %v\n", cs.WarningIcon(), remote.Name, err)
|
|
} else {
|
|
fmt.Fprintf(opts.IO.ErrOut, "%s Warning: unable to update remote: %v\n", cs.WarningIcon(), err)
|
|
}
|
|
} else if opts.IO.IsStdoutTTY() {
|
|
fmt.Fprintf(opts.IO.Out, "%s Updated the %q remote\n", cs.SuccessIcon(), remote.Name)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func updateRemote(repo ghrepo.Interface, renamed ghrepo.Interface, opts *RenameOptions) (*ghContext.Remote, error) {
|
|
cfg, err := opts.Config()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
protocol := cfg.GitProtocol(repo.RepoHost()).Value
|
|
|
|
remotes, err := opts.Remotes()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
remote, err := remotes.FindByRepo(repo.RepoOwner(), repo.RepoName())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
remoteURL := ghrepo.FormatRemoteURL(renamed, protocol)
|
|
err = opts.GitClient.UpdateRemoteURL(context.Background(), remote.Name, remoteURL)
|
|
|
|
return remote, err
|
|
}
|