1111
1212namespace Symfony \Bridge \Twig \Command ;
1313
14+ use Symfony \Component \Console \CI \GithubActionReporter ;
1415use Symfony \Component \Console \Command \Command ;
1516use Symfony \Component \Console \Exception \InvalidArgumentException ;
1617use Symfony \Component \Console \Exception \RuntimeException ;
@@ -37,6 +38,10 @@ class LintCommand extends Command
3738protected static $ defaultName ='lint:twig ' ;
3839
3940private $ twig ;
41+ /**
42+ * @var string
43+ */
44+ private $ format ;
4045
4146public function __construct (Environment $ twig )
4247 {
@@ -49,7 +54,7 @@ protected function configure()
4954 {
5055$ this
5156 ->setDescription ('Lints a template and outputs encountered errors ' )
52- ->addOption ('format ' ,null , InputOption::VALUE_REQUIRED ,'The output format ' , ' txt ' )
57+ ->addOption ('format ' ,null , InputOption::VALUE_REQUIRED ,'The output format ' )
5358 ->addOption ('show-deprecations ' ,null , InputOption::VALUE_NONE ,'Show deprecations as errors ' )
5459 ->addArgument ('filename ' , InputArgument::IS_ARRAY ,'A file, a directory or "-" for reading from STDIN ' )
5560 ->setHelp (<<<'EOF'
@@ -79,6 +84,15 @@ protected function execute(InputInterface $input, OutputInterface $output)
7984$ io =new SymfonyStyle ($ input ,$ output );
8085$ filenames =$ input ->getArgument ('filename ' );
8186$ showDeprecations =$ input ->getOption ('show-deprecations ' );
87+ $ this ->format =$ input ->getOption ('format ' );
88+
89+ if ('github ' ===$ this ->format && !class_exists (GithubActionReporter::class)) {
90+ throw new \InvalidArgumentException ('The "github" format is only available since "symfony/console" >= 5.3. ' );
91+ }
92+
93+ if (null ===$ this ->format ) {
94+ $ this ->format =class_exists (GithubActionReporter::class) && GithubActionReporter::isGithubActionEnvironment () ?'github ' :'txt ' ;
95+ }
8296
8397if (['- ' ] ===$ filenames ) {
8498return $ this ->display ($ input ,$ output ,$ io , [$ this ->validate (file_get_contents ('php://stdin ' ),uniqid ('sf_ ' ,true ))]);
@@ -168,26 +182,29 @@ private function validate(string $template, string $file): array
168182
169183private function display (InputInterface $ input ,OutputInterface $ output ,SymfonyStyle $ io ,array $ files )
170184 {
171- switch ($ input -> getOption ( ' format ' ) ) {
185+ switch ($ this -> format ) {
172186case 'txt ' :
173187return $ this ->displayTxt ($ output ,$ io ,$ files );
174188case 'json ' :
175189return $ this ->displayJson ($ output ,$ files );
190+ case 'github ' :
191+ return $ this ->displayTxt ($ output ,$ io ,$ files ,true );
176192default :
177193throw new InvalidArgumentException (sprintf ('The format "%s" is not supported. ' ,$ input ->getOption ('format ' )));
178194 }
179195 }
180196
181- private function displayTxt (OutputInterface $ output ,SymfonyStyle $ io ,array $ filesInfo )
197+ private function displayTxt (OutputInterface $ output ,SymfonyStyle $ io ,array $ filesInfo, bool $ errorAsGithubAnnotations = false )
182198 {
183199$ errors =0 ;
200+ $ githubReporter =$ errorAsGithubAnnotations ?new GithubActionReporter ($ output ) :null ;
184201
185202foreach ($ filesInfoas $ info ) {
186203if ($ info ['valid ' ] &&$ output ->isVerbose ()) {
187204$ io ->comment ('<info>OK</info> ' .($ info ['file ' ] ?sprintf (' in %s ' ,$ info ['file ' ]) :'' ));
188205 }elseif (!$ info ['valid ' ]) {
189206 ++$ errors ;
190- $ this ->renderException ($ io ,$ info ['template ' ],$ info ['exception ' ],$ info ['file ' ]);
207+ $ this ->renderException ($ io ,$ info ['template ' ],$ info ['exception ' ],$ info ['file ' ], $ githubReporter );
191208 }
192209 }
193210
@@ -219,10 +236,14 @@ private function displayJson(OutputInterface $output, array $filesInfo)
219236return min ($ errors ,1 );
220237 }
221238
222- private function renderException (OutputInterface $ output ,string $ template ,Error $ exception ,string $ file =null )
239+ private function renderException (OutputInterface $ output ,string $ template ,Error $ exception ,string $ file =null , ? GithubActionReporter $ githubReporter = null )
223240 {
224241$ line =$ exception ->getTemplateLine ();
225242
243+ if ($ githubReporter ) {
244+ $ githubReporter ->error ($ exception ->getRawMessage (),$ file ,$ line );
245+ }
246+
226247if ($ file ) {
227248$ output ->text (sprintf ('<error> ERROR </error> in %s (line %s) ' ,$ file ,$ line ));
228249 }else {