github.com/pluralsh/plural-cli@v0.9.5/cmd/plural/validation.go (about) 1 package plural 2 3 import ( 4 "fmt" 5 "os" 6 7 "github.com/AlecAivazis/survey/v2" 8 "github.com/pluralsh/plural-cli/pkg/api" 9 "github.com/pluralsh/plural-cli/pkg/config" 10 "github.com/pluralsh/plural-cli/pkg/executor" 11 "github.com/pluralsh/plural-cli/pkg/manifest" 12 "github.com/pluralsh/plural-cli/pkg/provider" 13 "github.com/pluralsh/plural-cli/pkg/utils" 14 "github.com/pluralsh/plural-cli/pkg/utils/errors" 15 "github.com/pluralsh/plural-cli/pkg/utils/git" 16 "github.com/pluralsh/plural-cli/pkg/utils/pathing" 17 "github.com/pluralsh/polly/algorithms" 18 "github.com/urfave/cli" 19 ) 20 21 func init() { 22 bootstrapMode = false 23 } 24 25 var bootstrapMode bool 26 27 func requireArgs(fn func(*cli.Context) error, args []string) func(*cli.Context) error { 28 return func(c *cli.Context) error { 29 nargs := c.NArg() 30 if nargs > len(args) { 31 return fmt.Errorf("Too many args passed to %s. Try running --help to see usage.", c.Command.FullName()) 32 } 33 34 if nargs < len(args) { 35 return fmt.Errorf("Not enough arguments provided: needs %s. Try running --help to see usage.", args[nargs]) 36 } 37 38 return fn(c) 39 } 40 } 41 42 func rooted(fn func(*cli.Context) error) func(*cli.Context) error { 43 return func(c *cli.Context) error { 44 if err := repoRoot(); err != nil { 45 return err 46 } 47 48 return fn(c) 49 } 50 } 51 52 func owned(fn func(*cli.Context) error) func(*cli.Context) error { 53 return func(c *cli.Context) error { 54 if err := validateOwner(); err != nil { 55 return err 56 } 57 58 return fn(c) 59 } 60 } 61 62 func affirmed(fn func(*cli.Context) error, msg string, envKey string) func(*cli.Context) error { 63 return func(c *cli.Context) error { 64 if !affirm(msg, envKey) { 65 return nil 66 } 67 68 return fn(c) 69 } 70 } 71 72 func highlighted(fn func(*cli.Context) error) func(*cli.Context) error { 73 return func(c *cli.Context) error { 74 return utils.HighlightError(fn(c)) 75 } 76 } 77 78 func tracked(fn func(*cli.Context) error, event string) func(*cli.Context) error { 79 return func(c *cli.Context) error { 80 event := api.UserEventAttributes{Data: "", Event: event, Status: "OK"} 81 err := fn(c) 82 if err != nil { 83 event.Status = "ERROR" 84 if we, ok := err.(*executor.WrappedError); ok { //nolint:errorlint 85 event.Data = we.Output 86 } else { 87 event.Data = fmt.Sprint(err) 88 } 89 } 90 91 conf := config.Read() 92 if conf.ReportErrors { 93 client := api.FromConfig(&conf) 94 if err := client.CreateEvent(&event); err != nil { 95 return api.GetErrorResponse(err, "CreateEvent") 96 } 97 } 98 return err 99 } 100 } 101 102 func initKubeconfig(fn func(*cli.Context) error) func(*cli.Context) error { 103 return func(c *cli.Context) error { 104 _, found := utils.ProjectRoot() 105 if found { 106 prov, err := provider.GetProvider() 107 if err != nil { 108 return err 109 } 110 if bootstrapMode { 111 prov = &provider.KINDProvider{Clust: "bootstrap"} 112 } 113 if err := prov.KubeConfig(); err != nil { 114 return err 115 } 116 utils.LogInfo().Println("init", prov.Name(), "provider") 117 } else { 118 utils.LogInfo().Println("not found provider") 119 } 120 121 return fn(c) 122 } 123 } 124 125 func validateOwner() error { 126 path := manifest.ProjectManifestPath() 127 project, err := manifest.ReadProject(path) 128 if err != nil { 129 return fmt.Errorf("Your workspace hasn't been configured. Try running `plural init`.") 130 } 131 132 if owner := project.Owner; owner != nil { 133 conf := config.Read() 134 if owner.Endpoint != conf.Endpoint { 135 return fmt.Errorf( 136 "The owner of this project is actually %s; plural environment = %s", 137 owner.Email, 138 config.PluralUrl(owner.Endpoint), 139 ) 140 } 141 } 142 143 return nil 144 } 145 146 func confirm(msg string, envKey string) bool { 147 res := true 148 conf, ok := utils.GetEnvBoolValue(envKey) 149 if ok { 150 return conf 151 } 152 prompt := &survey.Confirm{Message: msg} 153 if err := survey.AskOne(prompt, &res, survey.WithValidator(survey.Required)); err != nil { 154 return false 155 } 156 return res 157 } 158 159 func affirm(msg string, envKey string) bool { 160 res := true 161 conf, ok := utils.GetEnvBoolValue(envKey) 162 if ok { 163 return conf 164 } 165 prompt := &survey.Confirm{Message: msg, Default: true} 166 if err := survey.AskOne(prompt, &res, survey.WithValidator(survey.Required)); err != nil { 167 return false 168 } 169 return res 170 } 171 172 func repoRoot() error { 173 dir, err := os.Getwd() 174 if err != nil { 175 return err 176 } 177 // santiize the filepath, respecting the OS 178 dir = pathing.SanitizeFilepath(dir) 179 180 root, err := git.Root() 181 if err != nil { 182 return err 183 } 184 185 if root != dir { 186 return fmt.Errorf("You must run this command at the root of your git repository") 187 } 188 189 return nil 190 } 191 192 func latestVersion(fn func(*cli.Context) error) func(*cli.Context) error { 193 return func(c *cli.Context) error { 194 if os.Getenv("PLURAL_CONSOLE") != "1" && os.Getenv("CLOUD_SHELL") != "1" && algorithms.Coinflip(1, 5) { 195 utils.CheckLatestVersion(Version) 196 } 197 198 return fn(c) 199 } 200 } 201 202 func upstreamSynced(fn func(*cli.Context) error) func(*cli.Context) error { 203 return func(c *cli.Context) error { 204 changed, sha, err := git.HasUpstreamChanges() 205 if err != nil { 206 utils.LogError().Println(err) 207 return errors.ErrorWrap(errNoGit, "Failed to get git information") 208 } 209 210 force := c.Bool("force") 211 if !changed && !force { 212 return errors.ErrorWrap(errRemoteDiff, fmt.Sprintf("Expecting HEAD at commit=%s", sha)) 213 } 214 215 return fn(c) 216 } 217 } 218 219 func requireKind(fn func(*cli.Context) error) func(*cli.Context) error { 220 return func(c *cli.Context) error { 221 exists, _ := utils.Which("kind") 222 if !exists { 223 return fmt.Errorf("The kind CLI is not installed") 224 } 225 226 return fn(c) 227 } 228 }