github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/internal/runners/fork/fork.go (about)

     1  package fork
     2  
     3  import (
     4  	"github.com/ActiveState/cli/internal/errs"
     5  	"github.com/ActiveState/cli/internal/locale"
     6  	"github.com/ActiveState/cli/internal/output"
     7  	"github.com/ActiveState/cli/internal/primer"
     8  	"github.com/ActiveState/cli/internal/prompt"
     9  	"github.com/ActiveState/cli/pkg/platform/api"
    10  	"github.com/ActiveState/cli/pkg/platform/authentication"
    11  	"github.com/ActiveState/cli/pkg/platform/model"
    12  	"github.com/ActiveState/cli/pkg/project"
    13  )
    14  
    15  type Params struct {
    16  	Namespace    project.Namespaced
    17  	Organization string
    18  	Name         string
    19  	Private      bool
    20  }
    21  
    22  type Fork struct {
    23  	out    output.Outputer
    24  	auth   *authentication.Auth
    25  	prompt prompt.Prompter
    26  }
    27  
    28  type primeable interface {
    29  	primer.Outputer
    30  	primer.Auther
    31  	primer.Prompter
    32  }
    33  
    34  func New(prime primeable) *Fork {
    35  	return &Fork{
    36  		prime.Output(),
    37  		prime.Auth(),
    38  		prime.Prompt(),
    39  	}
    40  }
    41  
    42  func (f *Fork) Run(params *Params) error {
    43  	if !f.auth.Authenticated() {
    44  		return locale.NewInputError("err_auth_required", "Authentication is required, please authenticate by running 'state auth'")
    45  	}
    46  
    47  	target := &project.Namespaced{
    48  		Owner:   params.Organization,
    49  		Project: params.Name,
    50  	}
    51  
    52  	if target.Owner == "" {
    53  		var err error
    54  		target.Owner, err = determineOwner(f.auth.WhoAmI(), f.prompt, f.auth)
    55  		if err != nil {
    56  			return errs.Wrap(err, "Cannot continue without an owner")
    57  		}
    58  	}
    59  
    60  	if target.Project == "" {
    61  		target.Project = params.Namespace.Project
    62  	}
    63  
    64  	url := api.GetPlatformURL(target.String()).String()
    65  
    66  	f.out.Notice(locale.Tl("fork_forking", "Creating fork of {{.V0}} at {{.V1}}...", params.Namespace.String(), url))
    67  
    68  	_, err := model.CreateCopy(params.Namespace.Owner, params.Namespace.Project, target.Owner, target.Project, params.Private, f.auth)
    69  	if err != nil {
    70  		return locale.WrapError(err, "err_fork_project", "Could not create fork")
    71  	}
    72  
    73  	f.out.Print(output.Prepare(
    74  		locale.Tl("fork_success", "Your fork has been successfully created at {{.V0}}.", url),
    75  		&struct {
    76  			OriginalOwner string `json:"OriginalOwner"`
    77  			OriginalName  string `json:"OriginalName"`
    78  			NewOwner      string `json:"NewOwner"`
    79  			NewName       string `json:"NewName"`
    80  		}{
    81  			params.Namespace.Owner,
    82  			params.Namespace.Project,
    83  			target.Owner,
    84  			target.Project,
    85  		}))
    86  
    87  	return nil
    88  }
    89  
    90  func determineOwner(username string, prompter prompt.Prompter, auth *authentication.Auth) (string, error) {
    91  	orgs, err := model.FetchOrganizations(auth)
    92  	if err != nil {
    93  		return "", locale.WrapError(err, "err_fork_orgs", "Could not retrieve list of organizations that you belong to.")
    94  	}
    95  	if len(orgs) == 0 {
    96  		return username, nil
    97  	}
    98  
    99  	options := make([]string, len(orgs))
   100  	displayNameToURLNameMap := make(map[string]string)
   101  	for i, org := range orgs {
   102  		options[i] = org.DisplayName
   103  		displayNameToURLNameMap[org.DisplayName] = org.URLname
   104  	}
   105  	options = append([]string{username}, options...)
   106  
   107  	r, err := prompter.Select(locale.Tl("fork_owner_title", "Owner"), locale.Tl("fork_select_org", "Who should the new project belong to?"), options, new(string))
   108  	owner, exists := displayNameToURLNameMap[r]
   109  	if !exists {
   110  		return "", errs.New("Selected organization does not have a URL name")
   111  	}
   112  	return owner, err
   113  }