LUCI Change Verifier (CV) is the LUCI microservice that is responsible for running pre-submit tests and submitting CLs when they pass all checks.
godoc
-based overview here. Notably:api
dir.Like all other LUCI go code:
SHOULD wrap errors with errors.Annotate
to provide additional context. Unlike other error-wrapping packages, it also captures the call stack.
SHOULD avoid ignoring errors. If it's justified, add a comment in code and if necessary log the error.
SHOULD use appstatus
on errors in RPC-handling codepaths.
LUCI CV also follows these conventions, which in some cases differ from other LUCI Go code:
SHOULD use CV‘s common.LogError(ctx, err)
for logging error + stack trace instead of errors.Log(ctx, err)
. The CV’s version packs the entire stack into as few log entries as possible, leading to a better debugging experience with Cloud Logging.
Tag the error with transient.Tag
if the function call can succeed on a retry. For example, most Datastore errors different from NoSuchEntity SHOULD be thus tagged.
SHOULD use common.TQifyError
or its custom version common.TQIfy{...}.Error(ctx, err)
before returning from a TQ task handler. This func logs the error with appropriate severity and with stack trace as necessary (via common.LogError
). Additionally, it converts the error to an appropriate server/tq
tag as needed. The custom common.TQIfy
SHOULD be used to reduce noise in logs and oncall alerting from the frequent errors during normal operation which don't critically harm the service, e.g. “ErrStaleGerritData”.
MAY panic when a function precondition fails, e.g. sqrt(x) may panic if x is negative. This is like an assert in Python / C / C++, which is contrary to Go's standard guidance.
MUST return a singular error from a function instead of errors.MultiError
or similar multi-error holders unless all of the below hold true, which was so far very rare in CV code:
func loadMany(clids ... int64) ([]*CL, errors.MultiError)
;SHOULD use common.MostSevereError
on a multi-error before returning. For example, a common pattern to choose 1 error after parallelizing is return common.MostSevereError(parallel.FanOut(...))
;
Land your code, which gets auto-deployed to luci-change-verifier-dev
project, You may also just upload a tainted version and switch all traffic to it, but beware that the next auto-deployment will override it. Thus, adding unit- and e2e tests with fake Gerrit and Cloud dependencies is a good first step and at times cheaper/faster to do.
cq-test
LUCI project can be used for any such tests. It‘s already connected to only luci-change-verifier-dev
. The cq-test
project’s config tells CV to watch 2 repositories:
cq-test
.Creating a CL on refs/heads/main
will use combinable config group, meaning multi-CL Runs in ChromeOS style can be created. For single-CL Runs, create CLs on refs/heads/single
ref:
git new-branch --upstream origin/single echo "fail, please" > touch_to_fail_tryjob echo "fail with INFRA_FAILURE, please" > touch_to_infra_fail_tryjob git commit -a -m "test a signle CL dry run with failing tryjobs" git cl upload -d
You can see recent Runs in https://luci-change-verifier-dev.appspot.com/ui/recents/cq-test.
(Optional) internal/cvtesting/e2e/manual contains tools to automate common tasks, e.g. creating and CQ-ing large CL stacks. Feel free to contribute :)
tl;dr
cd appengine go run main.go # See output for URLs to http URLs.
To work with Runs from the -dev project, connect to its Datastore by adding these arguments:
go run main.go \ -http-addr localhost:8800 -cloud-project luci-change-verifier-dev \ -root-secret devsecret://base64anything \ -primary-tink-aead-key devsecret-gen://tink/aead
NOTE: if you want the old page tokens to work on subsequent go run main.go ...
invocations, when you first invoke it, observe output of the first invocation which should mention a devsecret://veeeeeeeeeeeeeeery-looooooong-base64-line
, which you can use on subsequent invocations instead of devsecret-gen://tink/aead
.
For a quick check, eyeball these two pages:
Finally, you can deploy your work-in-progress to -dev project directly.
tl;dr this the usual way for LUCI GAE apps. Roughly,
CL lands in luci-go
(this) repo.
Autoroller rolls it into infra/infra
repo (example).
roll-dep go/src/go.chromium.org/luci
in your infra/infra
checkout.Tarball with only the necessary files is created by the Google-internal infra-gae-tarballs-continuous
builder.
Newest tarball is automatically rolled into also Google-internal infradata-gae
repo (example).
Google-internal gae-deploy
builder auto-deploys the newest tarball to luci-change-verifier-dev
GAE project.
Someone manually bumps tarball version to deploy to production luci-change-verifier
via a CL (example).
bump-dev-to-prod.py
tool to make such a CL. For example,cd gae/app/luci-change-verifier ./bump-dev-to-prod.py -- --bug $BUG -r <REVIEWER> -d -s
The same Google-internal gae-deploy
builder deploys the desired version to production luci-change-verifier
GAE project.
LUCI Change Verifier provides a command line interface luci-cv
intended for LUCI integrators to debug CV configurations.
luci-cv
CLI binary.There are two ways of getting the latest version of the binary at the moment:
Building it yourself from this package: go.chromium.org/luci/cv/cmd/luci-cv
e.g.
go build go.chromium/org/luci/cv/cmd/luci-cv
Getting it from CIPD e.g. via a command such as:
cipd ensure -ensure-file - -root cv-cli <<< 'infra/tools/luci-cv/${platform} latest'
For the appropriate syntax and flags information refer to the binary's built-in documentation. e.g. luci-cv help match-config
.
# (Assuming luci-cv was installed in the current dir) ~/infra/infra$ ./luci-cv match-config infra/config/generated/commit-queue.cfg https://chromium-review.googlesource.com/c/infra/luci/luci-go/+/3214613 https://chromium-review.googlesource.com/c/infra/luci/luci-go/+/3214613: Location: Host: chromium-review.googlesource.com, Repo: infra/luci/luci-go, Ref: refs/heads/main Matched: luci-go