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 }