Skip to content

Commit

Permalink
feature #29139 [FrameworkBundle][TranslationDebug] Return non-zero ex…
Browse files Browse the repository at this point in the history
…it code on failure (DAcodedBEAT)

This PR was squashed before being merged into the 5.1-dev branch (closes #29139).

Discussion
----------

[FrameworkBundle][TranslationDebug] Return non-zero exit code on failure

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | n/a
| License       | MIT
| Doc PR        | TBD

This PR introduces non-zero exit codes upon failure for the `debug:translations` command.  The addition can be useful for projects which wish to determine results easily in CI.

The exit code returned can be interpreted as a bit array and to determine what failed, one could Bitwise AND the returned exit code to determine what failed.

Exit Codes:

| Failure Reason   | bit array | integer |
| ----------------  | --------- | --------- |
| General Failure (i.e no translations at all) | `1000000` | 64 |
| Missing Translations | `1000001` | 65 |
| Unused Translations | `1000010` | 66 |
| Fallback Translations | `1000100` | 68 |

Example: Given there are missing and unused translations, the expected status code would be `TranslationDebugCommand::EXIT_CODE_MISSING | TranslationDebugCommand::EXIT_CODE_UNUSED`, which would be evaluated to `67`.

Commits
-------

0baafd8 [FrameworkBundle][TranslationDebug] Return non-zero exit code on failure
  • Loading branch information
fabpot committed Jan 31, 2020
2 parents 81abb4e + 0baafd8 commit 94efc95
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 11 deletions.
Expand Up @@ -38,6 +38,10 @@
*/
class TranslationDebugCommand extends Command
{
const EXIT_CODE_GENERAL_ERROR = 64;
const EXIT_CODE_MISSING = 65;
const EXIT_CODE_UNUSED = 66;
const EXIT_CODE_FALLBACK = 68;
const MESSAGE_MISSING = 0;
const MESSAGE_UNUSED = 1;
const MESSAGE_EQUALS_FALLBACK = 2;
Expand Down Expand Up @@ -123,6 +127,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int

$locale = $input->getArgument('locale');
$domain = $input->getOption('domain');

$exitCode = 0;

/** @var KernelInterface $kernel */
$kernel = $this->getApplication()->getKernel();

Expand Down Expand Up @@ -191,7 +198,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int

$io->getErrorStyle()->warning($outputMessage);

return 0;
return self::EXIT_CODE_GENERAL_ERROR;
}

// Load the fallback catalogues
Expand All @@ -212,9 +219,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int
if ($extractedCatalogue->defines($messageId, $domain)) {
if (!$currentCatalogue->defines($messageId, $domain)) {
$states[] = self::MESSAGE_MISSING;

$exitCode = $exitCode | self::EXIT_CODE_MISSING;
}
} elseif ($currentCatalogue->defines($messageId, $domain)) {
$states[] = self::MESSAGE_UNUSED;

$exitCode = $exitCode | self::EXIT_CODE_UNUSED;
}

if (!\in_array(self::MESSAGE_UNUSED, $states) && true === $input->getOption('only-unused')
Expand All @@ -226,6 +237,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
if ($fallbackCatalogue->defines($messageId, $domain) && $value === $fallbackCatalogue->get($messageId, $domain)) {
$states[] = self::MESSAGE_EQUALS_FALLBACK;

$exitCode = $exitCode | self::EXIT_CODE_FALLBACK;

break;
}
}
Expand All @@ -241,7 +254,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int

$io->table($headers, $rows);

return 0;
return $exitCode;
}

private function formatState(int $state): string
Expand Down
Expand Up @@ -26,42 +26,48 @@ class TranslationDebugCommandTest extends TestCase
public function testDebugMissingMessages()
{
$tester = $this->createCommandTester(['foo' => 'foo']);
$tester->execute(['locale' => 'en', 'bundle' => 'foo']);
$res = $tester->execute(['locale' => 'en', 'bundle' => 'foo']);

$this->assertRegExp('/missing/', $tester->getDisplay());
$this->assertEquals(TranslationDebugCommand::EXIT_CODE_MISSING, $res);
}

public function testDebugUnusedMessages()
{
$tester = $this->createCommandTester([], ['foo' => 'foo']);
$tester->execute(['locale' => 'en', 'bundle' => 'foo']);
$res = $tester->execute(['locale' => 'en', 'bundle' => 'foo']);

$this->assertRegExp('/unused/', $tester->getDisplay());
$this->assertEquals(TranslationDebugCommand::EXIT_CODE_UNUSED, $res);
}

