Running Diagnostics Without an Editor ===================================== The ``symfony-lsp check`` command runs Symfony Language Tools diagnostics against saved application files without an editor or Language Server Protocol client. Use it in local automation, pre-commit checks and continuous integration. The checker reports Symfony-specific diagnostics only. Keep your PHP syntax, type, style, dependency-security and test tools in the same CI pipeline. Installing the Executable ------------------------- The checker is included in the standalone ``symfony-lsp`` executable. For local automation and CI, follow the `standalone guide`_ to download the archive for your platform, verify its checksum and extract the executable. Add its directory to ``PATH`` or invoke it by its full path: .. code-block:: terminal $ /path/to/symfony-lsp check To build the executable yourself, follow the `source installation guide`_. Using Symfony CLI ----------------- Symfony CLI can manage the standalone executable and run the checker for the current project: .. code-block:: terminal $ symfony lsp:check This integration requires Symfony Language Tools 0.17.0 or newer. Symfony CLI selects the latest stable release for the current platform, verifies it against ``SHA256SUMS`` and keeps the complete distribution in its own cache. It checks for a newer stable release at most once every 24 hours, with the same behavior in interactive shells and non-interactive automation. When the release service is unavailable or an update can't be verified and installed safely, it reuses a compatible cached executable. If no cached copy is available, the Symfony CLI wrapper fails before the checker starts. Display the managed cache location with: .. code-block:: terminal $ symfony lsp:cache-dir When Symfony CLI starts the checker, its project-aware ``symfony php`` behavior becomes the default PHP command. This lets runtime analysis follow the PHP version and configuration selected for the project. An explicit ``phpCommand`` in ``.symfony-lsp.json``, editor initialization settings or ``symfony-lsp check --php-command`` remains authoritative and replaces this fallback. Source-only checks don't execute the project or invoke the configured PHP command: .. code-block:: terminal $ symfony lsp:check --source-only Running a Check --------------- Run the checker from the workspace root: .. code-block:: terminal $ symfony-lsp check With no path arguments, the command discovers Symfony projects and analyzes all supported project files. Pass files, directories or patterns to narrow the selection: .. code-block:: terminal $ symfony-lsp check src/ templates/ $ symfony-lsp check 'config/**/*.yaml' Paths and patterns are resolved from the workspace root. Files under ``.git/``, ``node_modules/``, ``var/`` or ``vendor/`` are skipped. Files excluded by ``.gitignore`` are also skipped, except project-root dotenv files (``.env*``), which Symfony reads even when ignored. This exception applies to default and explicit selections. The default selection also skips project ``excludePaths``. An explicit file, directory or pattern can select those configured exclusions, but it can't bypass the excluded directories or other ``.gitignore`` rules. Runtime analysis is enabled by default and boots the application with the configured PHP command. Use source-only mode for code that you don't trust or when CI must not execute the application: .. code-block:: terminal $ symfony-lsp check --source-only Reports indicate whether each project used runtime or source-only analysis. If invalid application configuration prevents runtime analysis, the report identifies the configuration failure and remains incomplete. Other runtime failures also exit with status ``12`` instead of silently switching to source-only analysis. If one runtime metadata section fails after other sections load, diagnostics backed by the healthy sections are still reported. Last successful metadata for the failed section remains active when available; otherwise diagnostics that need it are omitted. Configuring the Check --------------------- The checker and editor integrations share ``.symfony-lsp.json``. See the `project configuration`_ for available settings and multi-project examples. Command-line options override the shared configuration. Use ``--config=PATH`` to select another file and ``symfony-lsp check --help`` to list every option. Choosing an Output Format ------------------------- The default human format prints deterministic project status, diagnostics and a summary. Use JSON for automation: .. code-block:: terminal $ symfony-lsp check --format=json > diagnostics.json The JSON document uses ``schemaVersion`` 1. Diagnostic ranges are zero-based, end-exclusive and encoded as UTF-16 character offsets. It contains project identity, project-relative and workspace-relative paths, analysis mode, project status, baseline state, diagnostic provenance and summary counts. Operational errors include the provider and a sanitized cause when an exception is available. Use GitHub Actions annotations for pull request feedback: .. code-block:: terminal $ symfony-lsp check --format=github Publish diagnostics as a GitLab Code Quality report: .. code-block:: yaml symfony-lsp: stage: test script: - symfony lsp:check --format=gitlab > gl-code-quality-report.json artifacts: when: always reports: codequality: gl-code-quality-report.json GitLab reports map errors to ``major``, warnings to ``minor`` and information and hints to ``info``. They use repository-relative paths, one-based lines and occurrence-specific fingerprints. Invocation and operational failures still produce a valid JSON array, while the nonzero exit status and standard error identify the failed check. Generate a SARIF 2.1.0 report for code-scanning systems: .. code-block:: terminal $ symfony-lsp check --format=sarif > symfony-lsp.sarif SARIF results use workspace-relative paths, UTF-16 coordinates and stable partial fingerprints. Baseline matches remain visible as accepted external suppressions. Incomplete runs still produce valid SARIF with operational notifications, but don't upload reports from exit status ``11`` or ``12`` because their result set may be incomplete. Standard output contains only the selected report format. Operational details go to standard error. The Symfony CLI wrapper also keeps release-management and cache messages on standard error, so JSON, GitHub Actions, GitLab and SARIF output remain safe to pipe from standard output. Add ``--verbose`` to include sanitized runtime section causes in JSON and SARIF reports and show exception classes, messages, relative code locations and argument-free frames in human output. GitHub annotations remain generic. Once JSON, GitLab or SARIF is selected successfully, later invocation, configuration, indexing and internal failures still produce a valid structured report. Selecting Blocking Diagnostics ------------------------------ By default, every active error-severity diagnostic blocks the check. Warnings, such as ``config.deprecated_key`` and provisional source-only configuration findings, remain visible but don't block. Use ``--fail-on`` to make only selected codes blocking without filtering other diagnostics from the report: .. code-block:: terminal $ symfony-lsp check \ --fail-on=route.not_found,translation.not_found A selected warning becomes blocking. Unknown codes are configuration errors, so a removed or renamed code cannot silently weaken CI. List the supported contract with: .. code-block:: terminal $ symfony-lsp check --list-codes $ symfony-lsp check --format=json --list-codes Suppressing Intentional Diagnostics ----------------------------------- When source code intentionally triggers a diagnostic, add a code-qualified suppression in a native PHP, Twig, YAML or XML comment. The editor and ``symfony-lsp check`` apply the same suppressions: .. code-block:: php /* @symfony-lsp-ignore template.not_found (intentional missing template) */ $this->render('test/does_not_exist.html.twig'); .. code-block:: twig {# @symfony-lsp-ignore template.not_found (intentional missing template) #} {{ include('test/does_not_exist.html.twig') }} .. code-block:: yaml # @symfony-lsp-ignore config.unknown_key (compatibility fixture) framework: unsupported_option: true .. code-block:: xml true A standalone comment targets diagnostics whose ranges start on the next physical line. A comment that shares a line with source code targets that line. Blank lines aren't skipped. The directive accepts a comma-separated list of exact diagnostic codes. Each listed code suppresses one occurrence, so repeat a code to suppress several matching diagnostics on the same line. An optional parenthesized reason can follow the codes. Bare directives, malformed directives and unknown codes produce a ``suppression.invalid`` warning instead of suppressing diagnostics. Only native comments are recognized. Directive-shaped text in strings, Twig verbatim content, YAML block scalars and XML CDATA sections has no effect. Suppressed diagnostics are omitted from editor publications and checker reports, and they aren't written to new baselines. A matching entry in an existing baseline becomes stale. Using a Baseline ---------------- Create an occurrence-specific baseline when adopting the checker in an application with existing diagnostics: .. code-block:: terminal $ symfony-lsp check --generate-baseline This writes ``.symfony-lsp-baseline.json`` and records every collected diagnostic, regardless of the active ``--fail-on`` policy. Ordinary checks read but never modify the baseline: .. code-block:: terminal $ symfony-lsp check --baseline=.symfony-lsp-baseline.json Matched occurrences remain visible and don't block. A second identical occurrence in the same file remains active, and known diagnostics continue to match after unrelated line movement. Refresh the baseline explicitly after reviewing current diagnostics: .. code-block:: terminal $ symfony-lsp check --refresh-baseline Removed occurrences become stale baseline entries. They are reported but don't block by default. Add ``--strict-baseline`` to require stale entry cleanup. Exit Statuses ------------- The exit statuses are stable automation contracts: * ``0``: analysis completed without blocking diagnostics; * ``10``: analysis completed with blocking diagnostics or strict stale entries; * ``11``: invalid invocation, configuration, code policy, baseline or selection; * ``12``: incomplete analysis caused by indexing, timeout, cancellation, process or internal failure. Operational failure takes precedence over diagnostic findings. A partial report can contain diagnostics from completed projects and successful providers. If one provider fails for a file, the remaining providers continue and their findings stay in the report. ``complete`` remains ``false`` and the exit status is ``12``. When you run ``symfony lsp:check``, Symfony CLI forwards these checker statuses. A failure to select, download, verify or start the managed executable exits with status ``1`` instead: the checker didn't run, so no checker status or report was produced. Caching and Privacy ------------------- The checker stores its source index and last successful runtime information under ``var/symfony-lsp//`` in each application. Runtime analysis can also update the application's Symfony cache. These directories must be writable. A runtime failure still makes the analysis incomplete. When the current application configuration can be diagnosed, those diagnostics can use compatible runtime information from the cache. Remove the cache when reproducing a strictly cold analysis. CI can cache ``var/symfony-lsp/`` by project revision, platform and Symfony Language Tools version. Don't publish it as a build artifact or share it between untrusted projects. Treat the application's Symfony cache according to the same policy you use when running its console and tests. When CI uses Symfony CLI, it can also cache the directory printed by ``symfony lsp:cache-dir`` by operating system and architecture. A restored compatible installation can be used without network access; Symfony CLI still applies its normal latest-stable update policy when the cache is online. Reports and baselines can contain diagnostic messages and application names, but not parameter values, environment values, credentials or resolved secrets. Baselines contain no absolute checkout paths or source snippets. Limitations ----------- The checker has no watch mode and doesn't apply fixes. .. _`standalone guide`: ../index.rst#installing-a-standalone-release .. _`source installation guide`: ../index.rst#installing-the-server-from-source .. _`project configuration`: ../project-configuration.rst