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      )