github.com/ungtb10d/cli/v2@v2.0.0-20221110210412-98537dd9d6a1/pkg/cmd/repo/rename/rename.go (about) 1 package rename 2 3 import ( 4 "context" 5 "fmt" 6 "net/http" 7 8 "github.com/AlecAivazis/survey/v2" 9 "github.com/MakeNowJust/heredoc" 10 "github.com/ungtb10d/cli/v2/api" 11 ghContext "github.com/ungtb10d/cli/v2/context" 12 "github.com/ungtb10d/cli/v2/git" 13 "github.com/ungtb10d/cli/v2/internal/config" 14 "github.com/ungtb10d/cli/v2/internal/ghrepo" 15 "github.com/ungtb10d/cli/v2/pkg/cmdutil" 16 "github.com/ungtb10d/cli/v2/pkg/iostreams" 17 "github.com/ungtb10d/cli/v2/pkg/prompt" 18 "github.com/spf13/cobra" 19 ) 20 21 type RenameOptions struct { 22 HttpClient func() (*http.Client, error) 23 GitClient *git.Client 24 IO *iostreams.IOStreams 25 Config func() (config.Config, error) 26 BaseRepo func() (ghrepo.Interface, error) 27 Remotes func() (ghContext.Remotes, error) 28 DoConfirm bool 29 HasRepoOverride bool 30 newRepoSelector string 31 } 32 33 func NewCmdRename(f *cmdutil.Factory, runf func(*RenameOptions) error) *cobra.Command { 34 opts := &RenameOptions{ 35 IO: f.IOStreams, 36 HttpClient: f.HttpClient, 37 GitClient: f.GitClient, 38 Remotes: f.Remotes, 39 Config: f.Config, 40 } 41 42 var confirm bool 43 44 cmd := &cobra.Command{ 45 Use: "rename [<new-name>]", 46 Short: "Rename a repository", 47 Long: heredoc.Doc(`Rename a GitHub repository. 48 49 By default, this renames the current repository; otherwise renames the specified repository.`), 50 Args: cobra.MaximumNArgs(1), 51 RunE: func(cmd *cobra.Command, args []string) error { 52 opts.BaseRepo = f.BaseRepo 53 opts.HasRepoOverride = cmd.Flags().Changed("repo") 54 55 if len(args) > 0 { 56 opts.newRepoSelector = args[0] 57 } else if !opts.IO.CanPrompt() { 58 return cmdutil.FlagErrorf("new name argument required when not running interactively") 59 } 60 61 if len(args) == 1 && !confirm && !opts.HasRepoOverride { 62 if !opts.IO.CanPrompt() { 63 return cmdutil.FlagErrorf("--confirm required when passing a single argument") 64 } 65 opts.DoConfirm = true 66 } 67 68 if runf != nil { 69 return runf(opts) 70 } 71 return renameRun(opts) 72 }, 73 } 74 75 cmdutil.EnableRepoOverride(cmd, f) 76 cmd.Flags().BoolVarP(&confirm, "confirm", "y", false, "skip confirmation prompt") 77 78 return cmd 79 } 80 81 func renameRun(opts *RenameOptions) error { 82 httpClient, err := opts.HttpClient() 83 if err != nil { 84 return err 85 } 86 87 newRepoName := opts.newRepoSelector 88 89 currRepo, err := opts.BaseRepo() 90 if err != nil { 91 return err 92 } 93 94 if newRepoName == "" { 95 //nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter 96 err = prompt.SurveyAskOne( 97 &survey.Input{ 98 Message: fmt.Sprintf("Rename %s to: ", ghrepo.FullName(currRepo)), 99 }, 100 &newRepoName, 101 ) 102 if err != nil { 103 return err 104 } 105 } 106 107 if opts.DoConfirm { 108 var confirmed bool 109 p := &survey.Confirm{ 110 Message: fmt.Sprintf("Rename %s to %s?", ghrepo.FullName(currRepo), newRepoName), 111 Default: false, 112 } 113 //nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter 114 err = prompt.SurveyAskOne(p, &confirmed) 115 if err != nil { 116 return fmt.Errorf("failed to prompt: %w", err) 117 } 118 if !confirmed { 119 return nil 120 } 121 } 122 123 apiClient := api.NewClientFromHTTP(httpClient) 124 125 newRepo, err := api.RenameRepo(apiClient, currRepo, newRepoName) 126 if err != nil { 127 return err 128 } 129 130 renamedRepo := ghrepo.New(newRepo.Owner.Login, newRepo.Name) 131 132 cs := opts.IO.ColorScheme() 133 if opts.IO.IsStdoutTTY() { 134 fmt.Fprintf(opts.IO.Out, "%s Renamed repository %s\n", cs.SuccessIcon(), ghrepo.FullName(newRepo)) 135 } 136 137 if opts.HasRepoOverride { 138 return nil 139 } 140 141 remote, err := updateRemote(currRepo, renamedRepo, opts) 142 if err != nil { 143 fmt.Fprintf(opts.IO.ErrOut, "%s Warning: unable to update remote %q: %v\n", cs.WarningIcon(), remote.Name, err) 144 } else if opts.IO.IsStdoutTTY() { 145 fmt.Fprintf(opts.IO.Out, "%s Updated the %q remote\n", cs.SuccessIcon(), remote.Name) 146 } 147 148 return nil 149 } 150 151 func updateRemote(repo ghrepo.Interface, renamed ghrepo.Interface, opts *RenameOptions) (*ghContext.Remote, error) { 152 cfg, err := opts.Config() 153 if err != nil { 154 return nil, err 155 } 156 157 protocol, err := cfg.GetOrDefault(repo.RepoHost(), "git_protocol") 158 if err != nil { 159 return nil, err 160 } 161 162 remotes, err := opts.Remotes() 163 if err != nil { 164 return nil, err 165 } 166 167 remote, err := remotes.FindByRepo(repo.RepoOwner(), repo.RepoName()) 168 if err != nil { 169 return nil, err 170 } 171 172 remoteURL := ghrepo.FormatRemoteURL(renamed, protocol) 173 err = opts.GitClient.UpdateRemoteURL(context.Background(), remote.Name, remoteURL) 174 175 return remote, err 176 }