Skip to content

Commit b4d2bce

Browse files
committed
res comments
1 parent 1d382fa commit b4d2bce

File tree

4 files changed

+238
-195
lines changed

4 files changed

+238
-195
lines changed

pkg/cmd/repo/rename/http.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package rename
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"fmt"
7+
"net/http"
8+
9+
"github.com/cli/cli/v2/api"
10+
"github.com/cli/cli/v2/internal/ghinstance"
11+
"github.com/cli/cli/v2/internal/ghrepo"
12+
)
13+
14+
type renameRepo struct {
15+
RepoHost string
16+
RepoOwner string
17+
RepoName string
18+
Name string `json:"name,omitempty"`
19+
}
20+
21+
func runRename(client *http.Client, repo ghrepo.Interface, newRepoName string) error {
22+
23+
input := renameRepo{
24+
RepoHost: repo.RepoHost(),
25+
RepoOwner: repo.RepoOwner(),
26+
RepoName: repo.RepoName(),
27+
Name: newRepoName,
28+
}
29+
30+
body, err := json.Marshal(input)
31+
if err != nil {
32+
return err
33+
}
34+
35+
path := fmt.Sprintf("%srepos/%s",
36+
ghinstance.RESTPrefix(repo.RepoHost()),
37+
ghrepo.FullName(repo))
38+
39+
request, err := http.NewRequest("PATCH", path, bytes.NewBuffer(body))
40+
if err != nil {
41+
return err
42+
}
43+
44+
response, err := client.Do(request)
45+
if err != nil {
46+
return err
47+
}
48+
defer response.Body.Close()
49+
50+
if response.StatusCode > 299 {
51+
return api.HandleHTTPError(response)
52+
}
53+
return nil
54+
}

