Skip to content

Commit

Permalink
Allow changelog to be written to a file.
Browse files Browse the repository at this point in the history
  • Loading branch information
jwage committed May 19, 2018
1 parent 62cea31 commit e192aa6
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 7 deletions.
4 changes: 4 additions & 0 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@

<rule ref="Doctrine"/>

<rule ref="Squiz.Classes.ClassFileName.NoMatch">
<exclude-pattern>*/tests/*</exclude-pattern>
</rule>

<rule ref="PSR1.Classes.ClassDeclaration.MultipleClasses">
<exclude-pattern>*/tests/*</exclude-pattern>
</rule>
Expand Down
68 changes: 67 additions & 1 deletion src/ChangelogGenerator/Command/GenerateChangelogCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,15 @@
namespace ChangelogGenerator\Command;

use ChangelogGenerator\ChangelogGenerator;
use InvalidArgumentException;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\StreamOutput;
use function fopen;
use function getcwd;
use function sprintf;

class GenerateChangelogCommand extends Command
{
Expand Down Expand Up @@ -51,6 +56,19 @@ protected function configure() : void
InputOption::VALUE_REQUIRED,
'The milestone to build the changelog for.'
)
->addOption(
'file',
null,
InputOption::VALUE_OPTIONAL,
'Write the changelog to a file.',
false
)
->addOption(
'append',
null,
InputOption::VALUE_NONE,
'Append the changelog to the file.'
)
;
}

Expand All @@ -60,6 +78,54 @@ protected function execute(InputInterface $input, OutputInterface $output) : voi
$repository = $input->getOption('repository');
$milestone = $input->getOption('milestone');

$this->changelogGenerator->generate($user, $repository, $milestone, $output);
$changelogOutput = $this->getChangelogOutput($input, $output);

$this->changelogGenerator->generate($user, $repository, $milestone, $changelogOutput);
}

/**
* @return false|resource
*/
protected function fopen(string $file, string $mode)
{
return fopen($file, $mode);
}

/**
* @throws InvalidArgumentException
*/
protected function createStreamOutput(string $file, bool $append) : StreamOutput
{
$handle = $this->fopen($file, $this->getFileHandleMode($append));

if ($handle === false) {
throw new InvalidArgumentException(sprintf('Could not open handle for %s', $file));
}

return new StreamOutput($handle);
}

private function getFileHandleMode(bool $append) : string
{
return $append ? 'a+' : 'w+';
}

private function getChangelogOutput(InputInterface $input, OutputInterface $output) : OutputInterface
{
$file = $input->getOption('file');
$append = (bool) $input->getOption('append');

$changelogOutput = $output;

if ($file !== false) {
$changelogOutput = $this->createStreamOutput($this->getChangelogFilePath($file), $append);
}

return $changelogOutput;
}

private function getChangelogFilePath(?string $file) : string
{
return $file === null ? sprintf('%s/CHANGELOG.md', getcwd()) : $file;
}
}
140 changes: 134 additions & 6 deletions tests/ChangelogGenerator/Tests/Functional/ConsoleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,172 @@

use ChangelogGenerator\ChangelogGenerator;
use ChangelogGenerator\Command\GenerateChangelogCommand;
use InvalidArgumentException;
use PackageVersions\Versions;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\StreamOutput;
use function sprintf;
use function sys_get_temp_dir;
use function unlink;

