Skip to content

Commit 1cd363d

Browse files
committed
Add GitLab Code Quality check reports
1 parent 46f9825 commit 1cd363d

14 files changed

Lines changed: 183 additions & 20 deletions

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Unreleased
44

5+
- Add GitLab Code Quality reports to the diagnostics checker
56
- Suppress code-qualified diagnostics with source comments
67
- Honor router request context parameters in route diagnostics
78
- Report Symfony branches outside the live supported range

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,9 @@ symfony lsp:check
9191

9292
You can also invoke a standalone installation directly with
9393
`symfony-lsp check`. The checker supports deterministic human, JSON, GitHub
94-
Actions and SARIF output, code-based failure policies, source-only analysis and
95-
occurrence-specific baselines. Running it with runtime indexing enabled executes
96-
application code.
94+
Actions, GitLab Code Quality and SARIF output, code-based failure policies,
95+
source-only analysis and occurrence-specific baselines. Running it with runtime
96+
indexing enabled executes application code.
9797
See the [headless diagnostics guide](docs/features/headless-diagnostics.rst) for
9898
configuration, CI examples and stable exit statuses.
9999

docs/features/headless-diagnostics.rst

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,25 @@ Use GitHub Actions annotations for pull request feedback:
135135
136136
$ symfony-lsp check --format=github
137137
138+
Publish diagnostics as a GitLab Code Quality report:
139+
140+
.. code-block:: yaml
141+
142+
symfony-lsp:
143+
stage: test
144+
script:
145+
- symfony lsp:check --format=gitlab > gl-code-quality-report.json
146+
artifacts:
147+
when: always
148+
reports:
149+
codequality: gl-code-quality-report.json
150+
151+
GitLab reports map errors to ``major``, warnings to ``minor`` and information
152+
and hints to ``info``. They use repository-relative paths, one-based lines and
153+
occurrence-specific fingerprints. Invocation and operational failures still
154+
produce a valid JSON array, while the nonzero exit status and standard error
155+
identify the failed check.
156+
138157
Generate a SARIF 2.1.0 report for code-scanning systems:
139158

140159
.. code-block:: terminal
@@ -149,12 +168,13 @@ because their result set may be incomplete.
149168

150169
Standard output contains only the selected report format. Operational details
151170
go to standard error. The Symfony CLI wrapper also keeps release-management
152-
and cache messages on standard error, so JSON, GitHub Actions and SARIF output
153-
remain safe to pipe from standard output. Add ``--verbose`` to human output to
154-
show sanitized exception classes and messages. GitHub annotations remain
155-
generic.
156-
Once JSON or SARIF is selected successfully, later invocation, configuration,
157-
indexing and internal failures still produce a valid structured report.
171+
and cache messages on standard error, so JSON, GitHub Actions, GitLab and SARIF
172+
output remain safe to pipe from standard output. Add ``--verbose`` to human
173+
output to show sanitized exception classes and messages. GitHub annotations
174+
remain generic.
175+
Once JSON, GitLab or SARIF is selected successfully, later invocation,
176+
configuration, indexing and internal failures still produce a valid structured
177+
report.
158178

159179
Selecting Blocking Diagnostics
160180
------------------------------

docs/index.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,10 @@ or CI:
122122
123123
$ ./symfony-lsp check
124124
125-
The command can produce human, JSON, GitHub Actions and SARIF reports, select
126-
blocking diagnostic codes and maintain an occurrence-specific baseline. Runtime
127-
analysis executes application code; pass ``--source-only`` when it must remain
128-
disabled.
125+
The command can produce human, JSON, GitHub Actions, GitLab Code Quality and
126+
SARIF reports, select blocking diagnostic codes and maintain an
127+
occurrence-specific baseline. Runtime analysis executes application code; pass
128+
``--source-only`` when it must remain disabled.
129129
See `Running Diagnostics Without an Editor`_ for configuration, output,
130130
baseline and exit-status details.
131131

