This doc is intended for readers who are interested in building and deploying a new Tricium Analyzer. A Tricium Analyzer can automatically produce conveniently timed warnings and suggestions for changes under review in your project, in the form of code review comments.
Analyzers are run by triggering LUCI builders; each builder is configured to run some recipe. Tricium Analyzer recipes will call api.tricium.emit_results
and the Tricium service will post comments to the CL when the build is done.
See the tricium recipe module.
Analyzer recipes can run third-party tools, or read files directly, or run any number of pre-made common legacy analyzers.
A legacy analyzer, also called a simple analyzer, takes some input (usually FILES
) and produces Tricium RESULTS
. Results of Analyzers can be visible as comments in code review. Such analyzers read input (files and metadata) from the -input
flag value, and write output to “tricium/data/results.json”, relative to the -output
flag value. Each program is packaged and deployed using CIPD.
Example Analyzers implemented in Go are located in tricium/functions/.
If you add a legacy analyzer, it must be run inside a recipe.
The input and output types that Tricium Analyzers can take are defined in data.proto; there are three main important types:
GIT_FILE_DETAILS
: Just the information required to fetch the repository, but without any file contents. This doesn't include the actual contents of the file, but it does include the git repository URL and ref string as well as a list of files. Example.FILES
: The list of files and file metadata, along with the actual contents of the files. The file metadata includes the relative path, how the file was changed, and whether it is binary or text. Many simple Analyzers that depend on just the text of the files changed in the CL can use this type. This input type does not include repository URL or git ref. Example.RESULTS
: The result of an Analyzer, which is a list of comments to post, as well as (optionally) the platform that the results apply to. Results are generated Example in a unit test; an example output can be generated by running make test
in one of the analyzer directories like [../functions/spellchecker].All legacy analyzers take FILES input, and all recipe analyzers take GIT_FILE_DETAILS. All analyzers produce RESULTS.
Third-party language-specific “linter” programs exist for many languages; to adapt them for Tricium, we need to make a wrapper that will run the program and produce Tricium RESULTS
, such as Pylint.
If third-party dependencies are required, they should be fetched and included in the CIPD package, but generally shouldn't be checked into source. The dependencies may be fetched using a set-up script that is run at package-build time. For example, the ESLint Analyzer uses a script called setup.py that is run before building and uploading a CIPD package.
Some checks may also just read the input files and check for certain text patterns. Examples include Copyright.
To build the Go Analyzers examples, you should first set up the infra Go environment; see The infra Go README.. After the environment is set up, running go build
in the directory should produce a usable binary.
Besides writing unit tests, you can also test run your Analyzer locally, because the Analyzer is just a program that reads from local files and writes to local files. You can make an example test input directory, for example tricium/functions/spacey/test/.
Then, you can build your program (if necessary) and run it. For Go programs, this may be done by running go build
and then invoking the resulting binary with the arguments -input
and -output
.
Analyzers are run in recipes, and changes to recipes can be tested before committing using led
. In order to test, you‘ll need (1) an example build of the analyzer builder that you’ll be changing and (2) an example change to run on.
You should be able to test by making a uncommitted change to an analyzer recipe, and then running something like:
led get-build <build-number> | \ led edit-recipe-bundle | \ led edit-cr-cl <example change patchset>` | led launch
See go/luci-how-to-led or led help
for more information.
Make sure you have the CIPD client installed; see installation instructions. Add a cipd.yaml
file to the root of your Analyzer's directory tree, e.g. hello/cipd.yaml:
package: infra/tricium/function/hello install_mode: symlink data: - file: hello
Note that package should be infra/tricium/functions/ANALYZER
, replacing CamelCase (e.g. ClangTidy) with words separated with dashes, e.g. (clang-tidy). The data section should list files to be included in the CIPD package; see cipd/client/cipd/local/pkgdef.go for details.
Run the CIPD command line tool to create and tag the new release. If the CIPD client complains about a lack of authentication, contact tricium-dev@google.com to get added to the “tricium-contributors” group.
Uploading a new version of an Analyzer usually has two steps: uploading a new instance and setting the ref “live” to that instance.
There is a convenience helper script update.sh which may be used to update Analyzers.
$ cipd create -pkg-def cipd.yaml … infra/tricium/function/hello:5b010cd78bc78252dda3e791cd6510c56111a990 was successfully registered $ cipd set-ref infra/tricium/functions/hello -ref live -version 5b010cd78bc78252dda3e791cd6510c56111a990 [P26551 20:36:06.432 client.go:1004 I] cipd: setting ref of "infra/tricium/function/hello": "live" => "5b010cd78bc78252dda3e791cd6510c56111a990" Packages: infra/tricium/function/hello:5b010cd78bc78252dda3e791cd6510c56111a990
NB! If your Analyzer contains compiled binaries, make sure that the target platform for your built binaries are the same as the platform that will run the Analyzer; for example, if it will run on Windows, you must build for Windows. The place where the runtime platform is configured is in the Analyzer definition; see the example config below, which specifies “UBUNTU”.
CIPD packages are basically zip files with a manifest file. They have an instance ID which is a digest of the zip package, which may look like ZEBe-8SEx5Z3TQ_bby6Ok82WbLc71YPdLEAnGWjmHKsC
.
CIPD package instances have a package name and version. Versions can be the instance ID, or a ref, such as “live”. It's conventional for Tricium Analyzers to use the “live” ref, which is set in the Analyzer definition in the config file, as in the example below.
To enable a legacy analyzer, you must change the relevant recipe.
To enable a new recipe analyzer or analyzer wrapper recipe, you must add an entry to the project config, which will look like this:
# Analyzer definition. functions { type: ANALYZER name: "Wrapper" needs: GIT_FILE_DETAILS provides: RESULTS owner: "someone@chromium.org" monorail_component: "Infra>Platform>Tricium>Analyzer" impls { runtime_platform: LINUX provides_for_platform: LINUX # The recipe determines the actual behavior, including what is run. recipe { project: "my-project" bucket: "try" builder: "tricium-analysis" } deadline: 900 } } selections { function: "Wrapper" platform: LINUX # Must match platform in definition. } repos { gerrit_project { host: "chromium-review.googlesource.com" project: "my/project" git_url: "https://chromium.googlesource.com/my-project" } } service_account: "tricium-prod@appspot.gserviceaccount.com"
Deploying to a limited environment:
tricium-dev
(e.g. playground/gerrit-tricium), add the Analyzer definition and selection to the project config. The Analyzer definition and selection can both be put in the project config file for the playground repository.Releasing:
tricium-prod
service config (internal). A tricium-prod.cfg
config file for your project must be created or updated to include a selection for your Analyzer. The example for chromium/src is at //infra/config/tricium-prod.cfg.A Tricium analyzer can take more time and include more checks than presubmit. It should find some results when run on the whole codebase, but not too many so that it's overwhelming.
If you have an Analyzer that's already running and configured, and you want to release a new version, the following is a general process for release:
First, test locally; try both unit tests and a test-invocation on sample input. Note, you can run Go unit tests by running go test ./...
. Make sure you run this on a machine that is binary-compatible with the production execution environment.
Optionally, you could try with a local devserver instance of Tricium (documentation pending; for now, Googlers can see the current doc at go/tricium-playbook). The advantage of testing it out with a devserver instance would be that you can change the configs without making any actual commits, by changing tricium/appengine/devcfg.
After you're ready, upload it as described above in the “Deploy CIPD Package” section, by running the cipd
commands yourself or possibly by running update.sh my-analyzer
from tricium/functions.
Then, again optionally, upload a new patchset or a new CL to confirm that it works as expected.