github.com/blend/go-sdk@v1.20220411.3/cmd/profanity/main.go (about) 1 /* 2 3 Copyright (c) 2022 - Present. Blend Labs, Inc. All rights reserved 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file. 5 6 */ 7 8 package main 9 10 import ( 11 "context" 12 "fmt" 13 "os" 14 15 "github.com/spf13/cobra" 16 17 "github.com/blend/go-sdk/configutil" 18 "github.com/blend/go-sdk/logger" 19 "github.com/blend/go-sdk/profanity" 20 "github.com/blend/go-sdk/ref" 21 ) 22 23 var ( 24 flagRulesFile *string 25 flagRulesInclude, flagRulesExclude *[]string 26 flagFilesInclude, flagFilesExclude *[]string 27 flagDirsInclude, flagDirsExclude *[]string 28 flagVerbose *bool 29 flagDebug *bool 30 flagExitFirst *bool 31 ) 32 33 var ( 34 _ configutil.Resolver = (*config)(nil) 35 ) 36 37 type config struct { 38 profanity.Config `yaml:",inline"` 39 } 40 41 // Resolve resolves the config. 42 func (c *config) Resolve(ctx context.Context) error { 43 return configutil.Resolve(ctx, 44 configutil.SetBoolPtr(&c.ExitFirst, configutil.Bool(flagExitFirst), configutil.Bool(c.ExitFirst), configutil.Bool(ref.Bool(false))), 45 configutil.SetString(&c.RulesFile, configutil.String(*flagRulesFile), configutil.String(c.RulesFile), configutil.String(profanity.DefaultRulesFile)), 46 configutil.SetStrings(&c.Rules.Include, configutil.Strings(*flagRulesInclude), configutil.Strings(c.Rules.Include)), 47 configutil.SetStrings(&c.Rules.Exclude, configutil.Strings(*flagRulesExclude), configutil.Strings(c.Rules.Exclude)), 48 configutil.SetStrings(&c.Files.Include, configutil.Strings(*flagFilesInclude), configutil.Strings(c.Files.Include)), 49 configutil.SetStrings(&c.Files.Exclude, configutil.Strings(*flagFilesExclude), configutil.Strings(c.Files.Exclude)), 50 configutil.SetStrings(&c.Dirs.Include, configutil.Strings(*flagDirsInclude), configutil.Strings(c.Dirs.Include)), 51 configutil.SetStrings(&c.Dirs.Exclude, configutil.Strings(*flagDirsExclude), configutil.Strings(c.Dirs.Exclude)), 52 configutil.SetBoolPtr(&c.Verbose, configutil.Bool(flagVerbose), configutil.Bool(c.Verbose), configutil.Bool(ref.Bool(false))), 53 configutil.SetBoolPtr(&c.Debug, configutil.Bool(flagDebug), configutil.Bool(c.Debug), configutil.Bool(ref.Bool(false))), 54 ) 55 } 56 57 var configExample = `CONTAINS_EXAMPLE: # id is meant to be a de-duplicating identifier 58 description: "please use 'foo.Bar', not a concrete type reference" # description should include remediation steps 59 contents: { contains: { include: [ "foo.BarImpl" ] } } 60 61 EXCLUDES_EXAMPLE: 62 description: "please dont use HerpDerp except in tests" 63 contents: { regex: { include: [ "HerpDerp$" ] } } 64 files: { exclude: [ "*_test.go" ] } 65 66 IMPORTS_EXAMPLE: # you can assert a go AST doesnt contains a given import by glob 67 description: "dont include command stuff" 68 goImports: { include: [ "github.com/blend/go-sdk/cmd/*" ] } 69 ` 70 71 func command() *cobra.Command { 72 root := &cobra.Command{ 73 Use: "profanity", 74 Short: "Enforce profanity rules in a directory tree.", 75 Long: "Enforce profanity rules in a directory tree with inherited rules for each child directory.", 76 Example: fmt.Sprintf(` 77 # Run a basic rules set 78 profanity --rules=.profanity.yml 79 80 # Run a basic rules set with excluded files by glob 81 profanity --rules=.profanity.yml --files-exclude="*_test.go" 82 83 # Run a basic rules set with included and excluded files by glob 84 profanity --rules=.profanity.yml --files-include="*.go" --files-exclude="*_test.go" 85 86 # An example rule file looks like 87 88 """ yaml 89 %s 90 """ 91 92 For an example rule file (with many more rules), see .profanity.yml in the root of the repo. 93 `, configExample), 94 } 95 96 flagRulesFile = root.Flags().StringP("rules", "r", profanity.DefaultRulesFile, "The rules file to search for in each valid directory") 97 flagRulesInclude = root.Flags().StringArray("rules-include", nil, "Rules to include in glob matching format; can be multiple") 98 flagRulesExclude = root.Flags().StringArray("rules-exclude", nil, "Rules to exclude in glob matching format; can be multiple") 99 flagFilesInclude = root.Flags().StringArray("include-file", nil, "Files to include in glob matching format; can be multiple") 100 flagFilesExclude = root.Flags().StringArray("exclude-file", nil, "Files to exclude in glob matching format; can be multiple") 101 flagDirsInclude = root.Flags().StringArray("include-dir", nil, "Directories to include in glob matching format; can be multiple") 102 flagDirsExclude = root.Flags().StringArray("exclude-dir", nil, "Directories to exclude in glob matching format; can be multiple") 103 flagVerbose = root.Flags().BoolP("verbose", "v", false, "If we should show verbose output.") 104 flagDebug = root.Flags().BoolP("debug", "d", false, "If we should show debug output.") 105 flagExitFirst = root.Flags().Bool("exit-first", false, "If we should fail the run after the first error.") 106 return root 107 } 108 109 func main() { 110 cmd := command() 111 cmd.Run = func(parent *cobra.Command, args []string) { 112 var cfg config 113 var cfgOptions []configutil.Option 114 if flagDebug != nil && *flagDebug { 115 cfgOptions = append(cfgOptions, configutil.OptLog(logger.All().WithPath("config"))) 116 } 117 118 if _, err := configutil.Read(&cfg, cfgOptions...); !configutil.IsIgnored(err) { 119 fmt.Fprintf(os.Stderr, "%v\n", err) 120 os.Exit(1) 121 } 122 123 engine := profanity.New(profanity.OptConfig(cfg.Config)) 124 engine.Stdout = os.Stdout 125 engine.Stderr = os.Stderr 126 127 if err := engine.Process(); err != nil { 128 fmt.Fprintf(os.Stderr, "%v\n", err) 129 os.Exit(1) 130 return 131 } 132 } 133 134 if err := cmd.Execute(); err != nil { 135 fmt.Fprintf(os.Stderr, "%v\n", err) 136 os.Exit(1) 137 } 138 }