src/Check/CheckOptionsParser.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
final class CheckOptionsParser
1010
{
11-
private const FORMATS = ['human', 'json', 'github', 'sarif'];
11+
private const FORMATS = ['human', 'json', 'github', 'gitlab', 'sarif'];
1212

1313
private const FLAG_OPTIONS = [
1414
'--help' => ['help', true],
@@ -236,7 +236,7 @@ private function positiveNumber(string $name, string $value): float
236236
private function format(?string $current, string $requested): string
237237
{
238238
if (!\in_array($requested, self::FORMATS, true)) {
239-
throw new InvalidConfigurationException('The --format option must be human, json, github or sarif.');
239+
throw new InvalidConfigurationException('The --format option must be human, json, github, gitlab or sarif.');
240240
}
241241
if (null !== $current && $current !== $requested) {
242242
throw new InvalidConfigurationException('The --format option cannot select more than one format.');

src/Check/CheckReportDiagnosticView.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ final class CheckReportDiagnosticView
77
public function __construct(
88
public readonly CheckDiagnostic $diagnostic,
99
public readonly int $occurrence,
10+
public readonly string $occurrenceFingerprint,
1011
public readonly string $feature,
1112
public readonly ?string $environment,
1213
public readonly ?string $analysisMode,

src/Check/CheckReportViewBuilder.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public function build(CheckResult $result, int $exitCode): CheckReportView
2323
$diagnostics[] = new CheckReportDiagnosticView(
2424
$diagnostic,
2525
$occurrence->number,
26+
hash('sha256', $diagnostic->fingerprint."\0".$occurrence->number),
2627
strstr($diagnostic->code, '.', true) ?: $diagnostic->code,
2728
$project?->environment,
2829
$project?->mode,

src/Check/CheckReporter.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
final class CheckReporter
66
{
77
public function __construct(
8+
private readonly GitLabCheckReporter $gitLab,
89
private readonly SarifCheckReporter $sarif,
910
private readonly CheckReportViewBuilder $viewBuilder,
1011
) {
@@ -17,6 +18,7 @@ public function render(CheckResult $result, string $format, bool $verbose, int $
1718
return match ($format) {
1819
'json' => $this->json($view),
1920
'github' => $this->github($view),
21+
'gitlab' => $this->gitLab->render($view),
2022
'sarif' => $this->sarif->render($view),
2123
default => $this->human($view, $verbose),
2224
};
@@ -31,6 +33,7 @@ public function codes(array $codes, string $format): string
3133
'diagnosticCodes' => $codes,
3234
], \JSON_THROW_ON_ERROR | \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES)."\n",
3335
'sarif' => $this->sarif->codes($codes),
36+
'gitlab' => $this->gitLab->codes(),
3437
'github' => implode('', array_map(
3538
fn (string $code): string => \sprintf('::notice title=Symfony diagnostic code::%s%s', $this->escapeData($code), \PHP_EOL),
3639
$codes,
@@ -45,7 +48,7 @@ public function help(): string
4548
Usage: symfony-lsp check [options] [files, directories or patterns]
4649
4750
Options:
48-
--format=human|json|github|sarif Select the report format
51+
--format=human|json|github|gitlab|sarif Select the report format
4952
--workspace=PATH Set the workspace root
5053
--config=PATH Load a configuration file instead of .symfony-lsp.json
5154
--project-root=PATH Select an explicit Symfony project root; repeatable

src/Check/GitLabCheckReporter.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace Symfony\Lsp\Check;
4+
5+
final class GitLabCheckReporter
6+
{
7+
public function render(CheckReportView $view): string
8+
{
9+
return json_encode(array_map(static function (CheckReportDiagnosticView $diagnosticView): array {
10+
$diagnostic = $diagnosticView->diagnostic;
11+
12+
return [
13+
'description' => $diagnostic->message,
14+
'check_name' => $diagnostic->code,
15+
'fingerprint' => $diagnosticView->occurrenceFingerprint,
16+
'severity' => match ($diagnostic->severity) {
17+
1 => 'major',
18+
2 => 'minor',
19+
default => 'info',
20+
},
21+
'location' => [
22+
'path' => $diagnostic->workspacePath,
23+
'lines' => ['begin' => $diagnostic->startLine + 1],
24+
],
25+
];
26+
}, $view->diagnostics), \JSON_THROW_ON_ERROR | \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE | \JSON_INVALID_UTF8_SUBSTITUTE)."\n";
27+
}
28+
29+
public function codes(): string
30+
{
31+
return "[]\n";
32+
}
33+
}

src/Check/SarifCheckReporter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ private function results(array $diagnostics): array
112112
],
113113
]],
114114
'partialFingerprints' => [
115-
'symfonyLsp/v1' => hash('sha256', $diagnostic->fingerprint."\0".$diagnosticView->occurrence),
115+
'symfonyLsp/v1' => $diagnosticView->occurrenceFingerprint,
116116
],
117117
'properties' => $properties,
118118
];

0 commit comments

Comments
 (0)