Continuous integration
CI is built in. There is no root config file and no external service to wire up:
work is declared by project.toml files scattered through the tree, one per
buildable unit.
Projects
Section titled “Projects”[project]name = "api"language = "go"
[test]command = "go test ./..."timeout = "10m"
[deps]internal = ["libs/auth"]garden discovers every project.toml and uses them to scope what builds, what
tests run, and how changed files map to work. Full schema:
project.toml, or garden docs project.
Test selection
Section titled “Test selection”This is the payoff of declaring dependencies. A change in libs/auth selects
api’s tests too, because api named it in [deps].internal — while leaving
the other two hundred projects alone.
In a monorepo holding the whole company, running everything on every change isn’t an option. Selection is what makes keeping it all in one repo practical.
When it runs
Section titled “When it runs”Per revision, on every push. Then again in the merge queue against the rebase before landing, and once more on trunk afterwards.
Failures come back as review threads
Section titled “Failures come back as review threads”The part that differs most from other CI systems. A failing check doesn’t just
turn a status red — it posts an inline review thread on the failing line,
authored by ci-bot. Those threads:
- block the merge until resolved,
- reopen when the test re-fails, even if a human resolved them,
- resolve themselves when the test passes.
So a failing test lands in the same place as human feedback and clears the same way: fix it and push a new revision.
Inspecting checks
Section titled “Inspecting checks”garden ci list --pr 42 # every check on the head revisiongarden ci logs build --pr 42 # streams live, replays if donegarden ci tests --pr 42 # parsed test resultsgarden ci rerun build --pr 42 # new attemptgarden pr checks 42 is the quick summary and exits non-zero if anything failed
or is pending — usable as a gate in a script.
Extra rules
Section titled “Extra rules”Beyond [test], a project can declare rules that fire on matching changes, and
codegen that re-runs when its inputs change:
[[rule]]name = "lint"match = ["**/*.go"]run = "golangci-lint run"
[generate]commands = ["buf generate"]triggers = ["proto/**/*.proto"]Related
Section titled “Related”garden ci,garden pr checksproject.tomlreference- Code review — how threads work