From fdff3aeaba2183e236f99dea4b284559b85f7e23 Mon Sep 17 00:00:00 2001 From: Markus Staab <47448731+clxmstaab@users.noreply.github.com> Date: Thu, 13 Aug 2020 16:37:32 +0200 Subject: [PATCH] emit github action formatted error messages (#9120) --- .github/workflows/continuous-integration.yml | 1 + src/Composer/Console/Application.php | 22 ++++++++++- src/Composer/Console/GithubActionError.php | 40 ++++++++++++++++++++ src/Composer/Installer.php | 31 ++++++++++++--- 4 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 src/Composer/Console/GithubActionError.php diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 107aa2530..a57c5a804 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -11,6 +11,7 @@ on: env: COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" COMPOSER_UPDATE_FLAGS: "" + COMPOSER_TESTS_ARE_RUNNING: "1" SYMFONY_PHPUNIT_VERSION: "8.3" SYMFONY_PHPUNIT_REMOVE_RETURN_TYPEHINT: "1" diff --git a/src/Composer/Console/Application.php b/src/Composer/Console/Application.php index 622938476..acd0e4c0a 100644 --- a/src/Composer/Console/Application.php +++ b/src/Composer/Console/Application.php @@ -22,6 +22,7 @@ use Symfony\Component\Console\Helper\QuestionHelper; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +use Seld\JsonLint\ParsingException; use Composer\Command; use Composer\Composer; use Composer\Factory; @@ -191,6 +192,20 @@ class Application extends BaseApplication } } catch (NoSslException $e) { // suppress these as they are not relevant at this point + } catch (ParsingException $e) { + $details = $e->getDetails(); + + $file = realpath(Factory::getComposerFile()); + + $line = null; + if ($details && isset($details['line'])) { + $line = $details['line']; + } + + $ghe = new GithubActionError($this->io); + $ghe->emit($e->getMessage(), $file, $line); + + throw $e; } $this->hasPluginCommands = true; @@ -237,7 +252,7 @@ class Application extends BaseApplication if (function_exists('posix_getuid') && posix_getuid() === 0) { if ($commandName !== 'self-update' && $commandName !== 'selfupdate') { $io->writeError('Do not run Composer as root/super user! See https://getcomposer.org/root for details'); - + if ($io->isInteractive()) { if (!$io->askConfirmation('Continue as root/super user [yes]? ', true)) { return 1; @@ -307,8 +322,13 @@ class Application extends BaseApplication } catch (ScriptExecutionException $e) { return (int) $e->getCode(); } catch (\Exception $e) { + $ghe = new GithubActionError($this->io); + $ghe->emit($e->getMessage()); + $this->hintCommonErrors($e); + restore_error_handler(); + throw $e; } } diff --git a/src/Composer/Console/GithubActionError.php b/src/Composer/Console/GithubActionError.php new file mode 100644 index 000000000..bbf5eaca1 --- /dev/null +++ b/src/Composer/Console/GithubActionError.php @@ -0,0 +1,40 @@ +io = $io; + } + + /** + * @param string $message + * @param null|string $file + * @param null|int $line + */ + public function emit($message, $file = null, $line = null) + { + if (getenv('GITHUB_ACTIONS') && !getenv('COMPOSER_TESTS_ARE_RUNNING')) { + // newlines need to be encoded + // see https://github.com/actions/starter-workflows/issues/68#issuecomment-581479448 + $message = str_replace("\n", '%0A', $message); + + if ($file && $line) { + $this->io->write("::error file=". $file .",line=". $line ."::". $message); + } elseif ($file) { + $this->io->write("::error file=". $file ."::". $message); + } else { + $this->io->write("::error ::". $message); + } + } + } +} diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index b98a88c12..f8c788e10 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -13,6 +13,7 @@ namespace Composer; use Composer\Autoload\AutoloadGenerator; +use Composer\Console\GithubActionError; use Composer\DependencyResolver\DefaultPolicy; use Composer\DependencyResolver\LocalRepoTransaction; use Composer\DependencyResolver\LockTransaction; @@ -412,12 +413,18 @@ class Installer $ruleSetSize = $solver->getRuleSetSize(); $solver = null; } catch (SolverProblemsException $e) { - $this->io->writeError('Your requirements could not be resolved to an installable set of packages.', true, IOInterface::QUIET); - $this->io->writeError($e->getPrettyString($repositorySet, $request, $pool, $this->io->isVerbose())); + $err = 'Your requirements could not be resolved to an installable set of packages.'; + $prettyProblem = $e->getPrettyString($repositorySet, $request, $pool, $this->io->isVerbose()); + + $this->io->writeError(''. $err .'', true, IOInterface::QUIET); + $this->io->writeError($prettyProblem); if (!$this->devMode) { $this->io->writeError('Running update with --no-dev does not mean require-dev is ignored, it just means the packages will not be installed. If dev requirements are blocking the update you have to resolve those problems.', true, IOInterface::QUIET); } + $ghe = new GithubActionError($this->io); + $ghe->emit($err."\n".$prettyProblem); + return max(1, $e->getCode()); } @@ -571,10 +578,16 @@ class Installer $nonDevLockTransaction = $solver->solve($request, $this->ignorePlatformReqs); $solver = null; } catch (SolverProblemsException $e) { - $this->io->writeError('Unable to find a compatible set of packages based on your non-dev requirements alone.', true, IOInterface::QUIET); + $err = 'Unable to find a compatible set of packages based on your non-dev requirements alone.'; + $prettyProblem = $e->getPrettyString($repositorySet, $request, $pool, $this->io->isVerbose(), true); + + $this->io->writeError(''. $err .'', true, IOInterface::QUIET); $this->io->writeError('Your requirements can be resolved successfully when require-dev packages are present.'); $this->io->writeError('You may need to move packages from require-dev or some of their dependencies to require.'); - $this->io->writeError($e->getPrettyString($repositorySet, $request, $pool, $this->io->isVerbose(), true)); + $this->io->writeError($prettyProblem); + + $ghe = new GithubActionError($this->io); + $ghe->emit($err."\n".$prettyProblem); return max(1, $e->getCode()); } @@ -637,8 +650,14 @@ class Installer return 1; } } catch (SolverProblemsException $e) { - $this->io->writeError('Your lock file does not contain a compatible set of packages. Please run composer update.', true, IOInterface::QUIET); - $this->io->writeError($e->getPrettyString($repositorySet, $request, $pool, $this->io->isVerbose())); + $err = 'Your lock file does not contain a compatible set of packages. Please run composer update.'; + $prettyProblem = $e->getPrettyString($repositorySet, $request, $pool, $this->io->isVerbose()); + + $this->io->writeError(''. $err .'', true, IOInterface::QUIET); + $this->io->writeError($prettyProblem); + + $ghe = new GithubActionError($this->io); + $ghe->emit($err."\n".$prettyProblem); return max(1, $e->getCode()); }