github.com/please-build/puku@v1.7.3-0.20240516143641-f7d7f4941f57/README.md (about)

     1  # Puku
     2  
     3  Puku is a tool for maintaining your go rules, similar to gazelle. It's named after puku, which is an antelope native to
     4  Southern Africa. This tool is still under development but is rapidly approaching a generally available release!
     5  
     6  ## Quick start
     7  
     8  The easiest way to get started is to install puku with go:
     9  ```bash
    10  $ go install github.com/please-build/puku/cmd/puku
    11  ```
    12  
    13  Then make sure `$GOPATH/bin` is in `$PATH`. This can be done by adding `export PATH=$PATH:$GOROOT/bin:$GOPATH/bin` to 
    14  your `~/.bashrc`, or similar. 
    15  
    16  ### Running puku with Please
    17  
    18  Add a remote file to your repo under `third_party/binary/BUILD`
    19  ```python
    20  version = "9.9.9"
    21  remote_file(
    22      name = "puku",
    23      url = f"https://github.com/please-build/puku/releases/download/v{version}/puku-{version}-{CONFIG.OS}_{CONFIG.ARCH}",
    24      binary = True,
    25  )
    26  ```
    27  
    28  Then add an alias to your `.plzconfig`, or for personal usage, your `.plzconfig.local`:
    29  ```
    30  [Alias "puku"]
    31  Cmd = run //third_party/binary:puku --
    32  PositionalLabels = true
    33  Desc = A tool to update BUILD files in Go packages 
    34  ```
    35  
    36  Then you can use `plz puku` in place of `puku`. 
    37  
    38  ## Usage
    39  
    40  Running `puku fmt` with no args will format all your source files. It has sensible defaults, reading your 
    41  `.plzconfig` file to avoid unnecessary configuration, however it can be configured via `puku.json` files throughout the 
    42  repository. It supports both `go_module()` and `go_repo()` options for third party code, however it can also generate
    43  new `go_repo()` targets to satisfy new dependencies.
    44  
    45  Puku can also format files under specific paths using a similar wildcard syntax to Please:
    46  
    47  ```
    48  $ puku fmt //src/...
    49  ```
    50  
    51  Puku supports `go_library`, `go_test`, `go_binary`, `go_benchmark`, `proto_library`, and `grpc_library` out of the box, but can be
    52  configured to support other rules. See the configuration section below for more information.
    53  
    54  ### Updating and adding third party dependencies with go.mod (optional) 
    55  
    56  Puku will attempt to resolve new imports and add `go_repo` rules to satisfy them. This works most of the time, however 
    57  setting `ModFile = //:gomod` in your Go plugin, is far more robust and highly recommended. Without this, you may just 
    58  have to pass in modules via `requirements = ["github.com/example/module"]`, to help resolve imports to the correct module path.
    59  
    60  This approach facilitates using standard go tooling i.e. `go get` to resolve dependencies. Puku will then sync new 
    61  dependencies from your `go.mod` to `third_party/go/BUILD` automatically as necessary, or on demand via `puku sync` 
    62  
    63  To do this, add a filegroup in your repo root: 
    64  
    65  ```python
    66  filegroup(
    67      name = "gomod",
    68      srcs = ["go.mod"],
    69      visibility = ["PUBLIC"],
    70  )
    71  ```
    72  
    73  And configure the Go plugin like so:
    74  ```
    75  [Plugin "go"]
    76  Target = //plugins:go
    77  ModFile = //:gomod
    78  ...
    79  ```
    80  
    81  Then when adding a new module, run `go get github.com/foo/bar` and puku will sync this across when you next run 
    82  `puku fmt` or `puku sync`. Updating modules can be done similarly via `go get -u`, and `puku sync`. Puku currently 
    83  does **not** clear out old dependencies no longer found in the `go.mod`. 
    84  
    85  ### Migration
    86  
    87  Use `puku migrate` to migrate your third party rules from `go_module()` to `go_repo`. This subcommand will create
    88  build rules that mimic the behaviour of `go_module()` so this should be a drop in replacement. This command optionally 
    89  takes modules as positional arguments, allowing a piecemeal migration e.g. `puku migrate github.com/example/module`.
    90  
    91  ### Watch mode
    92  
    93  To run puku in watch mode, use `puku watch`. Puku will then watch all directories matched by the wildcards passed, 
    94  and automatically update rules as `.go` sources change.
    95  
    96  ### Lint mode
    97  
    98  By running `puku lint`, puku will run in a lint-only mode. It will exit without output if everything linted fine,
    99  otherwise, it will print the desired state to stdout. This can be useful to integrate with tools like arcanist that can
   100  prompt users with a preview before applying auto-fixes.
   101  
   102  ## Supporting custom build definitions
   103  
   104  Puku treats targets as one of three types: `library`, `binary`, or `test` targets. Sources are allocated to these 
   105  targets based on their type. Targets that are `library` types are additionally used to satisfy imports from other 
   106  targets. 
   107  
   108  For example, if you have the following `BUILD` file:
   109  
   110  ```
   111  my_go_library(
   112      name = "foo",
   113      srcs = ["foo.go"],
   114  )
   115  
   116  go_test(
   117      name = "foo_test",
   118      srcs = ["foo_test.go"],
   119      deps = [":foo"],
   120  )
   121  ```
   122  
   123  Puku can be configured to treat custom types as one of these three kinds by adding some configuration to `puku.json` 
   124  files. These can be checked in throughout the repo, and the kinds will apply to all subdirectories. For example, the
   125  following will make puku treat `my_go_library()` the same way it treats `go_library()`.
   126  
   127  ```
   128  libKinds": {
   129      "my_go_library": {
   130          "providedDeps": ["//common/go:some_common_lib"]
   131      },
   132  }
   133  ``` 
   134  
   135  Provided deps are assumed to be added to the list of deps provided to the build rule. Puku will avoid adding these when
   136  it sees an import that's satisfied by them. 
   137  
   138  ### Non-go sources
   139  Puku will try and determine the dependencies of a target by parsing their sources. Sometimes a target produces a go 
   140  package without taking in go sources directly, for example `proto_library()`. If we want to introduce a new protoc 
   141  plugin, say `grcp_gateway()`, we can teach puku about this like so:
   142  
   143  ```
   144  libKinds": {
   145      "grcp_gateway": {
   146          "nonGoSources": true
   147      },
   148  }
   149  ```
   150  
   151  When puku sees a target like this:
   152  ```
   153  grpc_gateway(
   154      name = "foo",
   155      srcs = ["foo.proto"],
   156  )
   157  ```
   158  
   159  Puku will avoid trying to parse `foo.proto` as a go source, and will not attempt to remove dependencies from the target,
   160  but it will still resolve imports for that path to that target. 
   161  
   162  ## Configuration
   163  
   164  Puku can be configured via `puku.json` files that are loaded as puku walks the directory structure. Configuration values
   165  are overridden as new files are discovered at a deeper level in the source tree.
   166  
   167  ```yaml
   168  {
   169    // The directory to load and write third party rules to. If using `go_repo`, puku will update this package to satisfy
   170    // new imports
   171    "thirdPartyDir": "third_party/go",
   172    // The path to the please binary
   173    "pleasePath": "plz",
   174    // A mapping between import paths and targets for any special cases that puku doesn't currently support
   175    "knownTargets": {
   176      "github.com/some/module": "//third_party/go:module"
   177    },
   178    // Any kinds that can satisfy an import. These will be treated much the same way puku treats go_library. Right now
   179    // puku assumes that the rules will use name, srcs, deps, and visibility arguments in the same way go_library does.
   180    // Puku will attempt to allocate production (i.e. non-test) sources to these targets.
   181    "libKinds": {
   182      "my_go_library": {
   183          // Any deps that the build definition will add to the target. Puku will avoid adding these dependencies via
   184          // deps.
   185          "providedDeps": ["//common/go:some_common_lib"],
   186          // The visibility of the target if no visibility arg is passed
   187          "defaultVisibility": ["PUBLIC"]
   188      },
   189      "my_proto_library": {
   190          // Setting this to true indicates to puku that these targets don't operate on Go sources, so it shouldn't try
   191          // to parse the sources to figure out the dependencies. These targets must still satisfy an import for the
   192          // package directory they're in.
   193          "nonGoSources": true
   194      }
   195    },
   196    // These are any kinds that behave like tests. Similar to lib kinds, puku assumes they have arguments that are similar
   197    // to go_test. Puku will try and assign test sources to targets of this kind.
   198    "testKinds": {
   199      "testify_test": {
   200          // Any deps that the build definition will add to the target. Puku will avoid adding these dependencies via
   201          // deps.
   202          "providedDeps": ["//third_party/go:testify"],
   203      },
   204    }
   205    // Again, these are similar to lib and test kinds except they are treated as binary targets. Puku assumes a similar
   206    // set of arguments to go_binary and will allocate binary sources to these targets.
   207    "binKinds": {
   208      "testify_test": {
   209          // Any deps that the build definition will add to the target. Puku will avoid adding these dependencies via
   210          // deps.
   211          "providedDeps": ["//third_party/go:testify"],
   212      },
   213    }
   214  
   215    // Setting this to true will stop puku from touching this directory and all directories under it. By default, puku
   216    // will skip over plz-out and .git, however this can be useful to extend that to other directories.
   217    "stop": false,
   218  
   219    // Puku will try and add a subinclude for the Go rules if it's not already subincluded. Setting this to false will 
   220    // disable this behavior. 
   221    "ensureSubincludes": false,
   222  
   223    // If you have changed the behavior of the default kinds, you may exclude them here so Puku stops treating them as a
   224    // known kind. This can be useful for cases where you have changed proto_library to output .go files, rather than to 
   225    // generate the go_library for that package. 
   226    "excludeBuiltinKinds": ["proto_library"],
   227  }
   228  ```
   229  
   230  ## Overview of the algorithm
   231  
   232  Puku will attempt to allocate any .go files in a directory to rules based on their type. There are 3 types:
   233  library, test, and binary. These sources are allocated to rules based on the rules kind type, as configured in the
   234  `puku.json` files.
   235  
   236  Once puku has determined the kind type for each source, it will parse the BUILD file to discover the existing build
   237  rules. It will parse the `srcs` arguments of each rule, evaluating `glob()`s as necessary in order to determine any
   238  unallocated sources.
   239  
   240  Sources are then allocated to existing rules where possible based on their kind type. If no rule can be found, then a
   241  new rule will be created. The kind type that puku chooses for new rules are the built-in base types i.e. `go_library`,
   242  `go_test`, and `go_binary`.
   243  
   244  Once all sources have been allocated, the imports for each source file are collected and resolved. Puku will resolve
   245  imports in the following order:
   246  
   247  1) Known imports as defined in the configuration file
   248  2) Installed packages from `go_module` or `go_repo`
   249  3) If using `go_repo`, by the module package naming convention (run `plz help go_repo` for more information)
   250  4) If using `go_repo`, by checking the go module proxy, or by reading the `go.mod` file
   251  
   252  When using `go_repo`, puku will attempt to automatically add new modules to the build graph, updating the existing
   253  modules as necessary.
   254  
   255  ## Contributing
   256  
   257  Contributions are more than welcome. Please make sure to raise an issue first, so we can avoid wasted effort. This 
   258  project and it's contributions are licensed under the Apache-2 licence.