Configure Linters
Trunk Code Quality's linter integrations are fully configurable. This means that you can easily tune existing linters or leverage our caching and hold-the-line solution with your own custom linters.
Here's an overview of the ways you can configure linters.
Config Hierarchy
Linters can be configured at different places:
The source plugin repo usually
https://github.com/trunk-io/plugins
.The repo-wide Trunk config file overrides the definitions in the plugin repos,
.trunk/trunk.yaml
Local, per-user configuration in
.trunk/user.yaml
which is used for local overrides of.trunk/trunk.yaml
and doesn'tPer linter configuration in linter config files such as
eslint.config.js
or.prettierrc
.
Plugin system
Trunk defines linter configuration in a plugin system. By default, it'll point to the Trunk plugin repo on GitHub. You can check if other custom plugin sources are specified in your trunk.yaml
file for Shared Configs.
Linter Definitions
Each linter implemented in the Plugin Repo has its own linter definition. Let's take clang-tidy as an example, which ships with the following default configuration:
Linter Definition Reference
You can find the default definitions for linters in the Plugin Repo and find reference for these fields in the Linter Definitions page.
Overriding Default Linter Definitions
You may find while using Trunk that you want to modify one of these defaults: perhaps you want clang-tidy
to not run on the upstream, or maybe you want the node
runtime to include another environment variable. In these cases, you can specify the field in your trunk.yaml
to override the default value.
If you wanted to flip the value of disable_upstream
to false
, you could, in your own trunk.yaml
, specify:
Overriding definitions in your trunk.yaml
file doesn't require you to specify the entire definition again. You only need to specify what's being overridden.
Configure Linter Commands
Some linters have multiple commands, such as Ruff, which can run in different ways. By default, Ruff is configured to only run as a linter:
You can configure ruff to also run the format command by adding it to the commands tuple:
Configure Linter Platforms
Similarly, some linters are configured to run differently on different platforms or at different versions. When overriding a command definition, overrides are applied on the tuple [name, version, platforms]
.
For example, if you wanted to disable batching when running ktlint on Windows, you could consider its default configuration:
And override it as such:
When executing linters, Trunk will execute the first matching command based on its compatible platforms and linter version. Note when overriding that new commands that don't match an existing tuple are prepended to the resulting commands list.
Alternatively, consider the default node
runtime:
If you want to add ${home}/my/special/node/path
to PATH
, you could specify the following:
Blocking Thresholds
All issue severities low-high are considered blocking by default. In cases where you might want to slowly try out a new linter, we provide a mechanism to set specific thresholds for each linter.
Every entry in threshold
defines a set of linters and the severity threshold that is considered blocking. In this example, we're saying that only high
lint issues should be considered blocking for clang-tidy
.
linters
List of linters (e.g. [black, eslint]
) or the special [ALL]
tag
level
Default low
. Threshold at which issues are considered blocking. One of: note
, low
, medium
, high
, or none
(this last option will result in issues never blocking)
Trigger rules
Some linters do not operate on individual files. Instead, you must lint your entire repo at once. The way this is handled in Trunk is to set up a trigger rule. Most linters will not require the use of a trigger rule.
Trigger rules work on 3 principles:
Input(s) that trigger the linters. These can be files, directories, or extended globs.
Linter(s) to run when a triggered file is modified.
Targets(s) to pass to the linters (can be files or directories).
An example for ansible-lint:
Triggered linters will also be run when executing trunk check with --all
so long as a file exists that matches one of the listed paths.
You may use .
as a target to run on the entire repo instead of an isolated directory.
File Size
By default, Trunk only lints files up to 4 MiB in size. To override this globally, specify a default_max_file_size
in lint
:
To override this for a specific linter, specify a max_file_size
in its definition:
Timeout
Each linter has a default timeout of 10 minutes. If its execution takes longer than this amount of time, Trunk Code Quality will terminate the process and return an error to the user.
To override the timeout for a specific linter, specify a run_timeout
in its definition:
The run_timeout
value can be specified in seconds (s
), minutes (m
), or hours (h
).
Local Linter Overrides
Trunk can also be managed by the .trunk/user.yaml
file in your repository. This file is optional, but it allows individual developers to customize how they want trunk
to run on their machines.
Simply configure .trunk/user.yaml
as you would for .trunk/trunk.yaml
. Be mindful that .trunk/user.yaml
takes precedence over .trunk/trunk.yaml
, so substantial modifications could violate hermeticity.
Per Linter Definitions
Trunk allows you to keep using your existing linter configs, and new linters recommended by Trunk will have their configs added in the .trunk/configs
folder. These config files will be symlinked in during any trunk check
run.
If you're using an IDE Extension like clangd with an LSP that relies on those configs being in the root, you will need to create an additional symlink from the hidden config to the workspace root.
Moving Linters
You can move existing linter config files into the .trunk/config
folder. You can check which files are automatically symlinked by looking for the direct_configs
of each plugin's definition. If there are config files not listed, you can add them by overriding the definition like this:
Last updated