github.com/ajguerrer/rules_go@v0.20.3/go/nogo.rst (about) 1 |logo| nogo build-time code analysis 2 ==================================== 3 4 .. _nogo: nogo.rst#nogo 5 .. _go_library: core.rst#go_library 6 .. _go_tool_library: core.rst#go_tool_library 7 .. _analysis: https://godoc.org/golang.org/x/tools/go/analysis 8 .. _Analyzer: https://godoc.org/golang.org/x/tools/go/analysis#Analyzer 9 .. _GoLibrary: providers.rst#GoLibrary 10 .. _GoSource: providers.rst#GoSource 11 .. _GoArchive: providers.rst#GoArchive 12 .. _vet: https://golang.org/cmd/vet/ 13 14 .. role:: param(kbd) 15 .. role:: type(emphasis) 16 .. role:: value(code) 17 .. |mandatory| replace:: **mandatory value** 18 .. |logo| image:: nogo_logo.png 19 .. footer:: The ``nogo`` logo was derived from the Go gopher, which was designed by Renee French. (http://reneefrench.blogspot.com/) The design is licensed under the Creative Commons 3.0 Attributions license. Read this article for more details: http://blog.golang.org/gopher 20 21 22 **WARNING**: This functionality is experimental, so its API might change. 23 Please do not rely on it for production use, but feel free to use it and file 24 issues. 25 26 ``nogo`` is a tool that analyzes the source code of Go programs. It runs 27 alongside the Go compiler in the Bazel Go rules and rejects programs that 28 contain disallowed coding patterns. In addition, ``nogo`` may report 29 compiler-like errors. 30 31 ``nogo`` is a powerful tool for preventing bugs and code anti-patterns early 32 in the development process. It may be used to run the same analyses as `vet`_, 33 and you can write new analyses for your own code base. 34 35 .. contents:: . 36 :depth: 2 37 38 ----- 39 40 Setup 41 ----- 42 43 Create a `nogo`_ target in a ``BUILD`` file in your workspace. The ``deps`` 44 attribute of this target must contain labels all the analyzers targets that you 45 want to run. 46 47 .. code:: bzl 48 49 load("@io_bazel_rules_go//go:def.bzl", "nogo") 50 51 nogo( 52 name = "my_nogo", 53 deps = [ 54 # analyzer from the local repository 55 ":importunsafe", 56 # analyzer from a remote repository 57 "@org_golang_x_tools//go/analysis/passes/printf:go_tool_library", 58 ], 59 visibility = ["//visibility:public"], # must have public visibility 60 ) 61 62 go_tool_library( 63 name = "importunsafe", 64 srcs = ["importunsafe.go"], 65 importpath = "importunsafe", 66 deps = ["@org_golang_x_tools//go/analysis:go_tool_library"], 67 visibility = ["//visibility:public"], 68 ) 69 70 Pass a label for your `nogo`_ target to ``go_register_toolchains`` in your 71 ``WORKSPACE`` file. 72 73 .. code:: bzl 74 75 load("@io_bazel_rules_go//go:deps.bzl", "go_rules_dependencies", "go_register_toolchains") 76 go_rules_dependencies() 77 go_register_toolchains(nogo="@//:my_nogo") # my_nogo is in the top-level BUILD file of this workspace 78 79 **NOTE**: You must include ``"@//"`` prefix when referring to targets in the local 80 workspace. 81 82 The `nogo`_ rule will generate a program that executes all the supplied 83 analyzers at build-time. The generated ``nogo`` program will run alongside the 84 compiler when building any Go target (e.g. `go_library`_) within your workspace, 85 even if the target is imported from an external repository. However, ``nogo`` 86 will not run when targets from the current repository are imported into other 87 workspaces and built there. 88 89 Writing and registering analyzers 90 --------------------------------- 91 92 ``nogo`` analyzers are Go packages that declare a variable named ``Analyzer`` 93 of type `Analyzer`_ from package `analysis`_. Each analyzer is invoked once per 94 Go package, and is provided the abstract syntax trees (ASTs) and type 95 information for that package, as well as relevant results of analyzers that have 96 already been run. For example: 97 98 .. code:: go 99 100 // package importunsafe checks whether a Go package imports package unsafe. 101 package importunsafe 102 103 import ( 104 "strconv" 105 106 "golang.org/x/tools/go/analysis" 107 ) 108 109 var Analyzer = &analysis.Analyzer{ 110 Name: "importunsafe", 111 Doc: "reports imports of package unsafe", 112 Run: run, 113 } 114 115 func run(pass *analysis.Pass) (interface{}, error) { 116 for _, f := range pass.Files { 117 for _, imp := range f.Imports { 118 path, err := strconv.Unquote(imp.Path.Value) 119 if err == nil && path == "unsafe" { 120 pass.Reportf(imp.Pos(), "package unsafe must not be imported") 121 } 122 } 123 } 124 return nil, nil 125 } 126 127 Any diagnostics reported by the analyzer will stop the build. Do not emit 128 diagnostics unless they are severe enough to warrant stopping the build. 129 130 Each analyzer must be written as a `go_tool_library`_ rule and must import 131 `@org_golang_x_tools//go/analysis:go_tool_library`, the `go_tool_library`_ 132 version of the package `analysis`_ target. 133 134 For example: 135 136 .. code:: bzl 137 138 load("@io_bazel_rules_go//go:def.bzl", "go_tool_library") 139 140 go_tool_library( 141 name = "importunsafe", 142 srcs = ["importunsafe.go"], 143 importpath = "importunsafe", 144 deps = ["@org_golang_x_tools//go/analysis:go_tool_library"], 145 visibility = ["//visibility:public"], 146 ) 147 148 go_tool_library( 149 name = "unsafedom", 150 srcs = [ 151 "check_dom.go", 152 "dom_utils.go", 153 ], 154 importpath = "unsafedom", 155 deps = ["@org_golang_x_tools//go/analysis:go_tool_library"], 156 visibility = ["//visibility:public"], 157 ) 158 159 **NOTE**: `go_tool_library`_ is a limited variant of ``go_library`` which avoids 160 a circular dependency: `go_library`_ implicitly depends on `nogo`_, which 161 depends on analyzer libraries, which must not depend on `nogo`_. 162 `go_tool_library`_ does not have the same implicit dependency. 163 164 Pass labels for these targets to the ``deps`` attribute of your `nogo`_ target, 165 as described in the `Setup`_ section. 166 167 Configuring analyzers 168 ~~~~~~~~~~~~~~~~~~~~~ 169 170 By default, ``nogo`` analyzers will emit diagnostics for all Go source files 171 built by Bazel. This behavior can be changed with a JSON configuration file. 172 173 The top-level JSON object in the file must be keyed by the name of the analyzer 174 being configured. These names must match the ``Analyzer.Name`` of the registered 175 analysis package. The JSON object's values are themselves objects which may 176 contain the following key-value pairs: 177 178 +----------------------------+---------------------------------------------------------------------+ 179 | **Key** | **Type** | 180 +----------------------------+---------------------------------------------------------------------+ 181 | ``"description"`` | :type:`string` | 182 +----------------------------+---------------------------------------------------------------------+ 183 | Description of this analyzer configuration. | 184 +----------------------------+---------------------------------------------------------------------+ 185 | ``"only_files"`` | :type:`dictionary, string to string` | 186 +----------------------------+---------------------------------------------------------------------+ 187 | Specifies files that this analyzer will emit diagnostics for. | 188 | Its keys are regular expression strings matching Go file names, and its values are strings | 189 | containing a description of the entry. | 190 | If both ``only_files`` and ``exclude_files`` are empty, this analyzer will emit diagnostics for | 191 | all Go files built by Bazel. | 192 +----------------------------+---------------------------------------------------------------------+ 193 | ``"exclude_files"`` | :type:`dictionary, string to string` | 194 +----------------------------+---------------------------------------------------------------------+ 195 | Specifies files that this analyzer will not emit diagnostics for. | 196 | Its keys and values are strings that have the same semantics as those in ``only_files``. | 197 | Keys in ``exclude_files`` override keys in ``only_files``. If a .go file matches a key present | 198 | in both ``only_files`` and ``exclude_files``, the analyzer will not emit diagnostics for that | 199 | file. | 200 +----------------------------+---------------------------------------------------------------------+ 201 202 Example 203 ^^^^^^^ 204 205 The following configuration file configures the analyzers named ``importunsafe`` 206 and ``unsafedom``. Since the ``loopclosure`` analyzer is not explicitly 207 configured, it will emit diagnostics for all Go files built by Bazel. 208 209 .. code:: json 210 211 { 212 "importunsafe": { 213 "exclude_files": { 214 "src/foo\\.go": "manually verified that behavior is working-as-intended", 215 "src/bar\\.go": "see issue #1337" 216 } 217 }, 218 "unsafedom": { 219 "only_files": { 220 "src/js/.*": "" 221 }, 222 "exclude_files": { 223 "src/(third_party|vendor)/.*": "enforce DOM safety requirements only on first-party code" 224 } 225 } 226 } 227 228 This label referencing this configuration file must be provided as the 229 ``config`` attribute value of the ``nogo`` rule. 230 231 .. code:: bzl 232 233 nogo( 234 name = "my_nogo", 235 deps = [ 236 ":importunsafe", 237 ":unsafedom", 238 "@analyzers//:loopclosure", 239 ], 240 config = "config.json", 241 visibility = ["//visibility:public"], 242 ) 243 244 Running vet 245 ----------- 246 247 `vet`_ is a tool that examines Go source code and reports correctness issues not 248 caught by Go compilers. It is included in the official Go distribution. Vet 249 runs analyses built with the Go `analysis`_ framework. nogo uses the 250 same framework, which means vet checks can be run with nogo. 251 252 You can choose to run a safe subset of vet checks alongside the Go compiler by 253 setting ``vet = True`` in your `nogo`_ target. This will only run vet checks 254 that are believed to be 100% accurate (the same set run by ``go test`` by 255 default). 256 257 .. code:: bzl 258 259 nogo( 260 name = "my_nogo", 261 vet = True, 262 visibility = ["//visibility:public"], 263 ) 264 265 Setting ``vet = True`` is equivalent to adding the ``atomic``, ``bools``, 266 ``buildtag``, ``nilfunc``, and ``printf`` analyzers from 267 ``@org_golang_x_tools//go/analysis/passes`` to the ``deps`` list of your 268 ``nogo`` rule. 269 270 See the full list of available nogo checks: 271 272 .. code:: shell 273 274 bazel query 'kind(go_tool_library, @org_golang_x_tools//go/analysis/passes/...)' 275 276 277 API 278 --- 279 280 nogo 281 ~~~~ 282 283 This generates a program that that analyzes the source code of Go programs. It 284 runs alongisde the Go compiler in the Bazel Go rules and rejects programs that 285 contain disallowed coding patterns. 286 287 Attributes 288 ^^^^^^^^^^ 289 290 +----------------------------+-----------------------------+---------------------------------------+ 291 | **Name** | **Type** | **Default value** | 292 +----------------------------+-----------------------------+---------------------------------------+ 293 | :param:`name` | :type:`string` | |mandatory| | 294 +----------------------------+-----------------------------+---------------------------------------+ 295 | A unique name for this rule. | 296 +----------------------------+-----------------------------+---------------------------------------+ 297 | :param:`deps` | :type:`label_list` | :value:`None` | 298 +----------------------------+-----------------------------+---------------------------------------+ 299 | List of Go libraries that will be linked to the generated nogo binary. | 300 | | 301 | These libraries must declare an ``analysis.Analyzer`` variable named `Analyzer` to ensure that | 302 | the analyzers they implement are called by nogo. | 303 | | 304 | To avoid bootstrapping problems, these libraries must be `go_tool_library`_ targets, and must | 305 | import `@org_golang_x_tools//go/analysis:go_tool_library`, the `go_tool_library`_ version of | 306 | the package `analysis`_ target. | 307 +----------------------------+-----------------------------+---------------------------------------+ 308 | :param:`config` | :type:`label` | :value:`None` | 309 +----------------------------+-----------------------------+---------------------------------------+ 310 | JSON configuration file that configures one or more of the analyzers in ``deps``. | 311 +----------------------------+-----------------------------+---------------------------------------+ 312 | :param:`vet` | :type:`bool` | :value:`False` | 313 +----------------------------+-----------------------------+---------------------------------------+ 314 | If true, a safe subset of vet checks will be run by nogo (the same subset run | 315 | by ``go test ``). | 316 +----------------------------+-----------------------------+---------------------------------------+ 317 318 Example 319 ^^^^^^^ 320 321 .. code:: bzl 322 323 nogo( 324 name = "my_nogo", 325 deps = [ 326 ":importunsafe", 327 ":otheranalyzer", 328 "@analyzers//:unsafedom", 329 ], 330 config = ":config.json", 331 vet = True, 332 visibility = ["//visibility:public"], 333 )