Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions pkg/cmd/repo/create/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,10 +262,15 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co

func createRun(opts *CreateOptions) error {
if opts.Interactive {
cfg, err := opts.Config()
if err != nil {
return err
}
host, _ := cfg.Authentication().DefaultHost()
answer, err := opts.Prompter.Select("What would you like to do?", "", []string{
"Create a new repository on GitHub from scratch",
"Create a new repository on GitHub from a template repository",
"Push an existing local repository to GitHub",
fmt.Sprintf("Create a new repository on %s from scratch", host),
fmt.Sprintf("Create a new repository on %s from a template repository", host),
fmt.Sprintf("Push an existing local repository to %s", host),
})
if err != nil {
return err
Expand Down Expand Up @@ -323,7 +328,9 @@ func createFromScratch(opts *CreateOptions) error {
if idx := strings.IndexRune(opts.Name, '/'); idx > 0 {
targetRepo = opts.Name[0:idx+1] + shared.NormalizeRepoName(opts.Name[idx+1:])
}
confirmed, err := opts.Prompter.Confirm(fmt.Sprintf(`This will create "%s" as a %s repository on GitHub. Continue?`, targetRepo, strings.ToLower(opts.Visibility)), true)
confirmed, err := opts.Prompter.Confirm(
fmt.Sprintf(`This will create "%s" as a %s repository on %s. Continue?`, targetRepo, strings.ToLower(opts.Visibility), host),
true)
if err != nil {
return err
} else if !confirmed {
Expand Down Expand Up @@ -392,9 +399,10 @@ func createFromScratch(opts *CreateOptions) error {
isTTY := opts.IO.IsStdoutTTY()
if isTTY {
fmt.Fprintf(opts.IO.Out,
"%s Created repository %s on GitHub\n %s\n",
"%s Created repository %s on %s\n %s\n",
cs.SuccessIconWithColor(cs.Green),
ghrepo.FullName(repo),
host,
repo.URL)
} else {
fmt.Fprintln(opts.IO.Out, repo.URL)
Expand Down Expand Up @@ -482,7 +490,9 @@ func createFromTemplate(opts *CreateOptions) error {
if idx := strings.IndexRune(opts.Name, '/'); idx > 0 {
targetRepo = opts.Name[0:idx+1] + shared.NormalizeRepoName(opts.Name[idx+1:])
}
confirmed, err := opts.Prompter.Confirm(fmt.Sprintf(`This will create "%s" as a %s repository on GitHub. Continue?`, targetRepo, strings.ToLower(opts.Visibility)), true)
confirmed, err := opts.Prompter.Confirm(
fmt.Sprintf(`This will create "%s" as a %s repository on %s. Continue?`, targetRepo, strings.ToLower(opts.Visibility), host),
true)
if err != nil {
return err
} else if !confirmed {
Expand All @@ -496,9 +506,10 @@ func createFromTemplate(opts *CreateOptions) error {

cs := opts.IO.ColorScheme()
fmt.Fprintf(opts.IO.Out,
"%s Created repository %s on GitHub\n %s\n",
"%s Created repository %s on %s\n %s\n",
cs.SuccessIconWithColor(cs.Green),
ghrepo.FullName(repo),
host,
repo.URL)

opts.Clone, err = opts.Prompter.Confirm("Clone the new repository locally?", true)
Expand Down Expand Up @@ -622,9 +633,10 @@ func createFromLocal(opts *CreateOptions) error {

if isTTY {
fmt.Fprintf(stdout,
"%s Created repository %s on GitHub\n %s\n",
"%s Created repository %s on %s\n %s\n",
cs.SuccessIconWithColor(cs.Green),
ghrepo.FullName(repo),
host,
repo.URL)
} else {
fmt.Fprintln(stdout, repo.URL)
Expand Down
126 changes: 106 additions & 20 deletions pkg/cmd/repo/create/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/cli/cli/v2/git"
"github.com/cli/cli/v2/internal/config"
"github.com/cli/cli/v2/internal/gh"
ghmock "github.com/cli/cli/v2/internal/gh/mock"
"github.com/cli/cli/v2/internal/prompter"
"github.com/cli/cli/v2/internal/run"
"github.com/cli/cli/v2/pkg/cmdutil"
Expand Down Expand Up @@ -201,7 +202,7 @@ func Test_createRun(t *testing.T) {
name: "interactive create from scratch with gitignore and license",
opts: &CreateOptions{Interactive: true},
tty: true,
wantStdout: "✓ Created repository OWNER/REPO on GitHub\n https://github.com/OWNER/REPO\n",
wantStdout: "✓ Created repository OWNER/REPO on github.com\n https://github.com/OWNER/REPO\n",
promptStubs: func(p *prompter.PrompterMock) {
p.ConfirmFunc = func(message string, defaultValue bool) (bool, error) {
switch message {
Expand All @@ -211,7 +212,7 @@ func Test_createRun(t *testing.T) {
return true, nil
case "Would you like to add a license?":
return true, nil
case `This will create "REPO" as a private repository on GitHub. Continue?`:
case `This will create "REPO" as a private repository on github.com. Continue?`:
return defaultValue, nil
case "Clone the new repository locally?":
return defaultValue, nil
Expand All @@ -232,7 +233,7 @@ func Test_createRun(t *testing.T) {
p.SelectFunc = func(message, defaultValue string, options []string) (int, error) {
switch message {
case "What would you like to do?":
return prompter.IndexFor(options, "Create a new repository on GitHub from scratch")
return prompter.IndexFor(options, "Create a new repository on github.com from scratch")
case "Visibility":
return prompter.IndexFor(options, "Private")
case "Choose a license":
Expand Down Expand Up @@ -267,7 +268,7 @@ func Test_createRun(t *testing.T) {
name: "interactive create from scratch but with prompted owner",
opts: &CreateOptions{Interactive: true},
tty: true,
wantStdout: "✓ Created repository org1/REPO on GitHub\n https://github.com/org1/REPO\n",
wantStdout: "✓ Created repository org1/REPO on github.com\n https://github.com/org1/REPO\n",
promptStubs: func(p *prompter.PrompterMock) {
p.ConfirmFunc = func(message string, defaultValue bool) (bool, error) {
switch message {
Expand All @@ -277,7 +278,7 @@ func Test_createRun(t *testing.T) {
return false, nil
case "Would you like to add a license?":
return false, nil
case `This will create "org1/REPO" as a private repository on GitHub. Continue?`:
case `This will create "org1/REPO" as a private repository on github.com. Continue?`:
return true, nil
case "Clone the new repository locally?":
return false, nil
Expand All @@ -300,7 +301,7 @@ func Test_createRun(t *testing.T) {
case "Repository owner":
return prompter.IndexFor(options, "org1")
case "What would you like to do?":
return prompter.IndexFor(options, "Create a new repository on GitHub from scratch")
return prompter.IndexFor(options, "Create a new repository on github.com from scratch")
case "Visibility":
return prompter.IndexFor(options, "Private")
default:
Expand Down Expand Up @@ -345,7 +346,7 @@ func Test_createRun(t *testing.T) {
return false, nil
case "Would you like to add a license?":
return false, nil
case `This will create "REPO" as a private repository on GitHub. Continue?`:
case `This will create "REPO" as a private repository on github.com. Continue?`:
return false, nil
default:
return false, fmt.Errorf("unexpected confirm prompt: %s", message)
Expand All @@ -364,7 +365,7 @@ func Test_createRun(t *testing.T) {
p.SelectFunc = func(message, defaultValue string, options []string) (int, error) {
switch message {
case "What would you like to do?":
return prompter.IndexFor(options, "Create a new repository on GitHub from scratch")
return prompter.IndexFor(options, "Create a new repository on github.com from scratch")
case "Visibility":
return prompter.IndexFor(options, "Private")
default:
Expand Down Expand Up @@ -409,7 +410,7 @@ func Test_createRun(t *testing.T) {
p.SelectFunc = func(message, defaultValue string, options []string) (int, error) {
switch message {
case "What would you like to do?":
return prompter.IndexFor(options, "Push an existing local repository to GitHub")
return prompter.IndexFor(options, "Push an existing local repository to github.com")
case "Visibility":
return prompter.IndexFor(options, "Private")
default:
Expand Down Expand Up @@ -441,7 +442,7 @@ func Test_createRun(t *testing.T) {
cs.Register(`git -C . rev-parse --git-dir`, 0, ".git")
cs.Register(`git -C . rev-parse HEAD`, 0, "commithash")
},
wantStdout: "✓ Created repository OWNER/REPO on GitHub\n https://github.com/OWNER/REPO\n",
wantStdout: "✓ Created repository OWNER/REPO on github.com\n https://github.com/OWNER/REPO\n",
},
{
name: "interactive with existing bare repository public and push",
Expand Down Expand Up @@ -475,7 +476,7 @@ func Test_createRun(t *testing.T) {
p.SelectFunc = func(message, defaultValue string, options []string) (int, error) {
switch message {
case "What would you like to do?":
return prompter.IndexFor(options, "Push an existing local repository to GitHub")
return prompter.IndexFor(options, "Push an existing local repository to github.com")
case "Visibility":
return prompter.IndexFor(options, "Private")
default:
Expand Down Expand Up @@ -509,7 +510,7 @@ func Test_createRun(t *testing.T) {
cs.Register(`git -C . remote add origin https://github.com/OWNER/REPO`, 0, "")
cs.Register(`git -C . push origin --mirror`, 0, "")
},
wantStdout: "✓ Created repository OWNER/REPO on GitHub\n https://github.com/OWNER/REPO\n✓ Added remote https://github.com/OWNER/REPO.git\n✓ Mirrored all refs to https://github.com/OWNER/REPO.git\n",
wantStdout: "✓ Created repository OWNER/REPO on github.com\n https://github.com/OWNER/REPO\n✓ Added remote https://github.com/OWNER/REPO.git\n✓ Mirrored all refs to https://github.com/OWNER/REPO.git\n",
},
{
name: "interactive with existing repository public add remote and push",
Expand Down Expand Up @@ -543,7 +544,7 @@ func Test_createRun(t *testing.T) {
p.SelectFunc = func(message, defaultValue string, options []string) (int, error) {
switch message {
case "What would you like to do?":
return prompter.IndexFor(options, "Push an existing local repository to GitHub")
return prompter.IndexFor(options, "Push an existing local repository to github.com")
case "Visibility":
return prompter.IndexFor(options, "Private")
default:
Expand Down Expand Up @@ -577,7 +578,7 @@ func Test_createRun(t *testing.T) {
cs.Register(`git -C . remote add origin https://github.com/OWNER/REPO`, 0, "")
cs.Register(`git -C . push --set-upstream origin HEAD`, 0, "")
},
wantStdout: "✓ Created repository OWNER/REPO on GitHub\n https://github.com/OWNER/REPO\n✓ Added remote https://github.com/OWNER/REPO.git\n✓ Pushed commits to https://github.com/OWNER/REPO.git\n",
wantStdout: "✓ Created repository OWNER/REPO on github.com\n https://github.com/OWNER/REPO\n✓ Added remote https://github.com/OWNER/REPO.git\n✓ Pushed commits to https://github.com/OWNER/REPO.git\n",
},
{
name: "interactive create from a template repository",
Expand All @@ -586,7 +587,7 @@ func Test_createRun(t *testing.T) {
promptStubs: func(p *prompter.PrompterMock) {
p.ConfirmFunc = func(message string, defaultValue bool) (bool, error) {
switch message {
case `This will create "OWNER/REPO" as a private repository on GitHub. Continue?`:
case `This will create "OWNER/REPO" as a private repository on github.com. Continue?`:
return defaultValue, nil
case "Clone the new repository locally?":
return defaultValue, nil
Expand All @@ -611,7 +612,7 @@ func Test_createRun(t *testing.T) {
case "Choose a template repository":
return prompter.IndexFor(options, "REPO")
case "What would you like to do?":
return prompter.IndexFor(options, "Create a new repository on GitHub from a template repository")
return prompter.IndexFor(options, "Create a new repository on github.com from a template repository")
case "Visibility":
return prompter.IndexFor(options, "Private")
default:
Expand Down Expand Up @@ -654,7 +655,7 @@ func Test_createRun(t *testing.T) {
execStubs: func(cs *run.CommandStubber) {
cs.Register(`git clone --branch main https://github.com/OWNER/REPO`, 0, "")
},
wantStdout: "✓ Created repository OWNER/REPO on GitHub\n https://github.com/OWNER/REPO\n",
wantStdout: "✓ Created repository OWNER/REPO on github.com\n https://github.com/OWNER/REPO\n",
},
{
name: "interactive create from template repo but there are no template repos",
Expand All @@ -680,7 +681,7 @@ func Test_createRun(t *testing.T) {
p.SelectFunc = func(message, defaultValue string, options []string) (int, error) {
switch message {
case "What would you like to do?":
return prompter.IndexFor(options, "Create a new repository on GitHub from a template repository")
return prompter.IndexFor(options, "Create a new repository on github.com from a template repository")
case "Visibility":
return prompter.IndexFor(options, "Private")
default:
Expand Down Expand Up @@ -950,6 +951,88 @@ func Test_createRun(t *testing.T) {
},
wantStdout: "https://github.com/OWNER/REPO\n",
},
{
name: "interactive create from scratch with host override",
opts: &CreateOptions{
Interactive: true,
Config: func() (gh.Config, error) {
cfg := &ghmock.ConfigMock{
AuthenticationFunc: func() gh.AuthConfig {
authCfg := &config.AuthConfig{}
authCfg.SetHosts([]string{"example.com"})
authCfg.SetDefaultHost("example.com", "GH_HOST")
return authCfg
},
}
return cfg, nil
},
},
tty: true,
promptStubs: func(p *prompter.PrompterMock) {
p.ConfirmFunc = func(message string, defaultValue bool) (bool, error) {
switch message {
case "Would you like to add a README file?":
return false, nil
case "Would you like to add a .gitignore?":
return false, nil
case "Would you like to add a license?":
return false, nil
case `This will create "REPO" as a private repository on example.com. Continue?`:
return defaultValue, nil
case "Clone the new repository locally?":
return false, nil
default:
return false, fmt.Errorf("unexpected confirm prompt: %s", message)
}
}
p.InputFunc = func(message, defaultValue string) (string, error) {
switch message {
case "Repository name":
return "REPO", nil
case "Description":
return "my new repo", nil
default:
return "", fmt.Errorf("unexpected input prompt: %s", message)
}
}
p.SelectFunc = func(message, defaultValue string, options []string) (int, error) {
switch message {
case "What would you like to do?":
return prompter.IndexFor(options, "Create a new repository on example.com from scratch")
case "Visibility":
return prompter.IndexFor(options, "Private")
case "Choose a license":
return prompter.IndexFor(options, "GNU Lesser General Public License v3.0")
case "Choose a .gitignore template":
return prompter.IndexFor(options, "Go")
default:
return 0, fmt.Errorf("unexpected select prompt: %s", message)
}
}
},
httpStubs: func(reg *httpmock.Registry) {
reg.Register(
httpmock.GraphQL(`query UserCurrent\b`),
httpmock.StringResponse(`{"data":{"viewer":{"login":"someuser","organizations":{"nodes": []}}}}`))
reg.Register(
httpmock.GraphQL(`mutation RepositoryCreate\b`),
httpmock.StringResponse(`
{
"data": {
"createRepository": {
"repository": {
"id": "REPOID",
"name": "REPO",
"owner": {"login":"OWNER"},
"url": "https://example.com/OWNER/REPO"
}
}
}
}`),
)
},
wantStdout: "✓ Created repository OWNER/REPO on example.com\n https://example.com/OWNER/REPO\n",
},
}
for _, tt := range tests {
prompterMock := &prompter.PrompterMock{}
Expand All @@ -965,8 +1048,11 @@ func Test_createRun(t *testing.T) {
tt.opts.HttpClient = func() (*http.Client, error) {
return &http.Client{Transport: reg}, nil
}
tt.opts.Config = func() (gh.Config, error) {
return config.NewBlankConfig(), nil

if tt.opts.Config == nil {
tt.opts.Config = func() (gh.Config, error) {
return config.NewBlankConfig(), nil
}
}

tt.opts.GitClient = &git.Client{
Expand Down