github.com/taubyte/tau-cli@v0.1.13-0.20240326000942-487f0d57edfc/cli/commands/resources/project/helpers.go (about) 1 package project 2 3 import ( 4 "context" 5 "encoding/json" 6 "io" 7 "sync" 8 9 "github.com/google/go-github/v53/github" 10 "github.com/pterm/pterm" 11 git "github.com/taubyte/go-simple-git" 12 projectFlags "github.com/taubyte/tau-cli/flags/project" 13 "github.com/taubyte/tau-cli/i18n" 14 projectI18n "github.com/taubyte/tau-cli/i18n/project" 15 repositoryI18n "github.com/taubyte/tau-cli/i18n/repository" 16 projectLib "github.com/taubyte/tau-cli/lib/project" 17 "github.com/taubyte/tau-cli/singletons/config" 18 "github.com/urfave/cli/v2" 19 "golang.org/x/oauth2" 20 ) 21 22 // See if they have cloned the project, if not show help 23 func checkProjectClonedHelp(name string) { 24 project, err := config.Projects().Get(name) 25 if err != nil || len(project.Location) == 0 { 26 i18n.Help().BeSureToCloneProject() 27 } 28 } 29 30 type dualRepoHandler struct { 31 ctx *cli.Context 32 projectName string 33 repository projectLib.ProjectRepository 34 action func(*git.Repository) error 35 errorFormat func(string) error 36 } 37 38 // Run will parse for config-only || code-only 39 // then Runs a go routine to commit the action on both 40 // config and code repositories asynchronously or run config/code only 41 func (h *dualRepoHandler) Run() error { 42 config, code, err := projectFlags.ParseConfigCodeFlags(h.ctx) 43 if err != nil { 44 return err 45 } 46 47 var ( 48 configErr error 49 codeErr error 50 ) 51 52 var wg sync.WaitGroup 53 54 if config { 55 wg.Add(1) 56 go func() { 57 defer wg.Done() 58 59 var configRepo *git.Repository 60 61 configRepo, configErr = h.repository.Config() 62 if configErr != nil { 63 return 64 } 65 66 configErr = h.action(configRepo) 67 if configErr != nil { 68 pterm.Error.Printfln(projectI18n.ConfigRepo, configErr) 69 } 70 }() 71 } 72 73 if code { 74 wg.Add(1) 75 go func() { 76 defer wg.Done() 77 78 var codeRepo *git.Repository 79 80 codeRepo, codeErr = h.repository.Code() 81 if codeErr != nil { 82 return 83 } 84 85 codeErr = h.action(codeRepo) 86 if codeErr != nil { 87 pterm.Error.Printfln(projectI18n.CodeRepo, codeErr) 88 } 89 }() 90 } 91 92 wg.Wait() 93 if configErr != nil || codeErr != nil { 94 return h.errorFormat(h.projectName) 95 } 96 97 return nil 98 } 99 100 func newGithubClient(ctx context.Context, token string) *github.Client { 101 ts := oauth2.StaticTokenSource( 102 &oauth2.Token{AccessToken: token}, 103 ) 104 105 tc := oauth2.NewClient(ctx, ts) 106 return github.NewClient(tc) 107 } 108 109 // Var to allow override in tests 110 var ListRepos = func(ctx context.Context, token, user string) ([]*github.Repository, error) { 111 client := newGithubClient(ctx, token) 112 repos, _, err := client.Repositories.List(ctx, "", &github.RepositoryListOptions{ 113 Visibility: "all", 114 Affiliation: "owner,collaborator,organization_member", 115 }) 116 if err != nil { 117 return nil, repositoryI18n.ErrorListRepositories(user, err) 118 } 119 120 return repos, nil 121 } 122 123 func removeFromGithub(ctx context.Context, token, user, name string) error { 124 client := newGithubClient(ctx, token) 125 if res, err := client.Repositories.Delete(ctx, user, name); err != nil { 126 var deleteRes deleteRes 127 data, err := io.ReadAll(res.Body) 128 if err == nil { 129 if err = json.Unmarshal(data, &deleteRes); err == nil && deleteRes.Message == adminRights { 130 pterm.Error.Println(adminRights[:len(adminRights)-1] + " to delete") 131 pterm.Info.Println( 132 "Add token with delete permissions\n" + 133 pterm.FgGreen.Sprint("$ tau login --new -n {profile-name} -p github -d -t {token}")) 134 return repositoryI18n.ErrorAdminRights 135 } 136 137 } 138 return repositoryI18n.ErrorDeleteRepository(name, err) 139 } 140 141 return nil 142 } 143 144 type deleteRes struct { 145 Message string `json:"message"` 146 } 147 148 var adminRights = "Must have admin rights to Repository."