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.