github.com/snyk/vervet/v6@v6.2.4/internal/cmd/cmd.go (about)

     1  // Package cmd provides subcommands for the vervet CLI.
     2  package cmd
     3  
     4  import (
     5  	"context"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"os"
    10  	"path/filepath"
    11  	"strings"
    12  
    13  	"github.com/manifoldco/promptui"
    14  	"github.com/urfave/cli/v2"
    15  )
    16  
    17  //go:generate ../../scripts/genversion.bash
    18  
    19  // VervetParams contains configuration parameters for the Vervet CLI application.
    20  type VervetParams struct {
    21  	Stdin  io.ReadCloser
    22  	Stdout io.WriteCloser
    23  	Stderr io.WriteCloser
    24  	Prompt VervetPrompt
    25  }
    26  
    27  // VervetApp contains the cli Application.
    28  type VervetApp struct {
    29  	App    *cli.App
    30  	Params VervetParams
    31  }
    32  
    33  // VervetPrompt defines the interface for interactive prompts in vervet.
    34  type VervetPrompt interface {
    35  	Confirm(label string) (bool, error)                  // Confirm y/n an action
    36  	Entry(label string) (string, error)                  // Gather a freeform entry in response to a question
    37  	Select(label string, items []string) (string, error) // Select from a limited number of entries
    38  }
    39  
    40  type runKey string
    41  
    42  var vervetKey = runKey("vervet")
    43  
    44  func contextWithApp(ctx context.Context, v *VervetApp) context.Context {
    45  	return context.WithValue(ctx, vervetKey, v)
    46  }
    47  
    48  // Run runs the cli.App with the Vervet config params.
    49  func (v *VervetApp) Run(args []string) error {
    50  	ctx := contextWithApp(context.Background(), v)
    51  	return v.App.RunContext(ctx, args)
    52  }
    53  
    54  // NewApp returns a new VervetApp with the provided params.
    55  func NewApp(app *cli.App, vp VervetParams) *VervetApp {
    56  	app.Reader = vp.Stdin
    57  	app.Writer = vp.Stdout
    58  	app.ErrWriter = vp.Stderr
    59  	return &VervetApp{
    60  		App:    app,
    61  		Params: vp,
    62  	}
    63  }
    64  
    65  var CLIApp = cli.App{
    66  	Name:    "vervet",
    67  	Usage:   "OpenAPI resource versioning tool",
    68  	Version: "develop", // Set in init created with go generate.
    69  	Flags: []cli.Flag{
    70  		&cli.BoolFlag{
    71  			Name:  "debug",
    72  			Usage: "Turn on debug logging",
    73  		},
    74  	},
    75  	Commands: []*cli.Command{
    76  		&BackstageCommand,
    77  		&BuildCommand,
    78  		&FilterCommand,
    79  		&GenerateCommand,
    80  		&LocalizeCommand,
    81  		&ResourceCommand,
    82  		&ResolveCommand,
    83  	},
    84  }
    85  
    86  // Prompt is the default interactive prompt for vervet.
    87  type Prompt struct{}
    88  
    89  // Confirm implements VervetPrompt.Confirm.
    90  func (p Prompt) Confirm(label string) (bool, error) {
    91  	prompt := promptui.Prompt{
    92  		Label:   fmt.Sprintf("%v (y/N)?", label),
    93  		Default: "N",
    94  		Validate: func(input string) error {
    95  			input = strings.ToLower(input)
    96  			if input != "n" && input != "y" {
    97  				return errors.New("you must pick y or n")
    98  			}
    99  			return nil
   100  		},
   101  	}
   102  	result, err := prompt.Run()
   103  	if err != nil {
   104  		return false, err
   105  	}
   106  	return (result == "y"), nil
   107  }
   108  
   109  // Entry implements VervetPrompt.Entry.
   110  func (p Prompt) Entry(label string) (string, error) {
   111  	prompt := promptui.Prompt{
   112  		Label: label,
   113  		Validate: func(result string) error {
   114  			if result == "" {
   115  				return errors.New("you must provide a non-empty response")
   116  			}
   117  			return nil
   118  		},
   119  	}
   120  	result, err := prompt.Run()
   121  	if err != nil {
   122  		return "", err
   123  	}
   124  	return result, nil
   125  }
   126  
   127  // Select implements VervetPrompt.Select.
   128  func (p Prompt) Select(label string, items []string) (string, error) {
   129  	prompt := promptui.Select{
   130  		Label: label,
   131  		Items: items,
   132  	}
   133  	_, result, err := prompt.Run()
   134  	if err != nil {
   135  		return "", err
   136  	}
   137  	return result, nil
   138  }
   139  
   140  // Vervet is the vervet application with the CLI application.
   141  var Vervet = NewApp(&CLIApp, VervetParams{
   142  	Stdin:  os.Stdin,
   143  	Stdout: os.Stdout,
   144  	Stderr: os.Stderr,
   145  	Prompt: Prompt{},
   146  })
   147  
   148  func absPath(path string) (string, error) {
   149  	if path == "" {
   150  		return "", fmt.Errorf("path missing or empty")
   151  	}
   152  	return filepath.Abs(path)
   153  }
   154  
   155  func projectConfig(ctx *cli.Context) (string, string, error) {
   156  	var projectDir, configFile string
   157  	var err error
   158  	if cf := ctx.String("config"); cf != "" {
   159  		configFile, err = filepath.Abs(cf)
   160  		if err != nil {
   161  			return "", "", err
   162  		}
   163  		projectDir = filepath.Dir(configFile)
   164  	} else {
   165  		configFile = filepath.Join(projectDir, ".vervet.yaml")
   166  		projectDir, err = os.Getwd()
   167  		if err != nil {
   168  			return "", "", err
   169  		}
   170  	}
   171  	return projectDir, configFile, nil
   172  }