public function testDebugFallbackMessages()
{
$tester = $this->createCommandTester([], ['foo' => 'foo']);
$tester->execute(['locale' => 'fr', 'bundle' => 'foo']);
$tester = $this->createCommandTester(['foo' => 'foo'], ['foo' => 'foo']);
$res = $tester->execute(['locale' => 'fr', 'bundle' => 'foo']);

$this->assertRegExp('/fallback/', $tester->getDisplay());
$this->assertEquals(TranslationDebugCommand::EXIT_CODE_FALLBACK, $res);
}

public function testNoDefinedMessages()
{
$tester = $this->createCommandTester();
$tester->execute(['locale' => 'fr', 'bundle' => 'test']);
$res = $tester->execute(['locale' => 'fr', 'bundle' => 'test']);

$this->assertRegExp('/No defined or extracted messages for locale "fr"/', $tester->getDisplay());
$this->assertEquals(TranslationDebugCommand::EXIT_CODE_GENERAL_ERROR, $res);
}

public function testDebugDefaultDirectory()
{
$tester = $this->createCommandTester(['foo' => 'foo'], ['bar' => 'bar']);
$tester->execute(['locale' => 'en']);
$res = $tester->execute(['locale' => 'en']);
$expectedExitStatus = TranslationDebugCommand::EXIT_CODE_MISSING | TranslationDebugCommand::EXIT_CODE_UNUSED;

$this->assertRegExp('/missing/', $tester->getDisplay());
$this->assertRegExp('/unused/', $tester->getDisplay());
$this->assertEquals($expectedExitStatus, $res);
}

public function testDebugDefaultRootDirectory()
Expand All @@ -72,11 +78,14 @@ public function testDebugDefaultRootDirectory()
$this->fs->mkdir($this->translationDir.'/translations');
$this->fs->mkdir($this->translationDir.'/templates');

$expectedExitStatus = TranslationDebugCommand::EXIT_CODE_MISSING | TranslationDebugCommand::EXIT_CODE_UNUSED;

$tester = $this->createCommandTester(['foo' => 'foo'], ['bar' => 'bar'], null, [$this->translationDir.'/trans'], [$this->translationDir.'/views']);
$tester->execute(['locale' => 'en']);
$res = $tester->execute(['locale' => 'en']);

$this->assertRegExp('/missing/', $tester->getDisplay());
$this->assertRegExp('/unused/', $tester->getDisplay());
$this->assertEquals($expectedExitStatus, $res);
}

public function testDebugCustomDirectory()
Expand All @@ -89,11 +98,14 @@ public function testDebugCustomDirectory()
->with($this->equalTo($this->translationDir.'/customDir'))
->willThrowException(new \InvalidArgumentException());

$expectedExitStatus = TranslationDebugCommand::EXIT_CODE_MISSING | TranslationDebugCommand::EXIT_CODE_UNUSED;

$tester = $this->createCommandTester(['foo' => 'foo'], ['bar' => 'bar'], $kernel);
$tester->execute(['locale' => 'en', 'bundle' => $this->translationDir.'/customDir']);
$res = $tester->execute(['locale' => 'en', 'bundle' => $this->translationDir.'/customDir']);

$this->assertRegExp('/missing/', $tester->getDisplay());
$this->assertRegExp('/unused/', $tester->getDisplay());
$this->assertEquals($expectedExitStatus, $res);
}

public function testDebugInvalidDirectory()
Expand Down
Expand Up @@ -11,6 +11,7 @@

namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;

use Symfony\Bundle\FrameworkBundle\Command\TranslationDebugCommand;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Tester\CommandTester;

Expand All @@ -32,7 +33,11 @@ public function testDumpAllTrans()
$tester = $this->createCommandTester();
$ret = $tester->execute(['locale' => 'en']);

$this->assertSame(0, $ret, 'Returns 0 in case of success');
$this->assertSame(
TranslationDebugCommand::EXIT_CODE_MISSING | TranslationDebugCommand::EXIT_CODE_UNUSED,
$ret,
'Returns appropriate exit code in the event of error'
);
$this->assertStringContainsString('missing messages hello_from_construct_arg_service', $tester->getDisplay());
$this->assertStringContainsString('missing messages hello_from_subscriber_service', $tester->getDisplay());
$this->assertStringContainsString('missing messages hello_from_property_service', $tester->getDisplay());
Expand Down

0 comments on commit 94efc95

Please sign in to comment.