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  }