github.com/olli-ai/jx/v2@v2.0.400-0.20210921045218-14731b4dd448/pkg/gits/git_repo.go (about)

     1  package gits
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/jenkins-x/jx-logging/pkg/log"
     8  	"github.com/olli-ai/jx/v2/pkg/auth"
     9  	"github.com/olli-ai/jx/v2/pkg/util"
    10  	"gopkg.in/AlecAivazis/survey.v1"
    11  )
    12  
    13  type CreateRepoData struct {
    14  	Organisation string
    15  	RepoName     string
    16  	FullName     string
    17  	Public       bool
    18  	User         *auth.UserAuth
    19  	GitProvider  GitProvider
    20  	GitServer    *auth.AuthServer
    21  }
    22  
    23  type GitRepositoryOptions struct {
    24  	ServerURL                string
    25  	ServerKind               string
    26  	Username                 string
    27  	ApiToken                 string
    28  	Owner                    string
    29  	RepoName                 string
    30  	Public                   bool
    31  	IgnoreExistingRepository bool
    32  }
    33  
    34  // GetRepository returns the repository if it already exists
    35  func (d *CreateRepoData) GetRepository() (*GitRepository, error) {
    36  	return d.GitProvider.GetRepository(d.Organisation, d.RepoName)
    37  }
    38  
    39  // CreateRepository creates the repository - failing if it already exists
    40  func (d *CreateRepoData) CreateRepository() (*GitRepository, error) {
    41  	return d.GitProvider.CreateRepository(d.Organisation, d.RepoName, !d.Public)
    42  }
    43  
    44  func PickNewOrExistingGitRepository(batchMode bool, authConfigSvc auth.ConfigService, defaultRepoName string,
    45  	repoOptions *GitRepositoryOptions, server *auth.AuthServer, userAuth *auth.UserAuth, git Gitter, allowExistingRepo bool, handles util.IOFileHandles) (*CreateRepoData, error) {
    46  	config := authConfigSvc.Config()
    47  
    48  	var err error
    49  	if server == nil {
    50  		if repoOptions.ServerURL != "" {
    51  			server = config.GetOrCreateServer(repoOptions.ServerURL)
    52  		} else {
    53  			if batchMode {
    54  				if len(config.Servers) == 0 {
    55  					return nil, fmt.Errorf("No Git servers are configured!")
    56  				}
    57  				// lets assume the first for now
    58  				server = config.Servers[0]
    59  				currentServer := config.CurrentServer
    60  				if currentServer != "" {
    61  					for _, s := range config.Servers {
    62  						if s.Name == currentServer || s.URL == currentServer {
    63  							server = s
    64  							break
    65  						}
    66  					}
    67  				}
    68  			} else {
    69  				server, err = config.PickServer("Which Git service?", batchMode, handles)
    70  				if err != nil {
    71  					return nil, err
    72  				}
    73  			}
    74  			repoOptions.ServerURL = server.URL
    75  		}
    76  	}
    77  
    78  	log.Logger().Infof("Using Git provider %s", util.ColorInfo(server.Description()))
    79  	url := server.URL
    80  
    81  	if userAuth == nil {
    82  		if repoOptions.Username != "" {
    83  			userAuth = config.GetOrCreateUserAuth(url, repoOptions.Username)
    84  			log.Logger().Infof(util.QuestionAnswer("Using Git user name", repoOptions.Username))
    85  		} else {
    86  			if batchMode {
    87  				if len(server.Users) == 0 {
    88  					return nil, fmt.Errorf("Server %s has no user auths defined", url)
    89  				}
    90  				var ua *auth.UserAuth
    91  				if server.CurrentUser != "" {
    92  					ua = config.FindUserAuth(url, server.CurrentUser)
    93  				}
    94  				if ua == nil {
    95  					ua = server.Users[0]
    96  				}
    97  				userAuth = ua
    98  			} else {
    99  				userAuth, err = config.PickServerUserAuth(server, "Git user name?", batchMode, "", handles)
   100  				if err != nil {
   101  					return nil, err
   102  				}
   103  			}
   104  		}
   105  	}
   106  
   107  	if userAuth.IsInvalid() && repoOptions.ApiToken != "" {
   108  		userAuth.ApiToken = repoOptions.ApiToken
   109  	}
   110  
   111  	if userAuth.IsInvalid() {
   112  		f := func(username string) error {
   113  			git.PrintCreateRepositoryGenerateAccessToken(server, username, handles.Out)
   114  			return nil
   115  		}
   116  
   117  		// TODO could we guess this based on the users ~/.git for github?
   118  		defaultUserName := ""
   119  		err = config.EditUserAuth(server.Label(), userAuth, defaultUserName, true, batchMode, f, handles)
   120  		if err != nil {
   121  			return nil, err
   122  		}
   123  
   124  		// TODO lets verify the auth works
   125  
   126  		err = authConfigSvc.SaveUserAuth(url, userAuth)
   127  		if err != nil {
   128  			return nil, fmt.Errorf("Failed to store git auth configuration %s", err)
   129  		}
   130  		if userAuth.IsInvalid() {
   131  			return nil, fmt.Errorf("You did not properly define the user authentication")
   132  		}
   133  	}
   134  
   135  	gitUsername := userAuth.Username
   136  	log.Logger().Debugf("About to create repository %s on server %s with user %s", util.ColorInfo(defaultRepoName), util.ColorInfo(url), util.ColorInfo(gitUsername))
   137  
   138  	provider, err := CreateProvider(server, userAuth, git)
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  
   143  	owner := repoOptions.Owner
   144  	if owner == "" {
   145  		owner, err = GetOwner(batchMode, provider, gitUsername, handles)
   146  		if err != nil {
   147  			return nil, err
   148  		}
   149  	} else {
   150  		log.Logger().Infof(util.QuestionAnswer("Using organisation", owner))
   151  	}
   152  
   153  	repoName := repoOptions.RepoName
   154  	if repoName == "" {
   155  		repoName, err = GetRepoName(batchMode, allowExistingRepo, provider, defaultRepoName, owner, handles)
   156  		if err != nil {
   157  			return nil, err
   158  		}
   159  	} else {
   160  		if !repoOptions.IgnoreExistingRepository {
   161  			err := provider.ValidateRepositoryName(owner, repoName)
   162  			if err != nil {
   163  				return nil, err
   164  			}
   165  			log.Logger().Infof(util.QuestionAnswer("Using repository", repoName))
   166  		}
   167  	}
   168  
   169  	fullName := git.RepoName(owner, repoName)
   170  	log.Logger().Infof("Creating repository %s", util.ColorInfo(fullName))
   171  
   172  	return &CreateRepoData{
   173  		Organisation: owner,
   174  		RepoName:     repoName,
   175  		FullName:     fullName,
   176  		Public:       repoOptions.Public,
   177  		User:         userAuth,
   178  		GitProvider:  provider,
   179  		GitServer:    server,
   180  	}, err
   181  }
   182  
   183  func GetRepoName(batchMode, allowExistingRepo bool, provider GitProvider, defaultRepoName, owner string, handles util.IOFileHandles) (string, error) {
   184  	surveyOpts := survey.WithStdio(handles.In, handles.Out, handles.Err)
   185  	repoName := ""
   186  	if batchMode {
   187  		repoName = defaultRepoName
   188  		if repoName == "" {
   189  			repoName = "dummy"
   190  		}
   191  	} else {
   192  		prompt := &survey.Input{
   193  			Message: "Enter the new repository name: ",
   194  			Default: defaultRepoName,
   195  		}
   196  		validator := func(val interface{}) error {
   197  			str, ok := val.(string)
   198  			if !ok {
   199  				return fmt.Errorf("Expected string value")
   200  			}
   201  			if strings.TrimSpace(str) == "" {
   202  				return fmt.Errorf("Repository name is required")
   203  			}
   204  			if allowExistingRepo {
   205  				return nil
   206  			}
   207  			return provider.ValidateRepositoryName(owner, str)
   208  		}
   209  		err := survey.AskOne(prompt, &repoName, validator, surveyOpts)
   210  		if err != nil {
   211  			return "", err
   212  		}
   213  		if repoName == "" {
   214  			return "", fmt.Errorf("No repository name specified")
   215  		}
   216  	}
   217  	return repoName, nil
   218  }
   219  
   220  func GetOwner(batchMode bool, provider OrganisationLister, gitUsername string, handles util.IOFileHandles) (string, error) {
   221  	owner := ""
   222  	if batchMode {
   223  		owner = gitUsername
   224  	} else {
   225  		org, err := PickOwner(provider, gitUsername, handles)
   226  		if err != nil {
   227  			return "", err
   228  		}
   229  		owner = org
   230  		if org == "" {
   231  			owner = gitUsername
   232  		}
   233  	}
   234  	return owner, nil
   235  }
   236  
   237  func PickNewGitRepository(batchMode bool, authConfigSvc auth.ConfigService, defaultRepoName string,
   238  	repoOptions *GitRepositoryOptions, server *auth.AuthServer, userAuth *auth.UserAuth, git Gitter, handles util.IOFileHandles) (*CreateRepoData, error) {
   239  	return PickNewOrExistingGitRepository(batchMode, authConfigSvc, defaultRepoName, repoOptions, server, userAuth, git, false, handles)
   240  }