Skip to main content

Pants 2.14: Less boilerplate, more Rust, better support for Go monorepos, interactive debugging support, and more!

· 6 min read
Stu Hood
Pants Maintainer

Highlights include: less boilerplate via hierarchical defaults for target field values, better Golang monorepo support, with multiple go.mods, do more of your workflows in Pants with the experimental deploy goal (with initial support for Helm), and much more…


We're pleased to announce Pants 2.14.0, the latest release of Pants, the scalable and ergonomic build system. To update, set pants_version = "2.14.0" in your pants.toml. See upgrade tips for more information.

Less boilerplate via hierarchical defaults for target field values

A key goal of Pants is reducing the amount of BUILD boilerplate that users have to maintain in order to quickly and reliably build their code. To that end, Pants 2.14 introduces __defaults__: a mechanism to set the default arguments used for the targets defined in a directory.

As an example: suppose that you wanted to use a non-default thirdparty resolve "spark3" for all targets in a particular subdirectory. To do that, you'd declare __defaults__ in a BUILD file in that subdirectory:

BUILD
__defaults__(all=dict(resolve="spark3"))

… and then all targets defined at or below that BUILD file would default to using resolve="spark3" (but could still override that default if they choose)!

__defaults__ also supports setting defaults for individual target types, or can be combined with parametrize. For more examples, see the docs for __defaults__!

Better Golang monorepo support, with multiple go.mods

Pants 2.14 adds support for using multiple go.mod files in one repository, by adapting dependency inference to infer dependencies only within the scope of a single parent go.mod.

Similar to our support for using multiple resolves (for Python, Java, Scala, Kotlin, etc), support for multiple go.mods can be really helpful for projects which can't fully migrate (or just haven't yet) to a single set of shared thirdparty dependencies in their repository.

Do more of your workflows in Pants with the experimental deploy goal, with initial support for Helm

Pants' philosophy around CLI "goals" (like test, fmt, run, etc) is to support caching, parallelism, and a consistent user interface across tools which accomplish similar tasks across different languages or ecosystems.

For example: the test goal provides a consistent interface to running and caching tests using pytest, junit, shunit2, etc, while the fmt goal safely pipelines (and even partially parallelizes) the running of code formatters like scalafmt, go fmt, black, isort, etc.

To that end: Pants 2.14 introduces an (experimental) deploy goal, with initial support for Helm installs. The Helm implementation of the deploy goal will:

  1. Infer the Docker image dependencies of your Helm charts
  2. Build and publish image dependencies
  3. Post-process the Kubernetes manifests to use the published image names
  4. Run the Kubernetes deployment resulting from the post-processing

We'd love your feedback on both the deploy goal and the support for Helm!

Easier interactive debugging for Python in VS Code using the DAP protocol

Pants usually runs processes in hermetic sandboxes for reproducibility. But in order to attach a console-based debugger like Python's PDB, the test --debug flag has long supported forcing a test to run in "interactive" mode in the foreground in your console.

In Pants 2.14, there is a new and shiny alternative to using console debuggers: using the --debug-adapter flag to launch an implementation of the DAP protocol for graphical debugging (particularly in VS Code) for either the test goal or run goal.

To try it out, run a test with ./pants test --debug-adapter $filename. You'll see a prompt like:

[INFO] Launching debug adapter at '127.0.0.1:5678', which will wait for a client connection…

… then set a breakpoint in VS Code, and use the Remote Attach action to run the test to your breakpoint!

Although the Python backend has the only implementation of the --debug-adapter flag so far, there are DAP server implementations for many other languages: we'd love to help you add support for your favorite language!

Better dependency computation performance by porting more critical paths to Rust

Since Pants 2.0, the "engine" of Pants has been implemented in Rust, with all language support added via the plugin API as Python 3 @rules.

Python and Rust make a great combination! They allow us to make it easy to write plugins using type safe async Python 3, while the most CPU intensive portions of Pants are written in safe and performant Rust.

The 2.14.x release brings a good example of this pairing: by porting a single codepath in the plugin API from Python to Rust (transparently to consumers!), we got a 12% speedup for the computation of dependencies.

We're always on the lookout for more API boundaries which can move to Rust: if you're interested in helping out, check out our page on profiling and benchmarking!

BUILD file formatters run in fmt and lint

In previous versions, BUILD file formatting and linting only ran in the update-build-files goal. But in 2.14, enabling a BUILD file formatter will cause it to run in the fmt and lint goals as well!

If you hadn't already enabled BUILD file formatting, you can do so by enabling one of the following backends:

  • pants.backend.build_files.fmt.black - to use Black
  • pants.backend.build_files.fmt.buildifier - to use Buildifier
  • pants.backend.build_files.fmt.yapf - to use YAPF Happy formatting!

Other notable changes

There are a long list of additional changes in 2.14, but highlights include:

  • mypy's incremental cache will now be used, which should significantly reduce the latency of typechecking.
  • Concurrent execution of Python test methods is now natively supported via pytest-xdist! If your test methods are concurrency safe, you can set [pytest].xdist_enabled = True to run individual test methods concurrently, in addition to Pants' usual file-level parallelism.
  • The file downloading intrinsic which is used to fetch fingerprinted remote binaries now has built in retry to reduce flakiness.
  • When a locally-run test times out, the stdio of the process will now be preserved, to assist with debugging which test(s) were slow.
  • mypy's output will now render in color, and at a reasonable width for all terminals (without breaking cache keys: huzzah!)
  • Pants' dependency inference for Scala has been significantly improved!
  • You can now add to dict-valued options in config files, using a similar syntax to that used for adding to list-valued options. To add a key to a dict option named [scope].example, you could use a pants.toml entry like:
pants.toml
[scope]
example.add = { an_additional_key = and_a_value }

Thanks

Thanks to all of the contributors to 2.14, including everyone who shared feedback on changes and who tested release candidates!