github.com/jonsyu1/godel@v0.0.0-20171017211503-64567a0cf169/docs/Check.md (about)

     1  Summary
     2  -------
     3  `./godelw check` runs a set of static analysis checks on the project Go files.
     4  
     5  Tutorial start state
     6  --------------------
     7  
     8  * `$GOPATH/src/github.com/nmiyake/echgo` exists and is the working directory
     9  * Project contains `godel` and `godelw`
    10  * Project contains `main.go`
    11  * Project contains `.gitignore` that ignores IDEA files
    12  * Project contains `echo/echo.go`
    13  
    14  ([Link](https://github.com/nmiyake/echgo/tree/24f63f727542c7189c82f04f7e2a4aa38c090137))
    15  
    16  Run checks
    17  ----------
    18  
    19  When writing Go code, it can be useful to check code for errors and consistency issues using static code analysis.
    20  
    21  The current echo program simply echoes the user's input exactly. We will extend the program to allow different types of
    22  echoes to be generated. As a first step to doing this, we will define an `Echoer` interface that defines an `Echo`
    23  function and refactor the current echo functionality to be a simple echoer that implements this interface.
    24  
    25  Run the following to update the program to perform this refactor:
    26  
    27  ```
    28  ➜ echo 'package echo
    29  
    30  type Echoer interface {
    31  	Echo(in string) string
    32  }' > echo/echoer.go
    33  ➜ echo 'package echo
    34  
    35  func NewEchoer() Echoer {
    36  	return &simpleEchoer{}
    37  }
    38  
    39  type simpleEchoer struct{}
    40  
    41  func (_ *simpleEchoer) Echo(in string) string {
    42  	return in
    43  }' > echo/echo.go
    44  ➜ echo 'package main
    45  
    46  import (
    47  	"fmt"
    48  	"os"
    49  	"strings"
    50  
    51  	"github.com/nmiyake/echgo/echo"
    52  )
    53  
    54  func main() {
    55  	echoer := echo.NewEchoer()
    56  	fmt.Println(echoer.Echo(strings.Join(os.Args[1:], " ")))
    57  }' > main.go
    58  ```
    59  
    60  These files are formatted correctly and form a fully functioning program. Run `./godelw check` to run static code checks
    61  on the project:
    62  
    63  ```
    64  ➜ ./godelw check
    65  Running compiles...
    66  Running deadcode...
    67  Running errcheck...
    68  Running extimport...
    69  Running golint...
    70  echo/echo.go:9:1: receiver name should not be an underscore
    71  Running govet...
    72  Running importalias...
    73  Running ineffassign...
    74  Running nobadfuncs...
    75  Running novendor...
    76  Running outparamcheck...
    77  Running unconvert...
    78  Running varcheck...
    79  Checks produced output: [golint]
    80  ```
    81  
    82  The output indicates that there was an issue identified by the `golint` check. Fix the issue by updating the receiver
    83  name:
    84  
    85  ```
    86  ➜ echo 'package echo
    87  
    88  func NewEchoer() Echoer {
    89  	return &simpleEchoer{}
    90  }
    91  
    92  type simpleEchoer struct{}
    93  
    94  func (e *simpleEchoer) Echo(in string) string {
    95  	return in
    96  }' > echo/echo.go
    97  ```
    98  
    99  Run `./godelw check` again to verify that the issue has been resolved:
   100  
   101  ```
   102  ➜ ./godelw check
   103  Running compiles...
   104  Running deadcode...
   105  Running errcheck...
   106  Running extimport...
   107  Running golint...
   108  Running govet...
   109  Running importalias...
   110  Running ineffassign...
   111  Running nobadfuncs...
   112  Running novendor...
   113  Running outparamcheck...
   114  Running unconvert...
   115  Running varcheck...
   116  ```
   117  
   118  Commit the changes to the repository:
   119  
   120  ```
   121  ➜ git add main.go echo
   122  ➜ git commit -m "Add echoer interface"
   123  [master 0a64992] Add echoer interface
   124   3 files changed, 15 insertions(+), 3 deletions(-)
   125   create mode 100644 echo/echoer.go
   126  ➜ git status
   127  On branch master
   128  nothing to commit, working directory clean
   129  ```
   130  
   131  Refer to the "More" sections below for examples of configuring the checks in different ways.
   132  
   133  Tutorial end state
   134  ------------------
   135  
   136  * `$GOPATH/src/github.com/nmiyake/echgo` exists and is the working directory
   137  * Project contains `godel` and `godelw`
   138  * Project contains `main.go`
   139  * Project contains `.gitignore` that ignores IDEA files
   140  * Project contains `echo/echo.go` and `echo/echoer.go`
   141  
   142  ([Link](https://github.com/nmiyake/echgo/tree/0a649925e317b7896e537ef23a4885062a3ec9fb))
   143  
   144  Tutorial next step
   145  ------------------
   146  
   147  [Run tests](https://github.com/palantir/godel/wiki/Test)
   148  
   149  More
   150  ----
   151  
   152  ### Suppress check issues based on output
   153  
   154  In some instances, it may be desirable to suppress certain issues flagged by checks. As an example, modify
   155  `echo/echoer.go` as follows:
   156  
   157  ```
   158  ➜ echo 'package echo
   159  
   160  // Echoes the input.
   161  type Echoer interface {
   162  	Echo(in string) string
   163  }' > echo/echoer.go
   164  ```
   165  
   166  Running `./godelw check` flags the following:
   167  
   168  ```
   169  ➜ ./godelw check
   170  Running compiles...
   171  Running deadcode...
   172  Running errcheck...
   173  Running extimport...
   174  Running golint...
   175  echo/echoer.go:3:1: comment on exported type Echoer should be of the form "Echoer ..." (with optional leading article)
   176  Running govet...
   177  Running importalias...
   178  Running ineffassign...
   179  Running nobadfuncs...
   180  Running novendor...
   181  Running outparamcheck...
   182  Running unconvert...
   183  Running varcheck...
   184  Checks produced output: [golint]
   185  ```
   186  
   187  Although this is a valid check performed by `go lint`, not all projects conform exactly with the Go style for comments.
   188  In some cases, it makes sense to disable specific checks like this. This can be done by updating the
   189  `godel/config/check.yml` file to configure the `check` command to ignore all output from the `golint` check that
   190  contains `comment on exported type \w should be of the form` in its message.
   191  
   192  The default configuration for `godel/config/check.yml` is as follows:
   193  
   194  ```
   195  ➜ cat godel/config/check.yml
   196  checks:
   197    golint:
   198      filters:
   199        - value: "should have comment or be unexported"
   200        - value: "or a comment on this block"
   201  ```
   202  
   203  Add the line `- value: "comment on exported type [[:word:]]+ should be of the form"` to this configuration:
   204  
   205  ```
   206  ➜ echo 'checks:
   207    golint:
   208      filters:
   209        - value: "should have comment or be unexported"
   210        - value: "or a comment on this block"
   211        - value: "comment on exported type [[:word:]]+ should be of the form"' > godel/config/check.yml
   212  ```
   213  
   214  Re-run `./godelw check` with the updated configuration to verify that lines that match this output are no longer
   215  reported:
   216  
   217  ```
   218  ➜ ./godelw check
   219  Running compiles...
   220  Running deadcode...
   221  Running errcheck...
   222  Running extimport...
   223  Running golint...
   224  Running govet...
   225  Running importalias...
   226  Running ineffassign...
   227  Running nobadfuncs...
   228  Running novendor...
   229  Running outparamcheck...
   230  Running unconvert...
   231  Running varcheck...
   232  ```
   233  
   234  Revert the local changes by running the following:
   235  
   236  ```
   237  ➜ git checkout -- echo godel
   238  ➜ git status
   239  On branch master
   240  nothing to commit, working directory clean
   241  ```
   242  
   243  Filters have a `type` and a `value`. When `type` is not specified (as in the examples above), it defaults to `message`,
   244  which means that the value is matched against the message of the output. The `type` field for filters can also be `name`
   245  or `path`. `name` matches files based on their name, while `path` matches based on an exact relative path.
   246  
   247  For example, the following configuration will ignore all issues reported by `errcheck` for `main.go`:
   248  
   249  ```yaml
   250  checks:
   251    errcheck:
   252      filters:
   253        - type: "path"
   254          value: "main.go"
   255  ```
   256  
   257  Because the `type` above is `path`, this configuration would ignore `errcheck` issues in `./main.go`. However, issues in
   258  other files named `main.go` in the project (for example, `./subproject/main.go`) would still be reported. Setting the
   259  `type` to `name` would change the behavior so that issues in all files named `main.go` would be ignored.
   260  
   261  The match values use Go regular expressions to perform matches. For example, the following configuration ignores all
   262  `golint` issues reported for any files that have the extension `.pb.go`:
   263  
   264  ```yaml
   265  checks:
   266    golint:
   267      filters:
   268        - type: "name"
   269          value: ".*.pb.go"
   270  ```
   271  
   272  ### Disable checks
   273  
   274  Checks can be disabled completely for the entire project by setting the `skip` field to `true`.
   275  
   276  For example, the following configuration will disable the `golint` check for the project:
   277  
   278  ```
   279  ➜ echo 'checks:
   280    golint:
   281      skip: true' > godel/config/check.yml
   282  ```
   283  
   284  Run `./godelw check` with the updated configuration to verify that the `golint` check is no longer run:
   285  
   286  ```
   287  ➜ ./godelw check
   288  Running compiles...
   289  Running deadcode...
   290  Running errcheck...
   291  Running extimport...
   292  Running govet...
   293  Running importalias...
   294  Running ineffassign...
   295  Running nobadfuncs...
   296  Running novendor...
   297  Running outparamcheck...
   298  Running unconvert...
   299  Running varcheck...
   300  ```
   301  
   302  Revert the local changes by running the following:
   303  
   304  ```
   305  ➜ git checkout -- godel
   306  ➜ git status
   307  On branch master
   308  nothing to commit, working directory clean
   309  ```
   310  
   311  ### Configure check arguments
   312  
   313  Many of the tools used by `check` accept command-line arguments. The arguments that are passed to the tool can be
   314  specified using the `args` parameter. The elements of the `args` parameter are provided to the underlying check. For
   315  example, the following configuration configures the `errcheck` check to be run with the arguments
   316  `-ignore 'io/ioutil:ReadFile'`:
   317  
   318  ```yaml
   319  checks:
   320    errcheck:
   321      args:
   322        - "-ignore"
   323        - "io/ioutil:ReadFile"
   324  ```
   325  
   326  ### Run individual checks
   327  
   328  Individual checks can be run in isolation by specifying the name of the check as an argument to `check`. This can be
   329  useful when iterating on code in an attempt to fix an issue flagged by a specific check.
   330  
   331  For example, the following runs only `govet`:
   332  
   333  ```
   334  ➜ ./godelw check govet
   335  Running govet...
   336  ```
   337  
   338  ### Constituent checks
   339  
   340  The following checks are run as part of `check`:
   341  
   342  * [`compiles`](https://github.com/palantir/checks/tree/master/compiles) verifies that all of the Go code in the project
   343    compiles, including code in test files (which is not checked by `go build`)
   344  * [`deadcode`](https://github.com/tsenart/deadcode) finds unused code
   345  * [`errcheck`](https://github.com/kisielk/errcheck) ensures that returned errors are checked
   346  * [`extimport`](https://github.com/palantir/checks/tree/master/extimport) verifies that all non-standard library
   347    packages that are imported by the project are present in a vendor directory within the project
   348  * [`govet`](https://github.com/nmiyake/govet) runs [`go vet`](https://golang.org/cmd/vet/)
   349  * [`importalias`](https://github.com/palantir/checks/tree/master/importalias) ensures that, if an import path in the
   350    package is imported using an alias, then all imports in the project that assign an alias for that path use the same
   351    alias
   352  * [`ineffassign`](https://github.com/gordonklaus/ineffassign) flags ineffectual assignment statements
   353  * [`nobadfuncs`](https://github.com/palantir/checks/tree/master/nobadfuncs) allows a project to blacklist specific
   354    functions (for example, `fmt.Println`) and flags all uses of the blacklisted functions unless the use is specifically
   355    whitelisted (see project documentation for details)
   356  * [`novendor`](https://github.com/palantir/checks/tree/master/novendor) flags projects that exist in the `vendor`
   357    directory but are not used by the project
   358  * [`outparamcheck`](https://github.com/palantir/checks/tree/master/outparamcheck) checks that functions that are meant
   359    to take an output parameter defined as an `interface{}` are passed pointers to an object rather than a concrete object
   360  * [`unconvert`](https://github.com/mdempsky/unconvert) flags unnecessary conversions
   361  * [`varcheck`](https://github.com/opennota/check) checks for unused global variables and constants
   362  
   363  One of the core principles of gödel is reproducibility, so the set of available checks (and their specific
   364  implementations) are hard-coded in gödel itself. This means that adding a new check or upgrading the version of a check
   365  is a change that must be made in gödel itself.
   366  
   367  If there is a check that you would like to see added to gödel (or believe that the version of an existing check should
   368  be updated), please file an issue on the project.
   369  
   370  Currently, the set of checks that are run are built into gödel itself. There are plans to make the checks that are run
   371  pluggable so that they can be customized based on the needs/desires of specific projects.