pkg/cmd/repo/rename/http_test.go

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
package rename
2+
3+
import (
4+
"net/http"
5+
"testing"
6+
7+
"github.com/cli/cli/v2/context"
8+
"github.com/cli/cli/v2/git"
9+
"github.com/cli/cli/v2/internal/config"
10+
"github.com/cli/cli/v2/internal/ghrepo"
11+
"github.com/cli/cli/v2/internal/run"
12+
"github.com/cli/cli/v2/pkg/httpmock"
13+
"github.com/cli/cli/v2/pkg/iostreams"
14+
"github.com/cli/cli/v2/pkg/prompt"
15+
"github.com/stretchr/testify/assert"
16+
)
17+
18+
func TestRenameRun(t *testing.T) {
19+
testCases := []struct {
20+
name string
21+
opts RenameOptions
22+
httpStubs func(*httpmock.Registry)
23+
execStubs func(*run.CommandStubber)
24+
askStubs func(*prompt.AskStubber)
25+
wantOut string
26+
tty bool
27+
prompt bool
28+
}{
29+
{
30+
name: "none argument",
31+
wantOut: "✓ Renamed repository OWNER/NEW_REPO\n✓ Updated the \"origin\" remote \n",
32+
askStubs: func(q *prompt.AskStubber) {
33+
q.StubOne("NEW_REPO")
34+
},
35+
httpStubs: func(reg *httpmock.Registry) {
36+
reg.Register(
37+
httpmock.REST("PATCH", "repos/OWNER/REPO"),
38+
httpmock.StatusStringResponse(204, "{}"))
39+
},
40+
execStubs: func(cs *run.CommandStubber) {
41+
cs.Register(`git remote set-url origin https://github.com/OWNER/REPO.git`, 0, "")
42+
},
43+
tty: true,
44+
},
45+
{
46+
name: "owner repo change name prompt",
47+
opts: RenameOptions{
48+
BaseRepo: func() (ghrepo.Interface, error) {
49+
return ghrepo.New("OWNER", "REPO"), nil
50+
},
51+
},
52+
wantOut: "✓ Renamed repository OWNER/NEW_REPO\n✓ Updated the \"origin\" remote \n",
53+
askStubs: func(q *prompt.AskStubber) {
54+
q.StubOne("NEW_REPO")
55+
},
56+
httpStubs: func(reg *httpmock.Registry) {
57+
reg.Register(
58+
httpmock.REST("PATCH", "repos/OWNER/REPO"),
59+
httpmock.StatusStringResponse(204, "{}"))
60+
},
61+
execStubs: func(cs *run.CommandStubber) {
62+
cs.Register(`git remote set-url origin https://github.com/OWNER/REPO.git`, 0, "")
63+
},
64+
tty: true,
65+
},
66+
{
67+
name: "owner repo change name prompt no tty",
68+
opts: RenameOptions{
69+
BaseRepo: func() (ghrepo.Interface, error) {
70+
return ghrepo.New("OWNER", "REPO"), nil
71+
},
72+
},
73+
askStubs: func(q *prompt.AskStubber) {
74+
q.StubOne("NEW_REPO")
75+
},
76+
httpStubs: func(reg *httpmock.Registry) {
77+
reg.Register(
78+
httpmock.REST("PATCH", "repos/OWNER/REPO"),
79+
httpmock.StatusStringResponse(204, "{}"))
80+
},
81+
execStubs: func(cs *run.CommandStubber) {
82+
cs.Register(`git remote set-url origin https://github.com/OWNER/REPO.git`, 0, "")
83+
},
84+
},
85+
{
86+
name: "owner repo change name argument tty",
87+
opts: RenameOptions{
88+
BaseRepo: func() (ghrepo.Interface, error) {
89+
return ghrepo.New("OWNER", "REPO"), nil
90+
},
91+
newRepoSelector: "NEW_REPO",
92+
},
93+
wantOut: "✓ Renamed repository OWNER/NEW_REPO\n✓ Updated the \"origin\" remote \n",
94+
httpStubs: func(reg *httpmock.Registry) {
95+
reg.Register(
96+
httpmock.REST("PATCH", "repos/OWNER/REPO"),
97+
httpmock.StatusStringResponse(204, "{}"))
98+
},
99+
execStubs: func(cs *run.CommandStubber) {
100+
cs.Register(`git remote set-url origin https://github.com/OWNER/REPO.git`, 0, "")
101+
},
102+
tty: true,
103+
},
104+
{
105+
name: "owner repo change name argument no tty",
106+
opts: RenameOptions{
107+
BaseRepo: func() (ghrepo.Interface, error) {
108+
return ghrepo.New("OWNER", "REPO"), nil
109+
},
110+
newRepoSelector: "REPO",
111+
},
112+
httpStubs: func(reg *httpmock.Registry) {
113+
reg.Register(
114+
httpmock.REST("PATCH", "repos/OWNER/REPO"),
115+
httpmock.StatusStringResponse(204, "{}"))
116+
},
117+
execStubs: func(cs *run.CommandStubber) {
118+
cs.Register(`git remote set-url origin https://github.com/OWNER/REPO.git`, 0, "")
119+
},
120+
},
121+
}
122+
123+
for _, tt := range testCases {
124+
q, teardown := prompt.InitAskStubber()
125+
defer teardown()
126+
if tt.askStubs != nil {
127+
tt.askStubs(q)
128+
}
129+
130+
repo, _ := ghrepo.FromFullName("OWNER/REPO")
131+
tt.opts.BaseRepo = func() (ghrepo.Interface, error) {
132+
return repo, nil
133+
}
134+
135+
tt.opts.Config = func() (config.Config, error) {
136+
return config.NewBlankConfig(), nil
137+
}
138+
139+
tt.opts.Remotes = func() (context.Remotes, error) {
140+
return []*context.Remote{
141+
{
142+
Remote: &git.Remote{Name: "origin"},
143+
Repo: repo,
144+
},
145+
}, nil
146+
}
147+
148+
reg := &httpmock.Registry{}
149+
if tt.httpStubs != nil {
150+
tt.httpStubs(reg)
151+
}
152+
tt.opts.HttpClient = func() (*http.Client, error) {
153+
return &http.Client{Transport: reg}, nil
154+
}
155+
156+
io, _, stdout, _ := iostreams.Test()
157+
io.SetStdinTTY(tt.tty)
158+
io.SetStdoutTTY(tt.tty)
159+
tt.opts.IO = io
160+
161+
t.Run(tt.name, func(t *testing.T) {
162+
defer reg.Verify(t)
163+
err := renameRun(&tt.opts)
164+
assert.NoError(t, err)
165+
assert.Equal(t, tt.wantOut, stdout.String())
166+
})
167+
}
168+
}

pkg/cmd/repo/rename/rename.go

Lines changed: 16 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
package rename
22

