Skip to content

Add Symfony LSP diagnostics to CI - #87

Merged
loevgaard merged 5 commits into
1.14.xfrom
symfony-lsp-check-1.14.x
Oct 19, 2026
Merged

loevgaard merged 5 commits into
1.14.xfrom
symfony-lsp-check-1.14.x

Conversation

@loevgaard

@loevgaard loevgaard commented Sep 9, 2026 •

Copy link
Copy Markdown
Member

Integrates symfony lsp:check into the build workflow as a step of the coding-standards job (PHP 8.1, highest deps), next to the YAML and Twig lint steps. It runs symfony lsp:check --format=github, so unknown routes/services/templates/translation keys, deprecated config keys etc. show up as annotations on pull requests.

This is the 1.14.x counterpart of #88. On 2.2.x the check lives in setono/sylius-plugin's coding-standards action. 1.14.x has a self-contained workflow (the setono/sylius-plugin v2 actions target Sylius 2), so here it's a step in build.yaml, with the Symfony CLI from setup-php's tools: symfony.

Configuration

.symfony-lsp.json points symfony-lsp at the repository root and names the test application's kernel, as #88 does on 2.2.x:

{
    "version": 1,
    "projectRoots": ["."],
    "kernel": "Acme\\SyliusExamplePlugin\\Tests\\Application\\Kernel",
    "translationDiagnostics": true
}
  • The root has vendor/autoload.php, which symfony-lsp's bridge hard-codes as <project>/vendor/autoload.php.
  • The kernel is autoloadable through the root composer.json.
  • The plugin's own src/Resources is analyzed, not only the test application.
  • APP_SECRET fallback: symfony-lsp only loads a .env file from the root it analyzes, so it boots the kernel without tests/Application/.env.
    • APP_SECRET is the only variable that's then missing (checked by leaving each one out); without it the analysis is incomplete (exit 12).
    • framework.yaml now gives it a fallback, the same way doctrine.yaml already does for DATABASE_URL. The fallback only applies when .env isn't loaded.
  • Cache: symfony-lsp keeps its cache in <project>/var/symfony-lsp, so /var/ is now ignored, in a separate block from /node_modules/, which Remove the root node_modules symlink and point badges at 1.14.x #96 changes.
  • Docs: CLAUDE.md documents the command.

Changed since the first version

The first version used projectRoots: ["tests/Application"]. That needed three workarounds just to boot the kernel:

  • a symfony/framework-bundle requirement and a PSR-4 entry in tests/Application/composer.json;
  • a tests/Application/vendor symlink;
  • a phpunit.xml.dist exclusion, because PHPUnit followed that symlink.

It also left the plugin's own templates unchecked. All three are reverted. The branch is also rebased onto the current 1.14.x.

Deprecated config keys

The second commit removes the two deprecated config keys the check flagged in the test application (framework.form.legacy_error_messages, security.enable_authenticator_manager). Both are no-ops on Symfony 6.4.

Verification

Run locally on PHP 8.1, as in CI, with symfony-lsp 0.24.0, the version the Symfony CLI in CI downloads:

  • Clean run: symfony-lsp check --format=github analyzes project . with runtime metadata, 0 diagnostics, exit code 0.
  • Plugin templates: a planted {{ path('nonexistent_route') }} in src/Resources/views/ is reported as route.not_found, exit code 10.
  • Tests and linting: vendor/bin/phpunit (4 tests), bin/console lint:container, lint:yaml and ECS pass.

Running the check locally requires the Symfony CLI 5.20 or newer (symfony lsp:check), or the standalone symfony-lsp binary from https://github.com/symfony/language-tools/releases.

@codecov

codecov Bot commented Sep 9, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (cc91068) to head (b3f36a2).

Additional details and impacted files
@@             Coverage Diff             @@
##              1.14.x       #87   +/-   ##
===========================================
  Coverage     100.00%   100.00%           
  Complexity         2         2           
===========================================
  Files              2         2           
  Lines             16        16           
===========================================
  Hits              16        16           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Run `symfony lsp:check` (https://symfony.com/blog/introducing-symfony-lsp-check-symfony-aware-diagnostics-in-your-ci)
as a new "symfony-diagnostics" job so that unknown routes, services,
templates, translation keys, deprecated configuration keys etc. are
reported as GitHub annotations.

symfony-lsp only discovers a Symfony application when its composer.json
requires symfony/framework-bundle and, to boot it, needs a PSR-4 entry
pointing at the kernel plus <project>/vendor/autoload.php. The test
application is not a standalone Composer project, so:

- tests/Application/composer.json declares the framework-bundle
  requirement and the PSR-4 namespace of the kernel (nothing is ever
  installed from this file)
- tests/Application/vendor is a symlink to the root vendor directory
- phpunit.xml.dist excludes tests/Application and vendor because
  PHPUnit follows symlinks when discovering tests
- .symfony-lsp.json points symfony-lsp at tests/Application and enables
  translation diagnostics
framework.form.legacy_error_messages and
security.enable_authenticator_manager are deprecated no-ops on
Symfony 6.4.
The check belongs with the other lint steps rather than in a job of
its own.
With tests/Application as the project root, symfony-lsp only analyzed the test
application, not the plugin's src/Resources. It also needed a PSR-4 entry in
tests/Application/composer.json and a tests/Application/vendor symlink to boot
the kernel at all, plus a phpunit.xml.dist exclusion because PHPUnit followed
that symlink.

Analyze the repository root instead and name the kernel in .symfony-lsp.json.
The root has vendor/autoload.php and the kernel is autoloadable through the
root composer.json, so those workarounds are reverted. A template in
src/Resources/views using a non-existent route is now reported.

symfony-lsp only loads a .env file from the root it analyzes, so the kernel now
boots without tests/Application/.env. The only variable that is then missing
is APP_SECRET; give it a fallback like doctrine.yaml does for DATABASE_URL.

symfony-lsp now keeps its cache in the root var/, so ignore it.
@loevgaard
loevgaard force-pushed the symfony-lsp-check-1.14.x branch from 76932ff to b3f36a2 Compare October 19, 2026 11:33
@loevgaard
loevgaard merged commit 38c29a6 into 1.14.x Oct 19, 2026
30 checks passed
@loevgaard
loevgaard deleted the symfony-lsp-check-1.14.x branch October 19, 2026 11:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant