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