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  }