33
import (
4-
"bytes"
5-
"encoding/json"
64
"errors"
75
"fmt"
86
"net/http"
97

108
"github.com/AlecAivazis/survey/v2"
119
"github.com/MakeNowJust/heredoc"
12-
"github.com/cli/cli/v2/api"
1310
"github.com/cli/cli/v2/context"
1411
"github.com/cli/cli/v2/git"
1512
"github.com/cli/cli/v2/internal/config"
@@ -30,13 +27,6 @@ type RenameOptions struct {
3027
newRepoSelector string
3128
}
3229

33-
type renameRepo struct {
34-
RepoHost string
35-
RepoOwner string
36-
RepoName string
37-
Name string `json:"name,omitempty"`
38-
}
39-
4030
func NewCmdRename(f *cmdutil.Factory, runf func(*RenameOptions) error) *cobra.Command {
4131
opts := &RenameOptions{
4232
IO: f.IOStreams,
@@ -46,15 +36,11 @@ func NewCmdRename(f *cmdutil.Factory, runf func(*RenameOptions) error) *cobra.Co
4636
}
4737

4838
cmd := &cobra.Command{
49-
Use: "rename [<repository>] [<new-name>]",
39+
Use: "rename [<new-name>]",
5040
Short: "Rename a repository",
5141
Long: heredoc.Doc(`Rename a GitHub repository
52-
53-
With no argument, the repository for the current directory is renamed using a prompt
54-
55-
With one argument, the repository of the current directory is renamed using the argument
56-
57-
With '-R', and two arguments the given repository is replaced with the new name`),
42+
43+
By default, renames the current repository otherwise rename the specified repository.`),
5844
Args: cobra.MaximumNArgs(1),
5945
RunE: func(cmd *cobra.Command, args []string) error {
6046
opts.BaseRepo = f.BaseRepo
@@ -63,7 +49,7 @@ func NewCmdRename(f *cmdutil.Factory, runf func(*RenameOptions) error) *cobra.Co
6349
if len(args) > 0 {
6450
opts.newRepoSelector = args[0]
6551
} else if !opts.IO.CanPrompt() {
66-
return &cmdutil.FlagError{Err: errors.New("could not prompt: proceed with a repo name")}
52+
return &cmdutil.FlagError{Err: errors.New("could not prompt: new name required when not running interactively")}
6753
}
6854

6955
if runf != nil {
@@ -83,12 +69,9 @@ func renameRun(opts *RenameOptions) error {
8369
if err != nil {
8470
return err
8571
}
86-
apiClient := api.NewClientFromHTTP(httpClient)
8772

88-
var input renameRepo
8973
var newRepo ghrepo.Interface
9074
var baseRemote *context.Remote
91-
var remoteUpdateError error
9275
newRepoName := opts.newRepoSelector
9376

9477
currRepo, err := opts.BaseRepo()
@@ -99,7 +82,7 @@ func renameRun(opts *RenameOptions) error {
9982
if newRepoName == "" {
10083
err = prompt.SurveyAskOne(
10184
&survey.Input{
102-
Message: fmt.Sprintf("Rename %s to: ", currRepo.RepoOwner()+"/"+currRepo.RepoName()),
85+
Message: fmt.Sprintf("Rename %s to: ", ghrepo.FullName(currRepo)),
10386
},
10487
&newRepoName,
10588
)
@@ -108,21 +91,20 @@ func renameRun(opts *RenameOptions) error {
10891
}
10992
}
11093

111-
input = renameRepo{
112-
RepoHost: currRepo.RepoHost(),
113-
RepoOwner: currRepo.RepoOwner(),
114-
RepoName: currRepo.RepoName(),
115-
Name: newRepoName,
116-
}
117-
11894
newRepo = ghrepo.NewWithHost(currRepo.RepoOwner(), newRepoName, currRepo.RepoHost())
11995

120-
err = runRename(apiClient, currRepo.RepoHost(), input)
96+
err = runRename(httpClient, currRepo, newRepoName)
12197
if err != nil {
122-
return fmt.Errorf("API called failed: %s, please check your parameters", err)
98+
return fmt.Errorf("API called failed: %s", err)
99+
}
100+
101+
if opts.IO.IsStdoutTTY() {
102+
cs := opts.IO.ColorScheme()
103+
fmt.Fprintf(opts.IO.Out, "%s Renamed repository %s\n", cs.SuccessIcon(), ghrepo.FullName(newRepo))
123104
}
124105

125106
if !opts.HasRepoOverride {
107+
cs := opts.IO.ColorScheme()
126108
cfg, err := opts.Config()
127109
if err != nil {
128110
return err
@@ -132,30 +114,13 @@ func renameRun(opts *RenameOptions) error {
132114
remotes, _ := opts.Remotes()
133115
baseRemote, _ = remotes.FindByRepo(currRepo.RepoOwner(), currRepo.RepoName())
134116
remoteURL := ghrepo.FormatRemoteURL(newRepo, protocol)
135-
remoteUpdateError = git.UpdateRemoteURL(baseRemote.Name, remoteURL)
136-
if remoteUpdateError != nil {
137-
cs := opts.IO.ColorScheme()
117+
err = git.UpdateRemoteURL(baseRemote.Name, remoteURL)
118+
if err != nil {
138119
fmt.Fprintf(opts.IO.ErrOut, "%s warning: unable to update remote '%s' \n", cs.WarningIcon(), err)
139120
}
140-
}
141-
142-
if opts.IO.IsStdoutTTY() {
143-
cs := opts.IO.ColorScheme()
144-
fmt.Fprintf(opts.IO.Out, "%s Renamed repository %s\n", cs.SuccessIcon(), input.RepoOwner+"/"+input.Name)
145-
if !opts.HasRepoOverride && remoteUpdateError == nil {
121+
if opts.IO.IsStdoutTTY() {
146122
fmt.Fprintf(opts.IO.Out, "%s Updated the %q remote \n", cs.SuccessIcon(), baseRemote.Name)
147123
}
148124
}
149125
return nil
150126
}
151-
152-
func runRename(apiClient *api.Client, hostname string, input renameRepo) error {
153-
path := fmt.Sprintf("repos/%s/%s", input.RepoOwner, input.RepoName)
154-
body := &bytes.Buffer{}
155-
enc := json.NewEncoder(body)
156-
if err := enc.Encode(input); err != nil {
157-
return err
158-
}
159-
160-
return apiClient.REST(hostname, "PATCH", path, body, nil)
161-
}

0 commit comments

Comments
 (0)