This file provides guidance to coding agents when working with code in this repository.
Please is a cross-language build system written in Go. This repo builds itself: plz is used to
build plz. That bootstrap relationship shapes nearly everything below — most workflows involve
building a new please binary and then running it against this same repo.
Building requires an existing Please. ./pleasew downloads/uses one if you don't have plz on
your $PATH; substitute it for plz in any command below.
./bootstrap.sh # Build please from scratch with `go run`, then run all tests
./bootstrap.sh --skip_tests # Just the build (alias: plz bootonly)
plz build //src:please # Incremental rebuild -> plz-out/bin/src/please
plz test //src/... # Run tests
./test.sh # What bootstrap.sh runs: unit tests, then e2e separatelyTest selection:
plz test //src/core:core_test # One target
plz test //src/core:core_test TestFoo # One test within a target (positional arg = selector)
plz test //src/... --exclude=e2e # Skip end-to-end tests
plz test //test/... --include=e2e # Only end-to-end tests
plz test //src/core:core_test --rerun # Force rerun even if the hash is unchanged
plz cover //src/... # Tests with coverageResults land in plz-out/log/test_results.xml; logs in plz-out/log/.
Lint and format:
plz lint # golangci-lint over src/... and tools/..., plus a `plz fmt` check
plz autofix # plz fmt -w, gofmt -s -w src tools test, and regenerate codegen
plz fmt -w # Format BUILD files only
plz puku sync # Reconcile third_party/go BUILD files with go.modTesting a change to Please against the repo itself:
plz plz build //src/... # `plz plz` runs the freshly-built in-repo please (alias in .plzconfig)
plz install # Install the built version into ~/.pleaseAll tests should be run via plz. Do not use go test or go build directly unless you have
a specific reason to; there are differences between how plz and go act which means that some
tests may not work as expected if run directly with go.
src/please.go is the CLI entry point — a big go-flags struct defining every subcommand. Each
subcommand assembles a core.BuildState and hands it to plz.Run (src/plz/plz.go), which is the
orchestrator: it spins up worker pools bounded by local and remote limiters and pulls from the task
queues that BuildState exposes.
The three pipeline stages each have their own package and their own README worth reading before changing them:
src/core—BuildTarget,BuildLabel,BuildGraph,Configuration,Subrepo, andBuildState. Everything hangs off this. The target queuing/activation logic here is the most subtle code in the repo: targets are added to the graph inactive, activated when needed, and progress through an orderedBuildTargetStateenum that also acts as the synchronisation primitive. All queuing funnels throughQueueTarget().src/parse— parses BUILD files into graph targets.src/parse/aspis a hand-written interpreter for the BUILD language: a Python subset (noimport/try/class/while, no floats or sets, string-keyed dicts only, immutable-ish lists). Its README lists the exact divergences. Parsing synchronises onstate.SyncParsePackage(label)— a nil return means you own the parse.src/build— builds a target. Three-way check: already built inplz-out, restorable from cache, or needs a real build. Complicated by post-build functions and output dirs, which can change the output hash after the fact, so metadata files are fetched and replayed before the outputs are.src/test— runs tests and collates results intocore.TestSuites in a Surefire-like XML format. Handles flaky reruns and--num_runsby keeping multipleTestExecutions perTestCase.
Supporting packages: src/remote implements the Bazel remote execution API client; src/cache has the
dir/http/cmd cache backends; src/output and src/cli handle the interactive display; src/fs,
src/process, src/sandbox are the OS-level layers. rules/*.build_defs are the built-in build
rules, written in the BUILD language itself and embedded into the binary.
Caching is hash-based, not timestamp-based: hashes cover rule definition, config, sources, and secrets. Anything that changes what a target produces must be folded into its hash, or you will create stale-cache bugs that only show up on other people's machines.
- Language plugins (go, cc, python, shell) are external repos pinned in
plugins/BUILDand preloaded via.plzconfig. Bumping a plugin version is aplugins/BUILDedit. - Third-party Go deps are BUILD targets under
third_party/go, managed bypukufromgo.mod. Don't hand-edit them; runplz puku sync. - The end-to-end tests in
test/invokeplzrecursively against this repo. They are deliberately run in a separate pass (seetest.sh) with the lock disabled and sandboxing off, and they assert on exact output text, so they're brittle — expect to update.txtgolden files.plz_e2e_testintest/build_defs/test.build_defsis the macro they all use. - Some tests need toolchains that may be absent (python3, xz);
test.shdetects this and passes--excludeflags. If a test fails locally but not in CI, check whether it's one of these. - Releases: bump
VERSIONand add aChangeLogentry in the existing format (version heading, then bullets with PR numbers). tree/is a generated perf-test repo, blacklisted from parsing;plz-out/is all build output.