66 "path"
77 "strings"
88
9+ "github.com/AlecAivazis/survey/v2"
910 "github.com/MakeNowJust/heredoc"
1011 "github.com/cli/cli/git"
1112 "github.com/cli/cli/internal/config"
@@ -23,13 +24,16 @@ type CreateOptions struct {
2324 Config func () (config.Config , error )
2425 IO * iostreams.IOStreams
2526
26- Name string
27- Description string
28- Homepage string
29- Team string
30- EnableIssues bool
31- EnableWiki bool
32- Public bool
27+ Name string
28+ Description string
29+ Homepage string
30+ Team string
31+ EnableIssues bool
32+ EnableWiki bool
33+ Public bool
34+ Private bool
35+ Internal bool
36+ ConfirmSubmit bool
3337}
3438
3539func NewCmdCreate (f * cmdutil.Factory , runF func (* CreateOptions ) error ) * cobra.Command {
@@ -78,7 +82,10 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
7882 cmd .Flags ().StringVarP (& opts .Team , "team" , "t" , "" , "The name of the organization team to be granted access" )
7983 cmd .Flags ().BoolVar (& opts .EnableIssues , "enable-issues" , true , "Enable issues in the new repository" )
8084 cmd .Flags ().BoolVar (& opts .EnableWiki , "enable-wiki" , true , "Enable wiki in the new repository" )
81- cmd .Flags ().BoolVar (& opts .Public , "public" , false , "Make the new repository public (default: private)" )
85+ cmd .Flags ().BoolVar (& opts .Public , "public" , false , "Make the new repository public" )
86+ cmd .Flags ().BoolVar (& opts .Private , "private" , false , "Make the new repository private" )
87+ cmd .Flags ().BoolVar (& opts .Internal , "internal" , false , "Make the new repository internal" )
88+ cmd .Flags ().BoolVarP (& opts .ConfirmSubmit , "confirm" , "y" , false , "Confirm the submission directly" )
8289
8390 return cmd
8491}
@@ -88,7 +95,12 @@ func createRun(opts *CreateOptions) error {
8895
8996 var repoToCreate ghrepo.Interface
9097
98+ isNameAnArg := false
99+ isDescEmpty := opts .Description == ""
100+ isVisibilityPassed := false
101+
91102 if opts .Name != "" {
103+ isNameAnArg = true
92104 if strings .Contains (opts .Name , "/" ) {
93105 var err error
94106 repoToCreate , err = ghrepo .FromFullName (opts .Name )
@@ -105,10 +117,52 @@ func createRun(opts *CreateOptions) error {
105117 repoToCreate = ghrepo .New ("" , path .Base (projectDir ))
106118 }
107119
108- visibility := "PRIVATE"
120+ enabledFlagCount := 0
121+ visibility := ""
109122 if opts .Public {
123+ enabledFlagCount ++
110124 visibility = "PUBLIC"
111125 }
126+ if opts .Private {
127+ enabledFlagCount ++
128+ visibility = "PRIVATE"
129+ }
130+ if opts .Internal {
131+ enabledFlagCount ++
132+ visibility = "INTERNAL"
133+ }
134+
135+ if enabledFlagCount > 1 {
136+ return fmt .Errorf ("expected exactly one of --public, --private, or --internal to be true" )
137+ } else if enabledFlagCount == 1 {
138+ isVisibilityPassed = true
139+ }
140+
141+ // Trigger interactive prompt if name is not passed
142+ if ! isNameAnArg {
143+ newName , newDesc , newVisibility , err := interactiveRepoCreate (isDescEmpty , isVisibilityPassed , repoToCreate .RepoName ())
144+ if err != nil {
145+ return err
146+ }
147+ if newName != "" {
148+ opts .Name = newName
149+ }
150+ if newDesc != "" {
151+ opts .Description = newDesc
152+ }
153+ if newVisibility != "" {
154+ visibility = newVisibility
155+ }
156+ } else {
157+ // Go for a prompt only if visibility isn't passed
158+ if ! isVisibilityPassed {
159+ newVisibility , err := getVisibility ()
160+ if err != nil {
161+ return nil
162+ }
163+ visibility = newVisibility
164+ }
165+ }
112166
113167 input := repoCreateInput {
114168 Name : repoToCreate .RepoName (),
@@ -126,67 +180,186 @@ func createRun(opts *CreateOptions) error {
126180 return err
127181 }
128182
129- repo , err := repoCreate (httpClient , repoToCreate .RepoHost (), input )
130- if err != nil {
131- return err
183+ createLocalDirectory := opts .ConfirmSubmit
184+ if ! opts .ConfirmSubmit {
185+ opts .ConfirmSubmit , err = confirmSubmission (input .Name , input .OwnerID , & opts .ConfirmSubmit )
186+ if err != nil {
187+ return err
188+ }
132189 }
133190
134- stderr := opts .IO .ErrOut
135- stdout := opts .IO .Out
136- isTTY := opts .IO .IsStdoutTTY ()
191+ if opts .ConfirmSubmit {
192+ repo , err := repoCreate (httpClient , repoToCreate .RepoHost (), input )
193+ if err != nil {
194+ return err
195+ }
137196
138- if isTTY {
139- fmt .Fprintf (stderr , "%s Created repository %s on GitHub\n " , utils .GreenCheck (), ghrepo .FullName (repo ))
140- } else {
141- fmt .Fprintln (stdout , repo .URL )
142- }
197+ stderr := opts .IO .ErrOut
198+ stdout := opts .IO .Out
199+ greenCheck := utils .Green ("✓" )
200+ isTTY := opts .IO .IsStdoutTTY ()
143201
144- // TODO This is overly wordy and I'd like to streamline this.
145- cfg , err := opts .Config ()
146- if err != nil {
147- return err
148- }
149- protocol , err := cfg .Get (repo .RepoHost (), "git_protocol" )
150- if err != nil {
151- return err
152- }
153- remoteURL := ghrepo .FormatRemoteURL (repo , protocol )
202+ if isTTY {
203+ fmt .Fprintf (stderr , "%s Created repository %s on GitHub\n " , greenCheck , ghrepo .FullName (repo ))
204+ } else {
205+ fmt .Fprintln (stdout , repo .URL )
206+ }
154207
155- if projectDirErr == nil {
156- _ , err = git . AddRemote ( "origin" , remoteURL )
208+ // TODO This is overly wordy and I'd like to streamline this.
209+ cfg , err := opts . Config ( )
157210 if err != nil {
158211 return err
159212 }
160- if isTTY {
161- fmt .Fprintf (stderr , "%s Added remote %s\n " , utils .GreenCheck (), remoteURL )
162- }
163- } else if isTTY {
164- doSetup := false
165- err := prompt .Confirm (fmt .Sprintf ("Create a local project directory for %s?" , ghrepo .FullName (repo )), & doSetup )
213+ protocol , err := cfg .Get (repo .RepoHost (), "git_protocol" )
166214 if err != nil {
167215 return err
168216 }
217+ remoteURL := ghrepo .FormatRemoteURL (repo , protocol )
169218
170- if doSetup {
171- path := repo .Name
172-
173- gitInit := git .GitCommand ("init" , path )
174- gitInit .Stdout = stdout
175- gitInit .Stderr = stderr
176- err = run .PrepareCmd (gitInit ).Run ()
219+ if projectDirErr == nil {
220+ _ , err = git .AddRemote ("origin" , remoteURL )
177221 if err != nil {
178222 return err
179223 }
180- gitRemoteAdd := git .GitCommand ("-C" , path , "remote" , "add" , "origin" , remoteURL )
181- gitRemoteAdd .Stdout = stdout
182- gitRemoteAdd .Stderr = stderr
183- err = run .PrepareCmd (gitRemoteAdd ).Run ()
184- if err != nil {
185- return err
224+ if isTTY {
225+ fmt .Fprintf (stderr , "%s Added remote %s\n " , greenCheck , remoteURL )
186226 }
227+ } else if isTTY {
228+ doSetup := createLocalDirectory
229+ if ! doSetup {
230+ err := prompt .Confirm (fmt .Sprintf ("Create a local project directory for %s?" , ghrepo .FullName (repo )), & doSetup )
231+ if err != nil {
232+ return err
233+ }
234+ }
235+ if doSetup {
236+ path := repo .Name
237+
238+ gitInit := git .GitCommand ("init" , path )
239+ gitInit .Stdout = stdout
240+ gitInit .Stderr = stderr
241+ err = run .PrepareCmd (gitInit ).Run ()
242+ if err != nil {
243+ return err
244+ }
245+ gitRemoteAdd := git .GitCommand ("-C" , path , "remote" , "add" , "origin" , remoteURL )
246+ gitRemoteAdd .Stdout = stdout
247+ gitRemoteAdd .Stderr = stderr
248+ err = run .PrepareCmd (gitRemoteAdd ).Run ()
249+ if err != nil {
250+ return err
251+ }
187252
188- fmt .Fprintf (stderr , "%s Initialized repository in './%s/'\n " , utils .GreenCheck (), path )
253+ fmt .Fprintf (stderr , "%s Initialized repository in './%s/'\n " , utils .GreenCheck (), path )
254+ }
189255 }
256+ return nil
190257 }
258+ fmt .Fprintln (opts .IO .Out , "Discarding..." )
191259 return nil
192260}
261+
262+ func interactiveRepoCreate (isDescEmpty bool , isVisibilityPassed bool , repoName string ) (string , string , string , error ) {
263+ qs := []* survey.Question {}
264+
265+ repoOwnerQuestion := & survey.Question {
266+ Name : "repoOwner" ,
267+ Prompt : & survey.Input {
268+ Message : "Repository name" ,
269+ Default : repoName ,
270+ },
271+ }
272+ qs = append (qs , repoOwnerQuestion )
273+
274+ if isDescEmpty {
275+ repoDescriptionQuestion := & survey.Question {
276+ Name : "repoDescription" ,
277+ Prompt : & survey.Input {
278+ Message : "Repository description" ,
279+ },
280+ }
281+
282+ qs = append (qs , repoDescriptionQuestion )
283+ }
284+
285+ if ! isVisibilityPassed {
286+ repoVisibilityQuestion := & survey.Question {
287+ Name : "repoVisibility" ,
288+ Prompt : & survey.Select {
289+ Message : "Visibility" ,
290+ Options : []string {"Public" , "Private" , "Internal" },
291+ },
292+ }
293+ qs = append (qs , repoVisibilityQuestion )
294+ }
295+
296+ answers := struct {
297+ RepoOwner string
298+ RepoDescription string
299+ RepoVisibility string
300+ }{}
301+
302+ err := prompt .SurveyAsk (qs , & answers )
303+
304+ if err != nil {
305+ return "" , "" , "" , err
306+ }
307+
308+ return answers .RepoOwner , answers .RepoDescription , strings .ToUpper (answers .RepoVisibility ), nil
309+
310+ }
311+
312+ func confirmSubmission (repoName string , repoOwner string , isConfirmFlagPassed * bool ) (bool , error ) {
313+ qs := []* survey.Question {}
314+
315+ promptString := ""
316+ if repoOwner != "" {
317+ promptString = fmt .Sprintf ("This will create '%s/%s' in your current directory. Continue? " , repoOwner , repoName )
318+ } else {
319+ promptString = fmt .Sprintf ("This will create '%s' in your current directory. Continue? " , repoName )
320+ }
321+
322+ confirmSubmitQuestion := & survey.Question {
323+ Name : "confirmSubmit" ,
324+ Prompt : & survey.Confirm {
325+ Message : promptString ,
326+ Default : true ,
327+ },
328+ }
329+ qs = append (qs , confirmSubmitQuestion )
330+
331+ answer := struct {
332+ ConfirmSubmit bool
333+ }{}
334+
335+ err := prompt .SurveyAsk (qs , & answer )
336+ if err != nil {
337+ return false , err
338+ }
339+
340+ return answer .ConfirmSubmit , nil
341+ }
342+
343+ func getVisibility () (string , error ) {
344+ qs := []* survey.Question {}
345+
346+ getVisibilityQuestion := & survey.Question {
347+ Name : "repoVisibility" ,
348+ Prompt : & survey.Select {
349+ Message : "Visibility" ,
350+ Options : []string {"Public" , "Private" , "Internal" },
351+ },
352+ }
353+ qs = append (qs , getVisibilityQuestion )
354+
355+ answer := struct {
356+ RepoVisibility string
357+ }{}
358+
359+ err := prompt .SurveyAsk (qs , & answer )
360+ if err != nil {
361+ return "" , err
362+ }
363+
364+ return strings .ToUpper (answer .RepoVisibility ), nil
365+ }
0 commit comments