github.com/w3security/vervet/v5@v5.3.1-0.20230618081846-5bd9b5d799dc/internal/cmd/compiler.go (about) 1 package cmd 2 3 import ( 4 "fmt" 5 "os" 6 "os/exec" 7 8 "github.com/urfave/cli/v2" 9 10 "github.com/w3security/vervet/v5/config" 11 "github.com/w3security/vervet/v5/internal/compiler" 12 ) 13 14 // BuildCommand is the `vervet build` subcommand. 15 var BuildCommand = cli.Command{ 16 Name: "build", 17 Usage: "Build versioned resources into versioned OpenAPI specs", 18 ArgsUsage: "[input resources root] [output api root]", 19 Flags: []cli.Flag{ 20 &cli.StringFlag{ 21 Name: "config", 22 Aliases: []string{"c", "conf"}, 23 Usage: "Project configuration file", 24 }, 25 &cli.BoolFlag{ 26 Name: "lint", 27 Usage: "Enable linting during build", 28 Value: true, 29 }, 30 &cli.StringFlag{ 31 Name: "include", 32 Aliases: []string{"I"}, 33 Usage: "OpenAPI specification to include in build output", 34 }, 35 }, 36 Action: Build, 37 } 38 39 // Build compiles versioned resources into versioned API specs. 40 func Build(ctx *cli.Context) error { 41 project, err := projectFromContext(ctx) 42 if err != nil { 43 return err 44 } 45 comp, err := compiler.New(ctx.Context, project, ctx.Bool("lint")) 46 if err != nil { 47 return err 48 } 49 return comp.BuildAll(ctx.Context) 50 } 51 52 // LintCommand is the `vervet lint` subcommand. 53 var LintCommand = cli.Command{ 54 Name: "lint", 55 Usage: "Lint versioned resources", 56 ArgsUsage: "[input resources root] [output api root]", 57 Flags: []cli.Flag{ 58 &cli.StringFlag{ 59 Name: "config", 60 Aliases: []string{"c", "conf"}, 61 Usage: "Project configuration file", 62 }, 63 }, 64 Action: Lint, 65 } 66 67 // Lint checks versioned resources against linting rules. 68 func Lint(ctx *cli.Context) error { 69 fmt.Fprintln(os.Stderr, ` 70 Vervet is no longer needed to perform API linting. 71 Update your projects to use 'spectral lint' or 'sweater-comb lint' instead. 72 `[1:]) 73 fmt.Fprintln(os.Stderr, ` 74 Attempting to run 'sweater-comb lint' from your current working directory... 75 `[1:]) 76 scpath, err := exec.LookPath("sweater-comb") 77 if err != nil { 78 scpath = "node_modules/.bin/sweater-comb" 79 } 80 if _, err := os.Stat(scpath); err != nil { 81 fmt.Fprintln(os.Stderr, ` 82 Failed to find a 'sweater-comb' executable script. 83 'npm install @w3security/sweater-comb' and try again? 84 `[1:]) 85 return err 86 } 87 cmd := exec.Command(scpath, "lint") 88 cmd.Stdin = os.Stdin 89 cmd.Stdout = os.Stdout 90 cmd.Stderr = os.Stderr 91 return cmd.Run() 92 } 93 94 func projectFromContext(ctx *cli.Context) (*config.Project, error) { 95 var project *config.Project 96 if ctx.Args().Len() == 0 { 97 var configPath string 98 if s := ctx.String("config"); s != "" { 99 configPath = s 100 } else { 101 configPath = ".vervet.yaml" 102 } 103 f, err := os.Open(configPath) 104 if err != nil { 105 return nil, fmt.Errorf("failed to open %q: %w", configPath, err) 106 } 107 defer f.Close() 108 project, err = config.Load(f) 109 if err != nil { 110 return nil, err 111 } 112 } else { 113 api := &config.API{ 114 Resources: []*config.ResourceSet{{ 115 Path: ctx.Args().Get(0), 116 }}, 117 Output: &config.Output{ 118 Path: ctx.Args().Get(1), 119 }, 120 } 121 if includePath := ctx.String("include"); includePath != "" { 122 api.Overlays = append(api.Overlays, &config.Overlay{ 123 Include: includePath, 124 }) 125 } 126 project = &config.Project{ 127 APIs: map[string]*config.API{ 128 "": api, 129 }, 130 } 131 } 132 return project, nil 133 }