final class ConsoleTest extends TestCase
{
/** @var \PHPUnit_Framework_MockObject_MockObject|ChangelogGenerator */
private $changelogGenerator;

/** @var \PHPUnit_Framework_MockObject_MockObject|GenerateChangelogCommand */
private $generateChangelogCommand;

/** @var Application */
private $application;

public function testGenerate() : void
{
$input = new ArrayInput([
'command' => 'generate',
'--user' => 'jwage',
'--repository' => 'changelog-generator',
'--milestone' => '1.0',
'command' => 'generate',
'--user' => 'jwage',
'--repository' => 'changelog-generator',
'--milestone' => '1.0',
]);

$output = $this->createMock(OutputInterface::class);

$this->changelogGenerator->expects($this->once())
->method('generate')
->with('jwage', 'changelog-generator', '1.0');
->with('jwage', 'changelog-generator', '1.0', $output);

$this->application->run($input, $output);
}

public function testGenerateFile() : void
{
$input = new ArrayInput([
'command' => 'generate',
'--user' => 'jwage',
'--repository' => 'changelog-generator',
'--milestone' => '1.0',
'--file' => null,
]);

$output = $this->createMock(OutputInterface::class);
$streamOutput = $this->createMock(StreamOutput::class);

$this->generateChangelogCommand->expects($this->once())
->method('createStreamOutput')
->willReturn($streamOutput);

$this->changelogGenerator->expects($this->once())
->method('generate')
->with('jwage', 'changelog-generator', '1.0', $streamOutput);

$this->application->run($input, $output);
}

public function testGenerateFilePathGiven() : void
{
$input = new ArrayInput([
'command' => 'generate',
'--user' => 'jwage',
'--repository' => 'changelog-generator',
'--milestone' => '1.0',
'--file' => 'CHANGELOG.md',
]);

$output = $this->createMock(OutputInterface::class);
$streamOutput = $this->createMock(StreamOutput::class);

$this->generateChangelogCommand->expects($this->once())
->method('createStreamOutput')
->willReturn($streamOutput);

$this->changelogGenerator->expects($this->once())
->method('generate')
->with('jwage', 'changelog-generator', '1.0', $streamOutput);

$this->application->run($input, $output);
}

public function testGenerateFileAppend() : void
{
$input = new ArrayInput([
'command' => 'generate',
'--user' => 'jwage',
'--repository' => 'changelog-generator',
'--milestone' => '1.0',
'--file' => 'CHANGELOG.md',
'--append' => true,
]);

$output = $this->createMock(OutputInterface::class);
$streamOutput = $this->createMock(StreamOutput::class);

$this->generateChangelogCommand->expects($this->once())
->method('createStreamOutput')
->willReturn($streamOutput);

$this->changelogGenerator->expects($this->once())
->method('generate')
->with('jwage', 'changelog-generator', '1.0', $streamOutput);

$this->application->run($input, $output);
}

public function testCreateStreamOutput() : void
{
$generateChangelogCommand = new GenerateChangelogCommandStub($this->changelogGenerator);

$file = sprintf('%s/test.md', sys_get_temp_dir());

self::assertInstanceOf(StreamOutput::class, $generateChangelogCommand->createStreamOutputTest($file, true));
self::assertInstanceOf(StreamOutput::class, $generateChangelogCommand->createStreamOutputTest($file, false));

unlink($file);
}

public function testCreateStreamOutputCouldNotOpenHandleInvalidArgumentException() : void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Could not open handle for /tmp/test.md');

$file = sprintf('%s/test.md', sys_get_temp_dir());

/** @var \PHPUnit_Framework_MockObject_MockObject|GenerateChangelogCommandStub $generateChangelogCommand */
$generateChangelogCommand = $this->getMockBuilder(GenerateChangelogCommandStub::class)
->setConstructorArgs([$this->changelogGenerator])
->setMethods(['fopen'])
->getMock();

$generateChangelogCommand->expects($this->once())
->method('fopen')
->with($file, 'a+')
->willReturn(false);

$generateChangelogCommand->createStreamOutputTest($file, true);
}

protected function setUp() : void
{
$this->changelogGenerator = $this->createMock(ChangelogGenerator::class);

$this->application = new Application('Changelog Generator', Versions::getVersion('jwage/changelog-generator'));
$this->application->setAutoExit(false);
$this->application->add(new GenerateChangelogCommand($this->changelogGenerator));

$this->generateChangelogCommand = $this->getMockBuilder(GenerateChangelogCommand::class)
->setConstructorArgs([$this->changelogGenerator])
->setMethods(['createStreamOutput'])
->getMock();

$this->application->add($this->generateChangelogCommand);
}
}

class GenerateChangelogCommandStub extends GenerateChangelogCommand
{
public function createStreamOutputTest(string $file, bool $append) : StreamOutput
{
return $this->createStreamOutput($file, $append);
}
}

0 comments on commit e192aa6

Please sign in to comment.