Skip to content

Commit b8d7e1f

Browse files
committed
feature #39826 [TwigBridge] LintCommand supports Github Actions annotations (YaFou)
This PR was merged into the 5.4 branch. Discussion ---------- [TwigBridge] LintCommand supports Github Actions annotations | Q | A | ------------- | --- | Branch? | 5.x | Bug fix? | no | New feature? | yes | Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Tickets | Fix #39122 (for `lint:twig`) | License | MIT | Doc PR | TODO <!-- Replace this notice by a short README for your feature/bugfix. This will help people understand your PR and can be used as a start for the documentation. Additionally (see https://symfony.com/releases): - Always add tests and ensure they pass. - Never break backward compatibility (see https://symfony.com/bc). - Bug fixes must be submitted against the lowest maintained branch where they apply (lowest branches are regularly merged to upper ones so they get the fixes too.) - Features and deprecations must be submitted against branch 5.x. --> Adds a format to the Twig linter command to print Github Actions annotations when an error occurred ([documentation](https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-an-error-message)). There is a new format: `github` and the command will detect automatically the format to use in comparison with the environment. > See a workflow example: https://github.com/YaFou/symfony-39826/actions/runs/485093369 --- TODO: - [x] Changelog - [x] Test with a real project Commits ------- 202eb26 [TwigBridge] LintCommand supports Github Actions annotations
2 parents ccd3a15 + 202eb26 commit b8d7e1f

File tree

4 files changed

+58
-7
lines changed

4 files changed

+58
-7
lines changed

src/Symfony/Bridge/Twig/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
CHANGELOG
22
=========
33

4+
5.4
5+
---
6+
7+
* Add `github` format & autodetection to render errors as annotations when
8+
running the Twig linter command in a Github Actions environment.
9+
410
5.3
511
---
612

src/Symfony/Bridge/Twig/Command/LintCommand.php

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Bridge\Twig\Command;
1313

14+
use Symfony\Component\Console\CI\GithubActionReporter;
1415
use Symfony\Component\Console\Command\Command;
1516
use Symfony\Component\Console\Exception\InvalidArgumentException;
1617
use Symfony\Component\Console\Exception\RuntimeException;
@@ -39,6 +40,11 @@ class LintCommand extends Command
3940

4041
private $twig;
4142

