LogoLogo
SlackLogin
  • Overview
    • Welcome
  • Setup & Configuration
    • Connecting to Trunk
    • Managing Your Organization
      • GitHub App Permissions
  • Integration with Slack
  • Flaky Tests (Beta)
    • Overview
    • Get Started
      • Test Frameworks
        • Android
        • Bazel
        • Behave
        • cargo-nextest
        • Cypress
        • Dart Test
        • Go
        • GoogleTest
        • Gradle
        • Jasmine
        • Jest
        • Karma
        • Maven
        • minitest
        • Mocha
        • Nightwatch
        • NUnit
        • Pest
        • PHPUnit
        • Playwright
        • Pytest
        • Robot Framework
        • RSpec
        • Swift Testing
        • Vitest
        • XCTest
        • Other Test Frameworks
      • CI Providers
        • Azure DevOps Pipelines
        • BitBucket Pipelines
        • Buildkite
        • CircleCI
        • Drone CI
        • GitHub Actions
        • GitLab
        • Jenkins
        • Semaphore CI
        • TeamCity
        • Travis CI
        • Other CI Providers
    • Dashboard
    • Flaky Test Detection
    • Quarantining
    • PR Comments
    • Ticketing Integrations
      • Jira Integration
      • Linear Integration
      • Other Ticketing Platforms
    • Webhooks
      • Slack Integration
      • Microsoft Teams Integration
      • GitHub Issues Integration
      • Linear Integration
    • Uploader CLI Reference
  • Merge Queue
    • Overview
    • How does it work?
    • Setup
      • Quick Start
      • Settings
      • Integration for Slack
    • Concepts and Optimizations
      • Predictive Testing
      • Optimistic Merging
      • Pending Failure Depth
      • Anti-Flake Protection
      • Batching
      • Parallel Queues
        • Bazel
        • Nx
        • API
      • FAQ
    • Priority
    • Managing Merge Queue
      • Using the Merge UI
      • Metrics
      • Command Line
    • Webhooks
    • Reference
  • Code Quality
    • Overview
    • Why Metalinters?
      • How does it work?
      • Why Code Quality?
    • Setup & Installation
      • Initialize Trunk
      • Local Linting
      • Linting in CI
      • Nightly Report (Deprecated)
    • IDE Integration
      • VSCode
      • Neovim
      • GitHub Codespaces
    • Linters
      • Supported Linters
        • Actionlint
        • Ansible-lint
        • Autopep8
        • Bandit
        • Biome
        • Black
        • Brakeman
        • buf
        • Buildifier
        • cfnlint
        • Checkov
        • circleci
        • ClangFormat
        • clang-tidy
        • Clippy
        • cmake-format
        • codespell
        • cspell
        • cue-fmt
        • dart
        • deno
        • Detekt
        • djlint
        • dotenv-linter
        • dotnet-format
        • dustilock
        • ESLint
        • Flake8
        • git-diff-check
        • Gitleaks
        • Gofmt
        • gofumpt
        • goimports
        • gokart
        • golangci-lint
        • golines
        • google-java-format
        • graphql-schema-linter
        • hadolint
        • haml-lint
        • isort
        • iwyu
        • ktlint
        • kube-linter
        • markdown-link-check
        • markdown-table-prettify
        • Markdownlint
        • markdownlint-cli2
        • mypy
        • nancy
        • nixpkgs-fmt
        • opa
        • OSV-Scanner
        • Oxipng
        • perlcritic
        • perltidy
        • php-cs-fixer
        • phpstan
        • pmd
        • pragma-once
        • pre-commit-hooks
        • Prettier
        • prisma
        • psscriptanalyzer
        • Pylint
        • pyright
        • regal
        • remark-lint
        • renovate
        • rome
        • rubocop
        • Ruff
        • rufo
        • rustfmt
        • scalafmt
        • semgrep
        • ShellCheck
        • shfmt
        • sort-package-json
        • sourcery
        • sql-formatter
        • SQLFluff
        • sqlfmt
        • squawk
        • standardrb
        • stringslint
        • stylelint
        • stylua
        • SVGO
        • swiftformat
        • swiftlint
        • taplo
        • Terraform
        • terragrunt
        • terrascan
        • TFLint
        • tfsec
        • tofu
        • Trivy
        • Trufflehog
        • txtpbfmt
        • vale
        • Yamllint
        • yapf
      • Run Linters
      • Manage Linters
      • Configure Linters
      • Ignoring Issues and Files
      • Custom Linters
      • Shared Configs
      • Upgrades
    • Debugging
    • Licensing
  • CLI & API References
    • CLI Reference
      • Install
      • Getting Started
        • Code Quality
        • Merge Queue
        • Flaky Tests
        • Tools
        • Actions
          • Git Hooks
        • Announce
      • Compatibility
      • Caching
      • Commands Reference
        • Code Quality
        • Actions
        • Merge
      • Configuration
        • Plugins
          • Share Config Between Codebases
          • Exporting Linter Configs
        • Runtimes
        • Tools
        • Lint
          • Definitions
          • Commands
          • Output
          • Output Parsing
          • Files and Caching
          • Dependencies
          • Auto-Enable
        • Actions
          • Notifications
          • Logging and Troubleshooting
        • Merge
        • Telemetry
        • Per User Overrides
    • API Reference
      • Flaky Tests
      • Merge Queue
      • Webhooks Reference
  • Pricing & Security
    • Security
  • Billing
  • Community & Support
  • Links
    • Open App
    • Slack Community
    • Changelog
    • Feature Requests
On this page
Edit on GitHub
  1. CLI & API References
  2. CLI Reference
  3. Configuration
  4. Lint

Output Parsing

If you have a command or utility that you want to run pretty much as-is, but Trunk doesn't natively understand how to parse it, you can inject your own custom parser to translate its output into a format that Trunk does understand!

For example, let's say that we want to use grep as a linter, but we want to add more context to the matches. We could define a custom linter like so:

lint:
  definitions:
    - name: todo-finder
      files: [ALL]
      commands:
        - output: regex
          # matches the parser run output
          parse_regex: "((?P<path>.*):(?P<line>\\d+):(?P<col>\\d+): 
              \\[(?P<severity>.*)\\] (?P<message>.*) \\((?P<code>.*)\\))" 
          run: grep --with-filename --line-number --ignore-case todo ${target}
          success_codes: [0, 1]
          read_output_from: stdout
          parser:
            run:
              "sed -E 's/(.*):([0-9]+):(.*)/\\1:\\2:0: 
                 [error] Found todo in \"\\3\" (found-todo)/'"

The execution model that trunk follows for a parser is that it will:

  • execute the linter's run field, asserting that either:

    • the linter's exit code is in success_codes, or

    • the linter's exit code is not in error_codes;

  • execute parser.run,

    • with the read_output_from of the linter execution fed to parser.run as stdin,

    • assert that the exit code of the parser is 0, and then

  • use output to determine how it should parse the parser's stdout.

Node

lint:
  definitions:
    - name: todo-finder-node
      files: [ALL]
      commands:
        - output: parsable
          # parse_regex matches the parser run output
          parse_regex: "((?P<path>.*):(?P<line>\\d+):(?P<col>\\d+): 
              \\[(?P<severity>.*)\\] (?P<message>.*) \\((?P<code>.*)\\))" 
          run: grep --with-filename --line-number --ignore-case todo ${target}
          success_codes: [0, 1]
          read_output_from: stdout
          parser:
            runtime: node
            run: ${workspace}/todo-finder-parser.js
#!/usr/bin/env node
'use strict';
let readline = require('readline');
let rl = readline.createInterface({ input: process.stdin });

rl.on('line', function(line){
  let match = line.match(/(.*):([0-9]+):(.*)/);

  if (match) {
    let [_, path, line_number, line_contents] = match;
    console.log(`${path}:${line_number}:0: [error]`
            +` Found todo in "${line_contents}" (found-todo)`);
  }

Remember to run chmod u+x todo-finder-parser.js so that trunk can run it!

Python

lint:
  definitions:
    - name: todo-finder-python
      files: [ALL]
      commands:
        - output: parsable
          # parse_regex matches the parser run output
          parse_regex: "((?P<path>.*):(?P<line>\\d+):(?P<col>\\d+): 
              \\[(?P<severity>.*)\\] (?P<message>.*) \\((?P<code>.*)\\))" 
          run: grep --with-filename --line-number --ignore-case todo ${target}
          success_codes: [0, 1]
          read_output_from: stdout
          parser:
            runtime: python
            run: ${workspace}/todo-finder-parser.js
#!/usr/bin/env python
import re, sys

for line in sys.stdin.readlines():
  match = re.match("(.*):([0-9]+):(.*)", line)
  if match:
    path, line_number, line_contents = match.groups()
    print(f"{path}:{line_number}:0: [error] "
           "Found todo in \"{line_contents}\" (found-todo)")

Remember to run chmod u+x todo-finder-parser.py so that trunk can run it!

Last updated 3 months ago

Note that you can also set parser.runtime to or so that you can write your parser in Javascript or Python instead, if you so prefer! You can find plenty of examples of python parsers in our .

plugins repo
node
python