From 202eb26ea0c748cc9dcccf62f5116f89d60b6897 Mon Sep 17 00:00:00 2001 From: YaFou <33806646+YaFou@users.noreply.github.com> Date: Thu, 14 Jan 2021 10:20:56 +0100 Subject: [PATCH] [TwigBridge] LintCommand supports Github Actions annotations --- src/Symfony/Bridge/Twig/CHANGELOG.md | 6 ++++ .../Bridge/Twig/Command/LintCommand.php | 28 +++++++++++++++---- .../Twig/Tests/Command/LintCommandTest.php | 27 ++++++++++++++++++ src/Symfony/Bridge/Twig/composer.json | 4 +-- 4 files changed, 58 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Bridge/Twig/CHANGELOG.md b/src/Symfony/Bridge/Twig/CHANGELOG.md index 16ce6d86a1ed8..535df0c0897b4 100644 --- a/src/Symfony/Bridge/Twig/CHANGELOG.md +++ b/src/Symfony/Bridge/Twig/CHANGELOG.md @@ -1,6 +1,12 @@ CHANGELOG ========= +5.4 +--- + +* Add `github` format & autodetection to render errors as annotations when + running the Twig linter command in a Github Actions environment. + 5.3 --- diff --git a/src/Symfony/Bridge/Twig/Command/LintCommand.php b/src/Symfony/Bridge/Twig/Command/LintCommand.php index a16c771d6b6ae..53e1d0bb583c4 100644 --- a/src/Symfony/Bridge/Twig/Command/LintCommand.php +++ b/src/Symfony/Bridge/Twig/Command/LintCommand.php @@ -11,6 +11,7 @@ namespace Symfony\Bridge\Twig\Command; +use Symfony\Component\Console\CI\GithubActionReporter; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Exception\RuntimeException; @@ -39,6 +40,11 @@ class LintCommand extends Command private $twig; + /** + * @var string|null + */ + private $format; + public function __construct(Environment $twig) { parent::__construct(); @@ -50,7 +56,7 @@ protected function configure() { $this ->setDescription(self::$defaultDescription) - ->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format', 'txt') + ->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format') ->addOption('show-deprecations', null, InputOption::VALUE_NONE, 'Show deprecations as errors') ->addArgument('filename', InputArgument::IS_ARRAY, 'A file, a directory or "-" for reading from STDIN') ->setHelp(<<<'EOF' @@ -80,6 +86,11 @@ protected function execute(InputInterface $input, OutputInterface $output) $io = new SymfonyStyle($input, $output); $filenames = $input->getArgument('filename'); $showDeprecations = $input->getOption('show-deprecations'); + $this->format = $input->getOption('format'); + + if (null === $this->format) { + $this->format = GithubActionReporter::isGithubActionEnvironment() ? 'github' : 'txt'; + } if (['-'] === $filenames) { 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 private function display(InputInterface $input, OutputInterface $output, SymfonyStyle $io, array $files) { - switch ($input->getOption('format')) { + switch ($this->format) { case 'txt': return $this->displayTxt($output, $io, $files); case 'json': return $this->displayJson($output, $files); + case 'github': + return $this->displayTxt($output, $io, $files, true); default: throw new InvalidArgumentException(sprintf('The format "%s" is not supported.', $input->getOption('format'))); } } - private function displayTxt(OutputInterface $output, SymfonyStyle $io, array $filesInfo) + private function displayTxt(OutputInterface $output, SymfonyStyle $io, array $filesInfo, bool $errorAsGithubAnnotations = false) { $errors = 0; + $githubReporter = $errorAsGithubAnnotations ? new GithubActionReporter($output) : null; foreach ($filesInfo as $info) { if ($info['valid'] && $output->isVerbose()) { $io->comment('OK'.($info['file'] ? sprintf(' in %s', $info['file']) : '')); } elseif (!$info['valid']) { ++$errors; - $this->renderException($io, $info['template'], $info['exception'], $info['file']); + $this->renderException($io, $info['template'], $info['exception'], $info['file'], $githubReporter); } } @@ -220,10 +234,14 @@ private function displayJson(OutputInterface $output, array $filesInfo) return min($errors, 1); } - private function renderException(SymfonyStyle $output, string $template, Error $exception, string $file = null) + private function renderException(SymfonyStyle $output, string $template, Error $exception, string $file = null, ?GithubActionReporter $githubReporter = null) { $line = $exception->getTemplateLine(); + if ($githubReporter) { + $githubReporter->error($exception->getRawMessage(), $file, $line <= 0 ? null : $line); + } + if ($file) { $output->text(sprintf(' ERROR in %s (line %s)', $file, $line)); } else { diff --git a/src/Symfony/Bridge/Twig/Tests/Command/LintCommandTest.php b/src/Symfony/Bridge/Twig/Tests/Command/LintCommandTest.php index 9bb9a9867c745..c26dabd6df9b0 100644 --- a/src/Symfony/Bridge/Twig/Tests/Command/LintCommandTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Command/LintCommandTest.php @@ -107,6 +107,33 @@ public function testLintDefaultPaths() self::assertStringContainsString('OK in', trim($tester->getDisplay())); } + public function testLintIncorrectFileWithGithubFormat() + { + $filename = $this->createFile('{{ foo'); + $tester = $this->createCommandTester(); + $tester->execute(['filename' => [$filename], '--format' => 'github'], ['decorated' => false]); + self::assertEquals(1, $tester->getStatusCode(), 'Returns 1 in case of error'); + self::assertStringMatchesFormat('%A::error file=%s,line=1,col=0::Unexpected token "end of template" ("end of print statement" expected).%A', trim($tester->getDisplay())); + } + + public function testLintAutodetectsGithubActionEnvironment() + { + $prev = getenv('GITHUB_ACTIONS'); + putenv('GITHUB_ACTIONS'); + + try { + putenv('GITHUB_ACTIONS=1'); + + $filename = $this->createFile('{{ foo'); + $tester = $this->createCommandTester(); + + $tester->execute(['filename' => [$filename]], ['decorated' => false]); + self::assertStringMatchesFormat('%A::error file=%s,line=1,col=0::Unexpected token "end of template" ("end of print statement" expected).%A', trim($tester->getDisplay())); + } finally { + putenv('GITHUB_ACTIONS'.($prev ? "=$prev" : '')); + } + } + private function createCommandTester(): CommandTester { $environment = new Environment(new FilesystemLoader(\dirname(__DIR__).'/Fixtures/templates/')); diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json index 5a0735e250df2..88f5f7896b18b 100644 --- a/src/Symfony/Bridge/Twig/composer.json +++ b/src/Symfony/Bridge/Twig/composer.json @@ -44,7 +44,7 @@ "symfony/security-http": "^4.4|^5.0|^6.0", "symfony/serializer": "^5.2|^6.0", "symfony/stopwatch": "^4.4|^5.0|^6.0", - "symfony/console": "^4.4|^5.0|^6.0", + "symfony/console": "^5.3|^6.0", "symfony/expression-language": "^4.4|^5.0|^6.0", "symfony/web-link": "^4.4|^5.0|^6.0", "symfony/workflow": "^5.2|^6.0", @@ -55,7 +55,7 @@ "conflict": { "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", - "symfony/console": "<4.4", + "symfony/console": "<5.3", "symfony/form": "<5.3", "symfony/http-foundation": "<5.3", "symfony/http-kernel": "<4.4", 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