43+
/**
44+
* @var string|null
45+
*/
46+
private $format;
47+
4248
public function __construct(Environment $twig)
4349
{
4450
parent::__construct();
@@ -50,7 +56,7 @@ protected function configure()
5056
{
5157
$this
5258
->setDescription(self::$defaultDescription)
53-
->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format', 'txt')
59+
->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format')
5460
->addOption('show-deprecations', null, InputOption::VALUE_NONE, 'Show deprecations as errors')
5561
->addArgument('filename', InputArgument::IS_ARRAY, 'A file, a directory or "-" for reading from STDIN')
5662
->setHelp(<<<'EOF'
@@ -80,6 +86,11 @@ protected function execute(InputInterface $input, OutputInterface $output)
8086
$io = new SymfonyStyle($input, $output);
8187
$filenames = $input->getArgument('filename');
8288
$showDeprecations = $input->getOption('show-deprecations');
89+
$this->format = $input->getOption('format');
90+
91+
if (null === $this->format) {
92+
$this->format = GithubActionReporter::isGithubActionEnvironment() ? 'github' : 'txt';
93+
}
8394

8495
if (['-'] === $filenames) {
8596
return $this->display($input, $output, $io, [$this->validate(file_get_contents('php://stdin'), uniqid('sf_', true))]);
@@ -169,26 +180,29 @@ private function validate(string $template, string $file): array
169180

170181
private function display(InputInterface $input, OutputInterface $output, SymfonyStyle $io, array $files)
171182
{
172-
switch ($input->getOption('format')) {
183+
switch ($this->format) {
173184
case 'txt':
174185
return $this->displayTxt($output, $io, $files);
175186
case 'json':
176187
return $this->displayJson($output, $files);
188+
case 'github':
189+
return $this->displayTxt($output, $io, $files, true);
177190
default:
178191
throw new InvalidArgumentException(sprintf('The format "%s" is not supported.', $input->getOption('format')));
179192
}
180193
}
181194

182-
private function displayTxt(OutputInterface $output, SymfonyStyle $io, array $filesInfo)
195+
private function displayTxt(OutputInterface $output, SymfonyStyle $io, array $filesInfo, bool $errorAsGithubAnnotations = false)
183196
{
184197
$errors = 0;
198+
$githubReporter = $errorAsGithubAnnotations ? new GithubActionReporter($output) : null;
185199

186200
foreach ($filesInfo as $info) {
187201
if ($info['valid'] && $output->isVerbose()) {
188202
$io->comment('<info>OK</info>'.($info['file'] ? sprintf(' in %s', $info['file']) : ''));
189203
} elseif (!$info['valid']) {
190204
++$errors;
191-
$this->renderException($io, $info['template'], $info['exception'], $info['file']);
205+
$this->renderException($io, $info['template'], $info['exception'], $info['file'], $githubReporter);
192206
}
193207
}
194208

@@ -220,10 +234,14 @@ private function displayJson(OutputInterface $output, array $filesInfo)
220234
return min($errors, 1);
221235
}
222236

223-
private function renderException(SymfonyStyle $output, string $template, Error $exception, string $file = null)
237+
private function renderException(SymfonyStyle $output, string $template, Error $exception, string $file = null, ?GithubActionReporter $githubReporter = null)
224238
{
225239
$line = $exception->getTemplateLine();
226240

241+
if ($githubReporter) {
242+
$githubReporter->error($exception->getRawMessage(), $file, $line <= 0 ? null : $line);
243+
}
244+
227245
if ($file) {
228246
$output->text(sprintf('<error> ERROR </error> in %s (line %s)', $file, $line));
229247
} else {

src/Symfony/Bridge/Twig/Tests/Command/LintCommandTest.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,33 @@ public function testLintDefaultPaths()
107107
self::assertStringContainsString('OK in', trim($tester->getDisplay()));
108108
}
109109

110+
public function testLintIncorrectFileWithGithubFormat()
111+
{
112+
$filename = $this->createFile('{{ foo');
113+
$tester = $this->createCommandTester();
114+
$tester->execute(['filename' => [$filename], '--format' => 'github'], ['decorated' => false]);
115+
self::assertEquals(1, $tester->getStatusCode(), 'Returns 1 in case of error');
116+
self::assertStringMatchesFormat('%A::error file=%s,line=1,col=0::Unexpected token "end of template" ("end of print statement" expected).%A', trim($tester->getDisplay()));
117+
}
118+
119+
public function testLintAutodetectsGithubActionEnvironment()
120+
{
121+
$prev = getenv('GITHUB_ACTIONS');
122+
putenv('GITHUB_ACTIONS');
123+
124+
try {
125+
putenv('GITHUB_ACTIONS=1');
126+
127+
$filename = $this->createFile('{{ foo');
128+
$tester = $this->createCommandTester();
129+
130+
$tester->execute(['filename' => [$filename]], ['decorated' => false]);
131+
self::assertStringMatchesFormat('%A::error file=%s,line=1,col=0::Unexpected token "end of template" ("end of print statement" expected).%A', trim($tester->getDisplay()));
132+
} finally {
133+
putenv('GITHUB_ACTIONS'.($prev ? "=$prev" : ''));
134+
}
135+
}
136+
110137
private function createCommandTester(): CommandTester
111138
{
112139
$environment = new Environment(new FilesystemLoader(\dirname(__DIR__).'/Fixtures/templates/'));

src/Symfony/Bridge/Twig/composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"symfony/security-http": "^4.4|^5.0|^6.0",
4545
"symfony/serializer": "^5.2|^6.0",
4646
"symfony/stopwatch": "^4.4|^5.0|^6.0",
47-
"symfony/console": "^4.4|^5.0|^6.0",
47+
"symfony/console": "^5.3|^6.0",
4848
"symfony/expression-language": "^4.4|^5.0|^6.0",
4949
"symfony/web-link": "^4.4|^5.0|^6.0",
5050
"symfony/workflow": "^5.2|^6.0",
@@ -55,7 +55,7 @@
5555
"conflict": {
5656
"phpdocumentor/reflection-docblock": "<3.2.2",
5757
"phpdocumentor/type-resolver": "<1.4.0",
58-
"symfony/console": "<4.4",
58+
"symfony/console": "<5.3",
5959
"symfony/form": "<5.3",
6060
"symfony/http-foundation": "<5.3",
6161
"symfony/http-kernel": "<4.4",

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy