# Create application Source: https://docs.qlty.sh/api-reference/applications/create-application https://api.qlty.sh/openapi.json post /gh/{ownerKeyOrId}/applications Create an Application for a Workspace. The Workspace must have Applications enabled. # Delete application Source: https://docs.qlty.sh/api-reference/applications/delete-application https://api.qlty.sh/openapi.json delete /gh/{ownerKeyOrId}/applications/{applicationIdOrName} Permanently delete an Application. Every Project assigned to it must be unassigned first. The Workspace must have Applications enabled. # Get an application Source: https://docs.qlty.sh/api-reference/applications/get-an-application https://api.qlty.sh/openapi.json get /gh/{ownerKeyOrId}/applications/{applicationIdOrName} Retrieves details about a specific Application # List applications Source: https://docs.qlty.sh/api-reference/applications/list-applications https://api.qlty.sh/openapi.json get /gh/{ownerKeyOrId}/applications Retrieve the Applications defined for a Workspace. Supports JSON, newline-delimited JSON (`application/x-ndjson`), and CSV (`text/csv`) response formats via the `Accept` header. # Update application Source: https://docs.qlty.sh/api-reference/applications/update-application https://api.qlty.sh/openapi.json patch /gh/{ownerKeyOrId}/applications/{applicationIdOrName} Update an Application's name and description. Omitted fields keep their current values; pass `description: null` to clear it. The Workspace must have Applications enabled. # Get a build Source: https://docs.qlty.sh/api-reference/builds/get-a-build https://api.qlty.sh/openapi.json get /gh/{ownerKeyOrId}/projects/{projectKeyOrId}/builds/{buildId} Retrieves details about a specific Build # Get a build's logs Source: https://docs.qlty.sh/api-reference/builds/get-a-builds-logs https://api.qlty.sh/openapi.json get /gh/{ownerKeyOrId}/projects/{projectKeyOrId}/builds/{buildId}/logs Retrieves the complete output of a Build as plain text. Responds 404 once the logs are no longer retained, or for a Build that never started a container. # List builds Source: https://docs.qlty.sh/api-reference/builds/list-builds https://api.qlty.sh/openapi.json get /gh/{ownerKeyOrId}/projects/{projectKeyOrId}/builds Retrieves a Project's Builds, most recently submitted first. Each entry carries a subset of the fields returned when retrieving a single Build. Supports JSON, newline-delimited JSON (`application/x-ndjson`), and CSV (`text/csv`) response formats via the `Accept` header. # Create component Source: https://docs.qlty.sh/api-reference/components/create-component https://api.qlty.sh/openapi.json post /gh/{ownerKeyOrId}/projects/{projectKeyOrId}/components Create a Component for a Project. Requires admin access to the Project, and the Project must have Components enabled. # Delete component Source: https://docs.qlty.sh/api-reference/components/delete-component https://api.qlty.sh/openapi.json delete /gh/{ownerKeyOrId}/projects/{projectKeyOrId}/components/{componentIdOrName} Permanently delete a Component from a Project. Requires admin access to the Project, and the Project must have Components enabled. # List components Source: https://docs.qlty.sh/api-reference/components/list-components https://api.qlty.sh/openapi.json get /gh/{ownerKeyOrId}/projects/{projectKeyOrId}/components Retrieve all Components defined for a Project. Supports JSON, newline-delimited JSON (`application/x-ndjson`), and CSV (`text/csv`) response formats via the `Accept` header. # Update component Source: https://docs.qlty.sh/api-reference/components/update-component https://api.qlty.sh/openapi.json put /gh/{ownerKeyOrId}/projects/{projectKeyOrId}/components/{componentIdOrName} Replace a Component's definition. Takes the same fields as create and fully replaces the existing definition; the Component's id and creator are preserved. Requires admin access to the Project, and the Project must have Components enabled. # Get file coverage Source: https://docs.qlty.sh/api-reference/coverage/get-file-coverage https://api.qlty.sh/openapi.json get /gh/{ownerKeyOrId}/projects/{projectKeyOrId}/coverage/file Retrieve line-by-line test coverage data for a file at a specific Git reference or commit SHA # List issues Source: https://docs.qlty.sh/api-reference/issues/list-issues https://api.qlty.sh/openapi.json get /gh/{ownerKeyOrId}/projects/{projectKeyOrId}/issues Retrieves a list of Issues associated with a Project. Supports JSON, newline-delimited JSON (`application/x-ndjson`), and CSV (`text/csv`) response formats via the `Accept` header. # Get component metric series Source: https://docs.qlty.sh/api-reference/metrics/get-component-metric-series https://api.qlty.sh/openapi.json get /gh/{ownerKeyOrId}/projects/{projectKeyOrId}/components/{componentIdOrName}/metrics/series Retrieve each metric's history for a specific Component on the Project's default branch as a time series over the requested window. Returns one series per metric — covering maintainability, reliability, security, size, coverage, and quality indicators — each with the metric's descriptor and one value per interval; narrow the result with the `metric` and `category` query parameters. Available as JSON, newline-delimited JSON (`application/x-ndjson`), or CSV (`text/csv`) via the `Accept` header. Buckets are UTC-aligned and labeled with the inclusive end of each interval; a bucket with no measurement carries the most recent prior value forward, and the final bucket (the one containing `to`) may be labeled later than `to` — including the future for an interval still in progress — with its value reflecting only measurements within the window. # Get component metrics Source: https://docs.qlty.sh/api-reference/metrics/get-component-metrics https://api.qlty.sh/openapi.json get /gh/{ownerKeyOrId}/projects/{projectKeyOrId}/components/{componentIdOrName}/metrics Retrieve the latest value of every metric for a specific Component on the Project's default branch, covering maintainability, reliability, security, size, coverage, and quality indicators. # Get file metrics Source: https://docs.qlty.sh/api-reference/metrics/get-file-metrics https://api.qlty.sh/openapi.json get /gh/{ownerKeyOrId}/projects/{projectKeyOrId}/files Retrieve the latest values of all metrics for a file in a Project's default branch # Get project metric series Source: https://docs.qlty.sh/api-reference/metrics/get-project-metric-series https://api.qlty.sh/openapi.json get /gh/{ownerKeyOrId}/projects/{projectKeyOrId}/metrics/series Retrieve each metric's history on a Project's default branch as a time series over the requested window. Returns one series per metric — covering maintainability, reliability, security, size, coverage, and quality indicators — each with the metric's descriptor and one value per interval; narrow the result with the `metric` and `category` query parameters. Available as JSON, newline-delimited JSON (`application/x-ndjson`), or CSV (`text/csv`) via the `Accept` header. Buckets are UTC-aligned and labeled with the inclusive end of each interval; a bucket with no measurement carries the most recent prior value forward, and the final bucket (the one containing `to`) may be labeled later than `to` — including the future for an interval still in progress — with its value reflecting only measurements within the window. # Get project metrics Source: https://docs.qlty.sh/api-reference/metrics/get-project-metrics https://api.qlty.sh/openapi.json get /gh/{ownerKeyOrId}/projects/{projectKeyOrId}/metrics Retrieve the latest value of every metric on a Project's default branch, covering maintainability, reliability, security, size, coverage, and quality indicators. # Get a project Source: https://docs.qlty.sh/api-reference/projects/get-a-project https://api.qlty.sh/openapi.json get /gh/{ownerKeyOrId}/projects/{keyOrId} Retrieves details about a specific Project # List projects Source: https://docs.qlty.sh/api-reference/projects/list-projects https://api.qlty.sh/openapi.json get /gh/{ownerKeyOrId}/projects Retrieves a list of Projects associated with a Workspace. Supports JSON, newline-delimited JSON (`application/x-ndjson`), and CSV (`text/csv`) response formats via the `Accept` header. # Update a project Source: https://docs.qlty.sh/api-reference/projects/update-a-project https://api.qlty.sh/openapi.json patch /gh/{ownerKeyOrId}/projects/{keyOrId} Assign a Project to an Application, or pass `applicationId: null` to unassign it. The Workspace must have Applications enabled. # Get rate limit status Source: https://docs.qlty.sh/api-reference/service/get-rate-limit-status https://api.qlty.sh/openapi.json get /rate_limit Retrieve the rate limit status for the authenticated token. Rate limits use a one-hour window; the current limit and usage are also reported on every response via the `x-ratelimit-*` headers. # Get authenticated user Source: https://docs.qlty.sh/api-reference/user/get-authenticated-user https://api.qlty.sh/openapi.json get /user Get the authenticated User based on the provided access token # Get a workspace Source: https://docs.qlty.sh/api-reference/workspaces/get-a-workspace https://api.qlty.sh/openapi.json get /workspaces/{keyOrId} Retrieve a single Workspace by its ID or key # List workspaces Source: https://docs.qlty.sh/api-reference/workspaces/list-workspaces https://api.qlty.sh/openapi.json get /workspaces List Workspaces accessible to the authenticated token. Supports JSON, newline-delimited JSON (`application/x-ndjson`), and CSV (`text/csv`) response formats via the `Accept` header. # Introduction Source: https://docs.qlty.sh/api/introduction > [!WARNING] > > The Qlty API is currently in an early access period and subject to change without warning. The Qlty API is organized around REST. The API provides predictable, resource-oriented URLs, accepts JSON-encoded request bodies, and returns JSON-encoded responses. We strive to make use of standard HTTP response codes, authentication, and verbs. ## Authentication The Qlty API uses tokens to authenticate requests. You can generate an API token through your user settings at [https://qlty.sh/user/settings/tokens](https://qlty.sh/user/settings/tokens) Authentication is performed by passing the token as a Bearer token in the `Authorization` header: ```bash lines theme={"system"} curl -H "Authorization: Bearer " https://api.qlty.sh/... ``` All API requests must be made over HTTPS. Calls made over plain HTTP or without authentication will fail. ## Errors Qlty uses conventional HTTP response codes to indicate the success or failure of an API request. Codes in the 2xx range indicate success. Codes in the 4xx range indicate an error that failed given the information provided (e.g., a required parameter was omitted). Codes in the 5xx range indicate an error with Qlty's server. | Code | Status | Description | | - | - | - | | 200 | OK | The request was successful. | | 400 | Bad Request | The request was invalid, often due to a missing input. | | 401 | Unauthorized | Authentication failed. | | 403 | Forbidden | The API token does not have permission to access the resource. | | 404 | Not Found | The requested resource was not found. | | 429 | Too Many Requests | Too many API requests were sent in too short of a period. | | 500, 502, 503, 504 | Server Error | An unexpected error occurred on the server. | Errors are returned in the `errors` key of the response. ```json Error response lines theme={"system"} { "errors": [ { "status": "400", "title": "Bad Request", "detail": "The request was invalid." } ] } ``` ## Pagination Many list API endpoints return paginated results. The Qlty API uses offset-based pagination. The `page[limit]` query parameter specifies the number of items to return per page. It defaults to `20` and may not exceed `100`. The `page[offset]` query parameter specifies the offset of the first item to return, and defaults to `0`. When additional records are available, the response will include a `meta` key with a `hasMore: true` property. ```bash lines theme={"system"} curl -X GET "https://api.qlty.sh/workspaces?page[limit]=2&page[offset]=0" \ -H "Authorization: Bearer " ``` ```json Pagination response lines theme={"system"} { "data": [ { "id": "01998c1e-0000-7000-8000-000000000001", "key": "acme" }, { "id": "01998c1e-0000-7000-8000-000000000002", "key": "globex" } ], "meta": { "hasMore": true } } ``` ## Rate Limiting Qlty uses rate limiting to ensure that the API is not overwhelmed by too many requests. If you exceed the rate limit, you will receive a `429 Too Many Requests` response. The rate limit is measured in units, not raw request counts. Most requests cost a single unit, but some endpoints that return larger or more expensive results cost more. By default, the limit is 5,000 units per hour, applied as a fixed window. Requests to workspace and project endpoints count against a per-workspace limit, and requests to user endpoints count against a per-user limit. Contact support if you need a higher rate limit. Responses include headers reporting your current rate limit usage: | Header | Description | | - | - | | `x-ratelimit-limit` | Maximum number of units allowed in the current window | | `x-ratelimit-remaining` | Number of units remaining in the current window | | `x-ratelimit-used` | Number of units used in the current window | | `x-ratelimit-reset` | Unix timestamp (in seconds) when the rate limit window resets | You can also check your current rate limit status without consuming any of your limit by calling the `GET /rate_limit` endpoint. ## Versioning The Qlty API does not currently have a versioning scheme. Today, all endpoints are available at `https://api.qlty.sh/`. Prior to the general availability of the API, we are evaluating a versioning scheme that will allow us to make breaking changes without affecting existing users. # Auto-formatting Source: https://docs.qlty.sh/auto-formatting Auto-formatting is the practice of using automated tools to rewrite source code files into a consistent format. These tools ensure that your code adheres to predefined styling and formatting guidelines, removing the need for manual adjustments and maintaining uniformity across the codebase. Popular auto-formatting tools include [`go fmt`](https://go.dev/blog/gofmt) for Go, [Prettier](https://prettier.io/) for JavaScript, and [Black](https://github.com/psf/black) for Python. > [!TIP] > > Auto-formatting is provided by [Qlty CLI](/cli/quickstart). ## Why is Auto-Formatting Useful? Auto-formatting offers several key benefits that can enhance your development workflow and code quality: 1. **Consistency**: Auto-formatting enforces a consistent style across the entire codebase, making the code easier to read and understand. 2. **Productivity**: By automating the formatting process, developers can focus on writing code rather than spending time on manual formatting. 3. **Faster Code Review**: Consistent formatting results in clean diffs and reduces the number of stylistic comments during code reviews, allowing reviewers to focus on the logic and functionality of the code. ## How Auto-Formatting Works Auto-formatting tools analyze your code and apply a set of formatting rules to transform it into a standard format. These rules cover various aspects of code style, including indentation, spacing, line breaks, and more. The tools can typically be configured to match the specific style guide of your development team or project. Here’s a simple example in Go using `go fmt`: ### Before Auto-Formatting ```go lines theme={"system"} package main import "fmt" func main() { fmt.Println("Hello, world!") } ``` ### After Auto-Formatting ```go lines theme={"system"} package main import "fmt" func main() { fmt.Println("Hello, world!") } ``` In this example, `go fmt` adjusts the import statement and function definition to follow Go's standard formatting rules. ## Integrating Auto-Formatting into Your Workflow Qlty supports auto-formatting tools as part of its comprehensive code quality toolkit via the Qlty CLI. 1. **On Demand:** By configuring auto-formatters and running `qlty fmt` regularly, you can ensure consistent code style. 2. **Pre-commit Hooks**: Adding `qlty fmt` as a Git pre-commit hook to ensure every correct formatting of every commit. 3. **Continuous Integration (CI)**: You can set up an automated job to run `qlty fmt` nightly and commit the results. ## Recommended Auto-Formatters by Language | Language | Auto-Formatter | | - | - | | Go | go fmt | | GraphQL | Prettier | | HTML | Prettier | | Java | google-java-format | | JavaScript | Prettier | | JSON | Prettier | | Kotlin | ktfmt | | Markdown | Prettier | | PHP | @prettier/plugin-php | | Python | Black | | Ruby | standardrb | | Rust | rustfmt | | Shell | shfmt | | TypeScript | Prettier | | YAML | Prettier | ## See Also * [Qlty CLI](/cli/quickstart) * [`qlty fmt`](/cli/commands/fmt) * [Available Plugins](/plugins) * [Analysis Configuration](/cli/analysis-configuration) # Changelog Source: https://docs.qlty.sh/changelog New features, improvements, and fixes across Qlty Cloud and the Qlty CLI **October 13, 2026** ## Automatic coverage setup Setting up coverage reporting on CI usually goes in a loop. You add the upload step, push, and wait for the test suite. A flag or a path is wrong, so you fix it, push, and wait again. Automatic coverage setup hands that work to Qlty Cloud's agent. Open **Project Settings → Code Coverage**, click **Set up coverage**, and on the **Automatic** tab click **Set up automatically**. A few minutes later there's a draft PR titled **Set up Qlty code coverage** on your repository, with the agent's report as its description. Review it and merge it, and the next CI run on your default branch sends coverage. The agent runs in an isolated build container with a copy of your default branch. It reads your CI configuration and test setup, and writes the smallest change that produces complete coverage. On GitHub Actions it uses OIDC, so there's no secret to add. It can't commit, push, add secrets or merge. Qlty turns its edits into the PR. We've tested it on GitHub Actions. On CircleCI and other providers, review the PR with extra care. If the PR's CI fails, the same page lets you run Qlty's open source [`setup-coverage` skill](https://github.com/qltysh/qlty-skills/tree/main/skills/setup-coverage) in your own coding agent, or set coverage up by hand. Starting a run needs the **admin** role on the project, and the [Qlty GitHub App](/cloud/github-app) needs the **Workflows** permission. If it's missing, the setup page links to where an organization owner can [accept it](/cloud/github-app#accepting-new-permissions). To set up coverage, Qlty sends your repository's default branch to an AI subprocessor, currently Anthropic, which does not train models on it. See [Data Usage](/cloud/data-usage). See [Automatic Coverage Setup](/coverage/automatic-setup) for details. **August 31, 2026** ## Is the code your team is shipping well covered? Most coverage trend charts plot a Project's total coverage over time. That's valuable, but on a large project total coverage is a lagging metric: a real change in how a team tests takes a long time to make a meaningful mark on the total. Diff coverage — the coverage of the lines a change touches — is a leading one. If your team is covering the code it ships, diff coverage is high now, and total coverage trends upward over time. Every Project's **Trends** page now includes a **Diff Coverage** chart, showing how well tested the code you merged was, week by week. Diff coverage is plotted as a line, with the executable lines changed in each period as bars behind it, so you can tell a meaningful week from a quiet one. Ranges run from 1 month to 3 years. There's nothing to configure — the chart is built from the coverage you already upload on your default branch. See [Diff Coverage Over Time](/coverage/diff-coverage-trends) for details. **August 5, 2026** ## Build Secrets (beta) Some linters need a credential to do their job: an API token to reach a private package registry, a license key for a commercial tool. Until now, there was no way to hand one to a cloud build without committing it to your repository. **Build Secrets** are encrypted environment variables you set per project. Open **Project Settings → Secrets**, add a name and a value, and it's available to that project's builds. Values are write-only — once saved, a secret is encrypted and can never be read back, only rotated or deleted. The list shows names and timestamps, and only project admins can see or change it. Adding a secret doesn't hand it to every plugin. The Qlty CLI runs each plugin in a subprocess with a restricted environment and passes through only the variables that plugin's definition names, so you opt each plugin in from your `qlty.toml`: ```toml theme={"system"} [[plugins.definitions.foo.environment]] name = "BAR" value = "${env.BAR}" ``` Secrets reach your plugins only while Qlty installs and runs them, and never reach builds for pull requests from forks. Build Secrets are in beta and rolled out per workspace — [contact Qlty Support](https://qlty.sh/contact/support) to request access. See [Build Secrets](/cloud/build-secrets) for details. **July 23, 2026** ## Selective Coverage on pull requests (beta) Qlty has always supported partial test runs through [tags](/coverage/tags). Publish your unit tests as `units` and that suite is tracked on its own, because a tag runs a predictable set of tests each time and every report for it is comparable to the last. Test optimization tools break that assumption. To keep pull request builds fast on a large codebase, they choose a different subset of tests for every build based on what the change touched. Each report covers a unique slice of the codebase, comparable to nothing before it, and to a coverage tool it looks like a sudden, dramatic drop. The coverage such a run reports would be misleading, so our recommendation has been not to publish it at all. **Selective Coverage** makes those runs usable by overlaying the selected report on the pull request's diff. Add `--selection` to `qlty coverage publish` in the builds that run a dynamically selected subset of your tests: ```bash Qlty CLI lines theme={"system"} qlty coverage publish --selection coverage/lcov.info ``` ```yaml GitHub Action lines theme={"system"} - uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: coverage/lcov.info selected: true ``` Qlty trusts a selected report for the lines it does cover — exactly what diff coverage needs — so the Diff Coverage commit status and PR comments work as usual. The Total Coverage status passes with "Not computable for select coverage" rather than a misleading percentage; total coverage metrics, component coverage, trends, and the file explorer are untouched; and a selected report is never used as the comparison base for another pull request. Selective Coverage is in beta and requires Qlty CLI v0.633.0, GitHub Action `qltysh/qlty-action` v2.3.0, or CircleCI orb `qltysh/qlty-orb` 0.1.2 — or newer. Publish full-suite coverage on your default branch to keep totals and baselines accurate. See [Selective Coverage](/coverage/selective-coverage) for details. **June 12, 2026** ## Seat-based licensing Qlty Cloud now licenses Workspaces by **seats** instead of active contributors. A new **Seat Management** settings page lets admins assign seats to contributors and see how many are in use. See [Seats](/cloud/billing/seats) for details. ## Verified seat assignment When you assign a seat on the Seat Management page, Qlty now verifies the GitHub username exists before granting the seat. A confirmation dialog shows the account's avatar, name, and whether they belong to your GitHub organization, so you can catch typos and confirm you're assigning the right person. Non-existent accounts are rejected before any seat is used. ## Search when adding projects The Add Projects page now has a search box that filters across all accessible repositories server-side, so you no longer have to page through every repo to find one in a large Workspace. ## `--skip-source-fetch` for `qlty coverage publish` `qlty coverage publish` now accepts `--skip-source-fetch`, matching `qlty check` and `qlty fmt`. When set, the command skips fetching remote sources and falls back to the default configuration if a source is not cached locally. See [coverage publish](/cli/commands/coverage-publish) for details. ## VB.NET maintainability analysis The Qlty CLI now analyzes `.vb` files for maintainability — complexity, duplication, and code smells — with VB.NET's case-insensitive member semantics handled correctly. ## Scala maintainability analysis The Qlty CLI now analyzes Scala (including Scala 3) source files for maintainability — complexity, duplication, and code smells. ## Knip honors `.qlty/configs/` Fixed Knip not picking up a configuration file placed under `.qlty/configs/` in nested-package layouts. Qlty now passes the config path to Knip explicitly. ## RuboCop `AllCops: Exclude` now respected Qlty now passes `--force-exclusion` to RuboCop, so `AllCops: Exclude` patterns in your `.rubocop.yml` are honored even though Qlty invokes RuboCop with explicit file targets. ## editorconfig-checker findings no longer dropped Fixed a bug where `editorconfig-checker` results were silently discarded when the tool reported a `-1` line number for an issue it couldn't locate. All findings are now reported. **June 2, 2026** ## Verified CLI downloads in GitHub Actions The Qlty GitHub Actions now verify the Qlty CLI's Sigstore attestation before running it. Each action checks the downloaded archive against its signed provenance using the GitHub CLI, giving your workflows tamper-evident assurance that the binary came from Qlty. Verification is automatic and uses your existing `${{ github.token }}`. See [Integrity Verification](/cli/integrity-verification) for details. ## More coverage formats in the GitHub Action The Qlty coverage GitHub Action now accepts `dotcover` and `xccov-json` as `format` values, so you can upload JetBrains dotCover and Xcode `xccov` JSON reports directly from your workflow without converting them first. See [Generating Coverage Data](/coverage/generating-data) for details. ## Node 24 runtime for GitHub Actions The Qlty GitHub Actions now run on the Node 24 runtime, clearing the deprecation warning GitHub showed for the older Node 20 runtime and keeping the actions on a supported runtime ahead of GitHub's automatic migration. ## Windows support for the fmt action The Qlty `fmt` GitHub Action now runs on Windows runners in addition to Linux and macOS, so Windows-based CI pipelines can auto-format code with Qlty. **April 15, 2026** ## C and C++ language support Qlty now provides maintainability analysis for C and C++. This includes complexity, duplication, and code smells, available in both the Qlty CLI and Qlty Cloud. See [C / C++](/languages/c-cpp) for details. ## Travis CI push branch detection Travis CI users no longer need to set the branch name manually when uploading coverage. The Qlty CLI now detects the branch automatically on Travis push builds, the same way it already does for other CI providers. **April 9, 2026** ## editorconfig-checker plugin We've added a plugin for [editorconfig-checker](https://github.com/editorconfig-checker/editorconfig-checker), which verifies that your codebase follows the rules defined in `.editorconfig`. ```bash lines theme={"system"} qlty plugins enable editorconfig-checker ``` **March 24, 2026** ## Spectral plugin We've added a plugin for [Spectral](https://github.com/stoplightio/spectral), a linter for OpenAPI and AsyncAPI specifications. ```bash lines theme={"system"} qlty plugins enable spectral ``` **March 18, 2026** ## golangci-lint v2 support The Qlty plugin for [golangci-lint](https://golangci-lint.run/) now supports the v2 output format in addition to v1, so you can upgrade golangci-lint without losing report parsing. **March 17, 2026** ## Client-side coverage summing The Qlty CLI can now sum multiple coverage reports on the client before upload, complementing our existing server-side coverage merging. This is useful in CI workflows that already collect multiple coverage files on a single machine. **March 5, 2026** ## Resync renamed repositories When a GitHub repository is renamed, you can now click a **Resync** button on the Add Project page to update Qlty's reference to the new repository name, keeping the Project's existing history and settings instead of having to re-add it from scratch. **February 14, 2026** ## Python 3.13+ support The Qlty CLI now supports multiple Python runtime releases, enabling Python 3.13 and newer for plugins that require recent Python versions. **February 5, 2026** ## On-demand source fetching You now have precise control over when private sources are loaded — useful in offline or air-gapped environments, and for pre-fetching sources once in CI before running multiple analyses. A new `qlty sources fetch` command fetches the sources defined in `qlty.toml` without running analysis, and a new `--skip-source-fetch` flag tells `qlty check` and `qlty fmt` to use what's already on disk. ```bash lines theme={"system"} qlty sources fetch qlty check --skip-source-fetch qlty fmt --skip-source-fetch ``` **January 29, 2026** ## SLSA provenance for installers and upgrades Qlty CLI installer scripts are now published with [SLSA](https://slsa.dev/) attestations, and the `qlty upgrade` command verifies SLSA provenance for new releases using the `gh` CLI. This adds an extra layer of supply-chain integrity to installations and upgrades. **January 26, 2026** ## Improved SAML re-authentication When a user accessing a Workspace with SAML enabled needs to re-authenticate, Qlty Cloud now surfaces a clearer re-authentication page with explicit instructions, rather than a generic error. **January 24, 2026** ## Always-available PR Coverage tab The Pull Request Coverage tab now renders even when a base coverage report is missing, so reviewers always have a coverage view to work from. When there is no base report, diff coverage is displayed as "N/A" rather than blocking the page. **January 20, 2026** ## Better missing coverage data messaging When a Project is missing expected coverage data, the Coverage page now displays a clearer message explaining what's missing and how to resolve it. **January 8, 2026** ## HTTPS required for all outgoing requests The Qlty CLI now requires HTTPS for all outgoing HTTP requests, including source fetching and tool downloads. All network activity from the CLI is encrypted in transit. **December 26, 2025** ## Jenkins CI auto-detection We now support automatic detection of build metadata from Jenkins. Uploading coverage from a Jenkins build only requires the path to the coverage data file. See [setting up coverage with Jenkins](/coverage/ci) for the full walkthrough. ```shell lines theme={"system"} qlty coverage publish coverage.lcov ``` **December 19, 2025** ## Coverage page redesign A clearer view of how a pull request moves your coverage. The Project Coverage page has been rebuilt from the ground up, with: * Improved stats cards * A Files Changed tab with rendered file diffs * A Components tab showing per-Component coverage for the pull request * A collapsible sidebar with coverage comparison details **December 5–12, 2025** ## Coverage summary comment improvements Coverage summary comments on pull requests have been redesigned. The new comment includes: * An updated rating display * A **Modified Components** section showing which Components changed in the pull request * An **AI prompt** section with a ready-to-paste prompt for your AI coding agent to write the missing tests * The Qlty header image and clearer formatting **December 10–12, 2025** ## More coverage formats supported The Qlty CLI now ingests two more coverage report variants without any conversion step: * Apple's `xccov-json` format produced by `xccov` from Xcode coverage data * JaCoCo reports containing `` elements, the standard output for multi-module Maven and Gradle projects **December 1–4, 2025** ## Coverage Report page Full visibility into how each commit's coverage report was built — and a way to clean it up when something goes wrong. Qlty Cloud now includes a Coverage Report details page for each commit, showing summary metrics and every upload that contributed to the report. Project admins can also delete individual reports or uploads from Coverage Settings when a bad upload needs to be removed. **December 1, 2025** ## Maintainability shown as effort duration Maintainability is now displayed as estimated remediation effort (e.g. "2h 30m") in addition to issue counts, making it easier to compare projects and plan remediation work. **November 21, 2025** ## Bitrise CI auto-detection We now support automatic detection of build metadata from Bitrise. Uploading coverage from a Bitrise build only requires the path to the coverage data file. ```shell lines theme={"system"} qlty coverage publish coverage.lcov ``` **October 28, 2025** ## Configuration typo warnings The Qlty CLI now emits warnings when your `qlty.toml` contains unexpected attributes, helping you catch typos and outdated configuration syntax before they silently change your analysis. **October 22, 2025** ## API rate limiting Qlty API requests are now rate limited to protect service availability for all users. Clients that exceed the limit receive a `429 Too Many Requests` response with standard rate-limit headers, so your client can back off cleanly. **October 16, 2025** ## Automatic path fixing for coverage `qlty coverage publish` now automatically detects and corrects common path mismatches between coverage reports and the repository, including paths produced inside Docker containers and CI runners. This works in addition to the explicit `--add-prefix` and `--strip-prefix` options. See [Path Fixing](/coverage/path-fixing) for details. **October 9, 2025** ## Install-only mode `qlty check` now supports an `--install-only` flag that installs the plugins required by your configuration without running them. Use it to warm caches in CI so the analysis step runs faster on every build. **October 3, 2025** ## Onboarding flow We've shipped an updated onboarding flow for new users and new Workspaces, walking through GitHub installation, Project selection, and coverage setup. **September 15, 2025** ## Coding with AI agents We've published a new guide on [coding with AI agents](/cli/coding-with-ai-agents) that documents recommended patterns for using the Qlty CLI with Claude Code, Cursor, GitHub Copilot, OpenAI Codex, and other agents that can run shell commands. **September 14, 2025** ## Applications For teams that ship a single product across several repositories, Applications give you one view of code quality at the product level. Group related Projects together at the Workspace level and see aggregated maintainability, duplication, security, and coverage metrics across all of them. Enable Applications from **Settings > Features**, then assign Projects from each Project's **Settings > General**. See the [Applications documentation](/cloud/applications) for details. ## Churn view in Project Hotspots The Project Hotspots page now includes a churn view that combines maintainability issues with file change frequency to surface the files most likely to benefit from refactoring. **September 9, 2025** ## Self-service Workspace deletion Workspace Owners can now delete their own Workspace directly from Workspace Settings, without needing to contact support. **September 5, 2025** ## Improved Projects index The Workspace Projects page now supports server-side sorting, a column picker, and shows the timestamp of the last build for each Project. **September 4, 2025** ## Components Track per-team or per-service code quality without splitting your repo. Qlty Cloud now supports Components, which let you group files inside a Project (for example, by service, package, or directory) and view maintainability metrics for each group independently. Components are particularly useful for monorepos and modular codebases. Configure them from your Project's settings. **August 29, 2025** ## Workspace Activation page A new Activation page in Workspace Settings shows which Projects are activated, with sorting, filtering, and pagination — making it easier to manage Qlty across large organizations. **August 27, 2025** ## ktlint plugin We've added a plugin for [ktlint](https://github.com/pinterest/ktlint), an anti-bikeshedding Kotlin linter and formatter. ```bash lines theme={"system"} qlty plugins enable ktlint ``` **August 21, 2025** ## Delegated billing Delegated billing lets a single Workspace manage payment and subscription for one or more other Workspaces. This is useful for agencies, consultancies, and parent organizations that pay for multiple Workspaces. **August 20, 2025** ## JaCoCo source path override Java and Kotlin projects with non-standard source layouts can now point JaCoCo coverage uploads at the right directories by setting the `JACOCO_SOURCE_PATH` environment variable before running `qlty coverage publish`. **August 18, 2025** ## Workspace Manager permissions A new Workspace Manager role lets you delegate workspace-level administration to specific users without granting them GitHub Organization Owner permissions. See [User Permissions](/cloud/permissions) for the full permissions matrix. **August 11, 2025** ## GitHub Merge Queue support The Qlty CLI now has initial support for GitHub Merge Queues. We also detect merge groups across any CI provider that listens to GitHub push events (#2320). **August 5, 2025** ## Analysis Minutes progress bar Workspace billing pages now show an Analysis Minutes progress bar and a usage breakdown table so you can see at a glance how your build minutes are being consumed. **August 4, 2025** ## Workspace pausing You can now pause a Workspace from its settings page. While paused, Qlty stops running analysis and coverage reporting — useful while a repository is dormant or when you need to temporarily halt billable usage without deleting the Workspace. ## Default coverage validation `qlty coverage publish` now validates coverage reports by default, catching path mismatches and malformed reports before they corrupt your metrics. If you need to temporarily disable validation while fixing a report, use `--no-validate`: ```bash lines theme={"system"} qlty coverage publish --no-validate coverage.lcov ``` See [Path Fixing](/coverage/path-fixing) for details. ## zizmor plugin We've added a plugin for [zizmor](https://github.com/woodruffw/zizmor), a security analyzer for GitHub Actions workflows. ```bash lines theme={"system"} qlty plugins enable zizmor ``` **July 17, 2025** ## Coverprofile parser The Qlty CLI now parses Go's native `cover.out` (Coverprofile) format. You can upload Go coverage data without converting to another format first. ```bash lines theme={"system"} qlty coverage publish cover.out ``` ## Faster debugging of plugin install failures When a plugin fails to install, the Qlty CLI now surfaces the installation log directly in the main build log and points you to the full debug log on disk. No more guessing why a CI build broke during plugin setup. **July 7, 2025** ## Project Hotspots Qlty Cloud now includes a Hotspots page on every Project. Hotspots highlight the files most likely to need attention by combining maintainability, duplication, and (in later updates) churn data. ## Named API access tokens API access tokens now have a name, description, and optional expiration date. You can manage your tokens from your user settings page. Existing tokens will continue to work — you can add metadata to them or rotate them at any time. **July 4, 2025** ## Project Trends Qlty Cloud now includes a Trends tab on every Project. The Trends view visualizes how key quality metrics — including maintainability, duplication, and code coverage — change over time on your default branch. **June 25, 2025** ## Qlty API (beta) Pull Qlty data into your own tools. The Qlty API is now in beta, with endpoints for listing and reading Projects and for reading analysis Issues for a Project. Authenticate with a personal access token from your user settings to query any Workspace you can access. See the [API Reference](/api/introduction) for details. ## Coverage Diff commit status setting A new workspace-level setting controls whether Qlty posts a separate **Coverage Diff** commit status to GitHub (in addition to the existing Coverage status). Toggle it from Workspace Settings if your branch protection rules don't expect this status. **June 24, 2025** ## Git-free coverage publishing You can now publish coverage from environments that don't have a Git working directory — for example, containers that only carry the test artifacts. Pass `--override-commit-time` to `qlty coverage publish` to skip Git detection. **June 11, 2025** ## dotCover format support The Qlty CLI now parses [dotCover](https://www.jetbrains.com/dotcover/) reports for .NET projects, in addition to the formats we already supported. ```bash lines theme={"system"} qlty coverage publish coverage.dcvr ``` **June 2, 2025** ## SARIF output for `qlty smells` `qlty smells` now supports the `--sarif` flag, joining `qlty check` in producing standardized [SARIF](https://sarifweb.azurewebsites.net/) output for integration with other tools. ```bash lines theme={"system"} qlty smells --sarif ``` **May 5, 2025** ## Qlty Cloud Enterprise plan We've added a new Enterprise plan for Qlty Cloud, tailored for organizations with advanced needs. This plan includes everything in our Pro plan, plus more analysis minutes and additional features to enhance your experience: * Priority support with a SLA * Named account manager available through a private Slack channel * Consolidated billing for multiple GitHub organizations * Payment via invoices (including ACH and wire transfer) * Migration assistance * Terms of Service customization Learn more about the [Enterprise plan](https://qlty.sh/pricing) and how it can benefit your organization. **May 2, 2025** ## Server-side coverage merging We're proud to announce a long-requested feature: Server-side coverage merging! In testing workflows which involve multiple test suites, parallelization, or multiple programming languages it is common to produce multiple code coveragate data files. Previously, we only offered client-side coverage merging which required that all of the coverage data was available on the same filesystem and sent to the server as a single upload. In many scenarios, client-side merging was cumbersome and required uploading and downloading files from shared storage (like S3 or GitHub Actions artifacts). Also, visibility into the process was limited, resulting in a poor debugging experience if something went wrong. The addition of server-side merging significantly simplifies the set up of code coverage reporting in complex CI workflows, and enabled full visibility into the process from Qlty Cloud. To ensure accurate reporting, we delay posting coverage reports to GitHub until all of the coverage data is received. ```yaml GitHub Action lines theme={"system"} # Upload each coverage file separately - uses: qltysh/qlty-action/coverage@v1 with: oidc: true files: coverage/coverage1.lcov incomplete: true - uses: qltysh/qlty-action/coverage@v1 with: oidc: true files: coverage/coverage2.lcov incomplete: true # Tell Qlty all parts have been uploaded $ qlty coverage complete ``` ```bash Qlty CLI lines theme={"system"} # Upload each coverage file separately qlty coverage publish --incomplete coverage/coverage1.lcov qlty coverage publish --incomplete coverage/coverage2.lcov # Tell Qlty all parts have been uploaded qlty coverage complete ``` We support Learn more about [coverage merging](/coverage/merging) in our documentation. **May 1, 2025** ## Qlty Cloud is out of beta We're excited to announce that we have completed our beta phase for Qlty Cloud and have advanced it to GA status! Thank you to everyone who provided feedback and helped us improve the product during the beta period. We are proud to have made significant improvements based on your input, including: * Server-side coverage merging * OpenID Connect (OIDC) authentication for easier coverage setup * Expanded support for programming languages like C# and Swift * Additional plugins, bringing our total to 70+ * Significant performance improvements to the Qlty Cloud website * Many bug fixes and improvements to the debugging experience With Qlty Cloud now in GA, we'll be activating our billing system for all users by the end of the month. We offer a plan which is free for unlimited, private contributors and have paid plans with additional features and build minutes. Learn more on our [pricing page](https://qlty.sh/pricing). We look forward to continuing to iterate Qlty rapidly to deliver code quality and coverage done right. **April 30, 2025** ## StringsLint plugin We've added a plugin for [StringsLint](https://github.com/dral3x/StringsLint) which is ensures that localized strings in a Swift project are complete and never unused. StringsLint runs on macOS and targets files with the extensions `*.strings`, `*.stringsdict`, `*.swift`, `*.m`, `*.xib`, and `*.storyboard`. You can enable it using the Qlty CI: ```bash lines theme={"system"} qlty plugins enable stringslint ``` > [!NOTE] > > StringsLint only runs on macOS and is not available on Qlty Cloud which runs on Linux. ## SwiftFormat plugin We've added a plugin for [SwiftFormat](https://github.com/swiftlang/swift-format), the official auto-formatter for Swift. This auto-formatter targets Swift files, runs on macOS, and can be enabled using the Qlty CI: ```bash lines theme={"system"} qlty plugins enable swiftformat ``` > [!NOTE] > > SwiftFormat only runs on macOS and is not available on Qlty Cloud which runs on Linux. **April 28, 2025** ## Cloud authentication improvements We've significantly improved the latency of most web pages by using a short-lived caching strategy for our GitHub authorization checks. Navigating around the website should feel faster. (The exception is the Dashboard, which we will be optimizing soon.) Also, for organizations that use SAML on GitHub, we now detect when GitHub requires SAML re-authorization and use that information to render better error messages. Users accessing a GitHub organization with SAML enabled need to re-authorize occasionaly, and we now show a message with instructions on how to do that. **April 27, 2025** ## Out-of-the-box linter configs The Qlty CLI now provides out-of-the-box linter configurations for several popular linters. These linter configuration files are copied into your project when you run `qlty init` or `qlty plugins enable PLUGIN`. This allows you to quickly set up your project with sensible defaults without needing to create a configuration file manually. Once the configuration files are in place, you can customize them to fit your project's needs. **April 26, 2025** ## Swift maintainability analysis Qlty now provides maintainability analysis for Swift. This includes duplication and complexity metrics as well as code smells. The maintainability analysis is available in the Qlty CLI and Qlty Cloud. ## ast-grep plugin We've added a plugin for [ast-grep](https://ast-grep.github.io/) (sg), a fast polyglot structural search and linting tool supporting 20+ languages. ast-grep offers a pattern language to support writing your own [custom checks](/custom-checks) or adopting checks provided by the ast-grep community. ```bash lines theme={"system"} qlty plugins enable ast-grep ``` **April 25, 2025** ## Improved coverage uploader output We've updated the output from `qlty coverage publish` to include more information to improve the setup an debugging experience. ```toml lines theme={"system"} SETTINGS cwd: /home/runner/work/qlty/qlty add-prefix: src/ METADATA CI: GitHub Commit: c6dc5239a9e011e55ebdd598e35ce5700dc29741 Branch: main Build ID: 14975425147:1 COVERAGE FILES: 1 Coverage File Format Size remix/api-coverage/lcov.info lcov 2.32 KiB COVERAGE DATA 5 unique code file paths All code files in the coverage data were found on disk. Covered Lines: 57 Uncovered Lines: 24 Omitted Lines: 161 Line Coverage: 70.37% EXPORTING... Exported: tmp/qlty-coverage/coverage.zip AUTHENTICATION Auth Method: OIDC Token: *** PREPARING TO UPLOAD... Upload ID: 0efcc860-ede8-4466-9170-038cee46ccd1 UPLOADING... Uploaded 2.34 KiB in 0.28s! View report: https://qlty.sh/gh/qltysh/projects/qlty/settings/coverage/uploads/0efcc860-ede8-4466-9170-038cee46ccd1 ``` **April 17, 2025** ## Package lockfiles The Qlty CLI now uses package lockfiles (e.g. `package-lock.json`, `yarn.lock`, `Gemfile.lock`) when they are available and the `package_file` directive is specified in the `qlty.toml` configuration file. This ensures the exact same linter versions are used across all machines, including Qlty Cloud. ## V1 of Coverage GitHub Action We've release v1.0.0 of our reusable GitHub Action for coverage uploading. We adhere to [semantic versioning](https://semver.org/) so going forward breaking changes will be represented with a bump in the major version. To use the latest version on the v1 line, pin your CI workflows to `@v1` like this: ```yaml lines theme={"system"} - uses: qltysh/qlty-action/coverage@v1 with: oidc: true files: coverage/lcov.info ``` **April 15, 2025** ## BuildKite support We now support automatic detection of build metadata from BuildKite. Therefore, uploading code coverage data from BuildKite only requires executing the Qlty CLI with the path to the coverage data file. ```shell lines theme={"system"} qlty coverage publish coverage.lcov ``` **April 11, 2025** ## OpenID Connect (OIDC) We now support OpenID Connect (OIDC) authentication for code coverage uploads from GitHub Actions. OIDC allows us to authenticate the repository running a GitHub Actions workflow with a short-lived token. This enables coverage uploading without needing to manage a long-lived token, providing better security and easier coverage setup. ```yaml lines theme={"system"} permissions: contents: read id-token: write # IMPORTANT # ... Later in a workflow job: ... - uses: qltysh/qlty-action/coverage@v1 with: oidc: true files: coverage/lcov.info ``` **April 8, 2025** ## dockerfmt plugin We've add a plugin for [dockerfmt](https://github.com/reteps/dockerfmt), a tool for automatically formatting Dockerfiles. ```bash lines theme={"system"} qlty plugins enable dockerfmt ``` **April 4, 2025** ## Support Linux Arm64 Musl The Qlty CLI now supports Linux systems using Arm64 architecture with Musl. We're now compiling binaries for these target systems with each release. To install the Qlty CLI on an Arm64 Linux system using Musl, use our installer: ```shell lines theme={"system"} curl https://qlty.sh | sh ``` **April 3, 2025** ## SARIF output from Qlty CLI The Qlty CLI now supoprts [SARIF](https://sarifweb.azurewebsites.net/) output format. This is a standardized format for static analysis results, making it easier to integrate with other tools and platforms. To use the SARIF output format, simply add the `--sarif` flag to your Qlty CLI command. For example: ```bash lines theme={"system"} qlty check --sarif ``` **March 30, 2025** ## Code coverate tags (beta) Qlty Cloud now offers support for Coverage Tags in beta. Coverage Tags are a powerful feature that allow you to group, upload, and report on coverage data with more granularity. Coverage Tags are particularly useful to track coverage by suite independently. For example, you can track unit test coverage separately from integration test coverage. They can also be used in monorepos to make it easy to upload and report on coverage by service. In addition to providing clear, independent reporting of coverage metrics, Coverage Tags also allow you to carry forward coverage data from previous runs. This means that you can maintain a complete picture of your code coverage over time, even if you only run a subset of all of your tests on each commit. To use Coverage Tags, you can add the `--tag` flag to the `qlty coverage publish` command. For example: ```bash lines theme={"system"} qlty coverage publish --tag unit coverage/unit.lcov qlty coverage publish --tag integration coverage/integration.lcov ``` **March 27, 2025** ## php-cs-fixer plugin plugin We've added support for [php-cs-fixer](https://cs.symfony.com/), a tool that fixes your PHP code to follow standards including the PHP coding standards as defined in the PSR-1, PSR-2, etc., or other community driven standards from organizations like Symfony. ```bash lines theme={"system"} qlty plugins enable php-cs-fixer ``` **March 13, 2025** ## Checkstyle plugin Qlty now supports [Checkstyle](https://checkstyle.sourceforge.io/), a tool that helps programmers write Java code that adheres to a coding standard. ```bash lines theme={"system"} qlty plugins enable checkstyle ``` **March 1, 2025** ## Improved coverage comments We've made significant improvements to the code coverage summary comments from Qlty Could. The new comments include more information about the coverage impact of your pull request, including diff coverage and a breakdown of coverage changes by file. We've also added a "Help" section with definitions for the coverage metrics to help make it easier to interpret the results. **February 25, 2025** ## Support for more SimpleCov formats We have added support for additional SimpleCov formats to make it easier to get your code coverage data from SimpleCov ingested into Qlty Cloud. We now support the simplecov-json and simplecov-merged formats. **February 21, 2025** ## Negated exclusion patterns The Qlty CLI now supports negated exclusion patterns. Exclusion patterns are processed in order, matching the way that Git processes them. This means that if you have a negated pattern that matches a file, it will override any previous exclusion patterns that match the same file. You can use negated exclusion patterns in your `qlty.toml` file by prefixing the pattern with an exclamation mark (`!`). ```toml lines theme={"system"} exclude_patterns = [ "**/ignores/**.sh", "!**/dont_ignore/**", "**/ignores/dont_ignore/ignore_this_one.sh" ] ``` **February 9, 2025** ## SempahoreCI support We now support automatic detection of build metadata from SemaphoreCI. Therefore, uploading code coverage data from SemaphoreCI only requires executing the Qlty CLI with the path to the coverage data file. ```shell lines theme={"system"} qlty coverage publish coverage.lcov ``` **February 7, 2025** ## Coverage example repositories We now provide code coverage example repositories for many of the programming languages we support. These repositories are designed to help you get started with Qlty Cloud and provide a reference for how to set up code coverage reporting in your own projects. You can find links to all of the example repositories in our [documentation](https://docs.qlty.sh/coverage/example-repositories). **February 1, 2025** ## Docker images for Qlty CLI We now build and publish Docker images for the Qlty CLI. This distribution format is an alternative to our native binaries and enables the use of the Qlty CLI on operating systems that are not natively supported. The Docker images are available on [GitHub Container Registry](https://github.com/qltysh/qlty/pkgs/container/qlty). ```shell lines theme={"system"} docker pull ghcr.io/qltysh/qlty:main ``` **January 30, 2025** ## Pull request coverage tab Qlty Cloud has a new Coverage sub-tab on the Pull Request page. This tab provides a summary of the code coverage for the pull request, including a breakdown of coverage changes by file and their impact on your overall coverage. We also show the diff of the pull request with coverage annotations in the left gutter. **January 20, 2025** ## Workspace-level coverage tokens Qlty Cloud now offers Workspace-level coverage tokens in order to simplify the seet up of uploading code coverage data. This feature is particularly useful for organizations that have multiple repositories and want to use the same coverage token across all of them. **January 16, 2025** ## Code coverage debugging information We have significantly expanded the amount of debugging information available for code coverage uploads in the Qlty Cloud web app. Navigate the the "Code Covearge" section of Project Settings and you will be able to find a record of every code coverage upload, including the metadata and coverage metrics. We also provide a link to download the coverage information as a Zip file for easy inspeciton if something goes wrong. **January 15, 2025** ## SOC 2 Type II certification Qlty Software Inc. is proud to announce that we have achieved SOC 2 Type II certification. You can find our full announcement on our [blog](https://qlty.sh/blog/qlty-achieves-soc-2-type-ii-certification). Additional information about our security and compliance program can be found in our [Trust Center](https://trust.qlty.sh/). **January 7, 2025** ## C# maintainability analysis Qlty now provides maintainability analysis for C#. This includes duplication and complexity metrics as well as code smells. The maintainability analysis is available in the Qlty CLI and Qlty Cloud. **January 2, 2025** ## Qlty CLI is now Fair Source The Qlty CLI is now released under a Fair Source license. This means that you can use the Qlty CLI for free including in commercial projects, as long as you are not using it to provide a competing service. After a delay, the Qlty CLI code reverts to an OSI-approved Open Source license, also known as delayed Open Source publication (DOSP). Read the full announcement on our [blog](https://qlty.sh/blog/qlty-cli-is-fair-source). # Qlty CLI vs. Qlty Cloud Source: https://docs.qlty.sh/cli-vs-cloud Qlty is available as a command line interface (CLI) that you can run on your machine, as well as a complete, hosted Code Health Platform. You can use either Qlty CLI or Qlty Cloud alone, or you can use them together. > **[Qlty CLI](/cli/quickstart)** > > Your local Code Quality Toolkit > **[Qlty Cloud](/cloud/quickstart)** > > Hosted Cloud Health Platform Here are some of the key differences. #### Qlty CLI * Qlty CLI makes it fast and easy to run 50+ linters locally * Qlty CLI supports multi-language auto-formatting * Qlty CLI offers the fastest feedback loop * Qlty CLI can automatically fix issues * Qlty CLI is available for Mac, Linux, and Windows #### Qlty Cloud * Qlty Cloud provides automated code review of pull requests * Qlty Cloud runs static analysis with no setup required * Qlty Cloud offers automated security scanning * Qlty Cloud tracks code coverage * Qlty Cloud provides quality visualizations and trends * Qlty Cloud works with repositories hosted on GitHub Cloud # Analysis Configuration Source: https://docs.qlty.sh/cli/analysis-configuration Qlty's static analysis is highly configurable to maximize the relevancy of your results. Project configuration is through a `qlty.toml` file which is committed into your Git repository as `.qlty/qlty.toml`. > [!NOTE] > > If your repository does not have a `.qlty/qlty.toml` file, Qlty Cloud will automatically > generate a basic configuration before analysis. However, we strongly recommend checking in a > `.qlty/qlty.toml` to enable customization. If you have the Qlty CLI installed, you can generate an initial configuration by running `qlty init`. This will look at the file types and configuration files in your repository to generate a baseline configuration. ```bash Generate a Qlty config for the current repository lines theme={"system"} qlty init ``` Alternatively, you can write your `.qlty/qlty.toml` file by hand. Here is a minimal starting point that you can check in: ```toml .qlty/qlty.toml lines theme={"system"} config_version = "0" exclude_patterns = ["**/node_modules/**"] test_patterns = ["**/test/**"] [[source]] name = "default" default = true ``` This configuration will analyze all [supported languages](/languages) for maintainability using the default thresholds. ## Excluding files and paths Qlty is Git-aware and honors `.gitignore` files. Additional exclude patterns can be specified using glob syntax: ```toml .qlty/qlty.toml lines theme={"system"} # ... exclude_patterns = [ "path/to/file.py", # Ignore a specific file "**/generated/**", # Ignore generated files "**/*.css" # Ignore all CSS files ] # ... ``` ## Maintainability checks and thresholds Qlty evaluates code maintainability using a set of static analysis checks implemented for all supported programming languages. These checks have reasonable defaults, and can be customized further. For example: ```toml .qlty/qlty.toml lines theme={"system"} # Disable the "too many return statements" check [smells.return_statements] enabled = false # Allow functions with 6 params (all languages) [smells.function_parameters] threshold = 6 # For Python, allow 7 params [language.python.checks] function_parameters.threshold = 7 ``` ## Linting and SAST plugins Plugins extend Qlty with thousands of checks from linters and security scanning tools. Plugin definitions are stored in a Git repository called a Source. Qlty provides a default source which should be included in your `.qlty/qlty.toml` as follows. (This is automatically generated if you used `qlty init`.) ```toml .qlty/qlty.toml lines theme={"system"} # ... [[source]] name = "default" default = true # ... ``` With your Source specified, you can list available plugins: ```bash List all available plugins with the CLI lines theme={"system"} qlty plugins list ``` Then, you can activate any [available plugin](/plugins) as follows. ```shell Qlty CLI lines theme={"system"} qlty plugins enable rubocop ``` ```toml qlty.toml lines theme={"system"} [[plugin]] name = "rubocop" version = "1.64.1" # Optionally, lock to a version ``` ## Plugin configurations When running Qlty, plugins are configured using their own analysis configuration files (e.g. `.eslintrc`). Plugin configuration files can be stored in the `.qlty/configs/` directory in order to keep the root of the repository tidy. Qlty will automatically make them available to plugins when it runs analysis. ## Check modes Qlty's maintinability analysis, linters, and security scanning plugins run Checks which emit findings called Issues. By configuring the *Mode*, you keep developer workflows streamlined while preserving issues for later review. Qlty Cloud uses the Mode to determine the behavior for handling issues. The Mode can be configured at a Plugin level to one of four options: | Mode | Behavior | | - | - | | `disabled` | This plugin will not be run. | | `monitor` | Issues are browseable on Qlty.sh, but not annotated on GitHub | | `comment` | Issues generate code review comments but do not fail the Quality Gate | | `block` | This issue may cause the Quality Gate to fail. | ```toml .qlty/qlty.toml lines theme={"system"} [[plugin]] name = "osv-scanner" mode = "monitor" ``` ## Complete example ```toml .qlty/qlty.toml lines theme={"system"} config_version = "0" exclude_patterns = ["**/fixtures/**", "**/generated/**", "*.css"] # Code maintainability (structure and duplication) issues # are posted as comments but do not fail Quality Gates [checks] mode = "comment" [[source]] name = "default" default = true [[plugin]] name = "rubocop" version = "1.64.1" [[plugin]] name = "hadolint" [[plugin]] name = "shellcheck" [[plugin]] name = "osv-scanner" mode = "monitor" ``` ## More information * [Available Plugins](/plugins) * [Supported Languages](/languages) * [Project Configuration (`qlty.toml`) reference](/cli/qlty-toml) # Continuous Integration Source: https://docs.qlty.sh/cli/ci Most Qlty users user [Qlty Cloud](https://qlty.sh), our fully automated Code Health Platform, to run static analysis in the cloud, making CI setup unnecessary. However, there are a few use cases where running Qlty CLI in your continuous integration (CI) pipeline is useful. ## Auto-formatting your code nightly Qlty Cloud does not currently support auto-formatting your code. However, you can run `qlty fmt` in your CI pipeline to automatically format your code nightly. Here is an example GitHub Actions workflow: ```yml .github/workflows/fmt.yml lines theme={"system"} name: fmt on: workflow_dispatch: schedule: - cron: "0 6 * * *" permissions: contents: write jobs: format: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} - uses: qltysh/qlty-action/fmt@v2 - name: Commit changes uses: stefanzweifel/git-auto-commit-action@v5 with: commit_message: qlty fmt --all branch: ${{ github.head_ref }} commit_user_name: qltysh[bot] commit_user_email: 168846912+qltysh[bot]@users.noreply.github.com commit_author: qltysh[bot] <168846912+qltysh[bot]@users.noreply.github.com> ``` ## Publishing code coverage data to Qlty Cloud Qlty CLI is used to publish code coverage data to Qlty Cloud. Please see our documentation for [setting up code coverage](/coverage/quickstart) for more information. # Coding with AI Agents Source: https://docs.qlty.sh/cli/coding-with-ai-agents # Use Qlty CLI with AI Coding Agents Qlty CLI gives your AI coding tools a universal "quality gate" for code linting, auto-formatting, and maintainability checks. When you let your coding agent run Qlty as part of its workflow, it can automatically clean up code, catch issues early, and ship changes that pass the same standards you expect from human contributors. ## Requirements * Qlty CLI installed and available on `$PATH`. * A Qlty analysis config (`.qlty/qlty.toml`) tailored to your project. ## Compatibility Qlty can be integrated with most AI coding agents that can run shell commands. Popular options include: * Claude Code * GitHub Copilot * Cursor IDE * OpenAI Codex * Other agents that can run shell commands > [!NOTE] > > Network access must be available from the agent environment. ## Integration methods Because `qlty` is a command-line tool, it can be integrated into your AI agent's workflow in several ways: 1. Project memory/instructions (simplest) -- e.g. `CLAUDE.md` 2. Git hooks -- This method works automatically for both humans and agents. 3. Agent-specific hooks -- e.g. Claude Code [hooks](https://docs.anthropic.com/en/docs/claude-code/hooks) The `qlty` command is run with CLI arguments and reads code files from the local filesystem. Output is printed to standard out, and exit codes indicate success or failure. This simple interface avoids the need for Model Context Protocol (MCP) server or API integration. ### Project memory integration Each AI Agent offer ways to integrate custom instructions. When coding, agents read these instructions and follow them as part of their workflow. You can add instructions to run the `qlty` command at the right time. The necessary instructions can be as simple as the following: ```md lines theme={"system"} - Before committing, ALWAYS run auto-formatting with `qlty fmt` - Before finishing, ALWAYS run `qlty check --fix --level=low` and fix any lint errors ``` You can customize these instructions to fit the particulars of your desired workflow. Each AI coding agent has different paths that it will check for instructions files. Some examples include: * Claude Code: `CLAUDE.md` * Cursor: `AGENTS.md` * OpenAI Codex: `AGENTS.md` * GitHub Copilot: `.github/copilot-instructions.md` Please refer to the documentation of your chosen agent for details on how to add custom instructions. ### Git hooks integration The Qlty CLI can be run through Git hooks to enforce quality gates for both human and AI commits. This method works with any AI agent that can commit code via Git. The typical configuration is to set up a pre-commit hook to run `qlty fmt` and a pre-push hook to run `qlty check`. See [Qlty Git Hooks](/cli/git-hooks) for more details. # cache clean Source: https://docs.qlty.sh/cli/commands/cache-clean This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty cache clean [OPTIONS] ``` Delete the cache for the current project This will remove all cached results, logs, and debugging files for the current repository. It can be useful when debugging or to reclaim disk space. Stored files that are shared by the Qlty CLI between repositories, like installed plugins, are not affected by this command. ## Examples ```bash Clean the cache for the current repository lines theme={"system"} qlty cache clean ``` ## See Also * [`cache dir`](/cli/commands/cache-dir) * [`cache status`](/cli/commands/cache-status) * [Global Options](/cli/global-options) # cache dir Source: https://docs.qlty.sh/cli/commands/cache-dir This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty cache dir [OPTIONS] ``` Print the cache directory for the current project The Qlty CLI creates symlinks from within the *repository's* top-level `.qlty/` folder into a global `~/.qlty/` directory within the home directory. This command retrieves the *global* filesystem path to where those files are stored (a non-symlink path). For example: ``` /Users/username/.qlty/cache/repos/da4c81b6f6ee723c7f3c1490954ac29e ``` ## Examples ```bash Print the cache directory for the current repository lines theme={"system"} qlty cache dir ``` ## See Also * [`cache clean`](/cli/commands/cache-clean) * [`cache status`](/cli/commands/cache-status) * [Global Options](/cli/global-options) # cache prune Source: https://docs.qlty.sh/cli/commands/cache-prune This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty cache prune [OPTIONS] ``` Prune the cache ## See Also * [Global Options](/cli/global-options) # cache status Source: https://docs.qlty.sh/cli/commands/cache-status This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty cache status [OPTIONS] ``` Print the status of the cache directory for the current project The printed information includes file counts and sizes for the cached analysis results, project logs, and debug files. ## Examples ```bash Print the cache status for the current repository lines theme={"system"} qlty cache status ``` ## See Also * [`cache clean`](/cli/commands/cache-clean) * [`cache dir`](/cli/commands/cache-dir) * [Global Options](/cli/global-options) # check Source: https://docs.qlty.sh/cli/commands/check This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty check [OPTIONS] [PATHS]... ``` Run linters By default, only changed files are analyzed. Use `--all` or specify paths to override this behavior. Installs plugins and their required runtimes as needed before analyzing. By default, issues are cached locally to speed up subsequent runs. Must be run within a Git repository with Qlty initialized. ## Arguments > **\[PATHS]...** > > Files to analyze > **-a, --all** > > Check all files, not just changed > **--fix** > > Apply all auto-fix suggestions > > When combined with `--ai`, AI-generated fixes are applied without prompting for review. See [AI Autofixes Security Considerations](/cloud/ai-autofixes#security-considerations) for important guidance when using this flag. > **--no-fix** > > Do not apply auto-fix suggestions > **--ai** > > Generate AI fixes (requires Qlty Cloud authentication) > > The fixes are generated by a large language model and require Qlty Cloud authentication. AI fixes should be reviewed before applying. Using `--ai` with `--fix` applies AI suggestions automatically without review—see [Security Considerations](/cloud/ai-autofixes#security-considerations). > **--unsafe** > > Allow fixes for rules that may produce incorrect results and require careful human review > > These are fixes for rules that may produce incorrect results and require careful human review. By default, fixes for certain rules are blocked because they are more likely to need manual judgment. This flag removes those restrictions. > **--no-formatters** > > Disable formatter checks > **--no-progress** > > Disable progress bar > **--no-fail** > > Exit successfully regardless of what issues are found > **--no-error** > > Exit successfully regardless of linter errors > **--sample \** > > Sample results from a number of files for each linter > **--level \** > > Minimum level of issues to show > > \[default: note] \[possible values: note, fmt, low, medium, high] > **-j, --jobs \** > > Maximum number of concurrent jobs > **--filter \** > > Only run these plugins, or only report these rules (comma-separated) > > Each entry is a plugin name (`eslint`) or a plugin and rule joined by a > colon (`eslint:no-unused-vars`). A plugin name runs only that plugin. A > rule runs its plugin but reports only issues for that rule. > > Examples: > \--filter eslint Run only eslint > \--filter eslint,rubocop Run only eslint and rubocop > \--filter eslint:no-unused-vars Report only eslint's no-unused-vars issues > \--filter eslint,rubocop:Style/StringLiterals > Report all eslint issues and only > rubocop's Style/StringLiterals issues > > Use with --skip to remove plugins or rules from what --filter selects. > **--skip \** > > Don't run these plugins, or don't report these rules (comma-separated) > > Each entry is a plugin name (`rubocop`) or a plugin and rule joined by a > colon (`rubocop:Style/StringLiterals`). A plugin name stops that plugin > from running. A rule still runs its plugin but drops issues for that rule. > > Examples: > \--skip rubocop Run every plugin except rubocop > \--skip rubocop,shellcheck Run every plugin except rubocop and shellcheck > \--skip rubocop:Style/StringLiterals Run every plugin; drop that one rubocop rule > > With --filter, --filter picks what runs first and --skip removes from it. > When both match, --skip wins: > \--filter eslint,rubocop --skip rubocop > Run only eslint > \--filter eslint --skip eslint:no-console > Run only eslint; drop its no-console issues > > Every plugin named must be enabled, and skipping every plugin is an error. > **--trigger \** > > Run as this trigger, so only plugins whose `triggers` include it run > > Each plugin's `triggers` list in qlty.toml names the triggers it runs > on. A plugin with no `triggers` list runs on every trigger. Qlty's git > hooks pass `pre-commit` to `qlty fmt` and `pre-push` to `qlty check`. > > Examples: > \--trigger pre-push Run only plugins that run on pre-push > > \[default: manual] \[possible values: manual, ide, agent, pre-commit, pre-push, build] > **-v, --verbose...** > > Print verbose output > **--summary** > > Print a summary of issues > **--upstream \** > > Upstream base ref to compare against > **--no-cache** > > Disable caching issues > **--print-errors** > > Print errors to stderr > **--fail-level \** > > Minimum level of issues to fail on > > \[default: fmt] \[possible values: note, fmt, low, medium, high] > **--sarif** > > SARIF output > **--install-only** > > Install tools only, do not run checks > **--skip-source-fetch** > > Skip fetching sources before running checks ## Examples ```bash Run linters on changed files on your current branch lines theme={"system"} qlty check ``` ```bash Run linters on all files lines theme={"system"} qlty check --all ``` ```bash Run only ESLint on all files lines theme={"system"} qlty check --all --filter=eslint ``` ```bash Run linters on the web/ folder lines theme={"system"} qlty check web/ ``` ## See Also * [`init`](/cli/commands/init) * [`fmt`](/cli/commands/fmt) * [Available Plugins](/plugins) * [Excluding Files](/cli/excluding-files) * [Ignoring Checks and Issues](/cli/ignoring-issues) * [Global Options](/cli/global-options) # completions Source: https://docs.qlty.sh/cli/commands/completions This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty completions [OPTIONS] ``` Generate or install Qlty CLI shell completions When the `--shell` argument is omitted, it will attempt to detect the current shell using the `$SHELL` environment variable (or an operating system check for PowerShell on Windows). When the `--install` argument is specified, it will attempt to update the current user's shell configuration to include the tab completions. This operation involves *writing* to files like `.zshrc` but should generally be safe. ## Arguments > **--shell \** > > Shell to generate completions for > > \[possible values: bash, elvish, fish, powershell, zsh] > **--install** > > Install completions for the given shell ## Examples ```bash Install Qlty CLI completions for the current shell lines theme={"system"} qlty completions --install ``` ```bash Generate completions for Bash (no install) lines theme={"system"} qlty completions --shell bash ``` ## See Also * [`init`](/cli/commands/init) * [Global Options](/cli/global-options) # config migrate Source: https://docs.qlty.sh/cli/commands/config-migrate This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty config migrate [OPTIONS] ``` Update qlty.toml with settings from .codeclimate.yml Qlty’s [default thresholds for Code Smells](https://docs.qlty.sh/qlty-toml#smellsnamethreshold) differ from the [default thresholds](https://docs.codeclimate.com/docs/default-analysis-configuration#default-thresholds) in Quality Classic. Because of this, maintainability ratings in Qlty may differ from those seen in Classic. For repos with a committed `.codeclimate.yml` file, `qlty config migrate` will adjust your Qlty configuration to more closely align with your configuration in Quality Classic. For example: * If your `.codeclimate.yml` specifies a custom threshold for the `return-statements` check, `qlty config migrate` will copy this threshold into your `qlty.toml` * If your `.codeclimate.yml` does not specify a custom threshold for the `return-statements` check, `qlty config migrate` will copy the default threshold for Quality Classic’s `return-statements` check into your `qlty.toml` Additionally, `qlty config migrate` will copy any existing `prepare` statements which exist in your `.codeclimate.yml`. ## Arguments > **--dry-run** > > Prints the migrated version of qlty.toml to the console without saving it to disk ## Examples ```bash Migrate configuration from .codeclimate.yml into qlty.toml lines theme={"system"} qlty config migrate ``` ```bash Preview the migration without making changes lines theme={"system"} qlty config migrate --dry-run ``` ## See Also * [`config show`](/cli/commands/config-show) * [Global Options](/cli/global-options) # config show Source: https://docs.qlty.sh/cli/commands/config-show This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty config show [OPTIONS] ``` Print the full, merged configuration Qlty uses a strategy of merging layered configuration in this order: 1. Global defaults 2. Any Sources declared in the project's `qlty.toml` 3. Configuration from the `qlty.toml` Each layer is able to override the earlier layers using a deep merge. The result of this process is a single, merged configuration with all of the configuration that Qlty uses. This command prints that configuration in YAML format to aid with debugging. If the configuration is missing or invalid, the command will exit with an error. ## Examples ```bash Print the current project's full, merged configuration lines theme={"system"} qlty config show ``` ## See Also * [`config validate`](/cli/commands/config-validate) * [Global Options](/cli/global-options) # config validate Source: https://docs.qlty.sh/cli/commands/config-validate This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty config validate [OPTIONS] ``` Validate the current project's configuration If the configuration is valid, the command will exit successfully with no output. If the configuration is missing or invalid, the command will exit with an error. ## Examples ```bash Validate the current project's configuration lines theme={"system"} qlty config validate ``` ## See Also * [`config show`](/cli/commands/config-show) * [Global Options](/cli/global-options) # coverage complete Source: https://docs.qlty.sh/cli/commands/coverage-complete This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty coverage complete [OPTIONS] ``` Mark coverage as complete on Qlty Cloud ## Arguments > **--tag \** > **--override-commit-sha \** > > Override the commit SHA from the CI environment > **-t, --token \** > > The token to use for authentication when uploading the report. By default, it retrieves the token from the QLTY\_COVERAGE\_TOKEN environment variable > **--project \** > > The name of the project to associate the coverage report with. Only needed when coverage token represents a workspace and if it cannot be inferred from the git origin > **--selection** > > Complete the uploads published with --selection. Selected and unselected uploads assemble into separate reports, so pass this exactly when it was passed to qlty coverage publish > **--dry-run** > > Perform a dry-run without actually completing the coverage > **-q, --quiet** ## See Also * [Global Options](/cli/global-options) # coverage publish Source: https://docs.qlty.sh/cli/commands/coverage-publish This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty coverage publish [OPTIONS] [PATHS]... ``` Upload coverage reports to the Qlty Cloud The `qlty coverage publish` command uploads code coverage reports to Qlty Cloud for analysis. It supports multiple report formats to ensure compatibility with various programming languages, including `simplecov`, `clover`, `cobertura`, `coverprofile`, `lcov`, `jacoco`, and the generic `qlty` format. Beyond uploading reports, this command allows the addition or removal of file path prefixes, tagging uploads for easier identification, and overriding the value of certain git-related variables. It integrates code coverage data into Qlty Cloud, offering a comprehensive view of your codebase's coverage. ## Arguments > **\[PATHS]...** > > One or more paths to the coverage reports to be uploaded > **--dry-run** > > Do not upload the coverage report, only export it to the output directory > **--format \** > > The format of the coverage report to transform. If not specified, the format will be inferred from the file extension or contents > > \[possible values: simplecov, clover, cobertura, coverprofile, dotcover, lcov, jacoco, qlty, xccov-json] > **--tag \** > > A tag to associate with this coverage report upload > **--override-build-id \** > > Override the build identifier from the CI environment > **--override-branch \** > > Override the branch from the CI environment > **--override-commit-sha \** > > Override the commit SHA from the CI environment > **--override-pr-number \** > > Override the pull request number from the CI environment > **--override-commit-time \** > > Override the commit time from git metadata. Accepts a Unix timestamp (seconds since epoch) or RFC3339/ISO8601 format > **--override-git-tag \** > > Override the git tag from the CI environment > **--add-prefix \** > > The prefix to add to file paths in coverage payloads, to make them match the project's directory structure > **--strip-prefix \** > > The prefix to remove from absolute paths in coverage payloads to make them relative to the project root. This is usually the directory in which the tests were run. Defaults to the root of the git repository > **-t, --token \** > > The token to use for authentication when uploading the report. By default, it retrieves the token from the QLTY\_COVERAGE\_TOKEN environment variable > **--project \** > > The name of the project to associate the coverage report with. Only needed when coverage token represents a workspace and if it cannot be inferred from the git origin > **--name \** > > A name for the upload to help identify it for debugging purposes > **--print** > > Print coverage > **--verbose** > > Verbose > **-q, --quiet** > > Suppress all output except for errors > **--total-parts-count \** > > The total number of parts that qlty cloud should expect. Each call to qlty publish will upload one part. (The total parts count is per coverage tag e.g. if you have 2 tags each with 3 parts, you should set this to 3) > **--no-validate** > > Disable validation of the coverage report before uploading it. By default, validation checks if the report is valid and minimum number of files are present > **--validate-file-threshold \** > > Custom threshold percentage for validation (0-100). Only applies when validation is enabled. Default is 90 > **--incomplete** > > Mark this upload as incomplete. This is useful when issuing multiple qlty coverage publish commands for the same coverage tag. The server will merge the uploads into a single report when qlty coverage complete is called > **--selection** > > Mark this upload as coming from a selected subset of the test suite — e.g. only the tests affected by a pull request's changes. Selected coverage contributes to diff coverage only and is excluded from total coverage > **--skip-source-fetch** > > Skip fetching sources before publishing. Requires sources to be cached locally > > When a remote source is not cached locally, publishing warns and falls back to the default configuration instead of fetching. Useful in CI where source fetching is unwanted or unavailable ## Examples Upload a [Cobertura](https://cobertura.github.io/cobertura/) report to Qlty Cloud: ```sh lines theme={"system"} qlty coverage publish cobertura.xml ``` ## See Also * [`(Qlty Cloud) Setting up Code Coverage`](/coverage/quickstart) * [Global Options](/cli/global-options) # coverage transform Source: https://docs.qlty.sh/cli/commands/coverage-transform This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty coverage transform [OPTIONS] ``` Transform coverage data to the Qlty format The `qlty coverage transform` command converts code coverage reports from their original formats into a generic format named `qlty`. It supports various input formats, including `lcov`, `cobertura`, `jacoco`, and `clover`. In addition to converting reports to the `qlty` format, this command can add or remove prefixes from file paths and print the transformed report. It is typically used in conjunction with the `coverage publish` command as an intermediate step to upload the transformed report to Qlty Cloud for analysis, particularly in sophisticated CI setups that implement Parallel Testing or other advanced configurations. ## Arguments > **\** > > The path to the coverage report, which may include its format (e.g., 'lcov:./coverage/lcov.info') > **--dry-run** > > Transform the coverage report without writing the output file > **--report-format \** > > The format of the coverage report to transform. If not specified, the format will be inferred from the file extension or contents > > \[possible values: simplecov, clover, cobertura, coverprofile, dotcover, lcov, jacoco, qlty, xccov-json] > **--add-prefix \** > > The prefix to add to file paths in coverage payloads. This helps to match the file paths with the project's directory structure > **--strip-prefix \** > > The prefix to remove from absolute paths in coverage payloads to make them relative to the project root. This is usually the directory in which the tests were run. Defaults to the root of the git repository > **--output \** > > The output file name for the transformed coverage report. If not specified, the report will be saved to 'coverage.jsonl' > **--print** > > Print coverage > **-q, --quiet** > > Suppresses most of the standard output messages ## See Also * [`coverage publish`](/cli/commands/coverage-publish) * [Global Options](/cli/global-options) # dashboard Source: https://docs.qlty.sh/cli/commands/dashboard This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty dashboard [OPTIONS] ``` Open the Qlty Cloud dashboard in the browser ## Examples ```bash Open the Qlty Cloud dashboard lines theme={"system"} qlty dashboard ``` ## See Also * [Global Options](/cli/global-options) # deinit Source: https://docs.qlty.sh/cli/commands/deinit This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty deinit [OPTIONS] ``` Remove Qlty from the current repository This command has the effect of removing the `.qlty/` directory at the root of the repository. > [!WARNING] > > All cached analysis results, logs, and debugging files will be lost. Because this is a destructive operation, the command will prompt for interactive confirmation. The `--yes` argument can be used to skip the confirmation step. If Qlty is not initialized in the current repository, this command will exit with an error. ## Arguments > **-y, --yes** > > Proceed without confirmation ## Examples ```bash Remove the Qlty configuration from the current project lines theme={"system"} qlty deinit ``` ## See Also * [`init`](/cli/commands/init) * [Global Options](/cli/global-options) # discord Source: https://docs.qlty.sh/cli/commands/discord This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty discord [OPTIONS] ``` Join our Discord server (opens in the browser) ## Examples ```bash Open the Qlty Discord server lines theme={"system"} qlty discord ``` ## See Also * [Global Options](/cli/global-options) # docs Source: https://docs.qlty.sh/cli/commands/docs This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty docs [OPTIONS] ``` Open the docs website in the browser ## Examples ```bash Open the Qlty documentation lines theme={"system"} qlty docs ``` ## See Also * [Global Options](/cli/global-options) # fmt Source: https://docs.qlty.sh/cli/commands/fmt This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty fmt [OPTIONS] [PATHS]... ``` Auto-format files by rewriting them By default, only changed files are auto-formatted. Use `--all` or specify paths to override this behavior. Installs plugins and their required runtimes as needed before analyzing. Must be run within a Git repository with Qlty initialized. ## Arguments > **\[PATHS]...** > > Files to analyze > **-a, --all** > > Check all files, not just changed > **--no-progress** > > Disable progress bar > **--no-error** > > Exit successfully regardless of linter errors > **--sample \** > > Sample results from a number of files for each linter > **--jobs \** > > Maximum number of concurrent jobs > **--filter \** > > Only run these formatter plugins (comma-separated) > > Examples: > \--filter prettier Run only prettier > \--filter prettier,black Run only prettier and black > > Use with --skip to remove plugins from what --filter selects. > **--skip \** > > Don't run these formatter plugins (comma-separated) > > Examples: > \--skip prettier Run every formatter except prettier > \--skip prettier,black Run every formatter except prettier and black > > With --filter, --filter picks what runs first and --skip removes from it. > When both match, --skip wins: > \--filter prettier,black --skip black Run only prettier > > Every plugin named must be enabled, and skipping every plugin is an error. > **--trigger \** > > Run as this trigger, so only formatters whose `triggers` include it run > > Each plugin's `triggers` list in qlty.toml names the triggers it runs > on. A plugin with no `triggers` list runs on every trigger. Qlty's git > hooks pass `pre-commit` to `qlty fmt` and `pre-push` to `qlty check`. > > Examples: > \--trigger pre-commit Run only formatters that run on pre-commit > > \[default: manual] \[possible values: manual, ide, agent, pre-commit, pre-push, build] > **-v, --verbose...** > > Print verbose output > **--upstream \** > > Upstream base ref to compare against > **--index** > > Format files in the Git index > **--index-file \** > > Format files in the specified Git index file > **--skip-source-fetch** > > Skip fetching sources before formatting ## Examples ```bash Auto-format changed files on your current branch lines theme={"system"} qlty fmt ``` ```bash Auto-format all files with prettier lines theme={"system"} qlty fmt --all --filter=prettier ``` ```bash Auto-format files in a directory lines theme={"system"} qlty fmt web/ ``` ## See Also * [`init`](/cli/commands/init) * [`check`](/cli/commands/check) * [Available Plugins](/plugins) * [Excluding Files](/cli/excluding-files) * [Global Options](/cli/global-options) # help Source: https://docs.qlty.sh/cli/commands/help This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty help [COMMAND]... ``` Print this message or the help of the given subcommand(s) ## Examples ```bash Show top-level subcommands lines theme={"system"} qlty help ``` ```bash Show help for the check command lines theme={"system"} qlty help check ``` ## See Also * [`version`](/cli/commands/version) * [Global Options](/cli/global-options) # init Source: https://docs.qlty.sh/cli/commands/init This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty init [OPTIONS] ``` Set up Qlty in the current repository This command will generate an initial project configuration file based on the contents of the repository and write it to `.qlty/qlty.toml` at the repository root. When run without the `--skip-plugins` command, initialization will try to determine a reasonable set of linters and formatters to enable. Certain linters and formatters are enabled based on the detection of a linter configuration file. Others are enabled just based on the presence of target files of the programming language. Following initialization, the command will print a summary of the configuration. After generating a configuration file, the command will ask if you want to *sample* the results of the enabled plugins. Sampling runs each plugin against a small set of targets. If Qlty is already initialized in the current repository, this command will exit with an error. ## Arguments > **-y, --yes** > > Answer yes to all prompts > **-n, --no** > > Answer no to all prompts > **--skip-plugins** > > Skip enabling plugins > **--dry-run** > > Print the generated configuration to stdout instead of saving to disk > **--skip-default-source** > > Initialize without default source > **--source \** > > A custom source to use for plugins. This can be a URL(name=url) or a path to a local directory(name=directory) ## Examples ```bash Generate a Qlty config for the current repository lines theme={"system"} qlty init ``` ```bash Generate a Qlty config and skip prompts lines theme={"system"} qlty init --no ``` ```bash Generate a Qlty config with no plugins lines theme={"system"} qlty init --skip-plugins ``` ## See Also * [`deinit`](/cli/commands/deinit) * [Global Options](/cli/global-options) # install Source: https://docs.qlty.sh/cli/commands/install This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty install [OPTIONS] ``` Install linters and their dependencies This command will examine the current project's configuration and install enabled plugins and any dependencies (e.g. runtimes like NodeJS). Installations are cached and re-used between runs of `qlty check` and `qlty fmt`. Under normal circumstances, running `qlty install` is not necessary, because plugins will automatically be installed as needed. However, plugin installations require an Internet connection and in some cases can be slow, so `qlty install` can be used to prepare the system for future analysis. When run with the `--filter ` argument, only the specified plugin and its dependencies will be installed. By default *all* plugins are installed. ## Arguments > **--no-progress** > > Disable progress bar > **-j, --jobs \** > > Maximum number of concurrent jobs > **--filter \** > > Only install this plugin (for example, `eslint`) ## Examples ```bash Install all plugins lines theme={"system"} qlty install ``` ```bash Install ESLint lines theme={"system"} qlty install --filter=eslint ``` ## See Also * [Global Options](/cli/global-options) # metrics Source: https://docs.qlty.sh/cli/commands/metrics This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty metrics [OPTIONS] [PATHS]... ``` Compute code quality metrics Calculate metrics like classes count, complexity, lines of code, and cohesion for [supported languages](/languages) using our custom built static analysis. ## Arguments > **\[PATHS]...** > > Files to analyze > **-a, --all** > > Compute metrics for all files, not just changed > **-d, --dirs** > > Print per-directory stats > **--functions** > > Print function stats > **--max-depth \** > > Directory depth to print, this flag will also set to print per-directory stats > **--sort \** > > Sort output by column > > \[possible values: name, classes, functions, fields, lines, loc, complexity, lcom] > **--limit \** > > Maximum rows to print > **--exclude-tests** > > Exclude tests > **--upstream \** > > Upstream base ref to compare against > **--quiet** > > Only show results ## Examples ```bash Summarize metrics across directories lines theme={"system"} qlty metrics --all --max-depth 2 ``` ```bash Review the 10 most complex files lines theme={"system"} qlty metrics --all --sort complexity --limit 10 ``` ```bash View function-level metrics for a file lines theme={"system"} qlty metrics --functions remix/app/root.tsx ``` ## See Also * [`qlty init`](/cli/commands/init) * [`qlty smells`](/cli/commands/smells) * [Support Languages](/languages) * [Excluding Files](/cli/excluding-files) * [Global Options](/cli/global-options) # plugins disable Source: https://docs.qlty.sh/cli/commands/plugins-disable This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty plugins disable [OPTIONS] [PLUGINS]... ``` Disable plugins for the current project The command edits the current project's `qlty.toml` file to disable plugins. ## Arguments > **\[PLUGINS]...** > > Plugins to disable by name ## Examples ```bash Disable the latest version of shellcheck lines theme={"system"} qlty plugins disable shellcheck ``` ```bash Disable rubocop and eslint lines theme={"system"} qlty plugins disable rubocop eslint ``` ## See Also * [`plugins enable`](/cli/commands/plugins-enable) * [`plugins upgrade`](/cli/commands/plugins-upgrade) * [`plugins list`](/cli/commands/plugins-list) * [Global Options](/cli/global-options) # plugins enable Source: https://docs.qlty.sh/cli/commands/plugins-enable This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty plugins enable [OPTIONS] [PLUGINS]... ``` Enable plugins for the current project The command edits the current project's `qlty.toml` file to enable plugins. ## Arguments > **\[PLUGINS]...** > > Plugins to enable specified as name=version ## Examples ```bash Enable the latest version of shellcheck lines theme={"system"} qlty plugins enable shellcheck ``` ```bash Enable shellcheck version 1.2.3 lines theme={"system"} qlty plugins enable shellcheck=1.2.3 ``` ```bash Enable rubocop and eslint lines theme={"system"} qlty plugins enable rubocop eslint ``` ## See Also * [`plugins upgrade`](/cli/commands/plugins-upgrade) * [`plugins disable`](/cli/commands/plugins-disable) * [`plugins list`](/cli/commands/plugins-list) * [Global Options](/cli/global-options) # plugins list Source: https://docs.qlty.sh/cli/commands/plugins-list This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty plugins list [OPTIONS] ``` List all available plugins This command lists all available plugins based on the sources declared in the current project's `qlty.toml` configuration file. ## Examples ```bash List all available plugins lines theme={"system"} qlty plugins list ``` ## See Also * [`plugins enable`](/cli/commands/plugins-enable) * [`plugins upgrade`](/cli/commands/plugins-upgrade) * [`plugins disable`](/cli/commands/plugins-disable) * [Global Options](/cli/global-options) # plugins upgrade Source: https://docs.qlty.sh/cli/commands/plugins-upgrade This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty plugins upgrade [OPTIONS] ``` Upgrade a plugin for the current project The command edits the current project's `qlty.toml` file to upgrade plugin version. ## Arguments > **\** > > Plugin to upgrade > **--version \** > > Optional - Specific version to upgrade to ## Examples ```bash Upgrade to the latest compatible version of shellcheck lines theme={"system"} qlty plugins upgrade shellcheck ``` ```bash Upgrade shellcheck to version 1.2.3 lines theme={"system"} qlty plugins upgrade shellcheck --version=1.2.3 ``` > [!WARNING] > > When specifying the version with --version option, it is responsibility of the user to make sure > the version is valid and compatible with qlty. ## See Also * [`plugins enable`](/cli/commands/plugins-enable) * [`plugins disable`](/cli/commands/plugins-disable) * [`plugins list`](/cli/commands/plugins-list) * [Global Options](/cli/global-options) # slop-one Source: https://docs.qlty.sh/cli/commands/slop-one This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty slop-one [OPTIONS] [FILES]... ``` Build the SlopOne code quality trends report, or score source files ## Arguments > **\[FILES]...** > > Source files to score; with none, build the trends report for this repository > **--offline** > > Use existing cached analyses; make no API calls > **--budget \** > > Maximum estimated API spend for this invocation in USD (default: 1 when scoring files, no cap for the report) > **--provider \** > > Jev provider: typesafe (direct), vercel (AI Gateway), or openrouter > > \[default: typesafe] \[possible values: typesafe, vercel, openrouter] > **--cache-dir \** > > Directory for cached analyses and run data (default: \~/.qlty/cache/slop-one) > **--jobs \** > > Number of files or contents to analyze concurrently > > \[default: 16] ### Report options > **--since \** > > Start of the report, YYYY-MM-DD (default: one year ago) > **--output \** > > Directory for the report (default: the working directory) > **--no-open** > > Write the report without opening it in the browser ### Scoring options > **--json** > > Emit one JSON result object > **--include-tests** > > Include test files and Rust inline test modules (excluded by default) > **--include-excluded** > > Include generated, dependency, documentation, and test files; also include inline tests > **--model-info** > > Show model metadata without evaluating files > **--top \** > > Number of positive and negative factors in text output (default: 3, or 5 when comparing) ### Comparison options > **--upstream \** > > Compare the files changed since the merge base with REF against their versions there > **--upstream-from-pre-push** > > Compare the commits being pushed, read from a Git pre-push hook's stdin > **--max-drop \** > > Largest score drop allowed before a changed file counts as declined (default: 1) > **--trigger \** > > What runs the comparison; pre-push reports a blocked push, lets errors through, and can be skipped with Enter > > \[default: manual] \[possible values: manual, ide, agent, pre-commit, pre-push, build] > **--prompt \** > > What the prompt printed for declined files asks a coding agent to do (default: recommend) > > \[possible values: recommend, refactor] ## See Also * [Global Options](/cli/global-options) # smells Source: https://docs.qlty.sh/cli/commands/smells This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty smells [OPTIONS] [PATHS]... ``` Find code smells like duplication and complexity Detect issues like duplication (copy and pasted code), high complexity, deeply nested control flows, etc. for [supported languages](/languages) using our custom built static analysis. ## Arguments > **\[PATHS]...** > > Files to analyze > **-a, --all** > > Compute smells for all files, not just changed > **--no-duplication** > > Don't check for duplication > **--include-tests** > > Include tests > **--no-snippets** > > Don't show code snippets > **--upstream \** > > Upstream base ref to compare against > **--quiet** > > Only show results > **--sarif** > > SARIF output ## Examples ```bash Analyze your current branch lines theme={"system"} qlty smells ``` ```bash Analyze your entire project for code smells lines theme={"system"} qlty smells --all ``` ```bash Analyze specific paths for code smells lines theme={"system"} qlty smells example-app/components/ui react-app/utils ``` ```bash Analyze a specific file for code smells lines theme={"system"} qlty smells example-app/components/ui/Dropdown.tsx ``` ```bash Skip duplication analysis lines theme={"system"} qlty smells --all --no-duplication ``` ```bash Analyze for code smells against a specific upstream branch lines theme={"system"} qlty smells --upstream origin/main ``` ## See Also * [Code Smells](/code-smells) * [Duplication](/duplication) * [Excluding Files](/cli/excluding-files) * [`qlty check`](/cli/commands/check) * [Global Options](/cli/global-options) # sources fetch Source: https://docs.qlty.sh/cli/commands/sources-fetch This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty sources fetch [OPTIONS] ``` Fetch plugin sources ## See Also * [Global Options](/cli/global-options) # upgrade Source: https://docs.qlty.sh/cli/commands/upgrade This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty upgrade [OPTIONS] [COMMAND] ``` Upgrade the Qlty CLI When run without a `--version` argument, this command checks if there is a newer version of the Qlty CLI available than the current version. If there is a release to install, it downloads the Qlty installer script from `qlty.sh` and runs it. The script downloads the release archive with `curl` or `wget` (PowerShell on Windows) and replaces the installed executable. That download relies on the operating system's certificate store and does not check the release's attestation. Finally, the upgrade command will attempt to install shell completions. ## Arguments > **--version \** > > The version to upgrade to. Defaults to the latest version > **--force** > > Run the upgrade even if the latest version is already installed > **--dry-run** > > Whether to perform a dry run > **--verify-attestations** > > Verify SLSA provenance attestation before installing > > \[env: QLTY\_VERIFY\_ATTESTATIONS=] > > See [Integrity Verification](/cli/integrity-verification). ## Commands > **source** > > Upgrades the source > > See [`upgrade source`](/cli/commands/upgrade-source). ## Examples ```bash Upgrade to the latest Qlty CLI if one is available lines theme={"system"} qlty upgrade ``` ```bash Upgrade to version 0.299.0 lines theme={"system"} qlty upgrade --version 0.299.0 ``` ```bash Force re-installation even if no new version is available lines theme={"system"} qlty upgrade --force ``` ```bash Verify the release's attestation before installing it lines theme={"system"} qlty upgrade --verify-attestations ``` ## See Also * [Upgrading the CLI](/cli/upgrading) * [`completions`](/cli/commands/completions) * [Global Options](/cli/global-options) # upgrade source Source: https://docs.qlty.sh/cli/commands/upgrade-source This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty upgrade source [OPTIONS] ``` Upgrades the source ## See Also * [Global Options](/cli/global-options) # version Source: https://docs.qlty.sh/cli/commands/version This reference documents Qlty CLI v0.662.0. ```bash lines theme={"system"} qlty version [OPTIONS] ``` Print the current Qlty CLI version Example output: ```plain lines theme={"system"} qlty 0.654.0 macos-arm64 (fa78745 2026-10-12) ``` Versions follow [Semantic Versioning](https://semver.org/). Following the version number are the operating system and architecture the CLI was built for, then the Git commit SHA that the CLI was built from and the build date. Debug builds are indicated with the word `debug` following the Git commit SHA. Otherwise, it is a release build. ## Examples ```bash Print the current version lines theme={"system"} qlty version ``` ## See Also * [`help`](/cli/commands/help) * [Global Options](/cli/global-options) # Plugins Source: https://docs.qlty.sh/cli/concepts/plugins Qlty integrates with linters, auto-formatters, security scanners, and other static analysis tools as plugins. > [!NOTE] > > Looking for plugin-specific configuration options, supported versions, or invocation details? > Each plugin lives in its own folder under > [qltysh/qlty/qlty-plugins](https://github.com/qltysh/qlty/tree/main/qlty-plugins) on GitHub — > check the plugin's `plugin.toml` and `README.md` for specifics. Each plugin consists of two components: 1. A plugin definition in a TOML configuration file 2. A results parser implemented in Rust Here is a simplified example plugin definition for [Ruff](https://github.com/astral-sh/ruff): ```toml plugin.toml for ruff lines theme={"system"} config_version = "0" [plugins.definitions.ruff] runtime = "python" package = "ruff" file_types = ["python"] version_command = "ruff version" config_files = ["ruff.toml"] issue_url_format = "https://docs.astral.sh/ruff/rules/${rule}" [plugins.definitions.ruff.drivers.lint] script = "ruff check --exit-zero --output-format sarif --output-file ${tmpfile} ${target}" success_codes = [0] output = "tmpfile" output_format = "sarif" batch = true ``` Gitleaks supports outputting results in the [SARIF](https://sarifweb.azurewebsites.net/) standard format, so a custom results parser is not needed. For tools which do not support SARIF, a results parser is implemented within the Qlty CLI and referenced by name. ## Auto-Formatters Auto-formatters are a special type of plugin because they *rewrite* files rather than outputting findings. Therefore, they do not require results parsers. Here is an example of a plugin definition for the [shfmt](https://github.com/mvdan/sh) auto-formatter: ```toml plugin.toml for shfmt lines theme={"system"} config_version = "0" [plugins.definitions.shfmt] package = "mvdan.cc/sh/v${major_version}/cmd/shfmt" runtime = "go" file_types = ["shell"] version_command = "shfmt --version" affects_cache = [".editorconfig"] [plugins.definitions.shfmt.drivers.format] script = "shfmt -w -s ${target}" success_codes = [0, 1] output = "rewrite" cache_results = true batch = true driver_type = "formatter" ``` Note the specification of `output = "rewrite"` and `driver_type = "formatter"`. # Runtimes Source: https://docs.qlty.sh/cli/concepts/runtimes For plugins which are not distributed as native binaries, Qlty supports a variety of Runtimes which are generally virtual machines: * Golang * Java * NodeJS * PHP * Python * Ruby Qlty is capable of installing packages using the package manager for each runtime (e.g. NPM for NodeJS). ## Runtime versions By default, Qlty will run the latest version of each runtime that it has been tested against as-needed in order to run plugins. It is also possible to specify the exact version of a Runtime to use with the following syntax: ```toml qlty.toml lines theme={"system"} # ... [runtimes.enabled] python = "3.10.13" # ... ``` With this configuration, Qlty will always use Python v3.10.13 when running PIP-based plugins. ## Optional runtime dependencies The PHP and Ruby runtimes have additional, optional system dependencies. Please see the [System Requirements](/cli/system-requirements#optional-dependencies) for additional information. # Sources Source: https://docs.qlty.sh/cli/concepts/sources Sources provide reusable Plugin definitions packaged as a Git repository. ## Adding Sources Sources are added to the `qlty.toml` configuration file in your repository using the following syntax: ```toml qlty.toml lines theme={"system"} [[source]] name = "default" default = true ``` Each Source declaration can point to the `default` source that comes bundled with the cli or an external repository with either a `tag` or a `branch`. If you target a tag, Qlty will fetch and checkout that tag when it first runs, and will never try to update it. If you target a branch, Qlty will check for updates to the named branch each time it runs. ```toml qlty.toml lines theme={"system"} [[source]] name = "custom" repository = "https://github.com/example/qlty-plugins.git" tag = "v1.2.3" # OR # branch = "main" ``` ## Default Source Qlty maintains a default source with linters, formatters, and security scanners which is automaticaly added to `qlty.toml` when initializing a new project: ```toml qlty.toml lines theme={"system"} # ... [[source]] name = "default" default = true # ... ``` ## Custom Sources You are not limited to the default source provided by Qlty. You can create your own custom Sources and reuse them across multiple projects. To do this, simply create a public Git repository with the following structure: ```shell lines theme={"system"} your-source-repository/ └─ linters/ └─ [linter-name]/ └─ plugin.toml ``` # Debugging Source: https://docs.qlty.sh/cli/debugging ## Plugin errors A plugin error indicates that a plugin exited with a status code that is interpretted as an error. This can occur for a number of different reasons. For example, some linters will crash if they attempt to analyze files with invalid syntax. > [!NOTE] > > Some linters exit with a non-zero code when they find issues. Qlty treats these exit codes as > *success* to differentiate the case where a plugin ran successfully identified issues vs. a > crash or unexpected failure. ### Verbose and debug output Typically the first step to investigating a plugin error is to re-run the plugin with verbose or debug output enabled. Here is an example: ```sh lines theme={"system"} qlty check --all --verbose --debug --filter=stylelint ``` The `--debug` option will increase the amount of detail in the logs going to `.qlty/logs/qlty-cli.*`. You can tail this log as you run the CLI to watch for issues with `tail -f .qlty/logs/qlty-cli.*`. The `--verbose` option will cause the CLI to print a summary of every invocation (execution) of the plugin from the run. The full details of each invocation are recorded in an output file saved to the `.qlty/out/` directory. Here is an example: ```yaml maxLines=10 lines theme={"system"} qlty_cli_version: 0.319.0 invocation_id: LaW4ba plugin_name: markdownlint driver_name: lint verb: Check config_files: - /Users/username/p/qltysh/qlty/.qlty/configs/.markdownlint.json - /Users/username/p/qltysh/qlty/.markdownlint.json script: sh -c "markdownlint --json fern-public/fern/docs/pages/cloud/additional-information/faq.mdx" env: PATH: /Users/username/.qlty/cache/tools/markdownlint/0.41.0-a8b86ee94758/node_modules/.bin:/Users/username/.qlty/cache/tools/node/19.6.0-cac67db15d71/bin:/Users/username/.qlty/cache/tools/node/19.6.0-cac67db15d71:/Users/username/.qlty/cache/tools/node/19.6.0-cac67db15d71/bin:/Users/username/.qlty/cache/tools/node/19.6.0-cac67db15d71:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin HOME: /Users/username NODE_PATH: /Users/username/.qlty/cache/tools/markdownlint/0.41.0-a8b86ee94758/node_modules cwd: /Users/username/p/qltysh/qlty duration_secs: 0.187106333 exit_result: Success exit_code: 1 stdout: "" stderr: | [ { "fileName": "fern-public/fern/docs/pages/cloud/additional-information/faq.mdx", "lineNumber": 5, "ruleNames": [ "MD041", "first-line-heading", "first-line-h1" ], "ruleDescription": "First line in a file should be a top-level heading", "ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md041.md", "errorDetail": null, "errorContext": "## Can I use Qlty without the ...", "errorRange": null, "fixInfo": null } ] tmpfile_path: null tmpfile_contents: null parser_error: null ``` From this file you can see the exact command that was run, the environment variables that were set, and the output that was produced. If any errors occurred, they will be included. ### `Could not find "[package-name]"` (Missing plugin extension) A common error is that a plugin may be missing an extension references in its configuration. For example: ``` Lint error stylelint: Exited with code 78 .qlty/out/invoke-tPeFXQ.yaml Error: Could not find "@blueprintjs/stylelint-plugin". Do you need a `configBasedir`? at module.exports (/Users/username/.qlty/cache/tools/stylelint/14.6.1-a7e99b04b5e3/node_modules/stylelint/lib/utils/configurationError.js:11:49) at getModulePath (/Users/username/.qlty/cache/tools/stylelint/14.6.1-a7e99b04b5e3/node_modules/stylelint/lib/utils/getModulePath.js:28:9) at /Users/username/.qlty/cache/tools/stylelint/14.6.1-a7e99b04b5e3/node_modules/stylelint/lib/augmentConfig.js:153:60 at Array.map () at absolutizePaths (/Users/username/.qlty/cache/tools/stylelint/14.6.1-a7e99b04b5e3/node_modules/stylelint/lib/augmentConfig.js:153:44) at Object.transform (/Users/username/.qlty/cache/tools/stylelint/14.6.1-a7e99b04b5e3/node_modules/stylelint/lib/augmentConfig.js:81:27) at runLoad (/Users/username/.qlty/cache/tools/stylelint/14.6.1-a7e99b04b5e3/node_modules/cosmiconfig/dist/Explorer.js:104:49) at async cacheWrapper (/Users/username/.qlty/cache/tools/stylelint/14.6.1-a7e99b04b5e3/node_modules/cosmiconfig/dist/cacheWrapper.js:16:18) at async extendConfig (/Users/username/.qlty/cache/tools/stylelint/14.6.1-a7e99b04b5e3/node_modules/stylelint/lib/augmentConfig.js:201:24) at async augmentConfigBasic (/Users/username/.qlty/cache/tools/stylelint/14.6.1-a7e99b04b5e3/node_modules/stylelint/lib/augmentConfig.js:52:20) ``` This error indicates that the Stylelint plugin was unable to load `@blueprintjs/stylelint-plugin`. The reason that this would happen is because the Qlty CLI installs static analysis tools into sandboxes in order to create conssitent, reporducible results whereever it is run. When an erorr like this occurs, you will generally find that the references package (in this case, `@blueprintjs/stylelint-plugin`) is included in the project's `package.json` file. By default, we do not install the packages in the `package.json` file when we run analysis. There are a three ways to fix this: > **Option 1: Use the `extra_packages` option** > > Specify the `extra_packages` option for the plugin in `qlty.toml`. Any listed packages will be installed into the tool's sandbox making them available. Here is an example: > > ```toml lines theme={"system"} > [[plugin]] > name = "stylelint" > version = "14.16.1" > extra_packages = ["stylelint-config-standard-scss@11.0.0"] > ``` > > This tells Qlty to install `stylelint-config-standard-scss@11.0.0` into the sandbox for the `stylelint` plugin before running. This syntax works for simple cases and has the benefit of keeping the dependency declaration directly inline with the plugin configuration. > **Option 2: Point the `package_file` option at your existing package.json** > > This will cause Qlty to install all of the packages in the `package.json` file into the sandbox for the plugin. Here is an example: > > ```toml lines theme={"system"} > [[plugin]] > name = "stylelint" > version = "14.16.1" > package_file = "package.json" > ``` > > If you are using a lot of extensions for your static analysis tools, this is a good way to get up and running quickly. The primary disadvantage is that all of the dependencies need to be installed before static analysis can be run, which can slow things down. > **Option 3: Create a new package.json limited to static analysis tools** > > This allows you to install all the extensions you need quickly and can allow you to de-clutter your main `package.json` file. Here is an example: > > ```sh lines theme={"system"} > cd .qlty/configs > echo '{}' > package.json > npm install --save-dev stylelint-config-standard-scss > ``` > > ```toml lines theme={"system"} > [[plugin]] > name = "stylelint" > version = "14.16.1" > package_file = ".qlty/configs/package.json" > ``` You can read more about this at [linter extensions page](/cli/linter-extensions). ### `Could not find "[config file].[json]"` (Missing configuration file) If you have a static analysis configuration file that is not using one of the tool's standard configuration filenames, Qlty needs to know about it. Otherwise, you will see errors like this: ``` Error: Could not find "../../../../shared/stylelintrc.shared.json". Do you need a `configBasedir`? ``` The fix is to make the Qlty CLI aware of the configuration filename, in this case `stylelintrc.shared.json`. To do this, you need to override the *definition* of the Stylelint plugin to include all of the configuration file names you use in your project. For example, you can add this towards the top of your `.qlty/qlty.toml` file: ```toml lines theme={"system"} [plugins.definitions.stylelint] config_files = [ ".stylelintrc", ".stylelintrc.cjs", ".stylelintrc.js", ".stylelintrc.json", ".stylelintrc.yaml", ".stylelintrc.yml", "stylelintrc.shared.json", # Custom, shared configuration file ] ``` This will cause Qlty to ensure that all of those listed configuration files, including the custom, shared configuration file, are properly made available to the plugin. ## Plugin parser errors A parse error indicates that Qlty was unable to process the results output by the plugin. This can happen is a static analysis tool changes its output format. If you encounter a parse error with a plugin, please contact support for assistance. # Developing Plugins Source: https://docs.qlty.sh/cli/developing-plugins Qlty is built on an extensible plugin platform that makes it easy to integrate linters, formatters, and security scanners. We will eventually be opening the plugin system up completely so that you can add plugins yourself if you'd like. For now, while we refine our system, we are happy to handle everything for you. ## Requesting new plugins Our goal is to ensure you can run all of the static analysis you need a single, unified experience with Qlty. If there is a static analysis tool that you use which we do not currently support, please let us know. Typically, we can add support for a new plugin with one week. > [!NOTE] > > To ensure a high quality product experience, we avoid adding plugins for static analysis tools > that are no longer maintained. ## Customizing existing plugins Existing plugins can be customized via your project configuration file (`.qlty/qlty.toml`). Using this approach, you can modify things like: * File types to analyze * Installing additional packages during setup (e.g. ESLint plugins) * Customizing issue categories or levels * Customizing linter invocations * Caching * Batching Please contact us and we would be happy to help you with this. ## More information * [Available Plugins](/plugins) # Excluding Files and Folders Source: https://docs.qlty.sh/cli/excluding-files Qlty is Git aware and always excludes `.gitignore`'d files. Additionally, we provide multiple ways to exlcude files from analysis. ## Using `exclude_patterns` in qlty.toml Files and path patterns can also be excluded in your project configuration (`.qlty/qlty.toml`) using the `exclude_patterns` key at the top level. For example: ```toml lines theme={"system"} # .. exclude_patterns = ["some/file.py", "**/fixtures/**"] # ... ``` Files that are excluded like this are not processed by any static analysis. > [!NOTE] > > `exclude_patterns` applies to static analysis only. To exclude files from **code coverage** > reporting, you'll need to configure exclusions within your local coverage tool where coverage > data is generated. See [Excluding Files from Coverage](/coverage/excluding-files) for details. ## See Also * [Ignoring Checks and Issues with Qlty CLI](/cli/ignoring-issues) * [Ignoring Checks and Issues with Qlty Cloud](/cloud/triaging-issues) # Frequently Asked Questions (FAQ) Source: https://docs.qlty.sh/cli/faq ## Why is Qlty not showing the specifics of formatting issues? Unlike linters, which are designed to output violations of rules, auto-formatters are instead simply rewrite your code on disk to adhere to match their defined standard. When Qlty analyzes your code, we run the auto-formatters in sandbox directory. This allows us to check if the auto-formatted result matches the current version of the file in you working directory, without overwriting it. If a change is detected in auto-formatters result, Qlty will emit an issue with the following description: > Incorrect formatting, autoformat by running `qlty fmt` No additional information is available so we cannot reference line numbes or specific formatting issues. The solution is to run the auto-formatter by running [`qlty fmt`](https://docs.qlty.sh/cli/commands/fmt) locally and commit the result. Additionally, by [integrating auto-formatters into your workflow](https://docs.qlty.sh/auto-formatting#integrating-auto-formatting-into-your-workflow), you can eliminate formatting issues before they make it to your PRs. # Git Hooks Source: https://docs.qlty.sh/cli/git-hooks Qlty can be integrated into git using git hooks to ensure: 1. code is formatted before committing (pre-commit hook) 2. code meets quality standards before pushes (pre-push hook) ## Installation Installation is easiest using the Qlty CLI. 1. First [Install Qlty](https://docs.qlty.sh/cli/quickstart). 2. Run: ```sh lines theme={"system"} qlty githooks install ``` See the [hook files](https://github.com/qltysh/qlty/tree/main/qlty-cli/src/commands/githooks) to understand what will be installed or to perform manual installation. ## Pre-commit The Git pre-commit hook runs `qlty fmt` on the files staged for the commit. ## Pre-push The Git pre-push hook will ensure that files are auto-formatted before pushing. If there are files that are formatted incorrectly, it will format them and generate a new commit. Due to the way Git works, when this occurs, you will need to run `git push` again. > [!NOTE] > > You can always run `git push --no-verify` to skip the pre-push hook. ## Keeping slow plugins out of git hooks Each hook tells Qlty which trigger is running. The pre-commit hook runs `qlty fmt --trigger pre-commit`, and the pre-push hook runs `qlty check --trigger pre-push`. A plugin runs on a trigger when its `triggers` list includes that trigger, or when it has no `triggers` list. See [Triggers](/cli/qlty-toml#triggers) for the trigger each context uses. There are two ways to keep a slow plugin out of your hooks: * **Limit the plugin's triggers** in `qlty.toml`. This works with the installed hooks, with your own hook scripts, and with [global hooks](#global-hooks). * **Skip the plugin** with `--skip` in a hook script for one repository. Pick one per plugin, not both. ### Limit the plugin's triggers In `qlty.toml`, give the plugin a `triggers` list without `pre-commit` or `pre-push`: ```toml .qlty/qlty.toml lines theme={"system"} [[plugin]] name = "brakeman" triggers = ["manual"] ``` With the hooks from `qlty githooks install`, that's all you need, because they pass `--trigger` for you. The plugin still runs when you run `qlty check` yourself and in Qlty Cloud analysis. To keep it running in the Qlty VS Code extension too, add `ide` to the list. > [!WARNING] > > Keep `manual` in the list. Qlty Cloud analysis runs plugins with the `manual` trigger, so a plugin without `manual` stops running there. If you write your own hook script, pass `--trigger` with the hook's name, as the installed hooks do, so `triggers` settings apply: ```sh .git/hooks/pre-push lines theme={"system"} #!/bin/sh qlty check \ --trigger pre-push \ --upstream-from-pre-push \ --no-formatters \ --skip-errored-plugins ``` ### Skip the plugin in one repository's hook In a hook script for a single repository, you can add `--skip` with the plugin's name: ```sh .git/hooks/pre-push lines theme={"system"} #!/bin/sh qlty check \ --trigger pre-push \ --upstream-from-pre-push \ --no-formatters \ --skip-errored-plugins \ --skip brakeman ``` `--skip` fails with `Plugin not found` when the plugin wouldn't run anyway: it isn't enabled, it's disabled, its `triggers` leave out the hook's trigger, or it has `skip_upstream = true` and the hook is pre-push. So don't use `--skip` in a hook that runs in more than one repository. Use `triggers` instead. See [`check`](/cli/commands/check) and [`fmt`](/cli/commands/fmt) for the `--trigger` and `--skip` flags. ## Global hooks A global hook runs in every repository on your machine. Git uses global hooks when `core.hooksPath` is set in your global Git config, for example with `git config --global core.hooksPath ~/.git-hooks`. To run Qlty from a global hook: * Call `qlty check` from your global hook script. When `core.hooksPath` is set, Git ignores each repository's `.git/hooks` directory, so hooks from `qlty githooks install` don't run. * Pass `--trigger pre-push` so `triggers` settings apply. * Keep slow plugins out with `triggers` in each repository's `qlty.toml`, not `--skip`. `--skip` fails in every repository that doesn't enable the plugin. * Skip repositories where Qlty isn't set up. There, `qlty check` exits with an error and blocks the push. ```sh ~/.git-hooks/pre-push lines theme={"system"} #!/bin/sh [ -f .qlty/qlty.toml ] || exit 0 qlty check \ --trigger pre-push \ --upstream-from-pre-push \ --no-formatters \ --skip-errored-plugins ``` # Global Options Source: https://docs.qlty.sh/cli/global-options This reference documents Qlty CLI v0.662.0. These options are available on every subcommand. ## Arguments > **--debug** > > Log with more information > **--no-upgrade-check** > > Do not check for updates > **-h, --help** > > Print help ## Environment Variables > **QLTY\_LOG** > > Control logging precisely with a [logging > directive](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives). Takes precedence over `--debug`. > > For example, to maximize logging from Qlty code set `QLTY_LOG=qlty=trace`. # Ignoring Issues with Qlty CLI Source: https://docs.qlty.sh/cli/ignoring-issues You can ignore issues in three ways: * **In your source code**, with `qlty-ignore` comments that silence a rule on a line, an indented block, a region, or a whole file. See [Silencing Issues](/cli/silencing-issues) for the syntax. * **With `[[exclude]]` rules** in `.qlty/qlty.toml`, which stop plugins from running on matching files. * **With `[[triage]]` rules** in `.qlty/qlty.toml`, which ignore issues that match plugins, rules, file patterns, and levels. ## Adding `[[exclude]]` rules in qlty.toml Qlty CLI also allows a simple way to exclude certain plugins from running on a set of files in your project configuration file (`.qlty/qlty.toml`). Each `[[exclude]]` block can specify conditions by plugins and file patterns. Qlty will avoid running the given plugins on files that match the given patterns or ignore any issues matching the plugins and file patterns. Examples: ```toml lines theme={"system"} # Exclude eslint from running on files in remix/app/components/ui/ [[exclude]] plugins = ["eslint"] file_patterns = ["remix/app/components/ui/**"] ``` ## Adding `[[triage]]` rules in qlty.toml Qlty CLI also allows a highly flexible way to suppress issues in your project configuration file (`.qlty/qlty.toml`). Each `[[triage]]` block can specify match conditions by plugins, rules, file globs, and levels. If an issue matches all the specified conditions, it will be ignored. Examples: ```toml lines theme={"system"} # Ignore the eslint react/prop-types check only in remix/app/components/ui/ [[triage]] match.rules = ["eslint:react/prop-types"] match.file_patterns = ["remix/app/components/ui/**"] set.ignored = true ``` ```toml lines theme={"system"} # Ignore all rubocop issues at "low" level [[triage]] match.plugins = ["rubocop"] match.levels = ["low"] set.ignored = true ``` ## Reviewing ignored issues Issues ignored with `qlty-ignore` comments or with rules in `.qlty/qlty.toml` are dropped during analysis. They are not reported by Qlty CLI and are not uploaded to Qlty Cloud, so they cannot be viewed in the Qlty web application. ## See Also * [Silencing Issues](/cli/silencing-issues) * [Excluding Files](/cli/excluding-files) * [Triaging Issues with Qlty Cloud](/cloud/triaging-issues) # Integrity Verification Source: https://docs.qlty.sh/cli/integrity-verification Qlty publishes cryptographic attestations for all CLI releases, allowing you to verify that the binary you downloaded was built by Qlty and hasn't been tampered with. These attestations are powered by [Sigstore](https://www.sigstore.dev/) and published as [GitHub artifact attestations](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds). ## How it works When we release a new version of the Qlty CLI, our GitHub Actions workflow: 1. Builds the CLI binaries for each supported platform 2. Generates a cryptographic attestation for each build artifact 3. Publishes the attestations to GitHub's attestation store These attestations cryptographically prove that the binary was built from our official repository using our CI/CD pipeline. ## Verifying the CLI You can verify any Qlty CLI release with the GitHub CLI (`gh`) before you install it. The check doesn't depend on your machine's certificate store, so it holds even when that store is out of date. > [!WARNING] > > Use `gh` 2.67.0 or later, signed in with `gh auth login`, even for public repositories. Older > versions can report success for an archive that has no attestation. Install `gh` from a source > that checks its own packages, such as Homebrew, winget, or a signed package repository. **Example (macOS Apple Silicon):** ```shell lines theme={"system"} VERSION=0.660.0 TARGET=aarch64-apple-darwin # Work in a new empty directory, so a failed step can't leave # files from an earlier run behind WORK="$(mktemp -d)" ARCHIVE="$WORK/qlty-$TARGET.tar.xz" # Install only if the download, the attestation check and the extraction # all succeed. This replaces the qlty on your PATH, or installs to # ~/.qlty/bin if you have none. if curl -fL "https://github.com/qltysh/qlty/releases/download/v$VERSION/qlty-$TARGET.tar.xz" -o "$ARCHIVE" && gh attestation verify "$ARCHIVE" --owner qltysh && tar -xJf "$ARCHIVE" -C "$WORK"; then DEST="$(dirname "$(command -v qlty || echo "$HOME/.qlty/bin/qlty")")" mkdir -p "$DEST" install -m 755 "$WORK/qlty-$TARGET/qlty" "$DEST/qlty" else echo "Download, attestation check or extraction failed. Not installing." >&2 fi # Confirm which qlty runs, and its version command -v qlty && qlty --version ``` If you installed to `~/.qlty/bin` for the first time, add it to your `PATH`. For other platforms, set `TARGET` to `x86_64-apple-darwin`, `x86_64-unknown-linux-gnu`, `aarch64-unknown-linux-gnu`, `x86_64-unknown-linux-musl` or `aarch64-unknown-linux-musl`. See all archives on [GitHub releases](https://github.com/qltysh/qlty/releases). **Example (Windows, PowerShell):** ```powershell lines theme={"system"} $Version = "0.660.0" $Zip = "qlty-x86_64-pc-windows-msvc.zip" # Work in a new empty directory, so a failed step can't leave # files from an earlier run behind $Work = New-Item -ItemType Directory -Path (Join-Path $env:TEMP ([guid]::NewGuid())) $Archive = Join-Path $Work $Zip Invoke-WebRequest -UseBasicParsing "https://github.com/qltysh/qlty/releases/download/v$Version/$Zip" -OutFile $Archive # Install only if the attestation verifies and the archive extracts. This # replaces the qlty.exe on your PATH, or installs to ~\.qlty\bin if you have none. gh attestation verify $Archive --owner qltysh if ($LASTEXITCODE -eq 0) { Expand-Archive $Archive -DestinationPath (Join-Path $Work "qlty") -ErrorAction Stop $Existing = Get-Command qlty -ErrorAction SilentlyContinue $Dest = if ($Existing) { Split-Path $Existing.Source } else { Join-Path $HOME ".qlty\bin" } New-Item -ItemType Directory -Force -Path $Dest | Out-Null Copy-Item (Join-Path $Work "qlty\qlty.exe") (Join-Path $Dest "qlty.exe") -Force -ErrorAction Stop if (-not $Existing) { $env:Path = "$Dest;$env:Path" } } else { Write-Error "Attestation verification failed. Not installing." } qlty --version ``` If you installed to `~\.qlty\bin` for the first time, the script adds it to `PATH` for the current session only. Add it to your user `PATH` to keep it. ## Checking an installed binary To check a `qlty` you already have, download and verify the archive for the version you installed, then compare the binaries. Set `VERSION` yourself rather than running `qlty --version`: if the binary was replaced, running it could expose your tokens. ```shell lines theme={"system"} VERSION=0.660.0 TARGET=aarch64-apple-darwin WORK="$(mktemp -d)" ARCHIVE="$WORK/qlty-$TARGET.tar.xz" if curl -fL "https://github.com/qltysh/qlty/releases/download/v$VERSION/qlty-$TARGET.tar.xz" -o "$ARCHIVE" && gh attestation verify "$ARCHIVE" --owner qltysh && tar -xJf "$ARCHIVE" -C "$WORK"; then shasum -a 256 "$WORK/qlty-$TARGET/qlty" "$(command -v qlty)" else echo "Download, attestation check or extraction failed. Nothing to compare." >&2 fi ``` If the two checksums differ, reinstall with the steps above, and rotate any Qlty tokens that machine could read. A `VERSION` that doesn't match the installed release also makes them differ, so check it first. ## Verifying upgrades `qlty upgrade --verify-attestations` downloads each release's archive and checks its attestation before installing it, on macOS and Linux. It needs `gh` 2.67.0 or later, signed in. From v0.662.0, the upgrade stops if the attestation can't be verified, and on Windows the command refuses and points to this page. Without the flag, `qlty upgrade` runs the installer script, which does not check attestations. See [`upgrade`](/cli/commands/upgrade). ## Verifying the Docker image Each platform image in `ghcr.io/qltysh/qlty` has its own attestation. The multi-platform tag does not, so verify a platform digest: ```shell lines theme={"system"} docker buildx imagetools inspect ghcr.io/qltysh/qlty:0.660.0 gh attestation verify oci://ghcr.io/qltysh/qlty@sha256: --owner qltysh ``` ## Successful verification A successful verification will display output similar to: ``` Loaded digest sha256:abc123... for file qlty-aarch64-apple-darwin.tar.xz Loaded 1 attestation from GitHub API ✓ Verification succeeded! ``` This confirms the binary was signed by GitHub Actions and built from the official Qlty repository. ## Learn more * [GitHub artifact attestations documentation](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds) * [Sigstore](https://www.sigstore.dev/) * [Qlty CLI releases](https://github.com/qltysh/qlty/releases) # Qlty CLI Internals Source: https://docs.qlty.sh/cli/internals ## Upstream Analysis > [!WARNING] > > This documentation is coming soon. In the meantime, please contact us and we can help! ## Reproducibility > [!WARNING] > > This documentation is coming soon. In the meantime, please contact us and we can help! ## Performance ### Caching > [!WARNING] > > This documentation is coming soon. In the meantime, please contact us and we can help! ### CPU Utilization > [!WARNING] > > This documentation is coming soon. In the meantime, please contact us and we can help! ## Configuration Merging > [!WARNING] > > This documentation is coming soon. In the meantime, please contact us and we can help! # Linter Extensions Source: https://docs.qlty.sh/cli/linter-extensions Linter extensions are additional packages or plugins that extend the functionality of base linter tools that Qlty uses. Depending on the linter, extensions can add: * Additional rule sets * Custom rules * Language support * Framework-specific checks * Additional parsers For example, ESLint has numerous plugins like `eslint-plugin-react`, `eslint-plugin-security`, and `eslint-plugin-jest` that add specialized rules for React development, security checks, and Jest testing, respectively. ## Supported Package Managers Qlty supports linter extensions through the following package managers: * **NPM** (Node.js) - For JavaScript/TypeScript tools like ESLint, Stylelint, etc. * **RubyGems** (Ruby) - For Ruby tools like RuboCop, Standard, etc. * **PIP** (Python) - For Python tools like Ruff, Pylint, Bandit, etc. * **Composer** (PHP) - For PHP tools like PHP\_CodeSniffer, PHPStan, etc. ## Managing linter extensions Qlty provides two mutually exclusive ways to configure linter extensions in your `qlty.toml` file: `extra_packages` and `package_file`. ### `extra_packages` The `extra_packages` property allows you to explicitly list additional packages that should be installed alongside the main linter package (including their versions). ```toml qlty.toml lines theme={"system"} [[plugin]] name = "eslint" version = "8.57.0" extra_packages = [ "eslint-plugin-react@7.33.2", "eslint-plugin-jest@27.6.0" ] ``` This works best when your project contains a very limited set of extra packages (1-2), but does not scale well for moderate to complex projects. **Pros:** * Simple, direct specification * Version pinning * Works without existing package files **Cons:** * Duplicates existing dependency management (e.g. package.json) * May diverge from project dependencies * Supports external packages only (not, e.g. in Project packages) ### `package_file` The `package_file` property allows you to reference a package manager file (like `package.json` or `Gemfile`) to manage dependencies. Depending on your use case, you can point the `package_file` either at your project's main package file or at a specific file that contains the linter-related packages. ```toml Project package file lines theme={"system"} [[plugin]] name = "eslint" version = "8.57.0" package_file = "package.json" ``` ```toml Linter package file lines theme={"system"} [[plugin]] name = "eslint" version = "8.57.0" package_file = ".qlty/configs/package.json" ``` **Pros:** * Take advantage of package manager's dependency resolution * Consistent with project dependencies (if pointing to the main package file) **Cons:** * Project's main package file contains many dependencies #### Unified or Linter-Specific Package File When using the `package_file` property, you can specify either the Project's standard package file, or create a new one with just linter-related dependencies. Which should you choose? Some considerations: * In some cases, [limitations](#limitations) may prevent a Project from using the project's primary package file. In these cases, using a separate package file is the only option, but usually works well. * For compatible package files, pointing qlty at your project's main package file results in qlty installing all of your projects dependencies, increasing build time. You can use [package\_filters](#package_filters) to limit these, but package filters cannot honor lock files * Reducing dependency duplication, so that all linter dependencies only exist in this new package file may require additional work. For example, if using standalone linters, in addition to qlty, you may need to update these tools to point at the new package file. #### `package_filters` When using `package_file`, you can use `package_filters` to selectively include only specific packages from the package file. This will cause Qlty to *filter* the packages in the package file and only install the ones that match the filters. This is most useful when you are pointing the `package_file` directive to your project's main package file, and you want to install only the linter-related packages. This can be used to speed up the installation of linters. > [!WARNING] > > You can achieve the same goal as package\_filters by using a separate package file which only > contains linter dependencies. Because a separate package file's dependencies can be fully > resolved using a lock file, we prefer this option. ```toml qlty.toml lines theme={"system"} [[plugin]] name = "eslint" version = "8.57.0" package_file = "package.json" package_filters = ["eslint"] ``` The `package_filters` option can offer a performance speed up or workaround issues installing the app dependencies at the tradeoff of additional complexity. ## Lock files Package lock files (like `package-lock.json`, `Gemfile.lock`, `yarn.lock`) can impact how Qlty installs and manages linter extensions: * When using `package_file`, Qlty respects the locked versions for reliability * When using `package_file` with `package_filters`, the lock files are ignored * For `extra_packages`, lock files are not used and specific versions are installed directly ## Custom RuboCop cops Qlty supports using in-repository Rubocop custom cops - custom rules defined within your codebase, which are referenced in your `.rubocop.yml` config file. Names of any such related files need to be added to plugin config. Otherwise you may get an error like `cannot load such file -- /tmp/qlty/qEYkEfFX-rw/./path/to/local/file` ```qlty.toml lines theme={"system"} [[plugin]] name = rubocop config_files = ["custom_cop.rb"] # files names of custom configuration files, not paths ``` ## Limitations Qlty currently does not support: * **Private linter extensions** - Extensions from private Git repositories or private package registries that require authentication * **Git-based dependencies** - Extensions referenced directly as Git repositories * **Local file dependencies outside the repository** - Extensions referenced from paths outside the repository ## Troubleshooting 1. **Version conflicts** If you see errors like "Dependency conflict" or "Incompatible versions", try: * Aligning versions between your package file and extra\_packages * Using `package_filters` to selectively include compatible packages 2. **Missing extensions** If a linter reports missing plugins or rules: * Verify the extension is correctly specified in `extra_packages` or `package_file`. * Check for typos in package names. * Ensure compatible versions are specified. 3. **Slow performance** If linter installation becomes slow with extensions: * Use either `package_filters` to filter installations, or create a separate package file for linter-related packages. 4. **Configuration issues** If the linter can't find the extension configuration: * Ensure your configuration file correctly references the extensions. * Check that the extension is properly installed. # Project Config (qlty.toml) Source: https://docs.qlty.sh/cli/qlty-toml Project configuration stored in a `qlty.toml` file is used by both Qlty CLI and Qlty Cloud. We strongly recommend that this file is committed into Git version control. This file uses the [TOML](https://toml.io/en/) format and is located at `.qlty/qlty.toml` in your repository: ```text theme={"system"} your-git-repository/ ├── .qlty/ │ ├── ... other qlty files │ └── qlty.toml └── ... rest of your repository files ``` > [!NOTE] > > If you do not have a `.qlty/qlty.toml` file checked in to your repository, Qlty Cloud will > generate a new, temporary configuration file before running the analysis using `qlty init`. ## `qlty.toml` Specification Each field in the `qlty.toml` file corresponds to a specific configuration setting. Detailed descriptions of these settings are provided below. ### `config_version` The version of the `qlty.toml` configuration file format. Currently, all `config_version`s are `0`. We may use this field in the future to introduce breaking changes to the configuration file format. ### `sources` `sources` are defined at the top-level and specify repositories which contain plugin definitions. By convention, sources are placed at the top of the `qlty.toml` file. The default auto-generated configuration file will include a default source conveniently named `default`. You can add additional sources from other Git repositories and name them as you like. Below are the accepted properties to define a source: | Name | Description | | - | - | | `name` | A unique name for this source | | `default` | Set to `true` for the primary source (only one allowed) | | `repository` | The URL of the git repository | | `tag` | The tag to fetch from the repository (conflicts with `branch`) | | `branch` | The branch to fetch from the repository (conflicts with `tag`) | Follow the example below to add a new source: ```toml lines theme={"system"} [[source]] name = "example" repository = "https://github.com/example/example.git" branch = "main" ``` > [!WARNING] > > For each source, you can specify either a `tag` or a `branch`, but not both. If you specify > both, the `tag` will be used. ### `exclude_patterns` Qlty is Git-aware and honors `.gitignore` files. The `exclude_patterns` setting allows you to specify additional directories and/or files that should be completely excluded from all Qlty activities, both from Qlty Cloud and Qlty CLI. This setting uses [glob syntax](https://en.wikipedia.org/wiki/Glob_\(programming\)) to match file and directory names. This setting is useful for excluding files that are not relevant for Qlty, such as generated code, build artifacts, temporary files, or third-party libraries. Below is an example of how to customize the `exclude_patterns` setting to fit your project: ```toml lines theme={"system"} exclude_patterns = [ "*.log", "**/*.min.js", "**/node_modules/**", "**/*.spec.js" ] ``` ### `test_patterns` The `test_patterns` setting allows you to specify directories and/or files that should considered automated tests run at build time rather than runtime application code. Qlty Cloud uses this information in order to provide higher quality analysis results. This setting uses [glob syntax](https://en.wikipedia.org/wiki/Glob_\(programming\)) to match file and directory names. Below is an example of how to customize the `test_patterns` setting to fit your project: ```toml lines theme={"system"} test_patterns = [ "**/test/**", "**/spec/**", "**/test_*.*", "**/spec_*.*", "**/*_test.*", "**/*_spec.*", ] ``` ### `smells` The `smells` setting defined at the top-level is used to configure the functioning of the `qlty smell` CLI command, which is employed by Qlty Cloud to identify code smells in your project. This allows you to customize the detection and management of various code quality smells. These settings apply for all supported programming languages, and can be customized further for each language using the `languages` setting. #### `smells.mode` The `mode` setting determines how Qlty Cloud handles detected code smells. Four modes are available: | Mode | Description | | - | - | | `block` | Code smells may fail the Qlty Gate (post them as pull request comments) | | `comment` (default) | Post comments on pull requests but never fail the Qlty Gate | | `monitor` | Analyze and report smells on Qlty Cloud but never post them to GitHub | | `disabled` | Smell detection will be disabled | #### `smells.[name].enabled` The `enabled` setting allows you to enable or disable the detection of specific code smells. By default, all smells are enabled, but you can selectively disable those that are not relevant to your project. Below is an example of how to enable or disable specific smells: ```toml lines theme={"system"} [smells.boolean_logic] enabled = true [smells.nested_control_flow] enabled = false ``` #### `smells.[name].threshold` The `smells.[name].threshold` setting allows you to fine-tune the parameters for identifying specific types of code smells. Below is a comprehensive list of all available smell settings and their default thresholds: | Smell Name | Threshold | Default | | - | - | - | | `boolean_logic` | Maximum number of boolean operators (such as `and` or `or`) in a single expression | 5 | | `nested_control_flow` | Maximum number of nested control flow statements | 5 | | `function_parameters` | Maximum number of function parameters | 5 | | `return_statements` | Maximum number of return statements in a function | 6 | | `file_complexity` | Maximum allowed complexity for a single file | 50 | | `function_complexity` | Maximum function complexity | 15 | | `identical_code` | Minimum number of duplicated lines for identical code to be flagged | 12 | | `similar_code` | Minimum number of duplicated lines for similar code to be flagged | 12 | #### `smells.duplication` The `smells.duplication` setting configures umbrella settings for duplicated code detection (*copypasta code*) that apply to both the `identical_code` and `similar_code` smells. | Setting Name | Description | Default | | - | - | - | | `nodes_threshold` | The minimum number of AST children nodes for a single node to be included in the duplication detection | 50 | | `filter_patterns` | Glob patterns to exclude from duplication checks | | To control the `enabled` and `threshold` settings for duplication, use `smells.identical_code` and `smells.similar_code` instead: ```toml lines theme={"system"} [smells.identical_code] enabled = true threshold = 20 [smells.similar_code] enabled = true threshold = 20 [smells.duplication] nodes_threshold = 30 ``` > [!NOTE] > > These settings apply to all programming languages. You can customize the duplication detection > settings for specific languages using the `language` setting. ### `language.[name]` The `language.[name]` setting allows you to customize various settings on a per-language basis, applicable to both Qlty Cloud and Qlty CLI. #### `language.[name].smells` This setting enables you to configure the detection and management of various code quality smells for a specific programming language. Below is an example of how to customize the detection of code smells for a particular language: ```toml lines theme={"system"} [language.rust.smells] duplication.filter_patterns = ["(use_declaration _)"] duplication.nodes_threshold = 40 function_parameters.threshold = 6 function_complexity.threshold = 20 ``` Alternatively, you can use this equally valid [TOML](https://toml.io/en/) syntax: ```toml lines theme={"system"} [language.rust.smells.duplication] filter_patterns = ["(use_declaration _)"] nodes_threshold = 40 [language.rust.smells.function_parameters] threshold = 6 [language.rust.smells.function_complexity] threshold = 20 ``` ### `[[plugin]]` Each `[[plugin]]` entry must be defined at the top-level of the `qlty.toml` file, specifying the configuration for a specific plugin. You will need one `[[plugin]]` entry for each plugin you want to enable in your project. Below are the accepted properties for defining a `[[plugin]]` entry: | Name | Description | | - | - | | `name` | The plugin name, e.g., *eslint*, *rubocop*, etc | | `version` | The plugin version, following the version specification used by the plugin (this may vary across plugins) | | `extra_packages` | Some plugins, like the *stylelint* plugin, are usually used in combination with other packages such as `stylelint-config-standard-scss`. This setting allows you to define these additional packages. This is also commonly used by other plugins such as *eslint* and *rubocop* | | `package_file` | This setting is only relevant to some plugins, like *eslint*, that heavily depend on external files. It specifies where a certain package file is located. For *eslint*, you may want to indicate the location of your `package.json` | | `package_filters` | This setting is only relevant when package\_file is specified, it is a list of strings, if a package in the package\_file has a name containing a filter, it is filtered out and the rest are removed from package file, so that only relevant packages can be installed. | | `drivers` | List of drivers to activate for the plugin, if not specified all drivers are activated. | | `config_files` | List of file names (not paths), that contain configuration information needed to run the plugin, for example custom cop files for rubocop. | | `affects_cache` | List of file names (not paths), changing which can affect the cache of existing issues for a plugin. | | `mode` | Enum with the values: `block`, `comment`, `monitor`, `disabled`. - `block`: sends red statuses on Github - `comment`: only sends comments - `monitor`: just records the issues - `disabled`: disables the plugin | | `triggers` | List of triggers the plugin runs on: `manual`, `ide`, `agent`, `pre-commit`, `pre-push`, `build`. With no list, the plugin runs on every trigger. With a list, it runs only on the listed triggers. See [Triggers](#triggers). | | `skip_upstream` | Whether the plugin should run against the upstream or not. The default is `false` | | `prefix` | Run the plugin in a specific subdirectory of the project root, the plugin's targets and config files are limited to that subdirectory only. Useful for monorepo setups, as same plugin can be specified with multiple prefixes. | Follow the example below to customize the execution of a plugin: ```toml lines theme={"system"} [[plugin]] name = "stylelint" version = "15.10.3" extra_packages = ["stylelint-config-standard-scss@11.0.0"] ``` > [!NOTE] > > To get started with a new plugin, you can run `qlty plugins enable ` to automatically add the plugin to your `qlty.toml file`. #### Triggers Every `qlty check` and `qlty fmt` run has a trigger. A plugin with a `triggers` list runs only when the current trigger is in that list. | Context | Trigger | | - | - | | `qlty check` or `qlty fmt` run by hand | `manual` | | Qlty Cloud analysis | `manual` | | Pre-commit hook from `qlty githooks install` | `pre-commit` | | Pre-push hook from `qlty githooks install` | `pre-push` | | Qlty VS Code extension | `ide` | | Any `qlty check` or `qlty fmt` with `--trigger` | its value | `ide`, `agent`, and `build` are set only by passing `--trigger`. The VS Code extension passes `--trigger ide`. Nothing else Qlty runs passes `agent` or `build`, so use them from your own scripts, for example `--trigger build` in your CI. A plugin whose `triggers` list leaves out `manual` doesn't run in Qlty Cloud analysis. See [Keeping slow plugins out of git hooks](/cli/git-hooks#keeping-slow-plugins-out-of-git-hooks). ### `[[exclude]]` The `[[exclude]]` block allows you to declare rules to ignore certain issues in your project, applicable to both Qlty Cloud and Qlty CLI. Each `[[exclude]]` entry can specify conditions based on `plugins`, and `file patterns`. Qlty will avoid running the given plugins on files matching the patterns and ignore any issues that match them. Below are the accepted properties for defining an `[[exclude]]` entry: | Name | Description | | - | - | | `file_patterns ` | A list of glob patterns to match files that should be ignored. The default pattern is `*` which matches all files | | `plugins` | A list of *plugin* names. Issues reported by these plugins will be ignored | Below is an example of how to use the `[[exclude]]` setting: ```toml lines theme={"system"} # Exclude eslint from running on files in remix/app/components/ui/ [[exclude]] plugins = ["eslint"] file_patterns = ["react-app/app/components/ui/**"] ``` > [!NOTE] > > `[[exclude]]` blocks are evaluated sequentially, and the first match will be applied. ### `[[triage]]` The `[[triage]]` block allows you to modify certain properties of issues detected by Qlty. Each `[[triage]]` entry is broken down into two parts, `match` and `set`. Match can specify conditions based on `plugins`, `levels`, `rules`, and `file patterns` to determine which issues the triage apply to. If an issue matches all the specified conditions, its properties will be overridden by the values specified in the set part of the `[[triage]]` entry. Below are the properties for defining an `[[triage]]` entry, divided into *match.* and *set.*: #### Match | Name | Description | | - | - | | `plugins` | A list of plugin names. Issues reported by these plugins will be matched | | `rules` | A list of rule names. Issues reported by these rules will be matched. Rules are plugin specific | | `levels` | A list of levels. Issues reported at these levels will be matched. | | `file_patterns` | A list of glob patterns to match files whose issues should be matched. The default pattern is `*` which matches all files | #### Set | Name | Description | | - | - | | `level` | The new level for the issues that match the conditions. Possible values are `unspecified`, `fmt`, `low`, `medium`, `high` | | `category` | The new category for the issues that match the conditions. Accepted categories are: `bug`, `vulnerability`, `structure`, `duplication`, `security_hotspot`, `performance`, `documentation`, `type_check`, `style`, `anti_pattern` and `accessibility` | | `mode` | The new mode for the issues that match the conditions. Possible values are `block`, `comment`, `monitor`, `disabled` | | `ignored` | The issues are ignored if set to true. Accepts boolean values true or false | Below are examples of how to use the `[[triage]]` setting: ```toml lines theme={"system"} # Override the level of eslint react/prop-types issues in react-app/components/ui/ to "low" [[triage]] match.rules = ["eslint:react/prop-types"] match.file_patterns = ["react-app/components/ui/**"] set.level = "low" # Override the mode of all rubocop issues to "comment" [[triage]] match.plugins = ["rubocop"] set.mode = "comment" # Override the category of issues in node_modules directory to "dependency" [[triage]] match.file_patterns = ["**/node_modules/**"] set.category = "dependency" ``` > [!NOTE] > > `[[triage]]` blocks are evaluated sequentially, and the first match will be applied ## Glob Syntax Reference Following, a table that illustrates the most commonly used glob syntaxes accepted by Qlty: | Example Pattern | Matches | | - | - | | `foo.rb` | `foo.rb` at the top-level of the repository | | `*.rb` | all files at the top-level that end with `.rb` | | `**/foo.rb` | `foo.rb` anywhere in the repository | | `**/*.rb` | all files that end with `.rb` anywhere in the repository | | `**/test/**` | All folders named `test` at any level | ## Full Example The exact auto generated version of your `.qlty/qlty.toml` file will vary depending on the languages and frameworks used in your project. Below is a general example of how it may look like for a JavaScript project. ```toml lines theme={"system"} config_version = "0" # Required, must be the string "0" exclude_patterns = ["**/node_modules/**","**/vendor/**"] test_patterns = ["**/test/**", "**/spec/**"] [[source]] name = "default" default = true # The default source for plugin definitions [[plugin]] name = "actionlint" [[plugin]] name = "checkov" version = "3.2.49" [[plugin]] name = "markdownlint" version = "0.31.1" [[plugin]] name = "osv-scanner" [[plugin]] name = "prettier" version = "2.8.4" [[plugin]] name = "ripgrep" [[plugin]] name = "shellcheck" version = "0.9.0" [[plugin]] name = "shfmt" [[plugin]] name = "trivy" [[plugin]] name = "trufflehog" [[plugin]] name = "yamllint" ``` > [!NOTE] > > The list of auto-enabled plugins provided by the Qlty CLI is a recommended suggestion. You are > encouraged to add or remove plugins as needed. # Getting Started with the Qlty CLI Source: https://docs.qlty.sh/cli/quickstart ### 1. Install the CLI First, install our CLI onto your local machine: ```shell macOS & Linux lines theme={"system"} curl https://qlty.sh | sh ``` ```shell Windows lines theme={"system"} powershell -c "iwr https://qlty.sh | iex" ``` [curl https://qlty.sh | sh](https://demo.arcade.software/pdnImPNfyJblLkMTw5o5?embed\&show_copy_link=true) Qlty CLI supports macOS and Linux on X64 and ARM64, with Windows support in development. > **Alternative: Installing with verification** > > We provide GitHub attestations powered by Sigstore that allow you to verify the authenticity of the Qlty CLI before installing it. The check uses the [GitHub CLI (`gh`)](https://cli.github.com/manual/installation) 2.67.0 or later and doesn't depend on your machine's certificate store. > > Follow the steps in [Integrity Verification](/cli/integrity-verification) to download a release, verify it and install it. ### 2. Initialize your repository From your Git repository, run: ```shell bash lines theme={"system"} qlty init ``` [qlty init](https://demo.arcade.software/wIIO4wY9U47bKAij79rG?embed\&show_copy_link=true) This will generate a baseline configuration based on the file types within your project and store it as `.qlty/qlty.toml` in your repository. You can find more plugins with `qlty plugins list` and enable them with `qlty plugins enable [plugin]`. ### 3. Identify code smells and review quality metrics Check the code quality (for [supported programming languages](/languages)): ```bash Scan for code smells like duplication lines theme={"system"} qlty smells --all ``` ```bash Review a summary of quality metrics lines theme={"system"} qlty metrics --all --max-depth=2 --sort complexity --limit 10 ``` [qlty smells remix/app/.server/jobs](https://demo.arcade.software/NHZHtbmkgrJxpbuJOb4E?embed\&show_copy_link=true) ### 4. Lint your project ```bash Run linters on changed files on your current branch lines theme={"system"} qlty check ``` [qlty check remix/app/.server/jobs](https://demo.arcade.software/jj69R7wlgRGgEL6urQJr?embed\&show_copy_link=true) ```bash Run linters on all files lines theme={"system"} qlty check --all ``` ```bash Run only the shellcheck linter on all files lines theme={"system"} qlty check --all --filter=shellcheck ``` ```bash Run linters on the web/ folder lines theme={"system"} qlty check web/ ``` ### 5. Auto-format your code ```bash Auto-format changed files on your current branch lines theme={"system"} qlty fmt ``` [Arcade Flow (Thu Jul 11 2024)](https://demo.arcade.software/QXbWdDfpOFn67JHQuNE3?embed\&show_copy_link=true) ```bash Auto-format files in a directory lines theme={"system"} qlty fmt web/ ``` ## Getting help * **Learn more:** Run `qlty` for a summary of the most commonly used commands and `qlty --help` for a full list. * Appending `--help` to any command will provide detailed information about that command. * **Join the community:** [Chat with us](https://qlty.sh/discord) on Discord * **Get community support:** [Open an issue or discussion](https://github.com/qltysh/codeclimate/issues/new/choose) on GitHub ## Next steps * [Exclude irrelevant files](/cli/excluding-files) in your repository * Refer to the [Analysis Configuration](/cli/analysis-configuration) guide * Explore the 40+ linters and security scanners [available as plugins](/plugins) # Radarlint Configuration Source: https://docs.qlty.sh/cli/radarlint-configuration Radarlint is a static analysis tool that brings open source SonarQube-style analysis to Qlty CLI. It provides linting and security scanning capabilities for multiple languages including Java, Kotlin, Python, PHP, and Go. > [!NOTE] > > Radarlint and Qlty Software is not affiliated with SonarQube or SonarSource. ## Overview Radarlint wraps open source SonarLint analyzers to provide: * Code quality checks based on SonarQube rules * Security vulnerability detection (SAST) * Configurable rule sets per language * Pass-through support for Sonar analyzer properties ## Configuration File Radarlint supports configuration via a `radarlint.properties` file placed in your project root. This file allows you to control both Sonar analyzer properties and individual rule toggles. ### File Location The configuration file should be placed at the root of your repository: ``` your-project/ ├── radarlint.properties ├── src/ │ └── ... ``` ## Property Types There are two main types of properties you can configure: ### Sonar Properties Standard SonarQube properties are passed directly to the underlying Sonar analyzers. These properties must start with `sonar.` to be recognized. Common Sonar properties include: | Property | Description | Example | | - | - | - | | `sonar.java.source` | Java source version | `17` | | `sonar.java.target` | Java target version | `17` | | `sonar.python.version` | Python version | `3.11` | | `sonar.go.exclusions` | Files to exclude for Go | `**/*_test.go` | **Example:** ```properties lines theme={"system"} sonar.java.source=17 sonar.java.target=17 sonar.python.version=3.11 ``` ### Rule Properties Rule properties control the enabling or disabling of specific rules. They follow the format: ``` radarlint.rules..= ``` Where: * ``: The language identifier (e.g., `java`, `kotlin`, `python`, `php`, `go`) * ``: The Sonar rule identifier (e.g., `S1110`, `S2196`) * Value: Must be exactly `true` or `false` (case-sensitive) **Example:** ```properties lines theme={"system"} radarlint.rules.java.S1110=true radarlint.rules.java.S2196=false radarlint.rules.python.S5754=false radarlint.rules.kotlin.S6530=true ``` This configuration: * Enables rule `java:S1110` (redundant parentheses) * Disables rule `java:S2196` (equals method override) * Disables rule `python:S5754` * Enables rule `kotlin:S6530` ## Finding Rule Keys To find the rule key for a specific issue: 1. Run `qlty check` to see issues with their rule identifiers 2. The rule key appears in the format `language:SnnNN` (e.g., `java:S1110`) 3. Use the rule number (e.g., `S1110`) in your configuration You can also browse the [SonarQube Rules](https://rules.sonarsource.com/) documentation to find rules by category or keyword. ## Complete Example Here's a complete `radarlint.properties` file: ```properties lines theme={"system"} # Java configuration sonar.java.source=17 sonar.java.target=17 # Python configuration sonar.python.version=3.11 # Rule overrides - Java radarlint.rules.java.S1110=true radarlint.rules.java.S2196=false radarlint.rules.java.S1135=false # Rule overrides - Kotlin radarlint.rules.kotlin.S6530=true # Rule overrides - Python radarlint.rules.python.S5754=false ``` ## Enabling Radarlint in Qlty To use radarlint with Qlty CLI, enable the appropriate plugin in your `qlty.toml`: ```toml lines theme={"system"} [[plugin]] name = "radarlint-java" [[plugin]] name = "radarlint-kotlin" [[plugin]] name = "radarlint-python" ``` Or enable via the CLI: ```bash lines theme={"system"} qlty plugins enable radarlint-java qlty plugins enable radarlint-kotlin ``` ## Property Parsing Rules Understanding how radarlint parses properties helps avoid configuration issues: * Properties not starting with `sonar.` or `radarlint.rules.` are silently ignored * Rule property values must be exactly `true` or `false` (case-sensitive) * Invalid rule values (e.g., `yes`, `1`, `TRUE`) are ignored * If `radarlint.properties` is missing, radarlint uses default settings * Empty lines and lines starting with `#` are treated as comments ## Troubleshooting ### Rules Not Being Applied If your rule configuration isn't taking effect: 1. Verify the properties file is named exactly `radarlint.properties` 2. Check that rule keys match the format `radarlint.rules..` 3. Ensure values are lowercase `true` or `false` 4. Confirm the rule key exists for your language version ### Analyzer Errors If you see errors related to language version mismatches: 1. Set the appropriate `sonar..source` or `sonar..version` property 2. Ensure your project files are compatible with the specified version ### Viewing Applied Configuration Run Qlty in debug mode to see configuration details: ```bash lines theme={"system"} qlty check --debug ``` ## See Also * [Available Plugins](/plugins) - List of all Qlty plugins including radarlint variants * [Analysis Configuration](/cli/analysis-configuration) - General Qlty configuration * [Ignoring Checks and Issues](/cli/ignoring-issues) - How to ignore specific issues # Shared Analysis Configuration Source: https://docs.qlty.sh/cli/shared-analysis-configuration This document outlines the capabilities available in Qlty CLI and Qlty Cloud to support sharing of analysis configuration across multiple repositories within a single workspace. # Goals * Simplify the set up and maintenance of static analysis configuration across a large number of GitHub repositories * Provide partial or full standardization of static analysis configuration for the organization # Custom Sources The primary method of sharing analysis configuration across multiple repositories is through defining a custom Source. A Source is a Git repository that stores version controlled static analysis configuration settings which can be re-used by other repositories. Custom Sources were designed to replace the delegated configuration feature of Code Climate Quality while adding new capabilities. ## Features of Custom Sources * Create and share new, custom Plugin Definitions * *Example:* Define a custom plugin to check that all `package.json` files specify an acceptable `license` value * Customize out-of-the-box Plugin Definitions * *Example*: Override the default definition of the Prettier auto-formatter to avoid rewriting `*.mdx` files * Share maintainability analysis settings * *Example:* Increase the complexity threshold for the "High Function Complexity" code smell * *Example:* Add a code filter to exclude common boilerplate from an internally developed framework from duplication detection * Share file path exclusions * *Example:* Exclude all files matching `**/our_generator/**` * Share issue triage rules * *Example:* Downgrade the `level` of issues found by Trivy in the `sandbox/**` folder to `low` * Automatically enable plugins * *Example:* Always run the Shellcheck for any shell scripts in all repositories * Share linter configuration files * *Example:* Provide a base `rubocop.yml` configuration that can be extended for each project ## Advantages of Custom Sources * Settings provided by the Source can be further customized with the Project's `qlty.toml` configuration file (layered configuration) * Sources can be declared as pinned (with Git tags) or floating to a branch * Custom sources work on Qlty CLI and Qlty Cloud ## Example To use a Custom Source, each repository would declare it from the `.qlty/qlty.toml` file: ```toml lines theme={"system"} config_version = "0" # First, use the built-in Qlty source [[source]] name = "default" default = true # Customize further with the organization's custom source [[source]] name = "AcmeCo" repository = "https://github.com/AcmeCo/qlty-source" branch = "main" ``` **Why are both sources needed?** The `default` source provides all the built-in Qlty plugin definitions. Your custom source adds overrides and customizations on top. Without the `default` source, Qlty wouldn't know how to run the standard plugins. To pin your source to a specific version instead of floating to a branch, use `tag`: ```toml lines theme={"system"} [[source]] name = "AcmeCo" repository = "https://github.com/AcmeCo/qlty-source" tag = "v1.0.0" ``` ## Source Repository Structure The custom Source is a regular Git repository which follows a conventional structure: ``` your-qlty-source/ ├── source.toml # Main configuration file ├── .eslintrc.js # Linter config files to share (optional) ├── rubocop.yml # └── plugins/ # Custom plugin definitions (optional) └── linters/ └── my-custom-plugin/ └── plugin.toml ``` * A `source.toml` file at the root of the repository provides settings * Plugins can be defined or modified in files matching the patterns `plugins/linters/*/plugin.toml` * Linter configuration files can be placed at the root to be shared with child repos via `exported_config_paths` ## Configuration Merging Notably, Qlty uses the same TOML configuration syntax in every configuration file. This allows for taking advantage of the same configuration options — from plugin declaration settings to tuning maintainability smells — in any `*.toml` file read by Qlty. Configuration is applied in the following order from lowest precedence to highest precedence: 1. `plugin.toml` files in Sources 2. `source.toml` file at the root of Sources 3. `qlty.toml` in the project As the final, merged configuration is assembled, the last setting wins. The full, merged configuration can be viewed as YAML by running `qlty config show`. ## Sharing Linter Configuration Files Linter plugins often use their own configuration files (e.g., `.eslintrc.js`, `rubocop.yml`, `.prettierrc`). You can share these files from your custom source repository so that all child repos use the same configuration. To share a linter configuration file: 1. Commit the linter configuration file to your custom source repository. 2. Within the `source.toml`, use the `exported_config_paths` property to specify which files should be copied to child repos at runtime. ```toml lines theme={"system"} [plugins.definitions.] exported_config_paths = [""] ``` > [!WARNING] > > `exported_config_paths` does not work inside `[[plugin]]`. It must be declared in `[plugins.definitions.]` or it will be silently ignored. **How it works:** When Qlty runs analysis on a child repo, it copies the files listed in `exported_config_paths` from your source repository into the child repo's working directory. The linter then finds and uses these configuration files as if they were committed directly to the child repo. **If `exported_config_paths` is not set**, config files in the source repo are NOT shared. The linter will use config files from the child repo if present, otherwise it falls back to its defaults. ### config\_files vs exported\_config\_paths These two properties work together but serve different purposes: | Property | Purpose | | - | - | | `config_files` | Tells the plugin which configuration files to look for when running | | `exported_config_paths` | Tells Qlty to copy these files from the source repo to the child repo | Example in `source.toml`: ```toml lines theme={"system"} # Enable the plugin and specify which config files it uses [[plugin]] name = "" config_files = [""] mode = "monitor" # Export the config files so child repos receive them [plugins.definitions.] exported_config_paths = [""] ``` You may place plugin configuration files anywhere within your custom source repo. The `exported_config_paths` must be relative to the location of your `source.toml`. ## Sharing Linter Extensions If a shared plugin configuration file utilizes [linter extensions](https://docs.qlty.sh/cli/linter-extensions), you'll need to define these using the `extra_packages` property within your `source.toml`. For example: ```toml lines theme={"system"} [[plugin]] name = "eslint" version = "8.57.0" extra_packages = [ "eslint-config-prettier@10.1.8", "eslint-plugin-prettier@5.5.3", "prettier@3.6.2" ] ``` ## Private Custom Sources Custom sources can be private repos, provided they are in the same GitHub Org and the user has installed the Qlty GitHub App. **Qlty Cloud:** HTTPS URLs work automatically. The GitHub App handles authentication. ```toml lines theme={"system"} [[source]] name = "AcmeCo" repository = "https://github.com/AcmeCo/qlty-source" branch = "main" ``` **Qlty CLI (local):** For private repos, use SSH URLs since the CLI doesn't have access to Qlty Cloud authentication: ```toml lines theme={"system"} [[source]] name = "AcmeCo" repository = "git@github.com:AcmeCo/qlty-source.git" branch = "main" ``` ## Complete Example Here's a complete working example of sharing configuration between repositories. ### Source Repository **`source.toml`:** ```toml lines theme={"system"} config_version = "0" [[source]] name = "default" default = true # Shared exclusions exclude_patterns = [ "**/tmp/**", "**/vendor/**", ] # Enable a plugin with shared config [[plugin]] name = "" config_files = [""] mode = "monitor" # Export the config file to child repos [plugins.definitions.] exported_config_paths = [""] ``` ### Child Repository **`.qlty/qlty.toml`:** ```toml lines theme={"system"} config_version = "0" [[source]] name = "default" default = true [[source]] name = "acme" repository = "https://github.com/AcmeCo/acme-qlty-source" branch = "main" ``` The child repository does not need its own linter configuration files — they will be inherited from the source repository when Qlty runs. # Silencing Issues Source: https://docs.qlty.sh/cli/silencing-issues Qlty supports a universal inline code comment syntax to silence issues generated during analysis. This feature is supported both locally in Qlty CLI and remotely in Qlty Cloud. ## Introducing the `qlty-ignore` Directive > [!NOTE] > > We use the C style `// comment` format in many of our examples, but rest assured that the ignore > directive can be used in any comment block using any language supported comment syntax. The `qlty-ignore` comment directive can be added to a comment on or before the an offending line of code to ignore any issues generated during analysis. Each directive line can contain one or more rule specifiers that will either ignore or unignore a rule. Each rule specifier can either apply to the next line, or be toggled on until it is turned off by a following directive. More details on the rule specifier syntax are provided later. ## Basic Usage To silence an issue generated in the following variable declaration, you can use the following comment syntax: ```js lines theme={"system"} // qlty-ignore: eslint:camelcase var my_variable = 42; // This line will no longer generate an issue ``` > [!TIP] > > When specifying an individual rule, make sure to provide the fully qualified rule name as listed > by Qlty results. In the above example, we ignore the `camelcase` rule from the `eslint` tool as > `eslint:camelcase`. This will ignore one ESLint rule (`camelcase`), but we did not silence the `no-var` rule. To silence both, we have a few different options: ### Multiple Rules in a Single Directive The ignore directive supports a comma or space delimited set of rules to ignore which we can use to specify multiple: ```js lines theme={"system"} // qlty-ignore: eslint:camelcase, eslint:no-var var my_variable = 42; ``` ### Adjacent Directive Lines are Additive We can provide multiple adjacent `qlty-ignore` directive lines each specifying a separate rule to ignore: ```js lines theme={"system"} /** * qlty-ignore: eslint:camelcase * qlty-ignore: eslint:no-var */ var my_variable = 42; ``` > [!NOTE] > > We used the block style `/* */` comment syntax here for illustration purposes. Any set of > adjacent comment lines would work. Rules will only apply to the next matching line of non-commented code (whitespace lines are ignored). ### Ignoring All Rules From a Tool Finally, we can ignore all eslint rules by just providing the tool name as the rule specifier: ```js lines theme={"system"} // qlty-ignore: eslint var my_variable = 42; ``` ### Same-Line comments If the language supports it, you can also place the ignore directive on the same line as the offending code: ```js lines theme={"system"} var my_variable = 42; // qlty-ignore: eslint:camelcase ``` ### Long-Form Directive Syntax In addition to the initial basic comment syntax, the `qlty-ignore` directive line can also be adjusted to support the addition of a helpful documentation comment to the ignore for developers to understand why the ignore was added. To add a comment to the ignore directive, use the following syntax: ```js lines theme={"system"} // qlty-ignore(eslint:camelcase): public API cannot be renamed. export const my_variable = 42; ``` ## Indented Blocks and Regions ### Silencing an Indented Block (Implicit Region) By default, a rule in a directive will apply to the next line and all subsequently indented lines of code. This indentation can be the continuation of a single statement or the grouping of an entire language construct like an if block, for loop, or even function declaration. In other words, for most formatted languages, applying the directive to a statement will silence all issues up until the end of the block. This is known as an "implicit region". Consider the following if statement: ```python lines theme={"system"} # qlty-ignore: pylint:line-too-long if some_very_long_condition_that_is_true: print("...Very long string...") # issue is also ignored on this line ``` Because the directive is applied to the `if` statement, the issue is also ignored on the subsequent line as part of the matching block. In order to opt out of this indentation behavior, you can use the `>` prefix to enforce the rule to only apply to the next line: ```python lines theme={"system"} # qlty-ignore: >pylint:line-too-long if some_very_long_condition_that_is_true: print("...Very long string...") # issue is not ignored on this line ``` > [!TIP] > > Use the `>` rule specifier prefix to silence a rule on the next line only instead of the rest of > the indented block. ### Silencing a Region or an Entire File To silence a rule for an entire file or a region of code, you can use the `+` prefix to begin a silenced region and the `-` prefix to end it. This can be useful for silencing rules for an entire file or for a large block of code. For example: ```python lines theme={"system"} # qlty-ignore: +pylint:unused-argument def my_function(unused_arg): pass def other_function(unused_arg): pass # qlty-ignore: -pylint:unused-argument # issue is not silenced on this line def my_function(unused_arg): pass ``` If you want to silence an entire file, simply place a `qlty-ignore: +rule` directive at the top of a file with no matching `-rule` directive: ```rust lines theme={"system"} // qlty-ignore: +clippy fn main() { let x = 42; } // ... remaining file contents ... ``` ### Unsilencing a Line in a Silenced Region If your language supports same line comments, you can unsilence a rule for a single line within a silenced region by using the `-rule` in a same line `qlty-ignore` directive comment: ```rust lines theme={"system"} // qlty-ignore(clippy): silence _almost_ all lint issues in this function fn main() { let x = 42; // qlty-ignore(-clippy): except we don't silence this one let y = 43; // this issue is silenced again } ``` > [!NOTE] > > This mechanism can be applied to either implicit (indented blocks) or explicit regions defined > by `+rule` ... `-rule` pairs. ## Rule Specifier Syntax Details A rule specifier is made up of an optional prefix followed by a tool name and optional rule name qualifier (separated by `:` or `/`) as defined in the following grammar: ```abnf lines theme={"system"} rule-specifier = [prefix] tool-name [(":" / "/") rule-name] prefix = "+" / "-" / ">" tool-name = [a-zA-Z0-9_-]+ rule-name = [a-zA-Z0-9_-]+ ``` ### Prefixes The following prefixes can be used to control the behavior of the rule specifier: * `+`: Begins a region in which the rule is ignored until the matching `-rule` prefix or the end of the file, whichever comes first. * `-`: Ends a region in which the rule is ignored. This can also be applied to same line comments to temporarily unsilence an issue for a single line within a silenced region. * `>`: Apply the rule to the next line only, ignoring all indentation matching that would otherwise occur. When no prefix is used, the next non-comment / non-empty line and all subsequent indented lines will be ignored. # System Requirements Source: https://docs.qlty.sh/cli/system-requirements Qlty CLI supports the following systems: | Operating System | X86 | Arm64 | | - | - | - | | macOS Sonoma 14+ | ✅ | ✅ | | Linux 6.1+ | ✅ | ✅ | | Windows 11+ | ✅ | | ## Linux support Our official support targets the following Linux distributions: * Ubuntu 22.04 LTS+ * Debian Bookworm 12+ * Fedora 41+ The Qlty CLI works on other Linux distributions, however we do not provide support for them. ### GLIBC and MUSL Qlty CLI builds against both the GNU C Library (glibc) and the MUSL C library. When using GLIBC, we require a minimum version of glibc 2.38, which is available on most modern Linux distributions. Some older distributions, notably Amazon Linux 2023 (AL2023) do not meet this requirement. If you are using AL2023, you have the option to run the Qlty CLI in a Docker container. ## Optional Dependencies ### Ruby plugins Qlty installs a binary installation of the Ruby interpreter but may still need a few system dependencies to compile Ruby plugins via RubyGems. As a result, you may need to manually install a few extra dependencies before linting Ruby code with the Qlty CLI. On macOS, Qlty requires [Homebrew](https://brew.sh) to install Ruby and run Ruby-based plugins. You must also install the following dependencies: ```bash Install Ruby on macOS with Homebrew lines theme={"system"} brew install gmp openssl libyaml ``` On Linux, you should install a compiler toolchain such as `build-essential` on Ubuntu or similar. Currently we only support running Ruby plugins on glibc based distributions. > **Note:** Ubuntu 20.04 and earlier are no longer supported for Ruby binary installs, as upstream Ruby packages for these versions have been removed. > To ensure compatibility, please upgrade to a [supported Ubuntu version](https://github.com/ruby/ruby-builder/releases/tag/toolcache). On Windows, we rely on the system Ruby installation. You can install Ruby using your preferred package manager or using [RubyInstaller](https://rubyinstaller.org/) directly. ### PHP plugins To run plugins implemented in PHP, we require that PHP be installed on the system into a standard directory. On macOS systems, `php` can be installed with Homebrew: ```bash Install PHP on macOS with Homebrew lines theme={"system"} brew install php ``` ## See Also * [Debugging](/cli/debugging) # Telemetry Source: https://docs.qlty.sh/cli/telemetry Qlty collects usage analytics which we use to help improve the CLI. For example, this usage data helps us find and fix issues, like performance issues and bugs, as well as to prioritize new features. This page explains what data we collect and why we collect it. Telemetry data **never includes your source code** or identifiers (e.g. filenames) from your repository. ## Types of telemetry data Qlty CLI collects two types of telemetry data: 1. **Crash reports**: When the CLI crashes, it sends a report to Qlty. This information is used to understand why the CLI crashed and the changes that we need to make to prevent future crashes. 2. **Usage analytics**: The CLI sends usage analytics to Qlty. This information is used for product improvements. ## Example analytics event Here is an example of an analytics event that the CLI sends to Qlty: ```json lines theme={"system"} { "type": "track", "event": "Command Run", "properties": { "Subcommand": "smells", "Command": "qlty smells --debug VALUE", "Duration MS": 833, "Repository": "a8f97a11fe29de4f636340ae2485e0a5", "Success": "true", "Exit Code": 0, "Failed": "false" }, "timestamp": "2024-11-17T01:38:43.120696Z", "context": { "locale": "en-US", "os": { "name": "macos" }, "device": { "type": "aarch64" }, "app": { "name": "qlty", "version": "0.422.0", "build": "(1f77afa)" } }, "anonymousId": "de38bf69f6249b6228d81223f9885504", "messageId": "fea07bfb-3cce-4cf0-bec1-eecf6e5c1896" } ``` ## Can I disable telemetry? Yes. Telemetry can be disabled by setting the `QLTY_TELEMETRY` environment variable. The value of the environment variable can be set to `errors` or `off`. The default value is `all`. | QLTY\_TELEMETRY | Crash reports | Usage data | | - | - | - | | Unset or `all` | Yes | Yes | | `errors` | Yes | No | | `off` | No | No | > [!WARNING] > > We strongly recommend keeping crash reporting turned on. # Upgrading the CLI Source: https://docs.qlty.sh/cli/upgrading Most of the time, upgrading is one command. When a Qlty security advisory asks you to upgrade, take the more careful steps in [Upgrading after a security advisory](#upgrading-after-a-security-advisory). ## Upgrade ```shell macOS & Linux lines theme={"system"} qlty upgrade ``` ```shell Homebrew lines theme={"system"} brew upgrade qlty ``` ```shell Windows lines theme={"system"} qlty upgrade ``` Then confirm which `qlty` runs, and its version: ```shell lines theme={"system"} command -v qlty && qlty --version ``` On Windows, run `qlty upgrade` from Command Prompt or Windows PowerShell, not PowerShell 7 (`pwsh`). From `pwsh`, releases up to v0.662.0 report success but keep the old version. The VS Code extension runs this upgrade each time it starts, unless `qlty.autoUpdateCli` is `false`. ## Upgrading after a security advisory [Qlty security advisories](https://github.com/qltysh/qlty/security/advisories) name the first release that fixes each problem. Some problems affect the upgrade itself. `qlty upgrade`, the install script, and Homebrew download the new release with your machine's own tools: `curl`, `wget`, `git`, or PowerShell. Those tools trust your operating system's certificate store, so a flaw there can let an attacker swap the download. If the advisory gives steps for your platform, follow them. They take precedence over this page. Otherwise: 1. **Pause automatic upgrades.** In VS Code, set `qlty.autoUpdateCli` to `false`, so the extension does not upgrade before you finish. 2. **Update your operating system.** On macOS and Windows, install the latest OS updates. On Linux, update the certificate package, for example `sudo apt-get update && sudo apt-get install -y ca-certificates` on Debian and Ubuntu. 3. **Upgrade with verification.** From v0.662.0 on macOS and Linux, run `qlty upgrade --verify-attestations`. It installs the release only after it confirms Qlty's release pipeline built it, and needs the GitHub CLI (`gh`) 2.67.0 or later, signed in. On Windows, or on an older CLI, download and verify the release by hand with [Integrity Verification](/cli/integrity-verification). That check does not depend on your certificate store. 4. **Confirm the version.** Run `command -v qlty && qlty --version` and compare it with the fixed release in the advisory. 5. **Check plugin runtimes.** If the advisory names a plugin runtime, run `qlty config show` and look under `runtimes:`. See [Plugin runtimes](#plugin-runtimes) below. 6. **Turn automatic upgrades back on.** ## Plugin runtimes A new release can update the Node, Python, and Java the CLI downloads to run plugins. The CLI reinstalls plugins on the new runtime the next time they run. A version set under `[runtimes.enabled]` keeps that runtime on the version you set, whatever the CLI release. A plugin source can set it too. To see the version in effect, run `qlty config show` and look under `runtimes:`. If the section shows `enabled: {}`, the CLI uses its own versions. See [Runtimes](/cli/concepts/runtimes). ## CI * **GitHub Actions:** `qltysh/qlty-action` installs the CLI and verifies it. `@v2` picks up new action releases. * **Install script:** `curl https://qlty.sh | sh` installs the latest release, or the version in `QLTY_VERSION`. After a security advisory, update the certificate package in the job or image first. * **Docker layers:** if a Dockerfile installs the CLI in a cached layer, change the version or build with `--no-cache` so the layer runs again. See [Continuous Integration](/cli/ci). # user.toml Source: https://docs.qlty.sh/cli/user-toml > [!WARNING] > > This documentation is coming soon. In the meantime, please contact us and we can help! # AI Autofixes Source: https://docs.qlty.sh/cloud/ai-autofixes ## Data Processing To use this feature, business customers must first opt-in by enabling the feature within Workspace Settings. When this feature is active, we will attempt to generate suggested code fixes for static analysis issues in your codebase. To do so, we will send the following data to OpenAI: * The path and content of the file where the issue was located * The details of the static analysis issue that was identified including the location and message This feature uses a large language model (LLM) from our subprocessor OpenAI. Data shared with OpenAI through use of this feature will not be used to train their models. ## Disabling the Feature This feature is disabled by default and requires an opt-in to enable. If you would like to disable this feature, you can do so in your Workspace Settings. ## Security Considerations AI-generated code fixes use large language models (LLMs) that construct prompts from user-controlled data, including file contents, file paths, and linter messages. This creates a potential risk of **indirect prompt injection**, where malicious content embedded in analyzed code or linter output could influence the model's suggestions. ### Prompt Injection Risk When generating fixes, the LLM receives: * The file path and content being analyzed * The linter tool name and rule key * The issue message and code snippet If any of these inputs contain crafted instructions (for example, in code comments or manipulated linter reports), they could potentially influence the AI to generate unexpected or malicious code changes. ### Best Practices **Always review AI suggestions before applying.** Treat AI-generated fixes as suggestions requiring human review, not as trusted automated changes. Carefully inspect the proposed changes before accepting them. **Avoid automatic application in untrusted contexts.** When using the CLI with `--fix --ai`, fixes are applied automatically without human review. This bypasses the "human in the loop" protection that helps catch potentially malicious suggestions. We recommend: * Reviewing suggested fixes in Qlty Cloud before using auto-apply * Using version control to review all changes after auto-apply * **Not using `--fix --ai` in automated CI/CD pipelines** where fixes would be applied without human review **Understand what `--unsafe` allows.** By default, fixes for certain rules that are more likely to produce incorrect results are blocked. The `--unsafe` flag allows these fixes, increasing the importance of manual review. # AI Explanations Source: https://docs.qlty.sh/cloud/ai-explanations ## Data Processing To use this feature, business customers must first opt-in by enabling the feature within Workspace Settings. When this feature is enabled, users can click the "Explain This Issue" button to receive an explanation of a static analysis issue in their codebase. To generate an explanation, we send the following data to OpenAI: * An example of the issue including the full file path and message * A snippet of your code that contains the issue This feature uses a large language model (LLM) from our subprocessor OpenAI. Data shared with OpenAI through use of this feature will not be used to train their models. ## Disabling the Feature This feature is disabled by default and requires an opt-in to enable. If you would like to disable this feature, you can do so in your Workspace Settings. # Analysis Frequency Source: https://docs.qlty.sh/cloud/analysis-frequency Qlty periodically analyzes your default branch to keep your project's quality data up to date. This page explains how that scheduling works, how to adjust it, and how the data you see in Qlty relates to your repository's current state. ## How analysis frequency works Qlty automatically analyzes your default branch on a recurring schedule. The default frequency is **every 24 hours**, but you can adjust it to match your team's needs. The available frequency options are: | Frequency | Best for | | - | - | | 15 minutes | High-activity repositories where near-real-time data is important | | 30 minutes | Active repositories with frequent merges | | 1 hour | Moderately active repositories | | 3 hours | Standard development pace | | 6 hours | Lower-activity repositories | | 12 hours | Repositories with daily activity | | **24 hours** (default) | Most repositories | | 3 days | Low-activity repositories | | 7 days | Rarely changing repositories | | 1 month | Archived or minimal-activity repositories | Higher analysis frequencies consume more [analysis minutes](/cloud/billing/analysis-minutes). ## Changing analysis frequency To change how often Qlty analyzes your default branch: 1. Go to **Project Settings > General** 2. Under **Default Branch Analysis**, find the **Analysis Frequency** dropdown 3. Select your preferred frequency 4. Save your changes ## Triggering analysis manually You can trigger an analysis at any time without changing your frequency setting: 1. Go to your project's **Builds** page 2. Click the **Build** button This is useful when you've made an important change and want to see updated results immediately, without increasing your regular analysis frequency. ## Understanding data freshness The data shown on your project pages comes from two independent sources: * **Analysis data**: Generated by Qlty's scheduled or manual analysis builds * **Coverage data**: Uploaded from your CI pipeline after running tests Qlty merges the latest available data from both sources to display your project's quality information. This means the data you see always reflects the most recently completed analysis and the most recently uploaded coverage report — which may not correspond to the very latest commit on your default branch. ### Why data may not match the latest commit Your repository on GitHub can receive new commits at any time — often faster than analysis and coverage processing can keep up. For example: * If your analysis frequency is set to every 24 hours, commits made during the day will not be reflected until the next analysis completes * If your CI pipeline takes 10 minutes to run tests and upload coverage, commits merged in the last 10 minutes will not yet have coverage data Once a new analysis completes or new coverage data is uploaded, Qlty updates the displayed data within about a minute. > [!TIP] > > If you need fresh data for a specific commit, you can [trigger a manual > analysis](#triggering-analysis-manually) rather than increasing your regular analysis frequency. > This keeps analysis minutes usage efficient while giving you up-to-date results when it matters. ### Deleted or renamed files If you delete or rename a file in your repository, that file may continue to appear in Qlty until both a new analysis and a new coverage upload have been processed. Once both data sources have been updated with data that no longer includes the file, it will no longer appear. ## See Also * [Analysis Configuration](/cli/analysis-configuration) — configure which files and tools are included in analysis * [Analysis Minutes Usage](/cloud/billing/analysis-minutes) — understand how analysis frequency affects minutes consumption * [Automated Code Review](/cloud/automated-code-review) — how Qlty analyzes pull requests # Applications Source: https://docs.qlty.sh/cloud/applications Applications let you group related projects together so you can view aggregated quality metrics across multiple repositories. For example, you might create a "Web App" application containing your frontend, backend, and shared library projects, or a "Mobile App" application grouping your iOS and Android repositories. > [!NOTE] > > Applications are disabled by default. To enable this feature, go to **Settings > Features** and > toggle **Applications** on. The **Applications** tab is visible in your workspace's top navigation alongside Projects. ## Creating an Application Create applications from **Settings > Applications** or from the **Applications** tab. Each application has a name (required) and an optional description. ## Assigning Projects to an Application Assign a project to an application from the project's **Settings > General** page using the **Application** dropdown. Each project can belong to at most one application. Select **None** to unassign. ## Viewing Application Metrics The **Applications** tab in your workspace displays a table of all applications with aggregated metrics across their assigned projects: | Column | Description | | - | - | | **Application** | The application name (click to view its projects) | | **Projects** | Number of projects assigned to the application | | **Size** | Aggregated codebase size | | **Maintainability** | Maintainability grade (A through F) with estimated remediation effort | | **Duplication** | Percentage of duplicated code across the application | | **Security** | Security rating with count of security issues | | **Coverage** | Code coverage percentage with a letter grade | Clicking an application name takes you to the **Projects** view filtered to show only that application's projects. You can search applications by name using the search bar, and sort by any column. ## Managing Applications Applications are disabled by default. Workspace administrators can enable the feature from **Settings > Features** by toggling **Applications** on. Edit or delete applications from **Settings > Applications** by clicking the application name. > [!WARNING] > > An application cannot be deleted while it still has projects assigned to it. Unassign all > projects first. # Automated Code Review Source: https://docs.qlty.sh/cloud/automated-code-review Qlty makes it easy to implement Continuous Quality using automated code review of your pull requests. When enabled, here is how it works: 1. A software developer writes code and opens a pull request on GitHub 2. GitHub sends Qlty a webhook 3. Qlty analyzes the code changes to identify newly introduced issues 4. Qlty sends results back to GitHub as comments and/or commit statuses ## Configuring automated code review Automated code review is configured on the *Project Settings > GitHub Integration* page. From this page you can: * Enable or disable summary comments and line comments * Enable or disable commit statuses for analysis and code coverage * Enable or disable review of draft pull requests When new Projects are added to Qlty, they inherit the Workspace's default settings for new Projects. ## Pull request comments After analysis is finished, Qlty can comment on your pull request to let you know of the new issues that are being introduced in your code directly in your workflow. ### Code comments Just like a human reviewer, Qlty will post comments directly under the code where the issues occur. These comments include the issues' message, the tool that it came from, and an identifier for the check. > [!NOTE] > > To limit noise, Qlty will post a maximum of 50 code comments when reviewing a pull request. You > can always view the full set of new issues on the Qlty website on the pull request summary page. ### Summary comments Additionally, Qlty can post a summary comment into the main pull request discussion thread. This comment includes a breakdown of the new issues found, grouped by check. When new code is pushed to the pull request and issues are fixed, Qlty will automatically update this comment with the latest information. ## Autofixes When available, code comments include Autofixes presented as suggestions. You can commit these changes directly to your pull request to quickly fix issues. > [!NOTE] > > To maximize accuracy, Autofixes are currently only available for certain checks and only for > single-line changes. # Analysis Minutes Usage Source: https://docs.qlty.sh/cloud/billing/analysis-minutes Every Qlty Cloud subscription includes a certain number of analysis minutes, which are used to run code quality checks on your codebase. These minutes are consumed based on the analysis of your projects, as well as code coverage uploads. Analysis minutes usage resets every month, and you can monitor your usage in the Qlty Cloud dashboard. ## Managing analysis minutes Analysis minutes usage is based on four main factors: repository size, analysis frequency, runner size, and the static analysis tools you use. The most minutes will be consumed by frequently analyzing large codebases with resource intensive static analysis tools. If you want to reduce the number of analysis minutes consumed, consider the following strategies: * Ensure that you are excluding unnecessary files and directories from analysis to increase analysis efficiency. * Consider running certain static analysis tools only on your default branch, in order to speed up analysis of pull requests. * Reduce the frequency of analysis of your default branch, especially for large repositories. ## Included analysis minutes | Plan | Analysis Minutes | | - | - | | Free | 1,000 minutes | | Pro | 20,000 minutes | | Enterprise | 75,000 minutes | If your usage exceeds the included analysis minutes, you will be charged for additional minutes at the overage rates below. > [!TIP] > > For customers purchasing 50 or more seats of the Enterprise plan, additional analysis minutes can be negotiated as part of an annual subscription. > > Please [contact sales](mailto:sales@qlty.sh) to learn more. ## Per-minute overage rates Standard analysis minutes are based on a 2 CPU core, 4 GB RAM Linux runner. Larger runners can be selected for more resource-intensive analyses, and consume minutes at multiples of the standard runner rate. Within your plans allotted analysis minutes, larger runners will consume minutes at the rates below. Above your plan's allotted minutes, the following overage rates will apply. ### Per-minute rates for standard runners | Operating system | CPU cores | RAM | Analyis minutes | Per-minute rate | | - | - | - | - | - | | Linux | 2 | 4 GB | 1 | \$0.01 | ### Per-minute rates for larger runners | Operating system | CPU cores | RAM | Analysis minutes | Per-minute rate | | - | - | - | - | - | | Linux | 4 | 8 GB | 2 | \$0.02 | | Linux | 8 | 16 GB | 4 | \$0.04 | | Linux | 16 | 32 GB | 8 | \$0.08 | ### Per-minute rates for code coverage uploads Each code coverage upload counts as one standard analysis minute, regardless of the size of the upload. This means that if you upload code coverage data for a large codebase, it will still only consume one analysis minute. (When server-side coverage merging is used, each upload part counts as one analysis minute.) ### Notes about larger runners * Larger runners are only available on the Pro and Enterprise plans. * Larger runners are not free for public repositories. ## How many minutes do I need? The number of analysis minutes you need depends on the size of your codebases, how often you want to analyze them, and which static analysis tools you use. We recommend loading your projects into Qlty Cloud, configuring their analysis settings to meet your needs, and then monitoring your analysis minutes usage over the course of a week to estimate your usage. If you need assistance estimating your analysis minutes needs, please [contact sales](mailto:sales@qlty.sh). ## Calculating analysis minutes usage At the end of the month or quarter, Qlty calculates any overage cost of analysis minutes used above what is included in your subscription. For example, if you are using the Enterprise plan with a 75,000 included analysis minutes, and you used 80,000 analysis minutes in a month (at the standard runner size), you would be charged for 5,000 additional minutes for an additional cost of $50/month. (5k times $0.01). # Education and Non-Profits Source: https://docs.qlty.sh/cloud/billing/edu-non-profit QLty supports educational use cases and nonprofits with special discounts. Please note that we cannot apply these discount retroactively to previous payments. > [!NOTE] > > Discounts only apply to the plan ubscription cost and do not apply to usage-based billing (e.g. > overages). ## Education discounts Qlty offers free services for classroom use within K-12 or universities. Please contact us to learn more. ## Non-profit discounts Qlty provides a 10% discount for nonprofits. To qualift, organizations must be 501(c)(3) registered (or equivalent) and non-governmental, non-academic, non-commercial, non-political, and have no religious affiliation. You can request a nonprofit discount by contacting us. Please make sure to include the following information: * Proof of your nonprofit status (e.g., 501(c)(3) letter) * The registered name of your organization * A summary of what your nonprofit organization does * Confirmation that your organization is non-governmental, non-academic, non-commercial, non-political, and has no religious affiliation # Limits on the Free Version Source: https://docs.qlty.sh/cloud/billing/free As you consider upgrading from the Free plan to a paid plan, here are some of the key differences to keep in mind. ## Analysis minutes The Free plan includes 1,000 analysis minutes per month so that you can try out Qlty Cloud and see how it works for your team. If you exceed this limit, your analysis will be paused until the start of the next month, or until you upgrade to a paid plan. Paid plans include significantly more analysis minutes, starting at 20,000 per month for the Pro plan, with the option to purchase additional minutes if needed. ## Trends & hotspots Our paid plans include access to code quality reports like trends and hotspots. Trends allow you to track your code quality progress over time, and hotspots highlight the most problematic areas of your codebase for your team to focus on. ## Support & service Our Free plan comes with public, community support via GitHub and Discord. Paid plans include email-based support, with the option for priority support, SLAs, and dedicated account management. ## Other limits * **Accelerated analysis** -- Paid plans are able to perform analysis using larger runners, which can significantly speed up analysis times. * **REST API** -- Paid plans include access to the API to ease administration and provide programatic access to your code quality data for integrations. * **Coverage tags** -- Paid plans include the ability to use coverage tags to track coverage for different suites or parts of your codebase (e.g. integration vs. unit tests). ## Upgrade to a Paid Plan To upgrade to a paid plan, follow these steps: 1. From your Dashboard, choose your Workspace. 2. Click on the **Workspace Settings** tab. 3. In the left sidebar, click the **Plan & Billing** section. 4. Choose your preferred plan and billing cycle, then click the **Subscribe** button. 5. Enter your payment details and click **Subscribe** to finalize the upgrade. # Managing Your Plan and Billing Source: https://docs.qlty.sh/cloud/billing/managing ## Change your plan or billing cycle Follow these steps to change your paid plan or billing cycle: 1. From your Dashboard, choose your Workspace. 2. Click on the **Workspace Settings** tab. 3. In the left sidebar, click the **Plan & Billing** section. 4. Click the **Manage Subscription** button, which will bring you to the billing portal. 5. Select your preferred plan and billing cycle. 6. Click the **Continue** button. 7. Review your changes and click **Confirm** to finalize the update. > [!NOTE] > > Some customers on legacy plans may need to contact us for plan changes. ## Manage your payment method To change your payment method, follow these steps: 1. From your Dashboard, choose your Workspace. 2. Click on the **Workspace Settings** tab. 3. In the left sidebar, click the **Plan & Billing** section. 4. Click the **Update Payment Details** button, which will bring you to the billing portal. 5. Click the **Add payment method** button to add a new payment method. 6. Enter your new payment details and click **Add** to save the payment method. 7. Make sure that the new payment method is set as the default by clicking the **Make default** button next to it. ## Cancel your subscription To cancel your subscription, follow these steps: 1. From your Dashboard, choose your Workspace. 2. Click on the **Workspace Settings** tab. 3. In the left sidebar, click the **Plan & Billing** section. 4. Click the **Cancel Subscription** button, which will bring you to the billing portal. 5. Review the details, and click the **Cancel subscription** to finalize the update. > [!NOTE] > > Some customers on legacy plans may need to contact us for plan changes. ## View your billing history To view your billing history, including past invoices and payment receipts, follow these steps: 1. From your Dashboard, choose your Workspace. 2. Click on the **Workspace Settings** tab. 3. In the left sidebar, click the **Plan & Billing** section. 4. Click the **View & Download Invoices** button, which will bring you to the billing portal. 5. At the bottom of the page, under **Invoice History**, you can view and download your past invoices and payment receipts. > [!WARNING] > > Due to a change in our billing system, receipts issued before August 2025 may no longer be > accessible. For invoices or receipts, please [contact support](/cloud/support). ## Update billing contact To update the billing contact who will receive billing-related notifications, follow these steps: 1. From your Dashboard, choose your Workspace. 2. Click on the **Workspace Settings** tab. 3. In the left sidebar, click the **Plan & Billing** section. 4. Click the **Update Billing Details** button, which will bring you to the billing portal. 5. Scroll down to the **Billing and shipping information** section. 6. Click the **Update information** link. 7. Fill in the billing contact details, including name, email, and phone number. 8. Click the **Save** button to save the billing contact information. ## Switch to invoicing Eligible customers can switch from credit card payments to paying by invoice. To make this change, please contact us. # Open Source Projects Source: https://docs.qlty.sh/cloud/billing/open-source Qlty provides free services for community-based open source projects. To take advantage of this, simply install the Qlty GitHub App for your open source repository. Under normal circumstances, there is no need to add a payment method to your account or select a plan. > [!NOTE] > > We reserve the right to restrict or block free usage for any reason, including abuse or use of > our system for unintended purposes. # Payment Methods Source: https://docs.qlty.sh/cloud/billing/payments The fastest way to pay for Qlty Cloud is by credit card, but you may also be eligible to pay by invoice. > [!NOTE] > > Currently, we only accept payments in US dollars (USD). ## Pay by credit card You can pay for Qlty Cloud by credit card (including Visa, MasterCard, American Express, and Discover) or debit card via our payment processor, Stripe. Qlty Cloud never handles payment card information directly, and all payments must be made via Stripe. ## Pay by invoice Some customers can pay for Qlty Cloud by ACH, bank transfer (aka wire transfer), or paper check. In all cases, payments are processed by Stripe, and we never handle or store your payment information directly. Invoices are deliverd by email to the billing contact on file on the first day of each billing cycle, and are due upon receipt. The invoice will include instructions for submitting payment. You can choose to pay by invoice if you meet the following criteria: 1. You are on the Qlty Cloud Enterprise plan. 2. You pay for Qlty Cloud annually. 3. Your annual subscription is at least \$10,000 USD. ## Sales tax Qlty Software reserves the right to assess applicable taxes as required by local law. Depending on location, customers mya be charged transaction taxes on their purchased of Qlty Cloud. Your company address is used to determine the correct tax rate, if applicable. Prices shown on our website do not include sales tax or value added tax (VAT). ## Vendor and remittance details Use the following information to set up Qlty Software as a vendor in your accounts payable system: ### Contact information Qlty Software Inc.\ 169 Madison Avenue\ STE 11723\ New York, NY, 10016 US * **Attention:** Accounts Receivable * **Email:** [accounting@qlty.sh](mailto:accounting@qlty.sh) * **Phone:** +1 (914) 530-0668 * **Service description:** Code quality tools for software development teams * **Incorporated:** Delaware, USA > [!NOTE] > > For bank account details, please refer to the bottom of your invoice. ### Additional information * **Federal tax ID:** 33-1266164 (EIN) * **NAICS:** 511210 (Software Publishers) # Plans and Features Source: https://docs.qlty.sh/cloud/billing/plans Learn about our free and paid [plans](https://qlty.sh/pricing). ## Usage limits | | Free | Pro | Enterprise | | - | - | - | - | | Public repositories | Unlimited | Unlimited | Unlimited | | Private repositories | Unlimited | Unlimited | Unlimited | | Contributors | Unlimited | Unlimited | Unlimited | | Analysis minutes | 1,000 | 20,000 | 75,000 | | AI autofixes | 100 | 500 | 5,000 | ## Developer experience | | Free | Pro | Enterprise | | - | - | - | - | | Qlty CLI | ✔ | ✔ | ✔ | | VS Code integration | ✔ | ✔ | ✔ | | IDE integration | ✔ | ✔ | ✔ | | Git hooks | ✔ | ✔ | ✔ | | Browser extension (GitHub.com) | ✔ | ✔ | ✔ | | AI coding integration\* | ✔ | ✔ | ✔ | > [!NOTE] > > \* Qlty CLI can be used as a tool by AI coding agents. AI capabilities of Qlty Cloud, like AI > autofixes, are available on an opt-in basis. ## Code analysis | | Free | Pro | Enterprise | | - | - | - | - | | Linting | ✔ | ✔ | ✔ | | Auto-fix suggestions | ✔ | ✔ | ✔ | | One-click auto-formatting | ✔ | ✔ | ✔ | | Duplication detection | ✔ | ✔ | ✔ | | Complexity metrics | ✔ | ✔ | ✔ | | Security scanning (SAST, SCA) | ✔ | ✔ | ✔ | | Secrets scanning | ✔ | ✔ | ✔ | | Infrastructure as Code (IaC) security | ✔ | ✔ | ✔ | | Custom checks | ✔ | ✔ | ✔ | | Pull request analysis | ✔ | ✔ | ✔ | | Quality statuses | ✔ | ✔ | ✔ | | Quality comments | ✔ | ✔ | ✔ | | Issue triage | ✔ | ✔ | ✔ | | Maximum analysis speed | 2 cores | 8 cores | 16 cores | ## Code coverage | | Free | Pro | Enterprise | | - | - | - | - | | Line coverage | ✔ | ✔ | ✔ | | Diff coverage | ✔ | ✔ | ✔ | | Coverage comments | ✔ | ✔ | ✔ | | Coverage statuses | ✔ | ✔ | ✔ | | Server-side merging | ✔ | ✔ | ✔ | | Coverage tags | | | ✔ | | Carryforward tags | | | ✔ | ## Advanced code quality | | Free | Pro | Enterprise | | - | - | - | - | | Pull request approvals | ✔ | ✔ | ✔ | | Shared review configs | ✔ | ✔ | ✔ | | Shared analysis configs | | | ✔ | | Monorepo support | | | ✔ | | Merge queue support | | | ✔ | ## Analytics & reporting | | Free | Pro | Enterprise | | - | - | - | - | | Quality ratings | ✔ | ✔ | ✔ | | Components | | ✔ | ✔ | | REST API | | ✔ | ✔ | | Project trends | | ✔ | ✔ | | Organization & application trends | | | ✔ | | Code hotspots | | | ✔ | | Churn reporting | | | ✔ | | Trends duration | | 1 year | 3 years | ## Security | | Free | Pro | Enterprise | | - | - | - | - | | GitHub single sign-on (SSO) | ✔ | ✔ | ✔ | | SOC 2 Type II certified | ✔ | ✔ | ✔ | | Regular penetration testing | ✔ | ✔ | ✔ | | Custom permissions | | | ✔ | ## Support | | Free | Pro | Enterprise | | - | - | - | - | | Support channel | Community | Email | Email | | Slack support | | | ✔ | | Priority support | | | ✔ | | Account manager | | | ✔ | | Consolidated billing | | | ✔ | | Uptime SLA | | | ✔ | | Migration assistance | | | ✔ | | Invoiced billing | | | Available at \$10k+ | | Terms customization | | | Available at \$40k+ | # Seats Source: https://docs.qlty.sh/cloud/billing/seats Qlty Cloud licensing is based on **seats**. Your subscription includes a set number of seats, and you assign a seat to each contributor who needs access. ## Managing seats The **Seat Management** page (Workspace Settings › Seat Management) shows: * **Subscription quantity** — the number of seats included in your subscription. * **Used seats** — seats currently assigned to contributors. * **Unassigned seats remaining** — seats still available to assign. Admins assign a seat to a contributor by entering their login (a user or bot), and can unassign a seat at any time to free it up. ## What requires a seat A contributor needs a seat for Qlty to show: * The in-app Pull Request **coverage view** in Qlty Cloud. * Qlty's **analysis and coverage comments** on the Pull Request on GitHub. If a Pull Request's author doesn't have a seat, Qlty hides those features for that Pull Request and prompts an admin to grant one. ## See Also * [Plans and Features](/cloud/billing/plans) * [Managing Your Plan and Billing](/cloud/billing/managing) * [Open Source Projects](/cloud/billing/open-source) # Build Repository Access Source: https://docs.qlty.sh/cloud/build-repository-access When Qlty runs a build for a project, it clones the repository using a short-lived [GitHub App](/cloud/github-app) installation access token. **Build Repository Access** controls which repositories that token is allowed to read, so you can give each project's builds least-privilege access to your code. This matters when a build needs to clone more than just the project's own repository — for example a private dependency, a Git submodule, or another repository in a monorepo workflow. ## Configuring access Open **Project Settings → General** and find the **GitHub** section. Set **Build Access Token Scope** to one of: | Option | The build token can clone… | | - | - | | **All Repositories** | Every repository the Qlty GitHub App can access in your workspace. Least restrictive. | | **This Repository Only** | Only this project's repository. Most restrictive. | | **Selected Repositories** | This project's repository, plus a list of additional repositories you choose. | > [!NOTE] > > Only workspace admins can view or change Build Repository Access. ## Selected repositories When you choose **Selected Repositories**, pick the additional repositories the build may clone. * This project's own repository is **always included** and cannot be removed. * You can add up to **5** additional repositories. * You can select any repository in your workspace that has been added to Qlty as a project. Use the search box to find a repository by name. ## Defaults * **New projects** default to **This Repository Only**. * Projects created before this setting was introduced keep **All Repositories**, so their existing builds are unaffected. Narrow the scope at any time from the project's settings. ## Behavior notes * Pull requests from **forks** are always scoped to the project's own repository, regardless of this setting. * If a selected repository is later deleted or removed from the Qlty GitHub App installation, it is automatically dropped from the build token so your builds keep working. Re-add an accessible repository from settings to restore it. # Build Secrets Source: https://docs.qlty.sh/cloud/build-secrets **Build Secrets** let you provide sensitive environment variables — such as an API token a linter plugin needs to reach a private package registry — to a project's cloud builds, without committing them to your repository. Each plugin must opt in to the secrets it needs (see [below](#making-a-secret-available-to-a-plugin)). > [!WARNING] > > Build Secrets are in **beta** and rolled out per workspace. To request access, [contact Qlty Support](https://qlty.sh/contact/support). ## Adding a secret Open **Project Settings → Secrets**, choose **New Secret**, and enter a name and value. * **Name** — uppercase letters, digits, and underscores only, and must not start with a digit (for example `NPM_TOKEN`). Names beginning with `QLTY_` are reserved. Up to 255 characters. * **Value** — up to 16 KB. Multi-line values (such as a PEM-encoded key) are supported. Secrets are **write-only**: once saved, a value is encrypted and can never be viewed again. To rotate a secret, enter a new value; to remove it, delete the secret. The list shows only names and timestamps. > [!NOTE] > > Only project admins can view the list of secrets or add, change, and remove them. ## Making a secret available to a plugin Adding a secret makes it available to the build, but that alone does **not** expose it to your plugins. The Qlty CLI runs each plugin's installation and invocation in a subprocess with a restricted environment, and only passes through environment variables that the plugin definition explicitly whitelists. This keeps secrets out of plugin subprocesses that don't need them. To expose a secret named `BAR` to a plugin named `foo`, add an `environment` entry to your `qlty.toml`: ```toml theme={"system"} [[plugins.definitions.foo.environment]] name = "BAR" value = "${env.BAR}" ``` `${env.BAR}` reads the value from the build environment — the secret you defined above — and passes it to `foo`'s installation and invocation subprocesses as `BAR`. Without this entry, the plugin will not see the secret even though it is present in the build. > [!NOTE] > > Secrets are available only while Qlty installs and runs your plugins (the tool installation and invocation phases). They are not exposed during other parts of the build, such as repository checkout. ## Security > [!NOTE] > > Pull requests from **forks** never receive project secrets, since the fork author controls the code the build runs. Build Secrets are handled in line with Qlty's overall [security practices](/cloud/security). # Continuous Quality Source: https://docs.qlty.sh/cloud/continuous-quality Qlty is designed to be used directly into the inner loop of your software development workflow with our GitHub pull request integration. When starting out, projects are likely to have pre-existing code quality issues -- complexity, lints, missing coverage, etc. Qlty's pull request integration highlights *new* code quality issues as they appear day-to-day. By fixing issues before the pull request is merged, the overall codebase quality will trend upwards over time. We call this *Continuous Quality*. # AI Data Usage Source: https://docs.qlty.sh/cloud/data-usage Qlty uses machine learning including large language models (LLMs) to provide a best-in-class code quality experience. With the power of AI, Qlty is always getting smarter. This page intends to provide a quick overview of how we leverage these technologies and how we use data for R\&D purposes, which varies by service. ## Services for individuals and open source projects For our services for *individuals*, including our free services for open source projects, we use customer data, including source code, to develop and train models. We have adopted the approach to our personal services based on OpenAI's own approach to using data from personal ChatGPT accounts for training purposes. | | Customer Content from individual services or open source | | - | - | | Is opt-in required? | No | | Is the underlying data identifiable? | Yes | | Who will this data (or any output) be shared with? | Approved AI subprocessors and other customers | | Will this data be used to train Qlty's models? | Yes | | Will this data be used to train 3rd party models? | No | For more on how we handle data for services for individuals and open source projects, see our [Cloud Services Agreement](https://commonpaper.com/standards/cloud-service-agreement/2.0/). ## Services for businesses For our services for *businesses*, we take a restrictive approach. We will not use any elements of your Customer Data that could be intellectual property, personally identifiable information or are otherwise identifiable to a customer (such as source code) without first obtaining opt-in permission. This will be collected in the form of an in-product opt-in for each separate R\&D use case that doesn’t involve Usage Data or Non-Identifying Data. Currently we have three features that use Customer Content: * [AI-generated issue explanations](/cloud/ai-explanations) and [AI-generated code fixes](/cloud/ai-autofixes), which must be opt-in enabled in Workspace Settings before use. * [Automatic coverage setup](/coverage/automatic-setup), which has no workspace setting. It runs only when a project admin clicks **Set up automatically** on a project, and each run sends that repository's default branch to the subprocessor. To perform these functions we share the data with approved AI subprocessors, currently OpenAI and Anthropic. Our full subprocessor list is in our [Trust Center](https://trust.qlty.sh/). Even when these features are enabled for opt-in, neither Qlty nor our 3rd party subprocessors train models with Customer Content. | | Customer Content from business services | | - | - | | Is opt-in required? | Yes | | Is the underlying data identifiable? | Yes | | Who will this data (or any output) be shared with? | Approved AI subprocessors | | Will this data be used to train Qlty's models? | No | | Will this data be used to train 3rd party models? | No | For more on how we handle data for services for businesses, see our [Business Terms](https://qlty.sh/legal/business-terms). ## Usage Data and Non-Identifying Data We use Usage Data and Non-Identifying Data to develop and train AI and ML. Examples of Usage Data would be web analytics and CLI telemetry. Examples of Non-Identifying Data include aggregated data about static analysis issues. An example of a feature that is powered by Non-Identifying Data is smart prioritization and grouping of static analysis issues. Examples of use of Usage Data are bug fixing, user experience improvements, and A/B testing. | | Non-Identifying Data | Usage Data | | - | - | - | | Is opt-in required? | No | No | | Is the underlying data identifiable? | No | Yes | | Who will this data (or any output) be shared with? | Other customers | Qlty only | | Will this data be used to train Qlty's models? | Yes | No | | Will this data be used to train 3rd party models? | No | No | ## Legal references * [Privacy Policy](https://qlty.sh/legal/privacy-policy) — how Qlty collects, uses, and shares personal information. * [Terms of Use](https://qlty.sh/legal/terms-of-use) — the agreement that governs your use of Qlty. * [Business Terms](https://qlty.sh/legal/business-terms) — the agreement that governs services for businesses. * [Cloud Services Agreement](https://commonpaper.com/standards/cloud-service-agreement/2.0/) — the agreement that governs services for individuals and open-source projects. # Frequently Asked Questions (FAQ) Source: https://docs.qlty.sh/cloud/faq ## Does Qlty work for projects that aren't hosted on GitHub? Yes — but only through the [Qlty CLI](/cli/quickstart). The CLI runs locally on any project regardless of where it's hosted, and supports linting, auto-formatting, code smells, complexity, and duplication analysis on Mac, Linux, and Windows. [Qlty Cloud](/cloud/quickstart) — the hosted product that adds automated code review of pull requests, code coverage tracking, quality trends, and pull request comments — currently integrates with GitHub Cloud only. Support for additional Git hosts isn't available today. If your code lives on GitLab, Bitbucket, Azure DevOps, or a self-hosted Git server, you can still use the Qlty CLI for everything it offers and run it in your existing CI provider. See [Qlty CLI vs. Qlty Cloud](/cli-vs-cloud) for the feature breakdown. ## Can I use Qlty without the AI features? Yes, the features that we provide which use large language models (LLMs) are optional. They require an explicit opt-in within your Workspace Settings. Please see our [AI Data Usage](/cloud/data-usage) page for more information. ## How do I add or remove users? Access to your organization on Qlty Cloud is always syncronized with GitHub. There is no invitation step required, and no users to manage within Qlty Cloud. A user will be able to access a project on Qlty Cloud if and only if they can access the underlying repository on GitHub. ## Will Qlty be free for open source projects? Yes, use of Qlty for public, open source projects will remain free forever. # Quality Gates Source: https://docs.qlty.sh/cloud/gates GitHub has a robust system for commit statuses that is used for external systems to report information about code changes in a simple go/no-go form. For example, continuous integration services commonly use commit statuses to indicate whether builds are passing or failing. You can configure Qlty to report one or more of the following Quality Gates: **Qlty Gate**: Provides a go/no-go assessment based on the analysis results. The Gate can be configured to consider new issues, vulnerabilities, and file maintainability. **Qlty Coverage**: Displays the total code coverage from the automated test suite. This status can be configured to return a failure if the coverage decreases compared to the base branch. **Qlty Diff Coverage**: Displays the code covergage of the new or changed lines in the pull request. This status can be configured to return a failure if the coverage of the modified code is below a threshold. # GitHub App Source: https://docs.qlty.sh/cloud/github-app Qlty uses a [GitHub App](https://github.com/apps/qltysh) to integrate with GitHub. ## Authentication GitHub OAuth is the only supported authentication method for Qlty. As part of the User authentication flow, the following permissions are granted: ### Account Permissions | Permission | Access | Reason | | - | - | - | | Email addresses | Read-only | Sending product and account-related notifications | | Watching | Read-only | Identifying repositories that are important to you | ## Permissions When installed, the GitHub App requires the following permissions: ### Repository Permissions | Permission | Access | Reason | | - | - | - | | Actions | Read and write | When prompted, generate and validate code quality fixes | | Checks | Read and write | Post code quality information on pull requests | | Code scanning alerts | Read and write | Generate unified code quality reports including security issues | | Commit statuses | Read and write | Post code quality information on pull requests | | Contents | Read and write | When prompted, push branches to open pull requests | | Custom properties | Read-only | Simplify administration by leveraging custom repository metadata | | Deployments | Read and write | Track the quality of and optionally gate deploys | | Environments | Read-only | Track the quality of and optionally gate deploys | | Issues | Read and write | When prompted, create issues for code quality issues | | Metadata | Read-only | Mandatory by GitHub | | Packages | Read-only | When needed, install private packages to run static analysis | | Pull Requests | Read and write | When prompted, open PRs to update config or improve code quality | | Workflows | Read and write | When prompted, open PRs that change GitHub Actions workflows, such as [automatic coverage setup](/coverage/automatic-setup) | ### Organization Permissions | Permission | Access | Reason | | - | - | - | | Members | Read-only | Checking permissions for authorization | ### Accepting new permissions When Qlty adds a permission to the GitHub App, installations made before the change keep their old permissions until an owner accepts the new one. GitHub emails the organization's owners, and features that need the permission do not work until it is accepted. The **Workflows** permission was added in September 2026, so installations made before then may not have granted it. To accept it: 1. Open the installation's settings on GitHub. For an organization, go to **Organization settings > Third-party access > GitHub Apps** and click **Configure** next to Qlty. For a personal account, go to **Settings > Applications > Installed GitHub Apps**. 2. GitHub shows a banner asking you to review the new permissions. Click **Review request**, then **Accept new permissions**. Only an organization owner can accept. Pages in Qlty that are blocked on a permission link to this settings page. ## Repository Access Access can be granted either to all repositories in a workspace, or individual repositories. By default, after authorization importing repositories as Qlty projects must be done manually. (In the future, we may provide an opt-in feature to automatically import repositories for convenience.) ## Webhooks In order to analyze new commits and keep data syncronized, Qlty subscribed to GitHub webhooks. ## More information * [Security](/cloud/security) # System Limits Source: https://docs.qlty.sh/cloud/limits Your usage of Qlty Cloud is subject to certain limits in order to ensure the stability and performance of the service. These limits are designed to maintain a high quality of service for all users and prevent abuse. > [!WARNING] > > In some cases the system may work even if you exceed the limits, but this is not guaranteed, and > you may experience unexpected behavior or degraded performance. Qlty is unable to provide > support for issues that arise from exceeding these limits. ## General limits | Name | Limit | Description | | - | - | - | | Project size | 1,000,000 | The maximum size of a project that can be analyzed in lines of code. | | Repository size | 1 Gigabyte | The maximum size of a Git repository that can be analyzed. | | File size | 2 Megabytes | The maximum size of a single code file that can be analyzed. | > [!NOTE] > > For customers with special needs, we can increase these limits on a case-by-case basis. Please > contact sales to discuss your requirements. ## Code analysis | Name | Limit | Description | | - | - | - | | Analysis runtime for pull requests | 10 minutes | The maximum time allowed for analyzing a pull request. | | Analysis runtime for the default branch | 20 minutes | The maximum time allowed for analyzing a branch. | | Issues | 50,000 | The maximum number of issues that can be reported in a single analysis. | | Issues per file | 500 | The maximum number of issues that can be reported in a single file. | | Issues per file per linter | 100 | The maximum number of issues that can be reported in a single file by a single linter. | | AST depth | 1,024 | The maximum depth of the Abstract Syntax Tree (AST) will be processed during maintainability analysis. | ## Code coverage | Name | Limit | Description | | - | - | - | | Coverage report file size | 10 Megabytes | The maximum size of a coverage report file that can be uploaded. | | Coverage file records | 100,000 | The maximum number of coverage records in a coverage upload | | Coverage parts | 200 | The maximum number of uploads for server-side merging | ## Pull request review | Name | Limit | Description | | - | - | - | | Files changed | 300 | The maximum number of files that can be included in a pull request diff for analysis. | | Comments per file | 30 | The maximum number of comments that can be made on a single file in a pull request. | | Comments per review | 50 | The maximum number of comments that can be made in a single pull request review. | ## Rate limits Requests made by Qlty to the GitHub API are subject to GitHub's rate limits. To ensure the security and availability of the system, we may impose additional rate limits. # Maintainability Metrics and Ratings Source: https://docs.qlty.sh/cloud/maintainability/metrics Qlty provides detailed code quality metrics and ratings to help you understand and improve the maintainability of your codebase. Here's a rundown of all of them. ## Metrics ### Lines of Code Out of the total lines in a file, Qlty differentiates between blank lines, comment lines and **lines of code**. Our lines of code metric represents executable lines in a file, without counting comments and blank lines. ### Issues Issues are findings from analysis that Qlty runs on your codebase. They can range from complexity and duplication issues, to lint results from supported plugins like ESLint, Semgrep, and Clippy. #### Code Smells Code smells are indicators of maintainability problems in the code that may not be bugs but could lead to issues in the future. Qlty's analysis finds code smells as issues in the `Duplication` and `Structure` categories. When using the CLI, you can run the `qlty smells` command to analyze your codebase for smells. The output will be a list of duplication and/or structure issues. #### Vulnerabilities Vulnerabilities are security-related issues. #### Issue Levels Qlty issues come with a Level which represents severity. We use a simple level system of high, medium, and low. You can use the `level` attribute to assess priorities when fixing issues in your codebase. #### Effort This metric is an estimate of the time in minutes that a developer may invest to remediate a code smell. Qlty calculates this number for `duplication` and `structure` issues. This number is used to help compute your codebase's [technical debt](#technical-debt). ### Complexity Code complexity is a measure of the difficulty to understand, test and maintain code. The higher the complexity, the more difficult it will be to achieve clean, readable and maintainable code. #### Complexity In Qlty, we use the term Complexity to refer to *cognitive* complexity. Cognitive complexity measures how difficult it is for a human to understand a piece of code. It takes into account the structural elements that affect readability and understandability, unlike cyclomatic complexity, which only counts the number of branches. For example, deeply nested code, complex conditionals, and the use of recursion can increase cognitive complexity. #### Cyclomatic Complexity Cyclomatic complexity, sometimes referred to as McCabe's complexity, is a count of the linearly independent paths through source code. You can also think of this more simply as "the number of decisions a given block of code needs to make". As the code branches out into different paths using constructs like if-else statements and loops, the cyclomatic complexity increases. For example, a simple function with no branching (if-else statements, loops) has a cyclomatic complexity of 1. Each additional branch increases the complexity by 1. ### Duplication Code duplication measures the amount of code that is repeated in a similar or identical form within the project. Reducing duplication helps in maintaining DRY (Don't Repeat Yourself) principles, making the code easier to maintain and less error-prone. Duplication is calculated as the percentage of lines that are duplicated in your code. For example, if a file has 100 lines and 10 of those lines are duplicated, the duplication percentage is 10%. ### Technical Debt Technical Debt sums the total effort (or remediation time) of the maintainability issues (structure and duplication) within a unit of code. This estimates how long it would take to improve the code to a high level of maintainability. ### Technical Debt Ratio The Technical Debt Ratio is obtained by dividing the Technical Debt to fix all the code smells by the estimated effort to rewrite the code from scratch. The higher the ratio, the more challenging a project will be to maintain and iterate over time. Qlty uses the Basic Constructive Cost Model (COCOMO) to estimate the time in person-months required to develop a software project. For example, if resolving all code smells in a project is estimated to take 3 weeks, and we estimate the project required 30 weeks to develop, the technical debt ratio would be 10%. ## Ratings There are a number of ratings that are computed using your project's metrics. Ratings helpe make code quality information easy to understand at a glance. They can be observed at a project level, as well as directory and file level. ### Size This rating represents the total lines of code, counting comments and blank lines. * At a project level, you can see a T-shirt size rating that estimates the size of your project with the following definition: | Lines of code | Size | | - | - | | less than 1k | XS | | less than 10k | S | | less than 100k | M | | 500k or less | L | | more than 500k | XL | * At a directory level, you can see the sum of the lines in each file under that folder. * At a file level, you can see the line count in the file. ### Maintainability The maintainability rating is a letter grade that is given depending on your technical debt or effort metrics. * At a project level, the letter grades are defined based on your technical debt ratio, like this: | Technical Debt Ratio | Rating | | - | - | | less than 5% | A | | 5% to 10% | B | | 10% to 20% | C | | 20% to 50% | D | | 50% or more | F | * At a file and directory level, the grades are calculated using a logorithmic function based on the total Technical Debt. ### Duplication This is the percentage of the lines that are duplicated in your code. You can see this metric at project, directory, and file level as the division between the count of duplicated lines over the total lines of code. ### Coverage Code coverage refers to the percentage of lines of code which are executed by automated unit tests. You can see this as a letter grade in your project, directory, and file views. At all levels, the coverage rating is calculated as the division between the count of covered lines over the relevant lines of code. Lines that are considered irrelevant to the supported coverage tools are not counted in the total. The grade is then defined as follows: | Coverage % | Grade | | - | - | | 90% or more | A | | 80% to 90% | B | | 70% to 80% | C | | 60% to 70% | D | | less than 60% | F | # User Permissions Source: https://docs.qlty.sh/cloud/permissions ## Permissions on GitHub Qlty Cloud uses a GitHub App to integrate with GitHub. The installation and authorization of the GitHub App occurs on the GitHub side based on GitHub Organization settings. Depending the GitHub organization's settings, an approval step may be necessary on the GitHub side. All authentiction uses GitHub OAuth, and we use the GitHub identity of the user to determine access to Qlty Cloud as described below. ### Repository selection The GitHub App can be installed with access to either *all* repositories within the organization or *selected* repositories. Updates to the repository selection can be done at any time on the GitHub side. Qlty Cloud can only access repositories that it has been authorized to access on the GitHub side. > [!NOTE] > > In order to ease migration from Code Climate Quality, Qlty Cloud will attempt to use the *Code > Climate* GitHub OAuth App when needed to access repositories that were previously authorized to > Code Climate Quality. For the best experience, we recommend that you authorize the new Qlty > Cloud GitHub App as soon as possible. Once you have authorized the new Qlty Cloud GitHub App for > all of the repositories you want to use with Qlty Cloud, you can remove the legacy Code Climate > Quality GitHub OAuth App from your GitHub organization. ## Workspace-level permissions Workspaces correspond to GitHub organizations or user accounts. For Workspaces corresponding to GitHub users, the user has full access to the workspace. For Workspaces corresponding to GitHub organizations, permissions are determined by the GitHub permissions as described in this table: | Permission | Organization Member | Organization Owner | | - | - | - | | Update Workspace settings | No | Yes | | Manage Workspace billing | No | Yes | | Rotate Workspace coverage token | No | Yes | | Remove Workspace | No | Yes | ## Project-level permissions Projects correspond to GitHub repositories. Permissions are determined by the GitHub repository role as described in this table: | Permission | Repository Viewer | Repository Admin | | - | - | - | | Add Repository as Project | Yes\* | Yes | | Read Project | Yes | Yes | | Rotate code coverage | Yes | Yes | | Triage issues | Yes | Yes | | Approve pull requests | Yes | Yes | | Update Project settings | Yes | Yes | | Remove Project | No | Yes | \* Only GitHub Repositories that have been authorized for access by the GitHub App # Code Source: https://docs.qlty.sh/cloud/projects/code The **Code** view, in a project's **Metrics** tab, lets you walk your repository's directory tree with per-file metrics. It's the fastest way to find which files in the project carry the most risk. ## Sub-views The Code area has three sub-tabs: * **Tree** — Hierarchical view that mirrors your repository's directory layout. Click a folder to drill into it; click a file to open its metrics page. Each row shows the path's aggregated size, complexity, coverage, and maintainability grade. * **List** — Flat list of every file in the tracked branch with the same columns as Tree, but sortable across the whole project. Use this when you want to find the most complex or worst-rated file regardless of where it lives. * **Unformatted Files** — Subset showing only files that Qlty's auto-formatters would rewrite (i.e. files with one or more `fmt`-level issues raised by a formatter plugin). Useful for working through a formatting backlog one file at a time. ## Columns Every row displays: * **Type** — folder or file icon. * **File** — the path, with a clickable link to either the deeper folder view or the per-file metrics page. * **Size** — code lines, expressed as a relative "shirt size" (S/M/L/XL) for quick scanning. * **Complexity** — cognitive complexity score for the file or aggregated for the folder. * **Coverage** — line coverage percentage (only when coverage data has been uploaded). * **Maintainability grade** — A–F rating combining smells, complexity, and duplication signals. Columns are sortable. Sort order is preserved in the URL so the view is shareable. ## When you click into a file The per-file metrics page shows: * The file's headline grade and individual metric values. * The list of open issues affecting the file. * Per-line coverage hits when coverage data exists. ## See Also * [Project Overview](/cloud/projects/overview) * [Issues](/cloud/projects/issues) * [Maintainability Metrics](/cloud/maintainability/metrics) * [Browsing Coverage](/coverage/browsing) # Issues Source: https://docs.qlty.sh/cloud/projects/issues The **Issues** view shows every open finding for the project's tracked branch in a filterable, sortable table. It's the primary place to triage, prioritise, and (where supported) resolve issues across all of Qlty's static analysis, security, and maintainability checks. By default the table shows issues with **status = open**, sorted by **priority descending**. ## Filters The view supports faceted filtering. Each filter is a list of values — selecting any value within a facet ORs across that facet, while selecting values across different facets ANDs. * **Status** — `open` (default), `ignored`, or `all`. Ignored covers issues you've dismissed in the web app (with a reason such as `false_positive` or `wont_fix`) or silenced through `qlty.toml`. * **Category** — bug, vulnerability, structure, duplication, security\_hotspot, performance, documentation, type\_check, style, anti\_pattern, accessibility, dead\_code, lint, secret, dependency\_alert. * **Level** — `note`, `fmt`, `low`, `medium`, `high`. * **Tool** — the plugin or analyzer that surfaced the issue (eslint, rubocop, semgrep, etc.). * **Language** — the file's programming language. There's also a free-text search box for matching against issue messages and file paths. The URL captures the current filter and sort state, so any view is shareable as a link. ## Acting on an issue Click into any row to see the full issue page, which includes: * The issue message, rule, and tool that reported it. * A code snippet showing the affected lines. * The category, \[level]\(/cloud/maintainability/metrics#issue-levels, and [mode](/cli/analysis-configuration#check-modes) applied to this finding. * Available actions — open a GitHub Issue, mark as Ignored, or jump to the source file on GitHub. If you've enabled [AI Autofixes](/cloud/ai-autofixes), you can request a fix suggestion directly from the issue page. ## See Also * [Project Overview](/cloud/projects/overview) * [Code Smells](/code-smells) * [Custom Checks](/custom-checks) * [Triaging Issues](/cloud/triaging-issues) * [Silencing Issues](/cli/silencing-issues) # Overview Source: https://docs.qlty.sh/cloud/projects/overview The **Overview** page is the landing screen for a project in Qlty Cloud. It surfaces the health of the project's default branch across three lenses: **Maintainability**, **Coverage**, and **Security**. ## Headline metrics The Overview reports an A–F grade for each lens, computed from the tracked branch: * **Maintainability** — overall code quality grade based on smells, complexity, and duplication. * **Coverage** — line coverage percentage and grade. * **Security** — count and severity of open security findings. Three tabs scope the rest of the page to a single lens. ## Hotspots The Hotspots list shows the top files in the project that most need attention for the selected lens: * **Maintainability** — top files by remediation effort (highest [Effort](/cloud/maintainability/metrics#effort) first). * **Coverage** — top files by lowest line coverage, excluding files with no coverage data. * **Security** — top files by open security finding count. Each entry links into the file's metrics page for a deeper view. See [Coverage Hotspots](/coverage/hotspots) for the coverage-specific behavior. ## Trend chart A 30-day time-series chart shows how the selected lens has evolved on the tracked branch, with one data point per day. The lens determines what's plotted — technical debt, coverage percent, or security issue count. See [Coverage Trends](/coverage/trends) for the coverage-specific chart. ## Sunburst chart A radial visualisation of the project's directory tree, colour-coded by either complexity or coverage. Each ring is a directory level; segment size is proportional to lines of code. Useful for spotting concentrations of risk at a glance. ## Files by grade A breakdown of how many files in the project sit at each maintainability rating (A through F). ## Where to go from here * **[Code](/cloud/projects/code)** — Walk the directory tree with per-file metrics. * **[Issues](/cloud/projects/issues)** — Browse and filter every open finding. * **[Pull Requests](/cloud/projects/pull-requests)** — Review per-PR analysis and coverage. ## See Also * [Maintainability Metrics](/cloud/maintainability/metrics) * [Security Framework](/cloud/security/framework) * [Code Coverage](/coverage) # Pull Requests Source: https://docs.qlty.sh/cloud/projects/pull-requests The **Pull Requests** view lists every open pull request in your project. Click into any PR to see your analysis results, which include both static-analysis issues introduced by the PR and the PR's coverage impact. ## Navigating PR Results Inside the PR Results page, two tabs are available: * **Issues** — every issue detected in the PR analysis, with the same filtering, sorting, and triage actions available on the [project-level Issues view](/cloud/projects/issues). * **Coverage** — the PR's coverage impact relative to its base, with stat cards for total coverage, diff coverage, and lines added/missed, plus per-file breakdowns. By default, opening a PR redirects to its Issues tab. ## Coverage tab The Coverage tab includes three sub-views: * **Direct changes** — files which have changes in coverage, and are directly modified by the PR. Shows the coverage delta per file. * **Indirect changes** — files whose coverage changed even though the PR didn't touch them (e.g. shared modules where test-call paths shifted). See [Indirect Changes](/coverage/unexpected-changes) for more. * **Components** — coverage for each [Component](/coverage/components) that contains a file changed by the PR, comparing the base and the head. ## Status posting Qlty posts commit statuses and (optionally) PR comments back to GitHub for each analyzed PR. See [Commit Statuses](/coverage/commit-statuses) and [Pull Request Comments](/coverage/pull-request-comments) for how those integrations work, and [Quality Gates](/cloud/gates) for the configurable pass/fail thresholds that drive them. ## See Also * [Automated Code Review](/cloud/automated-code-review) * [Quality Gates](/cloud/gates) * [Indirect Changes](/coverage/unexpected-changes) * [Project Overview](/cloud/projects/overview) # Qlty for Infrastructure Source: https://docs.qlty.sh/cloud/qlty-for-infrastructure For software infrastructure projects, Qlty offers a comprehensive set of static analysis tools in a single tool with industry-leading workflow integration. # Use Cases ## Linting and defect detection Modern infrastructure projects are inherently polyglot, with components written in HashiCorp Configuration Language (HCL), Dockerfiles, shell scripts, and Helm charts. Often the developers who are working in these languages are less familiar with the technologies as well as best practices for security, reliability, and maintainability, making static analysis especially important. With Qlty, teams can easily run best-in-class static analysis across all of their code and configuration files and receive the outputs directly in their GitHub pull request. 1. [TFLint](https://github.com/terraform-linters/tflint) – Extensible linter for Terraform 2. [Hadolint](https://github.com/hadolint/hadolint) – Dockerfile linter 3. [Shellcheck](https://github.com/koalaman/shellcheck) – Shell script linter 4. [KubeLinter](https://github.com/stackrox/kube-linter) – Linter for Kubernetes and Helm charts 5. [Actionlint](https://github.com/rhysd/actionlint) – Identify flaws and in CI / CD workflows ## Security Scanning (IaC, SAST, SCA, etc.) Moving to Infrastructure as Code with an emphasis on storing artifacts in version control offers an opportunity to shift left on security and detect issues before they are deployed into testing or production runtime environments. 1. [Checkov](https://www.checkov.io/) – Policy-as-code for Terraform and Kubernetes 2. [Trivy](https://github.com/aquasecurity/trivy) – Security scanner covering Terraform and Kubernetes 3. [Trufflehog](https://github.com/trufflesecurity/trufflehog) – Finds secrets or credentials checked into version control 4. [Semgrep](https://github.com/semgrep/semgrep) – Static analysis scanning of application code for vulnerabilities (SAST) that works across many programming languages and frameworks 5. [OSV Scanner](https://github.com/google/osv-scanner) – Identifies vulnerable dependencies across ecosystems like JavaScript, Java, Python, etc. based on the Open Source Vulnerability (OSV) database ## Conventions In addition to the static analysis tools above, [Semgrep Rules for Terraform](https://semgrep.dev/p/terraform) provides a simple pattern syntax, which teams can adopt out-of-the-box or fully custom conventions: * ***Example rule:*** [The AWS security group rule is missing a description](https://semgrep.dev/r?q=terraform.aws.security.aws-ec2-security-group-rule-missing-description.aws-ec2-security-group-rule-missing-description) ## Auto-formatting HashiCorp recommends the [terraform fmt](https://developer.hashicorp.com/terraform/cli/commands/fmt) subcommand to format HashiCorp Configuration Language (HCL) files for consistency and readable diffs. With Qlty, you can block improperly formatted pull requests from being merged. # Setting up Qlty Source: https://docs.qlty.sh/cloud/quickstart > [!TIP] > > If you are already using Code Climate Quality, please [contact > us](https://form.typeform.com/to/UpJJAD9X) for migration assistance. ### 1. Sign in to Qlty with your GitHub user [Sign in with GitHub](https://demo.arcade.software/uOXuWcgxjzrUn1LwgnRz?embed\&embed_mobile=tab\&embed_desktop=inline\&show_copy_link=true) ### 2. Install our Qlty GitHub Application Qlty integrates as a GitHub Application, which is installed for either a GitHub organization or a GitHub user. We refer to these installations as Workspaces. From your Dashboard, click *Add a GitHub Installation*. When GitHub asks where you want to install Qlty, select either your user or one of your organizations. You can authorize Qlty to access all of your repositories or only selected repositories. [Install GitHub App](https://demo.arcade.software/dgaKG0cB3Odjf94yotaY?embed\&embed_mobile=tab\&embed_desktop=inline\&show_copy_link=true) *Note:* Depending on your GitHub organization's configuration, the installation may need to be approved by an organization owner. ### 3. Add repositories as Projects Next, click the *Add Project* button. Select a repository to add it to Qlty as a Project. Adding the repository will immediately kick off an initial analysis of your default branch. You can monitor the progress of the static analysis build by clicking the *Last build* link on the right side of the project navigation. Once the initial analysis completes, you will be able to see code quality metrics, ratings, and issues. If your initial analysis errored, see [Troubleshooting](/cloud/troubleshooting). ## Next steps * Refine your analysis configuration with [file and path exclusions](/cli/excluding-files) * Explore the 40+ linters and security scanners available as plugins * Take advantage of automated code review with our [pull request workflow integration](/cloud/continuous-quality) * [Enable code coverage](/coverage/quickstart) reporting with Qlty * Inviting team members is as simple as sending them a link to [https://qlty.sh](https://qlty.sh) # Security Source: https://docs.qlty.sh/cloud/security Our commitment to security is our highest priority, and we implement a comprehensive and continually evolving program to ensure this critical data is protected. ## Source code protection * Static analysis is performed on sandboxed containers running on AWS Fargate which are destroyed after each run * Short-lived limited access tokens are used to fetch code from GitHub to prepare for analysis * Qlty does not store clones of analyzed Git repositories ## Product security * Secure coding practices are integrated into the software design process from day one * Authentication is provided by GitHub single sign-on (SSO). Qlty does not store passwords. * Qlty automatically checks permissions for authorization directly in GitHub. * Access to staff applications is additionally restricted behind a virtual private network (VPN). * Code changes require pull request review and approval * Third party penetration testing is performed at least annually * Static analysis for security vulnerabilities (SAST) and software composition analysis (SCA) is run continuously * Application performance and errors are monitored by Sentry ## Infrastructure security * Production data is hosted in the cloud on Amazon Web Services (AWS). To find out more information about AWS security practices, see: [https://aws.amazon.com/security/](https://aws.amazon.com/security/). * Services run within a virtual private cloud (VPC) with fine-tuned firewall rules * Access to AWS is done using short-lived role assumption. We do not run SSH daemons or bastion hosts. * Data in transit is encrypted with HTTPS using TLS (SSL) and enforced by HSTS. We maintain an A+ from SSL Labs. * Data at rest is encrypted at the disk level. Additionally, sensitive fields are encrypted before being stored in the database using envelope encryption. Amazon Key Management Service (KMS) is used for key management. * Infrastructure is managed as version controlled Terraform code (IaC) and subject to code review * Mobile Device Management (MDM) is deployed on systems which may access production systems * We implement a corporate security program including staff single-sign on (SSO), background checks, and security training ## SOC 2 Qlty has achieved SOC 2 Type II certification. SOC 2 (System and Organization Controls 2) is a rigorous framework developed by the American Institute of CPAs (AICPA) to ensure that a company manages customer data with the highest standards. Achieving SOC 2 Type II compliance means that we have implemented these controls and that an independent auditor has verified their effectiveness over an extended period. We have also implemented automated compliance monitoring with Vanta as part of our commitment to continuously improving our security posture. ## PCI Qlty uses Stripe for all payment processing. A PCI-certified auditor evaluated Stripe and certified us to PCI Service Provider Level 1. This is the most stringent level of certification available in the payments industry. ## Report a vulnerability Your input and feedback on our security, as well as responsible disclosure, is always appreciated. If you’ve discovered a security concern, please email us at [security@qlty.sh](mailto:security@qlty.sh). We’ll work with you to make sure we understand the issue and address it. We consider security correspondence and vulnerabilities our highest priorities, and we will work to promptly address any issues that arise. # Security Framework Source: https://docs.qlty.sh/cloud/security/framework Qlty allows you to effortlessly automate all five types of static analysis security scanning and process results in a unified experience. ## Application code scanning (SAST) Application code scanning, also known as Static Application Security Testing (SAST) analyzes your source code to identify potential security vulnerabilities like SQL injection, cross-site scripting (XSS), insecure authentication, and more. Qlty offers [Semgrep]() for application code scanning. ## Open Source vulnerabilities scanning (SCA) Open Source vulnerabilities scanning, sometimes referred to as Software Composition Analysis (SCA), identifies security vulnerabilities in the open-source components and libraries that your application uses. This process ensures that all third-party dependencies are up-to-date and free from known vulnerabilities, thus preventing potential security risks that could arise from outdated or insecure open-source code. Qlty offers [OSV Scanner]() for Open Source vulnerability scanning. ## Secrets scanning Secrets scanning detects sensitive information that may be inadvertently included in your codebase, such as API keys, passwords, and other confidential data. By identifying and addressing these secrets before they reach production, you can prevent unauthorized access and potential data breaches. Qlty offers [Gitleaks]() and [Trufflehog]() for secrets scanning. ## CI/CD scanning CI/CD scanning involves the automated review of your continuous integration and continuous deployment pipelines. This process ensures that your build and deployment scripts are secure and free from vulnerabilities that could be exploited during the software development lifecycle. Qlty offers [ActionLint]() for CI/CD scanning. ## Infrastructure as Code (IaC) scanning Infrastructure as Code (IaC) scanning analyzes your infrastructure configuration files, such as Terraform or CloudFormation scripts, to detect security vulnerabilities and misconfigurations. By ensuring that your infrastructure is securely defined and compliant with best practices, IaC scanning helps prevent potential security risks that could compromise your application's environment. Qlty offers [Trivy](), [Checkov](), [Hadolint](), and [ShellCheck]() for IaC scanning. ## Next steps * [Implementing Security Scanning]() # Implementing Security Scanning Source: https://docs.qlty.sh/cloud/security/implementing With Qlty, you can set up comprehensive, automated security scanning in minutes with three steps. ## Enabling scanners Getting started with security scanning is as easy as enabling plugins in your project's `.qlty/qlty.toml` configuration file. For example, to enable [Trufflehog]() for secrets scanning and allow newly detected secrets from blocking merging code, add this: ```toml lines theme={"system"} # ... [[plugin]] name = "trufflehog" mode = "block" # ... ``` Other types of security issues, like vulnerable open source packages, may be better handled with a dedicated process outside of the regular day-to-day pull request workflow. To run [OSV Scanner]() to find vulnerable dependencies and report them on the Qlty.sh website, enable the plugin in "monitor" mode: ```toml lines theme={"system"} [[plugin]] name = "osv-scanner" mode = "monitor" ``` Qlty offers a continuously expanding set of security scanning plugins for different programming languages, frameworks, and infrastructure tools. Please review our [available plugins]() for the latest information. ## Review and triage issues Security scanners find issues which may indicate a risk or vulnerability. These issues can be reviewed on the "Issues" tab within your Project, which can be filtered to the Vulnerability issue category. When reviewing findings, the first step is validating that the reported issue is a true positive. This needs to be done carefully, as sometimes a human developer may inaccurately dismiss a real vulnerability. For true positives, the next steps generally involve creating a ticket in a project management tool like Jira or GitHub Issues, and fixing it immediately or running it through a prioritization process. For issues that are not valuable, you can ignore them through either your project configuration file or from within the Qlty web applicaiton. ## A note about false positives All static analysis for security scanning has some level of false positives. Our goal is to ensure a false positive rate below 5% to ensure a good signal-to-noise ratio in your results. If you are receiving false positive security findings, please [contact us](), as we may be able to assist. ## More information * Available plugins * Ignoring issues * Full `qlty.toml` reference # Support Source: https://docs.qlty.sh/cloud/support ## Support channels Qlty provides community support through the following channels on a best effort basis: * [Q\&A support](https://github.com/orgs/qltysh/discussions/categories/q-a) via GitHub Discussions * Live chat on [Discord](https://qlty.sh/discord) * [Feature requests](https://github.com/orgs/qltysh/discussions/categories/feedback) via GitHub Discussions * [Bug reports](https://github.com/qltysh/qlty/issues/new/choose) via GitHub Issues * [Plugin request](https://github.com/qltysh/qlty/issues/new/choose) via GitHub Issues ### Paid support channels Support for paid subscribers is available via the following channels: * [Email](https://qlty.sh/contact/support) * Shared Slack channel for businesses on Enterprise plans ## Support hours Paid support is available Monday through Friday 10am - 5pm ET, excluding US holidays. ## Support access If Qlty Support needs to access your private content to address your support request, they will request permission for temporary access. If approved, Qlty Support will have access to the repository for up to five days or until the issue is resolved. During this window, Qlty Support staff with the required privileges can impersonate web users within the customer workspace. Qlty Support will never access your private repositories without your explicit consent. For more information, see the [Terms of Use](https://qlty.sh/legal/terms-of-use). ## Maintenance windows When a maintenance window longer than 10 minutes is needed and known in advance, we will provide advanced notice. > [!NOTE] > > Nothing on this page supersedes any agreements you have with Qlty Software. # Triaging Issues with Qlty Cloud Source: https://docs.qlty.sh/cloud/triaging-issues Within the Qlty web application, you can interactively ignore issues to quickly triage false positives. ## Ignoring one instance of an issue * From the Issues tab, navigate to the page for the check * Click the "X" icon to the right of the specific issue you want to ignore * From the dropdown menu, choose "Ignore this as intentional" or "Ignore this as a false positive" * Optionally add a comment and click the "Ignore" button to confirm The specific issue will now be ignored. *Note:* We use a fingerprinting algorithm to identify ignored issues in future static analysis runs. Fingerprinting is inherently imperfect, and in some cases a fingerprint will change on a previously ignored issue. When this happens, you will need to ignore it again ## Ignoring a check everywhere * From the Issues tab, navigate to the page for the check * Click the "Ignore" button on the right side of the page header * From the dropdown menu, choose "Everywhere" * After confirming, the check will be ignored everywhere ## Ignoring a check in a file * From the Issues tab, navigate to the page for the check * Click the "Ignore" button on the right side of the page header * From the dropdown menu, choose "For a path pattern" * For the Pattern, input the full file path relative to the repository * After confirming, the check will be ignored anywhere in the file ## Ignoring a check in a directory * From the Issues tab, navigate to the page for the check * Click the "Ignore" button on the right side of the page header * From the dropdown menu, choose "For a path pattern" * For the Pattern, input the directory in path glob form e.g. `some/directory/**` * After confirming, the check will be ignored in any files matching the path glob ## Reviewing ignore rules Ignore rules that were created in the Qlty web application can be viewed on the "Ignored Issues" tab in Project Settings. They can be removed from that page, in which case the issues will change their Status from Ignored to Open. > [!NOTE] > > Ignore rules that are stored in the project configuration file (`.qlty/qlty.toml`) can be viewed > there. ## See Also * [Excluding Files CLI](/cli/excluding-files) * [Ignoring Checks and Issues with Qlty CLI](/cli/ignoring-issues) # Troubleshooting Source: https://docs.qlty.sh/cloud/troubleshooting > [!NOTE] > > If Qlty has detected a problem with your workspace, it will be listed under **Alerts** in your > workspace navigation: [Analysis is paused](/cloud/troubleshooting-analysis-paused) or [Coverage > not received for default branch](/cloud/troubleshooting-default-branch-coverage). ## Analysis Errors ### Unknown error (U10) These errors indicate an unknown problem with our system. Our developers monitor closely for these types of errors. In most cases when they occur, we are already looking into it. If you see this error, please contact our support team with your project name and a screenshot. ### Inconclusive commit status (U11) This error occurs when pull request analysis starts, but Qlty hasn't posted a conclusive (green or red) status back to GitHub within 15 minutes. At that point, Qlty will mark your GitHub commit status as `error` (red). It’s possible that the analysis succeeded, but an external factor interfered with posting the status back to GitHub (e.g. a GitHub outage, network issue, etc.). If this happens, you will need to retry the analysis. ### Analysis timeout We apply timeouts to analysis runs to keep things running smoothly. If you find that a pull request or commit analysis frequently times out, see our documentation on [Troubleshooting Build Timeouts](/cloud/troubleshooting-build-timeouts). ### Missing analysis results *Problem: No code review comments or commit statuses are showing on my pull requests.* If you're not seeing pull request statuses or summary/code comments for your project, first confirm that the [Qlty GitHub App](/cloud/github-app) has been installed and granted access to your repository. Next, confirm that these features are enabled under `Project Settings -> Code Review`. For further troubleshooting please contact support. If nothing at all is being analyzed for the project, analysis may be paused. See [Analysis is paused](/cloud/troubleshooting-analysis-paused). ## Code Coverage Issues Please refer to our docs on [Troubleshooting Code Coverage](/coverage/troubleshooting). ## Other Troubleshooting ### Missing project *Problem: When I go to add a repository as a project, it's not visible in the list.* If you're trying to add a project but it doesn't appear in the list of available projects, first confirm the following: * Our [GitHub Application](/cloud/github-app) installation must grant access for that repository. * The repository must be accessible by you on GitHub. * Double check that someone hasn't already added the repository to Qlty * If the repository has been renamed in GitHub, Qlty updates the project automatically. If it is still listed under its old name — which can happen when the rename occurred while the [Qlty GitHub App](/cloud/github-app) was not installed, such as on a project migrated from Code Climate Quality — resync it from **Project Settings > General**. ### Permission denied error *Problem: I am trying to access a workspace or project but am getting blocked.* If you encounter a permission denied error, consider the following possible causes and solutions: * Insufficient access to the GitHub repository: Project-level permissions on Qlty are determined by a user's GitHub permissions. To view project analysis on Qlty, you need read access to the repository on GitHub. To view project settings on Qlty, you need admin access to the repository on GitHub. * Multiple Qlty users: Having more than one Qlty user can cause confusion. If this is the issue, you are likely logged into a user account that hasn't been added to the workspace owning the project you are trying to access. ### Forked PR analysis *Problem*: I am unable to analyze PRs raised from a fork By default, Qlty does not analyze PRs raised from forks of a repo. This functionality is available on an opt-in basis. To enable analysis of PRs from forks, [contact support](https://qlty.sh/contact/support). * Please list the specific repo(s) for which you'd like to enable this feature * Note: analysis of PRs from *public* forks of a repo is not supported. ### Missing link to Settings *Problem: I believe I have workspace admin access but I don't see a link to settings.* To manage workspace settings on Qlty, you must be an admin on the associated GitHub account. Please ensure that you have the appropriate permissions before attempting to access these settings. ### Private linter plugins or configurations *Problem: My build is failing because a linter can't find my private gem/package.* Qlty is unable to access any private gems, packages, or registries during analysis. For example: * **Rubocop**: `Unable to find gem our-private-rubocop-config; is the gem installed?` * Some users may maintain their Rubocop configuration within a private gem; this is not currently supported. * **OSV-Scanner**: `failed extracting pom.xml` * OSV-scanner scans for vulnerable dependencies, and it cannot access private packages or package registries. It is possible to configure OSV-scanner to ignore specific packages, as documented [here](https://google.github.io/osv-scanner/configuration/#override-specific-package). * For more help with configuring linter plugins, see our docs on [Linter Extensions](/cli/linter-extensions). ## Authentication Issues ### SAML re-authentication required *Problem: I'm seeing a "SAML re-authentication required" error when trying to access a project or workspace.* This error occurs when your GitHub organization requires SAML single sign-on (SSO) authentication, and Qlty's authorization to access that organization has expired or been revoked. GitHub organizations that use SAML SSO require periodic re-authorization of third-party applications like Qlty. **Why this happens:** When you first authorize Qlty to access your GitHub account, you also authorize it to access any organizations you belong to. However, organizations using SAML SSO can require that this authorization be refreshed periodically for security purposes. When the authorization expires, Qlty can no longer access repositories in that organization until you re-authenticate. **How to resolve:** 1. **Log out of Qlty** by clicking your profile menu and selecting "Log out" 2. **Log back in** to Qlty using GitHub 3. During the GitHub authorization flow, you may see a "Single sign-on to your organizations" screen 4. **Click the "Authorize" button** next to each organization that requires SAML authentication > [!NOTE] > > Clicking "Continue" alone is not sufficient. You must click the "Authorize" button next to each > organization that requires re-authentication. ![GitHub SSO page showing Authorize buttons next to organizations](https://mintlify.s3.us-west-1.amazonaws.com/qltysoftware/cloud/github-saml-reauthorize.png) If you continue to experience issues after re-authorizing, contact your organization's GitHub administrator to ensure the Qlty GitHub App is properly configured for SAML SSO access. ## See Also * [Known Issues and Limits](/cloud/limits) # Analysis is paused Source: https://docs.qlty.sh/cloud/troubleshooting-analysis-paused > [!WARNING] > > Qlty is not analyzing this project. New commits and pull requests are not analyzed, and no > commit statuses are posted, until analysis resumes. ## What happened Qlty could not check out your repository. After repeated checkout failures, Qlty stops attempting to analyze your codebase rather than retrying indefinitely. ## Why it happened There are a few reasons why Qlty might not be able to clone your repository: * **A GitHub outage.** If GitHub was unavailable while your builds ran, Qlty could not reach your repository. Qlty does not resume on its own once GitHub recovers. * **The Qlty GitHub App no longer has access.** The app was uninstalled, or its repository access was changed and no longer includes this repository. * **The repository was transferred to another owner.** * **The repository was deleted.** If the cause applies to your whole GitHub organization, other projects in your workspace are likely paused as well. ## How to fix it **Start by queueing a build.** Click **Run build** on the alert, or **Build** on the project's [Builds page](/cloud/analysis-frequency#triggering-analysis-manually). Analysis resumes on the first build that succeeds, and the alert clears with it. This is the right place to start because a pause often outlasts its cause: after a GitHub outage is resolved, nothing else is wrong, and one successful build is all it takes. If the build fails instead, you know the problem is still present. If the build fails, work through these steps. ### 1. Confirm GitHub App access The [Qlty GitHub App](/cloud/github-app) is installed on a GitHub organization, and that installation grants access to either **All repositories** or **Only select repositories**. Analysis breaks when the app is uninstalled, or when the repository is no longer in the selected list. In Qlty, go to **Settings > General > Connections** for your workspace. It shows the Qlty GitHub App and its Repository Access, each with a link out to GitHub to change the configuration. ### 2. Re-sync with GitHub If the repository was transferred to another owner, Qlty does not pick that up on its own. Go to **Project Settings > General** and click **Re-sync** under **Re-Sync with GitHub**. Then queue another build. If builds still fail with a repository error after access looks correct, [contact support](/cloud/support) with the project name and a failing build URL. ## Why pushing new commits does not help While analysis is paused, Qlty only runs builds that someone asks for directly. Pushes, pull requests, and [scheduled analysis](/cloud/analysis-frequency) are all ignored, so waiting for the next commit will never resume analysis on its own. This keeps a paused project quiet until someone has looked at it, rather than failing on every push. # Troubleshooting Build Timeouts Source: https://docs.qlty.sh/cloud/troubleshooting-build-timeouts Qlty Cloud runs builds with a timeout to keep analysis stable and avoid runaway costs. The timeouts for builds are: * **Builds for default branches:** 20 minutes * **Builds for pull-request branches:** 10 minutes The timeouts are system-level limits and cannot be increased. If a build is still running when the timeout is reached, it is terminated by the work scheduler. ## Recognizing build timeouts Your analysis has likely timed out if you experience any of these symptoms: * **Build failures —** The analysis status fails after running for an extended period, typically due to a timeout. As a result, Build Artifacts may not be available for download. * **Incomplete logs —** When a timeout occurs, the logs may not show a completed analysis and can appear truncated, without the final "analysis completed" line. * **Issue-limit warnings** — "Maximum issue count of 500 reached” followed by a list of skipped files. While these warnings by themselves don’t indicate a timeout, excessive warnings (combined with a failed, incomplete build) can signal that too many files are being analyzed -- which can ultimately lead to a time-out. ## Fixing build timeouts ### File path exclusions Analysis timeouts are generally caused by either an abnormally large number of files under analysis or by attempting to analyze files not typically intended for static analysis. Review your project's exclude patterns to ensure you're excluding any files or folders you're not intending to analyze. You can specify file and directory exclusions in your qlty.toml configuration file. Excluding files reduces the time Qlty spends analyzing your project. In general, we recommend excluding: * Vendored code * Generated code * Production assets such as minimized files * Dependencies (e.g., `/node_modules/`, `vendor/`) * Temporary files (e.g., `.tmp/`, `cache/`) * Large binary files or assets Example exclusions in `qlty.toml`: ``` exclude_patterns = [ "node_modules/**", "vendor/**", "build/**", "dist/**", ".generated/**", "*.min.js", "*.bundle.js", "coverage/**", ".tmp/**" ] ``` You can also exclude files for specific plugins: ``` [[exclude]] plugins = ["osv-scanner", "trufflehog"] file_patterns = ["/tests/**"] ``` ### Linter selection Certain linters, especially linters which analyze the entire program at once instead of each file individually, can be resource intensive. Disabling expensive linters and/or checks is another dimension which can help. Review which plugins are currently enabled in your project and consider: * Disabling computationally expensive plugins that perform whole-program analysis * Reducing the scope of expensive checks within plugins * Running only essential plugins for time-sensitive builds You can disable specific plugins in your `qlty.toml`: ``` [[plugin]] name = "plugin.name" mode = disabled ``` Or comment out the specific plugins in your `qlty.toml`: ``` # [[plugin]] # name = "plugin.name" ``` #### Increase analysis runner resources For paid accounts, we now have the ability to increase the size of the analysis runner from the default 2 CPU and 4 GB RAM to larger sizes. This can be found in the Project Settings area. To increase your analysis runner resources: 1. Navigate to your Project Settings 2. Locate the Analysis Resources section 3. Increase the CPU and RAM allocation beyond the default limits 4. Monitor performance improvement after the change **Note:** This option is only available for paid account holders. **Step-by-step diagnosis** #### Profile locally Run `qlty check` locally with the `--verbose --all` flags to see which analysis take a high amount of time: ``` qlty check --verbose --all ``` This will show you detailed output about which files and plugins are consuming the most resources during analysis. #### Isolate problematic plugins: If the verbose output doesn't identify the culprit, you can systematically identify resource-intensive plugins: 1. Remove all plugins from your `qlty.toml` configuration 2. Add plugins back one-by-one 3. Run analysis after adding each plugin to identify which one causes the timeout This process will help you pinpoint exactly which plugin is causing performance issues. ## Verification * In Qlty CLI: Re-run `qlty check --verbose --all` locally to confirm runtime is below the timeout. * In Qlty Cloud: Re-run your build and monitor performance improvement after any runner-size changes. ## Getting help If you have tried the steps above and your build is still timing out, please contact [Support](https://docs.qlty.sh/support) for further assistance. ## Related resources * [**Excluding Files and Paths**](https://docs.qlty.sh/analysis-configuration#excluding-files-and-paths) — details on exclusion-pattern syntax. # Coverage not received for default branch Source: https://docs.qlty.sh/cloud/troubleshooting-default-branch-coverage ## What happened Qlty has received code coverage for this project from pull requests, but never from its default branch. Coverage is normally set up in a pull request, so what this tells you is that the setup never reached your default branch. Usually that is one of two things: * **The pull request that added coverage was never merged.** The coverage step exists only on that branch, so it runs on the pull request and nowhere else. * **It was merged, but the coverage step only runs on pull requests.** The CI trigger lists `pull_request` and not `push`. Either way, coverage keeps arriving and nothing looks broken from Qlty's side. ## Why it matters Qlty reports coverage for your default branch, so until it arrives the project has no coverage information at all: * No total coverage percentage or grade on the project's [Overview](/cloud/projects/overview). * No coverage in the [Code view](/coverage/browsing), including line-by-line coverage for individual files. * No [trend chart](/coverage/trends), [hotspots](/coverage/hotspots), or coverage-coloured sunburst. * The **Qlty Coverage** [commit status](/coverage/commit-statuses) has no base branch coverage to compare against. ## How to fix it ### 1. Check whether the pull request was merged Find the pull request that added coverage to your CI configuration. If it is still open, merging it is the whole fix. ### 2. If it was merged, check the CI trigger Your coverage step needs to run on pushes to the default branch, not only on pull requests. In GitHub Actions, that means adding your default branch to `push`: ```yaml theme={"system"} on: push: branches: [main] pull_request: ``` Then confirm the coverage publish step is not itself conditional on the event being a pull request. > [!NOTE] > > The alert clears once Qlty has processed a coverage report for your default branch. For the full setup, see the [Code Coverage quickstart](/coverage/quickstart). If reports are being sent but not arriving, see [Troubleshooting Code Coverage](/coverage/troubleshooting). ## What counts Only coverage published for the project's configured default branch clears this alert. Coverage on another long-lived branch does not. If Qlty has the wrong default branch, go to **Project Settings > General** and click **Re-sync** under **Re-Sync with GitHub**. The count shown on the alert is the number of coverage reports Qlty has received from pull requests. It is there to show that coverage is arriving — the problem is where it is arriving from, not whether it works. You can see every report Qlty has received under **Project Settings > Code Coverage > Reports**. # Code Smells Source: https://docs.qlty.sh/code-smells Code smells are indicators of potential issues in your code that may not necessarily be bugs but could lead to deeper problems down the line. They suggest areas of your codebase that might benefit from refactoring to improve readability, maintainability, and overall quality. Identifying and addressing code smells can help prevent technical debt and ensure a more robust codebase. Qlty implements eight checks for common code maintainability issues which consider code structure and duplication. By default, these checks run on any files in one of our Supported Languages. > [!TIP] > > Code smell detection is provided by [Qlty CLI](/cli/quickstart) and [Qlty > Cloud](/cloud/quickstart). ## Similar code Duplicate code which is not identical but shares the same structure (e.g. variable names may differ) ## Identical code Duplicate code which is syntactically identical (but may be formatted differently) ## Many function parameters Methods or functions defined with a high number of arguments ```js Bad example lines theme={"system"} function foo(a, b, c, d, e, f, g) { // ... } ``` ```js Good example lines theme={"system"} function foo(a, b, c) { // ... } ``` ## Complex boolean logic Boolean logic that may be hard to understand ## High file complexity Excessive lines of code within a single file ## High function complexity Functions or methods that may be hard to understand (Cognitive Complexity) ## Deeply nested control flow Deeply nested control structures like if or case ## Many return statements Functions or methods with a high number of return statements > [!NOTE] > > Each maintainability check ships with a default threshold. These thresholds can be adjusted or > the check can be disabled entirely in the [`qlty.toml` configuration > file](/cli/analysis-configuration#maintainability-checks-and-thresholds). ## See Also * [Analysis Configuration](/cli/analysis-configuration) * [Complexity](/complexity) * [Duplication](/duplication) # Complexity Source: https://docs.qlty.sh/complexity Complexity (or *cognitive* complexity) is a measure of how difficult a unit of code is to intuitively understand. Unlike [Cyclomatic Complexity](https://en.wikipedia.org/wiki/Cyclomatic_complexity), which determines how difficult your code will be to test, our Complexity metric tells you how difficult your code will be to read and understand. Understanding and managing code complexity is crucial for several reasons: 1. **Readability:** Code that is easy to read helps developers quickly grasp the logic and intent, facilitating better collaboration and code reviews. 2. **Defect Prevention:** Lower complexity reduces the likelihood of bugs, as straightforward code paths are less prone to errors. 3. **Efficiency:** Developers can work more efficiently with less complex code, leading to faster development cycles and more reliable software. By identifying and addressing complex code, developers can enhance the maintainability, readability, and overall quality of their codebase. Qlty can help you identify which files and functions are overly difficult to understand and prevent introducing them into your code. > [!TIP] > > Complexity insights are provided by [Qlty CLI](/cli/quickstart) and [Qlty > Cloud](/cloud/quickstart). > [!NOTE] > > Our Complexity metric powers our [Code Smells](/code-smells) for high function complexity and > high file complexity. ## The Idea A functions's Complexity is based on a few simple principles: 1. Code is considered more complex when it uses shorthand that the language provides for collapsing multiple statements into one 2. Code is considered more complex for each break in the linear flow of the code 3. Code is considered more complex when flow breaking structures are nested Let's break those down: ### Shorthand Let's say you're writing Ruby, and you write: ```ruby Ruby && conditional lines theme={"system"} def destroy(post) if current_user && current_user.admin? post.destroy end end ``` This uses `&&`, which contributes the method's Complexity. If, however, you were to use the "safe navigation" operator and write: ```ruby Ruby safe navigation lines theme={"system"} def destroy(post) if current_user&.admin? post.destroy end end ``` This is a bit more intuitive, and doesn't contribute to the method's Complexity. ### Breaks in flow When a method's logic flows from top to bottom, it is very easy to understand. Take this JavaScript snippet for example: ```javascript Simple total lines theme={"system"} function count(a, b, c) { var total = 0; total += a; total += b; total += c; return total; } ``` It flows from top to bottom with no breaks. Compare to this alternative implementation: ```javascript Looping total lines theme={"system"} function count(a, b, c) { var total = 0; var nums = [a, b, c]; for (var i = 0; i < nums.length; i++) { total += nums[i]; } return total; } ``` The `for` loop changes the function so it no longer flows directly from top to bottom, but now loops in circles a few times in the middle, which contributes to Complexity for the reader. It's a small thing, but it adds up. Other examples of breaks in flow: * loops * conditionals * catching/rescuing exceptions * switch or case statements * sequences of logical operators (e.g. `a || b && c || d`) * recursion * jumps to labels ### Nesting The more deeply-nested your code gets, the harder it can be to reason about. This line of Java is pretty straight-forward: ```java If statement lines theme={"system"} if (env.debugMode()) { System.out.println("Hello, world!"); } ``` But when you're nested within multiple layers of conditionals or loops, a simple conditional isn't just a simple conditional, and leads to a greater Complexity. Here's the same conditional, in a totally different context: ```java Nested logic lines theme={"system"} while(theWorldTurns) { if(isMorning) { try { if (env.debugMode()) { System.out.println("Hello, world!"); } } catch (BadDay e) { System.out.println("Yikes!"); } } } ``` In this example, the same conditional adds more complexity. Context matters. The following count as nesting: * conditionals * loops * try/catch blocks ## Difference from Cyclomatic Complexity As an example of code which is easy to understand, but difficult to test, consider this PHP example: ```php Switch/case in PHP lines theme={"system"} [!TIP] > > Automatic setup is tested on GitHub Actions. On other CI providers it is best effort. See [Which CI providers it supports](#which-ci-providers-it-supports). ## Before you start * You need the **admin** role on the project. * The [Qlty GitHub App](/cloud/github-app) must be installed on the repository. On GitHub Actions, it also needs the **Workflows** permission. That permission was added in September 2026, so if the app was installed earlier, an organization owner has to accept it. See [Accepting new permissions](/cloud/github-app#accepting-new-permissions). * The project needs CI that runs automated tests. The agent adds a coverage upload step. It does not write tests. ## Setting up coverage ### 1. Open the setup page Go to **Project Settings > Code Coverage** and click **Set up coverage**. The page is also linked from the grey coverage shield on the project's Overview and in the projects list, for any project with no coverage yet. The **Automatic** tab is selected by default. ### 2. Click Set up automatically Qlty starts a build and takes you to its page. The build usually takes a few minutes. When it finishes, the build page shows the result with a link to the pull request. If the Qlty GitHub App is not installed on the repository, or it is missing the Workflows permission, the page says so. The message links to the GitHub page that fixes it. ### 3. Review the draft pull request The pull request is titled **Set up Qlty code coverage**. Qlty requests a review from you when GitHub allows it, which requires you to be a collaborator on the repository. Its description is the agent's report: what it changed, why, and anything you must do before merging. On GitHub Actions the upload authenticates with [OIDC](/coverage/tokens), so nothing is needed before merging. On other CI providers the pull request asks you to add a [coverage token](/coverage/tokens) as a CI secret. Add it before merging. Check the pull request's CI run for a successful upload. The upload step's log shows a line like `Line Coverage: 84.2%`. ### 4. Merge it After the next CI run on your default branch, the project shows total coverage, per-file coverage grades, and line-by-line coverage. Reports arrive under **Project Settings > Code Coverage > Reports**. ## What the agent does Qlty Cloud's agent runs in an isolated build container with a copy of your default branch and no Git credentials. It reads the CI configuration and the test setup, then reads these docs and makes the smallest change that produces complete coverage: * Where coverage data is already generated, it adds only the upload step and points it at the existing output file. * Where coverage data is not generated yet, it adds the minimum configuration to produce a report in a [supported format](/coverage/formats), passing flags from the CI workflow rather than editing the project's own scripts. * Where a Qlty upload already exists, it repairs that upload if it is incomplete and otherwise makes no changes. * Where several jobs or matrix entries produce different coverage, it uploads from each one and uses [server-side merging](/coverage/merging). Where CI runs test suites selectively, it uses [tags](/coverage/tags) instead. * On GitHub Actions it uses the [Qlty GitHub Action](https://github.com/qltysh/qlty-action) with OIDC, and skips uploads on pull requests from forks, which have no OIDC token. The agent cannot run your tests, install dependencies, or watch a CI run. It designs the change from the configuration and the docs, and the pull request says so. That is why the pull request is a draft: the first CI run on it is the test. The agent never adds secrets, never adds test suites, and never sets `validate: false` to get past a path validation error. ## When the pull request's CI fails Pull request CI failing or no report arriving usually means a path or format detail the agent could not check without running the tests. From the setup page, choose **Your agent** to run Qlty's open source [`setup-coverage` skill](https://github.com/qltysh/qlty-skills/tree/main/skills/setup-coverage) in your own coding agent. It can run your tests and iterate until CI passes. Or choose **Manual** and follow the [Coverage Quick Start](/coverage/quickstart). ## Which CI providers it supports | CI provider | Support | How it uploads | | - | - | - | | GitHub Actions | Tested | Qlty GitHub Action with OIDC. No secret needed. | | CircleCI | Best effort | [Qlty CircleCI Orb](https://circleci.com/developer/orbs/orb/qltysh/qlty-orb) with a workspace coverage token | | Other providers | Best effort | Qlty CLI with a workspace coverage token | "Best effort" means the agent follows the same approach, but we have not verified the results across these providers. Review the pull request with extra care, and expect to add the coverage token before merging. ## Build results The build page shows one of these results: * **Opened a pull request to set up code coverage.** Review and merge it. * **No coverage changes were needed.** Coverage is already set up and correct, or the repository has no CI or tests to add coverage to. The agent's explanation is on the build page. * **Coverage setup did not finish.** The run hit its cost or step limit, or ended with an error. Each run has a budget of 45 minutes. Start it again, or use **Your agent** or **Manual** setup. * **Could not open a pull request.** Qlty could not push the branch or open the pull request on GitHub, usually because of a permission change. Check the GitHub App's permissions and start it again. You can start setup again at any time from the same page. ## Data processing To set up coverage, Qlty sends the contents of your repository's default branch to an AI subprocessor, currently Anthropic, together with your CI configuration and the Qlty docs the agent reads. The subprocessor does not train models on this data. See [Data Usage](/cloud/data-usage). The agent runs with no Git or GitHub credentials, and it can only fetch pages from `docs.qlty.sh`, `docs.github.com`, and the CircleCI orb registry. The only way work leaves the container is the patch that Qlty turns into the pull request, which you review before anything runs on your default branch. ## Next steps * [Coverage Quick Start](/coverage/quickstart) for manual setup, or to understand what the pull request changed * [Coverage Tokens](/coverage/tokens) for OIDC and token authentication * [Troubleshooting Code Coverage](/coverage/troubleshooting) if reports are sent but not arriving # Chrome and Firefox Extension Source: https://docs.qlty.sh/coverage/browser-extension The Qlty Browser Extension enhances your GitHub experience by integrating code coverage information directly into the GitHub interface. This makes it easy to view coverage data while reviewing code, without switching contexts. The extension is currently in **alpha** and under active development. It’s not yet available in the Chrome Web Store or Firefox Add-ons Marketplace. You can try out the current version of the Chrome extension by installing it manually from our GitHub repository: [qltysh/qlty-browser](https://github.com/qltysh/qlty-browser) We’re actively looking for feedback. If you give it a spin, let us hear how it works for your team. # Browsing Coverage Source: https://docs.qlty.sh/coverage/browsing Qlty Cloud lets you browse a project's coverage data interactively, drilling from project-wide numbers down to individual lines. Browsing happens through the same per-project navigation that serves maintainability data, so coverage signals show up alongside other quality information for each file. ## Where to browse from There are three entry points depending on what you're trying to answer: ### Project Overview (Coverage tab) For a quick snapshot of where coverage stands on the tracked branch, open the project's [Overview](/cloud/projects/overview) page and switch to the **Coverage** tab. You get: * The project's total coverage percentage and grade. * The [Trend chart](/coverage/trends) — coverage over the last 30 days. * The [Hotspots list](/coverage/hotspots) — top files with the lowest coverage. * A coverage-coloured [Sunburst chart](/cloud/projects/overview#sunburst-chart) for spotting under-covered subtrees at a glance. ### Code view (per-file metrics) To walk the repository's directory tree with coverage alongside complexity and size, use the project's [Code](/cloud/projects/code) tab. Tree, List, and Unformatted-Files sub-views all expose coverage percentage as a sortable column. Clicking a file opens its metrics page, which includes line-by-line coverage hits. ### Pull Request coverage To see how a specific change affected coverage, open a PR from the [Pull Requests](/cloud/projects/pull-requests) tab and switch to the PR's **Coverage** sub-tab. That view breaks coverage impact into direct changes, [indirect changes](/coverage/unexpected-changes), and per-[component](/coverage/components) coverage. ## Filtering by coverage tag If your project uploads multiple [coverage tags](/coverage/tags) (e.g. `unit` and `integration`), the various views show coverage **per tag** as well as combined. This lets you answer questions like "what's our integration coverage on this file?" independent of unit-test coverage. ## What you need first All of these views require coverage reports to have been uploaded: * For project-level views, you need at least one upload on the tracked branch. * For PR-level views, you need an upload on the PR's head commit. If a view shows empty data, follow [Setting up Code Coverage](/coverage/quickstart) to wire up uploads from your CI. ## See Also * [Code Coverage](/coverage) * [Coverage Trends](/coverage/trends) * [Coverage Hotspots](/coverage/hotspots) * [Code view](/cloud/projects/code) * [Pull Request Coverage](/cloud/projects/pull-requests) # Carry Forward Tags Source: https://docs.qlty.sh/coverage/carry-forward-tags Carry forward tags allow Qlty to automatically reuse coverage data from previous commits when a commit runs only some of a project's test suites, ensuring your coverage metrics remain complete and accurate even when not every test suite runs. ## Background Many modern CI systems are configured to run only some of a project's test suites on each commit. One example is a monorepo where each folder represents a distinct service, configured to run only the test suites for the services that have changed. When test suites run selectively, coverage cannot be strictly compared across commits because those commits may have run different test suites, generating coverage reports that are unrelated. Because coverage data is associated with commits, this creates unique challenges associated with per-commit coverage: * The latest commit (alone) for a project won't have comprehensive coverage data * A pull request is a comparison across 2 commits, and these commits can have different coverage reports Qlty solves this problem with the intelligent use of coverage tags: if a project defines a tag per component, Qlty "carries forward" coverage for a tag from a previous commit onto a more recent relevant commit. While this behavior is seamless and requires no setup other than defining tags, understanding Carry Forward Tags can help you comprehend how coverage calculations are performed when test suites run selectively. ## How Carry Forward Works When Qlty processes coverage for a commit, it automatically fills in missing tag data by carrying forward the most recent coverage report for each tag. For example, in the following diagram, while the most recent commit, at the top, does not have direct coverage report data, the coverage data associated with the coverage tags "component A" and "component B" will be carried forward. ```mermaid theme={"system"} --- config: theme: base --- gitGraph TB: commit type: HIGHLIGHT commit tag:"component A" commit commit tag:"component B" commit ``` This ensures that your dashboards, PR checks, and coverage overlays always show the most complete and up-to-date coverage information available, even if that coverage information spans multiple commits. ## Best Practices To make the most of the automatic carry forward behavior: ### Consistent Tag Usage Use consistent tag names across all your coverage uploads. This ensures proper tracking and carry-forward behavior. ```bash Consistent Tag Names lines theme={"system"} # Correct approach - consistent tag name qlty coverage publish --tag=unit unit-tests.lcov qlty coverage publish --tag=unit more-unit-tests.lcov # Incorrect approach - inconsistent tag names qlty coverage publish --tag=unit unit-tests.lcov qlty coverage publish --tag=unit-tests more-unit-tests.lcov ``` ### Regular Complete Coverage Periodically run and upload coverage for all tags, such as on your main branch or nightly builds. This ensures carried forward data doesn't become too outdated. ## Limitations While carry forward is a valuable built-in behavior, it's important to understand its limitations: 1. **Accuracy over time**: Carried-forward data may become outdated if a component goes untested for a long period 2. **File-level granularity**: Carry forward operates at the tag level, not at individual file or line level 3. **Branch integrity**: Data is only carried forward within the same branch history 4. **Tag consistency**: Carry-forward requires consistent usage of tags across commits -- e.g. Carry forward will not work properly if the same tag reports information for a different set of tests each time ## See Also * [Coverage Tags](/coverage/tags) - How to organize coverage with tags * [Coverage Metrics](/coverage/metrics) - Understanding coverage measurements # CI Integration / Uploader Source: https://docs.qlty.sh/coverage/ci Integrating code coverage reporting into your CI pipeline ensures that coverage data is consistently collected and reported for every build. Qlty is compatible with every major CI provider. Qlty offers CI-specific packages for GitHub Actions (GitHub Action) and CircleCI (CircleCI Orb), but works just as well without them. Qlty provides [environment detection](/coverage/ci#environment-detection) for most CI providers, making integration simpler, but offers simple instructions for those without it. | CI Provider | Package | Environment Detection | OIDC | | - | - | - | - | | [GitHub Actions](/coverage/ci#github-actions) | qlty-action | Yes | Yes | | [CircleCI](/coverage/ci#circleci) | qlty-orb | Yes | No | | [Buildkite](/coverage/ci#buildkite) | | Yes | No | | [Jenkins](/coverage/ci#jenkins) | | Yes | No | | [CodeFresh](/coverage/ci#other-ci-providers) | | Yes | No | | [SemaphoreCI](/coverage/ci#other-ci-providers) | | Yes | No | | [TravisCI](/coverage/ci#travisci) | | Yes | No | | [bitrise](/coverage/ci#bitrise) | | Yes | No | | [Other CI Providers](/coverage/ci#other-ci-providers) | | No | No | ## CI Provider Integration ### GitHub Actions Integrate with Qlty using our GitHub Action. While integration can be done without our GitHub Action, using it allows you to take advantage of [OIDC support](/coverage/tokens). ```yaml OIDC-based authentication (recommended) lines theme={"system"} # .github/workflows/test.yml name: Test and Coverage on: push: branches: [ main ] pull_request: branches: [ main ] permissions: contents: read id-token: write # Required for OIDC jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 # Run your tests with coverage - name: Run tests run: npm test -- --coverage # Upload coverage to Qlty - uses: qltysh/qlty-action/coverage@v2 with: oidc: true files: coverage/lcov.info ``` ```yaml Using a Coverage Token lines theme={"system"} # .github/workflows/test.yml name: Test and Coverage on: push: branches: [ main ] pull_request: branches: [ main ] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 # Run your tests with coverage - name: Run tests run: npm test -- --coverage # Upload coverage to Qlty - uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: coverage/lcov.info ``` #### How the action verifies the Qlty CLI Before it runs the Qlty CLI, the action checks the CLI's [attestation](/cli/integrity-verification) with the GitHub CLI (`gh`). If the check rejects the CLI, the step fails, even with `skip-errors: true`, and the CLI never runs. If the check can't finish because GitHub is unavailable, the CLI doesn't run either, and `skip-errors` decides whether the step fails. `skip-errors`, which is on by default, keeps a problem with Qlty or with a service the action depends on from failing your build: a failed upload, a CLI error, or an attestation check that can't finish. It never lets an unverified Qlty CLI run. The check needs `gh` 2.67.0 or later on the machine that runs the step. GitHub-hosted runners include it. Self-hosted runners and `container:` jobs often don't. Without a usable `gh`, the action logs a warning that the run is unverified and continues. * **Pin versions deliberately:** if you pin the action by commit SHA or exact tag, or set `cli-version`, update those pins when a security release ships. `qltysh/qlty-action/coverage@v2` follows the latest v2 release. * **Self-hosted runners:** install `gh`, keep the operating system's `ca-certificates` package current, and keep the runner itself up to date, since actions run on the Node version bundled with the runner. ### CircleCI Qlty offers a CircleCI Orb for easy integration. ```yaml Using Qlty's CircleCI Orb lines theme={"system"} # Add the Qlty orb to your `.circleci/config.yml`: version: 2.1 orbs: qlty-orb: qltysh/qlty-orb@0.0 jobs: test: docker: - image: cimg/node:16.13 steps: # Checkout is required - checkout - run: name: Install dependencies command: npm ci - run: name: Run tests with coverage command: npm test - qlty-orb/coverage_publish: files: coverage/lcov.info workflows: main: jobs: - test ``` ```yaml Without Qlty's CircleCI Orb lines theme={"system"} version: 2.1 jobs: test: docker: - image: cimg/node:16.13 steps: - checkout - run: name: Install dependencies command: npm ci - run: name: Run tests with coverage command: npm test - run: name: Install Qlty CLI command: curl https://qlty.sh | sh - run: name: Upload coverage command: qlty coverage publish coverage/lcov.info environment: QLTY_COVERAGE_TOKEN: ${QLTY_COVERAGE_TOKEN} workflows: main: jobs: - test ``` ### Travis CI Add Qlty coverage reporting to your `.travis.yml`: ```yaml lines theme={"system"} language: node_js node_js: - 16 script: - npm test -- --coverage after_success: - curl https://qlty.sh | sh - qlty coverage publish coverage/lcov.info ``` Make sure to add your `QLTY_COVERAGE_TOKEN` in the Travis CI repository settings. > [!NOTE] > > On Travis CI, `qlty coverage publish` detects the branch for **push builds** (merge commits and > direct pushes) as well as Pull Request builds, so no `--override-branch` is required. ### GitLab CI Add coverage reporting to your `.gitlab-ci.yml`: ```yaml lines theme={"system"} test: stage: test script: - npm ci - npm test -- --coverage - curl https://qlty.sh | sh - qlty coverage publish coverage/lcov.info artifacts: paths: - coverage/ ``` Add your `QLTY_COVERAGE_TOKEN` as a CI/CD variable in your GitLab project settings. ### Buildkite Export your QLTY\_COVERAGE\_TOKEN as an environment variable. (See Buildkite's documentation on [managing secrets](https://buildkite.com/docs/pipelines/security/secrets/managing). One option is to export `QLTY_COVERAGE_TOKEN` in an [environment agent hook](https://buildkite.com/docs/pipelines/security/secrets/managing#without-a-secrets-storage-service-exporting-secrets-with-environment-hooks)): ```bash lines theme={"system"} #!/usr/bin/env bash set -e export QLTY_COVERAGE_TOKEN="YOUR_COVERAGE_TOKEN" ``` Then update your pipeline.yaml appropriately. Here's an example with Ruby test coverage: ```yaml lines theme={"system"} steps: - label: ":ruby: Ruby 3.1 Tests" key: "ruby-tests" command: | bundle install bundle exec rspec --require spec_helper artifact_paths: - "coverage/coverage.json" - wait - label: ":chart_with_upwards_trend: Coverage Report" command: | # Download the coverage artifact buildkite-agent artifact download "coverage/coverage.json" . curl https://qlty.sh | sh qlty coverage publish coverage/coverage.json depends_on: "ruby-tests" ``` ### Jenkins Jenkins requires a credentials entry for your `QLTY_COVERAGE_TOKEN`. To add this: 1. Navigate to **Manage Jenkins** → **Manage Credentials** 2. Select the appropriate credentials store (usually **Jenkins** → **Global credentials**) 3. Click **Add Credentials** 4. Set the **Kind** to **Secret text** 5. Enter your Qlty coverage token as the **Secret** 6. Set the **ID** to `qlty-coverage-token` 7. Add a **Description** (e.g., "Qlty Coverage Token") 8. Click **Create** Here's an example `Jenkinsfile` with Ruby test coverage: ```groovy lines theme={"system"} pipeline { agent any environment { GEM_HOME = "${WORKSPACE}/.gem" PATH = "${WORKSPACE}/.gem/bin:${env.PATH}" BUNDLE_PATH = "${WORKSPACE}/vendor/bundle" QLTY_COVERAGE_TOKEN = credentials('qlty-coverage-token') } stages { stage('Checkout') { steps { checkout scm } } stage('Install Dependencies') { steps { sh 'bundle install --jobs 4 --retry 3' } } stage('Run Tests') { steps { sh 'bundle exec rspec --require spec_helper' } } stage('Upload Coverage') { steps { sh ''' curl -sSL https://qlty.sh | sh ~/.qlty/bin/qlty coverage publish coverage/coverage.json ''' } } } post { always { cleanWs() } } } ``` The `credentials('qlty-coverage-token')` function retrieves the secret text credential you created and makes it available as the `QLTY_COVERAGE_TOKEN` environment variable. ### bitrise Configure your `QLTY_COVERAGE_TOKEN` as a [project level token](https://docs.bitrise.io/en/bitrise-ci/configure-builds/secrets.html). Check "Exposed to pull requests" in order to see diff coverage and total coverage in pull requests. The coverage data file(s) must be placed somewhere accessible to future steps. bitwrise's documentation lists [several options for managing files across steps](https://docs.bitrise.io/en/bitrise-ci/run-and-analyze-builds/managing-build-files/using-files-in-your-builds.html). Assuming a coverage data file located at `coverage.lcov`, the following step uploads coverage to qlty.sh: ```yaml lines theme={"system"} - script@1: inputs: - content: |- #!/usr/bin/env bash set -e set -o pipefail set -x curl https://qlty.sh | sh ~/.qlty/bin/qlty coverage publish coverage.lcov ``` ### Other CI Providers As long as your CI environment [meets the system requirements](/cli/system-requirements) to install the Qlt CLI, you can publish coverage. Publishing coverage on any CI provider follows the same procedure: 1. Ensure a `QLTY_COVERAGE_TOKEN` is available in the environment 2. Install the Qlty CLI 3. Execute `qlty coverage publish` command with the correct arguments For example: ```bash lines theme={"system"} # Assumes $QLTY_COVERAGE_TOKEN is set in the environment curl https://qlty.sh | sh qlty coverage publish coverage/lcov.info # Replace with path to your coverage data file(s) ``` > [!TIP] > > For security-sensitive environments, you can [verify the CLI's > integrity](/cli/integrity-verification) before installation. The Qlty CLI coverage commands leverage as much information from its environment as possible to ease integration. This includes environment variables as well as git metadata from the current working directory. However, sometimes, such as when attempting to publish coverage from a CI provider not listed above, Qlty is unable to detect this information from its environment. In these cases, you will need to provide the missing metadata to `qlty coverage publish` as additional arguments. Because usually no more than 2 - 4 arguments are needed, we recommend a trial and error process, following the instructions provided by the command when it errors. Below are some common scenarios you may run into. #### Path Validation Failures `qlty coverage publish` validates that the source files specified in your coverage data files match the source files in your repository. This ensures that we're able to properly associate coverage with your source files in Qlty Cloud. If we're unable to validate that a majority (up to a configurable threshold) of the source files referenced exist in your repository, `qlty coverage publish` will error. Usually these validate failures this can be addressed with the `--add-prefix` and/or `--strip-prefix` arguments. See [Path Fixing](/coverage/path-fixing) for more information. #### Commit SHA Missing A commit sha is always required when sending coverage data to Qlty.sh. The commit sha can be manually specified with: `--override-commit-sha ` #### Reference Missing When publishing coverage, Qlty associates the coverage data with a single reference. The reference can be one of: * a branch * a pull request * a git tag If not inferred, provide one of the following: * pull request: `--override-pr-number ` * branch: `--override-branch ` (can be used alongside `--override-pr-number`) * git tag: `--override-git-tag ` (cannot be combined with either `--override-pr-number` or `--override-branch`) #### Commit Time Missing A timestamp associated with the commit is also required. This can be specified with: `--override-commit-time ` The commit time can be a Unix timestamp (seconds since epoch) or a date in RFC3339/ISO8601 format. #### Examples ```shell Branch Override lines theme={"system"} QLTY_COVERAGE_TOKEN=QLTY_TOKEN qlty coverage publish --override-branch=main --override-commit-sha=e83c5163316f89bfbde7d9ab23ca2e25604af290 --override-commit=time=1704067200 lcov.info ``` ```shell Pull Request Override lines theme={"system"} QLTY_COVERAGE_TOKEN=QLTY_TOKEN qlty coverage publish --override-pr-number=34 --override-branch=feature-1 --override-commit-sha=e83c5163316f89bfbde7d9ab23ca2e25604af290 --override-commit=time=1704067200 lcov.info ``` ```shell Git Tag Override lines theme={"system"} QLTY_COVERAGE_TOKEN=QLTY_TOKEN qlty coverage publish --override-git-tag=v0.2.2 --override-commit-sha=e83c5163316f89bfbde7d9ab23ca2e25604af290 --override-commit=time=1704067200 lcov.info ``` ## Advanced CI Configuration ### Parallelized Tests When running tests in parallel, you'll need to merge the coverage reports before uploading. Qlty supports both client-side and server-side merging. #### Client-side Merging Collect all coverage reports into a single location and upload them together: ```bash lines theme={"system"} qlty coverage publish report1.lcov report2.lcov report3.lcov ``` #### Server-side Merging Upload each part separately and specify the total number of parts: ```bash lines theme={"system"} # Part 1 qlty coverage publish --total-parts-count=3 report1.lcov # Part 2 qlty coverage publish --total-parts-count=3 report2.lcov # Part 3 qlty coverage publish --total-parts-count=3 report3.lcov ``` Learn more about [Coverage Merging](/coverage/merging). ### Multiple Test Suites If you have different types of tests (unit, integration, e2e), you can track them separately using coverage tags: ```bash lines theme={"system"} # Upload unit test coverage qlty coverage publish --tag=unit unit-coverage.lcov # Upload integration test coverage qlty coverage publish --tag=integration integration-coverage.lcov ``` Learn more about [Coverage Tags](/coverage/tags). ## Environment Detection ### What is environment detection? Environment detection is Qlty CLI's ability to infer, without user input, metadata about your build from CI provider-specific environment variables. For example, CircleCI exposes the commit being built in an environment variable `CIRCLE_SHA1`. Without specific environment detection, you can still use our coverage publisher with a few extra command line arguments. See our documentation on [Other CI Providers](#other-ci-providers). ### Adding Environment Detection If you want automatic environment detection: 1. Double check [our Qlty repository](https://github.com/qltysh/qlty/tree/main/qlty-coverage/src/ci) for the most up to date list of supported CI providers. 2. Our coverage publisher is open source and you can add support by following [the other provider examples](https://github.com/qltysh/qlty/tree/main/qlty-coverage/src/ci) in under an hour. (Provide an LLM with the other examples and a link to your CI provider's list of available environment variables) ## Troubleshooting ### Common Issues * **Authentication failures**: Check that your token is correctly set as an environment variable * **Report format not recognized**: Make sure you're using a [supported coverage format](/coverage/formats) * **Path mismatches**: Use the `--strip-prefix` and `--add-prefix` options to [fix file paths](/coverage/path-fixing) * **Missing metadata**: Use `--override-branch`, `--override-commit` and `--override-build-id` if CI detection fails ## See Also * [Coverage Merging](/coverage/merging) - Combine multiple coverage reports * [Coverage Tags](/coverage/tags) - Track different test suites separately # Supported CI Providers Source: https://docs.qlty.sh/coverage/ci-providers Qlty is compatible with every major CI provider. Qlty offers CI-specific packages for GitHub Actions (GitHub Action) and CircleCI (CircleCI Orb), but works just as well without them. Qlty provides [environment detection](/coverage/ci#environment-detection) for most CI providers, making integration simpler, but offers simple instructions for those without it. | CI Provider | Package | Environment Detection | OIDC | | - | - | - | - | | [GitHub Actions](/coverage/ci#github-actions) | qlty-action | Yes | Yes | | [CircleCI](/coverage/ci#circleci) | qlty-orb | Yes | No | | [Buildkite](/coverage/ci#buildkite) | | Yes | No | | [Jenkins](/coverage/ci#jenkins) | | Yes | No | | [CodeFresh](/coverage/ci#other-ci-providers) | | Yes | No | | [SemaphoreCI](/coverage/ci#other-ci-providers) | | Yes | No | | [TravisCI](/coverage/ci#travisci) | | Yes | No | | [bitrise](/coverage/ci#bitrise) | | Yes | No | | [Other CI Providers](/coverage/ci#other-ci-providers) | | No | No | # Commit Statuses Source: https://docs.qlty.sh/coverage/commit-statuses Qlty can report code coverage metrics as GitHub commit statuses, making it easy to see at a glance if your code meets your coverage requirements. This guide explains how to set up and configure coverage-based commit statuses. ## What are Commit Statuses? Commit statuses are indicators displayed on GitHub pull requests that show whether certain checks or tests have passed or failed. Qlty can add statuses based on your code coverage metrics, helping you enforce quality standards. ## Available Coverage Statuses Qlty provides two types of coverage statuses: ### Total Coverage This status shows the total code coverage percentage for your pull request, and its delta as compared to the base branch. You can configure it to fail if: * Total coverage decreases compared to the base branch ### Diff Coverage This status shows the code coverage percentage only for lines changed in the pull request. You can configure it to fail if: * Diff coverage is below a minimum threshold ## Enabling Coverage Statuses To enable coverage statuses: 1. Go to your project in Qlty 2. Navigate to "Project Settings" > "Code Review" 3. Turn on Qlty Coverage and/or Qlty Coverage diff 4. Configure the thresholds according to your requirements ## Configuration Options ### Total Coverage Options * **Total Coverage Variation**: If total coverage drops by at least this percentage, Qlty will post a failed status to this commit. ### Diff Coverage Options * **Diff Coverage**: The minimum coverage required for changed lines * **Minimum Diff Size**: The minimum number of lines that must be changed for this status to apply ## Example Configurations ### Strict Coverage Policy This configuration enforces high standards for both total and differential coverage: * **Qlty Coverage**: * Total Coverage Variation: 1% * **Qlty Diff Coverage**: * Minimum diff coverage: 90% * Minimum lines: 5 ### Gradual Improvement Policy This configuration allows for gradual improvement while still maintaining standards: * **Qlty Coverage**: * Total Coverage Variation: 1% * **Qlty Diff Coverage**: * Minimum diff coverage: 30% * Minimum lines: 5 ## Branch Protection Rules To fully enforce your coverage requirements, integrate these statuses with GitHub branch protection rules: 1. Go to your repository on GitHub 2. Navigate to "Settings" > "Rules" > "Rulesets" 3. Edit or create a branch ruleset 4. Under "Rules" check "Require status checks to pass", click "Add Checks" and search for and select: * "Qlty Coverage" * "Qlty Diff Coverage" 5. Save your changes Now, pull requests cannot be merged unless they meet your coverage requirements. ## Troubleshooting ### Status Not Appearing If you don't see the commit status: * Ensure your Qlty GitHub App has been granted access to your repo. (Head to Workspace Settings > Connections to configure permissions) * Ensure that you've enabled the commit status from your Project Settings > Code Review page. * Verify that coverage reports were successfully uploaded for the both the merge base and branch head commits of your PR. (See Project Settings > Code Coverage for a list of uploaded reports). * Head to [Troubleshooting Coverage](/coverage/troubleshooting) for more info. ### Status Always Failing If your status is always failing: * Review your threshold settings and adjust if they're too strict * Check if your tests are running correctly and generating accurate coverage data * Verify the coverage report is being uploaded correctly ### Status Showing "N/A" If your status shows "N/A": * For diff coverage, this may happen if the number of changed lines is below your minimum threshold * It can also occur if there are no executable lines in the changed files (e.g., only comments or configuration changes) ## Best Practices * **Start with realistic thresholds**: Begin with attainable goals and gradually increase them * **Apply different thresholds for different projects**: New projects can aim for higher coverage than legacy codebases * **Use both total and diff coverage**: Enforce high standards for new code while gradually improving overall coverage ## See Also * [Quality Gates](/cloud/gates) - Learn about other quality gates in Qlty * [PR Comments](/coverage/pull-request-comments) - Configure code coverage comments on pull requests * [Coverage Metrics](/coverage/metrics) - Understand the different coverage metrics Qlty provides # Components Source: https://docs.qlty.sh/coverage/components Group a project's files by path to see code coverage per service, package, or team, with no changes to your CI setup. Components group the files in a project by path, so you can see coverage for each service, package, or team inside one repository. You define components in Qlty Cloud, not in CI, so you can add or change them at any time without touching your coverage uploads. Qlty already aggregates coverage by directory in the [Code view](/cloud/projects/code), so when each service lives in its own top-level directory you can see its coverage there without any setup. Components are for groupings that do not follow the directory tree: a team that owns several services spread across a monorepo, a shared library plus the places that use it, or all the files matched by one entry in a `CODEOWNERS` file. ## Components or coverage tags? Both features break coverage down into smaller pieces, but they work differently: | | Components | [Coverage tags](/coverage/tags) | | - | - | - | | Groups coverage by | File path | Coverage report (for example, one tag per test suite) | | Created by | Users, in project settings or through the API | CI, automatically, the first time a report is published with the tag | | Changed by | Editing the component's path patterns in Qlty | Editing the uploads in your CI configuration | | Commit statuses | None | One set per tag | | When a commit has no data | No carry forward | Its most recent report is carried forward from an earlier commit | | Effect of a stale entry | A component whose patterns match no files shows no coverage | A tag that no longer receives reports is still carried forward until deleted | Start with components. They need no CI changes, and you can adjust them as your codebase changes. Use coverage tags when your CI runs test suites selectively, for example a monorepo that only runs the tests for the service that changed. In that setup, Qlty needs tags to [carry forward](/coverage/carry-forward-tags) coverage for the suites that did not run. Tags and components can be used together. ## Enabling components Components are enabled per project. You need admin access to the project. 1. Open the project and go to *Project Settings > Features*. 2. Under **Analytics**, turn on **Components**. Once enabled, a **Components** tab appears in the project navigation. ## Defining a component 1. Go to *Project Settings > Components*. 2. Click **Create Component**. 3. Fill in the component details and save. | Field | Required | Details | | - | - | - | | **Name** | Yes | Up to 100 characters. Give each component a unique name, for example `Frontend` or `Billing`. | | **Description** | No | A note on what the component represents. | | **Path Patterns** | Yes | One or more patterns that select the component's files. Enter one per line, or separate them with commas. | The components list in *Project Settings > Components* shows a **Files** count for each component: the number of files on the default branch that its patterns match. Use it to confirm that your patterns select the files you expect. From the same list you can edit, duplicate, or delete a component. ## Path patterns Each pattern is matched against a file's path relative to the root of the repository, for example `backend/api/users.py`. These are the same paths that appear in your coverage reports after [path fixing](/coverage/path-fixing). A file belongs to a component when it matches at least one of the component's patterns. The rules are: * **A pattern must match the whole path.** `backend` on its own matches nothing inside the `backend/` directory. Use `backend/*`. * **A star matches any characters, including slashes.** `*` is not limited to one directory level: `backend/*` matches every file under `backend/` at any depth, and `backend/*.py` matches both `backend/app.py` and `backend/api/users.py`. * **A double star behaves the same as a single star.** `backend/**` and `backend/*` select the same files. * **Every other character is literal.** `?`, `[abc]`, `{a,b}`, and `!` have no special meaning. To cover several directories, add one pattern for each. | Pattern | Matches | Does not match | | - | - | - | | `backend/*` | `backend/app.py`, `backend/api/users.py` | `frontend/src/index.ts` | | `backend/*.py` | `backend/app.py`, `backend/api/users.py` | `backend/README.md` | | `backend/**/*.py` | `backend/api/users.py` | `backend/app.py` | | `*.test.ts` | `app.test.ts`, `web/src/utils/date.test.ts` | `web/src/utils/date.ts` | | `packages/ui/*` | `packages/ui/src/Button.tsx` | `packages/ui-kit/index.ts` | > [!NOTE] > > `backend/**/*.py` requires at least one directory between `backend/` and the file, so it skips files directly inside `backend/`. To select every Python file under `backend/`, use `backend/*.py`. Components do not have to cover the whole repository, and they can overlap: * A file that matches no component is left out of every component. It still counts toward the project's total coverage. * A file that matches several components counts toward each of them. ### Example: components by owning team A monorepo where each team owns a few services and packages, in directories that are not grouped by team: | Component | Path patterns | | - | - | | `Payments` | `services/billing/*`, `services/invoicing/*`, `packages/money/*` | | `Growth` | `services/onboarding/*`, `apps/web/src/signup/*` | | `Platform` | `services/gateway/*`, `packages/auth/*`, `infra/*` | Each team's component rolls up coverage across everything it owns, which no single directory in the Code view would show. ## Where component coverage appears ### Components tab The project's **Components** tab lists every component with its metrics on the default branch: files, lines of code, maintainability, complexity, duplication, coverage, and issues. Click a component to see its files with per-file coverage. ### Pull request coverage On a pull request's [Coverage tab](/cloud/projects/pull-requests#coverage-tab), the **Components** sub-view lists each component that contains a file changed by the pull request. For each one it shows the coverage rating on the base and the head, the coverage percentage on the head, and the change between the two. This view compares against the pull request's base, so it needs a coverage report for the base commit. It is empty when the pull request changes no files that belong to a component. ### Pull request comments The [coverage summary comment](/coverage/pull-request-comments) includes a **Modified Components** table. It lists the same components as the pull request's Components sub-view, with each component's coverage rating and its diff coverage: the coverage of the lines the pull request changed in that component. ### REST API The API returns the [latest metrics](/api-reference/metrics/get-component-metrics) and the [metric history](/api-reference/metrics/get-component-metric-series) for a component, including coverage. ## Changing a component When you edit a component's path patterns, the Components tab and pull request views use the new definition right away. Metric history is different. Qlty records each component's coverage when a coverage report is processed, using the component's definition at that time. Editing a component does not recalculate the history that was already recorded. [Selective coverage](/coverage/selective-coverage) uploads do not contribute to component coverage. ## Managing components with the API Components can also be managed through the REST API. Teams use it to keep components in sync with a `CODEOWNERS` file, so each owner's component tracks the paths the file assigns to them: * [List components](/api-reference/components/list-components) * [Create component](/api-reference/components/create-component) * [Update component](/api-reference/components/update-component) * [Delete component](/api-reference/components/delete-component) In the API, `pathGlobs` is an array with one pattern per entry. Components must be enabled for the project before they can be created or changed through the API. ## See Also * [Coverage Tags](/coverage/tags) - Break coverage down by coverage report * [Carry Forward Tags](/coverage/carry-forward-tags) - Complete coverage when CI runs test suites selectively * [Browsing Coverage](/coverage/browsing) - Other ways to explore coverage data * [Monorepos](/monorepos) - Using Qlty in a monorepo # Diff Coverage Over Time Source: https://docs.qlty.sh/coverage/diff-coverage-trends The **Diff Coverage** trend shows how well the code your team merged was tested, week by week. Find it on your project's **Trends** page, under **Diff Coverage**. Where [Coverage Trends](/coverage/trends) answers "how much of the codebase is covered today?", this chart answers "how well tested is the code we're shipping?" — a project sitting at 60% total coverage that merges 90%-covered changes every week is heading somewhere good, and that shows up here long before it shows up in the total. ## What's plotted * **Diff coverage** (line): of the executable lines changed on your default branch during the period, the share that your tests covered. * **Executable lines changed** (bars): how much changed code that percentage is based on. A week with 40 changed lines is a much weaker signal than a week with 4,000. Pick a range from **1 month** to **3 years**. Each point covers a week, or a month on the longest ranges, so no single day skews the chart. A point is weighted by size rather than averaged across its days: Qlty adds up the covered lines and the changed executable lines for every day in the period, then divides. A 2,000-line day counts for more than a 20-line day, so one quiet Friday can't swing the week. ## How a day is measured Every night, for each project with coverage, Qlty: 1. Finds the commit your default branch pointed at when the day started, and the one it pointed at when the day ended. 2. Diffs the two to get the day's changed lines. 3. Checks those lines against the most recent coverage report uploaded for the branch that day. 4. Stores the covered and changed-executable line counts for the day. The chart is built from those daily counts, so it only needs [coverage uploads on your default branch](/coverage/quickstart) — there's nothing extra to configure. It starts on the first day Qlty measured your project, and builds up from there. ## Gaps in the line A break in the line means Qlty has no measurement for that period, which happens when: * **Nothing merged.** No commits landed on the default branch. * **No coverage report.** The branch had no coverage uploaded that day. * **Nothing measurable changed.** The day's changes touched only non-executable lines — comments, docs, config. ## Merge commits and day boundaries Qlty uses commit timestamps to decide where one day's changes end and the next begins. When your default branch has merge commits, its history isn't linear: a commit can carry a timestamp from days before it actually merged. Those lines are counted on the day they were written rather than the day they landed, so daily boundaries are best effort. In practice this shifts a few lines between neighboring days, which weekly bucketing mostly absorbs. It doesn't drop changes or double-count them. ## See Also * [Coverage Metrics](/coverage/metrics) — how diff coverage is calculated * [Coverage Trends](/coverage/trends) — total coverage over time * [Coverage Gates](/coverage/commit-statuses) — diff coverage as a merge requirement * [Pull Request Comments](/coverage/pull-request-comments) — diff coverage on a single change # Example Repositories Source: https://docs.qlty.sh/coverage/example-repositories To help you get started with code coverage in Qlty, we've created example repositories for various languages and CI providers. These examples demonstrate best practices for generating and reporting code coverage metrics. ## Language Examples Qlty provides comprehensive examples for a variety of programming languages, all configured with GitHub Actions for CI/CD integration. | Language | GitHub Actions | | - | - | | [Go](https://github.com/qltysh/example-go) | [![Build](https://github.com/qltysh/example-go/actions/workflows/main.yml/badge.svg)](https://github.com/qltysh/example-go/actions/workflows/main.yml) | | [Java](https://github.com/qltysh/example-java) | [![Build](https://github.com/qltysh/example-java/actions/workflows/main.yml/badge.svg)](https://github.com/qltysh/example-java/actions/workflows/main.yml) | | [JavaScript](https://github.com/qltysh/example-javascript) | [![Build](https://github.com/qltysh/example-javascript/actions/workflows/main.yml/badge.svg)](https://github.com/qltysh/example-javascript/actions/workflows/main.yml) | | [Kotlin](https://github.com/qltysh/example-kotlin) | [![Build](https://github.com/qltysh/example-kotlin/actions/workflows/main.yml/badge.svg)](https://github.com/qltysh/example-kotlin/actions/workflows/main.yml) | | [PHP](https://github.com/qltysh/example-php) | [![Build](https://github.com/qltysh/example-php/actions/workflows/main.yml/badge.svg)](https://github.com/qltysh/example-php/actions/workflows/main.yml) | | [Python](https://github.com/qltysh/example-python) | [![Build](https://github.com/qltysh/example-python/actions/workflows/main.yml/badge.svg)](https://github.com/qltysh/example-python/actions/workflows/main.yml) | | [Ruby](https://github.com/qltysh/example-ruby) | [![Build](https://github.com/qltysh/example-ruby/actions/workflows/main.yml/badge.svg)](https://github.com/qltysh/example-ruby/actions/workflows/main.yml) | | [Rust](https://github.com/qltysh/example-rust) | [![Build](https://github.com/qltysh/example-rust/actions/workflows/main.yml/badge.svg)](https://github.com/qltysh/example-rust/actions/workflows/main.yml) | | [TypeScript](https://github.com/qltysh/example-typescript) | [![Build](https://github.com/qltysh/example-typescript/actions/workflows/main.yml/badge.svg)](https://github.com/qltysh/example-typescript/actions/workflows/main.yml) | | [Swift](https://github.com/qltysh/example-swift) | [![Build](https://github.com/qltysh/example-swift/actions/workflows/main.yml/badge.svg)](https://github.com/qltysh/example-swift/actions/workflows/main.yml) | | [Elixir](https://github.com/qltysh/example-elixir) | [![Build](https://github.com/qltysh/example-elixir/actions/workflows/main.yml/badge.svg)](https://github.com/qltysh/example-elixir/actions/workflows/main.yml) | ## Using the Examples To use these examples: 1. Clone the repository for your language of interest 2. Follow the setup instructions in the README 3. Configure your Qlty workspace and project 4. Update the CI configuration with your own tokens or OIDC setup 5. Push the changes to trigger a build and coverage report ## Need Help? If you need assistance setting up code coverage for your specific stack: * Join our [Discord community](https://qlty.sh/discord) * Open an [issue on GitHub](https://github.com/qltysh/qlty/issues/new) * [Contact our support team](mailto:support@qlty.sh) # Excluding Files from Coverage Source: https://docs.qlty.sh/coverage/excluding-files There are two ways to exclude files from coverage in Qlty: 1. **In your coverage tool** — exclude files before the coverage report is generated 2. **In `qlty.toml`** — filter files out of coverage data during upload If you use other coverage tools or dashboards alongside Qlty, configuring exclusions in your coverage tool keeps your coverage data consistent everywhere. If Qlty is where you manage coverage, either approach works — `qlty.toml` is often the simpler option. ## Excluding files in your coverage tool Each coverage tool has its own configuration for excluding files. Below are examples for common tools. > **JavaScript / TypeScript (Jest / Istanbul)** > > Configure coverage exclusions in your Jest config (`jest.config.js` or `package.json`): > > ```javascript theme={"system"} > // jest.config.js > module.exports = { > collectCoverageFrom: [ > "src/**/*.{js,ts,jsx,tsx}", > "!src/**/*.test.{js,ts,jsx,tsx}", > "!src/**/index.{js,ts}", > "!src/generated/**", > ], > coveragePathIgnorePatterns: [ > "/node_modules/", > "/vendor/", > "/dist/", > ], > }; > ``` > > * `collectCoverageFrom`: Specify which files to include (use `!` to exclude patterns) > * `coveragePathIgnorePatterns`: Exclude files matching these patterns > > If using NYC (Istanbul) directly, configure in `.nycrc` or `package.json`: > > ```json theme={"system"} > { > "exclude": [ > "test/**", > "**/*.test.js", > "vendor/**" > ] > } > ``` > **Python (pytest-cov / coverage.py)** > > Configure exclusions in your `pyproject.toml`, `setup.cfg`, or `.coveragerc`: > > ```toml theme={"system"} > # pyproject.toml > [tool.coverage.run] > omit = [ > "tests/*", > "*/migrations/*", > "setup.py", > "*/vendor/*", > ] > ``` > > Or in `.coveragerc`: > > ```ini theme={"system"} > [run] > omit = > tests/* > */migrations/* > setup.py > ``` > > You can also exclude specific lines or blocks using inline comments: > > ```python theme={"system"} > if TYPE_CHECKING: # pragma: no cover > import SomeModule > ``` > **Ruby (SimpleCov)** > > Configure exclusions in your test helper where SimpleCov is initialized: > > ```ruby theme={"system"} > require 'simplecov' > SimpleCov.start do > add_filter '/test/' > add_filter '/spec/' > add_filter '/vendor/' > add_filter '/config/' > add_filter do |source_file| > source_file.lines.count < 5 > end > end > ``` > > `add_filter` accepts strings, regex patterns, or blocks. > **Java / Kotlin (JaCoCo)** > > Configure exclusions in your build file. > > **Gradle:** > > ```groovy theme={"system"} > jacocoTestReport { > afterEvaluate { > classDirectories.setFrom(files(classDirectories.files.collect { > fileTree(dir: it, exclude: [ > '**/generated/**', > '**/model/**', > '**/config/**', > ]) > })) > } > } > ``` > > **Maven:** > > ```xml theme={"system"} > > org.jacoco > jacoco-maven-plugin > > > **/generated/** > **/model/** > **/config/** > > > > ``` > **Go** > > Go's built-in coverage tool uses build tags and package patterns to control coverage scope: > > ```bash theme={"system"} > # Cover only specific packages > go test -coverprofile=coverage.out ./pkg/... ./internal/... > > # Exclude specific packages by listing only what you want > go test -coverprofile=coverage.out $(go list ./... | grep -v /generated/ | grep -v /vendor/) > ``` > **PHP (PHPUnit)** > > Configure coverage exclusions in `phpunit.xml`: > > ```xml theme={"system"} > > > > src > > > src/Migrations > src/Kernel.php > > > > ``` > **Swift (Xcode / Slather)** > > When using Slather, configure exclusions in `.slather.yml`: > > ```yaml theme={"system"} > coverage_service: cobertura_xml > xcodeproj: YourProject.xcodeproj > scheme: YourScheme > output_directory: coverage > ignore: > - "Pods/*" > - "../**/*/Xcode*" > - "YourProject/Generated/*" > ``` > > When using `xccov`, exclusions must be configured at the Xcode scheme level or by post-processing the coverage data before uploading. > **Elixir (lcov\_ex)** > > In Elixir, configure which modules to exclude from coverage in `mix.exs`: > > ```elixir theme={"system"} > def project do > [ > test_coverage: [ > tool: LcovEx, > ignore_modules: [ > MyApp.Generated.Schema, > ~r/MyApp\.Vendor\..*/, > ] > ] > ] > end > ``` ## Excluding files in qlty.toml You can also exclude files from coverage using the `[coverage].ignores` setting in `qlty.toml`. When `qlty coverage publish` runs, any file path in the coverage report that matches an ignore pattern is dropped before uploading. ```toml lines theme={"system"} [coverage] ignores = [ "**/test_helpers/**", "**/fixtures/**", "**/*.generated.ts", ] ``` ### Built-in default exclusions Qlty applies a set of [default `exclude_patterns`](https://github.com/qltysh/qlty/blob/main/qlty-config/default.toml) that automatically propagate to coverage ignores. These include paths like: ``` **/node_modules/** **/vendor/** **/dist/** **/build/** **/generated/** **/target/** **/fixtures/** **/testdata/** **/cache/** *.min.* **/*.d.ts **/deps/** ``` Any patterns you add to `[coverage].ignores` are combined with these defaults. ### Using exclude\_patterns for coverage The top-level `exclude_patterns` setting in `qlty.toml` automatically propagates to `[coverage].ignores`. This means any pattern in `exclude_patterns` also excludes files from coverage. > [!WARNING] > > Using `exclude_patterns` for coverage exclusions is deprecated. Use `[coverage].ignores` for > coverage-specific exclusions instead. ### Removing missing files If your coverage report contains paths for files that don't exist on disk (e.g., generated during CI but not checked in), you can drop them during upload: ```bash lines theme={"system"} qlty coverage publish --skip-missing-files coverage/lcov.info ``` ## Common files to exclude Depending on your project, you may want to exclude: * **Generated code**: API clients, protobuf files, GraphQL types * **Vendor/third-party code**: Dependencies copied into your repository * **Configuration files**: Setup, bootstrap, or configuration modules * **Migration files**: Database migration scripts * **Test utilities**: Test helpers, fixtures, and factories ## See Also * [Generating Coverage Data](/coverage/generating-data) for language-specific setup * [Excluding Files from Analysis](/cli/excluding-files) for static analysis exclusions (separate from coverage) * [Unexpected Coverage Changes](/coverage/unexpected-changes) for troubleshooting coverage differences # Integrate Code Coverage Formats Source: https://docs.qlty.sh/coverage/formats Qlty accepts coverage data in multiple formats compatible with various tools and languages. See [Supported Languages and Formats](/coverage/generating-data) for more information. In rare cases where Qlty does not appear to support the coverage format you're using, below are some possible options to pursue: 1. Change the output format Some coverage tools support either output coverage data in multiple formats, or support conversion to popular formats. `gcovr`, for example, [supports conversion](https://gcovr.com/en/stable/output/clover.html) from a Go-specific format to Clover XML, supported by Qlty. LCOV (files in the form of `*.info`, `lcov.info`, `*.lcov`) is another popular format supported by Qlty to look out for. 2. Write your own parser Because the Qlty CLI is Open Source, you also have the opportunity to contribute your formatter back to the community. See [the parser directory](https://github.com/qltysh/qlty/tree/main/qlty-coverage/src/parser) for other examples. An LLM should be able to produce a simple parser given the pre-existing parsers and an example of the new input format. The target format, qlty, is described below under [Qlty format](#qlty-format) 3. Contact us If writing a formatter is not something you're up for, or you need assistance, feel free to [contact us](https://qlty.sh/contact/support). ## Qlty Format Qlty supports the import of a generic format, named `qlty`, which can be used as a target for custom conversion of reports from tools that are not directly supported. ### Specification The `qlty` format follows the [JSON Lines text file format](https://jsonlines.org/), also called newline-delimited JSON. Each line contains one JSON object. The structure of each JSON object is described using the [JSON schema standard](https://json-schema.org/), a declarative language that provides a standardized way to describe JSON data. ```JSON lines theme={"system"} { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "File Line Coverage", "description": "Indicates which lines of a file have been covered", "type": "object", "properties": { "path": { "description": "The file's path to inform code coverage for", "type": "string" }, "hits": { "description": "Sepcifies the number of times each line of the file has been covered", "type": "array", "items": { "description": "The number of hits for a specific line in the file, where -1 indicates the line was excluded from the report or it's irrelevant, and non-negative integers indicate the number of hits", "type": "string", "pattern": "^(-1|[0-9]+)$", } } } } ``` Following, an example of a consolidated `qlty` report: ``` { path: "user.js", hits: ["-1", "-1", "0", "0", "1", "4", "1", "2", "0", "-1"] } { path: "todo.js", hits: ["3", "3", "3", "0", "-1", "-1", "1", "2", "0", "4", "4", "4", "4"] } { path: "item.js", hits: ["0", "0", "0", "0", "0", "-1", "0", "0", "0", "0", "0", "0", "0"] } { path: "account.js", hits: ["1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1"] } ``` JSON Lines files are generally saved with the `.jsonl` extension, so it's recommended to save your `qlty` formatted coverage report with this extension. #### The `path` Property Ideally, the file path for your code coverage report should be relative to your Git project's root. However, you can transform the path using the universal reporter tool with the `--strip-prefix` and `--add-prefix` flags, modifying the final path of the uploaded report. #### The `hits` Property Depending on the tool used to exercise your code base, a single line could be: * Irrelevant regarding code coverage (e.g., comments) ("-1") * Not covered ("0") * Covered, possibly multiple times. This structure ensures that you can translate and submit coverage reports in a consistent format, regardless of the tool used to generate them. ### Uploading a `qlty` formatted Coverage Report Uploading a `qlty` formatted coverage report is no different than uploading a code coverage report in any other format. Follow these steps: 1. Convert your report to the `qlty` format. 2. Get your Qlty coverage token from your project's settings page under the Code Coverage section. 3. Upload the report using Qlty's coverage reporter: ```sh lines theme={"system"} export QLTY_COVERAGE_TOKEN=your_token ./qlty coverage publish path/to/coverage_report.jsonl ``` For explicitness, you can use the `--format=qlty` flag to specify the format, though `qlty` will infer it by default: ```sh lines theme={"system"} ./qlty coverage publish --format=qlty path/to/coverage_report.jsonl ``` ## Need help? If you need support for a specific code coverage format, [contact our support team](https://qlty.sh/contact/support). We may be able to complete the process within one week. # Generating Coverage Data Source: https://docs.qlty.sh/coverage/generating-data To use Qlty's code coverage features, you first need to generate coverage reports from your test suite. This page provides instructions for common languages and frameworks. ## Supported Languages and Formats | Language | Format / Coverage Tool | File Extension | | - | - | - | | Ruby | Simplecov | `.json` | | JavaScript | Lcov (generated by Istanbul) | `.lcov`, `.info` | | Python | Cobertura (generated by pytest or coverage.py) | `.xml` | | PHP | Clover | `*.xml` | | Go | Clover | `*.xml` | | Java | Cobertura and Jacoco | `*.xml` | | Swift | Cobertura (using native Xcode coverage and slather) | `*.xml` | | Kotlin | Cobertura and Jacoco | `*.xml` | | Scala | Cobertura (generated by sbt-scoverage) | `*.xml` | | C | Lcov (generated by gcov / lcov) | `*.info` | | C++ | Lcov (generated by gcov / lcov) | `*.info` | | .NET | dotCover | `*.xml` | | VB.NET | dotCover | `*.xml` | | Elixir | Lcov (Generated by lcov\_ex) | `*.info` | | Qlty | This is Qlty's generic coverage format | `*.jsonl` | ## Language-specific Instructions > **JavaScript / TypeScript** > > ### JavaScript / TypeScript with Jest > > Jest has built-in coverage reporting capabilities using Istanbul under the hood. > > ```bash theme={"system"} > # Add to your package.json or run directly > "scripts": { > "test": "jest --coverage" > } > ``` > > By default, Jest will output coverage reports to the `coverage` directory, including an LCOV report at `coverage/lcov.info`. > > ### React > > If you're using Create React App, Jest is already configured. Simply run: > > ```bash theme={"system"} > npm test -- --coverage > ``` > > ### Node.js with NYC (Istanbul) > > ```bash theme={"system"} > # Install NYC > npm install --save-dev nyc > > # Add to your package.json > "scripts": { > "test": "nyc mocha" > } > ``` > > NYC will generate an LCOV report at `coverage/lcov.info`. > **Python** > > ### Python with pytest > > ```bash theme={"system"} > # Install pytest-cov > pip install pytest-cov > > # Run tests with coverage > pytest --cov=. --cov-report=xml > ``` > > This will generate a coverage report in Cobertura XML format at `coverage.xml`. > > ### Python with coverage.py > > ```bash theme={"system"} > # Install coverage.py > pip install coverage > > # Run your tests with coverage > coverage run -m pytest > > # Generate an XML report > coverage xml > ``` > > This will also generate a coverage report in Cobertura XML format at `coverage.xml`. > **Ruby** > > ### Ruby with SimpleCov > > Add SimpleCov to your Gemfile: > > ```ruby theme={"system"} > group :test do > gem 'simplecov', require: false > end > ``` > > Configure SimpleCov at the top of your test helper file (e.g., `test/test_helper.rb` or `spec/spec_helper.rb`): > > ```ruby theme={"system"} > require 'simplecov' > SimpleCov.start > > # Rest of your test helper file... > ``` > > Run your tests normally: > > ```bash theme={"system"} > bundle exec rspec > # or > bundle exec rails test > ``` > > SimpleCov will generate a coverage report at `coverage/.resultset.json`. > **Go** > > ### Go > > Go has built-in coverage capabilities: > > ```bash theme={"system"} > # Run tests with coverage > go test -coverprofile=coverage.out ./... > > # Convert to Clover format for Qlty using goclover > # First install goclover: go install github.com/t-yuki/goclover@latest > goclover coverage.out > clover.xml > ``` > > This will generate a Clover XML report which Qlty can understand. > **Java / Kotlin** > > ### Java / Kotlin with Gradle and JaCoCo > > Add JaCoCo to your Gradle build: > > ```groovy theme={"system"} > plugins { > id 'jacoco' > } > > jacoco { > toolVersion = "0.8.8" > } > > jacocoTestReport { > reports { > xml.required = true > csv.required = false > html.required = true > } > } > ``` > > Run tests and generate a JaCoCo report: > > ```bash theme={"system"} > ./gradlew test jacocoTestReport > ``` > > This will generate an XML report at `build/reports/jacoco/test/jacocoTestReport.xml`. > > ### Java / Kotlin with Maven and JaCoCo > > Add JaCoCo to your Maven `pom.xml`: > > ```xml theme={"system"} > > org.jacoco > jacoco-maven-plugin > 0.8.8 > > > > prepare-agent > > > > report > test > > report > > > > > ``` > > Run tests and generate a JaCoCo report: > > ```bash theme={"system"} > mvn clean test > ``` > > This will generate an XML report at `target/site/jacoco/jacoco.xml`. > **PHP** > > ### PHP with PHPUnit > > Configure PHPUnit in your `phpunit.xml`: > > ```xml theme={"system"} > > > > > > > > > ``` > > Run PHPUnit: > > ```bash theme={"system"} > phpunit --coverage-clover=coverage.xml > ``` > > This will generate a Clover XML report at `coverage.xml`. > **Swift** > > ### Swift Options > > While there are multiple extraction options for Swift coverage data, each involves the same initial setup step: enable code coverage generation on your Xcode project or build. This can be done in your Xcode scheme, or via the `xcodebuild` command line option `enableCodeCoverage YES`. > > By providing these settings, Xcode will generate coverage data into a binary format. Coverage data next needs to be exported into a format recognized by Qlty. > > If you're using Xcode 9.3 or later (recommended for most modern projects), we recommend using `xccov` to export coverage data, but you can also use Slather. > > If using an older version of Xcode, Slather is likely your best option. > > #### Using `xccov` (Xcode >= 9.3) > > `xccov` was introduced in Xcode 9.3 as a simplified way to extract coverage data. `xccov` enables extracting coverage data from a single consolidated `.xcresult` bundle, greatly simplifying coverage setup. To use `xccov`: > > 1. Find / specify the location of the `*.xcresult` bundle > > If you are writing an Xcode build command yourself, you can supply it with the location where you'd like it to write the \*.xcresult: > > ```bash theme={"system"} > xcodebuild test -scheme MyTestProject -destination 'platform=macOS' -enableCodeCoverage YES -resultBundlePath ./TestResults.xcresult > ``` > > If instead you are utilizing a CI provider's Xcode test step which then executes Xcode on your behalf, examine the underlying xcodebuild command it uses. It may provide a standardized location for the `.xcresult` bundle. If not, the step may export an environment variable containing the path to the .xcresult bundle. > > 2. Export coverage data using `xccov` > > Qlty supports the xccov format which is output when passed `--archive` and `--json` are passed as arguments as follows: > > ```bash theme={"system"} > xcrun xccov view --archive --json TestResults.xcresult > xccov-coverage.json > ``` > > > [!WARNING] > > > > `xccov` supports two (poorly documented) coverage export JSON schemas generated with the command line arguments `--archive` and `--report`. The `--archive` format is the only supported format, as it's the only format that contains information about which specific lines were executed and which were not. Below are examples of the two formats for reference. > > ```json Archive format (supported) theme={"system"} > { > "/Users/ubuntu/code/qltysh/example-swift/Sources/MyTestProject/MyTestProject.swift": [ > { > "isExecutable": false, > "line": 1 > }, > { > "executionCount": 5, > "isExecutable": true, > "line": 2 > }, > { > "isExecutable": false, > "line": 3 > }, > { > "executionCount": 3, > "isExecutable": true, > "line": 4 > } > ] > } > ``` > > ```json Report format (unsupported) theme={"system"} > { > "coveredLines": 78, > "executableLines": 78, > "lineCoverage": 1, > "targets": [ > { > "buildProductPath": "/Users/ubuntu/Library/Developer/Xcode/DerivedData/example-swift-hchpojreepctqnbgwylrabwofawj/Build/Products/Debug/PackageFrameworks/MyTestProject_6D367B2C6E48974A_PackageProduct.framework/MyTestProject_6D367B2C6E48974A_PackageProduct", > "coveredLines": 14, > "executableLines": 14, > "files": [ > { > "coveredLines": 14, > "executableLines": 14, > "functions": [ > { > "coveredLines": 1, > "executableLines": 1, > "executionCount": 5, > "lineCoverage": 1, > "lineNumber": 2, > "name": "Calculator.init()" > } > ], > "lineCoverage": 1, > "name": "MyTestProject.swift", > "path": "/Users/ubuntu/code/qltysh/example-swift/Sources/MyTestProject/MyTestProject.swift" > } > ], > "lineCoverage": 1, > "name": "MyTestProject" > } > ] > } > ``` > > 3. When uploading this coverage data to Qlty, specify the format of the file as "xccov-json" > > For example, for the GitHub coverage action you would specify: > > ```yaml theme={"system"} > - name: Upload coverage report > uses: qltysh/qlty-action/coverage@ea1eaf434a27bf50cd544153084fbb11c52aaf84 > with: > oidc: true > format: xccov-json > files: xccov-coverage.json > ``` > > #### Swift with Xcode and Slather (see Slather's documentation for supported Xcode versions) > > [Slather](https://github.com/SlatherOrg/slather) is a Ruby gem that extracts coverage data from Xcode projects. > > On the pro side, Slather supports a wide range of Xcode versions, supports excluding files from coverage, and is fairly easy to use. > > On the con side, Slather relies on lower level Apple tools like `llvm-cov` which is more complex and relies on being able to locate coverage-related files. On simple projects this may be fine. More complex multi-module projects need extra setup to ensure all coverage data is extracted. See [Slather's documentation](https://github.com/SlatherOrg/slather/tree/master?tab=readme-ov-file#for-multiple-modules) for more information. In general the setup process is as follows: > > 1. Install Slather > > ```bash theme={"system"} > gem install slather > ``` > > 2. Create a `.slather.yml` file: > > ```yaml theme={"system"} > coverage_service: cobertura_xml > xcodeproj: YourProject.xcodeproj > scheme: YourScheme > output_directory: coverage > ``` > > 3. Run your tests and then generate a coverage report: > > ```bash theme={"system"} > xcodebuild -project YourProject.xcodeproj -scheme YourScheme -derivedDataPath Build/ -enableCodeCoverage YES test > slather > ``` > > This will generate a Cobertura XML report in the `coverage` directory. > > 4. When uploading coverage, specify the Cobertura format and provide the file generated by slather > **Elixir** > > ### Elixir with lcov\_ex > > Add lcov\_ex to your dependencies in `mix.exs`: > > ```elixir theme={"system"} > defp deps do > [ > {:lcov_ex, "~> 0.3", only: [:dev, :test], runtime: false} > ] > end > ``` > > Install the dependency: > > ```bash theme={"system"} > mix deps.get > ``` > > #### Option 1: Using the mix lcov task > > Run the lcov task to run tests and generate coverage: > > ```bash theme={"system"} > mix lcov > ``` > > This will generate a coverage report at `cover/lcov.info`. > > To output to a different folder: > > ```bash theme={"system"} > mix lcov --output coverage > ``` > > This will generate the report at `coverage/lcov.info`. > > #### Option 2: Using mix test --cover > > Alternatively, configure `LcovEx` as your test coverage tool in `mix.exs`: > > ```elixir theme={"system"} > def project do > [ > app: :your_app, > version: "0.1.0", > elixir: "~> 1.15", > deps: deps(), > test_coverage: [tool: LcovEx, output: "coverage"] > ] > end > ``` > > Then run tests with coverage: > > ```bash theme={"system"} > mix test --cover > ``` > > This will generate a coverage report at `coverage/lcov.info`. > > #### Umbrella Projects > > For umbrella projects, running `mix lcov` at the umbrella level will generate coverage reports for all individual apps and compile them into a single file at `cover/lcov.info`. > > To keep the individual app coverage files as well: > > ```bash theme={"system"} > mix lcov --keep > ``` ## Path Fixing For Qlty to accurately match a coverage report file to files in your Git repository, paths must align. The paths in your coverage report should be relative to your Git project's root, but this isn't always the case by default. To resolve path mismatches, the `qlty coverage publish` command supports these flags: * `--add-prefix`: Adds a prefix to file paths in coverage payloads * `--strip-prefix`: Removes a prefix from absolute paths in coverage payloads Example: ```bash lines theme={"system"} # If your coverage report has absolute paths like /home/user/project/src/file.js # but should be relative like src/file.js qlty coverage publish --strip-prefix=/home/user/project coverage.xml ``` ## Custom Formats with the Qlty Format In the unlikely event that your coverage tool does not export coverage data in a supported format, you can convert your coverage data to the `qlty` format. [Learn more about the Qlty format](/coverage/formats) ## Next Steps Once you've generated a coverage report, you can: * [Upload it to Qlty](/coverage/quickstart#step-3-upload-your-coverage-report) * [Set up CI integration](/coverage/ci) to automate uploads * [Merge multiple reports](/coverage/merging) if you have parallel tests # Coverage Hotspots Source: https://docs.qlty.sh/coverage/hotspots **Coverage Hotspots** highlight the files in your project with the worst line coverage on the tracked branch. They're surfaced on the project's [Overview](/cloud/projects/overview) page under the **Coverage** tab, and exist to give you a short, actionable list of files to focus on when you're trying to lift overall coverage. ## How files are picked The Coverage Hotspots list contains the **top 5 files** on the project's tracked branch with the **lowest line coverage percentage**, with two filtering rules: 1. Files with no coverage data are excluded (they show up as "uncovered" but aren't ranked alongside files with measured coverage). 2. Directory entries are excluded; only individual files appear. Each entry shows: * The filename (the last segment of the path; hover for the full path). * The line coverage percentage for that file. * The file's maintainability grade. Clicking any entry opens the file's metrics page, where you can see line-by-line coverage and the open issues affecting the file. ## When the list is empty If no coverage data has been uploaded yet for the tracked branch, the list shows a message and a button linking to the project's coverage setup page so you can wire up uploads. Once a coverage report lands successfully, the list populates on the next page load. ## Related hotspot views The Overview's lens tabs include two more hotspot lists: * **Maintainability hotspots** — top files by remediation effort. * **Security hotspots** — top files by open security finding count. All three lists use the same "top 5 files" pattern. ## See Also * [Project Overview](/cloud/projects/overview) * [Coverage Trends](/coverage/trends) * [Code Coverage](/coverage) * [Browsing Coverage](/coverage/browsing) # Code Coverage with Qlty Source: https://docs.qlty.sh/coverage/index > [!TIP] > > Code coverage reporting is part of [Qlty Cloud](/cloud/quickstart). ## Why use Qlty for code coverage? Qlty's code coverage integration is a workflow and visualization platform for improving code coverage across your projects. It integrates seamlessly with your existing coverage tools, enhancing your development process with configurable pull request gates, team-level metrics, and trend analysis that helps engineers work toward common coverage goals while highlighting overall progress across your codebase. ## Advantages > Consolidated metrics dashboard with coverage data correlated against other code quality > metrics. > Unified source view with toggleable overlays for coverage data and static analysis findings. > Configurable PR gates for ensuring new code meets your team's code coverage standards, > and/or that your total coverage remains above a defined threshold. Our platform ingests coverage reports from any source via standardized formats, supporting all major languages and frameworks through a language-agnostic architecture. Setup is minimal, requiring only the integration of our coverage uploader into your existing CI pipeline after your test coverage generation step. ## Advanced Features * **Delta Analysis**: Intelligent measurement of coverage changes in modified code, prioritizing new code coverage * **Coverage Isolation**: Segment coverage metrics by test type (unit, integration, e2e) for targeted improvement * **Carry Forward**: Complete total coverage for workflows which do not run every test suite on every commit * **Server Side and Client Side Merging**: Able to merge coverage reports on the same machine or across multiple isolated machines using both client and/or server side merging ## Implementation Path * [Coverage Quick Start](/coverage/quickstart) - CI/CD integration steps * [Generating Coverage Data](/coverage/generating-data) - Format-specific configuration * [Example Repositories](/coverage/example-repositories) - Reference implementations # Matrix Testing Source: https://docs.qlty.sh/coverage/matrix-testing ## What is Matrix Testing? Matrix testing runs a test suite across multiple combinations of languages, platforms, and frameworks to ensure compatibility and reliability across different environments. For example, a Ruby application might run tests across multiple Ruby and Rails versions: | Ruby Version | Rails 6.1 | Rails 7.0 | Rails 7.1 | | - | - | - | - | | Ruby 2.7 | ✓ | ✓ | ✗ | | Ruby 3.0 | ✓ | ✓ | ✓ | | Ruby 3.1 | ✓ | ✓ | ✓ | | Ruby 3.2 | ✗ | ✓ | ✓ | Each cell represents a unique test configuration that produces its own coverage report. ## Code Coverage for Matrix Testing ### Option 1: Representative Coverage (Primary Configuration Only) Choose a single matrix configuration as representative of your entire test suite and only report coverage for that configuration. This approach prioritizes speed over comprehensiveness by focusing on your primary supported environment. **Example:** ```yaml lines theme={"system"} name: Ruby and Rails Matrix Test with Representive Coverage on: [push, pull_request] jobs: test: runs-on: ubuntu-latest strategy: matrix: ruby: [3.1, 3.2, 3.3] rails: [6.1, 7.0, 7.1] env: RAILS_VERSION: ${{ matrix.rails }} steps: - name: Set up Ruby uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} bundler-cache: true - name: Checkout code uses: actions/checkout@v4 - name: Install dependencies run: | gem install bundler bundle install --jobs 4 --retry 3 - name: Run tests run: bundle exec rake - name: Upload coverage (only for primary configuration) if: ${{ matrix.ruby == '3.1' && matrix.rails == '7.0' }} uses: qltysh/qlty-action/coverage@v2 with: command: publish token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: coverage/coverage.lcov ``` **Advantages:** * Fast feedback - reports immediately when primary configuration completes * Simple setup with minimal configuration * Focuses on most important environment **Disadvantages:** * Not comprehensive across all supported configurations * May miss coverage gaps specific to certain environments * Assumes representative configuration covers edge cases ### Option 2: Treat as Single Test Suite When matrix testing focuses on compatibility rather than coverage analysis, you can merge all matrix cells into a single comprehensive report. This approach treats the matrix as "complete" only when all configurations have finished running. **Example:** ```yaml lines theme={"system"} name: Ruby and Rails Matrix Test with Final Coverage Complete Call on: [push, pull_request] jobs: test: runs-on: ubuntu-latest strategy: matrix: ruby: [3.1, 3.2, 3.3] rails: [6.1, 7.0, 7.1] env: RAILS_VERSION: ${{ matrix.rails }} steps: - name: Set up Ruby uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} bundler-cache: true - name: Checkout code uses: actions/checkout@v4 - name: Install dependencies run: | gem install bundler bundle install --jobs 4 --retry 3 - name: Run tests run: bundle exec rake - uses: qltysh/qlty-action/coverage@v2 with: command: publish token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: coverage/coverage.lcov incomplete: true final-step: needs: test runs-on: ubuntu-latest if: ${{ success() }} # Only run if all previous jobs succeeded steps: - uses: qltysh/qlty-action/coverage@v2 with: command: complete token: ${{ secrets.QLTY_COVERAGE_TOKEN }} ``` **Advantages:** * Provides comprehensive coverage across all configurations * Single unified coverage report * Best representation of overall test coverage **Disadvantages:** * Must wait for complete matrix to complete before reporting * May require a final workflow step to signal completion to Qlty * Slower feedback loop ### Option 3: Independent Suites with Tags Track coverage separately for each matrix configuration using unique tags. This approach enables comparison of test coverage across different environments and platforms. **Example:** ```yaml lines theme={"system"} name: Ruby and Rails Matrix Test with Representive Coverage on: [push, pull_request] jobs: test: runs-on: ubuntu-latest strategy: matrix: ruby: [3.1, 3.2, 3.3] rails: [6.1, 7.0, 7.1] env: RAILS_VERSION: ${{ matrix.rails }} steps: - name: Set up Ruby uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} bundler-cache: true - name: Checkout code uses: actions/checkout@v4 - name: Install dependencies run: | gem install bundler bundle install --jobs 4 --retry 3 - name: Run tests run: bundle exec rake - name: Upload coverage (only for primary configuration) uses: qltysh/qlty-action/coverage@v2 with: command: publish token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: coverage/coverage.lcov tag: "ruby-${{ matrix.ruby }}-rails-${{ matrix.rails }}" ``` This creates separate coverage reports for each combination: * `ruby-3.0-rails-6.1` * `ruby-3.1-rails-7.0` * `ruby-3.2-rails-7.1` * etc. **Advantages:** * Compare coverage differences across configurations * Identify environment-specific test gaps * Track coverage trends for each supported platform **Disadvantages:** * Creates a noisy user experience because every tag combination reports its own gate and summary comment. A 3x3 matrix would report 9 commit statuses. * Qlty does not currently rollup complete coverage across tags on commit statuses nor summary comments ## Frequently Asked Questions **Q: What happens if I accidentally upload the same report for every matrix configuration using the default (empty) tag?** A: Qlty automatically sums all coverage reports with the same tag. While the final result would be equivalent to a single comprehensive report, the user experience during execution could be confusing. As each matrix cell completes and uploads its report, the total coverage and diff coverage percentages may fluctuate until all configurations finish running. **Q: Which approach should I choose for my project?** A: Consider your priorities: * **Fast feedback**: Choose Option 1 (representative cell) * **Comprehensive coverage**: Choose Option 2 (single test suite) * **Platform comparison**: Choose Option 3 (independent suites with tags) Choose one approach consistently to avoid confusing coverage comparisons between different reporting strategies. # Coverage Merging Source: https://docs.qlty.sh/coverage/merging Many builds generate multiple code coverage reports. Some examples include: * Builds involving multiple programming languages, where each language requires different coverage instrumentation * Parallelized builds where each parallel unit (thread, process, virtual machine etc.) may generate its own coverage report * Different test suites (unit, integration, end-to-end) generating separate reports Qlty supports merging these separate reports into a single comprehensive report using either **Client-Side** or **Server-Side** merging. * If builds occur on a single machine (or multiple machines with shared storage), client-side merging is often the simplest approach. * If builds are spread across multiple machines and disks, server-side merging is likely the easiest solution. ## Client-side merging Client-side merging uses the Qlty CLI to combine multiple coverage reports into a single report. That single report is then uploaded to Qlty Cloud for processing. This is accomplished by passing the locations of your raw coverage reports (as paths or globs) to the `qlty coverage publish` subcommand: ```yaml GitHub Action lines theme={"system"} - uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: | coverage/coverage1.lcov coverage/coverage2.lcov coverage/coverage3.lcov ``` ```bash Qlty CLI lines theme={"system"} qlty coverage publish \ coverage/coverage1.lcov \ coverage/coverage2.lcov \ coverage/coverage3.lcov ``` Or using glob patterns: ```yaml GitHub Action lines theme={"system"} - uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: coverage/*.lcov ``` ```bash Qlty CLI lines theme={"system"} qlty coverage publish coverage/*.lcov ``` The CLI transforms each of these reports into the Qlty format, then publishes a single coverage report to Qlty Cloud. Client-side merging is ideal when all of your coverage data files are on a single machine. ## Server-side merging With server-side merging, a build publishes a series of partial reports to Qlty; when Qlty Cloud knows it's received all parts (as determined by the below options), it aggregates and reports coverage for that commit SHA. Server-side merging is ideal when: * Your tests run on multiple machines without shared storage * You want to avoid collecting all reports in a single location * Each report file may require unique path fixing Qlty provides two strategies for server-side merging: ### `coverage complete` `coverage complete` style coverage aggregation is our preferred server side aggregation option. To use it, upload all coverage parts, identifying each part as "incomplete", and then send a complete signal to Qlty: ```yaml GitHub Action lines theme={"system"} - uses: qltysh/qlty-action/coverage@v2 with: command: publish token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: coverage/coverage1.lcov incomplete: true - uses: qltysh/qlty-action/coverage@v2 with: command: publish token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: coverage/coverage2.lcov incomplete: true - uses: qltysh/qlty-action/coverage@v2 with: command: complete token: ${{ secrets.QLTY_COVERAGE_TOKEN }} ``` ```yaml CircleCI Orb lines theme={"system"} version: 2.1 orbs: qlty-orb: qltysh/qlty-orb@0.0 jobs: build: steps: # Checkout is required - checkout - qlty-orb/coverage_publish: incomplete: true files: coverage/coverage1.json - qlty-orb/coverage_publish: incomplete: true files: coverage/coverage2.json - qlty-orb/coverage_complete ``` ```bash Qlty CLI lines theme={"system"} # Send all parts with --incomplete qlty coverage publish --incomplete coverage/coverage1.lcov qlty coverage publish --incomplete coverage/coverage2.lcov # Tell Qlty all parts have been uploaded qlty coverage complete ``` When Qlty receives the completion signal, it will finalize the coverage report, merging all the received parts. Pros: * Coverage is only merged when a build finishes successfully. (For this reason, this style of merging is preferred) * The number of parts being sent does not need to be known in advance Cons: * Requires configuring an additional final step to be run only when the build finishes successfully ### Late-arriving incomplete parts If incomplete parts are received after a `qlty coverage complete` command has been issued, these parts will be incorporated into the final report as shown on the coverage tab of the PR on qlty.sh. However, any pull request statuses previously sent and/or summary comments will not be updated to reflect this new coverage data. To update the pull request with the latest coverage information after late-arriving parts, issue another `qlty coverage complete` command. This will trigger an update to both the PR statuses and summary comment to reflect the current merged coverage report. ### `total-parts-count` This approach works by specifying a `--total-parts-count=NUM` argument to the `qlty coverage publish` subcommand when publishing a coverage part. If, for example, your build consists of 2 parallelized builds, Qlty Cloud will wait for 2 coverage publish commands: ```yaml GitHub Action lines theme={"system"} - uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: coverage/coverage1.lcov total-parts-count: 2 - uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: coverage/coverage2.lcov total-parts-count: 2 ``` ```yaml CircleCI Orb lines theme={"system"} version: 2.1 orbs: qlty-orb: qltysh/qlty-orb@0.0 jobs: build: steps: # Checkout is required - checkout - qlty-orb/coverage_publish: total_parts_count: 2 files: coverage/coverage1.json - qlty-orb/coverage_publish: total_parts_count: 2 files: coverage/coverage2.json ``` ```bash Qlty CLI lines theme={"system"} qlty coverage publish --total-parts-count=2 coverage/coverage1.lcov qlty coverage publish --total-parts-count=2 coverage/coverage2.lcov ``` When using total-parts-count, Qlty only ever merges reports for the same build, as determined by the `buildId` inferred or provided explicitly to the `coverage publish` command (with the `--override-build-id` flag). Pros: * Your CI does not need to be configured with an additional final step as is the case with the `coverage complete` style option. Cons: * Because Qlty does not receive a "complete" signal indicating the build has finished, this solution has edge cases which could cause reports to be merged prematurely or not merged. If this is a concern, prefer the `complete` style merging option. * Qlty cannot merge parts across different builds to reduce the above noted edge cases ## Client and server-side merging together Client-side and server-side merging can also be used together: each machine itself can combine multiple coverage reports using client-side merging, and then post that combined report to Qlty as part of server-side merging. The total parts count always equals the number of total publish commands executed, regardless of the number of paths passed to the subcommand. If 2 machines perform client-side aggregation of N paths, `qlty coverage publish` should specify "2" as the total parts count. ```yaml GitHub Action lines theme={"system"} # Job 1: Combine and upload unit test reports - uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} total-parts-count: 2 files: | unit1.lcov unit2.lcov unit3.lcov # Job 2: Combine and upload integration test reports - uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} total-parts-count: 2 files: | integration1.lcov integration2.lcov ``` ```bash Qlty CLI lines theme={"system"} # Machine 1: Combine and upload unit test reports qlty coverage publish --total-parts-count=2 unit1.lcov unit2.lcov unit3.lcov # Machine 2: Combine and upload integration test reports qlty coverage publish --total-parts-count=2 integration1.lcov integration2.lcov ``` ## Using merging with coverage tags When using coverage tags with report merging, please refer to the [Coverage Tags](/coverage/tags) documentation for detailed information. The key points to remember: * Each `qlty coverage publish` command applies to a single tag (or no tag) * Merging always refers to combining reports for the same tag, not across different tags * Server-side merging requires tracking completion separately for each tag ## Common Scenarios ### Build matrix In GitHub Actions or other CI systems that support matrix builds: ```yaml lines theme={"system"} jobs: test: strategy: matrix: node-version: [14.x, 16.x, 18.x] os: [ubuntu-latest, windows-latest] runs-on: ${{ matrix.os }} steps: # ... run tests and generate coverage ... - name: Upload coverage uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: coverage/lcov.info # 3 node versions × 2 operating systems = 6 parts total-parts-count: 6 ``` ### Multiple languages For a project with both JavaScript and Python code: ```yaml lines theme={"system"} jobs: test-javascript: runs-on: ubuntu-latest steps: # ... run JS tests and generate coverage ... - name: Upload JS coverage uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: coverage/lcov.info total-parts-count: 2 # JavaScript + Python = 2 parts test-python: runs-on: ubuntu-latest steps: # ... run Python tests and generate coverage ... - name: Upload Python coverage uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: coverage.xml total-parts-count: 2 # JavaScript + Python = 2 parts ``` ## Verifying merging After publishing your coverage reports, you can verify that merging was successful: 1. Navigate to your project in Qlty Cloud 2. Go to Project Settings → Code Coverage 3. Filter the table below "Code Coverage Setup" by commit 4. You should see N + 1 reports: * N individual parts representing the reports you sent * 1 final merged report representing the combined coverage ## Troubleshooting ### Missing parts If your merged report doesn't appear after several minutes: **For Total Parts Count approach:** 1. Check that all parts were successfully uploaded 2. Verify that the `--total-parts-count` value matches the actual number of uploads 3. Ensure all parts were uploaded for the same commit SHA and branch 4. Check that all parts used the same tag (if using tags) **Completion Signal Issues** If you're using the incomplete flag approach and experiencing issues: 1. Ensure that all parts were uploaded with the `--incomplete` flag (otherwise, `qlty coverage publish` assumes by default that the report is complete) 2. Verify the completion command was executed for each tag you're tracking 3. Check that both upload and completion commands are using the same credentials and workspace 4. Verify all coverage parts were uploaded with the same commit SHA and branch ### Partial merging If some files are missing from your merged coverage: 1. Verify that all coverage reports were valid and complete 2. Check for path differences between reports 3. Ensure all reports use compatible formats 4. Consider using path fixing options if paths don't match ## See Also * [Coverage Tags](/coverage/tags) - Track different types of tests separately * [CI Integration](/coverage/ci) - Automate coverage reporting in your CI pipeline * [Path Fixing](/coverage/ci#path-fixing) - Fix path discrepancies in coverage reports # Coverage Metrics Source: https://docs.qlty.sh/coverage/metrics Qlty provides several different code coverage metrics to give you a comprehensive understanding of your test coverage. This page explains each metric and how to interpret them. ## Core Coverage Metrics ### Total Coverage Total Coverage measures the percentage of executable lines in your entire codebase that are covered by tests. It's calculated using the formula: ``` Total Coverage = Covered Lines / Executable Lines ``` Lines that are not executable (comments, blank lines, etc.) are excluded from this calculation. **When to use it:** * As a high-level indicator of overall project health * For tracking long-term trends in test coverage * For setting minimum coverage thresholds for the entire codebase **Example:** A project with 1,500 covered lines out of 2,000 executable lines has a Total Coverage of 75%. ### Diff Coverage Diff Coverage focuses only on the lines changed in a pull request or commit. It shows the percentage of new or modified executable lines that are covered by tests. ``` Diff Coverage = Covered Changed Lines / Executable Changed Lines ``` **When to use it:** * For evaluating the test coverage of specific changes * As a quality gate for pull requests * To ensure new code maintains or improves coverage **Example:** A pull request that adds 50 lines of code with 45 of them covered by tests has a Diff Coverage of 90%. ### Total Coverage Delta Total Coverage Delta shows how the Total Coverage has changed between two points, typically between the current branch and the base branch in a pull request. ``` Total Coverage Delta = New Total Coverage - Previous Total Coverage ``` **When to use it:** * To understand the impact of changes on overall project coverage * To prevent merging changes that significantly decrease coverage * To track progress toward coverage goals **Example:** If the base branch has 75% coverage and your changes result in 76% coverage, the Total Coverage Delta is +1%. ## File-level Metrics ### File Coverage File Coverage shows the percentage of executable lines in a specific file that are covered by tests. ``` File Coverage = Covered Lines in File / Executable Lines in File ``` **When to use it:** * To identify specific files that need more tests * To prioritize test writing efforts * To ensure critical files have high coverage **Example:** A file with 90 covered lines out of 100 executable lines has a File Coverage of 90%. ### Directory Coverage Directory Coverage shows the average coverage across all files in a directory. ``` Directory Coverage = Sum of Covered Lines in Directory / Sum of Executable Lines in Directory ``` **When to use it:** * To understand coverage at the module or component level * To identify areas of the codebase that need more testing * To set coverage goals for specific components **Example:** A directory containing files with a total of 500 covered lines out of 800 executable lines has a Directory Coverage of 62.5%. ## Coverage Ratings Qlty assigns letter grades to your coverage percentages to provide an easy-to-understand quality indicator. | Coverage Percentage | Qlty Coverage Rating | | :-: | :-: | | >= 90% | A | | >= 80% | B | | >= 70% | C | | >= 60% | D | | \< 60% | F | These ratings appear on your project dashboard and in coverage badges. ## Advanced Metrics ### Coverage by Tag When using [Coverage Tags](/coverage/tags), Qlty tracks separate coverage metrics for each tag, allowing you to see coverage from different test types. **Example:** * Unit test coverage: A (95%) * Integration test coverage: B (85%) * E2E test coverage: C (75%) ### Coverage Over Time Qlty tracks how your coverage metrics change over time, allowing you to see trends: * **Coverage Trend**: Graph showing total coverage over time * **Weekly Change**: How coverage has changed in the last week * **Monthly Change**: How coverage has changed in the last month * **Quarterly Change**: How coverage has changed in the last quarter ### Coverage Hotspots Coverage Hotspots identify files with low coverage that are frequently changed, highlighting areas where adding tests would have the most impact. The hotspot score is calculated based on: * How frequently the file changes * How low the file's coverage is * How important the file is (based on interconnectedness) ## Interpreting Coverage Metrics ### What's a "Good" Coverage Percentage? The ideal coverage percentage depends on your project's context: * **90%+ (A)**: Excellent for critical libraries, core business logic, and open-source projects * **80-90% (B)**: Very good for most application code * **70-80% (C)**: Acceptable for many projects * **60-70% (D)**: May indicate testing gaps * **Below 60% (F)**: Usually indicates insufficient testing ### When to Focus on Different Metrics * **Total Coverage**: For overall project health and long-term trends * **Diff Coverage**: For ensuring new code is well-tested * **File Coverage**: For identifying specific areas that need tests * **Directory Coverage**: For understanding module-level testing quality * **Coverage Deltas**: For preventing coverage regression ### Limitations of Coverage Metrics While coverage metrics are valuable, they don't tell the whole story: * High coverage doesn't guarantee high-quality tests * Some code may be inherently hard to test (e.g., UI, error handling) * Not all code is equally important to test * Coverage doesn't measure test effectiveness at finding bugs Use coverage as one of several metrics to evaluate your testing strategy, not as the only goal. ## Best Practices ### Setting Realistic Goals * Start with achievable coverage goals and gradually increase them * Set higher coverage requirements for critical code * Focus on Diff Coverage for new code rather than trying to immediately increase Total Coverage ### Effective Coverage Standards Typical coverage standards might include: * All new code must have at least 80% Diff Coverage * Critical modules must maintain at least 90% coverage * Total Coverage should not decrease ### Using Coverage Gates Configure [Coverage Gates](/coverage/commit-statuses) to enforce your coverage standards: * **Diff Coverage Gate**: Ensures new code meets coverage standards * **Total Coverage Gate**: Prevents significant coverage decreases * **Custom Gates**: For specific requirements like "100% coverage for security code" ## See Also * [Coverage Gates](/coverage/commit-statuses) - Using coverage as a quality gate * [Coverage Trends](/coverage/trends) - Tracking coverage changes over time # Path Fixing Source: https://docs.qlty.sh/coverage/path-fixing Coverage reports often contain file paths that don't match your repository structure. This can happen when tests run in different environments (Docker containers, CI runners, different operating systems), when using monorepos or when coverage tools generate absolute paths. Qlty provides path fixing options to resolve these mismatches. ## Common Path Issues ### Absolute Paths Coverage tools often generate absolute paths that include the full filesystem path or more than the root relative path: ``` /Users/developer/projects/myapp/src/components/Button.js /home/runner/work/myapp/myapp/src/components/Button.js /app/src/components/Button.js ``` These should be relative to your repository root: ``` src/components/Button.js ``` ### Container Paths When running tests in Docker containers, paths often include the container's working directory: ``` /app/src/components/Button.js /workspace/src/components/Button.js ``` ### Missing Path Prefixes Sometimes coverage reports have paths that are missing required prefixes, particularly in case of monorepos or nested projects: ``` components/Button.js # Missing "/app/javascript/" prefix app/models/foo.rb # Missing "server/" prefix ``` #### Jacoco Some Jacoco projects generate coverage with missing path prefixes where a single path prefix will not suffice. See [Using JACOCO\_SOURCE\_PATH](#using-jacoco_source_path). ## Path Fixing Options ### Strip Prefix Remove unwanted prefixes from file paths using `--strip-prefix`: ```yaml GitHub Actions lines theme={"system"} - name: Upload coverage to Qlty uses: qltysh/qlty-action/coverage@v2 with: oidc: true files: coverage/lcov.info strip-prefix: /app/ ``` ```bash CLI lines theme={"system"} # Remove Docker container path prefix qlty coverage publish --strip-prefix=app coverage.lcov # Remove absolute path prefix qlty coverage publish --strip-prefix=home/runner/work/myapp coverage.lcov ``` ### Add Prefix Add required prefixes to file paths using `--add-prefix`: ```yaml GitHub Actions lines theme={"system"} - name: Upload coverage to Qlty uses: qltysh/qlty-action/coverage@v2 with: oidc: true files: coverage/lcov.info add-prefix: src ``` ```yaml CircleCI lines theme={"system"} # Qlty Coverage Orb - qlty-orb/coverage_publish: files: coverage/coverage.json add_prefix: src ``` ```bash CLI lines theme={"system"} # Add missing "src/" prefix qlty coverage publish --add-prefix=src coverage.lcov # Add deeper path prefix qlty coverage publish --add-prefix=packages/frontend/src coverage.lcov ``` ### Combining Options You can use both `--strip-prefix` and `--add-prefix` together: ```bash lines theme={"system"} # Remove container path and add correct prefix qlty coverage publish \ --strip-prefix=home/runner/work/myapp \ --add-prefix=src \ coverage.lcov ``` ### Using `JACOCO_SOURCE_PATH` Java projects with multiple modules often generate coverage for each module with source code paths relative to their module, leaving out its parent directories. For example, a multi-module Maven project might have source code located in: ``` openpdf-core/src/main/java/ openpdf-fonts-extra/src/main/java/ openpdf-html/src/main/java/ ``` But the resulting `jacoco.xml` may not includes these directories when listing source code paths. To ensure paths are prefixed properly in the final report, specify an environment variable `JACOCO_SOURCE_PATH` with a whitespace-separated list of directories containing Java source code (relative to the repository root). Qlty will resolve source code paths and include the full proper path in its coverage report. ```yaml GitHub Actions with JACOCO_SOURCE_PATH lines theme={"system"} - name: Upload coverage to Qlty uses: qltysh/qlty-action/coverage@v2 env: JACOCO_SOURCE_PATH: openpdf-core/src/main/java openpdf-fonts-extra/src/main/java openpdf-html/src/main/java openpdf-kotlin/src/main/java openpdf-renderer/src/main/java pdf-swing/src/main/java pdf-toolbox/src/main/java with: oidc: true files: "**/target/site/jacoco/jacoco.xml" ``` ## Common Scenarios ### Docker Containers Most Docker setups require stripping the container's working directory: ```bash lines theme={"system"} # Container uses /app as working directory qlty coverage publish --strip-prefix=app coverage.lcov # Container uses /workspace qlty coverage publish --strip-prefix=workspace coverage.lcov ``` ### Monorepos In monorepos, you may need to add package-specific prefixes: ```bash lines theme={"system"} # Coverage from a specific package qlty coverage publish --add-prefix=packages/api coverage.lcov # Or strip and add for nested structures qlty coverage publish \ --strip-prefix=app \ --add-prefix=services/user-service \ coverage.lcov ``` ### CI Runners Different CI providers may generate different path structures: ```bash lines theme={"system"} # GitHub Actions qlty coverage publish --strip-prefix=home/runner/work/repo-name coverage.lcov # GitLab CI qlty coverage publish --strip-prefix=builds/group-name/repo-name coverage.lcov # CircleCI qlty coverage publish --strip-prefix=home/circleci/project coverage.lcov ``` ## Verifying Path Fixes ### Test with --dry-run Use dry run to see how paths are being processed: ```bash lines theme={"system"} qlty coverage publish --strip-prefix=app --dry-run coverage.lcov ``` ### Validate After Upload After uploading, check the coverage report in Qlty's web interface to ensure file paths match your repository structure. ## Language-Specific Examples ### JavaScript/Node.js ```bash lines theme={"system"} # Jest with Docker qlty coverage publish --strip-prefix=app coverage/lcov.info ``` ### Python ```bash lines theme={"system"} # Docker with Python qlty coverage publish --strip-prefix=app coverage.xml # Virtual environments qlty coverage publish --strip-prefix=opt/venv/lib/python3.9/site-packages/myapp coverage.xml ``` ### Java ```bash lines theme={"system"} # Maven with Docker qlty coverage publish --strip-prefix=app target/site/jacoco/jacoco.xml # Gradle projects qlty coverage publish --add-prefix=src/main/java build/reports/jacoco/test/jacocoTestReport.xml ``` #### Multi-Module Projects with Jacoco Jacoco projects may need to specify the environment variable `JACOCO_SOURCE_PATH` when publishing coverage. See [Using JACOCO\_SOURCE\_PATH](#using-jacoco_source_path). ### Go ```bash lines theme={"system"} # Go modules qlty coverage publish --strip-prefix=go/src/github.com/user/repo coverage.out ``` ### Ruby ```bash lines theme={"system"} # Rails in Docker qlty coverage publish --strip-prefix=app coverage/coverage.json # Bundler paths qlty coverage publish --strip-prefix=usr/local/bundle/gems coverage.json ``` ## Advanced Path Transformations ### Multiple Strip Operations For complex path structures, you may need multiple transformations: ```bash lines theme={"system"} # First strip the container path, then add the correct prefix qlty coverage publish \ --strip-prefix=app/tmp/build \ --add-prefix=src/main/java \ coverage.xml ``` ## Troubleshooting ### No Files Matched If Qlty reports no files were matched: 1. Check that your repository contains the files referenced in the coverage report 2. Verify the path transformations result in valid repository paths 3. Use debug mode to see the transformed paths ### Missing Coverage Data If some files are missing from the coverage report: 1. Confirm all source files are included in the original coverage report 2. Check that path transformations don't accidentally exclude files 3. Verify the coverage tool configuration includes all relevant files ## See Also * [Running Tests in Docker](/coverage/running-tests-in-docker) - Docker-specific path fixing examples * [CI Integration](/coverage/ci) - CI provider-specific path issues * [Coverage Formats](/coverage/formats) - How different formats handle file paths * [Troubleshooting](/coverage/troubleshooting) - General coverage upload issues # Pull Request Comments Source: https://docs.qlty.sh/coverage/pull-request-comments Qlty can automatically add informative code coverage comments to your GitHub pull requests. These comments provide immediate visibility into how code changes affect your test coverage without leaving GitHub. ## Benefits of PR Comments * **Immediate feedback**: See file-level coverage information directly in your PR * **Increased visibility**: Integrate coverage data into your PR comment threads * **Actionable insights**: Identify files in the PR with low coverage that need attention ## Example PR Comment Here's an example of a Qlty coverage comment on a pull request: ## Enabling PR Comments To enable pull request comments: 1. Go to your project in Qlty 2. Navigate to "Project Settings" > "Comments" 3. Toggle "Summary Comments" on ## Advanced Features ### Comment Updates Qlty automatically updates the PR comment when: * New coverage data is uploaded for the PR * The PR is updated with new commits * Coverage metrics change due to new tests This ensures the comment always shows the most current information. ## Customizing Comment Templates For organizations with specific needs, Qlty supports custom comment templates. Contact our support team to learn more about this enterprise feature. ## Combining with Commit Statuses For a complete quality gate system, combine PR comments with [commit statuses](/coverage/commit-statuses): * **Commit statuses**: Enforce coverage requirements before merging * **PR comments**: Provide detailed information to help developers meet those requirements This combination creates a powerful feedback loop that improves code quality and test coverage. ## Troubleshooting ### Comment Not Appearing If you don't see the PR comment: * Ensure the Qlty GitHub App is installed on that specific repository * Verify that a coverage report was successfully uploaded for the PR * Check that PR summary comments are enabled in your project settings ### Outdated Information If the comment shows outdated information: * Ensure your CI is uploading coverage reports for the latest commit * Verify the correct commit SHA is being reported with the coverage data ## See Also * [Commit Statuses](/coverage/commit-statuses) - Configure GitHub commit statuses for code coverage * [CI Integration](/coverage/ci) - Automate coverage reporting in your CI pipeline # Coverage Quick Start Source: https://docs.qlty.sh/coverage/quickstart This guide will help you set up code coverage reporting in your CI pipeline by hand. > [!TIP] > > Qlty can make these changes for you. [Automatic Coverage Setup](/coverage/automatic-setup) > opens a pull request that adds the upload step to your CI, for you to review and merge. Or run > Qlty's [`setup-coverage` skill](https://github.com/qltysh/qlty-skills/tree/main/skills/setup-coverage) > in your own coding agent. Both are offered under **Project Settings > Code Coverage > Set up coverage**. ## Prerequisites 1. A repository with automated tests that generate coverage data 2. A GitHub user with administrator permissions on your organization 3. Ability to modify and run CI scripts for your repository ## Step 1. Determine an authentication approach Qlty supports three ways to authenticate code coverage uploads from your CI system: 1. OpenID Connect (OIDC) with GitHub Actions (recommended) 2. Workspace-level coverage tokens 3. Project-level coverage tokens If you are using GitHub Actions, we recommend using OIDC as it is the most secure and requires no management of long-lived coverage tokens. If not using OIDC, a workspace-level token is the next most convenient, followed by project-specific tokens. ## Step 2. Store the coverage token as a CI secret *If you are using OIDC, you can skip this step. (OIDC is tokenless)* ### Obtain a Coverage Token * Login to Qlty via GitHub OAuth * Navigate to *Workspace Settings > Code Coverage* (e.g. `https://qlty.sh/gh/your-org/settings/coverage`) * Copy the workspace's coverage token ### Provide Coverage Token in Environment A coverage token should be treated as a credential and stored securely within your CI system. The specifics for how to store a secret at the organization level vary by provider: * [GitHub Actions](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions) * [CircleCI](https://circleci.com/docs/contexts/) * [Buildkite](https://buildkite.com/docs/pipelines/security/secrets/buildkite-secrets) * [Travis CI](https://docs.travis-ci.com/user/encryption-keys/) ## Step 3. Update CI workflow scripts This guide assumes that your CI scripts are already generating code coverage data from the execution of your automated tests. The method to generate this data varies by programming language and testing tools. Once you have code coverage data being generated in one of our [supported formats](/coverage/generating-data), continue with the steps below. ### GitHub Actions Add a step to run the `qltysh/qlty-action/coverage` reusable GitHub Action: ```yaml OIDC-based authentication (recommended) lines theme={"system"} # ... permissions: contents: read id-token: write # IMPORTANT jobs: build: # ... steps: # ... - uses: qltysh/qlty-action/coverage@v2 with: oidc: true files: coverage/lcov.info # REPLACE WITH PATH TO YOUR COVERAGE FILE ``` ```yaml Token-based authentication lines theme={"system"} # ... jobs: build: # ... steps: # ... - uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: coverage/lcov.info # REPLACE WITH PATH TO YOUR COVERAGE FILE ``` > [!NOTE] > > The Qlty GitHub Action is simply a convenience wrapper that installs the qlty CLI and executes `qlty coverage publish` with the provided arguments. > > If you are unable to use the Qlty Github Action (because your organization's security policy does not permit it, or you are using a self-hosted runner), using the Qlty CLI directly is straight-forward. See CLI Integration below. > [!WARNING] > > The Qlty GitHub Action is **not supported on self-hosted runners.** If you’re on self-hosted > runners, use the Qlty CLI to upload coverage instead. ### CircleCI Orb We provide a CircleCI Orb for uploading coverage reports. Add the following to your `.circleci/config.yml` file: ```yaml lines theme={"system"} # ... jobs: run_tests_and_publish_coverage: # ... steps: # ... - qlty-orb/coverage_publish: files: coverage/lcov.info ``` [Learn more about our CircleCI Orb](https://circleci.com/developer/orbs/orb/qltysh/qlty-orb) > [!NOTE] > > The Qlty CircleCI Orb is a convenience wrapper that simply installs the qlty CLI and executes `qlty coverage publish` with the provided arguments. > > If you are unable to use the Qlty CircleCI Orb manual integration is straight-forward. See CLI Integration below. ### CLI Integration If you are not using CircleCI or GitHub, or prefer not to use the convenience wrappers available for those providers, using the Qlty CLI in your workflow is simple and supported on any CI provider. To publish coverage, you will install the Qlty CLI and run the `qlty coverage publish` command, specifying the coverage data file(s): ```bash lines theme={"system"} # Assumes $QLTY_COVERAGE_TOKEN is set in the environment curl https://qlty.sh | sh qlty coverage publish coverage/lcov.info # Replace with path to your coverage data file(s) ``` > [!TIP] > > For security-sensitive environments, you can [verify the CLI's > integrity](/cli/integrity-verification) before installation. Occassionally, `qlty coverage publish` requires additional arguments. The most commonly used arguments are: * `--add-prefix` and/or `--strip-prefix` to ensure the paths to source files are valid * `--format` to specify the format of the coverage file (e.g. `--format jacoco`) See our documentation on [CI Integration](/coverage/ci) for more information. ## Step 4. Validate coverage uploads from a branch After updating your CI script: 1. Push your changes to a branch and trigger a build 2. Ensure the build completes successfully with no errors during the upload process 3. On Qlty, navigate to your *Project Settings > Code Coverage* page 4. Your uploaded coverage report should appear in the table at the bottom of the page 5. Click on the commit SHA to view your report details and verify it matches your expectations ## Step 5. Merge your CI script changes into your main branch Once coverage uploads are working successfully for your branch: 1. Merge the branch into your main branch and run a build 2. Ensure the build completes successfully with no errors from the coverage upload step 3. Validate the coverage upload in your Project Settings 4. Once Qlty receives a valid coverage report for your main branch, your coverage info will be displayed in your project's Overview page ## Optional: Enable coverage commit statuses To enforce coverage thresholds on pull requests: * Enable commit statuses (**Qlty Coverage** and **Qlty Diff Coverage**) within your Project's Gate settings * Adjust coverage check settings (including configurations for minimum diff size and total coverage decrease) ## Next Steps * [Generating Coverage Data](/coverage/generating-data) - Format-specific configuration * [Coverage Metrics](/coverage/metrics) - Learn about the coverage metrics Qlty provides * [Coverage Merging](/coverage/merging) - Merge multiple coverage reports from parallel test runs * [Example Repositories](/coverage/example-repositories) - Reference implementations * [Troubleshooting](/coverage/troubleshooting) - Common issues and solutions # Running Tests in Docker Source: https://docs.qlty.sh/coverage/running-tests-in-docker When running tests inside Docker containers, you need to extract coverage data from the container to upload it to Qlty. This guide covers two common approaches: using volume mounts and using `docker cp`. ## Method 1: Volume Mounting Volume mounting is the simplest approach where you mount your project directory into the container, allowing coverage files to be written directly to your host filesystem. ### GitHub Actions Example ```yaml lines theme={"system"} name: Main on: push: branches: [main] pull_request: permissions: contents: read id-token: write jobs: test: runs-on: ubuntu-latest steps: - name: Checkout repo uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Build Docker image run: docker build -t myapp-test . - name: Run tests in Docker run: | docker run --rm \ -v "$(pwd)":/app \ -w /app \ myapp-test \ npm test -- --coverage - name: Check coverage file exists run: test -f coverage/lcov.info - name: Upload coverage to Qlty uses: qltysh/qlty-action/coverage@v2 with: oidc: true files: coverage/lcov.info ``` ### Key Points for Volume Mounting * Mount your current directory (`$(pwd)`) to the container's working directory * Use `--rm` to automatically remove the container after tests complete * Coverage files are written directly to your host filesystem * Works with any coverage format supported by Qlty ## Method 2: Docker Copy When you can't use volume mounts (due to security restrictions or container design), you can copy coverage files out of the container after tests complete. ### GitHub Actions Example ```yaml lines theme={"system"} name: Main on: push: branches: [main] pull_request: permissions: contents: read id-token: write jobs: test: runs-on: ubuntu-latest steps: - name: Checkout repo uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Build Docker image run: docker build -t myapp-test . - name: Run tests in Docker (retain container) run: | docker run --name test-container \ -w /app \ myapp-test \ npm test -- --coverage - name: Copy coverage files out of container run: | docker cp test-container:/app/coverage/lcov.info coverage.lcov - name: Cleanup container run: docker rm test-container - name: Check coverage file exists run: test -f coverage.lcov - name: Upload coverage to Qlty uses: qltysh/qlty-action/coverage@v2 with: oidc: true files: coverage.lcov ``` ### Key Points for Docker Copy * Don't use `--rm` flag so the container persists after tests * Use `--name` to give the container a predictable name * Copy files using `docker cp container_name:/path/to/file destination` * Clean up the container manually after copying files ## Alternative CI Providers ### Using Coverage Tokens If you're not using GitHub Actions with OIDC, replace the upload step with a coverage token: ```yaml lines theme={"system"} - name: Upload coverage to Qlty uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: coverage/lcov.info ``` ### Manual CLI Upload For other CI providers, install the Qlty CLI and upload manually: ```bash lines theme={"system"} # After extracting coverage files from Docker curl https://qlty.sh | sh qlty coverage publish coverage/lcov.info ``` For some CI providers you may have to add `--override-commit-sha` and `--override-branch` flags with commit SHA and branch names. ```bash lines theme={"system"} # After extracting coverage files from Docker curl https://qlty.sh | sh qlty coverage publish coverage/lcov.info --override-commit-sha --override-branch ``` ## Multiple Coverage Files If your Docker container generates multiple coverage files, you can upload them all: ### Volume Mount Approach ```yaml lines theme={"system"} - name: Upload coverage to Qlty uses: qltysh/qlty-action/coverage@v2 with: oidc: true files: | coverage/unit.lcov coverage/integration.lcov ``` ### Docker Copy Approach ```bash lines theme={"system"} - name: Copy multiple coverage files run: | docker cp test-container:/app/coverage/unit.lcov unit.lcov docker cp test-container:/app/coverage/integration.lcov integration.lcov ``` ## Path Fixing When running tests in Docker, file paths in coverage reports might not match your repository structure. Use path fixing options: ```yaml lines theme={"system"} - name: Upload coverage to Qlty uses: qltysh/qlty-action/coverage@v2 with: oidc: true files: coverage/lcov.info strip-prefix: /app/ ``` Or with the CLI: ```bash lines theme={"system"} qlty coverage publish --strip-prefix=/app/ coverage/lcov.info ``` ## Troubleshooting ### Coverage File Not Found * Ensure your test command actually generates coverage files * Check that the coverage output directory matches your copy/mount paths * Verify file permissions allow reading from the container ### Path Mismatches * Use `--strip-prefix` to remove container-specific path prefixes * Use `--add-prefix` if you need to add a path prefix * Check that source paths in coverage reports match your repository structure ### Container Cleanup Issues * Always clean up named containers when using `docker cp` * Use `docker rm -f container_name` to force removal if needed * Consider using `--rm` with volume mounts to avoid cleanup ## See Also * [Coverage Tags](/coverage/tags) - Track different types of tests separately * [CI Integration](/coverage/ci) - Automate coverage reporting in your CI pipeline * [Path Fixing](/coverage/ci#path-fixing) - Fix path discrepancies in coverage reports * [Coverage Formats](/coverage/formats) - Supported coverage file formats # Selective Coverage Source: https://docs.qlty.sh/coverage/selective-coverage Selective coverage lets you upload coverage from a run that intentionally executed only a subset of your test suite — for example, only the tests affected by a pull request's changes. Marking these uploads with the `--selection` flag tells Qlty the report is a partial view of your codebase, so Qlty computes [diff coverage](/coverage/metrics) from it while excluding it from total coverage. > [!WARNING] > > Selective Coverage support is currently in **beta**. ## Background On large codebases, running the full test suite on every pull request can be too slow or too expensive. Many teams adopt **selective testing** (also called test selection or test impact analysis): each PR build runs only the tests relevant to the code that changed. Partial runs are not new to Qlty. [Tags](/coverage/tags) have always handled the predictable kind: publish your unit tests as `units` and Qlty tracks that suite separately, because the tag runs the same set of tests each time and every report for it is comparable to the last. Test selection breaks that assumption — the subset is chosen per build, so a report covers a unique slice of the codebase and is comparable to nothing before it. Selective testing creates a problem for coverage reporting. A selected run only exercises a fraction of the codebase, so its coverage report looks like a massive coverage drop compared to full-suite reports. Without extra information, Qlty would: * Report a misleading total coverage percentage for the PR, failing the Total Coverage commit status * Risk polluting project dashboards and future comparisons with partial data The `--selection` flag solves this. A selected report is trusted for the lines it covers — which is exactly what diff coverage needs — and is never treated as a measurement of your project's total coverage. ## How Selective Coverage Behaves When you publish coverage with `--selection`: * **Diff coverage works normally.** Changed lines in the pull request are evaluated against the selected report, and the Diff Coverage commit status and PR comments are posted as usual. * **Total coverage is not computed.** The Total Coverage commit status is posted as passing with the message "Not computable for select coverage" rather than reporting a misleading percentage. * **Project metrics are unaffected.** Selected reports never contribute to total coverage metrics, component coverage, coverage trends, or the file explorer. * **Comparisons stay accurate.** A selected report is never used as the comparison base for another pull request, even in stacked-PR workflows. * **Reports are labeled.** When all uploads for a commit are selected, the coverage report detail page in Qlty Cloud shows the report as "Selected." ## Publishing Selective Coverage > [!NOTE] > > Selective coverage requires [Qlty CLI](/cli/quickstart) v0.633.0, GitHub Action `qltysh/qlty-action` v2.3.0, or CircleCI orb `qltysh/qlty-orb` 0.1.2 — or newer. Workflows pinned to `qlty-action/coverage@v2` or `qlty-orb@0.1` pick these up automatically; exact-version pins need a bump. Add the `--selection` flag to `qlty coverage publish` in the builds that run a selected subset of tests: ```yaml GitHub Action lines theme={"system"} - uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: coverage/lcov.info selected: true ``` ```yaml CircleCI Orb lines theme={"system"} version: 2.1 orbs: qlty-orb: qltysh/qlty-orb@0.1 jobs: build: steps: - checkout - qlty-orb/coverage_publish: files: coverage/lcov.info selected: true ``` ```bash Qlty CLI lines theme={"system"} qlty coverage publish --selection coverage/lcov.info ``` Publish full-suite runs without the flag, exactly as before. A typical setup: * **Pull requests** run selected tests and publish with `--selection` * **The default branch** (and/or a nightly build) runs the full suite and publishes without `--selection`, keeping total coverage, dashboards, and comparison baselines accurate ## Selected and Full Coverage Together Selected and full uploads for the same commit and [tag](/coverage/tags) are assembled as **separate reports**: parts counting and completion signals are tracked independently for each, which is why the `--selection` flag must accompany every command for a selected report, including `qlty coverage complete`. The two reports still work together when a commit has both. Total coverage comes from the full report only, while diff coverage evaluates changed lines against the combined coverage of both reports — a line counts as covered if any upload covers it. In Qlty Cloud, the coverage reports page shows one entry per commit and tag, and its detail page is labeled "Selected" only when every upload for that commit and tag was selected. Upload order does not matter. If the selected report arrives first, the Total Coverage status reads "Not computable for select coverage" until the full report is processed, then updates to the actual percentage. If the full report arrives first, a later selected upload leaves the computed total in place. You can also separate them by tag — for example, a full `unit` suite alongside a selected `integration` subset on the same PR: ```bash Qlty CLI lines theme={"system"} # Full unit test run — totals computed for this tag qlty coverage publish --tag=unit unit.lcov # Selected integration subset — diff coverage only qlty coverage publish --tag=integration --selection integration.lcov ``` Each tag receives its own commit statuses, so the `unit` tag reports total coverage while the `integration` tag reports "Not computable for select coverage." ## Selective Coverage with Server-Side Merging Selective coverage composes with both [server-side merging](/coverage/merging) strategies. Because selected and unselected uploads assemble into separate reports, the selection flag is part of the report's identity — every command for the same report must agree on it. ### With `coverage complete` Pass `--selection` to **both** `publish` and `complete`. A plain `qlty coverage complete` will not find a report whose parts were published with `--selection` (and vice versa): ```yaml GitHub Action lines theme={"system"} - uses: qltysh/qlty-action/coverage@v2 with: command: publish token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: part1.lcov incomplete: true selected: true - uses: qltysh/qlty-action/coverage@v2 with: command: complete token: ${{ secrets.QLTY_COVERAGE_TOKEN }} selected: true ``` ```yaml CircleCI Orb lines theme={"system"} - qlty-orb/coverage_publish: files: part1.lcov incomplete: true selected: true - qlty-orb/coverage_complete: selected: true ``` ```bash Qlty CLI lines theme={"system"} qlty coverage publish --selection --incomplete part1.lcov qlty coverage publish --selection --incomplete part2.lcov qlty coverage complete --selection ``` ### With `total-parts-count` Pass `--selection` on every part. Selected and unselected parts are counted independently, so a build can upload a full report and a selected report in parallel, each with its own parts count: ```bash Qlty CLI lines theme={"system"} qlty coverage publish --selection --total-parts-count=2 part1.lcov qlty coverage publish --selection --total-parts-count=2 part2.lcov ``` ## Selective Coverage vs. Carry Forward Tags Both features address selective testing, at different granularities: * Use [carry forward tags](/coverage/carry-forward-tags) when entire suites (tags) are skipped for some commits — Qlty reuses each tag's most recent report so combined coverage stays complete. * Use selective coverage when a run executes a partial, changing subset of tests *within* a suite — the report is never a complete picture for its tag, so it should only feed diff coverage. Carry forward requires that a tag report the same set of tests each time it runs; selected runs break that assumption, which is exactly why they need the `--selection` flag instead. ## Best Practices * **Keep a full-coverage source of truth.** Publish full-suite (unselected) coverage on your default branch so total coverage metrics, trends, and PR comparison baselines remain meaningful. * **Use selective coverage on pull requests only.** Publishing a selected report to your default branch means no new total coverage data for that branch until the next full run. * **Gate PRs with Diff Coverage.** With selective testing, the Diff Coverage commit status is your primary quality gate; the Total Coverage status will pass with "Not computable for select coverage." If you prefer, you can disable the Total Coverage status entirely under Project Settings → Code Review. ## Troubleshooting ### `coverage complete` reports "Coverage report not found" If parts were published with `--selection`, the completion signal must also include it: `qlty coverage complete --selection`. Selected and unselected uploads assemble into separate reports, and each must be completed on its own. ### Total coverage status shows an unexpected drop Check that every build publishing a partial test run passes `--selection`. A selected run published without the flag is treated as a full report and will be compared against full-suite baselines. ### Diff coverage is missing changed lines Selective testing determines which tests run, and therefore which lines the coverage report can mark as covered. If changed lines show as uncovered, verify your selective testing setup actually ran the tests that exercise them. ## See Also * [Coverage Merging](/coverage/merging) - Combine multiple coverage reports * [Coverage Tags](/coverage/tags) - Track different types of tests separately * [Carry Forward Tags](/coverage/carry-forward-tags) - Reuse coverage when suites are skipped * [Commit Statuses](/coverage/commit-statuses) - Configure coverage gates on pull requests # Status Badges Source: https://docs.qlty.sh/coverage/status-badges Status badges let you display your project's code coverage and maintainability metrics directly in your repository README. These badges update automatically as your metrics change, giving visitors an at-a-glance view of your code quality. ## Available Badge Types Qlty provides two types of status badges: ### Code Coverage Badge Displays your project's code coverage percentage (0-100%). ![Coverage Badge Example](https://qlty.sh/gh/qltysh/projects/qlty/coverage.svg) ### Maintainability Badge Displays your project's maintainability rating as a letter grade (A, B, C, D, or F). ![Maintainability Badge Example](https://qlty.sh/gh/qltysh/projects/qlty/maintainability.svg) ## Getting Your Badge Code The easiest way to get your badge embed code is through the Qlty UI: 1. Go to your project on [qlty.sh](https://qlty.sh) 2. Navigate to **Settings** > **Badges** 3. Select the badge type (Maintainability or Code Coverage) 4. Choose the format (SVG or PNG) 5. Select the embed format (Markdown, HTML, or RDOC) 6. Click **Copy** to copy the code to your clipboard 7. Paste the code into your README ## Badge URL Format Badges are available at these URLs: ### By Project ID ``` https://qlty.sh/badges/{projectId}/coverage.svg https://qlty.sh/badges/{projectId}/maintainability.svg ``` ### By Workspace and Project ``` https://qlty.sh/gh/{workspace}/projects/{project}/coverage.svg https://qlty.sh/gh/{workspace}/projects/{project}/maintainability.svg ``` Both SVG (`.svg`) and PNG (`.png`) formats are supported. ## Embedding Examples ### Markdown ```markdown lines theme={"system"} [![Maintainability](https://qlty.sh/badges/{projectId}/maintainability.svg)](https://qlty.sh/gh/{workspace}/projects/{project}) [![Code Coverage](https://qlty.sh/badges/{projectId}/coverage.svg)](https://qlty.sh/gh/{workspace}/projects/{project}) ``` ### HTML ```html lines theme={"system"} Maintainability Code Coverage ``` ### RDOC ``` {Maintainability}[https://qlty.sh/gh/{workspace}/projects/{project}] {Code Coverage}[https://qlty.sh/gh/{workspace}/projects/{project}] ``` ## Migrating from CodeClimate Badges If you're migrating from CodeClimate, replacing your badges is straightforward: ### Step 1: Set Up Your Project on Qlty Before you can use Qlty badges, ensure your project is configured: 1. Add your project to [qlty.sh](https://qlty.sh) 2. For coverage badges, set up [coverage reporting](/coverage/quickstart) so Qlty receives your coverage data ### Step 2: Get Your New Badge Code 1. Go to your project's **Settings** > **Badges** page 2. Copy the badge code for each badge type you need ### Step 3: Replace the Badges in Your README Find your existing CodeClimate badges, which typically look like: ```markdown lines theme={"system"} [![Maintainability](https://api.codeclimate.com/v1/badges/{repo_id}/maintainability)](https://codeclimate.com/github/{org}/{repo}/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/{repo_id}/test_coverage)](https://codeclimate.com/github/{org}/{repo}/test_coverage) ``` Replace them with the Qlty badge code you copied: ```markdown lines theme={"system"} [![Maintainability](https://qlty.sh/badges/{projectId}/maintainability.svg)](https://qlty.sh/gh/{workspace}/projects/{project}) [![Code Coverage](https://qlty.sh/badges/{projectId}/coverage.svg)](https://qlty.sh/gh/{workspace}/projects/{project}) ``` ### Step 4: Commit and Push Commit your README changes and push to your repository. Your new Qlty badges will now display your current metrics. ## Troubleshooting ### Badge Shows "Unknown" If your badge displays "unknown" instead of a value: * **For coverage badges**: Ensure coverage data is being uploaded to Qlty. Check your CI pipeline and verify reports appear in **Project Settings** > **Code Coverage**. * **For maintainability badges**: Ensure your project has been analyzed by Qlty at least once. ### Badge Not Updating Badges are cached for up to 10 minutes. If you've just uploaded new coverage data, wait a few minutes and refresh. ### Badge Not Loading * Verify your project ID is correct * Check that the badge URL uses `https://` (not `http://`) * For private projects, badges are only accessible to authenticated project members ## See Also * [Coverage Metrics](/coverage/metrics) - Understand how coverage percentages are calculated * [Commit Statuses](/coverage/commit-statuses) - Display coverage status on GitHub pull requests * [PR Comments](/coverage/pull-request-comments) - Add coverage reports to pull request comments # Code Coverage Tags Source: https://docs.qlty.sh/coverage/tags A coverage tag is a name attached to a coverage report, usually the name of the test suite that produced it. A commit can have one coverage report per tag, and a report can be built from one or more uploads. There are two primary reasons to use coverage tags: * **To tell test suites apart.** Qlty reports and gates coverage per tag, so you can see and enforce unit test coverage separately from end-to-end coverage, for example. * **To keep total coverage accurate when not every commit or pull request runs every test suite.** Qlty carries forward the most recent report for each tag that did not run, so total coverage and its comparisons stay complete. ## Coverage tags or components? Both features break coverage down into smaller pieces, but they work differently: | | Coverage tags | Components | | - | - | - | | Groups coverage by | Coverage report (for example, one tag per test suite) | File path | | Created by | CI, automatically, the first time a report is published with the tag | Users, in project settings or through the API | | Changed by | Editing the uploads in your CI configuration | Editing the component's path patterns in Qlty | | Commit statuses | One set per tag | None | | When a commit has no data | Its most recent report is carried forward from an earlier commit | No carry forward | | Effect of a stale entry | A tag that no longer receives reports is still carried forward until deleted | A component whose patterns match no files shows no coverage | The [Code view](/cloud/projects/code) also aggregates coverage for every directory without any configuration. Tags and [components](/coverage/components) can be used together: tags describe which test suite produced the coverage, while components and directories describe which part of the codebase it covers. ## Where tag coverage appears When a project publishes tagged reports: * **Commit statuses.** Each tag reported for a pull request receives its own coverage gate (total coverage and/or diff coverage). Tags are currently the only way to publish more than one coverage commit status on a pull request. * **Pull request comments.** Each tag's results appear in a separate section of the [coverage summary comment](/coverage/pull-request-comments). * **Pull request coverage tab.** Changes can be filtered by one or more tags. * **Default branch.** When [browsing coverage](/coverage/browsing) for your default branch, the coverage presented combines all tags, and the views can also show coverage per tag. ## Carry forward and selectively running test suites If a commit has no report for a tag, Qlty [carries forward](/coverage/carry-forward-tags) the most recent report for that tag from an earlier commit. This is what makes tags work when a project runs its test suites selectively. Some CI setups run only some of a project's test suites on a pull request by design. For example, a monorepo might run only the test suite for the service that changed, so a repository with three test suites runs one or two of them on a typical pull request. Without tags, Qlty compares the pull request's coverage report against the base commit's report as a whole. If the base ran all three suites and the pull request ran one, total coverage appears to drop, even though nothing was lost. With one tag per test suite, Qlty knows which suites a commit did and did not run. For the suites that did not run, it carries forward the most recent report for that tag, so total coverage comparisons stay complete. ### Example: path-filtered workflows in a monorepo Each workflow runs only when its service changes, and each publishes its own tag: ```yaml GitHub Action lines theme={"system"} # .github/workflows/api.yml — runs only when api/ changes on: pull_request: paths: ["api/**"] # ... - uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: api/coverage/lcov.info tag: api # .github/workflows/web.yml — runs only when web/ changes on: pull_request: paths: ["web/**"] # ... - uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: web/coverage/lcov.info tag: web ``` A pull request that changes only `api/` publishes the `api` report. Qlty carries the `web` report forward from the most recent commit that published one, and compares the pull request's combined coverage against the base commit's combined coverage. Carry forward only comes into play when a commit lacks a report for a tag. If every suite ran on every pull request, each commit would have a report for both tags directly. ## Publishing tagged coverage Add the `tag` option to each upload. Every upload that contributes to a report carries the report's tag. ```yaml GitHub Action lines theme={"system"} # Unit test coverage - uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: coverage/unit/lcov.info tag: unit # End-to-end test coverage - uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: coverage/e2e/lcov.info tag: e2e ``` ```bash Qlty CLI lines theme={"system"} # Unit test coverage qlty coverage publish --tag=unit coverage/unit/lcov.info # End-to-end test coverage qlty coverage publish --tag=e2e coverage/e2e/lcov.info ``` There is nothing to define ahead of time. A tag is created the first time a report is published with its name. A few rules follow from tags being a property of the report: * Each upload carries one tag, or none. A commit can have one report per tag, plus one untagged report. * Use the same tag name for the same test suite on every commit. `unit` and `unit-tests` are two different tags, each tracked and carried forward on its own. * Tag names should not contain spaces or special characters. ## Tags with report merging Coverage tags work seamlessly with [report merging](/coverage/merging), allowing complex workflows while maintaining tag-specific insights. ### Important considerations When using coverage tags with report merging: 1. Each `qlty coverage publish` command applies to **a single tag** (or no tag) 2. Merging always refers to combining reports **for the same tag**, not across different tags 3. Server-side merging requires tracking completion separately for each tag ### Client-side merging with tags With client-side merging, run the `qlty coverage publish` command once per tag, combining all reports for that tag: ```yaml GitHub Action lines theme={"system"} # Publish unit test coverage (combining multiple reports) - uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} tag: unit files: | unit1.lcov unit2.lcov # Publish integration test coverage (combining multiple reports) - uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} tag: integration files: | integration1.lcov integration2.lcov ``` ```bash Qlty CLI lines theme={"system"} # Publish unit test coverage (combining multiple reports) qlty coverage publish --tag=unit \ unit1.lcov unit2.lcov # Publish integration test coverage (combining multiple reports) qlty coverage publish --tag=integration \ integration1.lcov integration2.lcov ``` ### Server-side merging with tags For server-side merging, each tag must be handled independently. #### Using `total-parts-count` with tags When using the `total-parts-count` approach, specify the count separately for each tag: ```yaml GitHub Action lines theme={"system"} # Integration tag example (1 of 4) - uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} tag: integration total-parts-count: 4 files: coverage.lcov # ... Three more `qltysh/qlty-action/coverage` steps for the `integration` tag ... # Unit tag example (1 of 2) - uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} tag: unit total-parts-count: 2 files: coverage.lcov # ... One more `qltysh/qlty-action/coverage` step for the `unit` tag ... ``` ```bash Qlty CLI lines theme={"system"} # Integration tag example (1 of 4) qlty coverage publish --tag=integration --total-parts-count=4 coverage.lcov # ... Three more `qlty coverage publish` commands for the `integration` tag ... # Unit tag example (1 of 2) qlty coverage publish --tag=unit --total-parts-count=2 coverage.lcov # ... One more `qlty coverage publish` command for the `unit` tag ... ``` #### Using `coverage complete` with tags When using the `--incomplete` flag approach, upload parts for each tag and then send a completion signal for that specific tag: ```bash Qlty CLI lines theme={"system"} qlty coverage publish --tag=unit --incomplete unit1.lcov qlty coverage publish --tag=unit --incomplete unit2.lcov qlty coverage complete --tag=unit qlty coverage publish --tag=integration --incomplete integration1.lcov qlty coverage publish --tag=integration --incomplete integration2.lcov qlty coverage publish --tag=integration --incomplete integration3.lcov qlty coverage complete --tag=integration ``` ## Managing tags Tags persist once created. This is what allows coverage for each tag to be tracked consistently over time, even when the tag's test suite does not run on every commit. It also means a tag that stops receiving reports does not go away on its own. Its last report keeps being carried forward onto newer commits and keeps counting toward the project's coverage. When a test suite is retired or renamed, delete its old tag so that stale coverage stops being included. ### Deleting tags To remove a tag that is no longer in use: 1. Navigate to your project in Qlty Cloud 2. Go to *Project Settings > Code Coverage* 3. Find the tag in the list of coverage tags 4. Click the **Delete** button next to the tag name Deleting a tag removes all historical coverage data associated with it. ## Troubleshooting ### Tag reporting issues If you're experiencing issues with tagged coverage reports: 1. Verify that the tag name is consistent across all commands 2. Ensure you're providing the correct tag when using `coverage complete` commands 3. Check that the tag name doesn't contain special characters or spaces ### Missing tag data If coverage data for a specific tag isn't appearing: 1. Confirm that the coverage report was successfully uploaded 2. Verify that the correct tag was specified in the upload command 3. For reports using server-side merging, check that the completion signal was sent 4. Ensure all parts of a tagged report have been uploaded if using the `total-parts-count` approach ## See Also * [Carry Forward Tags](/coverage/carry-forward-tags) - How carried-forward coverage is calculated * [Components](/coverage/components) - Group coverage by file path * [Coverage Merging](/coverage/merging) - How to merge multiple coverage reports * [CI Integration](/coverage/ci) - Automate coverage reporting in CI # Coverage Tokens Source: https://docs.qlty.sh/coverage/tokens Coverage tokens are used to authenticate when uploading code coverage reports to Qlty. This page explains the different types of tokens available, how to obtain them, and best practices for managing them securely. ## Types of Coverage Tokens Qlty offers three authentication methods for uploading coverage reports: ### 1. OpenID Connect (OIDC) with GitHub Actions OIDC is a tokenless approach that uses temporary credentials. It's the most secure method as it doesn't require storing any long-lived tokens. **Benefits:** * No token management required * Enhanced security with short-lived credentials * Automatic token rotation * Zero setup beyond the initial configuration **Limitations:** * Only works with GitHub Actions * Requires the `id-token: write` permission in your workflow ### 2. Workspace-level Coverage Tokens Workspace tokens provide coverage upload access for all repositories within a workspace (GitHub organization or user account). **Benefits:** * One token covers all repositories in a workspace * Simplified setup for organizations with many repositories * Works with any CI provider **Limitations:** * Broader scope than project tokens (less secure) * Must be rotated manually if compromised ### 3. Project-level Coverage Tokens Project tokens provide coverage upload access for a single repository. **Benefits:** * Most restrictive scope for enhanced security * Independent token management per repository * Works with any CI provider **Limitations:** * Requires separate token management for each project * Must be rotated manually if compromised ## Obtaining Coverage Tokens ### Workspace-level Token 1. Sign in to Qlty Cloud 2. Go to Workspace Settings 3. Navigate to the "Code Coverage" tab 4. Copy the workspace coverage token ### Project-level Token 1. Sign in to Qlty Cloud 2. Navigate to your project 3. Go to Project Settings 4. Select the "Code Coverage" tab 5. Copy the project coverage token ## Using Coverage Tokens ### In GitHub Actions Using OIDC (recommended): ```yaml lines theme={"system"} - uses: qltysh/qlty-action/coverage@v2 with: oidc: true files: coverage/lcov.info ``` Using a coverage token: ```yaml lines theme={"system"} - uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: coverage/lcov.info ``` ### In Other CI Systems Use the token as an environment variable: ```bash lines theme={"system"} QLTY_COVERAGE_TOKEN=your_token qlty coverage publish coverage/lcov.info ``` ## Security Best Practices ### Token Storage Coverage tokens should be treated as sensitive credentials: * **Never** commit tokens to your repository * **Always** use CI/CD environment variables or secrets * **Don't** expose tokens in build logs * **Don't** share tokens in communication channels ### Environment Variable Storage Store your coverage token as a secret environment variable in your CI system: * **GitHub Actions**: Repository or organization secrets * **CircleCI**: Environment variables or contexts * **Travis CI**: Environment variables * **GitLab CI**: CI/CD variables * **Azure DevOps**: Pipeline variables * **Jenkins**: Credentials binding plugin ### Token Rotation Rotate your coverage tokens periodically or immediately if you suspect they've been compromised: 1. Go to the same place where you obtained the token 2. Click "Refresh Token" (or similar) 3. Update the token in all your CI configurations Qlty will invalidate the old token and generate a new one. ### Scope Limitation Use the token with the most limited scope that meets your needs: * Use OIDC whenever possible with GitHub Actions * Use project-level tokens when working with a single repository * Use workspace-level tokens only when managing multiple repositories ## Common Questions ### What can someone do with a coverage token? Coverage tokens only allow uploading coverage reports to specific projects or workspaces. They cannot: * Access other Qlty features * Modify repository settings * Access source code * View private data The main risk of a leaked token is someone uploading fake coverage reports. ### How do I rotate a token? Tokens can be rotated through the same UI where you obtained them. Click "Refresh Token" to generate a new token and invalidate the old one. ### Can I use multiple tokens? Yes, you can use different tokens for different contexts. For example: * Different tokens for production vs. development environments * Different tokens for different CI pipelines * Different tokens for manual vs. automated uploads ### Should I verify my tokens are working? Yes, after setting up a new token, run a test upload to verify it's working correctly: ```bash lines theme={"system"} QLTY_COVERAGE_TOKEN=your_token qlty coverage publish coverage/lcov.info ``` Then check the project's coverage settings to confirm the report was received. ## Troubleshooting ### Authentication Failures If you get an authentication error: * Verify the token is correct (no extra spaces or line breaks) * Check that the environment variable is correctly defined * Ensure the token has not been rotated * Verify you're using the token in the correct context (workspace vs. project) ### Invalid Token Format If you see "Invalid token format" errors, check that: * The token is the complete string without any truncation * There are no extra characters or whitespace * You're not accidentally using a different type of token ## See Also * [CI Integration](/coverage/ci) - Set up automated coverage reporting * [GitHub OIDC](https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/about-security-hardening-with-openid-connect) - Detailed guide on using OIDC with GitHub Actions * [Troubleshooting](/coverage/troubleshooting) - Common issues and solutions # Coverage Trends Source: https://docs.qlty.sh/coverage/trends Qlty Cloud tracks your project's coverage over time and surfaces it as a chart on the project's [Overview](/cloud/projects/overview) page, under the **Coverage** tab. ## What's plotted * **Metric**: total line coverage percentage for the project's tracked branch. * **Time window**: the most recent 30 days. * **Granularity**: one data point per day. The chart redraws automatically as new coverage reports are uploaded — there's no manual refresh step. If a day has multiple coverage uploads, the most recent value wins; if a day has no upload, that point on the chart is interpolated using the most recent known coverage (so the trend line stays continuous as long as you've uploaded at least once). ## How the data gets there The Trend chart is based on coverage reports you've uploaded for your default branch. 1. [Set up coverage uploads](/coverage/quickstart) on your default branch. ## Related charts The Overview's lens tabs include two more trend lines: * **Maintainability** — technical debt over time. * **Security** — open security findings over time. All three use the same 30-day window and daily granularity, so switching tabs lets you compare them. ## See Also * [Diff Coverage Over Time](/coverage/diff-coverage-trends) * [Project Overview](/cloud/projects/overview) * [Coverage Hotspots](/coverage/hotspots) * [Code Coverage](/coverage) * [Coverage Metrics](/coverage/metrics) # Troubleshooting Source: https://docs.qlty.sh/coverage/troubleshooting This guide helps you troubleshoot common issues with code coverage in Qlty. ## Upload Issues ### Coverage Report Not Being Detected **Symptoms:** * "Unsupported format" errors * "Unable to parse coverage report" messages * No coverage data appears in Qlty after upload **Potential Causes:** * Unsupported coverage format * Corrupt or incomplete coverage report * Incorrect file path in upload command **Solutions:** 1. Verify your coverage format is [supported](/coverage/formats) 2. Check that the coverage report file exists and is complete 3. Try using the `--format` flag to explicitly specify the format: ```bash theme={"system"} qlty coverage publish --format=lcov path/to/coverage.info ``` 4. Examine the report file for valid content 5. Generate a fresh coverage report and try again ### Authentication Failures **Symptoms:** * "Authentication failed" errors * "Invalid token" messages * "Permission denied" errors **Potential Causes:** * Incorrect coverage token * Expired or rotated token * Missing environment variable * Using a token with incorrect scope **Solutions:** 1. Verify your token is correct in your CI settings 2. Check environment variable names (should be `QLTY_COVERAGE_TOKEN`) 3. Regenerate your token in Qlty and update your CI configuration 4. Ensure you're using the token for the correct workspace or project 5. If using OIDC, verify the permissions configuration in your GitHub workflow ### OIDC Token Failures on Forked PRs **Symptoms:** * Error: `Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable` * Coverage upload failures specifically on forked pull requests * OIDC authentication is working for regular PRs but failing on forks **Potential Causes:** * GitHub Actions security restrictions prevent OIDC token generation in workflows triggered by forked pull requests **Solutions:** For repositories that accept forked PRs, use Project Coverage Tokens instead of OIDC. See [Coverage Tokens](/coverage/tokens) for setup instructions. ### Path Mapping Issues **Symptoms:** * Coverage appears but doesn't match files in your repository * "File not found" errors when viewing coverage * Coverage shown for files that don't exist in your repo **Potential Causes:** * Coverage report contains absolute paths * Path structure differs between build environment and repository * Generated files with different paths **Solutions:** 1. See [Path Fixing](/coverage/path-fixing) for detailed solutions. ### S3 Upload Failures (403 Errors) **Symptoms:** * HTTP 403 Forbidden errors during coverage upload * "Access denied" messages when uploading to S3 * Coverage upload fails with permission errors **Potential Causes:** * Restrictive AWS VPC endpoint policies that block cross-account S3 operations * VPC endpoint policy doesn't allow `s3:PutObject` action to other AWS accounts **Solutions:** We are aware of 1 situation which can cause our coverage uploader to fail to upload with a 403 error: if you have a restrictive AWS VPC endpoint policy which does not allow the S3:PutObject action to another AWS account. In these cases, you'll need to open up your VPC to allow this action. Here are examples of how to configure this: **Terraform** ```hcl lines theme={"system"} { effect = "Allow" actions = ["s3:PutObject"] resources = ["*"] principals = { type = "AWS" identifiers = ["*"] } conditions = [ { test = "StringEquals" variable = "aws:PrincipalAccount" values = ["QLTY_AWS_ACCOUNT_ID"] }, { test = "StringEquals" variable = "aws:ResourceAccount" values = ["QLTY_AWS_ACCOUNT_ID"] } ] } ``` **AWS Policy** ```json lines theme={"system"} { "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": "s3:PutObject", "Resource": "*", "Condition": { "StringEquals": { "aws:ResourceAccount": "QLTY_AWS_ACCOUNT_ID", "aws:PrincipalAccount": "QLTY_AWS_ACCOUNT_ID" } } } ``` Reach out to [customer support](https://qlty.sh/contact/support) to obtain Qlty's AWS account id. ### Default Branch Coverage Not Displayed **Symptoms:** * Banner shows "We've received coverage reports; we haven't yet received a report for your default branch" * Coverage uploads exist but the project dashboard doesn't display default branch coverage **Potential Causes and Solutions:** #### Coverage config not yet merged to default branch The most common cause is that you've added coverage publishing to your CI config on a feature branch but haven't merged it to your default branch yet. Until the config change is merged, only PR branches will produce coverage uploads. Once you merge the PR that adds coverage publishing to your CI pipeline, subsequent pushes to your default branch will generate coverage uploads and the banner will go away. #### Default branch also a base branch for a long lived PR If you have an open pull request where your default branch is the **head** (source) branch (e.g., a long-lived PR from `main` → `production`), some CI providers may inject the PR number into every build on your default branch. This causes Qlty to classify the upload as a pull request upload instead of a branch upload. You can confirm this by visiting your coverage uploads page and checking whether uploads for your default branch show `refs/pull/XXXX` instead of `refs/heads/`. To resolve this, publish coverage a second time on default branch builds using the `--override-pr-number` flag with an empty string. This forces the upload to be classified as a branch upload while preserving PR coverage from the first publish. Add a second publish step after your existing coverage publish command: ```bash lines theme={"system"} # First publish (handles PR coverage as usual) qlty coverage publish # Second publish (only on default branch, forces branch classification) if [ "$CIRCLE_BRANCH" = "main" ]; then qlty coverage publish --override-pr-number "" fi ``` Replace `main` with your default branch name if different (e.g., `master`). ### Missing Metadata **Symptoms:** * Coverage is uploaded but not associated with the correct branch * Coverage doesn't appear in pull requests * Coverage data shows with incorrect commit information **Potential Causes:** * CI system metadata not detected * Shallow git clone in CI * Custom CI setup not recognized by Qlty **Solutions:** 1. Manually specify metadata with override flags: ```bash theme={"system"} qlty coverage publish --override-branch=main --override-commit-sha=abcdef123 coverage.xml ``` 2. Ensure your CI environment provides standard environment variables 3. Use a deeper git clone in CI (or fetch git metadata) 4. Check that the git repository is available in the CI environment ## Viewing Issues ### Coverage Not Showing in GitHub **Symptoms:** * No coverage status checks on pull requests * Missing coverage comments on pull requests * Coverage data visible in Qlty but not in GitHub **Potential Causes:** * GitHub app permissions issues * Coverage gates not enabled * PR comments not configured * Timing issues with CI and status reporting **Solutions:** 1. Verify GitHub integration settings in project settings 2. Check that coverage gates are enabled in quality gates settings 3. Ensure PR comments are enabled 4. Check GitHub app permissions in your organization settings 5. Try manually uploading coverage for the PR branch ### Inconsistent Coverage Reports **Symptoms:** * Coverage fluctuates between builds without code changes **Potential Causes:** * Test flakiness or non-deterministic tests * Cache issues in tests * Different coverage tool configurations **Solutions:** See [Unexpected Coverage Changes](/coverage/unexpected-changes) for a full discussion of possible causes and solutions. ### Missing Coverage for Some Files **Symptoms:** * Some files show no coverage data * Certain directories are missing from coverage reports * Coverage appears for some languages but not others **Potential Causes:** * Include/exclude patterns filtering out files * Multi-language projects with incomplete coverage setup * Files not being exercised by tests * Generated code or third-party code inclusion/exclusion **Solutions:** 1. Check your coverage tool's include/exclude configuration. See [Excluding Files from Coverage](/coverage/excluding-files) for language-specific examples. 2. Verify that all relevant files are included in coverage report generation. See our documentation on [Incomplete or Missing Coverage Reports](/coverage/unexpected-changes#incomplete-or-missing-coverage-reports) for more detail. 3. Set up coverage for each language in multi-language projects 4. Use multiple coverage reports for different parts of the codebase ## Quality Gate Issues ### Failing Coverage Gates **Symptoms:** * Pull requests failing due to coverage checks * "Coverage decreased" warnings even with improved test coverage * Diff coverage failing despite high coverage in changed files **Potential Causes:** * Thresholds set too high for your project's current state * Coverage decreasing in files not directly modified * Base branch coverage calculation issues * Coverage calculation includes excluded files **Solutions:** 1. Adjust coverage gate thresholds to realistic levels 2. Investigate [unexpected coverage changes](/coverage/unexpected-changes) 3. Temporarily disable gates while building up coverage 4. [Exclude irrelevant files](/coverage/excluding-files) in your coverage tool so they don't affect gates 5. Focus on diff coverage rather than total coverage for incremental improvement ### Coverage Badges Not Updating **Symptoms:** * Outdated coverage percentage in badges * Coverage badge shows "unknown" or "N/A" * Badge doesn't reflect recent coverage improvements **Potential Causes:** * Badge caching * No coverage data for default branch * Badge URL issues **Solutions:** 1. Ensure coverage is being uploaded for your default branch 2. Check badge URLs and project settings 3. Manually refresh cached badges 4. Verify that the badge is pointing to the correct project and metric 5. Wait for cache expiration (typically a few hours) ## Merging ### Coverage Data Missing **Presenting Problem** * Qlty reports less coverage for a source file than expected. For example, a line is covered according to the raw coverage data, but Qlty shows the line as not covered * Qlty does not show coverage data for a file **Diagnosis and Resolutions** 1. Ensure that Qlty has received all partial reports (uploads). The best diagnostic tool is the list of coverage uploads browsable on qlty.sh at Project Settings => Code Coverage. Search for the commit sha, pull request (e.g. `refs/pull/5`), or branch (e.g. `refs/heads/branchName`). You should see N "incomplete" reports representing the N uploads Qlty received as well as 1 "complete" report, representing a completion of the report. If you see less than you expect, check that: * Every upload attempt succeeded. Did the CLI report "Upload successful" at the end of its output? If not, what error occurred? * Every coverage report attempted an upload. Providing a unique name with every coverage report (with `--name`) can help pinpoint a missing coverage report. (The name will be show in the coverage upload detail page) * Each upload is associated with the same expected tag (or no tag) * Investigate [Incomplete or Missing Coverage Reports](/coverage/unexpected-changes#incomplete-or-missing-coverage-reports) ## Coverage Tag Issues **Symptoms:** * Tagged coverage not appearing separately * Incorrect coverage shown for specific tags * Tags not filtering correctly in UI **Potential Causes:** * Incorrect tag specification during upload * Mixing tagged and untagged uploads * UI filtering confusion **Solutions:** 1. Verify tag naming in upload commands: ```bash theme={"system"} qlty coverage publish --tag=unit coverage.xml ``` 2. Ensure consistent tag usage across uploads 3. Check tag configuration in project settings 4. Use different tags for different test types (unit, integration, etc.) ## Large Repository Issues **Symptoms:** * Coverage uploads timing out * Very slow coverage rendering in UI * Missing coverage for some files in large repositories **Potential Causes:** * Coverage reports too large * Too many files included in coverage * Performance limits in browser extensions **Solutions:** 1. [Exclude irrelevant files](/coverage/excluding-files) in your coverage tool to limit coverage to relevant code 2. Split large repositories into smaller projects 3. [Exclude generated code, vendor code, or test code](/coverage/excluding-files) from your coverage reports 4. Use more specific coverage focus for very large repositories 5. Contact Qlty support for help with large-scale deployments ## Getting Additional Help If you've tried the solutions above and are still experiencing issues: 1. **Contact Support**: Reach out to [Qlty support](mailto:support@qlty.sh) 2. **Join Discord**: Ask for help in our [Discord community](https://qlty.sh/discord) 3. **GitHub Issues**: Submit a bug report on our [GitHub issue tracker](https://github.com/qltysh/qlty/issues) When asking for help, include: * The exact command you're running * Any error messages (with sensitive information redacted) * Your CI provider and configuration * The coverage tool and language you're using * Steps you've already taken to troubleshoot # Unexpected Code Coverage Changes Source: https://docs.qlty.sh/coverage/unexpected-changes When working with code coverage, you might occasionally see unexpected changes in coverage metrics. This guide helps you understand why these changes occur and how to investigate them. Unexpected coverage changes often surface when you notice entries in the **Indirect Changes** section of a pull request's coverage summary — coverage that moved on files the pull request didn't touch. There are two high level reasons why your coverage might change unexpectedly: 1. Execution Path Changes 2. Incomplete or Missing Coverage Data ## Execution Path Changes Qlty is designed to trust code coverage data exactly as it is generated by coverage tools like Cobertura, LCOV, SimpleCov, etc. These coverage tools often reflect reality: coverage changed because tests executed code differently. The question that naturally follows is: what caused these changes? While tests may not fail, coverage can change for all the same reasons that tests can occassionally fail: code changes, dependency changes, non-determinism, and other environment changes can cause your code to execute slightly differently on subsequent runs, even for the same commit. ### Indirect Code Paths Although unexpected, this category of change represents a real change in your coverage data caused by a change in your code or tests — not by non-determinism or a problem collecting coverage data. The coverage of one file shifts because of how changed code elsewhere exercises it: * **Function Call Removal**: If File A stops calling a function in File B, File B's coverage might decrease * **Conditional Logic Changes**: Changing a condition in one file might prevent code in another file from executing * **Error Handling Changes**: Changes to how errors are thrown or caught can affect which code paths are exercised #### Example: ```javascript lines theme={"system"} // Before: UserService.js async function getUser(id) { return await UserRepository.findById(id); // UserRepository.findById is called every time } // After: UserService.js async function getUser(id) { if (!id) return null; // Now UserRepository.findById is only called when id exists return await UserRepository.findById(id); } ``` This change would reduce coverage in `UserRepository.js` even though it wasn't modified. > [!NOTE] > > Some code paths are gateway paths that control access to large portions of code: > > * **Auth/Permission Checks**: Changes to authentication logic might prevent large sections of code from running > * **Feature Flags**: Toggling feature flags can enable/disable entire features > * **Dependency Injection**: Changing what's injected can alter large execution paths ### Dependency Changes Any sizeable software project relies on dependencies, some explicit and direct, and some less obvious and less direct. Here's an (incomplete) list of dependencies that can cause execution changes and therefore coverage changes: * Explicit dependency changes (e.g. Bumping a package from version 1.2.3 to 1.3.4) * Floating dependencies (e.g. your code runs on the latest version of nodejs, and the latest version of nodejs changes) * Time: a time change can cause a test to follow a different execution path (even for the same commit) * Network connectivity * Other environmental changes ### Non-Determinism and Flaky Coverage As noted, unexpected coverage changes can be viewed through the same lens as engineers often view unexpected test failures. Just like a test can be flaky and fail occassionally, coverage can change for similar reasons. Some amount of non-determinism is often intentional. A common configuration is to run tests in a random order, which forces an engineering team to surface and address any issues that are the result of unexpected order dependencies between tests. This is healthy for the test suite, but it also means the exact set of lines executed — and therefore coverage — can vary slightly from run to run. Non-determinism tends to come up more often for larger, more complex test suites. As a suite grows, both the chance of some non-determinism and the surface area over which it can occur increase. Statistically, non-determinism tends to affect files that a given pull request didn't edit: a pull request usually touches only a small fraction of the codebase, so any run-to-run variation is far more likely to land on unedited files. As a result, non-determinism usually appears as [indirect coverage changes](#indirect-code-paths) — coverage shifting in files you didn't directly modify — which moves your Total Coverage number. These small movements in Total Coverage are usually tolerable: for large repositories, Total Coverage is generally a less helpful signal than [Diff Coverage](/coverage/metrics#diff-coverage) for understanding the coverage impact of a pull request. A small overall percentage change is normal, especially for large repositories. Large swings in coverage, on the other hand, are typically not the result of runtime non-determinism — they usually point to an issue with test coverage data collection, such as [incomplete or missing coverage reports](#incomplete-or-missing-coverage-reports). To diagnose whether non-determinism is the cause of a coverage change (rather than specific code or test changes), run the full test suite against the same commit (and/or tag, if applicable) enough times to gain confidence in the stability or instability of your coverage. You can [retrieve the raw coverage data](#retrieving-raw-coverage-data-for-diagnosis) for each of these runs to compare them directly. If your coverage changes between these runs, you know the cause is non-deterministic behavior in your test suite. Isolating the test and/or bisecting the test suite are good starting points for investigating what causes the non-determinism. > [!NOTE] > > Because the causes of non-determinism depend on your specific test environment, diagnosing the > root cause is not something the Qlty support team can typically help with. Support can, however, > help analyze the coverage data sent to us — if you're unsure how to interpret what you're seeing, > [reach out to support](/cloud/support). ## Incomplete or missing coverage reports ### Test optimization tools Test optimization tools sometimes intentionally or unintentionally (buggy) run less than 100% of tests. If the test optimization is new, this behavior would consistently result in Qlty reporting coverage drops. Depending on your test sharding and upload strategy, this truncation can sometimes be apparent in the raw coverage data: you may see fewer coverage data files than expected, or individual files that are unusually truncated. See [Retrieving Raw Coverage Data for Diagnosis](#retrieving-raw-coverage-data-for-diagnosis) to inspect the files Qlty received. > [!NOTE] > > Coordinating coverage with test optimization tools is not a configuration Qlty currently > supports, though it's something we've discussed supporting. If this is a setup you're interested > in, [reach out to support](/cloud/support). ### Overwritten or overlooked coverage data files Test suites commonly generate multiple coverage data files. Qlty must receive all coverage data files in order to accurately report coverage. While this can be straight-forward -- a file was not sent that should have -- there are a few less straight-forward ways this can happen: * A build parallelizes their test suite using multiple threads or processes, but each unit of parallelization overwrites one another's coverage data file, clobbering or corrupting coverage data * A build parallelizes their test suite using multiple machines, where each machine generates unique coverage data files. Then, either some machines's coverage data files are missed or the files, when collected together from different machines, because similarly named, overwrite one another. Review our [Coverage Merging documentation](/coverage/merging) to ensure you're sending coverage data correctly. See [Retrieving Raw Coverage Data for Diagnosis](#retrieving-raw-coverage-data-for-diagnosis) below for how to verify Qlty has received all coverage reports. ## Retrieving Raw Coverage Data for Diagnosis For several of the scenarios above, the most direct way to find the root cause is to examine the raw coverage data Qlty received — the exact files your coverage tools generated, before Qlty processes or merges them. There are various reasons you might want this data: comparing the base and head commits of a pull request, comparing multiple runs of the same commit to diagnose non-determinism, or verifying that every coverage file you expected was actually received. > [!NOTE] > > Qlty is designed to trust code coverage data exactly as it is generated by coverage tools like Cobertura, LCOV, SimpleCov, etc. > > Therefore, the Qlty technical support team is unable to investigate unexpected code coverage changes, as the causes are always unique to the codebase. > > If you find a discrepancy between the raw coverage data generated by your coverage tool and the data reported by Qlty, please let us know. ### Retrieving the raw coverage data To download and read the raw coverage data files for any coverage upload: 1. **Navigate to coverage uploads**: In your Qlty project, go to *Project Settings > Code Coverage* and search by commit SHA or branch to find the relevant coverage upload(s). 2. **Click "Download Zip"** > [!NOTE] > > If using [server-side merging](/coverage/merging#server-side-merging), you'll need to download > each "incomplete" coverage zip file by following the upload links marked as incomplete. 3. **Examine the coverage data files**: Extract the ZIP file and open the coverage data files in the `raw_files/` folder. Search for the file path you're investigating and read the relevant sections. > [!NOTE] > > If the folder seems empty note that some tools, like SimpleCov (`.resultset.json`), use a naming > convention that starts with a `.` causing the file to appear hidden in some operating systems. Each coverage file format is different, but you can often identify discrepancies by reading the data in a text editor. ### Comparing commits on a pull request A common, specific investigation is confirming that an unexpected coverage change on a pull request is real by comparing the coverage data for the base and head commits. 1. **Obtain commit SHAs**: Obtain the commit SHAs for both the branch head and merge base commits from Git or GitHub. > [!NOTE] > > While the commit sha for a the head of a pull request is often easy to determine, the merge base > is not currently listed on Qlty or GitHub. However, you can use `git merge-base` > ([documentation](https://git-scm.com/docs/git-merge-base)) to determine the relevant base > commit. Make sure you pull from remote first before using `git merge-base`. 2. **Compare the coverage metrics in Qlty Cloud**: For each commit, go to *Project Settings > Code Coverage*, search by commit SHA (NB: you can also search by branch), and use the on-page search to filter by the specific file path that's showing unexpected changes. Confirm whether the Covered Lines and/or Missed Lines values differ between the two uploads. 3. **Compare the raw coverage data**: For a deeper look, [retrieve the raw coverage data](#retrieving-the-raw-coverage-data) for both commits and compare the relevant sections between the two files. This process helps confirm whether the indirect coverage change is *internally consistent* (caused by actual test execution differences) or if there might be an issue with how coverage is being generated or reported in your CI/CD pipeline. After completing your investigation, you'll encounter one of two outcomes: * **If the coverage data file shows different coverage values**, this confirms the unexpected coverage change is real and legitimate. The coverage difference exists in your actual test execution between commits, meaning Qlty is correctly reporting what your coverage tools generated. * **If the coverage data shows identical coverage for both the base and head commits**, this suggests an inconsistency in Qlty's processing. If this is the case, feel free to report it to [Qlty support](/cloud/support) with your findings, including the commit SHAs and file paths. > [!NOTE] > > An inconsistency in Qlty's processing is exceedingly rare. In nearly all cases that customers > investigate, the root cause is a difference in the raw coverage data being provided to Qlty. # Custom Checks Source: https://docs.qlty.sh/custom-checks Custom checks allow you to create and enforce your own static analysis rules specific to your codebase and organization's needs. Qlty provides support for three powerful static analysis engines, giving you flexibility in how you define and implement custom checks. > [!TIP] > > Custom checks are supported by both [Qlty CLI](/cli/quickstart) and [Qlty > Cloud](/cloud/quickstart). ## Types of Custom Checks Qlty supports three plugins for custom checks: ### AST-Grep [AST-Grep](https://ast-grep.github.io/) is a syntax-aware code search and transformation tool that uses Abstract Syntax Trees (ASTs) to understand code structure. This makes it particularly effective for complex pattern matching that accounts for code syntax rather than just text matching. Key features: * Structural code search across 20+ programming languages * AST-based pattern matching for more accurate results * Fast execution * Supports languages including JavaScript, TypeScript, Python, Java, Go, C++, and more Use `qlty plugins enable ast-grep` or add ast-grep to your `qlty.toml`: ```toml lines theme={"system"} [[plugin]] name = "ast-grep" ``` ### Semgrep [Semgrep](https://semgrep.dev/) is a lightweight static analysis tool designed for finding bugs, detecting vulnerabilities, and enforcing code standards. It uses a pattern syntax that looks like the code you're searching for. Key features: * Supports 20+ programming languages * Pattern matching that understands code semantics * Designed for security-focused rules * Easy-to-write patterns that resemble the target code Use `qlty plugins enable semgrep` or add semgrep to your `qlty.toml`: ```toml lines theme={"system"} [[plugin]] name = "semgrep" ``` ### Ripgrep Ripgrep is a high-performance text search tool that can be used for simple pattern matching in your codebase. While it doesn't understand code structure like AST-Grep or Semgrep, it's extremely fast and useful for straightforward text pattern searches. Key features: * Blazing fast text search across files * Regular expression support * Useful for simpler pattern matching needs Use `qlty plugins enable ripgrep` or add ripgrep to your `qlty.toml`: ```toml lines theme={"system"} [[plugin]] name = "ripgrep" ``` ## Writing Custom Rules Each tool has its own syntax for defining rules: ### AST-Grep rules AST-Grep rules use a YAML format that defines patterns to match in the code's syntax tree: ```yaml lines theme={"system"} id: no-console-log language: javascript message: "Avoid using console.log in production code" severity: warning pattern: console.log($X) ``` Create an [`sgconfig.yml` configuration file](https://ast-grep.github.io/reference/sgconfig.html) in your project and use the `ruleDirs` key to specify the directory containing your custom rules. Learn more about writing AST-Grep rules in the [AST-Grep documentation](https://ast-grep.github.io/guide/pattern-syntax.html). ### Semgrep rules Semgrep rules also use YAML with a pattern syntax that closely resembles the code being searched: ```yaml lines theme={"system"} rules: - id: avoid-eval pattern: eval(...) message: "Avoid using eval() as it can lead to security vulnerabilities" languages: [javascript, typescript] severity: ERROR ``` Store your rules in a `.semgrep.yaml` file in your project root or `.qlty/configs/` directory. Learn more about writing Semgrep rules in the [Semgrep documentation](https://semgrep.dev/docs/writing-rules/overview). ### Ripgrep patterns Unlike AST-Grep and Semgrep, ripgrep uses regular expressions for pattern matching. Ripgrep matchers are defined in the `qlty.toml` file by customizing the `ripgrep` plugin definition, or creating a new plugin. Here is an example of customizing the `ripgrep` plugin, which by default looks for `TODO` comments, to look for other patterns in your code: ```toml lines theme={"system"} [plugins.definitions.ripgrep.drivers.lint-fixme] script = "rg \"APPLES|ORANGES|STRAWBERRIES\" ${target} --json --word-regexp --only-matching" ``` Here is an example of defining a brand new plugin based on ripgrep which finds references to an outdated name: ```toml lines theme={"system"} [plugins.definitions.rebranded-names] releases = ["ripgrep"] file_types = ["markdown"] description = "Finds references to rebranded names in Markdown" [plugins.definitions.rebranded-names.drivers.lint] script = "rg \"HBO Max|Dunkin Donuts|Square\" ${target} --json --word-regexp --only-matching" success_codes = [0, 1] output = "stdout" output_format = "ripgrep" batch = true cache_results = true ``` ## Triaging issues from custom checks You can define triage rules in `qlty.toml` which customize the category and level of issues found by your custom checks. This allows you to prioritize certain issues over others, or to categorize them based on your team's workflow. ```toml lines theme={"system"} # Set the category and level for issues found by `rebranded-names` plugin above [[triage]] match.plugins = ["rebranded-names"] set.category = "style" set.level = "low" ``` ## Benefits of Custom Checks * **Enforce organization-specific standards**: Create rules tailored to your team's coding guidelines * **Prevent common errors**: Catch recurring issues before they make it into production * **Ensure consistency**: Maintain coding style and best practices across your codebase * **Improve security**: Enforce security best practices specific to your application ## See Also * [Analysis Configuration](/cli/analysis-configuration) * [Linting](/linting) * [Plugins](/cli/concepts/plugins) # Duplication Source: https://docs.qlty.sh/duplication Qlty is able to detect duplicated code (aka copy/pasted code) across your entire repository for all of our [supported languages](/languages). Code duplication occurs when identical or similar code blocks appear in multiple places within a codebase. While it might seem harmless at first glance, duplication can lead to several significant issues in software development: 1. **Slower Comprehension:** Duplication can make the codebase more complex and harder to understand. Developers need to grasp multiple copies of the same logic, which can obscure the overall structure and flow of the application. 2. **Bug Propagation:** If a bug exists in a duplicated code block, it will likely be present in all copies. This can lead to widespread issues and make debugging more challenging. 3. **Reduced Reusability:** Code duplication reduces the modularity and reusability of code. Instead of having a single, reusable function or module, duplicated code fragments limit opportunities for efficient reuse and refactoring. By identifying and addressing duplicated code, developers can enhance the maintainability, readability, and quality of their codebase, leading to more robust and efficient software development practices. > [!TIP] > > Duplication detection is provided by [Qlty CLI](/cli/quickstart) and [Qlty > Cloud](/cloud/quickstart). ## How Duplication Detection Works Qlty implements its own duplication engine in Rust based on the Tree-Sitter parser. At its heart, it uses a fairly simple algorithm to decide which parts of your code are duplicated. 1. First, source files are parsed into abstract syntax trees (ASTs) 2. Nodes are recursively "fingerprinted" in a way that retains their structural information (node type and descendants) but discards their literal information (like variable names) 3. We build an index of all nodes organized by their fingerprints 4. For any fingerprint which matches multiple nodes, we have identified duplication 5. We remove duplication matches nested within other duplicates to output the largest matches 6. Finally, we apply a filter to exclude duplication which is on small sections of code ## See Also * [Analysis Configuration](/cli/analysis-configuration) * [Code Smells](/code-smells) * [Complexity](/complexity) # Programming Language Support Source: https://docs.qlty.sh/languages ## Full support Qlty (both Qlty CLI and Qlty Cloud) provides complete support for the following languages. > **[C / C++](/languages/c-cpp)** > **[C#](/languages/csharp)** > **[Go](/languages/golang)** > **[Java](/languages/java)** > **[JavaScript](/languages/javascript)** > **[Kotlin](/languages/kotlin)** > **[PHP](/languages/php)** > **[Python](/languages/python)** > **[Ruby](/languages/ruby)** > **[Rust](/languages/rust)** > **[Scala](/languages/scala)** > **[Swift](/languages/swift)** > **[TypeScript](/languages/typescript)** > **[VB.NET](/languages/vbnet)** ### Planned We are planning to add full support for the following languages: * Elixir * Groovy If you'd like us to add suport for a programming language that you use, please contact us. ## Infrastructure as Code (IaC) Languages Qlty provides security scanning and linting for the following Infrastructure as Code languages: * Terraform * CloudFormation * Kubernetes * Docker * Shell (Bash) * GitHub Actions workflows ## Additional Languages Qlty supports additional languages with a wide range of linter and auto-formatter [plugins](/plugins). | | Linting | Formatting | | - | - | - | | CSS | ✓ | ✓ | | GraphQL | | ✓ | | HTML | | ✓ | | JSON | | ✓ | | Markdown | ✓ | ✓ | | Prisma | ✓ | | | SASS | | ✓ | | SCSS | ✓ | | | SQL | ✓ | | | YAML | | ✓ | ## More information * [Available Plugins](/plugins) * [Security Framework](/cloud/security/framework) * [Implementing Security Scanning](/cloud/security/implementing) * [Developing Plugins](/cli/developing-plugins) # C / C++ Language Support Source: https://docs.qlty.sh/languages/c-cpp ## Summary
Feature Status Notes
[Maintainability](/cloud/maintainability/metrics) ✔ Complexity, duplication, code smells
[Linting](/linting) ✔ Via Semgrep
[Custom checks](/custom-checks) ✔
[Security scanning](/cloud/security/framework) ✔ AppSec and secrets
[Code metrics](/cloud/maintainability/metrics) ✔
[Code coverage](/coverage) ✔ Via gcov / LCOV
## Details
Maintainability
[Complexity](/complexity) ✔ Aka cognitive complexity
[Cyclomatic complexity](/complexity#difference-from-cyclomatic-complexity) ✔
[Identical code duplication](/duplication) ✔
[Similar code duplication](/duplication) ✔
[Code smells](/code-smells) ✔
Linters
[Semgrep](https://semgrep.dev) ✔ Static analysis with a community rule library
Custom checks
[ast-grep](https://github.com/ast-grep/ast-grep) ✔
[Semgrep](https://semgrep.dev) ✔
[ripgrep](https://github.com/BurntSushi/ripgrep) ✔
Security scanning
[Gitleaks](https://gitleaks.io/) ✔ Secrets scanning
[Semgrep](https://semgrep.dev) ✔ AppSec (SAST)
[Trivy](https://trivy.dev) ✔ Dependency scanning (SCA) for Conan
[TruffleHog](https://trufflesecurity.com/trufflehog) ✔ Secrets scanning
Code coverage
[gcov](https://gcc.gnu.org/onlinedocs/gcc/Gcov.html) / [lcov](https://github.com/linux-test-project/lcov) ✔
LCOV coverage format ✔
Cobertura coverage format ✔
## File extensions By default, C files are defined as: ``` [file_types.c] globs = ["*.c"] ``` By default, C++ files are defined as: ``` [file_types.cpp] globs = ["*.cpp", "*.hpp", "*.cc", "*.cxx", "*.c++", "*.h", "*.h++", "*.hh", "*.hxx"] ``` These patterns can be overridden from `qlty.toml`. # C# Language Support Source: https://docs.qlty.sh/languages/csharp ## Summary
Feature Status Notes
[Maintainability](/cloud/maintainability/metrics) ✔ Complexity, duplication, code smells
[Custom checks](/custom-checks) ✔
[Security scanning](/cloud/security/framework) ✔ AppSec, dependencies, and secrets
[Code metrics](/cloud/maintainability/metrics) ✔
[Code coverage](/coverage) ✔
## Details
Maintainability
[Complexity](/complexity) ✔ Aka cognitive complexity
[Cyclomatic complexity](/complexity#difference-from-cyclomatic-complexity) ✔
[Identical code duplication](/duplication) ✔
[Similar code duplication](/duplication) ✔
[Code smells](/code-smells) ✔
Custom checks
[Semgrep](https://semgrep.dev) ✔
[ripgrep](https://github.com/BurntSushi/ripgrep) ✔
Security scanning
[Gitleaks](https://gitleaks.io/) ✔ Secrets scanning
[Semgrep](https://semgrep.dev) ✔ AppSec (SAST)
[Trivy](https://trivy.dev) ✔ Dependency scanning (SCA) for NuGet
[TruffleHog](https://trufflesecurity.com/trufflehog) ✔ Secrets scanning
Code coverage
Cobertura coverage format ✔
## File extensions By default, C# files are defined as: ``` [file_types.csharp] globs = ["*.cs"] ``` These patterns can be overridden from `qlty.toml`. ## Supported C# versions We officially support C# 8+ and later for maintainability checks and code coverage. Each plugin may have its own version requirements. # Go Language Support Source: https://docs.qlty.sh/languages/golang ## Summary
Feature Status Notes
[Maintainability](/cloud/maintainability/metrics) ✔ Complexity, duplication, code smells
[Linting](/linting) ✔
[Auto-formatting](/auto-formatting) ✔
[Custom checks](/custom-checks) ✔
[Security scanning](/cloud/security/framework) ✔ AppSec, dependencies, and secrets
[Code metrics](/cloud/maintainability/metrics) ✔
[Code coverage](/coverage) ✔
## Details
Maintainability
[Complexity](/complexity) ✔ Aka cognitive complexity
[Cyclomatic complexity](/complexity#difference-from-cyclomatic-complexity) ✔
[Identical code duplication](/duplication) ✔
[Similar code duplication](/duplication) ✔
[Code smells](/code-smells) ✔
Linters
[golangci-lint](https://golangci-lint.run/) ✔ Fast Go linters runner
[radarlint-go](https://github.com/qltysh/radarlint) ✔ Static analysis tool
Auto-formatters
[gofmt](https://pkg.go.dev/cmd/gofmt) ✔ Standard Go formatter
Custom checks
[ast-grep](https://github.com/ast-grep/ast-grep) ✔
[Semgrep](https://semgrep.dev) ✔
[ripgrep](https://github.com/BurntSushi/ripgrep) ✔
Security scanning
[Gitleaks](https://gitleaks.io/) ✔ Secrets scanning
[OSV-Scanner](https://google.github.io/osv-scanner/) ✔ Dependency scanning (SCA)
[radarlint-go](https://github.com/qltysh/radarlint) ✔ AppSec (SAST)
[Semgrep](https://semgrep.dev) ✔ AppSec (SAST)
[Trivy](https://trivy.dev) ✔ Dependency scanning (SCA)
[TruffleHog](https://trufflesecurity.com/trufflehog) ✔ Secrets scanning
Code coverage
[go test](https://pkg.go.dev/cmd/go/internal/test) ✔
Clover coverage format ✔
Cobertura coverage format ✔
## File extensions By default, Go files are defined as: ``` [file_types.go] globs = ["*.go"] ``` These patterns can be overridden from `qlty.toml`. ## Supported Go versions We officially support Go 1.13 and later for maintainability checks and code coverage. Each plugin may have its own version requirements. # Java Language Support Source: https://docs.qlty.sh/languages/java ## Summary
Feature Status Notes
[Maintainability](/cloud/maintainability/metrics) ✔ Complexity, duplication, code smells
[Linting](/linting) ✔
[Auto-formatting](/auto-formatting) ✔
[Custom checks](/custom-checks) ✔
[Security scanning](/cloud/security/framework) ✔ AppSec, dependencies, and secrets
[Code metrics](/cloud/maintainability/metrics) ✔
[Code coverage](/coverage) ✔
## Details
Maintainability
[Complexity](/complexity) ✔ Aka cognitive complexity
[Cyclomatic complexity](/complexity#difference-from-cyclomatic-complexity) ✔
[Identical code duplication](/duplication) ✔
[Similar code duplication](/duplication) ✔
[Code smells](/code-smells) ✔
Linters
[Checkstyle](https://checkstyle.sourceforge.io/) ✔ Static code analysis tool
[PMD](https://pmd.github.io/) ✔ Source code analyzer
[radarlint-java](https://github.com/qltysh/radarlint) ✔ Static analysis tool
Auto-formatters
[google-java-format](https://github.com/google/google-java-format) ✔ Google's Java formatter
Custom checks
[ast-grep](https://github.com/ast-grep/ast-grep) ✔
[Semgrep](https://semgrep.dev) ✔
[ripgrep](https://github.com/BurntSushi/ripgrep) ✔
Security scanning
[Gitleaks](https://gitleaks.io/) ✔ Secrets scanning
[OSV-Scanner](https://google.github.io/osv-scanner/) ✔ Dependency scanning (SCA)
[radarlint-java](https://github.com/qltysh/radarlint) ✔ AppSec (SAST)
[PMD](https://pmd.github.io/) ✔ AppSec (SAST)
[Semgrep](https://semgrep.dev) ✔ AppSec (SAST)
[Trivy](https://trivy.dev) ✔ Dependency scanning (SCA)
[TruffleHog](https://trufflesecurity.com/trufflehog) ✔ Secrets scanning
Code coverage
[JUnit](https://junit.org/) ✔
JaCoCo coverage format ✔
Cobertura coverage format ✔
## File extensions By default, Java files are defined as: ``` [file_types.java] globs = ["*.java"] ``` These patterns can be overridden from `qlty.toml`. ## Supported Java versions We officially support Java 8 and later for maintainability checks and code coverage. Each plugin may have its own version requirements. # JavaScript Language Support Source: https://docs.qlty.sh/languages/javascript ## Summary
Feature Status Notes
[Maintainability](/cloud/maintainability/metrics) ✔ Complexity, duplication, code smells
[Linting](/linting) ✔
[Auto-formatting](/auto-formatting) ✔
[Custom checks](/custom-checks) ✔
[Security scanning](/cloud/security/framework) ✔ AppSec, dependencies, and secrets
[Code metrics](/cloud/maintainability/metrics) ✔
[Code coverage](/coverage) ✔
## Details
Maintainability
[Complexity](/complexity) ✔ Aka cognitive complexity
[Cyclomatic complexity](/complexity#difference-from-cyclomatic-complexity) ✔
[Identical code duplication](/duplication) ✔
[Similar code duplication](/duplication) ✔
[Code smells](/code-smells) ✔
Linters
[ESLint](https://eslint.org/) ✔ Pluggable linter for JavaScript
[OXC](https://oxc-project.github.io/) ✔ Fast JavaScript linter
[Knip](https://github.com/webpro/knip) ✔ Find unused files, dependencies and exports
[Biome](https://biomejs.dev/) ✔ Unified toolkit for web projects
Auto-formatters
[Prettier](https://prettier.io/) ✔ Opinionated code formatter
[Biome](https://biomejs.dev/) ✔ Includes formatting capabilities
Custom checks
[ast-grep](https://github.com/ast-grep/ast-grep) ✔
[Semgrep](https://semgrep.dev) ✔
[ripgrep](https://github.com/BurntSushi/ripgrep) ✔
Security scanning
[ESLint with security rules](https://github.com/eslint-community/eslint-plugin-security) ✔ AppSec (SAST)
[Gitleaks](https://gitleaks.io/) ✔ Secrets scanning
[OSV-Scanner](https://google.github.io/osv-scanner/) ✔ Dependency scanning (SCA)
[Semgrep](https://semgrep.dev) ✔ AppSec (SAST)
[Trivy](https://trivy.dev) ✔ Dependency scanning (SCA)
[TruffleHog](https://trufflesecurity.com/trufflehog) ✔ Secrets scanning
Code coverage
[Jest](https://jestjs.io/) ✔
[Vitest](https://vitest.dev/) ✔
[Mocha](https://mochajs.org/) ✔
LCOV coverage format ✔
Cobertura coverage format ✔
## File extensions By default, JavaScript files are defined as: ``` [file_types.javascript] globs = ["*.js", "*.mjs", "*.cjs", "**/Jakefile"] interpreters = [ "rhino", "gjs", "qjs", "js", "chakra", "v8-shell", "v8", "node", "d8", ] [file_types.jsx] globs = ["*.jsx", "*.mjsx", "*.cjsx"] ``` These patterns can be overridden from `qlty.toml`. ## Supported JavaScript versions We support modern JavaScript (ES2015+) for maintainability checks and code coverage. Each plugin may have its own version requirements. ## See also * [TypeScript](/languages/typescript) # Kotlin Language Support Source: https://docs.qlty.sh/languages/kotlin ## Summary
Feature Status Notes
[Maintainability](/cloud/maintainability/metrics) ✔ Complexity, duplication, code smells
[Linting](/linting) ✔
[Auto-formatting](/auto-formatting) ✔
[Custom checks](/custom-checks) ✔
[Security scanning](/cloud/security/framework) ✔ AppSec, dependencies, and secrets
[Code metrics](/cloud/maintainability/metrics) ✔
[Code coverage](/coverage) ✔
## Details
Maintainability
[Complexity](/complexity) ✔ Aka cognitive complexity
[Cyclomatic complexity](/complexity#difference-from-cyclomatic-complexity) ✔
[Identical code duplication](/duplication) ✔
[Similar code duplication](/duplication) ✔
[Code smells](/code-smells) ✔
Linters
[ktlint](https://ktlint.github.io/) ✔ Anti-bikeshedding Kotlin linter with built-in formatter
[radarlint-kotlin](https://github.com/qltysh/radarlint) ✔ Static analysis tool
Auto-formatters
[ktlint](https://ktlint.github.io/) ✔ Includes formatting capabilities
Custom checks
[ast-grep](https://github.com/ast-grep/ast-grep) ✔
[Semgrep](https://semgrep.dev) ✔
[ripgrep](https://github.com/BurntSushi/ripgrep) ✔
Security scanning
[Gitleaks](https://gitleaks.io/) ✔ Secrets scanning
[OSV-Scanner](https://google.github.io/osv-scanner/) ✔ Dependency scanning (SCA)
[radarlint-kotlin](https://github.com/qltysh/radarlint) ✔ AppSec (SAST)
[Semgrep](https://semgrep.dev) ✔ AppSec (SAST)
[Trivy](https://trivy.dev) ✔ Dependency scanning (SCA)
[TruffleHog](https://trufflesecurity.com/trufflehog) ✔ Secrets scanning
Code coverage
[JUnit](https://junit.org/) ✔
JaCoCo coverage format ✔
Cobertura coverage format ✔
## File extensions By default, Kotlin files are defined as: ``` [file_types.kotlin] globs = ["*.kt"] ``` These patterns can be overridden from `qlty.toml`. ## Supported Kotlin versions We officially support Kotlin 1.3 and later for maintainability checks and code coverage. Each plugin may have its own version requirements. # PHP Language Support Source: https://docs.qlty.sh/languages/php ## Summary
Feature Status Notes
[Maintainability](/cloud/maintainability/metrics) ✔ Complexity, duplication, code smells
[Linting](/linting) ✔
[Auto-formatting](/auto-formatting) ✔
[Custom checks](/custom-checks) ✔
[Security scanning](/cloud/security/framework) ✔ AppSec, dependencies, and secrets
[Code metrics](/cloud/maintainability/metrics) ✔
[Code coverage](/coverage) ✔
## Details
Maintainability
[Complexity](/complexity) ✔ Aka cognitive complexity
[Cyclomatic complexity](/complexity#difference-from-cyclomatic-complexity) ✔
[Identical code duplication](/duplication) ✔
[Similar code duplication](/duplication) ✔
[Code smells](/code-smells) ✔
Linters
[PHP\_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) ✔
[PHPStan](https://phpstan.org/) ✔
[radarlint-php](https://github.com/qltysh/radarlint) ✔
Auto-formatters
[php-cs-fixer](https://cs.symfony.com/) ✔
Custom checks
[ast-grep](https://github.com/ast-grep/ast-grep) ✔
[Semgrep](https://semgrep.dev) ✔
[ripgrep](https://github.com/BurntSushi/ripgrep) ✔
Security scanning
[Gitleaks](https://gitleaks.io/) ✔ Secrets scanning
[OSV-Scanner](https://google.github.io/osv-scanner/) ✔ Dependency scanning (SCA)
[radarlint-php](https://github.com/qltysh/radarlint) ✔ AppSec (SAST)
[Semgrep](https://semgrep.dev) ✔ AppSec (SAST)
[Trivy](https://trivy.dev) ✔ Dependency scanning (SCA)
[TruffleHog](https://trufflesecurity.com/trufflehog) ✔ Secrets scanning
Code coverage
[PHPUnit](https://phpunit.de/) ✔
Clover coverage format ✔
Cobertura coverage format ✔
## File extensions By default, PHP files are defined as: ``` [file_types.php] globs = [ "*.php", "*.ctp", "*.fcgi", "*.inc", "*.php3", "*.php4", "*.php5", "*.phps", "*.phpt", "*.phtml", "**/.php_cs", "**/.php_cs.dist", "**/Phakefile", ] ``` These patterns can be overridden from `qlty.toml`. ## Supported PHP versions We officially support PHP version 5 and later for maintainability checks and code coverage. Each plugin may have its own version requirements. # Python Language Support Source: https://docs.qlty.sh/languages/python ## Summary
Feature Status Notes
[Maintainability](/cloud/maintainability/metrics) ✔ Complexity, duplication, code smells
[Linting](/linting) ✔
[Auto-formatting](/auto-formatting) ✔
[Custom checks](/custom-checks) ✔
[Security scanning](/cloud/security/framework) ✔ AppSec, dependencies, and secrets
[Code metrics](/cloud/maintainability/metrics) ✔
[Code coverage](/coverage) ✔
## Details
Maintainability
[Complexity](/complexity) ✔ Aka cognitive complexity
[Cyclomatic complexity](/complexity#difference-from-cyclomatic-complexity) ✔
[Identical code duplication](/duplication) ✔
[Similar code duplication](/duplication) ✔
[Code smells](/code-smells) ✔
Linters
[Flake8](https://flake8.pycqa.org/) ✔ Style guide enforcement
[Mypy](https://mypy.readthedocs.io/) ✔ Static type checker
[Ruff](https://github.com/astral-sh/ruff) ✔ Fast Python linter
[Bandit](https://github.com/PyCQA/bandit) ✔ Security linter
[radarlint-python](https://github.com/qltysh/radarlint) ✔ Static analysis tool
Auto-formatters
[Black](https://github.com/psf/black) ✔ Code formatter
[Ruff](https://github.com/astral-sh/ruff) ✔ Includes formatting capabilities
Custom checks
[ast-grep](https://github.com/ast-grep/ast-grep) ✔
[Semgrep](https://semgrep.dev) ✔
[ripgrep](https://github.com/BurntSushi/ripgrep) ✔
Security scanning
[Bandit](https://github.com/PyCQA/bandit) ✔ AppSec (SAST)
[Gitleaks](https://gitleaks.io/) ✔ Secrets scanning
[OSV-Scanner](https://google.github.io/osv-scanner/) ✔ Dependency scanning (SCA)
[radarlint-python](https://github.com/qltysh/radarlint) ✔ AppSec (SAST)
[Semgrep](https://semgrep.dev) ✔ AppSec (SAST)
[Trivy](https://trivy.dev) ✔ Dependency scanning (SCA)
[TruffleHog](https://trufflesecurity.com/trufflehog) ✔ Secrets scanning
Code coverage
[pytest](https://docs.pytest.org/) ✔
[unittest](https://docs.python.org/3/library/unittest.html) ✔
Cobertura coverage format ✔
Coverage.py XML format ✔
## File extensions By default, Python files are defined as: ``` [file_types.python] globs = [ "*.py", "*.pyw", "**/DEPS", "**/Snakefile", "**/SConscript", "**/wscript", "**/SConstruct", "**/.gclient", ] interpreters = ["python", "python3", "python2", "pypy"] ``` These patterns can be overridden from `qlty.toml`. ## Supported Python versions We support Python 2 and Python 3 for maintainability checks and code coverage. Each plugin may have its own version requirements. # Ruby Language Support Source: https://docs.qlty.sh/languages/ruby ## Summary
Feature Status Notes
[Maintainability](/cloud/maintainability/metrics) ✔ Complexity, duplication, code smells
[Linting](/linting) ✔
[Auto-formatting](/auto-formatting) ✔
[Custom checks](/custom-checks) ✔
[Security scanning](/cloud/security/framework) ✔ AppSec, dependencies, and secrets
[Code metrics](/cloud/maintainability/metrics) ✔
[Code coverage](/coverage) ✔
## Details
Maintainability
[Complexity](/complexity) ✔ Aka cognitive complexity
[Cyclomatic complexity](/complexity#difference-from-cyclomatic-complexity) ✔
[Identical code duplication](/duplication) ✔
[Similar code duplication](/duplication) ✔
[Code smells](/code-smells) ✔
Linters
[RuboCop](https://github.com/rubocop/rubocop) ✔ Ruby static code analyzer and formatter
[Reek](https://github.com/troessner/reek) ✔ Code smell detector for Ruby
[StandardRB](https://github.com/standardrb/standard) ✔ Ruby style guide, linter, and formatter
[Brakeman](https://brakemanscanner.org/) ✔ Static analysis security vulnerability scanner
Auto-formatters
[RuboCop](https://github.com/rubocop/rubocop) ✔ Includes formatting capabilities
[StandardRB](https://github.com/standardrb/standard) ✔ Zero-config Ruby formatter
Custom checks
[ast-grep](https://github.com/ast-grep/ast-grep) ✔
[Semgrep](https://semgrep.dev) ✔
[ripgrep](https://github.com/BurntSushi/ripgrep) ✔
Security scanning
[Brakeman](https://brakemanscanner.org/) ✔ AppSec (SAST) for Ruby on Rails applications
[Gitleaks](https://gitleaks.io/) ✔ Secrets scanning
[OSV-Scanner](https://google.github.io/osv-scanner/) ✔ Dependency scanning (SCA)
[Semgrep](https://semgrep.dev) ✔ AppSec (SAST)
[Trivy](https://trivy.dev) ✔ Dependency scanning (SCA)
[TruffleHog](https://trufflesecurity.com/trufflehog) ✔ Secrets scanning
Code coverage
[SimpleCov](https://github.com/simplecov-ruby/simplecov) ✔
Cobertura coverage format ✔
JSON coverage format ✔
## File extensions By default, Ruby files are defined as: ``` [file_types.ruby] globs = [ "*.rb", "*.rake", "**/.irbrc", "**/.pryrc", "**/Appraisals", "**/Berksfile", "**/Brewfile", "**/buildfile", "**/Buildfile", "**/Capfile", "**/Dangerfile", "**/Deliverfile", "**/Fastfile", "**/Gemfile", "**/Guardfile", "**/Jarfile", "**/Mavenfile", "**/Podfile", "**/Puppetfile", "**/Rakefile", "**/Snapfile", "**/Thorfile", "**/Vagrantfile", ] interpreters = ["jruby", "rbx", "rake", "macruby", "ruby"] ``` These patterns can be overridden from `qlty.toml`. ## Code coverage setup QLTY supports code coverage for Ruby through SimpleCov. For a full working example, see our [example Ruby repository](https://github.com/qltysh/example-ruby). ### SimpleCov configuration To instrument test coverage with SimpleCov: 1. Install SimpleCov: ```sh lines theme={"system"} gem install simplecov ``` 2. Configure SimpleCov to generate JSON reports: ```ruby lines theme={"system"} require 'simplecov' require 'simplecov_json_formatter' SimpleCov.start do formatter SimpleCov::Formatter::JSONFormatter add_filter '/spec/' end ``` If you want to combine the JSON format with other formats, use SimpleCov's `MultiFormatter`: ```ruby lines theme={"system"} SimpleCov.start do formatter SimpleCov::Formatter::MultiFormatter.new([ SimpleCov::Formatter::JSONFormatter, SimpleCov::Formatter::HTMLFormatter ]) add_filter '/spec/' end ``` 3. Publish SimpleCov's JSON coverage reports using `qlty coverage publish`: ```sh lines theme={"system"} qlty coverage publish coverage/coverage.json ``` For GitHub Actions users, you can use our [example workflow](https://github.com/qltysh/example-ruby/blob/main/.github/workflows/main.yml). ## Supported Ruby versions We officially support Ruby 2.5 and later for maintainability checks and code coverage. SimpleCov version 0.22.0+ is recommended for code coverage. Each plugin may have its own version requirements. # Rust Language Support Source: https://docs.qlty.sh/languages/rust ## Summary
Feature Status Notes
[Maintainability](/cloud/maintainability/metrics) ✔ Complexity, duplication, code smells
[Linting](/linting) ✔
[Auto-formatting](/auto-formatting) ✔
[Custom checks](/custom-checks) ✔
[Security scanning](/cloud/security/framework) ✔ AppSec, dependencies, and secrets
[Code metrics](/cloud/maintainability/metrics) ✔
[Code coverage](/coverage) ✔
## Details
Maintainability
[Complexity](/complexity) ✔ Aka cognitive complexity
[Cyclomatic complexity](/complexity#difference-from-cyclomatic-complexity) ✔
[Identical code duplication](/duplication) ✔
[Similar code duplication](/duplication) ✔
[Code smells](/code-smells) ✔
Linters
[Clippy](https://github.com/rust-lang/rust-clippy) ✔ Rust linter providing a collection of lints
Auto-formatters
[rustfmt](https://github.com/rust-lang/rustfmt) ✔ Official Rust code formatter
Custom checks
[ast-grep](https://github.com/ast-grep/ast-grep) ✔
[Semgrep](https://semgrep.dev) ✔
[ripgrep](https://github.com/BurntSushi/ripgrep) ✔
Security scanning
[Gitleaks](https://gitleaks.io/) ✔ Secrets scanning
[OSV-Scanner](https://google.github.io/osv-scanner/) ✔ Dependency scanning (SCA)
[Semgrep](https://semgrep.dev) ✔ AppSec (SAST)
[Trivy](https://trivy.dev) ✔ Dependency scanning (SCA)
[TruffleHog](https://trufflesecurity.com/trufflehog) ✔ Secrets scanning
Code coverage
[cargo test](https://doc.rust-lang.org/cargo/commands/cargo-test.html) ✔
[grcov](https://github.com/mozilla/grcov) ✔
Cobertura coverage format ✔
LCOV coverage format ✔
## File extensions By default, Rust files are defined as: ``` [file_types.rust] globs = ["*.rs"] ``` These patterns can be overridden from `qlty.toml`. ## Test detection Rust test functions are automatically detected using the following patterns: ``` [language.rust] test_syntax_patterns = [""" ( (mod_item name: (identifier) @name) (#eq? @name "test") ) """, """ ( (attribute_item (attribute (identifier) @meta_item)) (function_item) @function (#eq? @meta_item "test") ) """] ``` ## Supported Rust versions We officially support Rust 1.30 and later for maintainability checks and code coverage. Each plugin may have its own version requirements. # Scala Language Support Source: https://docs.qlty.sh/languages/scala ## Summary
Feature Status Notes
[Maintainability](/cloud/maintainability/metrics) ✔ Complexity, duplication, code smells
[Custom checks](/custom-checks) ✔
[Security scanning](/cloud/security/framework) ✔ AppSec, dependencies, and secrets
[Code metrics](/cloud/maintainability/metrics) ✔
[Code coverage](/coverage) ✔
## Details
Maintainability
[Complexity](/complexity) ✔ Aka cognitive complexity
[Cyclomatic complexity](/complexity#difference-from-cyclomatic-complexity) ✔
[Identical code duplication](/duplication) ✔
[Similar code duplication](/duplication) ✔
[Code smells](/code-smells) ✔
Custom checks
[ast-grep](https://github.com/ast-grep/ast-grep) ✔
[Semgrep](https://semgrep.dev) ✔
[ripgrep](https://github.com/BurntSushi/ripgrep) ✔
Security scanning
[Gitleaks](https://gitleaks.io/) ✔ Secrets scanning
[OSV-Scanner](https://google.github.io/osv-scanner/) ✔ Dependency scanning (SCA)
[Semgrep](https://semgrep.dev) ✔ AppSec (SAST)
[Trivy](https://trivy.dev) ✔ Dependency scanning (SCA)
[TruffleHog](https://trufflesecurity.com/trufflehog) ✔ Secrets scanning
Code coverage
Cobertura coverage format ✔ Generated by [sbt-scoverage](https://github.com/scoverage/sbt-scoverage)
## File extensions By default, Scala files are defined as: ``` [file_types.scala] globs = ["*.scala", "*.sc"] ``` These patterns can be overridden from `qlty.toml`. ## Supported Scala versions We officially support Scala 2 and Scala 3 for maintainability checks and code coverage. Each plugin may have its own version requirements. # Swift Language Support Source: https://docs.qlty.sh/languages/swift ## Summary
Feature Status Notes
[Maintainability](/cloud/maintainability/metrics) ✔ Complexity, duplication, code smells
[Linting](/linting) ✔
[Auto-formatting](/auto-formatting) ✔
[Custom checks](/custom-checks) ✔
[Security scanning](/cloud/security/framework) ✔ AppSec, dependencies, and secrets
[Code metrics](/cloud/maintainability/metrics) ✔
[Code coverage](/coverage) ✔
## Details
Maintainability
[Complexity](/complexity) ✔ Aka cognitive complexity
[Cyclomatic complexity](/complexity#difference-from-cyclomatic-complexity) ✔
[Identical code duplication](/duplication) ✔
[Similar code duplication](/duplication) ✔
[Code smells](/code-smells) ✔
Linters
[SwiftLint](https://github.com/realm/SwiftLint)\* ✔ Tool to enforce Swift style and conventions.
[StringsLint](https://github.com/dral3x/StringsLint)\* ✔ Ensures localized strings are complete and not unused
Auto-formatters
[SwiftFormat](https://github.com/nicklockwood/SwiftFormat)\* ✔ CLI (and Xcode Extension) for formatting Swift code
Custom checks
[Semgrep](https://semgrep.dev) ✔
[ripgrep](https://github.com/BurntSushi/ripgrep) ✔
Security scanning
[Gitleaks](https://gitleaks.io/) ✔ Secrets scanning
[Semgrep](https://semgrep.dev) ✔ AppSec (SAST)
[Trivy](https://trivy.dev) ✔ Dependency scanning (SCA) for CocoaPods and Swift package managers
[TruffleHog](https://trufflesecurity.com/trufflehog) ✔ Secrets scanning
Code coverage
[slather](https://github.com/SlatherOrg/slather) ✔
Cobertura coverage format ✔
> [!NOTE] > > * These plugins only run on macOS and are available via the Qlty CLI. They are not available on > Qlty Cloud which runs on Linux. ## File extensions By default, Swift files are defined as: ``` [file_types.swift] globs = ["*.swift"] ``` These patterns can be overridden from `qlty.toml`. ## Supported Swift versions We officially support Swift 6+ and later for maintainability checks and code coverage. Each plugin may have its own version requirements. # TypeScript Language Support Source: https://docs.qlty.sh/languages/typescript ## Summary
Feature Status Notes
[Maintainability](/cloud/maintainability/metrics) ✔ Complexity, duplication, code smells
[Linting](/linting) ✔
[Auto-formatting](/auto-formatting) ✔
[Custom checks](/custom-checks) ✔
[Security scanning](/cloud/security/framework) ✔ AppSec, dependencies, and secrets
[Code metrics](/cloud/maintainability/metrics) ✔
[Code coverage](/coverage) ✔
## Details
Maintainability
[Complexity](/complexity) ✔ Aka cognitive complexity
[Cyclomatic complexity](/complexity#difference-from-cyclomatic-complexity) ✔
[Identical code duplication](/duplication) ✔
[Similar code duplication](/duplication) ✔
[Code smells](/code-smells) ✔
Linters
[ESLint](https://eslint.org/) ✔ JavaScript and TypeScript linter
[OXC](https://oxc-project.github.io/) ✔ Fast JavaScript/TypeScript linter
[Knip](https://github.com/webpro/knip) ✔ Find unused files, dependencies and exports
[Biome](https://biomejs.dev/) ✔ Unified toolkit for web projects
Auto-formatters
[Prettier](https://prettier.io/) ✔ Opinionated code formatter
[Biome](https://biomejs.dev/) ✔ Includes formatting capabilities
Custom checks
[ast-grep](https://github.com/ast-grep/ast-grep) ✔
[Semgrep](https://semgrep.dev) ✔
[ripgrep](https://github.com/BurntSushi/ripgrep) ✔
Security scanning
[ESLint with security rules](https://github.com/eslint-community/eslint-plugin-security) ✔ AppSec (SAST)
[Gitleaks](https://gitleaks.io/) ✔ Secrets scanning
[OSV-Scanner](https://google.github.io/osv-scanner/) ✔ Dependency scanning (SCA)
[Semgrep](https://semgrep.dev) ✔ AppSec (SAST)
[Trivy](https://trivy.dev) ✔ Dependency scanning (SCA)
[TruffleHog](https://trufflesecurity.com/trufflehog) ✔ Secrets scanning
Code coverage
[Jest](https://jestjs.io/) ✔
[Vitest](https://vitest.dev/) ✔
LCOV coverage format ✔
Cobertura coverage format ✔
## File extensions By default, TypeScript files are defined as: ``` [file_types.typescript] globs = ["*.ts", "*.mts", "*.cts"] interpreters = ["ts-node", "deno"] [file_types.tsx] globs = ["*.tsx", "*.mtsx", "*.ctsx"] ``` These patterns can be overridden from `qlty.toml`. ## Supported TypeScript versions We officially support TypeScript 3.0 and later for maintainability checks and code coverage. Each plugin may have its own version requirements. # VB.NET Language Support Source: https://docs.qlty.sh/languages/vbnet ## Summary
Feature Status Notes
[Maintainability](/cloud/maintainability/metrics) ✔ Complexity, duplication, code smells
[Custom checks](/custom-checks) ✔
[Security scanning](/cloud/security/framework) ✔ AppSec, dependencies, and secrets
[Code metrics](/cloud/maintainability/metrics) ✔
[Code coverage](/coverage) ✔
## Details
Maintainability
[Complexity](/complexity) ✔ Aka cognitive complexity
[Cyclomatic complexity](/complexity#difference-from-cyclomatic-complexity) ✔
[Identical code duplication](/duplication) ✔
[Similar code duplication](/duplication) ✔
[Code smells](/code-smells) ✔
Custom checks
[Semgrep](https://semgrep.dev) ✔
[ripgrep](https://github.com/BurntSushi/ripgrep) ✔
Security scanning
[Gitleaks](https://gitleaks.io/) ✔ Secrets scanning
[Semgrep](https://semgrep.dev) ✔ AppSec (SAST)
[Trivy](https://trivy.dev) ✔ Dependency scanning (SCA) for NuGet
[TruffleHog](https://trufflesecurity.com/trufflehog) ✔ Secrets scanning
Code coverage
Cobertura coverage format ✔
## File extensions By default, VB.NET files are defined as: ``` [file_types.vbnet] globs = ["*.vb"] ``` These patterns can be overridden from `qlty.toml`. ## Supported VB.NET versions We support VB.NET up to version 16.9 (the .NET 5 generation) for maintainability checks and code coverage. Each plugin may have its own version requirements. # Linting Source: https://docs.qlty.sh/linting Linting is the process of running a program that analyzes your code for potential errors, stylistic issues, and suspicious constructs. These programs, known as linters, can help identify issues in your codebase that might not be immediately apparent, ensuring that your code adheres to a set of predefined standards and best practices. Linting offers several benefits that can significantly enhance the quality and maintainability of your code: 1. **Error Detection**: Linters can catch syntactical errors, typos, and other mistakes that could cause runtime errors or bugs. 2. **Code Consistency**: By enforcing coding standards and style guidelines, linting ensures that your code is uniform, making it easier to read and maintain. 3. **Early Issue Identification**: Linting helps identify potential issues early in the development process, reducing the likelihood of bugs and improving code quality from the outset. Qlty offers 40+ linters as [plugins](/plugins) with a unified developer experience. > [!TIP] > > Linting is provided by [Qlty CLI](/cli/quickstart) and [Qlty Cloud](/cloud/quickstart). ## How Linting Works Linters analyze your code based on a set of rules or guidelines. These rules can be standard ones provided by the linter or custom rules defined by your development team. When the linter runs, it examines your code and flags any lines that violate these rules, often providing suggestions for how to fix the issues. Here’s a simple example in JavaScript using ESLint, a popular linter: ```js lines theme={"system"} // Bad example var foo = "bar"; if (foo == "bar") { console.log("Hello, world!"); } // Good example const foo = "bar"; if (foo === "bar") { console.log("Hello, world!"); } ``` In this example, ESLint might flag the use of `var` instead of `const`, and the use of `==` instead of `===`, promoting better coding practices. ## Integrating Linting into Your Workflow Unlike more advanced static analysis, linters typically run quickly and on a per-file basis. This makes them well suited to run frequently. Qlty makes it easy to integrate linting directly into your development workflow: * **Pre-commit Hooks**: Running the Qlty CLI's `qlty check` command before committing code to your version control system, preventing issues from being introduced. * **Automated Code Review**: Qlty Cloud can automatically run linters on your pull requests and post any identified issues as comments. ## See Also * [Qlty CLI](/cli/quickstart) * [`qlty check`](/cli/commands/check) * [Automated Code Review](/cloud/automated-code-review) * [Available Plugins](/plugins) * [Analysis Configuration](/cli/analysis-configuration) # Product Comparison Source: https://docs.qlty.sh/migration/comparison
Analysis Code Climate Quality Qlty
Supported languages 10 15+
Code smells ✔ ✔
Maintainability Ratings ✔ ✔
Duplication detection ✔ ✔
Security Scanning (IaC, SAST, SCA) ✖ ✔
Auto-formatting ✖ ✔
One-click auto-format ✖ ✔
AI explanations ✖ ✔
AI autofixes ✖ ✔
Project ratings ✖ ✔
Trends & Hotspots ✔ Coming Soon
Plugins Code Climate Quality Qlty
Available plugins 30 70+
Linter extensions Limited Bring your own
Private, custom plugins ✖ ✔
Effort to add plugins 1+ day \< 1 hour
Linter version availability Quarterly Immediate
Code Coverage Code Climate Quality Qlty
Project coverage ✔ ✔
Diff coverage ✔ ✔
Line-by-line coverage views ✔ ✔
Coverage tags / suites ✖ ✔
Customized coverage gates ✖ ✔
Coverage uploader GitHub Action ✖ ✔
Server-side merging ✖ ✔
Browser extension for GitHub.com ✔ ✔
GitHub Integrations Code Climate Quality Qlty
Commit statuses ✔ ✔
PR comments ✔ ✔
PR approvals ✔ ✔
Draft PR support ✔ ✔
Quality Gates Limited ✔
Resolve to ignore ✖ ✔
Fix suggestions ✖ ✔
Forked PR analysis ✖ ✔
README badges ✔ ✔
Configuration Code Climate Quality Qlty
Configuration format YAML TOML
In-app configuration ✔ ✔
Version controlled configuration ✔ ✔
Monorepo support ✖ ✔
Auto-triage rules ✖ ✔
Shared configuration ✔ ✔
Security & Compliance Code Climate Quality Qlty
Authentication Password or GitHub GitHub OAuth
Authorization GitHub or manual GitHub
SOC2 compliant ✖ ✔
Tools Code Climate Quality Qlty
CLI speed Slow Fast
Git hooks ✖ ✔
VS Code extension ✖ ✔
[REST API](/api/introduction) ✔ ✔
## See Also * [Migration Overview](/migration/overview) * [Migration Guide](/migration/guide) # Migrating Coverage Uploads Source: https://docs.qlty.sh/migration/coverage > [!WARNING] > > The Code Climate API was disabled on July 18, 2025. > > Any remaining attempts to upload coverage via the old `cc-test-reporter` will fail your CI builds. Remove (or comment out) any references to `cc-test-reporter` in your CI scripts and follow the steps below to upload to Qlty Cloud instead. This guide is for users who have previously set up code coverage reporting to Code Climate Quality and are now migrating to Qlty Cloud. ## Advantages of Qlty Cloud The new Qlty Cloud app offers many advantages over Code Climate Quality for code coverage. To help make coverage setup easier, we offer four new features: 1. Support for OpenID Connect (OIDC) with GitHub Actions for tokenless coverage uploads 2. Workspace-level coverage tokens 3. Reusable GitHub Action and CircleCI Orb tools 4. Server-side coverage coverage merging Once coverage is set up, Qlty Cloud supports all of the code coverage reporting features of Code Climate Quality like: * Coverage Tags for tracking data for e.g. tracking unit test coverage separately from integration test coverage * In-app views for reviewing coverage on Pull Request diffs (No broweser extension required) * Additional flexibility when configuring coverage gates (pass/fail commit statuses) ## Prerequisites 1. A Code Climate Quality account with repositories where you've previously configured coverage reporting 2. A GitHub user which is an Administrator of your GitHub organization 3. Ability to modify and run CI scripts for the relevant repositories ## Process > [!WARNING] > > Migrating a Ruby/RSpec repository? > > Previously SimpleCov [detected the use of Code Climate](https://github.com/simplecov-ruby/simplecov?tab=readme-ov-file#json-formatter) and auto-initialized SimpleCov. > > *This is no longer the case. Using Qlty requires explicit SimpleCov configuration*. > > See our [Ruby coverage docs](/coverage/generating-data#ruby-with-simplecov) for more information on recommended configuration. ### Step 1. Determine an authentication approach Qlty Cloud supports three ways to authenticate code coverage uploads from your CI system: 1. OpenID Connect (OIDC) with GitHub Actions 2. Workspace-level coverage tokens 3. Project-level coverage tokens If you are using GitHub Actions and are able to use OIDC, we recommend that approach as it is the most secure and requires no management of long-lived coverage tokens. If you are not using GitHub Actions, or are unable to use OIDC, you can use a workspace-level coverage token. This is a long-lived token that is scoped to your entire organization and can be used for all repositories within that organization. For situations were neight of those options are available, you can use a project-level coverage token. This is a long-lived token that is scoped to a single repository and can be used for that repository only. #### Obtain a coverage token from Qlty Cloud If you are not using OIDC, you will need to obtain a coverage token from Qlty Cloud. Qlty Cloud uses GitHub for both authentication and authorization checks. Therefore, any user with administrator permissions on a GitHub organization is automatically able to access the corresponding workspace on Qlty Cloud. * Login to Qlty via GitHub OAuth (as a GitHub Admin) * Navigate to *Workspace Settings > Code Coverage* (e.g. `https://qlty.sh/gh/org-name/settings/coverage`) * Copy the workspace’s coverage token ### Step 2. Store the coverage token as a CI secret (if not using OIDC) *If you are using OIDC, you can skip this step.* A coverage token only provides the ability to upload code coverage data to Qlty Cloud and does not provide access to read any data or administer any settings. Even still, it should be treated as a credential and stored securely within your CI system, as explained [here](/coverage/tokens#token-storage) The specifics for how to store a secret at the organization level and make it available to all repositories vary by provider: * [GitHub Actions](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions) * [CircleCI](https://circleci.com/docs/contexts/) * [Buildkite](https://buildkite.com/docs/pipelines/security/secrets/buildkite-secrets) * [Travis CI](https://docs.travis-ci.com/user/encryption-keys/) ### Step 3. Update CI workflow scripts This guide assumes that your CI scripts are already generating code coverage data from the execution of your automated unit tests. The method to generate this data and the output format varies by programming language and testing tools. Once you have code coverage data being generated in one of our [supported formats](/coverage/generating-data#supported-languages-and-formats), continue with the steps below. Generally, the process is to add an additional step after the code coverage data has been generated and written to disk on the CI runner. #### Reusable GitHub Action Add a step to run the `qltysh/qlty-action/coverage` reusable GitHub Action: ```yaml lines theme={"system"} # ... permissions: contents: read id-token: write # IMPORTANT jobs: build: # ... steps: # ... - uses: qltysh/qlty-action/coverage@v2 with: oidc: true files: COVERAGE_FILE_PATH # e.g. coverage/lcov.info ``` If you are using a workspace or project coverage token instead of OIDC, remove the `oidc: true` line and add `token: ${{ secrets.QLTY_COVERAGE_TOKEN }}` to the `with` block: ```yaml lines theme={"system"} # ... jobs: build: # ... steps: # ... - uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: COVERAGE_FILE_PATH # e.g. coverage/lcov.info ``` #### CircleCI Orb We provide a CircleCI Orb for uploading coverage reports. To use it, add the following to your `.circleci/config.yml` file: ```yaml lines theme={"system"} # ... jobs: run_tests_and_publish_coverage: # ... steps: # ... - qlty-orb/coverage_publish: files: coverage/lcov.info ``` [Learn more](https://circleci.com/developer/orbs/orb/qltysh/qlty-orb) #### Other CI providers With other CI providers, you will install the Qlty CLI and run the `qlty coverage publish` command, you will also need to provide the commit SHA and branch name explicitly: ```bash lines theme={"system"} # Assumes $QLTY_COVERAGE_TOKEN is set in the environment curl https://qlty.sh | sh qlty coverage publish --override-commit-sha COMMIT_SHA --override-branch BRANCH_NAME COVERAGE_FILE_PATH ``` The Qlty CLI is able to auto-detect workflow-related metadata from the environment variables set by your CI provider on the following platforms: * Buildkite * Travis CI * CodeFresh * Semaphore If you are using another CI provider not in this list, please contact us and we can add support for your system. ### Step 4. Validate coverage uploads from a branch After updating the CI script, trigger a build (of the branch including your updated script) and ensure it completes successfully. Check the output for the upload step and verify that no errors are occurring on the CI side during the upload process. * On Qlty Cloud, navigate to your *Project Settings > Code Coverage* page (example: `https://qlty.sh/gh/org-name/projects/repo-name/settings/coverage`). * Your uploaded coverage report should appear in the table at the bottom of the page * Click on the commit SHA to view your report details * Verify that the report details match your expectations (commit SHA, branch name, etc.) ### Step 5. Merge your CI script changes into your main branch Now that the coverage uploads are happening successfully for your branch, merge the branch into your default branch (e.g. main) and run a build. Ensure that the build completes successfully (with no errors from the coverage upload step), and validate the coverage upload in your Project Settings. Once Qlty receives a valid coverage report for your default branch, your coverage info will be displayed in your project's Overview page. You'll also see file-level and directory-level coverage on your project's Issues tab. ### Step 6. Remove coverage uploads to Code Climate Quality Once you've setup coverage reporting (and enabled coverage commit statuses) as desired, remove references to the old Code Climate test reporter within your CI script. The Code Climate API will be deactivated on July 18th. At this point, any references to `cc-test-reporter` will result in failed CI builds. ### Step 7. Repeat for each repository Steps 3 through 6 need to be repeated for each repository that you are migrating to Qlty Cloud. We have found that with a good prompt for an AI coding assistant, the process can be completed quickly. ### Optional: Enable coverage commit statuses from Qlty Cloud * Enable commit statuses (**Qlty Coverage** and **Qlty Diff Coverage**) within your Project's Commit Statuses settings: (`https://qlty.sh/gh/org-name/projects/repo-name/settings/gates`) * Adjust coverage check settings (including new configurations for minimum diff size and total coverage decrease) ## Resources * [Setting Up Code Coverage](/coverage/quickstart) * [Continuous Integration (CI) Tools](/coverage/ci) * [Code Coverage Metrics](/coverage/metrics) * [Troubleshooting Code Coverage](/coverage/troubleshooting) ## Get Help * Chat with us on [Discord](https://qlty.sh/discord) * File bugs on [GitHub Issues](https://github.com/qltysh/qlty/issues/new/choose) * [Contact Support](https://qlty.sh/contact/support) # Migration Guide Source: https://docs.qlty.sh/migration/guide > [!WARNING] > > The Code Climate API was disabled on July 18, 2025. > > Any remaining attempts to upload coverage via the old `cc-test-reporter` will fail your CI builds. Remove (or comment out) any references to `cc-test-reporter` in your CI scripts and follow the [coverage migration guide](/migration/coverage) to upload to Qlty Cloud instead. For existing users of Code Climate Quality, we’ve simplified the migration process by importing your existing Quality org, repositories, and users into Qlty. To roll out Qlty to your team, follow the steps below. ## Login 1. Head to [qlty.sh](https://qlty.sh/) and click Sign in with GitHub. 2. Login by authorizing the Qlty GitHub Application. 3. The GitHub organizations you have added to Code Climate Quality will automatically appear as Qlty Workspaces. Click on your Workspace to view a list of your migrated Projects. ## Recommended: Install the free Qlty CLI Though not required, we highly recommend installing the brand new [Qlty CLI](/cli/quickstart). The Qlty CLI will help you configure and run your analysis locally, allowing for faster feedback loops. ## Migrating your Analysis Configuration 1. View your Project's initial results on the Issues tab For projects containing a .codeclimate.yml, Qlty attempts to reproduce your existing configuration at build time. (This process is powered by `qlty config migrate`). The resulting configuration enables only plugins and checks which were explicitly enabled in your .codeclimate.yml. These initial Qlty results should closely resemble your existing results in Quality. For projects which don't contain a .codeclimate.yml, Qlty autogenerates a configuration during build time. (This process is powered by `qlty init`). This autogenerated configuration enables qlty smells (the replacement for Quality's maintainability checks), along with a wide range of new [Plugins](/plugins) (including linters, security scanners, etc.) previously unavailable in Code Climate Quality. Because of the large number of new plugins being run, your Qlty results will include numerous issues previously not reported in Quality. Though these initial results are quite noisy, the intention is to help users discover the wide range of the newly available tools. 2. Next, you can fine-tune your analysis configuration by creating a `qlty.toml`. For details, see our docs on [Analysis Configuration](/cli/analysis-configuration). Qlty supports much more granularity than in Quality. You're now able to set different thresholds for each language in your project, or specify thresholds for different directories, etc. As an alternative to committing a qlty.toml to your project, you can use now use the web-based Analysis Configuration within your Project Settings. (This allows you to quickly adjust and test new configurations without the need for a committed config). If you'd like to set a single global configuration to share across many repos, see our docs on [Shared Analysis Configuration](https://docs.qlty.sh/qlty-cli/additional-information/shared-analysis-configuration). ## Enable GitHub Integrations 1. Once you’ve adjusted your project’s analysis configuration as desired, you can begin configuring Qlty’s Commit Statuses, known as [Quality Gates](/cloud/gates). `qlty check` generates a pass/fail status on your GitHub PRs, and serves as a replacement for codeclimate/issues. Within your Project Settings, you can configure `qlty check` to fail on new issues or vulnerabilities based on [issue levels](https://docs.qlty.sh/cloud/maintainability/metrics#issue-levels). In Qlty, you can now analyze every PR within your project, and analysis is no longer limited to PRs targeting your default branch. You’ll also find Qlty Coverage Gates and PR Review Comments to replace the similar functionality found in Quality. Additionally, Qlty offers brand new integrations for [autoformatting](/auto-formatting), [AI autofixes](/cloud/ai-autofixes), and more. ## Enable Code Coverage Reporting: 1. To get started, head to our docs on [Migrating Coverage Uploads](/migration/coverage). Once you’ve begun uploading coverage reports to Qlty, you can enforce coverage code on Pull Requests using [Qlty Gates](/cloud/gates), configurable within your Project Settings for Code Review. `qlty coverage diff` serves to replace the existing `codeclimate/diff-coverage` status. As in Quality, you’ll see a configurable threshold for minimum diff coverage, as well a new option for Minimum Diff Size. `qlty coverage` serves to replace the existing `codeclimate/total-coverage` status, and includes new configurability with the new Total Coverage Variation setting. ## Updating Required Statuses 1. Once you've enabled Qlty Commit Statuses, you can then enforce Qlty analysis by setting a required status in GitHub. 2. If your GitHub repo has existing status requirements for your `codeclimate` statuses, you’ll need to remove those requirements in GitHub before uninstalling the Quality PR integrations on codeclimate.com. ## Configure Workspace Settings 1. In Qlty, you'll see new Workspace-level settings for Qlty Gates, Code Review, and more. Here, you can set default configurations to apply to all projects within your Workspace. ## Inviting your team 1. In Qlty, user permissions are synced directly to your GitHub organization, so you'll no longer need to manually send invites. By logging into Qlty with GitHub, they will automatically have access if they are a member of your GitHub Organization. ## Spinning down Code Climate Quality 1. Owners of existing Code Climate Quality orgs will receive an emailed migration notice including your specific migration timeline. On the date of your migration, your existing Code Climate Quality organization will be disabled, and existing GitHub integrations (commit statuses, PR comments, etc.) will be turned off automatically. Afterwards, you can remove any existing Code Climate Quality integrations (such as the Code Climate OAuth App, and the Code Climate GitHub App) within your GitHub settings. Any attempts to upload coverage to the Code Climate API (via the `cc-test-reporter`) will result in failed CI builds. To avoid disruption, you must remove (or comment out) any remaining references to the old `cc-test-reporter` within your CI scripts. ## Migration FAQ ### Setup & Migration **1. I'm ready. How do I get started?** Follow the step-by-step instructions in this guide to migrate your repositories and configure Qlty for your organization. **2. When will Code Climate Quality be shut down?** For paid Code Climate Quality accounts, Organization Owners will receive formal migration notices including the migration timeline for your specific organization. ### Features **3. Does Qlty support all of the features found in Quality?** Qlty includes nearly all of the functionality found in Code Climate Quality (and much more). See our [Product Comparison](/migration/comparison) for details. Qlty supports most (but not all) of the plugins found in Code Climate Quality. For help with plugins which are no longer supported, please [contact us](/cloud/support). ### User Management & Permissions **4. Why can't I access my organization settings?** In Qlty, user permissions are synced directly to GitHub. To access organization-level settings, you'll need Admin permission to your GitHub organization. **5. Where can I manage my users?** We're still working on the new People Settings for the Qlty UI. For now, users can be managed directly within the Code Climate UI. ### Billing **6. Is Qlty pricing similar to what I'm paying for Code Climate Quality?** The expected pricing for Qlty Cloud will be comparable to Code Climate Quality, with a modest increase. **7. Where can I manage my billing settings?** For now, billing is still managed via the Code Climate UI. ### Analysis & Configuration **8. Do I need to update my analysis configuration?** We highly recommend creating a `qlty.toml` to leverage the full range of Qlty's functionality. For migrated projects containing a `.codeclimate.yml`, Qlty attempts to replicate your existing configuration during analysis. For more info, head [here](/cli/commands/config-migrate). For migrated projects which don't contain a `.codeclimate.yml`, Qlty uses an autogenerated configuration. Existing in-app configurations (seen in the Code Climate UI) will not be migrated to Qlty. **9. Why are my Qlty results so much different than in Quality?** If your project does not contain a `.codeclimate.yml`, Qlty uses an autogenerated configuration which enables a much broader analysis than seen in Quality. Existing in-app configurations (from codeclimate.com) are not migrated. **10. Do I need to update my coverage reporting configuration?** Yes. The existing Code Climate test reporter is not supported in Qlty, so you'll need to update your CI configuration to implement Qlty's new coverage reporter. For more information, see our [Coverage Migration Guide](/migration/coverage). **11. Will my historical data be migrated from Code Climate?** Historical data (relating to Maintainability and Test Coverage) will not be migrated from Code Climate Quality. **12. Why are my maintainability ratings different in Qlty?** It's expected that maintainability ratings in Qlty may differ from those in Quality. Qlty's new checks for Code Smells, Duplication, and Complexity are analogous to [Code Climate Maintainability Checks](https://docs.codeclimate.com/docs/maintainability), but with minor differences: * Qlty supports a larger number of [languages in Qlty](/languages) than in [Code Climate Quality](https://docs.codeclimate.com/docs/supported-languages-for-maintainability). * The [default thresholds](/cli/qlty-toml#smellsnamethreshold) for Qlty checks may differ from [Quality's default thresholds](https://docs.codeclimate.com/docs/default-analysis-configuration#default-thresholds). * Qlty's default exclusions are broader than [Quality's default exclusions](https://docs.codeclimate.com/docs/default-analysis-configuration#excluded-folders). * Qlty is git aware and excludes all files in your `.gitignore`, whereas Quality is agnostic to the `.gitignore` file. ## See Also * [Migration Overview](/migration/overview) * [Migrating Coverage Reports](/migration/coverage) * [Product Comparison](/migration/comparison) # Migration Overview Source: https://docs.qlty.sh/migration/overview Qlty is the next generation of Code Climate Quality. Created in 2011, Code Climate Quality was a pioneer for automated code review, helping developers merge with confidence by bringing maintainability and code coverage metrics into the developer workflow. Now, building on our years of experience with Quality, we've decided to reinvest in the product — rebuilding the product from the ground up. Reflecting our renewed focus on code health, we’ve branched out Qlty into its own new company, Qlty Software. We’re now launching a brand new edition of Quality, available as Qlty Cloud and Qlty CLI. For users of Code Climate Quality, you'll notice some meaningful improvements: * Qlty CLI: The brand new Qlty CLI is designed to provide faster feedback loops by enabling configuration and analysis to be run locally. * Expanded Language Support: Qlty Cloud supports a broader range of languages, frameworks, and technologies, ensuring that your tools evolve alongside modern development trends. * Security Scanning: Qlty Cloud includes built-in security scanning for code vulnerabilities, providing integrated checks for SAST, IaC, and SCA—critical for identifying and addressing security risks earlier in your development process. * Enhanced Code Coverage Support: With improvements to coverage reporting, including diff coverage highlighting directly within the Qlty UI, you can manage coverage more effectively without needing a browser extension. * Improved Monorepo Support: Qlty offers better handling of monorepos, making it simpler to work across multiple repositories without the complexity traditionally associated with these setups. * Modernized Plugin Architecture: The new plugin system allows for greater flexibility and faster plugin integration, making it easier to extend Qlty Cloud with the tools your team needs. Qlty Cloud represents the future of Code Climate Quality. We're now analyzing your existing projects with Qlty Cloud, and we're excited to see what you think. ## See Also * [Product Comparison](/migration/comparison) * [Migration Guide](/migration/guide) # Monorepos Source: https://docs.qlty.sh/monorepos A *monorepo* houses multiple applications, services, or packages in a single version-controlled repository. While this model simplifies dependency management and cross-team collaboration, it introduces unique challenges for automated static analysis and code coverage: * **Slow static analysis**: Monorepos can be large, leading to longer analysis times. * **Developer tool conflicts**: Different components may use different tools or versions, causing conflicts. * **Diverse quality preferences**: Teams may have varying preferences for tools and configurations, complicating standardization. * **Separate test suites**: Each component may have its own test suite, making it difficult to aggregate results. Qlty was built with monorepos in mind, helping you to improve code quality and coverage even in large projects. ## Code analysis For code quality analysis, Qlty offers the following features to help you manage monorepos. ### Sandboxed tool installations In a monorepo, different components may use different tools, languages, or versions. Getting all of these installed and running consistently across platforms can be a challenge. Sometimes, as tools versions change, they may not be compatible with each other within the same repository. Qlty provides a unified interface to install and upgrade these tools making it easier to run them in a consistent manner on every developer machine. Each linter and its dependencies are installed into a separate sandbox, so they will never conflict. This is especially useful in monorepos where different components may require different versions of the same tool. *Note:* The Qlty CLI is compatible with MacOS, Linux, and Windows. ### Prefixes and package files Many static analysis tools tie their configuration to the root of the repository. This can make it difficult ("config hell") or impossible to tailor the analysis to the needs of each component in a monorepo. Qlty makes it easy to enable plugins with independent configurations using the `prefix` option. This can be combined with the `package_file` option to easily use different versions of the same tool in different components, or even different tools altogether. ```toml filename="qlty.toml" lines theme={"system"} # Enable ESLint for the "my-service" directory # using the packages defined in the "my-service/package.json" file. [[plugin]] name = "eslint" prefix = "my-service" package_file = "my-service/package.json" ``` ### Accelerated analysis Static analysis can be slow, especially in monorepos with many components. Qlty provides several features to speed up static analysis like concurrency and caching. With these features, we are often able to run linters [faster through Qlty](https://qlty.sh/blog/running-rubocop-3x-faster-with-qlty-cli) than running them directly. Also, Qlty is designed to perform *differential analysis*, meaning that it only analyzes the files that have changed in a given pull request. This approach makes it possible to get results quickly without interrupting developer flow. ### Triage rules Code quality is never one-size-fits-all, especially in a monorepo. Qlty offers an advanced triage and reporting system that can be tailored for monorepos. This allows maintainers within the monorepos to independently control their static analysis results without impacting other sub-projects. Here are some examples: > **Ignore issues based on directory patterns** > > ```toml qlty.toml theme={"system"} > # Exclude all ESLint issues in the legacy service directory > [[exclude]] > plugins = ["eslint"] > file_patterns = ["services/legacy-service/**"] > > # Ignore specific rule in the UI components directory > [[triage]] > match.rules = ["eslint:react/prop-types"] > match.file_patterns = ["packages/ui/components/**"] > set.ignored = true > ``` > **Override the level of certain issues in a directory** > > ```toml qlty.toml lines theme={"system"} > # Downgrade the severity of issues in the experimental service > [[triage]] > match.file_patterns = ["services/experimental/**"] > set.level = "low" > > # Change the mode of specific linting rules in test packages > [[triage]] > match.rules = ["rubocop:Metrics/BlockLength"] > match.file_patterns = ["**/test/**"] > set.mode = "monitor" > ``` > **Adjust the issue mode for a directory** > > ```toml qlty.toml theme={"system"} > # Configure a plugin with a specific mode for a subdirectory > [[plugin]] > name = "eslint" > prefix = "frontend-app" > package_file = "frontend-app/package.json" > mode = "comment" > > # Configure another plugin with a different mode for a different directory > [[plugin]] > name = "eslint" > prefix = "backend-app" > package_file = "backend-app/package.json" > mode = "block" > ``` ### Directory-level visualization The Qlty Cloud web application provides clear, directory-level reporting for monorepos. This allows you to see the code quality of each component in your monorepo at a glance, making it easy to identify areas that need attention. ![Directory-level visualization](https://mintlify.s3.us-west-1.amazonaws.com/qltysoftware/directories.png) ## Code coverage ### Diff coverage When working with monorepos, traditional coverage metrics like total coverage can be misleading. A large monorepo might have high overall test coverage, but the new code in a pull request could still be completely untested. Diff coverage (sometimes called patch coverage) solves this problem by focusing only on the code that has changed in a pull request. Qlty can report Diff Coverage as a commit status and through code review comments. ### Coverage tags Monorepos often run only the test suites for the services that changed on each commit. This approach significantly improves CI performance but creates challenges for coverage reporting. Qlty addresses this with Coverage Tags, which allow you to upload separate groupings of code coverage data. For example, you can use a unique tag for each service in the monorepo. This enables clear, independent reporting of coverage. Also, Qlty can "carry forward" coverage data from previous runs to infer the total coverage of the HEAD, allowing you to maintain a complete picture. ### Coverage merging Monorepos with multiple languages, frameworks, or parallelized test suites often generate multiple coverage reports that need to be combined. Qlty supports two powerful merging approaches: client-side merging and server-side merging. **Client-side merging**: * Multiple coverage reports are combined locally before uploading to Qlty * Ideal when all tests run on a single machine or shared filesystem * Example: `qlty coverage publish reports/*.lcov` **Server-side merging**: * Individual coverage reports are uploaded separately and combined by Qlty * Perfect for distributed CI systems where tests run across multiple machines * Uses a parts count to track when all reports have been received * Example: `qlty coverage publish --total-parts-count=3 report.lcov` These approaches can be combined together or with coverage tags for maximum flexibility. For instance, you might have three parts for "unit" coverage and two parts for "integration" coverage, all of which Qlty can merge appropriately. This flexibility makes Qlty ideal for complex monorepo setups where coverage data comes from multiple sources and needs to be aggregated intelligently. ## Related links * [Ignoring Issues](/cli/ignoring-issues) - Learn how to ignore issues in your monorepo * [Project Configuration](/cli/qlty-toml) - Detailed reference for `qlty.toml` configuration options * [Analysis Configuration](/cli/analysis-configuration) - Configure how Qlty analyzes your code * [Coverage Merging](/coverage/merging) - Detailed guide on merging coverage reports * [Code Coverage Setup](/coverage/quickstart) - How to set up code coverage for your project # Available Plugins Source: https://docs.qlty.sh/plugins The following plugins are available on both [Qlty CLI](/cli/quickstart) and [Qlty Cloud](/cloud/quickstart): > [!NOTE] > > Looking for plugin-specific configuration options, supported versions, or invocation details? > Each plugin lives in its own folder under > [qltysh/qlty/qlty-plugins](https://github.com/qltysh/qlty/tree/main/qlty-plugins) on GitHub — > check the plugin's `plugin.toml` and `README.md` for specifics. | Name | Language(s) | Check types | | - | - | - | | [actionlint](https://github.com/rhysd/actionlint) | GitHub Actions | Security, Linter | | [ast-grep](https://github.com/ast-grep/ast-grep) | All | Linter | | [bandit](https://github.com/PyCQA/bandit) | Python | Security | | [biome](https://github.com/biomejs/biome) | CSS, JavaScript, JSON, TypeScript | Linter, Formatter | | [black](https://github.com/psf/black) | Python | Formatter | | [brakeman](https://github.com/presidentbeef/brakeman) | Ruby on Rails | Security | | [checkov](https://github.com/bridgecrewio/checkov) | Terraform, CloudFormation, Kubernetes, Docker | Security | | [checkstyle](https://github.com/checkstyle/checkstyle) | Java | Linter | | [clippy](https://github.com/rust-lang/rust-clippy) | Rust | Linter | | [coffeelint](https://github.com/coffeelint/coffeelint) | CoffeeScript | Linter | | [dockerfmt](https://github.com/reteps/dockerfmt) | Dockerfile | Formatter | | [dotenv-linter](https://github.com/dotenv-linter/dotenv-linter) | Shell | Linter | | [editorconfig-checker](https://github.com/editorconfig-checker/editorconfig-checker) | All | Linter | | [eslint](https://github.com/eslint/eslint) | JavaScript, TypeScript | Linter | | [flake8](https://github.com/PyCQA/flake8) | Python | Linter | | [gitleaks](https://github.com/zricethezav/gitleaks) | Git | Security | | [gofmt](https://golang.org/cmd/gofmt/) | Go | Formatter | | [golangci-lint](https://github.com/golangci/golangci-lint) | Go | Linter | | [google-java-format](https://github.com/google/google-java-format) | Java | Formatter | | [hadolint](https://github.com/hadolint/hadolint) | Dockerfile | Linter | | [haml-lint](https://github.com/sds/haml-lint) | HAML | Linter | | [knip](https://github.com/webpro-nl/knip) | JavaScript, TypeScript | Linter | | [ktlint](https://github.com/pinterest/ktlint) | Kotlin | Linter, Formatter | | [kube-linter](https://github.com/stackrox/kube-linter) | Kubernetes | Security | | [markdownlint](https://github.com/DavidAnson/markdownlint) | Markdown | Linter | | [mypy](https://github.com/python/mypy) | Python | Linter | | [osv-scanner](https://github.com/google/osv-scanner) | C++, Dart, Elixir, Erlang, Go, Gradle, Maven, NodeJS, PHP, Python, R, Ruby, Rust | Security | | [oxc](https://github.com/oxc-project/oxc) | JavaScript, TypeScript | Linter | | [php-codesniffer](https://github.com/squizlabs/PHP_CodeSniffer) | PHP | Linter | | [php-cs-fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer) | PHP | Formatter | | [phpstan](https://github.com/phpstan/phpstan) | PHP | Linter | | [pmd](https://github.com/pmd/pmd) | Java, Apex | Linter | | [prettier](https://github.com/prettier/prettier) | CSS, Graphql, HTML, Javascript, JSON, Markdown, SASS, Typescript, YAML | Formatter | | [prisma](https://github.com/prisma/prisma) | Prisma | Linter | | radarlint | Docker, Go, Java, JavaScript, Kotlin, PHP, Python, Ruby, Scala, Terraform, TypeScript | Linter | | [redocly](https://github.com/Redocly/redocly-cli) | OpenAPI | Linter | | [reek](https://github.com/troessner/reek) | Ruby | Linter | | [ripgrep](https://github.com/BurntSushi/ripgrep) | All | Text search | | [rubocop](https://github.com/rubocop/rubocop) | Ruby | Linter | | [ruff](https://github.com/charliermarsh/ruff) | Python | Linter | | [rustfmt](https://github.com/rust-lang/rustfmt) | Rust | Formatter | | [semgrep](https://github.com/returntocorp/semgrep) | All | Security | | [shellcheck](https://github.com/koalaman/shellcheck) | Shell | Linter | | [shfmt](https://github.com/mvdan/sh) | Shell | Formatter | | [spectral](https://github.com/stoplightio/spectral) | OpenAPI, AsyncAPI | Linter | | [sqlfluff](https://github.com/sqlfluff/sqlfluff) | SQL | Linter | | [standardrb](https://github.com/testdouble/standard) | Ruby | Linter | | [stringslint](https://github.com/dral3x/StringsLint) | Swift, Objective-C | Linter | | [stylelint](https://github.com/stylelint/stylelint) | CSS, SCSS, Less | Linter | | [swiftformat](https://github.com/nicklockwood/SwiftFormat) | Swift | Formatter | | [swiftlint](https://github.com/realm/SwiftLint) | Swift | Linter | | [terraform](https://github.com/hashicorp/terraform) | Terraform | Formatter | | [tflint](https://github.com/terraform-linters/tflint) | Terraform | Linter | | [trivy](https://github.com/aquasecurity/trivy) | .NET, C#, C++, Dart, Elixir, Erlang, Go, Gradle, Maven, NodeJS, PHP, Python, Ruby, Rust, Swift | Security | | [trufflehog](https://github.com/trufflesecurity/trufflehog) | All | Security | | [vale](https://github.com/errata-ai/vale) | Prose, Markdown | Linter | | [yamllint](https://github.com/adrienverge/yamllint) | YAML | Linter | | [zizmor](https://github.com/woodruffw/zizmor) | GitHub Actions | Security | ## See Also * [Supported Languages](/languages) # What is Qlty? Source: https://docs.qlty.sh/what-is-qlty Qlty is a next generation, cloud-based Code Health Platform designed to help you take control of technical debt. Our open, extensible platform includes support for all modern programming languages, frameworks, and infrastructure platforms and offers: > Linting > > [Open](/linting) > Auto-formatting > > [Open](/auto-formatting) > Security scanning > > [Open](/cloud/security/framework) > Code coverage > > [Open](/coverage) > Duplication detection > > [Open](/duplication) > Complexity > > [Open](/complexity) > Code smells > > [Open](/code-smells) > Metrics > > [Open](/cloud/maintainability/metrics) > [!TIP] > > Qlty is from the makers of Code Climate, who built the first cloud-based code quality platform > in 2011. ## What problems does Qlty solve? * **Slow code reviews.** PR authors usually wait hours for review feedback followed by repeated back-and-forth cycles. Supplementing peer review with automated code review allows PR authors to get initial feedback in minutes, increases consistency, and allows reviewers to focus on deeper conversations. * **Noisy static analysis.** Analyzers offer valuable findings but are notoriously difficult to integrate into development processes and CI. Qlty focuses on *newly introduced* issues making every finding actionable. Pre-existing issues are available to browse and fix whenever you're ready. * **Developer tool SaaS sprawl.** Implementing static analysis, SAST, IaC scanning, and code coverage often requires setting up and managing at least three tools totaling over \$100 per developer per month. Qlty provides all those functions in a single, unified experience for half the cost. * **Hidden and increasing technical debt.** Without clear data and reports, technical debt accumulates invisibly over time. Qlty provides clear answers about status and trends to align all stakeholders to make better decisions. ## Developing with Qlty Qlty's fully automated, cloud-based solution to technical debt makes it easy to implement continuous code quality: 1. When you open a pull request, Qlty analyzes your changes using a highly customizable static analysis configuration. 2. Within minutes, you'll get automated code review comments for newly introduced issues directly in your pull request. 3. Configurable Quality Gates evaluate the mergeability of the change in a simple go/no-go status. 4. By preventing new quality issues from being merged, the overall quality of the codebase will improve over time All of this is possible with five minutes of setup, and without needing to run static analysis on your CI system. (A simple coverage uploader is provided for publishing code coverage reports to Qlty.)